瑞芯微Rockchip开发者社区
直播中

663597

12年用户 463经验值
私信 关注
[问答]

rockchip drm驱动的启动流程是怎样的

rockchip drm驱动的启动流程是怎样的?有哪几个阶段呢?

回帖(1)

陈桂英

2022-2-16 09:53:24
rockchip 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 的brightnesscontraststaturationhue 属性赋值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的初始化,并将连接器、编码器、图层三者关联起来。



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

更多回帖

发帖
×
20
完善资料,
赚取积分