
On Thu, Oct 5, 2017 at 8:07 AM, chin.liang.see@intel.com wrote:
From: Chin Liang See chin.liang.see@intel.com
Add DDR support for Stratix SoC
Signed-off-by: Chin Liang See chin.liang.see@intel.com
arch/arm/mach-socfpga/include/mach/sdram_s10.h | 333 +++++++++++++++++++++ drivers/ddr/altera/Makefile | 1 + drivers/ddr/altera/sdram_s10.c | 382 +++++++++++++++++++++++++ 3 files changed, 716 insertions(+) create mode 100644 arch/arm/mach-socfpga/include/mach/sdram_s10.h create mode 100644 drivers/ddr/altera/sdram_s10.c
diff --git a/arch/arm/mach-socfpga/include/mach/sdram_s10.h b/arch/arm/mach-socfpga/include/mach/sdram_s10.h new file mode 100644 index 0000000..d0fd958
[...]
diff --git a/drivers/ddr/altera/Makefile b/drivers/ddr/altera/Makefile index bdd2872..943b6cd 100644 --- a/drivers/ddr/altera/Makefile +++ b/drivers/ddr/altera/Makefile @@ -10,4 +10,5 @@
ifdef CONFIG_ALTERA_SDRAM obj-$(CONFIG_TARGET_SOCFPGA_GEN5) += sdram.o sequencer.o +obj-$(CONFIG_TARGET_SOCFPGA_STRATIX10) += sdram_s10.o endif diff --git a/drivers/ddr/altera/sdram_s10.c b/drivers/ddr/altera/sdram_s10.c new file mode 100644 index 0000000..c488caf --- /dev/null +++ b/drivers/ddr/altera/sdram_s10.c @@ -0,0 +1,382 @@ +/*
- Copyright (C) 2016-2017 Intel Corporation <www.intel.com>
- SPDX-License-Identifier: GPL-2.0
- */
+#include <common.h> +#include <errno.h> +#include <div64.h> +#include <asm/io.h> +#include <watchdog.h> +#include <asm/arch/sdram_s10.h> +#include <asm/arch/system_manager.h> +#include <asm/arch/reset_manager.h>
+DECLARE_GLOBAL_DATA_PTR;
+static const struct socfpga_ecc_hmc *socfpga_ecc_hmc_base =
(void *)SOCFPGA_SDR_ADDRESS;
+static const struct socfpga_noc_ddr_scheduler *socfpga_noc_ddr_scheduler_base =
(void *)SOCFPGA_SDR_SCHEDULER_ADDRESS;
+static const struct socfpga_io48_mmr *socfpga_io48_mmr_base =
(void *)SOCFPGA_HMC_MMR_IO48_ADDRESS;
+static const struct socfpga_system_manager *sysmgr_regs =
(void *)SOCFPGA_SYSMGR_ADDRESS;
+#define DDR_CONFIG(A, B, C, R) ((A<<24)|(B<<16)|(C<<8)|R)
+/* The followring are the supported configurations */ +u32 ddr_config[] = {
/* DDR_CONFIG(Address order,Bank,Column,Row) */
/* List for DDR3 or LPDDR3 (pinout order > chip, row, bank, column) */
DDR_CONFIG(0, 3, 10, 12),
DDR_CONFIG(0, 3, 9, 13),
DDR_CONFIG(0, 3, 10, 13),
DDR_CONFIG(0, 3, 9, 14),
DDR_CONFIG(0, 3, 10, 14),
DDR_CONFIG(0, 3, 10, 15),
DDR_CONFIG(0, 3, 11, 14),
DDR_CONFIG(0, 3, 11, 15),
DDR_CONFIG(0, 3, 10, 16),
DDR_CONFIG(0, 3, 11, 16),
DDR_CONFIG(0, 3, 12, 15), /* 0xa */
/* List for DDR4 only (pinout order > chip, bank, row, column) */
DDR_CONFIG(1, 3, 10, 14),
DDR_CONFIG(1, 4, 10, 14),
DDR_CONFIG(1, 3, 10, 15),
DDR_CONFIG(1, 4, 10, 15),
DDR_CONFIG(1, 3, 10, 16),
DDR_CONFIG(1, 4, 10, 16),
DDR_CONFIG(1, 3, 10, 17),
DDR_CONFIG(1, 4, 10, 17),
+};
+#define DDR_CONFIG_ELEMENTS (sizeof(ddr_config)/sizeof(u32))
+int match_ddr_conf(u32 ddr_conf)
Should be static.
+{
int i;
for (i = 0; i < DDR_CONFIG_ELEMENTS; i++) {
if (ddr_conf == ddr_config[i])
return i;
}
return 0;
+}
+static int emif_clear(void) +{
u32 s2c, i;
writel(0, &socfpga_ecc_hmc_base->rsthandshakectrl);
s2c = readl(&socfpga_ecc_hmc_base->rsthandshakestat) &
DDR_HMC_RSTHANDSHAKE_MASK;
for (i = 1000; (i > 0) && s2c; i--) {
WATCHDOG_RESET();
mdelay(1);
s2c = readl(&socfpga_ecc_hmc_base->rsthandshakestat) &
DDR_HMC_RSTHANDSHAKE_MASK;
}
return !s2c;
+}
+static int emif_reset(void)
What's the return used for? I don't see the callers of emif_reset checking the return values at all.
+{
u32 c2s, s2c, i;
c2s = readl(&socfpga_ecc_hmc_base->rsthandshakectrl) &
DDR_HMC_RSTHANDSHAKE_MASK;
s2c = readl(&socfpga_ecc_hmc_base->rsthandshakestat) &
DDR_HMC_RSTHANDSHAKE_MASK;
debug("DDR: c2s=%08x s2c=%08x nr0=%08x nr1=%08x nr2=%08x dst=%08x\n",
c2s, s2c, readl(&socfpga_io48_mmr_base->niosreserve0),
readl(&socfpga_io48_mmr_base->niosreserve1),
readl(&socfpga_io48_mmr_base->niosreserve2),
readl(&socfpga_io48_mmr_base->dramsts));
if (s2c && emif_clear()) {
printf("DDR: emif_clear() failed\n");
return -1;
}
puts("DDR: Triggerring emif_reset\n");
writel(DDR_HMC_CORE2SEQ_INT_REQ,
&socfpga_ecc_hmc_base->rsthandshakectrl);
for (i = 1000; i > 0; i--) {
/* if seq2core[3] = 0, we are good */
if (!(readl(&socfpga_ecc_hmc_base->rsthandshakestat) &
DDR_HMC_SEQ2CORE_INT_RESP_MASK))
break;
WATCHDOG_RESET();
mdelay(1);
}
if (!i) {
printf("DDR: failed to get ack from EMIF\n");
return -2;
}
if (emif_clear()) {
printf("DDR: emif_clear() failed\n");
return -3;
}
printf("DDR: emif_reset triggered successly\n");
return 0;
+}
+static int poll_hmc_clock_status(void) +{
u32 status, i;
for (i = 1000; i > 0; i--) {
status = readl(&sysmgr_regs->hmc_clk) &
SYSMGR_HMC_CLK_STATUS_MSK;
udelay(1);
if (status)
break;
WATCHDOG_RESET();
}
return status;
+}
+/**
- sdram_mmr_init_full() - Function to initialize SDRAM MMR
- Initialize the SDRAM MMR.
Remove extra comment that says the same thing.
- */
+int sdram_mmr_init_full(unsigned int unused) +{
u32 update_value, io48_value, ddrioctl;
u32 i, j, cal_success;
/* Enable access to DDR from CPU master */
clrbits_le32(CCU_CPU0_MPRT_ADBASE_DDRREG_ADDR, CCU_ADBASE_DI_MASK);
clrbits_le32(CCU_CPU0_MPRT_ADBASE_MEMSPACE0_ADDR, CCU_ADBASE_DI_MASK);
clrbits_le32(CCU_CPU0_MPRT_ADBASE_MEMSPACE1A_ADDR, CCU_ADBASE_DI_MASK);
clrbits_le32(CCU_CPU0_MPRT_ADBASE_MEMSPACE1B_ADDR, CCU_ADBASE_DI_MASK);
clrbits_le32(CCU_CPU0_MPRT_ADBASE_MEMSPACE1C_ADDR, CCU_ADBASE_DI_MASK);
clrbits_le32(CCU_CPU0_MPRT_ADBASE_MEMSPACE1D_ADDR, CCU_ADBASE_DI_MASK);
clrbits_le32(CCU_CPU0_MPRT_ADBASE_MEMSPACE1E_ADDR, CCU_ADBASE_DI_MASK);
/* Enable access to DDR from IO master */
clrbits_le32(CCU_IOM_MPRT_ADBASE_MEMSPACE0_ADDR, CCU_ADBASE_DI_MASK);
clrbits_le32(CCU_IOM_MPRT_ADBASE_MEMSPACE1A_ADDR, CCU_ADBASE_DI_MASK);
clrbits_le32(CCU_IOM_MPRT_ADBASE_MEMSPACE1B_ADDR, CCU_ADBASE_DI_MASK);
clrbits_le32(CCU_IOM_MPRT_ADBASE_MEMSPACE1C_ADDR, CCU_ADBASE_DI_MASK);
clrbits_le32(CCU_IOM_MPRT_ADBASE_MEMSPACE1D_ADDR, CCU_ADBASE_DI_MASK);
clrbits_le32(CCU_IOM_MPRT_ADBASE_MEMSPACE1E_ADDR, CCU_ADBASE_DI_MASK);
/* this enables nonsecure access to DDR */
/* mpuregion0addr_limit */
writel(0xFFFF0000, 0xF8020118);
writel(0x1F, 0xF802011c);
/* nonmpuregion0addr_limit */
writel(0xFFFF0000, 0xF8020198);
writel(0x1F, 0xF802019C);
/* Enable mpuregion0enable and nonmpuregion0enable */
writel(BIT(0) | BIT(8), 0xF8020100);
Add defines for the above addresses please.
/* Ensure HMC clock is running */
if (!poll_hmc_clock_status()) {
puts("DDR: Error as HMC clock not running\n");
return -1;
Use a valid error code...
}
/* release DDR scheduler from reset */
socfpga_per_reset(SOCFPGA_RESET(SDR), 0);
/* Try 3 times to do a calibration */
for (i = 0; i < 3; i++) {
cal_success = readl(&socfpga_ecc_hmc_base->ddrcalstat) &
DDR_HMC_DDRCALSTAT_CAL_MSK;
/* A delay to wait for calibration bit to set */
for (j = 0; (j < 1000) && !cal_success; j++) {
WATCHDOG_RESET();
mdelay(1);
cal_success = readl(&socfpga_ecc_hmc_base->ddrcalstat)
& DDR_HMC_DDRCALSTAT_CAL_MSK;
}
if (cal_success)
break;
else
emif_reset();
}
if (!cal_success) {
puts("DDR: Error as SDRAM calibration failed\n");
return -1;
Use a valid error code..
Dinh