From patchwork Fri Jan 24 05:50:19 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pragnesh Patel X-Patchwork-Id: 240038 List-Id: U-Boot discussion From: pragnesh.patel at sifive.com (Pragnesh Patel) Date: Fri, 24 Jan 2020 11:20:19 +0530 Subject: [PATCH v3 06/10] riscv: sifive: fu540: add SPL configuration In-Reply-To: <20200124055026.30787-1-pragnesh.patel@sifive.com> References: <20200124055026.30787-1-pragnesh.patel@sifive.com> Message-ID: <20200124055026.30787-7-pragnesh.patel@sifive.com> 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 Reviewed-by: Anup 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 */