diff --git a/Documentation/boards/bcm2835.rst b/Documentation/boards/bcm2835.rst index ea80d58..e9ad1d4 100644 --- a/Documentation/boards/bcm2835.rst +++ b/Documentation/boards/bcm2835.rst @@ -30,5 +30,15 @@ 6. Turn board's power on. +VideoCore firmware creates a device tree based on the entries in ``config.txt``. This file is available to the Barebox environment in the file ``/vc.dtb``. For example, to boot a kernel shipped with Raspbian:: + + bootm -o /vc.dtb /boot/kernel7.img + +VideoCore device tree also contains the kernel command-line that is constructed from ``cmdline.txt`` and other parameters internally determined by the VideoCore firmware. Normally in Barebox this command-line gets overwritten on boot by the Linux bootargs (see :ref:`booting_linux`). + +The original command-line from VideoCore device tree is available to the Barebox environment in the ``vc.bootargs`` global variable. For example, to append it to the Linux bootargs:: + + global linux.bootargs.vc="$global.vc.bootargs" + .. _Raspberry Pi firmware: https://codeload.github.com/raspberrypi/firmware/zip/80e1fbeb78f9df06701d28c0ed3a3060a3f557ef .. _documentation for config.txt: https://www.raspberrypi.org/documentation/configuration/config-txt/ diff --git a/arch/arm/boards/raspberry-pi/lowlevel.c b/arch/arm/boards/raspberry-pi/lowlevel.c index 34c9350..4b64f5d 100644 --- a/arch/arm/boards/raspberry-pi/lowlevel.c +++ b/arch/arm/boards/raspberry-pi/lowlevel.c @@ -3,33 +3,73 @@ #include #include #include +#include + +#include "lowlevel.h" + +static void copy_vc_fdt(void *dest, void *src, unsigned long max_size) +{ + struct fdt_header *oftree_src = src; + struct fdt_header *oftree_dest = dest; + + unsigned long size = be32_to_cpu(oftree_src->totalsize); + if (size > max_size) { + oftree_dest->magic = cpu_to_be32(VIDEOCORE_FDT_ERROR); + /* Save an error code after the magic value for easier + * debugging. We can't print out anything this early */ + oftree_dest->totalsize = cpu_to_be32(ENOMEM); + return; + } + + memmove(dest, src, size); +} + +/* Must be inline since stack isn't setup yet. */ +static inline void start_raspberry_pi(unsigned long memsize, void *fdt, + void *vc_fdt) +{ + void *saved_vc_fdt; + unsigned long membase = BCM2835_SDRAM_BASE; + + /* A pointer to the FDT created by VideoCore was passed to us in r2. We + * reserve some memory just above the region used for Basebox and copy + * this FDT there. We fetch it from there later in rpi_devices_init().*/ + memsize -= VIDEOCORE_FDT_SZ; + + arm_cpu_lowlevel_init(); + + /* Copied from barebox_arm_entry(). We need stack here early + * for normal function calls to work. */ + arm_setup_stack(arm_mem_stack_top(membase, membase + memsize) - 16); + + fdt += get_runtime_offset(); + + saved_vc_fdt = (void *)(membase + memsize); + copy_vc_fdt(saved_vc_fdt, vc_fdt, VIDEOCORE_FDT_SZ); + + barebox_arm_entry(membase, memsize, fdt); +} extern char __dtb_bcm2835_rpi_start[]; ENTRY_FUNCTION(start_raspberry_pi1, r0, r1, r2) { - void *fdt = __dtb_bcm2835_rpi_start + get_runtime_offset(); - - arm_cpu_lowlevel_init(); - - barebox_arm_entry(BCM2835_SDRAM_BASE, SZ_128M, fdt); + start_raspberry_pi(SZ_128M, __dtb_bcm2835_rpi_start, (void *)r2); } extern char __dtb_bcm2836_rpi_2_start[]; ENTRY_FUNCTION(start_raspberry_pi2, r0, r1, r2) { - void *fdt = __dtb_bcm2836_rpi_2_start + get_runtime_offset(); - - arm_cpu_lowlevel_init(); - - barebox_arm_entry(BCM2835_SDRAM_BASE, SZ_512M, fdt); + start_raspberry_pi(SZ_512M, __dtb_bcm2836_rpi_2_start, (void *)r2); } extern char __dtb_bcm2837_rpi_3_start[]; ENTRY_FUNCTION(start_raspberry_pi3, r0, r1, r2) { - void *fdt = __dtb_bcm2837_rpi_3_start + get_runtime_offset(); + start_raspberry_pi(SZ_512M, __dtb_bcm2837_rpi_3_start, (void *)r2); +} - arm_cpu_lowlevel_init(); - - barebox_arm_entry(BCM2835_SDRAM_BASE, SZ_512M, fdt); +extern char __dtb_bcm2837_rpi_cm3_start[]; +ENTRY_FUNCTION(start_raspberry_pi_cm3, r0, r1, r2) +{ + start_raspberry_pi(SZ_512M, __dtb_bcm2837_rpi_cm3_start, (void *)r2); } diff --git a/arch/arm/boards/raspberry-pi/lowlevel.h b/arch/arm/boards/raspberry-pi/lowlevel.h new file mode 100644 index 0000000..9ef9135 --- /dev/null +++ b/arch/arm/boards/raspberry-pi/lowlevel.h @@ -0,0 +1,9 @@ +#ifndef __ARCH_ARM_BOARDS_LOWLEVEL_H__ +#define __ARCH_ARM_BOARDS_LOWLEVEL_H__ + +#include + +#define VIDEOCORE_FDT_SZ SZ_1M +#define VIDEOCORE_FDT_ERROR 0xdeadfeed + +#endif /* __ARCH_ARM_BOARDS_LOWLEVEL_H__ */ diff --git a/arch/arm/boards/raspberry-pi/rpi-common.c b/arch/arm/boards/raspberry-pi/rpi-common.c index b5d16a1..60cea7f 100644 --- a/arch/arm/boards/raspberry-pi/rpi-common.c +++ b/arch/arm/boards/raspberry-pi/rpi-common.c @@ -16,21 +16,28 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include #include +#include #include +#include +#include #include #include +#include #include "rpi.h" +#include "lowlevel.h" struct msg_get_arm_mem { struct bcm2835_mbox_hdr hdr; @@ -314,10 +321,6 @@ } postconsole_initcall(rpi_clock_init); -#define BCM2835_PL011_BASE 0x20201000 -#define BCM2836_PL011_BASE 0x3f201000 -#define BCM2836_MINIUART_BASE 0x3f215040 - static int rpi_console_clock_init(void) { struct clk *clk; @@ -370,12 +373,87 @@ return 0; } +/* 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; + } + + node = of_find_node_by_path_from(root, "/chosen"); + if (!node) { + pr_err("no /chosen node\n"); + ret = -ENOENT; + goto out; + } + + cmdline = of_get_property(node, "bootargs", NULL); + if (!cmdline) { + pr_err("no bootargs property in the /chosen node\n"); + ret = -ENOENT; + goto out; + } + + globalvar_add_simple("vc.bootargs", cmdline); + +out: + if (root) + of_delete_node(root); + + return ret; +} + +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()); + + 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) { + pr_err("there was an error copying fdt in pbl: %d\n", + be32_to_cpu(oftree->totalsize)); + } + return; + } + + size = be32_to_cpu(oftree->totalsize); + 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; + } +} + static int rpi_devices_init(void) { rpi_model_init(); bcm2835_register_fb(); armlinux_set_architecture(MACH_TYPE_BCM2708); rpi_env_init(); + rpi_vc_fdt(); return 0; } late_initcall(rpi_devices_init); diff --git a/arch/arm/configs/rpi_defconfig b/arch/arm/configs/rpi_defconfig index dc5ab1f..f167625 100644 --- a/arch/arm/configs/rpi_defconfig +++ b/arch/arm/configs/rpi_defconfig @@ -71,8 +71,8 @@ CONFIG_LED_TRIGGERS=y CONFIG_WATCHDOG=y CONFIG_WATCHDOG_BCM2835=y -CONFIG_GPIO_BCM283X=y -# CONFIG_PINCTRL is not set +CONFIG_PINCTRL=y +CONFIG_PINCTRL_BCM283X=y CONFIG_REGULATOR=y CONFIG_FS_EXT4=y CONFIG_FS_FAT=y diff --git a/arch/arm/cpu/start.c b/arch/arm/cpu/start.c index 768fa9e..6573c2e 100644 --- a/arch/arm/cpu/start.c +++ b/arch/arm/cpu/start.c @@ -38,6 +38,7 @@ unsigned long arm_stack_top; static unsigned long arm_barebox_size; +static unsigned long arm_endmem; static void *barebox_boarddata; static unsigned long barebox_boarddata_size; @@ -131,6 +132,12 @@ } EXPORT_SYMBOL_GPL(arm_mem_ramoops_get); +unsigned long arm_mem_endmem_get(void) +{ + return arm_endmem; +} +EXPORT_SYMBOL_GPL(arm_mem_endmem_get); + static int barebox_memory_areas_init(void) { if(barebox_boarddata) @@ -163,6 +170,7 @@ pr_debug("memory at 0x%08lx, size 0x%08lx\n", membase, memsize); + arm_endmem = endmem; arm_stack_top = arm_mem_stack_top(membase, endmem); arm_barebox_size = barebox_size; malloc_end = barebox_base; diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 917a1eb..f989df6 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -76,6 +76,7 @@ pbl-dtb-$(CONFIG_MACH_RPI) += bcm2835-rpi.dtb.o pbl-dtb-$(CONFIG_MACH_RPI2) += bcm2836-rpi-2.dtb.o pbl-dtb-$(CONFIG_MACH_RPI3) += bcm2837-rpi-3.dtb.o +pbl-dtb-$(CONFIG_MACH_RPI_CM3) += bcm2837-rpi-cm3.dtb.o pbl-dtb-$(CONFIG_MACH_SABRELITE) += imx6q-sabrelite.dtb.o imx6dl-sabrelite.dtb.o pbl-dtb-$(CONFIG_MACH_SABRESD) += imx6q-sabresd.dtb.o pbl-dtb-$(CONFIG_MACH_FREESCALE_IMX6SX_SABRESDB) += imx6sx-sdb.dtb.o diff --git a/arch/arm/dts/bcm2837-rpi-3.dts b/arch/arm/dts/bcm2837-rpi-3.dts index 194b41c..5188361 100644 --- a/arch/arm/dts/bcm2837-rpi-3.dts +++ b/arch/arm/dts/bcm2837-rpi-3.dts @@ -9,3 +9,12 @@ reg = <0x0 0x0>; }; }; + +&sdhci { + pinctrl-0 = <&emmc_gpio48>; + /delete-node/ wifi@1; +}; + +&sdhost { + status = "disabled"; +}; diff --git a/arch/arm/dts/bcm2837-rpi-cm3.dts b/arch/arm/dts/bcm2837-rpi-cm3.dts new file mode 100644 index 0000000..cfbffe1 --- /dev/null +++ b/arch/arm/dts/bcm2837-rpi-cm3.dts @@ -0,0 +1,18 @@ +#include + +/ { + chosen { + stdout-path = &uart0; + }; + + memory { + reg = <0x0 0x0>; + }; +}; + +&sdhci { + pinctrl-0 = <&emmc_gpio48>; + no-sd; + non-removable; + status = "okay"; +}; diff --git a/arch/arm/include/asm/barebox-arm.h b/arch/arm/include/asm/barebox-arm.h index e065b47..a11d349 100644 --- a/arch/arm/include/asm/barebox-arm.h +++ b/arch/arm/include/asm/barebox-arm.h @@ -86,6 +86,7 @@ u32 barebox_arm_machine(void); unsigned long arm_mem_ramoops_get(void); +unsigned long arm_mem_endmem_get(void); struct barebox_arm_boarddata_compressed_dtb { #define BAREBOX_ARM_BOARDDATA_COMPRESSED_DTB_MAGIC 0x7b66bcbd diff --git a/arch/arm/include/asm/debug_ll_pl011.h b/arch/arm/include/asm/debug_ll_pl011.h deleted file mode 100644 index db015a3..0000000 --- a/arch/arm/include/asm/debug_ll_pl011.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef __INCLUDE_ARM_ASM_DEBUG_LL_PL011_H__ -#define __INCLUDE_ARM_ASM_DEBUG_LL_PL011_H__ - -#ifndef DEBUG_LL_UART_ADDR -#error DEBUG_LL_UART_ADDR is undefined! -#endif - -#include -#include - -static inline void PUTC_LL(char c) -{ - /* Wait until there is space in the FIFO */ - while (readl(DEBUG_LL_UART_ADDR + UART01x_FR) & UART01x_FR_TXFF) - ; - - /* Send the character */ - writel(c, DEBUG_LL_UART_ADDR + UART01x_DR); - - /* Wait to make sure it hits the line, in case we die too soon. */ - while (readl(DEBUG_LL_UART_ADDR + UART01x_FR) & UART01x_FR_TXFF) - ; -} - -#endif /* __INCLUDE_ARM_ASM_DEBUG_LL_PL011_H__ */ diff --git a/arch/arm/mach-bcm283x/Kconfig b/arch/arm/mach-bcm283x/Kconfig index af2f88c..9d6a7b2 100644 --- a/arch/arm/mach-bcm283x/Kconfig +++ b/arch/arm/mach-bcm283x/Kconfig @@ -25,26 +25,12 @@ select MACH_RPI_COMMON select ARM_SECURE_MONITOR +config MACH_RPI_CM3 + bool "RaspberryPi Compute Module 3 (BCM2837/CORTEX-A53)" + select CPU_V7 + select MACH_RPI_COMMON + select ARM_SECURE_MONITOR + endmenu -config MACH_RPI_DEBUG_UART_BASE - hex - default 0x20201000 if MACH_RPI_DEBUG_UART_RPI - default 0x3f201000 if MACH_RPI_DEBUG_UART_RPI2 - -if DEBUG_LL - -choice - prompt "Lowlevel debug UART" - -config MACH_RPI_DEBUG_UART_RPI - bool "use RaspberryPi 1 compatible base" - -config MACH_RPI_DEBUG_UART_RPI2 - bool "use RaspberryPi 2 and 3 compatible base" - -endchoice - -endif - endif diff --git a/arch/arm/mach-bcm283x/include/mach/debug_ll.h b/arch/arm/mach-bcm283x/include/mach/debug_ll.h index a625a8b..99c59d0 100644 --- a/arch/arm/mach-bcm283x/include/mach/debug_ll.h +++ b/arch/arm/mach-bcm283x/include/mach/debug_ll.h @@ -20,12 +20,53 @@ #include -#ifndef CONFIG_MACH_RPI_DEBUG_UART_BASE -#define CONFIG_MACH_RPI_DEBUG_UART_BASE 0 +#ifdef CONFIG_DEBUG_RPI1_UART + +static inline void debug_ll_init(void) +{ + /* Configured by ROM */ +} + +#define DEBUG_LL_UART_ADDR BCM2835_PL011_BASE +#include + +#elif defined CONFIG_DEBUG_RPI2_3_UART + +static inline void debug_ll_init(void) +{ + /* Configured by ROM */ +} + +#define DEBUG_LL_UART_ADDR BCM2836_PL011_BASE +#include + +#elif defined CONFIG_DEBUG_RPI3_MINI_UART + +static inline uint8_t debug_ll_read_reg(int reg) +{ + return readb(BCM2836_MINIUART_BASE + (reg << 2)); +} + +static inline void debug_ll_write_reg(int reg, uint8_t val) +{ + writeb(val, BCM2836_MINIUART_BASE + (reg << 2)); +} + +#define BCM2836_AUX_CLOCK_ENB 0x3f215004 /* BCM2835 AUX Clock enable register */ +#define BCM2836_AUX_CLOCK_EN_UART BIT(0) /* Bit 0 enables the Miniuart */ + +#include + +static inline void debug_ll_init(void) +{ + uint16_t divisor; + + writeb(BCM2836_AUX_CLOCK_EN_UART, BCM2836_AUX_CLOCK_ENB); + + divisor = debug_ll_ns16550_calc_divisor(250000000 * 2); + debug_ll_ns16550_init(divisor); +} + #endif -#define DEBUG_LL_UART_ADDR CONFIG_MACH_RPI_DEBUG_UART_BASE - -#include - #endif /* __MACH_BCM2835_DEBUG_LL_H__ */ diff --git a/arch/arm/mach-bcm283x/include/mach/platform.h b/arch/arm/mach-bcm283x/include/mach/platform.h index 80b529a..d8561c1 100644 --- a/arch/arm/mach-bcm283x/include/mach/platform.h +++ b/arch/arm/mach-bcm283x/include/mach/platform.h @@ -30,6 +30,10 @@ #define BCM2835_CACHELINE_SIZE 64 +#define BCM2835_PL011_BASE 0x20201000 +#define BCM2836_PL011_BASE 0x3f201000 +#define BCM2836_MINIUART_BASE 0x3f215040 + #endif /* END */ diff --git a/arch/arm/mach-highbank/include/mach/debug_ll.h b/arch/arm/mach-highbank/include/mach/debug_ll.h index 1820eb1..5d0fae8 100644 --- a/arch/arm/mach-highbank/include/mach/debug_ll.h +++ b/arch/arm/mach-highbank/include/mach/debug_ll.h @@ -9,6 +9,6 @@ #define DEBUG_LL_UART_ADDR 0xfff36000 -#include +#include #endif diff --git a/arch/arm/mach-qemu/include/mach/debug_ll.h b/arch/arm/mach-qemu/include/mach/debug_ll.h index 89b0692..d59f68e 100644 --- a/arch/arm/mach-qemu/include/mach/debug_ll.h +++ b/arch/arm/mach-qemu/include/mach/debug_ll.h @@ -19,6 +19,6 @@ #define DEBUG_LL_UART_ADDR DEBUG_LL_PHYS_BASE_RS1 #endif -#include +#include #endif diff --git a/arch/arm/mach-versatile/include/mach/debug_ll.h b/arch/arm/mach-versatile/include/mach/debug_ll.h index e6ee877..073402c 100644 --- a/arch/arm/mach-versatile/include/mach/debug_ll.h +++ b/arch/arm/mach-versatile/include/mach/debug_ll.h @@ -18,6 +18,6 @@ #define DEBUG_LL_UART_ADDR 0x101F1000 -#include +#include #endif diff --git a/arch/arm/mach-vexpress/include/mach/debug_ll.h b/arch/arm/mach-vexpress/include/mach/debug_ll.h index 89b0692..d59f68e 100644 --- a/arch/arm/mach-vexpress/include/mach/debug_ll.h +++ b/arch/arm/mach-vexpress/include/mach/debug_ll.h @@ -19,6 +19,6 @@ #define DEBUG_LL_UART_ADDR DEBUG_LL_PHYS_BASE_RS1 #endif -#include +#include #endif diff --git a/common/Kconfig b/common/Kconfig index 53052c9..5abe488 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -1159,7 +1159,26 @@ Say Y here if you want kernel low-level debugging support on SOCFPGA(Arria 10) based platforms. +config DEBUG_RPI1_UART + bool "RaspberryPi 1 PL011 UART" + depends on ARCH_BCM283X + help + Say Y here if you want low-level debugging support on + RaspberryPi 1 boards. +config DEBUG_RPI2_3_UART + bool "RaspberryPi 2/3 PL011 UART" + depends on ARCH_BCM283X + help + Say Y here if you want low-level debugging support on + RaspberryPi 2 and 3 boards. + +config DEBUG_RPI3_MINI_UART + bool "RaspberryPi 3 mini UART" + depends on ARCH_BCM283X + help + Say Y here if you want low-level debugging support on + RaspberryPi 3 board mini UART. endchoice config DEBUG_IMX_UART_PORT diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index ed93e86..c535904 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -21,10 +21,6 @@ shift registers. This driver can be used to provide access to more gpio outputs. -config GPIO_BCM283X - bool "GPIO support for BCM283X" - depends on ARCH_BCM283X - config GPIO_CLPS711X bool "GPIO support for CLPS711X" depends on ARCH_CLPS711X diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index f5ed876..52280f0 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -2,7 +2,6 @@ obj-$(CONFIG_GPIO_74164) += gpio-74164.o obj-$(CONFIG_MACH_MIPS_ATH79) += gpio-ath79.o -obj-$(CONFIG_GPIO_BCM283X) += gpio-bcm2835.o obj-$(CONFIG_GPIO_DAVINCI) += gpio-davinci.o obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o obj-$(CONFIG_GPIO_DIGIC) += gpio-digic.o diff --git a/drivers/gpio/gpio-bcm2835.c b/drivers/gpio/gpio-bcm2835.c deleted file mode 100644 index 1802ab7..0000000 --- a/drivers/gpio/gpio-bcm2835.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Author: Carlo Caione - * - * Based on linux/arch/arm/mach-bcm2708/bcm2708_gpio.c - * - * 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. - * - */ - -#include -#include -#include -#include -#include -#include - -#define GPIOFSEL(x) (0x00+(x)*4) -#define GPIOSET(x) (0x1c+(x)*4) -#define GPIOCLR(x) (0x28+(x)*4) -#define GPIOLEV(x) (0x34+(x)*4) -#define GPIOEDS(x) (0x40+(x)*4) -#define GPIOREN(x) (0x4c+(x)*4) -#define GPIOFEN(x) (0x58+(x)*4) -#define GPIOHEN(x) (0x64+(x)*4) -#define GPIOLEN(x) (0x70+(x)*4) -#define GPIOAREN(x) (0x7c+(x)*4) -#define GPIOAFEN(x) (0x88+(x)*4) -#define GPIOUD(x) (0x94+(x)*4) -#define GPIOUDCLK(x) (0x98+(x)*4) - -enum { - GPIO_FSEL_INPUT, GPIO_FSEL_OUTPUT, - GPIO_FSEL_ALT5, GPIO_FSEL_ALT_4, - GPIO_FSEL_ALT0, GPIO_FSEL_ALT1, - GPIO_FSEL_ALT2, GPIO_FSEL_ALT3, -}; - -struct bcm2835_gpio_chip { - void __iomem *base; - struct gpio_chip chip; -}; - -static int bcm2835_set_function(struct gpio_chip *chip, unsigned gpio, int function) -{ - struct bcm2835_gpio_chip *bcmgpio = container_of(chip, struct bcm2835_gpio_chip, chip); - void __iomem *base = bcmgpio->base; - unsigned gpiodir; - unsigned gpio_bank = gpio / 10; - unsigned gpio_field_offset = (gpio - 10 * gpio_bank) * 3; - - gpiodir = readl(base + GPIOFSEL(gpio_bank)); - gpiodir &= ~(7 << gpio_field_offset); - gpiodir |= function << gpio_field_offset; - writel(gpiodir, base + GPIOFSEL(gpio_bank)); - gpiodir = readl(base + GPIOFSEL(gpio_bank)); - - return 0; -} - -static void bcm2835_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value) -{ - struct bcm2835_gpio_chip *bcmgpio = container_of(chip, struct bcm2835_gpio_chip, chip); - void __iomem *base = bcmgpio->base; - unsigned gpio_bank = gpio / 32; - unsigned gpio_field_offset = gpio % 32; - - if (value) - writel(1 << gpio_field_offset, base + GPIOSET(gpio_bank)); - else - writel(1 << gpio_field_offset, base + GPIOCLR(gpio_bank)); -} - -static int bcm2835_gpio_get_value(struct gpio_chip *chip, unsigned gpio) -{ - struct bcm2835_gpio_chip *bcmgpio = container_of(chip, struct bcm2835_gpio_chip, chip); - void __iomem *base = bcmgpio->base; - unsigned gpio_bank = gpio / 32; - unsigned gpio_field_offset = gpio % 32; - unsigned lev; - - lev = readl(base + GPIOLEV(gpio_bank)); - return 0x1 & (lev >> gpio_field_offset); -} - -static int bcm2835_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) -{ - return bcm2835_set_function(chip, gpio, GPIO_FSEL_INPUT); -} - -static int bcm2835_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value) -{ - bcm2835_set_function(chip, gpio, GPIO_FSEL_OUTPUT); - bcm2835_gpio_set_value(chip, gpio, value); - - return 0; -} - -static struct gpio_ops bcm2835_gpio_ops = { - .direction_input = bcm2835_gpio_direction_input, - .direction_output = bcm2835_gpio_direction_output, - .get = bcm2835_gpio_get_value, - .set = bcm2835_gpio_set_value, -}; - -static int bcm2835_gpio_probe(struct device_d *dev) -{ - struct resource *iores; - struct bcm2835_gpio_chip *bcmgpio; - int ret; - - bcmgpio = xzalloc(sizeof(*bcmgpio)); - iores = dev_request_mem_resource(dev, 0); - if (IS_ERR(iores)) - return PTR_ERR(iores); - bcmgpio->base = IOMEM(iores->start); - bcmgpio->chip.ops = &bcm2835_gpio_ops; - bcmgpio->chip.base = 0; - bcmgpio->chip.ngpio = 54; - bcmgpio->chip.dev = dev; - - ret = gpiochip_add(&bcmgpio->chip); - if (ret) { - dev_err(dev, "couldn't add gpiochip, ret = %d\n", ret); - goto err; - } - dev_info(dev, "probed gpiochip%d with base %d\n", dev->id, bcmgpio->chip.base); - - return 0; - -err: - kfree(bcmgpio); - - return ret; -} - -static __maybe_unused struct of_device_id bcm2835_gpio_dt_ids[] = { - { - .compatible = "brcm,bcm2835-gpio", - }, { - /* sentinel */ - } -}; - -static struct driver_d bcm2835_gpio_driver = { - .name = "bcm2835-gpio", - .probe = bcm2835_gpio_probe, - .of_compatible = DRV_OF_COMPAT(bcm2835_gpio_dt_ids), -}; - -static int bcm2835_gpio_add(void) -{ - return platform_driver_register(&bcm2835_gpio_driver); -} -coredevice_initcall(bcm2835_gpio_add); diff --git a/drivers/mci/mci-bcm2835.c b/drivers/mci/mci-bcm2835.c index 9438e66..2ed1251 100644 --- a/drivers/mci/mci-bcm2835.c +++ b/drivers/mci/mci-bcm2835.c @@ -506,6 +506,9 @@ host->mci.hw_dev = hw_dev; host->hw_dev = hw_dev; host->max_clock = clk_get_rate(clk); + + mci_of_parse(&host->mci); + iores = dev_request_mem_resource(hw_dev, 0); if (IS_ERR(iores)) { dev_err(host->hw_dev, "Failed request mem region, aborting...\n"); @@ -561,4 +564,4 @@ { return platform_driver_register(&bcm2835_mci_driver); } -coredevice_initcall(bcm2835_mci_add); +device_initcall(bcm2835_mci_add); diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 12fff4f..45c3b35 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -1,3 +1,5 @@ +menu "Pin controllers" + config PINCTRL bool "Pin controller core support" default y if OFDEVICE @@ -15,6 +17,12 @@ help The pinmux controller found on AT91 SoCs. +config PINCTRL_BCM283X + bool "GPIO and pinmux support for BCM283X" + depends on ARCH_BCM283X + help + The pinmux controller on BCM2835 + config PINCTRL_IMX_IOMUX_V1 bool help @@ -83,3 +91,5 @@ help Pinmux controller found on Vybrid VF610 family of SoCs endif + +endmenu diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 9450dbb..35b2d47 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_PINCTRL) += pinctrl.o obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o +obj-$(CONFIG_PINCTRL_BCM283X) += pinctrl-bcm2835.o obj-$(CONFIG_PINCTRL_IMX_IOMUX_V1) += imx-iomux-v1.o obj-$(CONFIG_PINCTRL_IMX_IOMUX_V2) += imx-iomux-v2.o obj-$(CONFIG_PINCTRL_IMX_IOMUX_V3) += imx-iomux-v3.o diff --git a/drivers/pinctrl/pinctrl-bcm2835.c b/drivers/pinctrl/pinctrl-bcm2835.c new file mode 100644 index 0000000..5fd5740 --- /dev/null +++ b/drivers/pinctrl/pinctrl-bcm2835.c @@ -0,0 +1,212 @@ +/* + * Author: Carlo Caione + * + * GPIO code based on linux/arch/arm/mach-bcm2708/bcm2708_gpio.c + * + * pinctrl part added by Tomaz Solc + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define GPIOFSEL(x) (0x00+(x)*4) +#define GPIOSET(x) (0x1c+(x)*4) +#define GPIOCLR(x) (0x28+(x)*4) +#define GPIOLEV(x) (0x34+(x)*4) +#define GPIOEDS(x) (0x40+(x)*4) +#define GPIOREN(x) (0x4c+(x)*4) +#define GPIOFEN(x) (0x58+(x)*4) +#define GPIOHEN(x) (0x64+(x)*4) +#define GPIOLEN(x) (0x70+(x)*4) +#define GPIOAREN(x) (0x7c+(x)*4) +#define GPIOAFEN(x) (0x88+(x)*4) +#define GPIOUD(x) (0x94+(x)*4) +#define GPIOUDCLK(x) (0x98+(x)*4) + +enum { + GPIO_FSEL_INPUT, GPIO_FSEL_OUTPUT, + GPIO_FSEL_ALT5, GPIO_FSEL_ALT_4, + GPIO_FSEL_ALT0, GPIO_FSEL_ALT1, + GPIO_FSEL_ALT2, GPIO_FSEL_ALT3, +}; + +struct bcm2835_gpio_chip { + void __iomem *base; + struct gpio_chip chip; + struct pinctrl_device pctl; +}; + +static int bcm2835_set_function(struct gpio_chip *chip, unsigned gpio, int function) +{ + struct bcm2835_gpio_chip *bcmgpio = container_of(chip, struct bcm2835_gpio_chip, chip); + void __iomem *base = bcmgpio->base; + unsigned gpiodir; + unsigned gpio_bank = gpio / 10; + unsigned gpio_field_offset = (gpio - 10 * gpio_bank) * 3; + + gpiodir = readl(base + GPIOFSEL(gpio_bank)); + gpiodir &= ~(7 << gpio_field_offset); + gpiodir |= function << gpio_field_offset; + writel(gpiodir, base + GPIOFSEL(gpio_bank)); + gpiodir = readl(base + GPIOFSEL(gpio_bank)); + + return 0; +} + +static void bcm2835_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value) +{ + struct bcm2835_gpio_chip *bcmgpio = container_of(chip, struct bcm2835_gpio_chip, chip); + void __iomem *base = bcmgpio->base; + unsigned gpio_bank = gpio / 32; + unsigned gpio_field_offset = gpio % 32; + + if (value) + writel(1 << gpio_field_offset, base + GPIOSET(gpio_bank)); + else + writel(1 << gpio_field_offset, base + GPIOCLR(gpio_bank)); +} + +static int bcm2835_gpio_get_value(struct gpio_chip *chip, unsigned gpio) +{ + struct bcm2835_gpio_chip *bcmgpio = container_of(chip, struct bcm2835_gpio_chip, chip); + void __iomem *base = bcmgpio->base; + unsigned gpio_bank = gpio / 32; + unsigned gpio_field_offset = gpio % 32; + unsigned lev; + + lev = readl(base + GPIOLEV(gpio_bank)); + return 0x1 & (lev >> gpio_field_offset); +} + +static int bcm2835_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) +{ + return bcm2835_set_function(chip, gpio, GPIO_FSEL_INPUT); +} + +static int bcm2835_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value) +{ + bcm2835_set_function(chip, gpio, GPIO_FSEL_OUTPUT); + bcm2835_gpio_set_value(chip, gpio, value); + + return 0; +} + +static struct gpio_ops bcm2835_gpio_ops = { + .direction_input = bcm2835_gpio_direction_input, + .direction_output = bcm2835_gpio_direction_output, + .get = bcm2835_gpio_get_value, + .set = bcm2835_gpio_set_value, +}; + +static int bcm2835_pinctrl_set_state(struct pinctrl_device *pdev, struct device_node *np) +{ + const __be32 *list; + u32 function; + int i, size; + + list = of_get_property(np, "brcm,pins", &size); + if (!list) { + return -EINVAL; + } + + size /= sizeof(*list); + + if (of_property_read_u32(np, "brcm,function", &function)) { + return -EINVAL; + } + + for (i = 0; i < size; i++) { + int pin = be32_to_cpu(list[i]); + struct bcm2835_gpio_chip *bcmgpio = container_of(pdev, struct bcm2835_gpio_chip, pctl); + + dev_dbg(pdev->dev, "set_state pin %d to function %d\n", pin, function); + + bcm2835_set_function(&bcmgpio->chip, pin, function); + } + + return 0; +} + +static struct pinctrl_ops bcm2835_pinctrl_ops = { + .set_state = bcm2835_pinctrl_set_state, +}; + +static int bcm2835_gpio_probe(struct device_d *dev) +{ + struct resource *iores; + struct bcm2835_gpio_chip *bcmgpio; + int ret; + + bcmgpio = xzalloc(sizeof(*bcmgpio)); + iores = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores)) + return PTR_ERR(iores); + bcmgpio->base = IOMEM(iores->start); + bcmgpio->chip.ops = &bcm2835_gpio_ops; + bcmgpio->chip.base = 0; + bcmgpio->chip.ngpio = 54; + bcmgpio->chip.dev = dev; + bcmgpio->pctl.ops = &bcm2835_pinctrl_ops; + bcmgpio->pctl.dev = dev; + + ret = gpiochip_add(&bcmgpio->chip); + if (ret) { + dev_err(dev, "couldn't add gpiochip, ret = %d\n", ret); + goto err; + } + + dev_info(dev, "probed gpiochip%d with base %d\n", dev->id, bcmgpio->chip.base); + + if (IS_ENABLED(CONFIG_PINCTRL)) { + ret = pinctrl_register(&bcmgpio->pctl); + if (ret) { + dev_err(dev, "couldn't add pinctrl, ret = %d\n", ret); + // don't free bcmgpio, since it's already used by gpiochip. + } else { + dev_dbg(dev, "bcm283x pinctrl registered\n"); + } + } + + return 0; + +err: + kfree(bcmgpio); + + return ret; +} + +static __maybe_unused struct of_device_id bcm2835_gpio_dt_ids[] = { + { + .compatible = "brcm,bcm2835-gpio", + }, { + /* sentinel */ + } +}; + +static struct driver_d bcm2835_gpio_driver = { + .name = "bcm2835-gpio", + .probe = bcm2835_gpio_probe, + .of_compatible = DRV_OF_COMPAT(bcm2835_gpio_dt_ids), +}; + +static int bcm2835_gpio_add(void) +{ + return platform_driver_register(&bcm2835_gpio_driver); +} +coredevice_initcall(bcm2835_gpio_add); diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c index d0c51ed..781626f 100644 --- a/drivers/watchdog/bcm2835_wdt.c +++ b/drivers/watchdog/bcm2835_wdt.c @@ -45,6 +45,10 @@ #define SECS_TO_WDOG_TICKS(x) ((x) << 16) +/* Largest value where SECS_TO_WDOG_TICKS doesn't overflow 20 bits + * (PM_WDOG_TIME_SET) */ +#define WDOG_SECS_MAX 15 + struct bcm2835_wd { struct watchdog wd; void __iomem *base; @@ -101,6 +105,7 @@ } priv->base = IOMEM(iores->start); priv->wd.set_timeout = bcm2835_wd_set_timeout; + priv->wd.timeout_max = WDOG_SECS_MAX; priv->wd.hwdev = dev; priv->dev = dev; diff --git a/images/Makefile.bcm283x b/images/Makefile.bcm283x index 9199f15..3fd2c3d 100644 --- a/images/Makefile.bcm283x +++ b/images/Makefile.bcm283x @@ -12,4 +12,8 @@ pblb-$(CONFIG_MACH_RPI3) += start_raspberry_pi3 FILE_barebox-raspberry-pi-3.img = start_raspberry_pi3.pblb -image-$(CONFIG_MACH_RPI3) += barebox-raspberry-pi-3.img \ No newline at end of file +image-$(CONFIG_MACH_RPI3) += barebox-raspberry-pi-3.img + +pblb-$(CONFIG_MACH_RPI_CM3) += start_raspberry_pi_cm3 +FILE_barebox-raspberry-pi-cm3.img = start_raspberry_pi_cm3.pblb +image-$(CONFIG_MACH_RPI_CM3) += barebox-raspberry-pi-cm3.img \ No newline at end of file diff --git a/include/debug_ll/ns16550.h b/include/debug_ll/ns16550.h new file mode 100644 index 0000000..7e4dbeb --- /dev/null +++ b/include/debug_ll/ns16550.h @@ -0,0 +1,56 @@ +#ifndef __DEBUG_LL_NS16550_H +#define __DEBUG_LL_NS16550_H + +/* + * Early debugging functions for the NS16550 + * This file needs register access functions declared as: + * + * uint8_t debug_ll_read_reg(int reg); + * void debug_ll_write_reg(int reg, uint8_t val); + */ +#define NS16550_THR 0x0 +#define NS16550_RBR 0x0 +#define NS16550_DLL 0x0 +#define NS16550_IER 0x1 +#define NS16550_DLM 0x1 +#define NS16550_FCR 0x2 +#define NS16550_LCR 0x3 +#define NS16550_MCR 0x4 +#define NS16550_LSR 0x5 + +#define NS16550_LCR_VAL 0x3 /* 8 data, 1 stop, no parity */ +#define NS16550_MCR_VAL 0x3 /* RTS/DTR */ +#define NS16550_FCR_VAL 0x7 /* Clear & enable FIFOs */ + +#define NS16550_LSR_DR 0x01 /* UART received data present */ +#define NS16550_LSR_THRE 0x20 /* Xmit holding register empty */ + +#define NS16550_LCR_BKSE 0x80 /* Bank select enable */ + +static inline void PUTC_LL(char ch) +{ + while (!(debug_ll_read_reg(NS16550_LSR) & NS16550_LSR_THRE)) + ; + + debug_ll_write_reg(NS16550_THR, ch); +} + +static inline uint16_t debug_ll_ns16550_calc_divisor(unsigned long clk) +{ + return clk / (115200 * 16); +} + +static inline void debug_ll_ns16550_init(uint16_t divisor) +{ + debug_ll_write_reg(NS16550_LCR, 0x0); /* select ier reg */ + debug_ll_write_reg(0x00, NS16550_IER); + + debug_ll_write_reg(NS16550_LCR, NS16550_LCR_BKSE); + debug_ll_write_reg(NS16550_DLL, divisor & 0xff); + debug_ll_write_reg(NS16550_DLM, (divisor >> 8) & 0xff); + debug_ll_write_reg(NS16550_LCR, NS16550_LCR_VAL); + debug_ll_write_reg(NS16550_MCR, NS16550_MCR_VAL); + debug_ll_write_reg(NS16550_FCR, NS16550_FCR_VAL); +} + +#endif diff --git a/include/debug_ll/pl011.h b/include/debug_ll/pl011.h new file mode 100644 index 0000000..db015a3 --- /dev/null +++ b/include/debug_ll/pl011.h @@ -0,0 +1,25 @@ +#ifndef __INCLUDE_ARM_ASM_DEBUG_LL_PL011_H__ +#define __INCLUDE_ARM_ASM_DEBUG_LL_PL011_H__ + +#ifndef DEBUG_LL_UART_ADDR +#error DEBUG_LL_UART_ADDR is undefined! +#endif + +#include +#include + +static inline void PUTC_LL(char c) +{ + /* Wait until there is space in the FIFO */ + while (readl(DEBUG_LL_UART_ADDR + UART01x_FR) & UART01x_FR_TXFF) + ; + + /* Send the character */ + writel(c, DEBUG_LL_UART_ADDR + UART01x_DR); + + /* Wait to make sure it hits the line, in case we die too soon. */ + while (readl(DEBUG_LL_UART_ADDR + UART01x_FR) & UART01x_FR_TXFF) + ; +} + +#endif /* __INCLUDE_ARM_ASM_DEBUG_LL_PL011_H__ */