All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] arm: mvebu: turris_omnia: Show MCU type in show_board_info()
@ 2022-07-29 11:29 Pali Rohár
  2022-07-29 11:29 ` [PATCH 2/2] arm: mvebu: turris_omnia: Add support for design with SW reset signals Pali Rohár
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Pali Rohár @ 2022-07-29 11:29 UTC (permalink / raw)
  To: Stefan Roese, Marek Behún; +Cc: u-boot

Different Turris Omnia HW board revisions contains different MCU.
Show type in show_board_info() to easily identify which MCU is populated.

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 board/CZ.NIC/turris_omnia/turris_omnia.c | 45 ++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/board/CZ.NIC/turris_omnia/turris_omnia.c b/board/CZ.NIC/turris_omnia/turris_omnia.c
index b169abca0956..6fc2018c1cfb 100644
--- a/board/CZ.NIC/turris_omnia/turris_omnia.c
+++ b/board/CZ.NIC/turris_omnia/turris_omnia.c
@@ -62,13 +62,27 @@ enum mcu_commands {
 	CMD_GET_STATUS_WORD	= 0x01,
 	CMD_GET_RESET		= 0x09,
 	CMD_WATCHDOG_STATE	= 0x0b,
+
+	/* available if STS_FEATURES_SUPPORTED bit set in status word */
+	CMD_GET_FEATURES	= 0x10,
 };
 
 enum status_word_bits {
+	STS_MCU_TYPE_MASK	= GENMASK(1, 0),
+	STS_MCU_TYPE_STM32	= 0,
+	STS_MCU_TYPE_GD32	= 1,
+	STS_MCU_TYPE_MKL	= 2,
+	STS_MCU_TYPE_UNKN	= 3,
+	STS_FEATURES_SUPPORTED	= BIT(2),
 	CARD_DET_STSBIT		= 0x0010,
 	MSATA_IND_STSBIT	= 0x0020,
 };
 
+/* CMD_GET_FEATURES */
+enum features_e {
+	FEAT_PERIPH_MCU		= BIT(0),
+};
+
 /*
  * Those values and defines are taken from the Marvell U-Boot version
  * "u-boot-2013.01-2014_T3.0"
@@ -371,6 +385,36 @@ static int omnia_get_ram_size_gb(void)
 	return ram_size;
 }
 
+static const char * const omnia_get_mcu_type(void)
+{
+	static const char * const mcu_types[] = {
+		[STS_MCU_TYPE_STM32] = "STM32",
+		[STS_MCU_TYPE_GD32]  = "GD32",
+		[STS_MCU_TYPE_MKL]   = "MKL",
+		[STS_MCU_TYPE_UNKN]  = "unknown",
+	};
+	static const char * const mcu_types_with_perip_resets[] = {
+		[STS_MCU_TYPE_STM32] = "STM32 (with peripheral resets)",
+		[STS_MCU_TYPE_GD32]  = "GD32 (with peripheral resets)",
+		[STS_MCU_TYPE_MKL]   = "MKL (with peripheral resets)",
+		[STS_MCU_TYPE_UNKN]  = "unknown (with peripheral resets)",
+	};
+	u16 stsword, features;
+	int ret;
+
+	ret = omnia_mcu_read(CMD_GET_STATUS_WORD, &stsword, sizeof(stsword));
+	if (ret)
+		return "unknown";
+
+	if (stsword & STS_FEATURES_SUPPORTED) {
+		ret = omnia_mcu_read(CMD_GET_FEATURES, &features, sizeof(features));
+		if (ret == 0 && (features & FEAT_PERIPH_MCU))
+			return mcu_types_with_perip_resets[stsword & STS_MCU_TYPE_MASK];
+	}
+
+	return mcu_types[stsword & STS_MCU_TYPE_MASK];
+}
+
 /*
  * Define the DDR layout / topology here in the board file. This will
  * be used by the DDR3 init code in the SPL U-Boot version to configure
@@ -688,6 +732,7 @@ int show_board_info(void)
 
 	err = turris_atsha_otp_get_serial_number(&version_num, &serial_num);
 	printf("Model: Turris Omnia\n");
+	printf("  MCU type: %s\n", omnia_get_mcu_type());
 	printf("  RAM size: %i MiB\n", omnia_get_ram_size_gb() * 1024);
 	if (err)
 		printf("  Serial Number: unknown\n");
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/2] arm: mvebu: turris_omnia: Add support for design with SW reset signals
  2022-07-29 11:29 [PATCH 1/2] arm: mvebu: turris_omnia: Show MCU type in show_board_info() Pali Rohár
@ 2022-07-29 11:29 ` Pali Rohár
  2022-08-01 11:58   ` Stefan Roese
                     ` (2 more replies)
  2022-08-01 11:56 ` [PATCH 1/2] arm: mvebu: turris_omnia: Show MCU type in show_board_info() Stefan Roese
                   ` (2 subsequent siblings)
  3 siblings, 3 replies; 9+ messages in thread
From: Pali Rohár @ 2022-07-29 11:29 UTC (permalink / raw)
  To: Stefan Roese, Marek Behún; +Cc: u-boot

New Turris Omnia HW board revision requires that software controls
peripheral reset signals, namely PERST# signals on mPCIe slots, ethernet
phy reset and lan switch reset. Those pins are connected to MCU controlled
by MCU i2c API as GPIOs. On new HW board revision those pins stay in reset
after board reset and software has to release these peripherals from reset
manually. MCU announce this requirement by FEAT_PERIPH_MCU bit in
CMD_GET_FEATURES command.

On older HW board revisions when FEAT_PERIPH_MCU is not announced, all
those reset signals are automatically released after board finish reset.

Detect FEAT_PERIPH_MCU bit in board_fix_fdt() and ft_board_setup()
functions and insert into device tree blob pcie "reset-gpios" and eth phy
"phy-reset-gpios" properties with corresponding MCU gpio definitions.
PCIe and eth PHY drivers then automatically release resets during device
initialization. Both U-Boot and Linux kernel drivers support those device
tree reset properties.

Initialization of lan switch on new HW board revision is more complicated.
Switch strapping pins are shared with switch RGMII pins. And strapping pins
must be in specific configuration after releasing switch reset. Due to pin
sharing, it is first required to switch A385 side of switch pins into GPIO
mode, set strapping configuration, release switch from reset and after that
switch A385 pins back to RGMII mode.

Because this complicated setup is not supported by switch DSA drivers and
cannot be expressed easily in device tree, implement it manually in SPL
function spl_board_init(). So in proper U-Boot and OS/kernel would be lan
switch initialized and be in same configuration like it was on old HW board
revisions (where reset sequence did those steps at hardware level).

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 board/CZ.NIC/turris_omnia/turris_omnia.c | 226 +++++++++++++++++++++++
 1 file changed, 226 insertions(+)

diff --git a/board/CZ.NIC/turris_omnia/turris_omnia.c b/board/CZ.NIC/turris_omnia/turris_omnia.c
index 6fc2018c1cfb..e262ea1aba51 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);
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/2] arm: mvebu: turris_omnia: Show MCU type in show_board_info()
  2022-07-29 11:29 [PATCH 1/2] arm: mvebu: turris_omnia: Show MCU type in show_board_info() Pali Rohár
  2022-07-29 11:29 ` [PATCH 2/2] arm: mvebu: turris_omnia: Add support for design with SW reset signals Pali Rohár
@ 2022-08-01 11:56 ` Stefan Roese
  2022-08-01 15:49 ` Marek Behún
  2022-08-09 11:32 ` Stefan Roese
  3 siblings, 0 replies; 9+ messages in thread
From: Stefan Roese @ 2022-08-01 11:56 UTC (permalink / raw)
  To: Pali Rohár, Marek Behún; +Cc: u-boot

On 29.07.22 13:29, Pali Rohár wrote:
> Different Turris Omnia HW board revisions contains different MCU.
> Show type in show_board_info() to easily identify which MCU is populated.
> 
> Signed-off-by: Pali Rohár <pali@kernel.org>

Reviewed-by: Stefan Roese <sr@denx.de>

Thanks,
Stefan

> ---
>   board/CZ.NIC/turris_omnia/turris_omnia.c | 45 ++++++++++++++++++++++++
>   1 file changed, 45 insertions(+)
> 
> diff --git a/board/CZ.NIC/turris_omnia/turris_omnia.c b/board/CZ.NIC/turris_omnia/turris_omnia.c
> index b169abca0956..6fc2018c1cfb 100644
> --- a/board/CZ.NIC/turris_omnia/turris_omnia.c
> +++ b/board/CZ.NIC/turris_omnia/turris_omnia.c
> @@ -62,13 +62,27 @@ enum mcu_commands {
>   	CMD_GET_STATUS_WORD	= 0x01,
>   	CMD_GET_RESET		= 0x09,
>   	CMD_WATCHDOG_STATE	= 0x0b,
> +
> +	/* available if STS_FEATURES_SUPPORTED bit set in status word */
> +	CMD_GET_FEATURES	= 0x10,
>   };
>   
>   enum status_word_bits {
> +	STS_MCU_TYPE_MASK	= GENMASK(1, 0),
> +	STS_MCU_TYPE_STM32	= 0,
> +	STS_MCU_TYPE_GD32	= 1,
> +	STS_MCU_TYPE_MKL	= 2,
> +	STS_MCU_TYPE_UNKN	= 3,
> +	STS_FEATURES_SUPPORTED	= BIT(2),
>   	CARD_DET_STSBIT		= 0x0010,
>   	MSATA_IND_STSBIT	= 0x0020,
>   };
>   
> +/* CMD_GET_FEATURES */
> +enum features_e {
> +	FEAT_PERIPH_MCU		= BIT(0),
> +};
> +
>   /*
>    * Those values and defines are taken from the Marvell U-Boot version
>    * "u-boot-2013.01-2014_T3.0"
> @@ -371,6 +385,36 @@ static int omnia_get_ram_size_gb(void)
>   	return ram_size;
>   }
>   
> +static const char * const omnia_get_mcu_type(void)
> +{
> +	static const char * const mcu_types[] = {
> +		[STS_MCU_TYPE_STM32] = "STM32",
> +		[STS_MCU_TYPE_GD32]  = "GD32",
> +		[STS_MCU_TYPE_MKL]   = "MKL",
> +		[STS_MCU_TYPE_UNKN]  = "unknown",
> +	};
> +	static const char * const mcu_types_with_perip_resets[] = {
> +		[STS_MCU_TYPE_STM32] = "STM32 (with peripheral resets)",
> +		[STS_MCU_TYPE_GD32]  = "GD32 (with peripheral resets)",
> +		[STS_MCU_TYPE_MKL]   = "MKL (with peripheral resets)",
> +		[STS_MCU_TYPE_UNKN]  = "unknown (with peripheral resets)",
> +	};
> +	u16 stsword, features;
> +	int ret;
> +
> +	ret = omnia_mcu_read(CMD_GET_STATUS_WORD, &stsword, sizeof(stsword));
> +	if (ret)
> +		return "unknown";
> +
> +	if (stsword & STS_FEATURES_SUPPORTED) {
> +		ret = omnia_mcu_read(CMD_GET_FEATURES, &features, sizeof(features));
> +		if (ret == 0 && (features & FEAT_PERIPH_MCU))
> +			return mcu_types_with_perip_resets[stsword & STS_MCU_TYPE_MASK];
> +	}
> +
> +	return mcu_types[stsword & STS_MCU_TYPE_MASK];
> +}
> +
>   /*
>    * Define the DDR layout / topology here in the board file. This will
>    * be used by the DDR3 init code in the SPL U-Boot version to configure
> @@ -688,6 +732,7 @@ int show_board_info(void)
>   
>   	err = turris_atsha_otp_get_serial_number(&version_num, &serial_num);
>   	printf("Model: Turris Omnia\n");
> +	printf("  MCU type: %s\n", omnia_get_mcu_type());
>   	printf("  RAM size: %i MiB\n", omnia_get_ram_size_gb() * 1024);
>   	if (err)
>   		printf("  Serial Number: unknown\n");

Viele Grüße,
Stefan Roese

-- 
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-51 Fax: (+49)-8142-66989-80 Email: sr@denx.de

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/2] arm: mvebu: turris_omnia: Add support for design with SW reset signals
  2022-07-29 11:29 ` [PATCH 2/2] arm: mvebu: turris_omnia: Add support for design with SW reset signals Pali Rohár
@ 2022-08-01 11:58   ` Stefan Roese
  2022-08-01 12:19     ` Pali Rohár
  2022-08-01 15:49   ` Marek Behún
  2022-08-09 11:32   ` Stefan Roese
  2 siblings, 1 reply; 9+ messages in thread
From: Stefan Roese @ 2022-08-01 11:58 UTC (permalink / raw)
  To: Pali Rohár, Marek Behún; +Cc: u-boot

On 29.07.22 13:29, Pali Rohár wrote:
> New Turris Omnia HW board revision requires that software controls
> peripheral reset signals, namely PERST# signals on mPCIe slots, ethernet
> phy reset and lan switch reset. Those pins are connected to MCU controlled
> by MCU i2c API as GPIOs. On new HW board revision those pins stay in reset
> after board reset and software has to release these peripherals from reset
> manually. MCU announce this requirement by FEAT_PERIPH_MCU bit in
> CMD_GET_FEATURES command.
> 
> On older HW board revisions when FEAT_PERIPH_MCU is not announced, all
> those reset signals are automatically released after board finish reset.
> 
> Detect FEAT_PERIPH_MCU bit in board_fix_fdt() and ft_board_setup()
> functions and insert into device tree blob pcie "reset-gpios" and eth phy
> "phy-reset-gpios" properties with corresponding MCU gpio definitions.
> PCIe and eth PHY drivers then automatically release resets during device
> initialization. Both U-Boot and Linux kernel drivers support those device
> tree reset properties.
> 
> Initialization of lan switch on new HW board revision is more complicated.
> Switch strapping pins are shared with switch RGMII pins. And strapping pins
> must be in specific configuration after releasing switch reset. Due to pin
> sharing, it is first required to switch A385 side of switch pins into GPIO
> mode, set strapping configuration, release switch from reset and after that
> switch A385 pins back to RGMII mode.
> 
> Because this complicated setup is not supported by switch DSA drivers and
> cannot be expressed easily in device tree, implement it manually in SPL
> function spl_board_init(). So in proper U-Boot and OS/kernel would be lan
> switch initialized and be in same configuration like it was on old HW board
> revisions (where reset sequence did those steps at hardware level).
> 
> Signed-off-by: Pali Rohár <pali@kernel.org>

Wow, this looks pretty complex. But I assume that you already de-stilled
the "best solution", so:

Reviewed-by: Stefan Roese <sr@denx.de>

Thanks,
Stefan


> ---
>   board/CZ.NIC/turris_omnia/turris_omnia.c | 226 +++++++++++++++++++++++
>   1 file changed, 226 insertions(+)
> 
> diff --git a/board/CZ.NIC/turris_omnia/turris_omnia.c b/board/CZ.NIC/turris_omnia/turris_omnia.c
> index 6fc2018c1cfb..e262ea1aba51 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);

Viele Grüße,
Stefan Roese

-- 
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-51 Fax: (+49)-8142-66989-80 Email: sr@denx.de

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/2] arm: mvebu: turris_omnia: Add support for design with SW reset signals
  2022-08-01 11:58   ` Stefan Roese
@ 2022-08-01 12:19     ` Pali Rohár
  0 siblings, 0 replies; 9+ messages in thread
From: Pali Rohár @ 2022-08-01 12:19 UTC (permalink / raw)
  To: Stefan Roese; +Cc: Marek Behún, u-boot

On Monday 01 August 2022 13:58:24 Stefan Roese wrote:
> On 29.07.22 13:29, Pali Rohár wrote:
> > New Turris Omnia HW board revision requires that software controls
> > peripheral reset signals, namely PERST# signals on mPCIe slots, ethernet
> > phy reset and lan switch reset. Those pins are connected to MCU controlled
> > by MCU i2c API as GPIOs. On new HW board revision those pins stay in reset
> > after board reset and software has to release these peripherals from reset
> > manually. MCU announce this requirement by FEAT_PERIPH_MCU bit in
> > CMD_GET_FEATURES command.
> > 
> > On older HW board revisions when FEAT_PERIPH_MCU is not announced, all
> > those reset signals are automatically released after board finish reset.
> > 
> > Detect FEAT_PERIPH_MCU bit in board_fix_fdt() and ft_board_setup()
> > functions and insert into device tree blob pcie "reset-gpios" and eth phy
> > "phy-reset-gpios" properties with corresponding MCU gpio definitions.
> > PCIe and eth PHY drivers then automatically release resets during device
> > initialization. Both U-Boot and Linux kernel drivers support those device
> > tree reset properties.
> > 
> > Initialization of lan switch on new HW board revision is more complicated.
> > Switch strapping pins are shared with switch RGMII pins. And strapping pins
> > must be in specific configuration after releasing switch reset. Due to pin
> > sharing, it is first required to switch A385 side of switch pins into GPIO
> > mode, set strapping configuration, release switch from reset and after that
> > switch A385 pins back to RGMII mode.
> > 
> > Because this complicated setup is not supported by switch DSA drivers and
> > cannot be expressed easily in device tree, implement it manually in SPL
> > function spl_board_init(). So in proper U-Boot and OS/kernel would be lan
> > switch initialized and be in same configuration like it was on old HW board
> > revisions (where reset sequence did those steps at hardware level).
> > 
> > Signed-off-by: Pali Rohár <pali@kernel.org>
> 
> Wow, this looks pretty complex. But I assume that you already de-stilled
> the "best solution", so:

This SW setup is required as this is the only way how Marvell switch
88E6176 (Agate) can be configured. 88E6176 shares RGMII pins with
bootstrap pins. This is how Marvell designed this switch chip. In
previous board revisions 88E6176 setup was done in board reset procedure
by HW. In new board revision it is not by HW anymore.

Function initialize_switch() could be written differently, e.g. by using
U-Boot DM pinmux and GPIO APIs. But code would be larger (= slow UART
booting) and because this function is called from SPL, it would require
to adjust that DM code to fit into SPL memory and sizing limits... So
easier is to touch A385 GPIO registers directly as it require
relocations, DM usage and other stuff...

For other DT properties. Other option could be to include two DTS files
for Omnia and via some runtime u-boot hooks choose the correct DTS file.
And then there would be option question how to boot kernel correctly.
So DTS patching (which is already used in this board code) seems to be
easier and more robust solution and it allows to boot original
kernel/DTB binaries.

> Reviewed-by: Stefan Roese <sr@denx.de>
> 
> Thanks,
> Stefan
> 
> 
> > ---
> >   board/CZ.NIC/turris_omnia/turris_omnia.c | 226 +++++++++++++++++++++++
> >   1 file changed, 226 insertions(+)
> > 
> > diff --git a/board/CZ.NIC/turris_omnia/turris_omnia.c b/board/CZ.NIC/turris_omnia/turris_omnia.c
> > index 6fc2018c1cfb..e262ea1aba51 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);
> 
> Viele Grüße,
> Stefan Roese
> 
> -- 
> DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: (+49)-8142-66989-51 Fax: (+49)-8142-66989-80 Email: sr@denx.de

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/2] arm: mvebu: turris_omnia: Show MCU type in show_board_info()
  2022-07-29 11:29 [PATCH 1/2] arm: mvebu: turris_omnia: Show MCU type in show_board_info() Pali Rohár
  2022-07-29 11:29 ` [PATCH 2/2] arm: mvebu: turris_omnia: Add support for design with SW reset signals Pali Rohár
  2022-08-01 11:56 ` [PATCH 1/2] arm: mvebu: turris_omnia: Show MCU type in show_board_info() Stefan Roese
@ 2022-08-01 15:49 ` Marek Behún
  2022-08-09 11:32 ` Stefan Roese
  3 siblings, 0 replies; 9+ messages in thread
From: Marek Behún @ 2022-08-01 15:49 UTC (permalink / raw)
  To: Pali Rohár; +Cc: Stefan Roese, u-boot

On Fri, 29 Jul 2022 13:29:06 +0200
Pali Rohár <pali@kernel.org> wrote:

> Different Turris Omnia HW board revisions contains different MCU.
> Show type in show_board_info() to easily identify which MCU is populated.
> 
> Signed-off-by: Pali Rohár <pali@kernel.org>

Reviewed-by: Marek Behún <kabel@kernel.org>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/2] arm: mvebu: turris_omnia: Add support for design with SW reset signals
  2022-07-29 11:29 ` [PATCH 2/2] arm: mvebu: turris_omnia: Add support for design with SW reset signals Pali Rohár
  2022-08-01 11:58   ` Stefan Roese
@ 2022-08-01 15:49   ` Marek Behún
  2022-08-09 11:32   ` Stefan Roese
  2 siblings, 0 replies; 9+ messages in thread
From: Marek Behún @ 2022-08-01 15:49 UTC (permalink / raw)
  To: Pali Rohár; +Cc: Stefan Roese, u-boot

On Fri, 29 Jul 2022 13:29:07 +0200
Pali Rohár <pali@kernel.org> wrote:

> New Turris Omnia HW board revision requires that software controls
> peripheral reset signals, namely PERST# signals on mPCIe slots, ethernet
> phy reset and lan switch reset. Those pins are connected to MCU controlled
> by MCU i2c API as GPIOs. On new HW board revision those pins stay in reset
> after board reset and software has to release these peripherals from reset
> manually. MCU announce this requirement by FEAT_PERIPH_MCU bit in
> CMD_GET_FEATURES command.
> 
> On older HW board revisions when FEAT_PERIPH_MCU is not announced, all
> those reset signals are automatically released after board finish reset.
> 
> Detect FEAT_PERIPH_MCU bit in board_fix_fdt() and ft_board_setup()
> functions and insert into device tree blob pcie "reset-gpios" and eth phy
> "phy-reset-gpios" properties with corresponding MCU gpio definitions.
> PCIe and eth PHY drivers then automatically release resets during device
> initialization. Both U-Boot and Linux kernel drivers support those device
> tree reset properties.
> 
> Initialization of lan switch on new HW board revision is more complicated.
> Switch strapping pins are shared with switch RGMII pins. And strapping pins
> must be in specific configuration after releasing switch reset. Due to pin
> sharing, it is first required to switch A385 side of switch pins into GPIO
> mode, set strapping configuration, release switch from reset and after that
> switch A385 pins back to RGMII mode.
> 
> Because this complicated setup is not supported by switch DSA drivers and
> cannot be expressed easily in device tree, implement it manually in SPL
> function spl_board_init(). So in proper U-Boot and OS/kernel would be lan
> switch initialized and be in same configuration like it was on old HW board
> revisions (where reset sequence did those steps at hardware level).
> 
> Signed-off-by: Pali Rohár <pali@kernel.org>

Reviewed-by: Marek Behún <kabel@kernel.org>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/2] arm: mvebu: turris_omnia: Show MCU type in show_board_info()
  2022-07-29 11:29 [PATCH 1/2] arm: mvebu: turris_omnia: Show MCU type in show_board_info() Pali Rohár
                   ` (2 preceding siblings ...)
  2022-08-01 15:49 ` Marek Behún
@ 2022-08-09 11:32 ` Stefan Roese
  3 siblings, 0 replies; 9+ messages in thread
From: Stefan Roese @ 2022-08-09 11:32 UTC (permalink / raw)
  To: Pali Rohár, Marek Behún; +Cc: u-boot

On 29.07.22 13:29, Pali Rohár wrote:
> Different Turris Omnia HW board revisions contains different MCU.
> Show type in show_board_info() to easily identify which MCU is populated.
> 
> Signed-off-by: Pali Rohár <pali@kernel.org>

Applied to u-boot-marvell/master

Thanks,
Stefan

> ---
>   board/CZ.NIC/turris_omnia/turris_omnia.c | 45 ++++++++++++++++++++++++
>   1 file changed, 45 insertions(+)
> 
> diff --git a/board/CZ.NIC/turris_omnia/turris_omnia.c b/board/CZ.NIC/turris_omnia/turris_omnia.c
> index b169abca0956..6fc2018c1cfb 100644
> --- a/board/CZ.NIC/turris_omnia/turris_omnia.c
> +++ b/board/CZ.NIC/turris_omnia/turris_omnia.c
> @@ -62,13 +62,27 @@ enum mcu_commands {
>   	CMD_GET_STATUS_WORD	= 0x01,
>   	CMD_GET_RESET		= 0x09,
>   	CMD_WATCHDOG_STATE	= 0x0b,
> +
> +	/* available if STS_FEATURES_SUPPORTED bit set in status word */
> +	CMD_GET_FEATURES	= 0x10,
>   };
>   
>   enum status_word_bits {
> +	STS_MCU_TYPE_MASK	= GENMASK(1, 0),
> +	STS_MCU_TYPE_STM32	= 0,
> +	STS_MCU_TYPE_GD32	= 1,
> +	STS_MCU_TYPE_MKL	= 2,
> +	STS_MCU_TYPE_UNKN	= 3,
> +	STS_FEATURES_SUPPORTED	= BIT(2),
>   	CARD_DET_STSBIT		= 0x0010,
>   	MSATA_IND_STSBIT	= 0x0020,
>   };
>   
> +/* CMD_GET_FEATURES */
> +enum features_e {
> +	FEAT_PERIPH_MCU		= BIT(0),
> +};
> +
>   /*
>    * Those values and defines are taken from the Marvell U-Boot version
>    * "u-boot-2013.01-2014_T3.0"
> @@ -371,6 +385,36 @@ static int omnia_get_ram_size_gb(void)
>   	return ram_size;
>   }
>   
> +static const char * const omnia_get_mcu_type(void)
> +{
> +	static const char * const mcu_types[] = {
> +		[STS_MCU_TYPE_STM32] = "STM32",
> +		[STS_MCU_TYPE_GD32]  = "GD32",
> +		[STS_MCU_TYPE_MKL]   = "MKL",
> +		[STS_MCU_TYPE_UNKN]  = "unknown",
> +	};
> +	static const char * const mcu_types_with_perip_resets[] = {
> +		[STS_MCU_TYPE_STM32] = "STM32 (with peripheral resets)",
> +		[STS_MCU_TYPE_GD32]  = "GD32 (with peripheral resets)",
> +		[STS_MCU_TYPE_MKL]   = "MKL (with peripheral resets)",
> +		[STS_MCU_TYPE_UNKN]  = "unknown (with peripheral resets)",
> +	};
> +	u16 stsword, features;
> +	int ret;
> +
> +	ret = omnia_mcu_read(CMD_GET_STATUS_WORD, &stsword, sizeof(stsword));
> +	if (ret)
> +		return "unknown";
> +
> +	if (stsword & STS_FEATURES_SUPPORTED) {
> +		ret = omnia_mcu_read(CMD_GET_FEATURES, &features, sizeof(features));
> +		if (ret == 0 && (features & FEAT_PERIPH_MCU))
> +			return mcu_types_with_perip_resets[stsword & STS_MCU_TYPE_MASK];
> +	}
> +
> +	return mcu_types[stsword & STS_MCU_TYPE_MASK];
> +}
> +
>   /*
>    * Define the DDR layout / topology here in the board file. This will
>    * be used by the DDR3 init code in the SPL U-Boot version to configure
> @@ -688,6 +732,7 @@ int show_board_info(void)
>   
>   	err = turris_atsha_otp_get_serial_number(&version_num, &serial_num);
>   	printf("Model: Turris Omnia\n");
> +	printf("  MCU type: %s\n", omnia_get_mcu_type());
>   	printf("  RAM size: %i MiB\n", omnia_get_ram_size_gb() * 1024);
>   	if (err)
>   		printf("  Serial Number: unknown\n");

Viele Grüße,
Stefan Roese

-- 
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-51 Fax: (+49)-8142-66989-80 Email: sr@denx.de

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/2] arm: mvebu: turris_omnia: Add support for design with SW reset signals
  2022-07-29 11:29 ` [PATCH 2/2] arm: mvebu: turris_omnia: Add support for design with SW reset signals Pali Rohár
  2022-08-01 11:58   ` Stefan Roese
  2022-08-01 15:49   ` Marek Behún
@ 2022-08-09 11:32   ` Stefan Roese
  2 siblings, 0 replies; 9+ messages in thread
From: Stefan Roese @ 2022-08-09 11:32 UTC (permalink / raw)
  To: Pali Rohár, Marek Behún; +Cc: u-boot

On 29.07.22 13:29, Pali Rohár wrote:
> New Turris Omnia HW board revision requires that software controls
> peripheral reset signals, namely PERST# signals on mPCIe slots, ethernet
> phy reset and lan switch reset. Those pins are connected to MCU controlled
> by MCU i2c API as GPIOs. On new HW board revision those pins stay in reset
> after board reset and software has to release these peripherals from reset
> manually. MCU announce this requirement by FEAT_PERIPH_MCU bit in
> CMD_GET_FEATURES command.
> 
> On older HW board revisions when FEAT_PERIPH_MCU is not announced, all
> those reset signals are automatically released after board finish reset.
> 
> Detect FEAT_PERIPH_MCU bit in board_fix_fdt() and ft_board_setup()
> functions and insert into device tree blob pcie "reset-gpios" and eth phy
> "phy-reset-gpios" properties with corresponding MCU gpio definitions.
> PCIe and eth PHY drivers then automatically release resets during device
> initialization. Both U-Boot and Linux kernel drivers support those device
> tree reset properties.
> 
> Initialization of lan switch on new HW board revision is more complicated.
> Switch strapping pins are shared with switch RGMII pins. And strapping pins
> must be in specific configuration after releasing switch reset. Due to pin
> sharing, it is first required to switch A385 side of switch pins into GPIO
> mode, set strapping configuration, release switch from reset and after that
> switch A385 pins back to RGMII mode.
> 
> Because this complicated setup is not supported by switch DSA drivers and
> cannot be expressed easily in device tree, implement it manually in SPL
> function spl_board_init(). So in proper U-Boot and OS/kernel would be lan
> switch initialized and be in same configuration like it was on old HW board
> revisions (where reset sequence did those steps at hardware level).
> 
> Signed-off-by: Pali Rohár <pali@kernel.org>

Applied to u-boot-marvell/master

Thanks,
Stefan

> ---
>   board/CZ.NIC/turris_omnia/turris_omnia.c | 226 +++++++++++++++++++++++
>   1 file changed, 226 insertions(+)
> 
> diff --git a/board/CZ.NIC/turris_omnia/turris_omnia.c b/board/CZ.NIC/turris_omnia/turris_omnia.c
> index 6fc2018c1cfb..e262ea1aba51 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);

Viele Grüße,
Stefan Roese

-- 
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-51 Fax: (+49)-8142-66989-80 Email: sr@denx.de

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2022-08-09 11:32 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-29 11:29 [PATCH 1/2] arm: mvebu: turris_omnia: Show MCU type in show_board_info() Pali Rohár
2022-07-29 11:29 ` [PATCH 2/2] arm: mvebu: turris_omnia: Add support for design with SW reset signals Pali Rohár
2022-08-01 11:58   ` Stefan Roese
2022-08-01 12:19     ` Pali Rohár
2022-08-01 15:49   ` Marek Behún
2022-08-09 11:32   ` Stefan Roese
2022-08-01 11:56 ` [PATCH 1/2] arm: mvebu: turris_omnia: Show MCU type in show_board_info() Stefan Roese
2022-08-01 15:49 ` Marek Behún
2022-08-09 11:32 ` Stefan Roese

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.