arm: mvebu: turris_mox: Find DT nodes by compatible or alias instead of path
[platform/kernel/u-boot.git] / board / CZ.NIC / turris_mox / turris_mox.c
index f3c3996..03c9239 100644 (file)
@@ -7,13 +7,16 @@
 #include <asm/arch/cpu.h>
 #include <asm/arch/soc.h>
 #include <net.h>
+#include <asm/global_data.h>
 #include <asm/io.h>
 #include <asm/gpio.h>
+#include <button.h>
 #include <clk.h>
 #include <dm.h>
 #include <env.h>
 #include <fdt_support.h>
 #include <init.h>
+#include <led.h>
 #include <linux/delay.h>
 #include <linux/libfdt.h>
 #include <linux/string.h>
 #define ARMADA_37XX_SPI_DOUT   (MVEBU_REGISTER(0x10608))
 #define ARMADA_37XX_SPI_DIN    (MVEBU_REGISTER(0x1060c))
 
-#define ETH1_PATH      "/soc/internal-regs@d0000000/ethernet@40000"
-#define MDIO_PATH      "/soc/internal-regs@d0000000/mdio@32004"
-#define SFP_GPIO_PATH  "/soc/internal-regs@d0000000/spi@10600/moxtet@1/gpio@0"
-#define PCIE_PATH      "/soc/pcie@d0070000"
-#define SFP_PATH       "/sfp"
-
 DECLARE_GLOBAL_DATA_PTR;
 
 #if defined(CONFIG_OF_BOARD_FIXUP)
 int board_fix_fdt(void *blob)
 {
        u8 topology[MAX_MOX_MODULES];
-       int i, size, node;
-       bool enable;
+       enum fdt_status status;
+       int i, size, ret;
 
        /*
         * SPI driver is not loaded in driver model yet, but we have to find out
@@ -89,21 +86,15 @@ int board_fix_fdt(void *blob)
        if (size > 1 && (topology[1] == MOX_MODULE_PCI ||
                         topology[1] == MOX_MODULE_USB3 ||
                         topology[1] == MOX_MODULE_PASSPCI))
-               enable = true;
+               status = FDT_STATUS_OKAY;
        else
-               enable = false;
-
-       node = fdt_path_offset(blob, PCIE_PATH);
+               status = FDT_STATUS_DISABLED;
 
-       if (node < 0) {
-               printf("Cannot find PCIe node in U-Boot's device tree!\n");
-               return 0;
-       }
-
-       if (fdt_setprop_string(blob, node, "status",
-                              enable ? "okay" : "disabled") < 0) {
-               printf("Cannot %s PCIe in U-Boot's device tree!\n",
-                      enable ? "enable" : "disable");
+       ret = fdt_set_status_by_compatible(blob, "marvell,armada-3700-pcie",
+                                          status);
+       if (ret < 0) {
+               printf("Cannot set status for PCIe in U-Boot's device tree: %s!\n",
+                      fdt_strerror(ret));
                return 0;
        }
 
@@ -215,13 +206,13 @@ int comphy_update_map(struct comphy_map *serdes_map, int count)
 
        if (sfpindex >= 0 && swindex >= 0) {
                if (sfpindex < swindex)
-                       serdes_map[0].speed = PHY_SPEED_1_25G;
+                       serdes_map[0].speed = COMPHY_SPEED_1_25G;
                else
-                       serdes_map[0].speed = PHY_SPEED_3_125G;
+                       serdes_map[0].speed = COMPHY_SPEED_3_125G;
        } else if (sfpindex >= 0) {
-               serdes_map[0].speed = PHY_SPEED_1_25G;
+               serdes_map[0].speed = COMPHY_SPEED_1_25G;
        } else if (swindex >= 0) {
-               serdes_map[0].speed = PHY_SPEED_3_125G;
+               serdes_map[0].speed = COMPHY_SPEED_3_125G;
        }
 
        return 0;
@@ -354,62 +345,168 @@ static int get_reset_gpio(struct gpio_desc *reset_gpio)
 
 int misc_init_r(void)
 {
-       int ret;
-       u8 mac1[6], mac2[6];
+       u8 mac[2][6];
+       int i, ret;
 
-       ret = mbox_sp_get_board_info(NULL, mac1, mac2, NULL, NULL);
+       ret = mbox_sp_get_board_info(NULL, mac[0], mac[1], NULL, NULL);
        if (ret < 0) {
                printf("Cannot read data from OTP!\n");
                return 0;
        }
 
-       if (is_valid_ethaddr(mac1) && !env_get("ethaddr"))
-               eth_env_set_enetaddr("ethaddr", mac1);
+       for (i = 0; i < 2; ++i) {
+               u8 oldmac[6];
 
-       if (is_valid_ethaddr(mac2) && !env_get("eth1addr"))
-               eth_env_set_enetaddr("eth1addr", mac2);
+               if (is_valid_ethaddr(mac[i]) &&
+                   !eth_env_get_enetaddr_by_index("eth", i, oldmac))
+                       eth_env_set_enetaddr_by_index("eth", i, mac[i]);
+       }
 
        return 0;
 }
 
-static void mox_print_info(void)
+static void mox_phy_modify(struct phy_device *phydev, int page, int reg,
+                          u16 mask, u16 set)
 {
-       int ret, board_version, ram_size;
-       u64 serial_number;
-       const char *pub_key;
+       int val;
 
-       ret = mbox_sp_get_board_info(&serial_number, NULL, NULL, &board_version,
-                                    &ram_size);
-       if (ret < 0)
+       val = phydev->drv->readext(phydev, MDIO_DEVAD_NONE, page, reg);
+       val &= ~mask;
+       val |= set;
+       phydev->drv->writeext(phydev, MDIO_DEVAD_NONE, page, reg, val);
+}
+
+static void mox_phy_leds_start_blinking(void)
+{
+       struct phy_device *phydev;
+       struct mii_dev *bus;
+
+       bus = miiphy_get_dev_by_name("neta@30000");
+       if (!bus) {
+               printf("Cannot get MDIO bus device!\n");
                return;
+       }
 
-       printf("Turris Mox:\n");
-       printf("  Board version: %i\n", board_version);
-       printf("  RAM size: %i MiB\n", ram_size);
-       printf("  Serial Number: %016llX\n", serial_number);
+       phydev = phy_find_by_mask(bus, BIT(1), PHY_INTERFACE_MODE_RGMII);
+       if (!phydev) {
+               printf("Cannot get ethernet PHY!\n");
+               return;
+       }
 
-       pub_key = mox_sp_get_ecdsa_public_key();
-       if (pub_key)
-               printf("  ECDSA Public Key: %s\n", pub_key);
-       else
-               printf("Cannot read ECDSA Public Key\n");
+       mox_phy_modify(phydev, 3, 0x12, 0x700, 0x400);
+       mox_phy_modify(phydev, 3, 0x10, 0xff, 0xbb);
 }
 
-int last_stage_init(void)
+static bool read_reset_button(void)
 {
-       int ret, i;
+       struct udevice *button, *led;
+       int i;
+
+       if (device_get_global_by_ofnode(
+                       ofnode_first_subnode(ofnode_by_compatible(ofnode_null(),
+                                                                 "gpio-keys")),
+                       &button)) {
+               printf("Cannot find reset button!\n");
+               return false;
+       }
+
+       if (device_get_global_by_ofnode(
+                       ofnode_first_subnode(ofnode_by_compatible(ofnode_null(),
+                                                                 "gpio-leds")),
+                       &led)) {
+               printf("Cannot find status LED!\n");
+               return false;
+       }
+
+       led_set_state(led, LEDST_ON);
+
+       for (i = 0; i < 21; ++i) {
+               if (button_get_state(button) != BUTTON_ON)
+                       return false;
+               if (i < 20)
+                       mdelay(50);
+       }
+
+       led_set_state(led, LEDST_OFF);
+
+       return true;
+}
+
+static void handle_reset_button(void)
+{
+       const char * const vars[1] = { "bootcmd_rescue", };
+
+       /*
+        * Ensure that bootcmd_rescue has always stock value, so that running
+        *   run bootcmd_rescue
+        * always works correctly.
+        */
+       env_set_default_vars(1, (char * const *)vars, 0);
+
+       if (read_reset_button()) {
+               const char * const vars[2] = {
+                       "bootcmd",
+                       "distro_bootcmd",
+               };
+
+               /*
+                * Set the above envs to their default values, in case the user
+                * managed to break them.
+                */
+               env_set_default_vars(2, (char * const *)vars, 0);
+
+               /* Ensure bootcmd_rescue is used by distroboot */
+               env_set("boot_targets", "rescue");
+
+               /* start blinking PHY LEDs */
+               mox_phy_leds_start_blinking();
+
+               printf("RESET button was pressed, overwriting boot_targets!\n");
+       } else {
+               /*
+                * In case the user somehow managed to save environment with
+                * boot_targets=rescue, reset boot_targets to default value.
+                * This could happen in subsequent commands if bootcmd_rescue
+                * failed.
+                */
+               if (!strcmp(env_get("boot_targets"), "rescue")) {
+                       const char * const vars[1] = {
+                               "boot_targets",
+                       };
+
+                       env_set_default_vars(1, (char * const *)vars, 0);
+               }
+       }
+}
+
+int show_board_info(void)
+{
+       int i, ret, board_version, ram_size, is_sd;
+       const char *pub_key;
        const u8 *topology;
-       int is_sd;
-       struct mii_dev *bus;
-       struct gpio_desc reset_gpio = {};
+       u64 serial_number;
+
+       printf("Model: CZ.NIC Turris Mox Board\n");
 
-       mox_print_info();
+       ret = mbox_sp_get_board_info(&serial_number, NULL, NULL, &board_version,
+                                    &ram_size);
+       if (ret < 0) {
+               printf("  Cannot read board info: %i\n", ret);
+       } else {
+               printf("  Board version: %i\n", board_version);
+               printf("  RAM size: %i MiB\n", ram_size);
+               printf("  Serial Number: %016llX\n", serial_number);
+       }
+
+       pub_key = mox_sp_get_ecdsa_public_key();
+       if (pub_key)
+               printf("  ECDSA Public Key: %s\n", pub_key);
+       else
+               printf("  Cannot read ECDSA Public Key\n");
 
        ret = mox_get_topology(&topology, &module_count, &is_sd);
-       if (ret) {
+       if (ret)
                printf("Cannot read module topology!\n");
-               return 0;
-       }
 
        printf("  SD/eMMC version: %s\n", is_sd ? "SD" : "eMMC");
 
@@ -441,8 +538,7 @@ int last_stage_init(void)
                }
        }
 
-       /* now check if modules are connected in supported mode */
-
+       /* check if modules are connected in supported mode */
        for (i = 0; i < module_count; ++i) {
                switch (topology[i]) {
                case MOX_MODULE_SFP:
@@ -503,10 +599,19 @@ int last_stage_init(void)
                }
        }
 
-       /* now configure modules */
+       if (module_count)
+               printf("\n");
 
+       return 0;
+}
+
+int last_stage_init(void)
+{
+       struct gpio_desc reset_gpio = {};
+
+       /* configure modules */
        if (get_reset_gpio(&reset_gpio) < 0)
-               return 0;
+               goto handle_reset_btn;
 
        if (peridot > 0) {
                if (configure_peridots(&reset_gpio) < 0) {
@@ -520,16 +625,19 @@ int last_stage_init(void)
                mdelay(50);
        }
 
+       /*
+        * check if the addresses are set by reading Scratch & Misc register
+        * 0x70 of Peridot (and potentially Topaz) modules
+        */
        if (peridot || topaz) {
-               /*
-                * now check if the addresses are set by reading Scratch & Misc
-                * register 0x70 of Peridot (and potentially Topaz) modules
-                */
+               struct mii_dev *bus;
 
                bus = miiphy_get_dev_by_name("neta@30000");
                if (!bus) {
                        printf("Cannot get MDIO bus device!\n");
                } else {
+                       int i;
+
                        for (i = 0; i < peridot; ++i)
                                check_switch_address(bus, 0x10 + i);
 
@@ -540,99 +648,42 @@ int last_stage_init(void)
                }
        }
 
-       printf("\n");
+handle_reset_btn:
+       handle_reset_button();
 
        return 0;
 }
 
 #if defined(CONFIG_OF_BOARD_SETUP)
 
-static int vnode_by_path(void *blob, const char *fmt, va_list ap)
+static bool is_topaz(int id)
 {
-       char path[128];
-
-       vsnprintf(path, 128, fmt, ap);
-       return fdt_path_offset(blob, path);
+       return topaz && id == peridot + topaz - 1;
 }
 
-static int node_by_path(void *blob, const char *fmt, ...)
+static int switch_addr(int id)
 {
-       va_list ap;
-       int res;
-
-       va_start(ap, fmt);
-       res = vnode_by_path(blob, fmt, ap);
-       va_end(ap);
-
-       return res;
+       return is_topaz(id) ? 0x2 : 0x10 + id;
 }
 
-static int phandle_by_path(void *blob, const char *fmt, ...)
+static int setup_switch(void *blob, int id)
 {
-       va_list ap;
-       int node, phandle, res;
-
-       va_start(ap, fmt);
-       node = vnode_by_path(blob, fmt, ap);
-       va_end(ap);
+       int res, addr, i, node;
+       char mdio_path[64];
 
+       node = fdt_node_offset_by_compatible(blob, -1, "marvell,orion-mdio");
        if (node < 0)
                return node;
 
-       phandle = fdt_get_phandle(blob, node);
-       if (phandle > 0)
-               return phandle;
-
-       phandle = fdt_get_max_phandle(blob);
-       if (phandle < 0)
-               return phandle;
-
-       phandle += 1;
-
-       res = fdt_setprop_u32(blob, node, "linux,phandle", phandle);
+       res = fdt_get_path(blob, node, mdio_path, sizeof(mdio_path));
        if (res < 0)
                return res;
 
-       res = fdt_setprop_u32(blob, node, "phandle", phandle);
-       if (res < 0)
-               return res;
-
-       return phandle;
-}
-
-static int enable_by_path(void *blob, const char *fmt, ...)
-{
-       va_list ap;
-       int node;
-
-       va_start(ap, fmt);
-       node = vnode_by_path(blob, fmt, ap);
-       va_end(ap);
-
-       if (node < 0)
-               return node;
-
-       return fdt_setprop_string(blob, node, "status", "okay");
-}
-
-static bool is_topaz(int id)
-{
-       return topaz && id == peridot + topaz - 1;
-}
-
-static int switch_addr(int id)
-{
-       return is_topaz(id) ? 0x2 : 0x10 + id;
-}
-
-static int setup_switch(void *blob, int id)
-{
-       int res, addr, i, node, phandle;
-
        addr = switch_addr(id);
 
        /* first enable the switch by setting status = "okay" */
-       res = enable_by_path(blob, MDIO_PATH "/switch%i@%x", id, addr);
+       res = fdt_status_okay_by_pathf(blob, "%s/switch%i@%x", mdio_path, id,
+                                      addr);
        if (res < 0)
                return res;
 
@@ -641,13 +692,13 @@ static int setup_switch(void *blob, int id)
         * enable corresponding ports
         */
        if (id < peridot + topaz - 1) {
-               res = enable_by_path(blob,
-                                    MDIO_PATH "/switch%i@%x/ports/port@a",
-                                    id, addr);
+               res = fdt_status_okay_by_pathf(blob,
+                                              "%s/switch%i@%x/ports/port@a",
+                                              mdio_path, id, addr);
        } else if (id == peridot - 1 && !topaz && sfp) {
-               res = enable_by_path(blob,
-                                    MDIO_PATH "/switch%i@%x/ports/port-sfp@a",
-                                    id, addr);
+               res = fdt_status_okay_by_pathf(blob,
+                                              "%s/switch%i@%x/ports/port-sfp@a",
+                                              mdio_path, id, addr);
        } else {
                res = 0;
        }
@@ -658,18 +709,21 @@ static int setup_switch(void *blob, int id)
                return 0;
 
        /* finally change link property if needed */
-       node = node_by_path(blob, MDIO_PATH "/switch%i@%x/ports/port@a", id,
-                           addr);
+       node = fdt_node_offset_by_pathf(blob, "%s/switch%i@%x/ports/port@a",
+                                       mdio_path, id, addr);
        if (node < 0)
                return node;
 
        for (i = id + 1; i < peridot + topaz; ++i) {
-               phandle = phandle_by_path(blob,
-                                         MDIO_PATH "/switch%i@%x/ports/port@%x",
-                                         i, switch_addr(i),
-                                         is_topaz(i) ? 5 : 9);
-               if (phandle < 0)
-                       return phandle;
+               unsigned int phandle;
+
+               phandle = fdt_create_phandle_by_pathf(blob,
+                                                     "%s/switch%i@%x/ports/port@%x",
+                                                     mdio_path, i,
+                                                     switch_addr(i),
+                                                     is_topaz(i) ? 5 : 9);
+               if (!phandle)
+                       return -FDT_ERR_NOPHANDLES;
 
                if (i == id + 1)
                        res = fdt_setprop_u32(blob, node, "link", phandle);
@@ -700,20 +754,17 @@ static int remove_disabled_nodes(void *blob)
        return 0;
 }
 
-int ft_board_setup(void *blob, bd_t *bd)
+int ft_board_setup(void *blob, struct bd_info *bd)
 {
-       int node, phandle, res;
+       int res;
 
        /*
         * If MOX B (PCI), MOX F (USB) or MOX G (Passthrough PCI) modules are
         * connected, enable the PCIe node.
         */
        if (pci || usb || passpci) {
-               node = fdt_path_offset(blob, PCIE_PATH);
-               if (node < 0)
-                       return node;
-
-               res = fdt_setprop_string(blob, node, "status", "okay");
+               res = fdt_status_okay_by_compatible(blob,
+                                                   "marvell,armada-3700-pcie");
                if (res < 0)
                        return res;
 
@@ -730,7 +781,7 @@ int ft_board_setup(void *blob, bd_t *bd)
        if (peridot || topaz) {
                int i;
 
-               res = enable_by_path(blob, ETH1_PATH);
+               res = fdt_status_okay_by_alias(blob, "ethernet1");
                if (res < 0)
                        return res;
 
@@ -748,20 +799,25 @@ int ft_board_setup(void *blob, bd_t *bd)
         * Also enable and configure SFP GPIO controller node.
         */
        if (sfp) {
-               res = enable_by_path(blob, SFP_PATH);
+               int node;
+
+               res = fdt_status_okay_by_compatible(blob, "sff,sfp");
                if (res < 0)
                        return res;
 
-               res = enable_by_path(blob, ETH1_PATH);
+               res = fdt_status_okay_by_alias(blob, "ethernet1");
                if (res < 0)
                        return res;
 
                if (!peridot) {
-                       phandle = phandle_by_path(blob, SFP_PATH);
-                       if (phandle < 0)
-                               return res;
+                       unsigned int phandle;
+
+                       phandle = fdt_create_phandle_by_compatible(blob,
+                                                                  "sff,sfp");
+                       if (!phandle)
+                               return -FDT_ERR_NOPHANDLES;
 
-                       node = node_by_path(blob, ETH1_PATH);
+                       node = fdt_path_offset(blob, "ethernet1");
                        if (node < 0)
                                return node;
 
@@ -775,7 +831,7 @@ int ft_board_setup(void *blob, bd_t *bd)
                                return res;
                }
 
-               res = enable_by_path(blob, SFP_GPIO_PATH);
+               res = fdt_status_okay_by_compatible(blob, "cznic,moxtet-gpio");
                if (res < 0)
                        return res;
 
@@ -783,7 +839,8 @@ int ft_board_setup(void *blob, bd_t *bd)
                        char newname[16];
 
                        /* moxtet-sfp is on non-zero position, change default */
-                       node = node_by_path(blob, SFP_GPIO_PATH);
+                       node = fdt_node_offset_by_compatible(blob, -1,
+                                                            "cznic,moxtet-gpio");
                        if (node < 0)
                                return node;