From patchwork Thu Oct 5 13:07:29 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "See, Chin Liang" X-Patchwork-Id: 821766 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 3y7CsC5lnVz9s82 for ; Fri, 6 Oct 2017 00:14:07 +1100 (AEDT) Received: by lists.denx.de (Postfix, from userid 105) id 71C96C21FAC; Thu, 5 Oct 2017 13:11:50 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 0EBA8C21FCE; Thu, 5 Oct 2017 13:08:22 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 58078C21FD0; Thu, 5 Oct 2017 13:08:04 +0000 (UTC) Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by lists.denx.de (Postfix) with ESMTPS id 3EBCEC21FB3 for ; Thu, 5 Oct 2017 13:07:59 +0000 (UTC) Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 05 Oct 2017 06:07:58 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.42,481,1500966000"; d="scan'208";a="907051226" Received: from pg-interactive1.altera.com ([137.57.137.156]) by FMSMGA003.fm.intel.com with ESMTP; 05 Oct 2017 06:07:57 -0700 From: chin.liang.see@intel.com To: u-boot@lists.denx.de, Marek Vasut Date: Thu, 5 Oct 2017 21:07:29 +0800 Message-Id: <1507208851-32672-13-git-send-email-chin.liang.see@intel.com> X-Mailer: git-send-email 2.2.2 In-Reply-To: <1507208851-32672-1-git-send-email-chin.liang.see@intel.com> References: <1507208851-32672-1-git-send-email-chin.liang.see@intel.com> Cc: Tien Fong Chee , Chin Liang See Subject: [U-Boot] [PATCH v2 12/14] ddr: altera: stratix10: Add DDR support for Stratix10 SoC X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Chin Liang See Add DDR support for Stratix SoC Signed-off-by: Chin Liang See --- 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 --- /dev/null +++ b/arch/arm/mach-socfpga/include/mach/sdram_s10.h @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2016-2017 Intel Corporation + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _SDRAM_S10_H_ +#define _SDRAM_S10_H_ + +unsigned long sdram_calculate_size(void); +int sdram_mmr_init_full(unsigned int sdr_phy_reg); +int sdram_calibration_full(void); + +#define DDR_TWR 15 +#define DDR_READ_LATENCY_DELAY 40 +#define DDR_ACTIVATE_FAWBANK 0x1 + + +struct socfpga_ecc_hmc { + uint32_t ip_rev_id; + uint32_t _pad_0x4_0x7; + uint32_t ddrioctrl; + uint32_t ddrcalstat; + uint32_t mpr_0beat1; + uint32_t mpr_1beat1; + uint32_t mpr_2beat1; + uint32_t mpr_3beat1; + uint32_t mpr_4beat1; + uint32_t mpr_5beat1; + uint32_t mpr_6beat1; + uint32_t mpr_7beat1; + uint32_t mpr_8beat1; + uint32_t mpr_0beat2; + uint32_t mpr_1beat2; + uint32_t mpr_2beat2; + uint32_t mpr_3beat2; + uint32_t mpr_4beat2; + uint32_t mpr_5beat2; + uint32_t mpr_6beat2; + uint32_t mpr_7beat2; + uint32_t mpr_8beat2; + uint32_t _pad_0x58_0x5f[2]; + uint32_t auto_precharge; + uint32_t _pad_0x64_0xdf[31]; + uint32_t dramaddrwidth; + uint32_t _pad_0xe4_0xff[7]; + uint32_t eccctrl; + uint32_t eccctrl2; + uint32_t _pad_0x108_0x10f[2]; + uint32_t errinten; + uint32_t errintens; + uint32_t errintenr; + uint32_t intmode; + uint32_t intstat; + uint32_t diaginttest; + uint32_t modstat; + uint32_t derraddra; + uint32_t serraddra; + uint32_t _pad_0x134_0x137; + uint32_t autowb_corraddr; + uint32_t serrcntreg; + uint32_t autowb_drop_cntreg; + uint32_t ecc_reg2wreccdatabus; + uint32_t ecc_rdeccdata2regbus; + uint32_t ecc_reg2rdeccdatabus; + uint32_t ecc_diagon; + uint32_t ecc_decstat; + uint32_t _pad_0x158_0x15f[2]; + uint32_t ecc_errgenaddr_0; + uint32_t ecc_errgenaddr_1; + uint32_t ecc_errgenaddr_2; + uint32_t ecc_errgenaddr_3; + uint32_t ecc_ref2rddatabus_beat0; + uint32_t ecc_ref2rddatabus_beat1; + uint32_t ecc_ref2rddatabus_beat2; + uint32_t ecc_ref2rddatabus_beat3; + uint32_t ecc_errgenhaddr_0; + uint32_t ecc_errgenhaddr_1; + uint32_t ecc_errgenhaddr_2; + uint32_t ecc_errgenhaddr_3; + uint32_t ecc_rdeccdata2regbus_beat0; + uint32_t ecc_rdeccdata2regbus_beat1; + uint32_t ecc_rdeccdata2regbus_beat2; + uint32_t ecc_rdeccdata2regbus_beat3; + uint32_t _pad_0x1a0_0x1af[4]; + uint32_t derrhaddr; + uint32_t serrhaddr; + uint32_t _pad_0x1b8_0x1bb; + uint32_t autowb_corrhaddr; + uint32_t _pad_0x1c0_0x20f[20]; + uint32_t hpsintfcsel; + uint32_t rsthandshakectrl; + uint32_t rsthandshakestat; +}; + +struct socfpga_noc_ddr_scheduler { + uint32_t main_scheduler_id_coreid; + uint32_t main_scheduler_id_revisionid; + uint32_t main_scheduler_ddrconf; + uint32_t main_scheduler_ddrtiming; + uint32_t main_scheduler_ddrmode; + uint32_t main_scheduler_readlatency; + uint32_t _pad_0x18_0x37[8]; + uint32_t main_scheduler_activate; + uint32_t main_scheduler_devtodev; + uint32_t main_scheduler_ddr4timing; +}; + +struct socfpga_io48_mmr { + uint32_t dbgcfg0; + uint32_t dbgcfg1; + uint32_t dbgcfg2; + uint32_t dbgcfg3; + uint32_t dbgcfg4; + uint32_t dbgcfg5; + uint32_t dbgcfg6; + uint32_t reserve0; + uint32_t reserve1; + uint32_t reserve2; + uint32_t ctrlcfg0; + uint32_t ctrlcfg1; + uint32_t ctrlcfg2; + uint32_t ctrlcfg3; + uint32_t ctrlcfg4; + uint32_t ctrlcfg5; + uint32_t ctrlcfg6; + uint32_t ctrlcfg7; + uint32_t ctrlcfg8; + uint32_t ctrlcfg9; + uint32_t dramtiming0; + uint32_t dramodt0; + uint32_t dramodt1; + uint32_t sbcfg0; + uint32_t sbcfg1; + uint32_t sbcfg2; + uint32_t sbcfg3; + uint32_t sbcfg4; + uint32_t sbcfg5; + uint32_t sbcfg6; + uint32_t sbcfg7; + uint32_t caltiming0; + uint32_t caltiming1; + uint32_t caltiming2; + uint32_t caltiming3; + uint32_t caltiming4; + uint32_t caltiming5; + uint32_t caltiming6; + uint32_t caltiming7; + uint32_t caltiming8; + uint32_t caltiming9; + uint32_t caltiming10; + uint32_t dramaddrw; + uint32_t sideband0; + uint32_t sideband1; + uint32_t sideband2; + uint32_t sideband3; + uint32_t sideband4; + uint32_t sideband5; + uint32_t sideband6; + uint32_t sideband7; + uint32_t sideband8; + uint32_t sideband9; + uint32_t sideband10; + uint32_t sideband11; + uint32_t sideband12; + uint32_t sideband13; + uint32_t sideband14; + uint32_t sideband15; + uint32_t dramsts; + uint32_t dbgdone; + uint32_t dbgsignals; + uint32_t dbgreset; + uint32_t dbgmatch; + uint32_t counter0mask; + uint32_t counter1mask; + uint32_t counter0match; + uint32_t counter1match; + uint32_t niosreserve0; + uint32_t niosreserve1; + uint32_t niosreserve2; +}; + +union dramaddrw_reg { + struct { + u32 cfg_col_addr_width:5; + u32 cfg_row_addr_width:5; + u32 cfg_bank_addr_width:4; + u32 cfg_bank_group_addr_width:2; + u32 cfg_cs_addr_width:3; + u32 reserved:13; + }; + u32 word; +}; + +union ctrlcfg0_reg { + struct { + u32 cfg_mem_type:4; + u32 cfg_dimm_type:3; + u32 cfg_ac_pos:2; + u32 cfg_ctrl_burst_len:5; + u32 reserved:18; /* Other fields unused */ + }; + u32 word; +}; + +union ctrlcfg1_reg { + struct { + u32 cfg_dbc3_burst_len:5; + u32 cfg_addr_order:2; + u32 cfg_ctrl_enable_ecc:1; + u32 reserved:24; /* Other fields unused */ + }; + u32 word; +}; + +union dramtiming0_reg { + struct { + u32 cfg_tcl:6; + u32 reserved:8; /* Other fields unused */ + }; + u32 word; +}; + +union caltiming0_reg { + struct { + u32 cfg_act_to_rdwr:6; + u32 cfg_act_to_pch:6; + u32 cfg_act_to_act:6; + u32 cfg_act_to_act_db:6; + u32 reserved:8; /* Other fields unused */ + }; + u32 word; +}; + +union caltiming1_reg { + struct { + u32 cfg_rd_to_rd:6; + u32 cfg_rd_to_rd_dc:6; + u32 cfg_rd_to_rd_db:6; + u32 cfg_rd_to_wr:6; + u32 cfg_rd_to_wr_dc:6; + u32 reserved:2; + }; + u32 word; +}; + +union caltiming2_reg { + struct { + u32 cfg_rd_to_wr_db:6; + u32 cfg_rd_to_pch:6; + u32 cfg_rd_ap_to_valid:6; + u32 cfg_wr_to_wr:6; + u32 cfg_wr_to_wr_dc:6; + u32 reserved:2; + }; + u32 word; +}; + +union caltiming3_reg { + struct { + u32 cfg_wr_to_wr_db:6; + u32 cfg_wr_to_rd:6; + u32 cfg_wr_to_rd_dc:6; + u32 cfg_wr_to_rd_db:6; + u32 cfg_wr_to_pch:6; + u32 reserved:2; + }; + u32 word; +}; + +union caltiming4_reg { + struct { + u32 cfg_wr_ap_to_valid:6; + u32 cfg_pch_to_valid:6; + u32 cfg_pch_all_to_valid:6; + u32 cfg_arf_to_valid:8; + u32 cfg_pdn_to_valid:6; + }; + u32 word; +}; + +union caltiming9_reg { + struct { + u32 cfg_4_act_to_act:8; + u32 reserved:24; + }; + u32 word; +}; + +#define DDR_SCHED_DDRTIMING_ACTTOACT_OFFSET 0 +#define DDR_SCHED_DDRTIMING_RDTOMISS_OFFSET 6 +#define DDR_SCHED_DDRTIMING_WRTOMISS_OFFSET 12 +#define DDR_SCHED_DDRTIMING_BURSTLEN_OFFSET 18 +#define DDR_SCHED_DDRTIMING_RDTOWR_OFFSET 21 +#define DDR_SCHED_DDRTIMING_WRTORD_OFFSET 26 +#define DDR_SCHED_DDRTIMING_BWRATIO_OFFSET 31 +#define DDR_SCHED_DDRMOD_BWRATIOEXTENDED_OFFSET 1 +#define DDR_SCHED_ACTIVATE_RRD_OFFSET 0 +#define DDR_SCHED_ACTIVATE_FAW_OFFSET 4 +#define DDR_SCHED_ACTIVATE_FAWBANK_OFFSET 10 +#define DDR_SCHED_DEVTODEV_BUSRDTORD_OFFSET 0 +#define DDR_SCHED_DEVTODEV_BUSRDTOWR_OFFSET 2 +#define DDR_SCHED_DEVTODEV_BUSWRTORD_OFFSET 4 +#define DDR_HMC_DDRIOCTRL_IOSIZE_MSK 0x00000003 +#define DDR_HMC_DDRCALSTAT_CAL_MSK 0x00000001 +#define DDR_HMC_ECCCTL_AWB_CNT_RST_SET_MSK 0x00010000 +#define DDR_HMC_ECCCTL_CNT_RST_SET_MSK 0x00000100 +#define DDR_HMC_ECCCTL_ECC_EN_SET_MSK 0x00000001 +#define DDR_HMC_ECCCTL2_RMW_EN_SET_MSK 0x00000100 +#define DDR_HMC_ECCCTL2_AWB_EN_SET_MSK 0x00000001 +#define DDR_HMC_RSTHANDSHAKE_MASK 0x000000ff +#define DDR_HMC_CORE2SEQ_INT_REQ 0xF +#define DDR_HMC_SEQ2CORE_INT_RESP_MASK 0x8 +#define DDR_HMC_HPSINTFCSEL_ENABLE_MASK 0x001f1f1f + +#define CCU_CPU0_MPRT_ADBASE_DDRREG_ADDR 0xf7004400 +#define CCU_CPU0_MPRT_ADBASE_MEMSPACE0_ADDR 0xf70045c0 +#define CCU_CPU0_MPRT_ADBASE_MEMSPACE1A_ADDR 0xf70045e0 +#define CCU_CPU0_MPRT_ADBASE_MEMSPACE1B_ADDR 0xf7004600 +#define CCU_CPU0_MPRT_ADBASE_MEMSPACE1C_ADDR 0xf7004620 +#define CCU_CPU0_MPRT_ADBASE_MEMSPACE1D_ADDR 0xf7004640 +#define CCU_CPU0_MPRT_ADBASE_MEMSPACE1E_ADDR 0xf7004660 + +#define CCU_IOM_MPRT_ADBASE_MEMSPACE0_ADDR 0xf7018560 +#define CCU_IOM_MPRT_ADBASE_MEMSPACE1A_ADDR 0xf7018580 +#define CCU_IOM_MPRT_ADBASE_MEMSPACE1B_ADDR 0xf70185a0 +#define CCU_IOM_MPRT_ADBASE_MEMSPACE1C_ADDR 0xf70185c0 +#define CCU_IOM_MPRT_ADBASE_MEMSPACE1D_ADDR 0xf70185e0 +#define CCU_IOM_MPRT_ADBASE_MEMSPACE1E_ADDR 0xf7018600 + +#define CCU_ADBASE_DI_MASK 0x00000010 + +#endif /* _SDRAM_S10_H_ */ 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 + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +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) +{ + 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) +{ + 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. + */ +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); + + /* Ensure HMC clock is running */ + if (!poll_hmc_clock_status()) { + puts("DDR: Error as HMC clock not running\n"); + return -1; + } + + /* 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; + } + puts("DDR: Calibration success\n"); + + union ctrlcfg0_reg ctrlcfg0 = (union ctrlcfg0_reg) + readl(&socfpga_io48_mmr_base->ctrlcfg0); + union ctrlcfg1_reg ctrlcfg1 = (union ctrlcfg1_reg) + readl(&socfpga_io48_mmr_base->ctrlcfg1); + union dramaddrw_reg dramaddrw = (union dramaddrw_reg) + readl(&socfpga_io48_mmr_base->dramaddrw); + union dramtiming0_reg dramtim0 = (union dramtiming0_reg) + readl(&socfpga_io48_mmr_base->dramtiming0); + union caltiming0_reg caltim0 = (union caltiming0_reg) + readl(&socfpga_io48_mmr_base->caltiming0); + union caltiming1_reg caltim1 = (union caltiming1_reg) + readl(&socfpga_io48_mmr_base->caltiming1); + union caltiming2_reg caltim2 = (union caltiming2_reg) + readl(&socfpga_io48_mmr_base->caltiming2); + union caltiming3_reg caltim3 = (union caltiming3_reg) + readl(&socfpga_io48_mmr_base->caltiming3); + union caltiming4_reg caltim4 = (union caltiming4_reg) + readl(&socfpga_io48_mmr_base->caltiming4); + union caltiming9_reg caltim9 = (union caltiming9_reg) + readl(&socfpga_io48_mmr_base->caltiming9); + + /* + * Configure the DDR IO size [0xFFCFB008] + * niosreserve0: Used to indicate DDR width & + * bit[7:0] = Number of data bits (bit[6:5] 0x01=32bit, 0x10=64bit) + * bit[8] = 1 if user-mode OCT is present + * bit[9] = 1 if warm reset compiled into EMIF Cal Code + * bit[10] = 1 if warm reset is on during generation in EMIF Cal + * niosreserve1: IP ADCDS version encoded as 16 bit value + * bit[2:0] = Variant (0=not special,1=FAE beta, 2=Customer beta, + * 3=EAP, 4-6 are reserved) + * bit[5:3] = Service Pack # (e.g. 1) + * bit[9:6] = Minor Release # + * bit[14:10] = Major Release # + */ + update_value = readl(&socfpga_io48_mmr_base->niosreserve0); + writel(((update_value & 0xFF) >> 5), &socfpga_ecc_hmc_base->ddrioctrl); + ddrioctl = readl(&socfpga_ecc_hmc_base->ddrioctrl); + + /* enable HPS interface to HMC */ + writel(DDR_HMC_HPSINTFCSEL_ENABLE_MASK, + &socfpga_ecc_hmc_base->hpsintfcsel); + + /* Set the DDR Configuration */ + io48_value = DDR_CONFIG(ctrlcfg1.cfg_addr_order, + (dramaddrw.cfg_bank_addr_width + + dramaddrw.cfg_bank_group_addr_width), + dramaddrw.cfg_col_addr_width, + dramaddrw.cfg_row_addr_width); + + update_value = match_ddr_conf(io48_value); + if (update_value) + writel(update_value, + &socfpga_noc_ddr_scheduler_base->main_scheduler_ddrconf); + + /* Configure HMC dramaddrw */ + writel(readl(&socfpga_io48_mmr_base->dramaddrw), + &socfpga_ecc_hmc_base->dramaddrwidth); + + /* + * Configure DDR timing + * RDTOMISS = tRTP + tRP + tRCD - BL/2 + * WRTOMISS = WL + tWR + tRP + tRCD and + * WL = RL + BL/2 + 2 - rd-to-wr ; tWR = 15ns so... + * First part of equation is in memory clock units so divide by 2 + * for HMC clock units. 1066MHz is close to 1ns so use 15 directly. + * WRTOMISS = ((RL + BL/2 + 2 + tWR) >> 1)- rd-to-wr + tRP + tRCD + */ + update_value = caltim2.cfg_rd_to_pch + caltim4.cfg_pch_to_valid + + caltim0.cfg_act_to_rdwr - + (ctrlcfg0.cfg_ctrl_burst_len >> 2); + io48_value = (((dramtim0.cfg_tcl + 2 + DDR_TWR + + (ctrlcfg0.cfg_ctrl_burst_len >> 1)) >> 1) - + /* Up to here was in memory cycles so divide by 2 */ + caltim1.cfg_rd_to_wr + caltim0.cfg_act_to_rdwr + + caltim4.cfg_pch_to_valid); + + writel(((caltim0.cfg_act_to_act << DDR_SCHED_DDRTIMING_ACTTOACT_OFFSET) | + (update_value << DDR_SCHED_DDRTIMING_RDTOMISS_OFFSET) | + (io48_value << DDR_SCHED_DDRTIMING_WRTOMISS_OFFSET) | + ((ctrlcfg0.cfg_ctrl_burst_len >> 2) << + DDR_SCHED_DDRTIMING_BURSTLEN_OFFSET) | + (caltim1.cfg_rd_to_wr << DDR_SCHED_DDRTIMING_RDTOWR_OFFSET) | + (caltim3.cfg_wr_to_rd << DDR_SCHED_DDRTIMING_WRTORD_OFFSET) | + (((ddrioctl == 1) ? 1 : 0) << + DDR_SCHED_DDRTIMING_BWRATIO_OFFSET)), + &socfpga_noc_ddr_scheduler_base->main_scheduler_ddrtiming); + + /* Configure DDR mode [precharge = 0] */ + writel(((ddrioctl ? 0 : 1) << DDR_SCHED_DDRMOD_BWRATIOEXTENDED_OFFSET), + &socfpga_noc_ddr_scheduler_base->main_scheduler_ddrmode); + + /* Configure the read latency */ + writel((dramtim0.cfg_tcl >> 1) + DDR_READ_LATENCY_DELAY, + &socfpga_noc_ddr_scheduler_base->main_scheduler_readlatency); + + /* + * Configuring timing values concerning activate commands + * [FAWBANK alway 1 because always 4 bank DDR] + */ + writel(((caltim0.cfg_act_to_act_db << DDR_SCHED_ACTIVATE_RRD_OFFSET) | + (caltim9.cfg_4_act_to_act << DDR_SCHED_ACTIVATE_FAW_OFFSET) | + (DDR_ACTIVATE_FAWBANK << DDR_SCHED_ACTIVATE_FAWBANK_OFFSET)), + &socfpga_noc_ddr_scheduler_base->main_scheduler_activate); + + /* + * Configuring timing values concerning device to device data bus + * ownership change + */ + writel(((caltim1.cfg_rd_to_rd_dc << + DDR_SCHED_DEVTODEV_BUSRDTORD_OFFSET) | + (caltim1.cfg_rd_to_wr_dc << + DDR_SCHED_DEVTODEV_BUSRDTOWR_OFFSET) | + (caltim3.cfg_wr_to_rd_dc << + DDR_SCHED_DEVTODEV_BUSWRTORD_OFFSET)), + &socfpga_noc_ddr_scheduler_base->main_scheduler_devtodev); + + /* Enable or disable the SDRAM ECC */ + if (ctrlcfg1.cfg_ctrl_enable_ecc) { + setbits_le32(&socfpga_ecc_hmc_base->eccctrl, + (DDR_HMC_ECCCTL_AWB_CNT_RST_SET_MSK | + DDR_HMC_ECCCTL_CNT_RST_SET_MSK | + DDR_HMC_ECCCTL_ECC_EN_SET_MSK)); + clrbits_le32(&socfpga_ecc_hmc_base->eccctrl, + (DDR_HMC_ECCCTL_AWB_CNT_RST_SET_MSK | + DDR_HMC_ECCCTL_CNT_RST_SET_MSK)); + setbits_le32(&socfpga_ecc_hmc_base->eccctrl2, + (DDR_HMC_ECCCTL2_RMW_EN_SET_MSK | + DDR_HMC_ECCCTL2_AWB_EN_SET_MSK)); + } else { + clrbits_le32(&socfpga_ecc_hmc_base->eccctrl, + (DDR_HMC_ECCCTL_AWB_CNT_RST_SET_MSK | + DDR_HMC_ECCCTL_CNT_RST_SET_MSK | + DDR_HMC_ECCCTL_ECC_EN_SET_MSK)); + clrbits_le32(&socfpga_ecc_hmc_base->eccctrl2, + (DDR_HMC_ECCCTL2_RMW_EN_SET_MSK | + DDR_HMC_ECCCTL2_AWB_EN_SET_MSK)); + } + + puts("DDR: HMC init success\n"); + return 0; +} + +/** + * sdram_calculate_size() - Calculate SDRAM size + * + * Calculate SDRAM device size based on SDRAM controller parameters. + * Size is specified in bytes. + */ +unsigned long sdram_calculate_size(void) +{ + union dramaddrw_reg dramaddrw = + (union dramaddrw_reg)readl(&socfpga_io48_mmr_base->dramaddrw); + + u32 size = (1 << (dramaddrw.cfg_cs_addr_width + + dramaddrw.cfg_bank_group_addr_width + + dramaddrw.cfg_bank_addr_width + + dramaddrw.cfg_row_addr_width + + dramaddrw.cfg_col_addr_width)); + + size *= (2 << (readl(&socfpga_ecc_hmc_base->ddrioctrl) & + DDR_HMC_DDRIOCTRL_IOSIZE_MSK)); + + return size; +}