uboot/drivers/net/mscc_eswitch/luton_switch.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
   2/*
   3 * Copyright (c) 2019 Microsemi Corporation
   4 */
   5
   6#include <common.h>
   7#include <config.h>
   8#include <dm.h>
   9#include <malloc.h>
  10#include <dm/of_access.h>
  11#include <dm/of_addr.h>
  12#include <fdt_support.h>
  13#include <linux/bitops.h>
  14#include <linux/io.h>
  15#include <linux/ioport.h>
  16#include <miiphy.h>
  17#include <net.h>
  18#include <wait_bit.h>
  19
  20#include "mscc_xfer.h"
  21#include "mscc_mac_table.h"
  22#include "mscc_miim.h"
  23
  24#define ANA_PORT_VLAN_CFG(x)            (0x00 + 0x80 * (x))
  25#define         ANA_PORT_VLAN_CFG_AWARE_ENA     BIT(20)
  26#define         ANA_PORT_VLAN_CFG_POP_CNT(x)    ((x) << 18)
  27#define ANA_PORT_CPU_FWD_CFG(x)         (0x50 + 0x80 * (x))
  28#define         ANA_PORT_CPU_FWD_CFG_SRC_COPY_ENA       BIT(1)
  29#define ANA_PORT_PORT_CFG(x)            (0x60 + 0x80 * (x))
  30#define         ANA_PORT_PORT_CFG_RECV_ENA      BIT(5)
  31#define ANA_PGID(x)                     (0x1000 + 4 * (x))
  32
  33#define SYS_FRM_AGING                   0x8300
  34
  35#define SYS_SYSTEM_RST_CFG              0x81b0
  36#define         SYS_SYSTEM_RST_MEM_INIT         BIT(0)
  37#define         SYS_SYSTEM_RST_MEM_ENA          BIT(1)
  38#define         SYS_SYSTEM_RST_CORE_ENA         BIT(2)
  39#define SYS_PORT_MODE(x)                (0x81bc + 0x4 * (x))
  40#define         SYS_PORT_MODE_INCL_INJ_HDR      BIT(0)
  41#define SYS_SWITCH_PORT_MODE(x)         (0x8294 + 0x4 * (x))
  42#define         SYS_SWITCH_PORT_MODE_PORT_ENA   BIT(3)
  43#define SYS_EGR_NO_SHARING              0x8378
  44#define SYS_SCH_CPU                     0x85a0
  45
  46#define REW_PORT_CFG(x)                 (0x8 + 0x80 * (x))
  47#define         REW_PORT_CFG_IFH_INSERT_ENA     BIT(7)
  48
  49#define GCB_DEVCPU_RST_SOFT_CHIP_RST    0x90
  50#define         GCB_DEVCPU_RST_SOFT_CHIP_RST_SOFT_PHY   BIT(1)
  51#define GCB_MISC_STAT                   0x11c
  52#define         GCB_MISC_STAT_PHY_READY                 BIT(3)
  53
  54#define QS_XTR_MAP(x)                   (0x10 + 4 * (x))
  55#define         QS_XTR_MAP_GRP                  BIT(4)
  56#define         QS_XTR_MAP_ENA                  BIT(0)
  57
  58#define HSIO_PLL5G_CFG_PLL5G_CFG2       0x8
  59
  60#define HSIO_RCOMP_CFG_CFG0             0x20
  61#define         HSIO_RCOMP_CFG_CFG0_MODE_SEL(x)                 ((x) << 8)
  62#define         HSIO_RCOMP_CFG_CFG0_RUN_CAL                     BIT(12)
  63#define HSIO_RCOMP_STATUS               0x24
  64#define         HSIO_RCOMP_STATUS_BUSY                          BIT(12)
  65#define         HSIO_RCOMP_STATUS_RCOMP_M                       GENMASK(3, 0)
  66#define HSIO_SERDES6G_ANA_CFG_DES_CFG   0x64
  67#define         HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_ANA(x)         ((x) << 1)
  68#define         HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_HYST(x)        ((x) << 5)
  69#define         HSIO_SERDES6G_ANA_CFG_DES_CFG_MBTR_CTRL(x)      ((x) << 10)
  70#define         HSIO_SERDES6G_ANA_CFG_DES_CFG_PHS_CTRL(x)       ((x) << 13)
  71#define HSIO_SERDES6G_ANA_CFG_IB_CFG    0x68
  72#define         HSIO_SERDES6G_ANA_CFG_IB_CFG_RESISTOR_CTRL(x)   (x)
  73#define         HSIO_SERDES6G_ANA_CFG_IB_CFG_VBCOM(x)           ((x) << 4)
  74#define         HSIO_SERDES6G_ANA_CFG_IB_CFG_VBAC(x)            ((x) << 7)
  75#define         HSIO_SERDES6G_ANA_CFG_IB_CFG_RT(x)              ((x) << 9)
  76#define         HSIO_SERDES6G_ANA_CFG_IB_CFG_RF(x)              ((x) << 14)
  77#define HSIO_SERDES6G_ANA_CFG_IB_CFG1   0x6c
  78#define         HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST               BIT(0)
  79#define         HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSDC        BIT(2)
  80#define         HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSAC        BIT(3)
  81#define         HSIO_SERDES6G_ANA_CFG_IB_CFG1_ANEG_MODE BIT(6)
  82#define         HSIO_SERDES6G_ANA_CFG_IB_CFG1_CHF               BIT(7)
  83#define         HSIO_SERDES6G_ANA_CFG_IB_CFG1_C(x)              ((x) << 8)
  84#define HSIO_SERDES6G_ANA_CFG_OB_CFG    0x70
  85#define         HSIO_SERDES6G_ANA_CFG_OB_CFG_SR(x)              ((x) << 4)
  86#define         HSIO_SERDES6G_ANA_CFG_OB_CFG_SR_H               BIT(8)
  87#define         HSIO_SERDES6G_ANA_CFG_OB_CFG_POST0(x)           ((x) << 23)
  88#define         HSIO_SERDES6G_ANA_CFG_OB_CFG_POL                BIT(29)
  89#define         HSIO_SERDES6G_ANA_CFG_OB_CFG_ENA1V_MODE BIT(30)
  90#define HSIO_SERDES6G_ANA_CFG_OB_CFG1   0x74
  91#define         HSIO_SERDES6G_ANA_CFG_OB_CFG1_LEV(x)            (x)
  92#define         HSIO_SERDES6G_ANA_CFG_OB_CFG1_ENA_CAS(x)        ((x) << 6)
  93#define HSIO_SERDES6G_ANA_CFG_COMMON_CFG 0x7c
  94#define         HSIO_SERDES6G_ANA_CFG_COMMON_CFG_IF_MODE(x)     (x)
  95#define         HSIO_SERDES6G_ANA_CFG_COMMON_CFG_ENA_LANE       BIT(18)
  96#define         HSIO_SERDES6G_ANA_CFG_COMMON_CFG_SYS_RST        BIT(31)
  97#define HSIO_SERDES6G_ANA_CFG_PLL_CFG   0x80
  98#define         HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_ENA           BIT(7)
  99#define         HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_CTRL_DATA(x)  ((x) << 8)
 100#define HSIO_SERDES6G_ANA_CFG_SER_CFG   0x84
 101#define HSIO_SERDES6G_DIG_CFG_MISC_CFG  0x88
 102#define         HSIO_SERDES6G_DIG_CFG_MISC_CFG_LANE_RST         BIT(0)
 103#define HSIO_MCB_SERDES6G_CFG           0xac
 104#define         HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT               BIT(31)
 105#define         HSIO_MCB_SERDES6G_CFG_ADDR(x)                   (x)
 106
 107#define DEV_GMII_PORT_MODE_CLK          0x0
 108#define         DEV_GMII_PORT_MODE_CLK_PHY_RST  BIT(0)
 109#define DEV_GMII_MAC_CFG_MAC_ENA        0xc
 110#define         DEV_GMII_MAC_CFG_MAC_ENA_RX_ENA         BIT(4)
 111#define         DEV_GMII_MAC_CFG_MAC_ENA_TX_ENA         BIT(0)
 112
 113#define DEV_PORT_MODE_CLK               0x4
 114#define         DEV_PORT_MODE_CLK_PHY_RST               BIT(2)
 115#define         DEV_PORT_MODE_CLK_LINK_SPEED_1000       1
 116#define DEV_MAC_CFG_MAC_ENA             0x10
 117#define         DEV_MAC_CFG_MAC_ENA_RX_ENA              BIT(4)
 118#define         DEV_MAC_CFG_MAC_ENA_TX_ENA              BIT(0)
 119#define DEV_MAC_CFG_MAC_IFG             0x24
 120#define         DEV_MAC_CFG_MAC_IFG_TX_IFG(x)           ((x) << 8)
 121#define         DEV_MAC_CFG_MAC_IFG_RX_IFG2(x)          ((x) << 4)
 122#define         DEV_MAC_CFG_MAC_IFG_RX_IFG1(x)          (x)
 123#define DEV_PCS1G_CFG_PCS1G_CFG         0x40
 124#define         DEV_PCS1G_CFG_PCS1G_CFG_PCS_ENA         BIT(0)
 125#define DEV_PCS1G_CFG_PCS1G_MODE        0x44
 126#define DEV_PCS1G_CFG_PCS1G_SD          0x48
 127#define DEV_PCS1G_CFG_PCS1G_ANEG        0x4c
 128#define         DEV_PCS1G_CFG_PCS1G_ANEG_ADV_ABILITY(x) ((x) << 16)
 129
 130#define IFH_INJ_BYPASS          BIT(31)
 131#define IFH_TAG_TYPE_C          0
 132#define MAC_VID                 1
 133#define CPU_PORT                26
 134#define INTERNAL_PORT_MSK       0xFFFFFF
 135#define IFH_LEN                 2
 136#define ETH_ALEN                6
 137#define PGID_BROADCAST          28
 138#define PGID_UNICAST            29
 139#define PGID_SRC                80
 140
 141static const char * const regs_names[] = {
 142        "port0", "port1", "port2", "port3", "port4", "port5", "port6", "port7",
 143        "port8", "port9", "port10", "port11", "port12", "port13", "port14",
 144        "port15", "port16", "port17", "port18", "port19", "port20", "port21",
 145        "port22", "port23",
 146        "sys", "ana", "rew", "gcb", "qs", "hsio",
 147};
 148
 149#define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1
 150#define MAX_PORT 24
 151
 152enum luton_ctrl_regs {
 153        SYS = MAX_PORT,
 154        ANA,
 155        REW,
 156        GCB,
 157        QS,
 158        HSIO
 159};
 160
 161#define MIN_INT_PORT    0
 162#define PORT10          10
 163#define PORT11          11
 164#define MAX_INT_PORT    12
 165#define MIN_EXT_PORT    MAX_INT_PORT
 166#define MAX_EXT_PORT    MAX_PORT
 167
 168#define LUTON_MIIM_BUS_COUNT 2
 169
 170struct luton_phy_port_t {
 171        size_t phy_addr;
 172        struct mii_dev *bus;
 173        u8 serdes_index;
 174        u8 phy_mode;
 175};
 176
 177struct luton_private {
 178        void __iomem *regs[REGS_NAMES_COUNT];
 179        struct mii_dev *bus[LUTON_MIIM_BUS_COUNT];
 180        struct luton_phy_port_t ports[MAX_PORT];
 181};
 182
 183static const unsigned long luton_regs_qs[] = {
 184        [MSCC_QS_XTR_RD] = 0x18,
 185        [MSCC_QS_XTR_FLUSH] = 0x28,
 186        [MSCC_QS_XTR_DATA_PRESENT] = 0x2c,
 187        [MSCC_QS_INJ_WR] = 0x3c,
 188        [MSCC_QS_INJ_CTRL] = 0x44,
 189};
 190
 191static const unsigned long luton_regs_ana_table[] = {
 192        [MSCC_ANA_TABLES_MACHDATA] = 0x11b0,
 193        [MSCC_ANA_TABLES_MACLDATA] = 0x11b4,
 194        [MSCC_ANA_TABLES_MACACCESS] = 0x11b8,
 195};
 196
 197static struct mscc_miim_dev miim[LUTON_MIIM_BUS_COUNT];
 198static int miim_count = -1;
 199
 200static void luton_stop(struct udevice *dev)
 201{
 202        struct luton_private *priv = dev_get_priv(dev);
 203
 204        /*
 205         * Switch core only reset affects VCORE-III bus and MIPS frequency
 206         * and thereby also the DDR SDRAM controller. The workaround is to
 207         * not to redirect any trafic to the CPU after the data transfer.
 208         */
 209        writel(GENMASK(9, 2), priv->regs[SYS] + SYS_SCH_CPU);
 210}
 211
 212static void luton_cpu_capture_setup(struct luton_private *priv)
 213{
 214        int i;
 215
 216        /* map the 8 CPU extraction queues to CPU port 26 */
 217        writel(0x0, priv->regs[SYS] + SYS_SCH_CPU);
 218
 219        for (i = 0; i <= 1; i++) {
 220                /*
 221                 * One to one mapping from CPU Queue number to Group extraction
 222                 * number
 223                 */
 224                writel(QS_XTR_MAP_ENA | (QS_XTR_MAP_GRP * i),
 225                       priv->regs[QS] + QS_XTR_MAP(i));
 226
 227                /* Enable IFH insertion/parsing on CPU ports */
 228                setbits_le32(priv->regs[REW] + REW_PORT_CFG(CPU_PORT + i),
 229                             REW_PORT_CFG_IFH_INSERT_ENA);
 230
 231                /* Enable IFH parsing on CPU port 0 and 1 */
 232                setbits_le32(priv->regs[SYS] + SYS_PORT_MODE(CPU_PORT + i),
 233                             SYS_PORT_MODE_INCL_INJ_HDR);
 234        }
 235
 236        /* Make VLAN aware for CPU traffic */
 237        writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
 238               ANA_PORT_VLAN_CFG_POP_CNT(1) |
 239               MAC_VID,
 240               priv->regs[ANA] + ANA_PORT_VLAN_CFG(CPU_PORT));
 241
 242        /* Disable learning (only RECV_ENA must be set) */
 243        writel(ANA_PORT_PORT_CFG_RECV_ENA,
 244               priv->regs[ANA] + ANA_PORT_PORT_CFG(CPU_PORT));
 245
 246        /* Enable switching to/from cpu port */
 247        setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(CPU_PORT),
 248                     SYS_SWITCH_PORT_MODE_PORT_ENA);
 249
 250        setbits_le32(priv->regs[SYS] + SYS_EGR_NO_SHARING, BIT(CPU_PORT));
 251}
 252
 253static void luton_gmii_port_init(struct luton_private *priv, int port)
 254{
 255        void __iomem *regs = priv->regs[port];
 256
 257        writel(0, regs + DEV_GMII_PORT_MODE_CLK);
 258
 259        /* Enable MAC RX and TX */
 260        writel(DEV_GMII_MAC_CFG_MAC_ENA_RX_ENA |
 261               DEV_GMII_MAC_CFG_MAC_ENA_TX_ENA,
 262               regs + DEV_GMII_MAC_CFG_MAC_ENA);
 263
 264        /* Make VLAN aware for CPU traffic */
 265        writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
 266               ANA_PORT_VLAN_CFG_POP_CNT(1) |
 267               MAC_VID,
 268               priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
 269
 270        /* Enable switching to/from port */
 271        setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port),
 272                     SYS_SWITCH_PORT_MODE_PORT_ENA);
 273}
 274
 275static void luton_port_init(struct luton_private *priv, int port)
 276{
 277        void __iomem *regs = priv->regs[port];
 278
 279        writel(0, regs + DEV_PORT_MODE_CLK);
 280
 281        /* Enable MAC RX and TX */
 282        writel(DEV_MAC_CFG_MAC_ENA_RX_ENA |
 283               DEV_MAC_CFG_MAC_ENA_TX_ENA,
 284               regs + DEV_MAC_CFG_MAC_ENA);
 285
 286        /* Make VLAN aware for CPU traffic */
 287        writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
 288               ANA_PORT_VLAN_CFG_POP_CNT(1) |
 289               MAC_VID,
 290               priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
 291
 292        /* Enable switching to/from port */
 293        setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port),
 294                     SYS_SWITCH_PORT_MODE_PORT_ENA);
 295}
 296
 297static void luton_ext_port_init(struct luton_private *priv, int port)
 298{
 299        void __iomem *regs = priv->regs[port];
 300
 301        /* Enable PCS */
 302        writel(DEV_PCS1G_CFG_PCS1G_CFG_PCS_ENA,
 303               regs + DEV_PCS1G_CFG_PCS1G_CFG);
 304
 305        /* Disable Signal Detect */
 306        writel(0, regs + DEV_PCS1G_CFG_PCS1G_SD);
 307
 308        /* Enable MAC RX and TX */
 309        writel(DEV_MAC_CFG_MAC_ENA_RX_ENA |
 310               DEV_MAC_CFG_MAC_ENA_TX_ENA,
 311               regs + DEV_MAC_CFG_MAC_ENA);
 312
 313        /* Clear sgmii_mode_ena */
 314        writel(0, regs + DEV_PCS1G_CFG_PCS1G_MODE);
 315
 316        /*
 317         * Clear sw_resolve_ena(bit 0) and set adv_ability to
 318         * something meaningful just in case
 319         */
 320        writel(DEV_PCS1G_CFG_PCS1G_ANEG_ADV_ABILITY(0x20),
 321               regs + DEV_PCS1G_CFG_PCS1G_ANEG);
 322
 323        /* Set MAC IFG Gaps */
 324        writel(DEV_MAC_CFG_MAC_IFG_TX_IFG(7) |
 325               DEV_MAC_CFG_MAC_IFG_RX_IFG1(1) |
 326               DEV_MAC_CFG_MAC_IFG_RX_IFG2(5),
 327               regs + DEV_MAC_CFG_MAC_IFG);
 328
 329        /* Set link speed and release all resets */
 330        writel(DEV_PORT_MODE_CLK_LINK_SPEED_1000,
 331               regs + DEV_PORT_MODE_CLK);
 332
 333        /* Make VLAN aware for CPU traffic */
 334        writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
 335               ANA_PORT_VLAN_CFG_POP_CNT(1) |
 336               MAC_VID,
 337               priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
 338
 339        /* Enable switching to/from port */
 340        setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port),
 341                     SYS_SWITCH_PORT_MODE_PORT_ENA);
 342}
 343
 344static void serdes6g_write(void __iomem *base, u32 addr)
 345{
 346        u32 data;
 347
 348        writel(HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT |
 349               HSIO_MCB_SERDES6G_CFG_ADDR(addr),
 350               base + HSIO_MCB_SERDES6G_CFG);
 351
 352        do {
 353                data = readl(base + HSIO_MCB_SERDES6G_CFG);
 354        } while (data & HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT);
 355}
 356
 357static void serdes6g_setup(void __iomem *base, uint32_t addr,
 358                           phy_interface_t interface)
 359{
 360        writel(HSIO_RCOMP_CFG_CFG0_MODE_SEL(0x3) |
 361               HSIO_RCOMP_CFG_CFG0_RUN_CAL,
 362               base + HSIO_RCOMP_CFG_CFG0);
 363
 364        while (readl(base + HSIO_RCOMP_STATUS) &
 365               HSIO_RCOMP_STATUS_BUSY)
 366                ;
 367
 368        writel(HSIO_SERDES6G_ANA_CFG_OB_CFG_SR(0xb) |
 369               HSIO_SERDES6G_ANA_CFG_OB_CFG_SR_H |
 370               HSIO_SERDES6G_ANA_CFG_OB_CFG_POST0(0x10) |
 371               HSIO_SERDES6G_ANA_CFG_OB_CFG_POL |
 372               HSIO_SERDES6G_ANA_CFG_OB_CFG_ENA1V_MODE,
 373               base + HSIO_SERDES6G_ANA_CFG_OB_CFG);
 374        writel(HSIO_SERDES6G_ANA_CFG_OB_CFG1_LEV(0x18) |
 375               HSIO_SERDES6G_ANA_CFG_OB_CFG1_ENA_CAS(0x1),
 376               base + HSIO_SERDES6G_ANA_CFG_OB_CFG1);
 377        writel(HSIO_SERDES6G_ANA_CFG_IB_CFG_RESISTOR_CTRL(0xc) |
 378               HSIO_SERDES6G_ANA_CFG_IB_CFG_VBCOM(0x4) |
 379               HSIO_SERDES6G_ANA_CFG_IB_CFG_VBAC(0x5) |
 380               HSIO_SERDES6G_ANA_CFG_IB_CFG_RT(0xf) |
 381               HSIO_SERDES6G_ANA_CFG_IB_CFG_RF(0x4),
 382               base + HSIO_SERDES6G_ANA_CFG_IB_CFG);
 383        writel(HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST |
 384               HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSDC |
 385               HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSAC |
 386               HSIO_SERDES6G_ANA_CFG_IB_CFG1_ANEG_MODE |
 387               HSIO_SERDES6G_ANA_CFG_IB_CFG1_CHF |
 388               HSIO_SERDES6G_ANA_CFG_IB_CFG1_C(0x4),
 389               base + HSIO_SERDES6G_ANA_CFG_IB_CFG1);
 390        writel(HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_ANA(0x5) |
 391               HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_HYST(0x5) |
 392               HSIO_SERDES6G_ANA_CFG_DES_CFG_MBTR_CTRL(0x2) |
 393               HSIO_SERDES6G_ANA_CFG_DES_CFG_PHS_CTRL(0x6),
 394               base + HSIO_SERDES6G_ANA_CFG_DES_CFG);
 395        writel(HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_ENA |
 396               HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_CTRL_DATA(0x78),
 397               base + HSIO_SERDES6G_ANA_CFG_PLL_CFG);
 398        writel(HSIO_SERDES6G_ANA_CFG_COMMON_CFG_IF_MODE(0x30) |
 399               HSIO_SERDES6G_ANA_CFG_COMMON_CFG_ENA_LANE,
 400               base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG);
 401        /*
 402         * There are 4 serdes6g, configure all except serdes6g0, therefore
 403         * the address is b1110
 404         */
 405        serdes6g_write(base, addr);
 406
 407        writel(readl(base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG) |
 408               HSIO_SERDES6G_ANA_CFG_COMMON_CFG_SYS_RST,
 409               base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG);
 410        serdes6g_write(base, addr);
 411
 412        clrbits_le32(base + HSIO_SERDES6G_ANA_CFG_IB_CFG1,
 413                     HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST);
 414        writel(HSIO_SERDES6G_DIG_CFG_MISC_CFG_LANE_RST,
 415               base + HSIO_SERDES6G_DIG_CFG_MISC_CFG);
 416        serdes6g_write(base, addr);
 417}
 418
 419static void serdes_setup(struct luton_private *priv)
 420{
 421        size_t mask;
 422        int i = 0;
 423
 424        for (i = 0; i < MAX_PORT; ++i) {
 425                if (!priv->ports[i].bus || priv->ports[i].serdes_index == 0xff)
 426                        continue;
 427
 428                mask = BIT(priv->ports[i].serdes_index);
 429                serdes6g_setup(priv->regs[HSIO], mask, priv->ports[i].phy_mode);
 430        }
 431}
 432
 433static int luton_switch_init(struct luton_private *priv)
 434{
 435        setbits_le32(priv->regs[HSIO] + HSIO_PLL5G_CFG_PLL5G_CFG2, BIT(1));
 436        clrbits_le32(priv->regs[HSIO] + HSIO_PLL5G_CFG_PLL5G_CFG2, BIT(1));
 437
 438        /* Reset switch & memories */
 439        writel(SYS_SYSTEM_RST_MEM_ENA | SYS_SYSTEM_RST_MEM_INIT,
 440               priv->regs[SYS] + SYS_SYSTEM_RST_CFG);
 441
 442        /* Wait to complete */
 443        if (wait_for_bit_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
 444                              SYS_SYSTEM_RST_MEM_INIT, false, 2000, false)) {
 445                printf("Timeout in memory reset\n");
 446        }
 447
 448        /* Enable switch core */
 449        setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
 450                     SYS_SYSTEM_RST_CORE_ENA);
 451
 452        /* Setup the Serdes macros */
 453        serdes_setup(priv);
 454
 455        return 0;
 456}
 457
 458static int luton_initialize(struct luton_private *priv)
 459{
 460        int ret, i;
 461
 462        /* Initialize switch memories, enable core */
 463        ret = luton_switch_init(priv);
 464        if (ret)
 465                return ret;
 466
 467        /*
 468         * Disable port-to-port by switching
 469         * Put front ports in "port isolation modes" - i.e. they can't send
 470         * to other ports - via the PGID sorce masks.
 471         */
 472        for (i = 0; i < MAX_PORT; i++)
 473                writel(0, priv->regs[ANA] + ANA_PGID(PGID_SRC + i));
 474
 475        /* Flush queues */
 476        mscc_flush(priv->regs[QS], luton_regs_qs);
 477
 478        /* Setup frame ageing - "2 sec" - The unit is 4ns on Luton*/
 479        writel(2000000000 / 4,
 480               priv->regs[SYS] + SYS_FRM_AGING);
 481
 482        for (i = 0; i < MAX_PORT; i++) {
 483                if (i < PORT10)
 484                        luton_gmii_port_init(priv, i);
 485                else
 486                        if (i == PORT10 || i == PORT11)
 487                                luton_port_init(priv, i);
 488                        else
 489                                luton_ext_port_init(priv, i);
 490        }
 491
 492        luton_cpu_capture_setup(priv);
 493
 494        return 0;
 495}
 496
 497static int luton_write_hwaddr(struct udevice *dev)
 498{
 499        struct luton_private *priv = dev_get_priv(dev);
 500        struct eth_pdata *pdata = dev_get_plat(dev);
 501
 502        mscc_mac_table_add(priv->regs[ANA], luton_regs_ana_table,
 503                           pdata->enetaddr, PGID_UNICAST);
 504
 505        writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
 506
 507        return 0;
 508}
 509
 510static int luton_start(struct udevice *dev)
 511{
 512        struct luton_private *priv = dev_get_priv(dev);
 513        struct eth_pdata *pdata = dev_get_plat(dev);
 514        const unsigned char mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff,
 515                                              0xff };
 516        int ret;
 517
 518        ret = luton_initialize(priv);
 519        if (ret)
 520                return ret;
 521
 522        /* Set MAC address tables entries for CPU redirection */
 523        mscc_mac_table_add(priv->regs[ANA], luton_regs_ana_table,
 524                           mac, PGID_BROADCAST);
 525
 526        writel(BIT(CPU_PORT) | INTERNAL_PORT_MSK,
 527               priv->regs[ANA] + ANA_PGID(PGID_BROADCAST));
 528
 529        mscc_mac_table_add(priv->regs[ANA], luton_regs_ana_table,
 530                           pdata->enetaddr, PGID_UNICAST);
 531
 532        writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
 533
 534        return 0;
 535}
 536
 537static int luton_send(struct udevice *dev, void *packet, int length)
 538{
 539        struct luton_private *priv = dev_get_priv(dev);
 540        u32 ifh[IFH_LEN];
 541        int port = BIT(0);      /* use port 0 */
 542        u32 *buf = packet;
 543
 544        ifh[0] = IFH_INJ_BYPASS | port;
 545        ifh[1] = (IFH_TAG_TYPE_C << 16);
 546
 547        return mscc_send(priv->regs[QS], luton_regs_qs,
 548                         ifh, IFH_LEN, buf, length);
 549}
 550
 551static int luton_recv(struct udevice *dev, int flags, uchar **packetp)
 552{
 553        struct luton_private *priv = dev_get_priv(dev);
 554        u32 *rxbuf = (u32 *)net_rx_packets[0];
 555        int byte_cnt = 0;
 556
 557        byte_cnt = mscc_recv(priv->regs[QS], luton_regs_qs, rxbuf, IFH_LEN,
 558                             true);
 559
 560        *packetp = net_rx_packets[0];
 561
 562        return byte_cnt;
 563}
 564
 565static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size)
 566{
 567        int i = 0;
 568
 569        for (i = 0; i < LUTON_MIIM_BUS_COUNT; ++i)
 570                if (miim[i].miim_base == base && miim[i].miim_size == size)
 571                        return miim[i].bus;
 572
 573        return NULL;
 574}
 575
 576static void add_port_entry(struct luton_private *priv, size_t index,
 577                           size_t phy_addr, struct mii_dev *bus,
 578                           u8 serdes_index, u8 phy_mode)
 579{
 580        priv->ports[index].phy_addr = phy_addr;
 581        priv->ports[index].bus = bus;
 582        priv->ports[index].serdes_index = serdes_index;
 583        priv->ports[index].phy_mode = phy_mode;
 584}
 585
 586static int luton_probe(struct udevice *dev)
 587{
 588        struct luton_private *priv = dev_get_priv(dev);
 589        int i, ret;
 590        struct resource res;
 591        phys_addr_t addr_base;
 592        unsigned long addr_size;
 593        ofnode eth_node, node, mdio_node;
 594        size_t phy_addr;
 595        struct mii_dev *bus;
 596        struct ofnode_phandle_args phandle;
 597        struct phy_device *phy;
 598
 599        if (!priv)
 600                return -EINVAL;
 601
 602        /* Get registers and map them to the private structure */
 603        for (i = 0; i < ARRAY_SIZE(regs_names); i++) {
 604                priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]);
 605                if (!priv->regs[i]) {
 606                        debug
 607                            ("Error can't get regs base addresses for %s\n",
 608                             regs_names[i]);
 609                        return -ENOMEM;
 610                }
 611        }
 612
 613        /* Release reset in the CU-PHY */
 614        writel(0, priv->regs[GCB] + GCB_DEVCPU_RST_SOFT_CHIP_RST);
 615
 616        /* Ports with ext phy don't need to reset clk */
 617        for (i = 0; i < MAX_INT_PORT; i++) {
 618                if (i < PORT10)
 619                        clrbits_le32(priv->regs[i] + DEV_GMII_PORT_MODE_CLK,
 620                                     DEV_GMII_PORT_MODE_CLK_PHY_RST);
 621                else
 622                        clrbits_le32(priv->regs[i] + DEV_PORT_MODE_CLK,
 623                                     DEV_PORT_MODE_CLK_PHY_RST);
 624        }
 625
 626        /* Wait for internal PHY to be ready */
 627        if (wait_for_bit_le32(priv->regs[GCB] + GCB_MISC_STAT,
 628                              GCB_MISC_STAT_PHY_READY, true, 500, false))
 629                return -EACCES;
 630
 631
 632        /* Initialize miim buses */
 633        memset(&miim, 0x0, sizeof(miim) * LUTON_MIIM_BUS_COUNT);
 634
 635        /* iterate all the ports and find out on which bus they are */
 636        i = 0;
 637        eth_node = dev_read_first_subnode(dev);
 638        for (node = ofnode_first_subnode(eth_node);
 639             ofnode_valid(node);
 640             node = ofnode_next_subnode(node)) {
 641                if (ofnode_read_resource(node, 0, &res))
 642                        return -ENOMEM;
 643                i = res.start;
 644
 645                ret = ofnode_parse_phandle_with_args(node, "phy-handle", NULL,
 646                                                     0, 0, &phandle);
 647                if (ret)
 648                        continue;
 649
 650                /* Get phy address on mdio bus */
 651                if (ofnode_read_resource(phandle.node, 0, &res))
 652                        return -ENOMEM;
 653                phy_addr = res.start;
 654
 655                /* Get mdio node */
 656                mdio_node = ofnode_get_parent(phandle.node);
 657
 658                if (ofnode_read_resource(mdio_node, 0, &res))
 659                        return -ENOMEM;
 660                addr_base = res.start;
 661                addr_size = res.end - res.start;
 662
 663                /* If the bus is new then create a new bus */
 664                if (!get_mdiobus(addr_base, addr_size))
 665                        priv->bus[miim_count] =
 666                                mscc_mdiobus_init(miim, &miim_count, addr_base,
 667                                                  addr_size);
 668
 669                /* Connect mdio bus with the port */
 670                bus = get_mdiobus(addr_base, addr_size);
 671
 672                /* Get serdes info */
 673                ret = ofnode_parse_phandle_with_args(node, "phys", NULL,
 674                                                     3, 0, &phandle);
 675                if (ret)
 676                        add_port_entry(priv, i, phy_addr, bus, 0xff, 0xff);
 677                else
 678                        add_port_entry(priv, i, phy_addr, bus, phandle.args[1],
 679                                       phandle.args[2]);
 680        }
 681
 682        for (i = 0; i < MAX_PORT; i++) {
 683                if (!priv->ports[i].bus)
 684                        continue;
 685
 686                phy = phy_connect(priv->ports[i].bus,
 687                                  priv->ports[i].phy_addr, dev,
 688                                  PHY_INTERFACE_MODE_NONE);
 689                if (phy && i >= MAX_INT_PORT)
 690                        board_phy_config(phy);
 691        }
 692
 693        /*
 694         * coma_mode is need on only one phy, because all the other phys
 695         * will be affected.
 696         */
 697        mscc_miim_write(priv->ports[0].bus, 0, 0, 31, 0x10);
 698        mscc_miim_write(priv->ports[0].bus, 0, 0, 14, 0x800);
 699        mscc_miim_write(priv->ports[0].bus, 0, 0, 31, 0);
 700
 701        return 0;
 702}
 703
 704static int luton_remove(struct udevice *dev)
 705{
 706        struct luton_private *priv = dev_get_priv(dev);
 707        int i;
 708
 709        for (i = 0; i < LUTON_MIIM_BUS_COUNT; i++) {
 710                mdio_unregister(priv->bus[i]);
 711                mdio_free(priv->bus[i]);
 712        }
 713
 714        return 0;
 715}
 716
 717static const struct eth_ops luton_ops = {
 718        .start        = luton_start,
 719        .stop         = luton_stop,
 720        .send         = luton_send,
 721        .recv         = luton_recv,
 722        .write_hwaddr = luton_write_hwaddr,
 723};
 724
 725static const struct udevice_id mscc_luton_ids[] = {
 726        {.compatible = "mscc,vsc7527-switch", },
 727        { /* Sentinel */ }
 728};
 729
 730U_BOOT_DRIVER(luton) = {
 731        .name     = "luton-switch",
 732        .id       = UCLASS_ETH,
 733        .of_match = mscc_luton_ids,
 734        .probe    = luton_probe,
 735        .remove   = luton_remove,
 736        .ops      = &luton_ops,
 737        .priv_auto      = sizeof(struct luton_private),
 738        .plat_auto      = sizeof(struct eth_pdata),
 739};
 740