本文主要是介绍在RT-Thread下为MPU手搓以太网MAC驱动-4,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
文章目录
- MAC驱动里面对MDIO的支持
- MAC驱动与MDIO总线
这是个人驱动开发过程中做的一些记录,仅代表个人意见和理解,不喜勿喷
- MAC驱动需要支持不同的PHY芯片
MAC驱动里面对MDIO的支持
在第一篇文章中提到对MAC设备做出了抽象,其中MAC抽象里面有提供通过MDIO总线去访问PHY寄存器的读写操作接口(有省去其他操作接口)
struct h3_macplib_ops
{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);
};
那我们同时也需要实现一个MDIO设备驱动,因为在RT-Thread下也有定义MDIO相关的操作接口。
struct rt_mdio_bus_ops
{rt_bool_t (*init)(void *bus, rt_uint32_t src_clock_hz);rt_size_t (*read)(void *bus, rt_uint32_t addr, rt_uint32_t reg, void *data, rt_uint32_t size);rt_size_t (*write)(void *bus, rt_uint32_t addr, rt_uint32_t reg, void *data, rt_uint32_t size);rt_bool_t (*uninit)(void *bus);
};struct rt_mdio_bus
{void *hw_obj;char *name;struct rt_mdio_bus_ops *ops;
};
我们可以看到在RT-Thread下对MDIO设备和驱动接口也做了抽象的定义,比如MDIO驱动的操作接口包括初始化、读、写和解除初始化操作。对于MDIO设备,其包含对应的硬件内容,MDIO设备名和操作接口
static struct rt_mdio_bus_ops h3_mdiobus_ops =
{.init = h3_mdioplib_init,.read = h3_mdioplib_read,.write = h3_mdioplib_write,.uninit = RT_NULL,
};
在mac驱动下,MDIO设备驱动的读取接口实现如下,在这个驱动接口实现中,我们通过获取MDIO总线下包含的硬件信息,做一个类型的强制转换,获取到了指向macplib_dev实例的指针,然后就可以通过这个macplib_dev访问mac设备抽象接口提供的PHY寄存器访问操作,实现了MDIO的读操作,整个代码还是相当的简单。
static rt_size_t h3_mdioplib_read(void *bus, rt_uint32_t addr,rt_uint32_t reg, void *data, rt_uint32_t size)
{rt_uint16_t val;rt_uint32_t *data_ptr = (rt_uint32_t *)data;struct h3_macplib_dev *macplib_dev;struct rt_mdio_bus *mdioplib_bus = (struct rt_mdio_bus *)bus;RT_ASSERT(data != NULL);RT_ASSERT(bus != NULL);if (4 != size) {return 0;}macplib_dev = (struct h3_macplib_dev *)mdioplib_bus->hw_obj;macplib_dev->mac_ops->macdev_readphy(&macplib_dev->mac_dev,(rt_uint16_t)addr, (rt_uint16_t)reg,&val);/* Get data from MII register. */*data_ptr = (rt_uint32_t)val;return 4;
}
在mac驱动下另外一个需要注意的地方是,mac驱动需要提供一个类似mdio驱动查找接口,用于PHY设备在初始化的时候,查找需要的MDIO设备驱动接口,用来实现对PHY寄存器的访问,代码实现如下。
rt_mdio_t *h3_mdioplib_search(const char *name)
{rt_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];if (rt_strcmp(name, macplib_dev->rt_mdiobus.name) == 0){return &macplib_dev->rt_mdiobus;}}return NULL;
}
在PHY驱动中,对PHY设备的抽象定义时,增加了一个mdio_name的定义,用于定义该PHY设备对应的MDIO总线设备名,然后PHY设备可以通过该mdio_name名字,去查找到对应的MDIO总线设备。
struct h3_kszplib_dev
{const char *phy_name;uint32_t phy_addr;const char *mdio_name;struct rt_phy_device rt_phydev;
} ;
static rt_phy_status h3_ksz9plib_init(struct rt_phy_device *phy, void *object,rt_uint32_t phy_addr, rt_uint32_t src_clock_hz)
{rt_bool_t ret;rt_phy_status result = PHY_STATUS_FAIL;rt_uint32_t counter = PHY_TIMEOUT_COUNT;rt_uint32_t regval = 0;rt_uint32_t deviceID = 0;struct rt_mdio_bus *mdio_bus;struct h3_kszplib_dev *kszplib_dev;RT_ASSERT(phy != RT_NULL);kszplib_dev = rt_container_of(phy, struct h3_kszplib_dev, rt_phydev);mdio_bus = h3_mdioplib_search(kszplib_dev->mdio_name);RESULT_MATCH_CHECK(mdio_bus, RT_NULL, outs)kszplib_dev->phy_addr = phy_addr;phy->bus = mdio_bus;phy->addr = phy_addr;ret = mdio_bus->ops->init(mdio_bus, src_clock_hz);NOT_MATCH_CHECK(ret, RT_TRUE, outs)/* Initialization after PHY stars to work. */do{h3_kszplib_read(phy, GMII_PHYID1, &deviceID);counter--;} while ((deviceID != GMII_PHYID1_KSZ9131) && (counter != 0));RESULT_MATCH_CHECK(counter, 0, outs)result = h3_kszplib_read(phy, GMII_MCR, ®val);RESULT_MATCH_CHECK(result, PHY_STATUS_FAIL, outs)regval |= GMII_MCR_ANENABLE | GMII_MCR_ANRESTART;result = h3_kszplib_write(phy, GMII_MCR, regval);RESULT_MATCH_CHECK(result, PHY_STATUS_FAIL, outs)counter = PHY_TIMEOUT_COUNT;/* Check auto negotiation complete. */do{result = h3_kszplib_read(phy, GMII_MSR, ®val);RESULT_MATCH_CHECK(result, PHY_STATUS_FAIL, outs)if ((regval & GMII_MSR_ANEGCOMPLETE) != 0){break;}} while (--counter > 1);outs:return result;
}
MAC驱动与MDIO总线
在mac设备的抽象中,由于都包含了rt_mdio_bus,因此在mac设备实例的初始化的时候,都将mac设备与其提供的mdio总线进行绑定,例如在实例初始化时的静态绑定。
struct h3_macplib_dev
{const char *name;IRQn_Type irqnum;H3_MAC_REGS regs;rt_uint8_t mac_addr[6];rt_uint8_t dev_id;rt_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;
} ;
#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,.rt_mdiobus ={.name = MDIO0_DEVICE_NAME,.ops = &h3_mdiobus_ops,},.phy_dev ={.name = PHY0_DEVICE_NAME,.phyID1 = H3_MACPLIB_PHY0ID1,.phyID2 = H3_MACPLIB_PHY0ID2,.phyaddr = PHY0_DEVICE_ADDRESS,},.mac_ops = &h3_macdev_ops,
};
#endif
初始化时的绑定(仅展示部分相关代码)。
int h3_macplib_init(void)
{rt_err_t state;rt_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;}
}
到此为止,mac驱动接口、PHY驱动接口和MDIO驱动接口,设备的抽象、接口的实现以及彼此之间的关系讲解完成。
这篇关于在RT-Thread下为MPU手搓以太网MAC驱动-4的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!