From mboxrd@z Thu Jan 1 00:00:00 1970 From: Anup Patel Date: Sat, 25 Jan 2020 14:05:44 +0530 Subject: [PATCH v3 06/10] riscv: sifive: fu540: add SPL configuration In-Reply-To: <20200124055026.30787-7-pragnesh.patel@sifive.com> References: <20200124055026.30787-1-pragnesh.patel@sifive.com> <20200124055026.30787-7-pragnesh.patel@sifive.com> Message-ID: List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de On Fri, Jan 24, 2020 at 11:21 AM Pragnesh Patel 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 > --- > 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 > +#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 > #include > #include > +#include > > /* > * 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 > +#include > +#include > + > +#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 > > +#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 Regards, Anup