基于3.14.28内核。

大致描述一下fb的初始化流程。

hdmi、lcd等驱动注册。

主要通过hdmi的注册来分析,提了一下lvds的注册。
hdmi的注册代码路径为/drivers/video/mxc/mxc_hdmi.c

1 设备树中的各hdmi节点。

"fsl,imx6q-hdmi-core"为hdmi的控制驱动。
"fsl,imx6q-hdmi-audio"为音频设备。
"fsl,imx6q-hdmi-video"为fb提供hdmi的设备,是fb的具体设备。在/arch/arm/boot/dts/imx6qdl.dtsi中。
"fsl,imx6-hdmi-i2c"是i2c设备,用来读取edid信息。在/arch/arm/boot/dts/imx6qdl-sabresd.dtsi中。
下面只列出了了video跟i2c两个的设备树信息。

hdmi: edid@50 {compatible = "fsl,imx6-hdmi-i2c";reg = <0x50>;
};
...
hdmi_video: hdmi_video@020e0000 {compatible = "fsl,imx6q-hdmi-video";reg = <0x020e0000 0x1000>;reg-names = "hdmi_gpr";interrupts = <0 115 IRQ_TYPE_LEVEL_HIGH>;clocks = <&clks IMX6QDL_CLK_HDMI_ISFR>,<&clks IMX6QDL_CLK_HDMI_IAHB>,<&clks IMX6QDL_CLK_HSI_TX>;clock-names = "hdmi_isfr", "hdmi_iahb", "mipi_core";status = "disabled";
};

2. 注册hdmi-i2c设备驱动。

是用来读取edid信息,匹配的设备为"fsl,imx6-hdmi-i2c"。
module_init(mxc_hdmi_i2c_init);模块入口,调用mxc_hdmi_i2c_init函数。mxc_hdmi_i2c_init中注册了mxc_hdmi_i2c_driver i2c设备驱动。主要代码如下。

static const struct of_device_id imx_hdmi_i2c_match[] = {{ .compatible = "fsl,imx6-hdmi-i2c", },{ /* sentinel */ }
};static const struct i2c_device_id mxc_hdmi_i2c_id[] = {{ "mxc_hdmi_i2c", 0 },{},
};
MODULE_DEVICE_TABLE(i2c, mxc_hdmi_i2c_id);static struct i2c_driver mxc_hdmi_i2c_driver = {.driver = {.name = "mxc_hdmi_i2c",.of_match_table    = imx_hdmi_i2c_match,},.probe = mxc_hdmi_i2c_probe,.remove = mxc_hdmi_i2c_remove,.id_table = mxc_hdmi_i2c_id,
};static int __init mxc_hdmi_i2c_init(void)
{return i2c_add_driver(&mxc_hdmi_i2c_driver);
}static void __exit mxc_hdmi_i2c_exit(void)
{i2c_del_driver(&mxc_hdmi_i2c_driver);
}module_init(mxc_hdmi_i2c_init);
module_exit(mxc_hdmi_i2c_exit);

在mxc_hdmi_i2c_probe函数中,可以看到比较简单,先检查i2c_adapter的特性,并将该设备赋值到全局变量中hdmi_i2c 。代码如下。

static int mxc_hdmi_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id)
{if (!i2c_check_functionality(client->adapter,I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C))return -ENODEV;hdmi_i2c = client;return 0;
}

3. 注册hdmi-video hdmi显示设备

这是具体的显示设备,过程与上面类似。代码如下。

static const struct of_device_id imx_hdmi_dt_ids[] = {{ .compatible = "fsl,imx6dl-hdmi-video", .data = &imx_hdmi_devtype[IMX6DL_HDMI],},{ .compatible = "fsl,imx6q-hdmi-video", .data = &imx_hdmi_devtype[IMX6Q_HDMI],},{ /* sentinel */ }
};
static struct platform_driver mxc_hdmi_driver = {.probe = mxc_hdmi_probe,.remove = mxc_hdmi_remove,.driver = {.name = "mxc_hdmi",.of_match_table = imx_hdmi_dt_ids,.owner = THIS_MODULE,},
};static int __init mxc_hdmi_init(void)
{return platform_driver_register(&mxc_hdmi_driver);
}
module_init(mxc_hdmi_init);

4. mxc_hdmi_probe函数。

  1. 首先检查hdcp是否在设备树中打开。这里没有设置打开。故hdcp_init为null。如果hdmi_i2c也为null会报错。这里hdmi_i2c已经初始化。代码如下。

    /* Check I2C driver is loaded and available* check hdcp function is enable by dts */
    hdmi_hdcp_get_property(pdev);
    if (!hdmi_i2c && !hdcp_init)return -ENODEV;
    
  2. 获取platform资源 res,该资源为reg = <0x20e0000 0x1000>,申请platform设备 mxc_hdmi 内存,并赋值全局变量。创建字符设备mxc_hdmi。 hdmi_major 主设备号为249。创建 hdmi_class,/sys/class/mxc_hdmi 目录。根据 hdmi_major 在 hdmi_class 创建子目录 mxc_hdmi。申请core_pdev内存。通过 ioremap 映射 res 。代码就不贴了。

  3. 调用mxc_dispdrv_register函数注册mxc_hdmi_drv,为初始化重要变量。

    hdmi->disp_mxc_hdmi = mxc_dispdrv_register(&mxc_hdmi_drv);
    if (IS_ERR(hdmi->disp_mxc_hdmi)) {dev_err(&pdev->dev, "Failed to register dispdrv - 0x%x\n",(int)hdmi->disp_mxc_hdmi);ret = (int)hdmi->disp_mxc_hdmi;goto edispdrv;
    }
    

    mxc_hdmi_drv保存了初始化等回调函数。

    static struct mxc_dispdrv_driver mxc_hdmi_drv = {.name   = DISPDRV_HDMI,.init   = mxc_hdmi_disp_init,.deinit   = mxc_hdmi_disp_deinit,.enable = mxc_hdmi_power_on,.disable = mxc_hdmi_power_off,
    };
    
  4. mxc_dispdrv_register函数在/drivers/video/mxc/mxc_dispdrv.c中,该文件有3组函数,用来保存具体显显示设备的回调信息,获取回调信息并调用初始化等。
    mxc_dispdrv_register首先申请了一个mxc_dispdrv_entry的节点new,将mxc_hdmi_drv保存在这个节点的drv成员中,然后将这个节点加入dispdrv_list链表中,最后返回该节点给调用者。代码如下:

    struct mxc_dispdrv_handle *mxc_dispdrv_register(struct mxc_dispdrv_driver *drv)
    {struct mxc_dispdrv_entry *new;mutex_lock(&dispdrv_lock);new = kzalloc(sizeof(struct mxc_dispdrv_entry), GFP_KERNEL);if (!new) {mutex_unlock(&dispdrv_lock);return ERR_PTR(-ENOMEM);}new->drv = drv;list_add_tail(&new->list, &dispdrv_list);mutex_unlock(&dispdrv_lock);return (struct mxc_dispdrv_handle *)new;
    }
    
  5. 设置变量。代码如下。

    mxc_dispdrv_setdata(hdmi->disp_mxc_hdmi, hdmi);
    platform_set_drvdata(pdev, hdmi);
    

    至此,hdmi-video hdmi显示设备注册完成。

5. lvds显示设备的流程与hdmi类似,代码在/drivers/video/mxc/ldb.c中。暂不添加具体分析了。

mxc framebuffer初始化过程

代码主要文件为/drivers/video/mxc/mxc_ipuv3_fb.c

1 设备树节点

在/arch/arm/boot/dts/imx6qdl-sabresd.dtsi中。共有mxcfb1:fb@0到mxcfb4: fb@3共4个节点。这里只列出第一个节点。该节点的disp_dev为"ldb",在驱动初始化时不使用此字段。

mxcfb1: fb@0 {compatible = "fsl,mxc_sdc_fb";disp_dev = "ldb";interface_pix_fmt = "RGB666";default_bpp = <16>;int_clk = <0>;late_init = <0>;status = "disabled";
};

2 模块注册。

与上面类似。最后调用mxcfb_probe函数。

3 mxcfb_probe分析

  1. 获取fb的id号,申请plat_data内存,mxcfb_get_of_property获取设备树参数。在mxcfb_get_of_property中plat_data->disp_dev读取了"disp_dev"节点参数,后续会修改此参数。

    pdev->id = of_alias_get_id(pdev->dev.of_node, "mxcfb");
    if (pdev->id < 0) {dev_err(&pdev->dev, "can not get alias id\n");return pdev->id;
    }plat_data = devm_kzalloc(&pdev->dev, sizeof(structipuv3_fb_platform_data), GFP_KERNEL);
    if (!plat_data)return -ENOMEM;
    pdev->dev.platform_data = plat_data;ret = mxcfb_get_of_property(pdev, plat_data);
    if (ret < 0) {dev_err(&pdev->dev, "get mxcfb of property fail\n");return ret;
    }
    
  2. 申请 fb_infomxcfb_info 内存并填充mxcfb_ops回调函数。
    /* Initialize FB structures */
    fbi = mxcfb_init_fbinfo(&pdev->dev, &mxcfb_ops);
    if (!fbi) {ret = -ENOMEM;goto init_fbinfo_failed;
    }
    
  3. 调用mxcfb_option_setup函数。在fb_get_options函数中,获取 kernel cmdline 中的显示参数。更新 disp_dev 字段。这里pdata->disp_dev被更新为hdmi。不能解析的参数放在pdata->mode_str中。
    name[5] += pdev->id;
    if (fb_get_options(name, &options)) {dev_err(&pdev->dev, "Can't get fb option for %s!\n", name);return -ENODEV;
    }
    ...
    if (!strncmp(opt, "dev=", 4)) {memcpy(pdata->disp_dev, opt + 4, strlen(opt) - 4);pdata->disp_dev[strlen(opt) - 4] = '\0';
    }
    ...
    
  4. 调用mxcfb_dispdrv_init函数。由pdata->disp_dev构建 disp_dev 字符串,调用mxc_dispdrv_gethandle函数。
    if (!strlen(plat_data->disp_dev)) {memcpy(disp_dev, default_dev, strlen(default_dev));disp_dev[strlen(default_dev)] = '\0';
    } else {memcpy(disp_dev, plat_data->disp_dev,strlen(plat_data->disp_dev));disp_dev[strlen(plat_data->disp_dev)] = '\0';
    }mxcfbi->dispdrv = mxc_dispdrv_gethandle(disp_dev, &setting);
    
  5. mxc_dispdrv_gethandle函数在/drivers/video/mxc/mxc_dispdrv.c中,与上面mxc_dispdrv_register是一系列函数。mxc_dispdrv_gethandle根据disp_dev参数name,遍历dispdrv_list列表,对比drv->name(回调变量中的name字段)与name,找到对应的drv,并调用drv->init。
    struct mxc_dispdrv_handle *mxc_dispdrv_gethandle(char *name,struct mxc_dispdrv_setting *setting)
    {int ret, found = 0;struct mxc_dispdrv_entry *entry;mutex_lock(&dispdrv_lock);list_for_each_entry(entry, &dispdrv_list, list) {if (!strcmp(entry->drv->name, name) && (entry->drv->init)) {ret = entry->drv->init((struct mxc_dispdrv_handle *)entry, setting);if (ret >= 0) {entry->active = true;found = 1;break;}}}mutex_unlock(&dispdrv_lock);return found ? (struct mxc_dispdrv_handle *)entry:ERR_PTR(-ENODEV);
    }
    
  6. drv->init函数为mxc_hdmi.c中的mxc_hdmi_disp_init函数。获取irq中断号,获取设备树参数。设置ipu,设置时钟等。
    struct mxc_hdmi *hdmi = mxc_dispdrv_getdata(disp);
    int irq = platform_get_irq(hdmi->pdev, 0);
    ...
    hdmi_get_of_property(hdmi);
    ...
    hdmi_init_route(hdmi);
    ...
    /* Setting HDMI default to blank state */
    ...
    //Enabled HDMI clocks
    
  7. 初始化modelist。选出最接近的分辨率设置为默认参数。
  8. 初始化热插拔工作队列hotplug_worker及hdcp队列。hotplug_worker工作队列在中断处理后工作,放在以后分析。
    INIT_DELAYED_WORK(&hdmi->hotplug_work, hotplug_worker);
    INIT_DELAYED_WORK(&hdmi->hdcp_hdp_work, hdcp_hdp_worker);
    
  9. 注册中断函数mxc_hdmi_hotplug, 处理hdmi热插拔事件。mxc_hdmi_hotplug以后分析。
    ret = devm_request_irq(&hdmi->pdev->dev, irq, mxc_hdmi_hotplug, IRQF_SHARED,dev_name(&hdmi->pdev->dev), hdmi);
    if (ret < 0) {dev_err(&hdmi->pdev->dev,"Unable to request irq: %d\n", ret);goto ereqirq;
    }
    
  10. 创建sys虚拟文件,hdmi_inited置位true表使已初始化。至此mxc_hdmi_disp_init运行结束。
  11. 回到mxcfb_probe函数。ipu设置,资源申请等。mxcfb_register函数注册fb_info。注册ipu中断函数。注册到framebuffer模块中。mxcfb_setup_overlay初始化overlay设备,调用mxcfb_register。创建sys虚拟文件。
  12. 至此,fb初始化完成。最后几步没有进行详细分析,可直接参考源代码。

imx6q mxc 的 framebuffer 初始化过程相关推荐

  1. android kernel控制台初始化过程

    对于我们的android平台,控制台被定义到了串口1上,因此初始化过程就是把控制台的输出配置到串口1上 对kernel控制台初始化是在挂载文件系统之前,由于没有串口的设备文件,不能通过打开设备文件来访 ...

  2. hadoop作业初始化过程详解(源码分析第三篇)

    (一)概述 我们在上一篇blog已经详细的分析了一个作业从用户输入提交命令到到达JobTracker之前的各个过程.在作业到达JobTracker之后初始化之前,JobTracker会通过submit ...

  3. 操作系统学习:进程、线程与Linux0.12初始化过程概述

    本文参考书籍 1.操作系统真相还原 2.Linux内核完全剖析:基于0.12内核 3.x86汇编语言 从实模式到保护模式 ps:基于x86硬件的pc系统 进程 进程是一种控制流集合,集合中至少包含一条 ...

  4. 超详细解读ORB-SLAM3 单目初始化过程(上篇)

    学习ORB-SLAM3单目视觉SLAM中,发现有很多知识点需要展开和深入,同时又需要对系统有整体的认知,为了强化记忆,记录该系列笔记,为自己图方便,也希望对大家有所启发. 因为知识有限,因此先记录初始 ...

  5. [Spring 深度解析]第7章 IoC容器的初始化过程

    7. IoC容器的初始化过程 ​ 简单来说,IoC容器的初始化是由前面介绍的refresh()方法来启动的,这个方法标志着IoC容器的正式启动.具体来说,这个启动包括BeanDefinition的Re ...

  6. nginx的启动初始化过程(一)

    nginx的启动初始化在src/core/nginx.c的main函数中完成,也是整个nginx的入口.nginx的初始化主要围绕一个类型为ngx_cycle_t的全局变量ngx_cycle展开. m ...

  7. 解析 Java 类和对象的初始化过程 由一个单态模式引出的问题谈起

    在 IBM Bluemix 云平台上开发并部署您的下一个应用. 开始您的试用 问题引入 近日我在调试一个枚举类型的解析器程序,该解析器是将数据库内一万多条枚举代码装载到缓存中,为了实现快速定位枚举代码 ...

  8. 不可逆的类初始化过程

    类的加载过程说复杂很复杂,说简单也简单,说复杂是因为细节很多,比如说今天要说的这个,可能很多人都不了解:说简单,大致都知道类加载有这么几个阶段,loaded->linked->initia ...

  9. Mybatis源码解析之Mybatis初始化过程

    一.搭建一个简单的Mybatis工程 为了了解Mybatis的初始化过程,这里需要搭建一个简单的Mybatis工程操作数据库,工程结构如下: 一个UserBean.java private int i ...

最新文章

  1. WCF服务端返回:(413) Request Entity Too Large
  2. Android JNI编程(五)——C语言的静态内存分配、动态内存分配、动态创建数组...
  3. java steam 去重_Java中对List去重, Stream去重
  4. docker -v 挂载文件_浅谈关于docker中数据卷的操作,附带案例
  5. 闪屏页新手引导页面主页判断跳转的逻辑
  6. 负离子程序员的一组未来手绘,酷毙了
  7. python入门先学什么-学习python需要什么基础
  8. 大学生免费查题公众号_诺奖作家英文作品赏析尔雅2020年答案查题公众号
  9. ftfind 桌面搜索引擎的设计文档 (2)
  10. python制作web网页实例_基于python实现简单网页服务器代码实例
  11. hp打印机装不上服务器系统,win10安装不了惠普打印机驱动怎么办
  12. linux usb 存储设备,找到哪个驱动器对应于Linux中的哪个USB大容量存储设备
  13. 说话干嘛要“之道”啦?(1-10)
  14. React 之 Expected an assignment or function call and instead saw an expression 解决办法
  15. Python数据分析——matplotlib
  16. Matery主题友联随机排列
  17. 【调剂】2020西南科技大学微系统中心招收硕士调剂硕士生
  18. 程序员怎么写出亮眼的简历?
  19. android手游sdk开发教程,Android SDK开发基本教程
  20. Mavenir推出智能物联网平台以实现更智能的分析

热门文章

  1. 看看各省地图都像什么,笑趴了!
  2. 【论文速递】TPAMI2022 - 自蒸馏:迈向高效紧凑的神经网络
  3. Java实操演练1——简单图书管理系统的设计与实现
  4. 335平台部分flash用烧录器烧写不能启动问题
  5. 【毕业设计】java ssm会议室预约管理系统
  6. Hexo(sakura)主题Mashiro大佬同款LOGO修改方法
  7. VREP Remote API工作模式详解(未写完,完成度90%)
  8. 青猴浏览器下载后会自动导入其他浏览器的书签?
  9. 1083_MISRA_C规范学习_2004_Rule_5.3
  10. java set 排序的_Set集合排序