diff options
-rw-r--r-- | board/CZ.NIC/turris_omnia/turris_omnia.c | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/board/CZ.NIC/turris_omnia/turris_omnia.c b/board/CZ.NIC/turris_omnia/turris_omnia.c index dab5711cf0c..a7c1c1fc797 100644 --- a/board/CZ.NIC/turris_omnia/turris_omnia.c +++ b/board/CZ.NIC/turris_omnia/turris_omnia.c @@ -19,9 +19,11 @@ #include <asm/arch/cpu.h> #include <asm/arch/soc.h> #include <dm/uclass.h> +#include <dt-bindings/gpio/gpio.h> #include <fdt_support.h> #include <time.h> #include <linux/bitops.h> +#include <linux/delay.h> #include <u-boot/crc.h> #include "../drivers/ddr/marvell/a38x/ddr3_init.h" @@ -65,6 +67,9 @@ enum mcu_commands { /* available if STS_FEATURES_SUPPORTED bit set in status word */ CMD_GET_FEATURES = 0x10, + + /* available if EXT_CMD bit set in features */ + CMD_EXT_CONTROL = 0x12, }; enum status_word_bits { @@ -81,6 +86,16 @@ enum status_word_bits { /* CMD_GET_FEATURES */ enum features_e { FEAT_PERIPH_MCU = BIT(0), + FEAT_EXT_CMDS = BIT(1), +}; + +/* CMD_EXT_CONTROL */ +enum ext_ctl_e { + EXT_CTL_nRES_LAN = BIT(1), + EXT_CTL_nRES_PHY = BIT(2), + EXT_CTL_nPERST0 = BIT(3), + EXT_CTL_nPERST1 = BIT(4), + EXT_CTL_nPERST2 = BIT(5), }; /* @@ -543,6 +558,90 @@ static void handle_reset_button(void) } } +static void initialize_switch(void) +{ + u32 val, val04, val08, val10, val14; + u16 ctrl[2]; + int err; + + printf("Initializing LAN eth switch... "); + + /* Change RGMII pins to GPIO mode */ + + val = val04 = readl(MVEBU_MPP_BASE + 0x04); + val &= ~GENMASK(19, 16); /* MPP[12] := GPIO */ + val &= ~GENMASK(23, 20); /* MPP[13] := GPIO */ + val &= ~GENMASK(27, 24); /* MPP[14] := GPIO */ + val &= ~GENMASK(31, 28); /* MPP[15] := GPIO */ + writel(val, MVEBU_MPP_BASE + 0x04); + + val = val08 = readl(MVEBU_MPP_BASE + 0x08); + val &= ~GENMASK(3, 0); /* MPP[16] := GPIO */ + val &= ~GENMASK(23, 20); /* MPP[21] := GPIO */ + writel(val, MVEBU_MPP_BASE + 0x08); + + val = val10 = readl(MVEBU_MPP_BASE + 0x10); + val &= ~GENMASK(27, 24); /* MPP[38] := GPIO */ + val &= ~GENMASK(31, 28); /* MPP[39] := GPIO */ + writel(val, MVEBU_MPP_BASE + 0x10); + + val = val14 = readl(MVEBU_MPP_BASE + 0x14); + val &= ~GENMASK(3, 0); /* MPP[40] := GPIO */ + val &= ~GENMASK(7, 4); /* MPP[41] := GPIO */ + writel(val, MVEBU_MPP_BASE + 0x14); + + /* Set initial values for switch reset strapping pins */ + + val = readl(MVEBU_GPIO0_BASE + 0x00); + val |= BIT(12); /* GPIO[12] := 1 */ + val |= BIT(13); /* GPIO[13] := 1 */ + val |= BIT(14); /* GPIO[14] := 1 */ + val |= BIT(15); /* GPIO[15] := 1 */ + val &= ~BIT(16); /* GPIO[16] := 0 */ + val |= BIT(21); /* GPIO[21] := 1 */ + writel(val, MVEBU_GPIO0_BASE + 0x00); + + val = readl(MVEBU_GPIO1_BASE + 0x00); + val |= BIT(6); /* GPIO[38] := 1 */ + val |= BIT(7); /* GPIO[39] := 1 */ + val |= BIT(8); /* GPIO[40] := 1 */ + val &= ~BIT(9); /* GPIO[41] := 0 */ + writel(val, MVEBU_GPIO1_BASE + 0x00); + + val = readl(MVEBU_GPIO0_BASE + 0x04); + val &= ~BIT(12); /* GPIO[12] := Out Enable */ + val &= ~BIT(13); /* GPIO[13] := Out Enable */ + val &= ~BIT(14); /* GPIO[14] := Out Enable */ + val &= ~BIT(15); /* GPIO[15] := Out Enable */ + val &= ~BIT(16); /* GPIO[16] := Out Enable */ + val &= ~BIT(21); /* GPIO[21] := Out Enable */ + writel(val, MVEBU_GPIO0_BASE + 0x04); + + val = readl(MVEBU_GPIO1_BASE + 0x04); + val &= ~BIT(6); /* GPIO[38] := Out Enable */ + val &= ~BIT(7); /* GPIO[39] := Out Enable */ + val &= ~BIT(8); /* GPIO[40] := Out Enable */ + val &= ~BIT(9); /* GPIO[41] := Out Enable */ + writel(val, MVEBU_GPIO1_BASE + 0x04); + + /* Release switch reset */ + + ctrl[0] = EXT_CTL_nRES_LAN; + ctrl[1] = EXT_CTL_nRES_LAN; + err = omnia_mcu_write(CMD_EXT_CONTROL, ctrl, sizeof(ctrl)); + + mdelay(10); + + /* Change RGMII pins back to RGMII mode */ + + writel(val04, MVEBU_MPP_BASE + 0x04); + writel(val08, MVEBU_MPP_BASE + 0x08); + writel(val10, MVEBU_MPP_BASE + 0x10); + writel(val14, MVEBU_MPP_BASE + 0x14); + + puts(err ? "failed\n" : "done\n"); +} + int board_early_init_f(void) { /* Configure MPP */ @@ -572,6 +671,9 @@ int board_early_init_f(void) void spl_board_init(void) { + u16 val; + int ret; + /* * If booting from UART, disable MCU watchdog in SPL, since uploading * U-Boot proper can take too much time and trigger it. Instead enable @@ -581,6 +683,19 @@ void spl_board_init(void) enable_a385_watchdog(10); disable_mcu_watchdog(); } + + /* + * When MCU controls peripheral resets then release LAN eth switch from + * the reset and initialize it. When MCU does not control peripheral + * resets then LAN eth switch is initialized automatically by bootstrap + * pins when A385 is released from the reset. + */ + ret = omnia_mcu_read(CMD_GET_STATUS_WORD, &val, sizeof(val)); + if (ret == 0 && (val & STS_FEATURES_SUPPORTED)) { + ret = omnia_mcu_read(CMD_GET_FEATURES, &val, sizeof(val)); + if (ret == 0 && (val & FEAT_PERIPH_MCU)) + initialize_switch(); + } } #if IS_ENABLED(CONFIG_OF_BOARD_FIXUP) || IS_ENABLED(CONFIG_OF_BOARD_SETUP) @@ -689,11 +804,109 @@ static void fixup_wwan_port_nodes(void *blob) disable_pcie_node(blob, 2); } +static int insert_mcu_gpio_prop(void *blob, int node, const char *prop, + unsigned int phandle, u32 bank, u32 gpio, + u32 flags) +{ + fdt32_t val[4] = { cpu_to_fdt32(phandle), cpu_to_fdt32(bank), + cpu_to_fdt32(gpio), cpu_to_fdt32(flags) }; + return fdt_setprop(blob, node, prop, &val, sizeof(val)); +} + +static int fixup_mcu_gpio_in_pcie_nodes(void *blob) +{ + unsigned int mcu_phandle; + int port, gpio; + int pcie_node; + int port_node; + int ret; + + ret = fdt_increase_size(blob, 128); + if (ret < 0) { + printf("Cannot increase FDT size!\n"); + return ret; + } + + mcu_phandle = fdt_create_phandle_by_compatible(blob, "cznic,turris-omnia-mcu"); + if (!mcu_phandle) + return -FDT_ERR_NOPHANDLES; + + fdt_for_each_node_by_compatible(pcie_node, blob, -1, "marvell,armada-370-pcie") { + if (!fdtdec_get_is_enabled(blob, pcie_node)) + continue; + + fdt_for_each_subnode(port_node, blob, pcie_node) { + if (!fdtdec_get_is_enabled(blob, port_node)) + continue; + + port = fdtdec_get_int(blob, port_node, "marvell,pcie-port", -1); + + if (port == 0) + gpio = ilog2(EXT_CTL_nPERST0); + else if (port == 1) + gpio = ilog2(EXT_CTL_nPERST1); + else if (port == 2) + gpio = ilog2(EXT_CTL_nPERST2); + else + continue; + + /* insert: reset-gpios = <&mcu 2 gpio GPIO_ACTIVE_LOW>; */ + ret = insert_mcu_gpio_prop(blob, port_node, "reset-gpios", + mcu_phandle, 2, gpio, GPIO_ACTIVE_LOW); + if (ret < 0) + return ret; + } + } + + return 0; +} + +static int fixup_mcu_gpio_in_eth_wan_node(void *blob) +{ + unsigned int mcu_phandle; + int eth_wan_node; + int ret; + + ret = fdt_increase_size(blob, 64); + if (ret < 0) { + printf("Cannot increase FDT size!\n"); + return ret; + } + + eth_wan_node = fdt_path_offset(blob, "ethernet2"); + if (eth_wan_node < 0) + return eth_wan_node; + + mcu_phandle = fdt_create_phandle_by_compatible(blob, "cznic,turris-omnia-mcu"); + if (!mcu_phandle) + return -FDT_ERR_NOPHANDLES; + + /* insert: phy-reset-gpios = <&mcu 2 gpio GPIO_ACTIVE_LOW>; */ + ret = insert_mcu_gpio_prop(blob, eth_wan_node, "phy-reset-gpios", + mcu_phandle, 2, ilog2(EXT_CTL_nRES_PHY), GPIO_ACTIVE_LOW); + if (ret < 0) + return ret; + + return 0; +} + #endif #if IS_ENABLED(CONFIG_OF_BOARD_FIXUP) int board_fix_fdt(void *blob) { + u16 val; + int ret; + + ret = omnia_mcu_read(CMD_GET_STATUS_WORD, &val, sizeof(val)); + if (ret == 0 && (val & STS_FEATURES_SUPPORTED)) { + ret = omnia_mcu_read(CMD_GET_FEATURES, &val, sizeof(val)); + if (ret == 0 && (val & FEAT_PERIPH_MCU)) { + fixup_mcu_gpio_in_pcie_nodes(blob); + fixup_mcu_gpio_in_eth_wan_node(blob); + } + } + fixup_msata_port_nodes(blob); fixup_wwan_port_nodes(blob); @@ -840,6 +1053,19 @@ fail: int ft_board_setup(void *blob, struct bd_info *bd) { + int node; + + /* + * U-Boot's FDT blob contains phy-reset-gpios in ethernet2 + * node when MCU controls all peripherals resets. + * Fixup MCU GPIO nodes in PCIe and eth wan nodes in this case. + */ + node = fdt_path_offset(gd->fdt_blob, "ethernet2"); + if (node >= 0 && fdt_getprop(gd->fdt_blob, node, "phy-reset-gpios", NULL)) { + fixup_mcu_gpio_in_pcie_nodes(blob); + fixup_mcu_gpio_in_eth_wan_node(blob); + } + fixup_spi_nor_partitions(blob); fixup_msata_port_nodes(blob); fixup_wwan_port_nodes(blob); |