X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fnet%2Fcpsw.c;h=e2395dbeb9ccc4a9715ed91b8525491a8edbc365;hb=ebca902aeb3af3eaedd2787928184ad84a86b98f;hp=774b021e356e430251a26d1a068b45608869a7d1;hpb=2e205ef7eb9e7793e922d0b6cd0fe4181309c058;p=u-boot diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c index 774b021e35..e2395dbeb9 100644 --- a/drivers/net/cpsw.c +++ b/drivers/net/cpsw.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include @@ -225,6 +225,18 @@ struct cpdma_chan { void *hdp, *cp, *rxfree; }; +/* AM33xx SoC specific definitions for the CONTROL port */ +#define AM33XX_GMII_SEL_MODE_MII 0 +#define AM33XX_GMII_SEL_MODE_RMII 1 +#define AM33XX_GMII_SEL_MODE_RGMII 2 + +#define AM33XX_GMII_SEL_RGMII1_IDMODE BIT(4) +#define AM33XX_GMII_SEL_RGMII2_IDMODE BIT(5) +#define AM33XX_GMII_SEL_RMII1_IO_CLK_EN BIT(6) +#define AM33XX_GMII_SEL_RMII2_IO_CLK_EN BIT(7) + +#define GMII_SEL_MODE_MASK 0x3 + #define desc_write(desc, fld, val) __raw_writel((u32)(val), &(desc)->fld) #define desc_read(desc, fld) __raw_readl(&(desc)->fld) #define desc_read_ptr(desc, fld) ((void *)__raw_readl(&(desc)->fld)) @@ -600,21 +612,25 @@ static void cpsw_set_slave_mac(struct cpsw_slave *slave, #endif } -static void cpsw_slave_update_link(struct cpsw_slave *slave, +static int cpsw_slave_update_link(struct cpsw_slave *slave, struct cpsw_priv *priv, int *link) { struct phy_device *phy; u32 mac_control = 0; + int ret = -ENODEV; phy = priv->phydev; - if (!phy) - return; + goto out; - phy_startup(phy); - *link = phy->link; + ret = phy_startup(phy); + if (ret) + goto out; - if (*link) { /* link up */ + if (link) + *link = phy->link; + + if (phy->link) { /* link up */ mac_control = priv->data.mac_control; if (phy->speed == 1000) mac_control |= GIGABITEN; @@ -625,7 +641,7 @@ static void cpsw_slave_update_link(struct cpsw_slave *slave, } if (mac_control == slave->mac_control) - return; + goto out; if (mac_control) { printf("link up on port %d, speed %d, %s duplex\n", @@ -637,17 +653,20 @@ static void cpsw_slave_update_link(struct cpsw_slave *slave, __raw_writel(mac_control, &slave->sliver->mac_control); slave->mac_control = mac_control; + +out: + return ret; } static int cpsw_update_link(struct cpsw_priv *priv) { - int link = 0; + int ret = -ENODEV; struct cpsw_slave *slave; for_active_slave(slave, priv) - cpsw_slave_update_link(slave, priv, &link); + ret = cpsw_slave_update_link(slave, priv, NULL); - return link; + return ret; } static inline u32 cpsw_get_slave_port(struct cpsw_priv *priv, u32 slave_num) @@ -810,7 +829,9 @@ static int _cpsw_init(struct cpsw_priv *priv, u8 *enetaddr) for_active_slave(slave, priv) cpsw_slave_init(slave, priv); - cpsw_update_link(priv); + ret = cpsw_update_link(priv); + if (ret) + goto out; /* init descriptor pool */ for (i = 0; i < NUM_DESCS; i++) { @@ -885,7 +906,8 @@ static int _cpsw_init(struct cpsw_priv *priv, u8 *enetaddr) } } - return 0; +out: + return ret; } static void _cpsw_halt(struct cpsw_priv *priv) @@ -908,7 +930,7 @@ static int _cpsw_send(struct cpsw_priv *priv, void *packet, int length) int timeout = CPDMA_TIMEOUT; flush_dcache_range((unsigned long)packet, - (unsigned long)packet + length); + (unsigned long)packet + ALIGN(length, PKTALIGN)); /* first reap completed packets */ while (timeout-- && @@ -927,7 +949,7 @@ static int _cpsw_recv(struct cpsw_priv *priv, uchar **pkt) { void *buffer; int len; - int ret = -EAGAIN; + int ret; ret = cpdma_process(priv, &priv->rx_chan, &buffer, &len); if (ret < 0) @@ -969,7 +991,7 @@ static int cpsw_phy_init(struct cpsw_priv *priv, struct cpsw_slave *slave) #ifdef CONFIG_DM_ETH if (slave->data->phy_of_handle) - phydev->dev->of_offset = slave->data->phy_of_handle; + dev_set_of_offset(phydev->dev, slave->data->phy_of_handle); #endif priv->phydev = phydev; @@ -1146,7 +1168,124 @@ static const struct eth_ops cpsw_eth_ops = { static inline fdt_addr_t cpsw_get_addr_by_node(const void *fdt, int node) { - return fdtdec_get_addr_size_auto_noparent(fdt, node, "reg", 0, NULL); + return fdtdec_get_addr_size_auto_noparent(fdt, node, "reg", 0, NULL, + false); +} + +static void cpsw_gmii_sel_am3352(struct cpsw_priv *priv, + phy_interface_t phy_mode) +{ + u32 reg; + u32 mask; + u32 mode = 0; + bool rgmii_id = false; + int slave = priv->data.active_slave; + + reg = readl(priv->data.gmii_sel); + + switch (phy_mode) { + case PHY_INTERFACE_MODE_RMII: + mode = AM33XX_GMII_SEL_MODE_RMII; + break; + + case PHY_INTERFACE_MODE_RGMII: + mode = AM33XX_GMII_SEL_MODE_RGMII; + break; + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + mode = AM33XX_GMII_SEL_MODE_RGMII; + rgmii_id = true; + break; + + case PHY_INTERFACE_MODE_MII: + default: + mode = AM33XX_GMII_SEL_MODE_MII; + break; + }; + + mask = GMII_SEL_MODE_MASK << (slave * 2) | BIT(slave + 6); + mode <<= slave * 2; + + if (priv->data.rmii_clock_external) { + if (slave == 0) + mode |= AM33XX_GMII_SEL_RMII1_IO_CLK_EN; + else + mode |= AM33XX_GMII_SEL_RMII2_IO_CLK_EN; + } + + if (rgmii_id) { + if (slave == 0) + mode |= AM33XX_GMII_SEL_RGMII1_IDMODE; + else + mode |= AM33XX_GMII_SEL_RGMII2_IDMODE; + } + + reg &= ~mask; + reg |= mode; + + writel(reg, priv->data.gmii_sel); +} + +static void cpsw_gmii_sel_dra7xx(struct cpsw_priv *priv, + phy_interface_t phy_mode) +{ + u32 reg; + u32 mask; + u32 mode = 0; + int slave = priv->data.active_slave; + + reg = readl(priv->data.gmii_sel); + + switch (phy_mode) { + case PHY_INTERFACE_MODE_RMII: + mode = AM33XX_GMII_SEL_MODE_RMII; + break; + + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + mode = AM33XX_GMII_SEL_MODE_RGMII; + break; + + case PHY_INTERFACE_MODE_MII: + default: + mode = AM33XX_GMII_SEL_MODE_MII; + break; + }; + + switch (slave) { + case 0: + mask = GMII_SEL_MODE_MASK; + break; + case 1: + mask = GMII_SEL_MODE_MASK << 4; + mode <<= 4; + break; + default: + dev_err(priv->dev, "invalid slave number...\n"); + return; + } + + if (priv->data.rmii_clock_external) + dev_err(priv->dev, "RMII External clock is not supported\n"); + + reg &= ~mask; + reg |= mode; + + writel(reg, priv->data.gmii_sel); +} + +static void cpsw_phy_sel(struct cpsw_priv *priv, const char *compat, + phy_interface_t phy_mode) +{ + if (!strcmp(compat, "ti,am3352-cpsw-phy-sel")) + cpsw_gmii_sel_am3352(priv, phy_mode); + if (!strcmp(compat, "ti,am43xx-cpsw-phy-sel")) + cpsw_gmii_sel_am3352(priv, phy_mode); + else if (!strcmp(compat, "ti,dra7xx-cpsw-phy-sel")) + cpsw_gmii_sel_dra7xx(priv, phy_mode); } static int cpsw_eth_ofdata_to_platdata(struct udevice *dev) @@ -1155,15 +1294,16 @@ static int cpsw_eth_ofdata_to_platdata(struct udevice *dev) struct cpsw_priv *priv = dev_get_priv(dev); struct gpio_desc *mode_gpios; const char *phy_mode; + const char *phy_sel_compat = NULL; const void *fdt = gd->fdt_blob; - int node = dev->of_offset; + int node = dev_of_offset(dev); int subnode; int slave_index = 0; int active_slave; int num_mode_gpios; int ret; - pdata->iobase = dev_get_addr(dev); + pdata->iobase = devfdt_get_addr(dev); priv->data.version = CPSW_CTRL_VERSION_2; priv->data.bd_ram_ofs = CPSW_BD_OFFSET; priv->data.ale_reg_ofs = CPSW_ALE_OFFSET; @@ -1218,7 +1358,7 @@ static int cpsw_eth_ofdata_to_platdata(struct udevice *dev) active_slave = fdtdec_get_int(fdt, node, "active_slave", 0); priv->data.active_slave = active_slave; - fdt_for_each_subnode(fdt, subnode, node) { + fdt_for_each_subnode(subnode, fdt, node) { int len; const char *name; @@ -1228,7 +1368,7 @@ static int cpsw_eth_ofdata_to_platdata(struct udevice *dev) mdio_base = cpsw_get_addr_by_node(fdt, subnode); if (mdio_base == FDT_ADDR_T_NONE) { - error("Not able to get MDIO address space\n"); + pr_err("Not able to get MDIO address space\n"); return -ENOENT; } priv->data.mdio_base = mdio_base; @@ -1267,7 +1407,18 @@ static int cpsw_eth_ofdata_to_platdata(struct udevice *dev) subnode); if (priv->data.gmii_sel == FDT_ADDR_T_NONE) { - error("Not able to get gmii_sel reg address\n"); + pr_err("Not able to get gmii_sel reg address\n"); + return -ENOENT; + } + + if (fdt_get_property(fdt, subnode, "rmii-clock-ext", + NULL)) + priv->data.rmii_clock_external = true; + + phy_sel_compat = fdt_getprop(fdt, subnode, "compatible", + NULL); + if (!phy_sel_compat) { + pr_err("Not able to get gmii_sel compatible\n"); return -ENOENT; } } @@ -1283,7 +1434,7 @@ static int cpsw_eth_ofdata_to_platdata(struct udevice *dev) ret = ti_cm_get_macid(dev, active_slave, pdata->enetaddr); if (ret < 0) { - error("cpsw read efuse mac failed\n"); + pr_err("cpsw read efuse mac failed\n"); return ret; } @@ -1292,20 +1443,9 @@ static int cpsw_eth_ofdata_to_platdata(struct udevice *dev) debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode); return -EINVAL; } - switch (pdata->phy_interface) { - case PHY_INTERFACE_MODE_MII: - writel(MII_MODE_ENABLE, priv->data.gmii_sel); - break; - case PHY_INTERFACE_MODE_RMII: - writel(RMII_MODE_ENABLE, priv->data.gmii_sel); - break; - case PHY_INTERFACE_MODE_RGMII: - case PHY_INTERFACE_MODE_RGMII_ID: - case PHY_INTERFACE_MODE_RGMII_RXID: - case PHY_INTERFACE_MODE_RGMII_TXID: - writel(RGMII_MODE_ENABLE, priv->data.gmii_sel); - break; - } + + /* Select phy interface in control module */ + cpsw_phy_sel(priv, phy_sel_compat, pdata->phy_interface); return 0; }