RK1808 DRM 驱动流程分析

时间:2024-04-02 17:59:03

rockchip drm驱动的启动流程图:

RK1808 DRM 驱动流程分析

 

第一阶段:

mipi_dsi_probe

res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //获取内存资源

dsi->irq = platform_get_irq(pdev, 0); //获取中断资源

dsi->pclk = devm_clk_get(dev, "pclk"); //获取pclk

dsi->regmap = devm_regmap_init_mmio(dev, regs, //初始化内存管理映射

ret = mipi_dphy_attach(dsi); //找到对应的phy

       dphy->phy = devm_phy_optional_get(dev, "mipi_dphy"); //根据char找到dphy

       ret = mipi_dsi_host_register(&dsi->dsi_host); //注册dsi host

              of_mipi_dsi_device_add(host, node); //建立dsi device 结构体

      component_add(dev, &dw_mipi_dsi_ops); //将mipi dsi 的componet 添加到list 中,供componet master调用其注册的回调函数dw_mipi_dsi_bind。

总结: mipi_dsi_probe 主要是将设备树中的资源解析出来 建立dsi dev ,最后完成component 框架的支持。

vop_probe

          component_add(dev, &vop_component_ops); //将vop的componet添加到list中,供 componet master调用其注册的回调函数vop_bind。

总结: vop_probe 就是添加了对component 框架的支持。

第二阶段:

rockchip_drm_platform_probe

port = of_parse_phandle(np, "ports", i); //遍历subsys 下的ports属性

component_match_add(dev, &match, compare_of, port->parent); //将每个ports属性加入数组中

rockchip_add_endpoints(dev, &match, port); //将ports下的endpoint 属性也加入数组中

component_match_add(dev, &match, compare_of, port); //将backlight属性也加入数组中

component_master_add_with_match(dev, &rockchip_drm_ops, match); //将match数组加入master中

        struct master *master; //定义了一个master

        master = kzalloc(sizeof(*master), GFP_KERNEL); //为其分配空间

        master->dev = dev; //填充master结构体

        master->ops = ops; //ops中包括了bind函数

        master->match = match; //包括了上面所有ports属性的match数组

        try_to_bring_up_master(master, NULL); //尝试初始化该master(调用rockchip_drm_bind)

总结:rockchip_drm_platform_probe 做了以下工作:

1、遍历所有的prots(VOP设备)并加入到match列表中

2、遍历所有prots下的endpoint(display设备)并加入到matc列表中

3、将bcaklight设备加入match例表中

4、创建了master并将上述的match填充进去后尝试通过match列表bind所有设备

rockchip_drm_bind

     drm_dev = drm_dev_alloc(&rockchip_drm_driver, dev);//申请一个drm设备数据结构

     ret = drm_dev_set_unique(drm_dev, "%s", dev_name(dev)); //设置drm设备的名字

     private->hdmi_pll.pll = devm_clk_get(dev, "hdmi-tmds-pll"); //获取hdmi-tmds-pll clk

     private->default_pll.pll = devm_clk_get(dev, "default-vop-pll"); //获取def-vop-pll clk

     ret = rockchip_drm_init_iommu(drm_dev); //iommu初始化

     drm_mode_config_init(drm_dev); //mode_config 结构体初始化,也是为了drm dev结构体

      rockchip_drm_mode_config_init(drm_dev); //宽、高限制

      rockchip_drm_create_properties(drm_dev); //创建相关属性 :对应property

      ret = component_bind_all(dev, drm_dev); //尝试调用所有子设备的bind函数(vop_bind、mipi_dsi_bind)

      rockchip_attach_connector_property(drm_dev);//为connector 的brightness\contrast\staturation\hue 属性赋值100

      ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc);//vlank 初始化?

      drm_mode_config_reset(drm_dev);//调用所有的reset callback函数

      rockchip_drm_set_property_default(drm_dev);

      drm_kms_helper_poll_init(drm_dev); //使能kms 轮询机制 主要是connector

      rockchip_gem_pool_init(drm_dev); //使能gem 轮询机制

      ret = of_reserved_mem_device_init(drm_dev->dev);//将dts配置中预留的memory 分配给device。

      ret = rockchip_drm_fbdev_init(drm_dev); //fbdev 初始化

      ret = drm_dev_register(drm_dev, 0); //注册drm dev

总结: rockchip_drm_bind 完成了drm dev的初始化,并调用了所有子设备的bind函数一起初始化整个display sys。

 

vop_bind

vop_data = of_device_get_match_data(dev);

alloc_size = sizeof(*vop) + sizeof(*vop->win) * num_wins; //需要申请内存的size

vop = devm_kzalloc(dev, alloc_size, GFP_KERNEL); //给vop分配内存,返回值为分配的内存区域的起始地址,分配内存区域在驱动卸载后自行释放。

ret = vop_win_init(vop); //初始化vop win

res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs")//phyaddr

vop->regs = devm_ioremap_resource(dev, res); //映射

vop->hclk = devm_clk_get(vop->dev, "hclk_vop"); //clk获取

irq = platform_get_irq(pdev, 0);

ret = devm_request_irq(dev, vop->irq, vop_isr, IRQF_SHARED, dev_name(dev), vop)//中断申请

disable_irq(vop->irq); //关闭中断,上电时开启

ret = vop_create_crtc(vop); //建立crtc

     for (i = 0; i < vop->num_wins; i++) //vop可能有好几个

          ret = vop_plane_init(vop, win, 0); //初始化plane(primary \ cursor)

                ret = drm_share_plane_init(vop->drm_dev, &win->base, share,

                drm_plane_helper_add(&win->base, &plane_helper_funcs);

          ret = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor, //建立跟plane相关的crtc(将上述plane结构体加入crtc结构体中)

         drm_crtc_helper_add(crtc, &vop_crtc_helper_funcs);//crtc相关辅助函数

         ret = vop_plane_init(vop, win, possible_crtcs);//初始化plane(overlay)

         drm_flip_work_init(&vop->fb_unref_work, "fb_unref", vop_fb_unref_worker);

         rockchip_register_crtc_funcs(crtc, &private_crtc_funcs);

总结:vob_bind主要完成了plane和crtc结构体的建立

 

dw_mipi_dsi_bind

ret = dw_mipi_dsi_dual_channel_probe(dsi);//mipi双通道

ret = dw_mipi_dsi_register(drm, dsi);

         encoder->possible_crtcs = drm_of_find_possible_crtcs(drm,//为encoder匹配一个crtc

         drm_encoder_helper_add(&dsi->encoder, //encoder的辅助函数

         ret = drm_encoder_init(drm, &dsi->encoder, //encoder初始化

                    。。。填充结构体,encoder type = DRM_MODE_ENCODER_DSI

         ret = drm_connector_init(drm, &dsi->connector,//connector 初始化

                   。。。填充结构体

          drm_connector_helper_add(connector, //connector的辅助函数

          drm_mode_connector_attach_encoder(connector, encoder);将连接器和编码器连接起来(connector 结构体中有个encoderid数组用于匹配)

          ret = drm_panel_attach(dsi->panel, &dsi->connector); //将连接器和图层绑定起来

总结:dw_mipi_dsi_bind主要实现了encoder和connector的初始化,并将连接器、编码器、图层三者关联起来。

RK1808 DRM 驱动流程分析

 

 

结束语:

DRM驱动主要就是完成CRTCPLANEENCODERCONNECTORDRM_BUF几个要素的初始化和连接,最后通过一个drm结构管理整个驱动,在这个过程中为了保证每个成员的启动顺序加入了component 框架,为了便于对DRM_BUF的管理加入了GEM对其进行分配、释放和映射。