当前位置:网站首页>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* 是代表存在多屏情况下的因素。
边栏推荐
- "Microservice Architecture" Arrangement and Choreography - Different Models for Making Systems Work Together
- Excel绘制统计图
- How to break the DeepFake face-changing scam?turn him over
- 12 【其它组合式API】
- The first offline workshop in 2022!Data application experience day for application developers is coming | TiDB Workshop Day
- 08 【Props 组件事件】
- Message Queuing Overview
- Defending risks with technology and escorting cloud native | Tongchuang Yongyi X Boyun held a joint product launch conference
- CAD to WPF: Tips on converting CAD drawing files to WPF vector code files (xaml files)
- UE4 Sequence添加基础动画效果 (05-蓝图触发Sequence)
猜你喜欢

绘制温度曲线图;QChart,

Development environment variable record under win

Vivado时序约束中Tcl命令的对象及属性

英伟达游戏显卡营收暴跌/ 谷歌数据中心爆炸致3人受伤/ iPhone电量百分比回归…今日更多新鲜事在此...

支付 x 聚合 x 分账 - 回流平台“二清”风险规避之路

数据库注入提权总结(一)

CAD to WPF: Tips on converting CAD drawing files to WPF vector code files (xaml files)

The Generation of Matlab Symbolic Functions and the Calculation of Its Function Values

Flink运行时架构 完整使用 (第四章)

UE4 Sequence添加基础动画效果 (05-蓝图触发Sequence)
随机推荐
Excel draws statistical graphs
1 活动时间与安排
"Guangzhou highway engineering measures for the supervision and administration of production safety, and revised from six aspects
Lasso回归(Stata)
Shell functions and arrays
How to understand the difference between BIO, NIO, and AIO
支付 x 聚合 x 分账 - 回流平台“二清”风险规避之路
Oracle rac所在的网络要割接,停掉其中一个rac节点,这种方案可行吗?
多线程浅谈
Matlab符号函数的生成及计算其函数值
[OAuth2] 20. OAuth2 Extended Protocol PKCE
Singleton pattern base class
【Prometheus】Node Exporter常用查询PromQL 语句大总结
浅析JWT安全问题
J9 digital science: Web 3.0 is about data ownership or decentralized?
[Metaverse Omi Says] Listen to how Rabbit Fan Rabbit creates a new era of trendy play from virtual to reality
SQL优化总结
Defending risks with technology and escorting cloud native | Tongchuang Yongyi X Boyun held a joint product launch conference
PostgreSQL 2022 发展现状:13 个非 psql 工具
英伟达游戏显卡营收暴跌/ 谷歌数据中心爆炸致3人受伤/ iPhone电量百分比回归…今日更多新鲜事在此...