diff options
Diffstat (limited to 'arch/arm/boards/raspberry-pi/rpi-common.c')
-rw-r--r-- | arch/arm/boards/raspberry-pi/rpi-common.c | 891 |
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); |