当前位置: 首页 > news >正文

lk2nd 移植实战:为广信 EF33 老年机添加 ST7789V SPI 屏支持的 2 个核心补丁

为广信EF33老年机移植lk2nd:ST7789V SPI屏幕驱动开发全记录

引言

在嵌入式系统开发领域,Bootloader移植往往是项目成功的关键第一步。当面对一款采用高通msm8909平台的广信EF33老年机时,原厂锁定的fastboot模式让lk2nd移植成为唯一选择。本文将详细记录如何通过逆向工程手段,为这款设备特有的ST7789V SPI屏幕开发驱动补丁的全过程。

不同于常见的MIPI接口,SPI屏幕在移动设备中相对少见,这为驱动开发带来了独特挑战。我们将从硬件分析开始,逐步深入到寄存器配置、GPIO映射和时钟树调整,最终提供两个可直接应用于lk2nd的补丁文件。这些实战经验对于任何需要在高通平台添加非标准显示设备的开发者都具有参考价值。

1. 硬件分析与逆向工程准备

1.1 设备基础信息确认

通过adb shell获取的硬件信息显示,这款广信EF33老年机采用以下配置:

  • 高通msm8909平台(骁龙210)
  • 512MB RAM + 4GB ROM
  • 单摄像头,无触摸屏
  • 2.4GHz WCN3610v1 WiFi模块

关键发现来自/proc/cmdline中的显示参数:

mdss_mdp3.panel=0:spi:0:qcom,mdss_spi_st7789v_ctc_qvga_nrx_cmd

这明确指出了屏幕型号为ST7789V,采用SPI接口。

1.2 调试接口利用

由于fastboot被厂商锁定,我们通过以下途径获取硬件信息:

  1. 挂载debugfs获取GPIO状态:
mount -t debugfs debugfs /sdcard/debug cat /sdcard/debug/gpio

输出显示关键GPIO:

gpio-928 (dc-gpios ) out hi gpio-1022 (red ) out lo gpio-1023 (green ) out hi
  1. 通过EDL模式提取固件,获得lk二进制文件。高通平台的Bootloader带有ELF头,这大大简化了逆向工程工作。

1.3 Ghidra逆向分析

将提取的lk二进制导入Ghidra后,我们重点关注以下数据结构:

struct mdss_spi_cmd { int size; // 指令长度 char *payload; // 指令内容 int wait; // 延迟时间 uint8_t cmds_post_tg; };

通过交叉引用分析,我们定位到屏幕初始化序列存储在st7789v_ctc_qvga_nrx_cmd_on_command数组中。与标准ST7789V数据手册对比,发现厂商对以下参数做了定制:

寄存器标准值定制值作用
0x360x000xC0屏幕扫描方向
0xB20x0C0x0C空周期控制
0xB70x350x75门控控制

2. lk2nd移植核心步骤

2.1 基础环境搭建

使用lk2nd的experimental-rebase分支而非官方LK,原因在于:

  • 更好的GCC新版本兼容性
  • 已包含msm8909基础支持
  • 社区维护更活跃

编译命令:

make TOOLCHAIN_PREFIX=arm-none-eabi- msm8909 -j8

2.2 屏幕驱动集成

target/msm8909/oem_panel.c中添加以下关键修改:

+#include "include/panel_st7789v_ctc_qvga_nrx_cmd.h" enum { AUO_390P_CMD_PANEL, ST7789v2_QVGA_SPI_CMD_PANEL, + ST7789V_CTC_QVGA_NRX_CMD_PANEL, UNKNOWN_PANEL }; static struct panel_list supp_panels[] = { {"auo_390p_cmd", AUO_390P_CMD_PANEL}, {"ST7789V2_qvga_cmd", ST7789v2_QVGA_SPI_CMD_PANEL}, + {"st7789v_ctc_qvga_nrx_cmd", ST7789V_CTC_QVGA_NRX_CMD_PANEL}, };

初始化函数中绑定逆向得到的数据结构:

case ST7789V_CTC_QVGA_NRX_CMD_PANEL: panelstruct->paneldata = &st7789v_ctc_qvga_nrx_cmd_panel_data; panelstruct->panelres = &st7789v_ctc_qvga_nrx_cmd_panel_res; panelstruct->color = &st7789v_ctc_qvga_nrx_cmd_color; pinfo->spi.panel_cmds = st7789v_ctc_qvga_nrx_cmd_on_command; pan_type = PANEL_TYPE_SPI; break;

2.3 SPI总线配置调整

通过逆向设备树发现屏幕连接在BLSP1_QUP5,而非lk2nd默认的QUP4。需要以下修改:

  1. 时钟寄存器定义(platform/msm8909/include/platform/iomap.h):
+#define GCC_BLSP1_QUP6_SPI_APPS_CBCR (CLK_CTL_BASE + 0x701C) +#define GCC_BLSP1_QUP6_SPI_APPS_CMD_RCGR (CLK_CTL_BASE + 0x7024)
  1. GPIO配置(platform/msm8909/gpio.c):
void gpio_config_blsp_spi(uint8_t blsp_id, uint8_t qup_id) { if(blsp_id == BLSP_ID_1 && qup_id == QUP_ID_5) { gpio_tlmm_config(8, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_16MA, GPIO_DISABLE); // MOSI gpio_tlmm_config(9, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_16MA, GPIO_DISABLE); // MISO gpio_tlmm_config(10, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_16MA, GPIO_DISABLE); // CS gpio_tlmm_config(11, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_16MA, GPIO_DISABLE); // CLK } }
  1. 修改默认QUP ID(target/msm8909/include/target/display.h):
-#define SPI_QUP_ID 4 +#define SPI_QUP_ID 5

3. 关键问题解决与调试

3.1 白屏问题排查

初期烧录后出现白屏但背光亮起的现象,通过以下步骤定位问题:

  1. 确认初始化日志显示驱动已加载:
[LK] panel st7789v_ctc_qvga_nrx_cmd init
  1. 使用逻辑分析仪抓取SPI信号,发现CS线无活动

  2. 对比设备树与代码,发现QUP配置不匹配:

qcom,mdss_spi_client { reg = <0x00>; label = "MDSS SPI QUP5 CLIENT"; spi-max-frequency = <0x2faf080>; // 50MHz };

3.2 时钟配置验证

BLSP时钟树配置需要确保:

  1. 核心时钟(BLSP1_AHB_CLK)已使能
  2. SPI应用时钟(BLSP1_SPI_APPS_CLK)正确分频
  3. 时钟源选择GPLL0(800MHz)

调试时添加的日志输出:

dprintf(INFO, "BLSP1_CLK_ENA: 0x%x\n", readl(GCC_BLSP1_AHB_CBCR)); dprintf(INFO, "SPI_APPS_CLK_SRC: 0x%x\n", readl(GCC_BLSP1_QUP5_SPI_APPS_CMD_RCGR));

3.3 电源时序调整

ST7789V要求严格的电源上电顺序:

  1. VCCIO (1.8V) 先上电
  2. 延迟10ms后上电VCC (2.8V)
  3. 再延迟5ms后释放复位

通过修改panel_st7789v_ctc_qvga_nrx_cmd_reset_seq实现:

static struct reset_seq st7789v_ctc_qvga_nrx_cmd_reset_seq = { .sequence = { {1, 0, 1}, // GPIO928 (RESET) 拉低 {10, 0, 0}, // 保持10ms {0, 1, 1}, // GPIO928 拉高 {120, 0, 0} // 保持120ms }, .size = 4 };

4. 完整补丁文件

4.1 oem_panel.c补丁

--- a/target/msm8909/oem_panel.c +++ b/target/msm8909/oem_panel.c @@ -54,6 +56,7 @@ #include "include/panel_auo_390p_cmd.h" #include "include/panel_st7789v2_qvga_spi_cmd.h" #include "include/panel_gc9305_qvga_spi_cmd.h" +#include "include/panel_st7789v_ctc_qvga_nrx_cmd.h" enum { AUO_390P_CMD_PANEL, @@ -86,6 +89,7 @@ static struct panel_list supp_panels[] = { {"auo_390p_cmd", AUO_390P_CMD_PANEL}, {"ST7789V2_qvga_cmd", ST7789v2_QVGA_SPI_CMD_PANEL}, + {"st7789v_ctc_qvga_nrx_cmd", ST7789V_CTC_QVGA_NRX_CMD_PANEL}, {"gc9305_qvga_cmd", GC9305_QVGA_SPI_CMD_PANEL}, UNKNOWN_PANEL }; @@ -502,20 +506,22 @@ uint32_t platform_type = board_platform_id(); uint32_t platform_subtype = board_hardware_subtype(); int32_t panel_override_id; + int oem_panel_id = oem_read_panel_id(); + dprintf(INFO, "[HACK] oem_panel_id :%d\n",oem_panel_id); - if (panel_name) { + if (1) { panel_override_id = panel_name_to_id(supp_panels, - ARRAY_SIZE(supp_panels), panel_name); + ARRAY_SIZE(supp_panels), "st7789v_ctc_qvga_nrx_cmd"); if (panel_override_id < 0) { dprintf(CRITICAL, "Not able to search the panel:%s\n", - panel_name); + "st7789v_ctc_qvga_nrx_cmd"); } else if (panel_override_id < UNKNOWN_PANEL) { /* panel override using fastboot oem command */ panel_id = panel_override_id; dprintf(INFO, "OEM panel override:%s\n", - panel_name); + "st7789v_ctc_qvga_nrx_cmd"); goto panel_init; } }

4.2 gpio.c补丁

--- a/platform/msm8909/gpio.c +++ b/platform/msm8909/gpio.c @@ -124,13 +124,6 @@ GPIO_8MA, GPIO_DISABLE); break; case QUP_ID_5: - /* configure I2C SDA gpio */ - gpio_tlmm_config(18, 3, GPIO_OUTPUT, GPIO_NO_PULL, - GPIO_8MA, GPIO_DISABLE); - - /* configure I2C SCL gpio */ - gpio_tlmm_config(19, 3, GPIO_OUTPUT, GPIO_NO_PULL, - GPIO_8MA, GPIO_DISABLE); break; default: dprintf(CRITICAL, "Incorrect QUP id %d\n",qup_id); @@ -147,51 +140,33 @@ { if(blsp_id == BLSP_ID_1) { switch (qup_id) { - case QUP_ID_3: - /* configure SPI MOSI gpio */ - gpio_tlmm_config(12, 1, GPIO_OUTPUT, GPIO_NO_PULL, - GPIO_16MA, GPIO_DISABLE); - - /* configure SPI MISO gpio */ - gpio_tlmm_config(13, 1, GPIO_OUTPUT, GPIO_NO_PULL, - GPIO_16MA, GPIO_DISABLE); - - /* configure SPI CS_N gpio */ - gpio_tlmm_config(14, 1, GPIO_OUTPUT, GPIO_NO_PULL, - GPIO_16MA, GPIO_DISABLE); - - /* configure SPI CLK gpio */ - gpio_tlmm_config(15, 1, GPIO_OUTPUT, GPIO_NO_PULL, - GPIO_16MA, GPIO_DISABLE); - break; - case QUP_ID_4: + case QUP_ID_5: /* configure SPI MOSI gpio */ - gpio_tlmm_config(16, 1, GPIO_OUTPUT, GPIO_NO_PULL, + gpio_tlmm_config(8, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_16MA, GPIO_DISABLE); /* configure SPI MISO gpio */ - gpio_tlmm_config(17, 1, GPIO_OUTPUT, GPIO_NO_PULL, + gpio_tlmm_config(9, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_16MA, GPIO_DISABLE); /* configure SPI CS_N gpio */ - gpio_tlmm_config(18, 1, GPIO_OUTPUT, GPIO_NO_PULL, + gpio_tlmm_config(10, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_16MA, GPIO_DISABLE); /* configure SPI CLK gpio */ - gpio_tlmm_config(19, 1, GPIO_OUTPUT, GPIO_NO_PULL, + gpio_tlmm_config(11, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_16MA, GPIO_DISABLE); - break; - - case QUP_ID_0: - case QUP_ID_1: - case QUP_ID_2: - case QUP_ID_5: default: dprintf(CRITICAL, "Incorrect QUP id %d\n",qup_id); ASSERT(0);

5. 验证与后续工作

成功烧录修改后的lk2nd后,设备能够正常显示Bootloader界面。通过以下命令验证显示子系统状态:

fastboot oem panel-info

输出应包含:

Panel: st7789v_ctc_qvga_nrx_cmd Interface: SPI Resolution: 240x320

后续可继续完善:

  1. 添加动态屏幕旋转支持
  2. 实现帧缓冲控制台
  3. 优化SPI传输效率(启用DMA模式)
  4. 为主线Linux内核开发对应的tinydrm驱动

这个案例展示了即使面对非标准硬件配置,通过系统化的逆向工程和模块化修改,也能成功实现Bootloader的深度定制。最重要的是保持对硬件文档的细致分析和对日志信息的充分利用,这两者往往是解决复杂移植问题的关键。

http://www.cnnetsun.cn/news/3252261.html

相关文章:

  • DeepSeek V4 API价格策略解析与成本优化实战指南
  • 华为 MH5000-31 5G模组 Windows/Linux 双平台部署:从驱动安装到AT指令上网全流程
  • macOS Catalina下Jupyter Notebook配置全指南
  • OCRAutoScore:基于多模态AI的智能阅卷系统架构解析
  • 在线算法在实时推荐系统中的应用与性能保障7
  • 代理模式和适配器模式区别
  • HarmonyOS 小游戏《对战五子棋》开发第23篇 - 保持棋盘正方形
  • 维度建模实战:电商数仓 6 步构建星型模型,产出 10+ 核心事实/维度表
  • 直流有刷电机驱动方案:TC78H651AFNG与PIC18F85J10实战
  • 02-01-确认环境依赖(全平台发布)
  • 延伸音(Tension)应用指南:属七和弦5种常用Tension音搭配与省略五音原则
  • 【Bug已解决】openclaw network timeout / Connection timed out — OpenClaw 网络超时解决方案
  • 你想不想用一套系统方法,把复杂的医学数据变成清晰结论?
  • QT入门篇
  • ADS131M02与PIC24EP512GU814的高精度ADC系统设计
  • 2026大直径紧固件双叠自锁垫圈怎么选型
  • 使用英特尔流式SIMD扩展优化动画模型的 渲染 流水线
  • MAX77654与PIC18LF46K40的嵌入式电源管理方案
  • 有些软件明明就是财务软件,为什么要说是ERP呢?
  • 终极指南:3分钟掌握Boss-Key老板键,一键保护你的数字隐私空间
  • MP2672A双节锂电池充电管理与STM32控制方案
  • 如何用AI快速移除图片和视频背景?BackgroundRemover完整指南
  • 夏天,死磕这 6 个燃脂行为,体脂率下降 5%!
  • Steam挂刀神器:5分钟搭建你的饰品交易监控系统,发现隐藏利润空间!
  • 终极指南:如何彻底解决MHY扫码器直播监视功能崩溃问题 [特殊字符]
  • 有没有覆盖全学段的靠谱论文 AI?整理一份不白花冤枉钱工具榜单
  • Flink 1.18.0 本地模式性能初探:WordCount作业737ms运行时间分析
  • Go入门:代码格式化与gofmt使用指南
  • TRAE:面向 Vue 3 移动端开发的 AI IDE 工作流
  • Kilo Code:面向工程落地的跨端AI编程加速器