第4章 GTY的复位与初始化:让收发器「醒过来」的正确姿势

各位同学,欢迎来到第四章。前面我们聊了GTY的架构和时钟,但一个硬件模块光有电和时钟是不够的——你得让它「醒过来」,并且按照正确的顺序进入工作状态。

复位与初始化,说白了就是给GTY一个清晰的启动流程。我见过不少新手在这块翻车:复位时序不对,数据线死活拉不高;或者初始化顺序搞反了,误码率高得吓人。这章我们就来掰扯清楚,GTY到底该怎么正确复位和初始化。

核心结论先放前面: GTY的复位不是啪一下拉低再拉高就完事了。它有一套严格的序列,必须按照CPLL → 通道PCS → TX/RX数据通路的顺序来。跳步?想都别想。
GTY复位与初始化完整流程图 1. 硬复位 / 上电复位 GTY_GTRESET = 1 保持 ≥ 10 us 2. CPLL 复位与锁定 CPLLRESET = 1 → 0 等待 CPLLLOCK = 1 3. TX / RX 通道复位 TXUSERRDY / RXUSERRDY 等待 PCS 初始化完成 初始化阶段(自动 / 配置驱动) GTY_DRP 配置通道参数(预加重、均衡、极性等) PCS / PMA 复位释放 → 时钟对齐 → CDR 锁定 RX 侧等待 RXELECIDLE 消失,确认链路正常 4. 数据通路就绪 TX / RX 数据可以正常收发 ⚠ 常见陷阱:复位顺序不能乱!CPLL未锁定就操作通道 → 数据永久错误 每次复位都需要完整走一遍流程,不允许跳步

4.1 复位信号的分类与作用

GTY的复位信号有好几根,它们各管一摊,千万别混淆。我习惯把它们分成三类:

复位类型 信号名 作用对象 作用范围
硬复位 GTY_GTRESET 整个GTY Quad 所有通道、PLL、时钟
PLL复位 CPLLRESET / QPLLRESET 对应PLL 仅复位PLL本身
通道复位 TXPCSRESET / RXPCSRESET 单个通道的PCS逻辑 TX或RX的数据通路

有人问:我直接用GTY_GTRESET把全部复位一遍不就完了吗?省事儿。嗯,我以前也这么干过,但后来发现一个问题——每次全局复位,PLL都要重新锁定,这得花好几十微秒。如果只是通道数据出了问题,复位PCS就够了,不需要动PLL。

我的建议: 设计一个自动状态机,把全局复位作为上电/异常恢复的最后手段。平时用通道级复位来快速重置数据通路,这样系统恢复时间可以从几十微秒降到几微秒。

4.2 复位序列——千万别搞反顺序

很多同学第一次看UG手册,发现复位序列列了一堆步骤,头都大了。其实记住一条主线就行:时钟域 → PLL → 数据通路。核心逻辑是——先有稳定的参考时钟和PLL输出,才能去初始化依赖它们的PCS和数据通路。这个顺序是物理决定的,不是Xilinx强加的。

推荐复位步骤(以单个GTY通道为例)

  1. 确保参考时钟已稳定——时钟芯片的输出要稳定,GTY的REFCLK输入不能有毛刺。
  2. 拉低GTY_GTRESET,保持至少10微秒——这期间内部所有状态机归零。
  3. 释放GTY_GTRESET——注意这里只是释放硬复位,不是马上操作通道。
  4. 复位并等待CPLL锁定:
    • 拉高CPLLRESET,保持1微秒以上;
    • 拉低CPLLRESET;
    • 轮询CPLLLOCK信号,直到它为高;
  5. 释放TX/RX PCS复位:
    • 拉低TXPCSRESET和RXPCSRESET(如果有独立信号);
    • 或者通过GTY的初始化状态机,驱动TXUSERRDY和RXUSERRDY为高;
  6. 等待PCS初始化完成——TX侧等待TXRESETDONE,RX侧等待RXRESETDONE。
  7. 检查CDR锁定和RX信号质量——对于RX侧还要确认RXELECIDLE已经消失。

举个例子,下面是我某个项目里用的Verilog代码片段,只展示了核心控制逻辑:

// 复位状态机 - 简化版
// 状态:IDLE → CPLL_RESET → WAIT_CPLL → PCS_RESET → WAIT_PCS → READY

always @(posedge clk or posedge rst_i) begin
    if (rst_i) begin
        state       <= IDLE;
        gty_reset_n <= 1'b0;
        cpll_reset  <= 1'b1;
        tx_usrrdy   <= 1'b0;
        rx_usrrdy   <= 1'b0;
    end else begin
        case (state)
            IDLE: begin
                gty_reset_n <= 1'b1;      // 释放硬复位
                state <= CPLL_RESET;
            end
            CPLL_RESET: begin
                cpll_reset <= 1'b0;       // 释放CPLL复位
                state <= WAIT_CPLL;
            end
            WAIT_CPLL: begin
                if (cpll_locked) begin
                    tx_usrrdy <= 1'b1;    // 通知通道PCS开始初始化
                    rx_usrrdy <= 1'b1;
                    state <= PCS_RESET;
                end
            end
            PCS_RESET: begin
                // 等待TXRESETDONE和RXRESETDONE
                if (tx_resetdone && rx_resetdone)
                    state <= READY;
            end
            READY: begin
                // 数据通路已就绪
            end
        endcase
    end
end
重要提醒: 上面的代码是为了展示概念而简化的。实际项目中,每个状态还要加上超时保护——如果CPLL超过50微秒还没锁定,就应该上报错误并尝试重启复位序列,不能卡死在等待状态上。

4.3 复位完成信号怎么看?

复位序列走完了,怎么确认GTY真的准备好了?靠几个状态指示信号:

  • CPLLLOCK / QPLLLOCK:PLL锁定的硬性指示。逻辑高表示频率锁定。
  • TXRESETDONE:TX侧的PCS初始化完成。高电平表示TX数据通路已准备就绪。
  • RXRESETDONE:RX侧PCS初始化完成。注意,这个信号高并不代表CDR也锁定了。
  • RXELECIDLE:RX检测到线路空闲。正常工作时应该是低电平。
  • RXCLKCORCNT:时钟校正计数。可以用来判断RX侧的时钟对齐是否稳定。

我个人的习惯是:在上层控制器里把这些信号都引出来,做成一个状态寄存器,方便上板调试时通过ILA观察。你想想看,如果复位完成后TXRESETDONE是低的,你还在拼命往TX FIFO里写数据——那不是白费功夫吗?

4.4 初始化阶段需要配置什么?

复位做完只是第一步,真正的「初始化」还包括通过DRP(动态重配置端口)写入通道参数。说白了,你需要在复位完成后,按顺序写寄存器:

配置项 DRP地址 典型值 说明
TX预加重 0x16 0x0001 (2.5dB) 根据PCB走线长度调整
RX均衡器 0x1F 0x0003 (5dB) 补偿高频损耗
极性控制 0x10 0x0000 TX/RX极性翻转
输出幅度 0x12 0x0010 (800mVpp) 幅度越大,功耗越高

这些配置必须在PLL锁定之后、数据通路激活之前写入。我以前踩过一个坑:先把PCS复位释放了,再去写DRP,结果写进去的值不生效,因为PCS已经在按默认值初始化了。顺序错位,白忙活一场。

小技巧: 如果你不通过DRP动态配置,直接在Vivado的GT Wizard里把这些参数设好,那Vivado会在bit文件生成时帮你把这些配置放进去。上电后GTY自己会加载这些初始化值,你只需要关注复位时序就行。

4.5 常见陷阱与实践建议

最后分享几个我遇到过的真实问题,希望能帮你们少走弯路:

  • CPLL复位时间不够: 手册上说CPLLRESET低电平至少保持1微秒。我见过有人只拉了100纳秒,结果CPLLLOCK一直不拉高——因为内部模拟电路根本没复位彻底。
  • 多个通道共用CPLL: 如果一个CPLL给两个通道服务,复位其中一个通道时不能把CPLLRESET拉高,否则另一个通道也会掉线。用通道级的TXPCSRESET和RXPCSRESET就好。
  • RXELECIDLE没消失就认为链路OK: 我曾经在调试时发现RXRESETDONE拉了,就以为数据通了,结果上板抓ILA发现RXELECIDLE还是高——链路根本没建立。需要加上检查RXELECIDLE和RX信号质量的逻辑。
  • 仿真和实物表现不一致: 仿真时复位时序跑得好好的,上板就不行。为什么?因为仿真器里的PLL锁定时间和CDR锁定时间都是理想化的,实际芯片可能慢好几倍。复位时间参数一定要留余量。
  • 热复位与冷重置: 如果系统运行中需要复位GTY,记得先让链路伙伴端的发送器停止发送,不然RX侧会收到一堆假信号。我建议设计一个握手协议,复位前通知对端。

嗯,关于复位与初始化,就讲这么多。记住那个核心顺序——时钟 → PLL → 数据通路,然后仔细检查每个完成信号。GTY不会自己告诉你「我还没准备好」,但如果复位序列不对,它一定会用各种奇怪的方式让你知道——数据错乱、链路断开、误码暴增。把这些基础打牢了,后面的内容就好办了。