1. HDMI 1.4 源端初始化与寄存器配置

HDMI 1.4 源端初始化与寄存器配置 学习卡片

任务说明

本案例面向HDMI 1.4源端(Source)驱动开发,目标是在典型SoC平台上完成HDMI发送控制器(TX Controller)的初始化与寄存器配置,使PHY输出稳定的TMDS时钟与数据信号,并进入就绪状态以等待上层应用启动视频传输。案例以实际驱动开发中最常涉及的寄存器操作序列为核心,不涉及具体视频时序参数计算(该部分由后续案例覆盖)。

硬件上下文与寄存器模型

为保持案例独立可复现,我们定义一个简化的HDMI TX控制器寄存器映射(基于常见SoC设计抽象),包含以下关键寄存器:

  • HDMI_TX_CTRL(0x1000):全局控制,bit0=PWR_EN,bit1=TX_EN,bit2=HDMI_MODE(1=HDMI,0=DVI)
  • HDMI_TX_CLK_CTRL(0x1004):时钟控制,bit0=TMDS_CLK_EN,bit1=PHY_PLL_EN,bit2=SOURCE_CLK_EN
  • HDMI_TX_PHY_CTRL(0x1008):PHY配置,bit[3:0]=TERM_RES(终端电阻),bit[5:4]=DRV_CURR(驱动电流)
  • HDMI_TX_STATUS(0x100C):状态寄存器,bit0=PLL_LOCKED,bit1=TMDS_CLK_READY,bit2=PHY_READY
  • HDMI_TX_INT_EN(0x1010):中断使能,bit0=HPD_EN(热插拔检测),bit1=ERR_EN

初始化流程与代码实现

初始化遵循以下顺序:上电使能 → 配置PHY参数 → 使能PLL与时钟 → 等待状态就绪 → 配置中断。以下C代码实现完整的初始化函数,并包含必要的寄存器读写抽象与超时保护:

#include <stdint.h>
#include <stdbool.h>

// 寄存器基地址(实际项目中由平台内存映射决定)
#define HDMI_TX_BASE      0x10000000UL

// 寄存器偏移
#define REG_CTRL          0x1000
#define REG_CLK_CTRL      0x1004
#define REG_PHY_CTRL      0x1008
#define REG_STATUS        0x100C
#define REG_INT_EN        0x1010

// 寄存器位定义
#define CTRL_PWR_EN       (1U << 0)
#define CTRL_TX_EN        (1U << 1)
#define CTRL_HDMI_MODE    (1U << 2)

#define CLK_TMDS_EN       (1U << 0)
#define CLK_PHY_PLL_EN    (1U << 1)
#define CLK_SOURCE_EN     (1U << 2)

#define PHY_TERM_RES_50   (0x5U)   // 50欧姆终端电阻
#define PHY_DRV_CURR_10mA (0x2U << 4) // 10mA驱动电流

#define STATUS_PLL_LOCKED (1U << 0)
#define STATUS_TMDS_READY (1U << 1)
#define STATUS_PHY_READY  (1U << 2)

#define INT_HPD_EN        (1U << 0)
#define INT_ERR_EN        (1U << 1)

// 寄存器读写抽象(实际项目中替换为平台IO访问)
static inline uint32_t reg_read(uint32_t offset) {
    return *(volatile uint32_t *)(HDMI_TX_BASE + offset);
}

static inline void reg_write(uint32_t offset, uint32_t value) {
    *(volatile uint32_t *)(HDMI_TX_BASE + offset) = value;
}

// 等待状态位,带超时
static bool wait_status_bit(uint32_t bit, uint32_t timeout_us) {
    while (timeout_us--) {
        if (reg_read(REG_STATUS) & bit)
            return true;
        // 简单忙等待,实际驱动中可替换为udelay或调度
        for (volatile int i = 0; i < 100; i++);
    }
    return false;
}

// HDMI 1.4 源端初始化主函数
// 返回true表示初始化成功,false表示超时失败
bool hdmi_tx_init(void) {
    // 1. 全局上电,先关闭发送使能
    reg_write(REG_CTRL, CTRL_PWR_EN);
    
    // 2. 配置PHY参数:50欧姆终端电阻,10mA驱动电流
    reg_write(REG_PHY_CTRL, PHY_TERM_RES_50 | PHY_DRV_CURR_10mA);
    
    // 3. 使能PHY PLL,等待锁定
    reg_write(REG_CLK_CTRL, CLK_PHY_PLL_EN);
    if (!wait_status_bit(STATUS_PLL_LOCKED, 10000)) {
        return false;  // PLL锁定超时
    }
    
    // 4. 使能TMDS时钟与源端时钟
    uint32_t clk_ctrl = reg_read(REG_CLK_CTRL);
    clk_ctrl |= CLK_TMDS_EN | CLK_SOURCE_EN;
    reg_write(REG_CLK_CTRL, clk_ctrl);
    
    // 5. 等待TMDS时钟稳定与PHY就绪
    if (!wait_status_bit(STATUS_TMDS_READY, 5000)) {
        return false;  // TMDS时钟超时
    }
    if (!wait_status_bit(STATUS_PHY_READY, 5000)) {
        return false;  // PHY未就绪
    }
    
    // 6. 配置为HDMI模式(非DVI),使能发送
    uint32_t ctrl = reg_read(REG_CTRL);
    ctrl |= CTRL_HDMI_MODE | CTRL_TX_EN;
    reg_write(REG_CTRL, ctrl);
    
    // 7. 使能热插拔检测与错误中断
    reg_write(REG_INT_EN, INT_HPD_EN | INT_ERR_EN);
    
    return true;
}

关键配置说明

上述代码中,PHY终端电阻设为50欧姆(符合HDMI规范对源端阻抗匹配的要求),驱动电流设为10mA(典型值,实际需根据PCB走线阻抗与信号完整性仿真调整)。PLL锁定等待时间为10ms量级,TMDS时钟与PHY就绪等待为5ms量级,这些超时值基于常见PHY上电时序设定,实际项目中应根据PHY数据手册调整。

验证方法

在目标平台上编译并运行上述代码,验证步骤如下:

  1. 调用hdmi_tx_init()后检查返回值,若为false,通过调试器读取REG_STATUS(0x100C),确认是PLL锁定失败还是时钟/PHY就绪超时;
  2. 若返回true,读取REG_STATUS,预期bit[2:0]均为1(PLL_LOCKED、TMDS_CLK_READY、PHY_READY同时置位);
  3. 使用示波器或逻辑分析仪测量HDMI TX差分引脚对(TMDS Data0/1/2与Clock),在无视频数据输入时应观察到稳定的TMDS时钟信号(频率由后续视频时序配置决定,当前仅验证时钟存在且无毛刺);
  4. 读取REG_INT_EN(0x1010),确认值为0x03,表示HPD与错误中断均已使能。

判定标准:函数返回true,状态寄存器bit[2:0]全为1,且示波器能捕获到TMDS时钟输出,即判定初始化通过。若任一状态位未置位或时钟无输出,则根据状态寄存器内容定位故障寄存器配置。

HDMI 1.4 源端初始化寄存器操作序列 ① 写 CTRL PWR_EN=1 ② 写 PHY_CTRL TERM=50Ω DRV=10mA ③ 写 CLK_CTRL PHY_PLL_EN=1 ④ 读 STATUS PLL_LOCKED? 是 否→超时 ⑤ 写 CLK_CTRL TMDS_EN|SOURCE_EN ⑥ 读 STATUS TMDS_READY? ⑦ 读 STATUS PHY_READY? ⑧ 写 CTRL HDMI_MODE|TX_EN ⑨ 写 INT_EN HPD_EN|ERR_EN 初始化完成 STATUS (0x100C) bit0=PLL bit1=TMDS bit2=PHY 成功时 = 0x07

落地与集成说明

本案例代码可直接作为驱动模块的初始化入口。实际集成时需注意:reg_read/reg_write应替换为平台提供的IO访问接口(如writel/readl);超时等待中的忙循环应替换为基于系统定时器的延时;若SoC的HDMI控制器有复位控制,需在调用hdmi_tx_init()前完成模块复位释放。本案例未涉及视频时序参数(如像素时钟频率、H/V同步参数)配置,这些参数需在后续视频通路使能阶段设置,不影响当前初始化验证。