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