1
0
mirror of https://xff.cz/git/u-boot/ synced 2025-09-28 22:11:16 +02:00
- Fixes 7e249bc13a: ("riscv: Move all SMP related SBI calls to
  SBI_v01") Move sbi_probe_extension() out of CONFIG_SBI_V01.
- SiFive FU540 support SPL.
This commit is contained in:
Tom Rini
2020-06-04 13:50:39 -04:00
35 changed files with 3039 additions and 131 deletions

View File

@@ -56,6 +56,7 @@ source "board/sifive/fu540/Kconfig"
# platform-specific options below # platform-specific options below
source "arch/riscv/cpu/ax25/Kconfig" source "arch/riscv/cpu/ax25/Kconfig"
source "arch/riscv/cpu/fu540/Kconfig"
source "arch/riscv/cpu/generic/Kconfig" source "arch/riscv/cpu/generic/Kconfig"
# architecture-specific options below # architecture-specific options below

View File

@@ -0,0 +1,15 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
config SIFIVE_FU540
bool
select ARCH_EARLY_INIT_R
imply CPU
imply CPU_RISCV
imply RISCV_TIMER
imply SIFIVE_CLINT if (RISCV_MMODE || SPL_RISCV_MMODE)
imply CMD_CPU
imply SPL_CPU_SUPPORT
imply SPL_OPENSBI
imply SPL_LOAD_FIT

View File

@@ -0,0 +1,11 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (C) 2020 SiFive, Inc
# Pragnesh Patel <pragnesh.patel@sifive.com>
ifeq ($(CONFIG_SPL_BUILD),y)
obj-y += spl.o
else
obj-y += dram.o
obj-y += cpu.o
endif

View File

@@ -0,0 +1,22 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
*/
#include <irq_func.h>
#include <asm/cache.h>
/*
* cleanup_before_linux() is called just before we call linux
* it prepares the processor for linux
*
* we disable interrupt and caches.
*/
int cleanup_before_linux(void)
{
disable_interrupts();
cache_flush();
return 0;
}

View File

@@ -0,0 +1,38 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
*/
#include <common.h>
#include <fdtdec.h>
#include <init.h>
#include <linux/sizes.h>
DECLARE_GLOBAL_DATA_PTR;
int dram_init(void)
{
return fdtdec_setup_mem_size_base();
}
int dram_init_banksize(void)
{
return fdtdec_setup_memory_banksize();
}
ulong board_get_usable_ram_top(ulong total_size)
{
#ifdef CONFIG_64BIT
/*
* Ensure that we run from first 4GB so that all
* addresses used by U-Boot are 32bit addresses.
*
* This in-turn ensures that 32bit DMA capable
* devices work fine because DMA mapping APIs will
* provide 32bit DMA addresses only.
*/
if (gd->ram_top > SZ_4G)
return SZ_4G;
#endif
return gd->ram_top;
}

View File

@@ -0,0 +1,23 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2020 SiFive, Inc
* Pragnesh Patel <pragnesh.patel@sifive.com>
*/
#include <dm.h>
#include <log.h>
int soc_spl_init(void)
{
int ret;
struct udevice *dev;
/* DDR init */
ret = uclass_get_device(UCLASS_RAM, 0, &dev);
if (ret) {
debug("DRAM init failed: %d\n", ret);
return ret;
}
return 0;
}

View File

@@ -72,6 +72,7 @@ SECTIONS
. = ALIGN(4); . = ALIGN(4);
_end = .; _end = .;
_image_binary_end = .;
.bss : { .bss : {
__bss_start = .; __bss_start = .;

View File

@@ -0,0 +1,89 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
* (C) Copyright 2019 SiFive, Inc
*/
/ {
cpus {
assigned-clocks = <&prci PRCI_CLK_COREPLL>;
assigned-clock-rates = <1000000000>;
u-boot,dm-spl;
cpu0: cpu@0 {
clocks = <&prci PRCI_CLK_COREPLL>;
u-boot,dm-spl;
status = "okay";
cpu0_intc: interrupt-controller {
u-boot,dm-spl;
};
};
cpu1: cpu@1 {
clocks = <&prci PRCI_CLK_COREPLL>;
u-boot,dm-spl;
cpu1_intc: interrupt-controller {
u-boot,dm-spl;
};
};
cpu2: cpu@2 {
clocks = <&prci PRCI_CLK_COREPLL>;
u-boot,dm-spl;
cpu2_intc: interrupt-controller {
u-boot,dm-spl;
};
};
cpu3: cpu@3 {
clocks = <&prci PRCI_CLK_COREPLL>;
u-boot,dm-spl;
cpu3_intc: interrupt-controller {
u-boot,dm-spl;
};
};
cpu4: cpu@4 {
clocks = <&prci PRCI_CLK_COREPLL>;
u-boot,dm-spl;
cpu4_intc: interrupt-controller {
u-boot,dm-spl;
};
};
};
soc {
u-boot,dm-spl;
otp: otp@10070000 {
compatible = "sifive,fu540-c000-otp";
reg = <0x0 0x10070000 0x0 0x0FFF>;
fuse-count = <0x1000>;
};
clint@2000000 {
compatible = "riscv,clint0";
interrupts-extended = <&cpu0_intc 3 &cpu0_intc 7 &cpu1_intc 3 &cpu1_intc 7 &cpu2_intc 3 &cpu2_intc 7 &cpu3_intc 3 &cpu3_intc 7 &cpu4_intc 3 &cpu4_intc 7>;
reg = <0x0 0x2000000 0x0 0xc0000>;
u-boot,dm-spl;
};
dmc: dmc@100b0000 {
compatible = "sifive,fu540-c000-ddr";
reg = <0x0 0x100b0000 0x0 0x0800
0x0 0x100b2000 0x0 0x2000
0x0 0x100b8000 0x0 0x0fff>;
clocks = <&prci PRCI_CLK_DDRPLL>;
clock-frequency = <933333324>;
u-boot,dm-spl;
};
};
};
&prci {
u-boot,dm-spl;
};
&uart0 {
u-boot,dm-spl;
};
&qspi2 {
u-boot,dm-spl;
};
&eth0 {
assigned-clocks = <&prci PRCI_CLK_GEMGXLPLL>;
assigned-clock-rates = <125000000>;
};

View File

@@ -54,6 +54,7 @@
reg = <1>; reg = <1>;
riscv,isa = "rv64imafdc"; riscv,isa = "rv64imafdc";
tlb-split; tlb-split;
next-level-cache = <&l2cache>;
cpu1_intc: interrupt-controller { cpu1_intc: interrupt-controller {
#interrupt-cells = <1>; #interrupt-cells = <1>;
compatible = "riscv,cpu-intc"; compatible = "riscv,cpu-intc";
@@ -77,6 +78,7 @@
reg = <2>; reg = <2>;
riscv,isa = "rv64imafdc"; riscv,isa = "rv64imafdc";
tlb-split; tlb-split;
next-level-cache = <&l2cache>;
cpu2_intc: interrupt-controller { cpu2_intc: interrupt-controller {
#interrupt-cells = <1>; #interrupt-cells = <1>;
compatible = "riscv,cpu-intc"; compatible = "riscv,cpu-intc";
@@ -100,6 +102,7 @@
reg = <3>; reg = <3>;
riscv,isa = "rv64imafdc"; riscv,isa = "rv64imafdc";
tlb-split; tlb-split;
next-level-cache = <&l2cache>;
cpu3_intc: interrupt-controller { cpu3_intc: interrupt-controller {
#interrupt-cells = <1>; #interrupt-cells = <1>;
compatible = "riscv,cpu-intc"; compatible = "riscv,cpu-intc";
@@ -123,6 +126,7 @@
reg = <4>; reg = <4>;
riscv,isa = "rv64imafdc"; riscv,isa = "rv64imafdc";
tlb-split; tlb-split;
next-level-cache = <&l2cache>;
cpu4_intc: interrupt-controller { cpu4_intc: interrupt-controller {
#interrupt-cells = <1>; #interrupt-cells = <1>;
compatible = "riscv,cpu-intc"; compatible = "riscv,cpu-intc";
@@ -162,6 +166,13 @@
clocks = <&prci PRCI_CLK_TLCLK>; clocks = <&prci PRCI_CLK_TLCLK>;
status = "disabled"; status = "disabled";
}; };
dma: dma@3000000 {
compatible = "sifive,fu540-c000-pdma";
reg = <0x0 0x3000000 0x0 0x8000>;
interrupt-parent = <&plic0>;
interrupts = <23 24 25 26 27 28 29 30>;
#dma-cells = <1>;
};
uart1: serial@10011000 { uart1: serial@10011000 {
compatible = "sifive,fu540-c000-uart", "sifive,uart0"; compatible = "sifive,fu540-c000-uart", "sifive,uart0";
reg = <0x0 0x10011000 0x0 0x1000>; reg = <0x0 0x10011000 0x0 0x1000>;
@@ -246,6 +257,30 @@
#pwm-cells = <3>; #pwm-cells = <3>;
status = "disabled"; status = "disabled";
}; };
l2cache: cache-controller@2010000 {
compatible = "sifive,fu540-c000-ccache", "cache";
cache-block-size = <64>;
cache-level = <2>;
cache-sets = <1024>;
cache-size = <2097152>;
cache-unified;
interrupt-parent = <&plic0>;
interrupts = <1 2 3>;
reg = <0x0 0x2010000 0x0 0x1000>;
};
gpio: gpio@10060000 {
compatible = "sifive,fu540-c000-gpio", "sifive,gpio0";
interrupt-parent = <&plic0>;
interrupts = <7>, <8>, <9>, <10>, <11>, <12>, <13>,
<14>, <15>, <16>, <17>, <18>, <19>, <20>,
<21>, <22>;
reg = <0x0 0x10060000 0x0 0x1000>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
clocks = <&prci PRCI_CLK_TLCLK>;
status = "disabled";
};
}; };
}; };

File diff suppressed because it is too large Load Diff

View File

@@ -3,9 +3,31 @@
* Copyright (C) 2019 Jagan Teki <jagan@amarulasolutions.com> * Copyright (C) 2019 Jagan Teki <jagan@amarulasolutions.com>
*/ */
#include "fu540-c000-u-boot.dtsi"
#include "fu540-hifive-unleashed-a00-ddr.dtsi"
/ { / {
aliases { aliases {
spi0 = &qspi0; spi0 = &qspi0;
spi2 = &qspi2; spi2 = &qspi2;
}; };
hfclk {
u-boot,dm-spl;
};
rtcclk {
u-boot,dm-spl;
};
};
&qspi2 {
mmc@0 {
u-boot,dm-spl;
};
};
&gpio {
u-boot,dm-spl;
}; };

View File

@@ -2,6 +2,7 @@
/* Copyright (c) 2018-2019 SiFive, Inc */ /* Copyright (c) 2018-2019 SiFive, Inc */
#include "fu540-c000.dtsi" #include "fu540-c000.dtsi"
#include <dt-bindings/gpio/gpio.h>
/* Clock frequency (in Hz) of the PCB crystal for rtcclk */ /* Clock frequency (in Hz) of the PCB crystal for rtcclk */
#define RTCCLK_FREQ 1000000 #define RTCCLK_FREQ 1000000
@@ -41,6 +42,10 @@
clock-frequency = <RTCCLK_FREQ>; clock-frequency = <RTCCLK_FREQ>;
clock-output-names = "rtcclk"; clock-output-names = "rtcclk";
}; };
gpio-restart {
compatible = "gpio-restart";
gpios = <&gpio 10 GPIO_ACTIVE_LOW>;
};
}; };
&uart0 { &uart0 {
@@ -94,3 +99,7 @@
&pwm1 { &pwm1 {
status = "okay"; status = "okay";
}; };
&gpio {
status = "okay";
};

View File

@@ -0,0 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (c) 2020 SiFive Inc
*
* Authors:
* Pragnesh Patel <pragnesh.patel@sifive.com>
*/
#ifndef __CLK_SIFIVE_H
#define __CLK_SIFIVE_H
/* Note: This is a placeholder header for driver compilation. */
#endif

View File

@@ -0,0 +1,38 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2019 SiFive, Inc.
*/
#ifndef _GPIO_SIFIVE_H
#define _GPIO_SIFIVE_H
#define GPIO_INPUT_VAL 0x00
#define GPIO_INPUT_EN 0x04
#define GPIO_OUTPUT_EN 0x08
#define GPIO_OUTPUT_VAL 0x0C
#define GPIO_RISE_IE 0x18
#define GPIO_RISE_IP 0x1C
#define GPIO_FALL_IE 0x20
#define GPIO_FALL_IP 0x24
#define GPIO_HIGH_IE 0x28
#define GPIO_HIGH_IP 0x2C
#define GPIO_LOW_IE 0x30
#define GPIO_LOW_IP 0x34
#define GPIO_OUTPUT_XOR 0x40
#define NR_GPIOS 16
enum gpio_state {
LOW,
HIGH
};
/* Details about a GPIO bank */
struct sifive_gpio_platdata {
void *base; /* address of registers in physical memory */
};
#define SIFIVE_GENERIC_GPIO_NR(port, index) \
(((port) * NR_GPIOS) + ((index) & (NR_GPIOS - 1)))
#endif /* _GPIO_SIFIVE_H */

View File

@@ -0,0 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2020 SiFive, Inc.
*
* Authors:
* Pragnesh Patel <pragnesh.patel@sifve.com>
*/
#ifndef _SPL_SIFIVE_H
#define _SPL_SIFIVE_H
int soc_spl_init(void);
#endif /* _SPL_SIFIVE_H */

View File

@@ -77,7 +77,6 @@ enum sbi_ext_rfence_fid {
#define SBI_FID_REMOTE_SFENCE_VMA_ASID SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID #define SBI_FID_REMOTE_SFENCE_VMA_ASID SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID
#endif #endif
#define SBI_SPEC_VERSION_DEFAULT 0x1
#define SBI_SPEC_VERSION_MAJOR_SHIFT 24 #define SBI_SPEC_VERSION_MAJOR_SHIFT 24
#define SBI_SPEC_VERSION_MAJOR_MASK 0x7f #define SBI_SPEC_VERSION_MAJOR_MASK 0x7f
#define SBI_SPEC_VERSION_MINOR_MASK 0xffffff #define SBI_SPEC_VERSION_MINOR_MASK 0xffffff
@@ -90,7 +89,6 @@ enum sbi_ext_rfence_fid {
#define SBI_ERR_DENIED -4 #define SBI_ERR_DENIED -4
#define SBI_ERR_INVALID_ADDRESS -5 #define SBI_ERR_INVALID_ADDRESS -5
extern unsigned long sbi_spec_version;
struct sbiret { struct sbiret {
long error; long error;
long value; long value;

View File

@@ -11,9 +11,6 @@
#include <asm/encoding.h> #include <asm/encoding.h>
#include <asm/sbi.h> #include <asm/sbi.h>
/* default SBI version is 0.1 */
unsigned long sbi_spec_version = SBI_SPEC_VERSION_DEFAULT;
struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0, struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
unsigned long arg1, unsigned long arg2, unsigned long arg1, unsigned long arg2,
unsigned long arg3, unsigned long arg4, unsigned long arg3, unsigned long arg4,
@@ -56,6 +53,25 @@ void sbi_set_timer(uint64_t stime_value)
#endif #endif
} }
/**
* sbi_probe_extension() - Check if an SBI extension ID is supported or not.
* @extid: The extension ID to be probed.
*
* Return: Extension specific nonzero value f yes, -ENOTSUPP otherwise.
*/
int sbi_probe_extension(int extid)
{
struct sbiret ret;
ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_PROBE_EXT, extid,
0, 0, 0, 0, 0);
if (!ret.error)
if (ret.value)
return ret.value;
return -ENOTSUPP;
}
#ifdef CONFIG_SBI_V01 #ifdef CONFIG_SBI_V01
/** /**
@@ -165,22 +181,4 @@ void sbi_remote_sfence_vma_asid(const unsigned long *hart_mask,
(unsigned long)hart_mask, start, size, asid, 0, 0); (unsigned long)hart_mask, start, size, asid, 0, 0);
} }
/**
* sbi_probe_extension() - Check if an SBI extension ID is supported or not.
* @extid: The extension ID to be probed.
*
* Return: Extension specific nonzero value f yes, -ENOTSUPP otherwise.
*/
int sbi_probe_extension(int extid)
{
struct sbiret ret;
ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_PROBE_EXT, extid,
0, 0, 0, 0, 0);
if (!ret.error)
if (ret.value)
return ret.value;
return -ENOTSUPP;
}
#endif /* CONFIG_SBI_V01 */ #endif /* CONFIG_SBI_V01 */

View File

@@ -7,23 +7,35 @@ config SYS_VENDOR
default "sifive" default "sifive"
config SYS_CPU config SYS_CPU
default "generic" default "fu540"
config SYS_CONFIG_NAME config SYS_CONFIG_NAME
default "sifive-fu540" default "sifive-fu540"
config SYS_TEXT_BASE config SYS_TEXT_BASE
default 0x80200000 if SPL
default 0x80000000 if !RISCV_SMODE default 0x80000000 if !RISCV_SMODE
default 0x80200000 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 config BOARD_SPECIFIC_OPTIONS # dummy
def_bool y def_bool y
select GENERIC_RISCV select SIFIVE_FU540
select SUPPORT_SPL
select RAM
select SPL_RAM if SPL
imply CMD_DHCP imply CMD_DHCP
imply CMD_EXT2 imply CMD_EXT2
imply CMD_EXT4 imply CMD_EXT4
imply CMD_FAT imply CMD_FAT
imply CMD_FS_GENERIC imply CMD_FS_GENERIC
imply CMD_GPT
imply PARTITION_TYPE_GUID
imply CMD_NET imply CMD_NET
imply CMD_PING imply CMD_PING
imply CMD_SF imply CMD_SF
@@ -51,5 +63,7 @@ config BOARD_SPECIFIC_OPTIONS # dummy
imply SIFIVE_GPIO imply SIFIVE_GPIO
imply CMD_GPIO imply CMD_GPIO
imply SMP imply SMP
imply MISC
imply SIFIVE_OTP
endif endif

View File

@@ -3,3 +3,7 @@
# Copyright (c) 2019 Western Digital Corporation or its affiliates. # Copyright (c) 2019 Western Digital Corporation or its affiliates.
obj-y += fu540.o obj-y += fu540.o
ifdef CONFIG_SPL_BUILD
obj-y += spl.o
endif

View File

@@ -6,101 +6,69 @@
* Anup Patel <anup.patel@wdc.com> * Anup Patel <anup.patel@wdc.com>
*/ */
#include <common.h>
#include <dm.h> #include <dm.h>
#include <env.h> #include <env.h>
#include <init.h> #include <init.h>
#include <log.h>
#include <linux/bug.h> #include <linux/bug.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/io.h> #include <linux/io.h>
#include <misc.h>
#include <spl.h>
/*
* This define is a value used for error/unknown serial.
* If we really care about distinguishing errors and 0 is
* valid, we'll need a different one.
*/
#define ERROR_READING_SERIAL_NUMBER 0
#ifdef CONFIG_MISC_INIT_R #ifdef CONFIG_MISC_INIT_R
#define FU540_OTP_BASE_ADDR 0x10070000 #if CONFIG_IS_ENABLED(SIFIVE_OTP)
static u32 otp_read_serialnum(struct udevice *dev)
struct fu540_otp_regs {
u32 pa; /* Address input */
u32 paio; /* Program address input */
u32 pas; /* Program redundancy cell selection input */
u32 pce; /* OTP Macro enable input */
u32 pclk; /* Clock input */
u32 pdin; /* Write data input */
u32 pdout; /* Read data output */
u32 pdstb; /* Deep standby mode enable input (active low) */
u32 pprog; /* Program mode enable input */
u32 ptc; /* Test column enable input */
u32 ptm; /* Test mode enable input */
u32 ptm_rep;/* Repair function test mode enable input */
u32 ptr; /* Test row enable input */
u32 ptrim; /* Repair function enable input */
u32 pwe; /* Write enable input (defines program cycle) */
} __packed;
#define BYTES_PER_FUSE 4
#define NUM_FUSES 0x1000
static int fu540_otp_read(int offset, void *buf, int size)
{
struct fu540_otp_regs *regs = (void __iomem *)FU540_OTP_BASE_ADDR;
unsigned int i;
int fuseidx = offset / BYTES_PER_FUSE;
int fusecount = size / BYTES_PER_FUSE;
u32 fusebuf[fusecount];
/* check bounds */
if (offset < 0 || size < 0)
return -EINVAL;
if (fuseidx >= NUM_FUSES)
return -EINVAL;
if ((fuseidx + fusecount) > NUM_FUSES)
return -EINVAL;
/* init OTP */
writel(0x01, &regs->pdstb); /* wake up from stand-by */
writel(0x01, &regs->ptrim); /* enable repair function */
writel(0x01, &regs->pce); /* enable input */
/* read all requested fuses */
for (i = 0; i < fusecount; i++, fuseidx++) {
writel(fuseidx, &regs->pa);
/* cycle clock to read */
writel(0x01, &regs->pclk);
mdelay(1);
writel(0x00, &regs->pclk);
mdelay(1);
/* read the value */
fusebuf[i] = readl(&regs->pdout);
}
/* shut down */
writel(0, &regs->pce);
writel(0, &regs->ptrim);
writel(0, &regs->pdstb);
/* copy out */
memcpy(buf, fusebuf, size);
return 0;
}
static u32 fu540_read_serialnum(void)
{ {
int ret; int ret;
u32 serial[2] = {0}; u32 serial[2] = {0};
for (int i = 0xfe * 4; i > 0; i -= 8) { for (int i = 0xfe * 4; i > 0; i -= 8) {
ret = fu540_otp_read(i, serial, sizeof(serial)); ret = misc_read(dev, i, serial, sizeof(serial));
if (ret) {
printf("%s: error reading from OTP\n", __func__); if (ret != sizeof(serial)) {
printf("%s: error reading serial from OTP\n", __func__);
break; break;
} }
if (serial[0] == ~serial[1]) if (serial[0] == ~serial[1])
return serial[0]; return serial[0];
} }
return 0; return ERROR_READING_SERIAL_NUMBER;
}
#endif
static u32 fu540_read_serialnum(void)
{
u32 serial = ERROR_READING_SERIAL_NUMBER;
#if CONFIG_IS_ENABLED(SIFIVE_OTP)
struct udevice *dev;
int ret;
/* init OTP */
ret = uclass_get_device_by_driver(UCLASS_MISC,
DM_GET_DRIVER(sifive_otp), &dev);
if (ret) {
debug("%s: could not find otp device\n", __func__);
return serial;
}
/* read serial from OTP and set env var */
serial = otp_read_serialnum(dev);
#endif
return serial;
} }
static void fu540_setup_macaddr(u32 serialnum) static void fu540_setup_macaddr(u32 serialnum)
@@ -150,3 +118,23 @@ int board_init(void)
return 0; return 0;
} }
#ifdef CONFIG_SPL
u32 spl_boot_device(void)
{
#ifdef CONFIG_SPL_MMC_SUPPORT
return BOOT_DEVICE_MMC1;
#else
puts("Unknown boot device\n");
hang();
#endif
}
#endif
#ifdef CONFIG_SPL_LOAD_FIT
int board_fit_config_name_match(const char *name)
{
/* boot using first FIT config */
return 0;
}
#endif

74
board/sifive/fu540/spl.c Normal file
View File

@@ -0,0 +1,74 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2019 SiFive, Inc
*
* Authors:
* Pragnesh Patel <pragnesh.patel@sifive.com>
*/
#include <init.h>
#include <spl.h>
#include <misc.h>
#include <log.h>
#include <linux/delay.h>
#include <asm/gpio.h>
#include <asm/arch/gpio.h>
#include <asm/arch/spl.h>
#define GEM_PHY_RESET SIFIVE_GENERIC_GPIO_NR(0, 12)
int init_clk_and_ddr(void)
{
int ret;
ret = soc_spl_init();
if (ret) {
debug("FU540 SPL init failed: %d\n", ret);
return ret;
}
/*
* GEMGXL init VSC8541 PHY reset sequence;
* leave pull-down active for 2ms
*/
udelay(2000);
ret = gpio_request(GEM_PHY_RESET, "gem_phy_reset");
if (ret) {
debug("gem_phy_reset gpio request failed: %d\n", ret);
return ret;
}
/* Set GPIO 12 (PHY NRESET) */
ret = gpio_direction_output(GEM_PHY_RESET, 1);
if (ret) {
debug("gem_phy_reset gpio direction set failed: %d\n", ret);
return ret;
}
udelay(1);
/* Reset PHY again to enter unmanaged mode */
gpio_set_value(GEM_PHY_RESET, 0);
udelay(1);
gpio_set_value(GEM_PHY_RESET, 1);
mdelay(15);
return 0;
}
void board_init_f(ulong dummy)
{
int ret;
ret = spl_early_init();
if (ret)
panic("spl_early_init() failed: %d\n", ret);
arch_cpu_init_dm();
preloader_console_init();
ret = init_clk_and_ddr();
if (ret)
panic("init_clk_and_ddr() failed: %d\n", ret);
}

View File

@@ -308,7 +308,7 @@ config SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
ARCH_MX6 || ARCH_MX7 || \ ARCH_MX6 || ARCH_MX7 || \
ARCH_ROCKCHIP || ARCH_MVEBU || ARCH_SOCFPGA || \ ARCH_ROCKCHIP || ARCH_MVEBU || ARCH_SOCFPGA || \
ARCH_AT91 || ARCH_ZYNQ || ARCH_KEYSTONE || OMAP34XX || \ ARCH_AT91 || ARCH_ZYNQ || ARCH_KEYSTONE || OMAP34XX || \
OMAP44XX || OMAP54XX || AM33XX || AM43XX OMAP44XX || OMAP54XX || AM33XX || AM43XX || TARGET_SIFIVE_FU540
help help
Use sector number for specifying U-Boot location on MMC/SD in Use sector number for specifying U-Boot location on MMC/SD in
raw mode. raw mode.
@@ -325,6 +325,7 @@ config SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR
default 0x300 if ARCH_ZYNQ || ARCH_KEYSTONE || OMAP34XX || OMAP44XX || \ default 0x300 if ARCH_ZYNQ || ARCH_KEYSTONE || OMAP34XX || OMAP44XX || \
OMAP54XX || AM33XX || AM43XX || ARCH_K3 OMAP54XX || AM33XX || AM43XX || ARCH_K3
default 0x4000 if ARCH_ROCKCHIP default 0x4000 if ARCH_ROCKCHIP
default 0x822 if TARGET_SIFIVE_FU540
help help
Address on the MMC to load U-Boot from, when the MMC is being used Address on the MMC to load U-Boot from, when the MMC is being used
in raw mode. Units: MMC sectors (1 sector = 512 bytes). in raw mode. Units: MMC sectors (1 sector = 512 bytes).

View File

@@ -1,6 +1,11 @@
CONFIG_RISCV=y CONFIG_RISCV=y
CONFIG_SPL_GPIO_SUPPORT=y
CONFIG_SYS_MALLOC_F_LEN=0x3000
CONFIG_ENV_SIZE=0x20000 CONFIG_ENV_SIZE=0x20000
CONFIG_SPL_MMC_SUPPORT=y
CONFIG_NR_DRAM_BANKS=1 CONFIG_NR_DRAM_BANKS=1
CONFIG_SPL=y
CONFIG_SPL_SPI_SUPPORT=y
CONFIG_TARGET_SIFIVE_FU540=y CONFIG_TARGET_SIFIVE_FU540=y
CONFIG_ARCH_RV64I=y CONFIG_ARCH_RV64I=y
CONFIG_RISCV_SMODE=y CONFIG_RISCV_SMODE=y
@@ -9,7 +14,10 @@ CONFIG_FIT=y
CONFIG_MISC_INIT_R=y CONFIG_MISC_INIT_R=y
CONFIG_DISPLAY_CPUINFO=y CONFIG_DISPLAY_CPUINFO=y
CONFIG_DISPLAY_BOARDINFO=y CONFIG_DISPLAY_BOARDINFO=y
CONFIG_SPL_SEPARATE_BSS=y
CONFIG_SPL_YMODEM_SUPPORT=y
CONFIG_OF_BOARD_FIXUP=y CONFIG_OF_BOARD_FIXUP=y
CONFIG_DEFAULT_DEVICE_TREE="hifive-unleashed-a00" CONFIG_DEFAULT_DEVICE_TREE="hifive-unleashed-a00"
CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_SYS_RELOC_GD_ENV_ADDR=y
CONFIG_SPL_CLK=y
CONFIG_DM_MTD=y CONFIG_DM_MTD=y

View File

@@ -20,16 +20,8 @@ The support for following drivers are already enabled:
4. SiFive SPI Driver. 4. SiFive SPI Driver.
5. MMC SPI Driver for MMC/SD support. 5. MMC SPI Driver for MMC/SD support.
TODO: Booting from MMC using FSBL
---------------------------
1. U-Boot expects the serial console device entry to be present under /chosen
DT node. Without a serial console U-Boot will panic. Example:
.. code-block:: none
chosen {
stdout-path = "/soc/serial@10010000:115200";
};
Building Building
-------- --------
@@ -57,7 +49,7 @@ firmware. We need to compile OpenSBI with below command:
.. code-block:: none .. code-block:: none
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<path to u-boot-dtb.bin> make PLATFORM=generic FW_PAYLOAD_PATH=<path to u-boot-dtb.bin>
More detailed description of steps required to build FW_PAYLOAD firmware More detailed description of steps required to build FW_PAYLOAD firmware
is beyond the scope of this document. Please refer OpenSBI documenation. is beyond the scope of this document. Please refer OpenSBI documenation.
@@ -420,3 +412,124 @@ as well.
Please press Enter to activate this console. Please press Enter to activate this console.
/ # / #
Booting from MMC using U-Boot SPL
---------------------------------
Building
--------
Before building U-Boot SPL, OpenSBI must be built first. OpenSBI can be
cloned and built for FU540 as below:
.. code-block:: console
git clone https://github.com/riscv/opensbi.git
cd opensbi
make PLATFORM=generic
export OPENSBI=<path to opensbi/build/platform/generic/firmware/fw_dynamic.bin>
Now build the U-Boot SPL and U-Boot proper
.. code-block:: console
cd <U-Boot-dir>
make sifive_fu540_defconfig
make
This will generate spl/u-boot-spl.bin and FIT image (u-boot.itb)
Flashing
--------
ZSBL loads the U-Boot SPL (u-boot-spl.bin) from a partition with GUID type
5B193300-FC78-40CD-8002-E86C45580B47
U-Boot SPL expects a U-Boot FIT image (u-boot.itb) from a partition with GUID
type 2E54B353-1271-4842-806F-E436D6AF6985
FIT image (u-boot.itb) is a combination of fw_dynamic.bin, u-boot-nodtb.bin and
device tree blob (hifive-unleashed-a00.dtb)
Format the SD card (make sure the disk has GPT, otherwise use gdisk to switch)
.. code-block:: none
# sudo sgdisk --clear \
> --set-alignment=2 \
> --new=1:34:2081 --change-name=1:loader1 --typecode=1:5B193300-FC78-40CD-8002-E86C45580B47 \
> --new=2:2082:10273 --change-name=2:loader2 --typecode=2:2E54B353-1271-4842-806F-E436D6AF6985 \
> --new=3:10274: --change-name=3:rootfs --typecode=3:0FC63DAF-8483-4772-8E79-3D69D8477DE4 \
> /dev/sda
Program the SD card
.. code-block:: none
sudo dd if=spl/u-boot-spl.bin of=/dev/sda seek=34
sudo dd if=u-boot.itb of=/dev/sda seek=2082
Booting
-------
Once you plugin the sdcard and power up, you should see the U-Boot prompt.
Sample boot log from HiFive Unleashed board
-------------------------------------------
.. code-block:: none
U-Boot SPL 2020.04-rc2-00109-g63efc7e07e-dirty (Apr 30 2020 - 13:52:36 +0530)
Trying to boot from MMC1
U-Boot 2020.04-rc2-00109-g63efc7e07e-dirty (Apr 30 2020 - 13:52:36 +0530)
CPU: rv64imafdc
Model: SiFive HiFive Unleashed A00
DRAM: 8 GiB
MMC: spi@10050000:mmc@0: 0
In: serial@10010000
Out: serial@10010000
Err: serial@10010000
Net: eth0: ethernet@10090000
Hit any key to stop autoboot: 0
=> version
U-Boot 2020.04-rc2-00109-g63efc7e07e-dirty (Apr 30 2020 - 13:52:36 +0530)
riscv64-unknown-linux-gnu-gcc (crosstool-NG 1.24.0.37-3f461da) 9.2.0
GNU ld (crosstool-NG 1.24.0.37-3f461da) 2.32
=> mmc info
Device: spi@10050000:mmc@0
Manufacturer ID: 3
OEM: 5344
Name: SC16G
Bus Speed: 20000000
Mode: SD Legacy
Rd Block Len: 512
SD version 2.0
High Capacity: Yes
Capacity: 14.8 GiB
Bus Width: 1-bit
Erase Group Size: 512 Bytes
=> mmc part
Partition Map for MMC device 0 -- Partition Type: EFI
Part Start LBA End LBA Name
Attributes
Type GUID
Partition GUID
1 0x00000022 0x00000821 "loader1"
attrs: 0x0000000000000000
type: 5b193300-fc78-40cd-8002-e86c45580b47
guid: 66e2b5d2-74db-4df8-ad6f-694b3617f87f
2 0x00000822 0x00002821 "loader2"
attrs: 0x0000000000000000
type: 2e54b353-1271-4842-806f-e436d6af6985
guid: 8befaeaf-bca0-435d-b002-e201f37c0a2f
3 0x00002822 0x01dacbde "rootfs"
attrs: 0x0000000000000000
type: 0fc63daf-8483-4772-8e79-3d69d8477de4
type: linux
guid: 9faa81b6-39b1-4418-af5e-89c48f29c20d

View File

@@ -69,6 +69,11 @@
#define PRCI_COREPLLCFG0_LOCK_SHIFT 31 #define PRCI_COREPLLCFG0_LOCK_SHIFT 31
#define PRCI_COREPLLCFG0_LOCK_MASK (0x1 << PRCI_COREPLLCFG0_LOCK_SHIFT) #define PRCI_COREPLLCFG0_LOCK_MASK (0x1 << PRCI_COREPLLCFG0_LOCK_SHIFT)
/* COREPLLCFG1 */
#define PRCI_COREPLLCFG1_OFFSET 0x8
#define PRCI_COREPLLCFG1_CKE_SHIFT 31
#define PRCI_COREPLLCFG1_CKE_MASK (0x1 << PRCI_COREPLLCFG1_CKE_SHIFT)
/* DDRPLLCFG0 */ /* DDRPLLCFG0 */
#define PRCI_DDRPLLCFG0_OFFSET 0xc #define PRCI_DDRPLLCFG0_OFFSET 0xc
#define PRCI_DDRPLLCFG0_DIVR_SHIFT 0 #define PRCI_DDRPLLCFG0_DIVR_SHIFT 0
@@ -88,7 +93,7 @@
/* DDRPLLCFG1 */ /* DDRPLLCFG1 */
#define PRCI_DDRPLLCFG1_OFFSET 0x10 #define PRCI_DDRPLLCFG1_OFFSET 0x10
#define PRCI_DDRPLLCFG1_CKE_SHIFT 24 #define PRCI_DDRPLLCFG1_CKE_SHIFT 31
#define PRCI_DDRPLLCFG1_CKE_MASK (0x1 << PRCI_DDRPLLCFG1_CKE_SHIFT) #define PRCI_DDRPLLCFG1_CKE_MASK (0x1 << PRCI_DDRPLLCFG1_CKE_SHIFT)
/* GEMGXLPLLCFG0 */ /* GEMGXLPLLCFG0 */
@@ -115,7 +120,7 @@
/* GEMGXLPLLCFG1 */ /* GEMGXLPLLCFG1 */
#define PRCI_GEMGXLPLLCFG1_OFFSET 0x20 #define PRCI_GEMGXLPLLCFG1_OFFSET 0x20
#define PRCI_GEMGXLPLLCFG1_CKE_SHIFT 24 #define PRCI_GEMGXLPLLCFG1_CKE_SHIFT 31
#define PRCI_GEMGXLPLLCFG1_CKE_MASK (0x1 << PRCI_GEMGXLPLLCFG1_CKE_SHIFT) #define PRCI_GEMGXLPLLCFG1_CKE_MASK (0x1 << PRCI_GEMGXLPLLCFG1_CKE_SHIFT)
/* CORECLKSEL */ /* CORECLKSEL */
@@ -148,6 +153,12 @@
#define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK \ #define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK \
(0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT) (0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT)
/* PROCMONCFG */
#define PRCI_PROCMONCFG_OFFSET 0xF0
#define PRCI_PROCMONCFG_CORE_CLOCK_SHIFT 24
#define PRCI_PROCMONCFG_CORE_CLOCK_MASK \
(0x1 << PRCI_PROCMONCFG_CORE_CLOCK_SHIFT)
/* /*
* Private structures * Private structures
*/ */
@@ -171,6 +182,8 @@ struct __prci_data {
* @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL) * @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL)
* @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL) * @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL)
* @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address * @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address
* @cfg1_offs: WRPLL CFG1 register offset (in bytes) from the PRCI base address
* @release_reset: fn ptr to code to release clock reset
* *
* @enable_bypass and @disable_bypass are used for WRPLL instances * @enable_bypass and @disable_bypass are used for WRPLL instances
* that contain a separate external glitchless clock mux downstream * that contain a separate external glitchless clock mux downstream
@@ -181,6 +194,8 @@ struct __prci_wrpll_data {
void (*enable_bypass)(struct __prci_data *pd); void (*enable_bypass)(struct __prci_data *pd);
void (*disable_bypass)(struct __prci_data *pd); void (*disable_bypass)(struct __prci_data *pd);
u8 cfg0_offs; u8 cfg0_offs;
u8 cfg1_offs;
void (*release_reset)(struct __prci_data *pd);
}; };
struct __prci_clock; struct __prci_clock;
@@ -195,6 +210,7 @@ struct __prci_clock_ops {
unsigned long *parent_rate); unsigned long *parent_rate);
unsigned long (*recalc_rate)(struct __prci_clock *pc, unsigned long (*recalc_rate)(struct __prci_clock *pc,
unsigned long parent_rate); unsigned long parent_rate);
int (*enable_clk)(struct __prci_clock *pc, bool enable);
}; };
/** /**
@@ -317,7 +333,7 @@ static u32 __prci_wrpll_pack(const struct wrpll_cfg *c)
} }
/** /**
* __prci_wrpll_read_cfg() - read the WRPLL configuration from the PRCI * __prci_wrpll_read_cfg0() - read the WRPLL configuration from the PRCI
* @pd: PRCI context * @pd: PRCI context
* @pwd: PRCI WRPLL metadata * @pwd: PRCI WRPLL metadata
* *
@@ -328,14 +344,14 @@ static u32 __prci_wrpll_pack(const struct wrpll_cfg *c)
* Context: Any context. Caller must prevent the records pointed to by * Context: Any context. Caller must prevent the records pointed to by
* @pd and @pwd from changing during execution. * @pd and @pwd from changing during execution.
*/ */
static void __prci_wrpll_read_cfg(struct __prci_data *pd, static void __prci_wrpll_read_cfg0(struct __prci_data *pd,
struct __prci_wrpll_data *pwd) struct __prci_wrpll_data *pwd)
{ {
__prci_wrpll_unpack(&pwd->c, __prci_readl(pd, pwd->cfg0_offs)); __prci_wrpll_unpack(&pwd->c, __prci_readl(pd, pwd->cfg0_offs));
} }
/** /**
* __prci_wrpll_write_cfg() - write WRPLL configuration into the PRCI * __prci_wrpll_write_cfg0() - write WRPLL configuration into the PRCI
* @pd: PRCI context * @pd: PRCI context
* @pwd: PRCI WRPLL metadata * @pwd: PRCI WRPLL metadata
* @c: WRPLL configuration record to write * @c: WRPLL configuration record to write
@@ -348,7 +364,7 @@ static void __prci_wrpll_read_cfg(struct __prci_data *pd,
* Context: Any context. Caller must prevent the records pointed to by * Context: Any context. Caller must prevent the records pointed to by
* @pd and @pwd from changing during execution. * @pd and @pwd from changing during execution.
*/ */
static void __prci_wrpll_write_cfg(struct __prci_data *pd, static void __prci_wrpll_write_cfg0(struct __prci_data *pd,
struct __prci_wrpll_data *pwd, struct __prci_wrpll_data *pwd,
struct wrpll_cfg *c) struct wrpll_cfg *c)
{ {
@@ -357,6 +373,20 @@ static void __prci_wrpll_write_cfg(struct __prci_data *pd,
memcpy(&pwd->c, c, sizeof(*c)); memcpy(&pwd->c, c, sizeof(*c));
} }
/**
* __prci_wrpll_write_cfg1() - write Clock enable/disable configuration
* into the PRCI
* @pd: PRCI context
* @pwd: PRCI WRPLL metadata
* @enable: Clock enable or disable value
*/
static void __prci_wrpll_write_cfg1(struct __prci_data *pd,
struct __prci_wrpll_data *pwd,
u32 enable)
{
__prci_writel(enable, pwd->cfg1_offs, pd);
}
/* Core clock mux control */ /* Core clock mux control */
/** /**
@@ -438,7 +468,7 @@ static int sifive_fu540_prci_wrpll_set_rate(struct __prci_clock *pc,
if (pwd->enable_bypass) if (pwd->enable_bypass)
pwd->enable_bypass(pd); pwd->enable_bypass(pd);
__prci_wrpll_write_cfg(pd, pwd, &pwd->c); __prci_wrpll_write_cfg0(pd, pwd, &pwd->c);
udelay(wrpll_calc_max_lock_us(&pwd->c)); udelay(wrpll_calc_max_lock_us(&pwd->c));
@@ -448,14 +478,33 @@ static int sifive_fu540_prci_wrpll_set_rate(struct __prci_clock *pc,
return 0; return 0;
} }
static int sifive_fu540_prci_clock_enable(struct __prci_clock *pc, bool enable)
{
struct __prci_wrpll_data *pwd = pc->pwd;
struct __prci_data *pd = pc->pd;
if (enable) {
__prci_wrpll_write_cfg1(pd, pwd, PRCI_COREPLLCFG1_CKE_MASK);
if (pwd->release_reset)
pwd->release_reset(pd);
} else {
u32 r;
r = __prci_readl(pd, pwd->cfg1_offs);
r &= ~PRCI_COREPLLCFG1_CKE_MASK;
__prci_wrpll_write_cfg1(pd, pwd, r);
}
return 0;
}
static const struct __prci_clock_ops sifive_fu540_prci_wrpll_clk_ops = { static const struct __prci_clock_ops sifive_fu540_prci_wrpll_clk_ops = {
.set_rate = sifive_fu540_prci_wrpll_set_rate, .set_rate = sifive_fu540_prci_wrpll_set_rate,
.round_rate = sifive_fu540_prci_wrpll_round_rate, .round_rate = sifive_fu540_prci_wrpll_round_rate,
.recalc_rate = sifive_fu540_prci_wrpll_recalc_rate, .recalc_rate = sifive_fu540_prci_wrpll_recalc_rate,
}; .enable_clk = sifive_fu540_prci_clock_enable,
static const struct __prci_clock_ops sifive_fu540_prci_wrpll_ro_clk_ops = {
.recalc_rate = sifive_fu540_prci_wrpll_recalc_rate,
}; };
/* TLCLKSEL clock integration */ /* TLCLKSEL clock integration */
@@ -479,22 +528,78 @@ static const struct __prci_clock_ops sifive_fu540_prci_tlclksel_clk_ops = {
.recalc_rate = sifive_fu540_prci_tlclksel_recalc_rate, .recalc_rate = sifive_fu540_prci_tlclksel_recalc_rate,
}; };
/**
* __prci_ddr_release_reset() - Release DDR reset
* @pd: struct __prci_data * for the PRCI containing the DDRCLK mux reg
*
*/
static void __prci_ddr_release_reset(struct __prci_data *pd)
{
u32 v;
v = __prci_readl(pd, PRCI_DEVICESRESETREG_OFFSET);
v |= PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_MASK;
__prci_writel(v, PRCI_DEVICESRESETREG_OFFSET, pd);
/* HACK to get the '1 full controller clock cycle'. */
asm volatile ("fence");
v = __prci_readl(pd, PRCI_DEVICESRESETREG_OFFSET);
v |= (PRCI_DEVICESRESETREG_DDR_AXI_RST_N_MASK |
PRCI_DEVICESRESETREG_DDR_AHB_RST_N_MASK |
PRCI_DEVICESRESETREG_DDR_PHY_RST_N_MASK);
__prci_writel(v, PRCI_DEVICESRESETREG_OFFSET, pd);
/* 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.
*/
for (int i = 0; i < 256; i++)
asm volatile ("nop");
}
/**
* __prci_ethernet_release_reset() - Release ethernet reset
* @pd: struct __prci_data * for the PRCI containing the Ethernet CLK mux reg
*
*/
static void __prci_ethernet_release_reset(struct __prci_data *pd)
{
u32 v;
/* Release GEMGXL reset */
v = __prci_readl(pd, PRCI_DEVICESRESETREG_OFFSET);
v |= PRCI_DEVICESRESETREG_GEMGXL_RST_N_MASK;
__prci_writel(v, PRCI_DEVICESRESETREG_OFFSET, pd);
/* Procmon => core clock */
__prci_writel(PRCI_PROCMONCFG_CORE_CLOCK_MASK, PRCI_PROCMONCFG_OFFSET,
pd);
}
/* /*
* PRCI integration data for each WRPLL instance * PRCI integration data for each WRPLL instance
*/ */
static struct __prci_wrpll_data __prci_corepll_data = { static struct __prci_wrpll_data __prci_corepll_data = {
.cfg0_offs = PRCI_COREPLLCFG0_OFFSET, .cfg0_offs = PRCI_COREPLLCFG0_OFFSET,
.cfg1_offs = PRCI_COREPLLCFG1_OFFSET,
.enable_bypass = __prci_coreclksel_use_hfclk, .enable_bypass = __prci_coreclksel_use_hfclk,
.disable_bypass = __prci_coreclksel_use_corepll, .disable_bypass = __prci_coreclksel_use_corepll,
}; };
static struct __prci_wrpll_data __prci_ddrpll_data = { static struct __prci_wrpll_data __prci_ddrpll_data = {
.cfg0_offs = PRCI_DDRPLLCFG0_OFFSET, .cfg0_offs = PRCI_DDRPLLCFG0_OFFSET,
.cfg1_offs = PRCI_DDRPLLCFG1_OFFSET,
.release_reset = __prci_ddr_release_reset,
}; };
static struct __prci_wrpll_data __prci_gemgxlpll_data = { static struct __prci_wrpll_data __prci_gemgxlpll_data = {
.cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET, .cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET,
.cfg1_offs = PRCI_GEMGXLPLLCFG1_OFFSET,
.release_reset = __prci_ethernet_release_reset,
}; };
/* /*
@@ -511,7 +616,7 @@ static struct __prci_clock __prci_init_clocks[] = {
[PRCI_CLK_DDRPLL] = { [PRCI_CLK_DDRPLL] = {
.name = "ddrpll", .name = "ddrpll",
.parent_name = "hfclk", .parent_name = "hfclk",
.ops = &sifive_fu540_prci_wrpll_ro_clk_ops, .ops = &sifive_fu540_prci_wrpll_clk_ops,
.pwd = &__prci_ddrpll_data, .pwd = &__prci_ddrpll_data,
}, },
[PRCI_CLK_GEMGXLPLL] = { [PRCI_CLK_GEMGXLPLL] = {
@@ -581,6 +686,42 @@ static ulong sifive_fu540_prci_set_rate(struct clk *clk, ulong rate)
return rate; return rate;
} }
static int sifive_fu540_prci_enable(struct clk *clk)
{
struct __prci_clock *pc;
int ret = 0;
if (ARRAY_SIZE(__prci_init_clocks) <= clk->id)
return -ENXIO;
pc = &__prci_init_clocks[clk->id];
if (!pc->pd)
return -ENXIO;
if (pc->ops->enable_clk)
ret = pc->ops->enable_clk(pc, 1);
return ret;
}
static int sifive_fu540_prci_disable(struct clk *clk)
{
struct __prci_clock *pc;
int ret = 0;
if (ARRAY_SIZE(__prci_init_clocks) <= clk->id)
return -ENXIO;
pc = &__prci_init_clocks[clk->id];
if (!pc->pd)
return -ENXIO;
if (pc->ops->enable_clk)
ret = pc->ops->enable_clk(pc, 0);
return ret;
}
static int sifive_fu540_prci_probe(struct udevice *dev) static int sifive_fu540_prci_probe(struct udevice *dev)
{ {
int i, err; int i, err;
@@ -603,7 +744,7 @@ static int sifive_fu540_prci_probe(struct udevice *dev)
pc = &__prci_init_clocks[i]; pc = &__prci_init_clocks[i];
pc->pd = pd; pc->pd = pd;
if (pc->pwd) if (pc->pwd)
__prci_wrpll_read_cfg(pd, pc->pwd); __prci_wrpll_read_cfg0(pd, pc->pwd);
} }
return 0; return 0;
@@ -612,6 +753,8 @@ static int sifive_fu540_prci_probe(struct udevice *dev)
static struct clk_ops sifive_fu540_prci_ops = { static struct clk_ops sifive_fu540_prci_ops = {
.set_rate = sifive_fu540_prci_set_rate, .set_rate = sifive_fu540_prci_set_rate,
.get_rate = sifive_fu540_prci_get_rate, .get_rate = sifive_fu540_prci_get_rate,
.enable = sifive_fu540_prci_enable,
.disable = sifive_fu540_prci_disable,
}; };
static const struct udevice_id sifive_fu540_prci_ids[] = { static const struct udevice_id sifive_fu540_prci_ids[] = {

View File

@@ -68,6 +68,13 @@ config ROCKCHIP_OTP
addressing and a length or through child-nodes that are generated addressing and a length or through child-nodes that are generated
based on the e-fuse map retrieved from the DTS. based on the e-fuse map retrieved from the DTS.
config SIFIVE_OTP
bool "SiFive eMemory OTP driver"
depends on MISC
help
Enable support for reading and writing the eMemory OTP on the
SiFive SoCs.
config VEXPRESS_CONFIG config VEXPRESS_CONFIG
bool "Enable support for Arm Versatile Express config bus" bool "Enable support for Arm Versatile Express config bus"
depends on MISC depends on MISC

View File

@@ -59,6 +59,7 @@ obj-$(CONFIG_QFW) += qfw.o
obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o
obj-$(CONFIG_ROCKCHIP_OTP) += rockchip-otp.o obj-$(CONFIG_ROCKCHIP_OTP) += rockchip-otp.o
obj-$(CONFIG_SANDBOX) += syscon_sandbox.o misc_sandbox.o obj-$(CONFIG_SANDBOX) += syscon_sandbox.o misc_sandbox.o
obj-$(CONFIG_SIFIVE_OTP) += sifive-otp.o
obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o
obj-$(CONFIG_SMSC_SIO1007) += smsc_sio1007.o obj-$(CONFIG_SMSC_SIO1007) += smsc_sio1007.o
obj-$(CONFIG_STM32MP_FUSE) += stm32mp_fuse.o obj-$(CONFIG_STM32MP_FUSE) += stm32mp_fuse.o

275
drivers/misc/sifive-otp.c Normal file
View File

@@ -0,0 +1,275 @@
// SPDX-License-Identifier: GPL-2.0
/*
* This is a driver for the eMemory EG004K32TQ028XW01 NeoFuse
* One-Time-Programmable (OTP) memory used within the SiFive FU540.
* It is documented in the FU540 manual here:
* https://www.sifive.com/documentation/chips/freedom-u540-c000-manual/
*
* Copyright (C) 2018 Philipp Hug <philipp@hug.cx>
* Copyright (C) 2018 Joey Hewitt <joey@joeyhewitt.com>
*
* Copyright (C) 2020 SiFive, Inc
*/
/*
* The FU540 stores 4096x32 bit (16KiB) values.
* Index 0x00-0xff are reserved for SiFive internal use. (first 1KiB)
* Right now first 1KiB is used to store only serial number.
*/
#include <common.h>
#include <dm/device.h>
#include <dm/read.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <misc.h>
#define BYTES_PER_FUSE 4
#define PA_RESET_VAL 0x00
#define PAS_RESET_VAL 0x00
#define PAIO_RESET_VAL 0x00
#define PDIN_RESET_VAL 0x00
#define PTM_RESET_VAL 0x00
#define PCLK_ENABLE_VAL BIT(0)
#define PCLK_DISABLE_VAL 0x00
#define PWE_WRITE_ENABLE BIT(0)
#define PWE_WRITE_DISABLE 0x00
#define PTM_FUSE_PROGRAM_VAL BIT(1)
#define PCE_ENABLE_INPUT BIT(0)
#define PCE_DISABLE_INPUT 0x00
#define PPROG_ENABLE_INPUT BIT(0)
#define PPROG_DISABLE_INPUT 0x00
#define PTRIM_ENABLE_INPUT BIT(0)
#define PTRIM_DISABLE_INPUT 0x00
#define PDSTB_DEEP_STANDBY_ENABLE BIT(0)
#define PDSTB_DEEP_STANDBY_DISABLE 0x00
/* Tpw - Program Pulse width delay */
#define TPW_DELAY 20
/* Tpwi - Program Pulse interval delay */
#define TPWI_DELAY 5
/* Tasp - Program address setup delay */
#define TASP_DELAY 1
/* Tcd - read data access delay */
#define TCD_DELAY 40
/* Tkl - clok pulse low delay */
#define TKL_DELAY 10
/* Tms - PTM mode setup delay */
#define TMS_DELAY 1
struct sifive_otp_regs {
u32 pa; /* Address input */
u32 paio; /* Program address input */
u32 pas; /* Program redundancy cell selection input */
u32 pce; /* OTP Macro enable input */
u32 pclk; /* Clock input */
u32 pdin; /* Write data input */
u32 pdout; /* Read data output */
u32 pdstb; /* Deep standby mode enable input (active low) */
u32 pprog; /* Program mode enable input */
u32 ptc; /* Test column enable input */
u32 ptm; /* Test mode enable input */
u32 ptm_rep;/* Repair function test mode enable input */
u32 ptr; /* Test row enable input */
u32 ptrim; /* Repair function enable input */
u32 pwe; /* Write enable input (defines program cycle) */
};
struct sifive_otp_platdata {
struct sifive_otp_regs __iomem *regs;
u32 total_fuses;
};
/*
* offset and size are assumed aligned to the size of the fuses (32-bit).
*/
static int sifive_otp_read(struct udevice *dev, int offset,
void *buf, int size)
{
struct sifive_otp_platdata *plat = dev_get_platdata(dev);
struct sifive_otp_regs *regs = (struct sifive_otp_regs *)plat->regs;
/* Check if offset and size are multiple of BYTES_PER_FUSE */
if ((size % BYTES_PER_FUSE) || (offset % BYTES_PER_FUSE)) {
printf("%s: size and offset must be multiple of 4.\n",
__func__);
return -EINVAL;
}
int fuseidx = offset / BYTES_PER_FUSE;
int fusecount = size / BYTES_PER_FUSE;
/* check bounds */
if (offset < 0 || size < 0)
return -EINVAL;
if (fuseidx >= plat->total_fuses)
return -EINVAL;
if ((fuseidx + fusecount) > plat->total_fuses)
return -EINVAL;
u32 fusebuf[fusecount];
/* init OTP */
writel(PDSTB_DEEP_STANDBY_ENABLE, &regs->pdstb);
writel(PTRIM_ENABLE_INPUT, &regs->ptrim);
writel(PCE_ENABLE_INPUT, &regs->pce);
/* read all requested fuses */
for (unsigned int i = 0; i < fusecount; i++, fuseidx++) {
writel(fuseidx, &regs->pa);
/* cycle clock to read */
writel(PCLK_ENABLE_VAL, &regs->pclk);
ndelay(TCD_DELAY * 1000);
writel(PCLK_DISABLE_VAL, &regs->pclk);
ndelay(TKL_DELAY * 1000);
/* read the value */
fusebuf[i] = readl(&regs->pdout);
}
/* shut down */
writel(PCE_DISABLE_INPUT, &regs->pce);
writel(PTRIM_DISABLE_INPUT, &regs->ptrim);
writel(PDSTB_DEEP_STANDBY_DISABLE, &regs->pdstb);
/* copy out */
memcpy(buf, fusebuf, size);
return size;
}
/*
* Caution:
* OTP can be written only once, so use carefully.
*
* offset and size are assumed aligned to the size of the fuses (32-bit).
*/
static int sifive_otp_write(struct udevice *dev, int offset,
const void *buf, int size)
{
struct sifive_otp_platdata *plat = dev_get_platdata(dev);
struct sifive_otp_regs *regs = (struct sifive_otp_regs *)plat->regs;
/* Check if offset and size are multiple of BYTES_PER_FUSE */
if ((size % BYTES_PER_FUSE) || (offset % BYTES_PER_FUSE)) {
printf("%s: size and offset must be multiple of 4.\n",
__func__);
return -EINVAL;
}
int fuseidx = offset / BYTES_PER_FUSE;
int fusecount = size / BYTES_PER_FUSE;
u32 *write_buf = (u32 *)buf;
u32 write_data;
int i, pas, bit;
/* check bounds */
if (offset < 0 || size < 0)
return -EINVAL;
if (fuseidx >= plat->total_fuses)
return -EINVAL;
if ((fuseidx + fusecount) > plat->total_fuses)
return -EINVAL;
/* init OTP */
writel(PDSTB_DEEP_STANDBY_ENABLE, &regs->pdstb);
writel(PTRIM_ENABLE_INPUT, &regs->ptrim);
/* reset registers */
writel(PCLK_DISABLE_VAL, &regs->pclk);
writel(PA_RESET_VAL, &regs->pa);
writel(PAS_RESET_VAL, &regs->pas);
writel(PAIO_RESET_VAL, &regs->paio);
writel(PDIN_RESET_VAL, &regs->pdin);
writel(PWE_WRITE_DISABLE, &regs->pwe);
writel(PTM_FUSE_PROGRAM_VAL, &regs->ptm);
ndelay(TMS_DELAY * 1000);
writel(PCE_ENABLE_INPUT, &regs->pce);
writel(PPROG_ENABLE_INPUT, &regs->pprog);
/* write all requested fuses */
for (i = 0; i < fusecount; i++, fuseidx++) {
writel(fuseidx, &regs->pa);
write_data = *(write_buf++);
for (pas = 0; pas < 2; pas++) {
writel(pas, &regs->pas);
for (bit = 0; bit < 32; bit++) {
writel(bit, &regs->paio);
writel(((write_data >> bit) & 1),
&regs->pdin);
ndelay(TASP_DELAY * 1000);
writel(PWE_WRITE_ENABLE, &regs->pwe);
udelay(TPW_DELAY);
writel(PWE_WRITE_DISABLE, &regs->pwe);
udelay(TPWI_DELAY);
}
}
writel(PAS_RESET_VAL, &regs->pas);
}
/* shut down */
writel(PWE_WRITE_DISABLE, &regs->pwe);
writel(PPROG_DISABLE_INPUT, &regs->pprog);
writel(PCE_DISABLE_INPUT, &regs->pce);
writel(PTM_RESET_VAL, &regs->ptm);
writel(PTRIM_DISABLE_INPUT, &regs->ptrim);
writel(PDSTB_DEEP_STANDBY_DISABLE, &regs->pdstb);
return size;
}
static int sifive_otp_ofdata_to_platdata(struct udevice *dev)
{
struct sifive_otp_platdata *plat = dev_get_platdata(dev);
int ret;
plat->regs = dev_read_addr_ptr(dev);
ret = dev_read_u32(dev, "fuse-count", &plat->total_fuses);
if (ret < 0) {
pr_err("\"fuse-count\" not found\n");
return ret;
}
return 0;
}
static const struct misc_ops sifive_otp_ops = {
.read = sifive_otp_read,
.write = sifive_otp_write,
};
static const struct udevice_id sifive_otp_ids[] = {
{ .compatible = "sifive,fu540-c000-otp" },
{}
};
U_BOOT_DRIVER(sifive_otp) = {
.name = "sifive_otp",
.id = UCLASS_MISC,
.of_match = sifive_otp_ids,
.ofdata_to_platdata = sifive_otp_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct sifive_otp_platdata),
.ops = &sifive_otp_ops,
};

View File

@@ -74,4 +74,5 @@ config IMXRT_SDRAM
This driver is for the sdram memory interface with the SEMC. This driver is for the sdram memory interface with the SEMC.
source "drivers/ram/rockchip/Kconfig" source "drivers/ram/rockchip/Kconfig"
source "drivers/ram/sifive/Kconfig"
source "drivers/ram/stm32mp1/Kconfig" source "drivers/ram/stm32mp1/Kconfig"

View File

@@ -17,3 +17,5 @@ obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/
obj-$(CONFIG_K3_J721E_DDRSS) += k3-j721e/ obj-$(CONFIG_K3_J721E_DDRSS) += k3-j721e/
obj-$(CONFIG_IMXRT_SDRAM) += imxrt_sdram.o obj-$(CONFIG_IMXRT_SDRAM) += imxrt_sdram.o
obj-$(CONFIG_RAM_SIFIVE) += sifive/

View File

@@ -0,0 +1,13 @@
config RAM_SIFIVE
bool "Ram drivers support for SiFive SoCs"
depends on RAM && RISCV
default y
help
This enables support for ram drivers of SiFive SoCs.
config SIFIVE_FU540_DDR
bool "SiFive FU540 DDR driver"
depends on RAM_SIFIVE
default y if TARGET_SIFIVE_FU540
help
This enables DDR support for the platforms based on SiFive FU540 SoC.

View File

@@ -0,0 +1,6 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (c) 2020 SiFive, Inc
#
obj-$(CONFIG_SIFIVE_FU540_DDR) += fu540_ddr.o

View File

@@ -0,0 +1,410 @@
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
/*
* (C) Copyright 2020 SiFive, Inc.
*
* Authors:
* Pragnesh Patel <pragnesh.patel@sifive.com>
*/
#include <common.h>
#include <dm.h>
#include <init.h>
#include <ram.h>
#include <regmap.h>
#include <syscon.h>
#include <asm/io.h>
#include <clk.h>
#include <wait_bit.h>
#include <linux/bitops.h>
#define DENALI_CTL_0 0
#define DENALI_CTL_21 21
#define DENALI_CTL_120 120
#define DENALI_CTL_132 132
#define DENALI_CTL_136 136
#define DENALI_CTL_170 170
#define DENALI_CTL_181 181
#define DENALI_CTL_182 182
#define DENALI_CTL_184 184
#define DENALI_CTL_208 208
#define DENALI_CTL_209 209
#define DENALI_CTL_210 210
#define DENALI_CTL_212 212
#define DENALI_CTL_214 214
#define DENALI_CTL_216 216
#define DENALI_CTL_224 224
#define DENALI_CTL_225 225
#define DENALI_CTL_260 260
#define DENALI_PHY_1152 1152
#define DENALI_PHY_1214 1214
#define PAYLOAD_DEST 0x80000000
#define DDR_MEM_SIZE (8UL * 1024UL * 1024UL * 1024UL)
#define DRAM_CLASS_OFFSET 8
#define DRAM_CLASS_DDR4 0xA
#define OPTIMAL_RMODW_EN_OFFSET 0
#define DISABLE_RD_INTERLEAVE_OFFSET 16
#define OUT_OF_RANGE_OFFSET 1
#define MULTIPLE_OUT_OF_RANGE_OFFSET 2
#define PORT_COMMAND_CHANNEL_ERROR_OFFSET 7
#define MC_INIT_COMPLETE_OFFSET 8
#define LEVELING_OPERATION_COMPLETED_OFFSET 22
#define DFI_PHY_WRLELV_MODE_OFFSET 24
#define DFI_PHY_RDLVL_MODE_OFFSET 24
#define DFI_PHY_RDLVL_GATE_MODE_OFFSET 0
#define VREF_EN_OFFSET 24
#define PORT_ADDR_PROTECTION_EN_OFFSET 0
#define AXI0_ADDRESS_RANGE_ENABLE 8
#define AXI0_RANGE_PROT_BITS_0_OFFSET 24
#define RDLVL_EN_OFFSET 16
#define RDLVL_GATE_EN_OFFSET 24
#define WRLVL_EN_OFFSET 0
#define PHY_RX_CAL_DQ0_0_OFFSET 0
#define PHY_RX_CAL_DQ1_0_OFFSET 16
struct fu540_ddrctl {
volatile u32 denali_ctl[265];
};
struct fu540_ddrphy {
volatile u32 denali_phy[1215];
};
/**
* struct fu540_ddr_info
*
* @dev : pointer for the device
* @info : UCLASS RAM information
* @ctl : DDR controller base address
* @phy : DDR PHY base address
* @ctrl : DDR control base address
* @physical_filter_ctrl : DDR physical filter control base address
*/
struct fu540_ddr_info {
struct udevice *dev;
struct ram_info info;
struct fu540_ddrctl *ctl;
struct fu540_ddrphy *phy;
struct clk ddr_clk;
u32 *physical_filter_ctrl;
};
#if defined(CONFIG_SPL_BUILD)
struct fu540_ddr_params {
struct fu540_ddrctl pctl_regs;
struct fu540_ddrphy phy_regs;
};
struct sifive_dmc_plat {
struct fu540_ddr_params ddr_params;
};
/*
* TODO : It can be possible to use common sdram_copy_to_reg() API
* n: Unit bytes
*/
static void sdram_copy_to_reg(volatile u32 *dest,
volatile u32 *src, u32 n)
{
int i;
for (i = 0; i < n / sizeof(u32); i++) {
writel(*src, dest);
src++;
dest++;
}
}
static void fu540_ddr_setup_range_protection(volatile u32 *ctl, u64 end_addr)
{
u32 end_addr_16kblocks = ((end_addr >> 14) & 0x7FFFFF) - 1;
writel(0x0, DENALI_CTL_209 + ctl);
writel(end_addr_16kblocks, DENALI_CTL_210 + ctl);
writel(0x0, DENALI_CTL_212 + ctl);
writel(0x0, DENALI_CTL_214 + ctl);
writel(0x0, DENALI_CTL_216 + ctl);
setbits_le32(DENALI_CTL_224 + ctl,
0x3 << AXI0_RANGE_PROT_BITS_0_OFFSET);
writel(0xFFFFFFFF, DENALI_CTL_225 + ctl);
setbits_le32(DENALI_CTL_208 + ctl, 0x1 << AXI0_ADDRESS_RANGE_ENABLE);
setbits_le32(DENALI_CTL_208 + ctl,
0x1 << PORT_ADDR_PROTECTION_EN_OFFSET);
}
static void fu540_ddr_start(volatile u32 *ctl, u32 *physical_filter_ctrl,
u64 ddr_end)
{
volatile u64 *filterreg = (volatile u64 *)physical_filter_ctrl;
setbits_le32(DENALI_CTL_0 + ctl, 0x1);
wait_for_bit_le32((void *)ctl + DENALI_CTL_132,
BIT(MC_INIT_COMPLETE_OFFSET), false, 100, false);
/* Disable the BusBlocker in front of the controller AXI slave ports */
filterreg[0] = 0x0f00000000000000UL | (ddr_end >> 2);
}
static void fu540_ddr_check_errata(u32 regbase, u32 updownreg)
{
u64 fails = 0;
u32 dq = 0;
u32 down, up;
u8 failc0, failc1;
u32 phy_rx_cal_dqn_0_offset;
for (u32 bit = 0; bit < 2; bit++) {
if (bit == 0) {
phy_rx_cal_dqn_0_offset =
PHY_RX_CAL_DQ0_0_OFFSET;
} else {
phy_rx_cal_dqn_0_offset =
PHY_RX_CAL_DQ1_0_OFFSET;
}
down = (updownreg >>
phy_rx_cal_dqn_0_offset) & 0x3F;
up = (updownreg >>
(phy_rx_cal_dqn_0_offset + 6)) &
0x3F;
failc0 = ((down == 0) && (up == 0x3F));
failc1 = ((up == 0) && (down == 0x3F));
/* print error message on failure */
if (failc0 || failc1) {
if (fails == 0)
printf("DDR error in fixing up\n");
fails |= (1 << dq);
char slicelsc = '0';
char slicemsc = '0';
slicelsc += (dq % 10);
slicemsc += (dq / 10);
printf("S ");
printf("%c", slicemsc);
printf("%c", slicelsc);
if (failc0)
printf("U");
else
printf("D");
printf("\n");
}
dq++;
}
}
static u64 fu540_ddr_phy_fixup(volatile u32 *ddrphyreg)
{
u32 slicebase = 0;
/* check errata condition */
for (u32 slice = 0; slice < 8; slice++) {
u32 regbase = slicebase + 34;
for (u32 reg = 0; reg < 4; reg++) {
u32 updownreg = readl(regbase + reg + ddrphyreg);
fu540_ddr_check_errata(regbase, updownreg);
}
slicebase += 128;
}
return(0);
}
static u32 fu540_ddr_get_dram_class(volatile u32 *ctl)
{
u32 reg = readl(DENALI_CTL_0 + ctl);
return ((reg >> DRAM_CLASS_OFFSET) & 0xF);
}
static int fu540_ddr_setup(struct udevice *dev)
{
struct fu540_ddr_info *priv = dev_get_priv(dev);
struct sifive_dmc_plat *plat = dev_get_platdata(dev);
struct fu540_ddr_params *params = &plat->ddr_params;
volatile u32 *denali_ctl = priv->ctl->denali_ctl;
volatile u32 *denali_phy = priv->phy->denali_phy;
const u64 ddr_size = DDR_MEM_SIZE;
const u64 ddr_end = PAYLOAD_DEST + ddr_size;
int ret, i;
u32 physet;
ret = dev_read_u32_array(dev, "sifive,ddr-params",
(u32 *)&plat->ddr_params,
sizeof(plat->ddr_params) / sizeof(u32));
if (ret) {
printf("%s: Cannot read sifive,ddr-params %d\n",
__func__, ret);
return ret;
}
sdram_copy_to_reg(priv->ctl->denali_ctl,
params->pctl_regs.denali_ctl,
sizeof(struct fu540_ddrctl));
/* phy reset */
for (i = DENALI_PHY_1152; i <= DENALI_PHY_1214; i++) {
physet = params->phy_regs.denali_phy[i];
priv->phy->denali_phy[i] = physet;
}
for (i = 0; i < DENALI_PHY_1152; i++) {
physet = params->phy_regs.denali_phy[i];
priv->phy->denali_phy[i] = physet;
}
/* Disable read interleave DENALI_CTL_120 */
setbits_le32(DENALI_CTL_120 + denali_ctl,
1 << DISABLE_RD_INTERLEAVE_OFFSET);
/* Disable optimal read/modify/write logic DENALI_CTL_21 */
clrbits_le32(DENALI_CTL_21 + denali_ctl, 1 << OPTIMAL_RMODW_EN_OFFSET);
/* Enable write Leveling DENALI_CTL_170 */
setbits_le32(DENALI_CTL_170 + denali_ctl, (1 << WRLVL_EN_OFFSET)
| (1 << DFI_PHY_WRLELV_MODE_OFFSET));
/* Enable read leveling DENALI_CTL_181 and DENALI_CTL_260 */
setbits_le32(DENALI_CTL_181 + denali_ctl,
1 << DFI_PHY_RDLVL_MODE_OFFSET);
setbits_le32(DENALI_CTL_260 + denali_ctl, 1 << RDLVL_EN_OFFSET);
/* Enable read leveling gate DENALI_CTL_260 and DENALI_CTL_182 */
setbits_le32(DENALI_CTL_260 + denali_ctl, 1 << RDLVL_GATE_EN_OFFSET);
setbits_le32(DENALI_CTL_182 + denali_ctl,
1 << DFI_PHY_RDLVL_GATE_MODE_OFFSET);
if (fu540_ddr_get_dram_class(denali_ctl) == DRAM_CLASS_DDR4) {
/* Enable vref training DENALI_CTL_184 */
setbits_le32(DENALI_CTL_184 + denali_ctl, 1 << VREF_EN_OFFSET);
}
/* Mask off leveling completion interrupt DENALI_CTL_136 */
setbits_le32(DENALI_CTL_136 + denali_ctl,
1 << LEVELING_OPERATION_COMPLETED_OFFSET);
/* Mask off MC init complete interrupt DENALI_CTL_136 */
setbits_le32(DENALI_CTL_136 + denali_ctl, 1 << MC_INIT_COMPLETE_OFFSET);
/* Mask off out of range interrupts DENALI_CTL_136 */
setbits_le32(DENALI_CTL_136 + denali_ctl, (1 << OUT_OF_RANGE_OFFSET)
| (1 << MULTIPLE_OUT_OF_RANGE_OFFSET));
/* set up range protection */
fu540_ddr_setup_range_protection(denali_ctl, DDR_MEM_SIZE);
/* Mask off port command error interrupt DENALI_CTL_136 */
setbits_le32(DENALI_CTL_136 + denali_ctl,
1 << PORT_COMMAND_CHANNEL_ERROR_OFFSET);
fu540_ddr_start(denali_ctl, priv->physical_filter_ctrl, ddr_end);
fu540_ddr_phy_fixup(denali_phy);
/* check size */
priv->info.size = get_ram_size((long *)priv->info.base,
DDR_MEM_SIZE);
debug("%s : %lx\n", __func__, priv->info.size);
/* check memory access for all memory */
if (priv->info.size != DDR_MEM_SIZE) {
printf("DDR invalid size : 0x%lx, expected 0x%lx\n",
priv->info.size, DDR_MEM_SIZE);
return -EINVAL;
}
return 0;
}
#endif
static int fu540_ddr_probe(struct udevice *dev)
{
struct fu540_ddr_info *priv = dev_get_priv(dev);
#if defined(CONFIG_SPL_BUILD)
struct regmap *map;
int ret;
u32 clock = 0;
debug("FU540 DDR probe\n");
priv->dev = dev;
ret = regmap_init_mem(dev_ofnode(dev), &map);
if (ret)
return ret;
ret = clk_get_by_index(dev, 0, &priv->ddr_clk);
if (ret) {
debug("clk get failed %d\n", ret);
return ret;
}
ret = dev_read_u32(dev, "clock-frequency", &clock);
if (ret) {
debug("clock-frequency not found in dt %d\n", ret);
return ret;
} else {
ret = clk_set_rate(&priv->ddr_clk, clock);
if (ret < 0) {
debug("Could not set DDR clock\n");
return ret;
}
}
ret = clk_enable(&priv->ddr_clk);
priv->ctl = regmap_get_range(map, 0);
priv->phy = regmap_get_range(map, 1);
priv->physical_filter_ctrl = regmap_get_range(map, 2);
priv->info.base = CONFIG_SYS_SDRAM_BASE;
priv->info.size = 0;
return fu540_ddr_setup(dev);
#else
priv->info.base = CONFIG_SYS_SDRAM_BASE;
priv->info.size = DDR_MEM_SIZE;
#endif
return 0;
}
static int fu540_ddr_get_info(struct udevice *dev, struct ram_info *info)
{
struct fu540_ddr_info *priv = dev_get_priv(dev);
*info = priv->info;
return 0;
}
static struct ram_ops fu540_ddr_ops = {
.get_info = fu540_ddr_get_info,
};
static const struct udevice_id fu540_ddr_ids[] = {
{ .compatible = "sifive,fu540-c000-ddr" },
{ }
};
U_BOOT_DRIVER(fu540_ddr) = {
.name = "fu540_ddr",
.id = UCLASS_RAM,
.of_match = fu540_ddr_ids,
.ops = &fu540_ddr_ops,
.probe = fu540_ddr_probe,
.priv_auto_alloc_size = sizeof(struct fu540_ddr_info),
#if defined(CONFIG_SPL_BUILD)
.platdata_auto_alloc_size = sizeof(struct sifive_dmc_plat),
#endif
};

View File

@@ -11,6 +11,22 @@
#include <linux/sizes.h> #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_SDRAM_BASE 0x80000000
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + SZ_2M) #define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + SZ_2M)
@@ -24,12 +40,22 @@
/* Environment options */ /* Environment options */
#ifndef CONFIG_SPL_BUILD
#define BOOT_TARGET_DEVICES(func) \ #define BOOT_TARGET_DEVICES(func) \
func(MMC, mmc, 0) \ func(MMC, mmc, 0) \
func(DHCP, dhcp, na) func(DHCP, dhcp, na)
#include <config_distro_bootcmd.h> #include <config_distro_bootcmd.h>
#define TYPE_GUID_LOADER1 "5B193300-FC78-40CD-8002-E86C45580B47"
#define TYPE_GUID_LOADER2 "2E54B353-1271-4842-806F-E436D6AF6985"
#define TYPE_GUID_SYSTEM "0FC63DAF-8483-4772-8E79-3D69D8477DE4"
#define PARTS_DEFAULT \
"name=loader1,start=17K,size=1M,type=${type_guid_gpt_loader1};" \
"name=loader2,size=4MB,type=${type_guid_gpt_loader2};" \
"name=system,size=-,bootable,type=${type_guid_gpt_system};"
#define CONFIG_EXTRA_ENV_SETTINGS \ #define CONFIG_EXTRA_ENV_SETTINGS \
"fdt_high=0xffffffffffffffff\0" \ "fdt_high=0xffffffffffffffff\0" \
"initrd_high=0xffffffffffffffff\0" \ "initrd_high=0xffffffffffffffff\0" \
@@ -38,10 +64,15 @@
"scriptaddr=0x88100000\0" \ "scriptaddr=0x88100000\0" \
"pxefile_addr_r=0x88200000\0" \ "pxefile_addr_r=0x88200000\0" \
"ramdisk_addr_r=0x88300000\0" \ "ramdisk_addr_r=0x88300000\0" \
"type_guid_gpt_loader1=" TYPE_GUID_LOADER1 "\0" \
"type_guid_gpt_loader2=" TYPE_GUID_LOADER2 "\0" \
"type_guid_gpt_system=" TYPE_GUID_SYSTEM "\0" \
"partitions=" PARTS_DEFAULT "\0" \
BOOTENV BOOTENV
#define CONFIG_PREBOOT \ #define CONFIG_PREBOOT \
"setenv fdt_addr ${fdtcontroladdr};" \ "setenv fdt_addr ${fdtcontroladdr};" \
"fdt addr ${fdtcontroladdr};" "fdt addr ${fdtcontroladdr};"
#endif
#endif /* __CONFIG_H */ #endif /* __CONFIG_H */

View File

@@ -30,7 +30,6 @@ obj-y += charset.o
endif endif
endif endif
obj-$(CONFIG_USB_TTY) += circbuf.o obj-$(CONFIG_USB_TTY) += circbuf.o
obj-y += crc7.o
obj-y += crc8.o obj-y += crc8.o
obj-y += crc16.o obj-y += crc16.o
obj-$(CONFIG_ERRNO_STR) += errno_str.o obj-$(CONFIG_ERRNO_STR) += errno_str.o
@@ -90,6 +89,7 @@ obj-y += errno.o
obj-y += display_options.o obj-y += display_options.o
CFLAGS_display_options.o := $(if $(BUILD_TAG),-DBUILD_TAG='"$(BUILD_TAG)"') CFLAGS_display_options.o := $(if $(BUILD_TAG),-DBUILD_TAG='"$(BUILD_TAG)"')
obj-$(CONFIG_BCH) += bch.o obj-$(CONFIG_BCH) += bch.o
obj-$(CONFIG_MMC_SPI) += crc7.o
obj-y += crc32.o obj-y += crc32.o
obj-$(CONFIG_CRC32C) += crc32c.o obj-$(CONFIG_CRC32C) += crc32c.o
obj-y += ctype.o obj-y += ctype.o