Edit online

时钟

MAC 和 PHY 的协同工作共牵涉到以下时钟,Luban-Lite 已将时钟部分处理完整,不需要用户除 scons --menuconfig 配置 MAC 使用 external clkinternal clk 之外的其 他任何修改

MAC 工作时钟

MAC 的内部工作时钟通过 PLL 分频获得,为 50M, 工作时钟不会因为方案的不同而不同,为一固定值 配置代码在 “packages/third-party/lwip/contrib/ports/drv/aic/aic_mac_ll.c” 中。
void aicmac_low_level_init(uint32_t port, bool en)
{
    uint32_t id = CLK_GMAC0 + port;

    /* pin-mux */

    /* mac clock */
    if (en) {
        /* Set clock frequence = 50M */
        hal_clk_set_freq(id, 50000000);
        /* clock enable & reset deassert */
        hal_clk_enable_deassertrst_iter(id);
    } else {
        /* clock enable & reset deassert */
        hal_clk_disable_assertrst(id);
    }
}

MDC 时钟

MDC 时钟是 mdio 的工作时钟,是 MAC 和 PHY 进行配置的工作时钟,双方在使用初期会有一个协 商,一般是 MAC 通知 PHY,该时钟为 MAC 通过模块的内部工作时钟处理生成,也不会因为方案的 不同而不同,为一固定值。MDIO 时钟初始化在 “packages/third-party/lwip/contrib/ports/drv/aic/aicmac.c” 文件的 init 函数中
int aicmac_init(uint32_t port)
{
    ...

    /* MDCIO Internal Clock Select */
    tmpreg = readl(MAC(port, mdioctl));
    tmpreg &= ~(ETH_MDIOCTL_CR_MSK);
    ahbclk = hal_clk_get_freq(CLK_AHB0);
    if ((ahbclk >= 20000000) && (ahbclk < 35000000)) {
        tmpreg |= ETH_MDIOCTL_CR_Div16;
    } else if ((ahbclk >= 35000000) && (ahbclk < 60000000)) {
        tmpreg |= ETH_MDIOCTL_CR_Div26;
    } else if ((ahbclk >= 60000000) && (ahbclk < 100000000)) {
        tmpreg |= ETH_MDIOCTL_CR_Div42;
    } else if ((ahbclk >= 100000000) && (ahbclk < 150000000)) {
        tmpreg |= ETH_MDIOCTL_CR_Div62;
    } else if ((ahbclk >= 150000000) && (ahbclk < 250000000)) {
        tmpreg |= ETH_MDIOCTL_CR_Div102;
    } else /* ((ahbclk >= 250000000)&&(ahbclk <= 300000000)) */
    {
        tmpreg |= ETH_MDIOCTL_CR_Div124;
    }
    writel(tmpreg, MAC(port, mdioctl));
    ...
    ...
}

MDC 时钟配置错误,则 MAC 和 PHY 的通信不通,呈现的现象是 MAC 无法发现 PHY 设备

PHY 工作时钟

一般 PHY 的工作时钟是 25M, 一般的设计是外挂一个晶振提供时钟给 PHY 模组, AIC 不同型号芯片都对外提供几组时钟,也可以使用该时钟供给 PHY 模块工作。

该时钟 (clk-out2) 使能在 “target/soc name/board name/sys_clk.c” 中配置。如果需要可以打开
struct aic_sysclk aic_sysclk_config[] = {
    ...
    {25000000, CLK_OUT2},
    ...
};

void aic_board_sysclk_init(void)
{
    uint32_t i = 0;

    for (i=0; i<sizeof(aic_sysclk_config)/sizeof(struct aic_sysclk); i++) {
        hal_clk_set_freq(aic_sysclk_config[i].clk_id, aic_sysclk_config[i].freq);
    }

    /* Enable sys clk */
    hal_clk_enable_deassertrst_iter(CLK_GPIO);
    hal_clk_enable_deassertrst_iter(CLK_GTC);
#ifdef AIC_USING_GMAC0
    hal_clk_enable_deassertrst_iter(CLK_OUT2);
#endif
}

MDATA 时钟

MDATA 时钟 为 MAC 和 PHY 进行数据传输的时钟,对于百兆和千兆有不同的使用方式

  • 百兆网络:可以是 MAC 供给 PHY, 也可以是 PHY 供给 MAC

  • 千兆网络:只能是 MAC 供给 PHY,RGMII0-TXCK 端口

代码中会根据 scons --menuconfig 中的配置来决定 MAC 使用的时钟来源是内部时钟还是外部时钟
static s32 syscfg_gmac_init(u32 ch)
{
    #ifdef AIC_SYSCFG_DRV_V10
    u32 cfg_reg = ch ? SYSCFG_GMAC1_CFG : SYSCFG_GMAC0_CFG;
    #else
    u32 cfg_reg =  SYSCFG_GMAC0_CFG;
    #endif
    s32 cfg;

    cfg = syscfg_readl(cfg_reg);

    if (ch == 0) {
        #ifdef AIC_SYSCFG_DRV_V10
        #ifdef AIC_DEV_GMAC0_RGMII
        cfg |= SYSCFG_GMAC_PHY_RGMII_1000M;
        #else
        cfg &= ~SYSCFG_GMAC_PHY_RGMII_1000M;
        #endif
        #endif
        #ifdef AIC_DEV_GMAC0_PHY_EXTCLK
        cfg |= SYSCFG_GMAC_RMII_EXTCLK_SEL;
        #endif
        #if AIC_DEV_GMAC0_TXDELAY
        cfg |= (AIC_DEV_GMAC0_TXDELAY << SYSCFG_GMAC_TXDLY_SEL_SHIFT);
        #endif
        #if AIC_DEV_GMAC0_RXDELAY
        cfg |= (AIC_DEV_GMAC0_RXDELAY << SYSCFG_GMAC_RXDLY_SEL_SHIFT);
        #endif
    } else if (ch == 1) {
        #ifdef AIC_SYSCFG_DRV_V10
        #ifdef AIC_DEV_GMAC1_RGMII
        cfg |= SYSCFG_GMAC_PHY_RGMII_1000M;
        #else
        cfg &= ~SYSCFG_GMAC_PHY_RGMII_1000M;
        #endif
        #endif
        #ifdef AIC_DEV_GMAC1_PHY_EXTCLK
        cfg |= SYSCFG_GMAC_RMII_EXTCLK_SEL;
        #endif
        #if AIC_DEV_GMAC1_TXDELAY
        cfg |= (AIC_DEV_GMAC1_TXDELAY << SYSCFG_GMAC_TXDLY_SEL_SHIFT);
        #endif
        #if AIC_DEV_GMAC1_RXDELAY
        cfg |= (AIC_DEV_GMAC1_RXDELAY << SYSCFG_GMAC_RXDLY_SEL_SHIFT);
        #endif
    }

    syscfg_writel(cfg, cfg_reg);

    return 0;
}