diff mbox series

[u-boot-marvell,3/4] arm: mvebu: turris_mox: Setup Linux's device tree before boot

Message ID 20200330171926.26119-3-marek.behun@nic.cz
State New
Headers show
Series [u-boot-marvell,1/4] arm: mvebu: turris_mox: Fix early SPI communication | expand

Commit Message

Marek BehĂșn March 30, 2020, 5:19 p.m. UTC
Patch Linux's device tree according to which Mox modules are connected.
Linux's device tree is supposed to have some nodes already
preprogrammed. If user wants to use different device tree, they should
disable CONFIG_OF_BOARD_SETUP in U-Boot's config, so that the boot
command does not fail.

Signed-off-by: Marek Beh?n <marek.behun at nic.cz>
---
 board/CZ.NIC/turris_mox/turris_mox.c | 247 +++++++++++++++++++++++++++
 configs/turris_mox_defconfig         |   1 +
 2 files changed, 248 insertions(+)

Comments

Stefan Roese March 31, 2020, 10:38 a.m. UTC | #1
Hi Marek,

On 30.03.20 19:19, Marek Beh?n wrote:
> Patch Linux's device tree according to which Mox modules are connected.
> Linux's device tree is supposed to have some nodes already
> preprogrammed. If user wants to use different device tree, they should
> disable CONFIG_OF_BOARD_SETUP in U-Boot's config, so that the boot
> command does not fail.

There is a lot that you dynamically change in the DT here. Could you
please summarize a bit more of the details in the commit text and the
code of what exactly is being done / changed in the DT?

Thanks,
Stefan

> Signed-off-by: Marek Beh?n <marek.behun at nic.cz>
> ---
>   board/CZ.NIC/turris_mox/turris_mox.c | 247 +++++++++++++++++++++++++++
>   configs/turris_mox_defconfig         |   1 +
>   2 files changed, 248 insertions(+)
> 
> diff --git a/board/CZ.NIC/turris_mox/turris_mox.c b/board/CZ.NIC/turris_mox/turris_mox.c
> index 7118096f32..5137ed9d00 100644
> --- a/board/CZ.NIC/turris_mox/turris_mox.c
> +++ b/board/CZ.NIC/turris_mox/turris_mox.c
> @@ -3,6 +3,7 @@
>    * Copyright (C) 2018 Marek Behun <marek.behun at nic.cz>
>    */
>   
> +#include <stdarg.h>
>   #include <common.h>
>   #include <init.h>
>   #include <asm/gpio.h>
> @@ -34,7 +35,11 @@
>   #define ARMADA_37XX_SPI_DOUT	0xd0010608
>   #define ARMADA_37XX_SPI_DIN	0xd001060c
>   
> +#define ETH1_PATH	"/soc/internal-regs at d0000000/ethernet at 40000"
> +#define MDIO_PATH	"/soc/internal-regs at d0000000/mdio at 32004"
> +#define SFP_GPIO_PATH	"/soc/internal-regs at d0000000/spi at 10600/moxtet at 1/gpio at 0"
>   #define PCIE_PATH	"/soc/pcie at d0070000"
> +#define SFP_PATH	"/sfp"
>   
>   DECLARE_GLOBAL_DATA_PTR;
>   
> @@ -548,3 +553,245 @@ int last_stage_init(void)
>   
>   	return 0;
>   }
> +
> +#if defined(CONFIG_OF_BOARD_SETUP)
> +
> +static int vnode_by_path(void *blob, const char *fmt, va_list ap)
> +{
> +	char path[128];
> +
> +	vsprintf(path, fmt, ap);
> +	return fdt_path_offset(blob, path);
> +}
> +
> +static int node_by_path(void *blob, const char *fmt, ...)
> +{
> +	va_list ap;
> +	int res;
> +
> +	va_start(ap, fmt);
> +	res = vnode_by_path(blob, fmt, ap);
> +	va_end(ap);
> +
> +	return res;
> +}
> +
> +static int phandle_by_path(void *blob, const char *fmt, ...)
> +{
> +	va_list ap;
> +	int node, phandle, res;
> +
> +	va_start(ap, fmt);
> +	node = vnode_by_path(blob, fmt, ap);
> +	va_end(ap);
> +
> +	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);
> +	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);
> +	if (res < 0)
> +		return res;
> +
> +	/*
> +	 * now if there are more switches or a SFP module coming after,
> +	 * enable corresponding ports
> +	 */
> +	if (id < peridot + topaz - 1)
> +		res = enable_by_path(blob,
> +				     MDIO_PATH "/switch%i@%x/ports/port at a",
> +				     id, addr);
> +	else if (id == peridot - 1 && !topaz && sfp)
> +		res = enable_by_path(blob,
> +				     MDIO_PATH "/switch%i@%x/ports/port-sfp at a",
> +				     id, addr);
> +	else
> +		res = 0;
> +	if (res < 0)
> +		return res;
> +
> +	if (id >= peridot + topaz - 1)
> +		return 0;
> +
> +	/* finally change link property if needed */
> +	node = node_by_path(blob, MDIO_PATH "/switch%i@%x/ports/port at a", 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;
> +
> +		if (i == id + 1)
> +			res = fdt_setprop_u32(blob, node, "link", phandle);
> +		else
> +			res = fdt_appendprop_u32(blob, node, "link", phandle);
> +		if (res < 0)
> +			return res;
> +	}
> +
> +	return 0;
> +}
> +
> +static int remove_disabled_nodes(void *blob)
> +{
> +	while (1) {
> +		int res, offset;
> +
> +		offset = fdt_node_offset_by_prop_value(blob, -1, "status",
> +						       "disabled", 9);
> +		if (offset < 0)
> +			break;
> +
> +		res = fdt_del_node(blob, offset);
> +		if (res < 0)
> +			return res;
> +	}
> +
> +	return 0;
> +}
> +
> +int ft_board_setup(void *blob, bd_t *bd)
> +{
> +	int node, phandle, res;
> +
> +	if (pci || usb || passpci) {
> +		node = fdt_path_offset(blob, PCIE_PATH);
> +		if (node < 0)
> +			return node;
> +
> +		res = fdt_setprop_string(blob, node, "status", "okay");
> +		if (res < 0)
> +			return res;
> +	}
> +
> +	if (peridot || topaz) {
> +		int i;
> +
> +		res = enable_by_path(blob, ETH1_PATH);
> +		if (res < 0)
> +			return res;
> +
> +		for (i = 0; i < peridot + topaz; ++i) {
> +			res = setup_switch(blob, i);
> +			if (res < 0)
> +				return res;
> +		}
> +	}
> +
> +	if (sfp) {
> +		res = enable_by_path(blob, SFP_PATH);
> +		if (res < 0)
> +			return res;
> +
> +		res = enable_by_path(blob, ETH1_PATH);
> +		if (res < 0)
> +			return res;
> +
> +		if (!peridot) {
> +			phandle = phandle_by_path(blob, SFP_PATH);
> +			if (phandle < 0)
> +				return res;
> +
> +			node = node_by_path(blob, ETH1_PATH);
> +			if (node < 0)
> +				return node;
> +
> +			res = fdt_setprop_u32(blob, node, "sfp", phandle);
> +			if (res < 0)
> +				return res;
> +
> +			res = fdt_setprop_string(blob, node, "phy-mode",
> +						 "sgmii");
> +			if (res < 0)
> +				return res;
> +		}
> +
> +		res = enable_by_path(blob, SFP_GPIO_PATH);
> +		if (res < 0)
> +			return res;
> +
> +		if (sfp_pos) {
> +			char newname[16];
> +
> +			/* moxtet-sfp is on non-zero position, change default */
> +			node = node_by_path(blob, SFP_GPIO_PATH);
> +			if (node < 0)
> +				return node;
> +
> +			res = fdt_setprop_u32(blob, node, "reg", sfp_pos);
> +			if (res < 0)
> +				return res;
> +
> +			sprintf(newname, "gpio@%x", sfp_pos);
> +
> +			res = fdt_set_name(blob, node, newname);
> +			if (res < 0)
> +				return res;
> +		}
> +	}
> +
> +	fdt_fixup_ethernet(blob);
> +	remove_disabled_nodes(blob);
> +
> +	return 0;
> +}
> +
> +#endif
> diff --git a/configs/turris_mox_defconfig b/configs/turris_mox_defconfig
> index 2e637044c1..3bc69cda4d 100644
> --- a/configs/turris_mox_defconfig
> +++ b/configs/turris_mox_defconfig
> @@ -37,6 +37,7 @@ CONFIG_CMD_BTRFS=y
>   CONFIG_CMD_EXT4_WRITE=y
>   CONFIG_MAC_PARTITION=y
>   CONFIG_OF_BOARD_FIXUP=y
> +CONFIG_OF_BOARD_SETUP=y
>   CONFIG_DEFAULT_DEVICE_TREE="armada-3720-turris-mox"
>   CONFIG_ENV_IS_IN_SPI_FLASH=y
>   CONFIG_SYS_RELOC_GD_ENV_ADDR=y
> 


Viele Gr??e,
Stefan
diff mbox series

Patch

diff --git a/board/CZ.NIC/turris_mox/turris_mox.c b/board/CZ.NIC/turris_mox/turris_mox.c
index 7118096f32..5137ed9d00 100644
--- a/board/CZ.NIC/turris_mox/turris_mox.c
+++ b/board/CZ.NIC/turris_mox/turris_mox.c
@@ -3,6 +3,7 @@ 
  * Copyright (C) 2018 Marek Behun <marek.behun at nic.cz>
  */
 
+#include <stdarg.h>
 #include <common.h>
 #include <init.h>
 #include <asm/gpio.h>
@@ -34,7 +35,11 @@ 
 #define ARMADA_37XX_SPI_DOUT	0xd0010608
 #define ARMADA_37XX_SPI_DIN	0xd001060c
 
+#define ETH1_PATH	"/soc/internal-regs at d0000000/ethernet at 40000"
+#define MDIO_PATH	"/soc/internal-regs at d0000000/mdio at 32004"
+#define SFP_GPIO_PATH	"/soc/internal-regs at d0000000/spi at 10600/moxtet at 1/gpio at 0"
 #define PCIE_PATH	"/soc/pcie at d0070000"
+#define SFP_PATH	"/sfp"
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -548,3 +553,245 @@  int last_stage_init(void)
 
 	return 0;
 }
+
+#if defined(CONFIG_OF_BOARD_SETUP)
+
+static int vnode_by_path(void *blob, const char *fmt, va_list ap)
+{
+	char path[128];
+
+	vsprintf(path, fmt, ap);
+	return fdt_path_offset(blob, path);
+}
+
+static int node_by_path(void *blob, const char *fmt, ...)
+{
+	va_list ap;
+	int res;
+
+	va_start(ap, fmt);
+	res = vnode_by_path(blob, fmt, ap);
+	va_end(ap);
+
+	return res;
+}
+
+static int phandle_by_path(void *blob, const char *fmt, ...)
+{
+	va_list ap;
+	int node, phandle, res;
+
+	va_start(ap, fmt);
+	node = vnode_by_path(blob, fmt, ap);
+	va_end(ap);
+
+	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);
+	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);
+	if (res < 0)
+		return res;
+
+	/*
+	 * now if there are more switches or a SFP module coming after,
+	 * enable corresponding ports
+	 */
+	if (id < peridot + topaz - 1)
+		res = enable_by_path(blob,
+				     MDIO_PATH "/switch%i@%x/ports/port at a",
+				     id, addr);
+	else if (id == peridot - 1 && !topaz && sfp)
+		res = enable_by_path(blob,
+				     MDIO_PATH "/switch%i@%x/ports/port-sfp at a",
+				     id, addr);
+	else
+		res = 0;
+	if (res < 0)
+		return res;
+
+	if (id >= peridot + topaz - 1)
+		return 0;
+
+	/* finally change link property if needed */
+	node = node_by_path(blob, MDIO_PATH "/switch%i@%x/ports/port at a", 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;
+
+		if (i == id + 1)
+			res = fdt_setprop_u32(blob, node, "link", phandle);
+		else
+			res = fdt_appendprop_u32(blob, node, "link", phandle);
+		if (res < 0)
+			return res;
+	}
+
+	return 0;
+}
+
+static int remove_disabled_nodes(void *blob)
+{
+	while (1) {
+		int res, offset;
+
+		offset = fdt_node_offset_by_prop_value(blob, -1, "status",
+						       "disabled", 9);
+		if (offset < 0)
+			break;
+
+		res = fdt_del_node(blob, offset);
+		if (res < 0)
+			return res;
+	}
+
+	return 0;
+}
+
+int ft_board_setup(void *blob, bd_t *bd)
+{
+	int node, phandle, res;
+
+	if (pci || usb || passpci) {
+		node = fdt_path_offset(blob, PCIE_PATH);
+		if (node < 0)
+			return node;
+
+		res = fdt_setprop_string(blob, node, "status", "okay");
+		if (res < 0)
+			return res;
+	}
+
+	if (peridot || topaz) {
+		int i;
+
+		res = enable_by_path(blob, ETH1_PATH);
+		if (res < 0)
+			return res;
+
+		for (i = 0; i < peridot + topaz; ++i) {
+			res = setup_switch(blob, i);
+			if (res < 0)
+				return res;
+		}
+	}
+
+	if (sfp) {
+		res = enable_by_path(blob, SFP_PATH);
+		if (res < 0)
+			return res;
+
+		res = enable_by_path(blob, ETH1_PATH);
+		if (res < 0)
+			return res;
+
+		if (!peridot) {
+			phandle = phandle_by_path(blob, SFP_PATH);
+			if (phandle < 0)
+				return res;
+
+			node = node_by_path(blob, ETH1_PATH);
+			if (node < 0)
+				return node;
+
+			res = fdt_setprop_u32(blob, node, "sfp", phandle);
+			if (res < 0)
+				return res;
+
+			res = fdt_setprop_string(blob, node, "phy-mode",
+						 "sgmii");
+			if (res < 0)
+				return res;
+		}
+
+		res = enable_by_path(blob, SFP_GPIO_PATH);
+		if (res < 0)
+			return res;
+
+		if (sfp_pos) {
+			char newname[16];
+
+			/* moxtet-sfp is on non-zero position, change default */
+			node = node_by_path(blob, SFP_GPIO_PATH);
+			if (node < 0)
+				return node;
+
+			res = fdt_setprop_u32(blob, node, "reg", sfp_pos);
+			if (res < 0)
+				return res;
+
+			sprintf(newname, "gpio@%x", sfp_pos);
+
+			res = fdt_set_name(blob, node, newname);
+			if (res < 0)
+				return res;
+		}
+	}
+
+	fdt_fixup_ethernet(blob);
+	remove_disabled_nodes(blob);
+
+	return 0;
+}
+
+#endif
diff --git a/configs/turris_mox_defconfig b/configs/turris_mox_defconfig
index 2e637044c1..3bc69cda4d 100644
--- a/configs/turris_mox_defconfig
+++ b/configs/turris_mox_defconfig
@@ -37,6 +37,7 @@  CONFIG_CMD_BTRFS=y
 CONFIG_CMD_EXT4_WRITE=y
 CONFIG_MAC_PARTITION=y
 CONFIG_OF_BOARD_FIXUP=y
+CONFIG_OF_BOARD_SETUP=y
 CONFIG_DEFAULT_DEVICE_TREE="armada-3720-turris-mox"
 CONFIG_ENV_IS_IN_SPI_FLASH=y
 CONFIG_SYS_RELOC_GD_ENV_ADDR=y