当前位置:网站首页>LCD模块如何建立联系分析
LCD模块如何建立联系分析
2022-08-10 09:36:00 【沉沦者】
本文主要是基于rk3566/rk3568平台通过LCD uboot 和 设备树 的代码 对 vop - encoder/connector - panel 三者如何建立联系的进行分析。
一、设备树部分
设备树主要是借助remote-endpoint属性来达到选择相应的外设配置。
1、display-subsystem的设备树信息
1)以ports属性指定相应的vop端点
2)以route_dsi0 指定uboot 阶段的logo配置,其中的connect属性指定的vop需与ports的一致。
display_subsystem: display-subsystem { compatible = "rockchip,display-subsystem"; memory-region = <&drm_logo>, <&drm_cubic_lut>; memory-region-names = "drm-logo", "drm-cubic-lut"; ports = <&vop_out>; devfreq = <&dmc>; route { route_dsi0: route-dsi0 { status = "okay"; logo,uboot = "logo.bmp"; logo,kernel = "logo_kernel.bmp"; logo,mode = "center"; charge_logo,mode = "center"; connect = <&vp0_out_dsi0>; }; }; };
2、vop的设备树信息
1)以ports -> port -> endpoint -> remote-endpoint 的顺序,通过remote-endpoint 属性来指定远端的设备端点
vop: [email protected] { compatible = "rockchip,rk3568-vop"; reg = <0x0 0xfe040000 0x0 0x3000>, <0x0 0xfe044000 0x0 0x1000>; reg-names = "regs", "gamma_lut"; rockchip,grf = <&grf>; interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cru ACLK_VOP>, <&cru HCLK_VOP>, <&cru DCLK_VOP0>, <&cru DCLK_VOP1>, <&cru DCLK_VOP2>; clock-names = "aclk_vop", "hclk_vop", "dclk_vp0", "dclk_vp1", "dclk_vp2"; iommus = <&vop_mmu>; power-domains = <&power RK3568_PD_VO>; status = "okay"; vop_out: ports { #address-cells = <1>; #size-cells = <0>; vp0: [email protected] { #address-cells = <1>; #size-cells = <0>; reg = <0>; vp0_out_dsi0: [email protected] { reg = <0>; remote-endpoint = <&dsi0_in_vp0>; }; vp0_out_dsi1: [email protected] { reg = <1>; remote-endpoint = <&dsi1_in_vp0>; }; vp0_out_edp: [email protected] { reg = <2>; remote-endpoint = <&edp_in_vp0>; }; vp0_out_hdmi: [email protected] { reg = <3>; remote-endpoint = <&hdmi_in_vp0>; }; }; }; };
3、dsi的设备树信息
1)dsi -> ports -> port dsi0_in_vp0(endpoint) 下的remote-endpoint 为dsi与vop间建立关系的属性配置,其中dsi作为输入端,另一端接的是vop out端。
2)dsi -> ports -> port -> dsi_out_panel1/dsi_out_panel2/dsi_out_panel3(endpoint)下的remote-endpoint 为dsi 与 panel 间建立关系的属性配置。此处代表有三个panel。因此 若想多屏可以在此处增加节点达到和新panel建立联系。
3)dsi->panel 为panel的配置。正常是单独创建个屏dtsi文件后,在文件中引用(&dsi0) 来进行新增屏。此处只是为了更好的分析而集成在一起(本身设备树在编译的时候也是覆盖的操作)。
4)dsi -> panel -> ports -> port -> panel1_in_dsi(endpoint) 下的remote-endpoint 为panel与dsi间的关系,即此处是连到dsi_out_panel1上。
dsi0: [email protected] { compatible = "rockchip,rk3568-mipi-dsi"; reg = <0x0 0xfe060000 0x0 0x10000>; interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cru PCLK_DSITX_0>, <&cru HCLK_VO>, <&video_phy0>; clock-names = "pclk", "hclk", "hs_clk"; resets = <&cru SRST_P_DSITX_0>; reset-names = "apb"; phys = <&video_phy0>; phy-names = "mipi_dphy"; power-domains = <&power RK3568_PD_VO>; rockchip,grf = <&grf>; #address-cells = <1>; #size-cells = <0>; status = "okay"; ports { #address-cells = <1>; #size-cells = <0>; dsi0_in: [email protected] { reg = <0>; #address-cells = <1>; #size-cells = <0>; dsi0_in_vp0: [email protected] { reg = <0>; remote-endpoint = <&vp0_out_dsi0>; status = "okay"; }; dsi0_in_vp1: [email protected] { reg = <1>; remote-endpoint = <&vp1_out_dsi0>; status = "disabled"; }; }; [email protected] { reg = <1>; dsi_out_panel1: endpoint { remote-endpoint = <&panel1_in_dsi>; }; }; [email protected] { reg = <2>; dsi_out_panel2: endpoint { remote-endpoint = <&panel2_in_dsi>; }; }; [email protected] { reg = <3>; dsi_out_panel3: endpoint { remote-endpoint = <&panel3_in_dsi>; }; }; }; [email protected] { status = "okay"; compatible = "simple-panel-dsi"; reg = <0>; num = <0>; lcd-ic = "st7703"; lcd-vendor = "hbs"; id = [24]; id-reg = <0xDA>; power-supply = <&vcc3v3_lcd0_n>; reset-gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_LOW>; enable-gpios = <&gpio0 RK_PD5 GPIO_ACTIVE_HIGH>; //backlight = <&backlight>; reset-delay-ms = <60>; enable-delay-ms = <60>; prepare-delay-ms = <60>; unprepare-delay-ms = <60>; disable-delay-ms = <60>; init-delay-ms = <60>; dsi,flags = <(MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET)>; dsi,format = <MIPI_DSI_FMT_RGB888>; dsi,lanes = <4>; panel-init-sequence = [ 39 00 04 B9 F1 12 83 39 00 05 B1 00 00 00 DA ... ... 13 FA 02 11 00 13 32 02 29 00 ]; panel-exit-sequence = [ 05 32 01 28 05 FA 01 10 ]; display-timings { native-mode = <&dsi0_timing2>; dsi0_timing2: timing0 { clock-frequency = <55230000>; hactive = <720>; vactive = <1280>; hfront-porch = <50>; hsync-len = <20>; hback-porch = <50>; vfront-porch = <15>; vsync-len = <5>; vback-porch = <15>; hsync-active = <0>; vsync-active = <0>; de-active = <0>; pixelclk-active = <1>; }; }; ports { #address-cells = <1>; #size-cells = <0>; [email protected] { reg = <0>; panel1_in_dsi: endpoint { remote-endpoint = <&dsi_out_panel1>; }; }; }; }; [email protected] { status = "okay"; compatible = "simple-panel-dsi"; reg = <0>; num = <1>; id = [15]; id-reg = <0xDA>; power-supply = <&vcc3v3_lcd0_n>; reset-gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_LOW>; enable-gpios = <&gpio0 RK_PD5 GPIO_ACTIVE_HIGH>; //backlight = <&backlight>; reset-delay-ms = <60>; enable-delay-ms = <60>; prepare-delay-ms = <60>; unprepare-delay-ms = <60>; disable-delay-ms = <60>; init-delay-ms = <60>; dsi,flags = <(MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET)>; dsi,format = <MIPI_DSI_FMT_RGB888>; dsi,lanes = <4>; panel-init-sequence = [ 39 00 04 B9 F1 12 83 ... ... 13 78 02 11 00 13 0A 02 29 00 ]; panel-exit-sequence = [ 05 0A 01 28 05 78 01 10 ]; display-timings { native-mode = <&dsi0_timing1>; dsi0_timing1: timing0 { clock-frequency = <62640000>; hactive = <720>; vactive = <1280>; hfront-porch = <10>; hsync-len = <25>; hback-porch = <45>; vfront-porch = <10>; vsync-len = <4>; vback-porch = <11>; hsync-active = <0>; vsync-active = <0>; de-active = <0>; pixelclk-active = <1>; }; }; ports { #address-cells = <1>; #size-cells = <0>; [email protected] { reg = <0>; panel2_in_dsi: endpoint { remote-endpoint = <&dsi_out_panel2>; }; }; }; }; };
二、uboot部分
uboot部分主要是打算借助uboot上解析设备树部分的代码来进行分析。
1、通过ofnode_for_each_subnode遍历route节点下的子节点,即为route-dsi0。
2、通过route-dsi0 -> connect的属性值来定位到vop上的节点vp0_out_dsi0。
3、找到vop的节点后,通过uclass_get_device_by_ofnode启动vop设备,最终会执行到相应的rockchip_vop_probe函数(正常下,使用U_BOOT_DRIVER只会回调bind函数,而不会执行probe的)。
4、在执行到rockchip_of_find_connector函数时,实际传进的参数为vop节点下的vp0_out_dsi0。
static int rockchip_display_probe(struct udevice *dev){ ...//省略掉无关代码 ...route_node = dev_read_subnode(dev, "route");if (!ofnode_valid(route_node))return -ENODEV;ofnode_for_each_subnode(node, route_node) {if (!ofnode_is_available(node))continue;phandle = ofnode_read_u32_default(node, "connect", -1);if (phandle < 0) {printf("Warn: can't find connect node's handle");continue;}ep_node = of_find_node_by_phandle(phandle);if (!ofnode_valid(np_to_ofnode(ep_node))) {printf("Warn: can't find endpoint node from phandle");continue;}port_node = of_get_parent(ep_node);if (!ofnode_valid(np_to_ofnode(port_node))) {printf("Warn: can't find port node from phandle");continue;}port_parent_node = of_get_parent(port_node);if (!ofnode_valid(np_to_ofnode(port_parent_node))) {printf("Warn: can't find port parent node from phandle");continue;}is_ports_node = strstr(port_parent_node->full_name, "ports") ? 1 : 0;if (is_ports_node) {vop_node = of_get_parent(port_parent_node);if (!ofnode_valid(np_to_ofnode(vop_node))) {printf("Warn: can't find crtc node from phandle");continue;}} else {vop_node = port_parent_node;}ret = uclass_get_device_by_ofnode(UCLASS_VIDEO_CRTC, np_to_ofnode(vop_node), &crtc_dev);if (ret) {printf("Warn: can't find crtc driver %d", ret);continue;}crtc = (struct rockchip_crtc *)dev_get_driver_data(crtc_dev);conn_dev = rockchip_of_find_connector(np_to_ofnode(ep_node));if (!conn_dev) {printf("Warn: can't find connect driver");continue;}conn = (const struct rockchip_connector *)dev_get_driver_data(conn_dev);phy = rockchip_of_find_phy(conn_dev);bridge = rockchip_of_find_bridge(conn_dev);if (bridge)panel = rockchip_of_find_panel(bridge->dev);elsepanel = rockchip_of_find_panel(conn_dev); ... ...// 省略掉无关代码return 0;}
5、 通过子节点获取父节点的操作来定位,因此rockchip_of_find_connector函数下的conn即为dsi0节点,因此再次通过uclass_get_device_by_ofnode来加载dsi设备,即会调用dw_mipi_dsi_probe函数。
static struct udevice *rockchip_of_find_connector(ofnode endpoint){ofnode ep, port, ports, conn;uint phandle;struct udevice *dev;int ret;if (ofnode_read_u32(endpoint, "remote-endpoint", &phandle))return NULL;ep = ofnode_get_by_phandle(phandle);if (!ofnode_valid(ep) || !ofnode_is_available(ep))return NULL;port = ofnode_get_parent(ep);if (!ofnode_valid(port))return NULL;ports = ofnode_get_parent(port);if (!ofnode_valid(ports))return NULL;conn = ofnode_get_parent(ports);if (!ofnode_valid(conn) || !ofnode_is_available(conn))return NULL;ret = uclass_get_device_by_ofnode(UCLASS_DISPLAY, conn, &dev);if (ret)return NULL;return dev;}
6、rockchip_of_find_bridge查找是否存在bridge设备
static struct rockchip_bridge *rockchip_of_find_bridge(struct udevice *conn_dev){ofnode node, ports, port, ep;struct udevice *dev;int ret;ports = dev_read_subnode(conn_dev, "ports");if (!ofnode_valid(ports))return NULL;ofnode_for_each_subnode(port, ports) {u32 reg;if (ofnode_read_u32(port, "reg", ®))continue;if (reg != PORT_DIR_OUT)continue;ofnode_for_each_subnode(ep, port) {ofnode _ep, _port, _ports;uint phandle;if (ofnode_read_u32(ep, "remote-endpoint", &phandle))continue;_ep = ofnode_get_by_phandle(phandle);if (!ofnode_valid(_ep))continue;_port = ofnode_get_parent(_ep);if (!ofnode_valid(_port))continue;_ports = ofnode_get_parent(_port);if (!ofnode_valid(_ports))continue;node = ofnode_get_parent(_ports);if (!ofnode_valid(node))continue;ret = uclass_get_device_by_ofnode(UCLASS_VIDEO_BRIDGE, node, &dev);if (!ret)goto found;}}return NULL;found:return (struct rockchip_bridge *)dev_get_driver_data(dev);}
7、在dsi0的节点下,通过ports -> port -> remote-endpoint来找到[email protected]/2/3节点下的port 的endpoint节点,再依次通过获取父节点的方式获取到panel的节点,最后通过uclass_get_device_by_ofnode函数启动panel,即执行rockchip_panel_probe回调
static struct rockchip_panel *rockchip_of_find_panel(struct udevice *dev){ofnode panel_node, ports, port, ep, port_parent_node;struct udevice *panel_dev;int ret;panel_node = dev_read_subnode(dev, "panel");if (ofnode_valid(panel_node) && ofnode_is_available(panel_node)) {ret = uclass_get_device_by_ofnode(UCLASS_PANEL, panel_node, &panel_dev);if (!ret)goto found;}ports = dev_read_subnode(dev, "ports");if (!ofnode_valid(ports))return NULL;ofnode_for_each_subnode(port, ports) {u32 reg;if (ofnode_read_u32(port, "reg", ®))continue;if (reg != PORT_DIR_OUT)continue;ofnode_for_each_subnode(ep, port) {ofnode _ep, _port;uint phandle;bool is_ports_node = false;if (ofnode_read_u32(ep, "remote-endpoint", &phandle))continue;_ep = ofnode_get_by_phandle(phandle);if (!ofnode_valid(_ep))continue;_port = ofnode_get_parent(_ep);if (!ofnode_valid(_port))continue;port_parent_node = ofnode_get_parent(_port);is_ports_node = strstr(port_parent_node.np->full_name, "ports") ? 1 : 0;if (is_ports_node)panel_node = ofnode_get_parent(port_parent_node);elsepanel_node = ofnode_get_parent(_port);if (!ofnode_valid(panel_node))continue;ret = uclass_get_device_by_ofnode(UCLASS_PANEL, panel_node, &panel_dev);if (!ret)goto found;}}return NULL;found:return (struct rockchip_panel *)dev_get_driver_data(panel_dev);}
三、总结
1、由设备树分析可知:在display-subsystem 下通过ports -> port ->endpoint -> remote-endpoint的方式来实现建立vop - dsi - panel 的联系
2、由uboot分析可知:在rockchip_display_probe中先解析对应设备树节点,通过dev_read_subnode、of_find_node_by_phandle、of_get_parent、uclass_get_device_by_xxx(uclass_get_device_by_ofnode)等系列函数去启动vop 、connector(dsi)、panel等设备。
如下:整体的框架
注:
1)vop *(video out processor)代表有多个处理器时的情况。
2)panel* 是代表存在多屏情况下的因素。
边栏推荐
猜你喜欢
FPGA时钟篇(一) 7系列的时钟结构
[Data Architecture] Distributed Data Grid as a Solution for Centralized Data Monolith
2022 首期线下 Workshop!面向应用开发者们的数据应用体验日来了 | TiDB Workshop Day
J9 Number Theory: Macro Analysis of DAO Characteristics
win下的开发环境变量记录
12 【其它组合式API】
英伟达游戏显卡营收暴跌/ 谷歌数据中心爆炸致3人受伤/ iPhone电量百分比回归…今日更多新鲜事在此...
Flink部署 完整使用 (第三章)
腾讯云校园大使开始招募啦,内推名额和奖金等你来拿
[System Design] S3 Object Storage
随机推荐
Flink部署 完整使用 (第三章)
Singleton pattern base class
【数据架构】分布式数据网格作为集中式数据单体的解决方案
shell------ commonly used gadgets, sort, uniq, tr, cut
FPGA中BEL Site Tile FSR SLR分别指什么?
[System Design] S3 Object Storage
FPGA时钟篇(三) MRCC和SRCC的区别
DataStream API(基础篇) 完整使用 (第五章)
"Guangzhou highway engineering measures for the supervision and administration of production safety, and revised from six aspects
「微服务架构」编曲与编舞——让系统协同工作的不同模式
ARM Architecture 3: Addressing and Exception Handling of ARM Instructions
【API架构】REST API 行业辩论:OData vs GraphQL vs ORDS
Development environment variable record under win
07 【动态组件 组件注册】
腾讯发布四足机器人 Max 二代版本,梅花桩上完成跳跃、空翻
J9 Number Theory: Macro Analysis of DAO Characteristics
Guo Jingjing's personal chess teaching, the good guy is a robot
不要把公司当成家,被通知裁员时会变得不幸...
CAD转WPF: 关于CAD图纸文件转换为WPF矢量代码文件(xaml文件)的技巧
【Software Exam System Architect】Case Analysis ⑥ Web Application System Architecture Design