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