Message ID | 20200124055026.30787-7-pragnesh.patel@sifive.com |
---|---|
State | New |
Headers | show |
Series | RISC-V SiFive FU540 support SPL | expand |
On Fri, Jan 24, 2020 at 11:21 AM Pragnesh Patel <pragnesh.patel at sifive.com> wrote: > > Add a support for SPL which will boot from L2 LIM (0x0800_0000) and > then boot U-boot FIT image including OpenSBI FW_DYNAMIC firmware > and U-Boot proper images from 1st partition of MMC boot devices. > > SPL related code is leverage from FSBL > (https://github.com/sifive/freedom-u540-c000-bootloader.git) > > Signed-off-by: Pragnesh Patel <pragnesh.patel at sifive.com> > --- > board/sifive/fu540/Kconfig | 8 + > board/sifive/fu540/Makefile | 1 + > board/sifive/fu540/fu540-memory-map.h | 33 ++++ > board/sifive/fu540/fu540.c | 24 +++ > board/sifive/fu540/spl.c | 252 ++++++++++++++++++++++++++ > board/sifive/fu540/ux00prci.h | 56 ++++++ > include/configs/sifive-fu540.h | 18 ++ > 7 files changed, 392 insertions(+) > create mode 100644 board/sifive/fu540/fu540-memory-map.h > create mode 100644 board/sifive/fu540/spl.c > create mode 100644 board/sifive/fu540/ux00prci.h > > diff --git a/board/sifive/fu540/Kconfig b/board/sifive/fu540/Kconfig > index 5ca21474de..edb224ed7a 100644 > --- a/board/sifive/fu540/Kconfig > +++ b/board/sifive/fu540/Kconfig > @@ -13,12 +13,20 @@ config SYS_CONFIG_NAME > default "sifive-fu540" > > config SYS_TEXT_BASE > + default 0x80200000 if SPL > default 0x80000000 if !RISCV_SMODE > default 0x80200000 if RISCV_SMODE > > +config SPL_TEXT_BASE > + default 0x08000000 > + > +config SPL_OPENSBI_LOAD_ADDR > + default 0x80000000 > + > config BOARD_SPECIFIC_OPTIONS # dummy > def_bool y > select GENERIC_RISCV > + select SUPPORT_SPL > imply CMD_DHCP > imply CMD_EXT2 > imply CMD_EXT4 > diff --git a/board/sifive/fu540/Makefile b/board/sifive/fu540/Makefile > index e4e76e1de3..cdcf894ade 100644 > --- a/board/sifive/fu540/Makefile > +++ b/board/sifive/fu540/Makefile > @@ -5,5 +5,6 @@ > obj-y += fu540.o > > ifdef CONFIG_SPL_BUILD > +obj-y += spl.o > obj-y += ddr.o > endif > diff --git a/board/sifive/fu540/fu540-memory-map.h b/board/sifive/fu540/fu540-memory-map.h > new file mode 100644 > index 0000000000..c65203726b > --- /dev/null > +++ b/board/sifive/fu540/fu540-memory-map.h > @@ -0,0 +1,33 @@ > +/* SPDX-License-Identifier: GPL-2.0+ */ > +/* > + * Copyright (c) 2019 SiFive, Inc > + */ > + > +#ifndef FU540_MEMORY_MAP > +#define FU540_MEMORY_MAP > + > +#include <asm/arch/gpio.h> > +#include "ux00prci.h" > + > +/**************************************************************************** > + * Platform definitions > + *****************************************************************************/ > + > +/* Memory map */ > +#define GPIO_CTRL_ADDR _AC(0x10060000, UL) > + > +#define PHYSICAL_FILTER_CTRL_ADDR _AC(0x100b8000, UL) > + > +#define UX00DDR_CTRL_ADDR _AC(0x100b0000, UL) > +#define UX00PRCI_CTRL_ADDR _AC(0x10000000, UL) > + > +/* Helper functions */ > +#define _REG32(p, i) (*(volatile uint32_t *)((p) + (i))) > + > +#define UX00PRCI_REG(offset) \ > + _REG32(UX00PRCI_CTRL_ADDR, \ > + offset) > + > +#define GPIO_REG(offset) _REG32(GPIO_CTRL_ADDR, offset) > + > +#endif /* FU540_MEMORY_MAP */ > diff --git a/board/sifive/fu540/fu540.c b/board/sifive/fu540/fu540.c > index 3a5e74f1fb..b81003aa6f 100644 > --- a/board/sifive/fu540/fu540.c > +++ b/board/sifive/fu540/fu540.c > @@ -11,6 +11,7 @@ > #include <linux/delay.h> > #include <linux/io.h> > #include <misc.h> > +#include <spl.h> > > /* > * This define is a value used for error/unknown serial. > @@ -114,3 +115,26 @@ int board_init(void) > > return 0; > } > + > +#ifdef CONFIG_SPL > +void board_boot_order(u32 *spl_boot_list) > +{ > + u8 i; > + u32 boot_devices[] = { > +#ifdef CONFIG_SPL_MMC_SUPPORT > + BOOT_DEVICE_MMC1, > +#endif > + }; > + > + for (i = 0; i < ARRAY_SIZE(boot_devices); i++) > + spl_boot_list[i] = boot_devices[i]; > +} > +#endif > + > +#ifdef CONFIG_SPL_LOAD_FIT > +int board_fit_config_name_match(const char *name) > +{ > + /* boot using first FIT config */ > + return 0; > +} > +#endif > diff --git a/board/sifive/fu540/spl.c b/board/sifive/fu540/spl.c > new file mode 100644 > index 0000000000..c7ae4aa292 > --- /dev/null > +++ b/board/sifive/fu540/spl.c > @@ -0,0 +1,252 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * Copyright (c) 2019 SiFive, Inc > + */ > + > +#include <common.h> > +#include <spl.h> > +#include <misc.h> > + > +#include "ux00ddr.h" > +#include "fu540-memory-map.h" > + > +#define DDR_SIZE (8UL * 1024UL * 1024UL * 1024UL) > +#define DDRCTLPLL_F 55 > +#define DDRCTLPLL_Q 2 > + > +#define PHY_NRESET 0x1000 > + > +static inline int ux00prci_select_corepll(volatile u32 *coreclkselreg, > + volatile u32 *corepllcfg, > + volatile u32 *corepllout, > + u32 pllconfigval) > +{ > + (*corepllcfg) = pllconfigval; > + > + // Wait for lock > + while (((*corepllcfg) & (PLL_LOCK(1))) == 0) > + ; > + > + u32 core_out = > + (PLLOUT_DIV(PLLOUT_DIV_default)) | > + (PLLOUT_DIV_BY_1(PLLOUT_DIV_BY_1_default)) | > + (PLLOUT_CLK_EN(1)); > + (*corepllout) = core_out; > + > + // Set CORECLKSELREG to select COREPLL > + (*coreclkselreg) = PLL_CORECLKSEL_COREPLL; > + > + return 0; > +} > + > +static inline int ux00prci_select_corepll_500mhz(volatile u32 *coreclkselreg, > + volatile u32 *corepllcfg, > + volatile u32 *corepllout) > +{ > + /* > + * CORE pll init > + * Set corepll 33MHz -> 1GHz > + */ > + > + u32 core500mhz = > + (PLL_R(0)) | > + (PLL_F(59)) | // 4000MHz VCO > + (PLL_Q(3)) | /* /8 Output divider */ > + (PLL_RANGE(0x4)) | > + (PLL_BYPASS(0)) | > + (PLL_FSE(1)); > + > + return ux00prci_select_corepll(coreclkselreg, corepllcfg, corepllout, > + core500mhz); > +} > + > +static inline int ux00prci_select_corepll_1ghz(volatile u32 *coreclkselreg, > + volatile u32 *corepllcfg, > + volatile u32 *corepllout) > +{ > + /* > + * CORE pll init > + * Set corepll 33MHz -> 1GHz > + */ > + > + u32 core1ghz = > + (PLL_R(0)) | > + (PLL_F(59)) | // 4000MHz VCO > + (PLL_Q(2)) | /* /4 Output divider */ > + (PLL_RANGE(0x4)) | > + (PLL_BYPASS(0)) | > + (PLL_FSE(1)); > + > + return ux00prci_select_corepll(coreclkselreg, corepllcfg, corepllout, > + core1ghz); > +} > + > +long nsec_per_cyc = 300; // 33.333MHz > +void nsleep(long nsec) > +{ > + long step = nsec_per_cyc * 2; > + > + while (nsec > 0) > + nsec -= step; > +} > + > +void init_clk_and_ddr(void) > +{ > + // PRCI init > + > + // Check Reset Values (lock don't care) > + u32 pll_default = > + (PLL_R(PLL_R_default)) | > + (PLL_F(PLL_F_default)) | > + (PLL_Q(PLL_Q_default)) | > + (PLL_RANGE(PLL_RANGE_default)) | > + (PLL_BYPASS(PLL_BYPASS_default)) | > + (PLL_FSE(PLL_FSE_default)); > + u32 lockmask = ~PLL_LOCK(1); > + u32 pllout_default = > + (PLLOUT_DIV(PLLOUT_DIV_default)) | > + (PLLOUT_DIV_BY_1(PLLOUT_DIV_BY_1_default)) | > + (PLLOUT_CLK_EN(PLLOUT_CLK_EN_default)); > + > + if ((UX00PRCI_REG(UX00PRCI_COREPLLCFG) ^ pll_default) & lockmask) > + return; > + if ((UX00PRCI_REG(UX00PRCI_COREPLLOUT) ^ pllout_default)) > + return; > + if ((UX00PRCI_REG(UX00PRCI_DDRPLLCFG) ^ pll_default) & lockmask) > + return; > + if ((UX00PRCI_REG(UX00PRCI_DDRPLLOUT) ^ pllout_default)) > + return; > + if (((UX00PRCI_REG(UX00PRCI_GEMGXLPLLCFG)) ^ pll_default) & lockmask) > + return; > + if (((UX00PRCI_REG(UX00PRCI_GEMGXLPLLOUT)) ^ pllout_default)) > + return; > + > + /* CORE pll init > + * If tlclksel is set for 2:1 operation, > + * Set corepll 33Mhz -> 1GHz > + * Otherwise, set corepll 33MHz -> 500MHz. > + */ > + > + if (UX00PRCI_REG(UX00PRCI_CLKMUXSTATUSREG) & CLKMUX_STATUS_TLCLKSEL) { > + ux00prci_select_corepll_500mhz > + (&UX00PRCI_REG(UX00PRCI_CORECLKSELREG), > + &UX00PRCI_REG(UX00PRCI_COREPLLCFG), > + &UX00PRCI_REG(UX00PRCI_COREPLLOUT)); > + } else { > + ux00prci_select_corepll_1ghz > + (&UX00PRCI_REG(UX00PRCI_CORECLKSELREG), > + &UX00PRCI_REG(UX00PRCI_COREPLLCFG), > + &UX00PRCI_REG(UX00PRCI_COREPLLOUT)); > + } > + > + //DDR init > + u32 ddrctlmhz = > + (PLL_R(0)) | > + (PLL_F(DDRCTLPLL_F)) | > + (PLL_Q(DDRCTLPLL_Q)) | > + (PLL_RANGE(0x4)) | > + (PLL_BYPASS(0)) | > + (PLL_FSE(1)); > + UX00PRCI_REG(UX00PRCI_DDRPLLCFG) = ddrctlmhz; > + > + // Wait for lock > + while ((UX00PRCI_REG(UX00PRCI_DDRPLLCFG) & PLL_LOCK(1)) == 0) > + ; > + > + u32 ddrctl_out = > + (PLLOUT_DIV(PLLOUT_DIV_default)) | > + (PLLOUT_DIV_BY_1(PLLOUT_DIV_BY_1_default)) | > + (PLLOUT_CLK_EN(1)); > + (UX00PRCI_REG(UX00PRCI_DDRPLLOUT)) = ddrctl_out; > + > + //Release DDR reset. > + UX00PRCI_REG(UX00PRCI_DEVICESRESETREG) |= > + DEVICESRESET_DDR_CTRL_RST_N(1); > + > + // HACK to get the '1 full controller clock cycle'. > + asm volatile ("fence"); > + UX00PRCI_REG(UX00PRCI_DEVICESRESETREG) |= DEVICESRESET_DDR_AXI_RST_N(1) > + | DEVICESRESET_DDR_AHB_RST_N(1) | DEVICESRESET_DDR_PHY_RST_N(1); > + // HACK to get the '1 full controller clock cycle'. > + asm volatile ("fence"); > + > + /* These take like 16 cycles to actually propagate. We can't go sending > + * stuff before they come out of reset. So wait. (TODO: Add a register > + * to read the current reset states, or DDR Control device?) > + */ > + for (int i = 0; i < 256; i++) > + asm volatile ("nop"); > + > + ux00ddr_writeregmap(UX00DDR_CTRL_ADDR, ddr_ctl_settings, > + ddr_phy_settings); > + ux00ddr_disableaxireadinterleave(UX00DDR_CTRL_ADDR); > + > + ux00ddr_disableoptimalrmodw(UX00DDR_CTRL_ADDR); > + > + ux00ddr_enablewriteleveling(UX00DDR_CTRL_ADDR); > + ux00ddr_enablereadleveling(UX00DDR_CTRL_ADDR); > + ux00ddr_enablereadlevelinggate(UX00DDR_CTRL_ADDR); > + if (ux00ddr_getdramclass(UX00DDR_CTRL_ADDR) == DRAM_CLASS_DDR4) > + ux00ddr_enablevreftraining(UX00DDR_CTRL_ADDR); > + //mask off interrupts for leveling completion > + ux00ddr_mask_leveling_completed_interrupt(UX00DDR_CTRL_ADDR); > + > + ux00ddr_mask_mc_init_complete_interrupt(UX00DDR_CTRL_ADDR); > + ux00ddr_mask_outofrange_interrupts(UX00DDR_CTRL_ADDR); > + ux00ddr_setuprangeprotection(UX00DDR_CTRL_ADDR, DDR_SIZE); > + ux00ddr_mask_port_command_error_interrupt(UX00DDR_CTRL_ADDR); > + > + const u64 ddr_size = DDR_SIZE; > + const u64 ddr_end = CONFIG_SYS_SDRAM_BASE + ddr_size; > + > + ux00ddr_start(UX00DDR_CTRL_ADDR, PHYSICAL_FILTER_CTRL_ADDR, ddr_end); > + ux00ddr_phy_fixup(UX00DDR_CTRL_ADDR); > + > + //GEMGXL init > + u32 gemgxl125mhz = > + (PLL_R(0)) | > + (PLL_F(59)) | //4000Mhz VCO > + (PLL_Q(5)) | /* /32 */ > + (PLL_RANGE(0x4)) | > + (PLL_BYPASS(0)) | > + (PLL_FSE(1)); > + UX00PRCI_REG(UX00PRCI_GEMGXLPLLCFG) = gemgxl125mhz; > + > + // Wait for lock > + while ((UX00PRCI_REG(UX00PRCI_GEMGXLPLLCFG) & PLL_LOCK(1)) == 0) > + ; > + > + u32 gemgxlctl_out = > + (PLLOUT_DIV(PLLOUT_DIV_default)) | > + (PLLOUT_DIV_BY_1(PLLOUT_DIV_BY_1_default)) | > + (PLLOUT_CLK_EN(1)); > + UX00PRCI_REG(UX00PRCI_GEMGXLPLLOUT) = gemgxlctl_out; > + > + //Release GEMGXL reset (set bit DEVICESRESET_GEMGXL to 1) > + UX00PRCI_REG(UX00PRCI_DEVICESRESETREG) |= DEVICESRESET_GEMGXL_RST_N(1); > + > + // VSC8541 PHY reset sequence; leave pull-down active for 2ms > + nsleep(2000000); > + // Set GPIO 12 (PHY NRESET) to OE=1 and OVAL=1 > + GPIO_REG(GPIO_OUTPUT_VAL) |= PHY_NRESET; > + GPIO_REG(GPIO_OUTPUT_EN) |= PHY_NRESET; > + nsleep(100); > + > + // Procmon => core clock > + UX00PRCI_REG(UX00PRCI_PROCMONCFG) = 0x1 << 24; > +} > + > +void board_init_f(ulong dummy) > +{ > + int ret; > + > + ret = spl_early_init(); > + if (ret) > + panic("spl_early_init() failed: %d\n", ret); > + > + arch_cpu_init_dm(); > + > + init_clk_and_ddr(); > + > + preloader_console_init(); > +} > diff --git a/board/sifive/fu540/ux00prci.h b/board/sifive/fu540/ux00prci.h > new file mode 100644 > index 0000000000..90ca3cd258 > --- /dev/null > +++ b/board/sifive/fu540/ux00prci.h > @@ -0,0 +1,56 @@ > +/* SPDX-License-Identifier: GPL-2.0+ */ > +/* > + * Copyright (c) 2019 SiFive, Inc > + */ > + > +#ifndef _SIFIVE_UX00PRCI_H > +#define _SIFIVE_UX00PRCI_H > + > +/* Register offsets */ > +#define UX00PRCI_HFROSCCFG (0x0000) > +#define UX00PRCI_COREPLLCFG (0x0004) > +#define UX00PRCI_COREPLLOUT (0x0008) > +#define UX00PRCI_DDRPLLCFG (0x000C) > +#define UX00PRCI_DDRPLLOUT (0x0010) > +#define UX00PRCI_GEMGXLPLLCFG (0x001C) > +#define UX00PRCI_GEMGXLPLLOUT (0x0020) > +#define UX00PRCI_CORECLKSELREG (0x0024) > +#define UX00PRCI_DEVICESRESETREG (0x0028) > +#define UX00PRCI_CLKMUXSTATUSREG (0x002C) > +#define UX00PRCI_PROCMONCFG (0x00F0) > + > +#define PLL_R(x) (((x) & 0x3F) << 0) > +#define PLL_F(x) (((x) & 0x1FF) << 6) > +#define PLL_Q(x) (((x) & 0x7) << 15) > +#define PLL_RANGE(x) (((x) & 0x7) << 18) > +#define PLL_BYPASS(x) (((x) & 0x1) << 24) > +#define PLL_FSE(x) (((x) & 0x1) << 25) > +#define PLL_LOCK(x) (((x) & 0x1) << 31) > + > +#define PLLOUT_DIV(x) (((x) & 0x7F) << 0) > +#define PLLOUT_DIV_BY_1(x) (((x) & 0x1) << 8) > +#define PLLOUT_CLK_EN(x) (((x) & 0x1) << 31) > + > +#define PLL_R_default 0x1 > +#define PLL_F_default 0x1F > +#define PLL_Q_default 0x3 > +#define PLL_RANGE_default 0x0 > +#define PLL_BYPASS_default 0x1 > +#define PLL_FSE_default 0x1 > + > +#define PLLOUT_DIV_default 0x0 > +#define PLLOUT_DIV_BY_1_default 0x0 > +#define PLLOUT_CLK_EN_default 0x0 > + > +#define PLL_CORECLKSEL_HFXIN 0x1 > +#define PLL_CORECLKSEL_COREPLL 0x0 > + > +#define DEVICESRESET_DDR_CTRL_RST_N(x) (((x) & 0x1) << 0) > +#define DEVICESRESET_DDR_AXI_RST_N(x) (((x) & 0x1) << 1) > +#define DEVICESRESET_DDR_AHB_RST_N(x) (((x) & 0x1) << 2) > +#define DEVICESRESET_DDR_PHY_RST_N(x) (((x) & 0x1) << 3) > +#define DEVICESRESET_GEMGXL_RST_N(x) (((x) & 0x1) << 5) > + > +#define CLKMUX_STATUS_TLCLKSEL (0x1 << 1) > + > +#endif // _SIFIVE_UX00PRCI_H > diff --git a/include/configs/sifive-fu540.h b/include/configs/sifive-fu540.h > index 2756ed5a77..ef3ae9b650 100644 > --- a/include/configs/sifive-fu540.h > +++ b/include/configs/sifive-fu540.h > @@ -11,6 +11,22 @@ > > #include <linux/sizes.h> > > +#ifdef CONFIG_SPL > + > +#define CONFIG_SPL_MAX_SIZE 0x00100000 > +#define CONFIG_SPL_BSS_START_ADDR 0x85000000 > +#define CONFIG_SPL_BSS_MAX_SIZE 0x00100000 > +#define CONFIG_SYS_SPL_MALLOC_START (CONFIG_SPL_BSS_START_ADDR + \ > + CONFIG_SPL_BSS_MAX_SIZE) > +#define CONFIG_SYS_SPL_MALLOC_SIZE 0x00100000 > + > +#define CONFIG_SPL_LOAD_FIT_ADDRESS 0x84000000 > + > +#define CONFIG_SPL_STACK (0x08000000 + 0x001D0000 - \ > + GENERATED_GBL_DATA_SIZE) > + > +#endif > + > #define CONFIG_SYS_SDRAM_BASE 0x80000000 > #define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + SZ_2M) > > @@ -24,6 +40,7 @@ > > /* Environment options */ > > +#ifndef CONFIG_SPL_BUILD > #define BOOT_TARGET_DEVICES(func) \ > func(MMC, mmc, 0) \ > func(DHCP, dhcp, na) > @@ -43,5 +60,6 @@ > #define CONFIG_PREBOOT \ > "setenv fdt_addr ${fdtcontroladdr};" \ > "fdt addr ${fdtcontroladdr};" > +#endif > > #endif /* __CONFIG_H */ > -- > 2.17.1 > LGTM. Reviewed-by: Anup Patel <anup.patel at wdc.com> Regards, Anup
diff --git a/board/sifive/fu540/Kconfig b/board/sifive/fu540/Kconfig index 5ca21474de..edb224ed7a 100644 --- a/board/sifive/fu540/Kconfig +++ b/board/sifive/fu540/Kconfig @@ -13,12 +13,20 @@ config SYS_CONFIG_NAME default "sifive-fu540" config SYS_TEXT_BASE + default 0x80200000 if SPL default 0x80000000 if !RISCV_SMODE default 0x80200000 if RISCV_SMODE +config SPL_TEXT_BASE + default 0x08000000 + +config SPL_OPENSBI_LOAD_ADDR + default 0x80000000 + config BOARD_SPECIFIC_OPTIONS # dummy def_bool y select GENERIC_RISCV + select SUPPORT_SPL imply CMD_DHCP imply CMD_EXT2 imply CMD_EXT4 diff --git a/board/sifive/fu540/Makefile b/board/sifive/fu540/Makefile index e4e76e1de3..cdcf894ade 100644 --- a/board/sifive/fu540/Makefile +++ b/board/sifive/fu540/Makefile @@ -5,5 +5,6 @@ obj-y += fu540.o ifdef CONFIG_SPL_BUILD +obj-y += spl.o obj-y += ddr.o endif diff --git a/board/sifive/fu540/fu540-memory-map.h b/board/sifive/fu540/fu540-memory-map.h new file mode 100644 index 0000000000..c65203726b --- /dev/null +++ b/board/sifive/fu540/fu540-memory-map.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2019 SiFive, Inc + */ + +#ifndef FU540_MEMORY_MAP +#define FU540_MEMORY_MAP + +#include <asm/arch/gpio.h> +#include "ux00prci.h" + +/**************************************************************************** + * Platform definitions + *****************************************************************************/ + +/* Memory map */ +#define GPIO_CTRL_ADDR _AC(0x10060000, UL) + +#define PHYSICAL_FILTER_CTRL_ADDR _AC(0x100b8000, UL) + +#define UX00DDR_CTRL_ADDR _AC(0x100b0000, UL) +#define UX00PRCI_CTRL_ADDR _AC(0x10000000, UL) + +/* Helper functions */ +#define _REG32(p, i) (*(volatile uint32_t *)((p) + (i))) + +#define UX00PRCI_REG(offset) \ + _REG32(UX00PRCI_CTRL_ADDR, \ + offset) + +#define GPIO_REG(offset) _REG32(GPIO_CTRL_ADDR, offset) + +#endif /* FU540_MEMORY_MAP */ diff --git a/board/sifive/fu540/fu540.c b/board/sifive/fu540/fu540.c index 3a5e74f1fb..b81003aa6f 100644 --- a/board/sifive/fu540/fu540.c +++ b/board/sifive/fu540/fu540.c @@ -11,6 +11,7 @@ #include <linux/delay.h> #include <linux/io.h> #include <misc.h> +#include <spl.h> /* * This define is a value used for error/unknown serial. @@ -114,3 +115,26 @@ int board_init(void) return 0; } + +#ifdef CONFIG_SPL +void board_boot_order(u32 *spl_boot_list) +{ + u8 i; + u32 boot_devices[] = { +#ifdef CONFIG_SPL_MMC_SUPPORT + BOOT_DEVICE_MMC1, +#endif + }; + + for (i = 0; i < ARRAY_SIZE(boot_devices); i++) + spl_boot_list[i] = boot_devices[i]; +} +#endif + +#ifdef CONFIG_SPL_LOAD_FIT +int board_fit_config_name_match(const char *name) +{ + /* boot using first FIT config */ + return 0; +} +#endif diff --git a/board/sifive/fu540/spl.c b/board/sifive/fu540/spl.c new file mode 100644 index 0000000000..c7ae4aa292 --- /dev/null +++ b/board/sifive/fu540/spl.c @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2019 SiFive, Inc + */ + +#include <common.h> +#include <spl.h> +#include <misc.h> + +#include "ux00ddr.h" +#include "fu540-memory-map.h" + +#define DDR_SIZE (8UL * 1024UL * 1024UL * 1024UL) +#define DDRCTLPLL_F 55 +#define DDRCTLPLL_Q 2 + +#define PHY_NRESET 0x1000 + +static inline int ux00prci_select_corepll(volatile u32 *coreclkselreg, + volatile u32 *corepllcfg, + volatile u32 *corepllout, + u32 pllconfigval) +{ + (*corepllcfg) = pllconfigval; + + // Wait for lock + while (((*corepllcfg) & (PLL_LOCK(1))) == 0) + ; + + u32 core_out = + (PLLOUT_DIV(PLLOUT_DIV_default)) | + (PLLOUT_DIV_BY_1(PLLOUT_DIV_BY_1_default)) | + (PLLOUT_CLK_EN(1)); + (*corepllout) = core_out; + + // Set CORECLKSELREG to select COREPLL + (*coreclkselreg) = PLL_CORECLKSEL_COREPLL; + + return 0; +} + +static inline int ux00prci_select_corepll_500mhz(volatile u32 *coreclkselreg, + volatile u32 *corepllcfg, + volatile u32 *corepllout) +{ + /* + * CORE pll init + * Set corepll 33MHz -> 1GHz + */ + + u32 core500mhz = + (PLL_R(0)) | + (PLL_F(59)) | // 4000MHz VCO + (PLL_Q(3)) | /* /8 Output divider */ + (PLL_RANGE(0x4)) | + (PLL_BYPASS(0)) | + (PLL_FSE(1)); + + return ux00prci_select_corepll(coreclkselreg, corepllcfg, corepllout, + core500mhz); +} + +static inline int ux00prci_select_corepll_1ghz(volatile u32 *coreclkselreg, + volatile u32 *corepllcfg, + volatile u32 *corepllout) +{ + /* + * CORE pll init + * Set corepll 33MHz -> 1GHz + */ + + u32 core1ghz = + (PLL_R(0)) | + (PLL_F(59)) | // 4000MHz VCO + (PLL_Q(2)) | /* /4 Output divider */ + (PLL_RANGE(0x4)) | + (PLL_BYPASS(0)) | + (PLL_FSE(1)); + + return ux00prci_select_corepll(coreclkselreg, corepllcfg, corepllout, + core1ghz); +} + +long nsec_per_cyc = 300; // 33.333MHz +void nsleep(long nsec) +{ + long step = nsec_per_cyc * 2; + + while (nsec > 0) + nsec -= step; +} + +void init_clk_and_ddr(void) +{ + // PRCI init + + // Check Reset Values (lock don't care) + u32 pll_default = + (PLL_R(PLL_R_default)) | + (PLL_F(PLL_F_default)) | + (PLL_Q(PLL_Q_default)) | + (PLL_RANGE(PLL_RANGE_default)) | + (PLL_BYPASS(PLL_BYPASS_default)) | + (PLL_FSE(PLL_FSE_default)); + u32 lockmask = ~PLL_LOCK(1); + u32 pllout_default = + (PLLOUT_DIV(PLLOUT_DIV_default)) | + (PLLOUT_DIV_BY_1(PLLOUT_DIV_BY_1_default)) | + (PLLOUT_CLK_EN(PLLOUT_CLK_EN_default)); + + if ((UX00PRCI_REG(UX00PRCI_COREPLLCFG) ^ pll_default) & lockmask) + return; + if ((UX00PRCI_REG(UX00PRCI_COREPLLOUT) ^ pllout_default)) + return; + if ((UX00PRCI_REG(UX00PRCI_DDRPLLCFG) ^ pll_default) & lockmask) + return; + if ((UX00PRCI_REG(UX00PRCI_DDRPLLOUT) ^ pllout_default)) + return; + if (((UX00PRCI_REG(UX00PRCI_GEMGXLPLLCFG)) ^ pll_default) & lockmask) + return; + if (((UX00PRCI_REG(UX00PRCI_GEMGXLPLLOUT)) ^ pllout_default)) + return; + + /* CORE pll init + * If tlclksel is set for 2:1 operation, + * Set corepll 33Mhz -> 1GHz + * Otherwise, set corepll 33MHz -> 500MHz. + */ + + if (UX00PRCI_REG(UX00PRCI_CLKMUXSTATUSREG) & CLKMUX_STATUS_TLCLKSEL) { + ux00prci_select_corepll_500mhz + (&UX00PRCI_REG(UX00PRCI_CORECLKSELREG), + &UX00PRCI_REG(UX00PRCI_COREPLLCFG), + &UX00PRCI_REG(UX00PRCI_COREPLLOUT)); + } else { + ux00prci_select_corepll_1ghz + (&UX00PRCI_REG(UX00PRCI_CORECLKSELREG), + &UX00PRCI_REG(UX00PRCI_COREPLLCFG), + &UX00PRCI_REG(UX00PRCI_COREPLLOUT)); + } + + //DDR init + u32 ddrctlmhz = + (PLL_R(0)) | + (PLL_F(DDRCTLPLL_F)) | + (PLL_Q(DDRCTLPLL_Q)) | + (PLL_RANGE(0x4)) | + (PLL_BYPASS(0)) | + (PLL_FSE(1)); + UX00PRCI_REG(UX00PRCI_DDRPLLCFG) = ddrctlmhz; + + // Wait for lock + while ((UX00PRCI_REG(UX00PRCI_DDRPLLCFG) & PLL_LOCK(1)) == 0) + ; + + u32 ddrctl_out = + (PLLOUT_DIV(PLLOUT_DIV_default)) | + (PLLOUT_DIV_BY_1(PLLOUT_DIV_BY_1_default)) | + (PLLOUT_CLK_EN(1)); + (UX00PRCI_REG(UX00PRCI_DDRPLLOUT)) = ddrctl_out; + + //Release DDR reset. + UX00PRCI_REG(UX00PRCI_DEVICESRESETREG) |= + DEVICESRESET_DDR_CTRL_RST_N(1); + + // HACK to get the '1 full controller clock cycle'. + asm volatile ("fence"); + UX00PRCI_REG(UX00PRCI_DEVICESRESETREG) |= DEVICESRESET_DDR_AXI_RST_N(1) + | DEVICESRESET_DDR_AHB_RST_N(1) | DEVICESRESET_DDR_PHY_RST_N(1); + // HACK to get the '1 full controller clock cycle'. + asm volatile ("fence"); + + /* These take like 16 cycles to actually propagate. We can't go sending + * stuff before they come out of reset. So wait. (TODO: Add a register + * to read the current reset states, or DDR Control device?) + */ + for (int i = 0; i < 256; i++) + asm volatile ("nop"); + + ux00ddr_writeregmap(UX00DDR_CTRL_ADDR, ddr_ctl_settings, + ddr_phy_settings); + ux00ddr_disableaxireadinterleave(UX00DDR_CTRL_ADDR); + + ux00ddr_disableoptimalrmodw(UX00DDR_CTRL_ADDR); + + ux00ddr_enablewriteleveling(UX00DDR_CTRL_ADDR); + ux00ddr_enablereadleveling(UX00DDR_CTRL_ADDR); + ux00ddr_enablereadlevelinggate(UX00DDR_CTRL_ADDR); + if (ux00ddr_getdramclass(UX00DDR_CTRL_ADDR) == DRAM_CLASS_DDR4) + ux00ddr_enablevreftraining(UX00DDR_CTRL_ADDR); + //mask off interrupts for leveling completion + ux00ddr_mask_leveling_completed_interrupt(UX00DDR_CTRL_ADDR); + + ux00ddr_mask_mc_init_complete_interrupt(UX00DDR_CTRL_ADDR); + ux00ddr_mask_outofrange_interrupts(UX00DDR_CTRL_ADDR); + ux00ddr_setuprangeprotection(UX00DDR_CTRL_ADDR, DDR_SIZE); + ux00ddr_mask_port_command_error_interrupt(UX00DDR_CTRL_ADDR); + + const u64 ddr_size = DDR_SIZE; + const u64 ddr_end = CONFIG_SYS_SDRAM_BASE + ddr_size; + + ux00ddr_start(UX00DDR_CTRL_ADDR, PHYSICAL_FILTER_CTRL_ADDR, ddr_end); + ux00ddr_phy_fixup(UX00DDR_CTRL_ADDR); + + //GEMGXL init + u32 gemgxl125mhz = + (PLL_R(0)) | + (PLL_F(59)) | //4000Mhz VCO + (PLL_Q(5)) | /* /32 */ + (PLL_RANGE(0x4)) | + (PLL_BYPASS(0)) | + (PLL_FSE(1)); + UX00PRCI_REG(UX00PRCI_GEMGXLPLLCFG) = gemgxl125mhz; + + // Wait for lock + while ((UX00PRCI_REG(UX00PRCI_GEMGXLPLLCFG) & PLL_LOCK(1)) == 0) + ; + + u32 gemgxlctl_out = + (PLLOUT_DIV(PLLOUT_DIV_default)) | + (PLLOUT_DIV_BY_1(PLLOUT_DIV_BY_1_default)) | + (PLLOUT_CLK_EN(1)); + UX00PRCI_REG(UX00PRCI_GEMGXLPLLOUT) = gemgxlctl_out; + + //Release GEMGXL reset (set bit DEVICESRESET_GEMGXL to 1) + UX00PRCI_REG(UX00PRCI_DEVICESRESETREG) |= DEVICESRESET_GEMGXL_RST_N(1); + + // VSC8541 PHY reset sequence; leave pull-down active for 2ms + nsleep(2000000); + // Set GPIO 12 (PHY NRESET) to OE=1 and OVAL=1 + GPIO_REG(GPIO_OUTPUT_VAL) |= PHY_NRESET; + GPIO_REG(GPIO_OUTPUT_EN) |= PHY_NRESET; + nsleep(100); + + // Procmon => core clock + UX00PRCI_REG(UX00PRCI_PROCMONCFG) = 0x1 << 24; +} + +void board_init_f(ulong dummy) +{ + int ret; + + ret = spl_early_init(); + if (ret) + panic("spl_early_init() failed: %d\n", ret); + + arch_cpu_init_dm(); + + init_clk_and_ddr(); + + preloader_console_init(); +} diff --git a/board/sifive/fu540/ux00prci.h b/board/sifive/fu540/ux00prci.h new file mode 100644 index 0000000000..90ca3cd258 --- /dev/null +++ b/board/sifive/fu540/ux00prci.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2019 SiFive, Inc + */ + +#ifndef _SIFIVE_UX00PRCI_H +#define _SIFIVE_UX00PRCI_H + +/* Register offsets */ +#define UX00PRCI_HFROSCCFG (0x0000) +#define UX00PRCI_COREPLLCFG (0x0004) +#define UX00PRCI_COREPLLOUT (0x0008) +#define UX00PRCI_DDRPLLCFG (0x000C) +#define UX00PRCI_DDRPLLOUT (0x0010) +#define UX00PRCI_GEMGXLPLLCFG (0x001C) +#define UX00PRCI_GEMGXLPLLOUT (0x0020) +#define UX00PRCI_CORECLKSELREG (0x0024) +#define UX00PRCI_DEVICESRESETREG (0x0028) +#define UX00PRCI_CLKMUXSTATUSREG (0x002C) +#define UX00PRCI_PROCMONCFG (0x00F0) + +#define PLL_R(x) (((x) & 0x3F) << 0) +#define PLL_F(x) (((x) & 0x1FF) << 6) +#define PLL_Q(x) (((x) & 0x7) << 15) +#define PLL_RANGE(x) (((x) & 0x7) << 18) +#define PLL_BYPASS(x) (((x) & 0x1) << 24) +#define PLL_FSE(x) (((x) & 0x1) << 25) +#define PLL_LOCK(x) (((x) & 0x1) << 31) + +#define PLLOUT_DIV(x) (((x) & 0x7F) << 0) +#define PLLOUT_DIV_BY_1(x) (((x) & 0x1) << 8) +#define PLLOUT_CLK_EN(x) (((x) & 0x1) << 31) + +#define PLL_R_default 0x1 +#define PLL_F_default 0x1F +#define PLL_Q_default 0x3 +#define PLL_RANGE_default 0x0 +#define PLL_BYPASS_default 0x1 +#define PLL_FSE_default 0x1 + +#define PLLOUT_DIV_default 0x0 +#define PLLOUT_DIV_BY_1_default 0x0 +#define PLLOUT_CLK_EN_default 0x0 + +#define PLL_CORECLKSEL_HFXIN 0x1 +#define PLL_CORECLKSEL_COREPLL 0x0 + +#define DEVICESRESET_DDR_CTRL_RST_N(x) (((x) & 0x1) << 0) +#define DEVICESRESET_DDR_AXI_RST_N(x) (((x) & 0x1) << 1) +#define DEVICESRESET_DDR_AHB_RST_N(x) (((x) & 0x1) << 2) +#define DEVICESRESET_DDR_PHY_RST_N(x) (((x) & 0x1) << 3) +#define DEVICESRESET_GEMGXL_RST_N(x) (((x) & 0x1) << 5) + +#define CLKMUX_STATUS_TLCLKSEL (0x1 << 1) + +#endif // _SIFIVE_UX00PRCI_H diff --git a/include/configs/sifive-fu540.h b/include/configs/sifive-fu540.h index 2756ed5a77..ef3ae9b650 100644 --- a/include/configs/sifive-fu540.h +++ b/include/configs/sifive-fu540.h @@ -11,6 +11,22 @@ #include <linux/sizes.h> +#ifdef CONFIG_SPL + +#define CONFIG_SPL_MAX_SIZE 0x00100000 +#define CONFIG_SPL_BSS_START_ADDR 0x85000000 +#define CONFIG_SPL_BSS_MAX_SIZE 0x00100000 +#define CONFIG_SYS_SPL_MALLOC_START (CONFIG_SPL_BSS_START_ADDR + \ + CONFIG_SPL_BSS_MAX_SIZE) +#define CONFIG_SYS_SPL_MALLOC_SIZE 0x00100000 + +#define CONFIG_SPL_LOAD_FIT_ADDRESS 0x84000000 + +#define CONFIG_SPL_STACK (0x08000000 + 0x001D0000 - \ + GENERATED_GBL_DATA_SIZE) + +#endif + #define CONFIG_SYS_SDRAM_BASE 0x80000000 #define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + SZ_2M) @@ -24,6 +40,7 @@ /* Environment options */ +#ifndef CONFIG_SPL_BUILD #define BOOT_TARGET_DEVICES(func) \ func(MMC, mmc, 0) \ func(DHCP, dhcp, na) @@ -43,5 +60,6 @@ #define CONFIG_PREBOOT \ "setenv fdt_addr ${fdtcontroladdr};" \ "fdt addr ${fdtcontroladdr};" +#endif #endif /* __CONFIG_H */
Add a support for SPL which will boot from L2 LIM (0x0800_0000) and then boot U-boot FIT image including OpenSBI FW_DYNAMIC firmware and U-Boot proper images from 1st partition of MMC boot devices. SPL related code is leverage from FSBL (https://github.com/sifive/freedom-u540-c000-bootloader.git) Signed-off-by: Pragnesh Patel <pragnesh.patel at sifive.com> --- board/sifive/fu540/Kconfig | 8 + board/sifive/fu540/Makefile | 1 + board/sifive/fu540/fu540-memory-map.h | 33 ++++ board/sifive/fu540/fu540.c | 24 +++ board/sifive/fu540/spl.c | 252 ++++++++++++++++++++++++++ board/sifive/fu540/ux00prci.h | 56 ++++++ include/configs/sifive-fu540.h | 18 ++ 7 files changed, 392 insertions(+) create mode 100644 board/sifive/fu540/fu540-memory-map.h create mode 100644 board/sifive/fu540/spl.c create mode 100644 board/sifive/fu540/ux00prci.h