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

Thomas Fitzsimmons fitzsim at fitzsim.org
Sun May 6 11:09:22 UTC 2018


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 at fitzsim.org>
Cc: Stefan Roese <sr at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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(&regs->mspi_status);
+
+	while (!(status & 1)) {
+		if (get_timer(start_time) >
+		    CONFIG_SYS_BCMSTB_SPI_WAIT) {
+			return -ETIMEDOUT;
+		}
+		status = readl(&regs->mspi_status);
+	}
+
+	writel(readl(&regs->mspi_status) & ~1, &regs->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", &regs->txram[0]);
+	D("spi_xfer: rx addr: %p\n", &regs->rxram[0]);
+	D("spi_xfer: cd addr: %p\n", &regs->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,
+			       &regs->txram[priv->tx_slot << 1]);
+			D("WR CDRAM[%d]: %02x\n", priv->tx_slot, 0x8e);
+			writel(0x8e, &regs->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(&regs->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 at 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 at 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)
-- 
1.8.3.1



More information about the U-Boot mailing list