在RT-Thread下为MPU手搓以太网MAC驱动-1


这是个人驱动开发过程中做的一些记录,仅代表个人意见和理解,不喜勿喷

动手写驱动之前的思考

  • MAC驱动需要兼容不同的MPU平台
  • MAC驱动需要支持不同的PHY芯片
  • MAC驱动需要支持多个以太网接口
  • MAC驱动需要是否借鉴某个平台代码

在动手写驱动之前,脑海里就会在不停地思考这几个问题,等脑子里有个大概的可行框架就开始动手码代码。

MAC驱动兼容不同的MPU平台

Microchip 也有着丰富的MPU产品线(通过收购Atmel而获取),覆盖传统的ARM9、Cortex-A5和Cortex-A7内核。有的MPU它的以太网叫做GMAC,而有的又叫做EMAC,那编写驱动的时候就要留意对GMAC和EMAC的同时

解决不同MPU平台头文件包含的问题

选择在libraries/Kconfig文件下添加以下内容:

config SOC_SAM9X60_EK
    bool
    select RT_USING_COMPONENTS_INIT
    select RT_USING_CACHE

config SOC_SAM9X75_EK
    bool
    select RT_USING_COMPONENTS_INIT
    select RT_USING_CACHE

config SOC_SAMA5D2_XULT
    bool
    select ARCH_ARM_CORTEX_A
    select ARCH_ARM_CORTEX_FPU

config SOC_SAMA5D2_SOM1_EK
    bool
    select ARCH_ARM_CORTEX_A
    select ARCH_ARM_CORTEX_FPU

config SOC_SAMA7G54_EK
    bool
    select ARCH_ARM_CORTEX_A
    select ARCH_ARM_CORTEX_FPU

那在sam9x75-ek/board/Kconfig文件下这么做:

menu "Microchip Harmony Plib Configuration"

config SOC_SAM9X75
    bool
    select ARCH_ARM_ARM9
    select SOC_SAM9X75_EK
    select RT_USING_USER_MAIN
    default y

通过这样的方式,在选择sam9x75-ek平台做开发的时候,就会自动选择上SOC_SAM9X75_EK这个宏定义,后面会用到这个定义。

接下来在gmac/hpl_mac_async.h头文件中添加以下代码实现了对不同平台头文件的包含:

#ifdef SOC_SAMA5D2
#include <sama5d27.h>
#endif

#ifdef SOC_SAM9X75
#include <sam9x75.h>
#endif

#ifdef SOC_SAMA7G54
#include <sama7g54.h>
#endif

有的MPU平台只有一个GMAC,那它给的MAC相关ID定义是ID_GMAC,如果包含2个GMAC的MPU平台,则会给出ID_GMAC0和ID_GMAC1,那我选择在hpl_mac_async.h头文件添加这样的定义(后面会讲解到这样定义的作用):

#define ID_GMAC_NONE               0xFF

#ifdef ID_GMAC
#  define MAC0_ID                  ID_GMAC
#  define MAC1_ID                  ID_GMAC_NONE
#  define MAC0_IRQn                GMAC_IRQn
#  define MAC1_IRQn                ID_GMAC_NONE
#  define MAC0_REGS                GMAC_REGS
#  define MAC1_REGS                (void *)0
#else
#  define MAC0_ID                  ID_GMAC0
#  define MAC1_ID                  ID_GMAC1
#  define MAC0_IRQn                GMAC0_IRQn
#  define MAC1_IRQn                GMAC1_IRQn
#  define MAC0_REGS                GMAC0_REGS
#  define MAC1_REGS                GMAC1_REGS
#endif

对MAC操作接口的抽象

MAC操作接口的抽象,包括中断处理函数、初始化、使能和禁止、网络数据包的收发、获取接收数据包长度、过滤的设置、MAC地址的设置和非常重要的PHY读写访问接口:

struct h3_macplib_ops
{
    void     (*macdev_interrupt)(mac_dev *const dev);
    int32_t  (*macdev_init)(mac_dev *const dev, void *const hw);
    int32_t  (*macdev_deinit)(mac_dev *const dev);
    int32_t  (*macdev_enable)(mac_dev *const dev);
    int32_t  (*macdev_disable)(mac_dev *const dev);
    int32_t  (*macdev_change) (mac_dev *const dev, uint32_t speed);
    int32_t  (*macdev_send)(mac_dev *const dev, uint8_t *buf, uint32_t len);
    uint32_t (*macdev_recv)(mac_dev *const dev, uint8_t *buf, uint32_t len);
    uint32_t (*macdev_rxbyte)(mac_dev *const dev);
    int32_t  (*macdev_register)(mac_dev *const dev, mac_cb_type type, mac_async_cb fn);
    int32_t  (*macdev_filter)(mac_dev *const dev, uint8_t index, mac_filter *filter);
    int32_t  (*macdev_setmac)(mac_dev *const dev, uint8_t mac[6]);
    int32_t  (*macdev_writephy)(mac_dev *const dev, uint16_t addr, uint16_t reg, uint16_t data);
    int32_t  (*macdev_readphy) (mac_dev *const dev, uint16_t addr, uint16_t reg, uint16_t *val);
};

对MAC设备的抽象

对MAC设备也做出了抽象,MPU中如果存在多个MAC接口,那就会有对应数量的MAC设备实例:

struct h3_macplib_dev
{
    const char   *name;
    IRQn_Type     irqnum;
    H3_MAC_REGS   regs;
    uint8_t       mac_addr[6];
    uint8_t       dev_id;
    uint8_t       reserved;
    mac_async_dev mac_dev;
    phy_async_dev phy_dev;
    const struct rt_mdio_bus_ops *mdio_ops;
    const struct h3_macplib_ops  *mac_ops;
    struct rt_mdio_bus rt_mdiobus;
    struct eth_device  rt_ethdev;
};

MAC设备的注册

对MAC设备对应的实例,其部分成员都会在h3_macplib.c文件里面做静态的初始化:

#if defined(BSP_USING_GMAC0) || defined(BSP_USING_EMAC0)
struct h3_macplib_dev h3_macdev0 = {
    .name       = "e0",
    .irqnum     = MAC0_IRQn,
    .regs       = MAC0_REGS,
    .dev_id     = MAC0_ID,
    .phy_dev    =
    {
        .name       = PHY0_DEVICE_NAME,
        .phyID1     = H3_MACPLIB_PHY0ID1,
        .phyID2     = H3_MACPLIB_PHY0ID2,
        .phyaddr    = PHY0_DEVICE_ADDRESS,
    },
    .mac_ops    = &h3_macdev_ops,
};
#endif

#if defined(BSP_USING_GMAC1) || defined(BSP_USING_EMAC1)
struct h3_macplib_dev h3_macdev1 = {
    .name       = "e1",
    .irqnum     = MAC1_IRQn,
    .regs       = MAC1_REGS,
    .dev_id     = MAC1_ID,
    .phy_dev    =
    {
        .name       = PHY1_DEVICE_NAME,
        .phyID1     = H3_MACPLIB_PHY1ID1,
        .phyID2     = H3_MACPLIB_PHY1ID2,
        .phyaddr    = PHY1_DEVICE_ADDRESS,
    },
    .mac_ops    = &h3_macdev_ops,
};
#endif

实现对多个MAC设备的注册是这样来实现的:

static struct h3_macplib_dev *h3_macplib_devtable[] =
{
    0
#if defined(BSP_USING_GMAC0) || defined(BSP_USING_EMAC0)
    , &h3_macdev0
#endif
#if defined(BSP_USING_GMAC1) || defined(BSP_USING_EMAC1)
    , &h3_macdev1
#endif
};
int h3_macplib_init(void)
{
    rt_err_t state;
    uint8_t  macaddr = 0xAA;
    uint32_t table_sz = sizeof(h3_macplib_devtable)/sizeof(uint32_t);
    struct h3_macplib_dev *macplib_dev;

    for (uint32_t i = 1; i < table_sz; i++)
    {
        macplib_dev = h3_macplib_devtable[i];

        macplib_dev->mac_dev.devid     = macplib_dev->dev_id;
        macplib_dev->rt_mdiobus.hw_obj = (void *)macplib_dev;
        macplib_dev->rt_mdiobus.ops    = &h3_mdiobus_ops;

        /* GMAC MAC Address */
        macplib_dev->mac_addr[0] = 0x54;
        macplib_dev->mac_addr[1] = 0x27;
        macplib_dev->mac_addr[2] = 0x8d;
        macplib_dev->mac_addr[3] = 0x33;
        macplib_dev->mac_addr[4] = 0x55;
        macplib_dev->mac_addr[5] = macaddr++;

        macplib_dev->rt_ethdev.parent.init      = h3_macplib_initial;
        macplib_dev->rt_ethdev.parent.open      = h3_macplib_open;
        macplib_dev->rt_ethdev.parent.close     = h3_macplib_close;
        macplib_dev->rt_ethdev.parent.read      = h3_macplib_read;
        macplib_dev->rt_ethdev.parent.write     = h3_macplib_write;
        macplib_dev->rt_ethdev.parent.control   = h3_macplib_control;
        macplib_dev->rt_ethdev.parent.user_data = (void *)macplib_dev;

        macplib_dev->rt_ethdev.eth_rx = h3_macplib_rx;
        macplib_dev->rt_ethdev.eth_tx = h3_macplib_tx;

        /* register eth device */
        state = eth_device_init(&macplib_dev->rt_ethdev, macplib_dev->name);
        if (RT_EOK != state) {
            break;
        }

        eth_device_linkchange(&macplib_dev->rt_ethdev, RT_FALSE);
    }

    return state;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值