简单梳理一下LS1012开发板的Uboot阶段网络初始化过程
在文件:
1
| OK10xx-linux-fs/flexbuild/packages/firmware/u-boot/include/net/pfe_eth/pfe_eth.h
|
首先定义了我们所需要的三个结构体:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| struct gemac_s { void *gemac_base; void *egpi_base;
/* GEMAC config */ int gemac_mode; int gemac_speed; int gemac_duplex; int flags; /* phy iface */ int phy_address; int phy_mode; struct mii_dev *bus;
};
struct pfe_mdio_info { void *reg_base; char *name; };
struct pfe_eth_dev { int gemac_port; struct gemac_s *gem; struct pfe_ddr_address pfe_addr; struct udevice *dev; #ifdef CONFIG_PHYLIB struct phy_device *phydev; #endif };
|
在文件:
1
| OK10xx-linux-fs/flexbuild/packages/firmware/u-boot/drivers/net/pfe_eth/pfe_eth.c
|
创建了两个gem_info结构体:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| struct gemac_s gem_info[] = { /* PORT_0 configuration */ { /* GEMAC config */ .gemac_speed = PFE_MAC_SPEED_1000M, .gemac_duplex = DUPLEX_FULL,
/* phy iface */ .phy_address = CONFIG_PFE_EMAC1_PHY_ADDR, .phy_mode = PHY_INTERFACE_MODE_SGMII, }, /* PORT_1 configuration */ { /* GEMAC config */ .gemac_speed = PFE_MAC_SPEED_1000M, .gemac_duplex = DUPLEX_FULL,
/* phy iface */ .phy_address = CONFIG_PFE_EMAC2_PHY_ADDR, .phy_mode = PHY_INTERFACE_MODE_SGMII, }, };
|
分别是两个mac的速率,全双工还是半双工,对应连接的PHY的地址和工作模式
之后在同文件下的pfe_eth_probe(struct udevice *dev)函数中有:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| static int pfe_eth_probe(struct udevice *dev) { struct pfe_eth_dev *priv = dev_get_priv(dev); struct pfe_ddr_address *pfe_addr; struct pfe_eth_pdata *pdata = dev_get_platdata(dev); ... priv->gemac_port = pdata->pfe_eth_pdata_mac.phy_interface; priv->gem = &gem_info[priv->gemac_port]; priv->dev = dev;
switch (priv->gemac_port) { case EMAC_PORT_0: default: priv->gem->gemac_base = EMAC1_BASE_ADDR; priv->gem->egpi_base = EGPI1_BASE_ADDR; break; case EMAC_PORT_1: priv->gem->gemac_base = EMAC2_BASE_ADDR; priv->gem->egpi_base = EGPI2_BASE_ADDR; break; }
ret = pfe_eth_board_init(dev); if (ret) return ret;
#if defined(CONFIG_PHYLIB) ret = pfe_phy_configure(priv, pdata->pfe_eth_pdata_mac.phy_interface, gem_info[priv->gemac_port].phy_address); #endif return ret; }
|
probe函数中,首先获得了pfe设备的私有属性:dev_get_priv(dev);,并放到了priv中。
其次获得了pfe设备的平台信息:dev_get_platdata(dev);,并放到了pdata中。
然后取出平台信息中的一部分信息填充私有属性priv结构体。
将gem_info填充进priv结构体的gem结构中,同时填充gem结构的其他属性,比如MAC的基地址信息等。
之后进行pfe设备的初始化操作,生成网络设备:**pfe_eth_board_init(dev);**
最后再调用**pfe_phy_configure**函数进行mac的配置。
关于pfe_eth_board_init函数,在文件
1
| OK10xx-linux-fs/flexbuild/packages/firmware/u-boot/board/freescale/ls1012ardb/eth.c
|
在函数pfe_eth_board_init(dev)中有
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| int pfe_eth_board_init(struct udevice *dev) { static int init_done; struct mii_dev *bus; struct pfe_mdio_info mac_mdio_info; struct pfe_eth_dev *priv = dev_get_priv(dev); struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
int srds_s1 = in_be32(&gur->rcwsr[4]) & FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK; srds_s1 >>= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT;
if (!init_done) { ls1012ardb_reset_phy(); mac_mdio_info.reg_base = (void *)EMAC1_BASE_ADDR; mac_mdio_info.name = DEFAULT_PFE_MDIO_NAME;
bus = pfe_mdio_init(&mac_mdio_info); if (!bus) { printf("Failed to register mdio\n"); return -1; } init_done = 1; }
if (priv->gemac_port) { mac_mdio_info.reg_base = (void *)EMAC2_BASE_ADDR; mac_mdio_info.name = DEFAULT_PFE_MDIO1_NAME; bus = pfe_mdio_init(&mac_mdio_info); if (!bus) { printf("Failed to register mdio\n"); return -1; } }
pfe_set_mdio(priv->gemac_port, miiphy_get_dev_by_name(DEFAULT_PFE_MDIO_NAME));
switch (srds_s1) { case 0x3305: if (!priv->gemac_port) { /* MAC1 */ pfe_set_phy_address_mode(priv->gemac_port, CONFIG_PFE_EMAC1_PHY_ADDR, PHY_INTERFACE_MODE_SGMII); } else { /* MAC2 */ pfe_set_phy_address_mode(priv->gemac_port, CONFIG_PFE_EMAC2_PHY_ADDR, PHY_INTERFACE_MODE_SGMII); } break; default: printf("unsupported SerDes PRCTL= %d\n", srds_s1); break; } return 0; }
|
此函数分别对两个mdio设备进行初始化,包括对mac_mdio_info结构体填充对应MAC的基地址和名称,并调用pfe_mdio_init进行初始化。
在文件
1
| OK10xx-linux-fs/flexbuild/packages/firmware/u-boot/drivers/net/pfe_eth/pfe_mdio.c
|
在函数*pfe_mdio_init(struct pfe_mdio_info *mdio_info)中有:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| struct mii_dev *pfe_mdio_init(struct pfe_mdio_info *mdio_info) { struct mii_dev *bus; int ret; u32 mdio_speed; u32 pclk = 250000000;
bus = mdio_alloc(); if (!bus) { printf("mdio_alloc failed\n"); return NULL; } bus->read = pfe_phy_read; bus->write = pfe_phy_write;
/* MAC1 MDIO used to communicate with external PHYS */ bus->priv = mdio_info->reg_base; sprintf(bus->name, mdio_info->name);
/* configure mdio speed */ mdio_speed = (DIV_ROUND_UP(pclk, 4000000) << EMAC_MII_SPEED_SHIFT); mdio_speed = EMAC_HOLDTIME(0x5); writel(mdio_speed, mdio_info->reg_base + EMAC_MII_CTRL_REG);
ret = mdio_register(bus); if (ret) { printf("mdio_register failed\n"); free(bus); return NULL; } return bus; }
|
此函数主要为对mdio的速率进行设置
关于pfe_phy_configure函数,在文件
1
| OK10xx-linux-fs/flexbuild/packages/firmware/u-boot/drivers/net/pfe_eth/pfe_mdio.c
|
在函数pfe_phy_configure(struct pfe_eth_dev *priv, int dev_id, int phy_id)中有:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| int pfe_phy_configure(struct pfe_eth_dev *priv, int dev_id, int phy_id) { struct phy_device *phydev = NULL; struct udevice *dev = priv->dev; struct gemac_s *gem = priv->gem; struct ccsr_scfg *scfg = (struct ccsr_scfg *)CONFIG_SYS_FSL_SCFG_ADDR;
if (!gem->bus) return -1;
/* Configure SGMII PCS */ if (gem->phy_mode == PHY_INTERFACE_MODE_SGMII gem->phy_mode == PHY_INTERFACE_MODE_SGMII_2500) { out_be32(&scfg->mdioselcr, 0x00000000); pfe_configure_serdes(priv); }
mdelay(100);
/* By this time on-chip SGMII initialization is done * we can switch mdio interface to external PHYs */ out_be32(&scfg->mdioselcr, 0x80000000);
phydev = phy_connect(gem->bus, phy_id, dev, gem->phy_mode); if (!phydev) { printf("phy_connect failed\n"); return -ENODEV; }
phy_config(phydev);
priv->phydev = phydev;
return 0; }
|
此函数主要负责通过两个MDIO接口对各个MDIO所连接的MAC进行【SGMII PCS】的配置,使之工作在SGMII模式下,然后在SGMII初始化成功之后,将MDIO配置为外部PHY连接模式。
补充:在ls1012中,有两个MDIO接口,其中MDIO1连接MAC1的 SGMII PCS和外部PHY,MDIO2连接MAC2的SGMII PCS