summaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2016-01-28 18:42:10 -0500
committerTom Rini <trini@konsulko.com>2016-01-28 18:42:10 -0500
commit82d72a1b9967cff4908f22c57536c3660f794401 (patch)
treeed7f02df10ffa0f7c4ef87298c1c5e5f4be5dd45 /drivers/net
parent3faf2216d9649e2a22e6728194e9797cb46db933 (diff)
parentb2b7fbc33ff1b990804e481153dd45de579cff75 (diff)
downloadblackbird-obmc-uboot-82d72a1b9967cff4908f22c57536c3660f794401.tar.gz
blackbird-obmc-uboot-82d72a1b9967cff4908f22c57536c3660f794401.zip
Merge branch 'master' of git://git.denx.de/u-boot-net
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/designware.c16
-rw-r--r--drivers/net/designware.h1
-rw-r--r--drivers/net/fsl_mdio.c4
-rw-r--r--drivers/net/phy/cortina.c7
-rw-r--r--drivers/net/phy/micrel.c25
-rw-r--r--drivers/net/phy/phy.c102
-rw-r--r--drivers/net/tsec.c536
-rw-r--r--drivers/net/vsc9953.c354
8 files changed, 832 insertions, 213 deletions
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 68b6548309..77b98c94c0 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -196,6 +196,8 @@ static void dw_adjust_link(struct eth_mac_regs *mac_p,
if (phydev->speed != 1000)
conf |= MII_PORTSELECT;
+ else
+ conf &= ~MII_PORTSELECT;
if (phydev->speed == 100)
conf |= FES_100;
@@ -404,7 +406,7 @@ static int _dw_free_pkt(struct dw_eth_dev *priv)
static int dw_phy_init(struct dw_eth_dev *priv, void *dev)
{
struct phy_device *phydev;
- int mask = 0xffffffff;
+ int mask = 0xffffffff, ret;
#ifdef CONFIG_PHY_ADDR
mask = 1 << CONFIG_PHY_ADDR;
@@ -417,6 +419,11 @@ static int dw_phy_init(struct dw_eth_dev *priv, void *dev)
phy_connect_dev(phydev, dev);
phydev->supported &= PHY_GBIT_FEATURES;
+ if (priv->max_speed) {
+ ret = phy_set_supported(phydev, priv->max_speed);
+ if (ret)
+ return ret;
+ }
phydev->advertising = phydev->supported;
priv->phydev = phydev;
@@ -599,6 +606,7 @@ static int designware_eth_probe(struct udevice *dev)
priv->mac_regs_p = (struct eth_mac_regs *)iobase;
priv->dma_regs_p = (struct eth_dma_regs *)(iobase + DW_DMA_BASE_OFFSET);
priv->interface = pdata->phy_interface;
+ priv->max_speed = pdata->max_speed;
dw_mdio_init(dev->name, priv->mac_regs_p);
priv->bus = miiphy_get_dev_by_name(dev->name);
@@ -633,6 +641,7 @@ static int designware_eth_ofdata_to_platdata(struct udevice *dev)
{
struct eth_pdata *pdata = dev_get_platdata(dev);
const char *phy_mode;
+ const fdt32_t *cell;
pdata->iobase = dev_get_addr(dev);
pdata->phy_interface = -1;
@@ -644,6 +653,11 @@ static int designware_eth_ofdata_to_platdata(struct udevice *dev)
return -EINVAL;
}
+ pdata->max_speed = 0;
+ cell = fdt_getprop(gd->fdt_blob, dev->of_offset, "max-speed", NULL);
+ if (cell)
+ pdata->max_speed = fdt32_to_cpu(*cell);
+
return 0;
}
diff --git a/drivers/net/designware.h b/drivers/net/designware.h
index 4b9ec39cc8..ed6344cc28 100644
--- a/drivers/net/designware.h
+++ b/drivers/net/designware.h
@@ -223,6 +223,7 @@ struct dw_eth_dev {
char rxbuffs[RX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN);
u32 interface;
+ u32 max_speed;
u32 tx_currdescnum;
u32 rx_currdescnum;
diff --git a/drivers/net/fsl_mdio.c b/drivers/net/fsl_mdio.c
index f48bbc3123..77b9739a24 100644
--- a/drivers/net/fsl_mdio.c
+++ b/drivers/net/fsl_mdio.c
@@ -5,6 +5,7 @@
*
* SPDX-License-Identifier: GPL-2.0+
*/
+
#include <common.h>
#include <miiphy.h>
#include <phy.h>
@@ -32,8 +33,7 @@ int tsec_local_mdio_read(struct tsec_mii_mng __iomem *phyregs, int port_addr,
int value;
int timeout = 1000000;
- /* Put the address of the phy, and the register
- * number into MIIMADD */
+ /* Put the address of the phy, and the register number into MIIMADD */
out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f));
/* Clear the command register, and wait */
diff --git a/drivers/net/phy/cortina.c b/drivers/net/phy/cortina.c
index 447ecfbeb6..f975fd8209 100644
--- a/drivers/net/phy/cortina.c
+++ b/drivers/net/phy/cortina.c
@@ -257,6 +257,12 @@ int cs4340_config(struct phy_device *phydev)
return 0;
}
+int cs4340_probe(struct phy_device *phydev)
+{
+ phydev->flags = PHY_FLAG_BROKEN_RESET;
+ return 0;
+}
+
int cs4340_startup(struct phy_device *phydev)
{
phydev->link = 1;
@@ -276,6 +282,7 @@ struct phy_driver cs4340_driver = {
MDIO_DEVS_PHYXS | MDIO_DEVS_AN |
MDIO_DEVS_VEND1 | MDIO_DEVS_VEND2),
.config = &cs4340_config,
+ .probe = &cs4340_probe,
.startup = &cs4340_startup,
.shutdown = &gen10g_shutdown,
};
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index 19b6bc7472..c3da1606dc 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -27,12 +27,31 @@ static struct phy_driver KSZ804_driver = {
.shutdown = &genphy_shutdown,
};
+#define MII_KSZPHY_OMSO 0x16
+#define KSZPHY_OMSO_B_CAST_OFF (1 << 9)
+
+static int ksz_genconfig_bcastoff(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO,
+ ret | KSZPHY_OMSO_B_CAST_OFF);
+ if (ret < 0)
+ return ret;
+
+ return genphy_config(phydev);
+}
+
static struct phy_driver KSZ8031_driver = {
.name = "Micrel KSZ8021/KSZ8031",
.uid = 0x221550,
.mask = 0xfffff0,
.features = PHY_BASIC_FEATURES,
- .config = &genphy_config,
+ .config = &ksz_genconfig_bcastoff,
.startup = &genphy_startup,
.shutdown = &genphy_shutdown,
};
@@ -70,7 +89,7 @@ static struct phy_driver KSZ8081_driver = {
.uid = 0x221560,
.mask = 0xfffff0,
.features = PHY_BASIC_FEATURES,
- .config = &genphy_config,
+ .config = &ksz_genconfig_bcastoff,
.startup = &genphy_startup,
.shutdown = &genphy_shutdown,
};
@@ -211,7 +230,7 @@ static int ksz90x1_of_config_group(struct phy_device *phydev,
{
struct udevice *dev = phydev->dev;
struct phy_driver *drv = phydev->drv;
- const int ps_to_regval = 200;
+ const int ps_to_regval = 60;
int val[4];
int i, changed = 0, offset, max;
u16 regval = 0;
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 51b5746a5a..17866a244b 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -38,16 +38,16 @@ DECLARE_GLOBAL_DATA_PTR;
static int genphy_config_advert(struct phy_device *phydev)
{
u32 advertise;
- int oldadv, adv;
+ int oldadv, adv, bmsr;
int err, changed = 0;
- /* Only allow advertising what
- * this PHY supports */
+ /* Only allow advertising what this PHY supports */
phydev->advertising &= phydev->supported;
advertise = phydev->advertising;
/* Setup standard advertisement */
- oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
+ adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
+ oldadv = adv;
if (adv < 0)
return adv;
@@ -79,29 +79,40 @@ static int genphy_config_advert(struct phy_device *phydev)
changed = 1;
}
+ bmsr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
+ if (bmsr < 0)
+ return bmsr;
+
+ /* Per 802.3-2008, Section 22.2.4.2.16 Extended status all
+ * 1000Mbits/sec capable PHYs shall have the BMSR_ESTATEN bit set to a
+ * logical 1.
+ */
+ if (!(bmsr & BMSR_ESTATEN))
+ return changed;
+
/* Configure gigabit if it's supported */
- if (phydev->supported & (SUPPORTED_1000baseT_Half |
- SUPPORTED_1000baseT_Full)) {
- oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
+ adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
+ oldadv = adv;
+
+ if (adv < 0)
+ return adv;
- if (adv < 0)
- return adv;
+ adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
- adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+ if (phydev->supported & (SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full)) {
if (advertise & SUPPORTED_1000baseT_Half)
adv |= ADVERTISE_1000HALF;
if (advertise & SUPPORTED_1000baseT_Full)
adv |= ADVERTISE_1000FULL;
+ }
- if (adv != oldadv) {
- err = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000,
- adv);
+ if (adv != oldadv)
+ changed = 1;
- if (err < 0)
- return err;
- changed = 1;
- }
- }
+ err = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, adv);
+ if (err < 0)
+ return err;
return changed;
}
@@ -117,7 +128,7 @@ static int genphy_config_advert(struct phy_device *phydev)
static int genphy_setup_forced(struct phy_device *phydev)
{
int err;
- int ctl = 0;
+ int ctl = BMCR_ANRESTART;
phydev->pause = phydev->asym_pause = 0;
@@ -224,7 +235,8 @@ int genphy_update_link(struct phy_device *phydev)
if (phydev->link && mii_reg & BMSR_LSTATUS)
return 0;
- if ((mii_reg & BMSR_ANEGCAPABLE) && !(mii_reg & BMSR_ANEGCOMPLETE)) {
+ if ((phydev->autoneg == AUTONEG_ENABLE) &&
+ !(mii_reg & BMSR_ANEGCOMPLETE)) {
int i = 0;
printf("%s Waiting for PHY auto negotiation to complete",
@@ -280,7 +292,7 @@ int genphy_parse_link(struct phy_device *phydev)
int mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
/* We're using autonegotiation */
- if (phydev->supported & SUPPORTED_Autoneg) {
+ if (phydev->autoneg == AUTONEG_ENABLE) {
u32 lpa = 0;
int gblpa = 0;
u32 estatus = 0;
@@ -371,8 +383,6 @@ int genphy_config(struct phy_device *phydev)
int val;
u32 features;
- /* For now, I'll claim that the generic driver supports
- * all possible port types */
features = (SUPPORTED_TP | SUPPORTED_MII
| SUPPORTED_AUI | SUPPORTED_FIBRE |
SUPPORTED_BNC);
@@ -411,8 +421,8 @@ int genphy_config(struct phy_device *phydev)
features |= SUPPORTED_1000baseX_Half;
}
- phydev->supported = features;
- phydev->advertising = features;
+ phydev->supported &= features;
+ phydev->advertising &= features;
genphy_config_aneg(phydev);
@@ -436,7 +446,9 @@ static struct phy_driver genphy_driver = {
.uid = 0xffffffff,
.mask = 0xffffffff,
.name = "Generic PHY",
- .features = 0,
+ .features = PHY_GBIT_FEATURES | SUPPORTED_MII |
+ SUPPORTED_AUI | SUPPORTED_FIBRE |
+ SUPPORTED_BNC,
.config = genphy_config,
.startup = genphy_startup,
.shutdown = genphy_shutdown,
@@ -517,6 +529,30 @@ int phy_register(struct phy_driver *drv)
return 0;
}
+int phy_set_supported(struct phy_device *phydev, u32 max_speed)
+{
+ /* The default values for phydev->supported are provided by the PHY
+ * driver "features" member, we want to reset to sane defaults first
+ * before supporting higher speeds.
+ */
+ phydev->supported &= PHY_DEFAULT_FEATURES;
+
+ switch (max_speed) {
+ default:
+ return -ENOTSUPP;
+ case SPEED_1000:
+ phydev->supported |= PHY_1000BT_FEATURES;
+ /* fall through */
+ case SPEED_100:
+ phydev->supported |= PHY_100BT_FEATURES;
+ /* fall through */
+ case SPEED_10:
+ phydev->supported |= PHY_10BT_FEATURES;
+ }
+
+ return 0;
+}
+
static int phy_probe(struct phy_device *phydev)
{
int err = 0;
@@ -707,6 +743,9 @@ int phy_reset(struct phy_device *phydev)
int timeout = 500;
int devad = MDIO_DEVAD_NONE;
+ if (phydev->flags & PHY_FLAG_BROKEN_RESET)
+ return 0;
+
#ifdef CONFIG_PHYLIB_10G
/* If it's 10G, we need to issue reset through one of the MMDs */
if (is_10g_interface(phydev->interface)) {
@@ -717,15 +756,7 @@ int phy_reset(struct phy_device *phydev)
}
#endif
- reg = phy_read(phydev, devad, MII_BMCR);
- if (reg < 0) {
- debug("PHY status read failed\n");
- return -1;
- }
-
- reg |= BMCR_RESET;
-
- if (phy_write(phydev, devad, MII_BMCR, reg) < 0) {
+ if (phy_write(phydev, devad, MII_BMCR, BMCR_RESET) < 0) {
debug("PHY reset failed\n");
return -1;
}
@@ -738,6 +769,7 @@ int phy_reset(struct phy_device *phydev)
* auto-clearing). This should happen within 0.5 seconds per the
* IEEE spec.
*/
+ reg = phy_read(phydev, devad, MII_BMCR);
while ((reg & BMCR_RESET) && timeout--) {
reg = phy_read(phydev, devad, MII_BMCR);
diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c
index 9b09caf8c8..be0f38288f 100644
--- a/drivers/net/tsec.c
+++ b/drivers/net/tsec.c
@@ -1,18 +1,16 @@
/*
* Freescale Three Speed Ethernet Controller driver
*
- * This software may be used and distributed according to the
- * terms of the GNU Public License, Version 2, incorporated
- * herein by reference.
- *
* Copyright 2004-2011, 2013 Freescale Semiconductor, Inc.
* (C) Copyright 2003, Motorola, Inc.
* author Andy Fleming
*
+ * SPDX-License-Identifier: GPL-2.0+
*/
#include <config.h>
#include <common.h>
+#include <dm.h>
#include <malloc.h>
#include <net.h>
#include <command.h>
@@ -24,21 +22,7 @@
DECLARE_GLOBAL_DATA_PTR;
-#define TX_BUF_CNT 2
-
-static uint rx_idx; /* index of the current RX buffer */
-static uint tx_idx; /* index of the current TX buffer */
-
-#ifdef __GNUC__
-static struct txbd8 __iomem txbd[TX_BUF_CNT] __aligned(8);
-static struct rxbd8 __iomem rxbd[PKTBUFSRX] __aligned(8);
-
-#else
-#error "rtx must be 64-bit aligned"
-#endif
-
-static int tsec_send(struct eth_device *dev, void *packet, int length);
-
+#ifndef CONFIG_DM_ETH
/* Default initializations for TSEC controllers. */
static struct tsec_info_struct tsec_info[] = {
@@ -64,6 +48,7 @@ static struct tsec_info_struct tsec_info[] = {
STD_TSEC_INFO(4), /* TSEC4 */
#endif
};
+#endif /* CONFIG_DM_ETH */
#define TBIANA_SETTINGS ( \
TBIANA_ASYMMETRIC_PAUSE \
@@ -84,8 +69,10 @@ static struct tsec_info_struct tsec_info[] = {
/* Configure the TBI for SGMII operation */
static void tsec_configure_serdes(struct tsec_private *priv)
{
- /* Access TBI PHY registers at given TSEC register offset as opposed
- * to the register offset used for external PHY accesses */
+ /*
+ * Access TBI PHY registers at given TSEC register offset as opposed
+ * to the register offset used for external PHY accesses
+ */
tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa),
0, TBI_ANA, TBIANA_SETTINGS);
tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa),
@@ -100,7 +87,8 @@ static void tsec_configure_serdes(struct tsec_private *priv)
/* Set the appropriate hash bit for the given addr */
-/* The algorithm works like so:
+/*
+ * The algorithm works like so:
* 1) Take the Destination Address (ie the multicast address), and
* do a CRC on it (little endian), and reverse the bits of the
* result.
@@ -111,9 +99,13 @@ static void tsec_configure_serdes(struct tsec_private *priv)
* hash index which gaddr register to use, and the 5 other bits
* indicate which bit (assuming an IBM numbering scheme, which
* for PowerPC (tm) is usually the case) in the register holds
- * the entry. */
-static int
-tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set)
+ * the entry.
+ */
+#ifndef CONFIG_DM_ETH
+static int tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set)
+#else
+static int tsec_mcast_addr(struct udevice *dev, const u8 *mcast_mac, int set)
+#endif
{
struct tsec_private *priv = (struct tsec_private *)dev->priv;
struct tsec __iomem *regs = priv->regs;
@@ -135,7 +127,8 @@ tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set)
}
#endif /* Multicast TFTP ? */
-/* Initialized required registers to appropriate values, zeroing
+/*
+ * Initialized required registers to appropriate values, zeroing
* those we don't care about (unless zero is bad, in which case,
* choose a more appropriate value)
*/
@@ -181,7 +174,8 @@ static void init_registers(struct tsec __iomem *regs)
}
-/* Configure maccfg2 based on negotiated speed and duplex
+/*
+ * Configure maccfg2 based on negotiated speed and duplex
* reported by PHY handling code
*/
static void adjust_link(struct tsec_private *priv, struct phy_device *phydev)
@@ -212,7 +206,8 @@ static void adjust_link(struct tsec_private *priv, struct phy_device *phydev)
case 10:
maccfg2 |= MACCFG2_MII;
- /* Set R100 bit in all modes although
+ /*
+ * Set R100 bit in all modes although
* it is only used in RGMII mode
*/
if (phydev->speed == 100)
@@ -231,15 +226,174 @@ static void adjust_link(struct tsec_private *priv, struct phy_device *phydev)
(phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
}
+/*
+ * This returns the status bits of the device. The return value
+ * is never checked, and this is what the 8260 driver did, so we
+ * do the same. Presumably, this would be zero if there were no
+ * errors
+ */
+#ifndef CONFIG_DM_ETH
+static int tsec_send(struct eth_device *dev, void *packet, int length)
+#else
+static int tsec_send(struct udevice *dev, void *packet, int length)
+#endif
+{
+ struct tsec_private *priv = (struct tsec_private *)dev->priv;
+ struct tsec __iomem *regs = priv->regs;
+ uint16_t status;
+ int result = 0;
+ int i;
+
+ /* Find an empty buffer descriptor */
+ for (i = 0;
+ in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_READY;
+ i++) {
+ if (i >= TOUT_LOOP) {
+ debug("%s: tsec: tx buffers full\n", dev->name);
+ return result;
+ }
+ }
+
+ out_be32(&priv->txbd[priv->tx_idx].bufptr, (u32)packet);
+ out_be16(&priv->txbd[priv->tx_idx].length, length);
+ status = in_be16(&priv->txbd[priv->tx_idx].status);
+ out_be16(&priv->txbd[priv->tx_idx].status, status |
+ (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT));
+
+ /* Tell the DMA to go */
+ out_be32(&regs->tstat, TSTAT_CLEAR_THALT);
+
+ /* Wait for buffer to be transmitted */
+ for (i = 0;
+ in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_READY;
+ i++) {
+ if (i >= TOUT_LOOP) {
+ debug("%s: tsec: tx error\n", dev->name);
+ return result;
+ }
+ }
+
+ priv->tx_idx = (priv->tx_idx + 1) % TX_BUF_CNT;
+ result = in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_STATS;
+
+ return result;
+}
+
+#ifndef CONFIG_DM_ETH
+static int tsec_recv(struct eth_device *dev)
+{
+ struct tsec_private *priv = (struct tsec_private *)dev->priv;
+ struct tsec __iomem *regs = priv->regs;
+
+ while (!(in_be16(&priv->rxbd[priv->rx_idx].status) & RXBD_EMPTY)) {
+ int length = in_be16(&priv->rxbd[priv->rx_idx].length);
+ uint16_t status = in_be16(&priv->rxbd[priv->rx_idx].status);
+ uchar *packet = net_rx_packets[priv->rx_idx];
+
+ /* Send the packet up if there were no errors */
+ if (!(status & RXBD_STATS))
+ net_process_received_packet(packet, length - 4);
+ else
+ printf("Got error %x\n", (status & RXBD_STATS));
+
+ out_be16(&priv->rxbd[priv->rx_idx].length, 0);
+
+ status = RXBD_EMPTY;
+ /* Set the wrap bit if this is the last element in the list */
+ if ((priv->rx_idx + 1) == PKTBUFSRX)
+ status |= RXBD_WRAP;
+ out_be16(&priv->rxbd[priv->rx_idx].status, status);
+
+ priv->rx_idx = (priv->rx_idx + 1) % PKTBUFSRX;
+ }
+
+ if (in_be32(&regs->ievent) & IEVENT_BSY) {
+ out_be32(&regs->ievent, IEVENT_BSY);
+ out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
+ }
+
+ return -1;
+}
+#else
+static int tsec_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+ struct tsec_private *priv = (struct tsec_private *)dev->priv;
+ struct tsec __iomem *regs = priv->regs;
+ int ret = -1;
+
+ if (!(in_be16(&priv->rxbd[priv->rx_idx].status) & RXBD_EMPTY)) {
+ int length = in_be16(&priv->rxbd[priv->rx_idx].length);
+ uint16_t status = in_be16(&priv->rxbd[priv->rx_idx].status);
+ uint32_t buf;
+
+ /* Send the packet up if there were no errors */
+ if (!(status & RXBD_STATS)) {
+ buf = in_be32(&priv->rxbd[priv->rx_idx].bufptr);
+ *packetp = (uchar *)buf;
+ ret = length - 4;
+ } else {
+ printf("Got error %x\n", (status & RXBD_STATS));
+ }
+ }
+
+ if (in_be32(&regs->ievent) & IEVENT_BSY) {
+ out_be32(&regs->ievent, IEVENT_BSY);
+ out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
+ }
+
+ return ret;
+}
+
+static int tsec_free_pkt(struct udevice *dev, uchar *packet, int length)
+{
+ struct tsec_private *priv = (struct tsec_private *)dev->priv;
+ uint16_t status;
+
+ out_be16(&priv->rxbd[priv->rx_idx].length, 0);
+
+ status = RXBD_EMPTY;
+ /* Set the wrap bit if this is the last element in the list */
+ if ((priv->rx_idx + 1) == PKTBUFSRX)
+ status |= RXBD_WRAP;
+ out_be16(&priv->rxbd[priv->rx_idx].status, status);
+
+ priv->rx_idx = (priv->rx_idx + 1) % PKTBUFSRX;
+
+ return 0;
+}
+#endif
+
+/* Stop the interface */
+#ifndef CONFIG_DM_ETH
+static void tsec_halt(struct eth_device *dev)
+#else
+static void tsec_halt(struct udevice *dev)
+#endif
+{
+ struct tsec_private *priv = (struct tsec_private *)dev->priv;
+ struct tsec __iomem *regs = priv->regs;
+
+ clrbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
+ setbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
+
+ while ((in_be32(&regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC))
+ != (IEVENT_GRSC | IEVENT_GTSC))
+ ;
+
+ clrbits_be32(&regs->maccfg1, MACCFG1_TX_EN | MACCFG1_RX_EN);
+
+ /* Shut down the PHY, as needed */
+ phy_shutdown(priv->phydev);
+}
+
#ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129
/*
* When MACCFG1[Rx_EN] is enabled during system boot as part
* of the eTSEC port initialization sequence,
* the eTSEC Rx logic may not be properly initialized.
*/
-void redundant_init(struct eth_device *dev)
+void redundant_init(struct tsec_private *priv)
{
- struct tsec_private *priv = dev->priv;
struct tsec __iomem *regs = priv->regs;
uint t, count = 0;
int fail = 1;
@@ -274,25 +428,27 @@ void redundant_init(struct eth_device *dev)
do {
uint16_t status;
- tsec_send(dev, (void *)pkt, sizeof(pkt));
+ tsec_send(priv->dev, (void *)pkt, sizeof(pkt));
/* Wait for buffer to be received */
- for (t = 0; in_be16(&rxbd[rx_idx].status) & RXBD_EMPTY; t++) {
+ for (t = 0;
+ in_be16(&priv->rxbd[priv->rx_idx].status) & RXBD_EMPTY;
+ t++) {
if (t >= 10 * TOUT_LOOP) {
- printf("%s: tsec: rx error\n", dev->name);
+ printf("%s: tsec: rx error\n", priv->dev->name);
break;
}
}
- if (!memcmp(pkt, (void *)net_rx_packets[rx_idx], sizeof(pkt)))
+ if (!memcmp(pkt, net_rx_packets[priv->rx_idx], sizeof(pkt)))
fail = 0;
- out_be16(&rxbd[rx_idx].length, 0);
+ out_be16(&priv->rxbd[priv->rx_idx].length, 0);
status = RXBD_EMPTY;
- if ((rx_idx + 1) == PKTBUFSRX)
+ if ((priv->rx_idx + 1) == PKTBUFSRX)
status |= RXBD_WRAP;
- out_be16(&rxbd[rx_idx].status, status);
- rx_idx = (rx_idx + 1) % PKTBUFSRX;
+ out_be16(&priv->rxbd[priv->rx_idx].status, status);
+ priv->rx_idx = (priv->rx_idx + 1) % PKTBUFSRX;
if (in_be32(&regs->ievent) & IEVENT_BSY) {
out_be32(&regs->ievent, IEVENT_BSY);
@@ -315,49 +471,49 @@ void redundant_init(struct eth_device *dev)
}
#endif
-/* Set up the buffers and their descriptors, and bring up the
+/*
+ * Set up the buffers and their descriptors, and bring up the
* interface
*/
-static void startup_tsec(struct eth_device *dev)
+static void startup_tsec(struct tsec_private *priv)
{
- struct tsec_private *priv = (struct tsec_private *)dev->priv;
struct tsec __iomem *regs = priv->regs;
uint16_t status;
int i;
/* reset the indices to zero */
- rx_idx = 0;
- tx_idx = 0;
+ priv->rx_idx = 0;
+ priv->tx_idx = 0;
#ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129
uint svr;
#endif
/* Point to the buffer descriptors */
- out_be32(&regs->tbase, (u32)&txbd[0]);
- out_be32(&regs->rbase, (u32)&rxbd[0]);
+ out_be32(&regs->tbase, (u32)&priv->txbd[0]);
+ out_be32(&regs->rbase, (u32)&priv->rxbd[0]);
/* Initialize the Rx Buffer descriptors */
for (i = 0; i < PKTBUFSRX; i++) {
- out_be16(&rxbd[i].status, RXBD_EMPTY);
- out_be16(&rxbd[i].length, 0);
- out_be32(&rxbd[i].bufptr, (u32)net_rx_packets[i]);
+ out_be16(&priv->rxbd[i].status, RXBD_EMPTY);
+ out_be16(&priv->rxbd[i].length, 0);
+ out_be32(&priv->rxbd[i].bufptr, (u32)net_rx_packets[i]);
}
- status = in_be16(&rxbd[PKTBUFSRX - 1].status);
- out_be16(&rxbd[PKTBUFSRX - 1].status, status | RXBD_WRAP);
+ status = in_be16(&priv->rxbd[PKTBUFSRX - 1].status);
+ out_be16(&priv->rxbd[PKTBUFSRX - 1].status, status | RXBD_WRAP);
/* Initialize the TX Buffer Descriptors */
for (i = 0; i < TX_BUF_CNT; i++) {
- out_be16(&txbd[i].status, 0);
- out_be16(&txbd[i].length, 0);
- out_be32(&txbd[i].bufptr, 0);
+ out_be16(&priv->txbd[i].status, 0);
+ out_be16(&priv->txbd[i].length, 0);
+ out_be32(&priv->txbd[i].bufptr, 0);
}
- status = in_be16(&txbd[TX_BUF_CNT - 1].status);
- out_be16(&txbd[TX_BUF_CNT - 1].status, status | TXBD_WRAP);
+ status = in_be16(&priv->txbd[TX_BUF_CNT - 1].status);
+ out_be16(&priv->txbd[TX_BUF_CNT - 1].status, status | TXBD_WRAP);
#ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129
svr = get_svr();
if ((SVR_MAJ(svr) == 1) || IS_SVR_REV(svr, 2, 0))
- redundant_init(dev);
+ redundant_init(priv);
#endif
/* Enable Transmit and Receive */
setbits_be32(&regs->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN);
@@ -369,113 +525,22 @@ static void startup_tsec(struct eth_device *dev)
clrbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
}
-/* This returns the status bits of the device. The return value
- * is never checked, and this is what the 8260 driver did, so we
- * do the same. Presumably, this would be zero if there were no
- * errors
- */
-static int tsec_send(struct eth_device *dev, void *packet, int length)
-{
- struct tsec_private *priv = (struct tsec_private *)dev->priv;
- struct tsec __iomem *regs = priv->regs;
- uint16_t status;
- int result = 0;
- int i;
-
- /* Find an empty buffer descriptor */
- for (i = 0; in_be16(&txbd[tx_idx].status) & TXBD_READY; i++) {
- if (i >= TOUT_LOOP) {
- debug("%s: tsec: tx buffers full\n", dev->name);
- return result;
- }
- }
-
- out_be32(&txbd[tx_idx].bufptr, (u32)packet);
- out_be16(&txbd[tx_idx].length, length);
- status = in_be16(&txbd[tx_idx].status);
- out_be16(&txbd[tx_idx].status, status |
- (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT));
-
- /* Tell the DMA to go */
- out_be32(&regs->tstat, TSTAT_CLEAR_THALT);
-
- /* Wait for buffer to be transmitted */
- for (i = 0; in_be16(&txbd[tx_idx].status) & TXBD_READY; i++) {
- if (i >= TOUT_LOOP) {
- debug("%s: tsec: tx error\n", dev->name);
- return result;
- }
- }
-
- tx_idx = (tx_idx + 1) % TX_BUF_CNT;
- result = in_be16(&txbd[tx_idx].status) & TXBD_STATS;
-
- return result;
-}
-
-static int tsec_recv(struct eth_device *dev)
-{
- struct tsec_private *priv = (struct tsec_private *)dev->priv;
- struct tsec __iomem *regs = priv->regs;
-
- while (!(in_be16(&rxbd[rx_idx].status) & RXBD_EMPTY)) {
- int length = in_be16(&rxbd[rx_idx].length);
- uint16_t status = in_be16(&rxbd[rx_idx].status);
-
- /* Send the packet up if there were no errors */
- if (!(status & RXBD_STATS))
- net_process_received_packet(net_rx_packets[rx_idx],
- length - 4);
- else
- printf("Got error %x\n", (status & RXBD_STATS));
-
- out_be16(&rxbd[rx_idx].length, 0);
-
- status = RXBD_EMPTY;
- /* Set the wrap bit if this is the last element in the list */
- if ((rx_idx + 1) == PKTBUFSRX)
- status |= RXBD_WRAP;
- out_be16(&rxbd[rx_idx].status, status);
-
- rx_idx = (rx_idx + 1) % PKTBUFSRX;
- }
-
- if (in_be32(&regs->ievent) & IEVENT_BSY) {
- out_be32(&regs->ievent, IEVENT_BSY);
- out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
- }
-
- return -1;
-
-}
-
-/* Stop the interface */
-static void tsec_halt(struct eth_device *dev)
-{
- struct tsec_private *priv = (struct tsec_private *)dev->priv;
- struct tsec __iomem *regs = priv->regs;
-
- clrbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
- setbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
-
- while ((in_be32(&regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC))
- != (IEVENT_GRSC | IEVENT_GTSC))
- ;
-
- clrbits_be32(&regs->maccfg1, MACCFG1_TX_EN | MACCFG1_RX_EN);
-
- /* Shut down the PHY, as needed */
- phy_shutdown(priv->phydev);
-}
-
-/* Initializes data structures and registers for the controller,
- * and brings the interface up. Returns the link status, meaning
+/*
+ * Initializes data structures and registers for the controller,
+ * and brings the interface up. Returns the link status, meaning
* that it returns success if the link is up, failure otherwise.
- * This allows u-boot to find the first active controller.
+ * This allows U-Boot to find the first active controller.
*/
+#ifndef CONFIG_DM_ETH
static int tsec_init(struct eth_device *dev, bd_t * bd)
+#else
+static int tsec_init(struct udevice *dev)
+#endif
{
struct tsec_private *priv = (struct tsec_private *)dev->priv;
+#ifdef CONFIG_DM_ETH
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+#endif
struct tsec __iomem *regs = priv->regs;
u32 tempval;
int ret;
@@ -489,17 +554,27 @@ static int tsec_init(struct eth_device *dev, bd_t * bd)
/* Init ECNTRL */
out_be32(&regs->ecntrl, ECNTRL_INIT_SETTINGS);
- /* Copy the station address into the address registers.
+ /*
+ * Copy the station address into the address registers.
* For a station address of 0x12345678ABCD in transmission
* order (BE), MACnADDR1 is set to 0xCDAB7856 and
* MACnADDR2 is set to 0x34120000.
*/
+#ifndef CONFIG_DM_ETH
tempval = (dev->enetaddr[5] << 24) | (dev->enetaddr[4] << 16) |
(dev->enetaddr[3] << 8) | dev->enetaddr[2];
+#else
+ tempval = (pdata->enetaddr[5] << 24) | (pdata->enetaddr[4] << 16) |
+ (pdata->enetaddr[3] << 8) | pdata->enetaddr[2];
+#endif
out_be32(&regs->macstnaddr1, tempval);
+#ifndef CONFIG_DM_ETH
tempval = (dev->enetaddr[1] << 24) | (dev->enetaddr[0] << 16);
+#else
+ tempval = (pdata->enetaddr[1] << 24) | (pdata->enetaddr[0] << 16);
+#endif
out_be32(&regs->macstnaddr2, tempval);
@@ -507,7 +582,7 @@ static int tsec_init(struct eth_device *dev, bd_t * bd)
init_registers(regs);
/* Ready the device for tx/rx */
- startup_tsec(dev);
+ startup_tsec(priv);
/* Start up the PHY */
ret = phy_startup(priv->phydev);
@@ -551,8 +626,8 @@ static phy_interface_t tsec_get_interface(struct tsec_private *priv)
* be set by the platform code.
*/
if ((interface == PHY_INTERFACE_MODE_RGMII_ID) ||
- (interface == PHY_INTERFACE_MODE_RGMII_TXID) ||
- (interface == PHY_INTERFACE_MODE_RGMII_RXID))
+ (interface == PHY_INTERFACE_MODE_RGMII_TXID) ||
+ (interface == PHY_INTERFACE_MODE_RGMII_RXID))
return interface;
return PHY_INTERFACE_MODE_RGMII;
@@ -565,14 +640,13 @@ static phy_interface_t tsec_get_interface(struct tsec_private *priv)
return PHY_INTERFACE_MODE_MII;
}
-
-/* Discover which PHY is attached to the device, and configure it
+/*
+ * Discover which PHY is attached to the device, and configure it
* properly. If the PHY is not recognized, then return 0
* (failure). Otherwise, return 1
*/
-static int init_phy(struct eth_device *dev)
+static int init_phy(struct tsec_private *priv)
{
- struct tsec_private *priv = (struct tsec_private *)dev->priv;
struct phy_device *phydev;
struct tsec __iomem *regs = priv->regs;
u32 supported = (SUPPORTED_10baseT_Half |
@@ -584,14 +658,15 @@ static int init_phy(struct eth_device *dev)
supported |= SUPPORTED_1000baseT_Full;
/* Assign a Physical address to the TBI */
- out_be32(&regs->tbipa, CONFIG_SYS_TBIPA_VALUE);
+ out_be32(&regs->tbipa, priv->tbiaddr);
priv->interface = tsec_get_interface(priv);
if (priv->interface == PHY_INTERFACE_MODE_SGMII)
tsec_configure_serdes(priv);
- phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->interface);
+ phydev = phy_connect(priv->bus, priv->phyaddr, priv->dev,
+ priv->interface);
if (!phydev)
return 0;
@@ -605,7 +680,9 @@ static int init_phy(struct eth_device *dev)
return 1;
}
-/* Initialize device structure. Returns success if PHY
+#ifndef CONFIG_DM_ETH
+/*
+ * Initialize device structure. Returns success if PHY
* initialization succeeded (i.e. if it recognizes the PHY)
*/
static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
@@ -630,11 +707,13 @@ static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
priv->phyregs_sgmii = tsec_info->miiregs_sgmii;
priv->phyaddr = tsec_info->phyaddr;
+ priv->tbiaddr = CONFIG_SYS_TBIPA_VALUE;
priv->flags = tsec_info->flags;
strcpy(dev->name, tsec_info->devname);
priv->interface = tsec_info->interface;
priv->bus = miiphy_get_dev_by_name(tsec_info->mii_devname);
+ priv->dev = dev;
dev->iobase = 0;
dev->priv = priv;
dev->init = tsec_init;
@@ -645,7 +724,7 @@ static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
dev->mcast = tsec_mcast_addr;
#endif
- /* Tell u-boot to get the addr from the env */
+ /* Tell U-Boot to get the addr from the env */
for (i = 0; i < 6; i++)
dev->enetaddr[i] = 0;
@@ -657,7 +736,7 @@ static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
/* Try to initialize PHY here, and return */
- return init_phy(dev);
+ return init_phy(priv);
}
/*
@@ -690,3 +769,118 @@ int tsec_standard_init(bd_t *bis)
return tsec_eth_init(bis, tsec_info, ARRAY_SIZE(tsec_info));
}
+#else /* CONFIG_DM_ETH */
+int tsec_probe(struct udevice *dev)
+{
+ struct tsec_private *priv = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+ struct fsl_pq_mdio_info mdio_info;
+ int offset = 0;
+ int reg;
+ const char *phy_mode;
+ int ret;
+
+ pdata->iobase = (phys_addr_t)dev_get_addr(dev);
+ priv->regs = (struct tsec *)pdata->iobase;
+
+ offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset,
+ "phy-handle");
+ if (offset > 0) {
+ reg = fdtdec_get_int(gd->fdt_blob, offset, "reg", 0);
+ priv->phyaddr = reg;
+ } else {
+ debug("phy-handle does not exist under tsec %s\n", dev->name);
+ return -ENOENT;
+ }
+
+ offset = fdt_parent_offset(gd->fdt_blob, offset);
+ if (offset > 0) {
+ reg = fdtdec_get_int(gd->fdt_blob, offset, "reg", 0);
+ priv->phyregs_sgmii = (struct tsec_mii_mng *)(reg + 0x520);
+ } else {
+ debug("No parent node for PHY?\n");
+ return -ENOENT;
+ }
+
+ offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset,
+ "tbi-handle");
+ if (offset > 0) {
+ reg = fdtdec_get_int(gd->fdt_blob, offset, "reg",
+ CONFIG_SYS_TBIPA_VALUE);
+ priv->tbiaddr = reg;
+ } else {
+ priv->tbiaddr = CONFIG_SYS_TBIPA_VALUE;
+ }
+
+ phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset,
+ "phy-connection-type", NULL);
+ if (phy_mode)
+ pdata->phy_interface = phy_get_interface_by_name(phy_mode);
+ if (pdata->phy_interface == -1) {
+ debug("Invalid PHY interface '%s'\n", phy_mode);
+ return -EINVAL;
+ }
+ priv->interface = pdata->phy_interface;
+
+ /* Initialize flags */
+ priv->flags = TSEC_GIGABIT;
+ if (priv->interface == PHY_INTERFACE_MODE_SGMII)
+ priv->flags |= TSEC_SGMII;
+
+ mdio_info.regs = priv->phyregs_sgmii;
+ mdio_info.name = (char *)dev->name;
+ ret = fsl_pq_mdio_init(NULL, &mdio_info);
+ if (ret)
+ return ret;
+
+ /* Reset the MAC */
+ setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
+ udelay(2); /* Soft Reset must be asserted for 3 TX clocks */
+ clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
+
+ priv->dev = dev;
+ priv->bus = miiphy_get_dev_by_name(dev->name);
+
+ /* Try to initialize PHY here, and return */
+ return !init_phy(priv);
+}
+
+int tsec_remove(struct udevice *dev)
+{
+ struct tsec_private *priv = dev->priv;
+
+ free(priv->phydev);
+ mdio_unregister(priv->bus);
+ mdio_free(priv->bus);
+
+ return 0;
+}
+
+static const struct eth_ops tsec_ops = {
+ .start = tsec_init,
+ .send = tsec_send,
+ .recv = tsec_recv,
+ .free_pkt = tsec_free_pkt,
+ .stop = tsec_halt,
+#ifdef CONFIG_MCAST_TFTP
+ .mcast = tsec_mcast_addr,
+#endif
+};
+
+static const struct udevice_id tsec_ids[] = {
+ { .compatible = "fsl,tsec" },
+ { }
+};
+
+U_BOOT_DRIVER(eth_tsec) = {
+ .name = "tsec",
+ .id = UCLASS_ETH,
+ .of_match = tsec_ids,
+ .probe = tsec_probe,
+ .remove = tsec_remove,
+ .ops = &tsec_ops,
+ .priv_auto_alloc_size = sizeof(struct tsec_private),
+ .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif /* CONFIG_DM_ETH */
diff --git a/drivers/net/vsc9953.c b/drivers/net/vsc9953.c
index 7595db1acb..44afe14051 100644
--- a/drivers/net/vsc9953.c
+++ b/drivers/net/vsc9953.c
@@ -469,6 +469,47 @@ static void vsc9953_vlan_ingr_fltr_learn_drop(int enable)
clrbits_le32(&l2ana_reg->ana.adv_learn, VSC9953_VLAN_CHK);
}
+enum aggr_code_mode {
+ AGGR_CODE_RAND = 0,
+ AGGR_CODE_ALL, /* S/D MAC, IPv4 S/D IP, IPv6 Flow Label, S/D PORT */
+};
+
+/* Set aggregation code generation mode */
+static int vsc9953_aggr_code_set(enum aggr_code_mode ac)
+{
+ int rc;
+ struct vsc9953_analyzer *l2ana_reg;
+
+ l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+ VSC9953_ANA_OFFSET);
+
+ switch (ac) {
+ case AGGR_CODE_RAND:
+ clrsetbits_le32(&l2ana_reg->common.aggr_cfg,
+ VSC9953_AC_DMAC_ENA | VSC9953_AC_SMAC_ENA |
+ VSC9953_AC_IP6_LBL_ENA |
+ VSC9953_AC_IP6_TCPUDP_ENA |
+ VSC9953_AC_IP4_SIPDIP_ENA |
+ VSC9953_AC_IP4_TCPUDP_ENA, VSC9953_AC_RND_ENA);
+ rc = 0;
+ break;
+ case AGGR_CODE_ALL:
+ clrsetbits_le32(&l2ana_reg->common.aggr_cfg, VSC9953_AC_RND_ENA,
+ VSC9953_AC_DMAC_ENA | VSC9953_AC_SMAC_ENA |
+ VSC9953_AC_IP6_LBL_ENA |
+ VSC9953_AC_IP6_TCPUDP_ENA |
+ VSC9953_AC_IP4_SIPDIP_ENA |
+ VSC9953_AC_IP4_TCPUDP_ENA);
+ rc = 0;
+ break;
+ default:
+ /* unknown mode for aggregation code */
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
/* Egress untag modes of a VSC9953 port */
enum egress_untag_mode {
EGRESS_UNTAG_ALL = 0,
@@ -593,6 +634,25 @@ static void vsc9953_port_all_vlan_egress_untagged_set(
vsc9953_port_vlan_egr_untag_set(i, mode);
}
+static int vsc9953_autoage_time_set(int age_period)
+{
+ u32 autoage;
+ struct vsc9953_analyzer *l2ana_reg;
+
+ l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+ VSC9953_ANA_OFFSET);
+
+ if (age_period < 0 || age_period > VSC9953_AUTOAGE_PERIOD_MASK)
+ return -EINVAL;
+
+ autoage = bitfield_replace_by_mask(in_le32(&l2ana_reg->ana.auto_age),
+ VSC9953_AUTOAGE_PERIOD_MASK,
+ age_period);
+ out_le32(&l2ana_reg->ana.auto_age, autoage);
+
+ return 0;
+}
+
#ifdef CONFIG_CMD_ETHSW
/* Enable/disable status of a VSC9953 port */
@@ -1474,6 +1534,224 @@ static int vsc9953_port_ingress_filtering_get(int port_no)
return !!(val & (1 << port_no));
}
+/* Get the aggregation group of a port */
+static int vsc9953_port_aggr_grp_get(int port_no, int *aggr_grp)
+{
+ u32 val;
+ struct vsc9953_analyzer *l2ana_reg;
+
+ if (!VSC9953_PORT_CHECK(port_no))
+ return -EINVAL;
+
+ l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+ VSC9953_ANA_OFFSET);
+
+ val = in_le32(&l2ana_reg->port[port_no].port_cfg);
+ *aggr_grp = bitfield_extract_by_mask(val,
+ VSC9953_PORT_CFG_PORTID_MASK);
+
+ return 0;
+}
+
+static void vsc9953_aggr_grp_members_get(int aggr_grp,
+ u8 aggr_membr[VSC9953_MAX_PORTS])
+{
+ int port_no;
+ int aggr_membr_grp;
+
+ for (port_no = 0; port_no < VSC9953_MAX_PORTS; port_no++) {
+ aggr_membr[port_no] = 0;
+
+ if (vsc9953_port_aggr_grp_get(port_no, &aggr_membr_grp))
+ continue;
+
+ if (aggr_grp == aggr_membr_grp)
+ aggr_membr[port_no] = 1;
+ }
+}
+
+static void vsc9953_update_dest_members_masks(int port_no, u32 membr_bitfld_old,
+ u32 membr_bitfld_new)
+{
+ int i;
+ u32 pgid;
+ struct vsc9953_analyzer *l2ana_reg;
+
+ l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+ VSC9953_ANA_OFFSET);
+
+ /*
+ * NOTE: Only the unicast destination masks are updated, since
+ * we do not support for now Layer-2 multicast entries
+ */
+ for (i = 0; i < VSC9953_MAX_PORTS; i++) {
+ if (i == port_no) {
+ clrsetbits_le32(&l2ana_reg->port_id_tbl.port_grp_id[i],
+ VSC9953_PGID_PORT_MASK,
+ membr_bitfld_new);
+ continue;
+ }
+
+ pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[i]);
+ if ((u32)(1 << i) & membr_bitfld_old & VSC9953_PGID_PORT_MASK)
+ pgid &= ~((u32)(1 << port_no));
+ if ((u32)(1 << i) & membr_bitfld_new & VSC9953_PGID_PORT_MASK)
+ pgid |= ((u32)(1 << port_no));
+
+ out_le32(&l2ana_reg->port_id_tbl.port_grp_id[i], pgid);
+ }
+}
+
+static void vsc9953_update_source_members_masks(int port_no,
+ u32 membr_bitfld_old,
+ u32 membr_bitfld_new)
+{
+ int i;
+ int index;
+ u32 pgid;
+ struct vsc9953_analyzer *l2ana_reg;
+
+ l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+ VSC9953_ANA_OFFSET);
+
+ for (i = 0; i < VSC9953_MAX_PORTS + 1; i++) {
+ index = PGID_SRC_START + i;
+ pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[index]);
+ if (i == port_no) {
+ pgid = (pgid | VSC9953_PGID_PORT_MASK) &
+ ~membr_bitfld_new;
+ out_le32(&l2ana_reg->port_id_tbl.port_grp_id[index],
+ pgid);
+ continue;
+ }
+
+ if ((u32)(1 << i) & membr_bitfld_old & VSC9953_PGID_PORT_MASK)
+ pgid |= (u32)(1 << port_no);
+
+ if ((u32)(1 << i) & membr_bitfld_new & VSC9953_PGID_PORT_MASK)
+ pgid &= ~(u32)(1 << port_no);
+ out_le32(&l2ana_reg->port_id_tbl.port_grp_id[index], pgid);
+ }
+}
+
+static u32 vsc9953_aggr_mask_get_next(u32 aggr_mask, u32 member_bitfield)
+{
+ if (!member_bitfield)
+ return 0;
+
+ if (!(aggr_mask & VSC9953_PGID_PORT_MASK))
+ aggr_mask = 1;
+ else
+ aggr_mask <<= 1;
+
+ while (!(aggr_mask & member_bitfield)) {
+ aggr_mask <<= 1;
+ if (!(aggr_mask & VSC9953_PGID_PORT_MASK))
+ aggr_mask = 1;
+ }
+
+ return aggr_mask;
+}
+
+static void vsc9953_update_aggr_members_masks(int port_no, u32 membr_bitfld_old,
+ u32 membr_bitfld_new)
+{
+ int i;
+ u32 pgid;
+ u32 aggr_mask_old = 0;
+ u32 aggr_mask_new = 0;
+ struct vsc9953_analyzer *l2ana_reg;
+
+ l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+ VSC9953_ANA_OFFSET);
+
+ /* Update all the PGID aggregation masks */
+ for (i = PGID_AGGR_START; i < PGID_SRC_START; i++) {
+ pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[i]);
+
+ aggr_mask_old = vsc9953_aggr_mask_get_next(aggr_mask_old,
+ membr_bitfld_old);
+ pgid = (pgid & ~membr_bitfld_old) | aggr_mask_old;
+
+ aggr_mask_new = vsc9953_aggr_mask_get_next(aggr_mask_new,
+ membr_bitfld_new);
+ pgid = (pgid & ~membr_bitfld_new) | aggr_mask_new;
+
+ out_le32(&l2ana_reg->port_id_tbl.port_grp_id[i], pgid);
+ }
+}
+
+static u32 vsc9953_aggr_membr_bitfield_get(u8 member[VSC9953_MAX_PORTS])
+{
+ int i;
+ u32 member_bitfield = 0;
+
+ for (i = 0; i < VSC9953_MAX_PORTS; i++) {
+ if (member[i])
+ member_bitfield |= 1 << i;
+ }
+ member_bitfield &= VSC9953_PGID_PORT_MASK;
+
+ return member_bitfield;
+}
+
+static void vsc9953_update_members_masks(int port_no,
+ u8 member_old[VSC9953_MAX_PORTS],
+ u8 member_new[VSC9953_MAX_PORTS])
+{
+ u32 membr_bitfld_old = vsc9953_aggr_membr_bitfield_get(member_old);
+ u32 membr_bitfld_new = vsc9953_aggr_membr_bitfield_get(member_new);
+
+ vsc9953_update_dest_members_masks(port_no, membr_bitfld_old,
+ membr_bitfld_new);
+ vsc9953_update_source_members_masks(port_no, membr_bitfld_old,
+ membr_bitfld_new);
+ vsc9953_update_aggr_members_masks(port_no, membr_bitfld_old,
+ membr_bitfld_new);
+}
+
+/* Set the aggregation group of a port */
+static int vsc9953_port_aggr_grp_set(int port_no, int aggr_grp)
+{
+ u8 aggr_membr_old[VSC9953_MAX_PORTS];
+ u8 aggr_membr_new[VSC9953_MAX_PORTS];
+ int rc;
+ int aggr_grp_old;
+ u32 val;
+ struct vsc9953_analyzer *l2ana_reg;
+
+ if (!VSC9953_PORT_CHECK(port_no) || !VSC9953_PORT_CHECK(aggr_grp))
+ return -EINVAL;
+
+ l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+ VSC9953_ANA_OFFSET);
+
+ rc = vsc9953_port_aggr_grp_get(port_no, &aggr_grp_old);
+ if (rc)
+ return rc;
+
+ /* get all the members of the old aggregation group */
+ vsc9953_aggr_grp_members_get(aggr_grp_old, aggr_membr_old);
+
+ /* get all the members of the same aggregation group */
+ vsc9953_aggr_grp_members_get(aggr_grp, aggr_membr_new);
+
+ /* add current port as member to the new aggregation group */
+ aggr_membr_old[port_no] = 0;
+ aggr_membr_new[port_no] = 1;
+
+ /* update masks */
+ vsc9953_update_members_masks(port_no, aggr_membr_old, aggr_membr_new);
+
+ /* Change logical port number */
+ val = in_le32(&l2ana_reg->port[port_no].port_cfg);
+ val = bitfield_replace_by_mask(val,
+ VSC9953_PORT_CFG_PORTID_MASK, aggr_grp);
+ out_le32(&l2ana_reg->port[port_no].port_cfg, val);
+
+ return 0;
+}
+
static int vsc9953_port_status_key_func(struct ethsw_command_def *parsed_cmd)
{
int i;
@@ -2064,6 +2342,72 @@ static int vsc9953_ingr_fltr_set_key_func(struct ethsw_command_def *parsed_cmd)
return CMD_RET_SUCCESS;
}
+static int vsc9953_port_aggr_show_key_func(struct ethsw_command_def *parsed_cmd)
+{
+ int i;
+ int aggr_grp;
+
+ if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
+ if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
+ printf("Invalid port number: %d\n", parsed_cmd->port);
+ return CMD_RET_FAILURE;
+ }
+
+ if (vsc9953_port_aggr_grp_get(parsed_cmd->port, &aggr_grp))
+ return CMD_RET_FAILURE;
+ printf("%7s %10s\n", "Port", "Aggr grp");
+ printf("%7d %10d\n", parsed_cmd->port, aggr_grp);
+ } else {
+ printf("%7s %10s\n", "Port", "Aggr grp");
+ for (i = 0; i < VSC9953_MAX_PORTS; i++) {
+ if (vsc9953_port_aggr_grp_get(i, &aggr_grp))
+ continue;
+ printf("%7d %10d\n", i, aggr_grp);
+ }
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+static int vsc9953_port_aggr_set_key_func(struct ethsw_command_def *parsed_cmd)
+{
+ int i;
+
+ /* Aggregation group number should be set in parsed_cmd->aggr_grp */
+ if (parsed_cmd->aggr_grp == ETHSW_CMD_AGGR_GRP_NONE) {
+ printf("Please set an aggregation group value\n");
+ return CMD_RET_FAILURE;
+ }
+
+ if (!VSC9953_PORT_CHECK(parsed_cmd->aggr_grp)) {
+ printf("Invalid aggregation group number: %d\n",
+ parsed_cmd->aggr_grp);
+ return CMD_RET_FAILURE;
+ }
+
+ if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
+ if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
+ printf("Invalid port number: %d\n", parsed_cmd->port);
+ return CMD_RET_FAILURE;
+ }
+ if (vsc9953_port_aggr_grp_set(parsed_cmd->port,
+ parsed_cmd->aggr_grp)) {
+ printf("Port %d: failed to set aggr group %d\n",
+ parsed_cmd->port, parsed_cmd->aggr_grp);
+ }
+ } else {
+ for (i = 0; i < VSC9953_MAX_PORTS; i++) {
+ if (vsc9953_port_aggr_grp_set(i,
+ parsed_cmd->aggr_grp)) {
+ printf("Port %d: failed to set aggr group %d\n",
+ i, parsed_cmd->aggr_grp);
+ }
+ }
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
static struct ethsw_command_func vsc9953_cmd_func = {
.ethsw_name = "L2 Switch VSC9953",
.port_enable = &vsc9953_port_status_key_func,
@@ -2088,7 +2432,9 @@ static struct ethsw_command_func vsc9953_cmd_func = {
.vlan_learn_show = &vsc9953_vlan_learn_show_key_func,
.vlan_learn_set = &vsc9953_vlan_learn_set_key_func,
.port_ingr_filt_show = &vsc9953_ingr_fltr_show_key_func,
- .port_ingr_filt_set = &vsc9953_ingr_fltr_set_key_func
+ .port_ingr_filt_set = &vsc9953_ingr_fltr_set_key_func,
+ .port_aggr_show = &vsc9953_port_aggr_show_key_func,
+ .port_aggr_set = &vsc9953_port_aggr_set_key_func,
};
#endif /* CONFIG_CMD_ETHSW */
@@ -2107,6 +2453,10 @@ void vsc9953_default_configuration(void)
{
int i;
+ if (vsc9953_autoage_time_set(VSC9953_DEFAULT_AGE_TIME))
+ debug("VSC9953: failed to set AGE time to %d\n",
+ VSC9953_DEFAULT_AGE_TIME);
+
for (i = 0; i < VSC9953_MAX_VLAN; i++)
vsc9953_vlan_table_membership_all_set(i, 0);
vsc9953_port_all_vlan_aware_set(1);
@@ -2115,6 +2465,8 @@ void vsc9953_default_configuration(void)
vsc9953_vlan_table_membership_all_set(1, 1);
vsc9953_vlan_ingr_fltr_learn_drop(1);
vsc9953_port_all_vlan_egress_untagged_set(EGRESS_UNTAG_PVID_AND_ZERO);
+ if (vsc9953_aggr_code_set(AGGR_CODE_ALL))
+ debug("VSC9953: failed to set default aggregation code mode\n");
}
void vsc9953_init(bd_t *bis)
OpenPOWER on IntegriCloud