summaryrefslogtreecommitdiffstats
path: root/arch/arm/boards/raspberry-pi
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/boards/raspberry-pi')
-rw-r--r--arch/arm/boards/raspberry-pi/Makefile1
-rw-r--r--arch/arm/boards/raspberry-pi/lowlevel.c157
-rw-r--r--arch/arm/boards/raspberry-pi/lowlevel.h5
-rw-r--r--arch/arm/boards/raspberry-pi/mbox-helpers.c73
-rw-r--r--arch/arm/boards/raspberry-pi/rpi-common.c486
5 files changed, 555 insertions, 167 deletions
diff --git a/arch/arm/boards/raspberry-pi/Makefile b/arch/arm/boards/raspberry-pi/Makefile
index 6f995b5640..e4f91b4979 100644
--- a/arch/arm/boards/raspberry-pi/Makefile
+++ b/arch/arm/boards/raspberry-pi/Makefile
@@ -2,4 +2,5 @@
obj-$(CONFIG_MACH_RPI_COMMON) += rpi-common.o
lwl-y += lowlevel.o
+obj-pbl-y += mbox-helpers.o
bbenv-y += defaultenv-rpi
diff --git a/arch/arm/boards/raspberry-pi/lowlevel.c b/arch/arm/boards/raspberry-pi/lowlevel.c
index 7b9809b86c..b3727d930f 100644
--- a/arch/arm/boards/raspberry-pi/lowlevel.c
+++ b/arch/arm/boards/raspberry-pi/lowlevel.c
@@ -4,7 +4,11 @@
#include <asm/cache.h>
#include <common.h>
#include <linux/sizes.h>
-#include <mach/platform.h>
+#include <asm/unaligned.h>
+#include <mach/bcm283x/platform.h>
+#include <debug_ll.h>
+#include <mach/bcm283x/debug_ll.h>
+#include <mach/bcm283x/mbox.h>
#include <of.h>
#include "lowlevel.h"
@@ -33,50 +37,151 @@ static void copy_vc_fdt(void *dest, void *src, unsigned long max_size)
memmove(dest, src, size);
}
-/* A pointer to the FDT created by VideoCore was passed to us in r2. We
- * reserve some memory just above the region used for Barebox and copy
- * this FDT there. We fetch it from there later in rpi_devices_init().
- */
-#define rpi_stack_top(memsize) \
- arm_mem_stack_top(BCM2835_SDRAM_BASE, BCM2835_SDRAM_BASE + memsize - VIDEOCORE_FDT_SZ)
-
static inline void start_raspberry_pi(unsigned long memsize, void *fdt,
void *vc_fdt)
{
- unsigned long endmem = rpi_stack_top(memsize);
+ unsigned long endmem;
- arm_cpu_lowlevel_init();
+ /*
+ * A pointer to the FDT created by VideoCore was passed to us in x0/r2. We
+ * reserve some memory at the end of SDRAM copy this FDT there. We fetch it
+ * from there later in rpi_devices_init().
+ */
+ memsize -= VIDEOCORE_FDT_SZ;
+ endmem = BCM2835_SDRAM_BASE + memsize;
- copy_vc_fdt((void *)endmem, vc_fdt, VIDEOCORE_FDT_SZ);
+ /* leave SZ_1K for the initial stack */
+ copy_vc_fdt((void *)endmem, vc_fdt, VIDEOCORE_FDT_SZ - SZ_1K);
fdt += get_runtime_offset();
- barebox_arm_entry(BCM2835_SDRAM_BASE, endmem - BCM2835_SDRAM_BASE, fdt);
+ barebox_arm_entry(BCM2835_SDRAM_BASE, memsize, fdt);
+}
+
+#ifdef CONFIG_CPU_V8
+#define RPI_ENTRY_FUNCTION(name, memsize, fdt) \
+ ENTRY_FUNCTION_WITHSTACK(name, BCM2835_SDRAM_BASE + (memsize), fdt, __x1, __x2)
+#else
+#define RPI_ENTRY_FUNCTION(name, memsize, fdt) \
+ ENTRY_FUNCTION_WITHSTACK(name, BCM2835_SDRAM_BASE + (memsize), __r0, __r1, fdt)
+#endif
+
+extern char __dtb_z_bcm2835_rpi_start[];
+extern char __dtb_z_bcm2836_rpi_2_start[];
+extern char __dtb_z_bcm2837_rpi_3_start[];
+extern char __dtb_z_bcm2837_rpi_cm3_start[];
+extern char __dtb_z_bcm2711_rpi_4_start[];
+extern char __dtb_z_bcm2711_rpi_400_start[];
+extern char __dtb_z_bcm2711_rpi_cm4_io_start[];
+extern char __dtb_z_bcm2711_rpi_cm4s_io_start[];
+
+RPI_ENTRY_FUNCTION(start_raspberry_pi1, SZ_128M, fdt)
+{
+ arm_cpu_lowlevel_init();
+
+ start_raspberry_pi(SZ_128M, __dtb_z_bcm2835_rpi_start, (void *)fdt);
}
-#define RPI_ENTRY_FUNCTION(name, memsize, r2) \
- ENTRY_FUNCTION_WITHSTACK(name, rpi_stack_top(memsize), __r0, __r1, r2)
+RPI_ENTRY_FUNCTION(start_raspberry_pi2, SZ_512M, fdt)
+{
+ arm_cpu_lowlevel_init();
+
+ start_raspberry_pi(SZ_512M, __dtb_z_bcm2836_rpi_2_start, (void *)fdt);
+}
-extern char __dtb_bcm2835_rpi_start[];
-RPI_ENTRY_FUNCTION(start_raspberry_pi1, SZ_128M, r2)
+RPI_ENTRY_FUNCTION(start_raspberry_pi3, SZ_512M, fdt)
{
- start_raspberry_pi(SZ_128M, __dtb_bcm2835_rpi_start, (void *)r2);
+ arm_cpu_lowlevel_init();
+
+ start_raspberry_pi(SZ_512M, __dtb_z_bcm2837_rpi_3_start, (void *)fdt);
}
-extern char __dtb_bcm2836_rpi_2_start[];
-RPI_ENTRY_FUNCTION(start_raspberry_pi2, SZ_512M, r2)
+RPI_ENTRY_FUNCTION(start_raspberry_pi_cm3, SZ_512M, fdt)
{
- start_raspberry_pi(SZ_512M, __dtb_bcm2836_rpi_2_start, (void *)r2);
+ arm_cpu_lowlevel_init();
+
+ start_raspberry_pi(SZ_512M, __dtb_z_bcm2837_rpi_cm3_start, (void *)fdt);
}
-extern char __dtb_bcm2837_rpi_3_start[];
-RPI_ENTRY_FUNCTION(start_raspberry_pi3, SZ_512M, r2)
+#define DT_IF_ENABLED(dt, cfg) \
+ (IS_ENABLED(cfg) ? (dt) : NULL)
+
+static void *rpi_get_board_fdt(int rev)
{
- start_raspberry_pi(SZ_512M, __dtb_bcm2837_rpi_3_start, (void *)r2);
+ if (!(rev & 0x800000))
+ return DT_IF_ENABLED(__dtb_z_bcm2835_rpi_start, CONFIG_MACH_RPI);
+
+ switch (((rev >> 4) & 0xff)) {
+ case BCM2835_BOARD_REV_A:
+ case BCM2835_BOARD_REV_B:
+ case BCM2835_BOARD_REV_A_PLUS:
+ case BCM2835_BOARD_REV_B_PLUS:
+ case BCM2835_BOARD_REV_CM1:
+ case BCM2835_BOARD_REV_ZERO:
+ case BCM2835_BOARD_REV_ZERO_W:
+ return DT_IF_ENABLED(__dtb_z_bcm2835_rpi_start, CONFIG_MACH_RPI);
+
+ case BCM2836_BOARD_REV_2_B:
+ return DT_IF_ENABLED(__dtb_z_bcm2836_rpi_2_start, CONFIG_MACH_RPI2);
+
+ case BCM2837_BOARD_REV_3_B:
+ case BCM2837B0_BOARD_REV_3B_PLUS:
+ case BCM2837B0_BOARD_REV_3A_PLUS:
+ case BCM2837B0_BOARD_REV_ZERO_2:
+ return DT_IF_ENABLED(__dtb_z_bcm2837_rpi_3_start, CONFIG_MACH_RPI3);
+
+ case BCM2837_BOARD_REV_CM3:
+ case BCM2837B0_BOARD_REV_CM3_PLUS:
+ return DT_IF_ENABLED(__dtb_z_bcm2837_rpi_cm3_start, CONFIG_MACH_RPI_CM3);
+
+ case BCM2711_BOARD_REV_4_B:
+ return DT_IF_ENABLED(__dtb_z_bcm2711_rpi_4_start, CONFIG_MACH_RPI4);
+ case BCM2711_BOARD_REV_400:
+ return DT_IF_ENABLED(__dtb_z_bcm2711_rpi_400_start, CONFIG_MACH_RPI4);
+ case BCM2711_BOARD_REV_CM4:
+ return DT_IF_ENABLED(__dtb_z_bcm2711_rpi_cm4_io_start, CONFIG_MACH_RPI4);
+ case BCM2711_BOARD_REV_CM4_S:
+ return DT_IF_ENABLED(__dtb_z_bcm2711_rpi_cm4s_io_start, CONFIG_MACH_RPI4);
+ }
+
+ return NULL;
}
-extern char __dtb_bcm2837_rpi_cm3_start[];
-RPI_ENTRY_FUNCTION(start_raspberry_pi_cm3, SZ_512M, r2)
+RPI_ENTRY_FUNCTION(start_raspberry_pi_generic, SZ_128M, vc_fdt)
{
- start_raspberry_pi(SZ_512M, __dtb_bcm2837_rpi_cm3_start, (void *)r2);
+ void *fdt = NULL;
+ ssize_t memsize;
+ int rev;
+
+ arm_cpu_lowlevel_init();
+
+ debug_ll_init();
+
+ putc_ll('>');
+
+ relocate_to_current_adr();
+ setup_c();
+
+ memsize = rpi_get_arm_mem();
+ if (memsize < 0) {
+ pr_warn("mbox: failed to query ARM memory size. 128M assumed.\n");
+ memsize = SZ_128M;
+ }
+
+ rev = rpi_get_board_rev();
+ if (rev >= 0) {
+ pr_debug("Detected revision %08x\n", rev);
+ fdt = rpi_get_board_fdt(rev);
+ }
+
+ if (!fdt) {
+ fdt = (void *)vc_fdt;
+
+ pr_warn("Unknown Rpi board with rev %08x.\n", rev);
+
+ if (get_unaligned_be32(fdt) != 0xd00dfeed)
+ panic("No suitable built-in or videocore-supplied DT\n");
+ }
+
+ start_raspberry_pi(memsize, fdt, (void *)vc_fdt);
}
diff --git a/arch/arm/boards/raspberry-pi/lowlevel.h b/arch/arm/boards/raspberry-pi/lowlevel.h
index eacf973fb6..a29860d607 100644
--- a/arch/arm/boards/raspberry-pi/lowlevel.h
+++ b/arch/arm/boards/raspberry-pi/lowlevel.h
@@ -3,9 +3,14 @@
#ifndef __ARCH_ARM_BOARDS_LOWLEVEL_H__
#define __ARCH_ARM_BOARDS_LOWLEVEL_H__
+#include <linux/types.h>
#include <linux/sizes.h>
#define VIDEOCORE_FDT_SZ SZ_1M
#define VIDEOCORE_FDT_ERROR 0xdeadfeed
+ssize_t rpi_get_arm_mem(void);
+int rpi_get_usbethaddr(u8 mac[6]);
+int rpi_get_board_rev(void);
+
#endif /* __ARCH_ARM_BOARDS_LOWLEVEL_H__ */
diff --git a/arch/arm/boards/raspberry-pi/mbox-helpers.c b/arch/arm/boards/raspberry-pi/mbox-helpers.c
new file mode 100644
index 0000000000..3a76ac2b01
--- /dev/null
+++ b/arch/arm/boards/raspberry-pi/mbox-helpers.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2009 Carlo Caione <carlo@carlocaione.org>
+
+#include <mach/bcm283x/mbox.h>
+#include "lowlevel.h"
+
+struct msg_get_arm_mem {
+ struct bcm2835_mbox_hdr hdr;
+ struct bcm2835_mbox_tag_get_arm_mem get_arm_mem;
+ u32 end_tag;
+};
+
+struct msg_get_board_rev {
+ struct bcm2835_mbox_hdr hdr;
+ struct bcm2835_mbox_tag_get_board_rev get_board_rev;
+ u32 end_tag;
+};
+
+struct msg_get_mac_address {
+ struct bcm2835_mbox_hdr hdr;
+ struct bcm2835_mbox_tag_get_mac_address get_mac_address;
+ u32 end_tag;
+};
+
+ssize_t rpi_get_arm_mem(void)
+{
+ BCM2835_MBOX_STACK_ALIGN(struct msg_get_arm_mem, msg);
+ int ret;
+
+ BCM2835_MBOX_INIT_HDR(msg);
+ BCM2835_MBOX_INIT_TAG(&msg->get_arm_mem, GET_ARM_MEMORY);
+
+ ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
+ if (ret)
+ return ret;
+
+ return msg->get_arm_mem.body.resp.mem_size;
+}
+
+int rpi_get_usbethaddr(u8 mac[6])
+{
+ BCM2835_MBOX_STACK_ALIGN(struct msg_get_mac_address, msg);
+ int ret;
+
+ BCM2835_MBOX_INIT_HDR(msg);
+ BCM2835_MBOX_INIT_TAG(&msg->get_mac_address, GET_MAC_ADDRESS);
+
+ ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
+ if (ret) {
+ pr_info("bcm2835: Could not query MAC address\n");
+ return ret;
+ }
+
+ memcpy(mac, msg->get_mac_address.body.resp.mac, 6);
+ return 0;
+}
+
+int rpi_get_board_rev(void)
+{
+ int ret;
+
+ BCM2835_MBOX_STACK_ALIGN(struct msg_get_board_rev, msg);
+ BCM2835_MBOX_INIT_HDR(msg);
+ BCM2835_MBOX_INIT_TAG(&msg->get_board_rev, GET_BOARD_REV);
+
+ ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
+ if (ret) {
+ pr_err("Could not query board revision\n");
+ return ret;
+ }
+
+ return msg->get_board_rev.body.resp.rev;
+}
diff --git a/arch/arm/boards/raspberry-pi/rpi-common.c b/arch/arm/boards/raspberry-pi/rpi-common.c
index 05d59ae6bf..628f657ea2 100644
--- a/arch/arm/boards/raspberry-pi/rpi-common.c
+++ b/arch/arm/boards/raspberry-pi/rpi-common.c
@@ -19,17 +19,32 @@
#include <led.h>
#include <asm/armlinux.h>
#include <asm/barebox-arm.h>
-#include <generated/mach-types.h>
+#include <asm/mach-types.h>
#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 <mach/bcm283x/core.h>
+#include <mach/bcm283x/mbox.h>
+#include <mach/bcm283x/platform.h>
+
+#include <soc/bcm283x/wdt.h>
#include "lowlevel.h"
+//https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#BOOT_ORDER
+static const char * const boot_mode_names[] = {
+ [0x0] = "unknown",
+ [0x1] = "sd",
+ [0x2] = "net",
+ [0x3] = "rpiboot",
+ [0x4] = "usbmsd",
+ [0x5] = "usbc",
+ [0x6] = "nvme",
+ [0x7] = "http",
+};
+
struct rpi_priv;
struct rpi_machine_data {
int (*init)(struct rpi_priv *priv);
@@ -39,63 +54,25 @@ struct rpi_machine_data {
};
struct rpi_priv {
- struct device_d *dev;
+ struct device *dev;
const struct rpi_machine_data *dcfg;
unsigned int hw_id;
const char *name;
};
-struct msg_get_arm_mem {
- struct bcm2835_mbox_hdr hdr;
- struct bcm2835_mbox_tag_get_arm_mem get_arm_mem;
- u32 end_tag;
+struct rpi_property_fixup_data {
+ const struct device_node* vc_node;
+ const char *propname;
};
-struct msg_get_board_rev {
- struct bcm2835_mbox_hdr hdr;
- struct bcm2835_mbox_tag_get_board_rev get_board_rev;
- u32 end_tag;
-};
-
-struct msg_get_mac_address {
- struct bcm2835_mbox_hdr hdr;
- struct bcm2835_mbox_tag_get_mac_address get_mac_address;
- u32 end_tag;
-};
-
-static int rpi_get_arm_mem(u32 *size)
-{
- BCM2835_MBOX_STACK_ALIGN(struct msg_get_arm_mem, msg);
- int ret;
-
- BCM2835_MBOX_INIT_HDR(msg);
- BCM2835_MBOX_INIT_TAG(&msg->get_arm_mem, GET_ARM_MEMORY);
-
- ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
- if (ret)
- return ret;
-
- *size = msg->get_arm_mem.body.resp.mem_size;
-
- return 0;
-}
-
static void rpi_set_usbethaddr(void)
{
- BCM2835_MBOX_STACK_ALIGN(struct msg_get_mac_address, msg);
- int ret;
+ u8 mac[ETH_ALEN];
- BCM2835_MBOX_INIT_HDR(msg);
- BCM2835_MBOX_INIT_TAG(&msg->get_mac_address, GET_MAC_ADDRESS);
+ if (rpi_get_usbethaddr(mac))
+ return; /* Ignore error; not critical */
- ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
- if (ret) {
- printf("bcm2835: Could not query MAC address\n");
- /* Ignore error; not critical */
- return;
- }
-
- eth_register_ethaddr(0, msg->get_mac_address.body.resp.mac);
+ eth_register_ethaddr(0, mac);
}
static void rpi_set_usbotg(const char *alias)
@@ -138,6 +115,12 @@ static void rpi_add_led(void)
led_set_trigger(LED_TRIGGER_HEARTBEAT, &l->led);
}
+static int rpi_eth_init(struct rpi_priv *priv)
+{
+ rpi_set_usbethaddr();
+ return 0;
+}
+
static int rpi_b_init(struct rpi_priv *priv)
{
rpi_leds[0].gpio = 16;
@@ -185,62 +168,46 @@ static int rpi_0_w_init(struct rpi_priv *priv)
return of_device_disable_by_alias("serial0");
}
-static int rpi_get_board_rev(struct rpi_priv *priv)
-{
- int ret;
-
- BCM2835_MBOX_STACK_ALIGN(struct msg_get_board_rev, msg);
- BCM2835_MBOX_INIT_HDR(msg);
- BCM2835_MBOX_INIT_TAG(&msg->get_board_rev, GET_BOARD_REV);
-
- ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
- if (ret) {
- dev_err(priv->dev, "Could not query board revision\n");
- return ret;
- }
-
- /* Comments from u-boot:
- * For details of old-vs-new scheme, see:
- * https://github.com/pimoroni/RPi.version/blob/master/RPi/version.py
- * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=99293&p=690282
- * (a few posts down)
- *
- * For the RPi 1, bit 24 is the "warranty bit", so we mask off just the
- * lower byte to use as the board rev:
- * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=98367&start=250
- * http://www.raspberrypi.org/forums/viewtopic.php?f=31&t=20594
- */
- priv->hw_id = msg->get_board_rev.body.resp.rev;
-
- return 0;
-}
-
static int rpi_mem_init(void)
{
- u32 size = 0;
- int ret;
+ ssize_t size;
- ret = rpi_get_arm_mem(&size);
- if (ret)
+ if (!of_machine_is_compatible("brcm,bcm2837") &&
+ !of_machine_is_compatible("brcm,bcm2835") &&
+ !of_machine_is_compatible("brcm,bcm2711") &&
+ !of_machine_is_compatible("brcm,bcm2836"))
+ return 0;
+
+ size = rpi_get_arm_mem();
+ if (size < 0) {
printf("could not query ARM memory size\n");
+ size = get_ram_size((ulong *) BCM2835_SDRAM_BASE, SZ_128M);
+ }
bcm2835_add_device_sdram(size);
- return ret;
+ return 0;
}
mem_initcall(rpi_mem_init);
static int rpi_env_init(void)
{
struct stat s;
- const char *diskdev = "/dev/disk0.0";
+ const char *diskdev;
int ret;
device_detect_by_name("mci0");
+ device_detect_by_name("mci1");
+ diskdev = "/dev/disk0.0";
ret = stat(diskdev, &s);
if (ret) {
- printf("no %s. using default env\n", diskdev);
+ device_detect_by_name("mmc0");
+ diskdev = "/dev/mmc0.0";
+ ret = stat(diskdev, &s);
+ }
+ if (ret) {
+ printf("no /dev/disk0.0 or /dev/mmc0.0. using default env\n");
return 0;
}
@@ -258,62 +225,234 @@ 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)
+/* Some string properties in fdt passed to us from vc may be
+ * malformed by not being null terminated, so just create and
+ * return a fixed copy.
+ */
+static char *of_read_vc_string(struct device_node *node,
+ const char *prop_name)
{
- int ret = 0;
- struct device_node *root = NULL, *node;
- const char *cmdline;
-
- root = of_unflatten_dtb(fdt, INT_MAX);
- if (IS_ERR(root)) {
- ret = PTR_ERR(root);
- root = NULL;
- goto out;
+ int len;
+ const char *str;
+
+ str = of_get_property(node, prop_name, &len);
+ if (!str) {
+ pr_warn("no property '%s' found in vc fdt's '%pOF' node\n",
+ prop_name, node);
+ return NULL;
}
+ return xstrndup(str, len);
+}
- node = of_find_node_by_path_from(root, "/chosen");
- if (!node) {
- pr_err("no /chosen node\n");
- ret = -ENOENT;
- goto out;
+static enum reset_src_type rpi_decode_pm_rsts(struct device_node *chosen,
+ struct device_node *bootloader)
+{
+ u32 pm_rsts;
+ int ret;
+
+ ret = of_property_read_u32(chosen, "pm_rsts", &pm_rsts);
+ if (ret && bootloader)
+ ret = of_property_read_u32(bootloader, "rsts", &pm_rsts);
+
+ if (ret) {
+ pr_warn("'pm_rsts' value not found in vc fdt\n");
+ return RESET_UKWN;
}
+ /*
+ * https://github.com/raspberrypi/linux/issues/932#issuecomment-93989581
+ */
+
+ if (pm_rsts & PM_RSTS_HADPOR_SET)
+ return RESET_POR;
+ if (pm_rsts & PM_RSTS_HADDR_SET)
+ return RESET_JTAG;
+ if (pm_rsts & PM_RSTS_HADWR_SET)
+ return RESET_WDG;
+ if (pm_rsts & PM_RSTS_HADSR_SET)
+ return RESET_RST;
+
+ return RESET_UKWN;
+}
+
+static int rpi_vc_fdt_fixup(struct device_node *root, void *data)
+{
+ const struct device_node *vc_node = data;
+ struct device_node *node;
+ struct property *pp;
+
+ node = of_create_node(root, vc_node->full_name);
+ if (!node)
+ return -ENOMEM;
+
+ for_each_property_of_node(vc_node, pp)
+ of_copy_property(vc_node, pp->name, node);
- cmdline = of_get_property(node, "bootargs", NULL);
- if (!cmdline) {
- pr_err("no bootargs property in the /chosen node\n");
- ret = -ENOENT;
- goto out;
+ return 0;
+}
+
+static struct device_node *register_vc_fixup(struct device_node *root,
+ const char *path)
+{
+ struct device_node *ret, *tmp;
+
+ ret = of_find_node_by_path_from(root, path);
+ if (ret) {
+ tmp = of_dup(ret);
+ tmp->full_name = xstrdup(ret->full_name);
+ of_register_fixup(rpi_vc_fdt_fixup, tmp);
+ } else {
+ pr_info("no '%s' node found in vc fdt\n", path);
}
- globalvar_add_simple("vc.bootargs", cmdline);
+ return ret;
+}
- 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", "kernel7l.img");
- break;
+static int rpi_vc_fdt_fixup_property(struct device_node *root, void *data)
+{
+ const struct rpi_property_fixup_data *fixup = data;
+ struct device_node *node;
+ struct property *prop;
+
+ node = of_create_node(root, fixup->vc_node->full_name);
+ if (!node)
+ return -ENOMEM;
+
+ prop = of_find_property(fixup->vc_node, fixup->propname, NULL);
+ if (!prop)
+ return -ENOENT;
+
+ return of_set_property(node, prop->name,
+ of_property_get_value(prop), prop->length, 1);
+}
+
+static int register_vc_property_fixup(struct device_node *root,
+ const char *path, const char *propname)
+{
+ struct device_node *node, *tmp;
+ struct rpi_property_fixup_data* fixup_data;
+
+ node = of_find_node_by_path_from(root, path);
+ if (node) {
+ tmp = of_dup(node);
+ tmp->full_name = xstrdup(node->full_name);
+ fixup_data = xzalloc(sizeof(*fixup_data));
+ fixup_data->vc_node = tmp;
+ fixup_data->propname = xstrdup(propname);
+
+ of_register_fixup(rpi_vc_fdt_fixup_property, fixup_data);
+ } else {
+ pr_info("no '%s' node found in vc fdt\n", path);
+ return -ENOENT;
}
-out:
- if (root)
- of_delete_node(root);
+ return 0;
+}
- return ret;
+static u32 rpi_boot_mode, rpi_boot_part;
+/* 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(struct device_node *root)
+{
+ int ret;
+ struct device_node *chosen, *bootloader, *memory;
+ char *str;
+
+ str = of_read_vc_string(root, "serial-number");
+ if (str) {
+ barebox_set_serial_number(str);
+ free(str);
+ }
+
+ str = of_read_vc_string(root, "model");
+ if (str) {
+ barebox_set_model(str);
+ free(str);
+ }
+
+ register_vc_fixup(root, "/system");
+ register_vc_fixup(root, "/axi");
+ register_vc_property_fixup(root, "/reserved-memory/nvram@0", "reg");
+ register_vc_property_fixup(root, "/reserved-memory/nvram@0", "status");
+ register_vc_fixup(root, "/hat");
+ register_vc_property_fixup(root, "/emmc2bus", "dma-ranges");
+ register_vc_fixup(root, "/chosen/bootloader");
+ chosen = register_vc_fixup(root, "/chosen");
+ if (!chosen) {
+ pr_err("no '/chosen' node found in vc fdt\n");
+ return;
+ }
+
+ bootloader = of_find_node_by_name(chosen, "bootloader");
+
+ str = of_read_vc_string(chosen, "bootargs");
+ if (str) {
+ globalvar_add_simple("vc.bootargs", str);
+ free(str);
+ }
+
+ str = of_read_vc_string(chosen, "overlay_prefix");
+ if (str) {
+ globalvar_add_simple("vc.overlay_prefix", str);
+ free(str);
+ }
+
+ str = of_read_vc_string(chosen, "os_prefix");
+ if (str) {
+ globalvar_add_simple("vc.os_prefix", str);
+ free(str);
+ }
+
+ ret = of_property_read_u32(chosen, "boot-mode", &rpi_boot_mode);
+ if (ret && bootloader)
+ ret = of_property_read_u32(bootloader, "boot-mode", &rpi_boot_mode);
+ if (ret)
+ pr_debug("'boot-mode' property not found in vc fdt\n");
+ else
+ globalvar_add_simple_enum("vc.boot_mode", &rpi_boot_mode,
+ boot_mode_names,
+ ARRAY_SIZE(boot_mode_names));
+
+ ret = of_property_read_u32(chosen, "partition", &rpi_boot_part);
+ if (ret && bootloader)
+ ret = of_property_read_u32(bootloader, "partition", &rpi_boot_part);
+ if (ret)
+ pr_debug("'partition' property not found in vc fdt\n");
+ else
+ globalvar_add_simple_int("vc.boot_partition", &rpi_boot_part, "%u");
+
+ if (IS_ENABLED(CONFIG_RESET_SOURCE))
+ reset_source_set(rpi_decode_pm_rsts(chosen, bootloader));
+
+ /* Parse all available nodes with "memory" device_type */
+ memory = root;
+ while (1) {
+ memory = of_find_node_by_type(memory, "memory");
+ if (!memory)
+ break;
+
+ of_add_memory(memory, false);
+ }
}
-static void rpi_vc_fdt(void)
+/**
+ * rpi_vc_fdt - unflatten VideoCore provided DT
+ *
+ * If configured via config.txt, the VideoCore firmware will pass barebox PBL
+ * a device-tree in a register. This is saved to a handover memory area by
+ * the Raspberry Pi PBL, which is parsed here. barebox-dt-2nd doesn't
+ * populate this area, instead it uses the VideoCore DT as its own DT.
+ *
+ * Return: an unflattened DT on success, an error pointer if parsing the DT
+ * fails and NULL if a Raspberry Pi PBL has run, but no VideoCore FDT was
+ * saved.
+ */
+static struct device_node *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());
@@ -325,23 +464,30 @@ static void rpi_vc_fdt(void)
if (oftree->totalsize)
pr_err("there was an error copying fdt in pbl: %d\n",
be32_to_cpu(oftree->totalsize));
- return;
+ return NULL;
}
if (magic != FDT_MAGIC)
- return;
+ return ERR_PTR(-EINVAL);
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;
+ return of_unflatten_dtb(saved_vc_fdt, INT_MAX);
+}
+
+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;
}
}
@@ -355,6 +501,18 @@ static const struct rpi_machine_data *rpi_get_dcfg(struct rpi_priv *priv)
return NULL;
}
+ /* Comments from u-boot:
+ * For details of old-vs-new scheme, see:
+ * https://github.com/pimoroni/RPi.version/blob/master/RPi/version.py
+ * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=99293&p=690282
+ * (a few posts down)
+ *
+ * For the RPi 1, bit 24 is the "warranty bit", so we mask off just the
+ * lower byte to use as the board rev:
+ * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=98367&start=250
+ * http://www.raspberrypi.org/forums/viewtopic.php?f=31&t=20594
+ */
+
for (; dcfg->hw_id != U8_MAX; dcfg++) {
if (priv->hw_id & 0x800000) {
if (dcfg->hw_id != ((priv->hw_id >> 4) & 0xff))
@@ -374,11 +532,12 @@ static const struct rpi_machine_data *rpi_get_dcfg(struct rpi_priv *priv)
return ERR_PTR(-ENODEV);
}
-static int rpi_devices_probe(struct device_d *dev)
+static int rpi_devices_probe(struct device *dev)
{
const struct rpi_machine_data *dcfg;
struct regulator *reg;
struct rpi_priv *priv;
+ struct device_node *vc_root;
const char *name, *ptr;
char *hostname;
int ret;
@@ -386,10 +545,12 @@ static int rpi_devices_probe(struct device_d *dev)
priv = xzalloc(sizeof(*priv));
priv->dev = dev;
- ret = rpi_get_board_rev(priv);
- if (ret)
+ ret = rpi_get_board_rev();
+ if (ret < 0)
goto free_priv;
+ priv->hw_id = ret;
+
dcfg = rpi_get_dcfg(priv);
if (IS_ERR(dcfg))
goto free_priv;
@@ -405,7 +566,25 @@ static int rpi_devices_probe(struct device_d *dev)
bcm2835_register_fb();
armlinux_set_architecture(MACH_TYPE_BCM2708);
rpi_env_init();
- rpi_vc_fdt();
+
+ vc_root = rpi_vc_fdt();
+ if (!vc_root) {
+ dev_dbg(dev, "No VideoCore FDT was provided\n");
+ } else if (!IS_ERR(vc_root)) {
+ dev_dbg(dev, "VideoCore FDT was provided\n");
+ rpi_vc_fdt_parse(vc_root);
+ of_delete_node(vc_root);
+ } else if (IS_ERR(vc_root)) {
+ /* This is intentionally at a higher logging level, because we can't
+ * be sure that the external DT is indeed a barebox DT (and not a
+ * kernel DT that happened to be in the partition). So for ease
+ * of debugging, we report this at info log level.
+ */
+ dev_info(dev, "barebox FDT will be used for VideoCore FDT\n");
+ rpi_vc_fdt_parse(priv->dev->device_node);
+ }
+
+ rpi_set_kernel_name();
if (dcfg && dcfg->init)
dcfg->init(priv);
@@ -523,6 +702,7 @@ static const struct rpi_machine_data rpi_3_ids[] = {
.init = rpi_b_plus_init,
}, {
.hw_id = BCM2837_BOARD_REV_CM3,
+ .init = rpi_eth_init,
}, {
.hw_id = BCM2837B0_BOARD_REV_CM3_PLUS,
}, {
@@ -532,6 +712,24 @@ static const struct rpi_machine_data rpi_3_ids[] = {
},
};
+static const struct rpi_machine_data rpi_4_ids[] = {
+ {
+ .hw_id = BCM2711_BOARD_REV_4_B,
+ .init = rpi_eth_init,
+ }, {
+ .hw_id = BCM2711_BOARD_REV_400,
+ .init = rpi_eth_init,
+ }, {
+ .hw_id = BCM2711_BOARD_REV_CM4,
+ .init = rpi_eth_init,
+ }, {
+ .hw_id = BCM2711_BOARD_REV_CM4_S,
+ .init = rpi_eth_init,
+ }, {
+ .hw_id = U8_MAX
+ },
+};
+
static const struct of_device_id rpi_of_match[] = {
/* BCM2835 based Boards */
{ .compatible = "raspberrypi,model-a", .data = rpi_1_ids },
@@ -556,11 +754,17 @@ static const struct of_device_id rpi_of_match[] = {
{ .compatible = "raspberrypi,3-compute-module", .data = rpi_3_ids },
{ .compatible = "raspberrypi,3-compute-module-lite", .data = rpi_3_ids },
+ /* BCM2711 based Boards */
+ { .compatible = "raspberrypi,4-model-b", .data = rpi_4_ids },
+ { .compatible = "raspberrypi,4-compute-module", .data = rpi_4_ids },
+ { .compatible = "raspberrypi,4-compute-module-s", .data = rpi_4_ids },
+ { .compatible = "raspberrypi,400", .data = rpi_4_ids },
+
{ /* sentinel */ },
};
BAREBOX_DEEP_PROBE_ENABLE(rpi_of_match);
-static struct driver_d rpi_board_driver = {
+static struct driver rpi_board_driver = {
.name = "board-rpi",
.probe = rpi_devices_probe,
.of_compatible = DRV_OF_COMPAT(rpi_of_match),