>-----Original Message----- >From: Bin Meng <bmeng...@gmail.com> >Sent: 03 January 2020 21:05 >To: Pragnesh Patel <pragnesh.pa...@sifive.com> >Cc: U-Boot Mailing List <u-boot@lists.denx.de>; Rick Chen ><r...@andestech.com>; Paul Walmsley ( Sifive) <paul.walms...@sifive.com>; >Palmer Dabbelt ( Sifive) <pal...@sifive.com>; Anup Patel ><anup.pa...@wdc.com>; Atish Patra <atish.pa...@wdc.com>; Lukas Auer ><lukas.a...@aisec.fraunhofer.de>; AKASHI Takahiro ><takahiro.aka...@linaro.org>; Simon Glass <s...@chromium.org>; Marek >BehĂșn <marek.be...@nic.cz>; Simon Goldschmidt ><simon.k.r.goldschm...@gmail.com>; Peng Fan <peng....@nxp.com>; Boris >Brezillon <bbrezil...@kernel.org>; Alexander Graf <ag...@csgraf.de> >Subject: Re: [PATCH 3/3] riscv: sifive: fu540: add SPL configuration > >Hi Pragnesh, > >On Tue, Dec 31, 2019 at 2:31 PM Pragnesh Patel ><pragnesh.pa...@sifive.com> wrote: >> >> This patch provides sifive_fu540_spl_defconfig which can support >> U-boot SPL to boot from L2 LIM (0x0800_0000) and then boot FIT > >nits: U-Boot > >> image including OpenSBI FW_DYNAMIC firmware and U-Boot proper >> images from MMC boot devices. >> >> With sifive_fu540_spl_defconfig: >> >> U-Boot SPL will be loaded by ZSBL from SD card (replace fsbl.bin with >> u-boot-spl.bin) and runs in L2 LIM in machine mode and then load FIT >> image u-boot.itb from SD card (replace fw_payload.bin with u-boot.itb) >> into RAM. >> >> SPL related code is leverage from FSBL >> (https://github.com/sifive/freedom-u540-c000-bootloader.git) >> >> Signed-off-by: Pragnesh Patel <pragnesh.pa...@sifive.com> >> --- >> arch/riscv/cpu/u-boot-spl.lds | 1 + >> arch/riscv/dts/fu540-c000-u-boot.dtsi | 65 + >> .../dts/hifive-unleashed-a00-u-boot.dtsi | 24 + >> arch/riscv/include/asm/csr.h | 2 + >> board/sifive/fu540/Kconfig | 8 + >> board/sifive/fu540/MAINTAINERS | 1 + >> board/sifive/fu540/Makefile | 6 + >> board/sifive/fu540/ememoryotp.c | 143 ++ >> board/sifive/fu540/fu540.c | 31 +- >> board/sifive/fu540/include/ccache.h | 47 + >> board/sifive/fu540/include/clkutils.h | 75 + >> board/sifive/fu540/include/ddrregs.h | 622 +++++++++ >> board/sifive/fu540/include/ememoryotp.h | 24 + >> board/sifive/fu540/include/fu540-memory-map.h | 427 ++++++ >> board/sifive/fu540/include/i2c.h | 49 + >> board/sifive/fu540/include/regconfig-ctl.h | 274 ++++ >> board/sifive/fu540/include/regconfig-phy.h | 1224 +++++++++++++++++ >> board/sifive/fu540/include/spi.h | 233 ++++ >> board/sifive/fu540/include/uart.h | 54 + >> board/sifive/fu540/include/ux00ddr.h | 268 ++++ >> board/sifive/fu540/include/ux00prci.h | 206 +++ >> board/sifive/fu540/spl.c | 321 +++++ >> board/sifive/fu540/uart.c | 64 + >> configs/sifive_fu540_spl_defconfig | 23 + >> include/configs/sifive-fu540.h | 17 + >> lib/Makefile | 1 + >> 26 files changed, 4209 insertions(+), 1 deletion(-) >> create mode 100644 arch/riscv/dts/fu540-c000-u-boot.dtsi >> create mode 100644 arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi >> create mode 100644 board/sifive/fu540/ememoryotp.c >> create mode 100644 board/sifive/fu540/include/ccache.h >> create mode 100644 board/sifive/fu540/include/clkutils.h >> create mode 100644 board/sifive/fu540/include/ddrregs.h >> create mode 100644 board/sifive/fu540/include/ememoryotp.h >> create mode 100644 board/sifive/fu540/include/fu540-memory-map.h >> create mode 100644 board/sifive/fu540/include/i2c.h >> create mode 100644 board/sifive/fu540/include/regconfig-ctl.h >> create mode 100644 board/sifive/fu540/include/regconfig-phy.h >> create mode 100644 board/sifive/fu540/include/spi.h >> create mode 100644 board/sifive/fu540/include/uart.h >> create mode 100644 board/sifive/fu540/include/ux00ddr.h >> create mode 100644 board/sifive/fu540/include/ux00prci.h >> create mode 100644 board/sifive/fu540/spl.c >> create mode 100644 board/sifive/fu540/uart.c >> create mode 100644 configs/sifive_fu540_spl_defconfig >> >> diff --git a/arch/riscv/cpu/u-boot-spl.lds b/arch/riscv/cpu/u-boot-spl.lds >> index 955dd3106d..d0495ce248 100644 >> --- a/arch/riscv/cpu/u-boot-spl.lds >> +++ b/arch/riscv/cpu/u-boot-spl.lds >> @@ -72,6 +72,7 @@ SECTIONS >> . = ALIGN(4); >> >> _end = .; >> + _image_binary_end = .; > >This should be a separate patch.
Sure. > >> >> .bss : { >> __bss_start = .; >> diff --git a/arch/riscv/dts/fu540-c000-u-boot.dtsi b/arch/riscv/dts/fu540- >c000-u-boot.dtsi >> new file mode 100644 >> index 0000000000..b86cdfb38d >> --- /dev/null >> +++ b/arch/riscv/dts/fu540-c000-u-boot.dtsi >> @@ -0,0 +1,65 @@ >> +// SPDX-License-Identifier: GPL-2.0+ >> +/* >> + * (C) Copyright 2019 SiFive, Inc >> + */ >> + >> +/ { >> + cpus { >> + u-boot,dm-spl; >> + cpu0: cpu@0 { >> + u-boot,dm-spl; >> + status = "okay"; >> + cpu0_intc: interrupt-controller { >> + u-boot,dm-spl; >> + }; >> + }; >> + cpu1: cpu@1 { >> + u-boot,dm-spl; >> + cpu1_intc: interrupt-controller { >> + u-boot,dm-spl; >> + }; >> + }; >> + cpu2: cpu@2 { >> + u-boot,dm-spl; >> + cpu2_intc: interrupt-controller { >> + u-boot,dm-spl; >> + }; >> + }; >> + cpu3: cpu@3 { >> + u-boot,dm-spl; >> + cpu3_intc: interrupt-controller { >> + u-boot,dm-spl; >> + }; >> + }; >> + cpu4: cpu@4 { >> + u-boot,dm-spl; >> + cpu4_intc: interrupt-controller { >> + u-boot,dm-spl; >> + }; >> + }; >> + }; >> + >> + soc { >> + u-boot,dm-spl; >> + clint@2000000 { >> + compatible = "riscv,clint0"; >> + interrupts-extended = <&cpu0_intc 3 &cpu0_intc 7 >; >> + reg = <0x0 0x2000000 0x0 0xc0000>; >> + u-boot,dm-spl; >> + }; >> + >> + }; >> + >> +}; >> + >> +&prci { >> + u-boot,dm-spl; >> +}; >> + >> +&uart0 { >> + u-boot,dm-spl; >> +}; >> + >> +&qspi2 { >> + u-boot,dm-spl; >> +}; > >Are all of these peripherals needed in SPL? As far as I know they are all needed, I will recheck and remove any not needed peripherals in v2. > >> diff --git a/arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi >b/arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi >> new file mode 100644 >> index 0000000000..9b59f4ee14 >> --- /dev/null >> +++ b/arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi >> @@ -0,0 +1,24 @@ >> +// SPDX-License-Identifier: GPL-2.0+ >> +/* >> + * Copyright (C) 2019 SiFive, Inc >> + */ >> + >> +#include "fu540-c000-u-boot.dtsi" >> + >> +/ { >> + hfclk { >> + u-boot,dm-spl; >> + }; >> + >> + rtcclk { >> + u-boot,dm-spl; >> + }; >> +}; >> + >> +&qspi2 { >> + >> + mmc@0 { >> + u-boot,dm-spl; >> + }; >> + >> +}; >> diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h >> index d1520743a2..125c05dd8a 100644 >> --- a/arch/riscv/include/asm/csr.h >> +++ b/arch/riscv/include/asm/csr.h >> @@ -103,6 +103,8 @@ >> #define CSR_TIMEH 0xc81 >> #define CSR_INSTRETH 0xc82 >> #define CSR_MHARTID 0xf14 >> +#define CSR_MCYCLE 0xb00 >> +#define CSR_MCYCLEH 0xb80 >> >> #ifndef __ASSEMBLY__ >> >> diff --git a/board/sifive/fu540/Kconfig b/board/sifive/fu540/Kconfig >> index 816a135b21..ac7c6bff37 100644 >> --- a/board/sifive/fu540/Kconfig >> +++ b/board/sifive/fu540/Kconfig >> @@ -16,12 +16,20 @@ config SYS_SOC >> default "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/MAINTAINERS >b/board/sifive/fu540/MAINTAINERS >> index 702d803ad8..42c3f3deb0 100644 >> --- a/board/sifive/fu540/MAINTAINERS >> +++ b/board/sifive/fu540/MAINTAINERS >> @@ -7,3 +7,4 @@ S: Maintained >> F: board/sifive/fu540/ >> F: include/configs/sifive-fu540.h >> F: configs/sifive_fu540_defconfig >> +F: configs/sifive_fu540_spl_defconfig >> diff --git a/board/sifive/fu540/Makefile b/board/sifive/fu540/Makefile >> index 6e1862c475..e532beb9d5 100644 >> --- a/board/sifive/fu540/Makefile >> +++ b/board/sifive/fu540/Makefile >> @@ -3,3 +3,9 @@ >> # Copyright (c) 2019 Western Digital Corporation or its affiliates. >> >> obj-y += fu540.o >> + >> +ifdef CONFIG_SPL_BUILD >> +obj-y += spl.o >> +obj-y += ememoryotp.o >> +obj-y += uart.o >> +endif >> diff --git a/board/sifive/fu540/ememoryotp.c >b/board/sifive/fu540/ememoryotp.c >> new file mode 100644 >> index 0000000000..994724af37 >> --- /dev/null >> +++ b/board/sifive/fu540/ememoryotp.c >> @@ -0,0 +1,143 @@ >> +// SPDX-License-Identifier: GPL-2.0+ >> +/* >> + * Copyright (c) 2019 SiFive, Inc >> + * >> + * Authors: >> + * Pragnesh Patel <pragnesh.pa...@sifive.com> >> + * Troy Benjegerdes <troy.benjeger...@sifive.com> >> + */ >> + >> +#include <stdint.h> >> +#include "include/fu540-memory-map.h" >> +#include "include/clkutils.h" >> +#include "include/ememoryotp.h" >> + >> +#define max(x, y) ((x) > (y) ? (x) : (y)) >> + >> +extern inline void clkutils_delay_ns(int delay_ns); >> + >> +void ememory_otp_power_up_sequence(void) >> +{ >> + // Probably don't need to do this, since >> + // all the other stuff has been happening. >> + // But it is on the wave form. >> + clkutils_delay_ns(EMEMORYOTP_MIN_TVDS * 1000); >> + >> + EMEMORYOTP_REG(EMEMORYOTP_PDSTB) = 1; >> + clkutils_delay_ns(EMEMORYOTP_MIN_TSAS * 1000); >> + >> + EMEMORYOTP_REG(EMEMORYOTP_PTRIM) = 1; >> + clkutils_delay_ns(EMEMORYOTP_MIN_TTAS * 1000); >> +} >> + >> +void ememory_otp_power_down_sequence(void) >> +{ >> + clkutils_delay_ns(EMEMORYOTP_MIN_TTAH * 1000); >> + EMEMORYOTP_REG(EMEMORYOTP_PTRIM) = 0; >> + clkutils_delay_ns(EMEMORYOTP_MIN_TASH * 1000); >> + EMEMORYOTP_REG(EMEMORYOTP_PDSTB) = 0; >> + // No delay indicated after this >> +} >> + >> +void ememory_otp_begin_read(void) >> +{ >> + // Initialize >> + EMEMORYOTP_REG(EMEMORYOTP_PCLK) = 0; >> + EMEMORYOTP_REG(EMEMORYOTP_PA) = 0; >> + EMEMORYOTP_REG(EMEMORYOTP_PDIN) = 0; >> + EMEMORYOTP_REG(EMEMORYOTP_PWE) = 0; >> + EMEMORYOTP_REG(EMEMORYOTP_PTM) = 0; >> + clkutils_delay_ns(EMEMORYOTP_MIN_TMS * 1000); >> + >> + // Enable chip select >> + >> + EMEMORYOTP_REG(EMEMORYOTP_PCE) = 1; >> + clkutils_delay_ns(EMEMORYOTP_MIN_TCS * 1000); >> +} >> + >> +void ememory_otp_exit_read(void) >> +{ >> + EMEMORYOTP_REG(EMEMORYOTP_PCLK) = 0; >> + EMEMORYOTP_REG(EMEMORYOTP_PA) = 0; >> + EMEMORYOTP_REG(EMEMORYOTP_PDIN) = 0; >> + EMEMORYOTP_REG(EMEMORYOTP_PWE) = 0; >> + // Disable chip select >> + EMEMORYOTP_REG(EMEMORYOTP_PCE) = 0; >> + // Wait before changing PTM >> + clkutils_delay_ns(EMEMORYOTP_MIN_TMH * 1000); >> +} >> + >> +unsigned int ememory_otp_read(int address) >> +{ >> + unsigned int read_value; >> + >> + EMEMORYOTP_REG(EMEMORYOTP_PA) = address; >> + // Toggle clock >> + clkutils_delay_ns(EMEMORYOTP_MIN_TAS * 1000); >> + EMEMORYOTP_REG(EMEMORYOTP_PCLK) = 1; >> + // Insert delay until data is ready. >> + // There are lots of delays >> + // on the chart, but I think this is the most relevant. >> + int delay = max(EMEMORYOTP_MAX_TCD, EMEMORYOTP_MIN_TKH); >> + >> + clkutils_delay_ns(delay * 1000); >> + EMEMORYOTP_REG(EMEMORYOTP_PCLK) = 0; >> + read_value = EMEMORYOTP_REG(EMEMORYOTP_PDOUT); >> + // Could check here for things like TCYC < TAH + TCD >> + return read_value; >> +} >> + >> +void ememory_otp_pgm_entry(void) >> +{ >> + EMEMORYOTP_REG(EMEMORYOTP_PCLK) = 0; >> + EMEMORYOTP_REG(EMEMORYOTP_PA) = 0; >> + EMEMORYOTP_REG(EMEMORYOTP_PAS) = 0; >> + EMEMORYOTP_REG(EMEMORYOTP_PAIO) = 0; >> + EMEMORYOTP_REG(EMEMORYOTP_PDIN) = 0; >> + EMEMORYOTP_REG(EMEMORYOTP_PWE) = 0; >> + EMEMORYOTP_REG(EMEMORYOTP_PTM) = 2; >> + clkutils_delay_ns(EMEMORYOTP_MIN_TMS * 1000); >> + EMEMORYOTP_REG(EMEMORYOTP_PCE) = 1; >> + clkutils_delay_ns(EMEMORYOTP_TYP_TCSP * 1000); >> + EMEMORYOTP_REG(EMEMORYOTP_PPROG) = 1; >> + clkutils_delay_ns(EMEMORYOTP_TYP_TPPS * 1000); >> + EMEMORYOTP_REG(EMEMORYOTP_PTRIM) = 1; >> +} >> + >> +void ememory_otp_pgm_exit(void) >> +{ >> + EMEMORYOTP_REG(EMEMORYOTP_PWE) = 0; >> + clkutils_delay_ns(EMEMORYOTP_TYP_TPPH * 1000); >> + EMEMORYOTP_REG(EMEMORYOTP_PPROG) = 0; >> + clkutils_delay_ns(EMEMORYOTP_TYP_TPPR * 1000); >> + EMEMORYOTP_REG(EMEMORYOTP_PCE) = 0; >> + clkutils_delay_ns(EMEMORYOTP_MIN_TMH * 1000); >> + EMEMORYOTP_REG(EMEMORYOTP_PTM) = 0; >> +} >> + >> +void ememory_otp_pgm_access(int address, unsigned int write_data) >> +{ >> + int i; >> + >> + EMEMORYOTP_REG(EMEMORYOTP_PA) = address; >> + for (int pas = 0; pas < 2; pas++) { >> + EMEMORYOTP_REG(EMEMORYOTP_PAS) = pas; >> + for (i = 0; i < 32; i++) { >> + EMEMORYOTP_REG(EMEMORYOTP_PAIO) = i; >> + EMEMORYOTP_REG(EMEMORYOTP_PDIN) = ((write_data >> i) >& >> + 1); >> + >> + int delay = max(EMEMORYOTP_MIN_TASP, >> + EMEMORYOTP_MIN_TDSP); >> + >> + clkutils_delay_ns(delay * 1000); >> + EMEMORYOTP_REG(EMEMORYOTP_PWE) = 1; >> + clkutils_delay_ns(EMEMORYOTP_TYP_TPW * 1000); >> + EMEMORYOTP_REG(EMEMORYOTP_PWE) = 0; >> + delay = max(EMEMORYOTP_MIN_TAHP, >EMEMORYOTP_MIN_TDHP); >> + delay = max(delay, EMEMORYOTP_TYP_TPWI); >> + clkutils_delay_ns(delay * 1000); >> + } >> + } >> + EMEMORYOTP_REG(EMEMORYOTP_PAS) = 0; >> +} >> diff --git a/board/sifive/fu540/fu540.c b/board/sifive/fu540/fu540.c >> index 47a2090251..e91418a88a 100644 >> --- a/board/sifive/fu540/fu540.c >> +++ b/board/sifive/fu540/fu540.c >> @@ -10,6 +10,9 @@ >> #include <dm.h> >> #include <linux/delay.h> >> #include <linux/io.h> >> +#include <spl.h> >> +#include "include/ccache.h" >> +#include "include/fu540-memory-map.h" >> >> #ifdef CONFIG_MISC_INIT_R >> >> @@ -143,7 +146,33 @@ int misc_init_r(void) >> >> int board_init(void) >> { >> - /* For now nothing to do here. */ >> + /* enable all cache ways */ >> + ccache_enable_ways(CCACHE_CTRL_ADDR, 15); >> + return 0; >> +} >> + >> +#ifdef CONFIG_SPL >> +void board_boot_order(u32 *spl_boot_list) >> +{ >> + u8 i; >> + u32 boot_devices[] = { >> +#ifdef CONFIG_SPL_RAM_SUPPORT >> + BOOT_DEVICE_RAM, >> +#endif >> +#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/include/ccache.h >b/board/sifive/fu540/include/ccache.h >> new file mode 100644 >> index 0000000000..c7978ebdee >> --- /dev/null >> +++ b/board/sifive/fu540/include/ccache.h >> @@ -0,0 +1,47 @@ >> +/* SPDX-License-Identifier: GPL-2.0+ */ >> +/* >> + * Copyright (c) 2019 SiFive, Inc >> + * >> + * Authors: >> + * Pragnesh Patel <pragnesh.pa...@sifive.com> >> + * Troy Benjegerdes <troy.benjeger...@sifive.com> >> + */ >> + >> +#ifndef FU540_CCACHE_H >> +#define FU540_CCACHE_H >> + >> +#include <asm/arch/cache.h> >> + >> +#ifndef __ASSEMBLER__ >> + >> +#include <stdint.h> >> +#include <stdatomic.h> >> +#include <linux/types.h> >> + >> +// Block memory access until operation completed >> +static inline void ccache_barrier_0(void) >> +{ >> + asm volatile("fence rw, io" : : : "memory"); >> +} >> + >> +static inline void ccache_barrier_1(void) >> +{ >> + asm volatile("fence io, rw" : : : "memory"); >> +} >> + >> +// Enable ways; allow cache to use these ways >> +static inline u8 ccache_enable_ways(u64 base_addr, u8 value) >> +{ >> + u32 old; >> + >> + volatile _Atomic(u32) * enable = (_Atomic(u32) *)(base_addr + >> + CCACHE_ENABLE); >> + ccache_barrier_0(); >> + old = atomic_exchange_explicit(enable, value, >memory_order_relaxed); > >How does this work as we are calling a C11 API? I will check this and update in v2. > >> + ccache_barrier_1(); >> + return old; >> +} >> + >> +#endif >> + >> +#endif /* FU540_CCACHE_H */ >> diff --git a/board/sifive/fu540/include/clkutils.h >b/board/sifive/fu540/include/clkutils.h >> new file mode 100644 >> index 0000000000..dbb260a1c3 >> --- /dev/null >> +++ b/board/sifive/fu540/include/clkutils.h >> @@ -0,0 +1,75 @@ >> +/* SPDX-License-Identifier: GPL-2.0+ */ >> +/* >> + * Copyright (c) 2019 SiFive, Inc >> + * >> + * Authors: >> + * Pragnesh Patel <pragnesh.pa...@sifive.com> >> + * Troy Benjegerdes <troy.benjeger...@sifive.com> >> + */ >> + >> +#ifndef __ASSEMBLER__ >> + >> +#include <stdint.h> >> +#include <asm/encoding.h> >> +#include "fu540-memory-map.h" >> + >> +// Inlining header functions in C >> +// https://stackoverflow.com/a/23699777/7433423 >> +inline u64 clkutils_read_mtime(void) >> +{ >> +#if __riscv_xlen == 32 >> + u32 mtime_hi_0; >> + u32 mtime_lo; >> + u32 mtime_hi_1; >> + >> + do { >> + mtime_hi_0 = CLINT_REG(CLINT_MTIME + 4); >> + mtime_lo = CLINT_REG(CLINT_MTIME + 0); >> + mtime_hi_1 = CLINT_REG(CLINT_MTIME + 4); >> + } while (mtime_hi_0 != mtime_hi_1); >> + >> + return (((u64)mtime_hi_1 << 32) | ((u64)mtime_lo)); >> +#else >> + return CLINT_REG64(CLINT_MTIME); >> +#endif >> +} >> + >> +static inline u64 clkutils_read_mcycle(void) >> +{ >> +#if __riscv_xlen == 32 >> + u32 mcycle_hi_0; >> + u32 mcycle_lo; >> + u32 mcycle_hi_1; >> + >> + do { >> + mcycle_hi_0 = read_csr(mcycleh); >> + mcycle_lo = read_csr(mcycle); >> + mcycle_hi_1 = read_csr(mcycleh); >> + } while (mcycle_hi_0 != mcycle_hi_1); >> + >> + return (((u64)mcycle_hi_1 << 32) | ((u64)mcycle_lo)); >> +#else >> + return csr_read(CSR_MCYCLE); >> +#endif >> +} >> + >> +// Note that since this runs off RTC, which is >> +// currently ~1-10MHz, this function is >> +// not acccurate for small delays. >> +// In the future, we may want to determine whether to >> +// use RTC vs mcycle, or create a different function >> +// based off mcycle. >> +// We add 1 to the then value because otherwise, if you wanted >> +// to delay up to RTC_PERIOD_NS-1 (for example), you wouldn't delay >> +// at all. So this function delays AT LEAST delay_ns. >> +inline void clkutils_delay_ns(int delay_ns) >> +{ >> + u64 now = clkutils_read_mtime(); >> + u64 then = now + delay_ns / RTC_PERIOD_NS + 1; >> + >> + do { >> + now = clkutils_read_mtime(); >> + } while (now < then); >> +} >> + >> +#endif /* !__ASSEMBLER__ */ >> diff --git a/board/sifive/fu540/include/ddrregs.h >b/board/sifive/fu540/include/ddrregs.h >> new file mode 100644 >> index 0000000000..e436496d87 >> --- /dev/null >> +++ b/board/sifive/fu540/include/ddrregs.h >> @@ -0,0 +1,622 @@ >> +/* SPDX-License-Identifier: GPL-2.0+ */ >> +/* >> + * Copyright (c) 2019 SiFive, Inc >> + * >> + * Authors: >> + * Pragnesh Patel <pragnesh.pa...@sifive.com> >> + * Troy Benjegerdes <troy.benjeger...@sifive.com> >> + */ >> + >> +#include <stdint.h> >> + >> +u32 DENALI_PHY_DATA[1215] = { > >This is declaring a variable and should not be put in a header file. I will update in v2, thanks for the review. > >> + DENALI_PHY_00_DATA, DENALI_PHY_01_DATA, > [......] >> diff --git a/board/sifive/fu540/include/ememoryotp.h >b/board/sifive/fu540/include/ememoryotp.h >> new file mode 100644 >> index 0000000000..274283c4db >> --- /dev/null >> +++ b/board/sifive/fu540/include/ememoryotp.h >> @@ -0,0 +1,24 @@ >> +/* SPDX-License-Identifier: GPL-2.0+ */ >> +/* >> + * Copyright (c) 2019 SiFive, Inc >> + * >> + * Authors: >> + * Pragnesh Patel <pragnesh.pa...@sifive.com> >> + * Troy Benjegerdes <troy.benjeger...@sifive.com> >> + */ >> + >> +#ifndef FU540_EMEMORYOTP_H >> +#define FU540_EMEMORYOTP_H >> + >> +#include <asm/arch/otp.h> >> + >> +void ememory_otp_power_up_sequence(void); >> +void ememory_otp_power_down_sequence(void); >> +} >> + >> +#endif /* __ASSEMBLER__ */ >> + >> +#endif /* FU540_UX00DDR_H */ > [....] >> diff --git a/board/sifive/fu540/include/ux00prci.h >b/board/sifive/fu540/include/ux00prci.h >> new file mode 100644 >> index 0000000000..21f4aeb465 >> --- /dev/null >> +++ b/board/sifive/fu540/include/ux00prci.h >> @@ -0,0 +1,206 @@ >> +/* SPDX-License-Identifier: GPL-2.0+ */ >> + >> +/* >> + * Copyright (c) 2019 SiFive, Inc >> + * >> + * Authors: >> + * Pragnesh Patel <pragnesh.pa...@sifive.com> >> + * Troy Benjegerdes <troy.benjeger...@sifive.com> >> + */ >> + >> +#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) >> + >> +/* Fields */ >> +#define XOSC_EN(x) (((x) & 0x1) << 30) >> +#define XOSC_RDY(x) (((x) & 0x1) << 31) >> + >> +#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_CORECLKPLLSEL (0x1 << 0) >> +#define CLKMUX_STATUS_TLCLKSEL (0x1 << 1) >> +#define CLKMUX_STATUS_RTCXSEL (0x1 << 2) >> +#define CLKMUX_STATUS_DDRCTRLCLKSEL (0x1 << 3) >> +#define CLKMUX_STATUS_DDRPHYCLKSEL (0x1 << 4) >> +#define CLKMUX_STATUS_GEMGXLCLKSEL (0x1 << 6) >> + >> +#ifndef __ASSEMBLER__ >> + >> +#include <stdint.h> >> +#include <linux/types.h> >> + >> +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_1_4ghz(volatile u32 >> *coreclkselreg, >> + volatile u32 *corepllcfg, >> + volatile u32 *corepllout) >> +{ >> + // >> + // CORE pll init >> + // Set corepll 33MHz -> 1GHz >> + // >> + >> + u32 core14ghz = >> + (PLL_R(0)) | >> + (PLL_F(41)) | /*2800MHz VCO*/ >> + (PLL_Q(1)) | /* /2 Output divider */ >> + (PLL_RANGE(0x4)) | >> + (PLL_BYPASS(0)) | >> + (PLL_FSE(1)); >> + >> + return ux00prci_select_corepll(coreclkselreg, corepllcfg, corepllout, >> + core14ghz); >> +} >> + >> +static inline int ux00prci_select_corepll_1_5ghz(volatile u32 >> *coreclkselreg, >> + volatile u32 *corepllcfg, >> + volatile u32 *corepllout) >> +{ >> + // >> + // CORE pll init >> + // Set corepll 33MHz -> 1GHz >> + // >> + >> + u32 core15ghz = >> + (PLL_R(0)) | >> + (PLL_F(44)) | /*3000MHz VCO*/ >> + (PLL_Q(1)) | /* /2 Output divider */ >> + (PLL_RANGE(0x4)) | >> + (PLL_BYPASS(0)) | >> + (PLL_FSE(1)); >> + >> + return ux00prci_select_corepll(coreclkselreg, corepllcfg, corepllout, >> + core15ghz); >> +} >> + >> +static inline int ux00prci_select_corepll_1_6ghz(volatile u32 >> *coreclkselreg, >> + volatile u32 *corepllcfg, >> + volatile u32 *corepllout) >> +{ >> + // >> + // CORE pll init >> + // Set corepll 33MHz -> 1GHz >> + // >> + >> + u32 core16ghz = >> + (PLL_R(0)) | >> + (PLL_F(47)) | /*3200MHz VCO*/ >> + (PLL_Q(1)) | /* /2 Output divider */ >> + (PLL_RANGE(0x4)) | >> + (PLL_BYPASS(0)) | >> + (PLL_FSE(1)); >> + >> + return ux00prci_select_corepll(coreclkselreg, corepllcfg, corepllout, >> + core16ghz); >> +} >> + >> +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); >> +} >> + >> +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); >> +} >> + > >Can we reuse the U-Boot PRCI driver for SPL? If not, could we update >it instead of creating another ad-hoc driver? I agreed with you but for preload_console_init(), UART clock needs to be enabled and that is provided by tlclk (corepll). This clock initialization is necessary for SPL but I will move this code to spl.c from header file. Let me know if you have any other suggestion. > >> +#endif >> + >> +#endif // _SIFIVE_UX00PRCI_H >> diff --git a/board/sifive/fu540/spl.c b/board/sifive/fu540/spl.c >> new file mode 100644 >> index 0000000000..69187066ba >> --- /dev/null >> +++ b/board/sifive/fu540/spl.c >> @@ -0,0 +1,321 @@ >> +// SPDX-License-Identifier: GPL-2.0+ >> +/* >> + * Copyright (c) 2019 SiFive, Inc >> + * >> + * Authors: >> + * Pragnesh Patel <pragnesh.pa...@sifive.com> >> + * Troy Benjegerdes <troy.benjeger...@sifive.com> >> + */ >> + >> +#include <common.h> >> +#include <spl.h> >> + >> +#include "include/regconfig-ctl.h" >> +#include "include/regconfig-phy.h" >> +#include "include/ux00ddr.h" >> +#include "include/ddrregs.h" >> + >> +#include "include/fu540-memory-map.h" >> +#include <stdatomic.h> >> + >> +#define ddr_phy_settings DENALI_PHY_DATA >> +#define ddr_ctl_settings DENALI_CTL_DATA >> + >> +#define DDR_SIZE (8UL * 1024UL * 1024UL * 1024UL) >> +#define DDRCTLPLL_F 55 >> +#define DDRCTLPLL_Q 2 >> + >> +#define PHY_NRESET 0x1000 >> +#define FIRST_SLOT 0xfe >> +#define LAST_SLOT 0x80 >> + >> +static const uintptr_t i2c_devices[] = { >> + I2C_CTRL_ADDR, >> +}; >> + >> +static spi_ctrl * const spi_devices[] = { >> + (spi_ctrl *)SPI0_CTRL_ADDR, >> + (spi_ctrl *)SPI1_CTRL_ADDR, >> + (spi_ctrl *)SPI2_CTRL_ADDR, >> +}; >> + >> +static const uintptr_t uart_devices[] = { >> + UART0_CTRL_ADDR, >> + UART1_CTRL_ADDR, >> +}; >> + >> +unsigned int serial_to_burn = ~0; >> + >> +/** >> + * Scale peripheral clock dividers before changing core PLL. >> + */ >> +void update_peripheral_clock_dividers(unsigned int peripheral_input_khz) > >Are these a must-have? ie: can we have individual device driver (ie: >sifive i2c, or sifive spi driver to do such work in their probe() >routine)? Yes, you are right. Only UART clock divider needs to be updated. Will update in v2. > >> +{ >> + unsigned int i2c_target_khz = 400; >> + u16 prescaler = i2c_min_clk_prescaler(peripheral_input_khz, >> + i2c_target_khz); >> + >> + for (size_t i = 0; i < ARRAY_SIZE(i2c_devices); i++) { >> + _REG32(i2c_devices[i], I2C_PRESCALER_LO) = prescaler & 0xff; >> + _REG32(i2c_devices[i], I2C_PRESCALER_HI) = (prescaler >> 8) & >> + 0xff; >> + } >> + >> + unsigned int spi_target_khz = 50000; >> + unsigned int spi_div = spi_min_clk_divisor(peripheral_input_khz, >> + spi_target_khz); >> + >> + for (size_t i = 0; i < ARRAY_SIZE(spi_devices); i++) >> + spi_devices[i]->sckdiv = spi_div; >> + >> + unsigned int uart_target_hz = 115200ULL; >> + unsigned int uart_div = uart_min_clk_divisor(peripheral_input_khz * >> + 1000ULL, >> uart_target_hz); >> + >> + for (size_t i = 0; i < ARRAY_SIZE(uart_devices); i++) >> + _REG32(uart_devices[i], UART_REG_DIV) = uart_div; >> +} >> + >> +long nsec_per_cyc = 300; // 33.333MHz >> +void nsleep(long nsec) >> +{ >> + long step = nsec_per_cyc * 2; // 2 instructions per loop iteration >> + >> + while (nsec > 0) >> + nsec -= step; >> +} >> + >> +void init_clk_and_ddr(void) >> +{ >> + // PRCI init >> + >> + // Initialize UART divider for 33MHz core clock in case if >> + // trap is taken prior to core clock bump. >> + unsigned long long uart_target_hz = 115200ULL; >> + const u32 initial_core_clk_khz = 33000; >> + unsigned long peripheral_input_khz; >> + >> + if (UX00PRCI_REG(UX00PRCI_CLKMUXSTATUSREG) & >CLKMUX_STATUS_TLCLKSEL) >> + peripheral_input_khz = initial_core_clk_khz; >> + else >> + peripheral_input_khz = initial_core_clk_khz / 2; >> + UART0_REG(UART_REG_DIV) = >uart_min_clk_divisor(peripheral_input_khz * >> + 1000ULL, >> uart_target_hz); >> + >> + // 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) { >> + nsec_per_cyc = 2; >> + peripheral_input_khz = 500000; // peripheral_clk = tlclk >> + update_peripheral_clock_dividers(peripheral_input_khz); >> + ux00prci_select_corepll_500mhz >> + (&UX00PRCI_REG(UX00PRCI_CORECLKSELREG), >> + &UX00PRCI_REG(UX00PRCI_COREPLLCFG), >> + &UX00PRCI_REG(UX00PRCI_COREPLLOUT)); >> + } else { >> + nsec_per_cyc = 1; >> + peripheral_input_khz = (1000000 / 2); // peripheral_clk = >> tlclk >> + update_peripheral_clock_dividers(peripheral_input_khz); >> + >> + 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 >> + atomic_fetch_or(&GPIO_REG(GPIO_OUTPUT_VAL), PHY_NRESET); >> + atomic_fetch_or(&GPIO_REG(GPIO_OUTPUT_EN), PHY_NRESET); >> + nsleep(100); >> + >> + // Procmon => core clock >> + UX00PRCI_REG(UX00PRCI_PROCMONCFG) = 0x1 << 24; >> + >> + // Post the serial number and build info >> + UART0_REG(UART_REG_TXCTRL) = UART_TXEN; >> + puts("\r\nPRCI Initialized: "); >> + >> + unsigned int serial = ~0; >> + int serial_slot; >> + unsigned int pos; >> + unsigned int neg; >> + >> + ememory_otp_power_up_sequence(); >> + ememory_otp_begin_read(); >> + for (serial_slot = FIRST_SLOT; serial_slot >= LAST_SLOT; >> + serial_slot -= 2) { >> + pos = ememory_otp_read(serial_slot); >> + neg = ememory_otp_read(serial_slot + 1); >> + serial = pos; >> + if (pos == ~neg) >> + break; // legal serial # >> + if (pos == ~0 && neg == ~0) >> + break; // empty slot encountered >> + } >> + ememory_otp_exit_read(); >> + >> + void *uart = (void *)UART0_CTRL_ADDR; >> + >> + uart_puts(uart, "\r\nHiFive-U serial #: "); >> + uart_put_hex(uart, serial); > >I don't this we really need this. I will remove this. > >> + >> + // Program the OTP? >> + if (serial_to_burn != ~0 && serial != serial_to_burn && >> + serial_slot > LAST_SLOT) { >> + uart_puts(uart, "Programming serial: "); >> + uart_put_hex(uart, serial_to_burn); >> + uart_puts(uart, "\r\n"); >> + ememory_otp_pgm_entry(); >> + if (serial != ~0) { >> + // erase the current serial >> + uart_puts(uart, "Erasing prior serial\r\n"); >> + ememory_otp_pgm_access(serial_slot, 0); >> + ememory_otp_pgm_access(serial_slot + 1, 0); >> + serial_slot -= 2; >> + } >> + ememory_otp_pgm_access(serial_slot, serial_to_burn); >> + ememory_otp_pgm_access(serial_slot + 1, ~serial_to_burn); >> + ememory_otp_pgm_exit(); >> + uart_puts(uart, "Resuming boot\r\n"); >> + serial = serial_to_burn; >> + } >> + >> + ememory_otp_power_down_sequence(); >> + uart_puts(uart, "\r\n"); >> +} >> + >> +void board_init_f(ulong dummy) >> +{ >> + int ret; >> + >> + init_clk_and_ddr(); >> + >> + ret = spl_early_init(); >> + if (ret) >> + panic("spl_early_init() failed: %d\n", ret); >> + >> + arch_cpu_init_dm(); >> + >> + preloader_console_init(); >> +} >> diff --git a/board/sifive/fu540/uart.c b/board/sifive/fu540/uart.c >> new file mode 100644 >> index 0000000000..d16f6add47 >> --- /dev/null >> +++ b/board/sifive/fu540/uart.c > >Can we drop this, instead use the sifive uart driver directory? Will update in v2. > >> @@ -0,0 +1,64 @@ >> +// SPDX-License-Identifier: GPL-2.0+ >> +/* >> + * Copyright (c) 2019 SiFive, Inc >> + * >> + * Authors: >> + * Pragnesh Patel <pragnesh.pa...@sifive.com> >> + * Troy Benjegerdes <troy.benjeger...@sifive.com> >> + */ >> + >> +#include <stdatomic.h> >> +#include "include/fu540-memory-map.h" >> +#include "include/uart.h" >> + >> +void uart_putc(void *uartctrl, char c) >> +{ >> +#if __riscv_atomic >> + s32 r; >> + >> + do { >> + asm volatile ("amoor.w %0, %2, %1\n" : "=r" (r), >> + "+A" (_REG32(uartctrl, UART_REG_TXFIFO)) >> + : "r" (c) >> + ); >> + } while (r < 0); >> +#else >> + while ((int)_REG32(uartctrl, UART_REG_TXFIFO) < 0) >> + ; >> + _REG32(uartctrl, UART_REG_TXFIFO) = c; >> +#endif >> +} >> + >> +char uart_getc(void *uartctrl) >> +{ >> + s32 val = -1; >> + >> + while (val < 0) >> + val = (s32)_REG32(uartctrl, UART_REG_RXFIFO); >> + >> + return val & 0xFF; >> +} >> + >> +void uart_puts(void *uartctrl, const char *s) >> +{ >> + while (*s != '\0') >> + uart_putc(uartctrl, *s++); >> +} >> + >> +void uart_put_hex(void *uartctrl, u32 hex) >> +{ >> + int num_nibbles = sizeof(hex) * 2; >> + >> + for (int nibble_idx = num_nibbles - 1; nibble_idx >= 0; >> nibble_idx--) { >> + char nibble = (hex >> (nibble_idx * 4)) & 0xf; >> + >> + uart_putc(uartctrl, (nibble < 0xa) ? ('0' + nibble) : >> + ('a' + nibble - 0xa)); >> + } >> +} >> + >> +void uart_put_hex64(void *uartctrl, uint64_t hex) >> +{ >> + uart_put_hex(uartctrl, hex >> 32); >> + uart_put_hex(uartctrl, hex & 0xFFFFFFFF); >> +} >> diff --git a/configs/sifive_fu540_spl_defconfig >b/configs/sifive_fu540_spl_defconfig >> new file mode 100644 >> index 0000000000..6f9a70ee3e >> --- /dev/null >> +++ b/configs/sifive_fu540_spl_defconfig >> @@ -0,0 +1,23 @@ >> +CONFIG_RISCV=y >> +CONFIG_ENV_SIZE=0x20000 >> +CONFIG_NR_DRAM_BANKS=1 >> +CONFIG_TARGET_SIFIVE_FU540=y >> +CONFIG_ARCH_RV64I=y >> +CONFIG_RISCV_SMODE=y >> +CONFIG_DISTRO_DEFAULTS=y >> +CONFIG_FIT=y >> +CONFIG_MISC_INIT_R=y >> +CONFIG_DEFAULT_DEVICE_TREE="hifive-unleashed-a00" >> +CONFIG_DISPLAY_CPUINFO=y >> +CONFIG_DISPLAY_BOARDINFO=y >> +CONFIG_OF_SEPARATE=y >> +CONFIG_SPL_SEPARATE_BSS=y >> +CONFIG_SYS_RELOC_GD_ENV_ADDR=y >> +CONFIG_SPL=y >> +CONFIG_SPL_MMC_SUPPORT=y >> +CONFIG_SPL_SPI_SUPPORT=y >> +CONFIG_SPL_YMODEM_SUPPORT=y >> +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION=y >> +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION=1 >> +CONFIG_SPL_CLK=y >> +CONFIG_SPL_PAYLOAD="u-boot.itb" >> diff --git a/include/configs/sifive-fu540.h b/include/configs/sifive-fu540.h >> index 2756ed5a77..5afc7ddb66 100644 >> --- a/include/configs/sifive-fu540.h >> +++ b/include/configs/sifive-fu540.h >> @@ -11,6 +11,21 @@ >> >> #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 +39,7 @@ >> >> /* Environment options */ >> >> +#ifndef CONFIG_SPL_BUILD >> #define BOOT_TARGET_DEVICES(func) \ >> func(MMC, mmc, 0) \ >> func(DHCP, dhcp, na) >> @@ -43,5 +59,6 @@ >> #define CONFIG_PREBOOT \ >> "setenv fdt_addr ${fdtcontroladdr};" \ >> "fdt addr ${fdtcontroladdr};" >> +#endif >> >> #endif /* __CONFIG_H */ >> diff --git a/lib/Makefile b/lib/Makefile >> index 1fb650cd90..2d88c2ab5e 100644 >> --- a/lib/Makefile >> +++ b/lib/Makefile >> @@ -76,6 +76,7 @@ endif >> >> ifdef CONFIG_SPL_BUILD >> obj-$(CONFIG_SPL_YMODEM_SUPPORT) += crc16.o >> +obj-$(CONFIG_MMC_SPI) += crc7.o >> obj-$(CONFIG_$(SPL_TPL_)HASH_SUPPORT) += crc16.o >> obj-$(CONFIG_SPL_NET_SUPPORT) += net_utils.o >> endif > >One generic comment, the style in this patch is not aligned with U-Boot's. > >Regards, >Bin