uboot/board/CZ.NIC/turris_mox/turris_mox.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2018 Marek Behun <marek.behun@nic.cz>
   4 */
   5
   6#include <common.h>
   7#include <asm/arch/cpu.h>
   8#include <asm/arch/soc.h>
   9#include <net.h>
  10#include <asm/global_data.h>
  11#include <asm/io.h>
  12#include <asm/gpio.h>
  13#include <button.h>
  14#include <clk.h>
  15#include <dm.h>
  16#include <env.h>
  17#include <fdt_support.h>
  18#include <init.h>
  19#include <led.h>
  20#include <linux/delay.h>
  21#include <linux/libfdt.h>
  22#include <linux/string.h>
  23#include <miiphy.h>
  24#include <mvebu/comphy.h>
  25#include <spi.h>
  26
  27#include "mox_sp.h"
  28
  29#define MAX_MOX_MODULES         10
  30
  31#define MOX_MODULE_SFP          0x1
  32#define MOX_MODULE_PCI          0x2
  33#define MOX_MODULE_TOPAZ        0x3
  34#define MOX_MODULE_PERIDOT      0x4
  35#define MOX_MODULE_USB3         0x5
  36#define MOX_MODULE_PASSPCI      0x6
  37
  38#define ARMADA_37XX_NB_GPIO_SEL (MVEBU_REGISTER(0x13830))
  39#define ARMADA_37XX_SPI_CTRL    (MVEBU_REGISTER(0x10600))
  40#define ARMADA_37XX_SPI_CFG     (MVEBU_REGISTER(0x10604))
  41#define ARMADA_37XX_SPI_DOUT    (MVEBU_REGISTER(0x10608))
  42#define ARMADA_37XX_SPI_DIN     (MVEBU_REGISTER(0x1060c))
  43
  44#define ETH1_PATH       "/soc/internal-regs@d0000000/ethernet@40000"
  45#define MDIO_PATH       "/soc/internal-regs@d0000000/mdio@32004"
  46#define SFP_GPIO_PATH   "/soc/internal-regs@d0000000/spi@10600/moxtet@1/gpio@0"
  47#define PCIE_PATH       "/soc/pcie@d0070000"
  48#define SFP_PATH        "/sfp"
  49#define LED_PATH        "/leds/led"
  50#define BUTTON_PATH     "/gpio-keys/reset"
  51
  52DECLARE_GLOBAL_DATA_PTR;
  53
  54#if defined(CONFIG_OF_BOARD_FIXUP)
  55int board_fix_fdt(void *blob)
  56{
  57        u8 topology[MAX_MOX_MODULES];
  58        int i, size, node;
  59        bool enable;
  60
  61        /*
  62         * SPI driver is not loaded in driver model yet, but we have to find out
  63         * if pcie should be enabled in U-Boot's device tree. Therefore we have
  64         * to read SPI by reading/writing SPI registers directly
  65         */
  66
  67        writel(0x10df, ARMADA_37XX_SPI_CFG);
  68        /* put pin from GPIO to SPI mode */
  69        clrbits_le32(ARMADA_37XX_NB_GPIO_SEL, BIT(12));
  70        /* enable SPI CS1 */
  71        setbits_le32(ARMADA_37XX_SPI_CTRL, BIT(17));
  72
  73        while (!(readl(ARMADA_37XX_SPI_CTRL) & 0x2))
  74                udelay(1);
  75
  76        for (i = 0; i < MAX_MOX_MODULES; ++i) {
  77                writel(0x0, ARMADA_37XX_SPI_DOUT);
  78
  79                while (!(readl(ARMADA_37XX_SPI_CTRL) & 0x2))
  80                        udelay(1);
  81
  82                topology[i] = readl(ARMADA_37XX_SPI_DIN) & 0xff;
  83                if (topology[i] == 0xff)
  84                        break;
  85
  86                topology[i] &= 0xf;
  87        }
  88
  89        size = i;
  90
  91        /* disable SPI CS1 */
  92        clrbits_le32(ARMADA_37XX_SPI_CTRL, BIT(17));
  93
  94        if (size > 1 && (topology[1] == MOX_MODULE_PCI ||
  95                         topology[1] == MOX_MODULE_USB3 ||
  96                         topology[1] == MOX_MODULE_PASSPCI))
  97                enable = true;
  98        else
  99                enable = false;
 100
 101        node = fdt_path_offset(blob, PCIE_PATH);
 102
 103        if (node < 0) {
 104                printf("Cannot find PCIe node in U-Boot's device tree!\n");
 105                return 0;
 106        }
 107
 108        if (fdt_setprop_string(blob, node, "status",
 109                               enable ? "okay" : "disabled") < 0) {
 110                printf("Cannot %s PCIe in U-Boot's device tree!\n",
 111                       enable ? "enable" : "disable");
 112                return 0;
 113        }
 114
 115        if (a3700_fdt_fix_pcie_regions(blob) < 0) {
 116                printf("Cannot fix PCIe regions in U-Boot's device tree!\n");
 117                return 0;
 118        }
 119
 120        return 0;
 121}
 122#endif
 123
 124int board_init(void)
 125{
 126        /* address of boot parameters */
 127        gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
 128
 129        return 0;
 130}
 131
 132static int mox_do_spi(u8 *in, u8 *out, size_t size)
 133{
 134        struct spi_slave *slave;
 135        struct udevice *dev;
 136        int ret;
 137
 138        ret = spi_get_bus_and_cs(0, 1, 1000000, SPI_CPHA | SPI_CPOL,
 139                                 "spi_generic_drv", "moxtet@1", &dev,
 140                                 &slave);
 141        if (ret)
 142                goto fail;
 143
 144        ret = spi_claim_bus(slave);
 145        if (ret)
 146                goto fail_free;
 147
 148        ret = spi_xfer(slave, size * 8, out, in, SPI_XFER_ONCE);
 149
 150        spi_release_bus(slave);
 151fail_free:
 152        spi_free_slave(slave);
 153fail:
 154        return ret;
 155}
 156
 157static int mox_get_topology(const u8 **ptopology, int *psize, int *pis_sd)
 158{
 159        static int is_sd;
 160        static u8 topology[MAX_MOX_MODULES - 1];
 161        static int size;
 162        u8 din[MAX_MOX_MODULES], dout[MAX_MOX_MODULES];
 163        int ret, i;
 164
 165        if (size) {
 166                if (ptopology)
 167                        *ptopology = topology;
 168                if (psize)
 169                        *psize = size;
 170                if (pis_sd)
 171                        *pis_sd = is_sd;
 172                return 0;
 173        }
 174
 175        memset(din, 0, MAX_MOX_MODULES);
 176        memset(dout, 0, MAX_MOX_MODULES);
 177
 178        ret = mox_do_spi(din, dout, MAX_MOX_MODULES);
 179        if (ret)
 180                return ret;
 181
 182        if (din[0] == 0x10)
 183                is_sd = 1;
 184        else if (din[0] == 0x00)
 185                is_sd = 0;
 186        else
 187                return -ENODEV;
 188
 189        for (i = 1; i < MAX_MOX_MODULES && din[i] != 0xff; ++i)
 190                topology[i - 1] = din[i] & 0xf;
 191        size = i - 1;
 192
 193        if (ptopology)
 194                *ptopology = topology;
 195        if (psize)
 196                *psize = size;
 197        if (pis_sd)
 198                *pis_sd = is_sd;
 199
 200        return 0;
 201}
 202
 203int comphy_update_map(struct comphy_map *serdes_map, int count)
 204{
 205        int ret, i, size, sfpindex = -1, swindex = -1;
 206        const u8 *topology;
 207
 208        ret = mox_get_topology(&topology, &size, NULL);
 209        if (ret)
 210                return ret;
 211
 212        for (i = 0; i < size; ++i) {
 213                if (topology[i] == MOX_MODULE_SFP && sfpindex == -1)
 214                        sfpindex = i;
 215                else if ((topology[i] == MOX_MODULE_TOPAZ ||
 216                          topology[i] == MOX_MODULE_PERIDOT) &&
 217                         swindex == -1)
 218                        swindex = i;
 219        }
 220
 221        if (sfpindex >= 0 && swindex >= 0) {
 222                if (sfpindex < swindex)
 223                        serdes_map[0].speed = COMPHY_SPEED_1_25G;
 224                else
 225                        serdes_map[0].speed = COMPHY_SPEED_3_125G;
 226        } else if (sfpindex >= 0) {
 227                serdes_map[0].speed = COMPHY_SPEED_1_25G;
 228        } else if (swindex >= 0) {
 229                serdes_map[0].speed = COMPHY_SPEED_3_125G;
 230        }
 231
 232        return 0;
 233}
 234
 235#define SW_SMI_CMD_R(d, r)      (0x9800 | (((d) & 0x1f) << 5) | ((r) & 0x1f))
 236#define SW_SMI_CMD_W(d, r)      (0x9400 | (((d) & 0x1f) << 5) | ((r) & 0x1f))
 237
 238static int sw_multi_read(struct mii_dev *bus, int sw, int dev, int reg)
 239{
 240        bus->write(bus, sw, 0, 0, SW_SMI_CMD_R(dev, reg));
 241        mdelay(5);
 242        return bus->read(bus, sw, 0, 1);
 243}
 244
 245static void sw_multi_write(struct mii_dev *bus, int sw, int dev, int reg,
 246                           u16 val)
 247{
 248        bus->write(bus, sw, 0, 1, val);
 249        bus->write(bus, sw, 0, 0, SW_SMI_CMD_W(dev, reg));
 250        mdelay(5);
 251}
 252
 253static int sw_scratch_read(struct mii_dev *bus, int sw, int reg)
 254{
 255        sw_multi_write(bus, sw, 0x1c, 0x1a, (reg & 0x7f) << 8);
 256        return sw_multi_read(bus, sw, 0x1c, 0x1a) & 0xff;
 257}
 258
 259static void sw_led_write(struct mii_dev *bus, int sw, int port, int reg,
 260                         u16 val)
 261{
 262        sw_multi_write(bus, sw, port, 0x16, 0x8000 | ((reg & 7) << 12)
 263                                            | (val & 0x7ff));
 264}
 265
 266static void sw_blink_leds(struct mii_dev *bus, int peridot, int topaz)
 267{
 268        int i, p;
 269        struct {
 270                int port;
 271                u16 val;
 272                int wait;
 273        } regs[] = {
 274                { 2, 0xef, 1 }, { 2, 0xfe, 1 }, { 2, 0x33, 0 },
 275                { 4, 0xef, 1 }, { 4, 0xfe, 1 }, { 4, 0x33, 0 },
 276                { 3, 0xfe, 1 }, { 3, 0xef, 1 }, { 3, 0x33, 0 },
 277                { 1, 0xfe, 1 }, { 1, 0xef, 1 }, { 1, 0x33, 0 }
 278        };
 279
 280        for (i = 0; i < 12; ++i) {
 281                for (p = 0; p < peridot; ++p) {
 282                        sw_led_write(bus, 0x10 + p, regs[i].port, 0,
 283                                     regs[i].val);
 284                        sw_led_write(bus, 0x10 + p, regs[i].port + 4, 0,
 285                                     regs[i].val);
 286                }
 287                if (topaz) {
 288                        sw_led_write(bus, 0x2, 0x10 + regs[i].port, 0,
 289                                     regs[i].val);
 290                }
 291
 292                if (regs[i].wait)
 293                        mdelay(75);
 294        }
 295}
 296
 297static void check_switch_address(struct mii_dev *bus, int addr)
 298{
 299        if (sw_scratch_read(bus, addr, 0x70) >> 3 != addr)
 300                printf("Check of switch MDIO address failed for 0x%02x\n",
 301                       addr);
 302}
 303
 304static int sfp, pci, topaz, peridot, usb, passpci;
 305static int sfp_pos, peridot_pos[3];
 306static int module_count;
 307
 308static int configure_peridots(struct gpio_desc *reset_gpio)
 309{
 310        int i, ret;
 311        u8 dout[MAX_MOX_MODULES];
 312
 313        memset(dout, 0, MAX_MOX_MODULES);
 314
 315        /* set addresses of Peridot modules */
 316        for (i = 0; i < peridot; ++i)
 317                dout[module_count - peridot_pos[i]] = (~i) & 3;
 318
 319        /*
 320         * if there is a SFP module connected to the last Peridot module, set
 321         * the P10_SMODE to 1 for the Peridot module
 322         */
 323        if (sfp)
 324                dout[module_count - peridot_pos[i - 1]] |= 1 << 3;
 325
 326        dm_gpio_set_value(reset_gpio, 1);
 327        mdelay(10);
 328
 329        ret = mox_do_spi(NULL, dout, module_count + 1);
 330
 331        mdelay(10);
 332        dm_gpio_set_value(reset_gpio, 0);
 333
 334        mdelay(50);
 335
 336        return ret;
 337}
 338
 339static int get_reset_gpio(struct gpio_desc *reset_gpio)
 340{
 341        int node;
 342
 343        node = fdt_node_offset_by_compatible(gd->fdt_blob, 0, "cznic,moxtet");
 344        if (node < 0) {
 345                printf("Cannot find Moxtet bus device node!\n");
 346                return -1;
 347        }
 348
 349        gpio_request_by_name_nodev(offset_to_ofnode(node), "reset-gpios", 0,
 350                                   reset_gpio, GPIOD_IS_OUT);
 351
 352        if (!dm_gpio_is_valid(reset_gpio)) {
 353                printf("Cannot find reset GPIO for Moxtet bus!\n");
 354                return -1;
 355        }
 356
 357        return 0;
 358}
 359
 360int misc_init_r(void)
 361{
 362        u8 mac[2][6];
 363        int i, ret;
 364
 365        ret = mbox_sp_get_board_info(NULL, mac[0], mac[1], NULL, NULL);
 366        if (ret < 0) {
 367                printf("Cannot read data from OTP!\n");
 368                return 0;
 369        }
 370
 371        for (i = 0; i < 2; ++i) {
 372                u8 oldmac[6];
 373
 374                if (is_valid_ethaddr(mac[i]) &&
 375                    !eth_env_get_enetaddr_by_index("eth", i, oldmac))
 376                        eth_env_set_enetaddr_by_index("eth", i, mac[i]);
 377        }
 378
 379        return 0;
 380}
 381
 382static void mox_phy_modify(struct phy_device *phydev, int page, int reg,
 383                           u16 mask, u16 set)
 384{
 385        int val;
 386
 387        val = phydev->drv->readext(phydev, MDIO_DEVAD_NONE, page, reg);
 388        val &= ~mask;
 389        val |= set;
 390        phydev->drv->writeext(phydev, MDIO_DEVAD_NONE, page, reg, val);
 391}
 392
 393static void mox_phy_leds_start_blinking(void)
 394{
 395        struct phy_device *phydev;
 396        struct mii_dev *bus;
 397
 398        bus = miiphy_get_dev_by_name("neta@30000");
 399        if (!bus) {
 400                printf("Cannot get MDIO bus device!\n");
 401                return;
 402        }
 403
 404        phydev = phy_find_by_mask(bus, BIT(1), PHY_INTERFACE_MODE_RGMII);
 405        if (!phydev) {
 406                printf("Cannot get ethernet PHY!\n");
 407                return;
 408        }
 409
 410        mox_phy_modify(phydev, 3, 0x12, 0x700, 0x400);
 411        mox_phy_modify(phydev, 3, 0x10, 0xff, 0xbb);
 412}
 413
 414static bool read_reset_button(void)
 415{
 416        struct udevice *button, *led;
 417        int i;
 418
 419        if (device_get_global_by_ofnode(ofnode_path(BUTTON_PATH), &button)) {
 420                printf("Cannot find reset button!\n");
 421                return false;
 422        }
 423
 424        if (device_get_global_by_ofnode(ofnode_path(LED_PATH), &led)) {
 425                printf("Cannot find status LED!\n");
 426                return false;
 427        }
 428
 429        led_set_state(led, LEDST_ON);
 430
 431        for (i = 0; i < 21; ++i) {
 432                if (button_get_state(button) != BUTTON_ON)
 433                        return false;
 434                if (i < 20)
 435                        mdelay(50);
 436        }
 437
 438        led_set_state(led, LEDST_OFF);
 439
 440        return true;
 441}
 442
 443static void handle_reset_button(void)
 444{
 445        const char * const vars[1] = { "bootcmd_rescue", };
 446
 447        /*
 448         * Ensure that bootcmd_rescue has always stock value, so that running
 449         *   run bootcmd_rescue
 450         * always works correctly.
 451         */
 452        env_set_default_vars(1, (char * const *)vars, 0);
 453
 454        if (read_reset_button()) {
 455                const char * const vars[2] = {
 456                        "bootcmd",
 457                        "distro_bootcmd",
 458                };
 459
 460                /*
 461                 * Set the above envs to their default values, in case the user
 462                 * managed to break them.
 463                 */
 464                env_set_default_vars(2, (char * const *)vars, 0);
 465
 466                /* Ensure bootcmd_rescue is used by distroboot */
 467                env_set("boot_targets", "rescue");
 468
 469                /* start blinking PHY LEDs */
 470                mox_phy_leds_start_blinking();
 471
 472                printf("RESET button was pressed, overwriting boot_targets!\n");
 473        } else {
 474                /*
 475                 * In case the user somehow managed to save environment with
 476                 * boot_targets=rescue, reset boot_targets to default value.
 477                 * This could happen in subsequent commands if bootcmd_rescue
 478                 * failed.
 479                 */
 480                if (!strcmp(env_get("boot_targets"), "rescue")) {
 481                        const char * const vars[1] = {
 482                                "boot_targets",
 483                        };
 484
 485                        env_set_default_vars(1, (char * const *)vars, 0);
 486                }
 487        }
 488}
 489
 490int show_board_info(void)
 491{
 492        int i, ret, board_version, ram_size, is_sd;
 493        const char *pub_key;
 494        const u8 *topology;
 495        u64 serial_number;
 496
 497        printf("Model: CZ.NIC Turris Mox Board\n");
 498
 499        ret = mbox_sp_get_board_info(&serial_number, NULL, NULL, &board_version,
 500                                     &ram_size);
 501        if (ret < 0) {
 502                printf("  Cannot read board info: %i\n", ret);
 503        } else {
 504                printf("  Board version: %i\n", board_version);
 505                printf("  RAM size: %i MiB\n", ram_size);
 506                printf("  Serial Number: %016llX\n", serial_number);
 507        }
 508
 509        pub_key = mox_sp_get_ecdsa_public_key();
 510        if (pub_key)
 511                printf("  ECDSA Public Key: %s\n", pub_key);
 512        else
 513                printf("  Cannot read ECDSA Public Key\n");
 514
 515        ret = mox_get_topology(&topology, &module_count, &is_sd);
 516        if (ret)
 517                printf("Cannot read module topology!\n");
 518
 519        printf("  SD/eMMC version: %s\n", is_sd ? "SD" : "eMMC");
 520
 521        if (module_count)
 522                printf("Module Topology:\n");
 523
 524        for (i = 0; i < module_count; ++i) {
 525                switch (topology[i]) {
 526                case MOX_MODULE_SFP:
 527                        printf("% 4i: SFP Module\n", i + 1);
 528                        break;
 529                case MOX_MODULE_PCI:
 530                        printf("% 4i: Mini-PCIe Module\n", i + 1);
 531                        break;
 532                case MOX_MODULE_TOPAZ:
 533                        printf("% 4i: Topaz Switch Module (4-port)\n", i + 1);
 534                        break;
 535                case MOX_MODULE_PERIDOT:
 536                        printf("% 4i: Peridot Switch Module (8-port)\n", i + 1);
 537                        break;
 538                case MOX_MODULE_USB3:
 539                        printf("% 4i: USB 3.0 Module (4 ports)\n", i + 1);
 540                        break;
 541                case MOX_MODULE_PASSPCI:
 542                        printf("% 4i: Passthrough Mini-PCIe Module\n", i + 1);
 543                        break;
 544                default:
 545                        printf("% 4i: unknown (ID %i)\n", i + 1, topology[i]);
 546                }
 547        }
 548
 549        /* check if modules are connected in supported mode */
 550        for (i = 0; i < module_count; ++i) {
 551                switch (topology[i]) {
 552                case MOX_MODULE_SFP:
 553                        if (sfp) {
 554                                printf("Error: Only one SFP module is supported!\n");
 555                        } else if (topaz) {
 556                                printf("Error: SFP module cannot be connected after Topaz Switch module!\n");
 557                        } else {
 558                                sfp_pos = i;
 559                                ++sfp;
 560                        }
 561                        break;
 562                case MOX_MODULE_PCI:
 563                        if (pci)
 564                                printf("Error: Only one Mini-PCIe module is supported!\n");
 565                        else if (usb)
 566                                printf("Error: Mini-PCIe module cannot come after USB 3.0 module!\n");
 567                        else if (i && (i != 1 || !passpci))
 568                                printf("Error: Mini-PCIe module should be the first connected module or come right after Passthrough Mini-PCIe module!\n");
 569                        else
 570                                ++pci;
 571                        break;
 572                case MOX_MODULE_TOPAZ:
 573                        if (topaz)
 574                                printf("Error: Only one Topaz module is supported!\n");
 575                        else if (peridot >= 3)
 576                                printf("Error: At most two Peridot modules can come before Topaz module!\n");
 577                        else
 578                                ++topaz;
 579                        break;
 580                case MOX_MODULE_PERIDOT:
 581                        if (sfp || topaz) {
 582                                printf("Error: Peridot module must come before SFP or Topaz module!\n");
 583                        } else if (peridot >= 3) {
 584                                printf("Error: At most three Peridot modules are supported!\n");
 585                        } else {
 586                                peridot_pos[peridot] = i;
 587                                ++peridot;
 588                        }
 589                        break;
 590                case MOX_MODULE_USB3:
 591                        if (pci)
 592                                printf("Error: USB 3.0 module cannot come after Mini-PCIe module!\n");
 593                        else if (usb)
 594                                printf("Error: Only one USB 3.0 module is supported!\n");
 595                        else if (i && (i != 1 || !passpci))
 596                                printf("Error: USB 3.0 module should be the first connected module or come right after Passthrough Mini-PCIe module!\n");
 597                        else
 598                                ++usb;
 599                        break;
 600                case MOX_MODULE_PASSPCI:
 601                        if (passpci)
 602                                printf("Error: Only one Passthrough Mini-PCIe module is supported!\n");
 603                        else if (i != 0)
 604                                printf("Error: Passthrough Mini-PCIe module should be the first connected module!\n");
 605                        else
 606                                ++passpci;
 607                }
 608        }
 609
 610        if (module_count)
 611                printf("\n");
 612
 613        return 0;
 614}
 615
 616int last_stage_init(void)
 617{
 618        struct gpio_desc reset_gpio = {};
 619
 620        /* configure modules */
 621        if (get_reset_gpio(&reset_gpio) < 0)
 622                goto handle_reset_btn;
 623
 624        if (peridot > 0) {
 625                if (configure_peridots(&reset_gpio) < 0) {
 626                        printf("Cannot configure Peridot modules!\n");
 627                        peridot = 0;
 628                }
 629        } else {
 630                dm_gpio_set_value(&reset_gpio, 1);
 631                mdelay(50);
 632                dm_gpio_set_value(&reset_gpio, 0);
 633                mdelay(50);
 634        }
 635
 636        /*
 637         * check if the addresses are set by reading Scratch & Misc register
 638         * 0x70 of Peridot (and potentially Topaz) modules
 639         */
 640        if (peridot || topaz) {
 641                struct mii_dev *bus;
 642
 643                bus = miiphy_get_dev_by_name("neta@30000");
 644                if (!bus) {
 645                        printf("Cannot get MDIO bus device!\n");
 646                } else {
 647                        int i;
 648
 649                        for (i = 0; i < peridot; ++i)
 650                                check_switch_address(bus, 0x10 + i);
 651
 652                        if (topaz)
 653                                check_switch_address(bus, 0x2);
 654
 655                        sw_blink_leds(bus, peridot, topaz);
 656                }
 657        }
 658
 659handle_reset_btn:
 660        handle_reset_button();
 661
 662        return 0;
 663}
 664
 665#if defined(CONFIG_OF_BOARD_SETUP)
 666
 667static int vnode_by_path(void *blob, const char *fmt, va_list ap)
 668{
 669        char path[128];
 670
 671        vsnprintf(path, 128, fmt, ap);
 672        return fdt_path_offset(blob, path);
 673}
 674
 675static int node_by_path(void *blob, const char *fmt, ...)
 676{
 677        va_list ap;
 678        int res;
 679
 680        va_start(ap, fmt);
 681        res = vnode_by_path(blob, fmt, ap);
 682        va_end(ap);
 683
 684        return res;
 685}
 686
 687static int phandle_by_path(void *blob, const char *fmt, ...)
 688{
 689        va_list ap;
 690        int node, phandle, res;
 691
 692        va_start(ap, fmt);
 693        node = vnode_by_path(blob, fmt, ap);
 694        va_end(ap);
 695
 696        if (node < 0)
 697                return node;
 698
 699        phandle = fdt_get_phandle(blob, node);
 700        if (phandle > 0)
 701                return phandle;
 702
 703        phandle = fdt_get_max_phandle(blob);
 704        if (phandle < 0)
 705                return phandle;
 706
 707        phandle += 1;
 708
 709        res = fdt_setprop_u32(blob, node, "linux,phandle", phandle);
 710        if (res < 0)
 711                return res;
 712
 713        res = fdt_setprop_u32(blob, node, "phandle", phandle);
 714        if (res < 0)
 715                return res;
 716
 717        return phandle;
 718}
 719
 720static int enable_by_path(void *blob, const char *fmt, ...)
 721{
 722        va_list ap;
 723        int node;
 724
 725        va_start(ap, fmt);
 726        node = vnode_by_path(blob, fmt, ap);
 727        va_end(ap);
 728
 729        if (node < 0)
 730                return node;
 731
 732        return fdt_setprop_string(blob, node, "status", "okay");
 733}
 734
 735static bool is_topaz(int id)
 736{
 737        return topaz && id == peridot + topaz - 1;
 738}
 739
 740static int switch_addr(int id)
 741{
 742        return is_topaz(id) ? 0x2 : 0x10 + id;
 743}
 744
 745static int setup_switch(void *blob, int id)
 746{
 747        int res, addr, i, node, phandle;
 748
 749        addr = switch_addr(id);
 750
 751        /* first enable the switch by setting status = "okay" */
 752        res = enable_by_path(blob, MDIO_PATH "/switch%i@%x", id, addr);
 753        if (res < 0)
 754                return res;
 755
 756        /*
 757         * now if there are more switches or a SFP module coming after,
 758         * enable corresponding ports
 759         */
 760        if (id < peridot + topaz - 1) {
 761                res = enable_by_path(blob,
 762                                     MDIO_PATH "/switch%i@%x/ports/port@a",
 763                                     id, addr);
 764        } else if (id == peridot - 1 && !topaz && sfp) {
 765                res = enable_by_path(blob,
 766                                     MDIO_PATH "/switch%i@%x/ports/port-sfp@a",
 767                                     id, addr);
 768        } else {
 769                res = 0;
 770        }
 771        if (res < 0)
 772                return res;
 773
 774        if (id >= peridot + topaz - 1)
 775                return 0;
 776
 777        /* finally change link property if needed */
 778        node = node_by_path(blob, MDIO_PATH "/switch%i@%x/ports/port@a", id,
 779                            addr);
 780        if (node < 0)
 781                return node;
 782
 783        for (i = id + 1; i < peridot + topaz; ++i) {
 784                phandle = phandle_by_path(blob,
 785                                          MDIO_PATH "/switch%i@%x/ports/port@%x",
 786                                          i, switch_addr(i),
 787                                          is_topaz(i) ? 5 : 9);
 788                if (phandle < 0)
 789                        return phandle;
 790
 791                if (i == id + 1)
 792                        res = fdt_setprop_u32(blob, node, "link", phandle);
 793                else
 794                        res = fdt_appendprop_u32(blob, node, "link", phandle);
 795                if (res < 0)
 796                        return res;
 797        }
 798
 799        return 0;
 800}
 801
 802static int remove_disabled_nodes(void *blob)
 803{
 804        while (1) {
 805                int res, offset;
 806
 807                offset = fdt_node_offset_by_prop_value(blob, -1, "status",
 808                                                       "disabled", 9);
 809                if (offset < 0)
 810                        break;
 811
 812                res = fdt_del_node(blob, offset);
 813                if (res < 0)
 814                        return res;
 815        }
 816
 817        return 0;
 818}
 819
 820int ft_board_setup(void *blob, struct bd_info *bd)
 821{
 822        int node, phandle, res;
 823
 824        /*
 825         * If MOX B (PCI), MOX F (USB) or MOX G (Passthrough PCI) modules are
 826         * connected, enable the PCIe node.
 827         */
 828        if (pci || usb || passpci) {
 829                node = fdt_path_offset(blob, PCIE_PATH);
 830                if (node < 0)
 831                        return node;
 832
 833                res = fdt_setprop_string(blob, node, "status", "okay");
 834                if (res < 0)
 835                        return res;
 836
 837                /* Fix PCIe regions for devices with 4 GB RAM */
 838                res = a3700_fdt_fix_pcie_regions(blob);
 839                if (res < 0)
 840                        return res;
 841        }
 842
 843        /*
 844         * If MOX C (Topaz switch) and/or MOX E (Peridot switch) are connected,
 845         * enable the eth1 node and setup the switches.
 846         */
 847        if (peridot || topaz) {
 848                int i;
 849
 850                res = enable_by_path(blob, ETH1_PATH);
 851                if (res < 0)
 852                        return res;
 853
 854                for (i = 0; i < peridot + topaz; ++i) {
 855                        res = setup_switch(blob, i);
 856                        if (res < 0)
 857                                return res;
 858                }
 859        }
 860
 861        /*
 862         * If MOX D (SFP cage module) is connected, enable the SFP node and eth1
 863         * node. If there is no Peridot switch between MOX A and MOX D, add link
 864         * to the SFP node to eth1 node.
 865         * Also enable and configure SFP GPIO controller node.
 866         */
 867        if (sfp) {
 868                res = enable_by_path(blob, SFP_PATH);
 869                if (res < 0)
 870                        return res;
 871
 872                res = enable_by_path(blob, ETH1_PATH);
 873                if (res < 0)
 874                        return res;
 875
 876                if (!peridot) {
 877                        phandle = phandle_by_path(blob, SFP_PATH);
 878                        if (phandle < 0)
 879                                return res;
 880
 881                        node = node_by_path(blob, ETH1_PATH);
 882                        if (node < 0)
 883                                return node;
 884
 885                        res = fdt_setprop_u32(blob, node, "sfp", phandle);
 886                        if (res < 0)
 887                                return res;
 888
 889                        res = fdt_setprop_string(blob, node, "phy-mode",
 890                                                 "sgmii");
 891                        if (res < 0)
 892                                return res;
 893                }
 894
 895                res = enable_by_path(blob, SFP_GPIO_PATH);
 896                if (res < 0)
 897                        return res;
 898
 899                if (sfp_pos) {
 900                        char newname[16];
 901
 902                        /* moxtet-sfp is on non-zero position, change default */
 903                        node = node_by_path(blob, SFP_GPIO_PATH);
 904                        if (node < 0)
 905                                return node;
 906
 907                        res = fdt_setprop_u32(blob, node, "reg", sfp_pos);
 908                        if (res < 0)
 909                                return res;
 910
 911                        sprintf(newname, "gpio@%x", sfp_pos);
 912
 913                        res = fdt_set_name(blob, node, newname);
 914                        if (res < 0)
 915                                return res;
 916                }
 917        }
 918
 919        fdt_fixup_ethernet(blob);
 920
 921        /* Finally remove disabled nodes, as per Rob Herring's request. */
 922        remove_disabled_nodes(blob);
 923
 924        return 0;
 925}
 926
 927#endif
 928