[U-Boot] [PATCH 0/1] board: arm: Add support for Broadcom BCM7445D0

Hi,
This patch adds support for loading U-Boot on the Broadcom 7445D0 SoC, as a third stage bootloader loaded by Broadcom's BOLT bootloader.
While this is only a partial port, it does enable some of U-Boot's flexibility on this SoC, functionality beyond what BOLT provides. Specifically, it brings:
- ext4 file system traversal
- support for loading FIT images
- advanced scripting
- support for FIT-provided DTBs instead of relying on the BOLT-provided DTB
My team at Cisco is using a customized version of this port in production. The same approach may work on other BCM7xxx boards, with some configuration adjustments and memory layout experimentation.
Stefan Roese reviewed (off-list) some early revisions of these changes. This patch is my attempt to rebase on the current U-Boot master branch. I'm submitting it in case there is interest in including this port in upstream U-Boot.
Thomas
Thomas Fitzsimmons (1): board: arm: Add support for Broadcom BCM7445D0
arch/arm/Kconfig | 12 + arch/arm/cpu/armv7/Makefile | 1 + arch/arm/cpu/armv7/bcm7445d0/Makefile | 11 + arch/arm/cpu/armv7/bcm7445d0/lowlevel_init.S | 24 ++ arch/arm/lib/crt0.S | 2 + arch/arm/mach-bcm7445d0/include/mach/gpio.h | 12 + arch/arm/mach-bcm7445d0/include/mach/hardware.h | 12 + arch/arm/mach-bcm7445d0/include/mach/sdhci.h | 15 + board/broadcom/bcm7445d0/Kconfig | 132 ++++++++ board/broadcom/bcm7445d0/Makefile | 11 + board/broadcom/bcm7445d0/bcm7445d0.c | 147 ++++++++ common/fdt_support.c | 9 +- common/image-fit.c | 2 + configs/bcm7445d0_defconfig | 21 ++ drivers/mmc/Makefile | 1 + drivers/mmc/bcmstb_sdhci.c | 59 ++++ drivers/spi/Kconfig | 7 + drivers/spi/Makefile | 1 + drivers/spi/bcmstb_spi.c | 428 ++++++++++++++++++++++++ dts/Kconfig | 6 + include/configs/bcm7445d0.h | 227 +++++++++++++ include/configs/bcmstb.h | 57 ++++ lib/fdtdec.c | 8 + 23 files changed, 1204 insertions(+), 1 deletion(-) create mode 100644 arch/arm/cpu/armv7/bcm7445d0/Makefile create mode 100644 arch/arm/cpu/armv7/bcm7445d0/lowlevel_init.S create mode 100644 arch/arm/mach-bcm7445d0/include/mach/gpio.h create mode 100644 arch/arm/mach-bcm7445d0/include/mach/hardware.h create mode 100644 arch/arm/mach-bcm7445d0/include/mach/sdhci.h create mode 100644 board/broadcom/bcm7445d0/Kconfig create mode 100644 board/broadcom/bcm7445d0/Makefile create mode 100644 board/broadcom/bcm7445d0/bcm7445d0.c create mode 100644 configs/bcm7445d0_defconfig create mode 100644 drivers/mmc/bcmstb_sdhci.c create mode 100644 drivers/spi/bcmstb_spi.c create mode 100644 include/configs/bcm7445d0.h create mode 100644 include/configs/bcmstb.h

Add support for loading U-Boot on the Broadcom 7445D0 SoC. This port assumes Broadcom's BOLT bootloader is acting as the second stage bootloader, and U-Boot is acting as the third stage bootloader, loaded as an ELF program by BOLT.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Stefan Roese sr@denx.de --- arch/arm/Kconfig | 12 + arch/arm/cpu/armv7/Makefile | 1 + arch/arm/cpu/armv7/bcm7445d0/Makefile | 11 + arch/arm/cpu/armv7/bcm7445d0/lowlevel_init.S | 24 ++ arch/arm/lib/crt0.S | 2 + arch/arm/mach-bcm7445d0/include/mach/gpio.h | 12 + arch/arm/mach-bcm7445d0/include/mach/hardware.h | 12 + arch/arm/mach-bcm7445d0/include/mach/sdhci.h | 15 + board/broadcom/bcm7445d0/Kconfig | 132 ++++++++ board/broadcom/bcm7445d0/Makefile | 11 + board/broadcom/bcm7445d0/bcm7445d0.c | 147 ++++++++ common/fdt_support.c | 9 +- common/image-fit.c | 2 + configs/bcm7445d0_defconfig | 21 ++ drivers/mmc/Makefile | 1 + drivers/mmc/bcmstb_sdhci.c | 59 ++++ drivers/spi/Kconfig | 7 + drivers/spi/Makefile | 1 + drivers/spi/bcmstb_spi.c | 428 ++++++++++++++++++++++++ dts/Kconfig | 6 + include/configs/bcm7445d0.h | 227 +++++++++++++ include/configs/bcmstb.h | 57 ++++ lib/fdtdec.c | 8 + 23 files changed, 1204 insertions(+), 1 deletion(-) create mode 100644 arch/arm/cpu/armv7/bcm7445d0/Makefile create mode 100644 arch/arm/cpu/armv7/bcm7445d0/lowlevel_init.S create mode 100644 arch/arm/mach-bcm7445d0/include/mach/gpio.h create mode 100644 arch/arm/mach-bcm7445d0/include/mach/hardware.h create mode 100644 arch/arm/mach-bcm7445d0/include/mach/sdhci.h create mode 100644 board/broadcom/bcm7445d0/Kconfig create mode 100644 board/broadcom/bcm7445d0/Makefile create mode 100644 board/broadcom/bcm7445d0/bcm7445d0.c create mode 100644 configs/bcm7445d0_defconfig create mode 100644 drivers/mmc/bcmstb_sdhci.c create mode 100644 drivers/spi/bcmstb_spi.c create mode 100644 include/configs/bcm7445d0.h create mode 100644 include/configs/bcmstb.h
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9bd70f4..b2df30a 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -498,6 +498,17 @@ config TARGET_VEXPRESS_CA15_TC2 select CPU_V7_HAS_VIRT select PL011_SERIAL
+config TARGET_BCM7445D0 + bool "Broadcom 7445D0 TSBL" + select CPU_V7 + select SUPPORT_SPL + help + Support for the Broadcom 7445D0 SoC. This port assumes Bolt + is acting as the second stage bootloader, and U-Boot is + acting as the third stage bootloader (TSBL), loaded by Bolt. + This port may work on other BCM7xxx boards with + configuration changes. + config TARGET_VEXPRESS_CA5X2 bool "Support vexpress_ca5x2" select CPU_V7 @@ -1320,6 +1331,7 @@ source "board/armltd/vexpress/Kconfig" source "board/armltd/vexpress64/Kconfig" source "board/broadcom/bcm23550_w1d/Kconfig" source "board/broadcom/bcm28155_ap/Kconfig" +source "board/broadcom/bcm7445d0/Kconfig" source "board/broadcom/bcmcygnus/Kconfig" source "board/broadcom/bcmnsp/Kconfig" source "board/broadcom/bcmns2/Kconfig" diff --git a/arch/arm/cpu/armv7/Makefile b/arch/arm/cpu/armv7/Makefile index b14ee54..7183d4d 100644 --- a/arch/arm/cpu/armv7/Makefile +++ b/arch/arm/cpu/armv7/Makefile @@ -30,6 +30,7 @@ endif
obj-$(if $(filter bcm235xx,$(SOC)),y) += bcm235xx/ obj-$(if $(filter bcm281xx,$(SOC)),y) += bcm281xx/ +obj-$(if $(filter bcm7445d0,$(SOC)),y) += bcm7445d0/ obj-$(if $(filter bcmcygnus,$(SOC)),y) += bcmcygnus/ obj-$(if $(filter bcmnsp,$(SOC)),y) += bcmnsp/ obj-$(if $(filter ls102xa,$(SOC)),y) += ls102xa/ diff --git a/arch/arm/cpu/armv7/bcm7445d0/Makefile b/arch/arm/cpu/armv7/bcm7445d0/Makefile new file mode 100644 index 0000000..796f482 --- /dev/null +++ b/arch/arm/cpu/armv7/bcm7445d0/Makefile @@ -0,0 +1,11 @@ +# +# (C) Copyright 2018 +# Cisco Systems, Inc. <www.cisco.com> +# +# Author : +# Thomas Fitzsimmons fitzsim@fitzsim.org +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y := lowlevel_init.o diff --git a/arch/arm/cpu/armv7/bcm7445d0/lowlevel_init.S b/arch/arm/cpu/armv7/bcm7445d0/lowlevel_init.S new file mode 100644 index 0000000..1eb67a0 --- /dev/null +++ b/arch/arm/cpu/armv7/bcm7445d0/lowlevel_init.S @@ -0,0 +1,24 @@ +/* + * (C) Copyright 2018 + * Cisco Systems, Inc. <www.cisco.com> + * + * Author : + * Thomas Fitzsimmons fitzsim@fitzsim.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <linux/linkage.h> + +ENTRY(save_boot_params) + ldr r6, =bcm7445d0_boot_parameters + str r0, [r6, #0] + str r1, [r6, #4] + str r2, [r6, #8] + str r3, [r6, #12] + str sp, [r6, #16] + str lr, [r6, #20] + ldr r6, =prior_stage_fdt_address + str r2, [r6] + b save_boot_params_ret +ENDPROC(save_boot_params) diff --git a/arch/arm/lib/crt0.S b/arch/arm/lib/crt0.S index fa81317..f1a6f35 100644 --- a/arch/arm/lib/crt0.S +++ b/arch/arm/lib/crt0.S @@ -94,6 +94,7 @@ ENTRY(_main) * 'here' but relocated. */
+#if !defined(CONFIG_OF_PRIOR_STAGE) ldr r0, [r9, #GD_START_ADDR_SP] /* sp = gd->start_addr_sp */ bic r0, r0, #7 /* 8-byte alignment for ABI compliance */ mov sp, r0 @@ -108,6 +109,7 @@ ENTRY(_main) #endif ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */ b relocate_code +#endif here: /* * now relocate vectors diff --git a/arch/arm/mach-bcm7445d0/include/mach/gpio.h b/arch/arm/mach-bcm7445d0/include/mach/gpio.h new file mode 100644 index 0000000..f7163e4 --- /dev/null +++ b/arch/arm/mach-bcm7445d0/include/mach/gpio.h @@ -0,0 +1,12 @@ +/* + * (C) Copyright 2018 + * Cisco Systems, Inc. <www.cisco.com> + * + * Author : + * Thomas Fitzsimmons fitzsim@fitzsim.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#ifndef _BCM7445D0_GPIO_H +#define _BCM7445D0_GPIO_H +#endif /* _BCM7445D0_GPIO_H */ diff --git a/arch/arm/mach-bcm7445d0/include/mach/hardware.h b/arch/arm/mach-bcm7445d0/include/mach/hardware.h new file mode 100644 index 0000000..28418bf --- /dev/null +++ b/arch/arm/mach-bcm7445d0/include/mach/hardware.h @@ -0,0 +1,12 @@ +/* + * (C) Copyright 2018 + * Cisco Systems, Inc. <www.cisco.com> + * + * Author : + * Thomas Fitzsimmons fitzsim@fitzsim.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#ifndef _BCM7445D0_HARDWARE_H +#define _BCM7445D0_HARDWARE_H +#endif /* _BCM7445D0_HARDWARE_H */ diff --git a/arch/arm/mach-bcm7445d0/include/mach/sdhci.h b/arch/arm/mach-bcm7445d0/include/mach/sdhci.h new file mode 100644 index 0000000..2c7fb09 --- /dev/null +++ b/arch/arm/mach-bcm7445d0/include/mach/sdhci.h @@ -0,0 +1,15 @@ +/* + * (C) Copyright 2018 + * Cisco Systems, Inc. <www.cisco.com> + * + * Author : + * Thomas Fitzsimmons fitzsim@fitzsim.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#ifndef _BCM7445D0_SDHCI_H +#define _BCM7445D0_SDHCI_H + +int bcmstb_sdhci_init(phys_addr_t regbase); + +#endif /* _BCM7445D0_SDHCI_H */ diff --git a/board/broadcom/bcm7445d0/Kconfig b/board/broadcom/bcm7445d0/Kconfig new file mode 100644 index 0000000..d710503 --- /dev/null +++ b/board/broadcom/bcm7445d0/Kconfig @@ -0,0 +1,132 @@ +if TARGET_BCM7445D0 + +config SYS_BOARD + default "bcm7445d0" + +config SYS_VENDOR + default "broadcom" + +config SYS_CONFIG_NAME + default "bcm7445d0" + +config SYS_SOC + default "bcm7445d0" + +config BCHP_BSPI_MAST_N_BOOT_CTRL + hex "" + default 0x003e3208 + +config BCHP_EBI_CS_SPI_SELECT + hex "" + default 0x003e0920 + +config BCHP_HIF_MSPI_SPCR2_CONT_AFTER_CMD_MASK + hex "" + default 0x00000080 + +config BCHP_HIF_MSPI_SPCR2_SPE_MASK + hex "" + default 0x00000040 + +config BCHP_HIF_MSPI_SPCR2_SPIFIE_MASK + hex "" + default 0x00000020 + +config BCHP_HIF_MSPI_WRITE_LOCK + hex "" + default 0x003e3580 + +config BCHP_HIF_MSPI_WRITE_LOCK_WRITE_LOCK_DEFAULT + hex "" + default 0x00000000 + +config BCHP_HIF_MSPI_WRITE_LOCK_WRITE_LOCK_MASK + hex "" + default 0x00000001 + +config BCHP_HIF_MSPI_WRITE_LOCK_WRITE_LOCK_SHIFT + hex "" + default 0 + +config BCHP_HIF_SPI_INTR2_CPU_CLEAR + hex "" + default 0x003e1a08 + +config BCHP_HIF_SPI_INTR2_CPU_MASK_CLEAR + hex "" + default 0x003e1a14 + +config BCHP_HIF_SPI_INTR2_CPU_MASK_SET + hex "" + default 0x003e1a10 + +config BCHP_HIF_SPI_INTR2_CPU_SET_MSPI_DONE_MASK + hex "" + default 0x00000020 + +config BCMSTB_ACCOMMODATE_STBLINUX + bool "" + default y + help + This prevents U-Boot from adding memory reservations for the + lengths of initramfs and DTB. Without skipping these, + stblinux's "contiguous memory allocator" (CMA) Linux driver + (cma_driver) will allocate memory ranges smaller than what + are actually available, because it only checks reservation + sizes. It doesn't check if the reserved range overlaps the + range it allocates. stblinux also tries to move the DTB to + a lower memory location early in the Linux boot. If the FIT + image specifies a load address for the initramfs then + sometimes the DTB is moved into the range where the + initramfs image is loaded. Defining this will mean that + FIT-provided initramfs load addresses are ignored. + +config BCMSTB_SDHCI + bool "" + default y + +config BCMSTB_SDHCI_BASE + hex "" + default 0xf03e0200 + +config BCMSTB_SPI_BASE + hex "" + default 0xf03e3400 + +config CMD_FDT_MAX_DUMP + int "" + default 256 + +config GENERIC_MMC + bool "" + default y + +config MMC_SDMA + bool "" + default y + +config SDHCI + bool "" + default y + +config SYS_BCMSTB_SPI_WAIT + int "" + default 10 + +config SYS_FDT_SAVE_ADDRESS + hex "" + default 0x1f00000 + +config SYS_NO_FLASH + bool "" + default y + +config TIMER_FREQUENCY_REGISTER_ADDRESS + hex "" + default 0xf0412020 + +config TIMER_LOW_REGISTER_ADDRESS + hex "" + default 0xf0412008 + +endif diff --git a/board/broadcom/bcm7445d0/Makefile b/board/broadcom/bcm7445d0/Makefile new file mode 100644 index 0000000..265bc74 --- /dev/null +++ b/board/broadcom/bcm7445d0/Makefile @@ -0,0 +1,11 @@ +# +# (C) Copyright 2018 +# Cisco Systems, Inc. <www.cisco.com> +# +# Author : +# Thomas Fitzsimmons fitzsim@fitzsim.org +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y := bcm7445d0.o diff --git a/board/broadcom/bcm7445d0/bcm7445d0.c b/board/broadcom/bcm7445d0/bcm7445d0.c new file mode 100644 index 0000000..7f8e1f6 --- /dev/null +++ b/board/broadcom/bcm7445d0/bcm7445d0.c @@ -0,0 +1,147 @@ +/* + * (C) Copyright 2018 + * Cisco Systems, Inc. <www.cisco.com> + * + * Author : + * Thomas Fitzsimmons fitzsim@fitzsim.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <linux/types.h> +#include <common.h> +#include <asm/io.h> +#include <asm/arch/sdhci.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct bcm7445d0_boot_parameters { + u32 r0; + u32 r1; + u32 r2; + u32 r3; + u32 sp; + u32 lr; +}; + +struct bcm7445d0_boot_parameters bcm7445d0_boot_parameters \ +__attribute__((section(".data"))); + +phys_addr_t prior_stage_fdt_address __attribute__((section(".data"))); + +union reg_value_union { + const char *data; + const phys_addr_t *address; +}; + +int board_init(void) +{ + return 0; +} + +u32 get_board_rev(void) +{ + return 0; +} + +void reset_cpu(ulong ignored) +{ +} + +int print_cpuinfo(void) +{ + return 0; +} + +int dram_init(void) +{ + gd->ram_size = 0xc0000000; + + return 0; +} + +int dram_init_banksize(void) +{ + bd_t *bd = gd->bd; + + bd->bi_dram[0].start = 0x00000000; + bd->bi_dram[0].size = 0x40000000; + bd->bi_dram[1].start = 0x40000000; + bd->bi_dram[1].size = 0x40000000; + bd->bi_dram[2].start = 0x80000000; + bd->bi_dram[2].size = 0x40000000; + + return 0; +} + +void enable_caches(void) +{ + /* + * Nothing required here, since the prior stage bootloader has + * enabled I-cache and D-cache already. Implementing this + * function silences the warning in the default function. + */ +} + +int board_mmc_init(bd_t *bis) +{ + /* Just use the hard-coded SDHCI base address, though it could + * be determined from the DTB provided by the prior stage + * bootloader. + */ + bcmstb_sdhci_init(CONFIG_BCMSTB_SDHCI_BASE); + + return 0; +} + +int timer_init(void) +{ + gd->arch.timer_rate_hz = readl(CONFIG_TIMER_FREQUENCY_REGISTER_ADDRESS); + + return 0; +} + +ulong get_tbclk(void) +{ + return gd->arch.timer_rate_hz; +} + +unsigned long timer_read_counter(void) +{ + return readl(CONFIG_TIMER_LOW_REGISTER_ADDRESS); +} + +int board_late_init(void) +{ + printf("Arguments from prior stage bootloader:\n"); + printf("General Purpose Register 0: 0x%x\n", + bcm7445d0_boot_parameters.r0); + printf("General Purpose Register 1: 0x%x\n", + bcm7445d0_boot_parameters.r1); + printf("General Purpose Register 2: 0x%x\n", + bcm7445d0_boot_parameters.r2); + printf("General Purpose Register 3: 0x%x\n", + bcm7445d0_boot_parameters.r3); + printf("Stack Pointer Register: 0x%x\n", + bcm7445d0_boot_parameters.sp); + printf("Link Register: 0x%x\n", + bcm7445d0_boot_parameters.lr); + printf("Assuming timer frequency register at: 0x%x\n", + CONFIG_TIMER_FREQUENCY_REGISTER_ADDRESS); + printf("Read timer frequency (in Hz): %ld\n", gd->arch.timer_rate_hz); + printf("Prior stage provided DTB at: 0x%p\n", + (void *)prior_stage_fdt_address); + /* + * Set fdtcontroladdr in the environment so that scripts can + * refer to it, for example, to reuse it for fdtaddr. + */ + env_set_hex("fdtcontroladdr", prior_stage_fdt_address); + /* + * Do not set machid to the machine identifier value provided + * by the prior stage bootloader + * (bcm7445d0_boot_parameters.r1) because we're using a device + * tree to boot Linux. + */ + + return 0; +} diff --git a/common/fdt_support.c b/common/fdt_support.c index 66a313e..f07dfe3 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -242,11 +242,13 @@ int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end) } }
+#if !defined(CONFIG_BCMSTB_ACCOMMODATE_STBLINUX) err = fdt_add_mem_rsv(fdt, initrd_start, initrd_end - initrd_start); if (err < 0) { printf("fdt_initrd: %s\n", fdt_strerror(err)); return err; } +#endif
is_u64 = (fdt_address_cells(fdt, 0) == 2);
@@ -602,7 +604,10 @@ int fdt_shrink_to_minimum(void *blob, uint extrasize) { int i; uint64_t addr, size; - int total, ret; + int total; +#if !defined(CONFIG_BCMSTB_ACCOMMODATE_STBLINUX) + int ret; +#endif uint actualsize;
if (!blob) @@ -635,9 +640,11 @@ int fdt_shrink_to_minimum(void *blob, uint extrasize) fdt_set_totalsize(blob, actualsize);
/* Add the new reservation */ +#if !defined(CONFIG_BCMSTB_ACCOMMODATE_STBLINUX) ret = fdt_add_mem_rsv(blob, (uintptr_t)blob, actualsize); if (ret < 0) return ret; +#endif
return actualsize; } diff --git a/common/image-fit.c b/common/image-fit.c index 030a3e5..a346f8c 100644 --- a/common/image-fit.c +++ b/common/image-fit.c @@ -1905,6 +1905,7 @@ int fit_image_load(bootm_headers_t *images, ulong addr, return -EBADF; } } else if (load_op != FIT_LOAD_OPTIONAL_NON_ZERO || load) { +#if !defined(CONFIG_BCMSTB_ACCOMMODATE_STBLINUX) ulong image_start, image_end; ulong load_end; void *dst; @@ -1929,6 +1930,7 @@ int fit_image_load(bootm_headers_t *images, ulong addr, dst = map_sysmem(load, len); memmove(dst, buf, len); data = load; +#endif } bootstage_mark(bootstage_id + BOOTSTAGE_SUB_LOAD);
diff --git a/configs/bcm7445d0_defconfig b/configs/bcm7445d0_defconfig new file mode 100644 index 0000000..1e1162e --- /dev/null +++ b/configs/bcm7445d0_defconfig @@ -0,0 +1,21 @@ +CONFIG_ARM=y +CONFIG_SYS_TEXT_BASE=0x80100000 +CONFIG_TARGET_BCM7445D0=y +CONFIG_USE_PRIVATE_LIBGCC=y +CONFIG_OF_CONTROL=y +CONFIG_OF_PRIOR_STAGE=y +CONFIG_DM=y +CONFIG_DM_SPI=y +CONFIG_DM_SPI_FLASH=y +CONFIG_SPI=y +CONFIG_SPI_FLASH=y +CONFIG_ENV_IS_IN_SPI_FLASH=y +CONFIG_FIT=y +CONFIG_FIT_SIGNATURE=y +CONFIG_RSA=y +CONFIG_BLK=n +CONFIG_MMC_SDHCI=y +CONFIG_CONS_INDEX=3 +CONFIG_BOOTDELAY=1 +CONFIG_SYS_PROMPT="U-Boot>" +CONFIG_HUSH_PARSER=y diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index cf46c33..959f410 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_MMC_DW_EXYNOS) += exynos_dw_mmc.o obj-$(CONFIG_MMC_DW_K3) += hi6220_dw_mmc.o obj-$(CONFIG_MMC_DW_ROCKCHIP) += rockchip_dw_mmc.o obj-$(CONFIG_MMC_DW_SOCFPGA) += socfpga_dw_mmc.o +obj-$(CONFIG_BCMSTB_SDHCI) += bcmstb_sdhci.o obj-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o obj-$(CONFIG_FTSDC010) += ftsdc010_mci.o obj-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o diff --git a/drivers/mmc/bcmstb_sdhci.c b/drivers/mmc/bcmstb_sdhci.c new file mode 100644 index 0000000..933c546 --- /dev/null +++ b/drivers/mmc/bcmstb_sdhci.c @@ -0,0 +1,59 @@ +#include <common.h> +#include <malloc.h> +#include <sdhci.h> + +/* + * The BCMSTB SDHCI has a quirk in that its actual maximum frequency + * capability is 100 MHz. The divisor that is eventually written to + * SDHCI_CLOCK_CONTROL is calculated based on what the MMC device + * reports, and relative to this maximum frequency. + * + * This define used to be set to 52000000 (52 MHz), the desired + * maximum frequency, but that would result in the communication + * actually running at 100 MHz (seemingly without issue), which is + * out-of-spec. + * + * Now, by setting this to 0 (auto-detect), 100 MHz will be read from + * the capabilities register, and the resulting divisor will be + * doubled, meaning that the clock control register will be set to the + * in-spec 52 MHz value. + */ +#define BCMSTB_SDHCI_MAXIMUM_CLOCK_FREQUENCY 0 +/* + * When the minimum clock frequency is set to 0 (auto-detect), U-Boot + * sets it to 100 MHz divided by SDHCI_MAX_DIV_SPEC_300, or 48,875 Hz, + * which results in the controller timing out when trying to + * communicate with the MMC device. Hard-code this value to 400000 + * (400 kHz) to prevent this. + */ +#define BCMSTB_SDHCI_MINIMUM_CLOCK_FREQUENCY 400000 + +static char *BCMSTB_SDHCI_NAME = "bcmstb-sdhci"; + +/* + * This driver has only been tested with eMMC devices; SD devices may + * not work. + */ +int bcmstb_sdhci_init(phys_addr_t regbase) +{ + struct sdhci_host *host = NULL; + + host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host)); + if (!host) { + printf("bcmstb-sdhci malloc fail!\n"); + return 1; + } + memset(host, 0, sizeof(*host)); + + host->name = BCMSTB_SDHCI_NAME; + host->ioaddr = (void *)regbase; + host->quirks = 0; + + host->cfg.part_type = PART_TYPE_DOS; + + host->version = sdhci_readw(host, SDHCI_HOST_VERSION); + + return add_sdhci(host, + BCMSTB_SDHCI_MAXIMUM_CLOCK_FREQUENCY, + BCMSTB_SDHCI_MINIMUM_CLOCK_FREQUENCY); +} diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 6667f73..c4a6c8d 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -66,6 +66,13 @@ config BCM63XX_SPI access the SPI NOR flash on platforms embedding these Broadcom SPI cores.
+config BCMSTB_SPI + bool "Broadcom Set Top Box SPI driver" + help + Enable the Broadcom Set Top Box SPI driver. This driver can + be used to access the SPI flash on platforms embedding this + Broadcom SPI core. + config CADENCE_QSPI bool "Cadence QSPI driver" help diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 176bfa0..0f864be 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_ATH79_SPI) += ath79_spi.o obj-$(CONFIG_ATMEL_SPI) += atmel_spi.o obj-$(CONFIG_BCM63XX_HSSPI) += bcm63xx_hsspi.o obj-$(CONFIG_BCM63XX_SPI) += bcm63xx_spi.o +obj-$(CONFIG_BCMSTB_SPI) += bcmstb_spi.o obj-$(CONFIG_CADENCE_QSPI) += cadence_qspi.o cadence_qspi_apb.o obj-$(CONFIG_CF_SPI) += cf_spi.o obj-$(CONFIG_DAVINCI_SPI) += davinci_spi.o diff --git a/drivers/spi/bcmstb_spi.c b/drivers/spi/bcmstb_spi.c new file mode 100644 index 0000000..183a547 --- /dev/null +++ b/drivers/spi/bcmstb_spi.c @@ -0,0 +1,428 @@ +/* + * (C) Copyright 2018 + * Cisco Systems, Inc. <www.cisco.com> + * + * Author : + * Thomas Fitzsimmons fitzsim@fitzsim.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <asm/io.h> +#include <common.h> +#include <config.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <malloc.h> +#include <spi.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define SPBR_MIN 8 +#define BITS_PER_WORD 8 + +#define NUM_TXRAM 32 +#define NUM_RXRAM 32 +#define NUM_CDRAM 16 + +#ifdef DEBUG +static int debug_tx_rx; +#define D(fmt, args...) debug_cond(debug_tx_rx, fmt, ##args) +#else +#define D(fmt, args...) +#endif + +/* MSPI registers. BSPI is disabled. */ +struct bcmstb_spi_regs { + u32 spcr0_lsb; /* 0x000 */ + u32 spcr0_msb; /* 0x004 */ + u32 spcr1_lsb; /* 0x008 */ + u32 spcr1_msb; /* 0x00c */ + u32 newqp; /* 0x010 */ + u32 endqp; /* 0x014 */ + u32 spcr2; /* 0x018 */ + u32 reserved0; /* 0x01c */ + u32 mspi_status; /* 0x020 */ + u32 cptqp; /* 0x024 */ + u32 spcr3; /* 0x028 */ + u32 revision; /* 0x02c */ + u32 reserved1[4]; /* 0x030 */ + u32 txram[NUM_TXRAM]; /* 0x040 */ + u32 rxram[NUM_RXRAM]; /* 0x0c0 */ + u32 cdram[NUM_CDRAM]; /* 0x140 */ +}; + +struct bcmstb_spi_platdata { + struct bcmstb_spi_regs *regs; +}; + +struct bcmstb_spi_priv { + struct bcmstb_spi_regs *regs; + int default_cs; + int curr_cs; + uint tx_slot; + uint rx_slot; + u8 saved_cmd[NUM_CDRAM]; + uint saved_cmd_len; + void *saved_din_addr; +}; + +/* + * If we could rely on the prior stage bootloader to insert a "spi0" + * alias, we could enable CONFIG_DM_SEQ_ALIAS and omit + * bcmstb_spi_bind. We cannot rely on this behaviour, so we have to + * handle binding explicitly. + */ +static int bcmstb_spi_bind(struct udevice *bus) +{ + char spi0_name[30]; + int node = dev_of_offset(bus); + + memset(spi0_name, 0, sizeof(spi0_name)); + + debug("bcmstb_spi_bind: %s, ", bus->name); + + snprintf(spi0_name, sizeof(spi0_name), "spi@%08x", + CONFIG_BCMSTB_SPI_BASE); + if (strcmp(fdt_get_name(gd->fdt_blob, node, NULL), + spi0_name) == 0) { + bus->req_seq = 0; + } + + debug("%d\n", bus->req_seq); + + return 0; +} + +static int bcmstb_spi_ofdata_to_platdata(struct udevice *bus) +{ + struct bcmstb_spi_platdata *plat = dev_get_platdata(bus); + const void *blob = gd->fdt_blob; + int node = dev_of_offset(bus); + u32 address = 0; + int code = 0; + + code = fdtdec_get_int_array(blob, node, "reg", &address, 1); + if (code != 0) { + printf("bcmstb_spi_ofdata_to_platdata:" + " Failed to read reg property\n"); + return code; + } + + plat->regs = (struct bcmstb_spi_regs *)address; + D("spi_xfer: tx regs: %p\n", &plat->regs->txram[0]); + D("spi_xfer: rx regs: %p\n", &plat->regs->rxram[0]); + + return 0; +} + +static void bcmstb_spi_hw_set_parms(struct bcmstb_spi_priv *priv) +{ + writel(SPBR_MIN, &priv->regs->spcr0_lsb); + writel(BITS_PER_WORD << 2 | SPI_MODE_3, &priv->regs->spcr0_msb); +} + +static void bcmstb_spi_enable_interrupt(u32 mask) +{ + BDEV_SET_RB(CONFIG_BCHP_HIF_SPI_INTR2_CPU_MASK_CLEAR, mask); +} + +static void bcmstb_spi_disable_interrupt(u32 mask) +{ + BDEV_SET_RB(CONFIG_BCHP_HIF_SPI_INTR2_CPU_MASK_SET, mask); +} + +static void bcmstb_spi_clear_interrupt(u32 mask) +{ + BDEV_SET_RB(CONFIG_BCHP_HIF_SPI_INTR2_CPU_CLEAR, mask); +} + +static int bcmstb_spi_probe(struct udevice *bus) +{ + struct bcmstb_spi_platdata *plat = dev_get_platdata(bus); + struct bcmstb_spi_priv *priv = dev_get_priv(bus); + + priv->regs = plat->regs; + priv->default_cs = 0; + priv->curr_cs = -1; + priv->tx_slot = 0; + priv->rx_slot = 0; + memset(priv->saved_cmd, 0, NUM_CDRAM); + priv->saved_cmd_len = 0; + priv->saved_din_addr = NULL; + + /* Disable BSPI. */ + BDEV_WR_RB(CONFIG_BCHP_BSPI_MAST_N_BOOT_CTRL, 1); + + /* Set up interrupts. */ + bcmstb_spi_disable_interrupt(0xffffffff); + bcmstb_spi_clear_interrupt(0xffffffff); + bcmstb_spi_enable_interrupt( + CONFIG_BCHP_HIF_SPI_INTR2_CPU_SET_MSPI_DONE_MASK); + + /* Set up control registers. */ + writel(0, &priv->regs->spcr1_lsb); + writel(0, &priv->regs->spcr1_msb); + writel(0, &priv->regs->newqp); + writel(0, &priv->regs->endqp); + writel(CONFIG_BCHP_HIF_MSPI_SPCR2_SPIFIE_MASK, &priv->regs->spcr2); + writel(0, &priv->regs->spcr3); + + bcmstb_spi_hw_set_parms(priv); + + return 0; +} + +static int bcmstb_spi_remove(struct udevice *dev) +{ + return 0; +} + +static int bcmstb_spi_claim_bus(struct udevice *dev) +{ + return 0; +} + +static int bcmstb_spi_release_bus(struct udevice *dev) +{ + return 0; +} + +static void bcmstb_spi_submit(struct bcmstb_spi_priv *priv, bool done) +{ + D("WR NEWQP: %d\n", 0); + writel(0, &priv->regs->newqp); + + D("WR ENDQP: %d\n", priv->tx_slot - 1); + writel(priv->tx_slot - 1, &priv->regs->endqp); + + if (done) { + D("WR CDRAM[%d]: %02x\n", priv->tx_slot - 1, + readl(&priv->regs->cdram[priv->tx_slot - 1]) & ~0x80); + writel(readl(&priv->regs->cdram[priv->tx_slot - 1]) & ~0x80, + &priv->regs->cdram[priv->tx_slot - 1]); + } + + /* Force chip select first time. */ + if (priv->curr_cs != priv->default_cs) { + D("spi_xfer: switching chip select to %d\n", + priv->default_cs); + BDEV_WR_RB(CONFIG_BCHP_EBI_CS_SPI_SELECT, + (BDEV_RD(CONFIG_BCHP_EBI_CS_SPI_SELECT) & + ~0xff) | (1 << priv->default_cs)); + udelay(10); + priv->curr_cs = priv->default_cs; + } + + D("WR WRITE_LOCK: %02x\n", 1); + BDEV_WR_F_RB(HIF_MSPI_WRITE_LOCK, WRITE_LOCK, 1); + + D("WR SPCR2: %02x\n", + CONFIG_BCHP_HIF_MSPI_SPCR2_SPIFIE_MASK | + CONFIG_BCHP_HIF_MSPI_SPCR2_SPE_MASK | + CONFIG_BCHP_HIF_MSPI_SPCR2_CONT_AFTER_CMD_MASK); + writel(CONFIG_BCHP_HIF_MSPI_SPCR2_SPIFIE_MASK | + CONFIG_BCHP_HIF_MSPI_SPCR2_SPE_MASK | + CONFIG_BCHP_HIF_MSPI_SPCR2_CONT_AFTER_CMD_MASK, + &priv->regs->spcr2); +} + +static int bcmstb_spi_wait(struct bcmstb_spi_regs *regs) +{ + u32 start_time = get_timer(0); + u32 status = readl(®s->mspi_status); + + while (!(status & 1)) { + if (get_timer(start_time) > + CONFIG_SYS_BCMSTB_SPI_WAIT) { + return -ETIMEDOUT; + } + status = readl(®s->mspi_status); + } + + writel(readl(®s->mspi_status) & ~1, ®s->mspi_status); + bcmstb_spi_clear_interrupt( + CONFIG_BCHP_HIF_SPI_INTR2_CPU_SET_MSPI_DONE_MASK); + + return 0; +} + +static int bcmstb_spi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + uint len = bitlen / 8; + uint tx_len = len; + uint rx_len = len; + const u8 *out_bytes = (u8 *)dout; + u8 *in_bytes = (u8 *)din; + struct udevice *bus = dev_get_parent(dev); + struct bcmstb_spi_priv *priv = dev_get_priv(bus); + struct bcmstb_spi_regs *regs = priv->regs; + + D("spi_xfer: %d, t: %p, r: %p, f: %lx\n", len, dout, din, flags); + D("spi_xfer: chip select: %x\n", + readl(CONFIG_BCHP_EBI_CS_SPI_SELECT) & 0xff); + D("spi_xfer: tx addr: %p\n", ®s->txram[0]); + D("spi_xfer: rx addr: %p\n", ®s->rxram[0]); + D("spi_xfer: cd addr: %p\n", ®s->cdram[0]); + + if (flags & SPI_XFER_END) { + D("spi_xfer: clearing saved din address: %p\n", + priv->saved_din_addr); + priv->saved_din_addr = NULL; + priv->saved_cmd_len = 0; + memset(priv->saved_cmd, 0, NUM_CDRAM); + } + + if (bitlen == 0) + return 0; + + if (bitlen % 8) { + printf("bcmstb_spi_xfer: Non-byte-aligned transfer\n"); + return -EOPNOTSUPP; + } + + if (flags & ~(SPI_XFER_BEGIN | SPI_XFER_END)) { + printf("bcmstb_spi_xfer: Unsupported flags: %lx\n", flags); + return -EOPNOTSUPP; + } + + if (flags & SPI_XFER_BEGIN) { + priv->tx_slot = 0; + priv->rx_slot = 0; + + if (out_bytes && len > NUM_CDRAM) { + printf("bcmstb_spi_xfer: Unable to save transfer\n"); + return -EOPNOTSUPP; + } + + if (out_bytes && !(flags & SPI_XFER_END)) { + /* + * This is the start of a transmit operation + * that will need repeating if the calling + * code polls for the result. Save it for + * subsequent transmission. + */ + D("spi_xfer: saving command: %x, %d\n", + out_bytes[0], len); + priv->saved_cmd_len = len; + memcpy(priv->saved_cmd, out_bytes, priv->saved_cmd_len); + } + } + + if (!(flags & (SPI_XFER_BEGIN | SPI_XFER_END))) { + if (priv->saved_din_addr == din) { + /* + * The caller is polling for status. Repeat + * the last transmission. + */ + int code = 0; + + D("spi_xfer: Making recursive call\n"); + code = bcmstb_spi_xfer(dev, priv->saved_cmd_len * 8, + priv->saved_cmd, NULL, + SPI_XFER_BEGIN); + if (code) { + printf("bcmstb_spi_xfer:" + " Recursive call failed\n"); + return code; + } + } else { + D("spi_xfer: saving din address: %p\n", din); + priv->saved_din_addr = din; + } + } + + while (rx_len > 0) { + priv->rx_slot = priv->tx_slot; + + while (priv->tx_slot < NUM_CDRAM && tx_len > 0) { + bcmstb_spi_hw_set_parms(priv); + D("WR TXRAM[%d]: %02x\n", priv->tx_slot, + out_bytes ? out_bytes[len - tx_len] : 0xff); + writel(out_bytes ? out_bytes[len - tx_len] : 0xff, + ®s->txram[priv->tx_slot << 1]); + D("WR CDRAM[%d]: %02x\n", priv->tx_slot, 0x8e); + writel(0x8e, ®s->cdram[priv->tx_slot]); + priv->tx_slot++; + tx_len--; + if (!in_bytes) + rx_len--; + } + + D("spi_xfer: early return clauses: %d, %d, %d\n", + len <= NUM_CDRAM, + !in_bytes, + (flags & (SPI_XFER_BEGIN | SPI_XFER_END)) == SPI_XFER_BEGIN); + if (len <= NUM_CDRAM && + !in_bytes && + (flags & (SPI_XFER_BEGIN | SPI_XFER_END)) == SPI_XFER_BEGIN) + return 0; + + bcmstb_spi_submit(priv, tx_len == 0); + + if (bcmstb_spi_wait(regs) == -ETIMEDOUT) { + printf("bcmstb_spi_xfer: Timed out\n"); + return -ETIMEDOUT; + } + + priv->tx_slot %= NUM_CDRAM; + + if (in_bytes) { + while (priv->rx_slot < NUM_CDRAM && rx_len > 0) { + in_bytes[len - rx_len] = + readl(®s->rxram[(priv->rx_slot << 1) + + 1]) + & 0xff; + D("RD RXRAM[%d]: %02x\n", + priv->rx_slot, in_bytes[len - rx_len]); + priv->rx_slot++; + rx_len--; + } + } + } + + if (flags & SPI_XFER_END) { + D("WR WRITE_LOCK: %02x\n", 0); + BDEV_WR_F_RB(HIF_MSPI_WRITE_LOCK, WRITE_LOCK, 0); + } + + return 0; +} + +static int bcmstb_spi_set_speed(struct udevice *dev, uint speed) +{ + return 0; +} + +static int bcmstb_spi_set_mode(struct udevice *dev, uint mode) +{ + return 0; +} + +static const struct dm_spi_ops bcmstb_spi_ops = { + .claim_bus = bcmstb_spi_claim_bus, + .release_bus = bcmstb_spi_release_bus, + .xfer = bcmstb_spi_xfer, + .set_speed = bcmstb_spi_set_speed, + .set_mode = bcmstb_spi_set_mode, +}; + +static const struct udevice_id bcmstb_spi_ids[] = { + { .compatible = "brcm,spi-brcmstb" }, + { } +}; + +U_BOOT_DRIVER(bcmstb_spi) = { + .name = "bcmstb_spi", + .id = UCLASS_SPI, + .of_match = bcmstb_spi_ids, + .ops = &bcmstb_spi_ops, + .ofdata_to_platdata = bcmstb_spi_ofdata_to_platdata, + .probe = bcmstb_spi_probe, + .remove = bcmstb_spi_remove, + .platdata_auto_alloc_size = sizeof(struct bcmstb_spi_platdata), + .priv_auto_alloc_size = sizeof(struct bcmstb_spi_priv), + .bind = bcmstb_spi_bind, +}; diff --git a/dts/Kconfig b/dts/Kconfig index 0cef225..074784b 100644 --- a/dts/Kconfig +++ b/dts/Kconfig @@ -101,6 +101,12 @@ config OF_HOSTFILE This is only useful for Sandbox. Use the -d flag to U-Boot to specify the file to read.
+config OF_PRIOR_STAGE + bool "Prior stage bootloader DTB for DT control" + help + If this option is enabled, DTB will be read from a memory + location passed to U-Boot by the prior stage bootloader. + endchoice
config DEFAULT_DEVICE_TREE diff --git a/include/configs/bcm7445d0.h b/include/configs/bcm7445d0.h new file mode 100644 index 0000000..36155c7 --- /dev/null +++ b/include/configs/bcm7445d0.h @@ -0,0 +1,227 @@ +/* + * (C) Copyright 2018 + * Cisco Systems, Inc. <www.cisco.com> + * + * Author : + * Thomas Fitzsimmons fitzsim@fitzsim.org + * + * Configuration settings for the Broadcom BCM7445D0 SoC. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#include "bcmstb.h" +#include "version.h" + +/* + * Generic board configuration. + */ +#define CONFIG_SYS_GENERIC_BOARD + +/* + * CPU configuration. + */ +#define CONFIG_SKIP_LOWLEVEL_INIT + +/* + * Memory configuration. + * + * The prior stage BOLT bootloader sets up memory for us. An example + * invocation is: + * + * BOLT> boot -bsu -elf flash0.u-boot1 + * + * An example boot memory layout after loading everything is: + * + * 0x0000 8000 vmlinux.bin.gz + * : [31 MiB uncompressed max] + * 0x01ef f000 FIT containing signed public key + * : [~2 KiB in size] + * 0x01f0 0000 DTB copied from prior-stage-provided region + * : [~1 MiB max] + * ~0x01ff 4000 DTB modified by U-Boot (fdt_high - DTB size) + * : [~40 KiB in size] + * 0x0200 0000 FIT containing initramfs.cpio.gz + * : [208 MiB uncompressed max, to CMA low address] + * : [80 MiB compressed max, to PSB low address] + * 0x0700 0000 Prior stage bootloader (PSB) + * : + * 0x0761 7000 Prior-stage-provided device tree blob (DTB) + * : [~40 KiB in size] + * 0x0f00 0000 Contiguous memory allocator (CMA) low address + * : + * 0x8010 0000 U-Boot code at ELF load address + * : [~500 KiB in size, stripped] + * 0xc000 0000 Top of RAM + * + * CONFIG_OF_PRIOR_STAGE=y prevents U-Boot from relocating itself when + * it is run as an ELF program by the prior stage bootloader. + * + * The maximum value for fdt_high is the lowest physical address from + * which stblinux's CMA driver starts allocating, which is 0x0f000000. + * But a good setting for fdt_high is the default load address. + * + * Relocating the prior stage DTB prevents it from being overwritten + * when large initramfs images are loaded. Then the upper limit for + * the initramfs load region becomes the CMA low address. + * + * Overwriting the prior stage bootloader causes memory instability, + * so the compressed initramfs needs to fit between the load address + * and the PSB low address. In BOLT's default configuration this + * limits the compressed size of the initramfs to approximately 80 + * MiB. However, BOLT can be configured to allow loading larger + * initramfs images, in which case this limitation is eliminated. + * + * Newer versions of stblinux use the bmem mechanism for reserving + * physical regions of memory. In practice CMA/bmem values require + * experimentation and tuning to achieve a stable U-Boot memory layout + * and the desired Linux memory layout (see also + * BCMSTB_ACCOMMODATE_STBLINUX). + */ +#define CONFIG_NR_DRAM_BANKS 3 + +#define CONFIG_SYS_SDRAM_BASE 0x00000000 +#define CONFIG_SYS_TEXT_BASE 0x80100000 +#define CONFIG_SYS_INIT_RAM_ADDR 0x80200000 +#define CONFIG_SYS_INIT_RAM_SIZE 0x100000 +#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_INIT_RAM_ADDR + \ + CONFIG_SYS_INIT_RAM_SIZE - \ + GENERATED_GBL_DATA_SIZE) +#define CONFIG_SYS_MALLOC_LEN ((10 * 1024) << 10) /* 10 MiB */ +#define CONFIG_SYS_LOAD_ADDR 0x2000000 +/* + * CONFIG_SYS_LOAD_ADDR - 1 MiB. + */ +#define CONFIG_SYS_FDT_SAVE_ADDRESS 0x1f00000 +#define CONFIG_SYS_CBSIZE 512 +#define CONFIG_SYS_MAXARGS 32 + +/* + * Timer configuration. + */ +#define CONFIG_TIMER_FREQUENCY_REGISTER_ADDRESS 0xf0412020 +#define CONFIG_TIMER_LOW_REGISTER_ADDRESS 0xf0412008 + +/* + * NS16550 configuration. + */ +#define V_NS16550_CLK 81000000 + +#define CONFIG_SYS_NS16550 +#define CONFIG_SYS_NS16550_SERIAL +#define CONFIG_SYS_NS16550_REG_SIZE (-4) +#define CONFIG_SYS_NS16550_CLK V_NS16550_CLK + +/* + * Serial console configuration. + */ +#define CONFIG_SERIAL3 3 +/* + * For now, this must be a pre-defined macro, not looked up from the + * prior-stage-provided DTB. + */ +#define CONFIG_SYS_NS16550_COM3 0xf040ab00 +#define CONFIG_BAUDRATE 115200 +#define CONFIG_SYS_BAUDRATE_TABLE {4800, 9600, 19200, 38400, 57600,\ + 115200} + +/* + * Informational display configuration. + */ +#define CONFIG_REVISION_TAG + +/* + * Command configuration. + */ +#define CONFIG_CMD_ASKENV +#define CONFIG_CMD_CACHE +#define CONFIG_CMD_EXT2 +#define CONFIG_CMD_SF +#define CONFIG_CMD_SPI +#define CONFIG_CMD_SF_TEST +#define CONFIG_CMD_MMC + +/* + * Flattened device tree configuration. + */ +#define CONFIG_CMD_FDT_MAX_DUMP 256 + +/* + * Flash configuration. + */ +#define CONFIG_ST_SMI +#define CONFIG_BCMSTB_SPI +#define CONFIG_SPI_FLASH_STMICRO +#define CONFIG_SPI_FLASH_MACRONIX + +#define CONFIG_BCMSTB_SPI_BASE 0xf03e3400 + +/* + * Copied from stblinux, include/linux/brcmstb/7445d0/bchp_hif_mspi.h. + */ +#define CONFIG_BCHP_HIF_MSPI_SPCR2_SPIFIE_MASK 0x00000020 +#define CONFIG_BCHP_HIF_MSPI_SPCR2_SPE_MASK 0x00000040 +#define CONFIG_BCHP_HIF_MSPI_SPCR2_CONT_AFTER_CMD_MASK 0x00000080 +#define CONFIG_BCHP_HIF_MSPI_WRITE_LOCK 0x003e3580 +#define CONFIG_BCHP_HIF_MSPI_WRITE_LOCK_WRITE_LOCK_MASK 0x00000001 +#define CONFIG_BCHP_HIF_MSPI_WRITE_LOCK_WRITE_LOCK_DEFAULT 0x00000000 + +/* + * Copied from stblinux, include/linux/brcmstb/7445d0/bchp_hif_spi_intr2.h. + */ +#define CONFIG_BCHP_HIF_SPI_INTR2_CPU_CLEAR 0x003e1a08 +#define CONFIG_BCHP_HIF_SPI_INTR2_CPU_MASK_SET 0x003e1a10 +#define CONFIG_BCHP_HIF_SPI_INTR2_CPU_MASK_CLEAR 0x003e1a14 +#define CONFIG_BCHP_HIF_SPI_INTR2_CPU_SET_MSPI_DONE_MASK 0x00000020 + +/* + * Copied from stblinux, include/linux/brcmstb/7445d0/bchp_ebi.h. + */ +#define CONFIG_BCHP_EBI_CS_SPI_SELECT 0x003e0920 + +/* + * Copied from stblinux, include/linux/brcmstb/7445d0/bchp_bspi.h. + */ +#define CONFIG_BCHP_BSPI_MAST_N_BOOT_CTRL 0x003e3208 + +/* + * Filesystem configuration. + */ +#define CONFIG_DOS_PARTITION +#define CONFIG_CMD_EXT4 +#define CONFIG_FS_EXT4 +#define CONFIG_CMD_FS_GENERIC + +/* + * Environment configuration. + */ +#define CONFIG_SYS_REDUNDAND_ENVIRONMENT + +#define CONFIG_ENV_IS_IN_SPI_FLASH 1 +#define CONFIG_ENV_OFFSET 0x1e0000 +#define CONFIG_ENV_SIZE (64 << 10) /* 64 KiB */ +#define CONFIG_ENV_SECT_SIZE CONFIG_ENV_SIZE +#define CONFIG_ENV_OFFSET_REDUND (CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE) +#define CONFIG_ENV_OVERWRITE + +#define CONFIG_PREBOOT \ + "fdt addr ${fdtcontroladdr};" \ + "fdt move ${fdtcontroladdr} ${fdtsaveaddr};" \ + "fdt addr ${fdtsaveaddr};" +#define CONFIG_EXTRA_ENV_SETTINGS \ + "fdtsaveaddr=" __stringify(CONFIG_SYS_FDT_SAVE_ADDRESS) "\0" + +/* + * Set fdtaddr to prior stage-provided DTB in board_late_init, when + * writeable environment is available. + */ +#define CONFIG_BOARD_LATE_INIT + +#define CONFIG_SYS_MAX_FLASH_BANKS 1 + +#define CONFIG_DM_SPI 1 + +#endif /* __CONFIG_H */ diff --git a/include/configs/bcmstb.h b/include/configs/bcmstb.h new file mode 100644 index 0000000..33d1efc --- /dev/null +++ b/include/configs/bcmstb.h @@ -0,0 +1,57 @@ +/* + * (C) Copyright 2009 + * Broadcom Corporation + * + * Author : + * Thomas Fitzsimmons fitzsim@fitzsim.org + * + * Macros imported from Broadcom stblinux. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __BCMSTB_H +#define __BCMSTB_H + +/* Copied from stblinux, include/linux/brcmstb/brcmstb.h. */ +#define DEV_RD(x) (readl((x))) +#define DEV_WR(x, y) do { writel((y), (x)); } while (0) +#define DEV_UNSET(x, y) do { DEV_WR((x), DEV_RD(x) & ~(y)); } while (0) +#define DEV_SET(x, y) do { DEV_WR((x), DEV_RD(x) | (y)); } while (0) + +#define DEV_WR_RB(x, y) do { DEV_WR((x), (y)); DEV_RD(x); } while (0) +#define DEV_SET_RB(x, y) do { DEV_SET((x), (y)); DEV_RD(x); } while (0) +#define DEV_UNSET_RB(x, y) do { DEV_UNSET((x), (y)); DEV_RD(x); } while (0) + +/* Adjusted for U-Boot. */ +#define BRCMSTB_PERIPH_VIRT 0xf0000000 + +#define BVIRTADDR(x) (BRCMSTB_PERIPH_VIRT + ((x) & 0x0fffffff)) + +#define BDEV_RD(x) (DEV_RD(BVIRTADDR(x))) +#define BDEV_WR(x, y) do { DEV_WR(BVIRTADDR(x), (y)); } while (0) +#define BDEV_UNSET(x, y) do { BDEV_WR((x), BDEV_RD(x) & ~(y)); } while (0) +#define BDEV_SET(x, y) do { BDEV_WR((x), BDEV_RD(x) | (y)); } while (0) + +#define BDEV_SET_RB(x, y) do { BDEV_SET((x), (y)); BDEV_RD(x); } while (0) +#define BDEV_UNSET_RB(x, y) do { BDEV_UNSET((x), (y)); BDEV_RD(x); } while (0) +#define BDEV_WR_RB(x, y) do { BDEV_WR((x), (y)); BDEV_RD(x); } while (0) + +#define BDEV_RD_F(reg, field) \ + ((BDEV_RD(BCHP_##reg) & BCHP_##reg##_##field##_MASK) >> \ + BCHP_##reg##_##field##_SHIFT) +#define BDEV_WR_F(reg, field, val) do { \ + BDEV_WR(BCHP_##reg, \ + (BDEV_RD(BCHP_##reg) & ~BCHP_##reg##_##field##_MASK) | \ + (((val) << BCHP_##reg##_##field##_SHIFT) & \ + BCHP_##reg##_##field##_MASK)); \ + } while (0) +#define BDEV_WR_F_RB(reg, field, val) do { \ + BDEV_WR(CONFIG_BCHP_##reg, \ + (BDEV_RD(CONFIG_BCHP_##reg) & ~CONFIG_BCHP_##reg##_##field##_MASK) | \ + (((val) << CONFIG_BCHP_##reg##_##field##_SHIFT) & \ + CONFIG_BCHP_##reg##_##field##_MASK)); \ + BDEV_RD(CONFIG_BCHP_##reg); \ + } while (0) + +#endif /* __BCMSTB_H */ diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 320ee1d..aec12f2 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -1299,6 +1299,10 @@ __weak void *board_fdt_blob_setup(void) } #endif
+#if defined(CONFIG_OF_PRIOR_STAGE) +extern phys_addr_t prior_stage_fdt_address; +#endif + int fdtdec_setup(void) { #if CONFIG_IS_ENABLED(OF_CONTROL) @@ -1323,8 +1327,12 @@ int fdtdec_setup(void) # endif # ifndef CONFIG_SPL_BUILD /* Allow the early environment to override the fdt address */ +# if defined(CONFIG_OF_PRIOR_STAGE) + gd->fdt_blob = (void *)prior_stage_fdt_address; +# else gd->fdt_blob = (void *)env_get_ulong("fdtcontroladdr", 16, (uintptr_t)gd->fdt_blob); +# endif # endif
# if CONFIG_IS_ENABLED(MULTI_DTB_FIT)

On Sun, May 06, 2018 at 07:09:22AM -0400, Thomas Fitzsimmons wrote:
Add support for loading U-Boot on the Broadcom 7445D0 SoC. This port assumes Broadcom's BOLT bootloader is acting as the second stage bootloader, and U-Boot is acting as the third stage bootloader, loaded as an ELF program by BOLT.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Stefan Roese sr@denx.de
[snip]
diff --git a/arch/arm/lib/crt0.S b/arch/arm/lib/crt0.S index fa81317..f1a6f35 100644 --- a/arch/arm/lib/crt0.S +++ b/arch/arm/lib/crt0.S @@ -94,6 +94,7 @@ ENTRY(_main)
- 'here' but relocated.
*/
+#if !defined(CONFIG_OF_PRIOR_STAGE) ldr r0, [r9, #GD_START_ADDR_SP] /* sp = gd->start_addr_sp */ bic r0, r0, #7 /* 8-byte alignment for ABI compliance */ mov sp, r0 @@ -108,6 +109,7 @@ ENTRY(_main) #endif ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */ b relocate_code +#endif here: /*
- now relocate vectors
Can you explain this bit a good bit more?
+config BCHP_BSPI_MAST_N_BOOT_CTRL
- hex ""
- default 0x003e3208
Doing hex "" seems wrong. What are you doing here exactly?
diff --git a/common/fdt_support.c b/common/fdt_support.c index 66a313e..f07dfe3 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -242,11 +242,13 @@ int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end) } }
+#if !defined(CONFIG_BCMSTB_ACCOMMODATE_STBLINUX) err = fdt_add_mem_rsv(fdt, initrd_start, initrd_end - initrd_start); if (err < 0) { printf("fdt_initrd: %s\n", fdt_strerror(err)); return err; } +#endif
Why do we need this?
+#ifdef DEBUG +static int debug_tx_rx; +#define D(fmt, args...) debug_cond(debug_tx_rx, fmt, ##args) +#else +#define D(fmt, args...) +#endif
We have dbg() etc, please use. Thanks!

Tom Rini trini@konsulko.com writes:
On Sun, May 06, 2018 at 07:09:22AM -0400, Thomas Fitzsimmons wrote:
Add support for loading U-Boot on the Broadcom 7445D0 SoC. This port assumes Broadcom's BOLT bootloader is acting as the second stage bootloader, and U-Boot is acting as the third stage bootloader, loaded as an ELF program by BOLT.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Stefan Roese sr@denx.de
[snip]
diff --git a/arch/arm/lib/crt0.S b/arch/arm/lib/crt0.S index fa81317..f1a6f35 100644 --- a/arch/arm/lib/crt0.S +++ b/arch/arm/lib/crt0.S @@ -94,6 +94,7 @@ ENTRY(_main)
- 'here' but relocated.
*/
+#if !defined(CONFIG_OF_PRIOR_STAGE) ldr r0, [r9, #GD_START_ADDR_SP] /* sp = gd->start_addr_sp */ bic r0, r0, #7 /* 8-byte alignment for ABI compliance */ mov sp, r0 @@ -108,6 +109,7 @@ ENTRY(_main) #endif ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */ b relocate_code +#endif here: /*
- now relocate vectors
Can you explain this bit a good bit more?
When BOLT loads U-Boot as an ELF program, this relocation code hangs -- I haven't found out why yet -- but if I skip the relocation, U-Boot runs successfully. I figured out a different approach to preventing the relocation, one that only requires logic in an SoC-specific file, so v2 of the patch will not have any crt0.S changes.
+config BCHP_BSPI_MAST_N_BOOT_CTRL
- hex ""
- default 0x003e3208
Doing hex "" seems wrong. What are you doing here exactly?
I've reorganized all these into more appropriate locations, and documented all the remaining Kconfig items, which you'll see in the v2 patch I'll post shortly.
diff --git a/common/fdt_support.c b/common/fdt_support.c index 66a313e..f07dfe3 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -242,11 +242,13 @@ int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end) } }
+#if !defined(CONFIG_BCMSTB_ACCOMMODATE_STBLINUX) err = fdt_add_mem_rsv(fdt, initrd_start, initrd_end - initrd_start); if (err < 0) { printf("fdt_initrd: %s\n", fdt_strerror(err)); return err; } +#endif
Why do we need this?
The background is that stblinux is designed to use some physical memory for Linux itself, and leave the rest of physical memory for direct use by video decode blocks in the SoC.
Basically, without making accommodations for it in U-Boot, stblinux will allocate less memory for use by the video decode blocks than is actually available, even if it could safely allocate more.
In v2 of the patch, I've documented a different approach to loading FIT images (one that keeps the RFS and DTB in-place), which eliminates the need for this configuration macro.
+#ifdef DEBUG +static int debug_tx_rx; +#define D(fmt, args...) debug_cond(debug_tx_rx, fmt, ##args) +#else +#define D(fmt, args...) +#endif
We have dbg() etc, please use. Thanks!
OK, done in v2 of the patch.
Thanks for reviewing, Thomas

On 05/06/2018 04:09 AM, Thomas Fitzsimmons wrote:
Add support for loading U-Boot on the Broadcom 7445D0 SoC. This port assumes Broadcom's BOLT bootloader is acting as the second stage bootloader, and U-Boot is acting as the third stage bootloader, loaded as an ELF program by BOLT.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Stefan Roese sr@denx.de
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9bd70f4..b2df30a 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -498,6 +498,17 @@ config TARGET_VEXPRESS_CA15_TC2 select CPU_V7_HAS_VIRT select PL011_SERIAL
+config TARGET_BCM7445D0
- bool "Broadcom 7445D0 TSBL"
- select CPU_V7
- select SUPPORT_SPL
- help
Support for the Broadcom 7445D0 SoC. This port assumes Bolt
BOLT
is acting as the second stage bootloader, and U-Boot is
acting as the third stage bootloader (TSBL), loaded by Bolt.
again BOLT
This port may work on other BCM7xxx boards with
configuration changes.
There are other revisions than D0, so I would just name this TARGET_BCM7445. You would likely want to create a TARGET_BRCMSTB general menu which would encompass all ARMv7-A based SoCs from the Broadcom STB/CM division, and then have per-chip Kconfig options (similar to what the older <= 3.14 STB Linux kernels did).
+config BCMSTB_ACCOMMODATE_STBLINUX
- bool ""
- default y
- help
This prevents U-Boot from adding memory reservations for the
lengths of initramfs and DTB. Without skipping these,
stblinux's "contiguous memory allocator" (CMA) Linux driver
(cma_driver) will allocate memory ranges smaller than what
are actually available, because it only checks reservation
sizes. It doesn't check if the reserved range overlaps the
range it allocates. stblinux also tries to move the DTB to
a lower memory location early in the Linux boot. If the FIT
image specifies a load address for the initramfs then
sometimes the DTB is moved into the range where the
initramfs image is loaded. Defining this will mean that
FIT-provided initramfs load addresses are ignored.
What STB Linux kernel did you observe this with? I am afraid this is still true about the ranges vs. allocation even in newer kernels, but that is kind of intented to keep the logic KISS (because it's already too complicated IMHO).
+config BCMSTB_SDHCI
- bool ""
- default y
+config BCMSTB_SDHCI_BASE
- hex ""
- default 0xf03e0200
+config BCMSTB_SPI_BASE
- hex ""
- default 0xf03e3400
Why don't you get those from the Device Tree blob that BOLT passes?
+config CMD_FDT_MAX_DUMP
- int ""
- default 256
+config GENERIC_MMC
- bool ""
- default y
+config MMC_SDMA
- bool ""
- default y
+config SDHCI
- bool ""
- default y
+config SYS_BCMSTB_SPI_WAIT
- int ""
- default 10
+config SYS_FDT_SAVE_ADDRESS
- hex ""
- default 0x1f00000
+config SYS_NO_FLASH
- bool ""
- default y
+config TIMER_FREQUENCY_REGISTER_ADDRESS
- hex ""
- default 0xf0412020
+config TIMER_LOW_REGISTER_ADDRESS
- hex ""
- default 0xf0412008
All of these physical address ares not going to change given a 7445-based design, so why not hard code them in a header file unless you are keen on taking them from the passed Device Tree blob from BOLT?
+int dram_init_banksize(void) +{
- bd_t *bd = gd->bd;
- bd->bi_dram[0].start = 0x00000000;
- bd->bi_dram[0].size = 0x40000000;
- bd->bi_dram[1].start = 0x40000000;
- bd->bi_dram[1].size = 0x40000000;
- bd->bi_dram[2].start = 0x80000000;
- bd->bi_dram[2].size = 0x40000000;
This may be true for your system if you have 3x1GB populated, but 7445 supports additional extension regions, so this must be configurable if you want to make this flexible enough for other people to use it.
+/* Copied from stblinux, include/linux/brcmstb/brcmstb.h. */ +#define DEV_RD(x) (readl((x))) +#define DEV_WR(x, y) do { writel((y), (x)); } while (0) +#define DEV_UNSET(x, y) do { DEV_WR((x), DEV_RD(x) & ~(y)); } while (0) +#define DEV_SET(x, y) do { DEV_WR((x), DEV_RD(x) | (y)); } while (0)
+#define DEV_WR_RB(x, y) do { DEV_WR((x), (y)); DEV_RD(x); } while (0) +#define DEV_SET_RB(x, y) do { DEV_SET((x), (y)); DEV_RD(x); } while (0) +#define DEV_UNSET_RB(x, y) do { DEV_UNSET((x), (y)); DEV_RD(x); } while (0)
I would just flat out drop those macros and instead use standard accessors. Those happen to work just fine given Broadcom STB's GISB bus, but if you want portable drivers in u-boot, and you likely would want those, you should use more standard I/O accessors.

Florian Fainelli f.fainelli@gmail.com writes:
On 05/06/2018 04:09 AM, Thomas Fitzsimmons wrote:
Add support for loading U-Boot on the Broadcom 7445D0 SoC. This port assumes Broadcom's BOLT bootloader is acting as the second stage bootloader, and U-Boot is acting as the third stage bootloader, loaded as an ELF program by BOLT.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Stefan Roese sr@denx.de
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9bd70f4..b2df30a 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -498,6 +498,17 @@ config TARGET_VEXPRESS_CA15_TC2 select CPU_V7_HAS_VIRT select PL011_SERIAL
+config TARGET_BCM7445D0
- bool "Broadcom 7445D0 TSBL"
- select CPU_V7
- select SUPPORT_SPL
- help
Support for the Broadcom 7445D0 SoC. This port assumes Bolt
BOLT
is acting as the second stage bootloader, and U-Boot is
acting as the third stage bootloader (TSBL), loaded by Bolt.
again BOLT
Oops, will fix in a v2 patch.
This port may work on other BCM7xxx boards with
configuration changes.
There are other revisions than D0, so I would just name this TARGET_BCM7445. You would likely want to create a TARGET_BRCMSTB general menu which would encompass all ARMv7-A based SoCs from the Broadcom STB/CM division, and then have per-chip Kconfig options (similar to what the older <= 3.14 STB Linux kernels did).
OK, will try this in v2.
+config BCMSTB_ACCOMMODATE_STBLINUX
- bool ""
- default y
- help
This prevents U-Boot from adding memory reservations for the
lengths of initramfs and DTB. Without skipping these,
stblinux's "contiguous memory allocator" (CMA) Linux driver
(cma_driver) will allocate memory ranges smaller than what
are actually available, because it only checks reservation
sizes. It doesn't check if the reserved range overlaps the
range it allocates. stblinux also tries to move the DTB to
a lower memory location early in the Linux boot. If the FIT
image specifies a load address for the initramfs then
sometimes the DTB is moved into the range where the
initramfs image is loaded. Defining this will mean that
FIT-provided initramfs load addresses are ignored.
What STB Linux kernel did you observe this with? I am afraid this is still true about the ranges vs. allocation even in newer kernels, but that is kind of intented to keep the logic KISS (because it's already too complicated IMHO).
I investigated the allocation discrepancy and wrote the workaround while we were still using stblinux-3.14. Since then we've updated to stblinux-4.1 and I've left the workaround enabled, but I haven't investigated its interactions with the newer bmem mechanism. I should probably revisit this though, with stblinux-4.1 and stblinux-4.9, just to make sure this macro is still useful.
+config BCMSTB_SDHCI
- bool ""
- default y
+config BCMSTB_SDHCI_BASE
- hex ""
- default 0xf03e0200
+config BCMSTB_SPI_BASE
- hex ""
- default 0xf03e3400
Why don't you get those from the Device Tree blob that BOLT passes?
During development I did implement that for SDHCI_BASE, so it is possible. But I ended up #ifdef'ing it out and hard-coding the address in production, to keep the runtime logic simpler. Doing DTB traversal in code adds complexity but it may achieve portability to different BCM7xxx SoCs without further code changes, which would be nice.
+config CMD_FDT_MAX_DUMP
- int ""
- default 256
+config GENERIC_MMC
- bool ""
- default y
+config MMC_SDMA
- bool ""
- default y
+config SDHCI
- bool ""
- default y
+config SYS_BCMSTB_SPI_WAIT
- int ""
- default 10
+config SYS_FDT_SAVE_ADDRESS
- hex ""
- default 0x1f00000
+config SYS_NO_FLASH
- bool ""
- default y
+config TIMER_FREQUENCY_REGISTER_ADDRESS
- hex ""
- default 0xf0412020
+config TIMER_LOW_REGISTER_ADDRESS
- hex ""
- default 0xf0412008
All of these physical address ares not going to change given a 7445-based design, so why not hard code them in a header file unless you are keen on taking them from the passed Device Tree blob from BOLT?
Agreed, a header file or BOLT DTB lookup for these values would be better. I think for a v2 of the patch, I'll move these to a header file. If I get to adding another BCM7xxx board (I'm looking at BCM7260 right now) then I can revisit BOLT DTB lookups in the context of portability between the two SoCs.
+int dram_init_banksize(void) +{
- bd_t *bd = gd->bd;
- bd->bi_dram[0].start = 0x00000000;
- bd->bi_dram[0].size = 0x40000000;
- bd->bi_dram[1].start = 0x40000000;
- bd->bi_dram[1].size = 0x40000000;
- bd->bi_dram[2].start = 0x80000000;
- bd->bi_dram[2].size = 0x40000000;
This may be true for your system if you have 3x1GB populated, but 7445 supports additional extension regions, so this must be configurable if you want to make this flexible enough for other people to use it.
OK, I'm not familiar with extension regions. Would it be enough to size and initialize bi_dram based on different CONFIG_NR_DRAM_BANKS values?
+/* Copied from stblinux, include/linux/brcmstb/brcmstb.h. */ +#define DEV_RD(x) (readl((x))) +#define DEV_WR(x, y) do { writel((y), (x)); } while (0) +#define DEV_UNSET(x, y) do { DEV_WR((x), DEV_RD(x) & ~(y)); } while (0) +#define DEV_SET(x, y) do { DEV_WR((x), DEV_RD(x) | (y)); } while (0)
+#define DEV_WR_RB(x, y) do { DEV_WR((x), (y)); DEV_RD(x); } while (0) +#define DEV_SET_RB(x, y) do { DEV_SET((x), (y)); DEV_RD(x); } while (0) +#define DEV_UNSET_RB(x, y) do { DEV_UNSET((x), (y)); DEV_RD(x); } while (0)
I would just flat out drop those macros and instead use standard accessors. Those happen to work just fine given Broadcom STB's GISB bus, but if you want portable drivers in u-boot, and you likely would want those, you should use more standard I/O accessors.
OK, I'll look into this.
Thanks for reviewing, Thomas

On 05/10/2018 06:04 AM, Thomas Fitzsimmons wrote:
Florian Fainelli f.fainelli@gmail.com writes:
On 05/06/2018 04:09 AM, Thomas Fitzsimmons wrote:
Add support for loading U-Boot on the Broadcom 7445D0 SoC. This port assumes Broadcom's BOLT bootloader is acting as the second stage bootloader, and U-Boot is acting as the third stage bootloader, loaded as an ELF program by BOLT.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Stefan Roese sr@denx.de
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9bd70f4..b2df30a 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -498,6 +498,17 @@ config TARGET_VEXPRESS_CA15_TC2 select CPU_V7_HAS_VIRT select PL011_SERIAL
+config TARGET_BCM7445D0
- bool "Broadcom 7445D0 TSBL"
- select CPU_V7
- select SUPPORT_SPL
- help
Support for the Broadcom 7445D0 SoC. This port assumes Bolt
BOLT
is acting as the second stage bootloader, and U-Boot is
acting as the third stage bootloader (TSBL), loaded by Bolt.
again BOLT
Oops, will fix in a v2 patch.
This port may work on other BCM7xxx boards with
configuration changes.
There are other revisions than D0, so I would just name this TARGET_BCM7445. You would likely want to create a TARGET_BRCMSTB general menu which would encompass all ARMv7-A based SoCs from the Broadcom STB/CM division, and then have per-chip Kconfig options (similar to what the older <= 3.14 STB Linux kernels did).
OK, will try this in v2.
+config BCMSTB_ACCOMMODATE_STBLINUX
- bool ""
- default y
- help
This prevents U-Boot from adding memory reservations for the
lengths of initramfs and DTB. Without skipping these,
stblinux's "contiguous memory allocator" (CMA) Linux driver
(cma_driver) will allocate memory ranges smaller than what
are actually available, because it only checks reservation
sizes. It doesn't check if the reserved range overlaps the
range it allocates. stblinux also tries to move the DTB to
a lower memory location early in the Linux boot. If the FIT
image specifies a load address for the initramfs then
sometimes the DTB is moved into the range where the
initramfs image is loaded. Defining this will mean that
FIT-provided initramfs load addresses are ignored.
What STB Linux kernel did you observe this with? I am afraid this is still true about the ranges vs. allocation even in newer kernels, but that is kind of intented to keep the logic KISS (because it's already too complicated IMHO).
I investigated the allocation discrepancy and wrote the workaround while we were still using stblinux-3.14. Since then we've updated to stblinux-4.1 and I've left the workaround enabled, but I haven't investigated its interactions with the newer bmem mechanism. I should probably revisit this though, with stblinux-4.1 and stblinux-4.9, just to make sure this macro is still useful.
Sounds good, let me know if there is something that does not seem quite right, we could fix it.
+config BCMSTB_SDHCI
- bool ""
- default y
+config BCMSTB_SDHCI_BASE
- hex ""
- default 0xf03e0200
+config BCMSTB_SPI_BASE
- hex ""
- default 0xf03e3400
Why don't you get those from the Device Tree blob that BOLT passes?
During development I did implement that for SDHCI_BASE, so it is possible. But I ended up #ifdef'ing it out and hard-coding the address in production, to keep the runtime logic simpler. Doing DTB traversal in code adds complexity but it may achieve portability to different BCM7xxx SoCs without further code changes, which would be nice.
Given what I see with Broadcom STB customers, I don't think there is a strong push for anything other than BOLT, or another proprietary TSBL, so with that, I am not sure about whether there would be an use case for e.g; a single u-boot binary that would run on more than a flavor of a given SoC. I would be inclined to put the different base register addresses into a header file and use those constants in the respective drivers (or even better, in the part of code that does register those).
+config CMD_FDT_MAX_DUMP
- int ""
- default 256
+config GENERIC_MMC
- bool ""
- default y
+config MMC_SDMA
- bool ""
- default y
+config SDHCI
- bool ""
- default y
+config SYS_BCMSTB_SPI_WAIT
- int ""
- default 10
+config SYS_FDT_SAVE_ADDRESS
- hex ""
- default 0x1f00000
+config SYS_NO_FLASH
- bool ""
- default y
+config TIMER_FREQUENCY_REGISTER_ADDRESS
- hex ""
- default 0xf0412020
+config TIMER_LOW_REGISTER_ADDRESS
- hex ""
- default 0xf0412008
All of these physical address ares not going to change given a 7445-based design, so why not hard code them in a header file unless you are keen on taking them from the passed Device Tree blob from BOLT?
Agreed, a header file or BOLT DTB lookup for these values would be better. I think for a v2 of the patch, I'll move these to a header file. If I get to adding another BCM7xxx board (I'm looking at BCM7260 right now) then I can revisit BOLT DTB lookups in the context of portability between the two SoCs.
Sounds good.
+int dram_init_banksize(void) +{
- bd_t *bd = gd->bd;
- bd->bi_dram[0].start = 0x00000000;
- bd->bi_dram[0].size = 0x40000000;
- bd->bi_dram[1].start = 0x40000000;
- bd->bi_dram[1].size = 0x40000000;
- bd->bi_dram[2].start = 0x80000000;
- bd->bi_dram[2].size = 0x40000000;
This may be true for your system if you have 3x1GB populated, but 7445 supports additional extension regions, so this must be configurable if you want to make this flexible enough for other people to use it.
OK, I'm not familiar with extension regions. Would it be enough to size and initialize bi_dram based on different CONFIG_NR_DRAM_BANKS values?
Humm, sure that would be a good step forward. This is something that might be best extracted from the Device Tree provided by BOLT because there is a standard memory node's "reg" property being provided.
A possible challenge with u-boot's bi_dram structure is that the extension regions are way above the 4GB PA boundary. As long as you don't need to access those in u-boot, you should be fine with a "standard setup" (short page table descriptors etc.).

Florian Fainelli f.fainelli@gmail.com writes:
On 05/10/2018 06:04 AM, Thomas Fitzsimmons wrote:
Florian Fainelli f.fainelli@gmail.com writes:
On 05/06/2018 04:09 AM, Thomas Fitzsimmons wrote:
[...]
+config BCMSTB_ACCOMMODATE_STBLINUX
- bool ""
- default y
- help
This prevents U-Boot from adding memory reservations for the
lengths of initramfs and DTB. Without skipping these,
stblinux's "contiguous memory allocator" (CMA) Linux driver
(cma_driver) will allocate memory ranges smaller than what
are actually available, because it only checks reservation
sizes. It doesn't check if the reserved range overlaps the
range it allocates. stblinux also tries to move the DTB to
a lower memory location early in the Linux boot. If the FIT
image specifies a load address for the initramfs then
sometimes the DTB is moved into the range where the
initramfs image is loaded. Defining this will mean that
FIT-provided initramfs load addresses are ignored.
What STB Linux kernel did you observe this with? I am afraid this is still true about the ranges vs. allocation even in newer kernels, but that is kind of intented to keep the logic KISS (because it's already too complicated IMHO).
I investigated the allocation discrepancy and wrote the workaround while we were still using stblinux-3.14. Since then we've updated to stblinux-4.1 and I've left the workaround enabled, but I haven't investigated its interactions with the newer bmem mechanism. I should probably revisit this though, with stblinux-4.1 and stblinux-4.9, just to make sure this macro is still useful.
Sounds good, let me know if there is something that does not seem quite right, we could fix it.
[...]
In the v3 patch, I keep the FIT's RFS and DTB in-place. This approach eliminates the bmem/cma allocation discrepancies. I compared bmem/cma dmesg output for stblinux 3.14, 4.1 and 4.9, zImage and ITB builds, on my eval board, and they're all the same for the same kernel version. The only thing I noticed is that in 3.14 and 4.1 (zImage and ITB), the first bmem region is:
768 MiB at 0x0000000010000000
whereas in 4.9 (zImage and ITB), it is:
760 MiB at 0x0000000010800000
This is booting with no kernel command line arguments, so I guess some default may have changed between stblinux 4.1 and 4.9?
Thomas

On 06/06/2018 01:39 PM, Thomas Fitzsimmons wrote:
Florian Fainelli f.fainelli@gmail.com writes:
On 05/10/2018 06:04 AM, Thomas Fitzsimmons wrote:
Florian Fainelli f.fainelli@gmail.com writes:
On 05/06/2018 04:09 AM, Thomas Fitzsimmons wrote:
[...]
+config BCMSTB_ACCOMMODATE_STBLINUX
- bool ""
- default y
- help
This prevents U-Boot from adding memory reservations for the
lengths of initramfs and DTB. Without skipping these,
stblinux's "contiguous memory allocator" (CMA) Linux driver
(cma_driver) will allocate memory ranges smaller than what
are actually available, because it only checks reservation
sizes. It doesn't check if the reserved range overlaps the
range it allocates. stblinux also tries to move the DTB to
a lower memory location early in the Linux boot. If the FIT
image specifies a load address for the initramfs then
sometimes the DTB is moved into the range where the
initramfs image is loaded. Defining this will mean that
FIT-provided initramfs load addresses are ignored.
What STB Linux kernel did you observe this with? I am afraid this is still true about the ranges vs. allocation even in newer kernels, but that is kind of intented to keep the logic KISS (because it's already too complicated IMHO).
I investigated the allocation discrepancy and wrote the workaround while we were still using stblinux-3.14. Since then we've updated to stblinux-4.1 and I've left the workaround enabled, but I haven't investigated its interactions with the newer bmem mechanism. I should probably revisit this though, with stblinux-4.1 and stblinux-4.9, just to make sure this macro is still useful.
Sounds good, let me know if there is something that does not seem quite right, we could fix it.
[...]
In the v3 patch, I keep the FIT's RFS and DTB in-place. This approach eliminates the bmem/cma allocation discrepancies. I compared bmem/cma dmesg output for stblinux 3.14, 4.1 and 4.9, zImage and ITB builds, on my eval board, and they're all the same for the same kernel version. The only thing I noticed is that in 3.14 and 4.1 (zImage and ITB), the first bmem region is:
768 MiB at 0x0000000010000000
whereas in 4.9 (zImage and ITB), it is:
760 MiB at 0x0000000010800000
This is booting with no kernel command line arguments, so I guess some default may have changed between stblinux 4.1 and 4.9?
This upstream commit is responsible for what you see: 6ff0966052c46efb53980b8a1add2e7b49c9f560 ("ARM: 8432/1: move VMALLOC_END from 0xff000000 to 0xff800000") we've backported that change to our 3.14 and 4.1 kernels since then.

Add support for Broadcom BCM7445
Changes for v2: - Reorganize Kconfig to create ARCH_BCMSTB - Use generic bcmstb SoC name wherever possible - Eliminate crt0.S changes by moving relocation logic to bcmstb.c - Use debug() macro where appropriate - Read bcmstb_spi register base addresses from prior stage device tree, where possible - Read bcmstb_sdhci register base address from prior stage DT - Make timer register addresses configurable - Fix BOLT typos - Eliminate CONFIG_BCMSTB_ACCOMMODATE_STBLINUX by keeping FIT initramfs and device tree binary in-place - Add README.bcm7xxx - Read memory configuration from prior stage device tree - Add CONFIG_OF_PRIOR_STAGE support in spi-uclass.c - Fix issues reported by checkpatch.pl - Fix issues reported by sparse - Update some comments and formatting - Add a MAINTAINERS file
Thomas Fitzsimmons (1): board: arm: Add support for Broadcom BCM7445
arch/arm/Kconfig | 12 + arch/arm/Makefile | 1 + arch/arm/mach-bcmstb/Kconfig | 64 ++++ arch/arm/mach-bcmstb/Makefile | 9 + arch/arm/mach-bcmstb/include/mach/gpio.h | 12 + arch/arm/mach-bcmstb/include/mach/hardware.h | 12 + arch/arm/mach-bcmstb/include/mach/prior_stage.h | 31 ++ arch/arm/mach-bcmstb/include/mach/sdhci.h | 16 + arch/arm/mach-bcmstb/include/mach/timer.h | 14 + arch/arm/mach-bcmstb/lowlevel_init.S | 22 ++ board/broadcom/bcmstb/MAINTAINERS | 6 + board/broadcom/bcmstb/Makefile | 9 + board/broadcom/bcmstb/bcmstb.c | 192 +++++++++++ configs/bcm7445_defconfig | 27 ++ doc/README.bcm7xxx | 147 ++++++++ drivers/mmc/Kconfig | 11 + drivers/mmc/Makefile | 1 + drivers/mmc/bcmstb_sdhci.c | 68 ++++ drivers/spi/Kconfig | 7 + drivers/spi/Makefile | 1 + drivers/spi/bcmstb_spi.c | 440 ++++++++++++++++++++++++ drivers/spi/spi-uclass.c | 2 +- dts/Kconfig | 7 + include/configs/bcmstb.h | 189 ++++++++++ include/fdtdec.h | 4 + lib/fdtdec.c | 4 + 26 files changed, 1307 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-bcmstb/Kconfig create mode 100644 arch/arm/mach-bcmstb/Makefile create mode 100644 arch/arm/mach-bcmstb/include/mach/gpio.h create mode 100644 arch/arm/mach-bcmstb/include/mach/hardware.h create mode 100644 arch/arm/mach-bcmstb/include/mach/prior_stage.h create mode 100644 arch/arm/mach-bcmstb/include/mach/sdhci.h create mode 100644 arch/arm/mach-bcmstb/include/mach/timer.h create mode 100644 arch/arm/mach-bcmstb/lowlevel_init.S create mode 100644 board/broadcom/bcmstb/MAINTAINERS create mode 100644 board/broadcom/bcmstb/Makefile create mode 100644 board/broadcom/bcmstb/bcmstb.c create mode 100644 configs/bcm7445_defconfig create mode 100644 doc/README.bcm7xxx create mode 100644 drivers/mmc/bcmstb_sdhci.c create mode 100644 drivers/spi/bcmstb_spi.c create mode 100644 include/configs/bcmstb.h

Add support for loading U-Boot on the Broadcom 7445 SoC. This port assumes Broadcom's BOLT bootloader is acting as the second stage bootloader, and U-Boot is acting as the third stage bootloader, loaded as an ELF program by BOLT.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Stefan Roese sr@denx.de Cc: Tom Rini trini@konsulko.com Cc: Florian Fainelli f.fainelli@gmail.com --- Changes for v2: - Reorganize Kconfig to create ARCH_BCMSTB - Use generic bcmstb SoC name wherever possible - Eliminate crt0.S changes by moving relocation logic to bcmstb.c - Use debug() macro where appropriate - Read bcmstb_spi register base addresses from prior stage device tree, where possible - Read bcmstb_sdhci register base address from prior stage DT - Make timer register addresses configurable - Fix BOLT typos - Eliminate CONFIG_BCMSTB_ACCOMMODATE_STBLINUX by keeping FIT initramfs and device tree binary in-place - Add README.bcm7xxx - Read memory configuration from prior stage device tree - Add CONFIG_OF_PRIOR_STAGE support in spi-uclass.c - Fix issues reported by checkpatch.pl - Fix issues reported by sparse - Update some comments and formatting - Add a MAINTAINERS file
arch/arm/Kconfig | 12 + arch/arm/Makefile | 1 + arch/arm/mach-bcmstb/Kconfig | 64 ++++ arch/arm/mach-bcmstb/Makefile | 9 + arch/arm/mach-bcmstb/include/mach/gpio.h | 12 + arch/arm/mach-bcmstb/include/mach/hardware.h | 12 + arch/arm/mach-bcmstb/include/mach/prior_stage.h | 31 ++ arch/arm/mach-bcmstb/include/mach/sdhci.h | 16 + arch/arm/mach-bcmstb/include/mach/timer.h | 14 + arch/arm/mach-bcmstb/lowlevel_init.S | 22 ++ board/broadcom/bcmstb/MAINTAINERS | 6 + board/broadcom/bcmstb/Makefile | 9 + board/broadcom/bcmstb/bcmstb.c | 192 +++++++++++ configs/bcm7445_defconfig | 27 ++ doc/README.bcm7xxx | 147 ++++++++ drivers/mmc/Kconfig | 11 + drivers/mmc/Makefile | 1 + drivers/mmc/bcmstb_sdhci.c | 68 ++++ drivers/spi/Kconfig | 7 + drivers/spi/Makefile | 1 + drivers/spi/bcmstb_spi.c | 440 ++++++++++++++++++++++++ drivers/spi/spi-uclass.c | 2 +- dts/Kconfig | 7 + include/configs/bcmstb.h | 189 ++++++++++ include/fdtdec.h | 4 + lib/fdtdec.c | 4 + 26 files changed, 1307 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-bcmstb/Kconfig create mode 100644 arch/arm/mach-bcmstb/Makefile create mode 100644 arch/arm/mach-bcmstb/include/mach/gpio.h create mode 100644 arch/arm/mach-bcmstb/include/mach/hardware.h create mode 100644 arch/arm/mach-bcmstb/include/mach/prior_stage.h create mode 100644 arch/arm/mach-bcmstb/include/mach/sdhci.h create mode 100644 arch/arm/mach-bcmstb/include/mach/timer.h create mode 100644 arch/arm/mach-bcmstb/lowlevel_init.S create mode 100644 board/broadcom/bcmstb/MAINTAINERS create mode 100644 board/broadcom/bcmstb/Makefile create mode 100644 board/broadcom/bcmstb/bcmstb.c create mode 100644 configs/bcm7445_defconfig create mode 100644 doc/README.bcm7xxx create mode 100644 drivers/mmc/bcmstb_sdhci.c create mode 100644 drivers/spi/bcmstb_spi.c create mode 100644 include/configs/bcmstb.h
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9bd70f4..fa3089f 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -498,6 +498,16 @@ config TARGET_VEXPRESS_CA15_TC2 select CPU_V7_HAS_VIRT select PL011_SERIAL
+config ARCH_BCMSTB + bool "Broadcom BCM7XXX family" + select CPU_V7 + select DM + select OF_CONTROL + select OF_PRIOR_STAGE + help + This enables support for Broadcom ARM-based set-top box + chipsets, including the 7445 family of chips. + config TARGET_VEXPRESS_CA5X2 bool "Support vexpress_ca5x2" select CPU_V7 @@ -1237,6 +1247,8 @@ source "arch/arm/mach-at91/Kconfig"
source "arch/arm/mach-bcm283x/Kconfig"
+source "arch/arm/mach-bcmstb/Kconfig" + source "arch/arm/mach-davinci/Kconfig"
source "arch/arm/mach-exynos/Kconfig" diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 4fa8b38..b0cd152 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -53,6 +53,7 @@ PLATFORM_CPPFLAGS += $(arch-y) $(tune-y) machine-$(CONFIG_ARCH_ASPEED) += aspeed machine-$(CONFIG_ARCH_AT91) += at91 machine-$(CONFIG_ARCH_BCM283X) += bcm283x +machine-$(CONFIG_ARCH_BCMSTB) += bcmstb machine-$(CONFIG_ARCH_DAVINCI) += davinci machine-$(CONFIG_ARCH_EXYNOS) += exynos machine-$(CONFIG_ARCH_HIGHBANK) += highbank diff --git a/arch/arm/mach-bcmstb/Kconfig b/arch/arm/mach-bcmstb/Kconfig new file mode 100644 index 0000000..0c9dcda --- /dev/null +++ b/arch/arm/mach-bcmstb/Kconfig @@ -0,0 +1,64 @@ +if ARCH_BCMSTB + +config TARGET_BCM7445 + bool "Broadcom 7445 TSBL" + depends on ARCH_BCMSTB + help + Support for the Broadcom 7445 SoC. This port assumes BOLT + is acting as the second stage bootloader, and U-Boot is + acting as the third stage bootloader (TSBL), loaded by BOLT. + This port may work on other BCM7xxx boards with + configuration changes. + +config SYS_CPU + default "armv7" + +config SYS_BOARD + default "bcmstb" + +config SYS_VENDOR + default "broadcom" + +config SYS_SOC + default "bcmstb" + +config SYS_CONFIG_NAME + default "bcmstb" + +config SYS_FDT_SAVE_ADDRESS + hex "Address to which the prior stage provided DTB will be copied" + default 0x1f00000 + +config BCMSTB_SDHCI_INDEX + int "Index of preferred BCMSTB SDHCI alias in DTB" + default 1 + +config BCMSTB_SDHCI_BASE + hex "Physical base address of the BCMSTB SDHCI controller" + default 0xf03e0200 + +config BCMSTB_TIMER_LOW + hex "Address of BCMSTB timer low register" + default 0xf0412008 + +config BCMSTB_TIMER_FREQUENCY + hex "Address of BCMSTB timer frequency register" + default 0xf0412020 + +config BCMSTB_HIF_MSPI_BASE + hex "BCMSTB SPI hif_mspi base address" + default 0xf03e3400 + +config BCMSTB_BSPI_BASE + hex "BCMSTB SPI bspi base address" + default 0xf03e3200 + +config BCMSTB_HIF_SPI_INTR2 + hex "BCMSTB SPI hif_spi_intr2 base address" + default 0xf03e1a00 + +config BCMSTB_CS_REG + hex "BCMSTB SPI cs_reg address" + default 0xf03e0920 + +endif diff --git a/arch/arm/mach-bcmstb/Makefile b/arch/arm/mach-bcmstb/Makefile new file mode 100644 index 0000000..2c5da6b --- /dev/null +++ b/arch/arm/mach-bcmstb/Makefile @@ -0,0 +1,9 @@ +# +# (C) Copyright 2018 Cisco Systems, Inc. +# +# Author: Thomas Fitzsimmons fitzsim@fitzsim.org +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y := lowlevel_init.o diff --git a/arch/arm/mach-bcmstb/include/mach/gpio.h b/arch/arm/mach-bcmstb/include/mach/gpio.h new file mode 100644 index 0000000..a1d0d3b --- /dev/null +++ b/arch/arm/mach-bcmstb/include/mach/gpio.h @@ -0,0 +1,12 @@ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _BCMSTB_GPIO_H +#define _BCMSTB_GPIO_H + +#endif /* _BCMSTB_GPIO_H */ diff --git a/arch/arm/mach-bcmstb/include/mach/hardware.h b/arch/arm/mach-bcmstb/include/mach/hardware.h new file mode 100644 index 0000000..6b0bbbd --- /dev/null +++ b/arch/arm/mach-bcmstb/include/mach/hardware.h @@ -0,0 +1,12 @@ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _BCMSTB_HARDWARE_H +#define _BCMSTB_HARDWARE_H + +#endif /* _BCMSTB_HARDWARE_H */ diff --git a/arch/arm/mach-bcmstb/include/mach/prior_stage.h b/arch/arm/mach-bcmstb/include/mach/prior_stage.h new file mode 100644 index 0000000..4fa10b0 --- /dev/null +++ b/arch/arm/mach-bcmstb/include/mach/prior_stage.h @@ -0,0 +1,31 @@ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _BCMSTB_PRIOR_STAGE_H +#define _BCMSTB_PRIOR_STAGE_H + +#ifndef __ASSEMBLY__ + +#include <linux/types.h> + +struct bcmstb_boot_parameters { + u32 r0; + u32 r1; + u32 r2; + u32 r3; + u32 sp; + u32 lr; +}; + +extern struct bcmstb_boot_parameters bcmstb_boot_parameters; + +extern phys_addr_t prior_stage_fdt_address; + +#endif /* __ASSEMBLY__ */ + +#endif /* _BCMSTB_PRIOR_STAGE_H */ diff --git a/arch/arm/mach-bcmstb/include/mach/sdhci.h b/arch/arm/mach-bcmstb/include/mach/sdhci.h new file mode 100644 index 0000000..f3af388 --- /dev/null +++ b/arch/arm/mach-bcmstb/include/mach/sdhci.h @@ -0,0 +1,16 @@ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _BCMSTB_SDHCI_H +#define _BCMSTB_SDHCI_H + +#include <linux/types.h> + +int bcmstb_sdhci_init(phys_addr_t regbase); + +#endif /* _BCMSTB_SDHCI_H */ diff --git a/arch/arm/mach-bcmstb/include/mach/timer.h b/arch/arm/mach-bcmstb/include/mach/timer.h new file mode 100644 index 0000000..ca125a4 --- /dev/null +++ b/arch/arm/mach-bcmstb/include/mach/timer.h @@ -0,0 +1,14 @@ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _BCMSTB_TIMER_H +#define _BCMSTB_TIMER_H + +unsigned long timer_read_counter(void); + +#endif /* _BCMSTB_TIMER_H */ diff --git a/arch/arm/mach-bcmstb/lowlevel_init.S b/arch/arm/mach-bcmstb/lowlevel_init.S new file mode 100644 index 0000000..1eaac87 --- /dev/null +++ b/arch/arm/mach-bcmstb/lowlevel_init.S @@ -0,0 +1,22 @@ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <linux/linkage.h> + +ENTRY(save_boot_params) + ldr r6, =bcmstb_boot_parameters + str r0, [r6, #0] + str r1, [r6, #4] + str r2, [r6, #8] + str r3, [r6, #12] + str sp, [r6, #16] + str lr, [r6, #20] + ldr r6, =prior_stage_fdt_address + str r2, [r6] + b save_boot_params_ret +ENDPROC(save_boot_params) diff --git a/board/broadcom/bcmstb/MAINTAINERS b/board/broadcom/bcmstb/MAINTAINERS new file mode 100644 index 0000000..5e23ecd --- /dev/null +++ b/board/broadcom/bcmstb/MAINTAINERS @@ -0,0 +1,6 @@ +BCM7445 BOARD +M: Thomas Fitzsimmons fitzsim@fitzsim.org +S: Maintained +F: board/broadcom/bcmstb/ +F: include/configs/bcmstb.h +F: configs/bcm7445_defconfig diff --git a/board/broadcom/bcmstb/Makefile b/board/broadcom/bcmstb/Makefile new file mode 100644 index 0000000..4f03293 --- /dev/null +++ b/board/broadcom/bcmstb/Makefile @@ -0,0 +1,9 @@ +# +# (C) Copyright 2018 Cisco Systems, Inc. +# +# Author: Thomas Fitzsimmons fitzsim@fitzsim.org +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y := bcmstb.o diff --git a/board/broadcom/bcmstb/bcmstb.c b/board/broadcom/bcmstb/bcmstb.c new file mode 100644 index 0000000..f38478e --- /dev/null +++ b/board/broadcom/bcmstb/bcmstb.c @@ -0,0 +1,192 @@ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <linux/types.h> +#include <common.h> +#include <asm/io.h> +#include <asm/bootm.h> +#include <mach/sdhci.h> +#include <mach/timer.h> +#include <mmc.h> +#include <fdtdec.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define BCMSTB_DATA_SECTION __attribute__((section(".data"))) + +struct bcmstb_boot_parameters bcmstb_boot_parameters BCMSTB_DATA_SECTION; + +phys_addr_t prior_stage_fdt_address BCMSTB_DATA_SECTION; + +union reg_value_union { + const char *data; + const phys_addr_t *address; +}; + +int board_init(void) +{ + return 0; +} + +u32 get_board_rev(void) +{ + return 0; +} + +void reset_cpu(ulong ignored) +{ +} + +int print_cpuinfo(void) +{ + return 0; +} + +int dram_init(void) +{ + if (fdtdec_setup_memory_size() != 0) + return -EINVAL; + + return 0; +} + +int dram_init_banksize(void) +{ + fdtdec_setup_memory_banksize(); + + /* + * On this SoC, U-Boot is running as an ELF file. Change the + * relocation address to CONFIG_SYS_TEXT_BASE, so that in + * setup_reloc, gd->reloc_off works out to 0, effectively + * disabling relocation. Otherwise U-Boot hangs in the setup + * instructions just before relocate_code in + * arch/arm/lib/crt0.S. + */ + gd->relocaddr = CONFIG_SYS_TEXT_BASE; + + return 0; +} + +void enable_caches(void) +{ + /* + * Nothing required here, since the prior stage bootloader has + * enabled I-cache and D-cache already. Implementing this + * function silences the warning in the default function. + */ +} + +static const phys_addr_t bcmstb_sdhci_address(u32 alias_index) +{ + int node = 0; + int ret = 0; + char sdhci[16] = { 0 }; + const void *fdt = gd->fdt_blob; + const char *path = NULL; + struct fdt_resource resource = { 0 }; + + if (!fdt) { + printf("%s: Invalid gd->fdt_blob\n", __func__); + return 0; + } + + node = fdt_path_offset(fdt, "/aliases"); + if (node < 0) { + printf("%s: Failed to find /aliases node\n", __func__); + return 0; + } + + sprintf(sdhci, "sdhci%d", alias_index); + path = fdt_getprop(fdt, node, sdhci, NULL); + if (!path) { + printf("%s: Failed to find alias for %s\n", __func__, sdhci); + return 0; + } + + node = fdt_path_offset(fdt, path); + if (node < 0) { + printf("%s: Failed to resolve BCMSTB SDHCI alias\n", __func__); + return 0; + } + + ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", + "host", &resource); + if (ret) { + printf("%s: Failed to read BCMSTB SDHCI host resource\n", + __func__); + return 0; + } + + return resource.start; +} + +int board_mmc_init(bd_t *bis) +{ + phys_addr_t sdhci_base_address = 0; + + sdhci_base_address = bcmstb_sdhci_address(CONFIG_BCMSTB_SDHCI_INDEX); + + if (!sdhci_base_address) { + sdhci_base_address = CONFIG_BCMSTB_SDHCI_BASE; + printf("%s: Assuming BCMSTB SDHCI address: 0x%p\n", + __func__, (void *)sdhci_base_address); + } + + debug("BCMSTB SDHCI base address: 0x%p\n", (void *)sdhci_base_address); + + bcmstb_sdhci_init(sdhci_base_address); + + return 0; +} + +int timer_init(void) +{ + gd->arch.timer_rate_hz = readl(CONFIG_BCMSTB_TIMER_FREQUENCY); + + return 0; +} + +ulong get_tbclk(void) +{ + return gd->arch.timer_rate_hz; +} + +unsigned long timer_read_counter(void) +{ + return readl(CONFIG_BCMSTB_TIMER_LOW); +} + +int board_late_init(void) +{ + debug("Arguments from prior stage bootloader:\n"); + debug("General Purpose Register 0: 0x%x\n", bcmstb_boot_parameters.r0); + debug("General Purpose Register 1: 0x%x\n", bcmstb_boot_parameters.r1); + debug("General Purpose Register 2: 0x%x\n", bcmstb_boot_parameters.r2); + debug("General Purpose Register 3: 0x%x\n", bcmstb_boot_parameters.r3); + debug("Stack Pointer Register: 0x%x\n", bcmstb_boot_parameters.sp); + debug("Link Register: 0x%x\n", bcmstb_boot_parameters.lr); + debug("Assuming timer frequency register at: 0x%p\n", + (void *)CONFIG_BCMSTB_TIMER_FREQUENCY); + debug("Read timer frequency (in Hz): %ld\n", gd->arch.timer_rate_hz); + debug("Prior stage provided DTB at: 0x%p\n", + (void *)prior_stage_fdt_address); + + /* + * Set fdtcontroladdr in the environment so that scripts can + * refer to it, for example, to reuse it for fdtaddr. + */ + env_set_hex("fdtcontroladdr", prior_stage_fdt_address); + + /* + * Do not set machid to the machine identifier value provided + * by the prior stage bootloader (bcmstb_boot_parameters.r1) + * because we're using a device tree to boot Linux. + */ + + return 0; +} diff --git a/configs/bcm7445_defconfig b/configs/bcm7445_defconfig new file mode 100644 index 0000000..46dea17 --- /dev/null +++ b/configs/bcm7445_defconfig @@ -0,0 +1,27 @@ +CONFIG_ARM=y +CONFIG_ARCH_BCMSTB=y +CONFIG_TARGET_BCM7445=y +CONFIG_USE_PRIVATE_LIBGCC=y +CONFIG_OF_CONTROL=y +CONFIG_OF_PRIOR_STAGE=y +CONFIG_DM=y +CONFIG_DM_SPI=y +CONFIG_DM_SPI_FLASH=y +CONFIG_SPI=y +CONFIG_SPI_FLASH=y +CONFIG_ENV_IS_IN_SPI_FLASH=y +CONFIG_BCMSTB_SPI=y +CONFIG_FIT=y +CONFIG_FIT_SIGNATURE=y +CONFIG_RSA=y +CONFIG_BLK=n +CONFIG_SDHCI=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_BCMSTB=y +CONFIG_CONS_INDEX=3 +CONFIG_BOOTDELAY=1 +CONFIG_SYS_PROMPT="U-Boot>" +CONFIG_HUSH_PARSER=y +CONFIG_SYS_TEXT_BASE=0x80100000 +CONFIG_SYS_NS16550_COM3=0xf040ab00 +CONFIG_EFI_LOADER=n diff --git a/doc/README.bcm7xxx b/doc/README.bcm7xxx new file mode 100644 index 0000000..0545d0b --- /dev/null +++ b/doc/README.bcm7xxx @@ -0,0 +1,147 @@ +Summary +======= + +This document describes how to use U-Boot on the Broadcom 7445 SoC, as +a third stage bootloader loaded by Broadcom's BOLT bootloader. + +BOLT loads U-Boot as a generic ELF binary. Some U-Boot features such +as networking are not yet available but other important features are, +including: + + - ext4 file system traversal + + - support for loading FIT images + + - advanced scripting + + - support for FIT-provided DTBs instead of relying on the + BOLT-provided DTB + +A customized version of this port has been used in production. The +same approach may work on other BCM7xxx boards, with some +configuration adjustments and memory layout experimentation. + +Build +===== + +make bcm7445_defconfig +make +${CROSS_COMPILE}strip u-boot + +Run +=== + +Flash the u-boot binary into board storage, then invoke it from BOLT. +For example: + +BOLT> boot -bsu -elf flash0.u-boot1 + +Flattened Image Tree Support +============================ + +What follows is an example FIT image source file. Build it with: + +mkimage -f image.its image.itb + +Booting the resulting image.itb was tested on BOLT v1.20, with the +following kernels: + +https://github.com/Broadcom/stblinux-3.14 +https://github.com/Broadcom/stblinux-4.1 +https://github.com/Broadcom/stblinux-4.9 + +and with a generic ARMv7 root file system. + +image.its: +/dts-v1/; +/ { + description = "BCM7445 FIT"; + images { + kernel@1 { + description = "Linux kernel"; + /* + * This kernel image output format can be + * generated with: + * + * make vmlinux + * ${CROSS_COMPILE}objcopy -O binary -S vmlinux vmlinux.bin + * gzip -9 vmlinux.bin + * + * For stblinux-3.14, the specific Broadcom + * board type should be configured in the + * kernel, for example CONFIG_BCM7445D0=y. + */ + data = /incbin/("<vmlinux.bin.gz>"); + type = "kernel"; + arch = "arm"; + os = "linux"; + compression = "gzip"; + load = <0x8000>; + entry = <0x8000>; + hash@1 { + algo = "sha256"; + }; + }; + ramdisk@1 { + description = "Initramfs root file system"; + data = /incbin/("<initramfs.cpio.gz>"); + type = "ramdisk"; + arch = "arm"; + os = "linux"; + compression = "gzip"; + /* + * Set the environment variable initrd_high to + * 0xffffffff, and set "load" and "entry" here + * to 0x0 to keep initramfs in-place and to + * accommodate stblinux bmem/CMA reservations. + */ + load = <0x0>; + entry = <0x0>; + hash@1 { + algo = "sha256"; + }; + }; + fdt@1 { + description = "Device tree dumped from BOLT"; + /* + * This DTB should be similar to the + * BOLT-generated device tree, after BOLT has + * done its runtime modifications to it. For + * example, it can be dumped from within + * U-Boot (at ${fdtcontroladdr}), after BOLT + * has loaded U-Boot. The result can be added + * to the Linux source tree as a .dts file. + * + * To support modifications to the device tree + * in-place in U-Boot, add to Linux's + * arch/arm/boot/dts/Makefile: + * + * DTC_FLAGS ?= -p 4096 + * + * This will leave some padding in the DTB and + * thus reserve room for node additions. + * + * Also, set the environment variable fdt_high + * to 0xffffffff to keep the DTB in-place and + * to accommodate stblinux bmem/CMA + * reservations. + */ + data = /incbin/("<bolt-<version>.dtb"); + type = "flat_dt"; + arch = "arm"; + compression = "none"; + hash@1 { + algo = "sha256"; + }; + }; + }; + configurations { + default = "conf@bcm7445"; + conf@bcm7445 { + description = "BCM7445 configuration"; + kernel = "kernel@1"; + ramdisk = "ramdisk@1"; + fdt = "fdt@1"; + }; + }; +}; diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 4fa8dd8..c734d18 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -364,6 +364,17 @@ config MMC_SDHCI_BCM2835
If unsure, say N.
+config MMC_SDHCI_BCMSTB + tristate "SDHCI support for the BCMSTB SD/MMC Controller" + depends on MMC_SDHCI + help + This selects the Broadcom set-top box SD/MMC controller. + + If you have a BCMSTB platform with SD or MMC devices, + say Y here. + + If unsure, say N. + config MMC_SDHCI_CADENCE bool "SDHCI support for the Cadence SD/SDIO/eMMC controller" depends on BLK && DM_MMC diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index cf46c33..14d5ef4 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_STM32_SDMMC2) += stm32_sdmmc2.o obj-$(CONFIG_MMC_SDHCI) += sdhci.o obj-$(CONFIG_MMC_SDHCI_ATMEL) += atmel_sdhci.o obj-$(CONFIG_MMC_SDHCI_BCM2835) += bcm2835_sdhci.o +obj-$(CONFIG_MMC_SDHCI_BCMSTB) += bcmstb_sdhci.o obj-$(CONFIG_MMC_SDHCI_CADENCE) += sdhci-cadence.o obj-$(CONFIG_MMC_SDHCI_KONA) += kona_sdhci.o obj-$(CONFIG_MMC_SDHCI_MSM) += msm_sdhci.o diff --git a/drivers/mmc/bcmstb_sdhci.c b/drivers/mmc/bcmstb_sdhci.c new file mode 100644 index 0000000..16cd1aa --- /dev/null +++ b/drivers/mmc/bcmstb_sdhci.c @@ -0,0 +1,68 @@ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <mach/sdhci.h> +#include <malloc.h> +#include <sdhci.h> + +/* + * The BCMSTB SDHCI has a quirk in that its actual maximum frequency + * capability is 100 MHz. The divisor that is eventually written to + * SDHCI_CLOCK_CONTROL is calculated based on what the MMC device + * reports, and relative to this maximum frequency. + * + * This define used to be set to 52000000 (52 MHz), the desired + * maximum frequency, but that would result in the communication + * actually running at 100 MHz (seemingly without issue), which is + * out-of-spec. + * + * Now, by setting this to 0 (auto-detect), 100 MHz will be read from + * the capabilities register, and the resulting divisor will be + * doubled, meaning that the clock control register will be set to the + * in-spec 52 MHz value. + */ +#define BCMSTB_SDHCI_MAXIMUM_CLOCK_FREQUENCY 0 +/* + * When the minimum clock frequency is set to 0 (auto-detect), U-Boot + * sets it to 100 MHz divided by SDHCI_MAX_DIV_SPEC_300, or 48,875 Hz, + * which results in the controller timing out when trying to + * communicate with the MMC device. Hard-code this value to 400000 + * (400 kHz) to prevent this. + */ +#define BCMSTB_SDHCI_MINIMUM_CLOCK_FREQUENCY 400000 + +static char *BCMSTB_SDHCI_NAME = "bcmstb-sdhci"; + +/* + * This driver has only been tested with eMMC devices; SD devices may + * not work. + */ +int bcmstb_sdhci_init(phys_addr_t regbase) +{ + struct sdhci_host *host = NULL; + + host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host)); + if (!host) { + printf("%s: Failed to allocate memory\n", __func__); + return 1; + } + memset(host, 0, sizeof(*host)); + + host->name = BCMSTB_SDHCI_NAME; + host->ioaddr = (void *)regbase; + host->quirks = 0; + + host->cfg.part_type = PART_TYPE_DOS; + + host->version = sdhci_readw(host, SDHCI_HOST_VERSION); + + return add_sdhci(host, + BCMSTB_SDHCI_MAXIMUM_CLOCK_FREQUENCY, + BCMSTB_SDHCI_MINIMUM_CLOCK_FREQUENCY); +} diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 6667f73..e5dccfc 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -66,6 +66,13 @@ config BCM63XX_SPI access the SPI NOR flash on platforms embedding these Broadcom SPI cores.
+config BCMSTB_SPI + bool "BCMSTB SPI driver" + help + Enable the Broadcom set-top box SPI driver. This driver can + be used to access the SPI flash on platforms embedding this + Broadcom SPI core. + config CADENCE_QSPI bool "Cadence QSPI driver" help diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 176bfa0..0f864be 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_ATH79_SPI) += ath79_spi.o obj-$(CONFIG_ATMEL_SPI) += atmel_spi.o obj-$(CONFIG_BCM63XX_HSSPI) += bcm63xx_hsspi.o obj-$(CONFIG_BCM63XX_SPI) += bcm63xx_spi.o +obj-$(CONFIG_BCMSTB_SPI) += bcmstb_spi.o obj-$(CONFIG_CADENCE_QSPI) += cadence_qspi.o cadence_qspi_apb.o obj-$(CONFIG_CF_SPI) += cf_spi.o obj-$(CONFIG_DAVINCI_SPI) += davinci_spi.o diff --git a/drivers/spi/bcmstb_spi.c b/drivers/spi/bcmstb_spi.c new file mode 100644 index 0000000..2ca0a06 --- /dev/null +++ b/drivers/spi/bcmstb_spi.c @@ -0,0 +1,440 @@ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <asm/io.h> +#include <command.h> +#include <config.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <log.h> +#include <malloc.h> +#include <spi.h> +#include <time.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define SPBR_MIN 8 +#define BITS_PER_WORD 8 + +#define NUM_TXRAM 32 +#define NUM_RXRAM 32 +#define NUM_CDRAM 16 + +/* hif_mspi register structure. */ +struct bcmstb_hif_mspi_regs { + u32 spcr0_lsb; /* 0x000 */ + u32 spcr0_msb; /* 0x004 */ + u32 spcr1_lsb; /* 0x008 */ + u32 spcr1_msb; /* 0x00c */ + u32 newqp; /* 0x010 */ + u32 endqp; /* 0x014 */ + u32 spcr2; /* 0x018 */ + u32 reserved0; /* 0x01c */ + u32 mspi_status; /* 0x020 */ + u32 cptqp; /* 0x024 */ + u32 spcr3; /* 0x028 */ + u32 revision; /* 0x02c */ + u32 reserved1[4]; /* 0x030 */ + u32 txram[NUM_TXRAM]; /* 0x040 */ + u32 rxram[NUM_RXRAM]; /* 0x0c0 */ + u32 cdram[NUM_CDRAM]; /* 0x140 */ + u32 write_lock; /* 0x180 */ +}; + +/* hif_mspi masks. */ +#define HIF_MSPI_SPCR2_CONT_AFTER_CMD_MASK 0x00000080 +#define HIF_MSPI_SPCR2_SPE_MASK 0x00000040 +#define HIF_MSPI_SPCR2_SPIFIE_MASK 0x00000020 +#define HIF_MSPI_WRITE_LOCK_WRITE_LOCK_MASK 0x00000001 + +/* bspi offsets. */ +#define BSPI_MAST_N_BOOT_CTRL 0x008 + +/* bspi_raf is not used in this driver. */ + +/* hif_spi_intr2 offsets and masks. */ +#define HIF_SPI_INTR2_CPU_CLEAR 0x08 +#define HIF_SPI_INTR2_CPU_MASK_SET 0x10 +#define HIF_SPI_INTR2_CPU_MASK_CLEAR 0x14 +#define HIF_SPI_INTR2_CPU_SET_MSPI_DONE_MASK 0x00000020 + +/* SPI transfer timeout in milliseconds. */ +#define HIF_MSPI_WAIT 10 + +enum bcmstb_base_type { + HIF_MSPI, + BSPI, + HIF_SPI_INTR2, + CS_REG, + BASE_LAST, +}; + +struct bcmstb_spi_platdata { + void *base[4]; +}; + +struct bcmstb_spi_priv { + struct bcmstb_hif_mspi_regs *regs; + void *bspi; + void *hif_spi_intr2; + void *cs_reg; + int default_cs; + int curr_cs; + uint tx_slot; + uint rx_slot; + u8 saved_cmd[NUM_CDRAM]; + uint saved_cmd_len; + void *saved_din_addr; +}; + +static int bcmstb_spi_ofdata_to_platdata(struct udevice *bus) +{ + struct bcmstb_spi_platdata *plat = dev_get_platdata(bus); + const void *fdt = gd->fdt_blob; + int node = dev_of_offset(bus); + int ret = 0; + int i = 0; + struct fdt_resource resource = { 0 }; + char *names[BASE_LAST] = { "hif_mspi", "bspi", "hif_spi_intr2", + "cs_reg" }; + const phys_addr_t defaults[BASE_LAST] = { CONFIG_BCMSTB_HIF_MSPI_BASE, + CONFIG_BCMSTB_BSPI_BASE, + CONFIG_BCMSTB_HIF_SPI_INTR2, + CONFIG_BCMSTB_CS_REG }; + + for (i = 0; i < BASE_LAST; i++) { + plat->base[i] = (void *)defaults[i]; + + ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", + names[i], &resource); + if (ret) { + printf("%s: Assuming BCMSTB SPI %s address 0x0x%p\n", + __func__, names[i], (void *)defaults[i]); + } else { + plat->base[i] = (void *)resource.start; + debug("BCMSTB SPI %s address: 0x0x%p\n", + names[i], (void *)plat->base[i]); + } + } + + return 0; +} + +static void bcmstb_spi_hw_set_parms(struct bcmstb_spi_priv *priv) +{ + writel(SPBR_MIN, &priv->regs->spcr0_lsb); + writel(BITS_PER_WORD << 2 | SPI_MODE_3, &priv->regs->spcr0_msb); +} + +static void bcmstb_spi_enable_interrupt(void *base, u32 mask) +{ + void *reg = base + HIF_SPI_INTR2_CPU_MASK_CLEAR; + + writel(readl(reg) | mask, reg); + readl(reg); +} + +static void bcmstb_spi_disable_interrupt(void *base, u32 mask) +{ + void *reg = base + HIF_SPI_INTR2_CPU_MASK_SET; + + writel(readl(reg) | mask, reg); + readl(reg); +} + +static void bcmstb_spi_clear_interrupt(void *base, u32 mask) +{ + void *reg = base + HIF_SPI_INTR2_CPU_CLEAR; + + writel(readl(reg) | mask, reg); + readl(reg); +} + +static int bcmstb_spi_probe(struct udevice *bus) +{ + struct bcmstb_spi_platdata *plat = dev_get_platdata(bus); + struct bcmstb_spi_priv *priv = dev_get_priv(bus); + + priv->regs = plat->base[HIF_MSPI]; + priv->bspi = plat->base[BSPI]; + priv->hif_spi_intr2 = plat->base[HIF_SPI_INTR2]; + priv->cs_reg = plat->base[CS_REG]; + priv->default_cs = 0; + priv->curr_cs = -1; + priv->tx_slot = 0; + priv->rx_slot = 0; + memset(priv->saved_cmd, 0, NUM_CDRAM); + priv->saved_cmd_len = 0; + priv->saved_din_addr = NULL; + + debug("spi_xfer: tx regs: 0x%p\n", &priv->regs->txram[0]); + debug("spi_xfer: rx regs: 0x%p\n", &priv->regs->rxram[0]); + + /* Disable BSPI. */ + writel(1, priv->bspi + BSPI_MAST_N_BOOT_CTRL); + readl(priv->bspi + BSPI_MAST_N_BOOT_CTRL); + + /* Set up interrupts. */ + bcmstb_spi_disable_interrupt(priv->hif_spi_intr2, 0xffffffff); + bcmstb_spi_clear_interrupt(priv->hif_spi_intr2, 0xffffffff); + bcmstb_spi_enable_interrupt(priv->hif_spi_intr2, + HIF_SPI_INTR2_CPU_SET_MSPI_DONE_MASK); + + /* Set up control registers. */ + writel(0, &priv->regs->spcr1_lsb); + writel(0, &priv->regs->spcr1_msb); + writel(0, &priv->regs->newqp); + writel(0, &priv->regs->endqp); + writel(HIF_MSPI_SPCR2_SPIFIE_MASK, &priv->regs->spcr2); + writel(0, &priv->regs->spcr3); + + bcmstb_spi_hw_set_parms(priv); + + return 0; +} + +static void bcmstb_spi_submit(struct bcmstb_spi_priv *priv, bool done) +{ + debug("WR NEWQP: %d\n", 0); + writel(0, &priv->regs->newqp); + + debug("WR ENDQP: %d\n", priv->tx_slot - 1); + writel(priv->tx_slot - 1, &priv->regs->endqp); + + if (done) { + debug("WR CDRAM[%d]: %02x\n", priv->tx_slot - 1, + readl(&priv->regs->cdram[priv->tx_slot - 1]) & ~0x80); + writel(readl(&priv->regs->cdram[priv->tx_slot - 1]) & ~0x80, + &priv->regs->cdram[priv->tx_slot - 1]); + } + + /* Force chip select first time. */ + if (priv->curr_cs != priv->default_cs) { + debug("spi_xfer: switching chip select to %d\n", + priv->default_cs); + writel((readl(priv->cs_reg) & ~0xff) | (1 << priv->default_cs), + priv->cs_reg); + readl(priv->cs_reg); + udelay(10); + priv->curr_cs = priv->default_cs; + } + + debug("WR WRITE_LOCK: %02x\n", 1); + writel((readl(&priv->regs->write_lock) & + ~HIF_MSPI_WRITE_LOCK_WRITE_LOCK_MASK) | 1, + &priv->regs->write_lock); + readl(&priv->regs->write_lock); + + debug("WR SPCR2: %02x\n", + HIF_MSPI_SPCR2_SPIFIE_MASK | + HIF_MSPI_SPCR2_SPE_MASK | + HIF_MSPI_SPCR2_CONT_AFTER_CMD_MASK); + writel(HIF_MSPI_SPCR2_SPIFIE_MASK | + HIF_MSPI_SPCR2_SPE_MASK | + HIF_MSPI_SPCR2_CONT_AFTER_CMD_MASK, + &priv->regs->spcr2); +} + +static int bcmstb_spi_wait(struct bcmstb_spi_priv *priv) +{ + u32 start_time = get_timer(0); + u32 status = readl(&priv->regs->mspi_status); + + while (!(status & 1)) { + if (get_timer(start_time) > HIF_MSPI_WAIT) + return -ETIMEDOUT; + status = readl(&priv->regs->mspi_status); + } + + writel(readl(&priv->regs->mspi_status) & ~1, &priv->regs->mspi_status); + bcmstb_spi_clear_interrupt(priv->hif_spi_intr2, + HIF_SPI_INTR2_CPU_SET_MSPI_DONE_MASK); + + return 0; +} + +static int bcmstb_spi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + uint len = bitlen / 8; + uint tx_len = len; + uint rx_len = len; + const u8 *out_bytes = (u8 *)dout; + u8 *in_bytes = (u8 *)din; + struct udevice *bus = dev_get_parent(dev); + struct bcmstb_spi_priv *priv = dev_get_priv(bus); + struct bcmstb_hif_mspi_regs *regs = priv->regs; + + debug("spi_xfer: %d, t: 0x%p, r: 0x%p, f: %lx\n", + len, dout, din, flags); + debug("spi_xfer: chip select: %x\n", readl(priv->cs_reg) & 0xff); + debug("spi_xfer: tx addr: 0x%p\n", ®s->txram[0]); + debug("spi_xfer: rx addr: 0x%p\n", ®s->rxram[0]); + debug("spi_xfer: cd addr: 0x%p\n", ®s->cdram[0]); + + if (flags & SPI_XFER_END) { + debug("spi_xfer: clearing saved din address: 0x%p\n", + priv->saved_din_addr); + priv->saved_din_addr = NULL; + priv->saved_cmd_len = 0; + memset(priv->saved_cmd, 0, NUM_CDRAM); + } + + if (bitlen == 0) + return 0; + + if (bitlen % 8) { + printf("%s: Non-byte-aligned transfer\n", __func__); + return -EOPNOTSUPP; + } + + if (flags & ~(SPI_XFER_BEGIN | SPI_XFER_END)) { + printf("%s: Unsupported flags: %lx\n", __func__, flags); + return -EOPNOTSUPP; + } + + if (flags & SPI_XFER_BEGIN) { + priv->tx_slot = 0; + priv->rx_slot = 0; + + if (out_bytes && len > NUM_CDRAM) { + printf("%s: Unable to save transfer\n", __func__); + return -EOPNOTSUPP; + } + + if (out_bytes && !(flags & SPI_XFER_END)) { + /* + * This is the start of a transmit operation + * that will need repeating if the calling + * code polls for the result. Save it for + * subsequent transmission. + */ + debug("spi_xfer: saving command: %x, %d\n", + out_bytes[0], len); + priv->saved_cmd_len = len; + memcpy(priv->saved_cmd, out_bytes, priv->saved_cmd_len); + } + } + + if (!(flags & (SPI_XFER_BEGIN | SPI_XFER_END))) { + if (priv->saved_din_addr == din) { + /* + * The caller is polling for status. Repeat + * the last transmission. + */ + int ret = 0; + + debug("spi_xfer: Making recursive call\n"); + ret = bcmstb_spi_xfer(dev, priv->saved_cmd_len * 8, + priv->saved_cmd, NULL, + SPI_XFER_BEGIN); + if (ret) { + printf("%s: Recursive call failed\n", __func__); + return ret; + } + } else { + debug("spi_xfer: saving din address: 0x%p\n", din); + priv->saved_din_addr = din; + } + } + + while (rx_len > 0) { + priv->rx_slot = priv->tx_slot; + + while (priv->tx_slot < NUM_CDRAM && tx_len > 0) { + bcmstb_spi_hw_set_parms(priv); + debug("WR TXRAM[%d]: %02x\n", priv->tx_slot, + out_bytes ? out_bytes[len - tx_len] : 0xff); + writel(out_bytes ? out_bytes[len - tx_len] : 0xff, + ®s->txram[priv->tx_slot << 1]); + debug("WR CDRAM[%d]: %02x\n", priv->tx_slot, 0x8e); + writel(0x8e, ®s->cdram[priv->tx_slot]); + priv->tx_slot++; + tx_len--; + if (!in_bytes) + rx_len--; + } + + debug("spi_xfer: early return clauses: %d, %d, %d\n", + len <= NUM_CDRAM, + !in_bytes, + (flags & (SPI_XFER_BEGIN | + SPI_XFER_END)) == SPI_XFER_BEGIN); + if (len <= NUM_CDRAM && + !in_bytes && + (flags & (SPI_XFER_BEGIN | SPI_XFER_END)) == SPI_XFER_BEGIN) + return 0; + + bcmstb_spi_submit(priv, tx_len == 0); + + if (bcmstb_spi_wait(priv) == -ETIMEDOUT) { + printf("%s: Timed out\n", __func__); + return -ETIMEDOUT; + } + + priv->tx_slot %= NUM_CDRAM; + + if (in_bytes) { + while (priv->rx_slot < NUM_CDRAM && rx_len > 0) { + in_bytes[len - rx_len] = + readl(®s->rxram[(priv->rx_slot << 1) + + 1]) + & 0xff; + debug("RD RXRAM[%d]: %02x\n", + priv->rx_slot, in_bytes[len - rx_len]); + priv->rx_slot++; + rx_len--; + } + } + } + + if (flags & SPI_XFER_END) { + debug("WR WRITE_LOCK: %02x\n", 0); + writel((readl(&priv->regs->write_lock) & + ~HIF_MSPI_WRITE_LOCK_WRITE_LOCK_MASK) | 0, + &priv->regs->write_lock); + readl(&priv->regs->write_lock); + } + + return 0; +} + +static int bcmstb_spi_set_speed(struct udevice *dev, uint speed) +{ + return 0; +} + +static int bcmstb_spi_set_mode(struct udevice *dev, uint mode) +{ + return 0; +} + +static const struct dm_spi_ops bcmstb_spi_ops = { + .xfer = bcmstb_spi_xfer, + .set_speed = bcmstb_spi_set_speed, + .set_mode = bcmstb_spi_set_mode, +}; + +static const struct udevice_id bcmstb_spi_id[] = { + { .compatible = "brcm,spi-brcmstb" }, + { } +}; + +U_BOOT_DRIVER(bcmstb_spi) = { + .name = "bcmstb_spi", + .id = UCLASS_SPI, + .of_match = bcmstb_spi_id, + .ops = &bcmstb_spi_ops, + .ofdata_to_platdata = bcmstb_spi_ofdata_to_platdata, + .probe = bcmstb_spi_probe, + .platdata_auto_alloc_size = sizeof(struct bcmstb_spi_platdata), + .priv_auto_alloc_size = sizeof(struct bcmstb_spi_priv), +}; diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index 15d90a5..ebb50aa 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -274,7 +274,7 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, bool created = false; int ret;
-#if CONFIG_IS_ENABLED(OF_PLATDATA) +#if CONFIG_IS_ENABLED(OF_PLATDATA) || CONFIG_IS_ENABLED(OF_PRIOR_STAGE) ret = uclass_first_device_err(UCLASS_SPI, &bus); #else ret = uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus); diff --git a/dts/Kconfig b/dts/Kconfig index 0cef225..a1a92f2 100644 --- a/dts/Kconfig +++ b/dts/Kconfig @@ -101,6 +101,13 @@ config OF_HOSTFILE This is only useful for Sandbox. Use the -d flag to U-Boot to specify the file to read.
+config OF_PRIOR_STAGE + bool "Prior stage bootloader DTB for DT control" + help + If this option is enabled, the device tree used for DT + control will be read from a device tree binary, at a memory + location passed to U-Boot by the prior stage bootloader. + endchoice
config DEFAULT_DEVICE_TREE diff --git a/include/configs/bcmstb.h b/include/configs/bcmstb.h new file mode 100644 index 0000000..12aabf1 --- /dev/null +++ b/include/configs/bcmstb.h @@ -0,0 +1,189 @@ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + * + * Configuration settings for the Broadcom BCM7445 SoC family. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#include "version.h" +#include <linux/sizes.h> +#include <asm/arch/prior_stage.h> + +/* + * Generic board configuration. + */ +#define CONFIG_SYS_GENERIC_BOARD + +/* + * CPU configuration. + */ +#define CONFIG_SKIP_LOWLEVEL_INIT + +/* + * Memory configuration. + * + * The prior stage BOLT bootloader sets up memory for us. + * + * An example boot memory layout after loading everything is: + * + * 0x0000 8000 vmlinux.bin.gz + * : [~31 MiB uncompressed max] + * 0x01ef f000 FIT containing signed public key + * : [~2 KiB in size] + * 0x01f0 0000 DTB copied from prior-stage-provided region + * : [~1 MiB max] + * 0x0200 0000 FIT containing ramdisk and device tree + * : initramfs.cpio.gz + * : [~208 MiB uncompressed max, to CMA/bmem low address] + * : [~80 MiB compressed max, to PSB low address] + * : device tree binary + * : [~60 KiB] + * 0x0700 0000 Prior stage bootloader (PSB) + * : + * 0x0761 7000 Prior-stage-provided device tree binary (DTB) + * : [~40 KiB in size] + * 0x0f00 0000 Contiguous memory allocator (CMA/bmem) low address + * : + * 0x8010 0000 U-Boot code at ELF load address + * : [~500 KiB in size, stripped] + * 0xc000 0000 Top of RAM + * + * Setting gd->relocaddr to CONFIG_SYS_TEXT_BASE in dram_init_banksize + * prevents U-Boot from relocating itself when it is run as an ELF + * program by the prior stage bootloader. + * + * We want to keep the ramdisk and FDT in the FIT image in-place, to + * accommodate stblinux's bmem and CMA regions. To accomplish this, + * we set initrd_high and fdt_high to 0xffffffff, and the load and + * entry addresses of the FIT ramdisk entry to 0x0. + * + * Overwriting the prior stage bootloader causes memory instability, + * so the compressed initramfs needs to fit between the load address + * and the PSB low address. In BOLT's default configuration this + * limits the compressed size of the initramfs to approximately 80 + * MiB. However, BOLT can be configured to allow loading larger + * initramfs images, in which case this limitation is eliminated. + */ +#define CONFIG_NR_DRAM_BANKS 3 + +#define CONFIG_SYS_SDRAM_BASE 0x00000000 +#define CONFIG_SYS_TEXT_BASE 0x80100000 +#define CONFIG_SYS_INIT_RAM_ADDR 0x80200000 +#define CONFIG_SYS_INIT_RAM_SIZE 0x100000 +#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_INIT_RAM_ADDR + \ + CONFIG_SYS_INIT_RAM_SIZE - \ + GENERATED_GBL_DATA_SIZE) +#define CONFIG_SYS_MALLOC_LEN ((10 * 1024) << 10) /* 10 MiB */ +#define CONFIG_SYS_LOAD_ADDR 0x2000000 + +/* + * CONFIG_SYS_LOAD_ADDR - 1 MiB. + */ +#define CONFIG_SYS_FDT_SAVE_ADDRESS 0x1f00000 +#define CONFIG_SYS_CBSIZE 512 +#define CONFIG_SYS_MAXARGS 32 + +/* + * Large kernel image bootm configuration. + */ +#define CONFIG_SYS_BOOTM_LEN SZ_64M + +/* + * NS16550 configuration. + */ +#define V_NS16550_CLK 81000000 + +#define CONFIG_SYS_NS16550 +#define CONFIG_SYS_NS16550_SERIAL +#define CONFIG_SYS_NS16550_REG_SIZE (-4) +#define CONFIG_SYS_NS16550_CLK V_NS16550_CLK + +/* + * Serial console configuration. + */ +#define CONFIG_SERIAL3 3 + +/* + * For now, this must be a pre-defined macro, not looked up from the + * prior-stage-provided DTB. + */ +#define CONFIG_SYS_NS16550_COM3 0xf040ab00 +#define CONFIG_BAUDRATE 115200 +#define CONFIG_SYS_BAUDRATE_TABLE {4800, 9600, 19200, 38400, 57600, \ + 115200} + +/* + * Informational display configuration. + */ +#define CONFIG_REVISION_TAG + +/* + * Command configuration. + */ +#define CONFIG_CMD_ASKENV +#define CONFIG_CMD_CACHE +#define CONFIG_CMD_EXT2 +#define CONFIG_CMD_SF +#define CONFIG_CMD_SPI +#define CONFIG_CMD_SF_TEST +#define CONFIG_CMD_MMC + +/* + * Flash configuration. + */ +#define CONFIG_ST_SMI +#define CONFIG_SPI_FLASH_STMICRO +#define CONFIG_SPI_FLASH_MACRONIX + +/* + * Filesystem configuration. + */ +#define CONFIG_DOS_PARTITION +#define CONFIG_CMD_EXT4 +#define CONFIG_FS_EXT4 +#define CONFIG_CMD_FS_GENERIC + +/* + * Environment configuration. + */ +#define CONFIG_SYS_REDUNDAND_ENVIRONMENT + +#define CONFIG_ENV_IS_IN_SPI_FLASH 1 +#define CONFIG_ENV_OFFSET 0x1e0000 +#define CONFIG_ENV_SIZE (64 << 10) /* 64 KiB */ +#define CONFIG_ENV_SECT_SIZE CONFIG_ENV_SIZE +#define CONFIG_ENV_OFFSET_REDUND (CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE) +#define CONFIG_ENV_OVERWRITE + +/* + * Save the prior stage provided DTB. + */ +#define CONFIG_PREBOOT \ + "fdt addr ${fdtcontroladdr};" \ + "fdt move ${fdtcontroladdr} ${fdtsaveaddr};" \ + "fdt addr ${fdtsaveaddr};" +/* + * Enable in-place RFS with this initrd_high setting. + */ +#define CONFIG_EXTRA_ENV_SETTINGS \ + "fdtsaveaddr=" __stringify(CONFIG_SYS_FDT_SAVE_ADDRESS) "\0" \ + "initrd_high=0xffffffff\0" \ + "fdt_high=0xffffffff\0" + +/* + * Set fdtaddr to prior stage-provided DTB in board_late_init, when + * writeable environment is available. + */ +#define CONFIG_BOARD_LATE_INIT + +#define CONFIG_SYS_MAX_FLASH_BANKS 1 + +#define CONFIG_DM_SPI 1 + +#endif /* __CONFIG_H */ diff --git a/include/fdtdec.h b/include/fdtdec.h index 2941a2e..84753e3 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -47,6 +47,10 @@ struct fdt_memory { #define SPL_BUILD 0 #endif
+#if CONFIG_IS_ENABLED(OF_PRIOR_STAGE) +extern phys_addr_t prior_stage_fdt_address; +#endif + /* * Information about a resource. start is the first address of the resource * and end is the last address (inclusive). The length of the resource will diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 320ee1d..5473a2d 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -1323,8 +1323,12 @@ int fdtdec_setup(void) # endif # ifndef CONFIG_SPL_BUILD /* Allow the early environment to override the fdt address */ +# if CONFIG_IS_ENABLED(OF_PRIOR_STAGE) + gd->fdt_blob = (void *)prior_stage_fdt_address; +# else gd->fdt_blob = (void *)env_get_ulong("fdtcontroladdr", 16, (uintptr_t)gd->fdt_blob); +# endif # endif
# if CONFIG_IS_ENABLED(MULTI_DTB_FIT)

On Wed, May 23, 2018 at 09:24:03PM -0400, Thomas Fitzsimmons wrote:
Add support for loading U-Boot on the Broadcom 7445 SoC. This port assumes Broadcom's BOLT bootloader is acting as the second stage bootloader, and U-Boot is acting as the third stage bootloader, loaded as an ELF program by BOLT.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Stefan Roese sr@denx.de Cc: Tom Rini trini@konsulko.com Cc: Florian Fainelli f.fainelli@gmail.com
Please rebase this to master. While I can fixup the SPDX tags (and some formatting issues from checkpatch.pl) I also run in to: +(bcm7445) In file included from ../arch/arm/include/asm/system.h:6:0, +(bcm7445) from ../arch/arm/include/asm/cache.h:11, +(bcm7445) from ../include/net.h:15, +(bcm7445) from ../include/common.h:519, +(bcm7445) from ../lib/asm-offsets.c:14: +(bcm7445) ../arch/arm/include/asm/barriers.h:32:24: error: operator '>=' has no left operand +(bcm7445) #if __LINUX_ARM_ARCH__ >= 7 +(bcm7445) ^~ +(bcm7445) ../arch/arm/include/asm/barriers.h:36:26: error: operator '==' has no left operand +(bcm7445) #elif __LINUX_ARM_ARCH__ == 6 +(bcm7445) ^~ +(bcm7445) make[2]: *** [.././Kbuild:44: lib/asm-offsets.s] Error 1 +(bcm7445) make[1]: *** [Makefile:1433: prepare0] Error 2
Please look into, thanks!

Tom Rini trini@konsulko.com writes:
On Wed, May 23, 2018 at 09:24:03PM -0400, Thomas Fitzsimmons wrote:
Add support for loading U-Boot on the Broadcom 7445 SoC. This port assumes Broadcom's BOLT bootloader is acting as the second stage bootloader, and U-Boot is acting as the third stage bootloader, loaded as an ELF program by BOLT.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Stefan Roese sr@denx.de Cc: Tom Rini trini@konsulko.com Cc: Florian Fainelli f.fainelli@gmail.com
Please rebase this to master. While I can fixup the SPDX tags (and some formatting issues from checkpatch.pl)
I think I fixed all of these in v3 (just posted), by adding an entry to top-level MAINTAINERS and using the new SPDX formatting rules.
I also run in to: +(bcm7445) In file included from ../arch/arm/include/asm/system.h:6:0, +(bcm7445) from ../arch/arm/include/asm/cache.h:11, +(bcm7445) from ../include/net.h:15, +(bcm7445) from ../include/common.h:519, +(bcm7445) from ../lib/asm-offsets.c:14: +(bcm7445) ../arch/arm/include/asm/barriers.h:32:24: error: operator '>=' has no left operand +(bcm7445) #if __LINUX_ARM_ARCH__ >= 7 +(bcm7445) ^~ +(bcm7445) ../arch/arm/include/asm/barriers.h:36:26: error: operator '==' has no left operand +(bcm7445) #elif __LINUX_ARM_ARCH__ == 6 +(bcm7445) ^~ +(bcm7445) make[2]: *** [.././Kbuild:44: lib/asm-offsets.s] Error 1 +(bcm7445) make[1]: *** [Makefile:1433: prepare0] Error 2
Please look into, thanks!
This was caused by a Kconfig option being renamed on master (CPU_V7 to CPU_V7A). Fixed in v3.
Thanks, Thomas

Add support for Broadcom BCM7445
Changes for v3: - Rebase to master - Add "ARM BROADCOM BCMSTB" entry to top-level MAINTAINERS - Fix SPDX formatting - In Kconfig use CPU_V7A, not CPU_V7, per acf15001...
Thomas Fitzsimmons (1): board: arm: Add support for Broadcom BCM7445
MAINTAINERS | 10 + arch/arm/Kconfig | 12 + arch/arm/Makefile | 1 + arch/arm/mach-bcmstb/Kconfig | 64 ++++ arch/arm/mach-bcmstb/Makefile | 8 + arch/arm/mach-bcmstb/include/mach/gpio.h | 11 + arch/arm/mach-bcmstb/include/mach/hardware.h | 11 + arch/arm/mach-bcmstb/include/mach/prior_stage.h | 30 ++ arch/arm/mach-bcmstb/include/mach/sdhci.h | 15 + arch/arm/mach-bcmstb/include/mach/timer.h | 13 + arch/arm/mach-bcmstb/lowlevel_init.S | 21 ++ board/broadcom/bcmstb/MAINTAINERS | 6 + board/broadcom/bcmstb/Makefile | 8 + board/broadcom/bcmstb/bcmstb.c | 191 +++++++++++ configs/bcm7445_defconfig | 27 ++ doc/README.bcm7xxx | 147 ++++++++ drivers/mmc/Kconfig | 11 + drivers/mmc/Makefile | 1 + drivers/mmc/bcmstb_sdhci.c | 67 ++++ drivers/spi/Kconfig | 7 + drivers/spi/Makefile | 1 + drivers/spi/bcmstb_spi.c | 439 ++++++++++++++++++++++++ drivers/spi/spi-uclass.c | 2 +- dts/Kconfig | 7 + include/configs/bcmstb.h | 188 ++++++++++ include/fdtdec.h | 4 + lib/fdtdec.c | 4 + 27 files changed, 1305 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-bcmstb/Kconfig create mode 100644 arch/arm/mach-bcmstb/Makefile create mode 100644 arch/arm/mach-bcmstb/include/mach/gpio.h create mode 100644 arch/arm/mach-bcmstb/include/mach/hardware.h create mode 100644 arch/arm/mach-bcmstb/include/mach/prior_stage.h create mode 100644 arch/arm/mach-bcmstb/include/mach/sdhci.h create mode 100644 arch/arm/mach-bcmstb/include/mach/timer.h create mode 100644 arch/arm/mach-bcmstb/lowlevel_init.S create mode 100644 board/broadcom/bcmstb/MAINTAINERS create mode 100644 board/broadcom/bcmstb/Makefile create mode 100644 board/broadcom/bcmstb/bcmstb.c create mode 100644 configs/bcm7445_defconfig create mode 100644 doc/README.bcm7xxx create mode 100644 drivers/mmc/bcmstb_sdhci.c create mode 100644 drivers/spi/bcmstb_spi.c create mode 100644 include/configs/bcmstb.h

Add support for loading U-Boot on the Broadcom 7445 SoC. This port assumes Broadcom's BOLT bootloader is acting as the second stage bootloader, and U-Boot is acting as the third stage bootloader, loaded as an ELF program by BOLT.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Stefan Roese sr@denx.de Cc: Tom Rini trini@konsulko.com Cc: Florian Fainelli f.fainelli@gmail.com --- Changes for v3: - Rebase to master - Add "ARM BROADCOM BCMSTB" entry to top-level MAINTAINERS - Fix SPDX formatting - In Kconfig use CPU_V7A, not CPU_V7, per acf15001...
MAINTAINERS | 10 + arch/arm/Kconfig | 12 + arch/arm/Makefile | 1 + arch/arm/mach-bcmstb/Kconfig | 64 ++++ arch/arm/mach-bcmstb/Makefile | 8 + arch/arm/mach-bcmstb/include/mach/gpio.h | 11 + arch/arm/mach-bcmstb/include/mach/hardware.h | 11 + arch/arm/mach-bcmstb/include/mach/prior_stage.h | 30 ++ arch/arm/mach-bcmstb/include/mach/sdhci.h | 15 + arch/arm/mach-bcmstb/include/mach/timer.h | 13 + arch/arm/mach-bcmstb/lowlevel_init.S | 21 ++ board/broadcom/bcmstb/MAINTAINERS | 6 + board/broadcom/bcmstb/Makefile | 8 + board/broadcom/bcmstb/bcmstb.c | 191 +++++++++++ configs/bcm7445_defconfig | 27 ++ doc/README.bcm7xxx | 147 ++++++++ drivers/mmc/Kconfig | 11 + drivers/mmc/Makefile | 1 + drivers/mmc/bcmstb_sdhci.c | 67 ++++ drivers/spi/Kconfig | 7 + drivers/spi/Makefile | 1 + drivers/spi/bcmstb_spi.c | 439 ++++++++++++++++++++++++ drivers/spi/spi-uclass.c | 2 +- dts/Kconfig | 7 + include/configs/bcmstb.h | 188 ++++++++++ include/fdtdec.h | 4 + lib/fdtdec.c | 4 + 27 files changed, 1305 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-bcmstb/Kconfig create mode 100644 arch/arm/mach-bcmstb/Makefile create mode 100644 arch/arm/mach-bcmstb/include/mach/gpio.h create mode 100644 arch/arm/mach-bcmstb/include/mach/hardware.h create mode 100644 arch/arm/mach-bcmstb/include/mach/prior_stage.h create mode 100644 arch/arm/mach-bcmstb/include/mach/sdhci.h create mode 100644 arch/arm/mach-bcmstb/include/mach/timer.h create mode 100644 arch/arm/mach-bcmstb/lowlevel_init.S create mode 100644 board/broadcom/bcmstb/MAINTAINERS create mode 100644 board/broadcom/bcmstb/Makefile create mode 100644 board/broadcom/bcmstb/bcmstb.c create mode 100644 configs/bcm7445_defconfig create mode 100644 doc/README.bcm7xxx create mode 100644 drivers/mmc/bcmstb_sdhci.c create mode 100644 drivers/spi/bcmstb_spi.c create mode 100644 include/configs/bcmstb.h
diff --git a/MAINTAINERS b/MAINTAINERS index 642c448..58634fc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -107,6 +107,16 @@ F: drivers/video/bcm2835.c F: include/dm/platform_data/serial_bcm283x_mu.h F: drivers/pinctrl/broadcom/
+ARM BROADCOM BCMSTB +M: Thomas Fitzsimmons fitzsim@fitzsim.org +S: Maintained +F: arch/arm/mach-bcmstb/ +F: board/broadcom/bcmstb/ +F: configs/bcm7445_defconfig +F: doc/README.bcm7xxx +F: drivers/mmc/bcmstb_sdhci.c +F: drivers/spi/bcmstb_spi.c + ARM FREESCALE IMX M: Stefano Babic sbabic@denx.de M: Fabio Estevam fabio.estevam@nxp.com diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index dde422b..fa2001b 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -533,6 +533,16 @@ config TARGET_VEXPRESS_CA15_TC2 select CPU_V7_HAS_VIRT select PL011_SERIAL
+config ARCH_BCMSTB + bool "Broadcom BCM7XXX family" + select CPU_V7A + select DM + select OF_CONTROL + select OF_PRIOR_STAGE + help + This enables support for Broadcom ARM-based set-top box + chipsets, including the 7445 family of chips. + config TARGET_VEXPRESS_CA5X2 bool "Support vexpress_ca5x2" select CPU_V7A @@ -1297,6 +1307,8 @@ source "arch/arm/mach-at91/Kconfig"
source "arch/arm/mach-bcm283x/Kconfig"
+source "arch/arm/mach-bcmstb/Kconfig" + source "arch/arm/mach-davinci/Kconfig"
source "arch/arm/mach-exynos/Kconfig" diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 680c6e8..03252fe 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -54,6 +54,7 @@ PLATFORM_CPPFLAGS += $(arch-y) $(tune-y) machine-$(CONFIG_ARCH_ASPEED) += aspeed machine-$(CONFIG_ARCH_AT91) += at91 machine-$(CONFIG_ARCH_BCM283X) += bcm283x +machine-$(CONFIG_ARCH_BCMSTB) += bcmstb machine-$(CONFIG_ARCH_DAVINCI) += davinci machine-$(CONFIG_ARCH_EXYNOS) += exynos machine-$(CONFIG_ARCH_HIGHBANK) += highbank diff --git a/arch/arm/mach-bcmstb/Kconfig b/arch/arm/mach-bcmstb/Kconfig new file mode 100644 index 0000000..0c9dcda --- /dev/null +++ b/arch/arm/mach-bcmstb/Kconfig @@ -0,0 +1,64 @@ +if ARCH_BCMSTB + +config TARGET_BCM7445 + bool "Broadcom 7445 TSBL" + depends on ARCH_BCMSTB + help + Support for the Broadcom 7445 SoC. This port assumes BOLT + is acting as the second stage bootloader, and U-Boot is + acting as the third stage bootloader (TSBL), loaded by BOLT. + This port may work on other BCM7xxx boards with + configuration changes. + +config SYS_CPU + default "armv7" + +config SYS_BOARD + default "bcmstb" + +config SYS_VENDOR + default "broadcom" + +config SYS_SOC + default "bcmstb" + +config SYS_CONFIG_NAME + default "bcmstb" + +config SYS_FDT_SAVE_ADDRESS + hex "Address to which the prior stage provided DTB will be copied" + default 0x1f00000 + +config BCMSTB_SDHCI_INDEX + int "Index of preferred BCMSTB SDHCI alias in DTB" + default 1 + +config BCMSTB_SDHCI_BASE + hex "Physical base address of the BCMSTB SDHCI controller" + default 0xf03e0200 + +config BCMSTB_TIMER_LOW + hex "Address of BCMSTB timer low register" + default 0xf0412008 + +config BCMSTB_TIMER_FREQUENCY + hex "Address of BCMSTB timer frequency register" + default 0xf0412020 + +config BCMSTB_HIF_MSPI_BASE + hex "BCMSTB SPI hif_mspi base address" + default 0xf03e3400 + +config BCMSTB_BSPI_BASE + hex "BCMSTB SPI bspi base address" + default 0xf03e3200 + +config BCMSTB_HIF_SPI_INTR2 + hex "BCMSTB SPI hif_spi_intr2 base address" + default 0xf03e1a00 + +config BCMSTB_CS_REG + hex "BCMSTB SPI cs_reg address" + default 0xf03e0920 + +endif diff --git a/arch/arm/mach-bcmstb/Makefile b/arch/arm/mach-bcmstb/Makefile new file mode 100644 index 0000000..71e5727 --- /dev/null +++ b/arch/arm/mach-bcmstb/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2018 Cisco Systems, Inc. +# +# Author: Thomas Fitzsimmons fitzsim@fitzsim.org +# + +obj-y := lowlevel_init.o diff --git a/arch/arm/mach-bcmstb/include/mach/gpio.h b/arch/arm/mach-bcmstb/include/mach/gpio.h new file mode 100644 index 0000000..bffecf9 --- /dev/null +++ b/arch/arm/mach-bcmstb/include/mach/gpio.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + */ + +#ifndef _BCMSTB_GPIO_H +#define _BCMSTB_GPIO_H + +#endif /* _BCMSTB_GPIO_H */ diff --git a/arch/arm/mach-bcmstb/include/mach/hardware.h b/arch/arm/mach-bcmstb/include/mach/hardware.h new file mode 100644 index 0000000..76f799d --- /dev/null +++ b/arch/arm/mach-bcmstb/include/mach/hardware.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + */ + +#ifndef _BCMSTB_HARDWARE_H +#define _BCMSTB_HARDWARE_H + +#endif /* _BCMSTB_HARDWARE_H */ diff --git a/arch/arm/mach-bcmstb/include/mach/prior_stage.h b/arch/arm/mach-bcmstb/include/mach/prior_stage.h new file mode 100644 index 0000000..6c36c68 --- /dev/null +++ b/arch/arm/mach-bcmstb/include/mach/prior_stage.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + */ + +#ifndef _BCMSTB_PRIOR_STAGE_H +#define _BCMSTB_PRIOR_STAGE_H + +#ifndef __ASSEMBLY__ + +#include <linux/types.h> + +struct bcmstb_boot_parameters { + u32 r0; + u32 r1; + u32 r2; + u32 r3; + u32 sp; + u32 lr; +}; + +extern struct bcmstb_boot_parameters bcmstb_boot_parameters; + +extern phys_addr_t prior_stage_fdt_address; + +#endif /* __ASSEMBLY__ */ + +#endif /* _BCMSTB_PRIOR_STAGE_H */ diff --git a/arch/arm/mach-bcmstb/include/mach/sdhci.h b/arch/arm/mach-bcmstb/include/mach/sdhci.h new file mode 100644 index 0000000..243783d --- /dev/null +++ b/arch/arm/mach-bcmstb/include/mach/sdhci.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + */ + +#ifndef _BCMSTB_SDHCI_H +#define _BCMSTB_SDHCI_H + +#include <linux/types.h> + +int bcmstb_sdhci_init(phys_addr_t regbase); + +#endif /* _BCMSTB_SDHCI_H */ diff --git a/arch/arm/mach-bcmstb/include/mach/timer.h b/arch/arm/mach-bcmstb/include/mach/timer.h new file mode 100644 index 0000000..d05b4d6 --- /dev/null +++ b/arch/arm/mach-bcmstb/include/mach/timer.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + */ + +#ifndef _BCMSTB_TIMER_H +#define _BCMSTB_TIMER_H + +unsigned long timer_read_counter(void); + +#endif /* _BCMSTB_TIMER_H */ diff --git a/arch/arm/mach-bcmstb/lowlevel_init.S b/arch/arm/mach-bcmstb/lowlevel_init.S new file mode 100644 index 0000000..aa81f70 --- /dev/null +++ b/arch/arm/mach-bcmstb/lowlevel_init.S @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + */ + +#include <linux/linkage.h> + +ENTRY(save_boot_params) + ldr r6, =bcmstb_boot_parameters + str r0, [r6, #0] + str r1, [r6, #4] + str r2, [r6, #8] + str r3, [r6, #12] + str sp, [r6, #16] + str lr, [r6, #20] + ldr r6, =prior_stage_fdt_address + str r2, [r6] + b save_boot_params_ret +ENDPROC(save_boot_params) diff --git a/board/broadcom/bcmstb/MAINTAINERS b/board/broadcom/bcmstb/MAINTAINERS new file mode 100644 index 0000000..5e23ecd --- /dev/null +++ b/board/broadcom/bcmstb/MAINTAINERS @@ -0,0 +1,6 @@ +BCM7445 BOARD +M: Thomas Fitzsimmons fitzsim@fitzsim.org +S: Maintained +F: board/broadcom/bcmstb/ +F: include/configs/bcmstb.h +F: configs/bcm7445_defconfig diff --git a/board/broadcom/bcmstb/Makefile b/board/broadcom/bcmstb/Makefile new file mode 100644 index 0000000..9609887 --- /dev/null +++ b/board/broadcom/bcmstb/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2018 Cisco Systems, Inc. +# +# Author: Thomas Fitzsimmons fitzsim@fitzsim.org +# + +obj-y := bcmstb.o diff --git a/board/broadcom/bcmstb/bcmstb.c b/board/broadcom/bcmstb/bcmstb.c new file mode 100644 index 0000000..2544497 --- /dev/null +++ b/board/broadcom/bcmstb/bcmstb.c @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + */ + +#include <linux/types.h> +#include <common.h> +#include <asm/io.h> +#include <asm/bootm.h> +#include <mach/sdhci.h> +#include <mach/timer.h> +#include <mmc.h> +#include <fdtdec.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define BCMSTB_DATA_SECTION __attribute__((section(".data"))) + +struct bcmstb_boot_parameters bcmstb_boot_parameters BCMSTB_DATA_SECTION; + +phys_addr_t prior_stage_fdt_address BCMSTB_DATA_SECTION; + +union reg_value_union { + const char *data; + const phys_addr_t *address; +}; + +int board_init(void) +{ + return 0; +} + +u32 get_board_rev(void) +{ + return 0; +} + +void reset_cpu(ulong ignored) +{ +} + +int print_cpuinfo(void) +{ + return 0; +} + +int dram_init(void) +{ + if (fdtdec_setup_memory_size() != 0) + return -EINVAL; + + return 0; +} + +int dram_init_banksize(void) +{ + fdtdec_setup_memory_banksize(); + + /* + * On this SoC, U-Boot is running as an ELF file. Change the + * relocation address to CONFIG_SYS_TEXT_BASE, so that in + * setup_reloc, gd->reloc_off works out to 0, effectively + * disabling relocation. Otherwise U-Boot hangs in the setup + * instructions just before relocate_code in + * arch/arm/lib/crt0.S. + */ + gd->relocaddr = CONFIG_SYS_TEXT_BASE; + + return 0; +} + +void enable_caches(void) +{ + /* + * Nothing required here, since the prior stage bootloader has + * enabled I-cache and D-cache already. Implementing this + * function silences the warning in the default function. + */ +} + +static const phys_addr_t bcmstb_sdhci_address(u32 alias_index) +{ + int node = 0; + int ret = 0; + char sdhci[16] = { 0 }; + const void *fdt = gd->fdt_blob; + const char *path = NULL; + struct fdt_resource resource = { 0 }; + + if (!fdt) { + printf("%s: Invalid gd->fdt_blob\n", __func__); + return 0; + } + + node = fdt_path_offset(fdt, "/aliases"); + if (node < 0) { + printf("%s: Failed to find /aliases node\n", __func__); + return 0; + } + + sprintf(sdhci, "sdhci%d", alias_index); + path = fdt_getprop(fdt, node, sdhci, NULL); + if (!path) { + printf("%s: Failed to find alias for %s\n", __func__, sdhci); + return 0; + } + + node = fdt_path_offset(fdt, path); + if (node < 0) { + printf("%s: Failed to resolve BCMSTB SDHCI alias\n", __func__); + return 0; + } + + ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", + "host", &resource); + if (ret) { + printf("%s: Failed to read BCMSTB SDHCI host resource\n", + __func__); + return 0; + } + + return resource.start; +} + +int board_mmc_init(bd_t *bis) +{ + phys_addr_t sdhci_base_address = 0; + + sdhci_base_address = bcmstb_sdhci_address(CONFIG_BCMSTB_SDHCI_INDEX); + + if (!sdhci_base_address) { + sdhci_base_address = CONFIG_BCMSTB_SDHCI_BASE; + printf("%s: Assuming BCMSTB SDHCI address: 0x%p\n", + __func__, (void *)sdhci_base_address); + } + + debug("BCMSTB SDHCI base address: 0x%p\n", (void *)sdhci_base_address); + + bcmstb_sdhci_init(sdhci_base_address); + + return 0; +} + +int timer_init(void) +{ + gd->arch.timer_rate_hz = readl(CONFIG_BCMSTB_TIMER_FREQUENCY); + + return 0; +} + +ulong get_tbclk(void) +{ + return gd->arch.timer_rate_hz; +} + +unsigned long timer_read_counter(void) +{ + return readl(CONFIG_BCMSTB_TIMER_LOW); +} + +int board_late_init(void) +{ + debug("Arguments from prior stage bootloader:\n"); + debug("General Purpose Register 0: 0x%x\n", bcmstb_boot_parameters.r0); + debug("General Purpose Register 1: 0x%x\n", bcmstb_boot_parameters.r1); + debug("General Purpose Register 2: 0x%x\n", bcmstb_boot_parameters.r2); + debug("General Purpose Register 3: 0x%x\n", bcmstb_boot_parameters.r3); + debug("Stack Pointer Register: 0x%x\n", bcmstb_boot_parameters.sp); + debug("Link Register: 0x%x\n", bcmstb_boot_parameters.lr); + debug("Assuming timer frequency register at: 0x%p\n", + (void *)CONFIG_BCMSTB_TIMER_FREQUENCY); + debug("Read timer frequency (in Hz): %ld\n", gd->arch.timer_rate_hz); + debug("Prior stage provided DTB at: 0x%p\n", + (void *)prior_stage_fdt_address); + + /* + * Set fdtcontroladdr in the environment so that scripts can + * refer to it, for example, to reuse it for fdtaddr. + */ + env_set_hex("fdtcontroladdr", prior_stage_fdt_address); + + /* + * Do not set machid to the machine identifier value provided + * by the prior stage bootloader (bcmstb_boot_parameters.r1) + * because we're using a device tree to boot Linux. + */ + + return 0; +} diff --git a/configs/bcm7445_defconfig b/configs/bcm7445_defconfig new file mode 100644 index 0000000..46dea17 --- /dev/null +++ b/configs/bcm7445_defconfig @@ -0,0 +1,27 @@ +CONFIG_ARM=y +CONFIG_ARCH_BCMSTB=y +CONFIG_TARGET_BCM7445=y +CONFIG_USE_PRIVATE_LIBGCC=y +CONFIG_OF_CONTROL=y +CONFIG_OF_PRIOR_STAGE=y +CONFIG_DM=y +CONFIG_DM_SPI=y +CONFIG_DM_SPI_FLASH=y +CONFIG_SPI=y +CONFIG_SPI_FLASH=y +CONFIG_ENV_IS_IN_SPI_FLASH=y +CONFIG_BCMSTB_SPI=y +CONFIG_FIT=y +CONFIG_FIT_SIGNATURE=y +CONFIG_RSA=y +CONFIG_BLK=n +CONFIG_SDHCI=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_BCMSTB=y +CONFIG_CONS_INDEX=3 +CONFIG_BOOTDELAY=1 +CONFIG_SYS_PROMPT="U-Boot>" +CONFIG_HUSH_PARSER=y +CONFIG_SYS_TEXT_BASE=0x80100000 +CONFIG_SYS_NS16550_COM3=0xf040ab00 +CONFIG_EFI_LOADER=n diff --git a/doc/README.bcm7xxx b/doc/README.bcm7xxx new file mode 100644 index 0000000..0545d0b --- /dev/null +++ b/doc/README.bcm7xxx @@ -0,0 +1,147 @@ +Summary +======= + +This document describes how to use U-Boot on the Broadcom 7445 SoC, as +a third stage bootloader loaded by Broadcom's BOLT bootloader. + +BOLT loads U-Boot as a generic ELF binary. Some U-Boot features such +as networking are not yet available but other important features are, +including: + + - ext4 file system traversal + + - support for loading FIT images + + - advanced scripting + + - support for FIT-provided DTBs instead of relying on the + BOLT-provided DTB + +A customized version of this port has been used in production. The +same approach may work on other BCM7xxx boards, with some +configuration adjustments and memory layout experimentation. + +Build +===== + +make bcm7445_defconfig +make +${CROSS_COMPILE}strip u-boot + +Run +=== + +Flash the u-boot binary into board storage, then invoke it from BOLT. +For example: + +BOLT> boot -bsu -elf flash0.u-boot1 + +Flattened Image Tree Support +============================ + +What follows is an example FIT image source file. Build it with: + +mkimage -f image.its image.itb + +Booting the resulting image.itb was tested on BOLT v1.20, with the +following kernels: + +https://github.com/Broadcom/stblinux-3.14 +https://github.com/Broadcom/stblinux-4.1 +https://github.com/Broadcom/stblinux-4.9 + +and with a generic ARMv7 root file system. + +image.its: +/dts-v1/; +/ { + description = "BCM7445 FIT"; + images { + kernel@1 { + description = "Linux kernel"; + /* + * This kernel image output format can be + * generated with: + * + * make vmlinux + * ${CROSS_COMPILE}objcopy -O binary -S vmlinux vmlinux.bin + * gzip -9 vmlinux.bin + * + * For stblinux-3.14, the specific Broadcom + * board type should be configured in the + * kernel, for example CONFIG_BCM7445D0=y. + */ + data = /incbin/("<vmlinux.bin.gz>"); + type = "kernel"; + arch = "arm"; + os = "linux"; + compression = "gzip"; + load = <0x8000>; + entry = <0x8000>; + hash@1 { + algo = "sha256"; + }; + }; + ramdisk@1 { + description = "Initramfs root file system"; + data = /incbin/("<initramfs.cpio.gz>"); + type = "ramdisk"; + arch = "arm"; + os = "linux"; + compression = "gzip"; + /* + * Set the environment variable initrd_high to + * 0xffffffff, and set "load" and "entry" here + * to 0x0 to keep initramfs in-place and to + * accommodate stblinux bmem/CMA reservations. + */ + load = <0x0>; + entry = <0x0>; + hash@1 { + algo = "sha256"; + }; + }; + fdt@1 { + description = "Device tree dumped from BOLT"; + /* + * This DTB should be similar to the + * BOLT-generated device tree, after BOLT has + * done its runtime modifications to it. For + * example, it can be dumped from within + * U-Boot (at ${fdtcontroladdr}), after BOLT + * has loaded U-Boot. The result can be added + * to the Linux source tree as a .dts file. + * + * To support modifications to the device tree + * in-place in U-Boot, add to Linux's + * arch/arm/boot/dts/Makefile: + * + * DTC_FLAGS ?= -p 4096 + * + * This will leave some padding in the DTB and + * thus reserve room for node additions. + * + * Also, set the environment variable fdt_high + * to 0xffffffff to keep the DTB in-place and + * to accommodate stblinux bmem/CMA + * reservations. + */ + data = /incbin/("<bolt-<version>.dtb"); + type = "flat_dt"; + arch = "arm"; + compression = "none"; + hash@1 { + algo = "sha256"; + }; + }; + }; + configurations { + default = "conf@bcm7445"; + conf@bcm7445 { + description = "BCM7445 configuration"; + kernel = "kernel@1"; + ramdisk = "ramdisk@1"; + fdt = "fdt@1"; + }; + }; +}; diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 693b3ce..377b1c4 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -379,6 +379,17 @@ config MMC_SDHCI_BCM2835
If unsure, say N.
+config MMC_SDHCI_BCMSTB + tristate "SDHCI support for the BCMSTB SD/MMC Controller" + depends on MMC_SDHCI + help + This selects the Broadcom set-top box SD/MMC controller. + + If you have a BCMSTB platform with SD or MMC devices, + say Y here. + + If unsure, say N. + config MMC_SDHCI_CADENCE bool "SDHCI support for the Cadence SD/SDIO/eMMC controller" depends on BLK && DM_MMC diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 3a9805d..f619186 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_STM32_SDMMC2) += stm32_sdmmc2.o obj-$(CONFIG_MMC_SDHCI) += sdhci.o obj-$(CONFIG_MMC_SDHCI_ATMEL) += atmel_sdhci.o obj-$(CONFIG_MMC_SDHCI_BCM2835) += bcm2835_sdhci.o +obj-$(CONFIG_MMC_SDHCI_BCMSTB) += bcmstb_sdhci.o obj-$(CONFIG_MMC_SDHCI_CADENCE) += sdhci-cadence.o obj-$(CONFIG_MMC_SDHCI_KONA) += kona_sdhci.o obj-$(CONFIG_MMC_SDHCI_MSM) += msm_sdhci.o diff --git a/drivers/mmc/bcmstb_sdhci.c b/drivers/mmc/bcmstb_sdhci.c new file mode 100644 index 0000000..443ae8d --- /dev/null +++ b/drivers/mmc/bcmstb_sdhci.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + */ + +#include <common.h> +#include <mach/sdhci.h> +#include <malloc.h> +#include <sdhci.h> + +/* + * The BCMSTB SDHCI has a quirk in that its actual maximum frequency + * capability is 100 MHz. The divisor that is eventually written to + * SDHCI_CLOCK_CONTROL is calculated based on what the MMC device + * reports, and relative to this maximum frequency. + * + * This define used to be set to 52000000 (52 MHz), the desired + * maximum frequency, but that would result in the communication + * actually running at 100 MHz (seemingly without issue), which is + * out-of-spec. + * + * Now, by setting this to 0 (auto-detect), 100 MHz will be read from + * the capabilities register, and the resulting divisor will be + * doubled, meaning that the clock control register will be set to the + * in-spec 52 MHz value. + */ +#define BCMSTB_SDHCI_MAXIMUM_CLOCK_FREQUENCY 0 +/* + * When the minimum clock frequency is set to 0 (auto-detect), U-Boot + * sets it to 100 MHz divided by SDHCI_MAX_DIV_SPEC_300, or 48,875 Hz, + * which results in the controller timing out when trying to + * communicate with the MMC device. Hard-code this value to 400000 + * (400 kHz) to prevent this. + */ +#define BCMSTB_SDHCI_MINIMUM_CLOCK_FREQUENCY 400000 + +static char *BCMSTB_SDHCI_NAME = "bcmstb-sdhci"; + +/* + * This driver has only been tested with eMMC devices; SD devices may + * not work. + */ +int bcmstb_sdhci_init(phys_addr_t regbase) +{ + struct sdhci_host *host = NULL; + + host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host)); + if (!host) { + printf("%s: Failed to allocate memory\n", __func__); + return 1; + } + memset(host, 0, sizeof(*host)); + + host->name = BCMSTB_SDHCI_NAME; + host->ioaddr = (void *)regbase; + host->quirks = 0; + + host->cfg.part_type = PART_TYPE_DOS; + + host->version = sdhci_readw(host, SDHCI_HOST_VERSION); + + return add_sdhci(host, + BCMSTB_SDHCI_MAXIMUM_CLOCK_FREQUENCY, + BCMSTB_SDHCI_MINIMUM_CLOCK_FREQUENCY); +} diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 3532c2a..f5960a7 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -66,6 +66,13 @@ config BCM63XX_SPI access the SPI NOR flash on platforms embedding these Broadcom SPI cores.
+config BCMSTB_SPI + bool "BCMSTB SPI driver" + help + Enable the Broadcom set-top box SPI driver. This driver can + be used to access the SPI flash on platforms embedding this + Broadcom SPI core. + config CADENCE_QSPI bool "Cadence QSPI driver" help diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 5a2c00e..e73b0cd 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_ATH79_SPI) += ath79_spi.o obj-$(CONFIG_ATMEL_SPI) += atmel_spi.o obj-$(CONFIG_BCM63XX_HSSPI) += bcm63xx_hsspi.o obj-$(CONFIG_BCM63XX_SPI) += bcm63xx_spi.o +obj-$(CONFIG_BCMSTB_SPI) += bcmstb_spi.o obj-$(CONFIG_CADENCE_QSPI) += cadence_qspi.o cadence_qspi_apb.o obj-$(CONFIG_CF_SPI) += cf_spi.o obj-$(CONFIG_DAVINCI_SPI) += davinci_spi.o diff --git a/drivers/spi/bcmstb_spi.c b/drivers/spi/bcmstb_spi.c new file mode 100644 index 0000000..7be57be --- /dev/null +++ b/drivers/spi/bcmstb_spi.c @@ -0,0 +1,439 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + */ + +#include <asm/io.h> +#include <command.h> +#include <config.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <log.h> +#include <malloc.h> +#include <spi.h> +#include <time.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define SPBR_MIN 8 +#define BITS_PER_WORD 8 + +#define NUM_TXRAM 32 +#define NUM_RXRAM 32 +#define NUM_CDRAM 16 + +/* hif_mspi register structure. */ +struct bcmstb_hif_mspi_regs { + u32 spcr0_lsb; /* 0x000 */ + u32 spcr0_msb; /* 0x004 */ + u32 spcr1_lsb; /* 0x008 */ + u32 spcr1_msb; /* 0x00c */ + u32 newqp; /* 0x010 */ + u32 endqp; /* 0x014 */ + u32 spcr2; /* 0x018 */ + u32 reserved0; /* 0x01c */ + u32 mspi_status; /* 0x020 */ + u32 cptqp; /* 0x024 */ + u32 spcr3; /* 0x028 */ + u32 revision; /* 0x02c */ + u32 reserved1[4]; /* 0x030 */ + u32 txram[NUM_TXRAM]; /* 0x040 */ + u32 rxram[NUM_RXRAM]; /* 0x0c0 */ + u32 cdram[NUM_CDRAM]; /* 0x140 */ + u32 write_lock; /* 0x180 */ +}; + +/* hif_mspi masks. */ +#define HIF_MSPI_SPCR2_CONT_AFTER_CMD_MASK 0x00000080 +#define HIF_MSPI_SPCR2_SPE_MASK 0x00000040 +#define HIF_MSPI_SPCR2_SPIFIE_MASK 0x00000020 +#define HIF_MSPI_WRITE_LOCK_WRITE_LOCK_MASK 0x00000001 + +/* bspi offsets. */ +#define BSPI_MAST_N_BOOT_CTRL 0x008 + +/* bspi_raf is not used in this driver. */ + +/* hif_spi_intr2 offsets and masks. */ +#define HIF_SPI_INTR2_CPU_CLEAR 0x08 +#define HIF_SPI_INTR2_CPU_MASK_SET 0x10 +#define HIF_SPI_INTR2_CPU_MASK_CLEAR 0x14 +#define HIF_SPI_INTR2_CPU_SET_MSPI_DONE_MASK 0x00000020 + +/* SPI transfer timeout in milliseconds. */ +#define HIF_MSPI_WAIT 10 + +enum bcmstb_base_type { + HIF_MSPI, + BSPI, + HIF_SPI_INTR2, + CS_REG, + BASE_LAST, +}; + +struct bcmstb_spi_platdata { + void *base[4]; +}; + +struct bcmstb_spi_priv { + struct bcmstb_hif_mspi_regs *regs; + void *bspi; + void *hif_spi_intr2; + void *cs_reg; + int default_cs; + int curr_cs; + uint tx_slot; + uint rx_slot; + u8 saved_cmd[NUM_CDRAM]; + uint saved_cmd_len; + void *saved_din_addr; +}; + +static int bcmstb_spi_ofdata_to_platdata(struct udevice *bus) +{ + struct bcmstb_spi_platdata *plat = dev_get_platdata(bus); + const void *fdt = gd->fdt_blob; + int node = dev_of_offset(bus); + int ret = 0; + int i = 0; + struct fdt_resource resource = { 0 }; + char *names[BASE_LAST] = { "hif_mspi", "bspi", "hif_spi_intr2", + "cs_reg" }; + const phys_addr_t defaults[BASE_LAST] = { CONFIG_BCMSTB_HIF_MSPI_BASE, + CONFIG_BCMSTB_BSPI_BASE, + CONFIG_BCMSTB_HIF_SPI_INTR2, + CONFIG_BCMSTB_CS_REG }; + + for (i = 0; i < BASE_LAST; i++) { + plat->base[i] = (void *)defaults[i]; + + ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", + names[i], &resource); + if (ret) { + printf("%s: Assuming BCMSTB SPI %s address 0x0x%p\n", + __func__, names[i], (void *)defaults[i]); + } else { + plat->base[i] = (void *)resource.start; + debug("BCMSTB SPI %s address: 0x0x%p\n", + names[i], (void *)plat->base[i]); + } + } + + return 0; +} + +static void bcmstb_spi_hw_set_parms(struct bcmstb_spi_priv *priv) +{ + writel(SPBR_MIN, &priv->regs->spcr0_lsb); + writel(BITS_PER_WORD << 2 | SPI_MODE_3, &priv->regs->spcr0_msb); +} + +static void bcmstb_spi_enable_interrupt(void *base, u32 mask) +{ + void *reg = base + HIF_SPI_INTR2_CPU_MASK_CLEAR; + + writel(readl(reg) | mask, reg); + readl(reg); +} + +static void bcmstb_spi_disable_interrupt(void *base, u32 mask) +{ + void *reg = base + HIF_SPI_INTR2_CPU_MASK_SET; + + writel(readl(reg) | mask, reg); + readl(reg); +} + +static void bcmstb_spi_clear_interrupt(void *base, u32 mask) +{ + void *reg = base + HIF_SPI_INTR2_CPU_CLEAR; + + writel(readl(reg) | mask, reg); + readl(reg); +} + +static int bcmstb_spi_probe(struct udevice *bus) +{ + struct bcmstb_spi_platdata *plat = dev_get_platdata(bus); + struct bcmstb_spi_priv *priv = dev_get_priv(bus); + + priv->regs = plat->base[HIF_MSPI]; + priv->bspi = plat->base[BSPI]; + priv->hif_spi_intr2 = plat->base[HIF_SPI_INTR2]; + priv->cs_reg = plat->base[CS_REG]; + priv->default_cs = 0; + priv->curr_cs = -1; + priv->tx_slot = 0; + priv->rx_slot = 0; + memset(priv->saved_cmd, 0, NUM_CDRAM); + priv->saved_cmd_len = 0; + priv->saved_din_addr = NULL; + + debug("spi_xfer: tx regs: 0x%p\n", &priv->regs->txram[0]); + debug("spi_xfer: rx regs: 0x%p\n", &priv->regs->rxram[0]); + + /* Disable BSPI. */ + writel(1, priv->bspi + BSPI_MAST_N_BOOT_CTRL); + readl(priv->bspi + BSPI_MAST_N_BOOT_CTRL); + + /* Set up interrupts. */ + bcmstb_spi_disable_interrupt(priv->hif_spi_intr2, 0xffffffff); + bcmstb_spi_clear_interrupt(priv->hif_spi_intr2, 0xffffffff); + bcmstb_spi_enable_interrupt(priv->hif_spi_intr2, + HIF_SPI_INTR2_CPU_SET_MSPI_DONE_MASK); + + /* Set up control registers. */ + writel(0, &priv->regs->spcr1_lsb); + writel(0, &priv->regs->spcr1_msb); + writel(0, &priv->regs->newqp); + writel(0, &priv->regs->endqp); + writel(HIF_MSPI_SPCR2_SPIFIE_MASK, &priv->regs->spcr2); + writel(0, &priv->regs->spcr3); + + bcmstb_spi_hw_set_parms(priv); + + return 0; +} + +static void bcmstb_spi_submit(struct bcmstb_spi_priv *priv, bool done) +{ + debug("WR NEWQP: %d\n", 0); + writel(0, &priv->regs->newqp); + + debug("WR ENDQP: %d\n", priv->tx_slot - 1); + writel(priv->tx_slot - 1, &priv->regs->endqp); + + if (done) { + debug("WR CDRAM[%d]: %02x\n", priv->tx_slot - 1, + readl(&priv->regs->cdram[priv->tx_slot - 1]) & ~0x80); + writel(readl(&priv->regs->cdram[priv->tx_slot - 1]) & ~0x80, + &priv->regs->cdram[priv->tx_slot - 1]); + } + + /* Force chip select first time. */ + if (priv->curr_cs != priv->default_cs) { + debug("spi_xfer: switching chip select to %d\n", + priv->default_cs); + writel((readl(priv->cs_reg) & ~0xff) | (1 << priv->default_cs), + priv->cs_reg); + readl(priv->cs_reg); + udelay(10); + priv->curr_cs = priv->default_cs; + } + + debug("WR WRITE_LOCK: %02x\n", 1); + writel((readl(&priv->regs->write_lock) & + ~HIF_MSPI_WRITE_LOCK_WRITE_LOCK_MASK) | 1, + &priv->regs->write_lock); + readl(&priv->regs->write_lock); + + debug("WR SPCR2: %02x\n", + HIF_MSPI_SPCR2_SPIFIE_MASK | + HIF_MSPI_SPCR2_SPE_MASK | + HIF_MSPI_SPCR2_CONT_AFTER_CMD_MASK); + writel(HIF_MSPI_SPCR2_SPIFIE_MASK | + HIF_MSPI_SPCR2_SPE_MASK | + HIF_MSPI_SPCR2_CONT_AFTER_CMD_MASK, + &priv->regs->spcr2); +} + +static int bcmstb_spi_wait(struct bcmstb_spi_priv *priv) +{ + u32 start_time = get_timer(0); + u32 status = readl(&priv->regs->mspi_status); + + while (!(status & 1)) { + if (get_timer(start_time) > HIF_MSPI_WAIT) + return -ETIMEDOUT; + status = readl(&priv->regs->mspi_status); + } + + writel(readl(&priv->regs->mspi_status) & ~1, &priv->regs->mspi_status); + bcmstb_spi_clear_interrupt(priv->hif_spi_intr2, + HIF_SPI_INTR2_CPU_SET_MSPI_DONE_MASK); + + return 0; +} + +static int bcmstb_spi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + uint len = bitlen / 8; + uint tx_len = len; + uint rx_len = len; + const u8 *out_bytes = (u8 *)dout; + u8 *in_bytes = (u8 *)din; + struct udevice *bus = dev_get_parent(dev); + struct bcmstb_spi_priv *priv = dev_get_priv(bus); + struct bcmstb_hif_mspi_regs *regs = priv->regs; + + debug("spi_xfer: %d, t: 0x%p, r: 0x%p, f: %lx\n", + len, dout, din, flags); + debug("spi_xfer: chip select: %x\n", readl(priv->cs_reg) & 0xff); + debug("spi_xfer: tx addr: 0x%p\n", ®s->txram[0]); + debug("spi_xfer: rx addr: 0x%p\n", ®s->rxram[0]); + debug("spi_xfer: cd addr: 0x%p\n", ®s->cdram[0]); + + if (flags & SPI_XFER_END) { + debug("spi_xfer: clearing saved din address: 0x%p\n", + priv->saved_din_addr); + priv->saved_din_addr = NULL; + priv->saved_cmd_len = 0; + memset(priv->saved_cmd, 0, NUM_CDRAM); + } + + if (bitlen == 0) + return 0; + + if (bitlen % 8) { + printf("%s: Non-byte-aligned transfer\n", __func__); + return -EOPNOTSUPP; + } + + if (flags & ~(SPI_XFER_BEGIN | SPI_XFER_END)) { + printf("%s: Unsupported flags: %lx\n", __func__, flags); + return -EOPNOTSUPP; + } + + if (flags & SPI_XFER_BEGIN) { + priv->tx_slot = 0; + priv->rx_slot = 0; + + if (out_bytes && len > NUM_CDRAM) { + printf("%s: Unable to save transfer\n", __func__); + return -EOPNOTSUPP; + } + + if (out_bytes && !(flags & SPI_XFER_END)) { + /* + * This is the start of a transmit operation + * that will need repeating if the calling + * code polls for the result. Save it for + * subsequent transmission. + */ + debug("spi_xfer: saving command: %x, %d\n", + out_bytes[0], len); + priv->saved_cmd_len = len; + memcpy(priv->saved_cmd, out_bytes, priv->saved_cmd_len); + } + } + + if (!(flags & (SPI_XFER_BEGIN | SPI_XFER_END))) { + if (priv->saved_din_addr == din) { + /* + * The caller is polling for status. Repeat + * the last transmission. + */ + int ret = 0; + + debug("spi_xfer: Making recursive call\n"); + ret = bcmstb_spi_xfer(dev, priv->saved_cmd_len * 8, + priv->saved_cmd, NULL, + SPI_XFER_BEGIN); + if (ret) { + printf("%s: Recursive call failed\n", __func__); + return ret; + } + } else { + debug("spi_xfer: saving din address: 0x%p\n", din); + priv->saved_din_addr = din; + } + } + + while (rx_len > 0) { + priv->rx_slot = priv->tx_slot; + + while (priv->tx_slot < NUM_CDRAM && tx_len > 0) { + bcmstb_spi_hw_set_parms(priv); + debug("WR TXRAM[%d]: %02x\n", priv->tx_slot, + out_bytes ? out_bytes[len - tx_len] : 0xff); + writel(out_bytes ? out_bytes[len - tx_len] : 0xff, + ®s->txram[priv->tx_slot << 1]); + debug("WR CDRAM[%d]: %02x\n", priv->tx_slot, 0x8e); + writel(0x8e, ®s->cdram[priv->tx_slot]); + priv->tx_slot++; + tx_len--; + if (!in_bytes) + rx_len--; + } + + debug("spi_xfer: early return clauses: %d, %d, %d\n", + len <= NUM_CDRAM, + !in_bytes, + (flags & (SPI_XFER_BEGIN | + SPI_XFER_END)) == SPI_XFER_BEGIN); + if (len <= NUM_CDRAM && + !in_bytes && + (flags & (SPI_XFER_BEGIN | SPI_XFER_END)) == SPI_XFER_BEGIN) + return 0; + + bcmstb_spi_submit(priv, tx_len == 0); + + if (bcmstb_spi_wait(priv) == -ETIMEDOUT) { + printf("%s: Timed out\n", __func__); + return -ETIMEDOUT; + } + + priv->tx_slot %= NUM_CDRAM; + + if (in_bytes) { + while (priv->rx_slot < NUM_CDRAM && rx_len > 0) { + in_bytes[len - rx_len] = + readl(®s->rxram[(priv->rx_slot << 1) + + 1]) + & 0xff; + debug("RD RXRAM[%d]: %02x\n", + priv->rx_slot, in_bytes[len - rx_len]); + priv->rx_slot++; + rx_len--; + } + } + } + + if (flags & SPI_XFER_END) { + debug("WR WRITE_LOCK: %02x\n", 0); + writel((readl(&priv->regs->write_lock) & + ~HIF_MSPI_WRITE_LOCK_WRITE_LOCK_MASK) | 0, + &priv->regs->write_lock); + readl(&priv->regs->write_lock); + } + + return 0; +} + +static int bcmstb_spi_set_speed(struct udevice *dev, uint speed) +{ + return 0; +} + +static int bcmstb_spi_set_mode(struct udevice *dev, uint mode) +{ + return 0; +} + +static const struct dm_spi_ops bcmstb_spi_ops = { + .xfer = bcmstb_spi_xfer, + .set_speed = bcmstb_spi_set_speed, + .set_mode = bcmstb_spi_set_mode, +}; + +static const struct udevice_id bcmstb_spi_id[] = { + { .compatible = "brcm,spi-brcmstb" }, + { } +}; + +U_BOOT_DRIVER(bcmstb_spi) = { + .name = "bcmstb_spi", + .id = UCLASS_SPI, + .of_match = bcmstb_spi_id, + .ops = &bcmstb_spi_ops, + .ofdata_to_platdata = bcmstb_spi_ofdata_to_platdata, + .probe = bcmstb_spi_probe, + .platdata_auto_alloc_size = sizeof(struct bcmstb_spi_platdata), + .priv_auto_alloc_size = sizeof(struct bcmstb_spi_priv), +}; diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index d2d091f..c517d06 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -273,7 +273,7 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, bool created = false; int ret;
-#if CONFIG_IS_ENABLED(OF_PLATDATA) +#if CONFIG_IS_ENABLED(OF_PLATDATA) || CONFIG_IS_ENABLED(OF_PRIOR_STAGE) ret = uclass_first_device_err(UCLASS_SPI, &bus); #else ret = uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus); diff --git a/dts/Kconfig b/dts/Kconfig index 0cef225..a1a92f2 100644 --- a/dts/Kconfig +++ b/dts/Kconfig @@ -101,6 +101,13 @@ config OF_HOSTFILE This is only useful for Sandbox. Use the -d flag to U-Boot to specify the file to read.
+config OF_PRIOR_STAGE + bool "Prior stage bootloader DTB for DT control" + help + If this option is enabled, the device tree used for DT + control will be read from a device tree binary, at a memory + location passed to U-Boot by the prior stage bootloader. + endchoice
config DEFAULT_DEVICE_TREE diff --git a/include/configs/bcmstb.h b/include/configs/bcmstb.h new file mode 100644 index 0000000..7e61727 --- /dev/null +++ b/include/configs/bcmstb.h @@ -0,0 +1,188 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + * + * Configuration settings for the Broadcom BCM7445 SoC family. + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#include "version.h" +#include <linux/sizes.h> +#include <asm/arch/prior_stage.h> + +/* + * Generic board configuration. + */ +#define CONFIG_SYS_GENERIC_BOARD + +/* + * CPU configuration. + */ +#define CONFIG_SKIP_LOWLEVEL_INIT + +/* + * Memory configuration. + * + * The prior stage BOLT bootloader sets up memory for us. + * + * An example boot memory layout after loading everything is: + * + * 0x0000 8000 vmlinux.bin.gz + * : [~31 MiB uncompressed max] + * 0x01ef f000 FIT containing signed public key + * : [~2 KiB in size] + * 0x01f0 0000 DTB copied from prior-stage-provided region + * : [~1 MiB max] + * 0x0200 0000 FIT containing ramdisk and device tree + * : initramfs.cpio.gz + * : [~208 MiB uncompressed max, to CMA/bmem low address] + * : [~80 MiB compressed max, to PSB low address] + * : device tree binary + * : [~60 KiB] + * 0x0700 0000 Prior stage bootloader (PSB) + * : + * 0x0761 7000 Prior-stage-provided device tree binary (DTB) + * : [~40 KiB in size] + * 0x0f00 0000 Contiguous memory allocator (CMA/bmem) low address + * : + * 0x8010 0000 U-Boot code at ELF load address + * : [~500 KiB in size, stripped] + * 0xc000 0000 Top of RAM + * + * Setting gd->relocaddr to CONFIG_SYS_TEXT_BASE in dram_init_banksize + * prevents U-Boot from relocating itself when it is run as an ELF + * program by the prior stage bootloader. + * + * We want to keep the ramdisk and FDT in the FIT image in-place, to + * accommodate stblinux's bmem and CMA regions. To accomplish this, + * we set initrd_high and fdt_high to 0xffffffff, and the load and + * entry addresses of the FIT ramdisk entry to 0x0. + * + * Overwriting the prior stage bootloader causes memory instability, + * so the compressed initramfs needs to fit between the load address + * and the PSB low address. In BOLT's default configuration this + * limits the compressed size of the initramfs to approximately 80 + * MiB. However, BOLT can be configured to allow loading larger + * initramfs images, in which case this limitation is eliminated. + */ +#define CONFIG_NR_DRAM_BANKS 3 + +#define CONFIG_SYS_SDRAM_BASE 0x00000000 +#define CONFIG_SYS_TEXT_BASE 0x80100000 +#define CONFIG_SYS_INIT_RAM_ADDR 0x80200000 +#define CONFIG_SYS_INIT_RAM_SIZE 0x100000 +#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_INIT_RAM_ADDR + \ + CONFIG_SYS_INIT_RAM_SIZE - \ + GENERATED_GBL_DATA_SIZE) +#define CONFIG_SYS_MALLOC_LEN ((10 * 1024) << 10) /* 10 MiB */ +#define CONFIG_SYS_LOAD_ADDR 0x2000000 + +/* + * CONFIG_SYS_LOAD_ADDR - 1 MiB. + */ +#define CONFIG_SYS_FDT_SAVE_ADDRESS 0x1f00000 +#define CONFIG_SYS_CBSIZE 512 +#define CONFIG_SYS_MAXARGS 32 + +/* + * Large kernel image bootm configuration. + */ +#define CONFIG_SYS_BOOTM_LEN SZ_64M + +/* + * NS16550 configuration. + */ +#define V_NS16550_CLK 81000000 + +#define CONFIG_SYS_NS16550 +#define CONFIG_SYS_NS16550_SERIAL +#define CONFIG_SYS_NS16550_REG_SIZE (-4) +#define CONFIG_SYS_NS16550_CLK V_NS16550_CLK + +/* + * Serial console configuration. + */ +#define CONFIG_SERIAL3 3 + +/* + * For now, this must be a pre-defined macro, not looked up from the + * prior-stage-provided DTB. + */ +#define CONFIG_SYS_NS16550_COM3 0xf040ab00 +#define CONFIG_BAUDRATE 115200 +#define CONFIG_SYS_BAUDRATE_TABLE {4800, 9600, 19200, 38400, 57600, \ + 115200} + +/* + * Informational display configuration. + */ +#define CONFIG_REVISION_TAG + +/* + * Command configuration. + */ +#define CONFIG_CMD_ASKENV +#define CONFIG_CMD_CACHE +#define CONFIG_CMD_EXT2 +#define CONFIG_CMD_SF +#define CONFIG_CMD_SPI +#define CONFIG_CMD_SF_TEST +#define CONFIG_CMD_MMC + +/* + * Flash configuration. + */ +#define CONFIG_ST_SMI +#define CONFIG_SPI_FLASH_STMICRO +#define CONFIG_SPI_FLASH_MACRONIX + +/* + * Filesystem configuration. + */ +#define CONFIG_DOS_PARTITION +#define CONFIG_CMD_EXT4 +#define CONFIG_FS_EXT4 +#define CONFIG_CMD_FS_GENERIC + +/* + * Environment configuration. + */ +#define CONFIG_SYS_REDUNDAND_ENVIRONMENT + +#define CONFIG_ENV_IS_IN_SPI_FLASH 1 +#define CONFIG_ENV_OFFSET 0x1e0000 +#define CONFIG_ENV_SIZE (64 << 10) /* 64 KiB */ +#define CONFIG_ENV_SECT_SIZE CONFIG_ENV_SIZE +#define CONFIG_ENV_OFFSET_REDUND (CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE) +#define CONFIG_ENV_OVERWRITE + +/* + * Save the prior stage provided DTB. + */ +#define CONFIG_PREBOOT \ + "fdt addr ${fdtcontroladdr};" \ + "fdt move ${fdtcontroladdr} ${fdtsaveaddr};" \ + "fdt addr ${fdtsaveaddr};" +/* + * Enable in-place RFS with this initrd_high setting. + */ +#define CONFIG_EXTRA_ENV_SETTINGS \ + "fdtsaveaddr=" __stringify(CONFIG_SYS_FDT_SAVE_ADDRESS) "\0" \ + "initrd_high=0xffffffff\0" \ + "fdt_high=0xffffffff\0" + +/* + * Set fdtaddr to prior stage-provided DTB in board_late_init, when + * writeable environment is available. + */ +#define CONFIG_BOARD_LATE_INIT + +#define CONFIG_SYS_MAX_FLASH_BANKS 1 + +#define CONFIG_DM_SPI 1 + +#endif /* __CONFIG_H */ diff --git a/include/fdtdec.h b/include/fdtdec.h index c15b2a0..ff1c5f5 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -47,6 +47,10 @@ struct fdt_memory { #define SPL_BUILD 0 #endif
+#if CONFIG_IS_ENABLED(OF_PRIOR_STAGE) +extern phys_addr_t prior_stage_fdt_address; +#endif + /* * Information about a resource. start is the first address of the resource * and end is the last address (inclusive). The length of the resource will diff --git a/lib/fdtdec.c b/lib/fdtdec.c index f4e8dbf..b29b283 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -1323,8 +1323,12 @@ int fdtdec_setup(void) # endif # ifndef CONFIG_SPL_BUILD /* Allow the early environment to override the fdt address */ +# if CONFIG_IS_ENABLED(OF_PRIOR_STAGE) + gd->fdt_blob = (void *)prior_stage_fdt_address; +# else gd->fdt_blob = (void *)env_get_ulong("fdtcontroladdr", 16, (uintptr_t)gd->fdt_blob); +# endif # endif
# if CONFIG_IS_ENABLED(MULTI_DTB_FIT)

On 06/06/2018 11:35 AM, Thomas Fitzsimmons wrote:
Add support for loading U-Boot on the Broadcom 7445 SoC. This port assumes Broadcom's BOLT bootloader is acting as the second stage bootloader, and U-Boot is acting as the third stage bootloader, loaded as an ELF program by BOLT.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Stefan Roese sr@denx.de Cc: Tom Rini trini@konsulko.com Cc: Florian Fainelli f.fainelli@gmail.com
Looks good, still some minor comments about the choice of representation for physical addresses of peripherals, see below.
+config BCMSTB_TIMER_LOW
- hex "Address of BCMSTB timer low register"
- default 0xf0412008
This looks very simplistic here since the CPU system control timer is a 64-bit timer.
I am really not a big fan of all of those configurable addresses which are a) fixed given a specific SoC family (7445, 7439 etc.) and b) are error prone because we let an user change those without necessarily knowing what is the implication. I really think sticking those constants into a header file would be much more appropriate.
+void enable_caches(void) +{
- /*
* Nothing required here, since the prior stage bootloader has
* enabled I-cache and D-cache already. Implementing this
* function silences the warning in the default function.
*/
This heavily depends on how you load your binary from BOLT, so you must be careful about this statement here.

Florian Fainelli f.fainelli@gmail.com writes:
On 06/06/2018 11:35 AM, Thomas Fitzsimmons wrote:
Add support for loading U-Boot on the Broadcom 7445 SoC. This port assumes Broadcom's BOLT bootloader is acting as the second stage bootloader, and U-Boot is acting as the third stage bootloader, loaded as an ELF program by BOLT.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Stefan Roese sr@denx.de Cc: Tom Rini trini@konsulko.com Cc: Florian Fainelli f.fainelli@gmail.com
Looks good, still some minor comments about the choice of representation for physical addresses of peripherals, see below.
+config BCMSTB_TIMER_LOW
- hex "Address of BCMSTB timer low register"
- default 0xf0412008
This looks very simplistic here since the CPU system control timer is a 64-bit timer.
This worked via the default get_ticks implementation in lib/time.c, which tracks rollovers and converts to a 64-bit value. But I agree it's better to use the high timer register, so that (among other reasons) get_ticks reflects total uptime including time spent in BOLT. I overrode get_ticks in v4 of the patch to use the high and low timer registers.
I am really not a big fan of all of those configurable addresses which are a) fixed given a specific SoC family (7445, 7439 etc.) and b) are error prone because we let an user change those without necessarily knowing what is the implication. I really think sticking those constants into a header file would be much more appropriate.
Makes sense, moved to a 7445-specific header in v4.
+void enable_caches(void) +{
- /*
* Nothing required here, since the prior stage bootloader has
* enabled I-cache and D-cache already. Implementing this
* function silences the warning in the default function.
*/
This heavily depends on how you load your binary from BOLT, so you must be careful about this statement here.
In v4 I adjusted the comment and added an entry to the README to document the expectation.
Thanks, Thomas

Add support for Broadcom BCM7445
Changes for v4: - Use high timer register for get_ticks - Move hard-coded register addresses from Kconfig to header - Document I-cache/D-cache expectation
Thomas Fitzsimmons (1): board: arm: Add support for Broadcom BCM7445
MAINTAINERS | 10 + arch/arm/Kconfig | 12 + arch/arm/Makefile | 1 + arch/arm/mach-bcmstb/Kconfig | 36 ++ arch/arm/mach-bcmstb/Makefile | 8 + arch/arm/mach-bcmstb/include/mach/gpio.h | 11 + arch/arm/mach-bcmstb/include/mach/hardware.h | 11 + arch/arm/mach-bcmstb/include/mach/prior_stage.h | 30 ++ arch/arm/mach-bcmstb/include/mach/sdhci.h | 15 + arch/arm/mach-bcmstb/include/mach/timer.h | 13 + arch/arm/mach-bcmstb/lowlevel_init.S | 21 ++ board/broadcom/bcmstb/MAINTAINERS | 7 + board/broadcom/bcmstb/Makefile | 8 + board/broadcom/bcmstb/bcmstb.c | 194 +++++++++++ configs/bcm7445_defconfig | 27 ++ doc/README.bcm7xxx | 150 ++++++++ drivers/mmc/Kconfig | 11 + drivers/mmc/Makefile | 1 + drivers/mmc/bcmstb_sdhci.c | 67 ++++ drivers/spi/Kconfig | 7 + drivers/spi/Makefile | 1 + drivers/spi/bcmstb_spi.c | 439 ++++++++++++++++++++++++ drivers/spi/spi-uclass.c | 2 +- dts/Kconfig | 7 + include/configs/bcm7445.h | 26 ++ include/configs/bcmstb.h | 183 ++++++++++ include/fdtdec.h | 4 + lib/fdtdec.c | 4 + 28 files changed, 1305 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-bcmstb/Kconfig create mode 100644 arch/arm/mach-bcmstb/Makefile create mode 100644 arch/arm/mach-bcmstb/include/mach/gpio.h create mode 100644 arch/arm/mach-bcmstb/include/mach/hardware.h create mode 100644 arch/arm/mach-bcmstb/include/mach/prior_stage.h create mode 100644 arch/arm/mach-bcmstb/include/mach/sdhci.h create mode 100644 arch/arm/mach-bcmstb/include/mach/timer.h create mode 100644 arch/arm/mach-bcmstb/lowlevel_init.S create mode 100644 board/broadcom/bcmstb/MAINTAINERS create mode 100644 board/broadcom/bcmstb/Makefile create mode 100644 board/broadcom/bcmstb/bcmstb.c create mode 100644 configs/bcm7445_defconfig create mode 100644 doc/README.bcm7xxx create mode 100644 drivers/mmc/bcmstb_sdhci.c create mode 100644 drivers/spi/bcmstb_spi.c create mode 100644 include/configs/bcm7445.h create mode 100644 include/configs/bcmstb.h

Add support for loading U-Boot on the Broadcom 7445 SoC. This port assumes Broadcom's BOLT bootloader is acting as the second stage bootloader, and U-Boot is acting as the third stage bootloader, loaded as an ELF program by BOLT.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Stefan Roese sr@denx.de Cc: Tom Rini trini@konsulko.com Cc: Florian Fainelli f.fainelli@gmail.com --- Changes for v4: - Use high timer register for get_ticks - Move hard-coded register addresses from Kconfig to header - Document I-cache/D-cache expectation
MAINTAINERS | 10 + arch/arm/Kconfig | 12 + arch/arm/Makefile | 1 + arch/arm/mach-bcmstb/Kconfig | 36 ++ arch/arm/mach-bcmstb/Makefile | 8 + arch/arm/mach-bcmstb/include/mach/gpio.h | 11 + arch/arm/mach-bcmstb/include/mach/hardware.h | 11 + arch/arm/mach-bcmstb/include/mach/prior_stage.h | 30 ++ arch/arm/mach-bcmstb/include/mach/sdhci.h | 15 + arch/arm/mach-bcmstb/include/mach/timer.h | 13 + arch/arm/mach-bcmstb/lowlevel_init.S | 21 ++ board/broadcom/bcmstb/MAINTAINERS | 7 + board/broadcom/bcmstb/Makefile | 8 + board/broadcom/bcmstb/bcmstb.c | 194 +++++++++++ configs/bcm7445_defconfig | 27 ++ doc/README.bcm7xxx | 150 ++++++++ drivers/mmc/Kconfig | 11 + drivers/mmc/Makefile | 1 + drivers/mmc/bcmstb_sdhci.c | 67 ++++ drivers/spi/Kconfig | 7 + drivers/spi/Makefile | 1 + drivers/spi/bcmstb_spi.c | 439 ++++++++++++++++++++++++ drivers/spi/spi-uclass.c | 2 +- dts/Kconfig | 7 + include/configs/bcm7445.h | 26 ++ include/configs/bcmstb.h | 183 ++++++++++ include/fdtdec.h | 4 + lib/fdtdec.c | 4 + 28 files changed, 1305 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-bcmstb/Kconfig create mode 100644 arch/arm/mach-bcmstb/Makefile create mode 100644 arch/arm/mach-bcmstb/include/mach/gpio.h create mode 100644 arch/arm/mach-bcmstb/include/mach/hardware.h create mode 100644 arch/arm/mach-bcmstb/include/mach/prior_stage.h create mode 100644 arch/arm/mach-bcmstb/include/mach/sdhci.h create mode 100644 arch/arm/mach-bcmstb/include/mach/timer.h create mode 100644 arch/arm/mach-bcmstb/lowlevel_init.S create mode 100644 board/broadcom/bcmstb/MAINTAINERS create mode 100644 board/broadcom/bcmstb/Makefile create mode 100644 board/broadcom/bcmstb/bcmstb.c create mode 100644 configs/bcm7445_defconfig create mode 100644 doc/README.bcm7xxx create mode 100644 drivers/mmc/bcmstb_sdhci.c create mode 100644 drivers/spi/bcmstb_spi.c create mode 100644 include/configs/bcm7445.h create mode 100644 include/configs/bcmstb.h
diff --git a/MAINTAINERS b/MAINTAINERS index 642c448..58634fc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -107,6 +107,16 @@ F: drivers/video/bcm2835.c F: include/dm/platform_data/serial_bcm283x_mu.h F: drivers/pinctrl/broadcom/
+ARM BROADCOM BCMSTB +M: Thomas Fitzsimmons fitzsim@fitzsim.org +S: Maintained +F: arch/arm/mach-bcmstb/ +F: board/broadcom/bcmstb/ +F: configs/bcm7445_defconfig +F: doc/README.bcm7xxx +F: drivers/mmc/bcmstb_sdhci.c +F: drivers/spi/bcmstb_spi.c + ARM FREESCALE IMX M: Stefano Babic sbabic@denx.de M: Fabio Estevam fabio.estevam@nxp.com diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index dde422b..fa2001b 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -533,6 +533,16 @@ config TARGET_VEXPRESS_CA15_TC2 select CPU_V7_HAS_VIRT select PL011_SERIAL
+config ARCH_BCMSTB + bool "Broadcom BCM7XXX family" + select CPU_V7A + select DM + select OF_CONTROL + select OF_PRIOR_STAGE + help + This enables support for Broadcom ARM-based set-top box + chipsets, including the 7445 family of chips. + config TARGET_VEXPRESS_CA5X2 bool "Support vexpress_ca5x2" select CPU_V7A @@ -1297,6 +1307,8 @@ source "arch/arm/mach-at91/Kconfig"
source "arch/arm/mach-bcm283x/Kconfig"
+source "arch/arm/mach-bcmstb/Kconfig" + source "arch/arm/mach-davinci/Kconfig"
source "arch/arm/mach-exynos/Kconfig" diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 680c6e8..03252fe 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -54,6 +54,7 @@ PLATFORM_CPPFLAGS += $(arch-y) $(tune-y) machine-$(CONFIG_ARCH_ASPEED) += aspeed machine-$(CONFIG_ARCH_AT91) += at91 machine-$(CONFIG_ARCH_BCM283X) += bcm283x +machine-$(CONFIG_ARCH_BCMSTB) += bcmstb machine-$(CONFIG_ARCH_DAVINCI) += davinci machine-$(CONFIG_ARCH_EXYNOS) += exynos machine-$(CONFIG_ARCH_HIGHBANK) += highbank diff --git a/arch/arm/mach-bcmstb/Kconfig b/arch/arm/mach-bcmstb/Kconfig new file mode 100644 index 0000000..6c7952f --- /dev/null +++ b/arch/arm/mach-bcmstb/Kconfig @@ -0,0 +1,36 @@ +if ARCH_BCMSTB + +config TARGET_BCM7445 + bool "Broadcom 7445 TSBL" + depends on ARCH_BCMSTB + help + Support for the Broadcom 7445 SoC. This port assumes BOLT + is acting as the second stage bootloader, and U-Boot is + acting as the third stage bootloader (TSBL), loaded by BOLT. + This port may work on other BCM7xxx boards with + configuration changes. + +config SYS_CPU + default "armv7" + +config SYS_BOARD + default "bcmstb" + +config SYS_VENDOR + default "broadcom" + +config SYS_SOC + default "bcmstb" + +config SYS_CONFIG_NAME + default "bcm7445" + +config SYS_FDT_SAVE_ADDRESS + hex "Address to which the prior stage provided DTB will be copied" + default 0x1f00000 + +config BCMSTB_SDHCI_INDEX + int "Index of preferred BCMSTB SDHCI alias in DTB" + default 1 + +endif diff --git a/arch/arm/mach-bcmstb/Makefile b/arch/arm/mach-bcmstb/Makefile new file mode 100644 index 0000000..71e5727 --- /dev/null +++ b/arch/arm/mach-bcmstb/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2018 Cisco Systems, Inc. +# +# Author: Thomas Fitzsimmons fitzsim@fitzsim.org +# + +obj-y := lowlevel_init.o diff --git a/arch/arm/mach-bcmstb/include/mach/gpio.h b/arch/arm/mach-bcmstb/include/mach/gpio.h new file mode 100644 index 0000000..bffecf9 --- /dev/null +++ b/arch/arm/mach-bcmstb/include/mach/gpio.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + */ + +#ifndef _BCMSTB_GPIO_H +#define _BCMSTB_GPIO_H + +#endif /* _BCMSTB_GPIO_H */ diff --git a/arch/arm/mach-bcmstb/include/mach/hardware.h b/arch/arm/mach-bcmstb/include/mach/hardware.h new file mode 100644 index 0000000..76f799d --- /dev/null +++ b/arch/arm/mach-bcmstb/include/mach/hardware.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + */ + +#ifndef _BCMSTB_HARDWARE_H +#define _BCMSTB_HARDWARE_H + +#endif /* _BCMSTB_HARDWARE_H */ diff --git a/arch/arm/mach-bcmstb/include/mach/prior_stage.h b/arch/arm/mach-bcmstb/include/mach/prior_stage.h new file mode 100644 index 0000000..6c36c68 --- /dev/null +++ b/arch/arm/mach-bcmstb/include/mach/prior_stage.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + */ + +#ifndef _BCMSTB_PRIOR_STAGE_H +#define _BCMSTB_PRIOR_STAGE_H + +#ifndef __ASSEMBLY__ + +#include <linux/types.h> + +struct bcmstb_boot_parameters { + u32 r0; + u32 r1; + u32 r2; + u32 r3; + u32 sp; + u32 lr; +}; + +extern struct bcmstb_boot_parameters bcmstb_boot_parameters; + +extern phys_addr_t prior_stage_fdt_address; + +#endif /* __ASSEMBLY__ */ + +#endif /* _BCMSTB_PRIOR_STAGE_H */ diff --git a/arch/arm/mach-bcmstb/include/mach/sdhci.h b/arch/arm/mach-bcmstb/include/mach/sdhci.h new file mode 100644 index 0000000..243783d --- /dev/null +++ b/arch/arm/mach-bcmstb/include/mach/sdhci.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + */ + +#ifndef _BCMSTB_SDHCI_H +#define _BCMSTB_SDHCI_H + +#include <linux/types.h> + +int bcmstb_sdhci_init(phys_addr_t regbase); + +#endif /* _BCMSTB_SDHCI_H */ diff --git a/arch/arm/mach-bcmstb/include/mach/timer.h b/arch/arm/mach-bcmstb/include/mach/timer.h new file mode 100644 index 0000000..d05b4d6 --- /dev/null +++ b/arch/arm/mach-bcmstb/include/mach/timer.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + */ + +#ifndef _BCMSTB_TIMER_H +#define _BCMSTB_TIMER_H + +unsigned long timer_read_counter(void); + +#endif /* _BCMSTB_TIMER_H */ diff --git a/arch/arm/mach-bcmstb/lowlevel_init.S b/arch/arm/mach-bcmstb/lowlevel_init.S new file mode 100644 index 0000000..aa81f70 --- /dev/null +++ b/arch/arm/mach-bcmstb/lowlevel_init.S @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + */ + +#include <linux/linkage.h> + +ENTRY(save_boot_params) + ldr r6, =bcmstb_boot_parameters + str r0, [r6, #0] + str r1, [r6, #4] + str r2, [r6, #8] + str r3, [r6, #12] + str sp, [r6, #16] + str lr, [r6, #20] + ldr r6, =prior_stage_fdt_address + str r2, [r6] + b save_boot_params_ret +ENDPROC(save_boot_params) diff --git a/board/broadcom/bcmstb/MAINTAINERS b/board/broadcom/bcmstb/MAINTAINERS new file mode 100644 index 0000000..5851cb9 --- /dev/null +++ b/board/broadcom/bcmstb/MAINTAINERS @@ -0,0 +1,7 @@ +BCM7445 BOARD +M: Thomas Fitzsimmons fitzsim@fitzsim.org +S: Maintained +F: board/broadcom/bcmstb/ +F: include/configs/bcmstb.h +F: include/configs/bcm7445.h +F: configs/bcm7445_defconfig diff --git a/board/broadcom/bcmstb/Makefile b/board/broadcom/bcmstb/Makefile new file mode 100644 index 0000000..9609887 --- /dev/null +++ b/board/broadcom/bcmstb/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2018 Cisco Systems, Inc. +# +# Author: Thomas Fitzsimmons fitzsim@fitzsim.org +# + +obj-y := bcmstb.o diff --git a/board/broadcom/bcmstb/bcmstb.c b/board/broadcom/bcmstb/bcmstb.c new file mode 100644 index 0000000..25cd354 --- /dev/null +++ b/board/broadcom/bcmstb/bcmstb.c @@ -0,0 +1,194 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + */ + +#include <linux/types.h> +#include <common.h> +#include <asm/io.h> +#include <asm/bootm.h> +#include <mach/sdhci.h> +#include <mach/timer.h> +#include <mmc.h> +#include <fdtdec.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define BCMSTB_DATA_SECTION __attribute__((section(".data"))) + +struct bcmstb_boot_parameters bcmstb_boot_parameters BCMSTB_DATA_SECTION; + +phys_addr_t prior_stage_fdt_address BCMSTB_DATA_SECTION; + +union reg_value_union { + const char *data; + const phys_addr_t *address; +}; + +int board_init(void) +{ + return 0; +} + +u32 get_board_rev(void) +{ + return 0; +} + +void reset_cpu(ulong ignored) +{ +} + +int print_cpuinfo(void) +{ + return 0; +} + +int dram_init(void) +{ + if (fdtdec_setup_memory_size() != 0) + return -EINVAL; + + return 0; +} + +int dram_init_banksize(void) +{ + fdtdec_setup_memory_banksize(); + + /* + * On this SoC, U-Boot is running as an ELF file. Change the + * relocation address to CONFIG_SYS_TEXT_BASE, so that in + * setup_reloc, gd->reloc_off works out to 0, effectively + * disabling relocation. Otherwise U-Boot hangs in the setup + * instructions just before relocate_code in + * arch/arm/lib/crt0.S. + */ + gd->relocaddr = CONFIG_SYS_TEXT_BASE; + + return 0; +} + +void enable_caches(void) +{ + /* + * This port assumes that the prior stage bootloader has + * enabled I-cache and D-cache already. Implementing this + * function silences the warning in the default function. + */ +} + +static const phys_addr_t bcmstb_sdhci_address(u32 alias_index) +{ + int node = 0; + int ret = 0; + char sdhci[16] = { 0 }; + const void *fdt = gd->fdt_blob; + const char *path = NULL; + struct fdt_resource resource = { 0 }; + + if (!fdt) { + printf("%s: Invalid gd->fdt_blob\n", __func__); + return 0; + } + + node = fdt_path_offset(fdt, "/aliases"); + if (node < 0) { + printf("%s: Failed to find /aliases node\n", __func__); + return 0; + } + + sprintf(sdhci, "sdhci%d", alias_index); + path = fdt_getprop(fdt, node, sdhci, NULL); + if (!path) { + printf("%s: Failed to find alias for %s\n", __func__, sdhci); + return 0; + } + + node = fdt_path_offset(fdt, path); + if (node < 0) { + printf("%s: Failed to resolve BCMSTB SDHCI alias\n", __func__); + return 0; + } + + ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", + "host", &resource); + if (ret) { + printf("%s: Failed to read BCMSTB SDHCI host resource\n", + __func__); + return 0; + } + + return resource.start; +} + +int board_mmc_init(bd_t *bis) +{ + phys_addr_t sdhci_base_address = 0; + + sdhci_base_address = bcmstb_sdhci_address(CONFIG_BCMSTB_SDHCI_INDEX); + + if (!sdhci_base_address) { + sdhci_base_address = BCMSTB_SDHCI_BASE; + printf("%s: Assuming BCMSTB SDHCI address: 0x%p\n", + __func__, (void *)sdhci_base_address); + } + + debug("BCMSTB SDHCI base address: 0x%p\n", (void *)sdhci_base_address); + + bcmstb_sdhci_init(sdhci_base_address); + + return 0; +} + +int timer_init(void) +{ + gd->arch.timer_rate_hz = readl(BCMSTB_TIMER_FREQUENCY); + + return 0; +} + +ulong get_tbclk(void) +{ + return gd->arch.timer_rate_hz; +} + +uint64_t get_ticks(void) +{ + gd->timebase_h = readl(BCMSTB_TIMER_HIGH); + gd->timebase_l = readl(BCMSTB_TIMER_LOW); + + return ((uint64_t)gd->timebase_h << 32) | gd->timebase_l; +} + +int board_late_init(void) +{ + debug("Arguments from prior stage bootloader:\n"); + debug("General Purpose Register 0: 0x%x\n", bcmstb_boot_parameters.r0); + debug("General Purpose Register 1: 0x%x\n", bcmstb_boot_parameters.r1); + debug("General Purpose Register 2: 0x%x\n", bcmstb_boot_parameters.r2); + debug("General Purpose Register 3: 0x%x\n", bcmstb_boot_parameters.r3); + debug("Stack Pointer Register: 0x%x\n", bcmstb_boot_parameters.sp); + debug("Link Register: 0x%x\n", bcmstb_boot_parameters.lr); + debug("Assuming timer frequency register at: 0x%p\n", + (void *)BCMSTB_TIMER_FREQUENCY); + debug("Read timer frequency (in Hz): %ld\n", gd->arch.timer_rate_hz); + debug("Prior stage provided DTB at: 0x%p\n", + (void *)prior_stage_fdt_address); + + /* + * Set fdtcontroladdr in the environment so that scripts can + * refer to it, for example, to reuse it for fdtaddr. + */ + env_set_hex("fdtcontroladdr", prior_stage_fdt_address); + + /* + * Do not set machid to the machine identifier value provided + * by the prior stage bootloader (bcmstb_boot_parameters.r1) + * because we're using a device tree to boot Linux. + */ + + return 0; +} diff --git a/configs/bcm7445_defconfig b/configs/bcm7445_defconfig new file mode 100644 index 0000000..46dea17 --- /dev/null +++ b/configs/bcm7445_defconfig @@ -0,0 +1,27 @@ +CONFIG_ARM=y +CONFIG_ARCH_BCMSTB=y +CONFIG_TARGET_BCM7445=y +CONFIG_USE_PRIVATE_LIBGCC=y +CONFIG_OF_CONTROL=y +CONFIG_OF_PRIOR_STAGE=y +CONFIG_DM=y +CONFIG_DM_SPI=y +CONFIG_DM_SPI_FLASH=y +CONFIG_SPI=y +CONFIG_SPI_FLASH=y +CONFIG_ENV_IS_IN_SPI_FLASH=y +CONFIG_BCMSTB_SPI=y +CONFIG_FIT=y +CONFIG_FIT_SIGNATURE=y +CONFIG_RSA=y +CONFIG_BLK=n +CONFIG_SDHCI=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_BCMSTB=y +CONFIG_CONS_INDEX=3 +CONFIG_BOOTDELAY=1 +CONFIG_SYS_PROMPT="U-Boot>" +CONFIG_HUSH_PARSER=y +CONFIG_SYS_TEXT_BASE=0x80100000 +CONFIG_SYS_NS16550_COM3=0xf040ab00 +CONFIG_EFI_LOADER=n diff --git a/doc/README.bcm7xxx b/doc/README.bcm7xxx new file mode 100644 index 0000000..9b5eae4 --- /dev/null +++ b/doc/README.bcm7xxx @@ -0,0 +1,150 @@ +Summary +======= + +This document describes how to use U-Boot on the Broadcom 7445 SoC, as +a third stage bootloader loaded by Broadcom's BOLT bootloader. + +BOLT loads U-Boot as a generic ELF binary. Some U-Boot features such +as networking are not yet available but other important features are, +including: + + - ext4 file system traversal + + - support for loading FIT images + + - advanced scripting + + - support for FIT-provided DTBs instead of relying on the + BOLT-provided DTB + +A customized version of this port has been used in production. The +same approach may work on other BCM7xxx boards, with some +configuration adjustments and memory layout experimentation. + +Build +===== + +make bcm7445_defconfig +make +${CROSS_COMPILE}strip u-boot + +Run +=== + +Flash the u-boot binary into board storage, then invoke it from BOLT. +For example: + +BOLT> boot -bsu -elf flash0.u-boot1 + +This port assumes that I-cache and D-cache are already enabled when +U-Boot is entered. + +Flattened Image Tree Support +============================ + +What follows is an example FIT image source file. Build it with: + +mkimage -f image.its image.itb + +Booting the resulting image.itb was tested on BOLT v1.20, with the +following kernels: + +https://github.com/Broadcom/stblinux-3.14 +https://github.com/Broadcom/stblinux-4.1 +https://github.com/Broadcom/stblinux-4.9 + +and with a generic ARMv7 root file system. + +image.its: +/dts-v1/; +/ { + description = "BCM7445 FIT"; + images { + kernel@1 { + description = "Linux kernel"; + /* + * This kernel image output format can be + * generated with: + * + * make vmlinux + * ${CROSS_COMPILE}objcopy -O binary -S vmlinux vmlinux.bin + * gzip -9 vmlinux.bin + * + * For stblinux-3.14, the specific Broadcom + * board type should be configured in the + * kernel, for example CONFIG_BCM7445D0=y. + */ + data = /incbin/("<vmlinux.bin.gz>"); + type = "kernel"; + arch = "arm"; + os = "linux"; + compression = "gzip"; + load = <0x8000>; + entry = <0x8000>; + hash@1 { + algo = "sha256"; + }; + }; + ramdisk@1 { + description = "Initramfs root file system"; + data = /incbin/("<initramfs.cpio.gz>"); + type = "ramdisk"; + arch = "arm"; + os = "linux"; + compression = "gzip"; + /* + * Set the environment variable initrd_high to + * 0xffffffff, and set "load" and "entry" here + * to 0x0 to keep initramfs in-place and to + * accommodate stblinux bmem/CMA reservations. + */ + load = <0x0>; + entry = <0x0>; + hash@1 { + algo = "sha256"; + }; + }; + fdt@1 { + description = "Device tree dumped from BOLT"; + /* + * This DTB should be similar to the + * BOLT-generated device tree, after BOLT has + * done its runtime modifications to it. For + * example, it can be dumped from within + * U-Boot (at ${fdtcontroladdr}), after BOLT + * has loaded U-Boot. The result can be added + * to the Linux source tree as a .dts file. + * + * To support modifications to the device tree + * in-place in U-Boot, add to Linux's + * arch/arm/boot/dts/Makefile: + * + * DTC_FLAGS ?= -p 4096 + * + * This will leave some padding in the DTB and + * thus reserve room for node additions. + * + * Also, set the environment variable fdt_high + * to 0xffffffff to keep the DTB in-place and + * to accommodate stblinux bmem/CMA + * reservations. + */ + data = /incbin/("<bolt-<version>.dtb"); + type = "flat_dt"; + arch = "arm"; + compression = "none"; + hash@1 { + algo = "sha256"; + }; + }; + }; + configurations { + default = "conf@bcm7445"; + conf@bcm7445 { + description = "BCM7445 configuration"; + kernel = "kernel@1"; + ramdisk = "ramdisk@1"; + fdt = "fdt@1"; + }; + }; +}; diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 693b3ce..377b1c4 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -379,6 +379,17 @@ config MMC_SDHCI_BCM2835
If unsure, say N.
+config MMC_SDHCI_BCMSTB + tristate "SDHCI support for the BCMSTB SD/MMC Controller" + depends on MMC_SDHCI + help + This selects the Broadcom set-top box SD/MMC controller. + + If you have a BCMSTB platform with SD or MMC devices, + say Y here. + + If unsure, say N. + config MMC_SDHCI_CADENCE bool "SDHCI support for the Cadence SD/SDIO/eMMC controller" depends on BLK && DM_MMC diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 3a9805d..f619186 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_STM32_SDMMC2) += stm32_sdmmc2.o obj-$(CONFIG_MMC_SDHCI) += sdhci.o obj-$(CONFIG_MMC_SDHCI_ATMEL) += atmel_sdhci.o obj-$(CONFIG_MMC_SDHCI_BCM2835) += bcm2835_sdhci.o +obj-$(CONFIG_MMC_SDHCI_BCMSTB) += bcmstb_sdhci.o obj-$(CONFIG_MMC_SDHCI_CADENCE) += sdhci-cadence.o obj-$(CONFIG_MMC_SDHCI_KONA) += kona_sdhci.o obj-$(CONFIG_MMC_SDHCI_MSM) += msm_sdhci.o diff --git a/drivers/mmc/bcmstb_sdhci.c b/drivers/mmc/bcmstb_sdhci.c new file mode 100644 index 0000000..443ae8d --- /dev/null +++ b/drivers/mmc/bcmstb_sdhci.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + */ + +#include <common.h> +#include <mach/sdhci.h> +#include <malloc.h> +#include <sdhci.h> + +/* + * The BCMSTB SDHCI has a quirk in that its actual maximum frequency + * capability is 100 MHz. The divisor that is eventually written to + * SDHCI_CLOCK_CONTROL is calculated based on what the MMC device + * reports, and relative to this maximum frequency. + * + * This define used to be set to 52000000 (52 MHz), the desired + * maximum frequency, but that would result in the communication + * actually running at 100 MHz (seemingly without issue), which is + * out-of-spec. + * + * Now, by setting this to 0 (auto-detect), 100 MHz will be read from + * the capabilities register, and the resulting divisor will be + * doubled, meaning that the clock control register will be set to the + * in-spec 52 MHz value. + */ +#define BCMSTB_SDHCI_MAXIMUM_CLOCK_FREQUENCY 0 +/* + * When the minimum clock frequency is set to 0 (auto-detect), U-Boot + * sets it to 100 MHz divided by SDHCI_MAX_DIV_SPEC_300, or 48,875 Hz, + * which results in the controller timing out when trying to + * communicate with the MMC device. Hard-code this value to 400000 + * (400 kHz) to prevent this. + */ +#define BCMSTB_SDHCI_MINIMUM_CLOCK_FREQUENCY 400000 + +static char *BCMSTB_SDHCI_NAME = "bcmstb-sdhci"; + +/* + * This driver has only been tested with eMMC devices; SD devices may + * not work. + */ +int bcmstb_sdhci_init(phys_addr_t regbase) +{ + struct sdhci_host *host = NULL; + + host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host)); + if (!host) { + printf("%s: Failed to allocate memory\n", __func__); + return 1; + } + memset(host, 0, sizeof(*host)); + + host->name = BCMSTB_SDHCI_NAME; + host->ioaddr = (void *)regbase; + host->quirks = 0; + + host->cfg.part_type = PART_TYPE_DOS; + + host->version = sdhci_readw(host, SDHCI_HOST_VERSION); + + return add_sdhci(host, + BCMSTB_SDHCI_MAXIMUM_CLOCK_FREQUENCY, + BCMSTB_SDHCI_MINIMUM_CLOCK_FREQUENCY); +} diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 3532c2a..f5960a7 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -66,6 +66,13 @@ config BCM63XX_SPI access the SPI NOR flash on platforms embedding these Broadcom SPI cores.
+config BCMSTB_SPI + bool "BCMSTB SPI driver" + help + Enable the Broadcom set-top box SPI driver. This driver can + be used to access the SPI flash on platforms embedding this + Broadcom SPI core. + config CADENCE_QSPI bool "Cadence QSPI driver" help diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 5a2c00e..e73b0cd 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_ATH79_SPI) += ath79_spi.o obj-$(CONFIG_ATMEL_SPI) += atmel_spi.o obj-$(CONFIG_BCM63XX_HSSPI) += bcm63xx_hsspi.o obj-$(CONFIG_BCM63XX_SPI) += bcm63xx_spi.o +obj-$(CONFIG_BCMSTB_SPI) += bcmstb_spi.o obj-$(CONFIG_CADENCE_QSPI) += cadence_qspi.o cadence_qspi_apb.o obj-$(CONFIG_CF_SPI) += cf_spi.o obj-$(CONFIG_DAVINCI_SPI) += davinci_spi.o diff --git a/drivers/spi/bcmstb_spi.c b/drivers/spi/bcmstb_spi.c new file mode 100644 index 0000000..fb1dc46 --- /dev/null +++ b/drivers/spi/bcmstb_spi.c @@ -0,0 +1,439 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + */ + +#include <asm/io.h> +#include <command.h> +#include <config.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <log.h> +#include <malloc.h> +#include <spi.h> +#include <time.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define SPBR_MIN 8 +#define BITS_PER_WORD 8 + +#define NUM_TXRAM 32 +#define NUM_RXRAM 32 +#define NUM_CDRAM 16 + +/* hif_mspi register structure. */ +struct bcmstb_hif_mspi_regs { + u32 spcr0_lsb; /* 0x000 */ + u32 spcr0_msb; /* 0x004 */ + u32 spcr1_lsb; /* 0x008 */ + u32 spcr1_msb; /* 0x00c */ + u32 newqp; /* 0x010 */ + u32 endqp; /* 0x014 */ + u32 spcr2; /* 0x018 */ + u32 reserved0; /* 0x01c */ + u32 mspi_status; /* 0x020 */ + u32 cptqp; /* 0x024 */ + u32 spcr3; /* 0x028 */ + u32 revision; /* 0x02c */ + u32 reserved1[4]; /* 0x030 */ + u32 txram[NUM_TXRAM]; /* 0x040 */ + u32 rxram[NUM_RXRAM]; /* 0x0c0 */ + u32 cdram[NUM_CDRAM]; /* 0x140 */ + u32 write_lock; /* 0x180 */ +}; + +/* hif_mspi masks. */ +#define HIF_MSPI_SPCR2_CONT_AFTER_CMD_MASK 0x00000080 +#define HIF_MSPI_SPCR2_SPE_MASK 0x00000040 +#define HIF_MSPI_SPCR2_SPIFIE_MASK 0x00000020 +#define HIF_MSPI_WRITE_LOCK_WRITE_LOCK_MASK 0x00000001 + +/* bspi offsets. */ +#define BSPI_MAST_N_BOOT_CTRL 0x008 + +/* bspi_raf is not used in this driver. */ + +/* hif_spi_intr2 offsets and masks. */ +#define HIF_SPI_INTR2_CPU_CLEAR 0x08 +#define HIF_SPI_INTR2_CPU_MASK_SET 0x10 +#define HIF_SPI_INTR2_CPU_MASK_CLEAR 0x14 +#define HIF_SPI_INTR2_CPU_SET_MSPI_DONE_MASK 0x00000020 + +/* SPI transfer timeout in milliseconds. */ +#define HIF_MSPI_WAIT 10 + +enum bcmstb_base_type { + HIF_MSPI, + BSPI, + HIF_SPI_INTR2, + CS_REG, + BASE_LAST, +}; + +struct bcmstb_spi_platdata { + void *base[4]; +}; + +struct bcmstb_spi_priv { + struct bcmstb_hif_mspi_regs *regs; + void *bspi; + void *hif_spi_intr2; + void *cs_reg; + int default_cs; + int curr_cs; + uint tx_slot; + uint rx_slot; + u8 saved_cmd[NUM_CDRAM]; + uint saved_cmd_len; + void *saved_din_addr; +}; + +static int bcmstb_spi_ofdata_to_platdata(struct udevice *bus) +{ + struct bcmstb_spi_platdata *plat = dev_get_platdata(bus); + const void *fdt = gd->fdt_blob; + int node = dev_of_offset(bus); + int ret = 0; + int i = 0; + struct fdt_resource resource = { 0 }; + char *names[BASE_LAST] = { "hif_mspi", "bspi", "hif_spi_intr2", + "cs_reg" }; + const phys_addr_t defaults[BASE_LAST] = { BCMSTB_HIF_MSPI_BASE, + BCMSTB_BSPI_BASE, + BCMSTB_HIF_SPI_INTR2, + BCMSTB_CS_REG }; + + for (i = 0; i < BASE_LAST; i++) { + plat->base[i] = (void *)defaults[i]; + + ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", + names[i], &resource); + if (ret) { + printf("%s: Assuming BCMSTB SPI %s address 0x0x%p\n", + __func__, names[i], (void *)defaults[i]); + } else { + plat->base[i] = (void *)resource.start; + debug("BCMSTB SPI %s address: 0x0x%p\n", + names[i], (void *)plat->base[i]); + } + } + + return 0; +} + +static void bcmstb_spi_hw_set_parms(struct bcmstb_spi_priv *priv) +{ + writel(SPBR_MIN, &priv->regs->spcr0_lsb); + writel(BITS_PER_WORD << 2 | SPI_MODE_3, &priv->regs->spcr0_msb); +} + +static void bcmstb_spi_enable_interrupt(void *base, u32 mask) +{ + void *reg = base + HIF_SPI_INTR2_CPU_MASK_CLEAR; + + writel(readl(reg) | mask, reg); + readl(reg); +} + +static void bcmstb_spi_disable_interrupt(void *base, u32 mask) +{ + void *reg = base + HIF_SPI_INTR2_CPU_MASK_SET; + + writel(readl(reg) | mask, reg); + readl(reg); +} + +static void bcmstb_spi_clear_interrupt(void *base, u32 mask) +{ + void *reg = base + HIF_SPI_INTR2_CPU_CLEAR; + + writel(readl(reg) | mask, reg); + readl(reg); +} + +static int bcmstb_spi_probe(struct udevice *bus) +{ + struct bcmstb_spi_platdata *plat = dev_get_platdata(bus); + struct bcmstb_spi_priv *priv = dev_get_priv(bus); + + priv->regs = plat->base[HIF_MSPI]; + priv->bspi = plat->base[BSPI]; + priv->hif_spi_intr2 = plat->base[HIF_SPI_INTR2]; + priv->cs_reg = plat->base[CS_REG]; + priv->default_cs = 0; + priv->curr_cs = -1; + priv->tx_slot = 0; + priv->rx_slot = 0; + memset(priv->saved_cmd, 0, NUM_CDRAM); + priv->saved_cmd_len = 0; + priv->saved_din_addr = NULL; + + debug("spi_xfer: tx regs: 0x%p\n", &priv->regs->txram[0]); + debug("spi_xfer: rx regs: 0x%p\n", &priv->regs->rxram[0]); + + /* Disable BSPI. */ + writel(1, priv->bspi + BSPI_MAST_N_BOOT_CTRL); + readl(priv->bspi + BSPI_MAST_N_BOOT_CTRL); + + /* Set up interrupts. */ + bcmstb_spi_disable_interrupt(priv->hif_spi_intr2, 0xffffffff); + bcmstb_spi_clear_interrupt(priv->hif_spi_intr2, 0xffffffff); + bcmstb_spi_enable_interrupt(priv->hif_spi_intr2, + HIF_SPI_INTR2_CPU_SET_MSPI_DONE_MASK); + + /* Set up control registers. */ + writel(0, &priv->regs->spcr1_lsb); + writel(0, &priv->regs->spcr1_msb); + writel(0, &priv->regs->newqp); + writel(0, &priv->regs->endqp); + writel(HIF_MSPI_SPCR2_SPIFIE_MASK, &priv->regs->spcr2); + writel(0, &priv->regs->spcr3); + + bcmstb_spi_hw_set_parms(priv); + + return 0; +} + +static void bcmstb_spi_submit(struct bcmstb_spi_priv *priv, bool done) +{ + debug("WR NEWQP: %d\n", 0); + writel(0, &priv->regs->newqp); + + debug("WR ENDQP: %d\n", priv->tx_slot - 1); + writel(priv->tx_slot - 1, &priv->regs->endqp); + + if (done) { + debug("WR CDRAM[%d]: %02x\n", priv->tx_slot - 1, + readl(&priv->regs->cdram[priv->tx_slot - 1]) & ~0x80); + writel(readl(&priv->regs->cdram[priv->tx_slot - 1]) & ~0x80, + &priv->regs->cdram[priv->tx_slot - 1]); + } + + /* Force chip select first time. */ + if (priv->curr_cs != priv->default_cs) { + debug("spi_xfer: switching chip select to %d\n", + priv->default_cs); + writel((readl(priv->cs_reg) & ~0xff) | (1 << priv->default_cs), + priv->cs_reg); + readl(priv->cs_reg); + udelay(10); + priv->curr_cs = priv->default_cs; + } + + debug("WR WRITE_LOCK: %02x\n", 1); + writel((readl(&priv->regs->write_lock) & + ~HIF_MSPI_WRITE_LOCK_WRITE_LOCK_MASK) | 1, + &priv->regs->write_lock); + readl(&priv->regs->write_lock); + + debug("WR SPCR2: %02x\n", + HIF_MSPI_SPCR2_SPIFIE_MASK | + HIF_MSPI_SPCR2_SPE_MASK | + HIF_MSPI_SPCR2_CONT_AFTER_CMD_MASK); + writel(HIF_MSPI_SPCR2_SPIFIE_MASK | + HIF_MSPI_SPCR2_SPE_MASK | + HIF_MSPI_SPCR2_CONT_AFTER_CMD_MASK, + &priv->regs->spcr2); +} + +static int bcmstb_spi_wait(struct bcmstb_spi_priv *priv) +{ + u32 start_time = get_timer(0); + u32 status = readl(&priv->regs->mspi_status); + + while (!(status & 1)) { + if (get_timer(start_time) > HIF_MSPI_WAIT) + return -ETIMEDOUT; + status = readl(&priv->regs->mspi_status); + } + + writel(readl(&priv->regs->mspi_status) & ~1, &priv->regs->mspi_status); + bcmstb_spi_clear_interrupt(priv->hif_spi_intr2, + HIF_SPI_INTR2_CPU_SET_MSPI_DONE_MASK); + + return 0; +} + +static int bcmstb_spi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + uint len = bitlen / 8; + uint tx_len = len; + uint rx_len = len; + const u8 *out_bytes = (u8 *)dout; + u8 *in_bytes = (u8 *)din; + struct udevice *bus = dev_get_parent(dev); + struct bcmstb_spi_priv *priv = dev_get_priv(bus); + struct bcmstb_hif_mspi_regs *regs = priv->regs; + + debug("spi_xfer: %d, t: 0x%p, r: 0x%p, f: %lx\n", + len, dout, din, flags); + debug("spi_xfer: chip select: %x\n", readl(priv->cs_reg) & 0xff); + debug("spi_xfer: tx addr: 0x%p\n", ®s->txram[0]); + debug("spi_xfer: rx addr: 0x%p\n", ®s->rxram[0]); + debug("spi_xfer: cd addr: 0x%p\n", ®s->cdram[0]); + + if (flags & SPI_XFER_END) { + debug("spi_xfer: clearing saved din address: 0x%p\n", + priv->saved_din_addr); + priv->saved_din_addr = NULL; + priv->saved_cmd_len = 0; + memset(priv->saved_cmd, 0, NUM_CDRAM); + } + + if (bitlen == 0) + return 0; + + if (bitlen % 8) { + printf("%s: Non-byte-aligned transfer\n", __func__); + return -EOPNOTSUPP; + } + + if (flags & ~(SPI_XFER_BEGIN | SPI_XFER_END)) { + printf("%s: Unsupported flags: %lx\n", __func__, flags); + return -EOPNOTSUPP; + } + + if (flags & SPI_XFER_BEGIN) { + priv->tx_slot = 0; + priv->rx_slot = 0; + + if (out_bytes && len > NUM_CDRAM) { + printf("%s: Unable to save transfer\n", __func__); + return -EOPNOTSUPP; + } + + if (out_bytes && !(flags & SPI_XFER_END)) { + /* + * This is the start of a transmit operation + * that will need repeating if the calling + * code polls for the result. Save it for + * subsequent transmission. + */ + debug("spi_xfer: saving command: %x, %d\n", + out_bytes[0], len); + priv->saved_cmd_len = len; + memcpy(priv->saved_cmd, out_bytes, priv->saved_cmd_len); + } + } + + if (!(flags & (SPI_XFER_BEGIN | SPI_XFER_END))) { + if (priv->saved_din_addr == din) { + /* + * The caller is polling for status. Repeat + * the last transmission. + */ + int ret = 0; + + debug("spi_xfer: Making recursive call\n"); + ret = bcmstb_spi_xfer(dev, priv->saved_cmd_len * 8, + priv->saved_cmd, NULL, + SPI_XFER_BEGIN); + if (ret) { + printf("%s: Recursive call failed\n", __func__); + return ret; + } + } else { + debug("spi_xfer: saving din address: 0x%p\n", din); + priv->saved_din_addr = din; + } + } + + while (rx_len > 0) { + priv->rx_slot = priv->tx_slot; + + while (priv->tx_slot < NUM_CDRAM && tx_len > 0) { + bcmstb_spi_hw_set_parms(priv); + debug("WR TXRAM[%d]: %02x\n", priv->tx_slot, + out_bytes ? out_bytes[len - tx_len] : 0xff); + writel(out_bytes ? out_bytes[len - tx_len] : 0xff, + ®s->txram[priv->tx_slot << 1]); + debug("WR CDRAM[%d]: %02x\n", priv->tx_slot, 0x8e); + writel(0x8e, ®s->cdram[priv->tx_slot]); + priv->tx_slot++; + tx_len--; + if (!in_bytes) + rx_len--; + } + + debug("spi_xfer: early return clauses: %d, %d, %d\n", + len <= NUM_CDRAM, + !in_bytes, + (flags & (SPI_XFER_BEGIN | + SPI_XFER_END)) == SPI_XFER_BEGIN); + if (len <= NUM_CDRAM && + !in_bytes && + (flags & (SPI_XFER_BEGIN | SPI_XFER_END)) == SPI_XFER_BEGIN) + return 0; + + bcmstb_spi_submit(priv, tx_len == 0); + + if (bcmstb_spi_wait(priv) == -ETIMEDOUT) { + printf("%s: Timed out\n", __func__); + return -ETIMEDOUT; + } + + priv->tx_slot %= NUM_CDRAM; + + if (in_bytes) { + while (priv->rx_slot < NUM_CDRAM && rx_len > 0) { + in_bytes[len - rx_len] = + readl(®s->rxram[(priv->rx_slot << 1) + + 1]) + & 0xff; + debug("RD RXRAM[%d]: %02x\n", + priv->rx_slot, in_bytes[len - rx_len]); + priv->rx_slot++; + rx_len--; + } + } + } + + if (flags & SPI_XFER_END) { + debug("WR WRITE_LOCK: %02x\n", 0); + writel((readl(&priv->regs->write_lock) & + ~HIF_MSPI_WRITE_LOCK_WRITE_LOCK_MASK) | 0, + &priv->regs->write_lock); + readl(&priv->regs->write_lock); + } + + return 0; +} + +static int bcmstb_spi_set_speed(struct udevice *dev, uint speed) +{ + return 0; +} + +static int bcmstb_spi_set_mode(struct udevice *dev, uint mode) +{ + return 0; +} + +static const struct dm_spi_ops bcmstb_spi_ops = { + .xfer = bcmstb_spi_xfer, + .set_speed = bcmstb_spi_set_speed, + .set_mode = bcmstb_spi_set_mode, +}; + +static const struct udevice_id bcmstb_spi_id[] = { + { .compatible = "brcm,spi-brcmstb" }, + { } +}; + +U_BOOT_DRIVER(bcmstb_spi) = { + .name = "bcmstb_spi", + .id = UCLASS_SPI, + .of_match = bcmstb_spi_id, + .ops = &bcmstb_spi_ops, + .ofdata_to_platdata = bcmstb_spi_ofdata_to_platdata, + .probe = bcmstb_spi_probe, + .platdata_auto_alloc_size = sizeof(struct bcmstb_spi_platdata), + .priv_auto_alloc_size = sizeof(struct bcmstb_spi_priv), +}; diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index d2d091f..c517d06 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -273,7 +273,7 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, bool created = false; int ret;
-#if CONFIG_IS_ENABLED(OF_PLATDATA) +#if CONFIG_IS_ENABLED(OF_PLATDATA) || CONFIG_IS_ENABLED(OF_PRIOR_STAGE) ret = uclass_first_device_err(UCLASS_SPI, &bus); #else ret = uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus); diff --git a/dts/Kconfig b/dts/Kconfig index 0cef225..a1a92f2 100644 --- a/dts/Kconfig +++ b/dts/Kconfig @@ -101,6 +101,13 @@ config OF_HOSTFILE This is only useful for Sandbox. Use the -d flag to U-Boot to specify the file to read.
+config OF_PRIOR_STAGE + bool "Prior stage bootloader DTB for DT control" + help + If this option is enabled, the device tree used for DT + control will be read from a device tree binary, at a memory + location passed to U-Boot by the prior stage bootloader. + endchoice
config DEFAULT_DEVICE_TREE diff --git a/include/configs/bcm7445.h b/include/configs/bcm7445.h new file mode 100644 index 0000000..f720035 --- /dev/null +++ b/include/configs/bcm7445.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + * + * Configuration settings for the Broadcom BCM7445 SoC family. + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#include "bcmstb.h" + +#define CONFIG_SYS_NS16550_COM3 0xf040ab00 + +#define BCMSTB_SDHCI_BASE 0xf03e0200 +#define BCMSTB_TIMER_LOW 0xf0412008 +#define BCMSTB_TIMER_HIGH 0xf041200c +#define BCMSTB_TIMER_FREQUENCY 0xf0412020 +#define BCMSTB_HIF_MSPI_BASE 0xf03e3400 +#define BCMSTB_BSPI_BASE 0xf03e3200 +#define BCMSTB_HIF_SPI_INTR2 0xf03e1a00 +#define BCMSTB_CS_REG 0xf03e0920 + +#endif /* __CONFIG_H */ diff --git a/include/configs/bcmstb.h b/include/configs/bcmstb.h new file mode 100644 index 0000000..8c61780 --- /dev/null +++ b/include/configs/bcmstb.h @@ -0,0 +1,183 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2018 Cisco Systems, Inc. + * + * Author: Thomas Fitzsimmons fitzsim@fitzsim.org + * + * Configuration settings for the Broadcom BCMSTB SoC family. + */ + +#ifndef __BCMSTB_H +#define __BCMSTB_H + +#include "version.h" +#include <linux/sizes.h> +#include <asm/arch/prior_stage.h> + +/* + * Generic board configuration. + */ +#define CONFIG_SYS_GENERIC_BOARD + +/* + * CPU configuration. + */ +#define CONFIG_SKIP_LOWLEVEL_INIT + +/* + * Memory configuration. + * + * The prior stage BOLT bootloader sets up memory for us. + * + * An example boot memory layout after loading everything is: + * + * 0x0000 8000 vmlinux.bin.gz + * : [~31 MiB uncompressed max] + * 0x01ef f000 FIT containing signed public key + * : [~2 KiB in size] + * 0x01f0 0000 DTB copied from prior-stage-provided region + * : [~1 MiB max] + * 0x0200 0000 FIT containing ramdisk and device tree + * : initramfs.cpio.gz + * : [~208 MiB uncompressed max, to CMA/bmem low address] + * : [~80 MiB compressed max, to PSB low address] + * : device tree binary + * : [~60 KiB] + * 0x0700 0000 Prior stage bootloader (PSB) + * : + * 0x0761 7000 Prior-stage-provided device tree binary (DTB) + * : [~40 KiB in size] + * 0x0f00 0000 Contiguous memory allocator (CMA/bmem) low address + * : + * 0x8010 0000 U-Boot code at ELF load address + * : [~500 KiB in size, stripped] + * 0xc000 0000 Top of RAM + * + * Setting gd->relocaddr to CONFIG_SYS_TEXT_BASE in dram_init_banksize + * prevents U-Boot from relocating itself when it is run as an ELF + * program by the prior stage bootloader. + * + * We want to keep the ramdisk and FDT in the FIT image in-place, to + * accommodate stblinux's bmem and CMA regions. To accomplish this, + * we set initrd_high and fdt_high to 0xffffffff, and the load and + * entry addresses of the FIT ramdisk entry to 0x0. + * + * Overwriting the prior stage bootloader causes memory instability, + * so the compressed initramfs needs to fit between the load address + * and the PSB low address. In BOLT's default configuration this + * limits the compressed size of the initramfs to approximately 80 + * MiB. However, BOLT can be configured to allow loading larger + * initramfs images, in which case this limitation is eliminated. + */ +#define CONFIG_NR_DRAM_BANKS 3 + +#define CONFIG_SYS_SDRAM_BASE 0x00000000 +#define CONFIG_SYS_TEXT_BASE 0x80100000 +#define CONFIG_SYS_INIT_RAM_ADDR 0x80200000 +#define CONFIG_SYS_INIT_RAM_SIZE 0x100000 +#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_INIT_RAM_ADDR + \ + CONFIG_SYS_INIT_RAM_SIZE - \ + GENERATED_GBL_DATA_SIZE) +#define CONFIG_SYS_MALLOC_LEN ((10 * 1024) << 10) /* 10 MiB */ +#define CONFIG_SYS_LOAD_ADDR 0x2000000 + +/* + * CONFIG_SYS_LOAD_ADDR - 1 MiB. + */ +#define CONFIG_SYS_FDT_SAVE_ADDRESS 0x1f00000 +#define CONFIG_SYS_CBSIZE 512 +#define CONFIG_SYS_MAXARGS 32 + +/* + * Large kernel image bootm configuration. + */ +#define CONFIG_SYS_BOOTM_LEN SZ_64M + +/* + * NS16550 configuration. + */ +#define V_NS16550_CLK 81000000 + +#define CONFIG_SYS_NS16550 +#define CONFIG_SYS_NS16550_SERIAL +#define CONFIG_SYS_NS16550_REG_SIZE (-4) +#define CONFIG_SYS_NS16550_CLK V_NS16550_CLK + +/* + * Serial console configuration. + */ +#define CONFIG_SERIAL3 3 + +#define CONFIG_BAUDRATE 115200 +#define CONFIG_SYS_BAUDRATE_TABLE {4800, 9600, 19200, 38400, 57600, \ + 115200} + +/* + * Informational display configuration. + */ +#define CONFIG_REVISION_TAG + +/* + * Command configuration. + */ +#define CONFIG_CMD_ASKENV +#define CONFIG_CMD_CACHE +#define CONFIG_CMD_EXT2 +#define CONFIG_CMD_SF +#define CONFIG_CMD_SPI +#define CONFIG_CMD_SF_TEST +#define CONFIG_CMD_MMC + +/* + * Flash configuration. + */ +#define CONFIG_ST_SMI +#define CONFIG_SPI_FLASH_STMICRO +#define CONFIG_SPI_FLASH_MACRONIX + +/* + * Filesystem configuration. + */ +#define CONFIG_DOS_PARTITION +#define CONFIG_CMD_EXT4 +#define CONFIG_FS_EXT4 +#define CONFIG_CMD_FS_GENERIC + +/* + * Environment configuration. + */ +#define CONFIG_SYS_REDUNDAND_ENVIRONMENT + +#define CONFIG_ENV_IS_IN_SPI_FLASH 1 +#define CONFIG_ENV_OFFSET 0x1e0000 +#define CONFIG_ENV_SIZE (64 << 10) /* 64 KiB */ +#define CONFIG_ENV_SECT_SIZE CONFIG_ENV_SIZE +#define CONFIG_ENV_OFFSET_REDUND (CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE) +#define CONFIG_ENV_OVERWRITE + +/* + * Save the prior stage provided DTB. + */ +#define CONFIG_PREBOOT \ + "fdt addr ${fdtcontroladdr};" \ + "fdt move ${fdtcontroladdr} ${fdtsaveaddr};" \ + "fdt addr ${fdtsaveaddr};" +/* + * Enable in-place RFS with this initrd_high setting. + */ +#define CONFIG_EXTRA_ENV_SETTINGS \ + "fdtsaveaddr=" __stringify(CONFIG_SYS_FDT_SAVE_ADDRESS) "\0" \ + "initrd_high=0xffffffff\0" \ + "fdt_high=0xffffffff\0" + +/* + * Set fdtaddr to prior stage-provided DTB in board_late_init, when + * writeable environment is available. + */ +#define CONFIG_BOARD_LATE_INIT + +#define CONFIG_SYS_MAX_FLASH_BANKS 1 + +#define CONFIG_DM_SPI 1 + +#endif /* __BCMSTB_H */ diff --git a/include/fdtdec.h b/include/fdtdec.h index c15b2a0..ff1c5f5 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -47,6 +47,10 @@ struct fdt_memory { #define SPL_BUILD 0 #endif
+#if CONFIG_IS_ENABLED(OF_PRIOR_STAGE) +extern phys_addr_t prior_stage_fdt_address; +#endif + /* * Information about a resource. start is the first address of the resource * and end is the last address (inclusive). The length of the resource will diff --git a/lib/fdtdec.c b/lib/fdtdec.c index f4e8dbf..b29b283 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -1323,8 +1323,12 @@ int fdtdec_setup(void) # endif # ifndef CONFIG_SPL_BUILD /* Allow the early environment to override the fdt address */ +# if CONFIG_IS_ENABLED(OF_PRIOR_STAGE) + gd->fdt_blob = (void *)prior_stage_fdt_address; +# else gd->fdt_blob = (void *)env_get_ulong("fdtcontroladdr", 16, (uintptr_t)gd->fdt_blob); +# endif # endif
# if CONFIG_IS_ENABLED(MULTI_DTB_FIT)

On Fri, Jun 08, 2018 at 05:59:45PM -0400, Thomas Fitzsimmons wrote:
Add support for loading U-Boot on the Broadcom 7445 SoC. This port assumes Broadcom's BOLT bootloader is acting as the second stage bootloader, and U-Boot is acting as the third stage bootloader, loaded as an ELF program by BOLT.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Stefan Roese sr@denx.de Cc: Tom Rini trini@konsulko.com Cc: Florian Fainelli f.fainelli@gmail.com
Applied to u-boot/master, thanks!

Hi Thomas,
On Sat, Jun 9, 2018 at 6:06 AM Thomas Fitzsimmons fitzsim@fitzsim.org wrote:
Add support for loading U-Boot on the Broadcom 7445 SoC. This port assumes Broadcom's BOLT bootloader is acting as the second stage bootloader, and U-Boot is acting as the third stage bootloader, loaded as an ELF program by BOLT.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Stefan Roese sr@denx.de Cc: Tom Rini trini@konsulko.com Cc: Florian Fainelli f.fainelli@gmail.com
Changes for v4:
- Use high timer register for get_ticks
- Move hard-coded register addresses from Kconfig to header
- Document I-cache/D-cache expectation
MAINTAINERS | 10 + arch/arm/Kconfig | 12 + arch/arm/Makefile | 1 + arch/arm/mach-bcmstb/Kconfig | 36 ++ arch/arm/mach-bcmstb/Makefile | 8 + arch/arm/mach-bcmstb/include/mach/gpio.h | 11 + arch/arm/mach-bcmstb/include/mach/hardware.h | 11 + arch/arm/mach-bcmstb/include/mach/prior_stage.h | 30 ++ arch/arm/mach-bcmstb/include/mach/sdhci.h | 15 + arch/arm/mach-bcmstb/include/mach/timer.h | 13 + arch/arm/mach-bcmstb/lowlevel_init.S | 21 ++ board/broadcom/bcmstb/MAINTAINERS | 7 + board/broadcom/bcmstb/Makefile | 8 + board/broadcom/bcmstb/bcmstb.c | 194 +++++++++++ configs/bcm7445_defconfig | 27 ++ doc/README.bcm7xxx | 150 ++++++++ drivers/mmc/Kconfig | 11 + drivers/mmc/Makefile | 1 + drivers/mmc/bcmstb_sdhci.c | 67 ++++ drivers/spi/Kconfig | 7 + drivers/spi/Makefile | 1 + drivers/spi/bcmstb_spi.c | 439 ++++++++++++++++++++++++ drivers/spi/spi-uclass.c | 2 +- dts/Kconfig | 7 + include/configs/bcm7445.h | 26 ++ include/configs/bcmstb.h | 183 ++++++++++ include/fdtdec.h | 4 + lib/fdtdec.c | 4 + 28 files changed, 1305 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-bcmstb/Kconfig create mode 100644 arch/arm/mach-bcmstb/Makefile create mode 100644 arch/arm/mach-bcmstb/include/mach/gpio.h create mode 100644 arch/arm/mach-bcmstb/include/mach/hardware.h create mode 100644 arch/arm/mach-bcmstb/include/mach/prior_stage.h create mode 100644 arch/arm/mach-bcmstb/include/mach/sdhci.h create mode 100644 arch/arm/mach-bcmstb/include/mach/timer.h create mode 100644 arch/arm/mach-bcmstb/lowlevel_init.S create mode 100644 board/broadcom/bcmstb/MAINTAINERS create mode 100644 board/broadcom/bcmstb/Makefile create mode 100644 board/broadcom/bcmstb/bcmstb.c create mode 100644 configs/bcm7445_defconfig create mode 100644 doc/README.bcm7xxx create mode 100644 drivers/mmc/bcmstb_sdhci.c create mode 100644 drivers/spi/bcmstb_spi.c create mode 100644 include/configs/bcm7445.h create mode 100644 include/configs/bcmstb.h
[snip]
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index d2d091f..c517d06 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -273,7 +273,7 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, bool created = false; int ret;
-#if CONFIG_IS_ENABLED(OF_PLATDATA) +#if CONFIG_IS_ENABLED(OF_PLATDATA) || CONFIG_IS_ENABLED(OF_PRIOR_STAGE)
Could you please explain this change a little bit? Why should we call uclass_first_device_err() for OF_PRIOR_STAGE?
ret = uclass_first_device_err(UCLASS_SPI, &bus);
#else ret = uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus); diff --git a/dts/Kconfig b/dts/Kconfig index 0cef225..a1a92f2 100644 --- a/dts/Kconfig +++ b/dts/Kconfig @@ -101,6 +101,13 @@ config OF_HOSTFILE This is only useful for Sandbox. Use the -d flag to U-Boot to specify the file to read.
+config OF_PRIOR_STAGE
bool "Prior stage bootloader DTB for DT control"
help
If this option is enabled, the device tree used for DT
control will be read from a device tree binary, at a memory
location passed to U-Boot by the prior stage bootloader.
endchoice
[snip]
Regards, Bin

Hi Bin,
Bin Meng bmeng.cn@gmail.com writes:
Hi Thomas,
On Sat, Jun 9, 2018 at 6:06 AM Thomas Fitzsimmons fitzsim@fitzsim.org wrote:
Add support for loading U-Boot on the Broadcom 7445 SoC. This port assumes Broadcom's BOLT bootloader is acting as the second stage bootloader, and U-Boot is acting as the third stage bootloader, loaded as an ELF program by BOLT.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Stefan Roese sr@denx.de Cc: Tom Rini trini@konsulko.com Cc: Florian Fainelli f.fainelli@gmail.com
Changes for v4:
- Use high timer register for get_ticks
- Move hard-coded register addresses from Kconfig to header
- Document I-cache/D-cache expectation
MAINTAINERS | 10 + arch/arm/Kconfig | 12 + arch/arm/Makefile | 1 + arch/arm/mach-bcmstb/Kconfig | 36 ++ arch/arm/mach-bcmstb/Makefile | 8 + arch/arm/mach-bcmstb/include/mach/gpio.h | 11 + arch/arm/mach-bcmstb/include/mach/hardware.h | 11 + arch/arm/mach-bcmstb/include/mach/prior_stage.h | 30 ++ arch/arm/mach-bcmstb/include/mach/sdhci.h | 15 + arch/arm/mach-bcmstb/include/mach/timer.h | 13 + arch/arm/mach-bcmstb/lowlevel_init.S | 21 ++ board/broadcom/bcmstb/MAINTAINERS | 7 + board/broadcom/bcmstb/Makefile | 8 + board/broadcom/bcmstb/bcmstb.c | 194 +++++++++++ configs/bcm7445_defconfig | 27 ++ doc/README.bcm7xxx | 150 ++++++++ drivers/mmc/Kconfig | 11 + drivers/mmc/Makefile | 1 + drivers/mmc/bcmstb_sdhci.c | 67 ++++ drivers/spi/Kconfig | 7 + drivers/spi/Makefile | 1 + drivers/spi/bcmstb_spi.c | 439 ++++++++++++++++++++++++ drivers/spi/spi-uclass.c | 2 +- dts/Kconfig | 7 + include/configs/bcm7445.h | 26 ++ include/configs/bcmstb.h | 183 ++++++++++ include/fdtdec.h | 4 + lib/fdtdec.c | 4 + 28 files changed, 1305 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-bcmstb/Kconfig create mode 100644 arch/arm/mach-bcmstb/Makefile create mode 100644 arch/arm/mach-bcmstb/include/mach/gpio.h create mode 100644 arch/arm/mach-bcmstb/include/mach/hardware.h create mode 100644 arch/arm/mach-bcmstb/include/mach/prior_stage.h create mode 100644 arch/arm/mach-bcmstb/include/mach/sdhci.h create mode 100644 arch/arm/mach-bcmstb/include/mach/timer.h create mode 100644 arch/arm/mach-bcmstb/lowlevel_init.S create mode 100644 board/broadcom/bcmstb/MAINTAINERS create mode 100644 board/broadcom/bcmstb/Makefile create mode 100644 board/broadcom/bcmstb/bcmstb.c create mode 100644 configs/bcm7445_defconfig create mode 100644 doc/README.bcm7xxx create mode 100644 drivers/mmc/bcmstb_sdhci.c create mode 100644 drivers/spi/bcmstb_spi.c create mode 100644 include/configs/bcm7445.h create mode 100644 include/configs/bcmstb.h
[snip]
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index d2d091f..c517d06 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -273,7 +273,7 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, bool created = false; int ret;
-#if CONFIG_IS_ENABLED(OF_PLATDATA) +#if CONFIG_IS_ENABLED(OF_PLATDATA) || CONFIG_IS_ENABLED(OF_PRIOR_STAGE)
Could you please explain this change a little bit? Why should we call uclass_first_device_err() for OF_PRIOR_STAGE?
ret = uclass_first_device_err(UCLASS_SPI, &bus);
#else ret = uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus);
On the BCM7445 eval board, the prior-stage-provided device tree does not have an alias for spi0, though it has aliases for other device types; I don't know why this is the case, but I don't have control over what the prior stage bootloader (Broadcom's BOLT) provides. Without that alias, uclass_get_device_by_seq fails to find the SPI bus (and so U-Boot can't find the SPI flash device that stores its environment).
At the time, I checked other ARM device trees in the Linux kernel and not many set an alias for spi0, so I wrote the patch to choose the first SPI bus. Doing so was in line with what CONFIG_OF_PLATDATA did on boards that wanted to avoid device tree accesses.
I see that since I introduced CONFIG_OF_PRIOR_STAGE, several other ports have started using it, so there's probably a need to generalize this; if other prior stage bootloaders provide SPI aliases then there should be a way for this code to use them.
diff --git a/dts/Kconfig b/dts/Kconfig index 0cef225..a1a92f2 100644 --- a/dts/Kconfig +++ b/dts/Kconfig @@ -101,6 +101,13 @@ config OF_HOSTFILE This is only useful for Sandbox. Use the -d flag to U-Boot to specify the file to read.
+config OF_PRIOR_STAGE
bool "Prior stage bootloader DTB for DT control"
help
If this option is enabled, the device tree used for DT
control will be read from a device tree binary, at a memory
location passed to U-Boot by the prior stage bootloader.
endchoice
[snip]
Thomas

Hi Thomas,
On Wed, Aug 28, 2019 at 6:31 AM Thomas Fitzsimmons fitzsim@fitzsim.org wrote:
Hi Bin,
Bin Meng bmeng.cn@gmail.com writes:
Hi Thomas,
On Sat, Jun 9, 2018 at 6:06 AM Thomas Fitzsimmons fitzsim@fitzsim.org wrote:
Add support for loading U-Boot on the Broadcom 7445 SoC. This port assumes Broadcom's BOLT bootloader is acting as the second stage bootloader, and U-Boot is acting as the third stage bootloader, loaded as an ELF program by BOLT.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Stefan Roese sr@denx.de Cc: Tom Rini trini@konsulko.com Cc: Florian Fainelli f.fainelli@gmail.com
Changes for v4:
- Use high timer register for get_ticks
- Move hard-coded register addresses from Kconfig to header
- Document I-cache/D-cache expectation
MAINTAINERS | 10 + arch/arm/Kconfig | 12 + arch/arm/Makefile | 1 + arch/arm/mach-bcmstb/Kconfig | 36 ++ arch/arm/mach-bcmstb/Makefile | 8 + arch/arm/mach-bcmstb/include/mach/gpio.h | 11 + arch/arm/mach-bcmstb/include/mach/hardware.h | 11 + arch/arm/mach-bcmstb/include/mach/prior_stage.h | 30 ++ arch/arm/mach-bcmstb/include/mach/sdhci.h | 15 + arch/arm/mach-bcmstb/include/mach/timer.h | 13 + arch/arm/mach-bcmstb/lowlevel_init.S | 21 ++ board/broadcom/bcmstb/MAINTAINERS | 7 + board/broadcom/bcmstb/Makefile | 8 + board/broadcom/bcmstb/bcmstb.c | 194 +++++++++++ configs/bcm7445_defconfig | 27 ++ doc/README.bcm7xxx | 150 ++++++++ drivers/mmc/Kconfig | 11 + drivers/mmc/Makefile | 1 + drivers/mmc/bcmstb_sdhci.c | 67 ++++ drivers/spi/Kconfig | 7 + drivers/spi/Makefile | 1 + drivers/spi/bcmstb_spi.c | 439 ++++++++++++++++++++++++ drivers/spi/spi-uclass.c | 2 +- dts/Kconfig | 7 + include/configs/bcm7445.h | 26 ++ include/configs/bcmstb.h | 183 ++++++++++ include/fdtdec.h | 4 + lib/fdtdec.c | 4 + 28 files changed, 1305 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-bcmstb/Kconfig create mode 100644 arch/arm/mach-bcmstb/Makefile create mode 100644 arch/arm/mach-bcmstb/include/mach/gpio.h create mode 100644 arch/arm/mach-bcmstb/include/mach/hardware.h create mode 100644 arch/arm/mach-bcmstb/include/mach/prior_stage.h create mode 100644 arch/arm/mach-bcmstb/include/mach/sdhci.h create mode 100644 arch/arm/mach-bcmstb/include/mach/timer.h create mode 100644 arch/arm/mach-bcmstb/lowlevel_init.S create mode 100644 board/broadcom/bcmstb/MAINTAINERS create mode 100644 board/broadcom/bcmstb/Makefile create mode 100644 board/broadcom/bcmstb/bcmstb.c create mode 100644 configs/bcm7445_defconfig create mode 100644 doc/README.bcm7xxx create mode 100644 drivers/mmc/bcmstb_sdhci.c create mode 100644 drivers/spi/bcmstb_spi.c create mode 100644 include/configs/bcm7445.h create mode 100644 include/configs/bcmstb.h
[snip]
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index d2d091f..c517d06 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -273,7 +273,7 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, bool created = false; int ret;
-#if CONFIG_IS_ENABLED(OF_PLATDATA) +#if CONFIG_IS_ENABLED(OF_PLATDATA) || CONFIG_IS_ENABLED(OF_PRIOR_STAGE)
Could you please explain this change a little bit? Why should we call uclass_first_device_err() for OF_PRIOR_STAGE?
ret = uclass_first_device_err(UCLASS_SPI, &bus);
#else ret = uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus);
On the BCM7445 eval board, the prior-stage-provided device tree does not have an alias for spi0, though it has aliases for other device types; I don't know why this is the case, but I don't have control over what the prior stage bootloader (Broadcom's BOLT) provides. Without that alias, uclass_get_device_by_seq fails to find the SPI bus (and so U-Boot can't find the SPI flash device that stores its environment).
I checked uclass_get_device_by_seq() and did not find any codes that are trying to read aliases. Am I missing anything?
At the time, I checked other ARM device trees in the Linux kernel and not many set an alias for spi0, so I wrote the patch to choose the first SPI bus. Doing so was in line with what CONFIG_OF_PLATDATA did on boards that wanted to avoid device tree accesses.
Based on what you said, the adding of OF_PRIOR_STAGE here sounds like a hack.
I see that since I introduced CONFIG_OF_PRIOR_STAGE, several other ports have started using it, so there's probably a need to generalize this; if other prior stage bootloaders provide SPI aliases then there should be a way for this code to use them.
I think the correct way is to call uclass_get_device_by_seq(). CONFIG_OF_PRIOR_STAGE should not imply such behavior.
Regards, Bin

Hi Bin,
Bin Meng bmeng.cn@gmail.com writes:
Hi Thomas,
On Wed, Aug 28, 2019 at 6:31 AM Thomas Fitzsimmons fitzsim@fitzsim.org wrote:
Hi Bin,
Bin Meng bmeng.cn@gmail.com writes:
Hi Thomas,
On Sat, Jun 9, 2018 at 6:06 AM Thomas Fitzsimmons fitzsim@fitzsim.org wrote:
Add support for loading U-Boot on the Broadcom 7445 SoC. This port assumes Broadcom's BOLT bootloader is acting as the second stage bootloader, and U-Boot is acting as the third stage bootloader, loaded as an ELF program by BOLT.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Stefan Roese sr@denx.de Cc: Tom Rini trini@konsulko.com Cc: Florian Fainelli f.fainelli@gmail.com
Changes for v4:
- Use high timer register for get_ticks
- Move hard-coded register addresses from Kconfig to header
- Document I-cache/D-cache expectation
MAINTAINERS | 10 + arch/arm/Kconfig | 12 + arch/arm/Makefile | 1 + arch/arm/mach-bcmstb/Kconfig | 36 ++ arch/arm/mach-bcmstb/Makefile | 8 + arch/arm/mach-bcmstb/include/mach/gpio.h | 11 + arch/arm/mach-bcmstb/include/mach/hardware.h | 11 + arch/arm/mach-bcmstb/include/mach/prior_stage.h | 30 ++ arch/arm/mach-bcmstb/include/mach/sdhci.h | 15 + arch/arm/mach-bcmstb/include/mach/timer.h | 13 + arch/arm/mach-bcmstb/lowlevel_init.S | 21 ++ board/broadcom/bcmstb/MAINTAINERS | 7 + board/broadcom/bcmstb/Makefile | 8 + board/broadcom/bcmstb/bcmstb.c | 194 +++++++++++ configs/bcm7445_defconfig | 27 ++ doc/README.bcm7xxx | 150 ++++++++ drivers/mmc/Kconfig | 11 + drivers/mmc/Makefile | 1 + drivers/mmc/bcmstb_sdhci.c | 67 ++++ drivers/spi/Kconfig | 7 + drivers/spi/Makefile | 1 + drivers/spi/bcmstb_spi.c | 439 ++++++++++++++++++++++++ drivers/spi/spi-uclass.c | 2 +- dts/Kconfig | 7 + include/configs/bcm7445.h | 26 ++ include/configs/bcmstb.h | 183 ++++++++++ include/fdtdec.h | 4 + lib/fdtdec.c | 4 + 28 files changed, 1305 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-bcmstb/Kconfig create mode 100644 arch/arm/mach-bcmstb/Makefile create mode 100644 arch/arm/mach-bcmstb/include/mach/gpio.h create mode 100644 arch/arm/mach-bcmstb/include/mach/hardware.h create mode 100644 arch/arm/mach-bcmstb/include/mach/prior_stage.h create mode 100644 arch/arm/mach-bcmstb/include/mach/sdhci.h create mode 100644 arch/arm/mach-bcmstb/include/mach/timer.h create mode 100644 arch/arm/mach-bcmstb/lowlevel_init.S create mode 100644 board/broadcom/bcmstb/MAINTAINERS create mode 100644 board/broadcom/bcmstb/Makefile create mode 100644 board/broadcom/bcmstb/bcmstb.c create mode 100644 configs/bcm7445_defconfig create mode 100644 doc/README.bcm7xxx create mode 100644 drivers/mmc/bcmstb_sdhci.c create mode 100644 drivers/spi/bcmstb_spi.c create mode 100644 include/configs/bcm7445.h create mode 100644 include/configs/bcmstb.h
[snip]
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index d2d091f..c517d06 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -273,7 +273,7 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, bool created = false; int ret;
-#if CONFIG_IS_ENABLED(OF_PLATDATA) +#if CONFIG_IS_ENABLED(OF_PLATDATA) || CONFIG_IS_ENABLED(OF_PRIOR_STAGE)
Could you please explain this change a little bit? Why should we call uclass_first_device_err() for OF_PRIOR_STAGE?
ret = uclass_first_device_err(UCLASS_SPI, &bus);
#else ret = uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus);
On the BCM7445 eval board, the prior-stage-provided device tree does not have an alias for spi0, though it has aliases for other device types; I don't know why this is the case, but I don't have control over what the prior stage bootloader (Broadcom's BOLT) provides. Without that alias, uclass_get_device_by_seq fails to find the SPI bus (and so U-Boot can't find the SPI flash device that stores its environment).
I checked uclass_get_device_by_seq() and did not find any codes that are trying to read aliases. Am I missing anything?
Alias handling is not in the direct uclass_get_device_by_seq call chain, and it took some debugging to find this. The requested sequence number is handled earlier in the boot, in device_bind_common:
dev->seq = -1; dev->req_seq = -1; if (CONFIG_IS_ENABLED(DM_SEQ_ALIAS) && (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS)) { /* * Some devices, such as a SPI bus, I2C bus and serial ports * are numbered using aliases. * * This is just a 'requested' sequence, and will be * resolved (and ->seq updated) when the device is probed. */ if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) { if (uc->uc_drv->name && ofnode_valid(node)) dev_read_alias_seq(dev, &dev->req_seq); } else { dev->req_seq = uclass_find_next_free_req_seq(drv->id); } }
If the prior stage bootloader provides no SPI bus alias, then dev_read_alias_seq fails, dev->req_seq stays unset (-1), and later when an attempt is made to access the SPI bus, the call to uclass_get_device_by_seq fails.
At the time, I checked other ARM device trees in the Linux kernel and not many set an alias for spi0, so I wrote the patch to choose the first SPI bus. Doing so was in line with what CONFIG_OF_PLATDATA did on boards that wanted to avoid device tree accesses.
Based on what you said, the adding of OF_PRIOR_STAGE here sounds like a hack.
Yeah, it makes an assumption about which SPI bus to use, that may or may not be valid on other boards.
I see that since I introduced CONFIG_OF_PRIOR_STAGE, several other ports have started using it, so there's probably a need to generalize this; if other prior stage bootloaders provide SPI aliases then there should be a way for this code to use them.
I think the correct way is to call uclass_get_device_by_seq(). CONFIG_OF_PRIOR_STAGE should not imply such behavior.
OK, but without other changes this would break boards that rely on the above assumption (for example BCM7445).
I'm experimenting with patches that work on BCM7445 and eliminate the SPI bus assumption but I don't know what effect they might have on other ports that use OF_PRIOR_STAGE.
In general it seems like a good idea to use the prior-stage-provided aliases, but the question is what to do when an alias is missing; maybe always fall back to calling uclass_find_next_free_req_seq?
Have you found a board for which uclass_get_device_by_seq works for SPI and uclass_first_device_err does the wrong thing? Is it a publicly available port that I can have a look at?
Thanks, Thomas

+Simon
On Thu, Aug 29, 2019 at 1:24 AM Thomas Fitzsimmons fitzsim@fitzsim.org wrote:
Hi Bin,
Bin Meng bmeng.cn@gmail.com writes:
Hi Thomas,
On Wed, Aug 28, 2019 at 6:31 AM Thomas Fitzsimmons fitzsim@fitzsim.org wrote:
Hi Bin,
Bin Meng bmeng.cn@gmail.com writes:
Hi Thomas,
On Sat, Jun 9, 2018 at 6:06 AM Thomas Fitzsimmons fitzsim@fitzsim.org wrote:
Add support for loading U-Boot on the Broadcom 7445 SoC. This port assumes Broadcom's BOLT bootloader is acting as the second stage bootloader, and U-Boot is acting as the third stage bootloader, loaded as an ELF program by BOLT.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Stefan Roese sr@denx.de Cc: Tom Rini trini@konsulko.com Cc: Florian Fainelli f.fainelli@gmail.com
Changes for v4:
- Use high timer register for get_ticks
- Move hard-coded register addresses from Kconfig to header
- Document I-cache/D-cache expectation
MAINTAINERS | 10 + arch/arm/Kconfig | 12 + arch/arm/Makefile | 1 + arch/arm/mach-bcmstb/Kconfig | 36 ++ arch/arm/mach-bcmstb/Makefile | 8 + arch/arm/mach-bcmstb/include/mach/gpio.h | 11 + arch/arm/mach-bcmstb/include/mach/hardware.h | 11 + arch/arm/mach-bcmstb/include/mach/prior_stage.h | 30 ++ arch/arm/mach-bcmstb/include/mach/sdhci.h | 15 + arch/arm/mach-bcmstb/include/mach/timer.h | 13 + arch/arm/mach-bcmstb/lowlevel_init.S | 21 ++ board/broadcom/bcmstb/MAINTAINERS | 7 + board/broadcom/bcmstb/Makefile | 8 + board/broadcom/bcmstb/bcmstb.c | 194 +++++++++++ configs/bcm7445_defconfig | 27 ++ doc/README.bcm7xxx | 150 ++++++++ drivers/mmc/Kconfig | 11 + drivers/mmc/Makefile | 1 + drivers/mmc/bcmstb_sdhci.c | 67 ++++ drivers/spi/Kconfig | 7 + drivers/spi/Makefile | 1 + drivers/spi/bcmstb_spi.c | 439 ++++++++++++++++++++++++ drivers/spi/spi-uclass.c | 2 +- dts/Kconfig | 7 + include/configs/bcm7445.h | 26 ++ include/configs/bcmstb.h | 183 ++++++++++ include/fdtdec.h | 4 + lib/fdtdec.c | 4 + 28 files changed, 1305 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-bcmstb/Kconfig create mode 100644 arch/arm/mach-bcmstb/Makefile create mode 100644 arch/arm/mach-bcmstb/include/mach/gpio.h create mode 100644 arch/arm/mach-bcmstb/include/mach/hardware.h create mode 100644 arch/arm/mach-bcmstb/include/mach/prior_stage.h create mode 100644 arch/arm/mach-bcmstb/include/mach/sdhci.h create mode 100644 arch/arm/mach-bcmstb/include/mach/timer.h create mode 100644 arch/arm/mach-bcmstb/lowlevel_init.S create mode 100644 board/broadcom/bcmstb/MAINTAINERS create mode 100644 board/broadcom/bcmstb/Makefile create mode 100644 board/broadcom/bcmstb/bcmstb.c create mode 100644 configs/bcm7445_defconfig create mode 100644 doc/README.bcm7xxx create mode 100644 drivers/mmc/bcmstb_sdhci.c create mode 100644 drivers/spi/bcmstb_spi.c create mode 100644 include/configs/bcm7445.h create mode 100644 include/configs/bcmstb.h
[snip]
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index d2d091f..c517d06 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -273,7 +273,7 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, bool created = false; int ret;
-#if CONFIG_IS_ENABLED(OF_PLATDATA) +#if CONFIG_IS_ENABLED(OF_PLATDATA) || CONFIG_IS_ENABLED(OF_PRIOR_STAGE)
Could you please explain this change a little bit? Why should we call uclass_first_device_err() for OF_PRIOR_STAGE?
ret = uclass_first_device_err(UCLASS_SPI, &bus);
#else ret = uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus);
On the BCM7445 eval board, the prior-stage-provided device tree does not have an alias for spi0, though it has aliases for other device types; I don't know why this is the case, but I don't have control over what the prior stage bootloader (Broadcom's BOLT) provides. Without that alias, uclass_get_device_by_seq fails to find the SPI bus (and so U-Boot can't find the SPI flash device that stores its environment).
I checked uclass_get_device_by_seq() and did not find any codes that are trying to read aliases. Am I missing anything?
Alias handling is not in the direct uclass_get_device_by_seq call chain, and it took some debugging to find this. The requested sequence number is handled earlier in the boot, in device_bind_common:
dev->seq = -1; dev->req_seq = -1; if (CONFIG_IS_ENABLED(DM_SEQ_ALIAS) && (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS)) { /* * Some devices, such as a SPI bus, I2C bus and serial ports * are numbered using aliases. * * This is just a 'requested' sequence, and will be * resolved (and ->seq updated) when the device is probed. */ if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) { if (uc->uc_drv->name && ofnode_valid(node)) dev_read_alias_seq(dev, &dev->req_seq); } else { dev->req_seq = uclass_find_next_free_req_seq(drv->id); } }
If the prior stage bootloader provides no SPI bus alias, then dev_read_alias_seq fails, dev->req_seq stays unset (-1), and later when an attempt is made to access the SPI bus, the call to uclass_get_device_by_seq fails.
Ah, I see. Thanks!
At the time, I checked other ARM device trees in the Linux kernel and not many set an alias for spi0, so I wrote the patch to choose the first SPI bus. Doing so was in line with what CONFIG_OF_PLATDATA did on boards that wanted to avoid device tree accesses.
Based on what you said, the adding of OF_PRIOR_STAGE here sounds like a hack.
Yeah, it makes an assumption about which SPI bus to use, that may or may not be valid on other boards.
I see that since I introduced CONFIG_OF_PRIOR_STAGE, several other ports have started using it, so there's probably a need to generalize this; if other prior stage bootloaders provide SPI aliases then there should be a way for this code to use them.
I think the correct way is to call uclass_get_device_by_seq(). CONFIG_OF_PRIOR_STAGE should not imply such behavior.
OK, but without other changes this would break boards that rely on the above assumption (for example BCM7445).
I'm experimenting with patches that work on BCM7445 and eliminate the SPI bus assumption but I don't know what effect they might have on other ports that use OF_PRIOR_STAGE.
In general it seems like a good idea to use the prior-stage-provided aliases, but the question is what to do when an alias is missing; maybe always fall back to calling uclass_find_next_free_req_seq?
I tend to agree. As I see lots of places in U-Boot sources, like below:
drivers/i2c/intel_i2c.c::intel_i2c_bind()
if (device_is_on_pci_bus(dev)) { /* * ToDo: * Setting req_seq in the driver is probably not recommended. * But without a DT alias the number is not configured. And * using this driver is impossible for PCIe I2C devices. * This can be removed, once a better (correct) way for this * is found and implemented. */ dev->req_seq = num_cards;
And another example: drivers/usb/host/ehci-vf.c::vf_usb_bind()
/* * Without this hack, if we return ENODEV for USB Controller 0, on * probe for the next controller, USB Controller 1 will be given a * sequence number of 0. This conflicts with our requirement of * sequence numbers while initialising the peripherals. */ dev->req_seq = num_controllers;
Simon, do you think we should change the behavior of dev->req_seq in the device bind for uclass drivers with DM_UC_FLAG_SEQ_ALIAS flag?
Have you found a board for which uclass_get_device_by_seq works for SPI and uclass_first_device_err does the wrong thing? Is it a publicly available port that I can have a look at?
No, I was not indicating an error like uclass_get_device_by_seq works for SPI and uclass_first_device_err does the wrong thing. The issue with your implementation is that it forces probing the first SPI controller and ignore the "busnum" completely. This makes a board with multiple SPI controllers unable to probe other controllers than the very first one.
Regards, Bin

Hi Simon,
On Thu, Aug 29, 2019 at 11:24 PM Bin Meng bmeng.cn@gmail.com wrote:
+Simon
On Thu, Aug 29, 2019 at 1:24 AM Thomas Fitzsimmons fitzsim@fitzsim.org wrote:
Hi Bin,
Bin Meng bmeng.cn@gmail.com writes:
Hi Thomas,
On Wed, Aug 28, 2019 at 6:31 AM Thomas Fitzsimmons fitzsim@fitzsim.org wrote:
Hi Bin,
Bin Meng bmeng.cn@gmail.com writes:
Hi Thomas,
On Sat, Jun 9, 2018 at 6:06 AM Thomas Fitzsimmons fitzsim@fitzsim.org wrote:
Add support for loading U-Boot on the Broadcom 7445 SoC. This port assumes Broadcom's BOLT bootloader is acting as the second stage bootloader, and U-Boot is acting as the third stage bootloader, loaded as an ELF program by BOLT.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Stefan Roese sr@denx.de Cc: Tom Rini trini@konsulko.com Cc: Florian Fainelli f.fainelli@gmail.com
Changes for v4:
- Use high timer register for get_ticks
- Move hard-coded register addresses from Kconfig to header
- Document I-cache/D-cache expectation
MAINTAINERS | 10 + arch/arm/Kconfig | 12 + arch/arm/Makefile | 1 + arch/arm/mach-bcmstb/Kconfig | 36 ++ arch/arm/mach-bcmstb/Makefile | 8 + arch/arm/mach-bcmstb/include/mach/gpio.h | 11 + arch/arm/mach-bcmstb/include/mach/hardware.h | 11 + arch/arm/mach-bcmstb/include/mach/prior_stage.h | 30 ++ arch/arm/mach-bcmstb/include/mach/sdhci.h | 15 + arch/arm/mach-bcmstb/include/mach/timer.h | 13 + arch/arm/mach-bcmstb/lowlevel_init.S | 21 ++ board/broadcom/bcmstb/MAINTAINERS | 7 + board/broadcom/bcmstb/Makefile | 8 + board/broadcom/bcmstb/bcmstb.c | 194 +++++++++++ configs/bcm7445_defconfig | 27 ++ doc/README.bcm7xxx | 150 ++++++++ drivers/mmc/Kconfig | 11 + drivers/mmc/Makefile | 1 + drivers/mmc/bcmstb_sdhci.c | 67 ++++ drivers/spi/Kconfig | 7 + drivers/spi/Makefile | 1 + drivers/spi/bcmstb_spi.c | 439 ++++++++++++++++++++++++ drivers/spi/spi-uclass.c | 2 +- dts/Kconfig | 7 + include/configs/bcm7445.h | 26 ++ include/configs/bcmstb.h | 183 ++++++++++ include/fdtdec.h | 4 + lib/fdtdec.c | 4 + 28 files changed, 1305 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-bcmstb/Kconfig create mode 100644 arch/arm/mach-bcmstb/Makefile create mode 100644 arch/arm/mach-bcmstb/include/mach/gpio.h create mode 100644 arch/arm/mach-bcmstb/include/mach/hardware.h create mode 100644 arch/arm/mach-bcmstb/include/mach/prior_stage.h create mode 100644 arch/arm/mach-bcmstb/include/mach/sdhci.h create mode 100644 arch/arm/mach-bcmstb/include/mach/timer.h create mode 100644 arch/arm/mach-bcmstb/lowlevel_init.S create mode 100644 board/broadcom/bcmstb/MAINTAINERS create mode 100644 board/broadcom/bcmstb/Makefile create mode 100644 board/broadcom/bcmstb/bcmstb.c create mode 100644 configs/bcm7445_defconfig create mode 100644 doc/README.bcm7xxx create mode 100644 drivers/mmc/bcmstb_sdhci.c create mode 100644 drivers/spi/bcmstb_spi.c create mode 100644 include/configs/bcm7445.h create mode 100644 include/configs/bcmstb.h
[snip]
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index d2d091f..c517d06 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -273,7 +273,7 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, bool created = false; int ret;
-#if CONFIG_IS_ENABLED(OF_PLATDATA) +#if CONFIG_IS_ENABLED(OF_PLATDATA) || CONFIG_IS_ENABLED(OF_PRIOR_STAGE)
Could you please explain this change a little bit? Why should we call uclass_first_device_err() for OF_PRIOR_STAGE?
ret = uclass_first_device_err(UCLASS_SPI, &bus);
#else ret = uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus);
On the BCM7445 eval board, the prior-stage-provided device tree does not have an alias for spi0, though it has aliases for other device types; I don't know why this is the case, but I don't have control over what the prior stage bootloader (Broadcom's BOLT) provides. Without that alias, uclass_get_device_by_seq fails to find the SPI bus (and so U-Boot can't find the SPI flash device that stores its environment).
I checked uclass_get_device_by_seq() and did not find any codes that are trying to read aliases. Am I missing anything?
Alias handling is not in the direct uclass_get_device_by_seq call chain, and it took some debugging to find this. The requested sequence number is handled earlier in the boot, in device_bind_common:
dev->seq = -1; dev->req_seq = -1; if (CONFIG_IS_ENABLED(DM_SEQ_ALIAS) && (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS)) { /* * Some devices, such as a SPI bus, I2C bus and serial ports * are numbered using aliases. * * This is just a 'requested' sequence, and will be * resolved (and ->seq updated) when the device is probed. */ if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) { if (uc->uc_drv->name && ofnode_valid(node)) dev_read_alias_seq(dev, &dev->req_seq); } else { dev->req_seq = uclass_find_next_free_req_seq(drv->id); } }
If the prior stage bootloader provides no SPI bus alias, then dev_read_alias_seq fails, dev->req_seq stays unset (-1), and later when an attempt is made to access the SPI bus, the call to uclass_get_device_by_seq fails.
Ah, I see. Thanks!
At the time, I checked other ARM device trees in the Linux kernel and not many set an alias for spi0, so I wrote the patch to choose the first SPI bus. Doing so was in line with what CONFIG_OF_PLATDATA did on boards that wanted to avoid device tree accesses.
Based on what you said, the adding of OF_PRIOR_STAGE here sounds like a hack.
Yeah, it makes an assumption about which SPI bus to use, that may or may not be valid on other boards.
I see that since I introduced CONFIG_OF_PRIOR_STAGE, several other ports have started using it, so there's probably a need to generalize this; if other prior stage bootloaders provide SPI aliases then there should be a way for this code to use them.
I think the correct way is to call uclass_get_device_by_seq(). CONFIG_OF_PRIOR_STAGE should not imply such behavior.
OK, but without other changes this would break boards that rely on the above assumption (for example BCM7445).
I'm experimenting with patches that work on BCM7445 and eliminate the SPI bus assumption but I don't know what effect they might have on other ports that use OF_PRIOR_STAGE.
In general it seems like a good idea to use the prior-stage-provided aliases, but the question is what to do when an alias is missing; maybe always fall back to calling uclass_find_next_free_req_seq?
I tend to agree. As I see lots of places in U-Boot sources, like below:
drivers/i2c/intel_i2c.c::intel_i2c_bind()
if (device_is_on_pci_bus(dev)) { /* * ToDo: * Setting req_seq in the driver is probably not recommended. * But without a DT alias the number is not configured. And * using this driver is impossible for PCIe I2C devices. * This can be removed, once a better (correct) way for this * is found and implemented. */ dev->req_seq = num_cards;
And another example: drivers/usb/host/ehci-vf.c::vf_usb_bind()
/* * Without this hack, if we return ENODEV for USB Controller 0, on * probe for the next controller, USB Controller 1 will be given a * sequence number of 0. This conflicts with our requirement of * sequence numbers while initialising the peripherals. */ dev->req_seq = num_controllers;
Simon, do you think we should change the behavior of dev->req_seq in the device bind for uclass drivers with DM_UC_FLAG_SEQ_ALIAS flag?
Would you please give some comments regarding this?
Have you found a board for which uclass_get_device_by_seq works for SPI and uclass_first_device_err does the wrong thing? Is it a publicly available port that I can have a look at?
No, I was not indicating an error like uclass_get_device_by_seq works for SPI and uclass_first_device_err does the wrong thing. The issue with your implementation is that it forces probing the first SPI controller and ignore the "busnum" completely. This makes a board with multiple SPI controllers unable to probe other controllers than the very first one.
Regards, Bin

Hi Bin,
On Thu, 5 Sep 2019 at 06:10, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Thu, Aug 29, 2019 at 11:24 PM Bin Meng bmeng.cn@gmail.com wrote:
+Simon
On Thu, Aug 29, 2019 at 1:24 AM Thomas Fitzsimmons fitzsim@fitzsim.org wrote:
Hi Bin,
Bin Meng bmeng.cn@gmail.com writes:
Hi Thomas,
On Wed, Aug 28, 2019 at 6:31 AM Thomas Fitzsimmons fitzsim@fitzsim.org wrote:
Hi Bin,
Bin Meng bmeng.cn@gmail.com writes:
Hi Thomas,
On Sat, Jun 9, 2018 at 6:06 AM Thomas Fitzsimmons fitzsim@fitzsim.org wrote: > > Add support for loading U-Boot on the Broadcom 7445 SoC. This port > assumes Broadcom's BOLT bootloader is acting as the second stage > bootloader, and U-Boot is acting as the third stage bootloader, loaded > as an ELF program by BOLT. > > Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org > Cc: Stefan Roese sr@denx.de > Cc: Tom Rini trini@konsulko.com > Cc: Florian Fainelli f.fainelli@gmail.com > --- > Changes for v4: > - Use high timer register for get_ticks > - Move hard-coded register addresses from Kconfig to header > - Document I-cache/D-cache expectation > > MAINTAINERS | 10 + > arch/arm/Kconfig | 12 + > arch/arm/Makefile | 1 + > arch/arm/mach-bcmstb/Kconfig | 36 ++ > arch/arm/mach-bcmstb/Makefile | 8 + > arch/arm/mach-bcmstb/include/mach/gpio.h | 11 + > arch/arm/mach-bcmstb/include/mach/hardware.h | 11 + > arch/arm/mach-bcmstb/include/mach/prior_stage.h | 30 ++ > arch/arm/mach-bcmstb/include/mach/sdhci.h | 15 + > arch/arm/mach-bcmstb/include/mach/timer.h | 13 + > arch/arm/mach-bcmstb/lowlevel_init.S | 21 ++ > board/broadcom/bcmstb/MAINTAINERS | 7 + > board/broadcom/bcmstb/Makefile | 8 + > board/broadcom/bcmstb/bcmstb.c | 194 +++++++++++ > configs/bcm7445_defconfig | 27 ++ > doc/README.bcm7xxx | 150 ++++++++ > drivers/mmc/Kconfig | 11 + > drivers/mmc/Makefile | 1 + > drivers/mmc/bcmstb_sdhci.c | 67 ++++ > drivers/spi/Kconfig | 7 + > drivers/spi/Makefile | 1 + > drivers/spi/bcmstb_spi.c | 439 ++++++++++++++++++++++++ > drivers/spi/spi-uclass.c | 2 +- > dts/Kconfig | 7 + > include/configs/bcm7445.h | 26 ++ > include/configs/bcmstb.h | 183 ++++++++++ > include/fdtdec.h | 4 + > lib/fdtdec.c | 4 + > 28 files changed, 1305 insertions(+), 1 deletion(-) > create mode 100644 arch/arm/mach-bcmstb/Kconfig > create mode 100644 arch/arm/mach-bcmstb/Makefile > create mode 100644 arch/arm/mach-bcmstb/include/mach/gpio.h > create mode 100644 arch/arm/mach-bcmstb/include/mach/hardware.h > create mode 100644 arch/arm/mach-bcmstb/include/mach/prior_stage.h > create mode 100644 arch/arm/mach-bcmstb/include/mach/sdhci.h > create mode 100644 arch/arm/mach-bcmstb/include/mach/timer.h > create mode 100644 arch/arm/mach-bcmstb/lowlevel_init.S > create mode 100644 board/broadcom/bcmstb/MAINTAINERS > create mode 100644 board/broadcom/bcmstb/Makefile > create mode 100644 board/broadcom/bcmstb/bcmstb.c > create mode 100644 configs/bcm7445_defconfig > create mode 100644 doc/README.bcm7xxx > create mode 100644 drivers/mmc/bcmstb_sdhci.c > create mode 100644 drivers/spi/bcmstb_spi.c > create mode 100644 include/configs/bcm7445.h > create mode 100644 include/configs/bcmstb.h >
[snip]
> diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c > index d2d091f..c517d06 100644 > --- a/drivers/spi/spi-uclass.c > +++ b/drivers/spi/spi-uclass.c > @@ -273,7 +273,7 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, > bool created = false; > int ret; > > -#if CONFIG_IS_ENABLED(OF_PLATDATA) > +#if CONFIG_IS_ENABLED(OF_PLATDATA) || CONFIG_IS_ENABLED(OF_PRIOR_STAGE)
Could you please explain this change a little bit? Why should we call uclass_first_device_err() for OF_PRIOR_STAGE?
> ret = uclass_first_device_err(UCLASS_SPI, &bus); > #else > ret = uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus);
On the BCM7445 eval board, the prior-stage-provided device tree does not have an alias for spi0, though it has aliases for other device types; I don't know why this is the case, but I don't have control over what the prior stage bootloader (Broadcom's BOLT) provides. Without that alias, uclass_get_device_by_seq fails to find the SPI bus (and so U-Boot can't find the SPI flash device that stores its environment).
I checked uclass_get_device_by_seq() and did not find any codes that are trying to read aliases. Am I missing anything?
Alias handling is not in the direct uclass_get_device_by_seq call chain, and it took some debugging to find this. The requested sequence number is handled earlier in the boot, in device_bind_common:
dev->seq = -1; dev->req_seq = -1; if (CONFIG_IS_ENABLED(DM_SEQ_ALIAS) && (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS)) { /* * Some devices, such as a SPI bus, I2C bus and serial ports * are numbered using aliases. * * This is just a 'requested' sequence, and will be * resolved (and ->seq updated) when the device is probed. */ if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) { if (uc->uc_drv->name && ofnode_valid(node)) dev_read_alias_seq(dev, &dev->req_seq); } else { dev->req_seq = uclass_find_next_free_req_seq(drv->id); } }
If the prior stage bootloader provides no SPI bus alias, then dev_read_alias_seq fails, dev->req_seq stays unset (-1), and later when an attempt is made to access the SPI bus, the call to uclass_get_device_by_seq fails.
Ah, I see. Thanks!
At the time, I checked other ARM device trees in the Linux kernel and not many set an alias for spi0, so I wrote the patch to choose the first SPI bus. Doing so was in line with what CONFIG_OF_PLATDATA did on boards that wanted to avoid device tree accesses.
Based on what you said, the adding of OF_PRIOR_STAGE here sounds like a hack.
Yeah, it makes an assumption about which SPI bus to use, that may or may not be valid on other boards.
I see that since I introduced CONFIG_OF_PRIOR_STAGE, several other ports have started using it, so there's probably a need to generalize this; if other prior stage bootloaders provide SPI aliases then there should be a way for this code to use them.
I think the correct way is to call uclass_get_device_by_seq(). CONFIG_OF_PRIOR_STAGE should not imply such behavior.
OK, but without other changes this would break boards that rely on the above assumption (for example BCM7445).
I'm experimenting with patches that work on BCM7445 and eliminate the SPI bus assumption but I don't know what effect they might have on other ports that use OF_PRIOR_STAGE.
In general it seems like a good idea to use the prior-stage-provided aliases, but the question is what to do when an alias is missing; maybe always fall back to calling uclass_find_next_free_req_seq?
I tend to agree. As I see lots of places in U-Boot sources, like below:
drivers/i2c/intel_i2c.c::intel_i2c_bind()
if (device_is_on_pci_bus(dev)) { /* * ToDo: * Setting req_seq in the driver is probably not recommended. * But without a DT alias the number is not configured. And * using this driver is impossible for PCIe I2C devices. * This can be removed, once a better (correct) way for this * is found and implemented. */ dev->req_seq = num_cards;
And another example: drivers/usb/host/ehci-vf.c::vf_usb_bind()
/* * Without this hack, if we return ENODEV for USB Controller 0, on * probe for the next controller, USB Controller 1 will be given a * sequence number of 0. This conflicts with our requirement of * sequence numbers while initialising the peripherals. */ dev->req_seq = num_controllers;
Simon, do you think we should change the behavior of dev->req_seq in the device bind for uclass drivers with DM_UC_FLAG_SEQ_ALIAS flag?
Would you please give some comments regarding this?
Yes I think we should do something here.
I am not quite clear on the best action though.
At present ->seq is set when the device is proved and dropped when it is removed. This is good in the sense that different devices can 'take over' a sequence number. But in practice I don't think we have found that to be very useful.
An alternative would be to do this processing when the device is bound. We might then remove the two separate values and just have one. However it would mean processing aliases which could potentially be slow.
In general I had hoped that sequence numbers would become less important in U-Boot, as they have in Linux. But for now we need to deal with it.
Have you found a board for which uclass_get_device_by_seq works for SPI and uclass_first_device_err does the wrong thing? Is it a publicly available port that I can have a look at?
No, I was not indicating an error like uclass_get_device_by_seq works for SPI and uclass_first_device_err does the wrong thing. The issue with your implementation is that it forces probing the first SPI controller and ignore the "busnum" completely. This makes a board with multiple SPI controllers unable to probe other controllers than the very first one.
Regards, Bin
Regards, Simon

These patches remove a workaround that was needed for ports that use CONFIG_OF_PRIOR_STAGE, that need to probe a SPI bus, and whose prior stage device tree does not provide SPI bus aliases.
Thomas Fitzsimmons (2): dm: device: Request next sequence number dm: spi: Do not assume first SPI bus
drivers/core/device.c | 5 +++++ drivers/core/uclass.c | 4 +++- drivers/spi/spi-uclass.c | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-)

For CONFIG_OF_PRIOR_STAGE, in the absence of a device tree alias for a given device, use the next request number for that type of device. This allows aliases to be used when they're available, while still allowing unaliased devices to be probed.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Bin Meng bmeng.cn@gmail.com Cc: Simon Glass sjg@chromium.org --- drivers/core/device.c | 5 +++++ drivers/core/uclass.c | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/core/device.c b/drivers/core/device.c index 474c1642ee..ca8be208a9 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -82,6 +82,11 @@ static int device_bind_common(struct udevice *parent, const struct driver *drv, if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) { if (uc->uc_drv->name && ofnode_valid(node)) dev_read_alias_seq(dev, &dev->req_seq); +#if CONFIG_IS_ENABLED(OF_PRIOR_STAGE) + if (dev->req_seq == -1) + dev->req_seq = + uclass_find_next_free_req_seq(drv->id); +#endif } else { dev->req_seq = uclass_find_next_free_req_seq(drv->id); } diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index b33296542f..d7aedac351 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -269,7 +269,9 @@ int uclass_find_device_by_name(enum uclass_id id, const char *name, return -ENODEV; }
-#if !CONFIG_IS_ENABLED(OF_CONTROL) || CONFIG_IS_ENABLED(OF_PLATDATA) +#if !CONFIG_IS_ENABLED(OF_CONTROL) || \ + CONFIG_IS_ENABLED(OF_PLATDATA) || \ + CONFIG_IS_ENABLED(OF_PRIOR_STAGE) int uclass_find_next_free_req_seq(enum uclass_id id) { struct uclass *uc;

Hi Thomas,
On Fri, Sep 6, 2019 at 7:52 PM Thomas Fitzsimmons fitzsim@fitzsim.org wrote:
For CONFIG_OF_PRIOR_STAGE, in the absence of a device tree alias for a given device, use the next request number for that type of device. This allows aliases to be used when they're available, while still allowing unaliased devices to be probed.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Bin Meng bmeng.cn@gmail.com Cc: Simon Glass sjg@chromium.org
drivers/core/device.c | 5 +++++ drivers/core/uclass.c | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/core/device.c b/drivers/core/device.c index 474c1642ee..ca8be208a9 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -82,6 +82,11 @@ static int device_bind_common(struct udevice *parent, const struct driver *drv, if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) { if (uc->uc_drv->name && ofnode_valid(node)) dev_read_alias_seq(dev, &dev->req_seq); +#if CONFIG_IS_ENABLED(OF_PRIOR_STAGE)
I was wondering whether we should limit such only for OF_PRIOR_STATE, instead change the behaviors for all DM devices.
Because as I pointed out in https://lists.denx.de/pipermail/u-boot/2019-August/382368.html, it seems there are quite some codes in the existing code base that tried to workaround such limitation in their own way.
if (dev->req_seq == -1)
dev->req_seq =
uclass_find_next_free_req_seq(drv->id);
+#endif } else { dev->req_seq = uclass_find_next_free_req_seq(drv->id); } diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index b33296542f..d7aedac351 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -269,7 +269,9 @@ int uclass_find_device_by_name(enum uclass_id id, const char *name, return -ENODEV; }
-#if !CONFIG_IS_ENABLED(OF_CONTROL) || CONFIG_IS_ENABLED(OF_PLATDATA) +#if !CONFIG_IS_ENABLED(OF_CONTROL) || \
- CONFIG_IS_ENABLED(OF_PLATDATA) || \
- CONFIG_IS_ENABLED(OF_PRIOR_STAGE)
int uclass_find_next_free_req_seq(enum uclass_id id) { struct uclass *uc; --
Regards, Bin

Hi Bin,
Bin Meng bmeng.cn@gmail.com writes:
[...]
On Fri, Sep 6, 2019 at 7:52 PM Thomas Fitzsimmons fitzsim@fitzsim.org wrote:
For CONFIG_OF_PRIOR_STAGE, in the absence of a device tree alias for a given device, use the next request number for that type of device. This allows aliases to be used when they're available, while still allowing unaliased devices to be probed.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Bin Meng bmeng.cn@gmail.com Cc: Simon Glass sjg@chromium.org
drivers/core/device.c | 5 +++++ drivers/core/uclass.c | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/core/device.c b/drivers/core/device.c index 474c1642ee..ca8be208a9 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -82,6 +82,11 @@ static int device_bind_common(struct udevice *parent, const struct driver *drv, if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) { if (uc->uc_drv->name && ofnode_valid(node)) dev_read_alias_seq(dev, &dev->req_seq); +#if CONFIG_IS_ENABLED(OF_PRIOR_STAGE)
I was wondering whether we should limit such only for OF_PRIOR_STATE, instead change the behaviors for all DM devices.
Maybe, though I wouldn't want to break assumptions made in this area by non-OF_PRIOR_STAGE boards.
Because as I pointed out in https://lists.denx.de/pipermail/u-boot/2019-August/382368.html, it seems there are quite some codes in the existing code base that tried to workaround such limitation in their own way.
I could create a separate config option to control this behavior, and document what it does in Kconfig. Then other ports could adopt it gradually, and eventually we could make it unconditional. I think OF_PRIOR_STAGE should select the new option, since I can confirm this is an improvement for my OF_PRIOR_STAGE-using board.
Thomas

On Sat, 14 Sep 2019 at 06:41, Thomas Fitzsimmons fitzsim@fitzsim.org wrote:
Hi Bin,
Bin Meng bmeng.cn@gmail.com writes:
[...]
On Fri, Sep 6, 2019 at 7:52 PM Thomas Fitzsimmons fitzsim@fitzsim.org wrote:
For CONFIG_OF_PRIOR_STAGE, in the absence of a device tree alias for a given device, use the next request number for that type of device. This allows aliases to be used when they're available, while still allowing unaliased devices to be probed.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Bin Meng bmeng.cn@gmail.com Cc: Simon Glass sjg@chromium.org
drivers/core/device.c | 5 +++++ drivers/core/uclass.c | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/core/device.c b/drivers/core/device.c index 474c1642ee..ca8be208a9 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -82,6 +82,11 @@ static int device_bind_common(struct udevice *parent, const struct driver *drv, if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) { if (uc->uc_drv->name && ofnode_valid(node)) dev_read_alias_seq(dev, &dev->req_seq); +#if CONFIG_IS_ENABLED(OF_PRIOR_STAGE)
I was wondering whether we should limit such only for OF_PRIOR_STATE, instead change the behaviors for all DM devices.
Maybe, though I wouldn't want to break assumptions made in this area by non-OF_PRIOR_STAGE boards.
Because as I pointed out in https://lists.denx.de/pipermail/u-boot/2019-August/382368.html, it seems there are quite some codes in the existing code base that tried to workaround such limitation in their own way.
I could create a separate config option to control this behavior, and document what it does in Kconfig. Then other ports could adopt it gradually, and eventually we could make it unconditional. I think OF_PRIOR_STAGE should select the new option, since I can confirm this is an improvement for my OF_PRIOR_STAGE-using board.
Thomas
Reviewed-by: Simon Glass sjg@chromium.org
It is best to use if() instead of #if if possible.

On Sat, 14 Sep 2019 at 06:41, Thomas Fitzsimmons fitzsim@fitzsim.org wrote:
Hi Bin,
Bin Meng bmeng.cn@gmail.com writes:
[...]
On Fri, Sep 6, 2019 at 7:52 PM Thomas Fitzsimmons fitzsim@fitzsim.org wrote:
For CONFIG_OF_PRIOR_STAGE, in the absence of a device tree alias for a given device, use the next request number for that type of device. This allows aliases to be used when they're available, while still allowing unaliased devices to be probed.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Bin Meng bmeng.cn@gmail.com Cc: Simon Glass sjg@chromium.org
drivers/core/device.c | 5 +++++ drivers/core/uclass.c | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-)
Applied to u-boot-dm/next, thanks!

When CONFIG_OF_PRIOR_STAGE is enabled, this workaround was needed before device_bind_common assigned request numbers sequentially in the absence of aliases.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Bin Meng bmeng.cn@gmail.com Cc: Simon Glass sjg@chromium.org --- drivers/spi/spi-uclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index 88cb2a1262..5e1f2232e5 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -275,7 +275,7 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, bool created = false; int ret;
-#if CONFIG_IS_ENABLED(OF_PLATDATA) || CONFIG_IS_ENABLED(OF_PRIOR_STAGE) +#if CONFIG_IS_ENABLED(OF_PLATDATA) ret = uclass_first_device_err(UCLASS_SPI, &bus); #else ret = uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus);

On Fri, 6 Sep 2019 at 04:52, Thomas Fitzsimmons fitzsim@fitzsim.org wrote:
When CONFIG_OF_PRIOR_STAGE is enabled, this workaround was needed before device_bind_common assigned request numbers sequentially in the absence of aliases.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Bin Meng bmeng.cn@gmail.com Cc: Simon Glass sjg@chromium.org
drivers/spi/spi-uclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Reviewed-by: Simon Glass sjg@chromium.org

On Fri, 6 Sep 2019 at 04:52, Thomas Fitzsimmons fitzsim@fitzsim.org wrote:
When CONFIG_OF_PRIOR_STAGE is enabled, this workaround was needed before device_bind_common assigned request numbers sequentially in the absence of aliases.
Signed-off-by: Thomas Fitzsimmons fitzsim@fitzsim.org Cc: Bin Meng bmeng.cn@gmail.com Cc: Simon Glass sjg@chromium.org
drivers/spi/spi-uclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Reviewed-by: Simon Glass sjg@chromium.org
Applied to u-boot-dm/next, thanks!

On Thu, May 24, 2018 at 9:24 AM Thomas Fitzsimmons fitzsim@fitzsim.org wrote:
Add support for Broadcom BCM7445
Changes for v2:
- Reorganize Kconfig to create ARCH_BCMSTB
- Use generic bcmstb SoC name wherever possible
- Eliminate crt0.S changes by moving relocation logic to bcmstb.c
- Use debug() macro where appropriate
- Read bcmstb_spi register base addresses from prior stage device tree, where possible
- Read bcmstb_sdhci register base address from prior stage DT
- Make timer register addresses configurable
- Fix BOLT typos
- Eliminate CONFIG_BCMSTB_ACCOMMODATE_STBLINUX by keeping FIT initramfs and device tree binary in-place
- Add README.bcm7xxx
- Read memory configuration from prior stage device tree
- Add CONFIG_OF_PRIOR_STAGE support in spi-uclass.c
- Fix issues reported by checkpatch.pl
- Fix issues reported by sparse
- Update some comments and formatting
- Add a MAINTAINERS file
Thomas Fitzsimmons (1): board: arm: Add support for Broadcom BCM7445
arch/arm/Kconfig | 12 + arch/arm/Makefile | 1 + arch/arm/mach-bcmstb/Kconfig | 64 ++++ arch/arm/mach-bcmstb/Makefile | 9 + arch/arm/mach-bcmstb/include/mach/gpio.h | 12 + arch/arm/mach-bcmstb/include/mach/hardware.h | 12 + arch/arm/mach-bcmstb/include/mach/prior_stage.h | 31 ++ arch/arm/mach-bcmstb/include/mach/sdhci.h | 16 + arch/arm/mach-bcmstb/include/mach/timer.h | 14 + arch/arm/mach-bcmstb/lowlevel_init.S | 22 ++ board/broadcom/bcmstb/MAINTAINERS | 6 + board/broadcom/bcmstb/Makefile | 9 + board/broadcom/bcmstb/bcmstb.c | 192 +++++++++++ configs/bcm7445_defconfig | 27 ++ doc/README.bcm7xxx | 147 ++++++++ drivers/mmc/Kconfig | 11 + drivers/mmc/Makefile | 1 + drivers/mmc/bcmstb_sdhci.c | 68 ++++ drivers/spi/Kconfig | 7 + drivers/spi/Makefile | 1 + drivers/spi/bcmstb_spi.c | 440 ++++++++++++++++++++++++ drivers/spi/spi-uclass.c | 2 +- dts/Kconfig | 7 + include/configs/bcmstb.h | 189 ++++++++++ include/fdtdec.h | 4 + lib/fdtdec.c | 4 + 26 files changed, 1307 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-bcmstb/Kconfig create mode 100644 arch/arm/mach-bcmstb/Makefile create mode 100644 arch/arm/mach-bcmstb/include/mach/gpio.h create mode 100644 arch/arm/mach-bcmstb/include/mach/hardware.h create mode 100644 arch/arm/mach-bcmstb/include/mach/prior_stage.h create mode 100644 arch/arm/mach-bcmstb/include/mach/sdhci.h create mode 100644 arch/arm/mach-bcmstb/include/mach/timer.h create mode 100644 arch/arm/mach-bcmstb/lowlevel_init.S create mode 100644 board/broadcom/bcmstb/MAINTAINERS create mode 100644 board/broadcom/bcmstb/Makefile create mode 100644 board/broadcom/bcmstb/bcmstb.c create mode 100644 configs/bcm7445_defconfig create mode 100644 doc/README.bcm7xxx create mode 100644 drivers/mmc/bcmstb_sdhci.c create mode 100644 drivers/spi/bcmstb_spi.c create mode 100644 include/configs/bcmstb.h
I am tracing an issue that lead me to this commit, a huge single commit that changes everywhere. We should not have such a commit merged, sigh.
Regards, Bin
participants (6)
-
Bin Meng
-
Florian Fainelli
-
Simon Glass
-
sjg@google.com
-
Thomas Fitzsimmons
-
Tom Rini