
On Sat, May 2, 2020 at 3:37 PM Pragnesh Patel pragnesh.patel@sifive.com wrote:
Add driver for fu540 to support ddr initialization in SPL. This driver is based on FSBL (https://github.com/sifive/freedom-u540-c000-bootloader.git)
Signed-off-by: Pragnesh Patel pragnesh.patel@sifive.com
board/sifive/fu540/Kconfig | 2 + drivers/ram/Kconfig | 1 + drivers/ram/Makefile | 2 + drivers/ram/sifive/Kconfig | 13 + drivers/ram/sifive/Makefile | 6 + drivers/ram/sifive/sdram_fu540.c | 416 +++++++++++++++++++++++++++++++ 6 files changed, 440 insertions(+) create mode 100644 drivers/ram/sifive/Kconfig create mode 100644 drivers/ram/sifive/Makefile create mode 100644 drivers/ram/sifive/sdram_fu540.c
diff --git a/board/sifive/fu540/Kconfig b/board/sifive/fu540/Kconfig index 4330ac4491..d41c305227 100644 --- a/board/sifive/fu540/Kconfig +++ b/board/sifive/fu540/Kconfig @@ -19,6 +19,8 @@ config SYS_TEXT_BASE config BOARD_SPECIFIC_OPTIONS # dummy def_bool y select GENERIC_RISCV
select RAM
select SPL_RAM if SPL imply CMD_DHCP imply CMD_EXT2 imply CMD_EXT4
diff --git a/drivers/ram/Kconfig b/drivers/ram/Kconfig index 56fea7c94c..66074d1feb 100644 --- a/drivers/ram/Kconfig +++ b/drivers/ram/Kconfig @@ -75,3 +75,4 @@ config IMXRT_SDRAM
source "drivers/ram/rockchip/Kconfig" source "drivers/ram/stm32mp1/Kconfig" +source "drivers/ram/sifive/Kconfig" diff --git a/drivers/ram/Makefile b/drivers/ram/Makefile index 5c897410c6..769c9d6218 100644 --- a/drivers/ram/Makefile +++ b/drivers/ram/Makefile @@ -17,3 +17,5 @@ obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ obj-$(CONFIG_K3_J721E_DDRSS) += k3-j721e/
obj-$(CONFIG_IMXRT_SDRAM) += imxrt_sdram.o
+obj-$(CONFIG_RAM_SIFIVE) += sifive/ diff --git a/drivers/ram/sifive/Kconfig b/drivers/ram/sifive/Kconfig new file mode 100644 index 0000000000..6aca22ab2a --- /dev/null +++ b/drivers/ram/sifive/Kconfig @@ -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.
diff --git a/drivers/ram/sifive/Makefile b/drivers/ram/sifive/Makefile new file mode 100644 index 0000000000..0187805199 --- /dev/null +++ b/drivers/ram/sifive/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (c) 2020 SiFive, Inc +#
+obj-$(CONFIG_SIFIVE_FU540_DDR) += sdram_fu540.o diff --git a/drivers/ram/sifive/sdram_fu540.c b/drivers/ram/sifive/sdram_fu540.c new file mode 100644 index 0000000000..0aa2b2b44a --- /dev/null +++ b/drivers/ram/sifive/sdram_fu540.c @@ -0,0 +1,416 @@ +// 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>
+#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 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 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_TPL_BUILD) || \
(!defined(CONFIG_TPL) && defined(CONFIG_SPL_BUILD))
+struct fu540_sdram_params {
struct fu540_ddrctl pctl_regs;
struct fu540_ddrphy phy_regs;
+};
+struct sifive_dmc_plat { +#if CONFIG_IS_ENABLED(OF_PLATDATA)
struct dtd_sifive_fu540_dmc dtplat;
+#else
struct fu540_sdram_params sdram_params;
+#endif +};
+/* n: Unit bytes */
Please add TODO "It can be possible to use common copy_to_reg API"
+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 ddr_setuprangeprotection(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 ddr_start(volatile u32 *ctl, u32 *physical_filter_ctrl, u64 ddr_end) +{
int val;
volatile u64 *filterreg = (volatile u64 *)physical_filter_ctrl;
setbits_le32(DENALI_CTL_0 + ctl, 0x1);
do {
val = readl(DENALI_CTL_132 + ctl) &
(1 << MC_INIT_COMPLETE_OFFSET);
} while (val == 0);
wait_for_bit_le32(DENALI_CTL_132 + ctl, BIT(MC_INIT_COMPLETE_OFFSET), true, 100, false);
otherwise,
Reviewed-by: Jagan Teki jagan@amarulasolutions.com