我仍在努力让 Broadcom“BCM84891L”10GbE PHY 启动并运行(相关线程是
同时,我能够在 1G 模式(使用带有 SerDes 协议 0x3333 的 SGMII)和 10G 模式(使用带有 SerDes 协议 0x1133 的 XFI)下运行 PHY。现在我需要在运行时在 1G 和 10G 之间切换。由于我无法在运行时更改 RCW,我尝试重新配置 SerDes 通道,但到目前为止没有成功。
对于冗长的帖子感到抱歉,但我相信许多细节对于找到问题是必要的......
两个 RCW 几乎相同(差异以粗体显示):
# 1G(单个PLL ):
0C140012
0E000000000000000000000000000000000000000000000000000000
来
#10G(单独的PLL):
0C140012 0E00000000000000000000000000000000000000000000000000.000000.11335559
C000500 6 60000000 C1000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000来
问题 1:我可以切换通道使用的 PLL 时钟吗?
PLL1 以 125 MHz 运行,PLL2 以 156.25 MHz 运行。
1G-RCW 设置 RCW[SRDS_REFCLK_SEL_S1]=1,即 Lanes C 和 D 使用 PLL2,PLL2 使用 PLL1=125MHz 作为源(这个可行)。
10G-RCW设置RCW[SRDS_REFCLK_SEL_S1]=0,即Lane C和D使用PLL2,PLL2使用156.25MHz作为source(这个可行)。
现在我使用 10G RCW 启动,然后将通道 D 重新配置为 SGMII。在此过程中,我设置了 LNDGCR0[RPLL_LES]=1 和 LNDGCR0[TPLL_LES]=1 以使用 PLL1。这不同于 1G-RCW 使用的配置(它使用 LNDGCR0[RPLL_LES]=0)。它不起作用。
当然,我重新配置的不仅仅是 RPLL_LES 和 TPLL_LES(见下文)。但是我不涉及 PLL 配置,即我不需要遵守“PLL 复位和重新配置”部分。
问:是否允许将 Lane D 从 PLL2 切换到 PLL1?是否有我可能忽略的陷阱?
问题 2:车道重新配置:我的方法可以吗?
我使用 10G-RCW (XFI) 启动 U-Boot。U-Boot 中的 ping 命令按预期工作(使用 10G 远程 PC)。然后我将通道重新配置为 SGMII。此后 ping 不起作用。然后我重新配置回 XFI,然后 ping 再次工作。因此我怀疑重新配置序列有效,但我错过了一些关于 SGMII 配置的信息。
以下是我切换到 SGMII-Configuration 的方法(请参阅下文了解set_bit32()、
clear_bit32()和
change_bits32()的说明):
mac_disable();
// 第 1 步:将通道放入重置
值 = byteswap4(*serdes_lnagcr0);
clear_bit32(&value, LNxGCR0__TRST_B);
clear_bit32(&value, LNxGCR0__RRST_B);
*serdes_lnagcr0 = byteswap4(值);
value = byteswap4(*serdes_lnbgcr0);
clear_bit32(&value, LNxGCR0__TRST_B);
clear_bit32(&value, LNxGCR0__RRST_B);
*serdes_lnbgcr0 = byteswap4(值);
值 = byteswap4(*serdes_lncgcr0);
clear_bit32(&value, LNxGCR0__TRST_B);
clear_bit32(&value, LNxGCR0__RRST_B);
*serdes_lncgcr0 = byteswap4(值);
value = byteswap4(*serdes_lndgcr0);
clear_bit32(&value, LNxGCR0__TRST_B);
clear_bit32(&value, LNxGCR0__RRST_B);
*serdes_lndgcr0 = byteswap4(值);
// 第 2 步:等待至少 50 ns
ndelay(50);
// 第 3 步:更改所需的每通道设置
value = byteswap4(*serdes_lndgcr0);
set_bit32(&value, LNxGCR0__RPLL_LES); // 使用 PLL 1(而不是 PLL 2)
set_bit32(&value, LNxGCR0__TPLL_LES); // 使用 PLL 1(而不是 PLL 2)
*serdes_lndgcr0 = byteswap4(value);
值 = byteswap4(*serdes_pccrb);
change_bits32(&value, PCCRB__XFIA_CFG__MSB, PCCRB__XFIA_CFG__LSB, 0x0);
*serdes_pccrb = byteswap4(值);
值 = byteswap4(*serdes_pccr8);
change_bits32(&value, PCCR8__SGMIID_CFG__MSB, PCCR8__SGMIID_CFG__LSB, 0x1);
*serdes_pccr8 = byteswap4(值);
value = byteswap4(*serdes_lndgcr0);
change_bits32(&value, LNxGCR0__RRAT_SEL__MSB, LNxGCR0__RRAT_SEL__LSB, 0x2);
change_bits32(&value, LNxGCR0__TRAT_SEL__MSB, LNxGCR0__TRAT_SEL__LSB, 0x2);
change_bits32(&value, LNxGCR0__PROTS__MSB, LNxGCR0__PROTS__LSB, 0x1);
clear_bit32(&value, LNxGCR0__IF20BIT_EN);
*serdes_lndgcr0 = byteswap4(值);
value = byteswap4(*serdes_lndgcr1);
change_bits32(&value, LNxGCR1__REIDL_TH_MSB, LNxGCR1__REIDL_TH_LSB, 0x1);
clear_bit32(&value, LNxGCR1__REIDL_EX_MSB);
change_bits32(&value, LNxGCR1__REIDL_EX_SEL__MSB,
LNxGCR1__REIDL_EX_SEL__LSB, 0x3);
set_bit32(&value, LNxGCR1__REIDL_ET_MSB);
change_bits32(&value, LNxGCR1__REIDL_ET_SEL__MSB,
LNxGCR1__REIDL_ET_SEL__LSB, 0x0);
*serdes_lndgcr1 = byteswap4(值);
value = byteswap4(*serdes_lndrecr0);
clear_bit32(&value, LNxRECR0__RXEQ_BST);
change_bits32(&value, LNxRECR0__GK2OVD__MSB, LNxRECR0__GK2OVD__LSB, 0xf);
change_bits32(&value, LNxRECR0__GK3OVD__MSB, LNxRECR0__GK3OVD__LSB, 0xf);
set_bit32(&value, LNxRECR0__GK2OVD_EN);
set_bit32(&value, LNxRECR0__GK3OVD_EN);
clear_bit32(&value, LNxRECR0__OSETOVD_EN);
change_bits32(&value, LNxRECR0__BASE_WAND__MSB,
LNxRECR0__BASE_WAND__LSB, 0x0);
change_bits32(&value, LNxRECR0__OSETOVD__MSB,
LNxRECR0__OSETOVD__LSB, 0x1f);
*serdes_lndrecr0 = byteswap4(值);
value = byteswap4(*serdes_lndtecr0);
change_bits32(&value, LNxTECR0__TEQ_TYPE__MSB,
LNxTECR0__TEQ_TYPE__LSB, 0x0);
clear_bit32(&value, LNxTECR0__SGN_PREQ);
change_bits32(&value, LNxTECR0__RATIO_PREQ__MSB,
LNxTECR0__RATIO_PREQ__LSB, 0x0);
clear_bit32(&value, LNxTECR0__SGN_POST1Q);
change_bits32(&value, LNxTECR0__RATIO_POST1Q__MSB,
LNxTECR0__RATIO_POST1Q__LSB, 0x0);
change_bits32(&value, LNxTECR0__ADPT_EQ__MSB,
LNxTECR0__ADPT_EQ__LSB, 0x30);
change_bits32(&value, LNxTECR0__AMP_RED__MSB, LNxTECR0__AMP_RED__LSB, 0x6);
*serdes_lndtecr0 = byteswap4(值);
value = byteswap4(*serdes_lndttlcr0);
change_bits32(&value, LNxTTLCR0__FLT_SEL__MSB,
LNxTTLCR0__FLT_SEL__LSB, 0x39);
*serdes_lndttlcr0 = byteswap4(值);
value = byteswap4(*serdes_sgmiidcr1);
set_bit32(&value, SGMIIxCR1__SGPCS_EN);
*serdes_sgmiidcr1 = byteswap4(值);
// 泳道第 4 步:等待至少 120 ns
ndelay(120);
// Lane 第 5 步:从 reset value = byteswap4(*serdes_lnagcr0) 中取出 lane(s)
;
set_bit32(&value, LNxGCR0__TRST_B);
set_bit32(&value, LNxGCR0__RRST_B);
*serdes_lnagcr0 = byteswap4(值);
value = byteswap4(*serdes_lnbgcr0);
set_bit32(&value, LNxGCR0__TRST_B);
set_bit32(&value, LNxGCR0__RRST_B);
*serdes_lnbgcr0 = byteswap4(值);
值 = byteswap4(*serdes_lncgcr0);
set_bit32(&value, LNxGCR0__TRST_B);
set_bit32(&value, LNxGCR0__RRST_B);
*serdes_lncgcr0 = byteswap4(值);
value = byteswap4(*serdes_lndgcr0);
set_bit32(&value, LNxGCR0__TRST_B);
set_bit32(&value, LNxGCR0__RRST_B);
*serdes_lndgcr0 = byteswap4(值);
// 最后,再次启用 MAC
mac_enable();
之后我更改了一些 MDIO 寄存器:
值 = memac_mdio_read (dev_mdio_mac_9, 0x0, MDIO_DEVAD_NONE, 0x14);
值 &= ~0x1f; // 将所有非保留位设置为 0
值 |= 0x9; // 双工=0, 速度=0b10, an=0, en=1
memac_mdio_write(dev_mdio_mac_9, 0x0, MDIO_DEVAD_NONE, 0x14, value);
值 = memac_mdio_read (dev_mdio_mac_9, 0x0, MDIO_DEVAD_NONE, 0x4);
值 |= 0x1;// SGMII 模式=1
memac_mdio_write(dev_mdio_mac_9, 0x0, MDIO_DEVAD_NONE, 0x4, value);
值 = memac_mdio_read (dev_mdio_mac_9, 0x0, MDIO_DEVAD_NONE, 0x0);
值 &= ~0xffc0; // 将所有非保留位设置为 0
值 |= 0x8000; // 重置=1
memac_mdio_write(dev_mdio_mac_9, 0x0, MDIO_DEVAD_NONE, 0x0, value);
以下是我禁用 MAC 的方法:
// COMMAND_CONFIG[RXSTP]=1
value = byteswap4(*emac9_command_config);
set_bit32(&value, COMMAND_CONFIG__RXSTP);
*emac9_command_config = byteswap4(值);
// 等待 IEVENT[RX_EMPTY] 被设置
while(!(byteswap4(*emac9_ievent) & (0x1 << IEVENT__RX_EMPTY)))
{
byteswap4(*emac9_ievent));
}
//COMMAND_CONFIG[RX_EN]=0
value = byteswap4(*emac9_command_config);
clear_bit32(&value, COMMAND_CONFIG__RX_EN);
*emac9_command_config = byteswap4(值);
// 等待 IEVENT[TX_EMPTY] 被设置
while(!(byteswap4(*emac9_ievent) & (0x1 << IEVENT__TX_EMPTY)))
{
}
// 3) 写入 COMMAND_CONFIG[TX_EN]=0
value = byteswap4(*emac9_command_config);
clear_bit32(&value, COMMAND_CONFIG__TX_EN);
*emac9_command_config = byteswap4(值);
这是我再次启用 MAC 的方法:
// 设置 COMMAND_CONFIG[SWR]
值 = byteswap4(*emac9_command_config);
set_bit32(&value, COMMAND_CONFIG__SWR);
clear_bit32(&value, COMMAND_CONFIG__RXSTP);
*emac9_command_config = byteswap4(值);
// 初始化 IF_MODE 寄存器
值 = byteswap4(*emac9_if_mode);
值 = if_mode_value;
*emac9_if_mode = byteswap4(值);
// 设置 STATN_CONFIG[CLR]
值 = byteswap4(*emac9_statn_config);
set_bit32(&value, STATN_CONFIG__CLR);
*emac9_statn_config = byteswap4(值);
延迟(1);// 等到重置完成(需要 32 个 FMAN 周期,1 usec 就足够了!)
// 清除 IEVENT 寄存器
*emac9_ievent = 0;
// 初始化 IMASK 寄存器
*emac9_imask = 0;
// 设置 COMMAND_CONFIG[RX_EN],设置 COMMAND_CONFIG[TX_EN]
value = byteswap4(*emac9_command_config);
set_bit32(&value, COMMAND_CONFIG__RX_EN);
set_bit32(&value, COMMAND_CONFIG__TX_EN);
*emac9_command_config = byteswap4(值);
我的方法好吗?以这种方式改变车道是否合法?我是否正确禁用并重新启动 MAC?
问题三:如何分析硬件状态?
从 XFI 配置到 SGMII 后,我可以看到 U-Boot 正在将数据包送入 BMAN,但数据包并未由 MAC 传输。我能否确定 BMAN 是否正确“连接”到 MAC?是否有“链接”状态或其他什么?还有其他重要的状态位吗?
附录:辅助函数和命名约定
宏名称:
- 第一部分是寄存器名称,第二部分是位名称,有时第三部分是 MSB/LSB。各部分由双下划线分隔。
- 示例:SGMIIxCR1__SGPCS_EN:SGMIIxCR1 是寄存器(SGMIIaCR1、SGMIIbCR1 等),SGPCS_EN 是寄存器内的位。
- 示例:LNxTECR0__ADPT_EQ__MSB: LNxTECR0 是寄存器,ADPT_EQ 是该寄存器中的位。由于 ADPT_EQ 跨越多个位,因此我将 MSB 和 LSB 用于最高位和最低位。
位操作:
- set_bit32() 和 clear_bit32() 执行读取-修改-写入以设置/清除单个位。参数为LS1046ARM中规定的bit号,例如LNDGCR0[TPLL_LES]为bit 4。
- change_bits32() 的工作原理类似,但会更改多个相邻位。例如,change_bits32(&value, LNxTECR0__ADPT_EQ__MSB, LNxTECR0__ADPT_EQ__LSB, 0x30) 将位 18 到 23 更改为值 0x30,而不触及寄存器中的其他位。