U-boot phy驱动开发总结
生活随笔
收集整理的這篇文章主要介紹了
U-boot phy驱动开发总结
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 基礎
- 須知
- 數據結構
- 數據結構UML類圖
- PHY核心 API
- 初始化
- 支持uclass
- 支持legacy
- 總結
基礎
須知
數據結構
- MAC設備,struct eth_device *dev;
- MDIO總線,struct mii_dev *bus;
- PHY設備,struct phy_device *dev;
- phy驅動
- MAC實例私有數據,struct eqos_priv
- PHY實例私有數據,struct ip18xx_phy_priv
數據結構UML類圖
PHY核心 API
core: phy.c u-boot\drivers\net\phy\phy.c
struct phy_device *phy_connect(struct mii_dev *bus, int addr, struct eth_device *dev, phy_interface_t interface)
int phy_config(struct phy_device *phydev)
int phy_startup(struct phy_device *phydev)
int phy_shutdown(struct phy_device *phydev)
初始化
支持uclass
總線:
1、程序段:.u_boot_list_2_driver_2_eth_eqos中先定義結構體:struct driver u_boot_list_2_driver_2_eth_eqos
支持legacy
非通用驅動,走uboot初始化流程 X:\source_code\Nt9852x\workspace_sourceInsight\u-boot\drivers\net\eth_na51055.cinit_sequence_r // u-boot\common\board_r.cinitr_neteth_initialize();if (board_eth_init != __def_eth_init) {board_eth_init(gd->bd)c // #1 弱符號,板級實現,所以在 board\novatek\nvt-na51055\na51055evb.cna51055_eth_initialize(bis); // u-boot\board\novatek\nvt-na51055\na51055evb.cstruct eth_device *dev;eth_parse_phy_intf(); // DTS中 MII 數據總線分析(接口類型與時鐘)dev = malloc(sizeof *dev);sprintf(dev->name, "eth_na51055"); // 網卡設備,初始化,dev->init = eqos_start; // #2 初始化實現 eth_register(dev); // 網卡設備添加到鏈表,eth_devices->nexteqos = malloc(sizeof *eqos); // 直接申請eqos私有數據需要的內存;dev->priv = eqos; // #4 網卡驅動私有數據關聯eqoseqos->dev = dev;eqos_probe_resources_core(dev);eqos_probe_hwinit();eqos->mii = mdio_alloc(); // #3 eqos關聯miieqos->mii->read = eqos_mdio_read;eqos->mii->write = eqos_mdio_write;eqos->mii->priv = eqos; // #5 mdio總線關聯私有數據eqosstrcpy(eqos->mii->name, dev->name);mdio_register(eqos->mii); // memcpy(dev->enetaddr, default_mac_addr, 6); // MAC地址設置 for (i = 0; i < 32; i++) { // *1 探測物理MDIO總線上的PHY設備,第一個被探測到的設備被視為目標連接設備phyval = eqos_mdio_read(eqos->mii, i, 0, MII_BMSR);if (phyval != 0x0000 && phyval != 0xffff) {phyaddr = i; eqos->phyaddr = phyaddr; // *2 記錄phyaddr,在init階段視為連接的目標*1、*2 : NT的邏輯,phyaddr靠前的PHY優先被視為目標連接的phy,在dev->init = eqos_start階段就以此為目標連接的PHY#4 :網卡驅動eth_device私有數據關聯eqos #5 : mdio總線關聯私有數據eqosstatic int eqos_start(struct udevice *dev)struct eqos_priv *eqos = dev_get_priv(dev);eqos->phy = phy_connect(eqos->mii, eqos->phyaddr, eth_dev, 0); // #12 連接PHY,根據phyaddr,先確認是否已實例,如果沒有則創建。關聯phystruct phy_device *phydev = NULL;uint mask = (addr > 0) ? (1 << addr) : 0xffffffff; // #2 如果沒有指定phyaddr,遍歷32個phyphydev = phy_find_by_mask(bus, mask, interface); // 以mask查找物理mdio總線上匹配的phy設備并實例化get_phy_device_by_mask(bus, phy_mask, interface);phydev = search_for_existing_phy(bus, phy_mask, interface); // 查找bus->phymap[addr]中已經記錄的phy設備,如果在在直接返回;if (phydev) return phydev;phydev = create_phy_by_mask(bus, phy_mask, i ? i : MDIO_DEVAD_NONE, interface);u32 phy_id = 0xffffffff;while (phy_mask) { // #3 從高地址到低地址,探測phy_mask下所有phy,第一個被探測到的設備被視為目標連接設備int addr = ffs(phy_mask) - 1; int r = get_phy_id(bus, addr, devad, &phy_id); // *6 弱符號, 讀取通用PHY的ID寄存器:MII_PHYSID1(0x02)、MII_PHYSID2(0x03)if (r == 0 && (phy_id & 0x1fffffff) != 0x1fffffff) {return phy_device_create(bus, addr, phy_id, is_c45, interface);dev = malloc(sizeof(*dev));dev->phy_id = phy_id;。。。 // dev->... 其他參數初始化dev->drv = get_phy_driver(dev, interface);list_for_each(entry, &phy_drivers) {drv = list_entry(entry, struct phy_driver, list);if ((drv->uid & drv->mask) == (phy_id & drv->mask)) // #1 匹配規則:驅動與實際的uid & mask相匹配return drv;return generic_for_interface(interface); // #2 如果沒有匹配的PHY驅動則使用genphy_driver,即通用PHY驅動phy_probe(dev); // *1 probe匹配,此處沒有返回值檢查,如果probe失敗,仍會繼續if (phydev->drv->probe)err = phydev->drv->probe(phydev); // #3 如果驅動有自己的probe實現,則調用 phy_mask &= ~(1 << addr);phy_connect_dev(phydev, dev);phy_reset(phydev); // #4 使用通用PHY 控制寄存器軟件復位,對于switch需要額外復位時間if (phydev->flags & PHY_FLAG_BROKEN_RESET) return 0;#ifdef CONFIG_PHY_RESET_DELAYudelay(CONFIG_PHY_RESET_DELAY); /* Intel LXT971A needs this */phydev->dev = dev; // #11 將eth與phydev關聯return phydev;ret = phy_config(eqos->phy);board_phy_config(phydev); // #5 弱符號,PHY相關配置,所以IP18xx中需要實現configif (phydev->drv->config)return phydev->drv->config(phydev); // #7, 驅動自實現ret = phy_startup(eqos->phy);if (phydev->drv->startup)return phydev->drv->startup(phydev); // #8, 驅動自實現ret = eqos_adjust_link(dev);if (eqos->phy->duplex)ret = eqos_set_full_duplex(dev); // #9, RGMII全雙工switch (eqos->phy->speed) {case SPEED_1000: // #10, 千兆PHY,RGMII配置en_calibration = true;ret = eqos_set_gmii_speed(dev);case 。。。 // 其他速率配置。。。#5、6 :弱符號,盡量不要實現,否則對其他PHY驅動匹配干擾 static struct phy_driver ip18xx_driver = {.name = "IP18xx",.uid = 0x00,.mask = 0xffffffff,.features = PHY_GBIT_FEATURES,.probe = ip18xx_probe,.config = ip18xx_phy_config,.startup = ip18xx_phy_startup, };#1 :驅動與實際的uid & mask相匹配 #9、10 :RGMII總線相關配置,注意不要與電口上的速率等配置信息混淆*1 :目前發現的uboot下phy.c 核心的問題:probe失敗不終止初始化流程 *6 :get_phy_id,弱符號,讀取通用PHY的ID寄存器:MII_PHYSID1(0x02)、MII_PHYSID2(0x03),問題:不合理重實現后,會對內置PHY、其他switch造成干擾#2 :Nt邏輯,指定目標phy設備的addr去連接phy。如果沒有指定phyaddr,從高地址探測32個phyaddr,連接每第一個探測到的PHY并匹配驅動。 #3 : 與na51055_eth_initialize中探測phy的方式相向而行,目標只有一個,兩者最終都指向phyaddr; #4 :復位PHY,對于switch可以設置phydev->flags & PHY_FLAG_BROKEN_RESET,表示不支持軟件復位#11 : phy設備phydev關聯eth_device設備dev #12 :私有數據eqos關聯phydev總結
總結
以上是生活随笔為你收集整理的U-boot phy驱动开发总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BZOJ K大数查询(分治)(Zjoi2
- 下一篇: WCF X.509验证