Marvell交换芯片88E6390驱动开发

参考

Marvell交换芯片88E6321/88E6320驱动总结-硬件篇
Marvell交换芯片88E6321/88E6320驱动总结-寄存器篇
Marvell 88E6390交换芯片disable自动学习功能的坑
88E6390端口Link问题BUG解决
STM32连接Marvell交换芯片88E6176的PHY
Marvell 交换芯片DSA(分布式交换架构)功能介绍
以太网交换芯片及PHY处理相关
二层交换机和三层交换机的区别
zynq and marvell dsa 88e6352 integration, device tree
zynqmp and marvell dsa 88e6320
Problem with Marvell 88E6320 connected to GEM3 in ZynqMP
Zynq and Marvell DSA integration

介绍

Marvell 88E6390是一款11端口全千兆以太网二层交换芯片,1port-8配置为千兆电口,port9-10千兆光口,88E6390x则具8个集成的1Gb IEEE802.3az PHY和两个10Gb端口,10Gb端口支持10Gbps、2.5Gbps和1Gbps速率,支持IEEE1588 1-step时间戳,支持最新Audio/Video Bridging(AVB)和Time Sensitive Networking(TSN)标准。

NO_CPU模式

在复位状态下(RESETn = low)时,设置NO_CPU引脚电平后,RESETn上升沿将锁存引脚电平。若此时NO_CPU=0则表示芯片由CPU控制,NO_CPU=1则表示芯片非CPU控制。在NO_CPU=0模式下,所有的Port在初始化时都被关闭,PHY的供电关闭,使得CPU可以在芯片工作前进行启动与配置,该引脚内部上拉,默认上电所有Port打开。为了方便,可以将NO_CPU置为1进行调试,调试通过后,考虑低功耗处理时,可以采用NO_CPU=0模式,以屏蔽不需要打开的Port。
NO_CPU模式决定了上电之后端口的默认状态

MDIO

由于88E6321本身功能强大,即可以做MAC也可以做PHY(2个Port)、SERDES(2个Port),因此虽然只是一个芯片,88E6321有两种芯片寻址模式:单芯片寻址与多芯片寻址。
通过在复位状态时设置ADDR[4:0]n引脚的电平可以设置设备地址(需要注意的是,ADDR所设置的地址为实际SMI地址的反码,即ADDR=0x1F对应的实际SMI地址为0x00,,ADDR=0x00对应的实际SMI地址0x1F)。
主控可以通过这个接口(MDC_CPU与MDIO_CPU)对88E6321进行管理。MDC_CPU最高支持20MHz,MDIO_CPU需要外接一个4.7K到10K的上拉电阻。

单芯片寻址模式:

当ADDR[4:0]n=0x1F时,进入单芯片寻址模式,此时通过内部地址直接访问,在这个模式下,88E6321会响应所有的32个SMI地址,因此必须确保他是惟一的SMI从设备,在设备寄存器映射图中,SMI设备地址地址0X03、0X04(对应Port3、4的PHY)、0X0C、0X0D(对应Port0、1的SERDES),0X10-0X16(对应Port0-Port7),0X1B-0X1D(对应特殊寄存器Global1-3)是可以直接访问的,而地址0X03、0X04(对应Port3、4的PHY)、0X0C、0X0D(对应Port0、1的SERDES),当然寄存器也可以通过使用Global2地址的SMI PHY Command和SMI PHY Data两个寄存器进行间接访问。

多芯片寻址模式:

当ADDR[4:0]n!=0x1F时,则进入多芯片寻址模式,此时,88E6321只会响应ADDR设置的地址的反码 (ADDR[4:0]的反码),同时仅有两个寄存器可以直接访问(SMI Command寄存器与SMI Data寄存器),其他寄存器则通过这两个寄存器间接访问(包括在单芯片寻址模式下间接访问的寄存器)。间接访问的函数,STM32版本,

/*!
 * \fn write_smi_phy_reg
 * \brief PHY寄存器设置
 *          
 * \param [in] ETH_HandleTypeDef *heth STM32以太网结构体定义
 * \param [in] uint16_t dev_addr PHY地址,单芯片寻址模式下为0x03或0x04
 * \param [in] uint16_t reg_addr 寄存器地址
 * \param [in] uint32_t reg_value 写入值
 * 
 * \retval error_code_t  
 */
error_code_t write_smi_phy_reg(ETH_HandleTypeDef *heth, uint16_t dev_addr, uint16_t reg_addr, uint32_t reg_value)
{
    volatile uint16_t time_out;
    uint32_t smi_reg;
    time_out = 100;

    /*!
     *  检测当前PHY是否Busy
     */
    do {
        if (HAL_ETH_ReadPHYRegister_New(heth, GLOBAL2_DEV_ADDR(0x1C), SMI_PHY_CMD_REG(0x18), &smi_reg) != ok) {
            ERROR_MSG("Read SMI_PHY_CMD_REG register failed");
            return error;
        }
        if (time_out-- < 1) {
            ERROR_MSG("Read SMI_PHY_CMD_REG register timed out");
            return error;
        }
    } while (smi_reg & SMI_BUSY(0x8000));

    /*!
     *  先将需要写入的数据写入SMI_PHY_DATA_REG,待后续写命令时完成传输
     */
    if (HAL_ETH_WritePHYRegister_New(heth, GLOBAL2_DEV_ADDR, SMI_PHY_DATA_REG, reg_value) != ok) {
        return error;
    }

    smi_reg = SMI_BUSY | (dev_addr << 5) | (SMI_WRITE(0x01) << 10) | (reg_addr << 0) | (SMI_CLAUSE22 << 12);//!< 设置需要写入的命令(写命令、smi地址、phy寄存器地址、条款) By: Ouqichen 2019年2月11日
    
    /*!
     *  写入命令
     */
    if (HAL_ETH_WritePHYRegister_New(heth, GLOBAL2_DEV_ADDR, SMI_PHY_CMD_REG, smi_reg) != ok) {
        ERROR_MSG("Write PHY_QD_REG_SMI_PHY_CMD Register Failed");
        return error;
    }

    return ok;
}

/*!
 * \fn read_smi_phy_reg
 * \brief PHY寄存器读取
 *          
 * \param [in] ETH_HandleTypeDef *heth STM32以太网结构体定义
 * \param [in] uint16_t dev_addr PHY地址,单芯片寻址模式下为0x03或0x04
 * \param [in] uint16_t reg_addr 寄存器地址
 * \param [out] uint32_t *reg_value 读出值
 * 
 * \retval error_code_t 
 */
error_code_t read_smi_phy_reg(ETH_HandleTypeDef *heth, uint16_t dev_addr, uint16_t reg_addr, uint32_t reg_value)
{
    volatile uint16_t time_out;
    uint32_t smi_reg;

    time_out =100;
    /*!
     *  检测当前PHY是否Busy
     */
    do {
        if (HAL_ETH_ReadPHYRegister_New(heth, GLOBAL2_DEV_ADDR(0x1C), SMI_PHY_CMD_REG(0x18), &smi_reg) != ok) {
            ERROR_MSG("Read SMI_PHY_CMD_REG register failed");
            return error;
        }
        if (time_out-- < 1) {
            ERROR_MSG("Read SMI_PHY_CMD_REG register timed out");
            return error;
        }
    } while (smi_reg & SMI_BUSY(0x8000));

    smi_reg = SMI_BUSY | (dev_addr << 5) | (SMI_READ_22(0x02) << 10) | (reg_addr << 0) | (SMI_CLAUSE22 << 12);//!< 设置需要写入的命令(读命令、smi地址、phy寄存器地址、条款) By: Ouqichen 2019年2月11日

    /*!
     *  写入命令
     */
    if (HAL_ETH_WritePHYRegister_New(heth, GLOBAL2_DEV_ADDR, SMI_PHY_CMD_REG, smi_reg) != ok) {
        ERROR_MSG("Write PHY_QD_REG_SMI_PHY_CMD Register Failed");
        return error;
    }

    time_out =100;
    /*!
     *  检测当前PHY是否Busy
     */
    do {
        if (HAL_ETH_ReadPHYRegister_New(heth, GLOBAL2_DEV_ADDR(0x1C), SMI_PHY_CMD_REG(0x18), &smi_reg) != ok) {
            ERROR_MSG("Read SMI_PHY_CMD_REG register failed");
            return error;
        }
        if (time_out-- < 1) {
            ERROR_MSG("Read SMI_PHY_CMD_REG register timed out");
            return error;
        }
    } while (smi_reg & SMI_BUSY(0x8000));

    /*!
     *  待总线不忙碌时读取数据
     */
    if (HAL_ETH_WritePHYRegister_New(heth, GLOBAL2_DEV_ADDR, SMI_PHY_DATA_REG, reg_value) != ok) {
        return error;
    }

    *reg_value = smi_reg;

    return ok; 
}

IEEE中只为PHY定义了32个寄存器地址,为了拓展寄存器地址,这里采用的页机制,其中寄存器22的[7:0]用于切换页。切换函数,

/*!
 * \fn read_smi_page_phy_reg
 * \brief 带页切换的PHY寄存器读取
 *          
 * \param [in] ETH_HandleTypeDef *heth STM32以太网结构体定义
 * \param [in] uint16_t port_num 端口号
 * \param [in] uint8_t page_num 页号码
 * \param [in] uint16_t reg_addr 寄存器地址
 * \param [out] uint32_t *reg_value 读出值
 * 
 * \retval error_code_t 
 */
error_code_t read_smi_page_phy_reg(ETH_HandleTypeDef *heth, uint8_t port_num, uint8_t page_num, uint16_t reg_addr, uint32_t *reg_value)
{
    error_code_t ret_value;
    ret_value = write_smi_phy_reg(heth, (uint16_t)port_num, SMI_PHY_PAGE_ANY_REG(0x16), (uint32_t)page_num);

    if (ret_value != ok)
        return ret_value;

    ret_value = read_smi_phy_reg(heth, (uint16_t)port_num, reg_addr, reg_value);
    return ret_value;
}

/*!
 * \fn write_smi_phy_reg
 * \brief PHY寄存器设置
 *          
 * \param [in] ETH_HandleTypeDef *heth STM32以太网结构体定义
 * \param [in] uint16_t port_num 端口号
 * \param [in] uint8_t page_num 页号码
 * \param [in] uint16_t reg_addr 寄存器地址
 * \param [in] uint32_t reg_value 写入值
 * 
 * \retval error_code_t  
 */
error_code_t read_smi_page_phy_reg(ETH_HandleTypeDef *heth, uint8_t port_num, uint8_t page_num, uint16_t reg_addr, uint32_t reg_value)
{

    error_code_t ret_value;
    ret_value = write_smi_phy_reg(heth, (uint16_t)port_num,SMI_PHY_PAGE_ANY_REG(0x16), (uint32_t)page_num);

    if (ret_value != ok)
        return ret_value;

    ret_value = write_smi_phy_reg(heth, (uint16_t)port_num, reg_addr, reg_value);
    return ret_value;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章