[PATCH 3/3] riscv: sifive: fu540: add SPL configuration
Pragnesh Patel
pragnesh.patel at sifive.com
Mon Jan 13 15:54:05 CET 2020
>-----Original Message-----
>From: Bin Meng <bmeng.cn at gmail.com>
>Sent: 03 January 2020 21:05
>To: Pragnesh Patel <pragnesh.patel at sifive.com>
>Cc: U-Boot Mailing List <u-boot at lists.denx.de>; Rick Chen
><rick at andestech.com>; Paul Walmsley ( Sifive) <paul.walmsley at sifive.com>;
>Palmer Dabbelt ( Sifive) <palmer at sifive.com>; Anup Patel
><anup.patel at wdc.com>; Atish Patra <atish.patra at wdc.com>; Lukas Auer
><lukas.auer at aisec.fraunhofer.de>; AKASHI Takahiro
><takahiro.akashi at linaro.org>; Simon Glass <sjg at chromium.org>; Marek
>BehĂșn <marek.behun at nic.cz>; Simon Goldschmidt
><simon.k.r.goldschmidt at gmail.com>; Peng Fan <peng.fan at nxp.com>; Boris
>Brezillon <bbrezillon at kernel.org>; Alexander Graf <agraf at 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.patel at 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.patel at 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 at 0 {
>> + u-boot,dm-spl;
>> + status = "okay";
>> + cpu0_intc: interrupt-controller {
>> + u-boot,dm-spl;
>> + };
>> + };
>> + cpu1: cpu at 1 {
>> + u-boot,dm-spl;
>> + cpu1_intc: interrupt-controller {
>> + u-boot,dm-spl;
>> + };
>> + };
>> + cpu2: cpu at 2 {
>> + u-boot,dm-spl;
>> + cpu2_intc: interrupt-controller {
>> + u-boot,dm-spl;
>> + };
>> + };
>> + cpu3: cpu at 3 {
>> + u-boot,dm-spl;
>> + cpu3_intc: interrupt-controller {
>> + u-boot,dm-spl;
>> + };
>> + };
>> + cpu4: cpu at 4 {
>> + u-boot,dm-spl;
>> + cpu4_intc: interrupt-controller {
>> + u-boot,dm-spl;
>> + };
>> + };
>> + };
>> +
>> + soc {
>> + u-boot,dm-spl;
>> + clint at 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 at 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.patel at sifive.com>
>> + * Troy Benjegerdes <troy.benjegerdes at 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.patel at sifive.com>
>> + * Troy Benjegerdes <troy.benjegerdes at 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.patel at sifive.com>
>> + * Troy Benjegerdes <troy.benjegerdes at 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.patel at sifive.com>
>> + * Troy Benjegerdes <troy.benjegerdes at 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.patel at sifive.com>
>> + * Troy Benjegerdes <troy.benjegerdes at 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.patel at sifive.com>
>> + * Troy Benjegerdes <troy.benjegerdes at 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.patel at sifive.com>
>> + * Troy Benjegerdes <troy.benjegerdes at 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.patel at sifive.com>
>> + * Troy Benjegerdes <troy.benjegerdes at 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
More information about the U-Boot
mailing list