[PATCH] ARM: rpi: parse useful data from vc fdt

Daniel Brát danek.brat at gmail.com
Sat Jun 11 11:39:39 PDT 2022


Videocore first-stage loader on rpi passes us many useful information
inside the vc fdt, including the real value of PM_RSTS register, not
easily available by other means and which we can use to determine
the reset cause.
Also make the relevant funtions ignore most of the errors since the fdt
from vc is now optional for barebox's basic function.

Signed-off-by: Daniel Brát <danek.brat at gmail.com>
---
 arch/arm/boards/raspberry-pi/rpi-common.c | 155 ++++++++++++++++------
 drivers/watchdog/bcm2835_wdt.c            |  23 +---
 drivers/watchdog/bcm2835_wdt.h            |  40 ++++++
 3 files changed, 153 insertions(+), 65 deletions(-)
 create mode 100644 drivers/watchdog/bcm2835_wdt.h

diff --git a/arch/arm/boards/raspberry-pi/rpi-common.c b/arch/arm/boards/raspberry-pi/rpi-common.c
index 12a4f4a0a..884dc7239 100644
--- a/arch/arm/boards/raspberry-pi/rpi-common.c
+++ b/arch/arm/boards/raspberry-pi/rpi-common.c
@@ -23,12 +23,14 @@
 #include <linux/sizes.h>
 #include <globalvar.h>
 #include <asm/system_info.h>
+#include <reset_source.h>
 
 #include <mach/core.h>
 #include <mach/mbox.h>
 #include <mach/platform.h>
 
 #include "lowlevel.h"
+#include "../../../../drivers/watchdog/bcm2835_wdt.h"
 
 struct rpi_priv;
 struct rpi_machine_data {
@@ -186,54 +188,114 @@ static int rpi_env_init(void)
 	return 0;
 }
 
-/* Extract /chosen/bootargs from the VideoCore FDT into vc.bootargs
- * global variable. */
-static int rpi_vc_fdt_bootargs(void *fdt)
+/* Extract useful information from the VideoCore FDT we got.
+ * Some parameters are defined here:
+ * https://www.raspberrypi.com/documentation/computers/configuration.html#part4
+ */
+static void rpi_vc_fdt_parse(void *fdt)
 {
-	int ret = 0;
-	struct device_node *root = NULL, *node;
-	const char *cmdline;
+	int ret, len;
+	struct device_node *root, *chosen, *bootloader;
+	enum reset_src_type rst_src = RESET_UKWN;
+	const char *str;
+	char *model;
+	u32 num, *pnum;
 
 	root = of_unflatten_dtb(fdt, INT_MAX);
-	if (IS_ERR(root)) {
-		ret = PTR_ERR(root);
-		root = NULL;
-		goto out;
-	}
+	if (IS_ERR(root))
+		return;
 
-	node = of_find_node_by_path_from(root, "/chosen");
-	if (!node) {
-		pr_err("no /chosen node\n");
-		ret = -ENOENT;
-		goto out;
+	str = of_get_property(root, "serial-number", &len);
+	if (!str)
+		pr_warn("no 'serial-number' property found in vc fdt\n");
+	else
+		globalvar_add_simple("vc.bootargs", xstrndup(str, len));
+
+	str = of_get_property(root, "model", &len);
+	if (!str) {
+		pr_warn("no 'model' property found in vc fdt\n");
+	} else {
+		model = xstrndup(str, len);
+		barebox_set_model(model);
+		free(model);
 	}
 
-	cmdline = of_get_property(node, "bootargs", NULL);
-	if (!cmdline) {
-		pr_err("no bootargs property in the /chosen node\n");
-		ret = -ENOENT;
+	chosen = of_find_node_by_path_from(root, "/chosen");
+	if (!chosen) {
+		pr_err("no '/chosen' node found in vc fdt\n");
 		goto out;
 	}
 
-	globalvar_add_simple("vc.bootargs", cmdline);
-
-	switch(cpu_architecture()) {
-	case CPU_ARCH_ARMv6:
-		globalvar_add_simple("vc.kernel", "kernel.img");
-		break;
-	case CPU_ARCH_ARMv7:
-		globalvar_add_simple("vc.kernel", "kernel7.img");
-		break;
-	case CPU_ARCH_ARMv8:
-		globalvar_add_simple("vc.kernel", "kernel8.img");
-		break;
+	bootloader = of_find_node_by_name(chosen, "bootloader");
+
+	str = of_get_property(chosen, "bootargs", &len);
+	if (!str)
+		pr_warn("no 'bootargs' property in the /chosen node\n");
+	else
+		globalvar_add_simple("vc.bootargs", xstrndup(str, len));
+
+	str = of_get_property(chosen, "overlay_prefix", &len);
+	if (!str)
+		pr_warn("no 'overlay_prefix' property in the /chosen node\n");
+	else
+		globalvar_add_simple("vc.overlay_prefix", xstrndup(str, len));
+
+	str = of_get_property(chosen, "os_prefix", &len);
+	if (!str)
+		pr_warn("no 'os_prefix' property in the /chosen node\n");
+	else
+		globalvar_add_simple("vc.os_prefix", xstrndup(str, len));
+
+	ret = of_property_read_u32(chosen, "boot-mode", &num);
+	if (ret && bootloader)
+		ret = of_property_read_u32(bootloader, "boot-mode", &num);
+        if (ret) {
+        	pr_warn("'boot-mode' property not found\n");
+	} else {
+		pnum = xmalloc(sizeof(u32));
+		*pnum = num;
+		globalvar_add_simple_int("vc.boot_mode", pnum, "%u");
 	}
 
+	ret = of_property_read_u32(chosen, "partition", &num);
+	if (ret && bootloader)
+		ret = of_property_read_u32(bootloader, "partition", &num);
+	if (ret) {
+		pr_warn("'partition' property not found\n");
+        } else {
+        	pnum = xmalloc(sizeof(u32));
+        	*pnum = num;
+        	globalvar_add_simple_int("vc.boot_partition", pnum, "%u");
+        }
+
+	if (IS_ENABLED(CONFIG_RESET_SOURCE)) {
+		ret = of_property_read_u32(chosen, "pm_rsts", &num);
+		if (ret && bootloader)
+			 ret = of_property_read_u32(bootloader, "rsts", &num);
+
+		if (ret) {
+			pr_warn("'pm_rsts'/'rsts' property not found\n");
+		} else {
+/*
+ * https://github.com/raspberrypi/linux/issues/932#issuecomment-93989581
+ */
+			if (num & PM_RSTS_HADPOR_SET)
+				rst_src = RESET_POR;
+			else if (num & PM_RSTS_HADDR_SET)
+				rst_src = RESET_JTAG;
+			else if (num & PM_RSTS_HADWR_SET)
+				rst_src = RESET_WDG;
+			else if (num & PM_RSTS_HADSR_SET)
+				rst_src = RESET_RST;
+			reset_source_set_prinst(rst_src,
+						RESET_SOURCE_DEFAULT_PRIORITY,
+						reset_source_get_instance());
+		}
+	}
 out:
 	if (root)
 		of_delete_node(root);
-
-	return ret;
+	return;
 }
 
 static void rpi_vc_fdt(void)
@@ -241,7 +303,6 @@ static void rpi_vc_fdt(void)
 	void *saved_vc_fdt;
 	struct fdt_header *oftree;
 	unsigned long magic, size;
-	int ret;
 
 	/* VideoCore FDT was copied in PBL just above Barebox memory */
 	saved_vc_fdt = (void *)(arm_mem_endmem_get());
@@ -260,16 +321,23 @@ static void rpi_vc_fdt(void)
 		return;
 
 	size = be32_to_cpu(oftree->totalsize);
-	if (write_file("/vc.dtb", saved_vc_fdt, size)) {
+	if (write_file("/vc.dtb", saved_vc_fdt, size))
 		pr_err("failed to save videocore fdt to a file\n");
-		return;
-	}
 
-	ret = rpi_vc_fdt_bootargs(saved_vc_fdt);
-	if (ret) {
-		pr_err("failed to extract bootargs from videocore fdt: %d\n",
-									ret);
-		return;
+	rpi_vc_fdt_parse(saved_vc_fdt);
+}
+
+static void rpi_set_kernel_name(void) {
+	switch(cpu_architecture()) {
+	case CPU_ARCH_ARMv6:
+		globalvar_add_simple("vc.kernel", "kernel.img");
+		break;
+	case CPU_ARCH_ARMv7:
+		globalvar_add_simple("vc.kernel", "kernel7.img");
+		break;
+	case CPU_ARCH_ARMv8:
+		globalvar_add_simple("vc.kernel", "kernel8.img");
+		break;
 	}
 }
 
@@ -348,6 +416,7 @@ static int rpi_devices_probe(struct device_d *dev)
 	armlinux_set_architecture(MACH_TYPE_BCM2708);
 	rpi_env_init();
 	rpi_vc_fdt();
+	rpi_set_kernel_name();
 
 	if (dcfg && dcfg->init)
 		dcfg->init(priv);
diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c
index ece80837b..a7ae25185 100644
--- a/drivers/watchdog/bcm2835_wdt.c
+++ b/drivers/watchdog/bcm2835_wdt.c
@@ -10,28 +10,7 @@
 #include <restart.h>
 #include <watchdog.h>
 
-#define PM_RSTC		0x1c
-#define PM_RSTS		0x20
-#define PM_WDOG		0x24
-
-#define PM_WDOG_RESET				0000000000
-#define PM_PASSWORD				0x5a000000
-#define PM_WDOG_TIME_SET			0x000fffff
-#define PM_RSTC_WRCFG_CLR			0xffffffcf
-#define PM_RSTC_WRCFG_SET			0x00000030
-#define PM_RSTC_WRCFG_FULL_RESET		0x00000020
-#define PM_RSTC_RESET				0x00000102
-
-#define PM_RSTS_HADPOR_SET			0x00001000
-#define PM_RSTS_HADSRH_SET			0x00000400
-#define PM_RSTS_HADSRF_SET			0x00000200
-#define PM_RSTS_HADSRQ_SET			0x00000100
-#define PM_RSTS_HADWRH_SET			0x00000040
-#define PM_RSTS_HADWRF_SET			0x00000020
-#define PM_RSTS_HADWRQ_SET			0x00000010
-#define PM_RSTS_HADDRH_SET			0x00000004
-#define PM_RSTS_HADDRF_SET			0x00000002
-#define PM_RSTS_HADDRQ_SET			0x00000001
+#include "bcm2835_wdt.h"
 
 #define SECS_TO_WDOG_TICKS(x) ((x) << 16)
 
diff --git a/drivers/watchdog/bcm2835_wdt.h b/drivers/watchdog/bcm2835_wdt.h
new file mode 100644
index 000000000..ce97b1eb5
--- /dev/null
+++ b/drivers/watchdog/bcm2835_wdt.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 Pengutronix, Lucas Stach <l.stach at pengutronix.de>
+ *
+ * Based on code from  Carlo Caione <carlo at carlocaione.org>
+ */
+
+#ifndef __BCM2835_WDT_H
+#define __BCM2835_WDT_H
+
+#define PM_RSTC				0x1c
+#define PM_RSTS				0x20
+#define PM_WDOG				0x24
+
+#define PM_WDOG_RESET			0000000000
+#define PM_PASSWORD			0x5a000000
+#define PM_WDOG_TIME_SET		0x000fffff
+#define PM_RSTC_WRCFG_CLR		0xffffffcf
+#define PM_RSTC_WRCFG_SET		0x00000030
+#define PM_RSTC_WRCFG_FULL_RESET	0x00000020
+#define PM_RSTC_RESET			0x00000102
+
+#define PM_RSTS_HADPOR_SET		0x00001000
+#define PM_RSTS_HADSRH_SET		0x00000400
+#define PM_RSTS_HADSRF_SET		0x00000200
+#define PM_RSTS_HADSRQ_SET		0x00000100
+#define PM_RSTS_HADWRH_SET		0x00000040
+#define PM_RSTS_HADWRF_SET		0x00000020
+#define PM_RSTS_HADWRQ_SET		0x00000010
+#define PM_RSTS_HADDRH_SET		0x00000004
+#define PM_RSTS_HADDRF_SET		0x00000002
+#define PM_RSTS_HADDRQ_SET		0x00000001
+
+#define PM_RSTS_HADDR_SET \
+	(PM_RSTS_HADDRQ_SET | PM_RSTS_HADDRF_SET | PM_RSTS_HADDRH_SET)
+#define PM_RSTS_HADWR_SET \
+	(PM_RSTS_HADWRQ_SET | PM_RSTS_HADWRF_SET | PM_RSTS_HADWRH_SET)
+#define PM_RSTS_HADSR_SET \
+	(PM_RSTS_HADSRQ_SET | PM_RSTS_HADSRF_SET | PM_RSTS_HADSRH_SET)
+
+#endif
-- 
2.17.1




More information about the barebox mailing list