[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