资讯中心

驱动之路#04:LCD 驱动程序分析(基于 RK3576)

📅 2026/9/27 11:00:13
驱动之路#04:LCD 驱动程序分析(基于 RK3576)
驱动之#04LCD 驱动程序分析基于 RK3576摘以 RK3576 的panel-simple.c为例从字符设备驱动入口、设备树匹配、probe流程、背光到 MIPI-DSI 挂理 LCD 驱动的整体析方法。1. 为什么要分析 LCD 驱动实际工作中通常不需要从零编写 LCD 驱动但必须掌握 LCD 驱动框架读和理解现有驱动定位显示问题在需要时修改驱动以适配硬件或产品需求。LCD 驱动本质上也是字符设。掌握字符设备动的架后以从驱动入口函数开始沿着driver与deviceDTS的匹配关系追踪到probe函数和后续初始化流程。本文以 RK3576 平台的以文件为例kernel-6.1/drivers/gpu/drm/panel/panel-simple.c2. 从口函数开始阅读panel-simple.c的口函数注册了 3 个驱动说明该文件同时兼容 DPI、DSI 和 SPI 接口连接的 panel。以panel_simple_dsi_driver为例驱动和 device备树compatible属性匹配内核会调用panel_simple_dsi_probe。因此读该probe函数的具体操作就能基本掌握该 DSI panel 驱的工作方式。3.panel_simple_dsi_probe流程下面的代码按执行顺序标注了关键骤/* MIPI-DSI 面板测函数负责初始 DSI 接口的面板设备 */staticintpanel_simple_dsi_probe(structmipi_dsi_device*dsi){/* 局变量定义 */structpanel_simple*panel;structdevice*devdsi-dev;conststructpanel_desc_dsi*desc;structpanel_desc_dsi*d;conststructof_device_id*id;interr;/* 1. 设备树匹 */idof_match_node(dsi_of_match,dsi-dev.of_node);if(!id)return-ENODEV;/* 2. 处理面描述符 */if(!id-data){ddevm_kzalloc(dev,sizeof(*d),GFP_KERNEL);if(!d)return-ENOMEM;errpanel_simple_dsi_of_get_desc_data(dev,d);if(err){dev_err(dev,failed to get desc data: %d\\n,err);returnerr;}}/* 3. 选择最终述符 */descid-data?id-data:d;/* 4. 通用面板初始化 */errpanel_simple_probe(dsi-dev,desc-desc);if(err0)returnerr;/* 5. 获取面板数据并关联 DSI 设备 */paneldev_get_drvdata(dev);panel-dsidsi;/* 6. 有背光备时注册 DCS 背光 */if(!panel-base.backlight){structbacklight_propertiesprops;memset(props,0,sizeof(props));props.typeBACKLIGHT_RAW;props.brightness255;props.max_brightness255;panel-base.backlightdevm_backlight_device_register(dev,dev_name(dev),dev,panel,dcs_bl_ops,props);if(IS_ERR(panel-base.backlight)){errPTR_ERR(panel-base.backlight);dev_err(dev,failed to register dcs backlight: %d\\n,err);returnerr;}}/* 7. 配置 DSI 主机控制器参 */dsi-mode_flagsdesc-flags;dsi-formatdesc-format;dsi-lanesdesc-lanes;/* 8. 将面板附加到 DSI 主机 */errmipi_dsi_attach(dsi);if(err){structpanel_simple*panelmipi_dsi_get_drvdata(dsi);drm_panel_remove(panel-base);}/* 9. 成功返回 0失败返回错误码 */returnerr;} 从这段流程可以看到probe 要负责1.匹配设备树2.2.获取或解析 panel 描述符3.3.调用用 panel 初始化4.4.注册或关背光设备5.5.设置 DSI 参数6.6.将 panel 挂接到 DSI 机。 ##4.备树参数从哪来 设备树中定义的屏参以及 MIPI 初始化相内容最终通过以下两个函数获取 cpanel_simple_dsi_of_get_desc_data()panel_simple_of_get_desc_data()4.1 解 DSI 专有数staticintpanel_simple_dsi_of_get_desc_data(structdevice*dev,structpanel_desc_dsi*desc){structdevice_node*npdev-of_node;u32 val;interr;errpanel_simple_of_get_desc_data(dev,desc-desc);if(err)returnerr;desc-desc.connector_typeDRM_MODE_CONNECTOR_DSI;if(!of_property_read_u32(np,dsi,flags,val))desc-flagsval;if(!of_property_read_u32(np,dsi,format,val))desc-formatval;if(!of_property_read_u32(np,dsi,lanes,val))desc-lanesval;return0;}|属性|作用||---|---||dsi,flags|DSI 工作式标志||dsi,format|像素据格式||dsi,lanes|DSI 通道数量|###4.2解析通用 panel 参数 cstaticintpanel_simple_of_get_desc_data(structdevice*dev,structpanel_desc*desc){structdevice_node*npdev-of_node;u32 bus_flags;constvoid*data;intlen;interr;/* 1. 解析显示时序 */if(of_child_node_is_present(np,display-timings)){structdrm_display_mode*mode;modedevm_kzalloc(dev,sizeof(*mode),GFP_KERNEL);if(!mode)return-ENOMEM;if(of_get_drm_display_mode(np,mode,bus_flags,OF_USE_NATIVE_MODE)){desc-modesmode;desc-num_modes1;desc-bus_flagsbus_flags;}}elseif(of_child_node_is_present(np,panel-timing)){structdisplay_timing*timing;structvideomodevm;timingdevm_kzalloc(dev,sizeof(*timing),GFP_KERNEL);if(!timing)return-ENOMEM;if(!of_get_display_timing(np,panel-timing,timing)){desc-timingstiming;desc-num_timings1;bus_flags0;vm.flagstiming-flags;drm_bus_flags_from_videomode(vm,bus_flags);desc-bus_flagsbus_flags;}}/* 2. 解析基本面属 */if(desc-num_modes||desc-num_timings){of_property_read_u32(np,bpc,desc-bpc);of_property_read_u32(np,connector-type,desc-connector_type);of_property_read_u32(np,bus-format,desc-bus_format);of_property_read_u32(np,width-mm,desc-size.width);of_property_read_u32(np,height-mm,desc-size.height);}/* 3. 解析时序延迟参数 */of_property_read_u32(np,prepare-delay-ms,desc-delay.prepare);of_property_read_u32(np,enable-delay-ms,desc-delay.enable);of_property_read_u32(np,disable-delay-ms,desc-delay.disable);of_property_read_u32(np,unprepare-delay-ms,desc-delay.unprepare);of_property_read_u32(np,reset-delay-ms,desc-delay.reset);of_property_read_u32(np,init-delay-ms,desc-delay.init);/* 4. 解析初序列 */dataof_get_property(np,panel-init-sequence,len);if(data){desc-init_seqdevm_kzalloc(dev,sizeof(*desc-init_seq),GFP_KERNEL);if(!desc-init_seq)return-ENOMEM;errpanel_simple_parse_cmd_seq(dev,data,len,desc-init_seq);if(err){dev_err(dev,failed to parse init sequence\\n);returnerr;}}/* 5. 解析退出序 */dataof_get_property(np,panel-exit-sequence,len);if(data){desc-exit_seqdevm_kzalloc(dev,sizeof(*desc-exit_seq),GFP_KERNEL);if(!desc-exit_seq)return-ENOMEM;errpanel_simple_parse_cmd_seq(dev,data,len,desc-exit_seq);if(err){dev_err(dev,failed to parse exit sequence\\n);returnerr;}}return0;} 该函数解析范围包括-display-timings 或 panel-timing 示时序--色深 bpc、接器型、总线格式--板物理尺寸--prepare/enable/disable 等时序延迟--panel-init-sequence 初始化命令序列--panel-exit-sequence 出命令序。 ##5.分析驱动时应关注什么 分析字符设备动建议按下面的路径阅读 text 入口注册 driver 与 device/DTS 匹配 → probe → 资源与参数解析 子设/背光注册 → 总线或控制器 attach → 后续 enable/disable 流程 不需要花大量时逐行解释所有代码。更有价值的是掌握整体驱动框、关键函数的调用关系以及设备树参数如何进入驱动。 ##6.小结 本文以 RK3576 的 panel-simple.c 为例梳理 MIPI-DSI LCD 动的核心流程1.通过 compatible 完成设备树匹配2.2.在 probe 中获取预定义动态解析的 panel 描述符3.3.由通用函数解析显示时、尺寸、延迟和初始化序列4.4.配置背光与 DSI 的 flagsformat、lanes5.5.调用 mipi_dsi_attach() 将 panel 附加 DSI 主机。 握这主线后就可以更高效地阅读和体 LCD 驱动问题。

看完文章,想为自己的企业也做一次专业网站诊断?

尧图顾问免费为您评估现有网站,并给出建站/改版建议与报价方案。

免费获取方案