uboot/board/Marvell/octeon_ebb7304/board.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2020 Stefan Roese <sr@denx.de>
   4 */
   5
   6#include <dm.h>
   7#include <fdt_support.h>
   8#include <ram.h>
   9#include <asm/gpio.h>
  10
  11#include <mach/octeon_ddr.h>
  12#include <mach/cvmx-qlm.h>
  13#include <mach/octeon_qlm.h>
  14#include <mach/octeon_fdt.h>
  15#include <mach/cvmx-helper.h>
  16#include <mach/cvmx-helper-cfg.h>
  17#include <mach/cvmx-helper-util.h>
  18#include <mach/cvmx-bgxx-defs.h>
  19
  20#include "board_ddr.h"
  21
  22#define MAX_MIX_ENV_VARS        4
  23
  24#define EBB7304_DEF_DRAM_FREQ   800
  25
  26static struct ddr_conf board_ddr_conf[] = {
  27        OCTEON_EBB7304_DDR_CONFIGURATION
  28};
  29
  30static int no_phy[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  31
  32struct ddr_conf *octeon_ddr_conf_table_get(int *count, int *def_ddr_freq)
  33{
  34        *count = ARRAY_SIZE(board_ddr_conf);
  35        *def_ddr_freq = EBB7304_DEF_DRAM_FREQ;
  36
  37        return board_ddr_conf;
  38}
  39
  40/*
  41 * parse_env_var:       Parse the environment variable ("bgx_for_mix%d") to
  42 *                      extract the lmac it is set to.
  43 *
  44 *  index:              Index of environment variable to parse.
  45 *                      environment variable.
  46 *  env_bgx:            Updated with the bgx of the lmac in the environment
  47 *                      variable.
  48 *  env_lmac:           Updated with the index of lmac in the environment
  49 *                      variable.
  50 *
  51 *  returns:            Zero on success, error otherwise.
  52 */
  53static int parse_env_var(int index, int *env_bgx, int *env_lmac)
  54{
  55        char env_var[20];
  56        ulong xipd_port;
  57
  58        sprintf(env_var, "bgx_for_mix%d", index);
  59        xipd_port = env_get_ulong(env_var, 0, 0xffff);
  60        if (xipd_port != 0xffff) {
  61                int xiface;
  62                struct cvmx_xiface xi;
  63                struct cvmx_xport xp;
  64
  65                /*
  66                 * The environemt variable is set to the xipd port. Convert the
  67                 * xipd port to numa node, bgx, and lmac.
  68                 */
  69                xiface = cvmx_helper_get_interface_num(xipd_port);
  70                xi = cvmx_helper_xiface_to_node_interface(xiface);
  71                xp = cvmx_helper_ipd_port_to_xport(xipd_port);
  72                *env_bgx = xi.interface;
  73                *env_lmac = cvmx_helper_get_interface_index_num(xp.port);
  74                return 0;
  75        }
  76
  77        return -1;
  78}
  79
  80/*
  81 * get_lmac_fdt_node:   Search the device tree for the node corresponding to
  82 *                      a given bgx lmac.
  83 *
  84 *  fdt:                Pointer to flat device tree
  85 *  search_node:        Numa node of the lmac to search for.
  86 *  search_bgx:         Bgx of the lmac to search for.
  87 *  search_lmac:        Lmac index to search for.
  88 *  compat:             Compatible string to search for.
  89
  90 *  returns:            The device tree node of the lmac if found,
  91 *                      or -1 otherwise.
  92 */
  93static int get_lmac_fdt_node(const void *fdt, int search_node, int search_bgx, int search_lmac,
  94                             const char *compat)
  95{
  96        int node;
  97        const fdt32_t *reg;
  98        u64 addr;
  99        int fdt_node = -1;
 100        int fdt_bgx = -1;
 101        int fdt_lmac = -1;
 102        int len;
 103        int parent;
 104
 105        /* Iterate through all bgx ports */
 106        node = -1;
 107        while ((node = fdt_node_offset_by_compatible((void *)fdt, node,
 108                                                     compat)) >= 0) {
 109                /* Get the node and bgx from the physical address */
 110                parent = fdt_parent_offset(fdt, node);
 111                reg = fdt_getprop(fdt, parent, "reg", &len);
 112                if (parent < 0 || !reg)
 113                        continue;
 114
 115                addr = fdt_translate_address((void *)fdt, parent, reg);
 116                fdt_node = (addr >> 36) & 0x7;
 117                fdt_bgx = (addr >> 24) & 0xf;
 118
 119                /* Get the lmac index from the reg property */
 120                reg = fdt_getprop(fdt, node, "reg", &len);
 121                if (reg)
 122                        fdt_lmac = *reg;
 123
 124                /* Check for a match */
 125                if (search_node == fdt_node && search_bgx == fdt_bgx &&
 126                    search_lmac == fdt_lmac)
 127                        return node;
 128        }
 129
 130        return -1;
 131}
 132
 133/*
 134 * get_mix_fdt_node:    Search the device tree for the node corresponding to
 135 *                      a given mix.
 136 *
 137 *  fdt:                Pointer to flat device tree
 138 *  search_node:        Mix numa node to search for.
 139 *  search_index:       Mix index to search for.
 140 *
 141 *  returns:            The device tree node of the lmac if found,
 142 *                      or -1 otherwise.
 143 */
 144static int get_mix_fdt_node(const void *fdt, int search_node, int search_index)
 145{
 146        int node;
 147
 148        /* Iterate through all the mix fdt nodes */
 149        node = -1;
 150        while ((node = fdt_node_offset_by_compatible((void *)fdt, node,
 151                                                     "cavium,octeon-7890-mix")) >= 0) {
 152                int parent;
 153                int len;
 154                const char *name;
 155                int mix_numa_node;
 156                const fdt32_t *reg;
 157                int mix_index = -1;
 158                u64 addr;
 159
 160                /* Get the numa node of the mix from the parent node name */
 161                parent = fdt_parent_offset(fdt, node);
 162                if (parent < 0 ||
 163                    ((name = fdt_get_name(fdt, parent, &len)) == NULL) ||
 164                    ((name = strchr(name, '@')) == NULL))
 165                        continue;
 166
 167                name++;
 168                mix_numa_node = simple_strtol(name, NULL, 0) ? 1 : 0;
 169
 170                /* Get the mix index from the reg property */
 171                reg = fdt_getprop(fdt, node, "reg", &len);
 172                if (reg) {
 173                        addr = fdt_translate_address((void *)fdt, parent, reg);
 174                        mix_index = (addr >> 11) & 1;
 175                }
 176
 177                /* Check for a match */
 178                if (mix_numa_node == search_node && mix_index == search_index)
 179                        return node;
 180        }
 181
 182        return -1;
 183}
 184
 185/*
 186 * fdt_fix_mix:         Fix the mix nodes in the device tree. Only the mix nodes
 187 *                      configured by the user will be preserved. All other mix
 188 *                      nodes will be trimmed.
 189 *
 190 *  fdt:                Pointer to flat device tree
 191 *
 192 *  returns:            Zero on success, error otherwise.
 193 */
 194static int fdt_fix_mix(const void *fdt)
 195{
 196        int node;
 197        int next_node;
 198        int len;
 199        int i;
 200
 201        /* Parse all the mix port environment variables */
 202        for (i = 0; i < MAX_MIX_ENV_VARS; i++) {
 203                int env_node = 0;
 204                int env_bgx = -1;
 205                int env_lmac = -1;
 206                int lmac_fdt_node = -1;
 207                int mix_fdt_node = -1;
 208                int lmac_phandle;
 209                char *compat;
 210
 211                /* Get the lmac for this environment variable */
 212                if (parse_env_var(i, &env_bgx, &env_lmac))
 213                        continue;
 214
 215                /* Get the fdt node for this lmac and add a phandle to it */
 216                compat = "cavium,octeon-7890-bgx-port";
 217                lmac_fdt_node = get_lmac_fdt_node(fdt, env_node, env_bgx,
 218                                                  env_lmac, compat);
 219                if (lmac_fdt_node < 0) {
 220                        /* Must check for the xcv compatible string too */
 221                        compat = "cavium,octeon-7360-xcv";
 222                        lmac_fdt_node = get_lmac_fdt_node(fdt, env_node,
 223                                                          env_bgx, env_lmac,
 224                                                          compat);
 225                        if (lmac_fdt_node < 0) {
 226                                printf("WARNING: Failed to get lmac fdt node for %d%d%d\n",
 227                                       env_node, env_bgx, env_lmac);
 228                                continue;
 229                        }
 230                }
 231
 232                lmac_phandle = fdt_alloc_phandle((void *)fdt);
 233                fdt_set_phandle((void *)fdt, lmac_fdt_node, lmac_phandle);
 234
 235                /* Get the fdt mix node corresponding to this lmac */
 236                mix_fdt_node = get_mix_fdt_node(fdt, env_node, env_lmac);
 237                if (mix_fdt_node < 0)
 238                        continue;
 239
 240                /* Point the mix to the lmac */
 241                fdt_getprop(fdt, mix_fdt_node, "cavium,mac-handle", &len);
 242                fdt_setprop_inplace((void *)fdt, mix_fdt_node,
 243                                    "cavium,mac-handle", &lmac_phandle, len);
 244        }
 245
 246        /* Trim unused mix'es from the device tree */
 247        for (node = fdt_next_node(fdt, -1, NULL); node >= 0; node = next_node) {
 248                const char *compat;
 249                const fdt32_t *reg;
 250
 251                next_node = fdt_next_node(fdt, node, NULL);
 252
 253                compat = fdt_getprop(fdt, node, "compatible", &len);
 254                if (compat) {
 255                        if (strcmp(compat, "cavium,octeon-7890-mix"))
 256                                continue;
 257
 258                        reg = fdt_getprop(fdt, node, "cavium,mac-handle", &len);
 259                        if (reg) {
 260                                if (*reg == 0xffff)
 261                                        fdt_nop_node((void *)fdt, node);
 262                        }
 263                }
 264        }
 265
 266        return 0;
 267}
 268
 269static void kill_fdt_phy(void *fdt, int offset, void *arg)
 270{
 271        int len, phy_offset;
 272        const fdt32_t *php;
 273        u32 phandle;
 274
 275        php = fdt_getprop(fdt, offset, "phy-handle", &len);
 276        if (php && len == sizeof(*php)) {
 277                phandle = fdt32_to_cpu(*php);
 278                fdt_nop_property(fdt, offset, "phy-handle");
 279                phy_offset = fdt_node_offset_by_phandle(fdt, phandle);
 280                if (phy_offset > 0)
 281                        fdt_nop_node(fdt, phy_offset);
 282        }
 283}
 284
 285void __fixup_xcv(void)
 286{
 287        unsigned long bgx = env_get_ulong("bgx_for_rgmii", 10,
 288                                          (unsigned long)-1);
 289        char fdt_key[16];
 290        int i;
 291
 292        debug("%s: BGX %d\n", __func__, (int)bgx);
 293
 294        for (i = 0; i < 3; i++) {
 295                snprintf(fdt_key, sizeof(fdt_key),
 296                         bgx == i ? "%d,xcv" : "%d,not-xcv", i);
 297                debug("%s: trimming bgx %lu with key %s\n",
 298                      __func__, bgx, fdt_key);
 299
 300                octeon_fdt_patch_rename((void *)gd->fdt_blob, fdt_key,
 301                                        "cavium,xcv-trim", true, NULL, NULL);
 302        }
 303}
 304
 305/* QLM0 - QLM6 */
 306void __fixup_fdt(void)
 307{
 308        int qlm;
 309        int speed = 0;
 310
 311        for (qlm = 0; qlm < 7; qlm++) {
 312                enum cvmx_qlm_mode mode;
 313                char fdt_key[16];
 314                const char *type_str = "none";
 315
 316                mode = cvmx_qlm_get_mode(qlm);
 317                switch (mode) {
 318                case CVMX_QLM_MODE_SGMII:
 319                case CVMX_QLM_MODE_RGMII_SGMII:
 320                case CVMX_QLM_MODE_RGMII_SGMII_1X1:
 321                        type_str = "sgmii";
 322                        break;
 323                case CVMX_QLM_MODE_XAUI:
 324                case CVMX_QLM_MODE_RGMII_XAUI:
 325                        speed = (cvmx_qlm_get_gbaud_mhz(qlm) * 8 / 10) * 4;
 326                        if (speed == 10000)
 327                                type_str = "xaui";
 328                        else
 329                                type_str = "dxaui";
 330                        break;
 331                case CVMX_QLM_MODE_RXAUI:
 332                case CVMX_QLM_MODE_RGMII_RXAUI:
 333                        type_str = "rxaui";
 334                        break;
 335                case CVMX_QLM_MODE_XLAUI:
 336                case CVMX_QLM_MODE_RGMII_XLAUI:
 337                        type_str = "xlaui";
 338                        break;
 339                case CVMX_QLM_MODE_XFI:
 340                case CVMX_QLM_MODE_RGMII_XFI:
 341                case CVMX_QLM_MODE_RGMII_XFI_1X1:
 342                        type_str = "10gbase-r";
 343                        break;
 344                case CVMX_QLM_MODE_10G_KR:
 345                case CVMX_QLM_MODE_RGMII_10G_KR:
 346                        type_str = "10G_KR";
 347                        break;
 348                case CVMX_QLM_MODE_40G_KR4:
 349                case CVMX_QLM_MODE_RGMII_40G_KR4:
 350                        type_str = "40G_KR4";
 351                        break;
 352                case CVMX_QLM_MODE_SATA_2X1:
 353                        type_str = "sata";
 354                        break;
 355                case CVMX_QLM_MODE_SGMII_2X1:
 356                case CVMX_QLM_MODE_XFI_1X2:
 357                case CVMX_QLM_MODE_10G_KR_1X2:
 358                case CVMX_QLM_MODE_RXAUI_1X2:
 359                case CVMX_QLM_MODE_MIXED: // special for DLM5 & DLM6
 360                {
 361                        cvmx_bgxx_cmrx_config_t cmr_config;
 362                        cvmx_bgxx_spux_br_pmd_control_t pmd_control;
 363                        int mux = cvmx_qlm_mux_interface(2);
 364
 365                        if (mux == 2) { // only dlm6
 366                                cmr_config.u64 = csr_rd(CVMX_BGXX_CMRX_CONFIG(2, 2));
 367                                pmd_control.u64 =
 368                                        csr_rd(CVMX_BGXX_SPUX_BR_PMD_CONTROL(2, 2));
 369                        } else {
 370                                if (qlm == 5) {
 371                                        cmr_config.u64 =
 372                                                csr_rd(CVMX_BGXX_CMRX_CONFIG(0, 2));
 373                                        pmd_control.u64 =
 374                                                csr_rd(CVMX_BGXX_SPUX_BR_PMD_CONTROL(0, 2));
 375                                } else {
 376                                        cmr_config.u64 =
 377                                                csr_rd(CVMX_BGXX_CMRX_CONFIG(2, 2));
 378                                        pmd_control.u64 =
 379                                                csr_rd(CVMX_BGXX_SPUX_BR_PMD_CONTROL(2, 2));
 380                                }
 381                        }
 382                        switch (cmr_config.s.lmac_type) {
 383                        case 0:
 384                                type_str = "sgmii";
 385                                break;
 386                        case 1:
 387                                type_str = "xaui";
 388                                break;
 389                        case 2:
 390                                type_str = "rxaui";
 391                                break;
 392                        case 3:
 393                                if (pmd_control.s.train_en)
 394                                        type_str = "10G_KR";
 395                                else
 396                                        type_str = "10gbase-r";
 397                                break;
 398                        case 4:
 399                                if (pmd_control.s.train_en)
 400                                        type_str = "40G_KR4";
 401                                else
 402                                        type_str = "xlaui";
 403                                break;
 404                        default:
 405                                type_str = "none";
 406                                break;
 407                        }
 408                        break;
 409                }
 410                default:
 411                        type_str = "none";
 412                        break;
 413                }
 414                sprintf(fdt_key, "%d,%s", qlm, type_str);
 415                debug("Patching qlm %d for %s for mode %d%s\n", qlm, fdt_key, mode,
 416                      no_phy[qlm] ? ", removing PHY" : "");
 417                octeon_fdt_patch_rename((void *)gd->fdt_blob, fdt_key, NULL, true,
 418                                        no_phy[qlm] ? kill_fdt_phy : NULL, NULL);
 419        }
 420}
 421
 422int board_fix_fdt(void)
 423{
 424        __fixup_fdt();
 425        __fixup_xcv();
 426
 427        /* Fix the mix ports */
 428        fdt_fix_mix(gd->fdt_blob);
 429
 430        return 0;
 431}
 432
 433/*
 434 * Here is the description of the parameters that are passed to QLM
 435 * configuration:
 436 *
 437 *      param0 : The QLM to configure
 438 *      param1 : Speed to configure the QLM at
 439 *      param2 : Mode the QLM to configure
 440 *      param3 : 1 = RC, 0 = EP
 441 *      param4 : 0 = GEN1, 1 = GEN2, 2 = GEN3
 442 *      param5 : ref clock select, 0 = 100Mhz, 1 = 125MHz, 2 = 156MHz
 443 *      param6 : ref clock input to use:
 444 *               0 - external reference (QLMx_REF_CLK)
 445 *               1 = common clock 0 (QLMC_REF_CLK0)
 446 *               2 = common_clock 1 (QLMC_REF_CLK1)
 447 */
 448static void board_configure_qlms(void)
 449{
 450        int speed[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 451        int mode[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };
 452        int pcie_rc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 453        int pcie_gen[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 454        int ref_clock_sel[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 455        int ref_clock_input[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 456        struct gpio_desc desc;
 457        int rbgx, rqlm;
 458        char env_var[16];
 459        int qlm;
 460        int ret;
 461
 462        /* RGMII PHY reset GPIO */
 463        ret = dm_gpio_lookup_name("gpio-controllerA27", &desc);
 464        if (ret)
 465                debug("gpio ret=%d\n", ret);
 466        ret = dm_gpio_request(&desc, "rgmii_phy_reset");
 467        if (ret)
 468                debug("gpio_request ret=%d\n", ret);
 469        ret = dm_gpio_set_dir_flags(&desc, GPIOD_IS_OUT);
 470        if (ret)
 471                debug("gpio dir ret=%d\n", ret);
 472
 473        /* Put RGMII PHY in reset */
 474        dm_gpio_set_value(&desc, 0);
 475
 476        octeon_init_qlm(0);
 477
 478        rbgx = env_get_ulong("bgx_for_rgmii", 10, (unsigned long)-1);
 479        switch (rbgx) {
 480        case 0:
 481                rqlm = 2;
 482                break;
 483        case 1:
 484                rqlm = 3;
 485                break;
 486        case 2:
 487                rqlm = 5;
 488                break;
 489        default:
 490                rqlm = -1;
 491                break;
 492        }
 493
 494        for (qlm = 0; qlm < 7; qlm++) {
 495                const char *mode_str;
 496                char spd_env[16];
 497
 498                mode[qlm] = CVMX_QLM_MODE_DISABLED;
 499                sprintf(env_var, "qlm%d_mode", qlm);
 500                mode_str = env_get(env_var);
 501                if (!mode_str)
 502                        continue;
 503
 504                if (qlm == 4 && mode[4] != -1 &&
 505                    mode[4] != CVMX_QLM_MODE_SATA_2X1) {
 506                        printf("Error: DLM 4 can only be configured for SATA\n");
 507                        continue;
 508                }
 509
 510                if (strstr(mode_str, ",no_phy"))
 511                        no_phy[qlm] = 1;
 512
 513                if (!strncmp(mode_str, "sgmii", 5)) {
 514                        bool rgmii = false;
 515
 516                        speed[qlm] = 1250;
 517                        if (rqlm == qlm && qlm < 5) {
 518                                mode[qlm] = CVMX_QLM_MODE_RGMII_SGMII;
 519                                rgmii = true;
 520                        } else if (qlm == 6 || qlm == 5) {
 521                                if (rqlm == qlm && qlm == 5) {
 522                                        mode[qlm] = CVMX_QLM_MODE_RGMII_SGMII_1X1;
 523                                        rgmii = true;
 524                                } else if (rqlm == 5 && qlm == 6 &&
 525                                           mode[5] != CVMX_QLM_MODE_RGMII_SGMII_1X1) {
 526                                        mode[qlm] = CVMX_QLM_MODE_RGMII_SGMII_2X1;
 527                                        rgmii = true;
 528                                } else {
 529                                        mode[qlm] = CVMX_QLM_MODE_SGMII_2X1;
 530                                }
 531                        } else {
 532                                mode[qlm] = CVMX_QLM_MODE_SGMII;
 533                        }
 534                        ref_clock_sel[qlm] = 2;
 535
 536                        if (qlm == 5 || qlm == 6)
 537                                ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1
 538
 539                        if (no_phy[qlm]) {
 540                                int i;
 541                                int start = 0, stop = 2;
 542
 543                                rbgx = 0;
 544                                switch (qlm) {
 545                                case 3:
 546                                        rbgx = 1;
 547                                case 2:
 548                                        for (i = 0; i < 4; i++) {
 549                                                printf("Ignoring PHY for interface: %d, port: %d\n",
 550                                                       rbgx, i);
 551                                                cvmx_helper_set_port_force_link_up(rbgx, i, true);
 552                                        }
 553                                        break;
 554                                case 6:
 555                                        start = 2;
 556                                        stop = 4;
 557                                case 5:
 558                                        for (i = start; i < stop; i++) {
 559                                                printf("Ignoring PHY for interface: %d, port: %d\n",
 560                                                       2, i);
 561                                                cvmx_helper_set_port_force_link_up(2, i, true);
 562                                        }
 563                                        break;
 564                                default:
 565                                        printf("SGMII not supported for QLM/DLM %d\n",
 566                                               qlm);
 567                                        break;
 568                                }
 569                        }
 570                        printf("QLM %d: SGMII%s\n",
 571                               qlm, rgmii ? ", RGMII" : "");
 572                } else if (!strncmp(mode_str, "xaui", 4)) {
 573                        speed[qlm] = 3125;
 574                        mode[qlm] = CVMX_QLM_MODE_XAUI;
 575                        ref_clock_sel[qlm] = 2;
 576                        if (qlm == 5 || qlm == 6)
 577                                ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1
 578                        printf("QLM %d: XAUI\n", qlm);
 579                } else if (!strncmp(mode_str, "dxaui", 5)) {
 580                        speed[qlm] = 6250;
 581                        mode[qlm] = CVMX_QLM_MODE_XAUI;
 582                        ref_clock_sel[qlm] = 2;
 583                        if (qlm == 5 || qlm == 6)
 584                                ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1
 585                        printf("QLM %d: DXAUI\n", qlm);
 586                } else if (!strncmp(mode_str, "rxaui", 5)) {
 587                        bool rgmii = false;
 588
 589                        speed[qlm] = 6250;
 590                        if (qlm == 5 || qlm == 6) {
 591                                if (rqlm == qlm && qlm == 5) {
 592                                        mode[qlm] = CVMX_QLM_MODE_RGMII_RXAUI;
 593                                        rgmii = true;
 594                                } else {
 595                                        mode[qlm] = CVMX_QLM_MODE_RXAUI_1X2;
 596                                }
 597                        } else {
 598                                mode[qlm] = CVMX_QLM_MODE_RXAUI;
 599                        }
 600                        ref_clock_sel[qlm] = 2;
 601                        if (qlm == 5 || qlm == 6)
 602                                ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1
 603                        printf("QLM %d: RXAUI%s\n",
 604                               qlm, rgmii ? ", rgmii" : "");
 605                } else if (!strncmp(mode_str, "xlaui", 5)) {
 606                        speed[qlm] = 103125;
 607                        mode[qlm] = CVMX_QLM_MODE_XLAUI;
 608                        ref_clock_sel[qlm] = 2;
 609                        if (qlm == 5 || qlm == 6)
 610                                ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1
 611                        sprintf(spd_env, "qlm%d_speed", qlm);
 612                        if (env_get(spd_env)) {
 613                                int spd = env_get_ulong(spd_env, 0, 8);
 614
 615                                if (spd)
 616                                        speed[qlm] = spd;
 617                                else
 618                                        speed[qlm] = 103125;
 619                        }
 620                        printf("QLM %d: XLAUI\n", qlm);
 621                } else if (!strncmp(mode_str, "10gbase-r", 3)) {
 622                        bool rgmii = false;
 623
 624                        speed[qlm] = 103125;
 625                        if (rqlm == qlm) {
 626                                mode[qlm] = CVMX_QLM_MODE_RGMII_XFI;
 627                                rgmii = true;
 628                        } else if (qlm == 5 || qlm == 6) {
 629                                mode[qlm] = CVMX_QLM_MODE_XFI_1X2;
 630                        } else {
 631                                mode[qlm] = CVMX_QLM_MODE_XFI;
 632                        }
 633                        ref_clock_sel[qlm] = 2;
 634                        if (qlm == 5 || qlm == 6)
 635                                ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1
 636                        printf("QLM %d: XFI%s\n", qlm, rgmii ? ", RGMII" : "");
 637                } else if (!strncmp(mode_str, "10G_KR", 6)) {
 638                        speed[qlm] = 103125;
 639                        if (rqlm == qlm && qlm == 5)
 640                                mode[qlm] = CVMX_QLM_MODE_RGMII_10G_KR;
 641                        else if (qlm == 5 || qlm == 6)
 642                                mode[qlm] = CVMX_QLM_MODE_10G_KR_1X2;
 643                        else
 644                                mode[qlm] = CVMX_QLM_MODE_10G_KR;
 645                        ref_clock_sel[qlm] = 2;
 646                        if (qlm == 5 || qlm == 6)
 647                                ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1
 648                        printf("QLM %d: 10G_KR\n", qlm);
 649                } else if (!strncmp(mode_str, "40G_KR4", 7)) {
 650                        speed[qlm] = 103125;
 651                        mode[qlm] = CVMX_QLM_MODE_40G_KR4;
 652                        ref_clock_sel[qlm] = 2;
 653                        if (qlm == 5 || qlm == 6)
 654                                ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1
 655                        printf("QLM %d: 40G_KR4\n", qlm);
 656                } else if (!strcmp(mode_str, "pcie")) {
 657                        char *pmode;
 658                        int lanes = 0;
 659
 660                        sprintf(env_var, "pcie%d_mode", qlm);
 661                        pmode = env_get(env_var);
 662                        if (pmode && !strcmp(pmode, "ep"))
 663                                pcie_rc[qlm] = 0;
 664                        else
 665                                pcie_rc[qlm] = 1;
 666                        sprintf(env_var, "pcie%d_gen", qlm);
 667                        pcie_gen[qlm] = env_get_ulong(env_var, 0, 3);
 668                        sprintf(env_var, "pcie%d_lanes", qlm);
 669                        lanes = env_get_ulong(env_var, 0, 8);
 670                        if (lanes == 8) {
 671                                mode[qlm] = CVMX_QLM_MODE_PCIE_1X8;
 672                        } else if (qlm == 5 || qlm == 6) {
 673                                if (lanes != 2) {
 674                                        printf("QLM%d: Invalid lanes selected, defaulting to 2 lanes\n",
 675                                               qlm);
 676                                }
 677                                mode[qlm] = CVMX_QLM_MODE_PCIE_1X2;
 678                                ref_clock_input[qlm] = 1; // use QLMC_REF_CLK0
 679                        } else {
 680                                mode[qlm] = CVMX_QLM_MODE_PCIE;
 681                        }
 682                        ref_clock_sel[qlm] = 0;
 683                        printf("QLM %d: PCIe gen%d %s, x%d lanes\n",
 684                               qlm, pcie_gen[qlm] + 1,
 685                               pcie_rc[qlm] ? "root complex" : "endpoint",
 686                               lanes);
 687                } else if (!strcmp(mode_str, "sata")) {
 688                        mode[qlm] = CVMX_QLM_MODE_SATA_2X1;
 689                        ref_clock_sel[qlm] = 0;
 690                        ref_clock_input[qlm] = 1;
 691                        sprintf(spd_env, "qlm%d_speed", qlm);
 692                        if (env_get(spd_env)) {
 693                                int spd = env_get_ulong(spd_env, 0, 8);
 694
 695                                if (spd == 1500 || spd == 3000 || spd == 3000)
 696                                        speed[qlm] = spd;
 697                                else
 698                                        speed[qlm] = 6000;
 699                        } else {
 700                                speed[qlm] = 6000;
 701                        }
 702                } else {
 703                        printf("QLM %d: disabled\n", qlm);
 704                }
 705        }
 706
 707        for (qlm = 0; qlm < 7; qlm++) {
 708                int rc;
 709
 710                if (mode[qlm] == -1)
 711                        continue;
 712
 713                debug("Configuring qlm%d with speed(%d), mode(%d), RC(%d), Gen(%d), REF_CLK(%d), CLK_SOURCE(%d)\n",
 714                      qlm, speed[qlm], mode[qlm], pcie_rc[qlm],
 715                      pcie_gen[qlm] + 1,
 716                      ref_clock_sel[qlm], ref_clock_input[qlm]);
 717                rc = octeon_configure_qlm(qlm, speed[qlm], mode[qlm],
 718                                          pcie_rc[qlm], pcie_gen[qlm],
 719                                          ref_clock_sel[qlm],
 720                                          ref_clock_input[qlm]);
 721
 722                if (speed[qlm] == 6250) {
 723                        if (mode[qlm] == CVMX_QLM_MODE_RXAUI) {
 724                                octeon_qlm_tune_v3(0, qlm, speed[qlm], 0x12,
 725                                                   0xa0, -1, -1);
 726                        } else {
 727                                octeon_qlm_tune_v3(0, qlm, speed[qlm], 0xa,
 728                                                   0xa0, -1, -1);
 729                        }
 730                } else if (speed[qlm] == 103125) {
 731                        octeon_qlm_tune_v3(0, qlm, speed[qlm], 0xd, 0xd0,
 732                                           -1, -1);
 733                }
 734
 735                if (qlm == 4 && rc != 0)
 736                        /*
 737                         * There is a bug with SATA with 73xx.  Until it's
 738                         * fixed we need to strip it from the device tree.
 739                         */
 740                        octeon_fdt_patch_rename((void *)gd->fdt_blob, "4,none",
 741                                                NULL, true, NULL, NULL);
 742        }
 743
 744        dm_gpio_set_value(&desc, 0); /* Put RGMII PHY in reset */
 745        mdelay(10);
 746        dm_gpio_set_value(&desc, 1); /* Take RGMII PHY out of reset */
 747}
 748
 749int board_late_init(void)
 750{
 751        board_configure_qlms();
 752
 753        return 0;
 754}
 755