From patchwork Mon Jun 15 12:32:21 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vitaly Andrianov X-Patchwork-Id: 484267 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 74305140216 for ; Mon, 15 Jun 2015 22:28:11 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 6DF0B4B716; Mon, 15 Jun 2015 14:28:09 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id COu-z-lcPTnf; Mon, 15 Jun 2015 14:28:09 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id DA6AF4B6FD; Mon, 15 Jun 2015 14:28:08 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id C33394B6FD for ; Mon, 15 Jun 2015 14:28:03 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 6mYNCUhaW_wc for ; Mon, 15 Jun 2015 14:28:03 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from comal.ext.ti.com (comal.ext.ti.com [198.47.26.152]) by theia.denx.de (Postfix) with ESMTPS id 105844B6FC for ; Mon, 15 Jun 2015 14:28:00 +0200 (CEST) Received: from dflxv15.itg.ti.com ([128.247.5.124]) by comal.ext.ti.com (8.13.7/8.13.7) with ESMTP id t5FCRvGt007983; Mon, 15 Jun 2015 07:27:57 -0500 Received: from DLEE70.ent.ti.com (dlee70.ent.ti.com [157.170.170.113]) by dflxv15.itg.ti.com (8.14.3/8.13.8) with ESMTP id t5FCRuEo003651; Mon, 15 Jun 2015 07:27:57 -0500 Received: from dflp32.itg.ti.com (10.64.6.15) by DLEE70.ent.ti.com (157.170.170.113) with Microsoft SMTP Server id 14.3.224.2; Mon, 15 Jun 2015 07:27:56 -0500 Received: from uda0794637.am.dhcp.ti.com (ileax41-snat.itg.ti.com [10.172.224.153]) by dflp32.itg.ti.com (8.14.3/8.13.8) with ESMTP id t5FCRumk021329; Mon, 15 Jun 2015 07:27:56 -0500 From: Vitaly Andrianov To: , Date: Mon, 15 Jun 2015 08:32:21 -0400 Message-ID: <1434371541-32633-1-git-send-email-vitalya@ti.com> X-Mailer: git-send-email 1.9.1 MIME-Version: 1.0 Subject: [U-Boot] [PATCH] keystone2: use SPD info to configure K2HK and K2E DDR3 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.15 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" 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 --- 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, # 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, * * SPDX-License-Identifier: GPL-2.0+ @@ -12,42 +12,46 @@ #include 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, + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include + +#include +#include +#include + +#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; +} +