mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-22 11:13:07 +00:00
83d290c56f
When U-Boot started using SPDX tags we were among the early adopters and there weren't a lot of other examples to borrow from. So we picked the area of the file that usually had a full license text and replaced it with an appropriate SPDX-License-Identifier: entry. Since then, the Linux Kernel has adopted SPDX tags and they place it as the very first line in a file (except where shebangs are used, then it's second line) and with slightly different comment styles than us. In part due to community overlap, in part due to better tag visibility and in part for other minor reasons, switch over to that style. This commit changes all instances where we have a single declared license in the tag as both the before and after are identical in tag contents. There's also a few places where I found we did not have a tag and have introduced one. Signed-off-by: Tom Rini <trini@konsulko.com>
462 lines
12 KiB
C
462 lines
12 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Keystone2: DDR3 SPD configuration
|
|
*
|
|
* (C) Copyright 2015-2016 Texas Instruments Incorporated, <www.ti.com>
|
|
*/
|
|
|
|
#include <common.h>
|
|
|
|
#include <i2c.h>
|
|
#include <ddr_spd.h>
|
|
#include <asm/arch/ddr3.h>
|
|
#include <asm/arch/hardware.h>
|
|
|
|
#define DUMP_DDR_CONFIG 0 /* set to 1 to debug */
|
|
#define debug_ddr_cfg(fmt, args...) \
|
|
debug_cond(DUMP_DDR_CONFIG, fmt, ##args)
|
|
|
|
static void dump_phy_config(struct ddr3_phy_config *ptr)
|
|
{
|
|
debug_ddr_cfg("\npllcr 0x%08X\n", ptr->pllcr);
|
|
debug_ddr_cfg("pgcr1_mask 0x%08X\n", ptr->pgcr1_mask);
|
|
debug_ddr_cfg("pgcr1_val 0x%08X\n", ptr->pgcr1_val);
|
|
debug_ddr_cfg("ptr0 0x%08X\n", ptr->ptr0);
|
|
debug_ddr_cfg("ptr1 0x%08X\n", ptr->ptr1);
|
|
debug_ddr_cfg("ptr2 0x%08X\n", ptr->ptr2);
|
|
debug_ddr_cfg("ptr3 0x%08X\n", ptr->ptr3);
|
|
debug_ddr_cfg("ptr4 0x%08X\n", ptr->ptr4);
|
|
debug_ddr_cfg("dcr_mask 0x%08X\n", ptr->dcr_mask);
|
|
debug_ddr_cfg("dcr_val 0x%08X\n", ptr->dcr_val);
|
|
debug_ddr_cfg("dtpr0 0x%08X\n", ptr->dtpr0);
|
|
debug_ddr_cfg("dtpr1 0x%08X\n", ptr->dtpr1);
|
|
debug_ddr_cfg("dtpr2 0x%08X\n", ptr->dtpr2);
|
|
debug_ddr_cfg("mr0 0x%08X\n", ptr->mr0);
|
|
debug_ddr_cfg("mr1 0x%08X\n", ptr->mr1);
|
|
debug_ddr_cfg("mr2 0x%08X\n", ptr->mr2);
|
|
debug_ddr_cfg("dtcr 0x%08X\n", ptr->dtcr);
|
|
debug_ddr_cfg("pgcr2 0x%08X\n", ptr->pgcr2);
|
|
debug_ddr_cfg("zq0cr1 0x%08X\n", ptr->zq0cr1);
|
|
debug_ddr_cfg("zq1cr1 0x%08X\n", ptr->zq1cr1);
|
|
debug_ddr_cfg("zq2cr1 0x%08X\n", ptr->zq2cr1);
|
|
debug_ddr_cfg("pir_v1 0x%08X\n", ptr->pir_v1);
|
|
debug_ddr_cfg("pir_v2 0x%08X\n\n", ptr->pir_v2);
|
|
};
|
|
|
|
static void dump_emif_config(struct ddr3_emif_config *ptr)
|
|
{
|
|
debug_ddr_cfg("\nsdcfg 0x%08X\n", ptr->sdcfg);
|
|
debug_ddr_cfg("sdtim1 0x%08X\n", ptr->sdtim1);
|
|
debug_ddr_cfg("sdtim2 0x%08X\n", ptr->sdtim2);
|
|
debug_ddr_cfg("sdtim3 0x%08X\n", ptr->sdtim3);
|
|
debug_ddr_cfg("sdtim4 0x%08X\n", ptr->sdtim4);
|
|
debug_ddr_cfg("zqcfg 0x%08X\n", ptr->zqcfg);
|
|
debug_ddr_cfg("sdrfc 0x%08X\n\n", ptr->sdrfc);
|
|
};
|
|
|
|
#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
|
|
|
|
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 {
|
|
u32 t_ck;
|
|
u32 freqsel;
|
|
u32 t_xp;
|
|
u32 t_cke;
|
|
u32 t_pllpd;
|
|
u32 t_pllgs;
|
|
u32 t_phyrst;
|
|
u32 t_plllock;
|
|
u32 t_pllrst;
|
|
u32 t_rfc;
|
|
u32 t_xs;
|
|
u32 t_dinit0;
|
|
u32 t_dinit1;
|
|
u32 t_dinit2;
|
|
u32 t_dinit3;
|
|
u32 t_rtp;
|
|
u32 t_wtr;
|
|
u32 t_rp;
|
|
u32 t_rcd;
|
|
u32 t_ras;
|
|
u32 t_rrd;
|
|
u32 t_rc;
|
|
u32 t_faw;
|
|
u32 t_mrd;
|
|
u32 t_mod;
|
|
u32 t_wlo;
|
|
u32 t_wlmrd;
|
|
u32 t_xsdll;
|
|
u32 t_xpdll;
|
|
u32 t_ckesr;
|
|
u32 t_dllk;
|
|
u32 t_wr;
|
|
u32 t_wr_bin;
|
|
u32 cas;
|
|
u32 cwl;
|
|
u32 asr;
|
|
u32 pasr;
|
|
u32 t_refprd;
|
|
u8 sdram_type;
|
|
u8 ibank;
|
|
u8 pagesize;
|
|
u8 t_rrd2;
|
|
u8 t_ras_max;
|
|
u8 t_zqcs;
|
|
u32 refresh_rate;
|
|
u8 t_csta;
|
|
|
|
u8 rank;
|
|
u8 mirrored;
|
|
u8 buswidth;
|
|
};
|
|
|
|
static u8 cas_latancy(u16 temp)
|
|
{
|
|
int loop;
|
|
u8 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 ddr3_get_size_in_mb(ddr3_spd_eeprom_t *buf)
|
|
{
|
|
return (((buf->organization & 0x38) >> 3) + 1) *
|
|
(256 << (buf->density_banks & 0xf));
|
|
}
|
|
|
|
static int ddrtimingcalculation(ddr3_spd_eeprom_t *buf, struct ddr3_sodimm *spd,
|
|
struct ddr3_spd_cb *spd_cb)
|
|
{
|
|
u32 mtb, clk_freq;
|
|
|
|
if ((buf->mem_type != 0x0b) ||
|
|
((buf->density_banks & 0x70) != 0x00))
|
|
return 1;
|
|
|
|
spd->sdram_type = 0x03;
|
|
spd->ibank = 0x03;
|
|
|
|
mtb = buf->mtb_dividend * 1000 / buf->mtb_divisor;
|
|
|
|
spd->t_ck = buf->tck_min * mtb;
|
|
|
|
spd_cb->ddrspdclock = 2000000 / spd->t_ck;
|
|
clk_freq = spd_cb->ddrspdclock / 2;
|
|
|
|
spd->rank = ((buf->organization & 0x38) >> 3) + 1;
|
|
if (spd->rank > 2)
|
|
return 1;
|
|
|
|
spd->pagesize = (buf->addressing & 0x07) + 1;
|
|
if (spd->pagesize > 3)
|
|
return 1;
|
|
|
|
spd->buswidth = 8 << (buf->bus_width & 0x7);
|
|
if ((spd->buswidth < 16) || (spd->buswidth > 64))
|
|
return 1;
|
|
|
|
spd->mirrored = buf->mod_section.unbuffered.addr_mapping & 1;
|
|
|
|
printf("DDR3A Speed will be configured for %d Operation.\n",
|
|
spd_cb->ddrspdclock);
|
|
if (spd_cb->ddrspdclock == 1333) {
|
|
spd->t_xp = ((3 * spd->t_ck) > 6000) ?
|
|
3 : ((5999 / spd->t_ck) + 1);
|
|
spd->t_cke = ((3 * spd->t_ck) > 5625) ?
|
|
3 : ((5624 / spd->t_ck) + 1);
|
|
} else if (spd_cb->ddrspdclock == 1600) {
|
|
spd->t_xp = ((3 * spd->t_ck) > 6000) ?
|
|
3 : ((5999 / spd->t_ck) + 1);
|
|
spd->t_cke = ((3 * spd->t_ck) > 5000) ?
|
|
3 : ((4999 / spd->t_ck) + 1);
|
|
} else {
|
|
printf("Unsupported DDR3 speed %d\n", spd_cb->ddrspdclock);
|
|
return 1;
|
|
}
|
|
|
|
spd->t_xpdll = (spd->t_ck > 2400) ? 10 : 24000 / spd->t_ck;
|
|
spd->t_ckesr = spd->t_cke + 1;
|
|
|
|
/* SPD Calculated Values */
|
|
spd->cas = cas_latancy((buf->caslat_msb << 8) |
|
|
buf->caslat_lsb);
|
|
|
|
spd->t_wr = (buf->twr_min * mtb) / spd->t_ck;
|
|
spd->t_wr_bin = (spd->t_wr / 2) & 0x07;
|
|
|
|
spd->t_rcd = ((buf->trcd_min * mtb) - 1) / spd->t_ck + 1;
|
|
spd->t_rrd = ((buf->trrd_min * mtb) - 1) / spd->t_ck + 1;
|
|
spd->t_rp = (((buf->trp_min * mtb) - 1) / spd->t_ck) + 1;
|
|
|
|
spd->t_ras = (((buf->tras_trc_ext & 0x0f) << 8 | buf->tras_min_lsb) *
|
|
mtb) / spd->t_ck;
|
|
|
|
spd->t_rc = (((((buf->tras_trc_ext & 0xf0) << 4) | buf->trc_min_lsb) *
|
|
mtb) - 1) / spd->t_ck + 1;
|
|
|
|
spd->t_rfc = (buf->trfc_min_lsb | (buf->trfc_min_msb << 8)) * mtb /
|
|
1000;
|
|
spd->t_wtr = (buf->twtr_min * mtb) / spd->t_ck;
|
|
spd->t_rtp = (buf->trtp_min * mtb) / spd->t_ck;
|
|
|
|
spd->t_xs = (((spd->t_rfc + 10) * 1000) / spd->t_ck);
|
|
spd->t_rfc = ((spd->t_rfc * 1000) - 1) / spd->t_ck + 1;
|
|
|
|
spd->t_faw = (((buf->tfaw_msb << 8) | buf->tfaw_min) * mtb) / spd->t_ck;
|
|
spd->t_rrd2 = ((((buf->tfaw_msb << 8) |
|
|
buf->tfaw_min) * 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 >= 2500)
|
|
spd->cwl = 0;
|
|
else if (spd->t_ck >= 1875)
|
|
spd->cwl = 1;
|
|
else if (spd->t_ck >= 1500)
|
|
spd->cwl = 2;
|
|
else if (spd->t_ck >= 1250)
|
|
spd->cwl = 3;
|
|
else if (spd->t_ck >= 1071)
|
|
spd->cwl = 4;
|
|
else
|
|
spd->cwl = 5;
|
|
|
|
/* SD:RAM Thermal and Refresh Options */
|
|
spd->asr = (buf->therm_ref_opt & 0x04) >> 2;
|
|
spd->pasr = (buf->therm_ref_opt & 0x80) >> 7;
|
|
spd->t_zqcs = 64;
|
|
|
|
spd->t_refprd = (TEMP == NORMAL_TEMP) ? 7812500 : 3906250;
|
|
spd->t_refprd = spd->t_refprd / spd->t_ck;
|
|
|
|
spd->refresh_rate = spd->t_refprd;
|
|
spd->t_refprd = spd->t_refprd * 5;
|
|
|
|
/* Set MISC PHY space registers fields */
|
|
if ((clk_freq / 2) >= 166 && (clk_freq / 2 < 275))
|
|
spd->freqsel = 0x03;
|
|
else if ((clk_freq / 2) > 225 && (clk_freq / 2 < 385))
|
|
spd->freqsel = 0x01;
|
|
else if ((clk_freq / 2) > 335 && (clk_freq / 2 < 534))
|
|
spd->freqsel = 0x00;
|
|
|
|
spd->t_dinit0 = 500000000 / spd->t_ck; /* CKE low time 500 us */
|
|
spd->t_dinit1 = spd->t_xs;
|
|
spd->t_dinit2 = 200000000 / spd->t_ck; /* Reset low time 200 us */
|
|
/* Time from ZQ initialization command to first command (1 us) */
|
|
spd->t_dinit3 = 1000000 / 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;
|
|
|
|
spd_cb->ddr_size_gbyte = ddr3_get_size_in_mb(buf) / 1024;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void init_ddr3param(struct ddr3_spd_cb *spd_cb,
|
|
struct ddr3_sodimm *spd)
|
|
{
|
|
spd_cb->phy_cfg.pllcr = (spd->freqsel & 3) << 18 | 0xE << 13;
|
|
spd_cb->phy_cfg.pgcr1_mask = (IODDRM_MASK | ZCKSEL_MASK);
|
|
spd_cb->phy_cfg.pgcr1_val = ((1 << 2) | (1 << 7) | (1 << 23));
|
|
spd_cb->phy_cfg.ptr0 = ((spd->t_pllpd & 0x7ff) << 21) |
|
|
((spd->t_pllgs & 0x7fff) << 6) | (spd->t_phyrst & 0x3f);
|
|
spd_cb->phy_cfg.ptr1 = ((spd->t_plllock & 0xffff) << 16) |
|
|
(spd->t_pllrst & 0x1fff);
|
|
spd_cb->phy_cfg.ptr2 = 0;
|
|
spd_cb->phy_cfg.ptr3 = ((spd->t_dinit1 & 0x1ff) << 20) |
|
|
(spd->t_dinit0 & 0xfffff);
|
|
spd_cb->phy_cfg.ptr4 = ((spd->t_dinit3 & 0x3ff) << 18) |
|
|
(spd->t_dinit2 & 0x3ffff);
|
|
|
|
spd_cb->phy_cfg.dcr_mask = PDQ_MASK | MPRDQ_MASK | BYTEMASK_MASK;
|
|
spd_cb->phy_cfg.dcr_val = 1 << 10;
|
|
|
|
if (spd->mirrored) {
|
|
spd_cb->phy_cfg.dcr_mask |= NOSRA_MASK | UDIMM_MASK;
|
|
spd_cb->phy_cfg.dcr_val |= (1 << 27) | (1 << 29);
|
|
}
|
|
|
|
spd_cb->phy_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);
|
|
spd_cb->phy_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);
|
|
|
|
spd_cb->phy_cfg.dtpr2 = 0 << 31 | 1 << 30 | 0 << 29 |
|
|
(spd->t_dllk & 0x3ff) << 19 | (spd->t_ckesr & 0xf) << 15;
|
|
|
|
spd_cb->phy_cfg.dtpr2 |= (((spd->t_xp > spd->t_xpdll) ?
|
|
spd->t_xp : spd->t_xpdll) &
|
|
0x1f) << 10;
|
|
|
|
spd_cb->phy_cfg.dtpr2 |= (((spd->t_xs > spd->t_xsdll) ?
|
|
spd->t_xs : spd->t_xsdll) &
|
|
0x3ff);
|
|
|
|
spd_cb->phy_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;
|
|
|
|
spd_cb->phy_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;
|
|
|
|
spd_cb->phy_cfg.mr2 = DYN_ODT << 9 | TEMP << 7 | (spd->asr & 1) << 6 |
|
|
(spd->cwl & 7) << 3 | (spd->pasr & 7);
|
|
|
|
spd_cb->phy_cfg.dtcr = (spd->rank == 2) ? 0x730035C7 : 0x710035C7;
|
|
spd_cb->phy_cfg.pgcr2 = (0xF << 20) | ((int)spd->t_refprd & 0x3ffff);
|
|
|
|
spd_cb->phy_cfg.zq0cr1 = 0x0000005D;
|
|
spd_cb->phy_cfg.zq1cr1 = 0x0000005B;
|
|
spd_cb->phy_cfg.zq2cr1 = 0x0000005B;
|
|
|
|
spd_cb->phy_cfg.pir_v1 = 0x00000033;
|
|
spd_cb->phy_cfg.pir_v2 = 0x0000FF81;
|
|
|
|
/* EMIF Registers */
|
|
spd_cb->emif_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)
|
|
spd_cb->emif_cfg.sdcfg |= 1 << 3;
|
|
|
|
spd_cb->emif_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);
|
|
|
|
spd_cb->emif_cfg.sdtim2 = 0x07 << 10 | ((spd->t_rp - 1) & 0x1f) << 5 |
|
|
((spd->t_rcd - 1) & 0x1f);
|
|
|
|
spd_cb->emif_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);
|
|
|
|
spd_cb->emif_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);
|
|
|
|
spd_cb->emif_cfg.sdrfc = (spd->refresh_rate - 1) & 0xffff;
|
|
|
|
/* TODO zqcfg value fixed ,May be required correction for K2E evm. */
|
|
spd_cb->emif_cfg.zqcfg = (spd->rank == 2) ? 0xF0073200 : 0x70073200;
|
|
}
|
|
|
|
static int ddr3_read_spd(ddr3_spd_eeprom_t *spd_params)
|
|
{
|
|
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, (unsigned char *)spd_params, 256);
|
|
|
|
i2c_set_bus_num(old_bus);
|
|
|
|
if (ret) {
|
|
printf("Cannot read DIMM params\n");
|
|
return 1;
|
|
}
|
|
|
|
if (ddr3_spd_check(spd_params))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ddr3_get_size(void)
|
|
{
|
|
ddr3_spd_eeprom_t spd_params;
|
|
|
|
if (ddr3_read_spd(&spd_params))
|
|
return 0;
|
|
|
|
return ddr3_get_size_in_mb(&spd_params) / 1024;
|
|
}
|
|
|
|
int ddr3_get_dimm_params_from_spd(struct ddr3_spd_cb *spd_cb)
|
|
{
|
|
struct ddr3_sodimm spd;
|
|
ddr3_spd_eeprom_t spd_params;
|
|
|
|
memset(&spd, 0, sizeof(spd));
|
|
|
|
if (ddr3_read_spd(&spd_params))
|
|
return 1;
|
|
|
|
if (ddrtimingcalculation(&spd_params, &spd, spd_cb)) {
|
|
printf("Timing caclulation error\n");
|
|
return 1;
|
|
}
|
|
|
|
strncpy(spd_cb->dimm_name, (char *)spd_params.mpart, 18);
|
|
spd_cb->dimm_name[18] = '\0';
|
|
|
|
init_ddr3param(spd_cb, &spd);
|
|
|
|
dump_emif_config(&spd_cb->emif_cfg);
|
|
dump_phy_config(&spd_cb->phy_cfg);
|
|
|
|
return 0;
|
|
}
|