uboot/board/freescale/lx2160a/eth_lx2160aqds.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright 2018-2020 NXP
   4 *
   5 */
   6
   7#include <common.h>
   8#include <env.h>
   9#include <fdt_support.h>
  10#include <hwconfig.h>
  11#include <command.h>
  12#include <log.h>
  13#include <net.h>
  14#include <netdev.h>
  15#include <malloc.h>
  16#include <fsl_mdio.h>
  17#include <miiphy.h>
  18#include <phy.h>
  19#include <fm_eth.h>
  20#include <asm/io.h>
  21#include <exports.h>
  22#include <asm/arch/fsl_serdes.h>
  23#include <fsl-mc/fsl_mc.h>
  24#include <fsl-mc/ldpaa_wriop.h>
  25#include <linux/libfdt.h>
  26
  27#include "../common/qixis.h"
  28
  29DECLARE_GLOBAL_DATA_PTR;
  30
  31#ifndef CONFIG_DM_ETH
  32#define EMI_NONE        0
  33#define EMI1            1 /* Mdio Bus 1 */
  34#define EMI2            2 /* Mdio Bus 2 */
  35
  36#if defined(CONFIG_FSL_MC_ENET)
  37enum io_slot {
  38        IO_SLOT_NONE = 0,
  39        IO_SLOT_1,
  40        IO_SLOT_2,
  41        IO_SLOT_3,
  42        IO_SLOT_4,
  43        IO_SLOT_5,
  44        IO_SLOT_6,
  45        IO_SLOT_7,
  46        IO_SLOT_8,
  47        EMI1_RGMII1,
  48        EMI1_RGMII2,
  49        IO_SLOT_MAX
  50};
  51
  52struct lx2160a_qds_mdio {
  53        enum io_slot ioslot : 4;
  54        u8 realbusnum : 4;
  55        struct mii_dev *realbus;
  56};
  57
  58/* structure explaining the phy configuration on 8 lanes of a serdes*/
  59struct serdes_phy_config {
  60        u8 serdes; /* serdes protocol */
  61        struct phy_config {
  62                u8 dpmacid;
  63                /* -1 terminated array */
  64                int phy_address[WRIOP_MAX_PHY_NUM + 1];
  65                u8 mdio_bus;
  66                enum io_slot ioslot;
  67        } phy_config[SRDS_MAX_LANES];
  68};
  69
  70/* Table defining the phy configuration on 8 lanes of a serdes.
  71 * Various assumptions have been made while defining this table.
  72 * e.g. for serdes1 protocol 19 it is being assumed that X-M11-USXGMII
  73 * card is being used for dpmac 3-4. (X-M12-XFI could also have been used)
  74 * And also that this card is connected to IO Slot 1 (could have been connected
  75 * to any of the 8 IO slots (IO slot 1 - IO slot 8)).
  76 * similarly, it is also being assumed that MDIO 1 is selected on X-M7-40G card
  77 * used in serdes1 protocol 19 (could have selected MDIO 2)
  78 * To override these settings "dpmac" environment variable can be used after
  79 * defining "dpmac_override" in hwconfig environment variable.
  80 * This table has limited serdes protocol entries. It can be expanded as per
  81 * requirement.
  82 */
  83static const struct serdes_phy_config serdes1_phy_config[] = {
  84        {3, {{WRIOP1_DPMAC3, {AQ_PHY_ADDR1, -1},
  85              EMI1, IO_SLOT_1},
  86            {WRIOP1_DPMAC4, {AQ_PHY_ADDR2, -1},
  87             EMI1, IO_SLOT_1},
  88            {WRIOP1_DPMAC5, {AQ_PHY_ADDR3, -1},
  89             EMI1, IO_SLOT_1},
  90            {WRIOP1_DPMAC6, {AQ_PHY_ADDR4, -1},
  91             EMI1, IO_SLOT_1} } },
  92        {7, {{WRIOP1_DPMAC3, {AQ_PHY_ADDR1, -1},
  93              EMI1, IO_SLOT_1},
  94            {WRIOP1_DPMAC4, {AQ_PHY_ADDR2, -1},
  95             EMI1, IO_SLOT_1},
  96            {WRIOP1_DPMAC5, {AQ_PHY_ADDR3, -1},
  97             EMI1, IO_SLOT_1},
  98            {WRIOP1_DPMAC6, {AQ_PHY_ADDR4, -1},
  99             EMI1, IO_SLOT_1},
 100            {WRIOP1_DPMAC7, {SGMII_CARD_PORT1_PHY_ADDR, -1},
 101             EMI1, IO_SLOT_2},
 102            {WRIOP1_DPMAC8, {SGMII_CARD_PORT2_PHY_ADDR, -1},
 103             EMI1, IO_SLOT_2},
 104            {WRIOP1_DPMAC9, {SGMII_CARD_PORT3_PHY_ADDR, -1},
 105             EMI1, IO_SLOT_2},
 106            {WRIOP1_DPMAC10, {SGMII_CARD_PORT4_PHY_ADDR, -1},
 107             EMI1, IO_SLOT_2} } },
 108        {8, {} },
 109        {13, {{WRIOP1_DPMAC1, {INPHI_PHY_ADDR1, INPHI_PHY_ADDR2, -1},
 110               EMI1, IO_SLOT_1},
 111             {WRIOP1_DPMAC2, {INPHI_PHY_ADDR1, INPHI_PHY_ADDR2, -1},
 112              EMI1, IO_SLOT_2} } },
 113        {14, {{WRIOP1_DPMAC1, {INPHI_PHY_ADDR1, INPHI_PHY_ADDR2, -1},
 114               EMI1, IO_SLOT_1} } },
 115        {15, {{WRIOP1_DPMAC1, {INPHI_PHY_ADDR1, INPHI_PHY_ADDR2, -1},
 116               EMI1, IO_SLOT_1},
 117             {WRIOP1_DPMAC2, {INPHI_PHY_ADDR1, INPHI_PHY_ADDR2, -1},
 118              EMI1, IO_SLOT_1} } },
 119        {17, {{WRIOP1_DPMAC3, {INPHI_PHY_ADDR1, INPHI_PHY_ADDR2, -1},
 120               EMI1, IO_SLOT_1},
 121             {WRIOP1_DPMAC4, {INPHI_PHY_ADDR1, INPHI_PHY_ADDR2, -1},
 122              EMI1, IO_SLOT_1},
 123             {WRIOP1_DPMAC5, {INPHI_PHY_ADDR1, INPHI_PHY_ADDR2, -1},
 124              EMI1, IO_SLOT_1},
 125             {WRIOP1_DPMAC6, {INPHI_PHY_ADDR1, INPHI_PHY_ADDR2, -1},
 126              EMI1, IO_SLOT_1} } },
 127        {19, {{WRIOP1_DPMAC2, {CORTINA_PHY_ADDR1, -1},
 128               EMI1, IO_SLOT_2},
 129             {WRIOP1_DPMAC3, {AQ_PHY_ADDR1, -1},
 130              EMI1, IO_SLOT_1},
 131             {WRIOP1_DPMAC4, {AQ_PHY_ADDR2, -1},
 132              EMI1, IO_SLOT_1},
 133             {WRIOP1_DPMAC5, {INPHI_PHY_ADDR1, INPHI_PHY_ADDR2, -1},
 134              EMI1, IO_SLOT_6},
 135             {WRIOP1_DPMAC6, {INPHI_PHY_ADDR1, INPHI_PHY_ADDR2, -1},
 136              EMI1, IO_SLOT_6} } },
 137        {20, {{WRIOP1_DPMAC1, {CORTINA_PHY_ADDR1, -1},
 138               EMI1, IO_SLOT_1},
 139             {WRIOP1_DPMAC2, {CORTINA_PHY_ADDR1, -1},
 140              EMI1, IO_SLOT_2} } }
 141};
 142
 143static const struct serdes_phy_config serdes2_phy_config[] = {
 144        {2, {} },
 145        {3, {} },
 146        {5, {} },
 147        {11, {{WRIOP1_DPMAC12, {SGMII_CARD_PORT2_PHY_ADDR, -1},
 148               EMI1, IO_SLOT_7},
 149             {WRIOP1_DPMAC17, {SGMII_CARD_PORT3_PHY_ADDR, -1},
 150              EMI1, IO_SLOT_7},
 151             {WRIOP1_DPMAC18, {SGMII_CARD_PORT4_PHY_ADDR, -1},
 152              EMI1, IO_SLOT_7},
 153             {WRIOP1_DPMAC16, {SGMII_CARD_PORT2_PHY_ADDR, -1},
 154              EMI1, IO_SLOT_8},
 155             {WRIOP1_DPMAC13, {SGMII_CARD_PORT3_PHY_ADDR, -1},
 156              EMI1, IO_SLOT_8},
 157             {WRIOP1_DPMAC14, {SGMII_CARD_PORT4_PHY_ADDR, -1},
 158              EMI1, IO_SLOT_8} } },
 159};
 160
 161static const struct serdes_phy_config serdes3_phy_config[] = {
 162        {2, {} },
 163        {3, {} }
 164};
 165
 166static inline
 167const struct phy_config *get_phy_config(u8 serdes,
 168                                        const struct serdes_phy_config *table,
 169                                        u8 table_size)
 170{
 171        int i;
 172
 173        for (i = 0; i < table_size; i++) {
 174                if (table[i].serdes == serdes)
 175                        return table[i].phy_config;
 176        }
 177
 178        return NULL;
 179}
 180
 181/* BRDCFG4 controls EMI routing for the board.
 182 * Bits    Function
 183 * 7-6     EMI Interface #1 Primary Routing (CFG_MUX1_EMI1) (1.8V):
 184 * EMI1    00= On-board PHY #1
 185 *         01= On-board PHY #2
 186 *         10= (reserved)
 187 *         11= Slots 1..8 multiplexer and translator.
 188 * 5-3     EMI Interface #1 Secondary Routing (CFG_MUX2_EMI1) (2.5V):
 189 * EMI1X   000= Slot #1
 190 *         001= Slot #2
 191 *         010= Slot #3
 192 *         011= Slot #4
 193 *         100= Slot #5
 194 *         101= Slot #6
 195 *         110= Slot #7
 196 *         111= Slot #8
 197 * 2-0     EMI Interface #2 Routing (CFG_MUX_EMI2):
 198 * EMI2    000= Slot #1 (secondary EMI)
 199 *         001= Slot #2 (secondary EMI)
 200 *         010= Slot #3 (secondary EMI)
 201 *         011= Slot #4 (secondary EMI)
 202 *         100= Slot #5 (secondary EMI)
 203 *         101= Slot #6 (secondary EMI)
 204 *         110= Slot #7 (secondary EMI)
 205 *         111= Slot #8 (secondary EMI)
 206 */
 207static int lx2160a_qds_get_mdio_mux_val(u8 realbusnum, enum io_slot ioslot)
 208{
 209        switch (realbusnum) {
 210        case EMI1:
 211                switch (ioslot) {
 212                case EMI1_RGMII1:
 213                        return 0;
 214                case EMI1_RGMII2:
 215                        return 0x40;
 216                default:
 217                        return (((ioslot - 1) << BRDCFG4_EMI1SEL_SHIFT) | 0xC0);
 218                }
 219                break;
 220        case EMI2:
 221                return ((ioslot - 1) << BRDCFG4_EMI2SEL_SHIFT);
 222        default:
 223                return -1;
 224        }
 225}
 226
 227static void lx2160a_qds_mux_mdio(struct lx2160a_qds_mdio *priv)
 228{
 229        u8 brdcfg4, mux_val, reg;
 230
 231        brdcfg4 = QIXIS_READ(brdcfg[4]);
 232        reg = brdcfg4;
 233        mux_val = lx2160a_qds_get_mdio_mux_val(priv->realbusnum, priv->ioslot);
 234
 235        switch (priv->realbusnum) {
 236        case EMI1:
 237                brdcfg4 &= ~BRDCFG4_EMI1SEL_MASK;
 238                brdcfg4 |= mux_val;
 239                break;
 240        case EMI2:
 241                brdcfg4 &= ~BRDCFG4_EMI2SEL_MASK;
 242                brdcfg4 |= mux_val;
 243                break;
 244        }
 245
 246        if (brdcfg4 ^ reg)
 247                QIXIS_WRITE(brdcfg[4], brdcfg4);
 248}
 249
 250static int lx2160a_qds_mdio_read(struct mii_dev *bus, int addr,
 251                                 int devad, int regnum)
 252{
 253        struct lx2160a_qds_mdio *priv = bus->priv;
 254
 255        lx2160a_qds_mux_mdio(priv);
 256
 257        return priv->realbus->read(priv->realbus, addr, devad, regnum);
 258}
 259
 260static int lx2160a_qds_mdio_write(struct mii_dev *bus, int addr, int devad,
 261                                  int regnum, u16 value)
 262{
 263        struct lx2160a_qds_mdio *priv = bus->priv;
 264
 265        lx2160a_qds_mux_mdio(priv);
 266
 267        return priv->realbus->write(priv->realbus, addr, devad, regnum, value);
 268}
 269
 270static int lx2160a_qds_mdio_reset(struct mii_dev *bus)
 271{
 272        struct lx2160a_qds_mdio *priv = bus->priv;
 273
 274        return priv->realbus->reset(priv->realbus);
 275}
 276
 277static struct mii_dev *lx2160a_qds_mdio_init(u8 realbusnum, enum io_slot ioslot)
 278{
 279        struct lx2160a_qds_mdio *pmdio;
 280        struct mii_dev *bus;
 281        /*should be within MDIO_NAME_LEN*/
 282        char dummy_mdio_name[] = "LX2160A_QDS_MDIO1_IOSLOT1";
 283
 284        if (realbusnum == EMI2) {
 285                if (ioslot < IO_SLOT_1 || ioslot > IO_SLOT_8) {
 286                        printf("invalid ioslot %d\n", ioslot);
 287                        return NULL;
 288                }
 289        } else if (realbusnum == EMI1) {
 290                if (ioslot < IO_SLOT_1 || ioslot > EMI1_RGMII2) {
 291                        printf("invalid ioslot %d\n", ioslot);
 292                        return NULL;
 293                }
 294        } else {
 295                printf("not supported real mdio bus %d\n", realbusnum);
 296                return NULL;
 297        }
 298
 299        if (ioslot == EMI1_RGMII1)
 300                strcpy(dummy_mdio_name, "LX2160A_QDS_MDIO1_RGMII1");
 301        else if (ioslot == EMI1_RGMII2)
 302                strcpy(dummy_mdio_name, "LX2160A_QDS_MDIO1_RGMII2");
 303        else
 304                sprintf(dummy_mdio_name, "LX2160A_QDS_MDIO%d_IOSLOT%d",
 305                        realbusnum, ioslot);
 306        bus = miiphy_get_dev_by_name(dummy_mdio_name);
 307
 308        if (bus)
 309                return bus;
 310
 311        bus = mdio_alloc();
 312        if (!bus) {
 313                printf("Failed to allocate %s bus\n", dummy_mdio_name);
 314                return NULL;
 315        }
 316
 317        pmdio = malloc(sizeof(*pmdio));
 318        if (!pmdio) {
 319                printf("Failed to allocate %s private data\n", dummy_mdio_name);
 320                free(bus);
 321                return NULL;
 322        }
 323
 324        switch (realbusnum) {
 325        case EMI1:
 326                pmdio->realbus =
 327                  miiphy_get_dev_by_name(DEFAULT_WRIOP_MDIO1_NAME);
 328                break;
 329        case EMI2:
 330                pmdio->realbus =
 331                  miiphy_get_dev_by_name(DEFAULT_WRIOP_MDIO2_NAME);
 332                break;
 333        }
 334
 335        if (!pmdio->realbus) {
 336                printf("No real mdio bus num %d found\n", realbusnum);
 337                free(bus);
 338                free(pmdio);
 339                return NULL;
 340        }
 341
 342        pmdio->realbusnum = realbusnum;
 343        pmdio->ioslot = ioslot;
 344        bus->read = lx2160a_qds_mdio_read;
 345        bus->write = lx2160a_qds_mdio_write;
 346        bus->reset = lx2160a_qds_mdio_reset;
 347        strcpy(bus->name, dummy_mdio_name);
 348        bus->priv = pmdio;
 349
 350        if (!mdio_register(bus))
 351                return bus;
 352
 353        printf("No bus with name %s\n", dummy_mdio_name);
 354        free(bus);
 355        free(pmdio);
 356        return NULL;
 357}
 358
 359static inline void do_phy_config(const struct phy_config *phy_config)
 360{
 361        struct mii_dev *bus;
 362        int i, phy_num, phy_address;
 363
 364        for (i = 0; i < SRDS_MAX_LANES; i++) {
 365                if (!phy_config[i].dpmacid)
 366                        continue;
 367
 368                for (phy_num = 0;
 369                     phy_num < ARRAY_SIZE(phy_config[i].phy_address);
 370                     phy_num++) {
 371                        phy_address = phy_config[i].phy_address[phy_num];
 372                        if (phy_address == -1)
 373                                break;
 374                        wriop_set_phy_address(phy_config[i].dpmacid,
 375                                              phy_num, phy_address);
 376                }
 377                /*Register the muxing front-ends to the MDIO buses*/
 378                bus = lx2160a_qds_mdio_init(phy_config[i].mdio_bus,
 379                                            phy_config[i].ioslot);
 380                if (!bus)
 381                        printf("could not get bus for mdio %d ioslot %d\n",
 382                               phy_config[i].mdio_bus,
 383                               phy_config[i].ioslot);
 384                else
 385                        wriop_set_mdio(phy_config[i].dpmacid, bus);
 386        }
 387}
 388
 389static inline void do_dpmac_config(int dpmac, const char *arg_dpmacid,
 390                                   char *env_dpmac)
 391{
 392        const char *ret;
 393        size_t len;
 394        u8 realbusnum, ioslot;
 395        struct mii_dev *bus;
 396        int phy_num;
 397        char *phystr = "phy00";
 398
 399        /*search phy in dpmac arg*/
 400        for (phy_num = 0; phy_num < WRIOP_MAX_PHY_NUM; phy_num++) {
 401                sprintf(phystr, "phy%d", phy_num + 1);
 402                ret = hwconfig_subarg_f(arg_dpmacid, phystr, &len, env_dpmac);
 403                if (!ret) {
 404                        /*look for phy instead of phy1*/
 405                        if (!phy_num)
 406                                ret = hwconfig_subarg_f(arg_dpmacid, "phy",
 407                                                        &len, env_dpmac);
 408                        if (!ret)
 409                                continue;
 410                }
 411
 412                if (len != 4 || strncmp(ret, "0x", 2))
 413                        printf("invalid phy format in %s variable.\n"
 414                               "specify phy%d for %s in hex format e.g. 0x12\n",
 415                               env_dpmac, phy_num + 1, arg_dpmacid);
 416                else
 417                        wriop_set_phy_address(dpmac, phy_num,
 418                                              simple_strtoul(ret, NULL, 16));
 419        }
 420
 421        /*search mdio in dpmac arg*/
 422        ret = hwconfig_subarg_f(arg_dpmacid, "mdio", &len, env_dpmac);
 423        if (ret)
 424                realbusnum = *ret - '0';
 425        else
 426                realbusnum = EMI_NONE;
 427
 428        if (realbusnum) {
 429                /*search io in dpmac arg*/
 430                ret = hwconfig_subarg_f(arg_dpmacid, "io", &len, env_dpmac);
 431                if (ret)
 432                        ioslot = *ret - '0';
 433                else
 434                        ioslot = IO_SLOT_NONE;
 435                /*Register the muxing front-ends to the MDIO buses*/
 436                bus = lx2160a_qds_mdio_init(realbusnum, ioslot);
 437                if (!bus)
 438                        printf("could not get bus for mdio %d ioslot %d\n",
 439                               realbusnum, ioslot);
 440                else
 441                        wriop_set_mdio(dpmac, bus);
 442        }
 443}
 444
 445#endif
 446#endif /* !CONFIG_DM_ETH */
 447
 448int board_eth_init(bd_t *bis)
 449{
 450#ifndef CONFIG_DM_ETH
 451#if defined(CONFIG_FSL_MC_ENET)
 452        struct memac_mdio_info mdio_info;
 453        struct memac_mdio_controller *regs;
 454        int i;
 455        const char *ret;
 456        char *env_dpmac;
 457        char dpmacid[] = "dpmac00", srds[] = "00_00_00";
 458        size_t len;
 459        struct mii_dev *bus;
 460        const struct phy_config *phy_config;
 461        struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
 462        u32 srds_s1, srds_s2, srds_s3;
 463
 464        srds_s1 = in_le32(&gur->rcwsr[28]) &
 465                  FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_MASK;
 466        srds_s1 >>= FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_SHIFT;
 467
 468        srds_s2 = in_le32(&gur->rcwsr[28]) &
 469                  FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_MASK;
 470        srds_s2 >>= FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_SHIFT;
 471
 472        srds_s3 = in_le32(&gur->rcwsr[28]) &
 473                  FSL_CHASSIS3_RCWSR28_SRDS3_PRTCL_MASK;
 474        srds_s3 >>= FSL_CHASSIS3_RCWSR28_SRDS3_PRTCL_SHIFT;
 475
 476        sprintf(srds, "%d_%d_%d", srds_s1, srds_s2, srds_s3);
 477
 478        regs = (struct memac_mdio_controller *)CONFIG_SYS_FSL_WRIOP1_MDIO1;
 479        mdio_info.regs = regs;
 480        mdio_info.name = DEFAULT_WRIOP_MDIO1_NAME;
 481
 482        /*Register the EMI 1*/
 483        fm_memac_mdio_init(bis, &mdio_info);
 484
 485        regs = (struct memac_mdio_controller *)CONFIG_SYS_FSL_WRIOP1_MDIO2;
 486        mdio_info.regs = regs;
 487        mdio_info.name = DEFAULT_WRIOP_MDIO2_NAME;
 488
 489        /*Register the EMI 2*/
 490        fm_memac_mdio_init(bis, &mdio_info);
 491
 492        /* "dpmac" environment variable can be used after
 493         * defining "dpmac_override" in hwconfig environment variable.
 494         */
 495        if (hwconfig("dpmac_override")) {
 496                env_dpmac = env_get("dpmac");
 497                if (env_dpmac) {
 498                        ret = hwconfig_arg_f("srds", &len, env_dpmac);
 499                        if (ret) {
 500                                if (strncmp(ret, srds, strlen(srds))) {
 501                                        printf("SERDES configuration changed.\n"
 502                                               "previous: %.*s, current: %s.\n"
 503                                               "update dpmac variable.\n",
 504                                               (int)len, ret, srds);
 505                                }
 506                        } else {
 507                                printf("SERDES configuration not found.\n"
 508                                       "Please add srds:%s in dpmac variable\n",
 509                                       srds);
 510                        }
 511
 512                        for (i = WRIOP1_DPMAC1; i < NUM_WRIOP_PORTS; i++) {
 513                                /* Look for dpmac1 to dpmac24(current max) arg
 514                                 * in dpmac environment variable
 515                                 */
 516                                sprintf(dpmacid, "dpmac%d", i);
 517                                ret = hwconfig_arg_f(dpmacid, &len, env_dpmac);
 518                                if (ret)
 519                                        do_dpmac_config(i, dpmacid, env_dpmac);
 520                        }
 521                } else {
 522                        printf("Warning: environment dpmac not found.\n"
 523                               "DPAA network interfaces may not work\n");
 524                }
 525        } else {
 526                /*Look for phy config for serdes1 in phy config table*/
 527                phy_config = get_phy_config(srds_s1, serdes1_phy_config,
 528                                            ARRAY_SIZE(serdes1_phy_config));
 529                if (!phy_config) {
 530                        printf("%s WRIOP: Unsupported SerDes1 Protocol %d\n",
 531                               __func__, srds_s1);
 532                } else {
 533                        do_phy_config(phy_config);
 534                }
 535                phy_config = get_phy_config(srds_s2, serdes2_phy_config,
 536                                            ARRAY_SIZE(serdes2_phy_config));
 537                if (!phy_config) {
 538                        printf("%s WRIOP: Unsupported SerDes2 Protocol %d\n",
 539                               __func__, srds_s2);
 540                } else {
 541                        do_phy_config(phy_config);
 542                }
 543                phy_config = get_phy_config(srds_s3, serdes3_phy_config,
 544                                            ARRAY_SIZE(serdes3_phy_config));
 545                if (!phy_config) {
 546                        printf("%s WRIOP: Unsupported SerDes3 Protocol %d\n",
 547                               __func__, srds_s3);
 548                } else {
 549                        do_phy_config(phy_config);
 550                }
 551        }
 552
 553        if (wriop_get_enet_if(WRIOP1_DPMAC17) == PHY_INTERFACE_MODE_RGMII_ID) {
 554                wriop_set_phy_address(WRIOP1_DPMAC17, 0, RGMII_PHY_ADDR1);
 555                bus = lx2160a_qds_mdio_init(EMI1, EMI1_RGMII1);
 556                if (!bus)
 557                        printf("could not get bus for RGMII1\n");
 558                else
 559                        wriop_set_mdio(WRIOP1_DPMAC17, bus);
 560        }
 561
 562        if (wriop_get_enet_if(WRIOP1_DPMAC18) == PHY_INTERFACE_MODE_RGMII_ID) {
 563                wriop_set_phy_address(WRIOP1_DPMAC18, 0, RGMII_PHY_ADDR2);
 564                bus = lx2160a_qds_mdio_init(EMI1, EMI1_RGMII2);
 565                if (!bus)
 566                        printf("could not get bus for RGMII2\n");
 567                else
 568                        wriop_set_mdio(WRIOP1_DPMAC18, bus);
 569        }
 570
 571        cpu_eth_init(bis);
 572#endif /* CONFIG_FMAN_ENET */
 573#endif /* !CONFIG_DM_ETH */
 574
 575#ifdef CONFIG_PHY_AQUANTIA
 576        /*
 577         * Export functions to be used by AQ firmware
 578         * upload application
 579         */
 580        gd->jt->strcpy = strcpy;
 581        gd->jt->mdelay = mdelay;
 582        gd->jt->mdio_get_current_dev = mdio_get_current_dev;
 583        gd->jt->phy_find_by_mask = phy_find_by_mask;
 584        gd->jt->mdio_phydev_for_ethname = mdio_phydev_for_ethname;
 585        gd->jt->miiphy_set_current_dev = miiphy_set_current_dev;
 586#endif
 587
 588#ifdef CONFIG_DM_ETH
 589        return 0;
 590#else
 591        return pci_eth_init(bis);
 592#endif
 593}
 594
 595#if defined(CONFIG_RESET_PHY_R)
 596void reset_phy(void)
 597{
 598#if defined(CONFIG_FSL_MC_ENET)
 599        mc_env_boot();
 600#endif
 601}
 602#endif /* CONFIG_RESET_PHY_R */
 603
 604#ifndef CONFIG_DM_ETH
 605#if defined(CONFIG_FSL_MC_ENET)
 606int fdt_fixup_dpmac_phy_handle(void *fdt, int dpmac_id, int node_phandle)
 607{
 608        int offset;
 609        int ret;
 610        char dpmac_str[] = "dpmacs@00";
 611        const char *phy_string;
 612
 613        offset = fdt_path_offset(fdt, "/soc/fsl-mc/dpmacs");
 614
 615        if (offset < 0)
 616                offset = fdt_path_offset(fdt, "/fsl-mc/dpmacs");
 617
 618        if (offset < 0) {
 619                printf("dpmacs node not found in device tree\n");
 620                return offset;
 621        }
 622
 623        sprintf(dpmac_str, "dpmac@%x", dpmac_id);
 624        debug("dpmac_str = %s\n", dpmac_str);
 625
 626        offset = fdt_subnode_offset(fdt, offset, dpmac_str);
 627        if (offset < 0) {
 628                printf("%s node not found in device tree\n", dpmac_str);
 629                return offset;
 630        }
 631
 632        phy_string = fdt_getprop(fdt, offset, "phy-connection-type", NULL);
 633        if (is_backplane_mode(phy_string)) {
 634                /* Backplane KR mode: skip fixups */
 635                printf("Interface %d in backplane KR mode\n", dpmac_id);
 636                return 0;
 637        }
 638
 639        ret = fdt_appendprop_cell(fdt, offset, "phy-handle", node_phandle);
 640        if (ret)
 641                printf("%d@%s %d\n", __LINE__, __func__, ret);
 642
 643        phy_string = phy_string_for_interface(wriop_get_enet_if(dpmac_id));
 644        ret = fdt_setprop_string(fdt, offset, "phy-connection-type",
 645                                 phy_string);
 646        if (ret)
 647                printf("%d@%s %d\n", __LINE__, __func__, ret);
 648
 649        return ret;
 650}
 651
 652int fdt_get_ioslot_offset(void *fdt, struct mii_dev *mii_dev, int fpga_offset)
 653{
 654        char mdio_ioslot_str[] = "mdio@00";
 655        struct lx2160a_qds_mdio *priv;
 656        u64 reg;
 657        u32 phandle;
 658        int offset, mux_val;
 659
 660        /*Test if the MDIO bus is real mdio bus or muxing front end ?*/
 661        if (strncmp(mii_dev->name, "LX2160A_QDS_MDIO",
 662                    strlen("LX2160A_QDS_MDIO")))
 663                return -1;
 664
 665        /*Get the real MDIO bus num and ioslot info from bus's priv data*/
 666        priv = mii_dev->priv;
 667
 668        debug("real_bus_num = %d, ioslot = %d\n",
 669              priv->realbusnum, priv->ioslot);
 670
 671        if (priv->realbusnum == EMI1)
 672                reg = CONFIG_SYS_FSL_WRIOP1_MDIO1;
 673        else
 674                reg = CONFIG_SYS_FSL_WRIOP1_MDIO2;
 675
 676        offset = fdt_node_offset_by_compat_reg(fdt, "fsl,fman-memac-mdio", reg);
 677        if (offset < 0) {
 678                printf("mdio@%llx node not found in device tree\n", reg);
 679                return offset;
 680        }
 681
 682        phandle = fdt_get_phandle(fdt, offset);
 683        phandle = cpu_to_fdt32(phandle);
 684        offset = fdt_node_offset_by_prop_value(fdt, -1, "mdio-parent-bus",
 685                                               &phandle, 4);
 686        if (offset < 0) {
 687                printf("mdio-mux-%d node not found in device tree\n",
 688                       priv->realbusnum == EMI1 ? 1 : 2);
 689                return offset;
 690        }
 691
 692        mux_val = lx2160a_qds_get_mdio_mux_val(priv->realbusnum, priv->ioslot);
 693        if (priv->realbusnum == EMI1)
 694                mux_val >>= BRDCFG4_EMI1SEL_SHIFT;
 695        else
 696                mux_val >>= BRDCFG4_EMI2SEL_SHIFT;
 697        sprintf(mdio_ioslot_str, "mdio@%x", (u8)mux_val);
 698
 699        offset = fdt_subnode_offset(fdt, offset, mdio_ioslot_str);
 700        if (offset < 0) {
 701                printf("%s node not found in device tree\n", mdio_ioslot_str);
 702                return offset;
 703        }
 704
 705        return offset;
 706}
 707
 708int fdt_create_phy_node(void *fdt, int offset, u8 phyaddr, int *subnodeoffset,
 709                        struct phy_device *phy_dev, int phandle)
 710{
 711        char phy_node_name[] = "ethernet-phy@00";
 712        char phy_id_compatible_str[] = "ethernet-phy-id0000.0000,";
 713        int ret;
 714
 715        sprintf(phy_node_name, "ethernet-phy@%x", phyaddr);
 716        debug("phy_node_name = %s\n", phy_node_name);
 717
 718        *subnodeoffset = fdt_add_subnode(fdt, offset, phy_node_name);
 719        if (*subnodeoffset <= 0) {
 720                printf("Could not add subnode %s inside node %s err = %s\n",
 721                       phy_node_name, fdt_get_name(fdt, offset, NULL),
 722                       fdt_strerror(*subnodeoffset));
 723                return *subnodeoffset;
 724        }
 725
 726        sprintf(phy_id_compatible_str, "ethernet-phy-id%04x.%04x,",
 727                phy_dev->phy_id >> 16, phy_dev->phy_id & 0xFFFF);
 728        debug("phy_id_compatible_str %s\n", phy_id_compatible_str);
 729
 730        ret = fdt_setprop_string(fdt, *subnodeoffset, "compatible",
 731                                 phy_id_compatible_str);
 732        if (ret) {
 733                printf("%d@%s %d\n", __LINE__, __func__, ret);
 734                goto out;
 735        }
 736
 737        if (phy_dev->is_c45) {
 738                ret = fdt_appendprop_string(fdt, *subnodeoffset, "compatible",
 739                                            "ethernet-phy-ieee802.3-c45");
 740                if (ret) {
 741                        printf("%d@%s %d\n", __LINE__, __func__, ret);
 742                        goto out;
 743                }
 744        } else {
 745                ret = fdt_appendprop_string(fdt, *subnodeoffset, "compatible",
 746                                            "ethernet-phy-ieee802.3-c22");
 747                if (ret) {
 748                        printf("%d@%s %d\n", __LINE__, __func__, ret);
 749                        goto out;
 750                }
 751        }
 752
 753        ret = fdt_setprop_cell(fdt, *subnodeoffset, "reg", phyaddr);
 754        if (ret) {
 755                printf("%d@%s %d\n", __LINE__, __func__, ret);
 756                goto out;
 757        }
 758
 759        ret = fdt_set_phandle(fdt, *subnodeoffset, phandle);
 760        if (ret) {
 761                printf("%d@%s %d\n", __LINE__, __func__, ret);
 762                goto out;
 763        }
 764
 765out:
 766        if (ret)
 767                fdt_del_node(fdt, *subnodeoffset);
 768
 769        return ret;
 770}
 771
 772int fdt_fixup_board_phy(void *fdt)
 773{
 774        int fpga_offset, offset, subnodeoffset;
 775        struct mii_dev *mii_dev;
 776        struct list_head *mii_devs, *entry;
 777        int ret, dpmac_id, phandle, i;
 778        struct phy_device *phy_dev;
 779        char ethname[ETH_NAME_LEN];
 780        phy_interface_t phy_iface;
 781
 782        ret = 0;
 783        /* we know FPGA is connected to i2c0, therefore search path directly,
 784         * instead of compatible property, as it saves time
 785         */
 786        fpga_offset = fdt_path_offset(fdt, "/soc/i2c@2000000/fpga");
 787
 788        if (fpga_offset < 0)
 789                fpga_offset = fdt_path_offset(fdt, "/i2c@2000000/fpga");
 790
 791        if (fpga_offset < 0) {
 792                printf("i2c@2000000/fpga node not found in device tree\n");
 793                return fpga_offset;
 794        }
 795
 796        phandle = fdt_alloc_phandle(fdt);
 797        mii_devs = mdio_get_list_head();
 798
 799        list_for_each(entry, mii_devs) {
 800                mii_dev = list_entry(entry, struct mii_dev, link);
 801                debug("mii_dev name : %s\n", mii_dev->name);
 802                offset = fdt_get_ioslot_offset(fdt, mii_dev, fpga_offset);
 803                if (offset < 0)
 804                        continue;
 805
 806                // Look for phy devices attached to MDIO bus muxing front end
 807                // and create their entries with compatible being the device id
 808                for (i = 0; i < PHY_MAX_ADDR; i++) {
 809                        phy_dev = mii_dev->phymap[i];
 810                        if (!phy_dev)
 811                                continue;
 812
 813                        // TODO: use sscanf instead of loop
 814                        dpmac_id = WRIOP1_DPMAC1;
 815                        while (dpmac_id < NUM_WRIOP_PORTS) {
 816                                phy_iface = wriop_get_enet_if(dpmac_id);
 817                                snprintf(ethname, ETH_NAME_LEN, "DPMAC%d@%s",
 818                                         dpmac_id,
 819                                         phy_string_for_interface(phy_iface));
 820                                if (strcmp(ethname, phy_dev->dev->name) == 0)
 821                                        break;
 822                                dpmac_id++;
 823                        }
 824                        if (dpmac_id == NUM_WRIOP_PORTS)
 825                                continue;
 826                        ret = fdt_create_phy_node(fdt, offset, i,
 827                                                  &subnodeoffset,
 828                                                  phy_dev, phandle);
 829                        if (ret)
 830                                break;
 831
 832                        ret = fdt_fixup_dpmac_phy_handle(fdt,
 833                                                         dpmac_id, phandle);
 834                        if (ret) {
 835                                fdt_del_node(fdt, subnodeoffset);
 836                                break;
 837                        }
 838                        /* calculate offset again as new node addition may have
 839                         * changed offset;
 840                         */
 841                        offset = fdt_get_ioslot_offset(fdt, mii_dev,
 842                                                       fpga_offset);
 843                        phandle++;
 844                }
 845
 846                if (ret)
 847                        break;
 848        }
 849
 850        return ret;
 851}
 852#endif // CONFIG_FSL_MC_ENET
 853#endif
 854
 855#if defined(CONFIG_DM_ETH) && defined(CONFIG_MULTI_DTB_FIT)
 856
 857/* Structure to hold SERDES protocols supported in case of
 858 * CONFIG_DM_ETH enabled (network interfaces are described in the DTS).
 859 *
 860 * @serdes_block: the index of the SERDES block
 861 * @serdes_protocol: the decimal value of the protocol supported
 862 * @dts_needed: DTS notes describing the current configuration are needed
 863 *
 864 * When dts_needed is true, the board_fit_config_name_match() function
 865 * will try to exactly match the current configuration of the block with a DTS
 866 * name provided.
 867 */
 868static struct serdes_configuration {
 869        u8 serdes_block;
 870        u32 serdes_protocol;
 871        bool dts_needed;
 872} supported_protocols[] = {
 873        /* Serdes block #1 */
 874        {1, 3, true},
 875        {1, 7, true},
 876        {1, 19, true},
 877        {1, 20, true},
 878
 879        /* Serdes block #2 */
 880        {2, 2, false},
 881        {2, 3, false},
 882        {2, 5, false},
 883        {2, 11, true},
 884
 885        /* Serdes block #3 */
 886        {3, 2, false},
 887        {3, 3, false},
 888};
 889
 890#define SUPPORTED_SERDES_PROTOCOLS ARRAY_SIZE(supported_protocols)
 891
 892static bool protocol_supported(u8 serdes_block, u32 protocol)
 893{
 894        struct serdes_configuration serdes_conf;
 895        int i;
 896
 897        for (i = 0; i < SUPPORTED_SERDES_PROTOCOLS; i++) {
 898                serdes_conf = supported_protocols[i];
 899                if (serdes_conf.serdes_block == serdes_block &&
 900                    serdes_conf.serdes_protocol == protocol)
 901                        return true;
 902        }
 903
 904        return false;
 905}
 906
 907static void get_str_protocol(u8 serdes_block, u32 protocol, char *str)
 908{
 909        struct serdes_configuration serdes_conf;
 910        int i;
 911
 912        for (i = 0; i < SUPPORTED_SERDES_PROTOCOLS; i++) {
 913                serdes_conf = supported_protocols[i];
 914                if (serdes_conf.serdes_block == serdes_block &&
 915                    serdes_conf.serdes_protocol == protocol) {
 916                        if (serdes_conf.dts_needed == true)
 917                                sprintf(str, "%u", protocol);
 918                        else
 919                                sprintf(str, "x");
 920                        return;
 921                }
 922        }
 923}
 924
 925int board_fit_config_name_match(const char *name)
 926{
 927        struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
 928        u32 rcw_status = in_le32(&gur->rcwsr[28]);
 929        char srds_s1_str[2], srds_s2_str[2], srds_s3_str[2];
 930        u32 srds_s1, srds_s2, srds_s3;
 931        char expected_dts[100];
 932
 933        srds_s1 = rcw_status & FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_MASK;
 934        srds_s1 >>= FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_SHIFT;
 935
 936        srds_s2 = rcw_status & FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_MASK;
 937        srds_s2 >>= FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_SHIFT;
 938
 939        srds_s3 = rcw_status & FSL_CHASSIS3_RCWSR28_SRDS3_PRTCL_MASK;
 940        srds_s3 >>= FSL_CHASSIS3_RCWSR28_SRDS3_PRTCL_SHIFT;
 941
 942        /* Check for supported protocols. The default DTS will be used
 943         * in this case
 944         */
 945        if (!protocol_supported(1, srds_s1) ||
 946            !protocol_supported(2, srds_s2) ||
 947            !protocol_supported(3, srds_s3))
 948                return -1;
 949
 950        get_str_protocol(1, srds_s1, srds_s1_str);
 951        get_str_protocol(2, srds_s2, srds_s2_str);
 952        get_str_protocol(3, srds_s3, srds_s3_str);
 953
 954        sprintf(expected_dts, "fsl-lx2160a-qds-%s-%s-%s",
 955                srds_s1_str, srds_s2_str, srds_s3_str);
 956
 957        if (!strcmp(name, expected_dts))
 958                return 0;
 959
 960        return -1;
 961}
 962#endif
 963