#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
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;
}
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;
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");
}
}
- /* 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:
}
}
- /* 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) {
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);
}
}
- 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;
* 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;
}
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);
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;
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;
* 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;
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;
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;