[U-Boot] [PATCH] keystone2: use SPD info to configure K2HK and K2E DDR3

Vitaly Andrianov vitalya at ti.com
Mon Jun 15 14:32:21 CEST 2015


This commit replaces hard-coded EMIF and PHY DDR3 configurations for
predefined SODIMMs to a calculated configuration. The SODIMM parameters
are read from SODIMM's SPD and used to calculated the configuration.

The current commit supports calculation for DDR3 with 1600MHz and 1333MHz
only.

Signed-off-by: Vitaly Andrianov <vitalya at ti.com>
---
 board/ti/ks2_evm/Makefile    |   5 +-
 board/ti/ks2_evm/ddr3_cfg.c  |   2 +
 board/ti/ks2_evm/ddr3_cfg.h  |  10 +-
 board/ti/ks2_evm/ddr3_k2e.c  |  56 ++---
 board/ti/ks2_evm/ddr3_k2hk.c | 103 ++++-----
 board/ti/ks2_evm/ddr3_spd.c  | 531 +++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 616 insertions(+), 91 deletions(-)
 create mode 100644 board/ti/ks2_evm/ddr3_spd.c

diff --git a/board/ti/ks2_evm/Makefile b/board/ti/ks2_evm/Makefile
index 071dbee..c888ab3 100644
--- a/board/ti/ks2_evm/Makefile
+++ b/board/ti/ks2_evm/Makefile
@@ -1,6 +1,6 @@
 #
 # KS2-EVM: board Makefile
-# (C) Copyright 2012-2014
+# (C) Copyright 2012-2015
 #     Texas Instruments Incorporated, <www.ti.com>
 # SPDX-License-Identifier:     GPL-2.0+
 #
@@ -9,7 +9,10 @@ obj-y += board.o
 obj-y += ddr3_cfg.o
 obj-$(CONFIG_K2HK_EVM) += board_k2hk.o
 obj-$(CONFIG_K2HK_EVM) += ddr3_k2hk.o
+obj-$(CONFIG_K2HK_EVM) += ddr3_spd.o
 obj-$(CONFIG_K2E_EVM) += board_k2e.o
 obj-$(CONFIG_K2E_EVM) += ddr3_k2e.o
+obj-$(CONFIG_K2E_EVM) += ddr3_spd.o
 obj-$(CONFIG_K2L_EVM) += board_k2l.o
 obj-$(CONFIG_K2L_EVM) += ddr3_k2l.o
+
diff --git a/board/ti/ks2_evm/ddr3_cfg.c b/board/ti/ks2_evm/ddr3_cfg.c
index ab44676..34b4103 100644
--- a/board/ti/ks2_evm/ddr3_cfg.c
+++ b/board/ti/ks2_evm/ddr3_cfg.c
@@ -169,6 +169,7 @@ struct ddr3_emif_config ddr3_1600_2g = {
 	.sdrfc          = 0x00001869ul,
 };
 
+#ifndef CONFIG_SOC_K2HK
 int ddr3_get_dimm_params(char *dimm_name)
 {
 	int ret;
@@ -204,3 +205,4 @@ int ddr3_get_dimm_params(char *dimm_name)
 
 	return 0;
 }
+#endif
diff --git a/board/ti/ks2_evm/ddr3_cfg.h b/board/ti/ks2_evm/ddr3_cfg.h
index 5bd786c..5084508 100644
--- a/board/ti/ks2_evm/ddr3_cfg.h
+++ b/board/ti/ks2_evm/ddr3_cfg.h
@@ -10,18 +10,22 @@
 #ifndef __DDR3_CFG_H
 #define __DDR3_CFG_H
 
+extern struct ddr3_phy_config phy_spd_cfg;
+extern struct ddr3_emif_config emif_spd_cfg;
+int ddr3_get_dimm_params_from_spd(u8 *spd_params, int *ddr_clk,
+				  int *ddr_size);
+
 extern struct ddr3_phy_config ddr3phy_1600_8g;
 extern struct ddr3_emif_config ddr3_1600_8g;
 
 extern struct ddr3_phy_config ddr3phy_1333_2g;
 extern struct ddr3_emif_config ddr3_1333_2g;
 
-extern struct ddr3_phy_config ddr3phy_1600_4g;
-extern struct ddr3_emif_config ddr3_1600_4g;
-
 extern struct ddr3_phy_config ddr3phy_1600_2g;
 extern struct ddr3_emif_config ddr3_1600_2g;
 
 int ddr3_get_dimm_params(char *dimm_name);
 
+
+
 #endif /* __DDR3_CFG_H */
diff --git a/board/ti/ks2_evm/ddr3_k2e.c b/board/ti/ks2_evm/ddr3_k2e.c
index 35ffb42..adc2947 100644
--- a/board/ti/ks2_evm/ddr3_k2e.c
+++ b/board/ti/ks2_evm/ddr3_k2e.c
@@ -1,7 +1,7 @@
 /*
  * Keystone2: DDR3 initialization
  *
- * (C) Copyright 2014
+ * (C) Copyright 2014-2015
  *     Texas Instruments Incorporated, <www.ti.com>
  *
  * SPDX-License-Identifier:     GPL-2.0+
@@ -12,42 +12,46 @@
 #include <asm/arch/ddr3.h>
 
 static struct pll_init_data ddr3_400 = DDR3_PLL_400;
+static struct pll_init_data ddr3_333 = DDR3_PLL_333;
 
 u32 ddr3_init(void)
 {
-	u32 ddr3_size;
 	char dimm_name[32];
+	u8   spd_buf[256];
+	int  ddr_speed;
+	int  ddr_size;
 
-	if (~(readl(KS2_PLL_CNTRL_BASE + KS2_RSTCTRL_RSTYPE) & 0x1))
-		init_pll(&ddr3_400);
+	struct ddr3_phy_config *phy_cfg = &phy_spd_cfg;
+	struct ddr3_emif_config *emif_cfg = &emif_spd_cfg;
 
-	ddr3_get_dimm_params(dimm_name);
+	if (ddr3_get_dimm_params_from_spd(spd_buf, &ddr_speed, &ddr_size)) {
+		printf("Sorry, I don't know how to configure DDR3A.\n"
+		       "Bye :(\n");
+		for (;;)
+			;
+	}
+
+	strncpy(dimm_name, (char *)&spd_buf[0x80], 18);
+	dimm_name[18] = '\0';
 
 	printf("Detected SO-DIMM [%s]\n", dimm_name);
 
+	printf("DDR3 speed %d\n", ddr_speed);
+	if (ddr_speed == 1600)
+		init_pll(&ddr3_400);
+	else
+		init_pll(&ddr3_333);
+
 	/* Reset DDR3 PHY after PLL enabled */
 	ddr3_reset_ddrphy();
 
-	if (!strcmp(dimm_name, "18KSF1G72HZ-1G6E2 ")) {
-		/* 8G SO-DIMM */
-		ddr3_size = 8;
-		printf("DRAM: 8 GiB\n");
-		ddr3phy_1600_8g.zq0cr1 |= 0x10000;
-		ddr3phy_1600_8g.zq1cr1 |= 0x10000;
-		ddr3phy_1600_8g.zq2cr1 |= 0x10000;
-		ddr3_init_ddrphy(KS2_DDR3A_DDRPHYC, &ddr3phy_1600_8g);
-		ddr3_init_ddremif(KS2_DDR3A_EMIF_CTRL_BASE, &ddr3_1600_8g);
-	} else if (!strcmp(dimm_name, "18KSF51272HZ-1G6K2")) {
-		/* 4G SO-DIMM */
-		ddr3_size = 4;
-		printf("DRAM: 4 GiB\n");
-		ddr3_init_ddrphy(KS2_DDR3A_DDRPHYC, &ddr3phy_1600_4g);
-		ddr3_init_ddremif(KS2_DDR3A_EMIF_CTRL_BASE, &ddr3_1600_4g);
-	} else {
-		printf("Unknown SO-DIMM. Cannot configure DDR3\n");
-		while (1)
-			;
-	}
+	phy_cfg->zq0cr1 |= 0x10000;
+	phy_cfg->zq1cr1 |= 0x10000;
+	phy_cfg->zq2cr1 |= 0x10000;
+	ddr3_init_ddrphy(KS2_DDR3A_DDRPHYC, phy_cfg);
+	ddr3_init_ddremif(KS2_DDR3A_EMIF_CTRL_BASE, emif_cfg);
+
+	printf("DRAM: %d GiB\n", ddr_size);
 
-	return ddr3_size;
+	return (u32)ddr_size;
 }
diff --git a/board/ti/ks2_evm/ddr3_k2hk.c b/board/ti/ks2_evm/ddr3_k2hk.c
index b36eb27..37f9420 100644
--- a/board/ti/ks2_evm/ddr3_k2hk.c
+++ b/board/ti/ks2_evm/ddr3_k2hk.c
@@ -20,74 +20,55 @@ u32 ddr3_init(void)
 	char dimm_name[32];
 	u32 ddr3_size;
 
-	ddr3_get_dimm_params(dimm_name);
+	u8 spd_buf[256];
+	int  ddr_speed;
+	int  ddr_size;
+
+	struct ddr3_phy_config *phy_cfg = &phy_spd_cfg;
+	struct ddr3_emif_config *emif_cfg = &emif_spd_cfg;
+
+	if (ddr3_get_dimm_params_from_spd(spd_buf, &ddr_speed, &ddr_size)) {
+		printf("Sorry, I don't know how to configure DDR3A.\n"
+		       "Bye :(\n");
+		for (;;)
+			;
+	}
+
+	strncpy(dimm_name, (char *)&spd_buf[0x80], 18);
+	dimm_name[18] = '\0';
 
 	printf("Detected SO-DIMM [%s]\n", dimm_name);
 
-	if (!strcmp(dimm_name, "18KSF1G72HZ-1G6E2 ")) {
-		init_pll(&ddr3a_400);
-		if (cpu_revision() > 0) {
-			if (cpu_revision() > 1) {
-				/* PG 2.0 */
-				/* Reset DDR3A PHY after PLL enabled */
-				ddr3_reset_ddrphy();
-				ddr3phy_1600_8g.zq0cr1 |= 0x10000;
-				ddr3phy_1600_8g.zq1cr1 |= 0x10000;
-				ddr3phy_1600_8g.zq2cr1 |= 0x10000;
-				ddr3_init_ddrphy(KS2_DDR3A_DDRPHYC,
-						 &ddr3phy_1600_8g);
-			} else {
-				/* PG 1.1 */
-				ddr3_init_ddrphy(KS2_DDR3A_DDRPHYC,
-						 &ddr3phy_1600_8g);
-			}
+	if ((cpu_revision() > 1) ||
+	    (__raw_readl(KS2_PLL_CNTRL_BASE + KS2_RSTCTRL_RSTYPE) & 0x1)) {
+		printf("DDR3 speed %d\n", ddr_speed);
+		if (ddr_speed == 1600)
+			init_pll(&ddr3a_400);
+		else
+			init_pll(&ddr3a_333);
+	}
 
-			ddr3_init_ddremif(KS2_DDR3A_EMIF_CTRL_BASE,
-					  &ddr3_1600_8g);
-			printf("DRAM:  Capacity 8 GiB (includes reported below)\n");
-			ddr3_size = 8;
-		} else {
-			ddr3_init_ddrphy(KS2_DDR3A_DDRPHYC, &ddr3phy_1600_8g);
-			ddr3_1600_8g.sdcfg |= 0x1000;
-			ddr3_init_ddremif(KS2_DDR3A_EMIF_CTRL_BASE,
-					  &ddr3_1600_8g);
-			printf("DRAM:  Capacity 4 GiB (includes reported below)\n");
-			ddr3_size = 4;
-		}
-	} else if (!strcmp(dimm_name, "SQR-SD3T-2G1333SED")) {
-		init_pll(&ddr3a_333);
-		if (cpu_revision() > 0) {
-			if (cpu_revision() > 1) {
-				/* PG 2.0 */
-				/* Reset DDR3A PHY after PLL enabled */
-				ddr3_reset_ddrphy();
-				ddr3phy_1333_2g.zq0cr1 |= 0x10000;
-				ddr3phy_1333_2g.zq1cr1 |= 0x10000;
-				ddr3phy_1333_2g.zq2cr1 |= 0x10000;
-				ddr3_init_ddrphy(KS2_DDR3A_DDRPHYC,
-						 &ddr3phy_1333_2g);
-			} else {
-				/* PG 1.1 */
-				ddr3_init_ddrphy(KS2_DDR3A_DDRPHYC,
-						 &ddr3phy_1333_2g);
-			}
-			ddr3_init_ddremif(KS2_DDR3A_EMIF_CTRL_BASE,
-					  &ddr3_1333_2g);
-			ddr3_size = 2;
-			printf("DRAM:  2 GiB");
-		} else {
-			ddr3_init_ddrphy(KS2_DDR3A_DDRPHYC, &ddr3phy_1333_2g);
-			ddr3_1333_2g.sdcfg |= 0x1000;
-			ddr3_init_ddremif(KS2_DDR3A_EMIF_CTRL_BASE,
-					  &ddr3_1333_2g);
-			ddr3_size = 1;
-			printf("DRAM:  1 GiB");
+	if (cpu_revision() > 0) {
+		if (cpu_revision() > 1) {
+			/* PG 2.0 */
+			/* Reset DDR3A PHY after PLL enabled */
+			ddr3_reset_ddrphy();
+			phy_cfg->zq0cr1 |= 0x10000;
+			phy_cfg->zq1cr1 |= 0x10000;
+			phy_cfg->zq2cr1 |= 0x10000;
 		}
+		ddr3_init_ddrphy(KS2_DDR3A_DDRPHYC, phy_cfg);
+
+		ddr3_init_ddremif(KS2_DDR3A_EMIF_CTRL_BASE, emif_cfg);
+
+		ddr3_size = ddr_size;
 	} else {
-		printf("Unknown SO-DIMM. Cannot configure DDR3\n");
-		while (1)
-			;
+		ddr3_init_ddrphy(KS2_DDR3A_DDRPHYC, phy_cfg);
+		emif_cfg->sdcfg |= 0x1000;
+		ddr3_init_ddremif(KS2_DDR3A_EMIF_CTRL_BASE, emif_cfg);
+		ddr3_size = ddr_size / 2;
 	}
+	printf("DRAM: %d GiB (includes reported below)\n", ddr3_size);
 
 	/* Apply the workaround for PG 1.0 and 1.1 Silicons */
 	if (cpu_revision() <= 1)
diff --git a/board/ti/ks2_evm/ddr3_spd.c b/board/ti/ks2_evm/ddr3_spd.c
new file mode 100644
index 0000000..d5bed47
--- /dev/null
+++ b/board/ti/ks2_evm/ddr3_spd.c
@@ -0,0 +1,531 @@
+/*
+ * Keystone2: DDR3 SPD configuration
+ *
+ * (C) Copyright 2015
+ *     Texas Instruments Incorporated, <www.ti.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+
+#include <i2c.h>
+#include <asm/arch/ddr3.h>
+#include <asm/arch/hardware.h>
+
+#ifdef DUMP_DDR_CONFIG
+static void dump_phy_config(struct ddr3_phy_config *ptr)
+{
+	printf("\npllcr		0x%08X\n", ptr->pllcr);
+	printf("pgcr1_mask	0x%08X\n", ptr->pgcr1_mask);
+	printf("pgcr1_val	0x%08X\n", ptr->pgcr1_val);
+	printf("ptr0		0x%08X\n", ptr->ptr0);
+	printf("ptr1		0x%08X\n", ptr->ptr1);
+	printf("ptr2		0x%08X\n", ptr->ptr2);
+	printf("ptr3		0x%08X\n", ptr->ptr3);
+	printf("ptr4		0x%08X\n", ptr->ptr4);
+	printf("dcr_mask	0x%08X\n", ptr->dcr_mask);
+	printf("dcr_val		0x%08X\n", ptr->dcr_val);
+	printf("dtpr0		0x%08X\n", ptr->dtpr0);
+	printf("dtpr1		0x%08X\n", ptr->dtpr1);
+	printf("dtpr2		0x%08X\n", ptr->dtpr2);
+	printf("mr0		0x%08X\n", ptr->mr0);
+	printf("mr1		0x%08X\n", ptr->mr1);
+	printf("mr2		0x%08X\n", ptr->mr2);
+	printf("dtcr		0x%08X\n", ptr->dtcr);
+	printf("pgcr2		0x%08X\n", ptr->pgcr2);
+	printf("zq0cr1		0x%08X\n", ptr->zq0cr1);
+	printf("zq1cr1		0x%08X\n", ptr->zq1cr1);
+	printf("zq2cr1		0x%08X\n", ptr->zq2cr1);
+	printf("pir_v1		0x%08X\n", ptr->pir_v1);
+	printf("pir_v2		0x%08X\n\n", ptr->pir_v2);
+};
+
+static void dump_emif_config(struct ddr3_emif_config *ptr)
+{
+	printf("\nsdcfg		0x%08X\n", ptr->sdcfg);
+	printf("sdtim1		0x%08X\n", ptr->sdtim1);
+	printf("sdtim2		0x%08X\n", ptr->sdtim2);
+	printf("sdtim3		0x%08X\n", ptr->sdtim3);
+	printf("sdtim4		0x%08X\n", ptr->sdtim4);
+	printf("zqcfg		0x%08X\n", ptr->zqcfg);
+	printf("sdrfc		0x%08X\n\n", ptr->sdrfc);
+};
+#endif
+
+#define TEMP NORMAL_TEMP
+#define VBUS_CLKPERIOD 1.875 /* Corresponds to vbus=533MHz, */
+#define PLLGS_VAL	(4000.0 / VBUS_CLKPERIOD) /* 4 us */
+#define PLLPD_VAL	(1000.0 / VBUS_CLKPERIOD) /* 1 us */
+#define PLLLOCK_VAL	(100000.0 / VBUS_CLKPERIOD) /* 100 us */
+#define PLLRST_VAL	(9000.0 / VBUS_CLKPERIOD) /* 9 us */
+#define PHYRST_VAL	0x10
+#define DDR_TERM RZQ_4_TERM
+#define SDRAM_DRIVE RZQ_7_IMP
+#define DYN_ODT ODT_DISABLE
+
+struct ddr3_phy_config phy_spd_cfg;
+struct ddr3_emif_config emif_spd_cfg;
+static unsigned int ddrspdclock;
+static int    ddr_size_gbyte;
+
+enum ebank {
+	DCE0,
+	DCE0_DEC1
+};
+
+enum nm {
+	DDR3BUSWIDTH_64,
+	DDR3BUSWIDTH_32,
+	DDR3BUSWIDTH_16
+};
+
+enum srt {
+	NORMAL_TEMP,
+	EXTENDED_TEMP
+};
+
+enum out_impedance {
+	RZQ_6_IMP = 0,
+	RZQ_7_IMP
+};
+
+enum die_term {
+	ODT_DISABLE = 0,
+	RZQ_4_TERM,
+	RZQ_2_TERM,
+	RZQ_6_TERM,
+	RZQ_12_TERM,
+	RZQ_8_TERM
+};
+
+struct ddr3_sodimm {
+	float t_ck;
+	uint32_t freqsel;
+	uint32_t t_xp;
+	uint32_t t_cke;
+	uint32_t t_pllpd;
+	uint32_t t_pllgs;
+	uint32_t t_phyrst;
+	uint32_t t_plllock;
+	uint32_t t_pllrst;
+	uint32_t t_rfc;
+	uint32_t t_xs;
+	uint32_t t_dinit0;
+	uint32_t t_dinit1;
+	uint32_t t_dinit2;
+	uint32_t t_dinit3;
+	uint32_t t_rtp;
+	uint32_t t_wtr;
+	uint32_t t_rp;
+	uint32_t t_rcd;
+	uint32_t t_ras;
+	uint32_t t_rrd;
+	uint32_t t_rc;
+	uint32_t t_faw;
+	uint32_t t_mrd;
+	uint32_t t_mod;
+	uint32_t t_wlo;
+	uint32_t t_wlmrd;
+	uint32_t t_xsdll;
+	uint32_t t_xpdll;
+	uint32_t t_ckesr;
+	uint32_t t_dllk;
+	uint32_t t_wr;
+	uint32_t t_wr_bin;
+	uint32_t cas;
+	uint32_t cwl;
+	uint32_t asr;
+	uint32_t pasr;
+	float t_refprd;
+	uint8_t sdram_type;
+	uint8_t ibank;
+	uint8_t pagesize;
+	uint8_t t_rrd2;
+	uint8_t t_ras_max;
+	uint8_t t_zqcs;
+	uint32_t refresh_rate;
+	uint8_t t_csta;
+
+	uint8_t rank;
+	uint8_t mirrored;
+	uint8_t buswidth;
+} spd;
+
+static uint8_t cas_latancy(uint16_t temp)
+{
+	int loop;
+	uint8_t cas_bin = 0;
+
+	for (loop = 0; loop < 32; loop += 2, temp >>= 1) {
+		if (temp & 0x0001)
+			cas_bin = (loop > 15) ? loop - 15 : loop;
+	}
+
+	return cas_bin;
+}
+
+static int ddrtimingcalculation(uint8_t buf[])
+{
+	float mtb, clk_freq;
+
+	/* Determine Time Base */
+	mtb = (float)buf[10] / buf[11];
+
+	/* SDRAM Cycle Time */
+	spd.t_ck = buf[12] * mtb;
+	ddrspdclock = ((1 / spd.t_ck) * 1000) * 2;
+	clk_freq = ddrspdclock / 2;
+
+	if (buf[2] != 0x0b)
+		return 1;
+
+	spd.sdram_type = 0x03;
+
+	if ((buf[4] & 0x70) != 0x00)
+		return 1;
+
+	spd.ibank = 0x03;
+
+	/* Check number of ranks, stop if greater than two ranks */
+	switch ((buf[7] & 0x38) >> 3) {
+	case 0:
+		spd.rank = 1;
+		break;
+	case 1:
+		spd.rank = 2;
+		break;
+	default:
+		return 1;
+	}
+
+	/* Identify # of column address bits */
+	switch (buf[5] & 0x07) {
+	case 0:
+		spd.pagesize = 0x01;
+		break;
+	case 1:
+		spd.pagesize = 0x02;
+		break;
+	case 2:
+		spd.pagesize = 0x03;
+		break;
+	default:
+		return 1;
+	}
+
+	/* Identify Bus Width */
+	switch (buf[8] & 0x7) {
+	case 1:
+		spd.buswidth = DDR3BUSWIDTH_16;
+		break;
+	case 2:
+		spd.buswidth = DDR3BUSWIDTH_32;
+		break;
+	case 3:
+		spd.buswidth = DDR3BUSWIDTH_64;
+		break;
+	default:
+		return 1;
+	}
+
+	spd.mirrored = (buf[63] & 1) ? 1 : 0;
+
+	if (ddrspdclock == 1333) {
+		puts("DDR3A Speed will be configured for 1333 Operation.\n");
+
+		spd.t_xp = ((3 * spd.t_ck) > 6.0) ?
+			3 : (6.0 / spd.t_ck) + 0.5;
+		spd.t_cke = ((3 * spd.t_ck) > 5.625) ?
+			3 : (5.625 / spd.t_ck) + 0.5;
+	} else if (ddrspdclock == 1600) {
+		puts("DDR3A Speed will be configured for 1600 Operation.\n");
+
+		spd.t_xp = ((3 * spd.t_ck) > 6.0) ?
+			3 : (6.0 / spd.t_ck) + 0.5;
+		spd.t_cke = ((3 * spd.t_ck) > 5.0) ?
+			3 : (5.0 / spd.t_ck) + 0.5;
+	} else {
+		printf("Unsupported DDR3 speed %d\n", ddrspdclock);
+		return 1;
+	}
+
+	spd.t_xpdll = ((10 * spd.t_ck) > 24.0) ? 10 : 24.0 / spd.t_ck;
+	spd.t_ckesr = spd.t_cke + 1;
+
+	/* SPD Calculated Values */
+	spd.cas = cas_latancy(((buf[15] << 8) | buf[14]));
+
+	spd.t_wr = (buf[17] * mtb) / spd.t_ck;
+	spd.t_wr_bin = (spd.t_wr / 2) & 0x07;
+
+	spd.t_rcd = (((float)buf[18] * mtb) / spd.t_ck) + 0.5;
+	spd.t_rrd = (((float)buf[19] * mtb) / spd.t_ck) + 0.5;
+	spd.t_rp  = (((float)buf[20] * mtb) / spd.t_ck) + 0.5;
+
+	spd.t_ras = (buf[21] & 0x0f) << 8;
+	spd.t_ras |= buf[22];
+	spd.t_ras = (((float)spd.t_ras * mtb) / spd.t_ck) + 0.5;
+
+
+	spd.t_rc = (buf[21] & 0xf0) << 4;
+	spd.t_rc |= buf[23];
+	spd.t_rc = (((float)spd.t_rc * mtb) / spd.t_ck) + 0.5;
+
+	spd.t_rfc = (buf[24] | (buf[25] << 8)) * mtb;
+	spd.t_wtr = ((float)buf[26] * mtb) / spd.t_ck;
+	spd.t_rtp = ((float)buf[27] * mtb) / spd.t_ck;
+
+	spd.t_xs  = ((spd.t_rfc + 10) / spd.t_ck) + 0.5;
+	spd.t_rfc = (spd.t_rfc / spd.t_ck) + 0.5;
+
+	spd.t_faw = (((buf[28] << 8) | buf[29]) * mtb) / spd.t_ck;
+	spd.t_rrd2 = ((((buf[28] << 8) | buf[29]) * mtb) / (4 * spd.t_ck)) - 1;
+
+	/* Hard-coded values */
+	spd.t_mrd = 0x00;
+	spd.t_mod = 0x00;
+	spd.t_wlo = 0x0C;
+	spd.t_wlmrd = 0x28;
+	spd.t_xsdll = 0x200;
+	spd.t_ras_max = 0x0F;
+	spd.t_csta = 0x05;
+	spd.t_dllk = 0x200;
+
+	/* CAS Write Latency */
+	if (spd.t_ck >= 2.5)
+		spd.cwl = 0;
+	else if (spd.t_ck >= 1.875)
+		spd.cwl = 1;
+	else if (spd.t_ck >= 1.5)
+		spd.cwl = 2;
+	else if (spd.t_ck >= 1.25)
+		spd.cwl = 3;
+	else if (spd.t_ck >= 1.071)
+		spd.cwl = 4;
+	else
+		spd.cwl = 5;
+
+	/* SDRAM Thermal and Refresh Options */
+	spd.asr = (buf[31] & 0x04) >> 2;
+	spd.pasr = (buf[31] & 0x80) >> 7;
+	spd.t_zqcs = 64;
+
+	spd.t_refprd = ((TEMP == NORMAL_TEMP) ? 64000.00 : 32000.0) / 8192;
+	spd.t_refprd = (spd.t_refprd * 1000) / spd.t_ck;
+
+	spd.refresh_rate = spd.t_refprd;
+	spd.t_refprd = spd.t_refprd * 5;
+
+	/* Set MISC PHY space registers fields */
+	if (((int)clk_freq / 2) >= 166 && ((int)clk_freq / 2 < 275))
+		spd.freqsel = 0x03;
+	else if (((int)clk_freq / 2) > 225 && ((int)clk_freq / 2 < 385))
+		spd.freqsel = 0x01;
+	else if (((int)clk_freq / 2) > 335 && ((int)clk_freq / 2 < 534))
+		spd.freqsel = 0x00;
+
+	spd.t_dinit0 = 500000.0 / spd.t_ck; /* CKE low time 500 us */
+	spd.t_dinit1 = spd.t_xs;
+	spd.t_dinit2 = 200000.0 / spd.t_ck; /* Reset low time 200 us */
+	/* Time from ZQ initialization command to first command (1 us) */
+	spd.t_dinit3 =  1000.0 / spd.t_ck;
+
+	spd.t_pllgs = PLLGS_VAL + 1;
+	spd.t_pllpd = PLLPD_VAL + 1;
+	spd.t_plllock = PLLLOCK_VAL + 1;
+	spd.t_pllrst = PLLRST_VAL;
+	spd.t_phyrst = PHYRST_VAL;
+
+	ddr_size_gbyte = (spd.rank * (256 << (buf[4] & 0xf))) / 1024;
+
+	return 0;
+}
+
+static int crc16(uint8_t *ptr, int count)
+{
+	int crc, i;
+
+	crc = 0;
+	while (--count >= 0) {
+		crc = crc ^ (int)*ptr++ << 8;
+		for (i = 0; i < 8; ++i)
+			if (crc & 0x8000)
+				crc = crc << 1 ^ 0x1021;
+			else
+				crc = crc << 1;
+	}
+	return crc & 0xffff;
+}
+
+static unsigned int ddr3_spd_check(uint8_t spd[])
+{
+	int csum16;
+	int len;
+	unsigned char crc_lsb;   /* byte 126 */
+	unsigned char crc_msb;   /* byte 127 */
+
+	/*
+	 * SPD byte0[7] - CRC coverage
+	 * 0 = CRC covers bytes 0~125
+	 * 1 = CRC covers bytes 0~116
+	 */
+	len = !(spd[0] & 0x80) ? 126 : 117;
+	csum16 = crc16(spd, len);
+
+	crc_lsb = (unsigned char)(csum16 & 0xff);
+	crc_msb = (unsigned char)(csum16 >> 8);
+	if ((spd[126] == crc_lsb) && (spd[127] == crc_msb)) {
+		printf("SPD csum OK; in SPD: %02X %02X; computed %08X %02X\n",
+		       spd[127], spd[126], crc_msb, crc_lsb);
+		return 0;
+	}
+
+	printf("SPD csum ERROR; in SPD: %02X %02X; computed %08X %02X\n",
+	       spd[127], spd[126], crc_msb, crc_lsb);
+
+	return 1;
+}
+
+static void init_ddr3param(void)
+{
+	phy_spd_cfg.pllcr = (spd.freqsel & 3) << 18 | 0xE << 13;
+	phy_spd_cfg.pgcr1_mask = (IODDRM_MASK | ZCKSEL_MASK);
+	phy_spd_cfg.pgcr1_val = ((1 << 2) | (1 << 7) | (1 << 23));
+	phy_spd_cfg.ptr0 = ((spd.t_pllpd & 0x7ff) << 21) |
+		((spd.t_pllgs & 0x7fff) << 6) | (spd.t_phyrst & 0x3f);
+	phy_spd_cfg.ptr1 = ((spd.t_plllock & 0xffff) << 16) |
+		(spd.t_pllrst & 0x1fff);
+	phy_spd_cfg.ptr2 = 0;
+	phy_spd_cfg.ptr3 = ((spd.t_dinit1 & 0x1ff) << 20) |
+		(spd.t_dinit0 & 0xfffff);
+	phy_spd_cfg.ptr4 = ((spd.t_dinit3 & 0x3ff) << 18) |
+		(spd.t_dinit2 & 0x3ffff);
+
+	phy_spd_cfg.dcr_mask = PDQ_MASK | MPRDQ_MASK | BYTEMASK_MASK;
+	phy_spd_cfg.dcr_val = 1 << 10;
+
+	if (spd.mirrored) {
+		phy_spd_cfg.dcr_mask |= NOSRA_MASK | UDIMM_MASK;
+		phy_spd_cfg.dcr_val |= (1 << 27) | (1 << 29);
+	}
+
+	phy_spd_cfg.dtpr0 = (spd.t_rc & 0x3f) << 26 | (spd.t_rrd & 0xf) << 22 |
+		(spd.t_ras & 0x3f) << 16 | (spd.t_rcd & 0xf) << 12 |
+		(spd.t_rp & 0xf) << 8 | (spd.t_wtr & 0xf) << 4 |
+		(spd.t_rtp & 0xf);
+	phy_spd_cfg.dtpr1 = (spd.t_wlo & 0xf) << 26 |
+		(spd.t_wlmrd & 0x3f) << 20 | (spd.t_rfc & 0x1ff) << 11 |
+		(spd.t_faw & 0x3f) << 5 | (spd.t_mod & 0x7) << 2|
+		(spd.t_mrd & 0x3);
+
+	phy_spd_cfg.dtpr2 = 0 << 31 | 1 << 30 | 0 << 29 |
+		(spd.t_dllk & 0x3ff) << 19 | (spd.t_ckesr & 0xf) << 15;
+
+	phy_spd_cfg.dtpr2 |= (((spd.t_xp > spd.t_xpdll) ?
+			      spd.t_xp : spd.t_xpdll) &
+			     0x1f) << 10;
+
+	phy_spd_cfg.dtpr2 |= (((spd.t_xs > spd.t_xsdll) ?
+			      spd.t_xs : spd.t_xsdll) &
+			     0x3ff);
+
+	phy_spd_cfg.mr0 = 1 << 12 | (spd.t_wr_bin & 0x7) << 9 | 0 << 8 |
+		0 << 7 | ((spd.cas & 0x0E) >> 1) << 4 | 0 << 3 |
+		(spd.cas & 0x01) << 2;
+
+	phy_spd_cfg.mr1 = 0 << 12 | 0 << 11 | 0 << 7 | 0 << 3 |
+		((DDR_TERM >> 2) & 1) << 9 | ((DDR_TERM >> 1) & 1) << 6 |
+		(DDR_TERM & 0x1) << 2 | ((SDRAM_DRIVE >> 1) & 1) << 5 |
+		(SDRAM_DRIVE & 1) << 1 | 0 << 0;
+
+	phy_spd_cfg.mr2 = DYN_ODT << 9 | TEMP << 7 | (spd.asr & 1) << 6 |
+		(spd.cwl & 7) << 3 | (spd.pasr & 7);
+
+	phy_spd_cfg.dtcr = (spd.rank == 2) ? 0x730035C7 : 0x710035C7;
+	phy_spd_cfg.pgcr2 = (0xF << 20) | ((int)spd.t_refprd & 0x3ffff);
+
+	phy_spd_cfg.zq0cr1 = 0x0000005D;
+	phy_spd_cfg.zq1cr1 = 0x0000005B;
+	phy_spd_cfg.zq2cr1 = 0x0000005B;
+
+	phy_spd_cfg.pir_v1 = 0x00000033;
+	phy_spd_cfg.pir_v2 = 0x0000FF81;
+
+
+	/* EMIF Registers */
+	emif_spd_cfg.sdcfg = spd.sdram_type << 29 | (DDR_TERM & 7) << 25 |
+		(DYN_ODT & 3) << 22 | (spd.cwl & 0x7) << 14 |
+		(spd.cas & 0xf) << 8 | (spd.ibank & 3) << 5 |
+		(spd.buswidth & 3) << 12 | (spd.pagesize & 3);
+
+	if (spd.rank == 2)
+		emif_spd_cfg.sdcfg |= DCE0_DEC1 << 3;
+
+	emif_spd_cfg.sdtim1 = ((spd.t_wr - 1) & 0x1f) << 25 |
+		((spd.t_ras - 1) & 0x7f) << 18 |
+		((spd.t_rc - 1) & 0xff) << 10 |
+		(spd.t_rrd2 & 0x3f) << 4  |
+		((spd.t_wtr - 1) & 0xf);
+
+	emif_spd_cfg.sdtim2 = 0x07 << 10 | ((spd.t_rp - 1) & 0x1f) << 5 |
+		((spd.t_rcd-1) & 0x1f);
+
+	emif_spd_cfg.sdtim3 = ((spd.t_xp - 2) & 0xf) << 28 |
+		((spd.t_xs - 1) & 0x3ff) << 18 |
+		((spd.t_xsdll - 1) & 0x3ff) << 8 |
+		((spd.t_rtp - 1) & 0xf) << 4 | ((spd.t_cke) & 0xf);
+
+	emif_spd_cfg.sdtim4 = (spd.t_csta & 0xf) << 28 |
+		((spd.t_ckesr - 1) & 0xf) << 24 |
+		((spd.t_zqcs - 1) & 0xff) << 16 |
+		((spd.t_rfc - 1) & 0x3ff) << 4 |
+		(spd.t_ras_max & 0xf);
+
+	emif_spd_cfg.sdrfc = (spd.refresh_rate-1) & 0xffff;
+
+	/* TODO zqcfg value fixed ,May be required correction for K2E evm. */
+	emif_spd_cfg.zqcfg = (spd.rank == 2) ? 0xF0073200 : 0x70073200;
+}
+
+int ddr3_get_dimm_params_from_spd(u8 *spd_params, int *ddr_clk,
+				  int *ddr_size)
+{
+	int ret;
+	int old_bus;
+
+	i2c_init(CONFIG_SYS_DAVINCI_I2C_SPEED, CONFIG_SYS_DAVINCI_I2C_SLAVE);
+
+	old_bus = i2c_get_bus_num();
+	i2c_set_bus_num(1);
+
+	ret = i2c_read(0x53, 0, 1, spd_params, 256);
+
+	i2c_set_bus_num(old_bus);
+
+	if (ret) {
+		puts("Cannot read DIMM params\n");
+		return 1;
+	}
+
+	if (ddr3_spd_check(spd_params))
+		return 1;
+
+	if (ddrtimingcalculation(spd_params)) {
+		puts("Timing caclulation error\n");
+		return 1;
+	}
+
+	init_ddr3param();
+
+#ifdef DUMP_DDR_CONFIG
+	dump_emif_config(&emif_spd_cfg);
+	dump_phy_config(&phy_spd_cfg);
+#endif
+
+	*ddr_clk = ddrspdclock;
+	*ddr_size = ddr_size_gbyte;
+
+	return 0;
+}
+
-- 
1.9.1



More information about the U-Boot mailing list