summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/cpsw.c157
-rw-r--r--drivers/net/mvneta.c2
-rw-r--r--drivers/net/phy/atheros.c53
-rw-r--r--drivers/net/phy/mv88e61xx.c61
-rw-r--r--drivers/net/rtl8169.c3
-rw-r--r--drivers/usb/eth/smsc95xx.c16
6 files changed, 273 insertions, 19 deletions
diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c
index d17505e088..d1f024e0eb 100644
--- a/drivers/net/cpsw.c
+++ b/drivers/net/cpsw.c
@@ -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))
@@ -1150,12 +1162,129 @@ static inline fdt_addr_t cpsw_get_addr_by_node(const void *fdt, int node)
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)
{
struct eth_pdata *pdata = dev_get_platdata(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 subnode;
@@ -1271,6 +1400,17 @@ static int cpsw_eth_ofdata_to_platdata(struct udevice *dev)
error("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) {
+ error("Not able to get gmii_sel compatible\n");
+ return -ENOENT;
+ }
}
}
@@ -1293,20 +1433,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;
}
diff --git a/drivers/net/mvneta.c b/drivers/net/mvneta.c
index 51bb569a92..00f378f082 100644
--- a/drivers/net/mvneta.c
+++ b/drivers/net/mvneta.c
@@ -1619,7 +1619,7 @@ static int mvneta_probe(struct udevice *dev)
/*
* Allocate buffer area for descs and rx_buffers. This is only
* done once for all interfaces. As only one interface can
- * be active. Make this area DMA save by disabling the D-cache
+ * be active. Make this area DMA safe by disabling the D-cache
*/
if (!buffer_loc.tx_descs) {
/* Align buffer area for descs and rx_buffers to 1MiB */
diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c
index e57c4120a3..b34cdd3d87 100644
--- a/drivers/net/phy/atheros.c
+++ b/drivers/net/phy/atheros.c
@@ -8,6 +8,15 @@
*/
#include <phy.h>
+#define AR803x_PHY_DEBUG_ADDR_REG 0x1d
+#define AR803x_PHY_DEBUG_DATA_REG 0x1e
+
+#define AR803x_DEBUG_REG_5 0x5
+#define AR803x_RGMII_TX_CLK_DLY 0x100
+
+#define AR803x_DEBUG_REG_0 0x0
+#define AR803x_RGMII_RX_CLK_DLY 0x8000
+
static int ar8021_config(struct phy_device *phydev)
{
phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05);
@@ -17,6 +26,32 @@ static int ar8021_config(struct phy_device *phydev)
return 0;
}
+static int ar8031_config(struct phy_device *phydev)
+{
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID ||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
+ phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_ADDR_REG,
+ AR803x_DEBUG_REG_5);
+ phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_DATA_REG,
+ AR803x_RGMII_TX_CLK_DLY);
+ }
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID ||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
+ phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_ADDR_REG,
+ AR803x_DEBUG_REG_0);
+ phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_DATA_REG,
+ AR803x_RGMII_RX_CLK_DLY);
+ }
+
+ phydev->supported = phydev->drv->features;
+
+ genphy_config_aneg(phydev);
+ genphy_restart_aneg(phydev);
+
+ return 0;
+}
+
static int ar8035_config(struct phy_device *phydev)
{
int regval;
@@ -31,6 +66,22 @@ static int ar8035_config(struct phy_device *phydev)
regval = phy_read(phydev, MDIO_DEVAD_NONE, 0x1e);
phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, (regval|0x0100));
+ if ((phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) ||
+ (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) {
+ /* select debug reg 5 */
+ phy_write(phydev, MDIO_DEVAD_NONE, 0x1D, 0x5);
+ /* enable tx delay */
+ phy_write(phydev, MDIO_DEVAD_NONE, 0x1E, 0x0100);
+ }
+
+ if ((phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) ||
+ (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)) {
+ /* select debug reg 0 */
+ phy_write(phydev, MDIO_DEVAD_NONE, 0x1D, 0x0);
+ /* enable rx delay */
+ phy_write(phydev, MDIO_DEVAD_NONE, 0x1E, 0x8000);
+ }
+
phydev->supported = phydev->drv->features;
genphy_config_aneg(phydev);
@@ -54,7 +105,7 @@ static struct phy_driver AR8031_driver = {
.uid = 0x4dd074,
.mask = 0xffffffef,
.features = PHY_GBIT_FEATURES,
- .config = ar8035_config,
+ .config = ar8031_config,
.startup = genphy_startup,
.shutdown = genphy_shutdown,
};
diff --git a/drivers/net/phy/mv88e61xx.c b/drivers/net/phy/mv88e61xx.c
index 74d56098b5..a2fd1686fc 100644
--- a/drivers/net/phy/mv88e61xx.c
+++ b/drivers/net/phy/mv88e61xx.c
@@ -40,7 +40,7 @@
#define PHY_AUTONEGOTIATE_TIMEOUT 5000
-#define PORT_COUNT 7
+#define PORT_COUNT 11
#define PORT_MASK ((1 << PORT_COUNT) - 1)
/* Device addresses */
@@ -103,8 +103,16 @@
#define PORT_REG_STATUS_CMODE_1000BASE_X 0x9
#define PORT_REG_STATUS_CMODE_SGMII 0xa
+#define PORT_REG_PHYS_CTRL_PCS_AN_EN BIT(10)
+#define PORT_REG_PHYS_CTRL_PCS_AN_RST BIT(9)
+#define PORT_REG_PHYS_CTRL_FC_VALUE BIT(7)
+#define PORT_REG_PHYS_CTRL_FC_FORCE BIT(6)
#define PORT_REG_PHYS_CTRL_LINK_VALUE BIT(5)
#define PORT_REG_PHYS_CTRL_LINK_FORCE BIT(4)
+#define PORT_REG_PHYS_CTRL_DUPLEX_VALUE BIT(3)
+#define PORT_REG_PHYS_CTRL_DUPLEX_FORCE BIT(2)
+#define PORT_REG_PHYS_CTRL_SPD1000 BIT(1)
+#define PORT_REG_PHYS_CTRL_SPD_MASK (BIT(1) | BIT(0))
#define PORT_REG_CTRL_PSTATE_SHIFT 0
#define PORT_REG_CTRL_PSTATE_WIDTH 2
@@ -166,7 +174,17 @@
#error Define CONFIG_MV88E61XX_CPU_PORT to the port the CPU is attached to
#endif
+/*
+ * These are ports without PHYs that may be wired directly
+ * to other serdes interfaces
+ */
+#ifndef CONFIG_MV88E61XX_FIXED_PORTS
+#define CONFIG_MV88E61XX_FIXED_PORTS 0
+#endif
+
/* ID register values for different switch models */
+#define PORT_SWITCH_ID_6096 0x0980
+#define PORT_SWITCH_ID_6097 0x0990
#define PORT_SWITCH_ID_6172 0x1720
#define PORT_SWITCH_ID_6176 0x1760
#define PORT_SWITCH_ID_6240 0x2400
@@ -580,7 +598,7 @@ static int mv88e61xx_port_enable(struct phy_device *phydev, u8 port)
}
static int mv88e61xx_port_set_vlan(struct phy_device *phydev, u8 port,
- u8 mask)
+ u16 mask)
{
int val;
@@ -791,6 +809,27 @@ static int mv88e61xx_phy_setup(struct phy_device *phydev, u8 phy)
return 0;
}
+static int mv88e61xx_fixed_port_setup(struct phy_device *phydev, u8 port)
+{
+ int val;
+
+ val = mv88e61xx_port_read(phydev, port, PORT_REG_PHYS_CTRL);
+ if (val < 0)
+ return val;
+
+ val &= ~(PORT_REG_PHYS_CTRL_SPD_MASK |
+ PORT_REG_PHYS_CTRL_FC_VALUE);
+ val |= PORT_REG_PHYS_CTRL_PCS_AN_EN |
+ PORT_REG_PHYS_CTRL_PCS_AN_RST |
+ PORT_REG_PHYS_CTRL_FC_FORCE |
+ PORT_REG_PHYS_CTRL_DUPLEX_VALUE |
+ PORT_REG_PHYS_CTRL_DUPLEX_FORCE |
+ PORT_REG_PHYS_CTRL_SPD1000;
+
+ return mv88e61xx_port_write(phydev, port, PORT_REG_PHYS_CTRL,
+ val);
+}
+
static int mv88e61xx_phy_config_port(struct phy_device *phydev, u8 phy)
{
int val;
@@ -909,6 +948,12 @@ static int mv88e61xx_phy_config(struct phy_device *phydev)
/* Return success if any PHY succeeds */
ret = 0;
+ } else if ((1 << i) & CONFIG_MV88E61XX_FIXED_PORTS) {
+ res = mv88e61xx_fixed_port_setup(phydev, i);
+ if (res < 0) {
+ printf("Error configuring port %i\n", i);
+ continue;
+ }
}
}
@@ -974,9 +1019,21 @@ static struct phy_driver mv88e61xx_driver = {
.shutdown = &genphy_shutdown,
};
+static struct phy_driver mv88e609x_driver = {
+ .name = "Marvell MV88E609x",
+ .uid = 0x1410c89,
+ .mask = 0xfffffff0,
+ .features = PHY_GBIT_FEATURES,
+ .probe = mv88e61xx_probe,
+ .config = mv88e61xx_phy_config,
+ .startup = mv88e61xx_phy_startup,
+ .shutdown = &genphy_shutdown,
+};
+
int phy_mv88e61xx_init(void)
{
phy_register(&mv88e61xx_driver);
+ phy_register(&mv88e609x_driver);
return 0;
}
diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c
index 1cc0b40935..a3f4423a20 100644
--- a/drivers/net/rtl8169.c
+++ b/drivers/net/rtl8169.c
@@ -629,11 +629,12 @@ static int rtl_send_common(pci_dev_t dev, unsigned long dev_iobase,
/* point to the current txb incase multiple tx_rings are used */
ptxb = tpc->Tx_skbuff[entry * MAX_ETH_FRAME_SIZE];
memcpy(ptxb, (char *)packet, (int)length);
- rtl_flush_buffer(ptxb, length);
while (len < ETH_ZLEN)
ptxb[len++] = '\0';
+ rtl_flush_buffer(ptxb, ALIGN(len, RTL8169_ALIGN));
+
tpc->TxDescArray[entry].buf_Haddr = 0;
#ifdef CONFIG_DM_ETH
tpc->TxDescArray[entry].buf_addr = cpu_to_le32(
diff --git a/drivers/usb/eth/smsc95xx.c b/drivers/usb/eth/smsc95xx.c
index 7d9abfda3b..d4c8ea4a98 100644
--- a/drivers/usb/eth/smsc95xx.c
+++ b/drivers/usb/eth/smsc95xx.c
@@ -519,9 +519,11 @@ static int smsc95xx_init_common(struct usb_device *udev, struct ueth_data *dev,
debug("timeout waiting for PHY Reset\n");
return -ETIMEDOUT;
}
+#ifndef CONFIG_DM_ETH
if (!priv->have_hwaddr && smsc95xx_init_mac_address(enetaddr, udev) ==
0)
priv->have_hwaddr = 1;
+#endif
if (!priv->have_hwaddr) {
puts("Error: SMSC95xx: No MAC address set - set usbethaddr\n");
return -EADDRNOTAVAIL;
@@ -1022,6 +1024,19 @@ int smsc95xx_write_hwaddr(struct udevice *dev)
return smsc95xx_write_hwaddr_common(udev, priv, pdata->enetaddr);
}
+int smsc95xx_read_rom_hwaddr(struct udevice *dev)
+{
+ struct usb_device *udev = dev_get_parent_priv(dev);
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+ int ret;
+
+ ret = smsc95xx_init_mac_address(pdata->enetaddr, udev);
+ if (ret)
+ memset(pdata->enetaddr, 0, 6);
+
+ return 0;
+}
+
static int smsc95xx_eth_probe(struct udevice *dev)
{
struct smsc95xx_private *priv = dev_get_priv(dev);
@@ -1037,6 +1052,7 @@ static const struct eth_ops smsc95xx_eth_ops = {
.free_pkt = smsc95xx_free_pkt,
.stop = smsc95xx_eth_stop,
.write_hwaddr = smsc95xx_write_hwaddr,
+ .read_rom_hwaddr = smsc95xx_read_rom_hwaddr,
};
U_BOOT_DRIVER(smsc95xx_eth) = {