uboot与kernel之间参数的传递:
dsi_display.c
static char dsi_display_primary[MAX_CMDLINE_PARAM_LEN];
module_param_string(dsi_display0, dsi_display_primary, MAX_CMDLINE_PARAM_LEN, 0600);
MODULE_PARM_DESC(dsi_display0,
"msm_drm.dsi_display0=<display node>:<configX> where <display node> is 'primary dsi display node name' and <configX> where x represents index in the topology list");
MODULE_PARM_DESC:对参数进行说明
include\linux\moduleparam.h
#define module_param_string(name, string, len, perm) \
static const struct kparam_string __param_string_##name \
= {
len, string }; \
__module_param_call(MODULE_PARAM_PREFIX, name, \
¶m_ops_string, \
.str = &__param_string_##name, perm, -1, 0);\
__MODULE_PARM_TYPE(name, "string")
name:参数名字
string:驱动代码里的变量名
#ifdef MODULE
#define MODULE_PARAM_PREFIX /* empty */
#else
#define MODULE_PARAM_PREFIX KBUILD_MODNAME "."
#endif
include\linux\moduleparam.h
#if defined(CONFIG_ALPHA) || defined(CONFIG_IA64) || defined(CONFIG_PPC64)
#define __moduleparam_const
#else
#define __moduleparam_const const
#endif
vendor\qcom\opensource\display-drivers\msm\Android.mk
KBUILD_OPTIONS += MODNAME=msm_drm
注:msm_drm.dsi_display0应该就是这么来的
kernel\params.c
const struct kernel_param_ops param_ops_string = {
.set = param_set_copystring,
.get = param_get_string,
};
替换后得到
static const struct kparam_string __param_string_dsi_display0 = {
MAX_CMDLINE_PARAM_LEN, dsi_display_primary}; \
static const char __param_str_dsi_display0[] = "msm_drm.dsi_display0"; \
static struct kernel_param const __param_dsi_display0
__used __section("__param") __aligned(__alignof__(struct kernel_param)) \
= {
__param_str_dsi_display0, THIS_MODULE, ¶m_ops_string, \
VERIFY_OCTAL_PERMISSIONS(0600), -1, 0, {
.str = &__param_string_dsi_display0 } }
__param_dsi_display0 放在__param段中。
将"msm_drm.dsi_display0"和cmdline中的参数进行比较,如果同名,则会调用param_set_copystring,将值拷贝到dsi_display_primary。
static struct dsi_display_boot_param boot_displays[MAX_DSI_ACTIVE_DISPLAY] = {
{
.boot_param = dsi_display_primary},
{
.boot_param = dsi_display_secondary},
};
vendor\qcom\opensource\display-drivers\msm\dsi\dsi_display.c
static int dsi_display_parse_boot_display_selection(void)
{
char *pos = NULL;
char disp_buf[MAX_CMDLINE_PARAM_LEN] = {
'\0'};
int i, j;
for (i = 0; i < MAX_DSI_ACTIVE_DISPLAY; i++) {
strlcpy(disp_buf, boot_displays[i].boot_param, MAX_CMDLINE_PARAM_LEN);
pos = strnstr(disp_buf, ":", strlen(disp_buf));
/* Use ':' as a delimiter to retrieve the display name */
if (!pos) {
DSI_DEBUG("display name[%s]is not valid\n", disp_buf);
continue;
}
for (j = 0; (disp_buf + j) < pos; j++)
boot_displays[i].name[j] = *(disp_buf + j);
boot_displays[i].name[j] = '\0';
boot_displays[i].boot_disp_en = true;
}
return 0;
}
图片来源:Xiaomi POCO F1 (xiaomi-beryllium)
上图是某一款手机/proc/cmdline的值,能看到屏幕信息变量名是msm_drm.dsi_display0,变量值dsi_tianma_fhd_nt36672a_video_display后面是跟了一个’:'。和上面的代码对应起来了。
dsi_display.c
int dsi_display_dev_probe(struct platform_device *pdev)
{
boot_disp = &boot_displays[index];
node = pdev->dev.of_node;
if (boot_disp->boot_disp_en) {
/* The panel name should be same as UEFI name index */
panel_node = of_find_node_by_name(mdp_node, boot_disp->name);
if (!panel_node)
DSI_WARN("%s panel_node %s not found\n", display->display_type,
boot_disp->name);
} else {
panel_node = of_parse_phandle(node,
"qcom,dsi-default-panel", 0);
if (!panel_node)
DSI_WARN("%s default panel not found\n", display->display_type);
}
}
通过屏幕名字在设备树中查找屏幕节点。
问:为什么不在uboot/uefi阶段解析dts?
答:uboot/uefi会将dtb的首地址传给kernel。dts里那么多参数,uboot/uefi解析后怎么传给Kernel?
change list:
2023.4.9 module_param_string的分析更加具体一些;
参考资料:
[1]OnePlusOSS/android_kernel_modules_and_devicetree_oneplus_sm8475
[2]Kernel: Xiaomi kernel changes for Mi 10S and Redmi K40 Android R
[3]Linux驱动代码中MODULE_PARM_DESC的作用
[4]驱动模块传参
[5]CSDN kerneler_《linux kernel的cmdline参数解析原理分析》