summaryrefslogtreecommitdiffstats
path: root/arch/arm/boards/raspberry-pi/rpi-common.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/boards/raspberry-pi/rpi-common.c')
-rw-r--r--arch/arm/boards/raspberry-pi/rpi-common.c891
1 files changed, 597 insertions, 294 deletions
diff --git a/arch/arm/boards/raspberry-pi/rpi-common.c b/arch/arm/boards/raspberry-pi/rpi-common.c
index dd6bbd5bdd..628f657ea2 100644
--- a/arch/arm/boards/raspberry-pi/rpi-common.c
+++ b/arch/arm/boards/raspberry-pi/rpi-common.c
@@ -1,26 +1,17 @@
-/*
- * Copyright (C) 2009 Carlo Caione <carlo@carlocaione.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2009 Carlo Caione <carlo@carlocaione.org>
#include <common.h>
+#include <deep-probe.h>
#include <init.h>
#include <fs.h>
#include <of.h>
+#include <of_device.h>
#include <linux/stat.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <envfs.h>
+#include <regulator.h>
#include <malloc.h>
#include <libfile.h>
#include <gpio.h>
@@ -28,93 +19,72 @@
#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 "rpi.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;
+//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 msg_get_clock_rate {
- struct bcm2835_mbox_hdr hdr;
- struct bcm2835_mbox_tag_get_clock_rate get_clock_rate;
- u32 end_tag;
+struct rpi_priv;
+struct rpi_machine_data {
+ int (*init)(struct rpi_priv *priv);
+ u8 hw_id;
+#define RPI_OLD_SCHEMA BIT(0)
+ u8 flags;
};
-struct msg_get_board_rev {
- struct bcm2835_mbox_hdr hdr;
- struct bcm2835_mbox_tag_get_board_rev get_board_rev;
- u32 end_tag;
+struct rpi_priv {
+ struct device *dev;
+ const struct rpi_machine_data *dcfg;
+ unsigned int hw_id;
+ const char *name;
};
-struct msg_get_mac_address {
- struct bcm2835_mbox_hdr hdr;
- struct bcm2835_mbox_tag_get_mac_address get_mac_address;
- u32 end_tag;
+struct rpi_property_fixup_data {
+ const struct device_node* vc_node;
+ const char *propname;
};
-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 struct clk *rpi_register_firmware_clock(u32 clock_id, const char *name)
+static void rpi_set_usbethaddr(void)
{
- BCM2835_MBOX_STACK_ALIGN(struct msg_get_clock_rate, msg);
- int ret;
-
- BCM2835_MBOX_INIT_HDR(msg);
- BCM2835_MBOX_INIT_TAG(&msg->get_clock_rate, GET_CLOCK_RATE);
- msg->get_clock_rate.body.req.clock_id = clock_id;
+ u8 mac[ETH_ALEN];
- ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
- if (ret)
- return ERR_PTR(ret);
+ if (rpi_get_usbethaddr(mac))
+ return; /* Ignore error; not critical */
- return clk_fixed(name, msg->get_clock_rate.body.resp.rate_hz);
+ eth_register_ethaddr(0, mac);
}
-void rpi_set_usbethaddr(void)
+static void rpi_set_usbotg(const char *alias)
{
- 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) {
- printf("bcm2835: Could not query MAC address\n");
- /* Ignore error; not critical */
- return;
- }
+ struct device_node *usb;
- eth_register_ethaddr(0, msg->get_mac_address.body.resp.mac);
+ usb = of_find_node_by_alias(NULL, alias);
+ if (usb)
+ of_property_write_string(usb, "dr_mode", "otg");
}
-struct gpio_led rpi_leds[] = {
+static struct gpio_led rpi_leds[] = {
{
.gpio = -EINVAL,
.led = {
@@ -145,325 +115,658 @@ static void rpi_add_led(void)
led_set_trigger(LED_TRIGGER_HEARTBEAT, &l->led);
}
-static void rpi_b_init(void)
+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;
rpi_leds[0].active_low = 1;
rpi_set_usbethaddr();
+
+ return 0;
}
-static void rpi_b_plus_init(void)
+static int rpi_b_plus_init(struct rpi_priv *priv)
{
rpi_leds[0].gpio = 47;
rpi_leds[1].gpio = 35;
rpi_set_usbethaddr();
-}
-/* See comments in mbox.h for data source */
-const struct rpi_model rpi_models_old_scheme[] = {
- RPI_MODEL(0, "Unknown model", NULL),
- RPI_MODEL(BCM2835_BOARD_REV_B_I2C0_2, "Model B (no P5)", rpi_b_init),
- RPI_MODEL(BCM2835_BOARD_REV_B_I2C0_3, "Model B (no P5)", rpi_b_init),
- RPI_MODEL(BCM2835_BOARD_REV_B_I2C1_4, "Model B", rpi_b_init),
- RPI_MODEL(BCM2835_BOARD_REV_B_I2C1_5, "Model B", rpi_b_init),
- RPI_MODEL(BCM2835_BOARD_REV_B_I2C1_6, "Model B", rpi_b_init),
- RPI_MODEL(BCM2835_BOARD_REV_A_7, "Model A", NULL),
- RPI_MODEL(BCM2835_BOARD_REV_A_8, "Model A", NULL),
- RPI_MODEL(BCM2835_BOARD_REV_A_9, "Model A", NULL),
- RPI_MODEL(BCM2835_BOARD_REV_B_REV2_d, "Model B rev2", rpi_b_init),
- RPI_MODEL(BCM2835_BOARD_REV_B_REV2_e, "Model B rev2", rpi_b_init),
- RPI_MODEL(BCM2835_BOARD_REV_B_REV2_f, "Model B rev2", rpi_b_init),
- RPI_MODEL(BCM2835_BOARD_REV_B_PLUS_10, "Model B+", rpi_b_plus_init),
- RPI_MODEL(BCM2835_BOARD_REV_CM_11, "Compute Module", NULL),
- RPI_MODEL(BCM2835_BOARD_REV_A_PLUS_12, "Model A+", NULL),
- RPI_MODEL(BCM2835_BOARD_REV_B_PLUS_13, "Model B+", rpi_b_plus_init),
- RPI_MODEL(BCM2835_BOARD_REV_CM_14, "Compute Module", NULL),
- RPI_MODEL(BCM2835_BOARD_REV_A_PLUS_15, "Model A+", NULL),
-};
+ return 0;
+}
-const struct rpi_model rpi_models_new_scheme[] = {
- RPI_MODEL(BCM2835_BOARD_REV_A, "Model A", NULL ),
- RPI_MODEL(BCM2835_BOARD_REV_B, "Model B", rpi_b_init ),
- RPI_MODEL(BCM2835_BOARD_REV_A_PLUS, "Model A+", NULL ),
- RPI_MODEL(BCM2835_BOARD_REV_B_PLUS, "Model B+", rpi_b_plus_init ),
- RPI_MODEL(BCM2836_BOARD_REV_2_B, "Model 2B", rpi_b_plus_init),
- RPI_MODEL(BCM283x_BOARD_REV_Alpha, "Alpha", NULL),
- RPI_MODEL(BCM2835_BOARD_REV_CM1, "Compute Module", NULL ),
- RPI_MODEL(0x7, "Unknown model", NULL),
- RPI_MODEL(BCM2837_BOARD_REV_3_B, "Model 3B", rpi_b_init ),
- RPI_MODEL(BCM2835_BOARD_REV_ZERO, "Zero", rpi_b_plus_init),
- RPI_MODEL(BCM2837_BOARD_REV_CM3, "Compute Module 3", NULL ),
- RPI_MODEL(0xb, "Unknown model", NULL),
- RPI_MODEL(BCM2835_BOARD_REV_ZERO_W, "Zero W", rpi_b_plus_init),
- RPI_MODEL(BCM2837B0_BOARD_REV_3B_PLUS, "Model 3 B+", rpi_b_plus_init ),
- RPI_MODEL(BCM2837B0_BOARD_REV_3A_PLUS, "Nodel 3 A+", rpi_b_plus_init),
- RPI_MODEL(0xf, "Unknown model", NULL),
- RPI_MODEL(BCM2837B0_BOARD_REV_CM3_PLUS, "Compute Module 3+", NULL),
-};
+static int rpi_0_init(struct rpi_priv *priv)
+{
+ rpi_leds[0].gpio = 47;
+ rpi_set_usbotg("usb0");
-static int rpi_board_rev = 0;
-const struct rpi_model *model = NULL;
+ return 0;
+}
-static void rpi_get_board_rev(void)
+static int rpi_0_w_init(struct rpi_priv *priv)
{
+ struct device_node *np;
int ret;
- char *name;
- const struct rpi_model *rpi_models;
- size_t rpi_models_size;
- 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);
+ rpi_0_init(priv);
- ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
- if (ret) {
- printf("bcm2835: Could not query board revision\n");
- /* Ignore error; not critical */
- return;
- }
+ np = of_find_node_by_path("/chosen");
+ if (!np)
+ return -ENODEV;
- /* 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
- */
- rpi_board_rev = msg->get_board_rev.body.resp.rev;
- if (rpi_board_rev & 0x800000) {
- rpi_board_rev = (rpi_board_rev >> 4) & 0xff;
- rpi_models = rpi_models_new_scheme;
- rpi_models_size = ARRAY_SIZE(rpi_models_new_scheme);
+ if (!of_device_enable_and_register_by_alias("serial1"))
+ return -ENODEV;
- } else {
- rpi_board_rev &= 0xff;
- rpi_models = rpi_models_old_scheme;
- rpi_models_size = ARRAY_SIZE(rpi_models_old_scheme);
- }
+ ret = of_property_write_string(np, "stdout-path", "serial1:115200n8");
+ if (ret)
+ return ret;
- if (rpi_board_rev >= rpi_models_size) {
- printf("RPI: Board rev %u outside known range\n",
- rpi_board_rev);
- goto unknown_rev;
- }
+ return of_device_disable_by_alias("serial0");
+}
- if (!rpi_models[rpi_board_rev].name) {
- printf("RPI: Board rev %u unknown\n", rpi_board_rev);
- goto unknown_rev;
- }
+static int rpi_mem_init(void)
+{
+ ssize_t size;
- if (!rpi_board_rev)
- goto unknown_rev;
+ 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;
- model = &rpi_models[rpi_board_rev];
- name = basprintf("RaspberryPi %s", model->name);
- barebox_set_model(name);
- free(name);
+ 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);
+ }
- return;
+ bcm2835_add_device_sdram(size);
-unknown_rev:
- rpi_board_rev = 0;
- barebox_set_model("RaspberryPi (unknown rev)");
+ return 0;
}
+mem_initcall(rpi_mem_init);
-static void rpi_model_init(void)
+static int rpi_env_init(void)
{
- if (!model)
- return;
+ struct stat s;
+ const char *diskdev;
+ int ret;
- if (!model->init)
- return;
+ device_detect_by_name("mci0");
+ device_detect_by_name("mci1");
- model->init();
- rpi_add_led();
-}
+ diskdev = "/dev/disk0.0";
+ ret = stat(diskdev, &s);
+ if (ret) {
+ 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;
+ }
-static int rpi_mem_init(void)
-{
- u32 size = 0;
- int ret;
+ mkdir("/boot", 0666);
+ ret = mount(diskdev, "fat", "/boot", NULL);
+ if (ret) {
+ printf("failed to mount %s\n", diskdev);
+ return 0;
+ }
- ret = rpi_get_arm_mem(&size);
- if (ret)
- printf("could not query ARM memory size\n");
+ defaultenv_append_directory(defaultenv_rpi);
- bcm2835_add_device_sdram(size);
+ default_environment_path_set("/boot/barebox.env");
- return ret;
+ return 0;
}
-mem_initcall(rpi_mem_init);
-static int rpi_postcore_init(void)
+/* 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)
{
- rpi_get_board_rev();
- barebox_set_hostname("rpi");
-
- return 0;
+ 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);
}
-postcore_initcall(rpi_postcore_init);
-static int rpi_clock_init(void)
+static enum reset_src_type rpi_decode_pm_rsts(struct device_node *chosen,
+ struct device_node *bootloader)
{
- struct clk *clk;
+ 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
+ */
- clk = rpi_register_firmware_clock(BCM2835_MBOX_CLOCK_ID_EMMC,
- "bcm2835_mci0");
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ 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;
- clkdev_add_physbase(clk, 0x20300000, NULL);
- clkdev_add_physbase(clk, 0x3f300000, NULL);
+ return RESET_UKWN;
+}
- clk = rpi_register_firmware_clock(BCM2835_MBOX_CLOCK_ID_CORE,
- "bcm2835_sdhost");
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+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;
- clkdev_add_physbase(clk, 0x20202000, NULL);
- clkdev_add_physbase(clk, 0x3f202000, NULL);
+ 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);
return 0;
}
-postconsole_initcall(rpi_clock_init);
-static int rpi_console_clock_init(void)
+static struct device_node *register_vc_fixup(struct device_node *root,
+ const char *path)
{
- struct clk *clk;
+ struct device_node *ret, *tmp;
- clk = clk_fixed("apb_pclk", 0);
- clk_register_clkdev(clk, "apb_pclk", NULL);
+ 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);
+ }
- clk = clk_fixed("uart0-pl0110", 3 * 1000 * 1000);
- clk_register_clkdev(clk, NULL, "uart0-pl0110");
- clkdev_add_physbase(clk, BCM2835_PL011_BASE, NULL);
- clkdev_add_physbase(clk, BCM2836_PL011_BASE, NULL);
+ return ret;
+}
- clk = rpi_register_firmware_clock(BCM2835_MBOX_CLOCK_ID_CORE,
- "uart1-8250");
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+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;
- clkdev_add_physbase(clk, BCM2836_MINIUART_BASE, NULL);
+ node = of_create_node(root, fixup->vc_node->full_name);
+ if (!node)
+ return -ENOMEM;
- clk = clk_fixed("bcm2835-cs", 1 * 1000 * 1000);
- clk_register_clkdev(clk, NULL, "bcm2835-cs");
+ 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;
+ }
return 0;
}
-postcore_initcall(rpi_console_clock_init);
-static int rpi_env_init(void)
+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)
{
- struct stat s;
- const char *diskdev = "/dev/disk0.0";
int ret;
+ struct device_node *chosen, *bootloader, *memory;
+ char *str;
- device_detect_by_name("mci0");
-
- ret = stat(diskdev, &s);
- if (ret) {
- printf("no %s. using default env\n", diskdev);
- return 0;
+ str = of_read_vc_string(root, "serial-number");
+ if (str) {
+ barebox_set_serial_number(str);
+ free(str);
}
- mkdir("/boot", 0666);
- ret = mount(diskdev, "fat", "/boot", NULL);
- if (ret) {
- printf("failed to mount %s\n", diskdev);
- return 0;
+ str = of_read_vc_string(root, "model");
+ if (str) {
+ barebox_set_model(str);
+ free(str);
}
- default_environment_path_set("/boot/barebox.env");
+ 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;
+ }
- return 0;
-}
+ bootloader = of_find_node_by_name(chosen, "bootloader");
-/* Extract /chosen/bootargs from the VideoCore FDT into vc.bootargs
- * global variable. */
-static int rpi_vc_fdt_bootargs(void *fdt)
-{
- int ret = 0;
- struct device_node *root = NULL, *node;
- const char *cmdline;
-
- root = of_unflatten_dtb(fdt);
- if (IS_ERR(root)) {
- ret = PTR_ERR(root);
- root = NULL;
- goto out;
+ str = of_read_vc_string(chosen, "bootargs");
+ if (str) {
+ globalvar_add_simple("vc.bootargs", str);
+ free(str);
}
- node = of_find_node_by_path_from(root, "/chosen");
- if (!node) {
- pr_err("no /chosen node\n");
- ret = -ENOENT;
- goto out;
+ str = of_read_vc_string(chosen, "overlay_prefix");
+ if (str) {
+ globalvar_add_simple("vc.overlay_prefix", str);
+ free(str);
}
- cmdline = of_get_property(node, "bootargs", NULL);
- if (!cmdline) {
- pr_err("no bootargs property in the /chosen node\n");
- ret = -ENOENT;
- goto out;
+ str = of_read_vc_string(chosen, "os_prefix");
+ if (str) {
+ globalvar_add_simple("vc.os_prefix", str);
+ free(str);
}
- globalvar_add_simple("vc.bootargs", cmdline);
+ 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");
-out:
- if (root)
- of_delete_node(root);
+ if (IS_ENABLED(CONFIG_RESET_SOURCE))
+ reset_source_set(rpi_decode_pm_rsts(chosen, bootloader));
- return ret;
+ /* 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());
oftree = saved_vc_fdt;
magic = be32_to_cpu(oftree->magic);
- if (magic != FDT_MAGIC) {
- pr_err("videocore fdt saved in pbl has invalid magic\n");
- if (magic == VIDEOCORE_FDT_ERROR) {
+ if (magic == VIDEOCORE_FDT_ERROR) {
+ 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 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;
+
+ 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;
}
+}
- ret = rpi_vc_fdt_bootargs(saved_vc_fdt);
- if (ret) {
- pr_err("failed to extract bootargs from videocore fdt: %d\n",
- ret);
- return;
+static const struct rpi_machine_data *rpi_get_dcfg(struct rpi_priv *priv)
+{
+ const struct rpi_machine_data *dcfg;
+
+ dcfg = of_device_get_match_data(priv->dev);
+ if (!dcfg) {
+ dev_err(priv->dev, "Unknown board. Not applying fixups\n");
+ 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))
+ continue;
+ } else {
+ if (!(dcfg->flags & RPI_OLD_SCHEMA))
+ continue;
+ if (dcfg->hw_id != (priv->hw_id & 0xff))
+ continue;
+ }
+
+ return dcfg;
}
+
+ dev_err(priv->dev, "dcfg 0x%x for board_id doesn't match DT compatible\n",
+ priv->hw_id);
+ return ERR_PTR(-ENODEV);
}
-static int rpi_devices_init(void)
+static int rpi_devices_probe(struct device *dev)
{
- rpi_model_init();
+ 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;
+
+ priv = xzalloc(sizeof(*priv));
+ priv->dev = dev;
+
+ 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;
+
+ /* construct short recognizable host name */
+ name = of_device_get_match_compatible(priv->dev);
+ ptr = strchr(name, ',');
+ hostname = basprintf("rpi-%s", ptr ? ptr + 1 : name);
+ barebox_set_hostname(hostname);
+ free(hostname);
+
+ rpi_add_led();
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);
+
+ reg = regulator_get_name("bcm2835_usb");
+ if (IS_ERR(reg))
+ return PTR_ERR(reg);
+
+ regulator_enable(reg);
+
return 0;
+
+free_priv:
+ kfree(priv);
+ return ret;
}
-late_initcall(rpi_devices_init);
+
+static const struct rpi_machine_data rpi_1_ids[] = {
+ {
+ .hw_id = BCM2835_BOARD_REV_A_7,
+ .flags = RPI_OLD_SCHEMA,
+ }, {
+ .hw_id = BCM2835_BOARD_REV_A_8,
+ .flags = RPI_OLD_SCHEMA,
+ }, {
+ .hw_id = BCM2835_BOARD_REV_A_9,
+ .flags = RPI_OLD_SCHEMA,
+ }, {
+ .hw_id = BCM2835_BOARD_REV_A,
+ }, {
+ .hw_id = BCM2835_BOARD_REV_A_PLUS_12,
+ .flags = RPI_OLD_SCHEMA,
+ }, {
+ .hw_id = BCM2835_BOARD_REV_A_PLUS_15,
+ .flags = RPI_OLD_SCHEMA,
+ }, {
+ .hw_id = BCM2835_BOARD_REV_A_PLUS,
+ }, {
+ .hw_id = BCM2835_BOARD_REV_B_I2C1_4,
+ .flags = RPI_OLD_SCHEMA,
+ }, {
+ .hw_id = BCM2835_BOARD_REV_B_I2C1_5,
+ .flags = RPI_OLD_SCHEMA,
+ }, {
+ .hw_id = BCM2835_BOARD_REV_B_I2C1_6,
+ .flags = RPI_OLD_SCHEMA,
+ }, {
+ .hw_id = BCM2835_BOARD_REV_B,
+ }, {
+ .hw_id = BCM2835_BOARD_REV_B_I2C0_2,
+ .flags = RPI_OLD_SCHEMA,
+ }, {
+ .hw_id = BCM2835_BOARD_REV_B_I2C0_3,
+ .flags = RPI_OLD_SCHEMA,
+ }, {
+ .hw_id = BCM2835_BOARD_REV_B_REV2_d,
+ .flags = RPI_OLD_SCHEMA,
+ .init = rpi_b_init,
+ }, {
+ .hw_id = BCM2835_BOARD_REV_B_REV2_e,
+ .flags = RPI_OLD_SCHEMA,
+ .init = rpi_b_init,
+ }, {
+ .hw_id = BCM2835_BOARD_REV_B_REV2_f,
+ .flags = RPI_OLD_SCHEMA,
+ .init = rpi_b_init,
+ }, {
+ .hw_id = BCM2835_BOARD_REV_B_PLUS_10,
+ .flags = RPI_OLD_SCHEMA,
+ .init = rpi_b_plus_init,
+ }, {
+ .hw_id = BCM2835_BOARD_REV_B_PLUS_13,
+ .flags = RPI_OLD_SCHEMA,
+ .init = rpi_b_plus_init,
+ }, {
+ .hw_id = BCM2835_BOARD_REV_B_PLUS,
+ .init = rpi_b_plus_init,
+ }, {
+ .hw_id = BCM2835_BOARD_REV_CM_11,
+ .flags = RPI_OLD_SCHEMA,
+ }, {
+ .hw_id = BCM2835_BOARD_REV_CM_14,
+ .flags = RPI_OLD_SCHEMA,
+ }, {
+ .hw_id = BCM2835_BOARD_REV_CM1,
+ }, {
+ .hw_id = BCM2835_BOARD_REV_ZERO,
+ .init = rpi_0_init,
+ }, {
+ .hw_id = BCM2835_BOARD_REV_ZERO_W,
+ .init = rpi_0_w_init,
+ }, {
+ .hw_id = U8_MAX
+ },
+};
+
+static const struct rpi_machine_data rpi_2_ids[] = {
+ {
+ .hw_id = BCM2836_BOARD_REV_2_B,
+ .init = rpi_b_plus_init,
+ }, {
+ .hw_id = U8_MAX
+ },
+};
+
+static const struct rpi_machine_data rpi_3_ids[] = {
+ {
+ .hw_id = BCM2837B0_BOARD_REV_3A_PLUS,
+ .init = rpi_b_plus_init,
+ }, {
+ .hw_id = BCM2837_BOARD_REV_3_B,
+ .init = rpi_b_init,
+ }, {
+ .hw_id = BCM2837B0_BOARD_REV_3B_PLUS,
+ .init = rpi_b_plus_init,
+ }, {
+ .hw_id = BCM2837_BOARD_REV_CM3,
+ .init = rpi_eth_init,
+ }, {
+ .hw_id = BCM2837B0_BOARD_REV_CM3_PLUS,
+ }, {
+ .hw_id = BCM2837B0_BOARD_REV_ZERO_2,
+ }, {
+ .hw_id = U8_MAX
+ },
+};
+
+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 },
+ { .compatible = "raspberrypi,model-a-plus", .data = rpi_1_ids },
+ { .compatible = "raspberrypi,model-b", .data = rpi_1_ids },
+ /* Raspberry Pi Model B (no P5) */
+ { .compatible = "raspberrypi,model-b-i2c0", .data = rpi_1_ids },
+ { .compatible = "raspberrypi,model-b-rev2", .data = rpi_1_ids },
+ { .compatible = "raspberrypi,model-b-plus", .data = rpi_1_ids },
+ { .compatible = "raspberrypi,compute-module", .data = rpi_1_ids },
+ { .compatible = "raspberrypi,model-zero", .data = rpi_1_ids },
+ { .compatible = "raspberrypi,model-zero-w", .data = rpi_1_ids },
+
+ /* BCM2836 based Boards */
+ { .compatible = "raspberrypi,2-model-b", .data = rpi_2_ids },
+
+ /* BCM2837 based Boards */
+ { .compatible = "raspberrypi,3-model-a-plus", .data = rpi_3_ids },
+ { .compatible = "raspberrypi,3-model-b", .data = rpi_3_ids },
+ { .compatible = "raspberrypi,3-model-b-plus", .data = rpi_3_ids },
+ { .compatible = "raspberrypi,model-zero-2-w", .data = rpi_3_ids },
+ { .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 rpi_board_driver = {
+ .name = "board-rpi",
+ .probe = rpi_devices_probe,
+ .of_compatible = DRV_OF_COMPAT(rpi_of_match),
+};
+late_platform_driver(rpi_board_driver);