以太网PHY寄存器分析 以太网PHY驱动软件配置

描述

我们对g_ethercat_ssc_port0_ext_cfg这个全局变量深入追踪,其成员变量 g_ether_PHY0,正好是一个PHY实例的详细描述体。
 

/* Instance structure to use this module. */
const ether_PHY_instance_t g_ether_PHY0 =
{
    .p_ctrl        = &g_ether_PHY0_ctrl,
    .p_cfg         = &g_ether_PHY0_cfg,
    .p_api         = &g_ether_PHY_on_ether_PHY
};

 

其中g_ether_PHY0_cfg是pyh实例的配置结构体:

 

const ether_PHY_cfg_t g_ether_PHY0_cfg =
{


    .channel                   = 0,
    .PHY_lsi_address           = 0,
    .PHY_reset_wait_time       = 0x00020000,
    .mii_bit_access_wait_time  = 0,                         // Unused
    .flow_control              = ETHER_PHY_FLOW_CONTROL_DISABLE,
    .mii_type                  = (ether_PHY_mii_type_t) 0,  // Unused
    .p_context                 = NULL,
    .p_extend                  = &g_ether_PHY0_extend
};

 

这里又通过p_extend 做了扩展配置(其实可以合并在一起)如下所示:

 

const ether_PHY_extend_cfg_t g_ether_PHY0_extend =
{
    .port_type          = ETHER_PHY_PORT_TYPE_ETHER_CAT,
    .PHY_chip           = (ether_PHY_chip_t) ETHER_PHY_CHIP_VSC8541,
    .mdio_type          = ETHER_PHY_MDIO_GMAC,


    .bps                = ETHER_PHY_SPEED_100,
    .duplex             = ETHER_PHY_DUPLEX_FULL,
    .auto_negotiation   = ETHER_PHY_AUTO_NEGOTIATION_ON,


    .PHY_reset_pin      = BSP_IO_PORT_20_PIN_7,
    .PHY_reset_time     = 15000,


    .p_selector_instance = (ether_selector_instance_t *)&g_ether_selector0,
};

 

可以看到上面的扩展配置当中,PHY的具体硬件型号都已经列出,如PHY_chip = (ether_PHY_chip_t) ETHER_PHY_CHIP_;

可以看到在示例代码当中已经支持的PHY如下所示:

 

/** Identify PHY-LSI */
typedef enum e_ether_PHY_chip
{
    ETHER_PHY_CHIP_VSC8541 = (1 << 0), ///< VSC8541
    ETHER_PHY_CHIP_KSZ9131 = (1 << 1), ///< KSZ9131
    ETHER_PHY_CHIP_KSZ9031 = (1 << 2), ///< KSZ9031
    ETHER_PHY_CHIP_KSZ8081 = (1 << 3), ///< KSZ8081
    ETHER_PHY_CHIP_KSZ8041 = (1 << 4)  ///< KSZ8041
} ether_PHY_chip_t;

 

这里具体看一下 g_ether_selector0 这个 ether_selector_instance_t 类型的全局指针,指向 selector driver实例的成员变量:

 

typedef struct st_ether_selector_instance
{
    ether_selector_ctrl_t      * p_ctrl; ///< Pointer to the control structure for this instance
    ether_selector_cfg_t const * p_cfg;  ///< Pointer to the configuration structure for this instance
    ether_selector_api_t const * p_api;  ///< Pointer to the API structure for this instance
} ether_selector_instance_t;

 

这又是一个类似的结构体,通过三个指针来分别指向结构本身,selector的具体配置,和配置selector过程中所需要用的的成员方法api.

看一下selector的具体配置信息:

 

typedef struct st_ether_selector_cfg
{
    uint8_t port;                              ///< Port number
    ether_selector_PHYlink_polarity_t PHYlink; ///< PHY link signal polarity


    ether_selector_interface_t interface;      ///< Converter mode
    ether_selector_speed_t     speed;          ///< Converter Speed
    ether_selector_duplex_t    duplex;         ///< Converter Duplex
    ether_selector_ref_clock_t ref_clock;      ///< Converter REF_CLK
    void const               * p_extend;       ///< Placeholder for user extension.
} ether_selector_cfg_t;

 

可以看到selector 对应的端口号,PHY连接信号对应的极性,接口模式,速率,全双工,以及外部时钟输入。再看一下配置selector的过程中所需要用到的API函数:

 

const ether_selector_api_t g_ether_selector_on_ether_selector =
{
    .open         = R_ETHER_SELECTOR_Open,
    .converterSet = R_ETHER_SELECTOR_ConverterSet,
    .close        = R_ETHER_SELECTOR_Close,
    .versionGet   = R_ETHER_SELECTOR_VersionGet
};

 

其最主要的成员方法就是R_ETHER_SELECTOR_Open做了些什么:

先初始化ETHER_SELECTOR 

 

 /* One time initialization for all ETHER_SELECTOR instances. */
    r_ether_selector_state_initialize();


    /* Unlock write access protection for Ethernet subsystem registers */
    r_ether_selector_reg_protection_disable(p_reg_ethss);
   
    /* Set the function of Ethernet ports. */
    sw_mode = ETHER_SELECTOR_CFG_MODE;
    p_reg_ethss->MODCTRL_b.SW_MODE = sw_mode & ETHER_SELECTOR_MODCTRL_BIT_SWMODE_MASK;
    
    /* Set the MAC of all port for half-duplex.  */
    p_reg_ethss->SWDUPC_b.PHY_DUPLEX = 0;
    
    /* Set all Ethernet switch port to select not use 10Mbps.  */
    p_reg_ethss->SWCTRL_b.SET10 = 0;

 

根据端口号来选择对应控制寄存器

 

/* Set RGMII/RMII Converter configuration */
    switch (port)
    {
        case 0:
        {
            p_reg_convctrl = (uint32_t *) &p_reg_ethss->CONVCTRL[0];
            break;
        }


        case 1:
        {
            p_reg_convctrl = (uint32_t *) &p_reg_ethss->CONVCTRL[1];
            break;
        }


        case 2:
        default:
        {
            p_reg_convctrl = (uint32_t *) &p_reg_ethss->CONVCTRL[2];
            break;
        }
    }

 

根据指向selector的配置信息:

 

const ether_selector_cfg_t g_ether_selector0_cfg =
{
    .port                      = 0,
    .PHYlink                   = ETHER_SELECTOR_PHYLINK_POLARITY_LOW,
    .interface                 = ETHER_SELECTOR_INTERFACE_RGMII,
    .speed                     = ETHER_SELECTOR_SPEED_100MBPS,
    .duplex                    = ETHER_SELECTOR_DUPLEX_FULL,
    .ref_clock                 = ETHER_SELECTOR_REF_CLOCK_INPUT,
    .p_extend                  = NULL,
};

 

来对CONVCTRL[port_number]寄存器做相应的配置

PHY

这里结合RZ/T2M的用户手册,很容易理解其中的意思:

PHY

结合代码来看,总体ETHER_SELECTOR 的驱动的配置流程图台下所示:

PHY

在对ETHER_SELECTOR驱动做完配置后,下面具体看一下对ETHER_PHY_CHIP这个PHY,代码具体做了哪些操作:

首先是做初始化:

PHY

 

oid ether_PHY_targets_initialize_vsc8541 (ether_PHY_instance_ctrl_t * p_instance_ctrl)
{
    /* Vendor Specific PHY Registers */
 #define ETHER_PHY_REG_LED_MODE_SELECT                 (0x1D)
 #define ETHER_PHY_REG_LED_BEHAVIOR                    (0x1E)
 #define ETHER_PHY_REG_EXTEND_GPIO_PAGE                (0x1F)
...

 

这个初始化函数,并没有对IEEE 标准规定的16个寄存器做读写操作,只对厂商自定义的寄存器做了配置。初始化完成之后,对是否打开自动协商的功能对PHY进行了读写:

PHY

PHY

这里可以看到对PHY芯生来说,需要配置的寄存器并不是很多,大多数情况下,把自动协商寄存器配置好,就可以了。除此之后就是厂商自定义的寄存器的一些自定义的功能。这部分功能需要结合用户手册来理解和使用,大部分也是用来调试和指示的作用以及一些IEEE基本标准之外的特色功能,比如节能标准之类的。

对于用户说来,搞清楚数据结构之间的关联,剩下的就是驱动代码的执行逻辑,考虑到执行逻辑并不复杂,这里不展开来说。用户可以参考录屏材料进一步深入了解。

其它

经过验证的PHY芯片列表:

PHY






审核编辑:刘清

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分