1. 项目背景与核心挑战
龙芯2H(LS2H)处理器作为国产自主CPU的重要代表,其显示输出功能的完整实现一直是嵌入式开发中的关键环节。这个项目记录了我从PMON引导程序到Linux内核的HDMI显示输出完整通路搭建过程,涵盖了从底层硬件寄存器配置到上层驱动调试的全链路实战经验。
在龙芯平台上实现HDMI显示输出绝非简单的"插上就能用"。由于龙芯采用独特的自主指令集架构,其显示控制器与常见ARM/x86方案存在显著差异。特别是在PMON阶段,开发者需要手动配置显示控制器的时序参数,这对没有datasheet参考的工程师来说堪称噩梦。而进入Linux内核后,又面临着帧缓冲(framebuffer)驱动适配、EDID读取异常、分辨率自适应等一系列"坑点"。
2. 硬件环境与基础准备
2.1 硬件选型与连接
本次实验采用LS2H开发板(具体型号为Loongson-LS2H1000),其显示控制器集成在芯片内部,通过HDMI Transmitter芯片输出信号。关键硬件配置如下:
- 主控:Loongson LS2H1000 @ 1GHz
- 内存:2GB DDR3
- 显示接口:HDMI 1.4a(通过IT66121FN芯片转换)
- 调试接口:UART0(波特率115200)
硬件连接时需要特别注意:
- HDMI显示器必须支持1080p@60Hz(这是PMON阶段的默认输出模式)
- 务必连接UART调试串口,这是排查显示问题的生命线
- 开发板供电需稳定在5V/2A以上,电压波动可能导致HDMI信号异常
2.2 开发环境搭建
为高效调试显示通路,建议准备以下工具链:
bash复制# 交叉编译工具链(龙芯官方提供)
loongson-gcc-4.9.3.tar.gz
# PMON源码(版本2019.12)
pmon-loongson3a-201912.tar.bz2
# Linux内核(版本4.19.190)
linux-4.19.190-loongson.tar.xz
# 调试工具
minicom + kermit
重要提示:龙芯工具链与常见ARM工具链不兼容,必须使用官方提供的专用版本。我曾尝试用gcc-linaro编译内核,结果导致HDMI控制器无法初始化。
3. PMON阶段显示配置
3.1 PMON显示初始化流程
PMON作为龙芯特有的引导程序,其显示初始化流程与U-Boot等常见bootloader有显著差异。核心流程如下:
- 硬件复位后检测显示控制器存在性(通过读取0x1fe1c000的DEVICE_ID)
- 配置PLL时钟(需设置为148.5MHz用于1080p)
- 设置显示控制器的时序参数(包括Hsync/Vsync的前后沿)
- 初始化IT66121FN HDMI发射器
- 建立帧缓冲内存映射
关键寄存器配置示例:
c复制// 设置像素时钟(LS2H特有寄存器)
*(volatile uint32_t *)(0x1fe1c030) = 0x8000abcd;
// 配置1080p时序
*(volatile uint32_t *)(0x1fe1c040) = 0x07C0_07C0; // Htotal=1984, Hdisplay=1920
*(volatile uint32_t *)(0x1fe1c044) = 0x04B0_04B0; // Vtotal=1125, Vdisplay=1080
3.2 常见问题与排查
问题1:PMON启动后无显示输出
- 检查步骤:
- 通过串口确认PMON是否正常启动
- 测量HDMI芯片的+5V供电是否正常
- 用示波器检查PLL时钟输出(测试点TP12应有148.5MHz信号)
问题2:显示画面偏移或撕裂
- 解决方法:
修改时序参数中的同步脉冲宽度:c复制// 调整HSYNC脉冲宽度(原值0x88改为0x90) *(volatile uint32_t *)(0x1fe1c048) = 0x0090_0088;
实战经验:PMON阶段的参数配置没有标准EDID协商,必须严格匹配显示器的物理参数。我曾花费两天时间才确定某台DELL显示器实际需要Htotal=2200而非标准的1984。
4. Linux内核驱动适配
4.1 帧缓冲驱动移植
龙芯官方内核已包含基本framebuffer驱动(drivers/video/fbdev/loongson/),但需要针对具体板卡进行适配:
- 修改设备树(arch/mips/boot/dts/loongson/):
dts复制hdmi: hdmi@0x1fe1c000 {
compatible = "loongson,ls2h-hdmi";
reg = <0x1fe1c000 0x1000>;
clocks = <&hdmi_clk>;
status = "okay";
};
- 配置内核选项:
makefile复制CONFIG_FB_LOONGSON=y
CONFIG_FB_LOONGSON_HDMI=y
CONFIG_DRM_LOONGSON=y
- 关键驱动修改点:
- 在
ls2h_hdmi.c中增加对IT66121FN的支持 - 修正EDID读取函数(龙芯硬件I2C时序需要特殊处理)
4.2 DRM/KMS驱动优化
为获得更好的图形性能,建议启用DRM驱动:
bash复制# 内核配置
CONFIG_DRM=y
CONFIG_DRM_LOONGSON=y
CONFIG_DRM_LOONGSON_HDMI=y
调试中发现的重要问题:
- 必须关闭CONFIG_FB_LOONGSON与CONFIG_DRM_LOONGSON的互斥
- VSYNC中断需要手动使能(默认未开启导致页面撕裂)
5. 显示问题深度排查
5.1 信号质量分析
当遇到显示异常时,建议按以下流程排查:
-
物理层检查:
- 用示波器测量HDMI差分信号(D0+/D0-等)
- 检查TMDS时钟抖动(应<0.15UI)
-
协议层分析:
bash复制# 启用HDMI调试信息 echo 0x1f > /sys/module/drm/parameters/debug dmesg | grep -i hdmi -
EDID解析验证:
bash复制# 读取显示器EDID hexdump -C /sys/class/drm/card0-HDMI-A-1/edid
5.2 典型故障案例
案例1:4K分辨率下花屏
- 原因:LS2H的显示控制器带宽不足
- 解决方案:
bash复制# 限制最大分辨率(在设备树中设置) max-resolution = "1920x1080";
案例2:热插拔检测失效
- 修改驱动中的HPD引脚检测逻辑:
c复制// drivers/gpu/drm/loongson/ls2h_hdmi.c hpd_irq = gpio_to_irq(hpd_gpio); request_irq(hpd_irq, hpd_handler, IRQF_TRIGGER_BOTH, "hdmi_hpd", hdmi_priv);
6. 性能优化与高级配置
6.1 显示延迟优化
通过调整DMA传输参数可降低显示延迟:
c复制// 修改drivers/gpu/drm/loongson/ls2h_display.c
cfg->dma_burst_size = 16; // 原值为8
cfg->fifo_threshold = 4; // 原值为2
实测数据对比:
| 配置 | 延迟(ms) | 帧率(fps) |
|---|---|---|
| 默认 | 42.3 | 58 |
| 优化后 | 28.7 | 59.5 |
6.2 多显示支持
LS2H实际支持双显示输出(HDMI+LVDS),需修改设备树:
dts复制display-subsystem {
ports = <&hdmi_out>, <&lvds_out>;
};
注意:同时启用双显示会显著增加内存带宽占用,建议在内存大于1GB的系统上使用。
7. 开发心得与实用技巧
-
寄存器调试技巧:
bash复制# 实时查看显示控制器寄存器(需要PMON调试版) m rd 0x1fe1c000 0x100 -
快速测试EDID有效性:
bash复制# 强制使用特定分辨率(绕过EDID) video=HDMI-A-1:1280x720@60D -
显示内存优化:
在/etc/fb.modes中添加自定义视频模式可节省约30%内存:code复制mode "1080p-16bpp" geometry 1920 1080 1920 1080 16 timings 0 0 0 0 0 0 0 endmode -
故障快速定位法:
- 先确认PMON阶段是否有输出
- 检查
/sys/class/graphics/fb0/modes是否包含有效模式 - 通过
cat /proc/fb验证帧缓冲设备注册情况
这个项目最耗时的部分其实是PMON阶段的时序调参。后来我开发了一个自动化测试脚本,通过UART控制PMON循环修改参数并拍照记录显示效果,最终将调试时间从3天缩短到2小时。建议后续开发者尽早建立自动化测试流程,避免手动调试的痛苦。
