Commit c8546163fa92bb46c09017db18dadbb26e639895

Authored by Gregory CLEMENT
Committed by Daniel Schwierzeck
1 parent 55037902b8

net: add MSCC Ocelot switch support

This patch adds support for the Microsemi Ethernet switch present on
Ocelot SoCs.

Signed-off-by: Gregory CLEMENT <gregory.clement@bootlin.com>
Reviewed-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>

Showing 4 changed files with 774 additions and 0 deletions Side-by-side Diff

... ... @@ -539,6 +539,7 @@
539 539 F: drivers/spi/mscc_bb_spi.c
540 540 F: include/configs/vcoreiii.h
541 541 F: drivers/pinctrl/mscc/
  542 +F: drivers/net/ocelot_switch.c
542 543  
543 544 MIPS JZ4780
544 545 M: Ezequiel Garcia <ezequiel@collabora.com>
... ... @@ -432,6 +432,13 @@
432 432 This driver implements support for the Socionext AVE Ethernet
433 433 controller, as found on the Socionext UniPhier family.
434 434  
  435 +config MSCC_OCELOT_SWITCH
  436 + bool "Ocelot switch driver"
  437 + depends on DM_ETH && ARCH_MSCC
  438 + select PHYLIB
  439 + help
  440 + This driver supports the Ocelot network switch device.
  441 +
435 442 config ETHER_ON_FEC1
436 443 bool "FEC1"
437 444 depends on MPC8XX_FEC
drivers/net/Makefile
... ... @@ -75,4 +75,5 @@
75 75 obj-$(CONFIG_SNI_AVE) += sni_ave.o
76 76 obj-y += ti/
77 77 obj-$(CONFIG_MEDIATEK_ETH) += mtk_eth.o
  78 +obj-$(CONFIG_MSCC_OCELOT_SWITCH) += ocelot_switch.o
drivers/net/ocelot_switch.c
  1 +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
  2 +/*
  3 + * Copyright (c) 2018 Microsemi Corporation
  4 + */
  5 +
  6 +#include <common.h>
  7 +#include <config.h>
  8 +#include <dm.h>
  9 +#include <dm/of_access.h>
  10 +#include <dm/of_addr.h>
  11 +#include <fdt_support.h>
  12 +#include <linux/io.h>
  13 +#include <linux/ioport.h>
  14 +#include <miiphy.h>
  15 +#include <net.h>
  16 +#include <wait_bit.h>
  17 +
  18 +#define MIIM_STATUS 0x0
  19 +#define MIIM_STAT_BUSY BIT(3)
  20 +#define MIIM_CMD 0x8
  21 +#define MIIM_CMD_SCAN BIT(0)
  22 +#define MIIM_CMD_OPR_WRITE BIT(1)
  23 +#define MIIM_CMD_OPR_READ BIT(2)
  24 +#define MIIM_CMD_SINGLE_SCAN BIT(3)
  25 +#define MIIM_CMD_WRDATA(x) ((x) << 4)
  26 +#define MIIM_CMD_REGAD(x) ((x) << 20)
  27 +#define MIIM_CMD_PHYAD(x) ((x) << 25)
  28 +#define MIIM_CMD_VLD BIT(31)
  29 +#define MIIM_DATA 0xC
  30 +#define MIIM_DATA_ERROR (0x2 << 16)
  31 +
  32 +#define PHY_CFG 0x0
  33 +#define PHY_CFG_ENA 0xF
  34 +#define PHY_CFG_COMMON_RST BIT(4)
  35 +#define PHY_CFG_RST (0xF << 5)
  36 +#define PHY_STAT 0x4
  37 +#define PHY_STAT_SUPERVISOR_COMPLETE BIT(0)
  38 +
  39 +#define ANA_PORT_VLAN_CFG(x) (0x7000 + 0x100 * (x))
  40 +#define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20)
  41 +#define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18)
  42 +#define ANA_PORT_PORT_CFG(x) (0x7070 + 0x100 * (x))
  43 +#define ANA_PORT_PORT_CFG_RECV_ENA BIT(6)
  44 +#define ANA_TABLES_MACHDATA 0x8b34
  45 +#define ANA_TABLES_MACLDATA 0x8b38
  46 +#define ANA_TABLES_MACACCESS 0x8b3c
  47 +#define ANA_TABLES_MACACCESS_VALID BIT(11)
  48 +#define ANA_TABLES_MACACCESS_ENTRYTYPE(x) ((x) << 9)
  49 +#define ANA_TABLES_MACACCESS_DEST_IDX(x) ((x) << 3)
  50 +#define ANA_TABLES_MACACCESS_MAC_TABLE_CMD(x) (x)
  51 +#define ANA_TABLES_MACACCESS_MAC_TABLE_CMD_M GENMASK(2, 0)
  52 +#define MACACCESS_CMD_IDLE 0
  53 +#define MACACCESS_CMD_LEARN 1
  54 +#define MACACCESS_CMD_GET_NEXT 4
  55 +#define ANA_PGID(x) (0x8c00 + 4 * (x))
  56 +
  57 +#define SYS_FRM_AGING 0x574
  58 +#define SYS_FRM_AGING_ENA BIT(20)
  59 +
  60 +#define SYS_SYSTEM_RST_CFG 0x508
  61 +#define SYS_SYSTEM_RST_MEM_INIT BIT(0)
  62 +#define SYS_SYSTEM_RST_MEM_ENA BIT(1)
  63 +#define SYS_SYSTEM_RST_CORE_ENA BIT(2)
  64 +#define SYS_PORT_MODE(x) (0x514 + 0x4 * (x))
  65 +#define SYS_PORT_MODE_INCL_INJ_HDR(x) ((x) << 3)
  66 +#define SYS_PORT_MODE_INCL_INJ_HDR_M GENMASK(4, 3)
  67 +#define SYS_PORT_MODE_INCL_XTR_HDR(x) ((x) << 1)
  68 +#define SYS_PORT_MODE_INCL_XTR_HDR_M GENMASK(2, 1)
  69 +#define SYS_PAUSE_CFG(x) (0x608 + 0x4 * (x))
  70 +#define SYS_PAUSE_CFG_PAUSE_ENA BIT(0)
  71 +
  72 +#define QSYS_SWITCH_PORT_MODE(x) (0x11234 + 0x4 * (x))
  73 +#define QSYS_SWITCH_PORT_MODE_PORT_ENA BIT(14)
  74 +#define QSYS_QMAP 0x112d8
  75 +#define QSYS_EGR_NO_SHARING 0x1129c
  76 +
  77 +/* Port registers */
  78 +#define DEV_CLOCK_CFG 0x0
  79 +#define DEV_CLOCK_CFG_LINK_SPEED_1000 1
  80 +#define DEV_MAC_ENA_CFG 0x1c
  81 +#define DEV_MAC_ENA_CFG_RX_ENA BIT(4)
  82 +#define DEV_MAC_ENA_CFG_TX_ENA BIT(0)
  83 +
  84 +#define DEV_MAC_IFG_CFG 0x30
  85 +#define DEV_MAC_IFG_CFG_TX_IFG(x) ((x) << 8)
  86 +#define DEV_MAC_IFG_CFG_RX_IFG2(x) ((x) << 4)
  87 +#define DEV_MAC_IFG_CFG_RX_IFG1(x) (x)
  88 +
  89 +#define PCS1G_CFG 0x48
  90 +#define PCS1G_MODE_CFG_SGMII_MODE_ENA BIT(0)
  91 +#define PCS1G_MODE_CFG 0x4c
  92 +#define PCS1G_MODE_CFG_UNIDIR_MODE_ENA BIT(4)
  93 +#define PCS1G_MODE_CFG_SGMII_MODE_ENA BIT(0)
  94 +#define PCS1G_SD_CFG 0x50
  95 +#define PCS1G_ANEG_CFG 0x54
  96 +#define PCS1G_ANEG_CFG_ADV_ABILITY(x) ((x) << 16)
  97 +
  98 +#define QS_XTR_GRP_CFG(x) (4 * (x))
  99 +#define QS_XTR_GRP_CFG_MODE(x) ((x) << 2)
  100 +#define QS_XTR_GRP_CFG_STATUS_WORD_POS BIT(1)
  101 +#define QS_XTR_GRP_CFG_BYTE_SWAP BIT(0)
  102 +#define QS_XTR_RD(x) (0x8 + 4 * (x))
  103 +#define QS_XTR_FLUSH 0x18
  104 +#define QS_XTR_FLUSH_FLUSH GENMASK(1, 0)
  105 +#define QS_XTR_DATA_PRESENT 0x1c
  106 +#define QS_INJ_GRP_CFG(x) (0x24 + (x) * 4)
  107 +#define QS_INJ_GRP_CFG_MODE(x) ((x) << 2)
  108 +#define QS_INJ_GRP_CFG_BYTE_SWAP BIT(0)
  109 +#define QS_INJ_WR(x) (0x2c + 4 * (x))
  110 +#define QS_INJ_CTRL(x) (0x34 + 4 * (x))
  111 +#define QS_INJ_CTRL_GAP_SIZE(x) ((x) << 21)
  112 +#define QS_INJ_CTRL_EOF BIT(19)
  113 +#define QS_INJ_CTRL_SOF BIT(18)
  114 +#define QS_INJ_CTRL_VLD_BYTES(x) ((x) << 16)
  115 +
  116 +#define XTR_EOF_0 ntohl(0x80000000u)
  117 +#define XTR_EOF_1 ntohl(0x80000001u)
  118 +#define XTR_EOF_2 ntohl(0x80000002u)
  119 +#define XTR_EOF_3 ntohl(0x80000003u)
  120 +#define XTR_PRUNED ntohl(0x80000004u)
  121 +#define XTR_ABORT ntohl(0x80000005u)
  122 +#define XTR_ESCAPE ntohl(0x80000006u)
  123 +#define XTR_NOT_READY ntohl(0x80000007u)
  124 +
  125 +#define IFH_INJ_BYPASS BIT(31)
  126 +#define IFH_TAG_TYPE_C 0
  127 +#define XTR_VALID_BYTES(x) (4 - ((x) & 3))
  128 +#define MAC_VID 1
  129 +#define CPU_PORT 11
  130 +#define INTERNAL_PORT_MSK 0xF
  131 +#define IFH_LEN 4
  132 +#define OCELOT_BUF_CELL_SZ 60
  133 +#define ETH_ALEN 6
  134 +#define PGID_BROADCAST 13
  135 +#define PGID_UNICAST 14
  136 +#define PGID_SRC 80
  137 +
  138 +enum ocelot_target {
  139 + ANA,
  140 + QS,
  141 + QSYS,
  142 + REW,
  143 + SYS,
  144 + HSIO,
  145 + PORT0,
  146 + PORT1,
  147 + PORT2,
  148 + PORT3,
  149 + TARGET_MAX,
  150 +};
  151 +
  152 +#define MAX_PORT (PORT3 - PORT0)
  153 +
  154 +/* MAC table entry types.
  155 + * ENTRYTYPE_NORMAL is subject to aging.
  156 + * ENTRYTYPE_LOCKED is not subject to aging.
  157 + * ENTRYTYPE_MACv4 is not subject to aging. For IPv4 multicast.
  158 + * ENTRYTYPE_MACv6 is not subject to aging. For IPv6 multicast.
  159 + */
  160 +enum macaccess_entry_type {
  161 + ENTRYTYPE_NORMAL = 0,
  162 + ENTRYTYPE_LOCKED,
  163 + ENTRYTYPE_MACv4,
  164 + ENTRYTYPE_MACv6,
  165 +};
  166 +
  167 +enum ocelot_mdio_target {
  168 + MIIM,
  169 + PHY,
  170 + TARGET_MDIO_MAX,
  171 +};
  172 +
  173 +enum ocelot_phy_id {
  174 + INTERNAL,
  175 + EXTERNAL,
  176 + NUM_PHY,
  177 +};
  178 +
  179 +struct ocelot_private {
  180 + void __iomem *regs[TARGET_MAX];
  181 +
  182 + struct mii_dev *bus[NUM_PHY];
  183 + struct phy_device *phydev;
  184 + int phy_mode;
  185 + int max_speed;
  186 +
  187 + int rx_pos;
  188 + int rx_siz;
  189 + int rx_off;
  190 + int tx_num;
  191 +
  192 + u8 tx_adj_packetbuf[PKTSIZE_ALIGN + PKTALIGN];
  193 + void *tx_adj_buf;
  194 +};
  195 +
  196 +struct mscc_miim_dev {
  197 + void __iomem *regs;
  198 + void __iomem *phy_regs;
  199 +};
  200 +
  201 +struct mscc_miim_dev miim[NUM_PHY];
  202 +
  203 +static int mscc_miim_wait_ready(struct mscc_miim_dev *miim)
  204 +{
  205 + return wait_for_bit_le32(miim->regs + MIIM_STATUS, MIIM_STAT_BUSY,
  206 + false, 250, false);
  207 +}
  208 +
  209 +static int mscc_miim_reset(struct mii_dev *bus)
  210 +{
  211 + struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
  212 +
  213 + if (miim->phy_regs) {
  214 + writel(0, miim->phy_regs + PHY_CFG);
  215 + writel(PHY_CFG_RST | PHY_CFG_COMMON_RST
  216 + | PHY_CFG_ENA, miim->phy_regs + PHY_CFG);
  217 + mdelay(500);
  218 + }
  219 +
  220 + return 0;
  221 +}
  222 +
  223 +static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg)
  224 +{
  225 + struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
  226 + u32 val;
  227 + int ret;
  228 +
  229 + ret = mscc_miim_wait_ready(miim);
  230 + if (ret)
  231 + goto out;
  232 +
  233 + writel(MIIM_CMD_VLD | MIIM_CMD_PHYAD(addr) |
  234 + MIIM_CMD_REGAD(reg) | MIIM_CMD_OPR_READ,
  235 + miim->regs + MIIM_CMD);
  236 +
  237 + ret = mscc_miim_wait_ready(miim);
  238 + if (ret)
  239 + goto out;
  240 +
  241 + val = readl(miim->regs + MIIM_DATA);
  242 + if (val & MIIM_DATA_ERROR) {
  243 + ret = -EIO;
  244 + goto out;
  245 + }
  246 +
  247 + ret = val & 0xFFFF;
  248 + out:
  249 + return ret;
  250 +}
  251 +
  252 +static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg,
  253 + u16 val)
  254 +{
  255 + struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
  256 + int ret;
  257 +
  258 + ret = mscc_miim_wait_ready(miim);
  259 + if (ret < 0)
  260 + goto out;
  261 +
  262 + writel(MIIM_CMD_VLD | MIIM_CMD_PHYAD(addr) |
  263 + MIIM_CMD_REGAD(reg) | MIIM_CMD_WRDATA(val) |
  264 + MIIM_CMD_OPR_WRITE, miim->regs + MIIM_CMD);
  265 + out:
  266 + return ret;
  267 +}
  268 +
  269 +/* For now only setup the internal mdio bus */
  270 +static struct mii_dev *ocelot_mdiobus_init(struct udevice *dev)
  271 +{
  272 + unsigned long phy_size[TARGET_MAX];
  273 + phys_addr_t phy_base[TARGET_MAX];
  274 + struct ofnode_phandle_args phandle;
  275 + ofnode eth_node, node, mdio_node;
  276 + struct resource res;
  277 + struct mii_dev *bus;
  278 + fdt32_t faddr;
  279 + int i;
  280 +
  281 + bus = mdio_alloc();
  282 +
  283 + if (!bus)
  284 + return NULL;
  285 +
  286 + /* gathered only the first mdio bus */
  287 + eth_node = dev_read_first_subnode(dev);
  288 + node = ofnode_first_subnode(eth_node);
  289 + ofnode_parse_phandle_with_args(node, "phy-handle", NULL, 0, 0,
  290 + &phandle);
  291 + mdio_node = ofnode_get_parent(phandle.node);
  292 +
  293 + for (i = 0; i < TARGET_MDIO_MAX; i++) {
  294 + if (ofnode_read_resource(mdio_node, i, &res)) {
  295 + pr_err("%s: get OF resource failed\n", __func__);
  296 + return NULL;
  297 + }
  298 + faddr = cpu_to_fdt32(res.start);
  299 + phy_base[i] = ofnode_translate_address(mdio_node, &faddr);
  300 + phy_size[i] = res.end - res.start;
  301 + }
  302 +
  303 + strcpy(bus->name, "miim-internal");
  304 + miim[INTERNAL].phy_regs = ioremap(phy_base[PHY], phy_size[PHY]);
  305 + miim[INTERNAL].regs = ioremap(phy_base[MIIM], phy_size[MIIM]);
  306 + bus->priv = &miim[INTERNAL];
  307 + bus->reset = mscc_miim_reset;
  308 + bus->read = mscc_miim_read;
  309 + bus->write = mscc_miim_write;
  310 +
  311 + if (mdio_register(bus))
  312 + return NULL;
  313 + else
  314 + return bus;
  315 +}
  316 +
  317 +__weak void mscc_switch_reset(void)
  318 +{
  319 +}
  320 +
  321 +static void ocelot_stop(struct udevice *dev)
  322 +{
  323 + struct ocelot_private *priv = dev_get_priv(dev);
  324 + int i;
  325 +
  326 + mscc_switch_reset();
  327 + for (i = 0; i < NUM_PHY; i++)
  328 + if (priv->bus[i])
  329 + mscc_miim_reset(priv->bus[i]);
  330 +}
  331 +
  332 +static void ocelot_cpu_capture_setup(struct ocelot_private *priv)
  333 +{
  334 + int i;
  335 +
  336 + /* map the 8 CPU extraction queues to CPU port 11 */
  337 + writel(0, priv->regs[QSYS] + QSYS_QMAP);
  338 +
  339 + for (i = 0; i <= 1; i++) {
  340 + /*
  341 + * Do byte-swap and expect status after last data word
  342 + * Extraction: Mode: manual extraction) | Byte_swap
  343 + */
  344 + writel(QS_XTR_GRP_CFG_MODE(1) | QS_XTR_GRP_CFG_BYTE_SWAP,
  345 + priv->regs[QS] + QS_XTR_GRP_CFG(i));
  346 + /*
  347 + * Injection: Mode: manual extraction | Byte_swap
  348 + */
  349 + writel(QS_INJ_GRP_CFG_MODE(1) | QS_INJ_GRP_CFG_BYTE_SWAP,
  350 + priv->regs[QS] + QS_INJ_GRP_CFG(i));
  351 + }
  352 +
  353 + for (i = 0; i <= 1; i++)
  354 + /* Enable IFH insertion/parsing on CPU ports */
  355 + writel(SYS_PORT_MODE_INCL_INJ_HDR(1) |
  356 + SYS_PORT_MODE_INCL_XTR_HDR(1),
  357 + priv->regs[SYS] + SYS_PORT_MODE(CPU_PORT + i));
  358 + /*
  359 + * Setup the CPU port as VLAN aware to support switching frames
  360 + * based on tags
  361 + */
  362 + writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) |
  363 + MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(CPU_PORT));
  364 +
  365 + /* Disable learning (only RECV_ENA must be set) */
  366 + writel(ANA_PORT_PORT_CFG_RECV_ENA,
  367 + priv->regs[ANA] + ANA_PORT_PORT_CFG(CPU_PORT));
  368 +
  369 + /* Enable switching to/from cpu port */
  370 + setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(CPU_PORT),
  371 + QSYS_SWITCH_PORT_MODE_PORT_ENA);
  372 +
  373 + /* No pause on CPU port - not needed (off by default) */
  374 + clrbits_le32(priv->regs[SYS] + SYS_PAUSE_CFG(CPU_PORT),
  375 + SYS_PAUSE_CFG_PAUSE_ENA);
  376 +
  377 + setbits_le32(priv->regs[QSYS] + QSYS_EGR_NO_SHARING, BIT(CPU_PORT));
  378 +}
  379 +
  380 +static void ocelot_port_init(struct ocelot_private *priv, int port)
  381 +{
  382 + void __iomem *regs = priv->regs[port];
  383 +
  384 + /* Enable PCS */
  385 + writel(PCS1G_MODE_CFG_SGMII_MODE_ENA, regs + PCS1G_CFG);
  386 +
  387 + /* Disable Signal Detect */
  388 + writel(0, regs + PCS1G_SD_CFG);
  389 +
  390 + /* Enable MAC RX and TX */
  391 + writel(DEV_MAC_ENA_CFG_RX_ENA | DEV_MAC_ENA_CFG_TX_ENA,
  392 + regs + DEV_MAC_ENA_CFG);
  393 +
  394 + /* Clear sgmii_mode_ena */
  395 + writel(0, regs + PCS1G_MODE_CFG);
  396 +
  397 + /*
  398 + * Clear sw_resolve_ena(bit 0) and set adv_ability to
  399 + * something meaningful just in case
  400 + */
  401 + writel(PCS1G_ANEG_CFG_ADV_ABILITY(0x20), regs + PCS1G_ANEG_CFG);
  402 +
  403 + /* Set MAC IFG Gaps */
  404 + writel(DEV_MAC_IFG_CFG_TX_IFG(5) | DEV_MAC_IFG_CFG_RX_IFG1(5) |
  405 + DEV_MAC_IFG_CFG_RX_IFG2(1), regs + DEV_MAC_IFG_CFG);
  406 +
  407 + /* Set link speed and release all resets */
  408 + writel(DEV_CLOCK_CFG_LINK_SPEED_1000, regs + DEV_CLOCK_CFG);
  409 +
  410 + /* Make VLAN aware for CPU traffic */
  411 + writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) |
  412 + MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0));
  413 +
  414 + /* Enable the port in the core */
  415 + setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(port - PORT0),
  416 + QSYS_SWITCH_PORT_MODE_PORT_ENA);
  417 +}
  418 +
  419 +static int ocelot_switch_init(struct ocelot_private *priv)
  420 +{
  421 + /* Reset switch & memories */
  422 + writel(SYS_SYSTEM_RST_MEM_ENA | SYS_SYSTEM_RST_MEM_INIT,
  423 + priv->regs[SYS] + SYS_SYSTEM_RST_CFG);
  424 +
  425 + /* Wait to complete */
  426 + if (wait_for_bit_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
  427 + SYS_SYSTEM_RST_MEM_INIT, false, 2000, false)) {
  428 + pr_err("Timeout in memory reset\n");
  429 + return -EIO;
  430 + }
  431 +
  432 + /* Enable switch core */
  433 + setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
  434 + SYS_SYSTEM_RST_CORE_ENA);
  435 +
  436 + return 0;
  437 +}
  438 +
  439 +static void ocelot_switch_flush(struct ocelot_private *priv)
  440 +{
  441 + /* All Queues flush */
  442 + setbits_le32(priv->regs[QS] + QS_XTR_FLUSH, QS_XTR_FLUSH_FLUSH);
  443 + /* Allow to drain */
  444 + mdelay(1);
  445 + /* All Queues normal */
  446 + clrbits_le32(priv->regs[QS] + QS_XTR_FLUSH, QS_XTR_FLUSH_FLUSH);
  447 +}
  448 +
  449 +static int ocelot_initialize(struct ocelot_private *priv)
  450 +{
  451 + int ret, i;
  452 +
  453 + /* Initialize switch memories, enable core */
  454 + ret = ocelot_switch_init(priv);
  455 + if (ret)
  456 + return ret;
  457 + /*
  458 + * Disable port-to-port by switching
  459 + * Put fron ports in "port isolation modes" - i.e. they cant send
  460 + * to other ports - via the PGID sorce masks.
  461 + */
  462 + for (i = 0; i <= MAX_PORT; i++)
  463 + writel(0, priv->regs[ANA] + ANA_PGID(PGID_SRC + i));
  464 +
  465 + /* Flush queues */
  466 + ocelot_switch_flush(priv);
  467 +
  468 + /* Setup frame ageing - "2 sec" - The unit is 6.5us on Ocelot */
  469 + writel(SYS_FRM_AGING_ENA | (20000000 / 65),
  470 + priv->regs[SYS] + SYS_FRM_AGING);
  471 +
  472 + for (i = PORT0; i <= PORT3; i++)
  473 + ocelot_port_init(priv, i);
  474 +
  475 + ocelot_cpu_capture_setup(priv);
  476 +
  477 + debug("Ports enabled\n");
  478 +
  479 + return 0;
  480 +}
  481 +
  482 +static inline int ocelot_vlant_wait_for_completion(struct ocelot_private *priv)
  483 +{
  484 + unsigned int val, timeout = 10;
  485 +
  486 + /* Wait for the issued mac table command to be completed, or timeout.
  487 + * When the command read from ANA_TABLES_MACACCESS is
  488 + * MACACCESS_CMD_IDLE, the issued command completed successfully.
  489 + */
  490 + do {
  491 + val = readl(priv->regs[ANA] + ANA_TABLES_MACACCESS);
  492 + val &= ANA_TABLES_MACACCESS_MAC_TABLE_CMD_M;
  493 + } while (val != MACACCESS_CMD_IDLE && timeout--);
  494 +
  495 + if (!timeout)
  496 + return -ETIMEDOUT;
  497 +
  498 + return 0;
  499 +}
  500 +
  501 +static int ocelot_mac_table_add(struct ocelot_private *priv,
  502 + const unsigned char mac[ETH_ALEN], int pgid)
  503 +{
  504 + u32 macl = 0, mach = 0;
  505 + int ret;
  506 +
  507 + /* Set the MAC address to handle and the vlan associated in a format
  508 + * understood by the hardware.
  509 + */
  510 + mach |= MAC_VID << 16;
  511 + mach |= ((u32)mac[0]) << 8;
  512 + mach |= ((u32)mac[1]) << 0;
  513 + macl |= ((u32)mac[2]) << 24;
  514 + macl |= ((u32)mac[3]) << 16;
  515 + macl |= ((u32)mac[4]) << 8;
  516 + macl |= ((u32)mac[5]) << 0;
  517 +
  518 + writel(macl, priv->regs[ANA] + ANA_TABLES_MACLDATA);
  519 + writel(mach, priv->regs[ANA] + ANA_TABLES_MACHDATA);
  520 +
  521 + writel(ANA_TABLES_MACACCESS_VALID |
  522 + ANA_TABLES_MACACCESS_DEST_IDX(pgid) |
  523 + ANA_TABLES_MACACCESS_ENTRYTYPE(ENTRYTYPE_LOCKED) |
  524 + ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_LEARN),
  525 + priv->regs[ANA] + ANA_TABLES_MACACCESS);
  526 +
  527 + ret = ocelot_vlant_wait_for_completion(priv);
  528 +
  529 + return ret;
  530 +}
  531 +
  532 +static int ocelot_write_hwaddr(struct udevice *dev)
  533 +{
  534 + struct ocelot_private *priv = dev_get_priv(dev);
  535 + struct eth_pdata *pdata = dev_get_platdata(dev);
  536 +
  537 + ocelot_mac_table_add(priv, pdata->enetaddr, PGID_UNICAST);
  538 +
  539 + writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
  540 +
  541 + return 0;
  542 +}
  543 +
  544 +static int ocelot_start(struct udevice *dev)
  545 +{
  546 + struct ocelot_private *priv = dev_get_priv(dev);
  547 + struct eth_pdata *pdata = dev_get_platdata(dev);
  548 + const unsigned char mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff,
  549 + 0xff };
  550 + int ret;
  551 +
  552 + ret = ocelot_initialize(priv);
  553 + if (ret)
  554 + return ret;
  555 +
  556 + /* Set MAC address tables entries for CPU redirection */
  557 + ocelot_mac_table_add(priv, mac, PGID_BROADCAST);
  558 +
  559 + writel(BIT(CPU_PORT) | INTERNAL_PORT_MSK,
  560 + priv->regs[ANA] + ANA_PGID(PGID_BROADCAST));
  561 +
  562 + /* It should be setup latter in ocelot_write_hwaddr */
  563 + ocelot_mac_table_add(priv, pdata->enetaddr, PGID_UNICAST);
  564 +
  565 + writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
  566 +
  567 + return 0;
  568 +}
  569 +
  570 +static int ocelot_send(struct udevice *dev, void *packet, int length)
  571 +{
  572 + struct ocelot_private *priv = dev_get_priv(dev);
  573 + u32 ifh[IFH_LEN];
  574 + int port = BIT(0); /* use port 0 */
  575 + u8 grp = 0; /* Send everything on CPU group 0 */
  576 + int i, count = (length + 3) / 4, last = length % 4;
  577 + u32 *buf = packet;
  578 +
  579 + writel(QS_INJ_CTRL_GAP_SIZE(1) | QS_INJ_CTRL_SOF,
  580 + priv->regs[QS] + QS_INJ_CTRL(grp));
  581 +
  582 + /*
  583 + * Generate the IFH for frame injection
  584 + *
  585 + * The IFH is a 128bit-value
  586 + * bit 127: bypass the analyzer processing
  587 + * bit 56-67: destination mask
  588 + * bit 28-29: pop_cnt: 3 disables all rewriting of the frame
  589 + * bit 20-27: cpu extraction queue mask
  590 + * bit 16: tag type 0: C-tag, 1: S-tag
  591 + * bit 0-11: VID
  592 + */
  593 + ifh[0] = IFH_INJ_BYPASS;
  594 + ifh[1] = (0xf00 & port) >> 8;
  595 + ifh[2] = (0xff & port) << 24;
  596 + ifh[3] = (IFH_TAG_TYPE_C << 16);
  597 +
  598 + for (i = 0; i < IFH_LEN; i++)
  599 + writel(ifh[i], priv->regs[QS] + QS_INJ_WR(grp));
  600 +
  601 + for (i = 0; i < count; i++)
  602 + writel(buf[i], priv->regs[QS] + QS_INJ_WR(grp));
  603 +
  604 + /* Add padding */
  605 + while (i < (OCELOT_BUF_CELL_SZ / 4)) {
  606 + writel(0, priv->regs[QS] + QS_INJ_WR(grp));
  607 + i++;
  608 + }
  609 +
  610 + /* Indicate EOF and valid bytes in last word */
  611 + writel(QS_INJ_CTRL_GAP_SIZE(1) |
  612 + QS_INJ_CTRL_VLD_BYTES(length < OCELOT_BUF_CELL_SZ ? 0 : last) |
  613 + QS_INJ_CTRL_EOF, priv->regs[QS] + QS_INJ_CTRL(grp));
  614 +
  615 + /* Add dummy CRC */
  616 + writel(0, priv->regs[QS] + QS_INJ_WR(grp));
  617 +
  618 + return 0;
  619 +}
  620 +
  621 +static int ocelot_recv(struct udevice *dev, int flags, uchar **packetp)
  622 +{
  623 + struct ocelot_private *priv = dev_get_priv(dev);
  624 + u8 grp = 0; /* Send everything on CPU group 0 */
  625 + u32 *rxbuf = (u32 *)net_rx_packets[0];
  626 + int i, byte_cnt = 0;
  627 + bool eof_flag = false, pruned_flag = false, abort_flag = false;
  628 +
  629 + if (!(readl(priv->regs[QS] + QS_XTR_DATA_PRESENT) & BIT(grp)))
  630 + return -EAGAIN;
  631 +
  632 + /* skip IFH */
  633 + for (i = 0; i < IFH_LEN; i++)
  634 + readl(priv->regs[QS] + QS_XTR_RD(grp));
  635 +
  636 + while (!eof_flag) {
  637 + u32 val = readl(priv->regs[QS] + QS_XTR_RD(grp));
  638 +
  639 + switch (val) {
  640 + case XTR_NOT_READY:
  641 + debug("%d NOT_READY...?\n", byte_cnt);
  642 + break;
  643 + case XTR_ABORT:
  644 + /* really nedeed?? not done in linux */
  645 + *rxbuf = readl(priv->regs[QS] + QS_XTR_RD(grp));
  646 + abort_flag = true;
  647 + eof_flag = true;
  648 + debug("XTR_ABORT\n");
  649 + break;
  650 + case XTR_EOF_0:
  651 + case XTR_EOF_1:
  652 + case XTR_EOF_2:
  653 + case XTR_EOF_3:
  654 + byte_cnt += XTR_VALID_BYTES(val);
  655 + *rxbuf = readl(priv->regs[QS] + QS_XTR_RD(grp));
  656 + eof_flag = true;
  657 + debug("EOF\n");
  658 + break;
  659 + case XTR_PRUNED:
  660 + /* But get the last 4 bytes as well */
  661 + eof_flag = true;
  662 + pruned_flag = true;
  663 + debug("PRUNED\n");
  664 + /* fallthrough */
  665 + case XTR_ESCAPE:
  666 + *rxbuf = readl(priv->regs[QS] + QS_XTR_RD(grp));
  667 + byte_cnt += 4;
  668 + rxbuf++;
  669 + debug("ESCAPED\n");
  670 + break;
  671 + default:
  672 + *rxbuf = val;
  673 + byte_cnt += 4;
  674 + rxbuf++;
  675 + }
  676 + }
  677 +
  678 + if (abort_flag || pruned_flag || !eof_flag) {
  679 + debug("Discarded frame: abort:%d pruned:%d eof:%d\n",
  680 + abort_flag, pruned_flag, eof_flag);
  681 + return -EAGAIN;
  682 + }
  683 +
  684 + *packetp = net_rx_packets[0];
  685 +
  686 + return byte_cnt;
  687 +}
  688 +
  689 +static int ocelot_probe(struct udevice *dev)
  690 +{
  691 + struct ocelot_private *priv = dev_get_priv(dev);
  692 + int ret, i;
  693 +
  694 + struct {
  695 + enum ocelot_target id;
  696 + char *name;
  697 + } reg[] = {
  698 + { SYS, "sys" },
  699 + { REW, "rew" },
  700 + { QSYS, "qsys" },
  701 + { ANA, "ana" },
  702 + { QS, "qs" },
  703 + { HSIO, "hsio" },
  704 + { PORT0, "port0" },
  705 + { PORT1, "port1" },
  706 + { PORT2, "port2" },
  707 + { PORT3, "port3" },
  708 + };
  709 +
  710 + for (i = 0; i < ARRAY_SIZE(reg); i++) {
  711 + priv->regs[reg[i].id] = dev_remap_addr_name(dev, reg[i].name);
  712 + if (!priv->regs[reg[i].id]) {
  713 + pr_err
  714 + ("Error %d: can't get regs base addresses for %s\n",
  715 + ret, reg[i].name);
  716 + return -ENOMEM;
  717 + }
  718 + }
  719 +
  720 + priv->bus[INTERNAL] = ocelot_mdiobus_init(dev);
  721 +
  722 + for (i = 0; i < 4; i++) {
  723 + phy_connect(priv->bus[INTERNAL], i, dev,
  724 + PHY_INTERFACE_MODE_NONE);
  725 + }
  726 +
  727 + return 0;
  728 +}
  729 +
  730 +static int ocelot_remove(struct udevice *dev)
  731 +{
  732 + struct ocelot_private *priv = dev_get_priv(dev);
  733 + int i;
  734 +
  735 + for (i = 0; i < NUM_PHY; i++) {
  736 + mdio_unregister(priv->bus[i]);
  737 + mdio_free(priv->bus[i]);
  738 + }
  739 +
  740 + return 0;
  741 +}
  742 +
  743 +static const struct eth_ops ocelot_ops = {
  744 + .start = ocelot_start,
  745 + .stop = ocelot_stop,
  746 + .send = ocelot_send,
  747 + .recv = ocelot_recv,
  748 + .write_hwaddr = ocelot_write_hwaddr,
  749 +};
  750 +
  751 +static const struct udevice_id mscc_ocelot_ids[] = {
  752 + {.compatible = "mscc,vsc7514-switch"},
  753 + { /* Sentinel */ }
  754 +};
  755 +
  756 +U_BOOT_DRIVER(ocelot) = {
  757 + .name = "ocelot-switch",
  758 + .id = UCLASS_ETH,
  759 + .of_match = mscc_ocelot_ids,
  760 + .probe = ocelot_probe,
  761 + .remove = ocelot_remove,
  762 + .ops = &ocelot_ops,
  763 + .priv_auto_alloc_size = sizeof(struct ocelot_private),
  764 + .platdata_auto_alloc_size = sizeof(struct eth_pdata),
  765 +};