2.1 px30驱动移植-DRM驱动框架简介

写在前面

主要是介绍一下rk平台px30 移植LCD屏的工作心得

一、DRM基础

在这里插入图片描述

二、DRM相关目录结构

driverfiledoc
Corerockchip_drm_drv.c
Framebufferrockchip_drm_fb.c
GEMrockchip_drm_gem.c
VOProckchip_drm_vop.c ,rockchip_vop_reg.c
LVDSrockchip_lvds.c
RGBrockchip_rgb.c
MIPIdw_mipi_dsi.c,phy_rockchip-inno-mipi-dphy.c
HDMIdw_hdmi-rockchip.c,dw-hdmi.c
INNO HDMIinno_hdmi.c
eDpanalogix_dp-rockchip.c,analogix_dp_core.c,analogix_dp_reg.c,phy-rockchip-dp.c
DPcdn-dp-core.c,cdn-dp-reg.c
Panelpanel-simple.c

三、设备树

绑定路径如下
在这里插入图片描述

//数据传递流程如下:
vop(相当于显示控制器) --> dis/vlds/edp/rgb(相当于encoder) --> panel(相当于显示器)
//分析2代的配置,数据流向
vopb_out_rgb -> rgb_in_vopb -> rgb_out_panel -> panel_in_rgb
//phy
&video_phy {
       status = "okay";
};


//vop 配置
&display_subsystem {
       status = "okay";
};


&rgb_in_vopb {
       status = "okay";
};

&rgb_in_vopl {
       status = "disabled";
};
&route_rgb {
       connect = <&vopb_out_rgb>;
       //这块使能了,相当于使能了vopb_out_rgb输出
       status = "okay";
};

//总结:以上配置相当于配置了vop -> vopb -> vopb_out_rgb

//配置encoder
&rgb {
       //1.这块使能相当于使能了encoder
       status = "okay";

       ports {
               port@1 {
                       reg = <1>;

                       rgb_out_panel: endpoint {
                               //2.这块定义了连接的panel,即显示器
                               remote-endpoint = <&panel_in_rgb>;
                       };
               };
       };
};

//配置panel,在panel中设置与液晶屏相关内容,例如分辨率、时钟,时序等各参数
panel {
           compatible = "simple-panel";
           backlight = <&backlight>;
           power-supply = <&vcc_lcd>;
           enable-gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_HIGH>;
           // prepare-delay-ms = <120>;
           // enable-delay-ms = <120>;
           // disable-delay-ms = <120>;
           // unprepare-delay-ms = <120>;
           bus-format = <MEDIA_BUS_FMT_RBG888_1X24>;

           width-mm = <108>;
           height-mm = <64>;

           display-timings {
                   native-mode = <&timing0>;
                   timing0: timing0 {
                           clock-frequency = <33300000>;
                           hactive = <800>;
                           vactive = <480>;
                           hback-porch = <36>;
                           hfront-porch = <210>;
                           vback-porch = <13>;
                           vfront-porch = <22>;
                           hsync-len = <10>;
                           vsync-len = <10>;
                           hsync-active = <0>;
                           vsync-active = <0>;
                           de-active = <1>;
                           pixelclk-active = <1>;
                   };
           };

           port {
                   panel_in_rgb: endpoint {
                           remote-endpoint = <&rgb_out_panel>;
                   };
           };
   };  
}; 

四、component

在DRM、ALSA等子系统中,通过超级设备(superdevice)管理多个组件(component)加载顺序,保证所有组件都可正常使用,在drm驱动中,component设备用来表示vop和各显示接口(如:HDMI、MIPI等)

在设备树中定义了如下的显示子系统

&display_subsystem {
	status = "disabled";
	ports = <&vopb_out>, <&vopl_out>;
	logo-memory-region = <&drm_logo>;

	route {
		route_lvds: route-lvds {
			status = "disabled";
			logo,uboot = "logo.bmp";
			logo,kernel = "logo_kernel.bmp";
			logo,mode = "center";
			charge_logo,mode = "center";
			connect = <&vopb_out_lvds>;
		};

		route_dsi: route-dsi {
			status = "disabled";
			logo,uboot = "logo.bmp";
			logo,kernel = "logo_kernel.bmp";
			logo,mode = "center";
			charge_logo,mode = "center";
			connect = <&vopb_out_dsi>;
		};

		route_rgb: route-rgb {
			status = "disabled";
			logo,uboot = "logo.bmp";
			logo,kernel = "logo_kernel.bmp";
			logo,mode = "center";
			charge_logo,mode = "center";
			connect = <&vopb_out_rgb>;
		};
	};
};

其中添加vop组件

struct platform_driver vop_platform_driver = {
    .probe = vop_probe,
    .remove = vop_remove,
    .driver = {
        .name = "rockchip-vop",
        .owner = THIS_MODULE,
        .of_match_table = of_match_ptr(vop_driver_dt_match),
    },
};
//探测函数 添加组件
static int vop_probe(struct platform_device *pdev)
{
    struct device *dev = &pdev->dev;

    if (!dev->of_node) {
        dev_err(dev, "can't find vop devices\n");
        return -ENODEV;
    }
    //添加组件
    return component_add(dev, &vop_component_ops);
}

添加rgb组件

static const struct of_device_id rockchip_rgb_dt_ids[] = {
    { .compatible = "rockchip,px30-rgb", .data = &px30_rgb_funcs },
    { .compatible = "rockchip,rk1808-rgb", .data = &rk1808_rgb_funcs },
    { .compatible = "rockchip,rk3066-rgb", },
    { .compatible = "rockchip,rk3128-rgb", },
    { .compatible = "rockchip,rk3288-rgb", .data = &rk3288_rgb_funcs },
    { .compatible = "rockchip,rk3308-rgb", },
    { .compatible = "rockchip,rk3368-rgb", },
    { .compatible = "rockchip,rv1108-rgb", },
    {}
};
MODULE_DEVICE_TABLE(of, rockchip_rgb_dt_ids);

static struct platform_driver rockchip_rgb_driver = {
    .probe = rockchip_rgb_probe,
    .remove = rockchip_rgb_remove,
    .driver = {
        .name = "rockchip-rgb",
        .of_match_table = of_match_ptr(rockchip_rgb_dt_ids),
    },
};
//探测函数 添加组件
static int rockchip_rgb_probe(struct platform_device *pdev)
{
    struct device *dev = &pdev->dev;
    struct rockchip_rgb *rgb;
    int ret;

    rgb = devm_kzalloc(&pdev->dev, sizeof(*rgb), GFP_KERNEL);
    if (!rgb)
        return -ENOMEM;

    rgb->dev = dev;
    rgb->funcs = of_device_get_match_data(dev);
    platform_set_drvdata(pdev, rgb);

    rgb->data_sync = of_property_read_bool(dev->of_node,
                           "rockchip,data-sync");

    if (dev->parent && dev->parent->of_node) {
        rgb->grf = syscon_node_to_regmap(dev->parent->of_node);
        if (IS_ERR(rgb->grf)) {
            ret = PTR_ERR(rgb->grf);
            dev_err(dev, "Unable to get grf: %d\n", ret);
            return ret;
        }
    }

    rgb->phy = devm_phy_optional_get(dev, "phy");
    if (IS_ERR(rgb->phy)) {
        ret = PTR_ERR(rgb->phy);
        dev_err(dev, "failed to get phy: %d\n", ret);
        return ret;
    }
    //添加组件
    return component_add(dev, &rockchip_rgb_component_ops);
}

其实核心函数为

static const struct of_device_id rockchip_drm_dt_ids[] = {
    { .compatible = "rockchip,display-subsystem", },
    { /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, rockchip_drm_dt_ids);

static struct platform_driver rockchip_drm_platform_driver = {
    .probe = rockchip_drm_platform_probe,
    .remove = rockchip_drm_platform_remove,
    .shutdown = rockchip_drm_platform_shutdown,
    .driver = {
        .name = "rockchip-drm",
        .of_match_table = rockchip_drm_dt_ids,
        .pm = &rockchip_drm_pm_ops,
    },
};

static int rockchip_drm_platform_probe(struct platform_device *pdev)
{
    struct device *dev = &pdev->dev;
    struct component_match *match = NULL;
    struct device_node *np = dev->of_node;
    struct device_node *port;
    int i;

    DRM_INFO("Rockchip DRM driver version: %s\n", DRIVER_VERSION);
    if (!np)
        return -ENODEV;
    /*
     * Bind the crtc ports first, so that
     * drm_of_find_possible_crtcs called from encoder .bind callbacks
     * works as expected.
     */
    for (i = 0;; i++) {
        struct device_node *iommu;

        port = of_parse_phandle(np, "ports", i);
        if (!port)
            break;

        if (!of_device_is_available(port->parent)) {
            of_node_put(port);
            continue;
        }

        iommu = of_parse_phandle(port->parent, "iommus", 0);
        if (!iommu || !of_device_is_available(iommu->parent)) {
            dev_dbg(dev, "no iommu attached for %s, using non-iommu buffers\n",
                port->parent->full_name);
            /*
             * if there is a crtc not support iommu, force set all
             * crtc use non-iommu buffer.
             */
            is_support_iommu = false;
        }

        component_match_add(dev, &match, compare_of, port->parent);
        of_node_put(port);
    }

    if (i == 0) {
        dev_err(dev, "missing 'ports' property\n");
        return -ENODEV;
    }

    if (!match) {
        dev_err(dev, "No available vop found for display-subsystem.\n");
        return -ENODEV;
    }
    /*
     * For each bound crtc, bind the encoders attached to its
     * remote endpoint.
     */
    for (i = 0;; i++) {
        port = of_parse_phandle(np, "ports", i);
        if (!port)
            break;

        if (!of_device_is_available(port->parent)) {
            of_node_put(port);
            continue;
        }

        rockchip_add_endpoints(dev, &match, port);
        of_node_put(port);
    }

    port = of_parse_phandle(np, "backlight", 0);
    if (port && of_device_is_available(port)) {
        component_match_add(dev, &match, compare_of, port);
        of_node_put(port);
    }

    return component_master_add_with_match(dev, &rockchip_drm_ops, match);
}

component_master_add_with_match的函数调用栈为

rockchip_drm_platform_probe
  component_master_add_with_match
    try_to_bring_up_master
      find_components
      /* Found all components */
      rockchip_drm_bind //ret = master->ops->bind(master->dev);
        component_bind_all
          component->ops->bind //循环bind了所有组件
             

其实 也就是这张图
在这里插入图片描述

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值