如何通过cmdline获取panel型号的dtsi文件节点(qcom,lcd,id)

platform:msm8976 android 7.11

  1. 在lk层,常用的方法是通过读取panel的id来确定当前使用的panel的型号,然后将panel的型号放在cmdline里面,如下:
    project:/ # cat /proc/cmdline
    … … … androidconfig.secureboot=enabled mdss_mdp.panel=1:dsi:0:qcom,mdss_dsi_ili9885_lide_hcg_auo_fhd_video:1:none:cfg:single_dsi … … …
  2. 在kernel层,通过cmdline寻找panel的dtsi文件节点并得到属性,这个过程是在mdss_dsi_config_panel函数进行的,如下:
    (x:\work\project\kernel\drivers\video\msm\mdss\Mdss_dsi.c)mdss_dsi_ctrl_probe–>mdss_dsi_config_panel
    static struct device_node *mdss_dsi_config_panel(struct platform_device *pdev)
    {
    struct mdss_dsi_ctrl_pdata *ctrl_pdata = platform_get_drvdata(pdev);
    char panel_cfg[MDSS_MAX_PANEL_LEN];
    struct device_node dsi_pan_node = NULL;
    int rc = 0;
    if (!ctrl_pdata) {
    pr_err("%s: Unable to get the ctrl_pdata\n", func);
    return NULL;
    }
    /
    DSI panels can be different between controllers /
    rc = mdss_dsi_get_panel_cfg(panel_cfg, ctrl_pdata);
    if (!rc)
    /
    dsi panel cfg not present /
    pr_warn("%s:%d:dsi specific cfg not present\n",
    func, LINE);
    /
    find panel device node */
    dsi_pan_node = mdss_dsi_find_panel_of_node(pdev, panel_cfg);
    if (!dsi_pan_node) {
    pr_err("%s: can’t find panel node %s\n", func, panel_cfg);
    of_node_put(dsi_pan_node);
    return NULL;
    }
    rc = mdss_dsi_panel_init(dsi_pan_node, ctrl_pdata);
    if (rc) {
    pr_err("%s: dsi panel init failed\n", func);
    of_node_put(dsi_pan_node);
    return NULL;
    }
    return dsi_pan_node;
    }
  3. mdss_dsi_config_panel函数主要是由三个部分组成:
    3.1. 解析lk层传给kernel层cmdline的mdss_mdp.panel属性,在mdss_dsi_get_panel_cfg函数进行,
    3.2. 根据cmdline的mdss_mdp.panel属性寻找panel的dtsi文件节点,在mdss_dsi_find_panel_of_node函数进行
    3.3. 解析panel dtsi文件节点中的属性并配置panel的操作集,在mdss_dsi_panel_init函数进行
  4. 下面我们依次来说明这三个部分,首先是mdss_dsi_get_panel_cfg函数
    vim x:\work\project\kernel\drivers\video\msm\mdss\Mdss_dsi.c
    static int mdss_dsi_get_panel_cfg(char *panel_cfg,
    struct mdss_dsi_ctrl_pdata *ctrl)
    {
    int rc;
    struct mdss_panel_cfg *pan_cfg = NULL;
    if (!panel_cfg)
    return MDSS_PANEL_INTF_INVALID;
    pan_cfg = ctrl->mdss_util->panel_intf_type(MDSS_PANEL_INTF_DSI);
    if (IS_ERR(pan_cfg)) {
    return PTR_ERR(pan_cfg);
    } else if (!pan_cfg) {
    panel_cfg[0] = 0;
    return 0;
    }
    pr_debug("%s:%d: cfg:[%s]\n", func, LINE,
    pan_cfg->arg_cfg);
    rc = strlcpy(panel_cfg, pan_cfg->arg_cfg,
    sizeof(pan_cfg->arg_cfg));
    return rc;
    }
    通过日志,我们看到panel_cfg的字符串内容(0:qcom,mdss_dsi_ili9885_lide_hcg_auo_fhd_video:1:none:cfg:single_dsi),如下:
    [ 1.045387] mdss_dsi_get_panel_cfg:629: cfg:[0:qcom,mdss_dsi_ili9885_lide_hcg_auo_fhd_video:1:none:cfg:single_dsi]
    //0表示dsi0,说明panel_cfg的字符串内容包含panel的型号名称和panel所属的dsi number
  5. 接下来我们来看看mdss_dsi_find_panel_of_node函数
    vim x:\work\project\kernel\drivers\video\msm\mdss\Mdss_dsi.c
    static struct device_node *mdss_dsi_find_panel_of_node(
    struct platform_device *pdev, char *panel_cfg)
    {
    int len, i;
    int ctrl_id = pdev->id - 1;
    char panel_name[MDSS_MAX_PANEL_LEN];
    char ctrl_id_stream[3] = “0:”;
    char *stream = NULL, *pan = NULL;
    struct device_node *dsi_pan_node = NULL, mdss_node = NULL;
    len = strlen(panel_cfg);
    if (!len) {
    /
    no panel cfg chg, parse dt */
    pr_debug("%s:%d: no cmd line cfg present\n",
    func, LINE);
    goto end;
    } else {
    if (ctrl_id == 1)
    strlcpy(ctrl_id_stream, “1:”, 3);
    stream = strnstr(panel_cfg, ctrl_id_stream, len);
    if (!stream) {
    pr_err(“controller config is not present\n”);
    goto end;
    }
    stream += 2;
    pan = strnchr(stream, strlen(stream), ‘:’);
    if (!pan) {
    strlcpy(panel_name, stream, MDSS_MAX_PANEL_LEN); //根据panel_cfg的字符串的内容,得到panel的型号名称是qcom,mdss_dsi_ili9885_lide_hcg_auo_fhd_video
    } else {
    for (i = 0; (stream + i) < pan; i++)
    panel_name[i] = *(stream + i);
    panel_name[i] = 0;
    }
    pr_debug("%s:%d:%s:%s\n", func, LINE,
    panel_cfg, panel_name);
    //日志如下:[ 1.045392] mdss_dsi_find_panel_of_node:2355:0:qcom,mdss_dsi_ili9885_lide_hcg_auo_fhd_video:1:none:cfg:single_dsi:qcom,mdss_dsi_ili9885_lide_hcg_auo_fhd_video
    mdss_node = of_parse_phandle(pdev->dev.of_node, //得到mdss_mdp节点,因为所有的panel型号都是挂在mdss_mdp节点下面,mdss_mdp节点的compatible = “qcom,mdss_mdp”;
    “qcom,mdss-mdp”, 0);
    if (!mdss_node) {
    pr_err("%s: %d: mdss_node null\n",
    func, LINE);
    return NULL;
    }
    dsi_pan_node = of_find_node_by_name(mdss_node, //根据panel的型号名称找到panel型号的dtsi文件节点
    panel_name);
    if (!dsi_pan_node) {
    pr_err("%s: invalid pan node, selecting prim panel\n",
    func);
    goto end;
    }
    return dsi_pan_node; //返回panel型号的dtsi文件节点
    }
    end:
    if (strcmp(panel_name, NONE_PANEL))
    dsi_pan_node = mdss_dsi_pref_prim_panel(pdev);
    return dsi_pan_node;
    }
  6. 接下来我们来看看mdss_dsi_panel_init函数
    vim x:\work\xxx\kernel\drivers\video\msm\mdss\Mdss_dsi_panel.c
    int mdss_dsi_panel_init(struct device_node *node,
    struct mdss_dsi_ctrl_pdata *ctrl_pdata)
    {
    int rc = 0;
    static const char *panel_name;
    struct mdss_panel_info *pinfo;
    if (!node || !ctrl_pdata) {
    pr_err("%s: Invalid arguments\n", func);
    return -ENODEV;
    }
    pinfo = &ctrl_pdata->panel_data.panel_info;
    pr_debug("%s:%d\n", func, LINE);
    pinfo->panel_name[0] = ‘\0’;
    panel_name = of_get_property(node, “qcom,mdss-dsi-panel-name”, NULL); //得到panel节点的qcom,mdss-dsi-panel-name属性
    if (!panel_name) {
    pr_info("%s:%d, Panel name not specified\n",
    func, LINE);
    } else {
    pr_info("%s: Panel Name = %s\n", func, panel_name);
    strlcpy(&pinfo->panel_name[0], panel_name, MDSS_MAX_PANEL_LEN);
    }
    rc = mdss_panel_parse_dt(node, ctrl_pdata); //解析panel节点下面其他的属性
    if (rc) {
    pr_err("%s:%d panel dt parse failed\n", func, LINE);
    return rc;
    }
    mdss_dsi_set_prim_panel(ctrl_pdata);
    pinfo->dynamic_switch_pending = false;
    pinfo->is_lpm_mode = false;
    pinfo->esd_rdy = false;
    ctrl_pdata->on = mdss_dsi_panel_on; //以下都是panel的操作集,唤醒屏幕的操作
    ctrl_pdata->post_panel_on = mdss_dsi_post_panel_on; //唤醒屏幕的延迟操作
    ctrl_pdata->off = mdss_dsi_panel_off; //休眠屏幕的操作
    ctrl_pdata->low_power_config = mdss_dsi_panel_low_power_config; //针对屏的低功耗配置
    ctrl_pdata->panel_data.set_backlight = mdss_dsi_panel_bl_ctrl; //设置panel的背光操作函数
    ctrl_pdata->switch_mode = mdss_dsi_panel_switch_mode; //panel mode的切换,如:video2command,command2video
    return 0;
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以参考以下代码来使用 `saved_command_line` 来解析 `panel_id` 参数: ```c #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/string.h> static int panel_id = -1; // 初始化为无效值 static int __init my_module_init(void) { pr_info("my_module: panel_id=%d\n", panel_id); // 在这里使用 panel_id 参数进行其它操作 return 0; } static void __exit my_module_exit(void) { pr_info("my_module: exit\n"); } module_init(my_module_init); module_exit(my_module_exit); // 解析 panel_id 参数 static int __init parse_panel_id(char *str) { char *ptr; int id = -1; ptr = strstr(saved_command_line, "panel_id="); if (ptr != NULL) { id = simple_strtol(ptr + strlen("panel_id="), NULL, 10); } if (id >= 0) { panel_id = id; pr_info("my_module: panel_id=%d\n", panel_id); } else { pr_info("my_module: panel_id not found\n"); } return 1; // 返回 1 表示已处理该参数 } // 注册解析函数 static int __init register_parse_panel_id(void) { parse_early_param("panel_id", parse_panel_id); return 0; } early_initcall(register_parse_panel_id); ``` 在该程序中,我们使用 `strstr` 函数在 `saved_command_line` 中搜索 `panel_id` 参数,并使用 `simple_strtol` 函数将其转换为整数类型。如果解析成功,则将其存储到全局变量 `panel_id` 中。在模块初始化函数 `my_module_init` 中,我们可以使用 `panel_id` 参数进行其它操作。 需要注意的是,由于 `saved_command_line` 是一个字符串指针,其内容可能会被修改,因此需要在解析参数时使用字符串操作函数(如 `strtok`、`strchr` 等)来确保正确性。同时,由于在使用 `saved_command_line` 时需要在 `early_initcall` 中注册解析函数,因此该方法并不适用于需要在模块初始化函数中使用参数的情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值