[PATCH] ddr: altera: n5x: Add self-refresh support in DDR4
Jit Loon Lim
jit.loon.lim at intel.com
Tue Nov 22 16:31:03 CET 2022
From: Tien Fong Chee <tien.fong.chee at intel.com>
Enable self-refresh support in DDR4 for retaining DDR4 content with minimal
power when reset is triggered.
Signed-off-by: Tien Fong Chee <tien.fong.chee at intel.com>
Signed-off-by: Jit Loon Lim <jit.loon.lim at intel.com>
---
.../include/mach/system_manager_soc64.h | 3 +-
drivers/ddr/altera/sdram_n5x.c | 751 +++++++++++++++++-
2 files changed, 730 insertions(+), 24 deletions(-)
diff --git a/arch/arm/mach-socfpga/include/mach/system_manager_soc64.h b/arch/arm/mach-socfpga/include/mach/system_manager_soc64.h
index a8009664fe..c2d1f8e4b9 100644
--- a/arch/arm/mach-socfpga/include/mach/system_manager_soc64.h
+++ b/arch/arm/mach-socfpga/include/mach/system_manager_soc64.h
@@ -99,8 +99,7 @@ void populate_sysmgr_pinmux(void);
*/
#define SYSMGR_SCRATCH_REG_0_QSPI_REFCLK_MASK GENMASK(27, 0)
#define ALT_SYSMGR_SCRATCH_REG_0_DDR_RETENTION_MASK BIT(31)
-#define ALT_SYSMGR_SCRATCH_REG_0_DDR_SHA_MASK BIT(30)
-#define ALT_SYSMGR_SCRATCH_REG_0_DDR_RESET_TYPE_MASK (BIT(29) | BIT(28))
+#define ALT_SYSMGR_SCRATCH_REG_0_DDR_RESET_TYPE_MASK GENMASK(30, 28)
#define ALT_SYSMGR_SCRATCH_REG_0_DDR_RESET_TYPE_SHIFT 28
#define SYSMGR_SDMMC SYSMGR_SOC64_SDMMC
diff --git a/drivers/ddr/altera/sdram_n5x.c b/drivers/ddr/altera/sdram_n5x.c
index 5a20a8d78d..135bc8fd7d 100644
--- a/drivers/ddr/altera/sdram_n5x.c
+++ b/drivers/ddr/altera/sdram_n5x.c
@@ -9,6 +9,7 @@
#include <div64.h>
#include <dm.h>
#include <errno.h>
+#include <fs_loader.h>
#include <fdtdec.h>
#include <hang.h>
#include <ram.h>
@@ -21,11 +22,25 @@
#include <asm/arch/reset_manager.h>
#include <asm/arch/system_manager.h>
#include <asm/io.h>
+#include <dm/ofnode.h>
#include <linux/err.h>
#include <linux/sizes.h>
+#include <u-boot/crc.h>
+#include <u-boot/sha512.h>
DECLARE_GLOBAL_DATA_PTR;
+/* PHY calibration data backup attribute */
+#define SOC64_OCRAM_PHY_BACKUP_BASE 0xFFE5E400
+/* "SKIP" */
+#define SOC64_CRAM_PHY_BACKUP_SKIP_MAGIC 0x50494B53
+#define BAC_CAL_MMC_RAW_OFFSET (CONFIG_ENV_SIZE + CONFIG_ENV_OFFSET)
+
+/* DDR handoff SHA384 attribute */
+#define DDR_HANDOFF_IMG_ADDR 0xFFE44000
+#define DDR_HANDOFF_IMG_LEN 0x1A000
+#define CHUNKSZ_PER_WD_RESET (256 * 1024)
+
/* MPFE NOC registers */
#define FPGA2SDRAM_MGR_MAIN_SIDEBANDMGR_FLAGOUTSET0 0xF8024050
@@ -379,6 +394,117 @@ enum message_mode {
STREAMING_MESSAGE
};
+/* Reset type */
+enum reset_type {
+ POR_RESET,
+ WARM_RESET,
+ COLD_RESET,
+ NCONFIG,
+ JTAG_CONFIG,
+ RSU_RECONFIG
+};
+
+enum data_type {
+ HEADER_ONLY,
+ HEADER_DATA
+};
+
+/* Header for backup calibration data */
+struct cal_header_t {
+ u32 header_magic;
+ u32 data_len;
+ u32 caldata_crc32;
+ u8 ddrconfig_hash[SHA384_SUM_LEN];
+} __attribute__ ((__packed__));
+
+/* Header + backup calibration data */
+struct bac_cal_data_t {
+ struct cal_header_t header;
+ u16 data;
+} __attribute__ ((__packed__));
+
+enum data_process {
+ STORE,
+ LOADING
+};
+
+bool is_ddr_retention_enabled(u32 reg)
+{
+ if (reg & ALT_SYSMGR_SCRATCH_REG_0_DDR_RETENTION_MASK)
+ return true;
+
+ return false;
+}
+
+static enum reset_type get_reset_type(u32 reg)
+{
+ return (reg & ALT_SYSMGR_SCRATCH_REG_0_DDR_RESET_TYPE_MASK) >>
+ ALT_SYSMGR_SCRATCH_REG_0_DDR_RESET_TYPE_SHIFT;
+}
+
+void reset_type_print(enum reset_type reset_t)
+{
+ switch (reset_t) {
+ case POR_RESET:
+ printf("%s: POR is triggered\n", __func__);
+ break;
+ case WARM_RESET:
+ printf("%s: Warm reset is triggered\n", __func__);
+ break;
+ case COLD_RESET:
+ printf("%s: Cold reset is triggered\n", __func__);
+ break;
+ case NCONFIG:
+ printf("%s: NCONFIG is triggered\n", __func__);
+ break;
+ case JTAG_CONFIG:
+ printf("%s: JTAG_CONFIG is triggered\n", __func__);
+ break;
+ case RSU_RECONFIG:
+ printf("%s: RSU_RECONFIG is triggered\n", __func__);
+ break;
+ default:
+ printf("%s: Invalid reset type\n", __func__);
+ }
+}
+
+bool is_ddr_init_skipped(u32 reg)
+{
+ enum reset_type reset_t = get_reset_type(reg);
+
+ reset_type_print(reset_t);
+
+ if (reset_t == WARM_RESET) {
+ debug("%s: DDR init is skipped\n", __func__);
+ return true;
+ }
+
+ if (reset_t == COLD_RESET) {
+ if (is_ddr_retention_enabled(reg)) {
+ debug("%s: DDR retention bit is set\n", __func__);
+ debug("%s: DDR init is skipped\n", __func__);
+ return true;
+ }
+ }
+
+ debug("%s: DDR init is required\n", __func__);
+ return false;
+}
+
+bool is_ddr_calibration_skipped(u32 reg)
+{
+ enum reset_type reset_t = get_reset_type(reg);
+
+ if ((reset_t == NCONFIG || reset_t == JTAG_CONFIG ||
+ reset_t == RSU_RECONFIG) && is_ddr_retention_enabled(reg)) {
+ debug("%s: DDR retention bit is set\n", __func__);
+ return true;
+ }
+
+ debug("%s: DDR calibration is required\n", __func__);
+ return false;
+}
+
static int clr_ca_parity_error_status(phys_addr_t umctl2_base)
{
int ret;
@@ -711,6 +837,7 @@ static int scrubber_ddr_config(phys_addr_t umctl2_base,
writel(0, umctl2_base + DDR4_SBRRANGE0_OFFSET);
writel(0, umctl2_base + DDR4_SBRRANGE1_OFFSET);
+ printf("Enabling scrubber ...\n");
/* Enables scrubber */
setbits_le32(umctl2_base + DDR4_SBRCTL_OFFSET, DDR4_SBRCTL_SCRUB_EN);
/* Polling all scrub writes commands have been sent */
@@ -924,8 +1051,513 @@ static int phy_pre_handoff_config(phys_addr_t umctl2_base,
return ret;
}
+static void phy_ocram(phys_addr_t phy_base, phys_addr_t phy_offset,
+ u16 *data, enum data_process proc)
+{
+ u32 abs_addr;
+
+ abs_addr = phy_base + (phy_offset << 1);
+
+ if (proc == STORE) {
+ /* Storing PHY value */
+ writew(readw((uintptr_t)abs_addr), data);
+ debug("%s: PHY offset 0x%08x, data %x\n", __func__,
+ (u32)phy_offset, readw((uintptr_t)data));
+ } else if (proc == LOADING) {
+ /* Loading bak cal data to PHY */
+ writew(readw(data), (uintptr_t)abs_addr);
+ debug("%s: PHY offset 0x%08x, data %x\n", __func__,
+ (u32)phy_offset, readw((uintptr_t)abs_addr));
+ }
+}
+
+static void cal_data_ocram(phys_addr_t phy_base, u32 addr,
+ enum data_process proc)
+{
+ /*
+ * This array variable contains a list of PHY registers required for
+ * backup before DDR entering self-refresh mode
+ */
+ u32 phybak[] = {0x1005f, 0x1015f, 0x1105f, 0x1115f, 0x1205f,
+ 0x1215f, 0x1305f, 0x1315f, 0x1405f, 0x1415f,
+ 0x1505f, 0x1515f, 0x1605f, 0x1615f, 0x1705f,
+ 0x1715f, 0x1805f, 0x1815f, 0x00055, 0x01055,
+ 0x02055, 0x03055, 0x04055, 0x05055, 0x06055,
+ 0x07055, 0x08055, 0x09055, 0x200c5, 0x2002e,
+ 0x20024, 0x2003a, 0x2007d, 0x2007c, 0x20056,
+ 0x1004d, 0x1014d, 0x1104d, 0x1114d, 0x1204d,
+ 0x1214d, 0x1304d, 0x1314d, 0x1404d, 0x1414d,
+ 0x1504d, 0x1514d, 0x1604d, 0x1614d, 0x1704d,
+ 0x1714d, 0x1804d, 0x1814d, 0x10049, 0x10149,
+ 0x11049, 0x11149, 0x12049, 0x12149, 0x13049,
+ 0x13149, 0x14049, 0x14149, 0x15049, 0x15149,
+ 0x16049, 0x16149, 0x17049, 0x17149, 0x18049,
+ 0x18149, 0x00043, 0x01043, 0x02043, 0x03043,
+ 0x04043, 0x05043, 0x06043, 0x07043, 0x08043,
+ 0x09043, 0x20018, 0x20075, 0x20050, 0x2009b,
+ 0x20008, 0x20088, 0x200b2, 0x10043, 0x10143,
+ 0x11043, 0x11143, 0x12043, 0x12143, 0x13043,
+ 0x13143, 0x14043, 0x14143, 0x15043, 0x15143,
+ 0x16043, 0x16143, 0x17043, 0x17143, 0x18043,
+ 0x18143, 0x2005b, 0x2005c, 0x200fa, 0x20019,
+ 0x200f0, 0x200f1, 0x200f2, 0x200f3, 0x200f4,
+ 0x200f5, 0x200f6, 0x200f7, 0x1004a, 0x1104a,
+ 0x1204a, 0x1304a, 0x1404a, 0x1504a, 0x1604a,
+ 0x1704a, 0x1804a, 0x20025, 0x2002d, 0x2002c,
+ 0xd0000, 0x90000, 0x90001, 0x90002, 0x90003,
+ 0x90004, 0x90005, 0x90029, 0x9002a, 0x9002b,
+ 0x9002c, 0x9002d, 0x9002e, 0x9002f, 0x90030,
+ 0x90031, 0x90032, 0x90033, 0x90034, 0x90035,
+ 0x90036, 0x90037, 0x90038, 0x90039, 0x9003a,
+ 0x9003b, 0x9003c, 0x9003d, 0x9003e, 0x9003f,
+ 0x90040, 0x90041, 0x90042, 0x90043, 0x90044,
+ 0x90045, 0x90046, 0x90047, 0x90048, 0x90049,
+ 0x9004a, 0x9004b, 0x9004c, 0x9004d, 0x9004e,
+ 0x9004f, 0x90050, 0x90051, 0x90052, 0x90053,
+ 0x90054, 0x90055, 0x90056, 0x90057, 0x90058,
+ 0x90059, 0x9005a, 0x9005b, 0x9005c, 0x9005d,
+ 0x9005e, 0x9005f, 0x90060, 0x90061, 0x90062,
+ 0x90063, 0x90064, 0x90065, 0x90066, 0x90067,
+ 0x90068, 0x90069, 0x9006a, 0x9006b, 0x9006c,
+ 0x9006d, 0x9006e, 0x9006f, 0x90070, 0x90071,
+ 0x90072, 0x90073, 0x90074, 0x90075, 0x90076,
+ 0x90077, 0x90078, 0x90079, 0x9007a, 0x9007b,
+ 0x9007c, 0x9007d, 0x9007e, 0x9007f, 0x90080,
+ 0x90081, 0x90082, 0x90083, 0x90084, 0x90085,
+ 0x90086, 0x90087, 0x90088, 0x90089, 0x9008a,
+ 0x9008b, 0x9008c, 0x9008d, 0x9008e, 0x9008f,
+ 0x90090, 0x90091, 0x90092, 0x90093, 0x90094,
+ 0x90095, 0x90096, 0x90097, 0x90098, 0x90099,
+ 0x9009a, 0x9009b, 0x9009c, 0x9009d, 0x9009e,
+ 0x9009f, 0x900a0, 0x900a1, 0x900a2, 0x900a3,
+ 0x900a4, 0x900a5, 0x900a6, 0x900a7, 0x900a8,
+ 0x900a9, 0x900aa, 0x900ab, 0x900ac, 0x900ad,
+ 0x900ae, 0x900af, 0x900b0, 0x900b1, 0x900b2,
+ 0x900b3, 0x900b4, 0x900b5, 0x900b6, 0x900b7,
+ 0x900b8, 0x900b9, 0x900ba, 0x900bb, 0x900bc,
+ 0x900bd, 0x900be, 0x900bf, 0x900c0, 0x900c1,
+ 0x900c2, 0x900c3, 0x900c4, 0x900c5, 0x900c6,
+ 0x900c7, 0x90006, 0x90007, 0x90008, 0x90009,
+ 0x9000a, 0x9000b, 0xd00e7, 0x90017, 0x90026,
+ 0x2000b, 0x2000c, 0x2000d, 0x2000e, 0x9000c,
+ 0x9000d, 0x9000e, 0x9000f, 0x90010, 0x90011,
+ 0x90012, 0x90013, 0x20089, 0xc0080, 0x200cb,
+ 0x10068, 0x10069, 0x1006a, 0x1006b, 0x10168,
+ 0x10169, 0x1016a, 0x1016b, 0x10268, 0x10269,
+ 0x1026a, 0x1026b, 0x10368, 0x10369, 0x1036a,
+ 0x1036b, 0x10468, 0x10469, 0x1046a, 0x1046b,
+ 0x10568, 0x10569, 0x1056a, 0x1056b, 0x10668,
+ 0x10669, 0x1066a, 0x1066b, 0x10768, 0x10769,
+ 0x1076a, 0x1076b, 0x10868, 0x10869, 0x1086a,
+ 0x1086b, 0x11068, 0x11069, 0x1106a, 0x1106b,
+ 0x11168, 0x11169, 0x1116a, 0x1116b, 0x11268,
+ 0x11269, 0x1126a, 0x1126b, 0x11368, 0x11369,
+ 0x1136a, 0x1136b, 0x11468, 0x11469, 0x1146a,
+ 0x1146b, 0x11568, 0x11569, 0x1156a, 0x1156b,
+ 0x11668, 0x11669, 0x1166a, 0x1166b, 0x11768,
+ 0x11769, 0x1176a, 0x1176b, 0x11868, 0x11869,
+ 0x1186a, 0x1186b, 0x12068, 0x12069, 0x1206a,
+ 0x1206b, 0x12168, 0x12169, 0x1216a, 0x1216b,
+ 0x12268, 0x12269, 0x1226a, 0x1226b, 0x12368,
+ 0x12369, 0x1236a, 0x1236b, 0x12468, 0x12469,
+ 0x1246a, 0x1246b, 0x12568, 0x12569, 0x1256a,
+ 0x1256b, 0x12668, 0x12669, 0x1266a, 0x1266b,
+ 0x12768, 0x12769, 0x1276a, 0x1276b, 0x12868,
+ 0x12869, 0x1286a, 0x1286b, 0x13068, 0x13069,
+ 0x1306a, 0x1306b, 0x13168, 0x13169, 0x1316a,
+ 0x1316b, 0x13268, 0x13269, 0x1326a, 0x1326b,
+ 0x13368, 0x13369, 0x1336a, 0x1336b, 0x13468,
+ 0x13469, 0x1346a, 0x1346b, 0x13568, 0x13569,
+ 0x1356a, 0x1356b, 0x13668, 0x13669, 0x1366a,
+ 0x1366b, 0x13768, 0x13769, 0x1376a, 0x1376b,
+ 0x13868, 0x13869, 0x1386a, 0x1386b, 0x14068,
+ 0x14069, 0x1406a, 0x1406b, 0x14168, 0x14169,
+ 0x1416a, 0x1416b, 0x14268, 0x14269, 0x1426a,
+ 0x1426b, 0x14368, 0x14369, 0x1436a, 0x1436b,
+ 0x14468, 0x14469, 0x1446a, 0x1446b, 0x14568,
+ 0x14569, 0x1456a, 0x1456b, 0x14668, 0x14669,
+ 0x1466a, 0x1466b, 0x14768, 0x14769, 0x1476a,
+ 0x1476b, 0x14868, 0x14869, 0x1486a, 0x1486b,
+ 0x15068, 0x15069, 0x1506a, 0x1506b, 0x15168,
+ 0x15169, 0x1516a, 0x1516b, 0x15268, 0x15269,
+ 0x1526a, 0x1526b, 0x15368, 0x15369, 0x1536a,
+ 0x1536b, 0x15468, 0x15469, 0x1546a, 0x1546b,
+ 0x15568, 0x15569, 0x1556a, 0x1556b, 0x15668,
+ 0x15669, 0x1566a, 0x1566b, 0x15768, 0x15769,
+ 0x1576a, 0x1576b, 0x15868, 0x15869, 0x1586a,
+ 0x1586b, 0x16068, 0x16069, 0x1606a, 0x1606b,
+ 0x16168, 0x16169, 0x1616a, 0x1616b, 0x16268,
+ 0x16269, 0x1626a, 0x1626b, 0x16368, 0x16369,
+ 0x1636a, 0x1636b, 0x16468, 0x16469, 0x1646a,
+ 0x1646b, 0x16568, 0x16569, 0x1656a, 0x1656b,
+ 0x16668, 0x16669, 0x1666a, 0x1666b, 0x16768,
+ 0x16769, 0x1676a, 0x1676b, 0x16868, 0x16869,
+ 0x1686a, 0x1686b, 0x17068, 0x17069, 0x1706a,
+ 0x1706b, 0x17168, 0x17169, 0x1716a, 0x1716b,
+ 0x17268, 0x17269, 0x1726a, 0x1726b, 0x17368,
+ 0x17369, 0x1736a, 0x1736b, 0x17468, 0x17469,
+ 0x1746a, 0x1746b, 0x17568, 0x17569, 0x1756a,
+ 0x1756b, 0x17668, 0x17669, 0x1766a, 0x1766b,
+ 0x17768, 0x17769, 0x1776a, 0x1776b, 0x17868,
+ 0x17869, 0x1786a, 0x1786b, 0x18068, 0x18069,
+ 0x1806a, 0x1806b, 0x18168, 0x18169, 0x1816a,
+ 0x1816b, 0x18268, 0x18269, 0x1826a, 0x1826b,
+ 0x18368, 0x18369, 0x1836a, 0x1836b, 0x18468,
+ 0x18469, 0x1846a, 0x1846b, 0x18568, 0x18569,
+ 0x1856a, 0x1856b, 0x18668, 0x18669, 0x1866a,
+ 0x1866b, 0x18768, 0x18769, 0x1876a, 0x1876b,
+ 0x18868, 0x18869, 0x1886a, 0x1886b, 0x00080,
+ 0x01080, 0x02080, 0x03080, 0x04080, 0x05080,
+ 0x06080, 0x07080, 0x08080, 0x09080, 0x10020,
+ 0x10080, 0x10081, 0x10082, 0x10083, 0x100d0,
+ 0x100d1, 0x100d2, 0x100d3, 0x1008c, 0x1008d,
+ 0x1008e, 0x1008f, 0x10180, 0x10181, 0x10182,
+ 0x10183, 0x101d0, 0x101d1, 0x101d2, 0x101d3,
+ 0x1018c, 0x1018d, 0x1018e, 0x1018f, 0x100c0,
+ 0x100c1, 0x100c2, 0x100c3, 0x101c0, 0x101c1,
+ 0x101c2, 0x101c3, 0x102c0, 0x102c1, 0x102c2,
+ 0x102c3, 0x103c0, 0x103c1, 0x103c2, 0x103c3,
+ 0x104c0, 0x104c1, 0x104c2, 0x104c3, 0x105c0,
+ 0x105c1, 0x105c2, 0x105c3, 0x106c0, 0x106c1,
+ 0x106c2, 0x106c3, 0x107c0, 0x107c1, 0x107c2,
+ 0x107c3, 0x108c0, 0x108c1, 0x108c2, 0x108c3,
+ 0x11020, 0x11080, 0x11081, 0x11082, 0x11083,
+ 0x110d0, 0x110d1, 0x110d2, 0x110d3, 0x1108c,
+ 0x1108d, 0x1108e, 0x1108f, 0x11180, 0x11181,
+ 0x11182, 0x11183, 0x111d0, 0x111d1, 0x111d2,
+ 0x111d3, 0x1118c, 0x1118d, 0x1118e, 0x1118f,
+ 0x110c0, 0x110c1, 0x110c2, 0x110c3, 0x111c0,
+ 0x111c1, 0x111c2, 0x111c3, 0x112c0, 0x112c1,
+ 0x112c2, 0x112c3, 0x113c0, 0x113c1, 0x113c2,
+ 0x113c3, 0x114c0, 0x114c1, 0x114c2, 0x114c3,
+ 0x115c0, 0x115c1, 0x115c2, 0x115c3, 0x116c0,
+ 0x116c1, 0x116c2, 0x116c3, 0x117c0, 0x117c1,
+ 0x117c2, 0x117c3, 0x118c0, 0x118c1, 0x118c2,
+ 0x118c3, 0x12020, 0x12080, 0x12081, 0x12082,
+ 0x12083, 0x120d0, 0x120d1, 0x120d2, 0x120d3,
+ 0x1208c, 0x1208d, 0x1208e, 0x1208f, 0x12180,
+ 0x12181, 0x12182, 0x12183, 0x121d0, 0x121d1,
+ 0x121d2, 0x121d3, 0x1218c, 0x1218d, 0x1218e,
+ 0x1218f, 0x120c0, 0x120c1, 0x120c2, 0x120c3,
+ 0x121c0, 0x121c1, 0x121c2, 0x121c3, 0x122c0,
+ 0x122c1, 0x122c2, 0x122c3, 0x123c0, 0x123c1,
+ 0x123c2, 0x123c3, 0x124c0, 0x124c1, 0x124c2,
+ 0x124c3, 0x125c0, 0x125c1, 0x125c2, 0x125c3,
+ 0x126c0, 0x126c1, 0x126c2, 0x126c3, 0x127c0,
+ 0x127c1, 0x127c2, 0x127c3, 0x128c0, 0x128c1,
+ 0x128c2, 0x128c3, 0x13020, 0x13080, 0x13081,
+ 0x13082, 0x13083, 0x130d0, 0x130d1, 0x130d2,
+ 0x130d3, 0x1308c, 0x1308d, 0x1308e, 0x1308f,
+ 0x13180, 0x13181, 0x13182, 0x13183, 0x131d0,
+ 0x131d1, 0x131d2, 0x131d3, 0x1318c, 0x1318d,
+ 0x1318e, 0x1318f, 0x130c0, 0x130c1, 0x130c2,
+ 0x130c3, 0x131c0, 0x131c1, 0x131c2, 0x131c3,
+ 0x132c0, 0x132c1, 0x132c2, 0x132c3, 0x133c0,
+ 0x133c1, 0x133c2, 0x133c3, 0x134c0, 0x134c1,
+ 0x134c2, 0x134c3, 0x135c0, 0x135c1, 0x135c2,
+ 0x135c3, 0x136c0, 0x136c1, 0x136c2, 0x136c3,
+ 0x137c0, 0x137c1, 0x137c2, 0x137c3, 0x138c0,
+ 0x138c1, 0x138c2, 0x138c3, 0x14020, 0x14080,
+ 0x14081, 0x14082, 0x14083, 0x140d0, 0x140d1,
+ 0x140d2, 0x140d3, 0x1408c, 0x1408d, 0x1408e,
+ 0x1408f, 0x14180, 0x14181, 0x14182, 0x14183,
+ 0x141d0, 0x141d1, 0x141d2, 0x141d3, 0x1418c,
+ 0x1418d, 0x1418e, 0x1418f, 0x140c0, 0x140c1,
+ 0x140c2, 0x140c3, 0x141c0, 0x141c1, 0x141c2,
+ 0x141c3, 0x142c0, 0x142c1, 0x142c2, 0x142c3,
+ 0x143c0, 0x143c1, 0x143c2, 0x143c3, 0x144c0,
+ 0x144c1, 0x144c2, 0x144c3, 0x145c0, 0x145c1,
+ 0x145c2, 0x145c3, 0x146c0, 0x146c1, 0x146c2,
+ 0x146c3, 0x147c0, 0x147c1, 0x147c2, 0x147c3,
+ 0x148c0, 0x148c1, 0x148c2, 0x148c3, 0x15020,
+ 0x15080, 0x15081, 0x15082, 0x15083, 0x150d0,
+ 0x150d1, 0x150d2, 0x150d3, 0x1508c, 0x1508d,
+ 0x1508e, 0x1508f, 0x15180, 0x15181, 0x15182,
+ 0x15183, 0x151d0, 0x151d1, 0x151d2, 0x151d3,
+ 0x1518c, 0x1518d, 0x1518e, 0x1518f, 0x150c0,
+ 0x150c1, 0x150c2, 0x150c3, 0x151c0, 0x151c1,
+ 0x151c2, 0x151c3, 0x152c0, 0x152c1, 0x152c2,
+ 0x152c3, 0x153c0, 0x153c1, 0x153c2, 0x153c3,
+ 0x154c0, 0x154c1, 0x154c2, 0x154c3, 0x155c0,
+ 0x155c1, 0x155c2, 0x155c3, 0x156c0, 0x156c1,
+ 0x156c2, 0x156c3, 0x157c0, 0x157c1, 0x157c2,
+ 0x157c3, 0x158c0, 0x158c1, 0x158c2, 0x158c3,
+ 0x16020, 0x16080, 0x16081, 0x16082, 0x16083,
+ 0x160d0, 0x160d1, 0x160d2, 0x160d3, 0x1608c,
+ 0x1608d, 0x1608e, 0x1608f, 0x16180, 0x16181,
+ 0x16182, 0x16183, 0x161d0, 0x161d1, 0x161d2,
+ 0x161d3, 0x1618c, 0x1618d, 0x1618e, 0x1618f,
+ 0x160c0, 0x160c1, 0x160c2, 0x160c3, 0x161c0,
+ 0x161c1, 0x161c2, 0x161c3, 0x162c0, 0x162c1,
+ 0x162c2, 0x162c3, 0x163c0, 0x163c1, 0x163c2,
+ 0x163c3, 0x164c0, 0x164c1, 0x164c2, 0x164c3,
+ 0x165c0, 0x165c1, 0x165c2, 0x165c3, 0x166c0,
+ 0x166c1, 0x166c2, 0x166c3, 0x167c0, 0x167c1,
+ 0x167c2, 0x167c3, 0x168c0, 0x168c1, 0x168c2,
+ 0x168c3, 0x17020, 0x17080, 0x17081, 0x17082,
+ 0x17083, 0x170d0, 0x170d1, 0x170d2, 0x170d3,
+ 0x1708c, 0x1708d, 0x1708e, 0x1708f, 0x17180,
+ 0x17181, 0x17182, 0x17183, 0x171d0, 0x171d1,
+ 0x171d2, 0x171d3, 0x1718c, 0x1718d, 0x1718e,
+ 0x1718f, 0x170c0, 0x170c1, 0x170c2, 0x170c3,
+ 0x171c0, 0x171c1, 0x171c2, 0x171c3, 0x172c0,
+ 0x172c1, 0x172c2, 0x172c3, 0x173c0, 0x173c1,
+ 0x173c2, 0x173c3, 0x174c0, 0x174c1, 0x174c2,
+ 0x174c3, 0x175c0, 0x175c1, 0x175c2, 0x175c3,
+ 0x176c0, 0x176c1, 0x176c2, 0x176c3, 0x177c0,
+ 0x177c1, 0x177c2, 0x177c3, 0x178c0, 0x178c1,
+ 0x178c2, 0x178c3, 0x18020, 0x18080, 0x18081,
+ 0x18082, 0x18083, 0x180d0, 0x180d1, 0x180d2,
+ 0x180d3, 0x1808c, 0x1808d, 0x1808e, 0x1808f,
+ 0x18180, 0x18181, 0x18182, 0x18183, 0x181d0,
+ 0x181d1, 0x181d2, 0x181d3, 0x1818c, 0x1818d,
+ 0x1818e, 0x1818f, 0x180c0, 0x180c1, 0x180c2,
+ 0x180c3, 0x181c0, 0x181c1, 0x181c2, 0x181c3,
+ 0x182c0, 0x182c1, 0x182c2, 0x182c3, 0x183c0,
+ 0x183c1, 0x183c2, 0x183c3, 0x184c0, 0x184c1,
+ 0x184c2, 0x184c3, 0x185c0, 0x185c1, 0x185c2,
+ 0x185c3, 0x186c0, 0x186c1, 0x186c2, 0x186c3,
+ 0x187c0, 0x187c1, 0x187c2, 0x187c3, 0x188c0,
+ 0x188c1, 0x188c2, 0x188c3, 0x90201, 0x90202,
+ 0x90203, 0x90204, 0x90205, 0x90206, 0x90207,
+ 0x90208, 0x20077, 0x10040, 0x10030, 0x10140,
+ 0x10130, 0x10240, 0x10230, 0x10340, 0x10330,
+ 0x10440, 0x10430, 0x10540, 0x10530, 0x10640,
+ 0x10630, 0x10740, 0x10730, 0x10840, 0x10830,
+ 0x11040, 0x11030, 0x11140, 0x11130, 0x11240,
+ 0x11230, 0x11340, 0x11330, 0x11440, 0x11430,
+ 0x11540, 0x11530, 0x11640, 0x11630, 0x11740,
+ 0x11730, 0x11840, 0x11830, 0x12040, 0x12030,
+ 0x12140, 0x12130, 0x12240, 0x12230, 0x12340,
+ 0x12330, 0x12440, 0x12430, 0x12540, 0x12530,
+ 0x12640, 0x12630, 0x12740, 0x12730, 0x12840,
+ 0x12830, 0x13040, 0x13030, 0x13140, 0x13130,
+ 0x13240, 0x13230, 0x13340, 0x13330, 0x13440,
+ 0x13430, 0x13540, 0x13530, 0x13640, 0x13630,
+ 0x13740, 0x13730, 0x13840, 0x13830, 0x14040,
+ 0x14030, 0x14140, 0x14130, 0x14240, 0x14230,
+ 0x14340, 0x14330, 0x14440, 0x14430, 0x14540,
+ 0x14530, 0x14640, 0x14630, 0x14740, 0x14730,
+ 0x14840, 0x14830, 0x15040, 0x15030, 0x15140,
+ 0x15130, 0x15240, 0x15230, 0x15340, 0x15330,
+ 0x15440, 0x15430, 0x15540, 0x15530, 0x15640,
+ 0x15630, 0x15740, 0x15730, 0x15840, 0x15830,
+ 0x16040, 0x16030, 0x16140, 0x16130, 0x16240,
+ 0x16230, 0x16340, 0x16330, 0x16440, 0x16430,
+ 0x16540, 0x16530, 0x16640, 0x16630, 0x16740,
+ 0x16730, 0x16840, 0x16830, 0x17040, 0x17030,
+ 0x17140, 0x17130, 0x17240, 0x17230, 0x17340,
+ 0x17330, 0x17440, 0x17430, 0x17540, 0x17530,
+ 0x17640, 0x17630, 0x17740, 0x17730, 0x17840,
+ 0x17830, 0x18040, 0x18030, 0x18140, 0x18130,
+ 0x18240, 0x18230, 0x18340, 0x18330, 0x18440,
+ 0x18430, 0x18540, 0x18530, 0x18640, 0x18630,
+ 0x18740, 0x18730, 0x18840, 0x18830};
+ size_t phybak_num;
+ u32 *phybak_p = phybak;
+ u16 *data;
+ struct bac_cal_data_t *cal = (struct bac_cal_data_t *)
+ ((uintptr_t)addr);
+
+ /* Enable access to the PHY configuration registers */
+ clrbits_le16(phy_base + DDR_PHY_APBONLY0_OFFSET,
+ DDR_PHY_MICROCONTMUXSEL);
+
+ phybak_num = ARRAY_SIZE(phybak);
+
+ debug("%s: Total PHY backup %d registers\n", __func__,
+ (int)phybak_num);
+
+ if (proc == STORE) {
+ debug("%s: Storing PHY bak calibration to OCRAM ...\n",
+ __func__);
+ /* Creating header */
+ /* Write PHY magic number */
+ cal->header.header_magic = SOC64_HANDOFF_DDR_PHY_MAGIC;
+ cal->header.data_len = phybak_num * sizeof(*data);
+ } else if (proc == LOADING) {
+ debug("%s: Loading bak calibration to PHY from OCRAM ...\n",
+ __func__);
+ }
+
+ data = &cal->data;
+ while (phybak_num) {
+ phy_ocram(phy_base, *phybak_p, data, proc);
+ phybak_p++;
+ phybak_num--;
+ data++;
+ WATCHDOG_RESET();
+ };
+
+ if (proc == STORE) {
+ /* Creating header */
+ /* Generate HASH384 from the DDR config */
+ sha384_csum_wd((u8 *)DDR_HANDOFF_IMG_ADDR,
+ DDR_HANDOFF_IMG_LEN,
+ cal->header.ddrconfig_hash,
+ CHUNKSZ_PER_WD_RESET);
+
+ crc32_wd_buf((u8 *)&cal->data, cal->header.data_len,
+ (u8 *)&cal->header.caldata_crc32,
+ CHUNKSZ_PER_WD_RESET);
+ }
+
+ /* Isolate the APB access from internal CSRs */
+ setbits_le16(phy_base + DDR_PHY_APBONLY0_OFFSET,
+ DDR_PHY_MICROCONTMUXSEL);
+}
+
+static bool is_ddrconfig_hash_match(const void *buffer)
+{
+ int ret;
+ u8 hash[SHA384_SUM_LEN];
+
+ /* Magic symbol in first 4 bytes of header */
+ struct cal_header_t *header = (struct cal_header_t *)buffer;
+
+ /* Generate HASH384 from the image */
+ sha384_csum_wd((u8 *)DDR_HANDOFF_IMG_ADDR, DDR_HANDOFF_IMG_LEN,
+ hash, CHUNKSZ_PER_WD_RESET);
+
+ ret = memcmp((void *)hash, (const void *)header->ddrconfig_hash,
+ SHA384_SUM_LEN);
+ if (ret) {
+ debug("%s: DDR config hash mismatch\n", __func__);
+ return false;
+ }
+
+ return true;
+}
+
+static ofnode get_ddr_ofnode(ofnode from)
+{
+ return ofnode_by_compatible(from, "intel,sdr-ctl-dm");
+}
+
+static const char *get_ddrcal_ddr_offset(void)
+{
+ const char *ddr_offset = NULL;
+
+ ofnode ddr_node = get_ddr_ofnode(ofnode_null());
+
+ if (ofnode_valid(ddr_node))
+ ddr_offset = ofnode_read_string(ddr_node,
+ "intel,ddrcal-ddr-offset");
+
+ return ddr_offset;
+}
+
+static const char *get_ddrcal_qspi_offset(void)
+{
+ const char *qspi_offset = NULL;
+
+ ofnode ddr_node = get_ddr_ofnode(ofnode_null());
+
+ if (ofnode_valid(ddr_node))
+ qspi_offset = ofnode_read_string(ddr_node,
+ "intel,ddrcal-qspi-offset");
+
+ return qspi_offset;
+}
+
+static bool is_cal_bak_data_valid(void)
+{
+ int ret, size;
+ struct udevice *dev;
+ ofnode node;
+ const fdt32_t *phandle_p;
+ u32 phandle, crc32;
+ const char *qspi_offset = get_ddrcal_qspi_offset();
+ struct bac_cal_data_t *cal = (struct bac_cal_data_t *)((uintptr_t)
+ SOC64_OCRAM_PHY_BACKUP_BASE);
+
+ node = get_ddr_ofnode(ofnode_null());
+
+ if (ofnode_valid(node)) {
+ phandle_p = ofnode_get_property(node, "firmware-loader",
+ &size);
+ if (!phandle_p) {
+ node = ofnode_path("/chosen");
+ if (!ofnode_valid(node)) {
+ debug("%s: /chosen node was not found.\n",
+ __func__);
+ return false;
+ }
+
+ phandle_p = ofnode_get_property(node,
+ "firmware-loader",
+ &size);
+ if (!phandle_p) {
+ debug("%s: firmware-loader property ",
+ __func__);
+ debug("was not found.\n");
+ return false;
+ }
+ }
+ } else {
+ debug("%s: DDR node was not found.\n", __func__);
+ return false;
+ }
+
+ phandle = fdt32_to_cpu(*phandle_p);
+ ret = uclass_get_device_by_phandle_id(UCLASS_FS_FIRMWARE_LOADER,
+ phandle, &dev);
+ if (ret)
+ return false;
+
+ /* Load DDR bak cal header into OCRAM buffer */
+ ret = request_firmware_into_buf(dev,
+ qspi_offset,
+ (void *)SOC64_OCRAM_PHY_BACKUP_BASE,
+ sizeof(struct cal_header_t), 0);
+ if (ret < 0) {
+ debug("%s: Failed to read bak cal header from flash.\n",
+ __func__);
+ return false;
+ }
+
+ if (cal->header.header_magic != SOC64_HANDOFF_DDR_PHY_MAGIC) {
+ debug("%s: No magic found in cal backup header\n", __func__);
+ return false;
+ }
+
+ /* Load header + DDR bak cal into OCRAM buffer */
+ ret = request_firmware_into_buf(dev,
+ qspi_offset,
+ (void *)SOC64_OCRAM_PHY_BACKUP_BASE,
+ cal->header.data_len +
+ sizeof(struct cal_header_t),
+ 0);
+ if (ret < 0) {
+ debug("FPGA: Failed to read DDR bak cal data from flash.\n");
+ return false;
+ }
+
+ crc32_wd_buf((u8 *)&cal->data, cal->header.data_len,
+ (u8 *)&crc32, CHUNKSZ_PER_WD_RESET);
+ debug("%s: crc32 %x for bak calibration data from QSPI\n", __func__,
+ crc32);
+ if (crc32 != cal->header.caldata_crc32) {
+ debug("%s: CRC32 mismatch for calibration backup data\n",
+ __func__);
+ return false;
+ }
+
+ if (!is_ddrconfig_hash_match((const void *)
+ SOC64_OCRAM_PHY_BACKUP_BASE)) {
+ debug("%s: HASH mismatch for DDR config data\n", __func__);
+ return false;
+ }
+
+ return true;
+}
+
static int init_phy(struct ddr_handoff *ddr_handoff_info)
{
+ u32 handoff_table[ddr_handoff_info->phy_handoff_length];
+ u32 i, value;
+ u32 reg = readl(socfpga_get_sysmgr_addr() +
+ SYSMGR_SOC64_BOOT_SCRATCH_COLD0);
int ret;
printf("Initializing DDR PHY ...\n");
@@ -950,6 +1582,31 @@ static int init_phy(struct ddr_handoff *ddr_handoff_info)
handoff_process(ddr_handoff_info, ddr_handoff_info->phy_handoff_base,
ddr_handoff_info->phy_handoff_length,
ddr_handoff_info->phy_base);
+ if (is_ddr_calibration_skipped(reg)) {
+ if (is_cal_bak_data_valid())
+ *need_calibrate = false;
+ else
+ *need_calibrate = true;
+ }
+
+ debug("%s: Need calibrate %d\n", __func__, *need_calibrate);
+
+ if (*need_calibrate) {
+ /* Execute PHY configuration handoff */
+ handoff_process(ddr_handoff_info, ddr_handoff_info->phy_handoff_base,
+ ddr_handoff_info->phy_handoff_length,
+ ddr_handoff_info->phy_base);
+ } else {
+ cal_data_ocram(ddr_handoff_info->phy_base,
+ SOC64_OCRAM_PHY_BACKUP_BASE, LOADING);
+
+ /*
+ * Invalidate the section used for processing the PHY
+ * backup calibration data
+ */
+ writel(SOC64_CRAM_PHY_BACKUP_SKIP_MAGIC,
+ SOC64_OCRAM_PHY_BACKUP_BASE);
+ }
printf("DDR PHY configuration is completed\n");
@@ -1161,6 +1818,14 @@ int populate_ddr_handoff(struct ddr_handoff *handoff)
debug("user setting data\n");
return -ENOEXEC;
}
+
+ /* Checking DDR handoff is overflow? */
+ if (SOC64_OCRAM_PHY_BACKUP_BASE <=
+ (handoff->phy_engine_handoff_base +
+ handoff->phy_engine_total_length)) {
+ printf("%s: DDR handoff is overflow\n ", __func__);
+ return -ENOEXEC;
+ }
} else {
debug("%s: Wrong format for DDR handoff, expect PHY",
__func__);
@@ -1334,7 +1999,8 @@ static int ddr_trigger_sdram_init(phys_addr_t umctl2_base,
}
static int ddr_post_handoff_config(phys_addr_t umctl2_base,
- enum ddr_type umctl2_type)
+ enum ddr_type umctl2_type,
+ bool *need_calibrate)
{
int ret = 0;
u32 value;
@@ -1364,11 +2030,13 @@ static int ddr_post_handoff_config(phys_addr_t umctl2_base,
/* Checking ECC is enabled? */
value = readl(umctl2_base + DDR4_ECCCFG0_OFFSET) & DDR4_ECC_MODE;
- if (value) {
+ if (value)
printf("ECC is enabled\n");
+
+ if (value && *need_calibrate) {
ret = scrubber_ddr_config(umctl2_base, umctl2_type);
if (ret)
- printf("Failed to enable ECC\n");
+ printf("Failed to enable scrubber\n");
}
return ret;
@@ -2064,18 +2732,19 @@ static int trigger_sdram_init(struct ddr_handoff *handoff)
return ret;
}
-static int ddr_post_config(struct ddr_handoff *handoff)
+static int ddr_post_config(struct ddr_handoff *handoff, bool *need_calibrate)
{
int ret;
- ret = ddr_post_handoff_config(handoff->cntlr_base,
- handoff->cntlr_t);
+ ret = ddr_post_handoff_config(handoff->cntlr_base, handoff->cntlr_t,
+ need_calibrate);
if (ret)
return ret;
if (handoff->cntlr2_t == DDRTYPE_LPDDR4_1)
ret = ddr_post_handoff_config(handoff->cntlr2_base,
- handoff->cntlr2_t);
+ handoff->cntlr2_t,
+ need_calibrate);
return ret;
}
@@ -2149,7 +2818,13 @@ bool is_ddr_init(void)
int sdram_mmr_init_full(struct udevice *dev)
{
u32 user_backup[2], user_backup_2nd[2];
+ u32 reg = readl(socfpga_get_sysmgr_addr() +
+ SYSMGR_SOC64_BOOT_SCRATCH_COLD0);
int ret;
+ bool need_calibrate = true;
+ ulong ddr_offset;
+ char *endptr;
+ const char *offset = get_ddrcal_ddr_offset();
struct bd_info bd;
struct ddr_handoff ddr_handoff_info;
struct altera_sdram_priv *priv = dev_get_priv(dev);
@@ -2165,13 +2840,19 @@ int sdram_mmr_init_full(struct udevice *dev)
/* Set the MPFE NoC mux to correct DDR controller type */
use_ddr4(ddr_handoff_info.cntlr_t);
- if (is_ddr_init()) {
+ /*
+ * Invalidate the section used for processing the PHY backup
+ * calibration data
+ */
+ writel(SOC64_CRAM_PHY_BACKUP_SKIP_MAGIC, SOC64_OCRAM_PHY_BACKUP_BASE);
+
+ if (!is_ddr_init_skipped(reg)) {
printf("SDRAM init in progress ...\n");
/*
- * Polling reset complete, must be high to ensure DDR subsystem
- * in complete reset state before init DDR clock and DDR
- * controller
+ * Polling reset complete, must be high to ensure DDR
+ * subsystem in complete reset state before init DDR clock
+ * and DDR controller
*/
ret = wait_for_bit_le32((const void *)((uintptr_t)(readl
(ddr_handoff_info.mem_reset_base) +
@@ -2206,7 +2887,7 @@ int sdram_mmr_init_full(struct udevice *dev)
printf("DDR controller configuration is completed\n");
/* Initialize DDR PHY */
- ret = init_phy(&ddr_handoff_info);
+ ret = init_phy(&ddr_handoff_info, &need_calibrate);
if (ret) {
debug("%s: Failed to inilialize DDR PHY\n", __func__);
return ret;
@@ -2214,21 +2895,43 @@ int sdram_mmr_init_full(struct udevice *dev)
enable_phy_clk_for_csr_access(&ddr_handoff_info, true);
- ret = start_ddr_calibration(&ddr_handoff_info);
- if (ret) {
- debug("%s: Failed to calibrate DDR\n", __func__);
- return ret;
- }
+ if (need_calibrate) {
+ ret = start_ddr_calibration(&ddr_handoff_info);
+ if (ret) {
+ debug("%s: Failed to calibrate DDR\n",
+ __func__);
+ return ret;
+ }
- enable_phy_clk_for_csr_access(&ddr_handoff_info, false);
+ /* DDR freq set to support DDR4-3200 */
+ phy_init_engine(&ddr_handoff_info);
- /* Reset ARC processor when no using for security purpose */
+ /*
+ * Backup calibration data to OCRAM first, these data
+ * might be permanant stored to flash in later
+ */
+ if (is_ddr_retention_enabled(reg))
+ cal_data_ocram(ddr_handoff_info.phy_base,
+ SOC64_OCRAM_PHY_BACKUP_BASE,
+ STORE);
+
+ } else {
+ /* Updating training result to DDR controller */
+ ret = update_training_result(&ddr_handoff_info);
+ if (ret)
+ return ret;
+ }
+
+ /*
+ * Reset ARC processor when no using for security
+ * purpose
+ */
setbits_le16(ddr_handoff_info.phy_base +
DDR_PHY_MICRORESET_OFFSET,
DDR_PHY_MICRORESET_RESET);
/* DDR freq set to support DDR4-3200 */
- phy_init_engine(&ddr_handoff_info);
+ enable_phy_clk_for_csr_access(&ddr_handoff_info, false);
ret = dfi_init(&ddr_handoff_info);
if (ret)
@@ -2242,7 +2945,7 @@ int sdram_mmr_init_full(struct udevice *dev)
if (ret)
return ret;
- ret = ddr_post_config(&ddr_handoff_info);
+ ret = ddr_post_config(&ddr_handoff_info, &need_calibrate);
if (ret)
return ret;
@@ -2291,8 +2994,12 @@ int sdram_mmr_init_full(struct udevice *dev)
priv->info.size = gd->ram_size;
sdram_size_check(&bd);
-
sdram_set_firewall(&bd);
+ ddr_offset = simple_strtoul(offset, &endptr, 16);
+ if (!(offset == endptr || *endptr != '\0'))
+ memcpy((void *)ddr_offset,
+ (const void *)SOC64_OCRAM_PHY_BACKUP_BASE, SZ_4K);
+
return 0;
}
--
2.26.2
More information about the U-Boot
mailing list