avionic design with actual uboot and tooling
submodule of avionic design uboot bootloader and with included tools to get you started , read readme.md and readme-tk1-loader.md
This commit is contained in:
35
u-boot/drivers/ddr/fsl/Makefile
Normal file
35
u-boot/drivers/ddr/fsl/Makefile
Normal file
@@ -0,0 +1,35 @@
|
||||
#
|
||||
# Copyright 2008-2014 Freescale Semiconductor, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
|
||||
obj-$(CONFIG_SYS_FSL_DDR1) += main.o util.o ctrl_regs.o options.o \
|
||||
lc_common_dimm_params.o
|
||||
obj-$(CONFIG_SYS_FSL_DDR2) += main.o util.o ctrl_regs.o options.o \
|
||||
lc_common_dimm_params.o
|
||||
obj-$(CONFIG_SYS_FSL_DDR3) += main.o util.o ctrl_regs.o options.o \
|
||||
lc_common_dimm_params.o
|
||||
obj-$(CONFIG_SYS_FSL_DDR4) += main.o util.o ctrl_regs.o options.o \
|
||||
lc_common_dimm_params.o
|
||||
|
||||
ifdef CONFIG_DDR_SPD
|
||||
SPD := y
|
||||
endif
|
||||
ifdef CONFIG_SPD_EEPROM
|
||||
SPD := y
|
||||
endif
|
||||
ifdef SPD
|
||||
obj-$(CONFIG_SYS_FSL_DDR1) += ddr1_dimm_params.o
|
||||
obj-$(CONFIG_SYS_FSL_DDR2) += ddr2_dimm_params.o
|
||||
obj-$(CONFIG_SYS_FSL_DDR3) += ddr3_dimm_params.o
|
||||
obj-$(CONFIG_SYS_FSL_DDR4) += ddr4_dimm_params.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_FSL_DDR_INTERACTIVE) += interactive.o
|
||||
obj-$(CONFIG_SYS_FSL_DDRC_GEN1) += mpc85xx_ddr_gen1.o
|
||||
obj-$(CONFIG_SYS_FSL_DDRC_GEN2) += mpc85xx_ddr_gen2.o
|
||||
obj-$(CONFIG_SYS_FSL_DDRC_GEN3) += mpc85xx_ddr_gen3.o
|
||||
obj-$(CONFIG_SYS_FSL_DDR_86XX) += mpc86xx_ddr.o
|
||||
obj-$(CONFIG_SYS_FSL_DDRC_ARM_GEN3) += arm_ddr_gen3.o
|
||||
obj-$(CONFIG_SYS_FSL_DDRC_GEN4) += fsl_ddr_gen4.o
|
||||
247
u-boot/drivers/ddr/fsl/arm_ddr_gen3.c
Normal file
247
u-boot/drivers/ddr/fsl/arm_ddr_gen3.c
Normal file
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright 2013 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* Derived from mpc85xx_ddr_gen3.c, removed all workarounds
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <fsl_ddr_sdram.h>
|
||||
#include <asm/processor.h>
|
||||
#include <fsl_immap.h>
|
||||
#include <fsl_ddr.h>
|
||||
|
||||
#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4)
|
||||
#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* regs has the to-be-set values for DDR controller registers
|
||||
* ctrl_num is the DDR controller number
|
||||
* step: 0 goes through the initialization in one pass
|
||||
* 1 sets registers and returns before enabling controller
|
||||
* 2 resumes from step 1 and continues to initialize
|
||||
* Dividing the initialization to two steps to deassert DDR reset signal
|
||||
* to comply with JEDEC specs for RDIMMs.
|
||||
*/
|
||||
void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
|
||||
unsigned int ctrl_num, int step)
|
||||
{
|
||||
unsigned int i, bus_width;
|
||||
struct ccsr_ddr __iomem *ddr;
|
||||
u32 temp_sdram_cfg;
|
||||
u32 total_gb_size_per_controller;
|
||||
int timeout;
|
||||
|
||||
switch (ctrl_num) {
|
||||
case 0:
|
||||
ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR;
|
||||
break;
|
||||
#if defined(CONFIG_SYS_FSL_DDR2_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 1)
|
||||
case 1:
|
||||
ddr = (void *)CONFIG_SYS_FSL_DDR2_ADDR;
|
||||
break;
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_FSL_DDR3_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 2)
|
||||
case 2:
|
||||
ddr = (void *)CONFIG_SYS_FSL_DDR3_ADDR;
|
||||
break;
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_FSL_DDR4_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 3)
|
||||
case 3:
|
||||
ddr = (void *)CONFIG_SYS_FSL_DDR4_ADDR;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
printf("%s unexpected ctrl_num = %u\n", __func__, ctrl_num);
|
||||
return;
|
||||
}
|
||||
|
||||
if (step == 2)
|
||||
goto step2;
|
||||
|
||||
if (regs->ddr_eor)
|
||||
ddr_out32(&ddr->eor, regs->ddr_eor);
|
||||
for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
|
||||
if (i == 0) {
|
||||
ddr_out32(&ddr->cs0_bnds, regs->cs[i].bnds);
|
||||
ddr_out32(&ddr->cs0_config, regs->cs[i].config);
|
||||
ddr_out32(&ddr->cs0_config_2, regs->cs[i].config_2);
|
||||
|
||||
} else if (i == 1) {
|
||||
ddr_out32(&ddr->cs1_bnds, regs->cs[i].bnds);
|
||||
ddr_out32(&ddr->cs1_config, regs->cs[i].config);
|
||||
ddr_out32(&ddr->cs1_config_2, regs->cs[i].config_2);
|
||||
|
||||
} else if (i == 2) {
|
||||
ddr_out32(&ddr->cs2_bnds, regs->cs[i].bnds);
|
||||
ddr_out32(&ddr->cs2_config, regs->cs[i].config);
|
||||
ddr_out32(&ddr->cs2_config_2, regs->cs[i].config_2);
|
||||
|
||||
} else if (i == 3) {
|
||||
ddr_out32(&ddr->cs3_bnds, regs->cs[i].bnds);
|
||||
ddr_out32(&ddr->cs3_config, regs->cs[i].config);
|
||||
ddr_out32(&ddr->cs3_config_2, regs->cs[i].config_2);
|
||||
}
|
||||
}
|
||||
|
||||
ddr_out32(&ddr->timing_cfg_3, regs->timing_cfg_3);
|
||||
ddr_out32(&ddr->timing_cfg_0, regs->timing_cfg_0);
|
||||
ddr_out32(&ddr->timing_cfg_1, regs->timing_cfg_1);
|
||||
ddr_out32(&ddr->timing_cfg_2, regs->timing_cfg_2);
|
||||
ddr_out32(&ddr->sdram_mode, regs->ddr_sdram_mode);
|
||||
ddr_out32(&ddr->sdram_mode_2, regs->ddr_sdram_mode_2);
|
||||
ddr_out32(&ddr->sdram_mode_3, regs->ddr_sdram_mode_3);
|
||||
ddr_out32(&ddr->sdram_mode_4, regs->ddr_sdram_mode_4);
|
||||
ddr_out32(&ddr->sdram_mode_5, regs->ddr_sdram_mode_5);
|
||||
ddr_out32(&ddr->sdram_mode_6, regs->ddr_sdram_mode_6);
|
||||
ddr_out32(&ddr->sdram_mode_7, regs->ddr_sdram_mode_7);
|
||||
ddr_out32(&ddr->sdram_mode_8, regs->ddr_sdram_mode_8);
|
||||
ddr_out32(&ddr->sdram_md_cntl, regs->ddr_sdram_md_cntl);
|
||||
ddr_out32(&ddr->sdram_interval, regs->ddr_sdram_interval);
|
||||
ddr_out32(&ddr->sdram_data_init, regs->ddr_data_init);
|
||||
ddr_out32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl);
|
||||
ddr_out32(&ddr->timing_cfg_4, regs->timing_cfg_4);
|
||||
ddr_out32(&ddr->timing_cfg_5, regs->timing_cfg_5);
|
||||
ddr_out32(&ddr->ddr_zq_cntl, regs->ddr_zq_cntl);
|
||||
ddr_out32(&ddr->ddr_wrlvl_cntl, regs->ddr_wrlvl_cntl);
|
||||
#ifndef CONFIG_SYS_FSL_DDR_EMU
|
||||
/*
|
||||
* Skip these two registers if running on emulator
|
||||
* because emulator doesn't have skew between bytes.
|
||||
*/
|
||||
|
||||
if (regs->ddr_wrlvl_cntl_2)
|
||||
ddr_out32(&ddr->ddr_wrlvl_cntl_2, regs->ddr_wrlvl_cntl_2);
|
||||
if (regs->ddr_wrlvl_cntl_3)
|
||||
ddr_out32(&ddr->ddr_wrlvl_cntl_3, regs->ddr_wrlvl_cntl_3);
|
||||
#endif
|
||||
|
||||
ddr_out32(&ddr->ddr_sr_cntr, regs->ddr_sr_cntr);
|
||||
ddr_out32(&ddr->ddr_sdram_rcw_1, regs->ddr_sdram_rcw_1);
|
||||
ddr_out32(&ddr->ddr_sdram_rcw_2, regs->ddr_sdram_rcw_2);
|
||||
ddr_out32(&ddr->ddr_cdr1, regs->ddr_cdr1);
|
||||
#ifdef CONFIG_DEEP_SLEEP
|
||||
if (is_warm_boot()) {
|
||||
ddr_out32(&ddr->sdram_cfg_2,
|
||||
regs->ddr_sdram_cfg_2 & ~SDRAM_CFG2_D_INIT);
|
||||
ddr_out32(&ddr->init_addr, CONFIG_SYS_SDRAM_BASE);
|
||||
ddr_out32(&ddr->init_ext_addr, DDR_INIT_ADDR_EXT_UIA);
|
||||
|
||||
/* DRAM VRef will not be trained */
|
||||
ddr_out32(&ddr->ddr_cdr2,
|
||||
regs->ddr_cdr2 & ~DDR_CDR2_VREF_TRAIN_EN);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
ddr_out32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2);
|
||||
ddr_out32(&ddr->init_addr, regs->ddr_init_addr);
|
||||
ddr_out32(&ddr->init_ext_addr, regs->ddr_init_ext_addr);
|
||||
ddr_out32(&ddr->ddr_cdr2, regs->ddr_cdr2);
|
||||
}
|
||||
ddr_out32(&ddr->err_disable, regs->err_disable);
|
||||
ddr_out32(&ddr->err_int_en, regs->err_int_en);
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (regs->debug[i]) {
|
||||
debug("Write to debug_%d as %08x\n", i + 1,
|
||||
regs->debug[i]);
|
||||
ddr_out32(&ddr->debug[i], regs->debug[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For RDIMMs, JEDEC spec requires clocks to be stable before reset is
|
||||
* deasserted. Clocks start when any chip select is enabled and clock
|
||||
* control register is set. Because all DDR components are connected to
|
||||
* one reset signal, this needs to be done in two steps. Step 1 is to
|
||||
* get the clocks started. Step 2 resumes after reset signal is
|
||||
* deasserted.
|
||||
*/
|
||||
if (step == 1) {
|
||||
udelay(200);
|
||||
return;
|
||||
}
|
||||
|
||||
step2:
|
||||
/* Set, but do not enable the memory */
|
||||
temp_sdram_cfg = regs->ddr_sdram_cfg;
|
||||
temp_sdram_cfg &= ~(SDRAM_CFG_MEM_EN);
|
||||
ddr_out32(&ddr->sdram_cfg, temp_sdram_cfg);
|
||||
|
||||
/*
|
||||
* 500 painful micro-seconds must elapse between
|
||||
* the DDR clock setup and the DDR config enable.
|
||||
* DDR2 need 200 us, and DDR3 need 500 us from spec,
|
||||
* we choose the max, that is 500 us for all of case.
|
||||
*/
|
||||
udelay(500);
|
||||
asm volatile("dsb sy;isb");
|
||||
|
||||
#ifdef CONFIG_DEEP_SLEEP
|
||||
if (is_warm_boot()) {
|
||||
/* enter self-refresh */
|
||||
temp_sdram_cfg = ddr_in32(&ddr->sdram_cfg_2);
|
||||
temp_sdram_cfg |= SDRAM_CFG2_FRC_SR;
|
||||
ddr_out32(&ddr->sdram_cfg_2, temp_sdram_cfg);
|
||||
/* do board specific memory setup */
|
||||
board_mem_sleep_setup();
|
||||
|
||||
temp_sdram_cfg = (ddr_in32(&ddr->sdram_cfg) | SDRAM_CFG_BI);
|
||||
} else
|
||||
#endif
|
||||
temp_sdram_cfg = ddr_in32(&ddr->sdram_cfg) & ~SDRAM_CFG_BI;
|
||||
/* Let the controller go */
|
||||
ddr_out32(&ddr->sdram_cfg, temp_sdram_cfg | SDRAM_CFG_MEM_EN);
|
||||
asm volatile("dsb sy;isb");
|
||||
|
||||
total_gb_size_per_controller = 0;
|
||||
for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
|
||||
if (!(regs->cs[i].config & 0x80000000))
|
||||
continue;
|
||||
total_gb_size_per_controller += 1 << (
|
||||
((regs->cs[i].config >> 14) & 0x3) + 2 +
|
||||
((regs->cs[i].config >> 8) & 0x7) + 12 +
|
||||
((regs->cs[i].config >> 0) & 0x7) + 8 +
|
||||
3 - ((regs->ddr_sdram_cfg >> 19) & 0x3) -
|
||||
26); /* minus 26 (count of 64M) */
|
||||
}
|
||||
if (regs->cs[0].config & 0x20000000) {
|
||||
/* 2-way interleaving */
|
||||
total_gb_size_per_controller <<= 1;
|
||||
}
|
||||
/*
|
||||
* total memory / bus width = transactions needed
|
||||
* transactions needed / data rate = seconds
|
||||
* to add plenty of buffer, double the time
|
||||
* For example, 2GB on 666MT/s 64-bit bus takes about 402ms
|
||||
* Let's wait for 800ms
|
||||
*/
|
||||
bus_width = 3 - ((ddr_in32(&ddr->sdram_cfg) & SDRAM_CFG_DBW_MASK)
|
||||
>> SDRAM_CFG_DBW_SHIFT);
|
||||
timeout = ((total_gb_size_per_controller << (6 - bus_width)) * 100 /
|
||||
(get_ddr_freq(ctrl_num) >> 20)) << 1;
|
||||
total_gb_size_per_controller >>= 4; /* shift down to gb size */
|
||||
debug("total %d GB\n", total_gb_size_per_controller);
|
||||
debug("Need to wait up to %d * 10ms\n", timeout);
|
||||
|
||||
/* Poll DDR_SDRAM_CFG_2[D_INIT] bit until auto-data init is done. */
|
||||
while ((ddr_in32(&ddr->sdram_cfg_2) & SDRAM_CFG2_D_INIT) &&
|
||||
(timeout >= 0)) {
|
||||
udelay(10000); /* throttle polling rate */
|
||||
timeout--;
|
||||
}
|
||||
|
||||
if (timeout <= 0)
|
||||
printf("Waiting for D_INIT timeout. Memory may not work.\n");
|
||||
#ifdef CONFIG_DEEP_SLEEP
|
||||
if (is_warm_boot()) {
|
||||
/* exit self-refresh */
|
||||
temp_sdram_cfg = ddr_in32(&ddr->sdram_cfg_2);
|
||||
temp_sdram_cfg &= ~SDRAM_CFG2_FRC_SR;
|
||||
ddr_out32(&ddr->sdram_cfg_2, temp_sdram_cfg);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
2530
u-boot/drivers/ddr/fsl/ctrl_regs.c
Normal file
2530
u-boot/drivers/ddr/fsl/ctrl_regs.c
Normal file
File diff suppressed because it is too large
Load Diff
341
u-boot/drivers/ddr/fsl/ddr1_dimm_params.c
Normal file
341
u-boot/drivers/ddr/fsl/ddr1_dimm_params.c
Normal file
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* Copyright 2008 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <fsl_ddr_sdram.h>
|
||||
|
||||
#include <fsl_ddr.h>
|
||||
|
||||
/*
|
||||
* Calculate the Density of each Physical Rank.
|
||||
* Returned size is in bytes.
|
||||
*
|
||||
* Study these table from Byte 31 of JEDEC SPD Spec.
|
||||
*
|
||||
* DDR I DDR II
|
||||
* Bit Size Size
|
||||
* --- ----- ------
|
||||
* 7 high 512MB 512MB
|
||||
* 6 256MB 256MB
|
||||
* 5 128MB 128MB
|
||||
* 4 64MB 16GB
|
||||
* 3 32MB 8GB
|
||||
* 2 16MB 4GB
|
||||
* 1 2GB 2GB
|
||||
* 0 low 1GB 1GB
|
||||
*
|
||||
* Reorder Table to be linear by stripping the bottom
|
||||
* 2 or 5 bits off and shifting them up to the top.
|
||||
*/
|
||||
|
||||
static unsigned long long
|
||||
compute_ranksize(unsigned int mem_type, unsigned char row_dens)
|
||||
{
|
||||
unsigned long long bsize;
|
||||
|
||||
/* Bottom 2 bits up to the top. */
|
||||
bsize = ((row_dens >> 2) | ((row_dens & 3) << 6));
|
||||
bsize <<= 24ULL;
|
||||
debug("DDR: DDR I rank density = 0x%16llx\n", bsize);
|
||||
|
||||
return bsize;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a two-nibble BCD value into a cycle time.
|
||||
* While the spec calls for nano-seconds, picos are returned.
|
||||
*
|
||||
* This implements the tables for bytes 9, 23 and 25 for both
|
||||
* DDR I and II. No allowance for distinguishing the invalid
|
||||
* fields absent for DDR I yet present in DDR II is made.
|
||||
* (That is, cycle times of .25, .33, .66 and .75 ns are
|
||||
* allowed for both DDR II and I.)
|
||||
*/
|
||||
static unsigned int
|
||||
convert_bcd_tenths_to_cycle_time_ps(unsigned int spd_val)
|
||||
{
|
||||
/* Table look up the lower nibble, allow DDR I & II. */
|
||||
unsigned int tenths_ps[16] = {
|
||||
0,
|
||||
100,
|
||||
200,
|
||||
300,
|
||||
400,
|
||||
500,
|
||||
600,
|
||||
700,
|
||||
800,
|
||||
900,
|
||||
250, /* This and the next 3 entries valid ... */
|
||||
330, /* ... only for tCK calculations. */
|
||||
660,
|
||||
750,
|
||||
0, /* undefined */
|
||||
0 /* undefined */
|
||||
};
|
||||
|
||||
unsigned int whole_ns = (spd_val & 0xF0) >> 4;
|
||||
unsigned int tenth_ns = spd_val & 0x0F;
|
||||
unsigned int ps = whole_ns * 1000 + tenths_ps[tenth_ns];
|
||||
|
||||
return ps;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
convert_bcd_hundredths_to_cycle_time_ps(unsigned int spd_val)
|
||||
{
|
||||
unsigned int tenth_ns = (spd_val & 0xF0) >> 4;
|
||||
unsigned int hundredth_ns = spd_val & 0x0F;
|
||||
unsigned int ps = tenth_ns * 100 + hundredth_ns * 10;
|
||||
|
||||
return ps;
|
||||
}
|
||||
|
||||
static unsigned int byte40_table_ps[8] = {
|
||||
0,
|
||||
250,
|
||||
330,
|
||||
500,
|
||||
660,
|
||||
750,
|
||||
0, /* supposed to be RFC, but not sure what that means */
|
||||
0 /* Undefined */
|
||||
};
|
||||
|
||||
static unsigned int
|
||||
compute_trfc_ps_from_spd(unsigned char trctrfc_ext, unsigned char trfc)
|
||||
{
|
||||
unsigned int trfc_ps;
|
||||
|
||||
trfc_ps = (((trctrfc_ext & 0x1) * 256) + trfc) * 1000
|
||||
+ byte40_table_ps[(trctrfc_ext >> 1) & 0x7];
|
||||
|
||||
return trfc_ps;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
compute_trc_ps_from_spd(unsigned char trctrfc_ext, unsigned char trc)
|
||||
{
|
||||
unsigned int trc_ps;
|
||||
|
||||
trc_ps = trc * 1000 + byte40_table_ps[(trctrfc_ext >> 4) & 0x7];
|
||||
|
||||
return trc_ps;
|
||||
}
|
||||
|
||||
/*
|
||||
* tCKmax from DDR I SPD Byte 43
|
||||
*
|
||||
* Bits 7:2 == whole ns
|
||||
* Bits 1:0 == quarter ns
|
||||
* 00 == 0.00 ns
|
||||
* 01 == 0.25 ns
|
||||
* 10 == 0.50 ns
|
||||
* 11 == 0.75 ns
|
||||
*
|
||||
* Returns picoseconds.
|
||||
*/
|
||||
static unsigned int
|
||||
compute_tckmax_from_spd_ps(unsigned int byte43)
|
||||
{
|
||||
return (byte43 >> 2) * 1000 + (byte43 & 0x3) * 250;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine Refresh Rate. Ignore self refresh bit on DDR I.
|
||||
* Table from SPD Spec, Byte 12, converted to picoseconds and
|
||||
* filled in with "default" normal values.
|
||||
*/
|
||||
static unsigned int
|
||||
determine_refresh_rate_ps(const unsigned int spd_refresh)
|
||||
{
|
||||
unsigned int refresh_time_ps[8] = {
|
||||
15625000, /* 0 Normal 1.00x */
|
||||
3900000, /* 1 Reduced .25x */
|
||||
7800000, /* 2 Extended .50x */
|
||||
31300000, /* 3 Extended 2.00x */
|
||||
62500000, /* 4 Extended 4.00x */
|
||||
125000000, /* 5 Extended 8.00x */
|
||||
15625000, /* 6 Normal 1.00x filler */
|
||||
15625000, /* 7 Normal 1.00x filler */
|
||||
};
|
||||
|
||||
return refresh_time_ps[spd_refresh & 0x7];
|
||||
}
|
||||
|
||||
/*
|
||||
* The purpose of this function is to compute a suitable
|
||||
* CAS latency given the DRAM clock period. The SPD only
|
||||
* defines at most 3 CAS latencies. Typically the slower in
|
||||
* frequency the DIMM runs at, the shorter its CAS latency can be.
|
||||
* If the DIMM is operating at a sufficiently low frequency,
|
||||
* it may be able to run at a CAS latency shorter than the
|
||||
* shortest SPD-defined CAS latency.
|
||||
*
|
||||
* If a CAS latency is not found, 0 is returned.
|
||||
*
|
||||
* Do this by finding in the standard speed bin table the longest
|
||||
* tCKmin that doesn't exceed the value of mclk_ps (tCK).
|
||||
*
|
||||
* An assumption made is that the SDRAM device allows the
|
||||
* CL to be programmed for a value that is lower than those
|
||||
* advertised by the SPD. This is not always the case,
|
||||
* as those modes not defined in the SPD are optional.
|
||||
*
|
||||
* CAS latency de-rating based upon values JEDEC Standard No. 79-E
|
||||
* Table 11.
|
||||
*
|
||||
* ordinal 2, ddr1_speed_bins[1] contains tCK for CL=2
|
||||
*/
|
||||
/* CL2.0 CL2.5 CL3.0 */
|
||||
unsigned short ddr1_speed_bins[] = {0, 7500, 6000, 5000 };
|
||||
|
||||
unsigned int
|
||||
compute_derated_DDR1_CAS_latency(unsigned int mclk_ps)
|
||||
{
|
||||
const unsigned int num_speed_bins = ARRAY_SIZE(ddr1_speed_bins);
|
||||
unsigned int lowest_tCKmin_found = 0;
|
||||
unsigned int lowest_tCKmin_CL = 0;
|
||||
unsigned int i;
|
||||
|
||||
debug("mclk_ps = %u\n", mclk_ps);
|
||||
|
||||
for (i = 0; i < num_speed_bins; i++) {
|
||||
unsigned int x = ddr1_speed_bins[i];
|
||||
debug("i=%u, x = %u, lowest_tCKmin_found = %u\n",
|
||||
i, x, lowest_tCKmin_found);
|
||||
if (x && lowest_tCKmin_found <= x && x <= mclk_ps) {
|
||||
lowest_tCKmin_found = x;
|
||||
lowest_tCKmin_CL = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
debug("lowest_tCKmin_CL = %u\n", lowest_tCKmin_CL);
|
||||
|
||||
return lowest_tCKmin_CL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ddr_compute_dimm_parameters for DDR1 SPD
|
||||
*
|
||||
* Compute DIMM parameters based upon the SPD information in spd.
|
||||
* Writes the results to the dimm_params_t structure pointed by pdimm.
|
||||
*
|
||||
* FIXME: use #define for the retvals
|
||||
*/
|
||||
unsigned int ddr_compute_dimm_parameters(const unsigned int ctrl_num,
|
||||
const ddr1_spd_eeprom_t *spd,
|
||||
dimm_params_t *pdimm,
|
||||
unsigned int dimm_number)
|
||||
{
|
||||
unsigned int retval;
|
||||
|
||||
if (spd->mem_type) {
|
||||
if (spd->mem_type != SPD_MEMTYPE_DDR) {
|
||||
printf("DIMM %u: is not a DDR1 SPD.\n", dimm_number);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
memset(pdimm, 0, sizeof(dimm_params_t));
|
||||
return 1;
|
||||
}
|
||||
|
||||
retval = ddr1_spd_check(spd);
|
||||
if (retval) {
|
||||
printf("DIMM %u: failed checksum\n", dimm_number);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* The part name in ASCII in the SPD EEPROM is not null terminated.
|
||||
* Guarantee null termination here by presetting all bytes to 0
|
||||
* and copying the part name in ASCII from the SPD onto it
|
||||
*/
|
||||
memset(pdimm->mpart, 0, sizeof(pdimm->mpart));
|
||||
memcpy(pdimm->mpart, spd->mpart, sizeof(pdimm->mpart) - 1);
|
||||
|
||||
/* DIMM organization parameters */
|
||||
pdimm->n_ranks = spd->nrows;
|
||||
pdimm->rank_density = compute_ranksize(spd->mem_type, spd->bank_dens);
|
||||
pdimm->capacity = pdimm->n_ranks * pdimm->rank_density;
|
||||
pdimm->data_width = spd->dataw_lsb;
|
||||
pdimm->primary_sdram_width = spd->primw;
|
||||
pdimm->ec_sdram_width = spd->ecw;
|
||||
|
||||
/*
|
||||
* FIXME: Need to determine registered_dimm status.
|
||||
* 1 == register buffered
|
||||
* 0 == unbuffered
|
||||
*/
|
||||
pdimm->registered_dimm = 0; /* unbuffered */
|
||||
|
||||
/* SDRAM device parameters */
|
||||
pdimm->n_row_addr = spd->nrow_addr;
|
||||
pdimm->n_col_addr = spd->ncol_addr;
|
||||
pdimm->n_banks_per_sdram_device = spd->nbanks;
|
||||
pdimm->edc_config = spd->config;
|
||||
pdimm->burst_lengths_bitmask = spd->burstl;
|
||||
pdimm->row_density = spd->bank_dens;
|
||||
|
||||
/*
|
||||
* Calculate the Maximum Data Rate based on the Minimum Cycle time.
|
||||
* The SPD clk_cycle field (tCKmin) is measured in tenths of
|
||||
* nanoseconds and represented as BCD.
|
||||
*/
|
||||
pdimm->tckmin_x_ps
|
||||
= convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle);
|
||||
pdimm->tckmin_x_minus_1_ps
|
||||
= convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle2);
|
||||
pdimm->tckmin_x_minus_2_ps
|
||||
= convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle3);
|
||||
|
||||
pdimm->tckmax_ps = compute_tckmax_from_spd_ps(spd->tckmax);
|
||||
|
||||
/*
|
||||
* Compute CAS latencies defined by SPD
|
||||
* The SPD caslat_x should have at least 1 and at most 3 bits set.
|
||||
*
|
||||
* If cas_lat after masking is 0, the __ilog2 function returns
|
||||
* 255 into the variable. This behavior is abused once.
|
||||
*/
|
||||
pdimm->caslat_x = __ilog2(spd->cas_lat);
|
||||
pdimm->caslat_x_minus_1 = __ilog2(spd->cas_lat
|
||||
& ~(1 << pdimm->caslat_x));
|
||||
pdimm->caslat_x_minus_2 = __ilog2(spd->cas_lat
|
||||
& ~(1 << pdimm->caslat_x)
|
||||
& ~(1 << pdimm->caslat_x_minus_1));
|
||||
|
||||
/* Compute CAS latencies below that defined by SPD */
|
||||
pdimm->caslat_lowest_derated = compute_derated_DDR1_CAS_latency(
|
||||
get_memory_clk_period_ps(ctrl_num));
|
||||
|
||||
/* Compute timing parameters */
|
||||
pdimm->trcd_ps = spd->trcd * 250;
|
||||
pdimm->trp_ps = spd->trp * 250;
|
||||
pdimm->tras_ps = spd->tras * 1000;
|
||||
|
||||
pdimm->twr_ps = mclk_to_picos(ctrl_num, 3);
|
||||
pdimm->twtr_ps = mclk_to_picos(ctrl_num, 1);
|
||||
pdimm->trfc_ps = compute_trfc_ps_from_spd(0, spd->trfc);
|
||||
|
||||
pdimm->trrd_ps = spd->trrd * 250;
|
||||
pdimm->trc_ps = compute_trc_ps_from_spd(0, spd->trc);
|
||||
|
||||
pdimm->refresh_rate_ps = determine_refresh_rate_ps(spd->refresh);
|
||||
|
||||
pdimm->tis_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_setup);
|
||||
pdimm->tih_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_hold);
|
||||
pdimm->tds_ps
|
||||
= convert_bcd_hundredths_to_cycle_time_ps(spd->data_setup);
|
||||
pdimm->tdh_ps
|
||||
= convert_bcd_hundredths_to_cycle_time_ps(spd->data_hold);
|
||||
|
||||
pdimm->trtp_ps = mclk_to_picos(ctrl_num, 2); /* By the book. */
|
||||
pdimm->tdqsq_max_ps = spd->tdqsq * 10;
|
||||
pdimm->tqhs_ps = spd->tqhs * 10;
|
||||
|
||||
return 0;
|
||||
}
|
||||
340
u-boot/drivers/ddr/fsl/ddr2_dimm_params.c
Normal file
340
u-boot/drivers/ddr/fsl/ddr2_dimm_params.c
Normal file
@@ -0,0 +1,340 @@
|
||||
/*
|
||||
* Copyright 2008 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <fsl_ddr_sdram.h>
|
||||
|
||||
#include <fsl_ddr.h>
|
||||
/*
|
||||
* Calculate the Density of each Physical Rank.
|
||||
* Returned size is in bytes.
|
||||
*
|
||||
* Study these table from Byte 31 of JEDEC SPD Spec.
|
||||
*
|
||||
* DDR I DDR II
|
||||
* Bit Size Size
|
||||
* --- ----- ------
|
||||
* 7 high 512MB 512MB
|
||||
* 6 256MB 256MB
|
||||
* 5 128MB 128MB
|
||||
* 4 64MB 16GB
|
||||
* 3 32MB 8GB
|
||||
* 2 16MB 4GB
|
||||
* 1 2GB 2GB
|
||||
* 0 low 1GB 1GB
|
||||
*
|
||||
* Reorder Table to be linear by stripping the bottom
|
||||
* 2 or 5 bits off and shifting them up to the top.
|
||||
*
|
||||
*/
|
||||
static unsigned long long
|
||||
compute_ranksize(unsigned int mem_type, unsigned char row_dens)
|
||||
{
|
||||
unsigned long long bsize;
|
||||
|
||||
/* Bottom 5 bits up to the top. */
|
||||
bsize = ((row_dens >> 5) | ((row_dens & 31) << 3));
|
||||
bsize <<= 27ULL;
|
||||
debug("DDR: DDR II rank density = 0x%16llx\n", bsize);
|
||||
|
||||
return bsize;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a two-nibble BCD value into a cycle time.
|
||||
* While the spec calls for nano-seconds, picos are returned.
|
||||
*
|
||||
* This implements the tables for bytes 9, 23 and 25 for both
|
||||
* DDR I and II. No allowance for distinguishing the invalid
|
||||
* fields absent for DDR I yet present in DDR II is made.
|
||||
* (That is, cycle times of .25, .33, .66 and .75 ns are
|
||||
* allowed for both DDR II and I.)
|
||||
*/
|
||||
static unsigned int
|
||||
convert_bcd_tenths_to_cycle_time_ps(unsigned int spd_val)
|
||||
{
|
||||
/* Table look up the lower nibble, allow DDR I & II. */
|
||||
unsigned int tenths_ps[16] = {
|
||||
0,
|
||||
100,
|
||||
200,
|
||||
300,
|
||||
400,
|
||||
500,
|
||||
600,
|
||||
700,
|
||||
800,
|
||||
900,
|
||||
250, /* This and the next 3 entries valid ... */
|
||||
330, /* ... only for tCK calculations. */
|
||||
660,
|
||||
750,
|
||||
0, /* undefined */
|
||||
0 /* undefined */
|
||||
};
|
||||
|
||||
unsigned int whole_ns = (spd_val & 0xF0) >> 4;
|
||||
unsigned int tenth_ns = spd_val & 0x0F;
|
||||
unsigned int ps = whole_ns * 1000 + tenths_ps[tenth_ns];
|
||||
|
||||
return ps;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
convert_bcd_hundredths_to_cycle_time_ps(unsigned int spd_val)
|
||||
{
|
||||
unsigned int tenth_ns = (spd_val & 0xF0) >> 4;
|
||||
unsigned int hundredth_ns = spd_val & 0x0F;
|
||||
unsigned int ps = tenth_ns * 100 + hundredth_ns * 10;
|
||||
|
||||
return ps;
|
||||
}
|
||||
|
||||
static unsigned int byte40_table_ps[8] = {
|
||||
0,
|
||||
250,
|
||||
330,
|
||||
500,
|
||||
660,
|
||||
750,
|
||||
0, /* supposed to be RFC, but not sure what that means */
|
||||
0 /* Undefined */
|
||||
};
|
||||
|
||||
static unsigned int
|
||||
compute_trfc_ps_from_spd(unsigned char trctrfc_ext, unsigned char trfc)
|
||||
{
|
||||
unsigned int trfc_ps;
|
||||
|
||||
trfc_ps = (((trctrfc_ext & 0x1) * 256) + trfc) * 1000
|
||||
+ byte40_table_ps[(trctrfc_ext >> 1) & 0x7];
|
||||
|
||||
return trfc_ps;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
compute_trc_ps_from_spd(unsigned char trctrfc_ext, unsigned char trc)
|
||||
{
|
||||
unsigned int trc_ps;
|
||||
|
||||
trc_ps = trc * 1000 + byte40_table_ps[(trctrfc_ext >> 4) & 0x7];
|
||||
|
||||
return trc_ps;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine Refresh Rate. Ignore self refresh bit on DDR I.
|
||||
* Table from SPD Spec, Byte 12, converted to picoseconds and
|
||||
* filled in with "default" normal values.
|
||||
*/
|
||||
static unsigned int
|
||||
determine_refresh_rate_ps(const unsigned int spd_refresh)
|
||||
{
|
||||
unsigned int refresh_time_ps[8] = {
|
||||
15625000, /* 0 Normal 1.00x */
|
||||
3900000, /* 1 Reduced .25x */
|
||||
7800000, /* 2 Extended .50x */
|
||||
31300000, /* 3 Extended 2.00x */
|
||||
62500000, /* 4 Extended 4.00x */
|
||||
125000000, /* 5 Extended 8.00x */
|
||||
15625000, /* 6 Normal 1.00x filler */
|
||||
15625000, /* 7 Normal 1.00x filler */
|
||||
};
|
||||
|
||||
return refresh_time_ps[spd_refresh & 0x7];
|
||||
}
|
||||
|
||||
/*
|
||||
* The purpose of this function is to compute a suitable
|
||||
* CAS latency given the DRAM clock period. The SPD only
|
||||
* defines at most 3 CAS latencies. Typically the slower in
|
||||
* frequency the DIMM runs at, the shorter its CAS latency can.
|
||||
* be. If the DIMM is operating at a sufficiently low frequency,
|
||||
* it may be able to run at a CAS latency shorter than the
|
||||
* shortest SPD-defined CAS latency.
|
||||
*
|
||||
* If a CAS latency is not found, 0 is returned.
|
||||
*
|
||||
* Do this by finding in the standard speed bin table the longest
|
||||
* tCKmin that doesn't exceed the value of mclk_ps (tCK).
|
||||
*
|
||||
* An assumption made is that the SDRAM device allows the
|
||||
* CL to be programmed for a value that is lower than those
|
||||
* advertised by the SPD. This is not always the case,
|
||||
* as those modes not defined in the SPD are optional.
|
||||
*
|
||||
* CAS latency de-rating based upon values JEDEC Standard No. 79-2C
|
||||
* Table 40, "DDR2 SDRAM stanadard speed bins and tCK, tRCD, tRP, tRAS,
|
||||
* and tRC for corresponding bin"
|
||||
*
|
||||
* ordinal 2, ddr2_speed_bins[1] contains tCK for CL=3
|
||||
* Not certain if any good value exists for CL=2
|
||||
*/
|
||||
/* CL2 CL3 CL4 CL5 CL6 CL7*/
|
||||
unsigned short ddr2_speed_bins[] = { 0, 5000, 3750, 3000, 2500, 1875 };
|
||||
|
||||
unsigned int
|
||||
compute_derated_DDR2_CAS_latency(unsigned int mclk_ps)
|
||||
{
|
||||
const unsigned int num_speed_bins = ARRAY_SIZE(ddr2_speed_bins);
|
||||
unsigned int lowest_tCKmin_found = 0;
|
||||
unsigned int lowest_tCKmin_CL = 0;
|
||||
unsigned int i;
|
||||
|
||||
debug("mclk_ps = %u\n", mclk_ps);
|
||||
|
||||
for (i = 0; i < num_speed_bins; i++) {
|
||||
unsigned int x = ddr2_speed_bins[i];
|
||||
debug("i=%u, x = %u, lowest_tCKmin_found = %u\n",
|
||||
i, x, lowest_tCKmin_found);
|
||||
if (x && x <= mclk_ps && x >= lowest_tCKmin_found ) {
|
||||
lowest_tCKmin_found = x;
|
||||
lowest_tCKmin_CL = i + 2;
|
||||
}
|
||||
}
|
||||
|
||||
debug("lowest_tCKmin_CL = %u\n", lowest_tCKmin_CL);
|
||||
|
||||
return lowest_tCKmin_CL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ddr_compute_dimm_parameters for DDR2 SPD
|
||||
*
|
||||
* Compute DIMM parameters based upon the SPD information in spd.
|
||||
* Writes the results to the dimm_params_t structure pointed by pdimm.
|
||||
*
|
||||
* FIXME: use #define for the retvals
|
||||
*/
|
||||
unsigned int ddr_compute_dimm_parameters(const unsigned int ctrl_num,
|
||||
const ddr2_spd_eeprom_t *spd,
|
||||
dimm_params_t *pdimm,
|
||||
unsigned int dimm_number)
|
||||
{
|
||||
unsigned int retval;
|
||||
|
||||
if (spd->mem_type) {
|
||||
if (spd->mem_type != SPD_MEMTYPE_DDR2) {
|
||||
printf("DIMM %u: is not a DDR2 SPD.\n", dimm_number);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
memset(pdimm, 0, sizeof(dimm_params_t));
|
||||
return 1;
|
||||
}
|
||||
|
||||
retval = ddr2_spd_check(spd);
|
||||
if (retval) {
|
||||
printf("DIMM %u: failed checksum\n", dimm_number);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* The part name in ASCII in the SPD EEPROM is not null terminated.
|
||||
* Guarantee null termination here by presetting all bytes to 0
|
||||
* and copying the part name in ASCII from the SPD onto it
|
||||
*/
|
||||
memset(pdimm->mpart, 0, sizeof(pdimm->mpart));
|
||||
memcpy(pdimm->mpart, spd->mpart, sizeof(pdimm->mpart) - 1);
|
||||
|
||||
/* DIMM organization parameters */
|
||||
pdimm->n_ranks = (spd->mod_ranks & 0x7) + 1;
|
||||
pdimm->rank_density = compute_ranksize(spd->mem_type, spd->rank_dens);
|
||||
pdimm->capacity = pdimm->n_ranks * pdimm->rank_density;
|
||||
pdimm->data_width = spd->dataw;
|
||||
pdimm->primary_sdram_width = spd->primw;
|
||||
pdimm->ec_sdram_width = spd->ecw;
|
||||
|
||||
/* These are all the types defined by the JEDEC DDR2 SPD 1.3 spec */
|
||||
switch (spd->dimm_type) {
|
||||
case DDR2_SPD_DIMMTYPE_RDIMM:
|
||||
case DDR2_SPD_DIMMTYPE_72B_SO_RDIMM:
|
||||
case DDR2_SPD_DIMMTYPE_MINI_RDIMM:
|
||||
/* Registered/buffered DIMMs */
|
||||
pdimm->registered_dimm = 1;
|
||||
break;
|
||||
|
||||
case DDR2_SPD_DIMMTYPE_UDIMM:
|
||||
case DDR2_SPD_DIMMTYPE_SO_DIMM:
|
||||
case DDR2_SPD_DIMMTYPE_MICRO_DIMM:
|
||||
case DDR2_SPD_DIMMTYPE_MINI_UDIMM:
|
||||
/* Unbuffered DIMMs */
|
||||
pdimm->registered_dimm = 0;
|
||||
break;
|
||||
|
||||
case DDR2_SPD_DIMMTYPE_72B_SO_CDIMM:
|
||||
default:
|
||||
printf("unknown dimm_type 0x%02X\n", spd->dimm_type);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* SDRAM device parameters */
|
||||
pdimm->n_row_addr = spd->nrow_addr;
|
||||
pdimm->n_col_addr = spd->ncol_addr;
|
||||
pdimm->n_banks_per_sdram_device = spd->nbanks;
|
||||
pdimm->edc_config = spd->config;
|
||||
pdimm->burst_lengths_bitmask = spd->burstl;
|
||||
pdimm->row_density = spd->rank_dens;
|
||||
|
||||
/*
|
||||
* Calculate the Maximum Data Rate based on the Minimum Cycle time.
|
||||
* The SPD clk_cycle field (tCKmin) is measured in tenths of
|
||||
* nanoseconds and represented as BCD.
|
||||
*/
|
||||
pdimm->tckmin_x_ps
|
||||
= convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle);
|
||||
pdimm->tckmin_x_minus_1_ps
|
||||
= convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle2);
|
||||
pdimm->tckmin_x_minus_2_ps
|
||||
= convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle3);
|
||||
|
||||
pdimm->tckmax_ps = convert_bcd_tenths_to_cycle_time_ps(spd->tckmax);
|
||||
|
||||
/*
|
||||
* Compute CAS latencies defined by SPD
|
||||
* The SPD caslat_x should have at least 1 and at most 3 bits set.
|
||||
*
|
||||
* If cas_lat after masking is 0, the __ilog2 function returns
|
||||
* 255 into the variable. This behavior is abused once.
|
||||
*/
|
||||
pdimm->caslat_x = __ilog2(spd->cas_lat);
|
||||
pdimm->caslat_x_minus_1 = __ilog2(spd->cas_lat
|
||||
& ~(1 << pdimm->caslat_x));
|
||||
pdimm->caslat_x_minus_2 = __ilog2(spd->cas_lat
|
||||
& ~(1 << pdimm->caslat_x)
|
||||
& ~(1 << pdimm->caslat_x_minus_1));
|
||||
|
||||
/* Compute CAS latencies below that defined by SPD */
|
||||
pdimm->caslat_lowest_derated = compute_derated_DDR2_CAS_latency(
|
||||
get_memory_clk_period_ps(ctrl_num));
|
||||
|
||||
/* Compute timing parameters */
|
||||
pdimm->trcd_ps = spd->trcd * 250;
|
||||
pdimm->trp_ps = spd->trp * 250;
|
||||
pdimm->tras_ps = spd->tras * 1000;
|
||||
|
||||
pdimm->twr_ps = spd->twr * 250;
|
||||
pdimm->twtr_ps = spd->twtr * 250;
|
||||
pdimm->trfc_ps = compute_trfc_ps_from_spd(spd->trctrfc_ext, spd->trfc);
|
||||
|
||||
pdimm->trrd_ps = spd->trrd * 250;
|
||||
pdimm->trc_ps = compute_trc_ps_from_spd(spd->trctrfc_ext, spd->trc);
|
||||
|
||||
pdimm->refresh_rate_ps = determine_refresh_rate_ps(spd->refresh);
|
||||
|
||||
pdimm->tis_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_setup);
|
||||
pdimm->tih_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_hold);
|
||||
pdimm->tds_ps
|
||||
= convert_bcd_hundredths_to_cycle_time_ps(spd->data_setup);
|
||||
pdimm->tdh_ps
|
||||
= convert_bcd_hundredths_to_cycle_time_ps(spd->data_hold);
|
||||
|
||||
pdimm->trtp_ps = spd->trtp * 250;
|
||||
pdimm->tdqsq_max_ps = spd->tdqsq * 10;
|
||||
pdimm->tqhs_ps = spd->tqhs * 10;
|
||||
|
||||
return 0;
|
||||
}
|
||||
339
u-boot/drivers/ddr/fsl/ddr3_dimm_params.c
Normal file
339
u-boot/drivers/ddr/fsl/ddr3_dimm_params.c
Normal file
@@ -0,0 +1,339 @@
|
||||
/*
|
||||
* Copyright 2008-2012 Freescale Semiconductor, Inc.
|
||||
* Dave Liu <daveliu@freescale.com>
|
||||
*
|
||||
* calculate the organization and timing parameter
|
||||
* from ddr3 spd, please refer to the spec
|
||||
* JEDEC standard No.21-C 4_01_02_11R18.pdf
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <fsl_ddr_sdram.h>
|
||||
|
||||
#include <fsl_ddr.h>
|
||||
|
||||
/*
|
||||
* Calculate the Density of each Physical Rank.
|
||||
* Returned size is in bytes.
|
||||
*
|
||||
* each rank size =
|
||||
* sdram capacity(bit) / 8 * primary bus width / sdram width
|
||||
*
|
||||
* where: sdram capacity = spd byte4[3:0]
|
||||
* primary bus width = spd byte8[2:0]
|
||||
* sdram width = spd byte7[2:0]
|
||||
*
|
||||
* SPD byte4 - sdram density and banks
|
||||
* bit[3:0] size(bit) size(byte)
|
||||
* 0000 256Mb 32MB
|
||||
* 0001 512Mb 64MB
|
||||
* 0010 1Gb 128MB
|
||||
* 0011 2Gb 256MB
|
||||
* 0100 4Gb 512MB
|
||||
* 0101 8Gb 1GB
|
||||
* 0110 16Gb 2GB
|
||||
*
|
||||
* SPD byte8 - module memory bus width
|
||||
* bit[2:0] primary bus width
|
||||
* 000 8bits
|
||||
* 001 16bits
|
||||
* 010 32bits
|
||||
* 011 64bits
|
||||
*
|
||||
* SPD byte7 - module organiztion
|
||||
* bit[2:0] sdram device width
|
||||
* 000 4bits
|
||||
* 001 8bits
|
||||
* 010 16bits
|
||||
* 011 32bits
|
||||
*
|
||||
*/
|
||||
static unsigned long long
|
||||
compute_ranksize(const ddr3_spd_eeprom_t *spd)
|
||||
{
|
||||
unsigned long long bsize;
|
||||
|
||||
int nbit_sdram_cap_bsize = 0;
|
||||
int nbit_primary_bus_width = 0;
|
||||
int nbit_sdram_width = 0;
|
||||
|
||||
if ((spd->density_banks & 0xf) < 7)
|
||||
nbit_sdram_cap_bsize = (spd->density_banks & 0xf) + 28;
|
||||
if ((spd->bus_width & 0x7) < 4)
|
||||
nbit_primary_bus_width = (spd->bus_width & 0x7) + 3;
|
||||
if ((spd->organization & 0x7) < 4)
|
||||
nbit_sdram_width = (spd->organization & 0x7) + 2;
|
||||
|
||||
bsize = 1ULL << (nbit_sdram_cap_bsize - 3
|
||||
+ nbit_primary_bus_width - nbit_sdram_width);
|
||||
|
||||
debug("DDR: DDR III rank density = 0x%16llx\n", bsize);
|
||||
|
||||
return bsize;
|
||||
}
|
||||
|
||||
/*
|
||||
* ddr_compute_dimm_parameters for DDR3 SPD
|
||||
*
|
||||
* Compute DIMM parameters based upon the SPD information in spd.
|
||||
* Writes the results to the dimm_params_t structure pointed by pdimm.
|
||||
*
|
||||
*/
|
||||
unsigned int ddr_compute_dimm_parameters(const unsigned int ctrl_num,
|
||||
const ddr3_spd_eeprom_t *spd,
|
||||
dimm_params_t *pdimm,
|
||||
unsigned int dimm_number)
|
||||
{
|
||||
unsigned int retval;
|
||||
unsigned int mtb_ps;
|
||||
int ftb_10th_ps;
|
||||
int i;
|
||||
|
||||
if (spd->mem_type) {
|
||||
if (spd->mem_type != SPD_MEMTYPE_DDR3) {
|
||||
printf("DIMM %u: is not a DDR3 SPD.\n", dimm_number);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
memset(pdimm, 0, sizeof(dimm_params_t));
|
||||
return 1;
|
||||
}
|
||||
|
||||
retval = ddr3_spd_check(spd);
|
||||
if (retval) {
|
||||
printf("DIMM %u: failed checksum\n", dimm_number);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* The part name in ASCII in the SPD EEPROM is not null terminated.
|
||||
* Guarantee null termination here by presetting all bytes to 0
|
||||
* and copying the part name in ASCII from the SPD onto it
|
||||
*/
|
||||
memset(pdimm->mpart, 0, sizeof(pdimm->mpart));
|
||||
if ((spd->info_size_crc & 0xF) > 1)
|
||||
memcpy(pdimm->mpart, spd->mpart, sizeof(pdimm->mpart) - 1);
|
||||
|
||||
/* DIMM organization parameters */
|
||||
pdimm->n_ranks = ((spd->organization >> 3) & 0x7) + 1;
|
||||
pdimm->rank_density = compute_ranksize(spd);
|
||||
pdimm->capacity = pdimm->n_ranks * pdimm->rank_density;
|
||||
pdimm->primary_sdram_width = 1 << (3 + (spd->bus_width & 0x7));
|
||||
if ((spd->bus_width >> 3) & 0x3)
|
||||
pdimm->ec_sdram_width = 8;
|
||||
else
|
||||
pdimm->ec_sdram_width = 0;
|
||||
pdimm->data_width = pdimm->primary_sdram_width
|
||||
+ pdimm->ec_sdram_width;
|
||||
pdimm->device_width = 1 << ((spd->organization & 0x7) + 2);
|
||||
|
||||
/* These are the types defined by the JEDEC DDR3 SPD spec */
|
||||
pdimm->mirrored_dimm = 0;
|
||||
pdimm->registered_dimm = 0;
|
||||
switch (spd->module_type & DDR3_SPD_MODULETYPE_MASK) {
|
||||
case DDR3_SPD_MODULETYPE_RDIMM:
|
||||
case DDR3_SPD_MODULETYPE_MINI_RDIMM:
|
||||
case DDR3_SPD_MODULETYPE_72B_SO_RDIMM:
|
||||
/* Registered/buffered DIMMs */
|
||||
pdimm->registered_dimm = 1;
|
||||
for (i = 0; i < 16; i += 2) {
|
||||
u8 rcw = spd->mod_section.registered.rcw[i/2];
|
||||
pdimm->rcw[i] = (rcw >> 0) & 0x0F;
|
||||
pdimm->rcw[i+1] = (rcw >> 4) & 0x0F;
|
||||
}
|
||||
break;
|
||||
|
||||
case DDR3_SPD_MODULETYPE_UDIMM:
|
||||
case DDR3_SPD_MODULETYPE_SO_DIMM:
|
||||
case DDR3_SPD_MODULETYPE_MICRO_DIMM:
|
||||
case DDR3_SPD_MODULETYPE_MINI_UDIMM:
|
||||
case DDR3_SPD_MODULETYPE_MINI_CDIMM:
|
||||
case DDR3_SPD_MODULETYPE_72B_SO_UDIMM:
|
||||
case DDR3_SPD_MODULETYPE_72B_SO_CDIMM:
|
||||
case DDR3_SPD_MODULETYPE_LRDIMM:
|
||||
case DDR3_SPD_MODULETYPE_16B_SO_DIMM:
|
||||
case DDR3_SPD_MODULETYPE_32B_SO_DIMM:
|
||||
/* Unbuffered DIMMs */
|
||||
if (spd->mod_section.unbuffered.addr_mapping & 0x1)
|
||||
pdimm->mirrored_dimm = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("unknown module_type 0x%02X\n", spd->module_type);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* SDRAM device parameters */
|
||||
pdimm->n_row_addr = ((spd->addressing >> 3) & 0x7) + 12;
|
||||
pdimm->n_col_addr = (spd->addressing & 0x7) + 9;
|
||||
pdimm->n_banks_per_sdram_device = 8 << ((spd->density_banks >> 4) & 0x7);
|
||||
|
||||
/*
|
||||
* The SPD spec has not the ECC bit,
|
||||
* We consider the DIMM as ECC capability
|
||||
* when the extension bus exist
|
||||
*/
|
||||
if (pdimm->ec_sdram_width)
|
||||
pdimm->edc_config = 0x02;
|
||||
else
|
||||
pdimm->edc_config = 0x00;
|
||||
|
||||
/*
|
||||
* The SPD spec has not the burst length byte
|
||||
* but DDR3 spec has nature BL8 and BC4,
|
||||
* BL8 -bit3, BC4 -bit2
|
||||
*/
|
||||
pdimm->burst_lengths_bitmask = 0x0c;
|
||||
pdimm->row_density = __ilog2(pdimm->rank_density);
|
||||
|
||||
/* MTB - medium timebase
|
||||
* The unit in the SPD spec is ns,
|
||||
* We convert it to ps.
|
||||
* eg: MTB = 0.125ns (125ps)
|
||||
*/
|
||||
mtb_ps = (spd->mtb_dividend * 1000) /spd->mtb_divisor;
|
||||
pdimm->mtb_ps = mtb_ps;
|
||||
|
||||
/*
|
||||
* FTB - fine timebase
|
||||
* use 1/10th of ps as our unit to avoid floating point
|
||||
* eg, 10 for 1ps, 25 for 2.5ps, 50 for 5ps
|
||||
*/
|
||||
ftb_10th_ps =
|
||||
((spd->ftb_div & 0xf0) >> 4) * 10 / (spd->ftb_div & 0x0f);
|
||||
pdimm->ftb_10th_ps = ftb_10th_ps;
|
||||
/*
|
||||
* sdram minimum cycle time
|
||||
* we assume the MTB is 0.125ns
|
||||
* eg:
|
||||
* tck_min=15 MTB (1.875ns) ->DDR3-1066
|
||||
* =12 MTB (1.5ns) ->DDR3-1333
|
||||
* =10 MTB (1.25ns) ->DDR3-1600
|
||||
*/
|
||||
pdimm->tckmin_x_ps = spd->tck_min * mtb_ps +
|
||||
(spd->fine_tck_min * ftb_10th_ps) / 10;
|
||||
|
||||
/*
|
||||
* CAS latency supported
|
||||
* bit4 - CL4
|
||||
* bit5 - CL5
|
||||
* bit18 - CL18
|
||||
*/
|
||||
pdimm->caslat_x = ((spd->caslat_msb << 8) | spd->caslat_lsb) << 4;
|
||||
|
||||
/*
|
||||
* min CAS latency time
|
||||
* eg: taa_min =
|
||||
* DDR3-800D 100 MTB (12.5ns)
|
||||
* DDR3-1066F 105 MTB (13.125ns)
|
||||
* DDR3-1333H 108 MTB (13.5ns)
|
||||
* DDR3-1600H 90 MTB (11.25ns)
|
||||
*/
|
||||
pdimm->taa_ps = spd->taa_min * mtb_ps +
|
||||
(spd->fine_taa_min * ftb_10th_ps) / 10;
|
||||
|
||||
/*
|
||||
* min write recovery time
|
||||
* eg:
|
||||
* twr_min = 120 MTB (15ns) -> all speed grades.
|
||||
*/
|
||||
pdimm->twr_ps = spd->twr_min * mtb_ps;
|
||||
|
||||
/*
|
||||
* min RAS to CAS delay time
|
||||
* eg: trcd_min =
|
||||
* DDR3-800 100 MTB (12.5ns)
|
||||
* DDR3-1066F 105 MTB (13.125ns)
|
||||
* DDR3-1333H 108 MTB (13.5ns)
|
||||
* DDR3-1600H 90 MTB (11.25)
|
||||
*/
|
||||
pdimm->trcd_ps = spd->trcd_min * mtb_ps +
|
||||
(spd->fine_trcd_min * ftb_10th_ps) / 10;
|
||||
|
||||
/*
|
||||
* min row active to row active delay time
|
||||
* eg: trrd_min =
|
||||
* DDR3-800(1KB page) 80 MTB (10ns)
|
||||
* DDR3-1333(1KB page) 48 MTB (6ns)
|
||||
*/
|
||||
pdimm->trrd_ps = spd->trrd_min * mtb_ps;
|
||||
|
||||
/*
|
||||
* min row precharge delay time
|
||||
* eg: trp_min =
|
||||
* DDR3-800D 100 MTB (12.5ns)
|
||||
* DDR3-1066F 105 MTB (13.125ns)
|
||||
* DDR3-1333H 108 MTB (13.5ns)
|
||||
* DDR3-1600H 90 MTB (11.25ns)
|
||||
*/
|
||||
pdimm->trp_ps = spd->trp_min * mtb_ps +
|
||||
(spd->fine_trp_min * ftb_10th_ps) / 10;
|
||||
|
||||
/* min active to precharge delay time
|
||||
* eg: tRAS_min =
|
||||
* DDR3-800D 300 MTB (37.5ns)
|
||||
* DDR3-1066F 300 MTB (37.5ns)
|
||||
* DDR3-1333H 288 MTB (36ns)
|
||||
* DDR3-1600H 280 MTB (35ns)
|
||||
*/
|
||||
pdimm->tras_ps = (((spd->tras_trc_ext & 0xf) << 8) | spd->tras_min_lsb)
|
||||
* mtb_ps;
|
||||
/*
|
||||
* min active to actice/refresh delay time
|
||||
* eg: tRC_min =
|
||||
* DDR3-800D 400 MTB (50ns)
|
||||
* DDR3-1066F 405 MTB (50.625ns)
|
||||
* DDR3-1333H 396 MTB (49.5ns)
|
||||
* DDR3-1600H 370 MTB (46.25ns)
|
||||
*/
|
||||
pdimm->trc_ps = (((spd->tras_trc_ext & 0xf0) << 4) | spd->trc_min_lsb)
|
||||
* mtb_ps + (spd->fine_trc_min * ftb_10th_ps) / 10;
|
||||
/*
|
||||
* min refresh recovery delay time
|
||||
* eg: tRFC_min =
|
||||
* 512Mb 720 MTB (90ns)
|
||||
* 1Gb 880 MTB (110ns)
|
||||
* 2Gb 1280 MTB (160ns)
|
||||
*/
|
||||
pdimm->trfc_ps = ((spd->trfc_min_msb << 8) | spd->trfc_min_lsb)
|
||||
* mtb_ps;
|
||||
/*
|
||||
* min internal write to read command delay time
|
||||
* eg: twtr_min = 40 MTB (7.5ns) - all speed bins.
|
||||
* tWRT is at least 4 mclk independent of operating freq.
|
||||
*/
|
||||
pdimm->twtr_ps = spd->twtr_min * mtb_ps;
|
||||
|
||||
/*
|
||||
* min internal read to precharge command delay time
|
||||
* eg: trtp_min = 40 MTB (7.5ns) - all speed bins.
|
||||
* tRTP is at least 4 mclk independent of operating freq.
|
||||
*/
|
||||
pdimm->trtp_ps = spd->trtp_min * mtb_ps;
|
||||
|
||||
/*
|
||||
* Average periodic refresh interval
|
||||
* tREFI = 7.8 us at normal temperature range
|
||||
* = 3.9 us at ext temperature range
|
||||
*/
|
||||
pdimm->refresh_rate_ps = 7800000;
|
||||
if ((spd->therm_ref_opt & 0x1) && !(spd->therm_ref_opt & 0x2)) {
|
||||
pdimm->refresh_rate_ps = 3900000;
|
||||
pdimm->extended_op_srt = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* min four active window delay time
|
||||
* eg: tfaw_min =
|
||||
* DDR3-800(1KB page) 320 MTB (40ns)
|
||||
* DDR3-1066(1KB page) 300 MTB (37.5ns)
|
||||
* DDR3-1333(1KB page) 240 MTB (30ns)
|
||||
* DDR3-1600(1KB page) 240 MTB (30ns)
|
||||
*/
|
||||
pdimm->tfaw_ps = (((spd->tfaw_msb & 0xf) << 8) | spd->tfaw_min)
|
||||
* mtb_ps;
|
||||
|
||||
return 0;
|
||||
}
|
||||
323
u-boot/drivers/ddr/fsl/ddr4_dimm_params.c
Normal file
323
u-boot/drivers/ddr/fsl/ddr4_dimm_params.c
Normal file
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
* Copyright 2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* calculate the organization and timing parameter
|
||||
* from ddr3 spd, please refer to the spec
|
||||
* JEDEC standard No.21-C 4_01_02_12R23A.pdf
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <fsl_ddr_sdram.h>
|
||||
|
||||
#include <fsl_ddr.h>
|
||||
|
||||
/*
|
||||
* Calculate the Density of each Physical Rank.
|
||||
* Returned size is in bytes.
|
||||
*
|
||||
* Total DIMM size =
|
||||
* sdram capacity(bit) / 8 * primary bus width / sdram width
|
||||
* * Logical Ranks per DIMM
|
||||
*
|
||||
* where: sdram capacity = spd byte4[3:0]
|
||||
* primary bus width = spd byte13[2:0]
|
||||
* sdram width = spd byte12[2:0]
|
||||
* Logical Ranks per DIMM = spd byte12[5:3] for SDP, DDP, QDP
|
||||
* spd byte12{5:3] * spd byte6[6:4] for 3DS
|
||||
*
|
||||
* To simplify each rank size = total DIMM size / Number of Package Ranks
|
||||
* where Number of Package Ranks = spd byte12[5:3]
|
||||
*
|
||||
* SPD byte4 - sdram density and banks
|
||||
* bit[3:0] size(bit) size(byte)
|
||||
* 0000 256Mb 32MB
|
||||
* 0001 512Mb 64MB
|
||||
* 0010 1Gb 128MB
|
||||
* 0011 2Gb 256MB
|
||||
* 0100 4Gb 512MB
|
||||
* 0101 8Gb 1GB
|
||||
* 0110 16Gb 2GB
|
||||
* 0111 32Gb 4GB
|
||||
*
|
||||
* SPD byte13 - module memory bus width
|
||||
* bit[2:0] primary bus width
|
||||
* 000 8bits
|
||||
* 001 16bits
|
||||
* 010 32bits
|
||||
* 011 64bits
|
||||
*
|
||||
* SPD byte12 - module organization
|
||||
* bit[2:0] sdram device width
|
||||
* 000 4bits
|
||||
* 001 8bits
|
||||
* 010 16bits
|
||||
* 011 32bits
|
||||
*
|
||||
* SPD byte12 - module organization
|
||||
* bit[5:3] number of package ranks per DIMM
|
||||
* 000 1
|
||||
* 001 2
|
||||
* 010 3
|
||||
* 011 4
|
||||
*
|
||||
* SPD byte6 - SDRAM package type
|
||||
* bit[6:4] Die count
|
||||
* 000 1
|
||||
* 001 2
|
||||
* 010 3
|
||||
* 011 4
|
||||
* 100 5
|
||||
* 101 6
|
||||
* 110 7
|
||||
* 111 8
|
||||
*
|
||||
* SPD byte6 - SRAM package type
|
||||
* bit[1:0] Signal loading
|
||||
* 00 Not specified
|
||||
* 01 Multi load stack
|
||||
* 10 Sigle load stack (3DS)
|
||||
* 11 Reserved
|
||||
*/
|
||||
static unsigned long long
|
||||
compute_ranksize(const struct ddr4_spd_eeprom_s *spd)
|
||||
{
|
||||
unsigned long long bsize;
|
||||
|
||||
int nbit_sdram_cap_bsize = 0;
|
||||
int nbit_primary_bus_width = 0;
|
||||
int nbit_sdram_width = 0;
|
||||
int die_count = 0;
|
||||
bool package_3ds;
|
||||
|
||||
if ((spd->density_banks & 0xf) <= 7)
|
||||
nbit_sdram_cap_bsize = (spd->density_banks & 0xf) + 28;
|
||||
if ((spd->bus_width & 0x7) < 4)
|
||||
nbit_primary_bus_width = (spd->bus_width & 0x7) + 3;
|
||||
if ((spd->organization & 0x7) < 4)
|
||||
nbit_sdram_width = (spd->organization & 0x7) + 2;
|
||||
package_3ds = (spd->package_type & 0x3) == 0x2;
|
||||
if (package_3ds)
|
||||
die_count = (spd->package_type >> 4) & 0x7;
|
||||
|
||||
bsize = 1ULL << (nbit_sdram_cap_bsize - 3 +
|
||||
nbit_primary_bus_width - nbit_sdram_width +
|
||||
die_count);
|
||||
|
||||
debug("DDR: DDR III rank density = 0x%16llx\n", bsize);
|
||||
|
||||
return bsize;
|
||||
}
|
||||
|
||||
#define spd_to_ps(mtb, ftb) \
|
||||
(mtb * pdimm->mtb_ps + (ftb * pdimm->ftb_10th_ps) / 10)
|
||||
/*
|
||||
* ddr_compute_dimm_parameters for DDR4 SPD
|
||||
*
|
||||
* Compute DIMM parameters based upon the SPD information in spd.
|
||||
* Writes the results to the dimm_params_t structure pointed by pdimm.
|
||||
*
|
||||
*/
|
||||
unsigned int ddr_compute_dimm_parameters(const unsigned int ctrl_num,
|
||||
const generic_spd_eeprom_t *spd,
|
||||
dimm_params_t *pdimm,
|
||||
unsigned int dimm_number)
|
||||
{
|
||||
unsigned int retval;
|
||||
int i;
|
||||
const u8 udimm_rc_e_dq[18] = {
|
||||
0x0c, 0x2c, 0x15, 0x35, 0x15, 0x35, 0x0b, 0x2c, 0x15,
|
||||
0x35, 0x0b, 0x35, 0x0b, 0x2c, 0x0b, 0x35, 0x15, 0x36
|
||||
};
|
||||
int spd_error = 0;
|
||||
u8 *ptr;
|
||||
|
||||
if (spd->mem_type) {
|
||||
if (spd->mem_type != SPD_MEMTYPE_DDR4) {
|
||||
printf("Ctrl %u DIMM %u: is not a DDR4 SPD.\n",
|
||||
ctrl_num, dimm_number);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
memset(pdimm, 0, sizeof(dimm_params_t));
|
||||
return 1;
|
||||
}
|
||||
|
||||
retval = ddr4_spd_check(spd);
|
||||
if (retval) {
|
||||
printf("DIMM %u: failed checksum\n", dimm_number);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* The part name in ASCII in the SPD EEPROM is not null terminated.
|
||||
* Guarantee null termination here by presetting all bytes to 0
|
||||
* and copying the part name in ASCII from the SPD onto it
|
||||
*/
|
||||
memset(pdimm->mpart, 0, sizeof(pdimm->mpart));
|
||||
if ((spd->info_size_crc & 0xF) > 2)
|
||||
memcpy(pdimm->mpart, spd->mpart, sizeof(pdimm->mpart) - 1);
|
||||
|
||||
/* DIMM organization parameters */
|
||||
pdimm->n_ranks = ((spd->organization >> 3) & 0x7) + 1;
|
||||
pdimm->rank_density = compute_ranksize(spd);
|
||||
pdimm->capacity = pdimm->n_ranks * pdimm->rank_density;
|
||||
pdimm->primary_sdram_width = 1 << (3 + (spd->bus_width & 0x7));
|
||||
if ((spd->bus_width >> 3) & 0x3)
|
||||
pdimm->ec_sdram_width = 8;
|
||||
else
|
||||
pdimm->ec_sdram_width = 0;
|
||||
pdimm->data_width = pdimm->primary_sdram_width
|
||||
+ pdimm->ec_sdram_width;
|
||||
pdimm->device_width = 1 << ((spd->organization & 0x7) + 2);
|
||||
|
||||
/* These are the types defined by the JEDEC SPD spec */
|
||||
pdimm->mirrored_dimm = 0;
|
||||
pdimm->registered_dimm = 0;
|
||||
switch (spd->module_type & DDR4_SPD_MODULETYPE_MASK) {
|
||||
case DDR4_SPD_MODULETYPE_RDIMM:
|
||||
/* Registered/buffered DIMMs */
|
||||
pdimm->registered_dimm = 1;
|
||||
break;
|
||||
|
||||
case DDR4_SPD_MODULETYPE_UDIMM:
|
||||
case DDR4_SPD_MODULETYPE_SO_DIMM:
|
||||
/* Unbuffered DIMMs */
|
||||
if (spd->mod_section.unbuffered.addr_mapping & 0x1)
|
||||
pdimm->mirrored_dimm = 1;
|
||||
if ((spd->mod_section.unbuffered.mod_height & 0xe0) == 0 &&
|
||||
(spd->mod_section.unbuffered.ref_raw_card == 0x04)) {
|
||||
/* Fix SPD error found on DIMMs with raw card E0 */
|
||||
for (i = 0; i < 18; i++) {
|
||||
if (spd->mapping[i] == udimm_rc_e_dq[i])
|
||||
continue;
|
||||
spd_error = 1;
|
||||
debug("SPD byte %d: 0x%x, should be 0x%x\n",
|
||||
60 + i, spd->mapping[i],
|
||||
udimm_rc_e_dq[i]);
|
||||
ptr = (u8 *)&spd->mapping[i];
|
||||
*ptr = udimm_rc_e_dq[i];
|
||||
}
|
||||
if (spd_error)
|
||||
puts("SPD DQ mapping error fixed\n");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("unknown module_type 0x%02X\n", spd->module_type);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* SDRAM device parameters */
|
||||
pdimm->n_row_addr = ((spd->addressing >> 3) & 0x7) + 12;
|
||||
pdimm->n_col_addr = (spd->addressing & 0x7) + 9;
|
||||
pdimm->bank_addr_bits = (spd->density_banks >> 4) & 0x3;
|
||||
pdimm->bank_group_bits = (spd->density_banks >> 6) & 0x3;
|
||||
|
||||
/*
|
||||
* The SPD spec has not the ECC bit,
|
||||
* We consider the DIMM as ECC capability
|
||||
* when the extension bus exist
|
||||
*/
|
||||
if (pdimm->ec_sdram_width)
|
||||
pdimm->edc_config = 0x02;
|
||||
else
|
||||
pdimm->edc_config = 0x00;
|
||||
|
||||
/*
|
||||
* The SPD spec has not the burst length byte
|
||||
* but DDR4 spec has nature BL8 and BC4,
|
||||
* BL8 -bit3, BC4 -bit2
|
||||
*/
|
||||
pdimm->burst_lengths_bitmask = 0x0c;
|
||||
pdimm->row_density = __ilog2(pdimm->rank_density);
|
||||
|
||||
/* MTB - medium timebase
|
||||
* The MTB in the SPD spec is 125ps,
|
||||
*
|
||||
* FTB - fine timebase
|
||||
* use 1/10th of ps as our unit to avoid floating point
|
||||
* eg, 10 for 1ps, 25 for 2.5ps, 50 for 5ps
|
||||
*/
|
||||
if ((spd->timebases & 0xf) == 0x0) {
|
||||
pdimm->mtb_ps = 125;
|
||||
pdimm->ftb_10th_ps = 10;
|
||||
|
||||
} else {
|
||||
printf("Unknown Timebases\n");
|
||||
}
|
||||
|
||||
/* sdram minimum cycle time */
|
||||
pdimm->tckmin_x_ps = spd_to_ps(spd->tck_min, spd->fine_tck_min);
|
||||
|
||||
/* sdram max cycle time */
|
||||
pdimm->tckmax_ps = spd_to_ps(spd->tck_max, spd->fine_tck_max);
|
||||
|
||||
/*
|
||||
* CAS latency supported
|
||||
* bit0 - CL7
|
||||
* bit4 - CL11
|
||||
* bit8 - CL15
|
||||
* bit12- CL19
|
||||
* bit16- CL23
|
||||
*/
|
||||
pdimm->caslat_x = (spd->caslat_b1 << 7) |
|
||||
(spd->caslat_b2 << 15) |
|
||||
(spd->caslat_b3 << 23);
|
||||
|
||||
BUG_ON(spd->caslat_b4 != 0);
|
||||
|
||||
/*
|
||||
* min CAS latency time
|
||||
*/
|
||||
pdimm->taa_ps = spd_to_ps(spd->taa_min, spd->fine_taa_min);
|
||||
|
||||
/*
|
||||
* min RAS to CAS delay time
|
||||
*/
|
||||
pdimm->trcd_ps = spd_to_ps(spd->trcd_min, spd->fine_trcd_min);
|
||||
|
||||
/*
|
||||
* Min Row Precharge Delay Time
|
||||
*/
|
||||
pdimm->trp_ps = spd_to_ps(spd->trp_min, spd->fine_trp_min);
|
||||
|
||||
/* min active to precharge delay time */
|
||||
pdimm->tras_ps = (((spd->tras_trc_ext & 0xf) << 8) +
|
||||
spd->tras_min_lsb) * pdimm->mtb_ps;
|
||||
|
||||
/* min active to actice/refresh delay time */
|
||||
pdimm->trc_ps = spd_to_ps((((spd->tras_trc_ext & 0xf0) << 4) +
|
||||
spd->trc_min_lsb), spd->fine_trc_min);
|
||||
/* Min Refresh Recovery Delay Time */
|
||||
pdimm->trfc1_ps = ((spd->trfc1_min_msb << 8) | (spd->trfc1_min_lsb)) *
|
||||
pdimm->mtb_ps;
|
||||
pdimm->trfc2_ps = ((spd->trfc2_min_msb << 8) | (spd->trfc2_min_lsb)) *
|
||||
pdimm->mtb_ps;
|
||||
pdimm->trfc4_ps = ((spd->trfc4_min_msb << 8) | (spd->trfc4_min_lsb)) *
|
||||
pdimm->mtb_ps;
|
||||
/* min four active window delay time */
|
||||
pdimm->tfaw_ps = (((spd->tfaw_msb & 0xf) << 8) | spd->tfaw_min) *
|
||||
pdimm->mtb_ps;
|
||||
|
||||
/* min row active to row active delay time, different bank group */
|
||||
pdimm->trrds_ps = spd_to_ps(spd->trrds_min, spd->fine_trrds_min);
|
||||
/* min row active to row active delay time, same bank group */
|
||||
pdimm->trrdl_ps = spd_to_ps(spd->trrdl_min, spd->fine_trrdl_min);
|
||||
/* min CAS to CAS Delay Time (tCCD_Lmin), same bank group */
|
||||
pdimm->tccdl_ps = spd_to_ps(spd->tccdl_min, spd->fine_tccdl_min);
|
||||
|
||||
/*
|
||||
* Average periodic refresh interval
|
||||
* tREFI = 7.8 us at normal temperature range
|
||||
*/
|
||||
pdimm->refresh_rate_ps = 7800000;
|
||||
|
||||
for (i = 0; i < 18; i++)
|
||||
pdimm->dq_mapping[i] = spd->mapping[i];
|
||||
|
||||
pdimm->dq_mapping_ors = ((spd->mapping[0] >> 6) & 0x3) == 0 ? 1 : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
541
u-boot/drivers/ddr/fsl/fsl_ddr_gen4.c
Normal file
541
u-boot/drivers/ddr/fsl/fsl_ddr_gen4.c
Normal file
@@ -0,0 +1,541 @@
|
||||
/*
|
||||
* Copyright 2014-2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <fsl_ddr_sdram.h>
|
||||
#include <asm/processor.h>
|
||||
#include <fsl_immap.h>
|
||||
#include <fsl_ddr.h>
|
||||
#include <fsl_errata.h>
|
||||
|
||||
#if defined(CONFIG_SYS_FSL_ERRATUM_A008511) | \
|
||||
defined(CONFIG_SYS_FSL_ERRATUM_A009803)
|
||||
static void set_wait_for_bits_clear(void *ptr, u32 value, u32 bits)
|
||||
{
|
||||
int timeout = 1000;
|
||||
|
||||
ddr_out32(ptr, value);
|
||||
|
||||
while (ddr_in32(ptr) & bits) {
|
||||
udelay(100);
|
||||
timeout--;
|
||||
}
|
||||
if (timeout <= 0)
|
||||
puts("Error: wait for clear timeout.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4)
|
||||
#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL
|
||||
#endif
|
||||
|
||||
/*
|
||||
* regs has the to-be-set values for DDR controller registers
|
||||
* ctrl_num is the DDR controller number
|
||||
* step: 0 goes through the initialization in one pass
|
||||
* 1 sets registers and returns before enabling controller
|
||||
* 2 resumes from step 1 and continues to initialize
|
||||
* Dividing the initialization to two steps to deassert DDR reset signal
|
||||
* to comply with JEDEC specs for RDIMMs.
|
||||
*/
|
||||
void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
|
||||
unsigned int ctrl_num, int step)
|
||||
{
|
||||
unsigned int i, bus_width;
|
||||
struct ccsr_ddr __iomem *ddr;
|
||||
u32 temp_sdram_cfg;
|
||||
u32 total_gb_size_per_controller;
|
||||
int timeout;
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A008511
|
||||
u32 temp32, mr6;
|
||||
u32 vref_seq1[3] = {0x80, 0x96, 0x16}; /* for range 1 */
|
||||
u32 vref_seq2[3] = {0xc0, 0xf0, 0x70}; /* for range 2 */
|
||||
u32 *vref_seq = vref_seq1;
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_FSL_ERRATUM_A009942) | \
|
||||
defined(CONFIG_SYS_FSL_ERRATUM_A010165)
|
||||
ulong ddr_freq;
|
||||
u32 tmp;
|
||||
#endif
|
||||
#ifdef CONFIG_FSL_DDR_BIST
|
||||
u32 mtcr, err_detect, err_sbe;
|
||||
u32 cs0_bnds, cs1_bnds, cs2_bnds, cs3_bnds, cs0_config;
|
||||
#endif
|
||||
#ifdef CONFIG_FSL_DDR_BIST
|
||||
char buffer[CONFIG_SYS_CBSIZE];
|
||||
#endif
|
||||
|
||||
switch (ctrl_num) {
|
||||
case 0:
|
||||
ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR;
|
||||
break;
|
||||
#if defined(CONFIG_SYS_FSL_DDR2_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 1)
|
||||
case 1:
|
||||
ddr = (void *)CONFIG_SYS_FSL_DDR2_ADDR;
|
||||
break;
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_FSL_DDR3_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 2)
|
||||
case 2:
|
||||
ddr = (void *)CONFIG_SYS_FSL_DDR3_ADDR;
|
||||
break;
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_FSL_DDR4_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 3)
|
||||
case 3:
|
||||
ddr = (void *)CONFIG_SYS_FSL_DDR4_ADDR;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
printf("%s unexpected ctrl_num = %u\n", __func__, ctrl_num);
|
||||
return;
|
||||
}
|
||||
|
||||
if (step == 2)
|
||||
goto step2;
|
||||
|
||||
if (regs->ddr_eor)
|
||||
ddr_out32(&ddr->eor, regs->ddr_eor);
|
||||
|
||||
ddr_out32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl);
|
||||
|
||||
for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
|
||||
if (i == 0) {
|
||||
ddr_out32(&ddr->cs0_bnds, regs->cs[i].bnds);
|
||||
ddr_out32(&ddr->cs0_config, regs->cs[i].config);
|
||||
ddr_out32(&ddr->cs0_config_2, regs->cs[i].config_2);
|
||||
|
||||
} else if (i == 1) {
|
||||
ddr_out32(&ddr->cs1_bnds, regs->cs[i].bnds);
|
||||
ddr_out32(&ddr->cs1_config, regs->cs[i].config);
|
||||
ddr_out32(&ddr->cs1_config_2, regs->cs[i].config_2);
|
||||
|
||||
} else if (i == 2) {
|
||||
ddr_out32(&ddr->cs2_bnds, regs->cs[i].bnds);
|
||||
ddr_out32(&ddr->cs2_config, regs->cs[i].config);
|
||||
ddr_out32(&ddr->cs2_config_2, regs->cs[i].config_2);
|
||||
|
||||
} else if (i == 3) {
|
||||
ddr_out32(&ddr->cs3_bnds, regs->cs[i].bnds);
|
||||
ddr_out32(&ddr->cs3_config, regs->cs[i].config);
|
||||
ddr_out32(&ddr->cs3_config_2, regs->cs[i].config_2);
|
||||
}
|
||||
}
|
||||
|
||||
ddr_out32(&ddr->timing_cfg_3, regs->timing_cfg_3);
|
||||
ddr_out32(&ddr->timing_cfg_0, regs->timing_cfg_0);
|
||||
ddr_out32(&ddr->timing_cfg_1, regs->timing_cfg_1);
|
||||
ddr_out32(&ddr->timing_cfg_2, regs->timing_cfg_2);
|
||||
ddr_out32(&ddr->timing_cfg_4, regs->timing_cfg_4);
|
||||
ddr_out32(&ddr->timing_cfg_5, regs->timing_cfg_5);
|
||||
ddr_out32(&ddr->timing_cfg_6, regs->timing_cfg_6);
|
||||
ddr_out32(&ddr->timing_cfg_7, regs->timing_cfg_7);
|
||||
ddr_out32(&ddr->timing_cfg_8, regs->timing_cfg_8);
|
||||
ddr_out32(&ddr->timing_cfg_9, regs->timing_cfg_9);
|
||||
ddr_out32(&ddr->ddr_zq_cntl, regs->ddr_zq_cntl);
|
||||
ddr_out32(&ddr->dq_map_0, regs->dq_map_0);
|
||||
ddr_out32(&ddr->dq_map_1, regs->dq_map_1);
|
||||
ddr_out32(&ddr->dq_map_2, regs->dq_map_2);
|
||||
ddr_out32(&ddr->dq_map_3, regs->dq_map_3);
|
||||
ddr_out32(&ddr->sdram_cfg_3, regs->ddr_sdram_cfg_3);
|
||||
ddr_out32(&ddr->sdram_mode, regs->ddr_sdram_mode);
|
||||
ddr_out32(&ddr->sdram_mode_2, regs->ddr_sdram_mode_2);
|
||||
ddr_out32(&ddr->sdram_mode_3, regs->ddr_sdram_mode_3);
|
||||
ddr_out32(&ddr->sdram_mode_4, regs->ddr_sdram_mode_4);
|
||||
ddr_out32(&ddr->sdram_mode_5, regs->ddr_sdram_mode_5);
|
||||
ddr_out32(&ddr->sdram_mode_6, regs->ddr_sdram_mode_6);
|
||||
ddr_out32(&ddr->sdram_mode_7, regs->ddr_sdram_mode_7);
|
||||
ddr_out32(&ddr->sdram_mode_8, regs->ddr_sdram_mode_8);
|
||||
ddr_out32(&ddr->sdram_mode_9, regs->ddr_sdram_mode_9);
|
||||
ddr_out32(&ddr->sdram_mode_10, regs->ddr_sdram_mode_10);
|
||||
ddr_out32(&ddr->sdram_mode_11, regs->ddr_sdram_mode_11);
|
||||
ddr_out32(&ddr->sdram_mode_12, regs->ddr_sdram_mode_12);
|
||||
ddr_out32(&ddr->sdram_mode_13, regs->ddr_sdram_mode_13);
|
||||
ddr_out32(&ddr->sdram_mode_14, regs->ddr_sdram_mode_14);
|
||||
ddr_out32(&ddr->sdram_mode_15, regs->ddr_sdram_mode_15);
|
||||
ddr_out32(&ddr->sdram_mode_16, regs->ddr_sdram_mode_16);
|
||||
ddr_out32(&ddr->sdram_md_cntl, regs->ddr_sdram_md_cntl);
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A009663
|
||||
ddr_out32(&ddr->sdram_interval,
|
||||
regs->ddr_sdram_interval & ~SDRAM_INTERVAL_BSTOPRE);
|
||||
#else
|
||||
ddr_out32(&ddr->sdram_interval, regs->ddr_sdram_interval);
|
||||
#endif
|
||||
ddr_out32(&ddr->sdram_data_init, regs->ddr_data_init);
|
||||
ddr_out32(&ddr->ddr_wrlvl_cntl, regs->ddr_wrlvl_cntl);
|
||||
#ifndef CONFIG_SYS_FSL_DDR_EMU
|
||||
/*
|
||||
* Skip these two registers if running on emulator
|
||||
* because emulator doesn't have skew between bytes.
|
||||
*/
|
||||
|
||||
if (regs->ddr_wrlvl_cntl_2)
|
||||
ddr_out32(&ddr->ddr_wrlvl_cntl_2, regs->ddr_wrlvl_cntl_2);
|
||||
if (regs->ddr_wrlvl_cntl_3)
|
||||
ddr_out32(&ddr->ddr_wrlvl_cntl_3, regs->ddr_wrlvl_cntl_3);
|
||||
#endif
|
||||
|
||||
ddr_out32(&ddr->ddr_sr_cntr, regs->ddr_sr_cntr);
|
||||
ddr_out32(&ddr->ddr_sdram_rcw_1, regs->ddr_sdram_rcw_1);
|
||||
ddr_out32(&ddr->ddr_sdram_rcw_2, regs->ddr_sdram_rcw_2);
|
||||
ddr_out32(&ddr->ddr_sdram_rcw_3, regs->ddr_sdram_rcw_3);
|
||||
ddr_out32(&ddr->ddr_sdram_rcw_4, regs->ddr_sdram_rcw_4);
|
||||
ddr_out32(&ddr->ddr_sdram_rcw_5, regs->ddr_sdram_rcw_5);
|
||||
ddr_out32(&ddr->ddr_sdram_rcw_6, regs->ddr_sdram_rcw_6);
|
||||
ddr_out32(&ddr->ddr_cdr1, regs->ddr_cdr1);
|
||||
#ifdef CONFIG_DEEP_SLEEP
|
||||
if (is_warm_boot()) {
|
||||
ddr_out32(&ddr->sdram_cfg_2,
|
||||
regs->ddr_sdram_cfg_2 & ~SDRAM_CFG2_D_INIT);
|
||||
ddr_out32(&ddr->init_addr, CONFIG_SYS_SDRAM_BASE);
|
||||
ddr_out32(&ddr->init_ext_addr, DDR_INIT_ADDR_EXT_UIA);
|
||||
|
||||
/* DRAM VRef will not be trained */
|
||||
ddr_out32(&ddr->ddr_cdr2,
|
||||
regs->ddr_cdr2 & ~DDR_CDR2_VREF_TRAIN_EN);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
ddr_out32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2);
|
||||
ddr_out32(&ddr->init_addr, regs->ddr_init_addr);
|
||||
ddr_out32(&ddr->init_ext_addr, regs->ddr_init_ext_addr);
|
||||
ddr_out32(&ddr->ddr_cdr2, regs->ddr_cdr2);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A009803
|
||||
/* part 1 of 2 */
|
||||
if (regs->ddr_sdram_cfg_2 & SDRAM_CFG2_AP_EN) {
|
||||
if (regs->ddr_sdram_cfg & SDRAM_CFG_RD_EN) { /* for RDIMM */
|
||||
ddr_out32(&ddr->ddr_sdram_rcw_2,
|
||||
regs->ddr_sdram_rcw_2 & ~0x0f000000);
|
||||
}
|
||||
ddr_out32(&ddr->err_disable, regs->err_disable |
|
||||
DDR_ERR_DISABLE_APED);
|
||||
}
|
||||
#else
|
||||
ddr_out32(&ddr->err_disable, regs->err_disable);
|
||||
#endif
|
||||
ddr_out32(&ddr->err_int_en, regs->err_int_en);
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (regs->debug[i]) {
|
||||
debug("Write to debug_%d as %08x\n",
|
||||
i+1, regs->debug[i]);
|
||||
ddr_out32(&ddr->debug[i], regs->debug[i]);
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A008378
|
||||
/* Erratum applies when accumulated ECC is used, or DBI is enabled */
|
||||
#define IS_ACC_ECC_EN(v) ((v) & 0x4)
|
||||
#define IS_DBI(v) ((((v) >> 12) & 0x3) == 0x2)
|
||||
if (has_erratum_a008378()) {
|
||||
if (IS_ACC_ECC_EN(regs->ddr_sdram_cfg) ||
|
||||
IS_DBI(regs->ddr_sdram_cfg_3))
|
||||
ddr_setbits32(&ddr->debug[28], 0x9 << 20);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A008511
|
||||
/* Part 1 of 2 */
|
||||
/* This erraum only applies to verion 5.2.0 */
|
||||
if (fsl_ddr_get_version(ctrl_num) == 0x50200) {
|
||||
/* Disable DRAM VRef training */
|
||||
ddr_out32(&ddr->ddr_cdr2,
|
||||
regs->ddr_cdr2 & ~DDR_CDR2_VREF_TRAIN_EN);
|
||||
/* disable transmit bit deskew */
|
||||
temp32 = ddr_in32(&ddr->debug[28]);
|
||||
temp32 |= DDR_TX_BD_DIS;
|
||||
ddr_out32(&ddr->debug[28], temp32);
|
||||
/* Disable D_INIT */
|
||||
ddr_out32(&ddr->sdram_cfg_2,
|
||||
regs->ddr_sdram_cfg_2 & ~SDRAM_CFG2_D_INIT);
|
||||
ddr_out32(&ddr->debug[25], 0x9000);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A009801
|
||||
temp32 = ddr_in32(&ddr->debug[25]);
|
||||
temp32 &= ~DDR_CAS_TO_PRE_SUB_MASK;
|
||||
temp32 |= 9 << DDR_CAS_TO_PRE_SUB_SHIFT;
|
||||
ddr_out32(&ddr->debug[25], temp32);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A009942
|
||||
ddr_freq = get_ddr_freq(ctrl_num) / 1000000;
|
||||
tmp = ddr_in32(&ddr->debug[28]);
|
||||
if (ddr_freq <= 1333)
|
||||
ddr_out32(&ddr->debug[28], tmp | 0x0080006a);
|
||||
else if (ddr_freq <= 1600)
|
||||
ddr_out32(&ddr->debug[28], tmp | 0x0070006f);
|
||||
else if (ddr_freq <= 1867)
|
||||
ddr_out32(&ddr->debug[28], tmp | 0x00700076);
|
||||
else if (ddr_freq <= 2133)
|
||||
ddr_out32(&ddr->debug[28], tmp | 0x0060007b);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A010165
|
||||
ddr_freq = get_ddr_freq(ctrl_num) / 1000000;
|
||||
if ((ddr_freq > 1900) && (ddr_freq < 2300)) {
|
||||
tmp = ddr_in32(&ddr->debug[28]);
|
||||
ddr_out32(&ddr->debug[28], tmp | 0x000a0000);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* For RDIMMs, JEDEC spec requires clocks to be stable before reset is
|
||||
* deasserted. Clocks start when any chip select is enabled and clock
|
||||
* control register is set. Because all DDR components are connected to
|
||||
* one reset signal, this needs to be done in two steps. Step 1 is to
|
||||
* get the clocks started. Step 2 resumes after reset signal is
|
||||
* deasserted.
|
||||
*/
|
||||
if (step == 1) {
|
||||
udelay(200);
|
||||
return;
|
||||
}
|
||||
|
||||
step2:
|
||||
/* Set, but do not enable the memory */
|
||||
temp_sdram_cfg = regs->ddr_sdram_cfg;
|
||||
temp_sdram_cfg &= ~(SDRAM_CFG_MEM_EN);
|
||||
ddr_out32(&ddr->sdram_cfg, temp_sdram_cfg);
|
||||
|
||||
/*
|
||||
* 500 painful micro-seconds must elapse between
|
||||
* the DDR clock setup and the DDR config enable.
|
||||
* DDR2 need 200 us, and DDR3 need 500 us from spec,
|
||||
* we choose the max, that is 500 us for all of case.
|
||||
*/
|
||||
udelay(500);
|
||||
mb();
|
||||
isb();
|
||||
|
||||
#ifdef CONFIG_DEEP_SLEEP
|
||||
if (is_warm_boot()) {
|
||||
/* enter self-refresh */
|
||||
temp_sdram_cfg = ddr_in32(&ddr->sdram_cfg_2);
|
||||
temp_sdram_cfg |= SDRAM_CFG2_FRC_SR;
|
||||
ddr_out32(&ddr->sdram_cfg_2, temp_sdram_cfg);
|
||||
/* do board specific memory setup */
|
||||
board_mem_sleep_setup();
|
||||
|
||||
temp_sdram_cfg = (ddr_in32(&ddr->sdram_cfg) | SDRAM_CFG_BI);
|
||||
} else
|
||||
#endif
|
||||
temp_sdram_cfg = ddr_in32(&ddr->sdram_cfg) & ~SDRAM_CFG_BI;
|
||||
/* Let the controller go */
|
||||
ddr_out32(&ddr->sdram_cfg, temp_sdram_cfg | SDRAM_CFG_MEM_EN);
|
||||
mb();
|
||||
isb();
|
||||
|
||||
#if defined(CONFIG_SYS_FSL_ERRATUM_A008511) || \
|
||||
defined(CONFIG_SYS_FSL_ERRATUM_A009803)
|
||||
/* Part 2 of 2 */
|
||||
/* This erraum only applies to verion 5.2.0 */
|
||||
if (fsl_ddr_get_version(ctrl_num) == 0x50200) {
|
||||
/* Wait for idle */
|
||||
timeout = 40;
|
||||
while (!(ddr_in32(&ddr->debug[1]) & 0x2) &&
|
||||
(timeout > 0)) {
|
||||
udelay(1000);
|
||||
timeout--;
|
||||
}
|
||||
if (timeout <= 0) {
|
||||
printf("Controler %d timeout, debug_2 = %x\n",
|
||||
ctrl_num, ddr_in32(&ddr->debug[1]));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A008511
|
||||
/* The vref setting sequence is different for range 2 */
|
||||
if (regs->ddr_cdr2 & DDR_CDR2_VREF_RANGE_2)
|
||||
vref_seq = vref_seq2;
|
||||
|
||||
/* Set VREF */
|
||||
for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
|
||||
if (!(regs->cs[i].config & SDRAM_CS_CONFIG_EN))
|
||||
continue;
|
||||
|
||||
mr6 = (regs->ddr_sdram_mode_10 >> 16) |
|
||||
MD_CNTL_MD_EN |
|
||||
MD_CNTL_CS_SEL(i) |
|
||||
MD_CNTL_MD_SEL(6) |
|
||||
0x00200000;
|
||||
temp32 = mr6 | vref_seq[0];
|
||||
set_wait_for_bits_clear(&ddr->sdram_md_cntl,
|
||||
temp32, MD_CNTL_MD_EN);
|
||||
udelay(1);
|
||||
debug("MR6 = 0x%08x\n", temp32);
|
||||
temp32 = mr6 | vref_seq[1];
|
||||
set_wait_for_bits_clear(&ddr->sdram_md_cntl,
|
||||
temp32, MD_CNTL_MD_EN);
|
||||
udelay(1);
|
||||
debug("MR6 = 0x%08x\n", temp32);
|
||||
temp32 = mr6 | vref_seq[2];
|
||||
set_wait_for_bits_clear(&ddr->sdram_md_cntl,
|
||||
temp32, MD_CNTL_MD_EN);
|
||||
udelay(1);
|
||||
debug("MR6 = 0x%08x\n", temp32);
|
||||
}
|
||||
ddr_out32(&ddr->sdram_md_cntl, 0);
|
||||
temp32 = ddr_in32(&ddr->debug[28]);
|
||||
temp32 &= ~DDR_TX_BD_DIS; /* Enable deskew */
|
||||
ddr_out32(&ddr->debug[28], temp32);
|
||||
ddr_out32(&ddr->debug[1], 0x400); /* restart deskew */
|
||||
/* wait for idle */
|
||||
timeout = 40;
|
||||
while (!(ddr_in32(&ddr->debug[1]) & 0x2) &&
|
||||
(timeout > 0)) {
|
||||
udelay(1000);
|
||||
timeout--;
|
||||
}
|
||||
if (timeout <= 0) {
|
||||
printf("Controler %d timeout, debug_2 = %x\n",
|
||||
ctrl_num, ddr_in32(&ddr->debug[1]));
|
||||
}
|
||||
/* Restore D_INIT */
|
||||
ddr_out32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2);
|
||||
#endif /* CONFIG_SYS_FSL_ERRATUM_A008511 */
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A009803
|
||||
if (regs->ddr_sdram_cfg_2 & SDRAM_CFG2_AP_EN) {
|
||||
/* if it's RDIMM */
|
||||
if (regs->ddr_sdram_cfg & SDRAM_CFG_RD_EN) {
|
||||
for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
|
||||
if (!(regs->cs[i].config & SDRAM_CS_CONFIG_EN))
|
||||
continue;
|
||||
set_wait_for_bits_clear(&ddr->sdram_md_cntl,
|
||||
MD_CNTL_MD_EN |
|
||||
MD_CNTL_CS_SEL(i) |
|
||||
0x070000ed,
|
||||
MD_CNTL_MD_EN);
|
||||
udelay(1);
|
||||
}
|
||||
}
|
||||
|
||||
ddr_out32(&ddr->err_disable,
|
||||
regs->err_disable & ~DDR_ERR_DISABLE_APED);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
total_gb_size_per_controller = 0;
|
||||
for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
|
||||
if (!(regs->cs[i].config & 0x80000000))
|
||||
continue;
|
||||
total_gb_size_per_controller += 1 << (
|
||||
((regs->cs[i].config >> 14) & 0x3) + 2 +
|
||||
((regs->cs[i].config >> 8) & 0x7) + 12 +
|
||||
((regs->cs[i].config >> 4) & 0x3) + 0 +
|
||||
((regs->cs[i].config >> 0) & 0x7) + 8 +
|
||||
3 - ((regs->ddr_sdram_cfg >> 19) & 0x3) -
|
||||
26); /* minus 26 (count of 64M) */
|
||||
}
|
||||
if (fsl_ddr_get_intl3r() & 0x80000000) /* 3-way interleaving */
|
||||
total_gb_size_per_controller *= 3;
|
||||
else if (regs->cs[0].config & 0x20000000) /* 2-way interleaving */
|
||||
total_gb_size_per_controller <<= 1;
|
||||
/*
|
||||
* total memory / bus width = transactions needed
|
||||
* transactions needed / data rate = seconds
|
||||
* to add plenty of buffer, double the time
|
||||
* For example, 2GB on 666MT/s 64-bit bus takes about 402ms
|
||||
* Let's wait for 800ms
|
||||
*/
|
||||
bus_width = 3 - ((ddr_in32(&ddr->sdram_cfg) & SDRAM_CFG_DBW_MASK)
|
||||
>> SDRAM_CFG_DBW_SHIFT);
|
||||
timeout = ((total_gb_size_per_controller << (6 - bus_width)) * 100 /
|
||||
(get_ddr_freq(ctrl_num) >> 20)) << 2;
|
||||
total_gb_size_per_controller >>= 4; /* shift down to gb size */
|
||||
debug("total %d GB\n", total_gb_size_per_controller);
|
||||
debug("Need to wait up to %d * 10ms\n", timeout);
|
||||
|
||||
/* Poll DDR_SDRAM_CFG_2[D_INIT] bit until auto-data init is done. */
|
||||
while ((ddr_in32(&ddr->sdram_cfg_2) & SDRAM_CFG2_D_INIT) &&
|
||||
(timeout >= 0)) {
|
||||
udelay(10000); /* throttle polling rate */
|
||||
timeout--;
|
||||
}
|
||||
|
||||
if (timeout <= 0)
|
||||
printf("Waiting for D_INIT timeout. Memory may not work.\n");
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A009663
|
||||
ddr_out32(&ddr->sdram_interval, regs->ddr_sdram_interval);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEEP_SLEEP
|
||||
if (is_warm_boot()) {
|
||||
/* exit self-refresh */
|
||||
temp_sdram_cfg = ddr_in32(&ddr->sdram_cfg_2);
|
||||
temp_sdram_cfg &= ~SDRAM_CFG2_FRC_SR;
|
||||
ddr_out32(&ddr->sdram_cfg_2, temp_sdram_cfg);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FSL_DDR_BIST
|
||||
#define BIST_PATTERN1 0xFFFFFFFF
|
||||
#define BIST_PATTERN2 0x0
|
||||
#define BIST_CR 0x80010000
|
||||
#define BIST_CR_EN 0x80000000
|
||||
#define BIST_CR_STAT 0x00000001
|
||||
#define CTLR_INTLV_MASK 0x20000000
|
||||
/* Perform build-in test on memory. Three-way interleaving is not yet
|
||||
* supported by this code. */
|
||||
if (getenv_f("ddr_bist", buffer, CONFIG_SYS_CBSIZE) >= 0) {
|
||||
puts("Running BIST test. This will take a while...");
|
||||
cs0_config = ddr_in32(&ddr->cs0_config);
|
||||
cs0_bnds = ddr_in32(&ddr->cs0_bnds);
|
||||
cs1_bnds = ddr_in32(&ddr->cs1_bnds);
|
||||
cs2_bnds = ddr_in32(&ddr->cs2_bnds);
|
||||
cs3_bnds = ddr_in32(&ddr->cs3_bnds);
|
||||
if (cs0_config & CTLR_INTLV_MASK) {
|
||||
/* set bnds to non-interleaving */
|
||||
ddr_out32(&ddr->cs0_bnds, (cs0_bnds & 0xfffefffe) >> 1);
|
||||
ddr_out32(&ddr->cs1_bnds, (cs1_bnds & 0xfffefffe) >> 1);
|
||||
ddr_out32(&ddr->cs2_bnds, (cs2_bnds & 0xfffefffe) >> 1);
|
||||
ddr_out32(&ddr->cs3_bnds, (cs3_bnds & 0xfffefffe) >> 1);
|
||||
}
|
||||
ddr_out32(&ddr->mtp1, BIST_PATTERN1);
|
||||
ddr_out32(&ddr->mtp2, BIST_PATTERN1);
|
||||
ddr_out32(&ddr->mtp3, BIST_PATTERN2);
|
||||
ddr_out32(&ddr->mtp4, BIST_PATTERN2);
|
||||
ddr_out32(&ddr->mtp5, BIST_PATTERN1);
|
||||
ddr_out32(&ddr->mtp6, BIST_PATTERN1);
|
||||
ddr_out32(&ddr->mtp7, BIST_PATTERN2);
|
||||
ddr_out32(&ddr->mtp8, BIST_PATTERN2);
|
||||
ddr_out32(&ddr->mtp9, BIST_PATTERN1);
|
||||
ddr_out32(&ddr->mtp10, BIST_PATTERN2);
|
||||
mtcr = BIST_CR;
|
||||
ddr_out32(&ddr->mtcr, mtcr);
|
||||
timeout = 100;
|
||||
while (timeout > 0 && (mtcr & BIST_CR_EN)) {
|
||||
mdelay(1000);
|
||||
timeout--;
|
||||
mtcr = ddr_in32(&ddr->mtcr);
|
||||
}
|
||||
if (timeout <= 0)
|
||||
puts("Timeout\n");
|
||||
else
|
||||
puts("Done\n");
|
||||
err_detect = ddr_in32(&ddr->err_detect);
|
||||
err_sbe = ddr_in32(&ddr->err_sbe);
|
||||
if (mtcr & BIST_CR_STAT) {
|
||||
printf("BIST test failed on controller %d.\n",
|
||||
ctrl_num);
|
||||
}
|
||||
if (err_detect || (err_sbe & 0xffff)) {
|
||||
printf("ECC error detected on controller %d.\n",
|
||||
ctrl_num);
|
||||
}
|
||||
|
||||
if (cs0_config & CTLR_INTLV_MASK) {
|
||||
/* restore bnds registers */
|
||||
ddr_out32(&ddr->cs0_bnds, cs0_bnds);
|
||||
ddr_out32(&ddr->cs1_bnds, cs1_bnds);
|
||||
ddr_out32(&ddr->cs2_bnds, cs2_bnds);
|
||||
ddr_out32(&ddr->cs3_bnds, cs3_bnds);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
2292
u-boot/drivers/ddr/fsl/interactive.c
Normal file
2292
u-boot/drivers/ddr/fsl/interactive.c
Normal file
File diff suppressed because it is too large
Load Diff
579
u-boot/drivers/ddr/fsl/lc_common_dimm_params.c
Normal file
579
u-boot/drivers/ddr/fsl/lc_common_dimm_params.c
Normal file
@@ -0,0 +1,579 @@
|
||||
/*
|
||||
* Copyright 2008-2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <fsl_ddr_sdram.h>
|
||||
|
||||
#include <fsl_ddr.h>
|
||||
|
||||
#if defined(CONFIG_SYS_FSL_DDR3) || defined(CONFIG_SYS_FSL_DDR4)
|
||||
static unsigned int
|
||||
compute_cas_latency(const unsigned int ctrl_num,
|
||||
const dimm_params_t *dimm_params,
|
||||
common_timing_params_t *outpdimm,
|
||||
unsigned int number_of_dimms)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int common_caslat;
|
||||
unsigned int caslat_actual;
|
||||
unsigned int retry = 16;
|
||||
unsigned int tmp = ~0;
|
||||
const unsigned int mclk_ps = get_memory_clk_period_ps(ctrl_num);
|
||||
#ifdef CONFIG_SYS_FSL_DDR3
|
||||
const unsigned int taamax = 20000;
|
||||
#else
|
||||
const unsigned int taamax = 18000;
|
||||
#endif
|
||||
|
||||
/* compute the common CAS latency supported between slots */
|
||||
for (i = 0; i < number_of_dimms; i++) {
|
||||
if (dimm_params[i].n_ranks)
|
||||
tmp &= dimm_params[i].caslat_x;
|
||||
}
|
||||
common_caslat = tmp;
|
||||
|
||||
/* validate if the memory clk is in the range of dimms */
|
||||
if (mclk_ps < outpdimm->tckmin_x_ps) {
|
||||
printf("DDR clock (MCLK cycle %u ps) is faster than "
|
||||
"the slowest DIMM(s) (tCKmin %u ps) can support.\n",
|
||||
mclk_ps, outpdimm->tckmin_x_ps);
|
||||
}
|
||||
#ifdef CONFIG_SYS_FSL_DDR4
|
||||
if (mclk_ps > outpdimm->tckmax_ps) {
|
||||
printf("DDR clock (MCLK cycle %u ps) is slower than DIMM(s) (tCKmax %u ps) can support.\n",
|
||||
mclk_ps, outpdimm->tckmax_ps);
|
||||
}
|
||||
#endif
|
||||
/* determine the acutal cas latency */
|
||||
caslat_actual = (outpdimm->taamin_ps + mclk_ps - 1) / mclk_ps;
|
||||
/* check if the dimms support the CAS latency */
|
||||
while (!(common_caslat & (1 << caslat_actual)) && retry > 0) {
|
||||
caslat_actual++;
|
||||
retry--;
|
||||
}
|
||||
/* once the caculation of caslat_actual is completed
|
||||
* we must verify that this CAS latency value does not
|
||||
* exceed tAAmax, which is 20 ns for all DDR3 speed grades,
|
||||
* 18ns for all DDR4 speed grades.
|
||||
*/
|
||||
if (caslat_actual * mclk_ps > taamax) {
|
||||
printf("The chosen cas latency %d is too large\n",
|
||||
caslat_actual);
|
||||
}
|
||||
outpdimm->lowest_common_spd_caslat = caslat_actual;
|
||||
debug("lowest_common_spd_caslat is 0x%x\n", caslat_actual);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else /* for DDR1 and DDR2 */
|
||||
static unsigned int
|
||||
compute_cas_latency(const unsigned int ctrl_num,
|
||||
const dimm_params_t *dimm_params,
|
||||
common_timing_params_t *outpdimm,
|
||||
unsigned int number_of_dimms)
|
||||
{
|
||||
int i;
|
||||
const unsigned int mclk_ps = get_memory_clk_period_ps(ctrl_num);
|
||||
unsigned int lowest_good_caslat;
|
||||
unsigned int not_ok;
|
||||
unsigned int temp1, temp2;
|
||||
|
||||
debug("using mclk_ps = %u\n", mclk_ps);
|
||||
if (mclk_ps > outpdimm->tckmax_ps) {
|
||||
printf("Warning: DDR clock (%u ps) is slower than DIMM(s) (tCKmax %u ps)\n",
|
||||
mclk_ps, outpdimm->tckmax_ps);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute a CAS latency suitable for all DIMMs
|
||||
*
|
||||
* Strategy for SPD-defined latencies: compute only
|
||||
* CAS latency defined by all DIMMs.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Step 1: find CAS latency common to all DIMMs using bitwise
|
||||
* operation.
|
||||
*/
|
||||
temp1 = 0xFF;
|
||||
for (i = 0; i < number_of_dimms; i++) {
|
||||
if (dimm_params[i].n_ranks) {
|
||||
temp2 = 0;
|
||||
temp2 |= 1 << dimm_params[i].caslat_x;
|
||||
temp2 |= 1 << dimm_params[i].caslat_x_minus_1;
|
||||
temp2 |= 1 << dimm_params[i].caslat_x_minus_2;
|
||||
/*
|
||||
* If there was no entry for X-2 (X-1) in
|
||||
* the SPD, then caslat_x_minus_2
|
||||
* (caslat_x_minus_1) contains either 255 or
|
||||
* 0xFFFFFFFF because that's what the glorious
|
||||
* __ilog2 function returns for an input of 0.
|
||||
* On 32-bit PowerPC, left shift counts with bit
|
||||
* 26 set (that the value of 255 or 0xFFFFFFFF
|
||||
* will have), cause the destination register to
|
||||
* be 0. That is why this works.
|
||||
*/
|
||||
temp1 &= temp2;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Step 2: check each common CAS latency against tCK of each
|
||||
* DIMM's SPD.
|
||||
*/
|
||||
lowest_good_caslat = 0;
|
||||
temp2 = 0;
|
||||
while (temp1) {
|
||||
not_ok = 0;
|
||||
temp2 = __ilog2(temp1);
|
||||
debug("checking common caslat = %u\n", temp2);
|
||||
|
||||
/* Check if this CAS latency will work on all DIMMs at tCK. */
|
||||
for (i = 0; i < number_of_dimms; i++) {
|
||||
if (!dimm_params[i].n_ranks)
|
||||
continue;
|
||||
|
||||
if (dimm_params[i].caslat_x == temp2) {
|
||||
if (mclk_ps >= dimm_params[i].tckmin_x_ps) {
|
||||
debug("CL = %u ok on DIMM %u at tCK=%u ps with tCKmin_X_ps of %u\n",
|
||||
temp2, i, mclk_ps,
|
||||
dimm_params[i].tckmin_x_ps);
|
||||
continue;
|
||||
} else {
|
||||
not_ok++;
|
||||
}
|
||||
}
|
||||
|
||||
if (dimm_params[i].caslat_x_minus_1 == temp2) {
|
||||
unsigned int tckmin_x_minus_1_ps
|
||||
= dimm_params[i].tckmin_x_minus_1_ps;
|
||||
if (mclk_ps >= tckmin_x_minus_1_ps) {
|
||||
debug("CL = %u ok on DIMM %u at tCK=%u ps with tckmin_x_minus_1_ps of %u\n",
|
||||
temp2, i, mclk_ps,
|
||||
tckmin_x_minus_1_ps);
|
||||
continue;
|
||||
} else {
|
||||
not_ok++;
|
||||
}
|
||||
}
|
||||
|
||||
if (dimm_params[i].caslat_x_minus_2 == temp2) {
|
||||
unsigned int tckmin_x_minus_2_ps
|
||||
= dimm_params[i].tckmin_x_minus_2_ps;
|
||||
if (mclk_ps >= tckmin_x_minus_2_ps) {
|
||||
debug("CL = %u ok on DIMM %u at tCK=%u ps with tckmin_x_minus_2_ps of %u\n",
|
||||
temp2, i, mclk_ps,
|
||||
tckmin_x_minus_2_ps);
|
||||
continue;
|
||||
} else {
|
||||
not_ok++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!not_ok)
|
||||
lowest_good_caslat = temp2;
|
||||
|
||||
temp1 &= ~(1 << temp2);
|
||||
}
|
||||
|
||||
debug("lowest common SPD-defined CAS latency = %u\n",
|
||||
lowest_good_caslat);
|
||||
outpdimm->lowest_common_spd_caslat = lowest_good_caslat;
|
||||
|
||||
|
||||
/*
|
||||
* Compute a common 'de-rated' CAS latency.
|
||||
*
|
||||
* The strategy here is to find the *highest* dereated cas latency
|
||||
* with the assumption that all of the DIMMs will support a dereated
|
||||
* CAS latency higher than or equal to their lowest dereated value.
|
||||
*/
|
||||
temp1 = 0;
|
||||
for (i = 0; i < number_of_dimms; i++)
|
||||
temp1 = max(temp1, dimm_params[i].caslat_lowest_derated);
|
||||
|
||||
outpdimm->highest_common_derated_caslat = temp1;
|
||||
debug("highest common dereated CAS latency = %u\n", temp1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* compute_lowest_common_dimm_parameters()
|
||||
*
|
||||
* Determine the worst-case DIMM timing parameters from the set of DIMMs
|
||||
* whose parameters have been computed into the array pointed to
|
||||
* by dimm_params.
|
||||
*/
|
||||
unsigned int
|
||||
compute_lowest_common_dimm_parameters(const unsigned int ctrl_num,
|
||||
const dimm_params_t *dimm_params,
|
||||
common_timing_params_t *outpdimm,
|
||||
const unsigned int number_of_dimms)
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
unsigned int tckmin_x_ps = 0;
|
||||
unsigned int tckmax_ps = 0xFFFFFFFF;
|
||||
unsigned int trcd_ps = 0;
|
||||
unsigned int trp_ps = 0;
|
||||
unsigned int tras_ps = 0;
|
||||
#if defined(CONFIG_SYS_FSL_DDR3) || defined(CONFIG_SYS_FSL_DDR4)
|
||||
unsigned int taamin_ps = 0;
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_DDR4
|
||||
unsigned int twr_ps = 15000;
|
||||
unsigned int trfc1_ps = 0;
|
||||
unsigned int trfc2_ps = 0;
|
||||
unsigned int trfc4_ps = 0;
|
||||
unsigned int trrds_ps = 0;
|
||||
unsigned int trrdl_ps = 0;
|
||||
unsigned int tccdl_ps = 0;
|
||||
#else
|
||||
unsigned int twr_ps = 0;
|
||||
unsigned int twtr_ps = 0;
|
||||
unsigned int trfc_ps = 0;
|
||||
unsigned int trrd_ps = 0;
|
||||
unsigned int trtp_ps = 0;
|
||||
#endif
|
||||
unsigned int trc_ps = 0;
|
||||
unsigned int refresh_rate_ps = 0;
|
||||
unsigned int extended_op_srt = 1;
|
||||
#if defined(CONFIG_SYS_FSL_DDR1) || defined(CONFIG_SYS_FSL_DDR2)
|
||||
unsigned int tis_ps = 0;
|
||||
unsigned int tih_ps = 0;
|
||||
unsigned int tds_ps = 0;
|
||||
unsigned int tdh_ps = 0;
|
||||
unsigned int tdqsq_max_ps = 0;
|
||||
unsigned int tqhs_ps = 0;
|
||||
#endif
|
||||
unsigned int temp1, temp2;
|
||||
unsigned int additive_latency = 0;
|
||||
|
||||
temp1 = 0;
|
||||
for (i = 0; i < number_of_dimms; i++) {
|
||||
/*
|
||||
* If there are no ranks on this DIMM,
|
||||
* it probably doesn't exist, so skip it.
|
||||
*/
|
||||
if (dimm_params[i].n_ranks == 0) {
|
||||
temp1++;
|
||||
continue;
|
||||
}
|
||||
if (dimm_params[i].n_ranks == 4 && i != 0) {
|
||||
printf("Found Quad-rank DIMM in wrong bank, ignored."
|
||||
" Software may not run as expected.\n");
|
||||
temp1++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* check if quad-rank DIMM is plugged if
|
||||
* CONFIG_CHIP_SELECT_QUAD_CAPABLE is not defined
|
||||
* Only the board with proper design is capable
|
||||
*/
|
||||
#ifndef CONFIG_FSL_DDR_FIRST_SLOT_QUAD_CAPABLE
|
||||
if (dimm_params[i].n_ranks == 4 && \
|
||||
CONFIG_CHIP_SELECTS_PER_CTRL/CONFIG_DIMM_SLOTS_PER_CTLR < 4) {
|
||||
printf("Found Quad-rank DIMM, not able to support.");
|
||||
temp1++;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Find minimum tckmax_ps to find fastest slow speed,
|
||||
* i.e., this is the slowest the whole system can go.
|
||||
*/
|
||||
tckmax_ps = min(tckmax_ps,
|
||||
(unsigned int)dimm_params[i].tckmax_ps);
|
||||
#if defined(CONFIG_SYS_FSL_DDR3) || defined(CONFIG_SYS_FSL_DDR4)
|
||||
taamin_ps = max(taamin_ps,
|
||||
(unsigned int)dimm_params[i].taa_ps);
|
||||
#endif
|
||||
tckmin_x_ps = max(tckmin_x_ps,
|
||||
(unsigned int)dimm_params[i].tckmin_x_ps);
|
||||
trcd_ps = max(trcd_ps, (unsigned int)dimm_params[i].trcd_ps);
|
||||
trp_ps = max(trp_ps, (unsigned int)dimm_params[i].trp_ps);
|
||||
tras_ps = max(tras_ps, (unsigned int)dimm_params[i].tras_ps);
|
||||
#ifdef CONFIG_SYS_FSL_DDR4
|
||||
trfc1_ps = max(trfc1_ps,
|
||||
(unsigned int)dimm_params[i].trfc1_ps);
|
||||
trfc2_ps = max(trfc2_ps,
|
||||
(unsigned int)dimm_params[i].trfc2_ps);
|
||||
trfc4_ps = max(trfc4_ps,
|
||||
(unsigned int)dimm_params[i].trfc4_ps);
|
||||
trrds_ps = max(trrds_ps,
|
||||
(unsigned int)dimm_params[i].trrds_ps);
|
||||
trrdl_ps = max(trrdl_ps,
|
||||
(unsigned int)dimm_params[i].trrdl_ps);
|
||||
tccdl_ps = max(tccdl_ps,
|
||||
(unsigned int)dimm_params[i].tccdl_ps);
|
||||
#else
|
||||
twr_ps = max(twr_ps, (unsigned int)dimm_params[i].twr_ps);
|
||||
twtr_ps = max(twtr_ps, (unsigned int)dimm_params[i].twtr_ps);
|
||||
trfc_ps = max(trfc_ps, (unsigned int)dimm_params[i].trfc_ps);
|
||||
trrd_ps = max(trrd_ps, (unsigned int)dimm_params[i].trrd_ps);
|
||||
trtp_ps = max(trtp_ps, (unsigned int)dimm_params[i].trtp_ps);
|
||||
#endif
|
||||
trc_ps = max(trc_ps, (unsigned int)dimm_params[i].trc_ps);
|
||||
#if defined(CONFIG_SYS_FSL_DDR1) || defined(CONFIG_SYS_FSL_DDR2)
|
||||
tis_ps = max(tis_ps, (unsigned int)dimm_params[i].tis_ps);
|
||||
tih_ps = max(tih_ps, (unsigned int)dimm_params[i].tih_ps);
|
||||
tds_ps = max(tds_ps, (unsigned int)dimm_params[i].tds_ps);
|
||||
tdh_ps = max(tdh_ps, (unsigned int)dimm_params[i].tdh_ps);
|
||||
tqhs_ps = max(tqhs_ps, (unsigned int)dimm_params[i].tqhs_ps);
|
||||
/*
|
||||
* Find maximum tdqsq_max_ps to find slowest.
|
||||
*
|
||||
* FIXME: is finding the slowest value the correct
|
||||
* strategy for this parameter?
|
||||
*/
|
||||
tdqsq_max_ps = max(tdqsq_max_ps,
|
||||
(unsigned int)dimm_params[i].tdqsq_max_ps);
|
||||
#endif
|
||||
refresh_rate_ps = max(refresh_rate_ps,
|
||||
(unsigned int)dimm_params[i].refresh_rate_ps);
|
||||
/* extended_op_srt is either 0 or 1, 0 having priority */
|
||||
extended_op_srt = min(extended_op_srt,
|
||||
(unsigned int)dimm_params[i].extended_op_srt);
|
||||
}
|
||||
|
||||
outpdimm->ndimms_present = number_of_dimms - temp1;
|
||||
|
||||
if (temp1 == number_of_dimms) {
|
||||
debug("no dimms this memory controller\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
outpdimm->tckmin_x_ps = tckmin_x_ps;
|
||||
outpdimm->tckmax_ps = tckmax_ps;
|
||||
#if defined(CONFIG_SYS_FSL_DDR3) || defined(CONFIG_SYS_FSL_DDR4)
|
||||
outpdimm->taamin_ps = taamin_ps;
|
||||
#endif
|
||||
outpdimm->trcd_ps = trcd_ps;
|
||||
outpdimm->trp_ps = trp_ps;
|
||||
outpdimm->tras_ps = tras_ps;
|
||||
#ifdef CONFIG_SYS_FSL_DDR4
|
||||
outpdimm->trfc1_ps = trfc1_ps;
|
||||
outpdimm->trfc2_ps = trfc2_ps;
|
||||
outpdimm->trfc4_ps = trfc4_ps;
|
||||
outpdimm->trrds_ps = trrds_ps;
|
||||
outpdimm->trrdl_ps = trrdl_ps;
|
||||
outpdimm->tccdl_ps = tccdl_ps;
|
||||
#else
|
||||
outpdimm->twtr_ps = twtr_ps;
|
||||
outpdimm->trfc_ps = trfc_ps;
|
||||
outpdimm->trrd_ps = trrd_ps;
|
||||
outpdimm->trtp_ps = trtp_ps;
|
||||
#endif
|
||||
outpdimm->twr_ps = twr_ps;
|
||||
outpdimm->trc_ps = trc_ps;
|
||||
outpdimm->refresh_rate_ps = refresh_rate_ps;
|
||||
outpdimm->extended_op_srt = extended_op_srt;
|
||||
#if defined(CONFIG_SYS_FSL_DDR1) || defined(CONFIG_SYS_FSL_DDR2)
|
||||
outpdimm->tis_ps = tis_ps;
|
||||
outpdimm->tih_ps = tih_ps;
|
||||
outpdimm->tds_ps = tds_ps;
|
||||
outpdimm->tdh_ps = tdh_ps;
|
||||
outpdimm->tdqsq_max_ps = tdqsq_max_ps;
|
||||
outpdimm->tqhs_ps = tqhs_ps;
|
||||
#endif
|
||||
|
||||
/* Determine common burst length for all DIMMs. */
|
||||
temp1 = 0xff;
|
||||
for (i = 0; i < number_of_dimms; i++) {
|
||||
if (dimm_params[i].n_ranks) {
|
||||
temp1 &= dimm_params[i].burst_lengths_bitmask;
|
||||
}
|
||||
}
|
||||
outpdimm->all_dimms_burst_lengths_bitmask = temp1;
|
||||
|
||||
/* Determine if all DIMMs registered buffered. */
|
||||
temp1 = temp2 = 0;
|
||||
for (i = 0; i < number_of_dimms; i++) {
|
||||
if (dimm_params[i].n_ranks) {
|
||||
if (dimm_params[i].registered_dimm) {
|
||||
temp1 = 1;
|
||||
#ifndef CONFIG_SPL_BUILD
|
||||
printf("Detected RDIMM %s\n",
|
||||
dimm_params[i].mpart);
|
||||
#endif
|
||||
} else {
|
||||
temp2 = 1;
|
||||
#ifndef CONFIG_SPL_BUILD
|
||||
printf("Detected UDIMM %s\n",
|
||||
dimm_params[i].mpart);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outpdimm->all_dimms_registered = 0;
|
||||
outpdimm->all_dimms_unbuffered = 0;
|
||||
if (temp1 && !temp2) {
|
||||
outpdimm->all_dimms_registered = 1;
|
||||
} else if (!temp1 && temp2) {
|
||||
outpdimm->all_dimms_unbuffered = 1;
|
||||
} else {
|
||||
printf("ERROR: Mix of registered buffered and unbuffered "
|
||||
"DIMMs detected!\n");
|
||||
}
|
||||
|
||||
temp1 = 0;
|
||||
if (outpdimm->all_dimms_registered)
|
||||
for (j = 0; j < 16; j++) {
|
||||
outpdimm->rcw[j] = dimm_params[0].rcw[j];
|
||||
for (i = 1; i < number_of_dimms; i++) {
|
||||
if (!dimm_params[i].n_ranks)
|
||||
continue;
|
||||
if (dimm_params[i].rcw[j] != dimm_params[0].rcw[j]) {
|
||||
temp1 = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (temp1 != 0)
|
||||
printf("ERROR: Mix different RDIMM detected!\n");
|
||||
|
||||
/* calculate cas latency for all DDR types */
|
||||
if (compute_cas_latency(ctrl_num, dimm_params,
|
||||
outpdimm, number_of_dimms))
|
||||
return 1;
|
||||
|
||||
/* Determine if all DIMMs ECC capable. */
|
||||
temp1 = 1;
|
||||
for (i = 0; i < number_of_dimms; i++) {
|
||||
if (dimm_params[i].n_ranks &&
|
||||
!(dimm_params[i].edc_config & EDC_ECC)) {
|
||||
temp1 = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (temp1) {
|
||||
debug("all DIMMs ECC capable\n");
|
||||
} else {
|
||||
debug("Warning: not all DIMMs ECC capable, cant enable ECC\n");
|
||||
}
|
||||
outpdimm->all_dimms_ecc_capable = temp1;
|
||||
|
||||
/*
|
||||
* Compute additive latency.
|
||||
*
|
||||
* For DDR1, additive latency should be 0.
|
||||
*
|
||||
* For DDR2, with ODT enabled, use "a value" less than ACTTORW,
|
||||
* which comes from Trcd, and also note that:
|
||||
* add_lat + caslat must be >= 4
|
||||
*
|
||||
* For DDR3, we use the AL=0
|
||||
*
|
||||
* When to use additive latency for DDR2:
|
||||
*
|
||||
* I. Because you are using CL=3 and need to do ODT on writes and
|
||||
* want functionality.
|
||||
* 1. Are you going to use ODT? (Does your board not have
|
||||
* additional termination circuitry for DQ, DQS, DQS_,
|
||||
* DM, RDQS, RDQS_ for x4/x8 configs?)
|
||||
* 2. If so, is your lowest supported CL going to be 3?
|
||||
* 3. If so, then you must set AL=1 because
|
||||
*
|
||||
* WL >= 3 for ODT on writes
|
||||
* RL = AL + CL
|
||||
* WL = RL - 1
|
||||
* ->
|
||||
* WL = AL + CL - 1
|
||||
* AL + CL - 1 >= 3
|
||||
* AL + CL >= 4
|
||||
* QED
|
||||
*
|
||||
* RL >= 3 for ODT on reads
|
||||
* RL = AL + CL
|
||||
*
|
||||
* Since CL aren't usually less than 2, AL=0 is a minimum,
|
||||
* so the WL-derived AL should be the -- FIXME?
|
||||
*
|
||||
* II. Because you are using auto-precharge globally and want to
|
||||
* use additive latency (posted CAS) to get more bandwidth.
|
||||
* 1. Are you going to use auto-precharge mode globally?
|
||||
*
|
||||
* Use addtivie latency and compute AL to be 1 cycle less than
|
||||
* tRCD, i.e. the READ or WRITE command is in the cycle
|
||||
* immediately following the ACTIVATE command..
|
||||
*
|
||||
* III. Because you feel like it or want to do some sort of
|
||||
* degraded-performance experiment.
|
||||
* 1. Do you just want to use additive latency because you feel
|
||||
* like it?
|
||||
*
|
||||
* Validation: AL is less than tRCD, and within the other
|
||||
* read-to-precharge constraints.
|
||||
*/
|
||||
|
||||
additive_latency = 0;
|
||||
|
||||
#if defined(CONFIG_SYS_FSL_DDR2)
|
||||
if ((outpdimm->lowest_common_spd_caslat < 4) &&
|
||||
(picos_to_mclk(ctrl_num, trcd_ps) >
|
||||
outpdimm->lowest_common_spd_caslat)) {
|
||||
additive_latency = picos_to_mclk(ctrl_num, trcd_ps) -
|
||||
outpdimm->lowest_common_spd_caslat;
|
||||
if (mclk_to_picos(ctrl_num, additive_latency) > trcd_ps) {
|
||||
additive_latency = picos_to_mclk(ctrl_num, trcd_ps);
|
||||
debug("setting additive_latency to %u because it was "
|
||||
" greater than tRCD_ps\n", additive_latency);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Validate additive latency
|
||||
*
|
||||
* AL <= tRCD(min)
|
||||
*/
|
||||
if (mclk_to_picos(ctrl_num, additive_latency) > trcd_ps) {
|
||||
printf("Error: invalid additive latency exceeds tRCD(min).\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* RL = CL + AL; RL >= 3 for ODT_RD_CFG to be enabled
|
||||
* WL = RL - 1; WL >= 3 for ODT_WL_CFG to be enabled
|
||||
* ADD_LAT (the register) must be set to a value less
|
||||
* than ACTTORW if WL = 1, then AL must be set to 1
|
||||
* RD_TO_PRE (the register) must be set to a minimum
|
||||
* tRTP + AL if AL is nonzero
|
||||
*/
|
||||
|
||||
/*
|
||||
* Additive latency will be applied only if the memctl option to
|
||||
* use it.
|
||||
*/
|
||||
outpdimm->additive_latency = additive_latency;
|
||||
|
||||
debug("tCKmin_ps = %u\n", outpdimm->tckmin_x_ps);
|
||||
debug("trcd_ps = %u\n", outpdimm->trcd_ps);
|
||||
debug("trp_ps = %u\n", outpdimm->trp_ps);
|
||||
debug("tras_ps = %u\n", outpdimm->tras_ps);
|
||||
#ifdef CONFIG_SYS_FSL_DDR4
|
||||
debug("trfc1_ps = %u\n", trfc1_ps);
|
||||
debug("trfc2_ps = %u\n", trfc2_ps);
|
||||
debug("trfc4_ps = %u\n", trfc4_ps);
|
||||
debug("trrds_ps = %u\n", trrds_ps);
|
||||
debug("trrdl_ps = %u\n", trrdl_ps);
|
||||
debug("tccdl_ps = %u\n", tccdl_ps);
|
||||
#else
|
||||
debug("twtr_ps = %u\n", outpdimm->twtr_ps);
|
||||
debug("trfc_ps = %u\n", outpdimm->trfc_ps);
|
||||
debug("trrd_ps = %u\n", outpdimm->trrd_ps);
|
||||
#endif
|
||||
debug("twr_ps = %u\n", outpdimm->twr_ps);
|
||||
debug("trc_ps = %u\n", outpdimm->trc_ps);
|
||||
|
||||
return 0;
|
||||
}
|
||||
866
u-boot/drivers/ddr/fsl/main.c
Normal file
866
u-boot/drivers/ddr/fsl/main.c
Normal file
@@ -0,0 +1,866 @@
|
||||
/*
|
||||
* Copyright 2008-2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Generic driver for Freescale DDR/DDR2/DDR3 memory controller.
|
||||
* Based on code from spd_sdram.c
|
||||
* Author: James Yang [at freescale.com]
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <i2c.h>
|
||||
#include <fsl_ddr_sdram.h>
|
||||
#include <fsl_ddr.h>
|
||||
|
||||
/*
|
||||
* CONFIG_SYS_FSL_DDR_SDRAM_BASE_PHY is the physical address from the view
|
||||
* of DDR controllers. It is the same as CONFIG_SYS_DDR_SDRAM_BASE for
|
||||
* all Power SoCs. But it could be different for ARM SoCs. For example,
|
||||
* fsl_lsch3 has a mapping mechanism to map DDR memory to ranges (in order) of
|
||||
* 0x00_8000_0000 ~ 0x00_ffff_ffff
|
||||
* 0x80_8000_0000 ~ 0xff_ffff_ffff
|
||||
*/
|
||||
#ifndef CONFIG_SYS_FSL_DDR_SDRAM_BASE_PHY
|
||||
#define CONFIG_SYS_FSL_DDR_SDRAM_BASE_PHY CONFIG_SYS_DDR_SDRAM_BASE
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PPC
|
||||
#include <asm/fsl_law.h>
|
||||
|
||||
void fsl_ddr_set_lawbar(
|
||||
const common_timing_params_t *memctl_common_params,
|
||||
unsigned int memctl_interleaved,
|
||||
unsigned int ctrl_num);
|
||||
#endif
|
||||
|
||||
void fsl_ddr_set_intl3r(const unsigned int granule_size);
|
||||
#if defined(SPD_EEPROM_ADDRESS) || \
|
||||
defined(SPD_EEPROM_ADDRESS1) || defined(SPD_EEPROM_ADDRESS2) || \
|
||||
defined(SPD_EEPROM_ADDRESS3) || defined(SPD_EEPROM_ADDRESS4)
|
||||
#if (CONFIG_NUM_DDR_CONTROLLERS == 1) && (CONFIG_DIMM_SLOTS_PER_CTLR == 1)
|
||||
u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = {
|
||||
[0][0] = SPD_EEPROM_ADDRESS,
|
||||
};
|
||||
#elif (CONFIG_NUM_DDR_CONTROLLERS == 1) && (CONFIG_DIMM_SLOTS_PER_CTLR == 2)
|
||||
u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = {
|
||||
[0][0] = SPD_EEPROM_ADDRESS1, /* controller 1 */
|
||||
[0][1] = SPD_EEPROM_ADDRESS2, /* controller 1 */
|
||||
};
|
||||
#elif (CONFIG_NUM_DDR_CONTROLLERS == 2) && (CONFIG_DIMM_SLOTS_PER_CTLR == 1)
|
||||
u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = {
|
||||
[0][0] = SPD_EEPROM_ADDRESS1, /* controller 1 */
|
||||
[1][0] = SPD_EEPROM_ADDRESS2, /* controller 2 */
|
||||
};
|
||||
#elif (CONFIG_NUM_DDR_CONTROLLERS == 2) && (CONFIG_DIMM_SLOTS_PER_CTLR == 2)
|
||||
u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = {
|
||||
[0][0] = SPD_EEPROM_ADDRESS1, /* controller 1 */
|
||||
[0][1] = SPD_EEPROM_ADDRESS2, /* controller 1 */
|
||||
[1][0] = SPD_EEPROM_ADDRESS3, /* controller 2 */
|
||||
[1][1] = SPD_EEPROM_ADDRESS4, /* controller 2 */
|
||||
};
|
||||
#elif (CONFIG_NUM_DDR_CONTROLLERS == 3) && (CONFIG_DIMM_SLOTS_PER_CTLR == 1)
|
||||
u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = {
|
||||
[0][0] = SPD_EEPROM_ADDRESS1, /* controller 1 */
|
||||
[1][0] = SPD_EEPROM_ADDRESS2, /* controller 2 */
|
||||
[2][0] = SPD_EEPROM_ADDRESS3, /* controller 3 */
|
||||
};
|
||||
#elif (CONFIG_NUM_DDR_CONTROLLERS == 3) && (CONFIG_DIMM_SLOTS_PER_CTLR == 2)
|
||||
u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = {
|
||||
[0][0] = SPD_EEPROM_ADDRESS1, /* controller 1 */
|
||||
[0][1] = SPD_EEPROM_ADDRESS2, /* controller 1 */
|
||||
[1][0] = SPD_EEPROM_ADDRESS3, /* controller 2 */
|
||||
[1][1] = SPD_EEPROM_ADDRESS4, /* controller 2 */
|
||||
[2][0] = SPD_EEPROM_ADDRESS5, /* controller 3 */
|
||||
[2][1] = SPD_EEPROM_ADDRESS6, /* controller 3 */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#define SPD_SPA0_ADDRESS 0x36
|
||||
#define SPD_SPA1_ADDRESS 0x37
|
||||
|
||||
static void __get_spd(generic_spd_eeprom_t *spd, u8 i2c_address)
|
||||
{
|
||||
int ret;
|
||||
#ifdef CONFIG_SYS_FSL_DDR4
|
||||
uint8_t dummy = 0;
|
||||
#endif
|
||||
|
||||
i2c_set_bus_num(CONFIG_SYS_SPD_BUS_NUM);
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_DDR4
|
||||
/*
|
||||
* DDR4 SPD has 384 to 512 bytes
|
||||
* To access the lower 256 bytes, we need to set EE page address to 0
|
||||
* To access the upper 256 bytes, we need to set EE page address to 1
|
||||
* See Jedec standar No. 21-C for detail
|
||||
*/
|
||||
i2c_write(SPD_SPA0_ADDRESS, 0, 1, &dummy, 1);
|
||||
ret = i2c_read(i2c_address, 0, 1, (uchar *)spd, 256);
|
||||
if (!ret) {
|
||||
i2c_write(SPD_SPA1_ADDRESS, 0, 1, &dummy, 1);
|
||||
ret = i2c_read(i2c_address, 0, 1,
|
||||
(uchar *)((ulong)spd + 256),
|
||||
min(256,
|
||||
(int)sizeof(generic_spd_eeprom_t) - 256));
|
||||
}
|
||||
#else
|
||||
ret = i2c_read(i2c_address, 0, 1, (uchar *)spd,
|
||||
sizeof(generic_spd_eeprom_t));
|
||||
#endif
|
||||
|
||||
if (ret) {
|
||||
if (i2c_address ==
|
||||
#ifdef SPD_EEPROM_ADDRESS
|
||||
SPD_EEPROM_ADDRESS
|
||||
#elif defined(SPD_EEPROM_ADDRESS1)
|
||||
SPD_EEPROM_ADDRESS1
|
||||
#endif
|
||||
) {
|
||||
printf("DDR: failed to read SPD from address %u\n",
|
||||
i2c_address);
|
||||
} else {
|
||||
debug("DDR: failed to read SPD from address %u\n",
|
||||
i2c_address);
|
||||
}
|
||||
memset(spd, 0, sizeof(generic_spd_eeprom_t));
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((weak, alias("__get_spd")))
|
||||
void get_spd(generic_spd_eeprom_t *spd, u8 i2c_address);
|
||||
|
||||
/* This function allows boards to update SPD address */
|
||||
__weak void update_spd_address(unsigned int ctrl_num,
|
||||
unsigned int slot,
|
||||
unsigned int *addr)
|
||||
{
|
||||
}
|
||||
|
||||
void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd,
|
||||
unsigned int ctrl_num, unsigned int dimm_slots_per_ctrl)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int i2c_address = 0;
|
||||
|
||||
if (ctrl_num >= CONFIG_NUM_DDR_CONTROLLERS) {
|
||||
printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < dimm_slots_per_ctrl; i++) {
|
||||
i2c_address = spd_i2c_addr[ctrl_num][i];
|
||||
update_spd_address(ctrl_num, i, &i2c_address);
|
||||
get_spd(&(ctrl_dimms_spd[i]), i2c_address);
|
||||
}
|
||||
}
|
||||
#else
|
||||
void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd,
|
||||
unsigned int ctrl_num, unsigned int dimm_slots_per_ctrl)
|
||||
{
|
||||
}
|
||||
#endif /* SPD_EEPROM_ADDRESSx */
|
||||
|
||||
/*
|
||||
* ASSUMPTIONS:
|
||||
* - Same number of CONFIG_DIMM_SLOTS_PER_CTLR on each controller
|
||||
* - Same memory data bus width on all controllers
|
||||
*
|
||||
* NOTES:
|
||||
*
|
||||
* The memory controller and associated documentation use confusing
|
||||
* terminology when referring to the orgranization of DRAM.
|
||||
*
|
||||
* Here is a terminology translation table:
|
||||
*
|
||||
* memory controller/documention |industry |this code |signals
|
||||
* -------------------------------|-----------|-----------|-----------------
|
||||
* physical bank/bank |rank |rank |chip select (CS)
|
||||
* logical bank/sub-bank |bank |bank |bank address (BA)
|
||||
* page/row |row |page |row address
|
||||
* ??? |column |column |column address
|
||||
*
|
||||
* The naming confusion is further exacerbated by the descriptions of the
|
||||
* memory controller interleaving feature, where accesses are interleaved
|
||||
* _BETWEEN_ two seperate memory controllers. This is configured only in
|
||||
* CS0_CONFIG[INTLV_CTL] of each memory controller.
|
||||
*
|
||||
* memory controller documentation | number of chip selects
|
||||
* | per memory controller supported
|
||||
* --------------------------------|-----------------------------------------
|
||||
* cache line interleaving | 1 (CS0 only)
|
||||
* page interleaving | 1 (CS0 only)
|
||||
* bank interleaving | 1 (CS0 only)
|
||||
* superbank interleraving | depends on bank (chip select)
|
||||
* | interleraving [rank interleaving]
|
||||
* | mode used on every memory controller
|
||||
*
|
||||
* Even further confusing is the existence of the interleaving feature
|
||||
* _WITHIN_ each memory controller. The feature is referred to in
|
||||
* documentation as chip select interleaving or bank interleaving,
|
||||
* although it is configured in the DDR_SDRAM_CFG field.
|
||||
*
|
||||
* Name of field | documentation name | this code
|
||||
* -----------------------------|-----------------------|------------------
|
||||
* DDR_SDRAM_CFG[BA_INTLV_CTL] | Bank (chip select) | rank interleaving
|
||||
* | interleaving
|
||||
*/
|
||||
|
||||
const char *step_string_tbl[] = {
|
||||
"STEP_GET_SPD",
|
||||
"STEP_COMPUTE_DIMM_PARMS",
|
||||
"STEP_COMPUTE_COMMON_PARMS",
|
||||
"STEP_GATHER_OPTS",
|
||||
"STEP_ASSIGN_ADDRESSES",
|
||||
"STEP_COMPUTE_REGS",
|
||||
"STEP_PROGRAM_REGS",
|
||||
"STEP_ALL"
|
||||
};
|
||||
|
||||
const char * step_to_string(unsigned int step) {
|
||||
|
||||
unsigned int s = __ilog2(step);
|
||||
|
||||
if ((1 << s) != step)
|
||||
return step_string_tbl[7];
|
||||
|
||||
if (s >= ARRAY_SIZE(step_string_tbl)) {
|
||||
printf("Error for the step in %s\n", __func__);
|
||||
s = 0;
|
||||
}
|
||||
|
||||
return step_string_tbl[s];
|
||||
}
|
||||
|
||||
static unsigned long long __step_assign_addresses(fsl_ddr_info_t *pinfo,
|
||||
unsigned int dbw_cap_adj[])
|
||||
{
|
||||
unsigned int i, j;
|
||||
unsigned long long total_mem, current_mem_base, total_ctlr_mem;
|
||||
unsigned long long rank_density, ctlr_density = 0;
|
||||
unsigned int first_ctrl = pinfo->first_ctrl;
|
||||
unsigned int last_ctrl = first_ctrl + pinfo->num_ctrls - 1;
|
||||
|
||||
/*
|
||||
* If a reduced data width is requested, but the SPD
|
||||
* specifies a physically wider device, adjust the
|
||||
* computed dimm capacities accordingly before
|
||||
* assigning addresses.
|
||||
*/
|
||||
for (i = first_ctrl; i <= last_ctrl; i++) {
|
||||
unsigned int found = 0;
|
||||
|
||||
switch (pinfo->memctl_opts[i].data_bus_width) {
|
||||
case 2:
|
||||
/* 16-bit */
|
||||
for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
|
||||
unsigned int dw;
|
||||
if (!pinfo->dimm_params[i][j].n_ranks)
|
||||
continue;
|
||||
dw = pinfo->dimm_params[i][j].primary_sdram_width;
|
||||
if ((dw == 72 || dw == 64)) {
|
||||
dbw_cap_adj[i] = 2;
|
||||
break;
|
||||
} else if ((dw == 40 || dw == 32)) {
|
||||
dbw_cap_adj[i] = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
/* 32-bit */
|
||||
for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
|
||||
unsigned int dw;
|
||||
dw = pinfo->dimm_params[i][j].data_width;
|
||||
if (pinfo->dimm_params[i][j].n_ranks
|
||||
&& (dw == 72 || dw == 64)) {
|
||||
/*
|
||||
* FIXME: can't really do it
|
||||
* like this because this just
|
||||
* further reduces the memory
|
||||
*/
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
dbw_cap_adj[i] = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0:
|
||||
/* 64-bit */
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("unexpected data bus width "
|
||||
"specified controller %u\n", i);
|
||||
return 1;
|
||||
}
|
||||
debug("dbw_cap_adj[%d]=%d\n", i, dbw_cap_adj[i]);
|
||||
}
|
||||
|
||||
current_mem_base = pinfo->mem_base;
|
||||
total_mem = 0;
|
||||
if (pinfo->memctl_opts[first_ctrl].memctl_interleaving) {
|
||||
rank_density = pinfo->dimm_params[first_ctrl][0].rank_density >>
|
||||
dbw_cap_adj[first_ctrl];
|
||||
switch (pinfo->memctl_opts[first_ctrl].ba_intlv_ctl &
|
||||
FSL_DDR_CS0_CS1_CS2_CS3) {
|
||||
case FSL_DDR_CS0_CS1_CS2_CS3:
|
||||
ctlr_density = 4 * rank_density;
|
||||
break;
|
||||
case FSL_DDR_CS0_CS1:
|
||||
case FSL_DDR_CS0_CS1_AND_CS2_CS3:
|
||||
ctlr_density = 2 * rank_density;
|
||||
break;
|
||||
case FSL_DDR_CS2_CS3:
|
||||
default:
|
||||
ctlr_density = rank_density;
|
||||
break;
|
||||
}
|
||||
debug("rank density is 0x%llx, ctlr density is 0x%llx\n",
|
||||
rank_density, ctlr_density);
|
||||
for (i = first_ctrl; i <= last_ctrl; i++) {
|
||||
if (pinfo->memctl_opts[i].memctl_interleaving) {
|
||||
switch (pinfo->memctl_opts[i].memctl_interleaving_mode) {
|
||||
case FSL_DDR_256B_INTERLEAVING:
|
||||
case FSL_DDR_CACHE_LINE_INTERLEAVING:
|
||||
case FSL_DDR_PAGE_INTERLEAVING:
|
||||
case FSL_DDR_BANK_INTERLEAVING:
|
||||
case FSL_DDR_SUPERBANK_INTERLEAVING:
|
||||
total_ctlr_mem = 2 * ctlr_density;
|
||||
break;
|
||||
case FSL_DDR_3WAY_1KB_INTERLEAVING:
|
||||
case FSL_DDR_3WAY_4KB_INTERLEAVING:
|
||||
case FSL_DDR_3WAY_8KB_INTERLEAVING:
|
||||
total_ctlr_mem = 3 * ctlr_density;
|
||||
break;
|
||||
case FSL_DDR_4WAY_1KB_INTERLEAVING:
|
||||
case FSL_DDR_4WAY_4KB_INTERLEAVING:
|
||||
case FSL_DDR_4WAY_8KB_INTERLEAVING:
|
||||
total_ctlr_mem = 4 * ctlr_density;
|
||||
break;
|
||||
default:
|
||||
panic("Unknown interleaving mode");
|
||||
}
|
||||
pinfo->common_timing_params[i].base_address =
|
||||
current_mem_base;
|
||||
pinfo->common_timing_params[i].total_mem =
|
||||
total_ctlr_mem;
|
||||
total_mem = current_mem_base + total_ctlr_mem;
|
||||
debug("ctrl %d base 0x%llx\n", i, current_mem_base);
|
||||
debug("ctrl %d total 0x%llx\n", i, total_ctlr_mem);
|
||||
} else {
|
||||
/* when 3rd controller not interleaved */
|
||||
current_mem_base = total_mem;
|
||||
total_ctlr_mem = 0;
|
||||
pinfo->common_timing_params[i].base_address =
|
||||
current_mem_base;
|
||||
for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
|
||||
unsigned long long cap =
|
||||
pinfo->dimm_params[i][j].capacity >> dbw_cap_adj[i];
|
||||
pinfo->dimm_params[i][j].base_address =
|
||||
current_mem_base;
|
||||
debug("ctrl %d dimm %d base 0x%llx\n", i, j, current_mem_base);
|
||||
current_mem_base += cap;
|
||||
total_ctlr_mem += cap;
|
||||
}
|
||||
debug("ctrl %d total 0x%llx\n", i, total_ctlr_mem);
|
||||
pinfo->common_timing_params[i].total_mem =
|
||||
total_ctlr_mem;
|
||||
total_mem += total_ctlr_mem;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Simple linear assignment if memory
|
||||
* controllers are not interleaved.
|
||||
*/
|
||||
for (i = first_ctrl; i <= last_ctrl; i++) {
|
||||
total_ctlr_mem = 0;
|
||||
pinfo->common_timing_params[i].base_address =
|
||||
current_mem_base;
|
||||
for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
|
||||
/* Compute DIMM base addresses. */
|
||||
unsigned long long cap =
|
||||
pinfo->dimm_params[i][j].capacity >> dbw_cap_adj[i];
|
||||
pinfo->dimm_params[i][j].base_address =
|
||||
current_mem_base;
|
||||
debug("ctrl %d dimm %d base 0x%llx\n", i, j, current_mem_base);
|
||||
current_mem_base += cap;
|
||||
total_ctlr_mem += cap;
|
||||
}
|
||||
debug("ctrl %d total 0x%llx\n", i, total_ctlr_mem);
|
||||
pinfo->common_timing_params[i].total_mem =
|
||||
total_ctlr_mem;
|
||||
total_mem += total_ctlr_mem;
|
||||
}
|
||||
}
|
||||
debug("Total mem by %s is 0x%llx\n", __func__, total_mem);
|
||||
|
||||
return total_mem;
|
||||
}
|
||||
|
||||
/* Use weak function to allow board file to override the address assignment */
|
||||
__attribute__((weak, alias("__step_assign_addresses")))
|
||||
unsigned long long step_assign_addresses(fsl_ddr_info_t *pinfo,
|
||||
unsigned int dbw_cap_adj[]);
|
||||
|
||||
unsigned long long
|
||||
fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
|
||||
unsigned int size_only)
|
||||
{
|
||||
unsigned int i, j;
|
||||
unsigned long long total_mem = 0;
|
||||
int assert_reset = 0;
|
||||
unsigned int first_ctrl = pinfo->first_ctrl;
|
||||
unsigned int last_ctrl = first_ctrl + pinfo->num_ctrls - 1;
|
||||
__maybe_unused int retval;
|
||||
__maybe_unused bool goodspd = false;
|
||||
__maybe_unused int dimm_slots_per_ctrl = pinfo->dimm_slots_per_ctrl;
|
||||
|
||||
fsl_ddr_cfg_regs_t *ddr_reg = pinfo->fsl_ddr_config_reg;
|
||||
common_timing_params_t *timing_params = pinfo->common_timing_params;
|
||||
if (pinfo->board_need_mem_reset)
|
||||
assert_reset = pinfo->board_need_mem_reset();
|
||||
|
||||
/* data bus width capacity adjust shift amount */
|
||||
unsigned int dbw_capacity_adjust[CONFIG_NUM_DDR_CONTROLLERS];
|
||||
|
||||
for (i = first_ctrl; i <= last_ctrl; i++)
|
||||
dbw_capacity_adjust[i] = 0;
|
||||
|
||||
debug("starting at step %u (%s)\n",
|
||||
start_step, step_to_string(start_step));
|
||||
|
||||
switch (start_step) {
|
||||
case STEP_GET_SPD:
|
||||
#if defined(CONFIG_DDR_SPD) || defined(CONFIG_SPD_EEPROM)
|
||||
/* STEP 1: Gather all DIMM SPD data */
|
||||
for (i = first_ctrl; i <= last_ctrl; i++) {
|
||||
fsl_ddr_get_spd(pinfo->spd_installed_dimms[i], i,
|
||||
dimm_slots_per_ctrl);
|
||||
}
|
||||
|
||||
case STEP_COMPUTE_DIMM_PARMS:
|
||||
/* STEP 2: Compute DIMM parameters from SPD data */
|
||||
|
||||
for (i = first_ctrl; i <= last_ctrl; i++) {
|
||||
for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
|
||||
generic_spd_eeprom_t *spd =
|
||||
&(pinfo->spd_installed_dimms[i][j]);
|
||||
dimm_params_t *pdimm =
|
||||
&(pinfo->dimm_params[i][j]);
|
||||
retval = compute_dimm_parameters(
|
||||
i, spd, pdimm, j);
|
||||
#ifdef CONFIG_SYS_DDR_RAW_TIMING
|
||||
if (!j && retval) {
|
||||
printf("SPD error on controller %d! "
|
||||
"Trying fallback to raw timing "
|
||||
"calculation\n", i);
|
||||
retval = fsl_ddr_get_dimm_params(pdimm,
|
||||
i, j);
|
||||
}
|
||||
#else
|
||||
if (retval == 2) {
|
||||
printf("Error: compute_dimm_parameters"
|
||||
" non-zero returned FATAL value "
|
||||
"for memctl=%u dimm=%u\n", i, j);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (retval) {
|
||||
debug("Warning: compute_dimm_parameters"
|
||||
" non-zero return value for memctl=%u "
|
||||
"dimm=%u\n", i, j);
|
||||
} else {
|
||||
goodspd = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!goodspd) {
|
||||
/*
|
||||
* No valid SPD found
|
||||
* Throw an error if this is for main memory, i.e.
|
||||
* first_ctrl == 0. Otherwise, siliently return 0
|
||||
* as the memory size.
|
||||
*/
|
||||
if (first_ctrl == 0)
|
||||
printf("Error: No valid SPD detected.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
#elif defined(CONFIG_SYS_DDR_RAW_TIMING)
|
||||
case STEP_COMPUTE_DIMM_PARMS:
|
||||
for (i = first_ctrl; i <= last_ctrl; i++) {
|
||||
for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
|
||||
dimm_params_t *pdimm =
|
||||
&(pinfo->dimm_params[i][j]);
|
||||
fsl_ddr_get_dimm_params(pdimm, i, j);
|
||||
}
|
||||
}
|
||||
debug("Filling dimm parameters from board specific file\n");
|
||||
#endif
|
||||
case STEP_COMPUTE_COMMON_PARMS:
|
||||
/*
|
||||
* STEP 3: Compute a common set of timing parameters
|
||||
* suitable for all of the DIMMs on each memory controller
|
||||
*/
|
||||
for (i = first_ctrl; i <= last_ctrl; i++) {
|
||||
debug("Computing lowest common DIMM"
|
||||
" parameters for memctl=%u\n", i);
|
||||
compute_lowest_common_dimm_parameters
|
||||
(i,
|
||||
pinfo->dimm_params[i],
|
||||
&timing_params[i],
|
||||
CONFIG_DIMM_SLOTS_PER_CTLR);
|
||||
}
|
||||
|
||||
case STEP_GATHER_OPTS:
|
||||
/* STEP 4: Gather configuration requirements from user */
|
||||
for (i = first_ctrl; i <= last_ctrl; i++) {
|
||||
debug("Reloading memory controller "
|
||||
"configuration options for memctl=%u\n", i);
|
||||
/*
|
||||
* This "reloads" the memory controller options
|
||||
* to defaults. If the user "edits" an option,
|
||||
* next_step points to the step after this,
|
||||
* which is currently STEP_ASSIGN_ADDRESSES.
|
||||
*/
|
||||
populate_memctl_options(
|
||||
&timing_params[i],
|
||||
&pinfo->memctl_opts[i],
|
||||
pinfo->dimm_params[i], i);
|
||||
/*
|
||||
* For RDIMMs, JEDEC spec requires clocks to be stable
|
||||
* before reset signal is deasserted. For the boards
|
||||
* using fixed parameters, this function should be
|
||||
* be called from board init file.
|
||||
*/
|
||||
if (timing_params[i].all_dimms_registered)
|
||||
assert_reset = 1;
|
||||
}
|
||||
if (assert_reset && !size_only) {
|
||||
if (pinfo->board_mem_reset) {
|
||||
debug("Asserting mem reset\n");
|
||||
pinfo->board_mem_reset();
|
||||
} else {
|
||||
debug("Asserting mem reset missing\n");
|
||||
}
|
||||
}
|
||||
|
||||
case STEP_ASSIGN_ADDRESSES:
|
||||
/* STEP 5: Assign addresses to chip selects */
|
||||
check_interleaving_options(pinfo);
|
||||
total_mem = step_assign_addresses(pinfo, dbw_capacity_adjust);
|
||||
debug("Total mem %llu assigned\n", total_mem);
|
||||
|
||||
case STEP_COMPUTE_REGS:
|
||||
/* STEP 6: compute controller register values */
|
||||
debug("FSL Memory ctrl register computation\n");
|
||||
for (i = first_ctrl; i <= last_ctrl; i++) {
|
||||
if (timing_params[i].ndimms_present == 0) {
|
||||
memset(&ddr_reg[i], 0,
|
||||
sizeof(fsl_ddr_cfg_regs_t));
|
||||
continue;
|
||||
}
|
||||
|
||||
compute_fsl_memctl_config_regs
|
||||
(i,
|
||||
&pinfo->memctl_opts[i],
|
||||
&ddr_reg[i], &timing_params[i],
|
||||
pinfo->dimm_params[i],
|
||||
dbw_capacity_adjust[i],
|
||||
size_only);
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
/*
|
||||
* Compute the amount of memory available just by
|
||||
* looking for the highest valid CSn_BNDS value.
|
||||
* This allows us to also experiment with using
|
||||
* only CS0 when using dual-rank DIMMs.
|
||||
*/
|
||||
unsigned int max_end = 0;
|
||||
|
||||
for (i = first_ctrl; i <= last_ctrl; i++) {
|
||||
for (j = 0; j < CONFIG_CHIP_SELECTS_PER_CTRL; j++) {
|
||||
fsl_ddr_cfg_regs_t *reg = &ddr_reg[i];
|
||||
if (reg->cs[j].config & 0x80000000) {
|
||||
unsigned int end;
|
||||
/*
|
||||
* 0xfffffff is a special value we put
|
||||
* for unused bnds
|
||||
*/
|
||||
if (reg->cs[j].bnds == 0xffffffff)
|
||||
continue;
|
||||
end = reg->cs[j].bnds & 0xffff;
|
||||
if (end > max_end) {
|
||||
max_end = end;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
total_mem = 1 + (((unsigned long long)max_end << 24ULL) |
|
||||
0xFFFFFFULL) - pinfo->mem_base;
|
||||
}
|
||||
|
||||
return total_mem;
|
||||
}
|
||||
|
||||
phys_size_t __fsl_ddr_sdram(fsl_ddr_info_t *pinfo)
|
||||
{
|
||||
unsigned int i, first_ctrl, last_ctrl;
|
||||
#ifdef CONFIG_PPC
|
||||
unsigned int law_memctl = LAW_TRGT_IF_DDR_1;
|
||||
#endif
|
||||
unsigned long long total_memory;
|
||||
int deassert_reset = 0;
|
||||
|
||||
first_ctrl = pinfo->first_ctrl;
|
||||
last_ctrl = first_ctrl + pinfo->num_ctrls - 1;
|
||||
|
||||
/* Compute it once normally. */
|
||||
#ifdef CONFIG_FSL_DDR_INTERACTIVE
|
||||
if (tstc() && (getc() == 'd')) { /* we got a key press of 'd' */
|
||||
total_memory = fsl_ddr_interactive(pinfo, 0);
|
||||
} else if (fsl_ddr_interactive_env_var_exists()) {
|
||||
total_memory = fsl_ddr_interactive(pinfo, 1);
|
||||
} else
|
||||
#endif
|
||||
total_memory = fsl_ddr_compute(pinfo, STEP_GET_SPD, 0);
|
||||
|
||||
/* setup 3-way interleaving before enabling DDRC */
|
||||
switch (pinfo->memctl_opts[first_ctrl].memctl_interleaving_mode) {
|
||||
case FSL_DDR_3WAY_1KB_INTERLEAVING:
|
||||
case FSL_DDR_3WAY_4KB_INTERLEAVING:
|
||||
case FSL_DDR_3WAY_8KB_INTERLEAVING:
|
||||
fsl_ddr_set_intl3r(
|
||||
pinfo->memctl_opts[first_ctrl].
|
||||
memctl_interleaving_mode);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Program configuration registers.
|
||||
* JEDEC specs requires clocks to be stable before deasserting reset
|
||||
* for RDIMMs. Clocks start after chip select is enabled and clock
|
||||
* control register is set. During step 1, all controllers have their
|
||||
* registers set but not enabled. Step 2 proceeds after deasserting
|
||||
* reset through board FPGA or GPIO.
|
||||
* For non-registered DIMMs, initialization can go through but it is
|
||||
* also OK to follow the same flow.
|
||||
*/
|
||||
if (pinfo->board_need_mem_reset)
|
||||
deassert_reset = pinfo->board_need_mem_reset();
|
||||
for (i = first_ctrl; i <= last_ctrl; i++) {
|
||||
if (pinfo->common_timing_params[i].all_dimms_registered)
|
||||
deassert_reset = 1;
|
||||
}
|
||||
for (i = first_ctrl; i <= last_ctrl; i++) {
|
||||
debug("Programming controller %u\n", i);
|
||||
if (pinfo->common_timing_params[i].ndimms_present == 0) {
|
||||
debug("No dimms present on controller %u; "
|
||||
"skipping programming\n", i);
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* The following call with step = 1 returns before enabling
|
||||
* the controller. It has to finish with step = 2 later.
|
||||
*/
|
||||
fsl_ddr_set_memctl_regs(&(pinfo->fsl_ddr_config_reg[i]), i,
|
||||
deassert_reset ? 1 : 0);
|
||||
}
|
||||
if (deassert_reset) {
|
||||
/* Use board FPGA or GPIO to deassert reset signal */
|
||||
if (pinfo->board_mem_de_reset) {
|
||||
debug("Deasserting mem reset\n");
|
||||
pinfo->board_mem_de_reset();
|
||||
} else {
|
||||
debug("Deasserting mem reset missing\n");
|
||||
}
|
||||
for (i = first_ctrl; i <= last_ctrl; i++) {
|
||||
/* Call with step = 2 to continue initialization */
|
||||
fsl_ddr_set_memctl_regs(&(pinfo->fsl_ddr_config_reg[i]),
|
||||
i, 2);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FSL_DDR_SYNC_REFRESH
|
||||
fsl_ddr_sync_memctl_refresh(first_ctrl, last_ctrl);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PPC
|
||||
/* program LAWs */
|
||||
for (i = first_ctrl; i <= last_ctrl; i++) {
|
||||
if (pinfo->memctl_opts[i].memctl_interleaving) {
|
||||
switch (pinfo->memctl_opts[i].
|
||||
memctl_interleaving_mode) {
|
||||
case FSL_DDR_CACHE_LINE_INTERLEAVING:
|
||||
case FSL_DDR_PAGE_INTERLEAVING:
|
||||
case FSL_DDR_BANK_INTERLEAVING:
|
||||
case FSL_DDR_SUPERBANK_INTERLEAVING:
|
||||
if (i % 2)
|
||||
break;
|
||||
if (i == 0) {
|
||||
law_memctl = LAW_TRGT_IF_DDR_INTRLV;
|
||||
fsl_ddr_set_lawbar(
|
||||
&pinfo->common_timing_params[i],
|
||||
law_memctl, i);
|
||||
}
|
||||
#if CONFIG_NUM_DDR_CONTROLLERS > 3
|
||||
else if (i == 2) {
|
||||
law_memctl = LAW_TRGT_IF_DDR_INTLV_34;
|
||||
fsl_ddr_set_lawbar(
|
||||
&pinfo->common_timing_params[i],
|
||||
law_memctl, i);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case FSL_DDR_3WAY_1KB_INTERLEAVING:
|
||||
case FSL_DDR_3WAY_4KB_INTERLEAVING:
|
||||
case FSL_DDR_3WAY_8KB_INTERLEAVING:
|
||||
law_memctl = LAW_TRGT_IF_DDR_INTLV_123;
|
||||
if (i == 0) {
|
||||
fsl_ddr_set_lawbar(
|
||||
&pinfo->common_timing_params[i],
|
||||
law_memctl, i);
|
||||
}
|
||||
break;
|
||||
case FSL_DDR_4WAY_1KB_INTERLEAVING:
|
||||
case FSL_DDR_4WAY_4KB_INTERLEAVING:
|
||||
case FSL_DDR_4WAY_8KB_INTERLEAVING:
|
||||
law_memctl = LAW_TRGT_IF_DDR_INTLV_1234;
|
||||
if (i == 0)
|
||||
fsl_ddr_set_lawbar(
|
||||
&pinfo->common_timing_params[i],
|
||||
law_memctl, i);
|
||||
/* place holder for future 4-way interleaving */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (i) {
|
||||
case 0:
|
||||
law_memctl = LAW_TRGT_IF_DDR_1;
|
||||
break;
|
||||
case 1:
|
||||
law_memctl = LAW_TRGT_IF_DDR_2;
|
||||
break;
|
||||
case 2:
|
||||
law_memctl = LAW_TRGT_IF_DDR_3;
|
||||
break;
|
||||
case 3:
|
||||
law_memctl = LAW_TRGT_IF_DDR_4;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
fsl_ddr_set_lawbar(&pinfo->common_timing_params[i],
|
||||
law_memctl, i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
debug("total_memory by %s = %llu\n", __func__, total_memory);
|
||||
|
||||
#if !defined(CONFIG_PHYS_64BIT)
|
||||
/* Check for 4G or more. Bad. */
|
||||
if ((first_ctrl == 0) && (total_memory >= (1ull << 32))) {
|
||||
puts("Detected ");
|
||||
print_size(total_memory, " of memory\n");
|
||||
printf(" This U-Boot only supports < 4G of DDR\n");
|
||||
printf(" You could rebuild it with CONFIG_PHYS_64BIT\n");
|
||||
printf(" "); /* re-align to match init_func_ram print */
|
||||
total_memory = CONFIG_MAX_MEM_MAPPED;
|
||||
}
|
||||
#endif
|
||||
|
||||
return total_memory;
|
||||
}
|
||||
|
||||
/*
|
||||
* fsl_ddr_sdram(void) -- this is the main function to be
|
||||
* called by initdram() in the board file.
|
||||
*
|
||||
* It returns amount of memory configured in bytes.
|
||||
*/
|
||||
phys_size_t fsl_ddr_sdram(void)
|
||||
{
|
||||
fsl_ddr_info_t info;
|
||||
|
||||
/* Reset info structure. */
|
||||
memset(&info, 0, sizeof(fsl_ddr_info_t));
|
||||
info.mem_base = CONFIG_SYS_FSL_DDR_SDRAM_BASE_PHY;
|
||||
info.first_ctrl = 0;
|
||||
info.num_ctrls = CONFIG_SYS_FSL_DDR_MAIN_NUM_CTRLS;
|
||||
info.dimm_slots_per_ctrl = CONFIG_DIMM_SLOTS_PER_CTLR;
|
||||
info.board_need_mem_reset = board_need_mem_reset;
|
||||
info.board_mem_reset = board_assert_mem_reset;
|
||||
info.board_mem_de_reset = board_deassert_mem_reset;
|
||||
remove_unused_controllers(&info);
|
||||
|
||||
return __fsl_ddr_sdram(&info);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_OTHER_DDR_NUM_CTRLS
|
||||
phys_size_t fsl_other_ddr_sdram(unsigned long long base,
|
||||
unsigned int first_ctrl,
|
||||
unsigned int num_ctrls,
|
||||
unsigned int dimm_slots_per_ctrl,
|
||||
int (*board_need_reset)(void),
|
||||
void (*board_reset)(void),
|
||||
void (*board_de_reset)(void))
|
||||
{
|
||||
fsl_ddr_info_t info;
|
||||
|
||||
/* Reset info structure. */
|
||||
memset(&info, 0, sizeof(fsl_ddr_info_t));
|
||||
info.mem_base = base;
|
||||
info.first_ctrl = first_ctrl;
|
||||
info.num_ctrls = num_ctrls;
|
||||
info.dimm_slots_per_ctrl = dimm_slots_per_ctrl;
|
||||
info.board_need_mem_reset = board_need_reset;
|
||||
info.board_mem_reset = board_reset;
|
||||
info.board_mem_de_reset = board_de_reset;
|
||||
|
||||
return __fsl_ddr_sdram(&info);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* fsl_ddr_sdram_size(first_ctrl, last_intlv) - This function only returns the
|
||||
* size of the total memory without setting ddr control registers.
|
||||
*/
|
||||
phys_size_t
|
||||
fsl_ddr_sdram_size(void)
|
||||
{
|
||||
fsl_ddr_info_t info;
|
||||
unsigned long long total_memory = 0;
|
||||
|
||||
memset(&info, 0 , sizeof(fsl_ddr_info_t));
|
||||
info.mem_base = CONFIG_SYS_FSL_DDR_SDRAM_BASE_PHY;
|
||||
info.first_ctrl = 0;
|
||||
info.num_ctrls = CONFIG_SYS_FSL_DDR_MAIN_NUM_CTRLS;
|
||||
info.dimm_slots_per_ctrl = CONFIG_DIMM_SLOTS_PER_CTLR;
|
||||
info.board_need_mem_reset = NULL;
|
||||
remove_unused_controllers(&info);
|
||||
|
||||
/* Compute it once normally. */
|
||||
total_memory = fsl_ddr_compute(&info, STEP_GET_SPD, 1);
|
||||
|
||||
return total_memory;
|
||||
}
|
||||
89
u-boot/drivers/ddr/fsl/mpc85xx_ddr_gen1.c
Normal file
89
u-boot/drivers/ddr/fsl/mpc85xx_ddr_gen1.c
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2008 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <fsl_ddr_sdram.h>
|
||||
|
||||
#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4)
|
||||
#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL
|
||||
#endif
|
||||
|
||||
void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
|
||||
unsigned int ctrl_num, int step)
|
||||
{
|
||||
unsigned int i;
|
||||
struct ccsr_ddr __iomem *ddr =
|
||||
(struct ccsr_ddr __iomem *)CONFIG_SYS_FSL_DDR_ADDR;
|
||||
|
||||
if (ctrl_num != 0) {
|
||||
printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
|
||||
if (i == 0) {
|
||||
out_be32(&ddr->cs0_bnds, regs->cs[i].bnds);
|
||||
out_be32(&ddr->cs0_config, regs->cs[i].config);
|
||||
|
||||
} else if (i == 1) {
|
||||
out_be32(&ddr->cs1_bnds, regs->cs[i].bnds);
|
||||
out_be32(&ddr->cs1_config, regs->cs[i].config);
|
||||
|
||||
} else if (i == 2) {
|
||||
out_be32(&ddr->cs2_bnds, regs->cs[i].bnds);
|
||||
out_be32(&ddr->cs2_config, regs->cs[i].config);
|
||||
|
||||
} else if (i == 3) {
|
||||
out_be32(&ddr->cs3_bnds, regs->cs[i].bnds);
|
||||
out_be32(&ddr->cs3_config, regs->cs[i].config);
|
||||
}
|
||||
}
|
||||
|
||||
out_be32(&ddr->timing_cfg_1, regs->timing_cfg_1);
|
||||
out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2);
|
||||
out_be32(&ddr->sdram_mode, regs->ddr_sdram_mode);
|
||||
out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval);
|
||||
#if defined(CONFIG_MPC8555) || defined(CONFIG_MPC8541)
|
||||
out_be32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 200 painful micro-seconds must elapse between
|
||||
* the DDR clock setup and the DDR config enable.
|
||||
*/
|
||||
udelay(200);
|
||||
asm volatile("sync;isync");
|
||||
|
||||
out_be32(&ddr->sdram_cfg, regs->ddr_sdram_cfg);
|
||||
|
||||
asm("sync;isync;msync");
|
||||
udelay(500);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DDR_ECC) && !defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER)
|
||||
/*
|
||||
* Initialize all of memory for ECC, then enable errors.
|
||||
*/
|
||||
|
||||
void
|
||||
ddr_enable_ecc(unsigned int dram_size)
|
||||
{
|
||||
struct ccsr_ddr __iomem *ddr =
|
||||
(struct ccsr_ddr __iomem *)(CONFIG_SYS_FSL_DDR_ADDR);
|
||||
|
||||
dma_meminit(CONFIG_MEM_INIT_VALUE, dram_size);
|
||||
|
||||
/*
|
||||
* Enable errors for ECC.
|
||||
*/
|
||||
debug("DMA DDR: err_disable = 0x%08x\n", ddr->err_disable);
|
||||
ddr->err_disable = 0x00000000;
|
||||
asm("sync;isync;msync");
|
||||
debug("DMA DDR: err_disable = 0x%08x\n", ddr->err_disable);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DDR_ECC && ! CONFIG_ECC_INIT_VIA_DDRCONTROLLER */
|
||||
94
u-boot/drivers/ddr/fsl/mpc85xx_ddr_gen2.c
Normal file
94
u-boot/drivers/ddr/fsl/mpc85xx_ddr_gen2.c
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2008-2011 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/processor.h>
|
||||
#include <fsl_ddr_sdram.h>
|
||||
|
||||
#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4)
|
||||
#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL
|
||||
#endif
|
||||
|
||||
void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
|
||||
unsigned int ctrl_num, int step)
|
||||
{
|
||||
unsigned int i;
|
||||
struct ccsr_ddr __iomem *ddr =
|
||||
(struct ccsr_ddr __iomem *)CONFIG_SYS_FSL_DDR_ADDR;
|
||||
|
||||
#if defined(CONFIG_SYS_FSL_ERRATUM_NMG_DDR120) && defined(CONFIG_MPC85xx)
|
||||
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
uint svr;
|
||||
#endif
|
||||
|
||||
if (ctrl_num) {
|
||||
printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_NMG_DDR120
|
||||
/*
|
||||
* Set the DDR IO receiver to an acceptable bias point.
|
||||
* Fixed in Rev 2.1.
|
||||
*/
|
||||
svr = get_svr();
|
||||
if ((SVR_MAJ(svr) == 1) || IS_SVR_REV(svr, 2, 0)) {
|
||||
if ((regs->ddr_sdram_cfg & SDRAM_CFG_SDRAM_TYPE_MASK) ==
|
||||
SDRAM_CFG_SDRAM_TYPE_DDR2)
|
||||
out_be32(&gur->ddrioovcr, 0x90000000);
|
||||
else
|
||||
out_be32(&gur->ddrioovcr, 0xA8000000);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
|
||||
if (i == 0) {
|
||||
out_be32(&ddr->cs0_bnds, regs->cs[i].bnds);
|
||||
out_be32(&ddr->cs0_config, regs->cs[i].config);
|
||||
|
||||
} else if (i == 1) {
|
||||
out_be32(&ddr->cs1_bnds, regs->cs[i].bnds);
|
||||
out_be32(&ddr->cs1_config, regs->cs[i].config);
|
||||
|
||||
} else if (i == 2) {
|
||||
out_be32(&ddr->cs2_bnds, regs->cs[i].bnds);
|
||||
out_be32(&ddr->cs2_config, regs->cs[i].config);
|
||||
|
||||
} else if (i == 3) {
|
||||
out_be32(&ddr->cs3_bnds, regs->cs[i].bnds);
|
||||
out_be32(&ddr->cs3_config, regs->cs[i].config);
|
||||
}
|
||||
}
|
||||
|
||||
out_be32(&ddr->timing_cfg_3, regs->timing_cfg_3);
|
||||
out_be32(&ddr->timing_cfg_0, regs->timing_cfg_0);
|
||||
out_be32(&ddr->timing_cfg_1, regs->timing_cfg_1);
|
||||
out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2);
|
||||
out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2);
|
||||
out_be32(&ddr->sdram_mode, regs->ddr_sdram_mode);
|
||||
out_be32(&ddr->sdram_mode_2, regs->ddr_sdram_mode_2);
|
||||
out_be32(&ddr->sdram_md_cntl, regs->ddr_sdram_md_cntl);
|
||||
out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval);
|
||||
out_be32(&ddr->sdram_data_init, regs->ddr_data_init);
|
||||
out_be32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl);
|
||||
out_be32(&ddr->init_addr, regs->ddr_init_addr);
|
||||
out_be32(&ddr->init_ext_addr, regs->ddr_init_ext_addr);
|
||||
|
||||
/*
|
||||
* 200 painful micro-seconds must elapse between
|
||||
* the DDR clock setup and the DDR config enable.
|
||||
*/
|
||||
udelay(200);
|
||||
asm volatile("sync;isync");
|
||||
|
||||
out_be32(&ddr->sdram_cfg, regs->ddr_sdram_cfg);
|
||||
|
||||
/* Poll DDR_SDRAM_CFG_2[D_INIT] bit until auto-data init is done. */
|
||||
while (in_be32(&ddr->sdram_cfg_2) & 0x10) {
|
||||
udelay(10000); /* throttle polling rate */
|
||||
}
|
||||
}
|
||||
556
u-boot/drivers/ddr/fsl/mpc85xx_ddr_gen3.c
Normal file
556
u-boot/drivers/ddr/fsl/mpc85xx_ddr_gen3.c
Normal file
@@ -0,0 +1,556 @@
|
||||
/*
|
||||
* Copyright 2008-2012 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <fsl_ddr_sdram.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4)
|
||||
#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL
|
||||
#endif
|
||||
|
||||
/*
|
||||
* regs has the to-be-set values for DDR controller registers
|
||||
* ctrl_num is the DDR controller number
|
||||
* step: 0 goes through the initialization in one pass
|
||||
* 1 sets registers and returns before enabling controller
|
||||
* 2 resumes from step 1 and continues to initialize
|
||||
* Dividing the initialization to two steps to deassert DDR reset signal
|
||||
* to comply with JEDEC specs for RDIMMs.
|
||||
*/
|
||||
void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
|
||||
unsigned int ctrl_num, int step)
|
||||
{
|
||||
unsigned int i, bus_width;
|
||||
struct ccsr_ddr __iomem *ddr;
|
||||
u32 temp_sdram_cfg;
|
||||
u32 total_gb_size_per_controller;
|
||||
int timeout;
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134
|
||||
int timeout_save;
|
||||
volatile ccsr_local_ecm_t *ecm = (void *)CONFIG_SYS_MPC85xx_ECM_ADDR;
|
||||
unsigned int csn_bnds_backup = 0, cs_sa, cs_ea, *csn_bnds_t;
|
||||
int csn = -1;
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_DDR_A003
|
||||
u32 save1, save2;
|
||||
#endif
|
||||
|
||||
switch (ctrl_num) {
|
||||
case 0:
|
||||
ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR;
|
||||
break;
|
||||
#if defined(CONFIG_SYS_FSL_DDR2_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 1)
|
||||
case 1:
|
||||
ddr = (void *)CONFIG_SYS_FSL_DDR2_ADDR;
|
||||
break;
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_FSL_DDR3_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 2)
|
||||
case 2:
|
||||
ddr = (void *)CONFIG_SYS_FSL_DDR3_ADDR;
|
||||
break;
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_FSL_DDR4_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 3)
|
||||
case 3:
|
||||
ddr = (void *)CONFIG_SYS_FSL_DDR4_ADDR;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num);
|
||||
return;
|
||||
}
|
||||
|
||||
if (step == 2)
|
||||
goto step2;
|
||||
|
||||
if (regs->ddr_eor)
|
||||
out_be32(&ddr->eor, regs->ddr_eor);
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134
|
||||
debug("Workaround for ERRATUM_DDR111_DDR134\n");
|
||||
for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
|
||||
cs_sa = (regs->cs[i].bnds >> 16) & 0xfff;
|
||||
cs_ea = regs->cs[i].bnds & 0xfff;
|
||||
if ((cs_sa <= 0xff) && (cs_ea >= 0xff)) {
|
||||
csn = i;
|
||||
csn_bnds_backup = regs->cs[i].bnds;
|
||||
csn_bnds_t = (unsigned int *) ®s->cs[i].bnds;
|
||||
if (cs_ea > 0xeff)
|
||||
*csn_bnds_t = regs->cs[i].bnds + 0x01000000;
|
||||
else
|
||||
*csn_bnds_t = regs->cs[i].bnds + 0x01000100;
|
||||
debug("Found cs%d_bns (0x%08x) covering 0xff000000, "
|
||||
"change it to 0x%x\n",
|
||||
csn, csn_bnds_backup, regs->cs[i].bnds);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
|
||||
if (i == 0) {
|
||||
out_be32(&ddr->cs0_bnds, regs->cs[i].bnds);
|
||||
out_be32(&ddr->cs0_config, regs->cs[i].config);
|
||||
out_be32(&ddr->cs0_config_2, regs->cs[i].config_2);
|
||||
|
||||
} else if (i == 1) {
|
||||
out_be32(&ddr->cs1_bnds, regs->cs[i].bnds);
|
||||
out_be32(&ddr->cs1_config, regs->cs[i].config);
|
||||
out_be32(&ddr->cs1_config_2, regs->cs[i].config_2);
|
||||
|
||||
} else if (i == 2) {
|
||||
out_be32(&ddr->cs2_bnds, regs->cs[i].bnds);
|
||||
out_be32(&ddr->cs2_config, regs->cs[i].config);
|
||||
out_be32(&ddr->cs2_config_2, regs->cs[i].config_2);
|
||||
|
||||
} else if (i == 3) {
|
||||
out_be32(&ddr->cs3_bnds, regs->cs[i].bnds);
|
||||
out_be32(&ddr->cs3_config, regs->cs[i].config);
|
||||
out_be32(&ddr->cs3_config_2, regs->cs[i].config_2);
|
||||
}
|
||||
}
|
||||
|
||||
out_be32(&ddr->timing_cfg_3, regs->timing_cfg_3);
|
||||
out_be32(&ddr->timing_cfg_0, regs->timing_cfg_0);
|
||||
out_be32(&ddr->timing_cfg_1, regs->timing_cfg_1);
|
||||
out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2);
|
||||
out_be32(&ddr->sdram_mode, regs->ddr_sdram_mode);
|
||||
out_be32(&ddr->sdram_mode_2, regs->ddr_sdram_mode_2);
|
||||
out_be32(&ddr->sdram_mode_3, regs->ddr_sdram_mode_3);
|
||||
out_be32(&ddr->sdram_mode_4, regs->ddr_sdram_mode_4);
|
||||
out_be32(&ddr->sdram_mode_5, regs->ddr_sdram_mode_5);
|
||||
out_be32(&ddr->sdram_mode_6, regs->ddr_sdram_mode_6);
|
||||
out_be32(&ddr->sdram_mode_7, regs->ddr_sdram_mode_7);
|
||||
out_be32(&ddr->sdram_mode_8, regs->ddr_sdram_mode_8);
|
||||
out_be32(&ddr->sdram_md_cntl, regs->ddr_sdram_md_cntl);
|
||||
out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval);
|
||||
out_be32(&ddr->sdram_data_init, regs->ddr_data_init);
|
||||
out_be32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl);
|
||||
out_be32(&ddr->timing_cfg_4, regs->timing_cfg_4);
|
||||
out_be32(&ddr->timing_cfg_5, regs->timing_cfg_5);
|
||||
out_be32(&ddr->ddr_zq_cntl, regs->ddr_zq_cntl);
|
||||
out_be32(&ddr->ddr_wrlvl_cntl, regs->ddr_wrlvl_cntl);
|
||||
#ifndef CONFIG_SYS_FSL_DDR_EMU
|
||||
/*
|
||||
* Skip these two registers if running on emulator
|
||||
* because emulator doesn't have skew between bytes.
|
||||
*/
|
||||
|
||||
if (regs->ddr_wrlvl_cntl_2)
|
||||
out_be32(&ddr->ddr_wrlvl_cntl_2, regs->ddr_wrlvl_cntl_2);
|
||||
if (regs->ddr_wrlvl_cntl_3)
|
||||
out_be32(&ddr->ddr_wrlvl_cntl_3, regs->ddr_wrlvl_cntl_3);
|
||||
#endif
|
||||
|
||||
out_be32(&ddr->ddr_sr_cntr, regs->ddr_sr_cntr);
|
||||
out_be32(&ddr->ddr_sdram_rcw_1, regs->ddr_sdram_rcw_1);
|
||||
out_be32(&ddr->ddr_sdram_rcw_2, regs->ddr_sdram_rcw_2);
|
||||
out_be32(&ddr->ddr_cdr1, regs->ddr_cdr1);
|
||||
#ifdef CONFIG_DEEP_SLEEP
|
||||
if (is_warm_boot()) {
|
||||
out_be32(&ddr->sdram_cfg_2,
|
||||
regs->ddr_sdram_cfg_2 & ~SDRAM_CFG2_D_INIT);
|
||||
out_be32(&ddr->init_addr, CONFIG_SYS_SDRAM_BASE);
|
||||
out_be32(&ddr->init_ext_addr, DDR_INIT_ADDR_EXT_UIA);
|
||||
|
||||
/* DRAM VRef will not be trained */
|
||||
out_be32(&ddr->ddr_cdr2,
|
||||
regs->ddr_cdr2 & ~DDR_CDR2_VREF_TRAIN_EN);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2);
|
||||
out_be32(&ddr->init_addr, regs->ddr_init_addr);
|
||||
out_be32(&ddr->init_ext_addr, regs->ddr_init_ext_addr);
|
||||
out_be32(&ddr->ddr_cdr2, regs->ddr_cdr2);
|
||||
}
|
||||
out_be32(&ddr->err_disable, regs->err_disable);
|
||||
out_be32(&ddr->err_int_en, regs->err_int_en);
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (regs->debug[i]) {
|
||||
debug("Write to debug_%d as %08x\n", i+1, regs->debug[i]);
|
||||
out_be32(&ddr->debug[i], regs->debug[i]);
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A_004934
|
||||
out_be32(&ddr->debug[28], 0x30003000);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_DDR_A003474
|
||||
out_be32(&ddr->debug[12], 0x00000015);
|
||||
out_be32(&ddr->debug[21], 0x24000000);
|
||||
#endif /* CONFIG_SYS_FSL_ERRATUM_DDR_A003474 */
|
||||
|
||||
/*
|
||||
* For RDIMMs, JEDEC spec requires clocks to be stable before reset is
|
||||
* deasserted. Clocks start when any chip select is enabled and clock
|
||||
* control register is set. Because all DDR components are connected to
|
||||
* one reset signal, this needs to be done in two steps. Step 1 is to
|
||||
* get the clocks started. Step 2 resumes after reset signal is
|
||||
* deasserted.
|
||||
*/
|
||||
if (step == 1) {
|
||||
udelay(200);
|
||||
return;
|
||||
}
|
||||
|
||||
step2:
|
||||
/* Set, but do not enable the memory */
|
||||
temp_sdram_cfg = regs->ddr_sdram_cfg;
|
||||
temp_sdram_cfg &= ~(SDRAM_CFG_MEM_EN);
|
||||
out_be32(&ddr->sdram_cfg, temp_sdram_cfg);
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_DDR_A003
|
||||
debug("Workaround for ERRATUM_DDR_A003\n");
|
||||
if (regs->ddr_sdram_rcw_2 & 0x00f00000) {
|
||||
out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2 & 0xf07fffff);
|
||||
out_be32(&ddr->debug[2], 0x00000400);
|
||||
out_be32(&ddr->ddr_zq_cntl, regs->ddr_zq_cntl & 0x7fffffff);
|
||||
out_be32(&ddr->ddr_wrlvl_cntl, regs->ddr_wrlvl_cntl & 0x7fffffff);
|
||||
out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2 & 0xffffffeb);
|
||||
out_be32(&ddr->mtcr, 0);
|
||||
save1 = in_be32(&ddr->debug[12]);
|
||||
save2 = in_be32(&ddr->debug[21]);
|
||||
out_be32(&ddr->debug[12], 0x00000015);
|
||||
out_be32(&ddr->debug[21], 0x24000000);
|
||||
out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval & 0xffff);
|
||||
out_be32(&ddr->sdram_cfg, temp_sdram_cfg | SDRAM_CFG_BI | SDRAM_CFG_MEM_EN);
|
||||
|
||||
asm volatile("sync;isync");
|
||||
while (!(in_be32(&ddr->debug[1]) & 0x2))
|
||||
;
|
||||
|
||||
switch (regs->ddr_sdram_rcw_2 & 0x00f00000) {
|
||||
case 0x00000000:
|
||||
out_be32(&ddr->sdram_md_cntl,
|
||||
MD_CNTL_MD_EN |
|
||||
MD_CNTL_CS_SEL_CS0_CS1 |
|
||||
0x04000000 |
|
||||
MD_CNTL_WRCW |
|
||||
MD_CNTL_MD_VALUE(0x02));
|
||||
#if (CONFIG_DIMM_SLOTS_PER_CTLR == 2)
|
||||
if (!(regs->cs[2].config & SDRAM_CS_CONFIG_EN))
|
||||
break;
|
||||
while (in_be32(&ddr->sdram_md_cntl) & MD_CNTL_MD_EN)
|
||||
;
|
||||
out_be32(&ddr->sdram_md_cntl,
|
||||
MD_CNTL_MD_EN |
|
||||
MD_CNTL_CS_SEL_CS2_CS3 |
|
||||
0x04000000 |
|
||||
MD_CNTL_WRCW |
|
||||
MD_CNTL_MD_VALUE(0x02));
|
||||
#endif
|
||||
break;
|
||||
case 0x00100000:
|
||||
out_be32(&ddr->sdram_md_cntl,
|
||||
MD_CNTL_MD_EN |
|
||||
MD_CNTL_CS_SEL_CS0_CS1 |
|
||||
0x04000000 |
|
||||
MD_CNTL_WRCW |
|
||||
MD_CNTL_MD_VALUE(0x0a));
|
||||
#if (CONFIG_DIMM_SLOTS_PER_CTLR == 2)
|
||||
if (!(regs->cs[2].config & SDRAM_CS_CONFIG_EN))
|
||||
break;
|
||||
while (in_be32(&ddr->sdram_md_cntl) & MD_CNTL_MD_EN)
|
||||
;
|
||||
out_be32(&ddr->sdram_md_cntl,
|
||||
MD_CNTL_MD_EN |
|
||||
MD_CNTL_CS_SEL_CS2_CS3 |
|
||||
0x04000000 |
|
||||
MD_CNTL_WRCW |
|
||||
MD_CNTL_MD_VALUE(0x0a));
|
||||
#endif
|
||||
break;
|
||||
case 0x00200000:
|
||||
out_be32(&ddr->sdram_md_cntl,
|
||||
MD_CNTL_MD_EN |
|
||||
MD_CNTL_CS_SEL_CS0_CS1 |
|
||||
0x04000000 |
|
||||
MD_CNTL_WRCW |
|
||||
MD_CNTL_MD_VALUE(0x12));
|
||||
#if (CONFIG_DIMM_SLOTS_PER_CTLR == 2)
|
||||
if (!(regs->cs[2].config & SDRAM_CS_CONFIG_EN))
|
||||
break;
|
||||
while (in_be32(&ddr->sdram_md_cntl) & MD_CNTL_MD_EN)
|
||||
;
|
||||
out_be32(&ddr->sdram_md_cntl,
|
||||
MD_CNTL_MD_EN |
|
||||
MD_CNTL_CS_SEL_CS2_CS3 |
|
||||
0x04000000 |
|
||||
MD_CNTL_WRCW |
|
||||
MD_CNTL_MD_VALUE(0x12));
|
||||
#endif
|
||||
break;
|
||||
case 0x00300000:
|
||||
out_be32(&ddr->sdram_md_cntl,
|
||||
MD_CNTL_MD_EN |
|
||||
MD_CNTL_CS_SEL_CS0_CS1 |
|
||||
0x04000000 |
|
||||
MD_CNTL_WRCW |
|
||||
MD_CNTL_MD_VALUE(0x1a));
|
||||
#if (CONFIG_DIMM_SLOTS_PER_CTLR == 2)
|
||||
if (!(regs->cs[2].config & SDRAM_CS_CONFIG_EN))
|
||||
break;
|
||||
while (in_be32(&ddr->sdram_md_cntl) & MD_CNTL_MD_EN)
|
||||
;
|
||||
out_be32(&ddr->sdram_md_cntl,
|
||||
MD_CNTL_MD_EN |
|
||||
MD_CNTL_CS_SEL_CS2_CS3 |
|
||||
0x04000000 |
|
||||
MD_CNTL_WRCW |
|
||||
MD_CNTL_MD_VALUE(0x1a));
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
out_be32(&ddr->sdram_md_cntl,
|
||||
MD_CNTL_MD_EN |
|
||||
MD_CNTL_CS_SEL_CS0_CS1 |
|
||||
0x04000000 |
|
||||
MD_CNTL_WRCW |
|
||||
MD_CNTL_MD_VALUE(0x02));
|
||||
#if (CONFIG_DIMM_SLOTS_PER_CTLR == 2)
|
||||
if (!(regs->cs[2].config & SDRAM_CS_CONFIG_EN))
|
||||
break;
|
||||
while (in_be32(&ddr->sdram_md_cntl) & MD_CNTL_MD_EN)
|
||||
;
|
||||
out_be32(&ddr->sdram_md_cntl,
|
||||
MD_CNTL_MD_EN |
|
||||
MD_CNTL_CS_SEL_CS2_CS3 |
|
||||
0x04000000 |
|
||||
MD_CNTL_WRCW |
|
||||
MD_CNTL_MD_VALUE(0x02));
|
||||
#endif
|
||||
printf("Unsupported RC10\n");
|
||||
break;
|
||||
}
|
||||
|
||||
while (in_be32(&ddr->sdram_md_cntl) & 0x80000000)
|
||||
;
|
||||
udelay(6);
|
||||
out_be32(&ddr->sdram_cfg, temp_sdram_cfg);
|
||||
out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2);
|
||||
out_be32(&ddr->debug[2], 0x0);
|
||||
out_be32(&ddr->ddr_zq_cntl, regs->ddr_zq_cntl);
|
||||
out_be32(&ddr->ddr_wrlvl_cntl, regs->ddr_wrlvl_cntl);
|
||||
out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2);
|
||||
out_be32(&ddr->debug[12], save1);
|
||||
out_be32(&ddr->debug[21], save2);
|
||||
out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval);
|
||||
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* For 8572 DDR1 erratum - DDR controller may enter illegal state
|
||||
* when operatiing in 32-bit bus mode with 4-beat bursts,
|
||||
* This erratum does not affect DDR3 mode, only for DDR2 mode.
|
||||
*/
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_DDR_115
|
||||
debug("Workaround for ERRATUM_DDR_115\n");
|
||||
if ((((in_be32(&ddr->sdram_cfg) >> 24) & 0x7) == SDRAM_TYPE_DDR2)
|
||||
&& in_be32(&ddr->sdram_cfg) & 0x80000) {
|
||||
/* set DEBUG_1[31] */
|
||||
setbits_be32(&ddr->debug[0], 1);
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134
|
||||
debug("Workaround for ERRATUM_DDR111_DDR134\n");
|
||||
/*
|
||||
* This is the combined workaround for DDR111 and DDR134
|
||||
* following the published errata for MPC8572
|
||||
*/
|
||||
|
||||
/* 1. Set EEBACR[3] */
|
||||
setbits_be32(&ecm->eebacr, 0x10000000);
|
||||
debug("Setting EEBACR[3] to 0x%08x\n", in_be32(&ecm->eebacr));
|
||||
|
||||
/* 2. Set DINIT in SDRAM_CFG_2*/
|
||||
setbits_be32(&ddr->sdram_cfg_2, SDRAM_CFG2_D_INIT);
|
||||
debug("Setting sdram_cfg_2[D_INIT] to 0x%08x\n",
|
||||
in_be32(&ddr->sdram_cfg_2));
|
||||
|
||||
/* 3. Set DEBUG_3[21] */
|
||||
setbits_be32(&ddr->debug[2], 0x400);
|
||||
debug("Setting DEBUG_3[21] to 0x%08x\n", in_be32(&ddr->debug[2]));
|
||||
|
||||
#endif /* part 1 of the workaound */
|
||||
|
||||
/*
|
||||
* 500 painful micro-seconds must elapse between
|
||||
* the DDR clock setup and the DDR config enable.
|
||||
* DDR2 need 200 us, and DDR3 need 500 us from spec,
|
||||
* we choose the max, that is 500 us for all of case.
|
||||
*/
|
||||
udelay(500);
|
||||
asm volatile("sync;isync");
|
||||
|
||||
#ifdef CONFIG_DEEP_SLEEP
|
||||
if (is_warm_boot()) {
|
||||
/* enter self-refresh */
|
||||
setbits_be32(&ddr->sdram_cfg_2, SDRAM_CFG2_FRC_SR);
|
||||
/* do board specific memory setup */
|
||||
board_mem_sleep_setup();
|
||||
temp_sdram_cfg = (in_be32(&ddr->sdram_cfg) | SDRAM_CFG_BI);
|
||||
} else
|
||||
#endif
|
||||
temp_sdram_cfg = (in_be32(&ddr->sdram_cfg) & ~SDRAM_CFG_BI);
|
||||
|
||||
/* Let the controller go */
|
||||
out_be32(&ddr->sdram_cfg, temp_sdram_cfg | SDRAM_CFG_MEM_EN);
|
||||
asm volatile("sync;isync");
|
||||
|
||||
total_gb_size_per_controller = 0;
|
||||
for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
|
||||
if (!(regs->cs[i].config & 0x80000000))
|
||||
continue;
|
||||
total_gb_size_per_controller += 1 << (
|
||||
((regs->cs[i].config >> 14) & 0x3) + 2 +
|
||||
((regs->cs[i].config >> 8) & 0x7) + 12 +
|
||||
((regs->cs[i].config >> 0) & 0x7) + 8 +
|
||||
3 - ((regs->ddr_sdram_cfg >> 19) & 0x3) -
|
||||
26); /* minus 26 (count of 64M) */
|
||||
}
|
||||
if (fsl_ddr_get_intl3r() & 0x80000000) /* 3-way interleaving */
|
||||
total_gb_size_per_controller *= 3;
|
||||
else if (regs->cs[0].config & 0x20000000) /* 2-way interleaving */
|
||||
total_gb_size_per_controller <<= 1;
|
||||
/*
|
||||
* total memory / bus width = transactions needed
|
||||
* transactions needed / data rate = seconds
|
||||
* to add plenty of buffer, double the time
|
||||
* For example, 2GB on 666MT/s 64-bit bus takes about 402ms
|
||||
* Let's wait for 800ms
|
||||
*/
|
||||
bus_width = 3 - ((ddr->sdram_cfg & SDRAM_CFG_DBW_MASK)
|
||||
>> SDRAM_CFG_DBW_SHIFT);
|
||||
timeout = ((total_gb_size_per_controller << (6 - bus_width)) * 100 /
|
||||
(get_ddr_freq(ctrl_num) >> 20)) << 1;
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134
|
||||
timeout_save = timeout;
|
||||
#endif
|
||||
total_gb_size_per_controller >>= 4; /* shift down to gb size */
|
||||
debug("total %d GB\n", total_gb_size_per_controller);
|
||||
debug("Need to wait up to %d * 10ms\n", timeout);
|
||||
|
||||
/* Poll DDR_SDRAM_CFG_2[D_INIT] bit until auto-data init is done. */
|
||||
while ((in_be32(&ddr->sdram_cfg_2) & SDRAM_CFG2_D_INIT) &&
|
||||
(timeout >= 0)) {
|
||||
udelay(10000); /* throttle polling rate */
|
||||
timeout--;
|
||||
}
|
||||
|
||||
if (timeout <= 0)
|
||||
printf("Waiting for D_INIT timeout. Memory may not work.\n");
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134
|
||||
/* continue this workaround */
|
||||
|
||||
/* 4. Clear DEBUG3[21] */
|
||||
clrbits_be32(&ddr->debug[2], 0x400);
|
||||
debug("Clearing D3[21] to 0x%08x\n", in_be32(&ddr->debug[2]));
|
||||
|
||||
/* DDR134 workaround starts */
|
||||
/* A: Clear sdram_cfg_2[odt_cfg] */
|
||||
clrbits_be32(&ddr->sdram_cfg_2, SDRAM_CFG2_ODT_CFG_MASK);
|
||||
debug("Clearing SDRAM_CFG2[ODT_CFG] to 0x%08x\n",
|
||||
in_be32(&ddr->sdram_cfg_2));
|
||||
|
||||
/* B: Set DEBUG1[15] */
|
||||
setbits_be32(&ddr->debug[0], 0x10000);
|
||||
debug("Setting D1[15] to 0x%08x\n", in_be32(&ddr->debug[0]));
|
||||
|
||||
/* C: Set timing_cfg_2[cpo] to 0b11111 */
|
||||
setbits_be32(&ddr->timing_cfg_2, TIMING_CFG_2_CPO_MASK);
|
||||
debug("Setting TMING_CFG_2[CPO] to 0x%08x\n",
|
||||
in_be32(&ddr->timing_cfg_2));
|
||||
|
||||
/* D: Set D6 to 0x9f9f9f9f */
|
||||
out_be32(&ddr->debug[5], 0x9f9f9f9f);
|
||||
debug("Setting D6 to 0x%08x\n", in_be32(&ddr->debug[5]));
|
||||
|
||||
/* E: Set D7 to 0x9f9f9f9f */
|
||||
out_be32(&ddr->debug[6], 0x9f9f9f9f);
|
||||
debug("Setting D7 to 0x%08x\n", in_be32(&ddr->debug[6]));
|
||||
|
||||
/* F: Set D2[20] */
|
||||
setbits_be32(&ddr->debug[1], 0x800);
|
||||
debug("Setting D2[20] to 0x%08x\n", in_be32(&ddr->debug[1]));
|
||||
|
||||
/* G: Poll on D2[20] until cleared */
|
||||
while (in_be32(&ddr->debug[1]) & 0x800)
|
||||
udelay(10000); /* throttle polling rate */
|
||||
|
||||
/* H: Clear D1[15] */
|
||||
clrbits_be32(&ddr->debug[0], 0x10000);
|
||||
debug("Setting D1[15] to 0x%08x\n", in_be32(&ddr->debug[0]));
|
||||
|
||||
/* I: Set sdram_cfg_2[odt_cfg] */
|
||||
setbits_be32(&ddr->sdram_cfg_2,
|
||||
regs->ddr_sdram_cfg_2 & SDRAM_CFG2_ODT_CFG_MASK);
|
||||
debug("Setting sdram_cfg_2 to 0x%08x\n", in_be32(&ddr->sdram_cfg_2));
|
||||
|
||||
/* Continuing with the DDR111 workaround */
|
||||
/* 5. Set D2[21] */
|
||||
setbits_be32(&ddr->debug[1], 0x400);
|
||||
debug("Setting D2[21] to 0x%08x\n", in_be32(&ddr->debug[1]));
|
||||
|
||||
/* 6. Poll D2[21] until its cleared */
|
||||
while (in_be32(&ddr->debug[1]) & 0x400)
|
||||
udelay(10000); /* throttle polling rate */
|
||||
|
||||
/* 7. Wait for state machine 2nd run, roughly 400ms/GB */
|
||||
debug("Wait for %d * 10ms\n", timeout_save);
|
||||
udelay(timeout_save * 10000);
|
||||
|
||||
/* 8. Set sdram_cfg_2[dinit] if options requires */
|
||||
setbits_be32(&ddr->sdram_cfg_2,
|
||||
regs->ddr_sdram_cfg_2 & SDRAM_CFG2_D_INIT);
|
||||
debug("Setting sdram_cfg_2 to 0x%08x\n", in_be32(&ddr->sdram_cfg_2));
|
||||
|
||||
/* 9. Poll until dinit is cleared */
|
||||
timeout = timeout_save;
|
||||
debug("Need to wait up to %d * 10ms\n", timeout);
|
||||
while ((in_be32(&ddr->sdram_cfg_2) & SDRAM_CFG2_D_INIT) &&
|
||||
(timeout >= 0)) {
|
||||
udelay(10000); /* throttle polling rate */
|
||||
timeout--;
|
||||
}
|
||||
|
||||
if (timeout <= 0)
|
||||
printf("Waiting for D_INIT timeout. Memory may not work.\n");
|
||||
|
||||
/* 10. Clear EEBACR[3] */
|
||||
clrbits_be32(&ecm->eebacr, 10000000);
|
||||
debug("Clearing EEBACR[3] to 0x%08x\n", in_be32(&ecm->eebacr));
|
||||
|
||||
if (csn != -1) {
|
||||
csn_bnds_t = (unsigned int *) ®s->cs[csn].bnds;
|
||||
*csn_bnds_t = csn_bnds_backup;
|
||||
debug("Change cs%d_bnds back to 0x%08x\n",
|
||||
csn, regs->cs[csn].bnds);
|
||||
setbits_be32(&ddr->sdram_cfg, 0x2); /* MEM_HALT */
|
||||
switch (csn) {
|
||||
case 0:
|
||||
out_be32(&ddr->cs0_bnds, regs->cs[csn].bnds);
|
||||
break;
|
||||
case 1:
|
||||
out_be32(&ddr->cs1_bnds, regs->cs[csn].bnds);
|
||||
break;
|
||||
#if CONFIG_CHIP_SELECTS_PER_CTRL > 2
|
||||
case 2:
|
||||
out_be32(&ddr->cs2_bnds, regs->cs[csn].bnds);
|
||||
break;
|
||||
case 3:
|
||||
out_be32(&ddr->cs3_bnds, regs->cs[csn].bnds);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
clrbits_be32(&ddr->sdram_cfg, 0x2);
|
||||
}
|
||||
#endif /* CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134 */
|
||||
#ifdef CONFIG_DEEP_SLEEP
|
||||
if (is_warm_boot())
|
||||
/* exit self-refresh */
|
||||
clrbits_be32(&ddr->sdram_cfg_2, SDRAM_CFG2_FRC_SR);
|
||||
#endif
|
||||
}
|
||||
83
u-boot/drivers/ddr/fsl/mpc86xx_ddr.c
Normal file
83
u-boot/drivers/ddr/fsl/mpc86xx_ddr.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2008 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <fsl_ddr_sdram.h>
|
||||
|
||||
#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4)
|
||||
#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL
|
||||
#endif
|
||||
|
||||
void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
|
||||
unsigned int ctrl_num, int step)
|
||||
{
|
||||
unsigned int i;
|
||||
struct ccsr_ddr __iomem *ddr;
|
||||
|
||||
switch (ctrl_num) {
|
||||
case 0:
|
||||
ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR;
|
||||
break;
|
||||
case 1:
|
||||
ddr = (void *)CONFIG_SYS_FSL_DDR2_ADDR;
|
||||
break;
|
||||
default:
|
||||
printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
|
||||
if (i == 0) {
|
||||
out_be32(&ddr->cs0_bnds, regs->cs[i].bnds);
|
||||
out_be32(&ddr->cs0_config, regs->cs[i].config);
|
||||
|
||||
} else if (i == 1) {
|
||||
out_be32(&ddr->cs1_bnds, regs->cs[i].bnds);
|
||||
out_be32(&ddr->cs1_config, regs->cs[i].config);
|
||||
|
||||
} else if (i == 2) {
|
||||
out_be32(&ddr->cs2_bnds, regs->cs[i].bnds);
|
||||
out_be32(&ddr->cs2_config, regs->cs[i].config);
|
||||
|
||||
} else if (i == 3) {
|
||||
out_be32(&ddr->cs3_bnds, regs->cs[i].bnds);
|
||||
out_be32(&ddr->cs3_config, regs->cs[i].config);
|
||||
}
|
||||
}
|
||||
|
||||
out_be32(&ddr->timing_cfg_3, regs->timing_cfg_3);
|
||||
out_be32(&ddr->timing_cfg_0, regs->timing_cfg_0);
|
||||
out_be32(&ddr->timing_cfg_1, regs->timing_cfg_1);
|
||||
out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2);
|
||||
out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2);
|
||||
out_be32(&ddr->sdram_mode, regs->ddr_sdram_mode);
|
||||
out_be32(&ddr->sdram_mode_2, regs->ddr_sdram_mode_2);
|
||||
out_be32(&ddr->sdram_md_cntl, regs->ddr_sdram_md_cntl);
|
||||
out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval);
|
||||
out_be32(&ddr->sdram_data_init, regs->ddr_data_init);
|
||||
out_be32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl);
|
||||
out_be32(&ddr->init_addr, regs->ddr_init_addr);
|
||||
out_be32(&ddr->init_ext_addr, regs->ddr_init_ext_addr);
|
||||
|
||||
debug("before go\n");
|
||||
|
||||
/*
|
||||
* 200 painful micro-seconds must elapse between
|
||||
* the DDR clock setup and the DDR config enable.
|
||||
*/
|
||||
udelay(200);
|
||||
asm volatile("sync;isync");
|
||||
|
||||
out_be32(&ddr->sdram_cfg, regs->ddr_sdram_cfg);
|
||||
|
||||
/*
|
||||
* Poll DDR_SDRAM_CFG_2[D_INIT] bit until auto-data init is done
|
||||
*/
|
||||
while (in_be32(&ddr->sdram_cfg_2) & 0x10) {
|
||||
udelay(10000); /* throttle polling rate */
|
||||
}
|
||||
}
|
||||
1415
u-boot/drivers/ddr/fsl/options.c
Normal file
1415
u-boot/drivers/ddr/fsl/options.c
Normal file
File diff suppressed because it is too large
Load Diff
425
u-boot/drivers/ddr/fsl/util.c
Normal file
425
u-boot/drivers/ddr/fsl/util.c
Normal file
@@ -0,0 +1,425 @@
|
||||
/*
|
||||
* Copyright 2008-2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#ifdef CONFIG_PPC
|
||||
#include <asm/fsl_law.h>
|
||||
#endif
|
||||
#include <div64.h>
|
||||
|
||||
#include <fsl_ddr.h>
|
||||
#include <fsl_immap.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/* To avoid 64-bit full-divides, we factor this here */
|
||||
#define ULL_2E12 2000000000000ULL
|
||||
#define UL_5POW12 244140625UL
|
||||
#define UL_2POW13 (1UL << 13)
|
||||
|
||||
#define ULL_8FS 0xFFFFFFFFULL
|
||||
|
||||
u32 fsl_ddr_get_version(unsigned int ctrl_num)
|
||||
{
|
||||
struct ccsr_ddr __iomem *ddr;
|
||||
u32 ver_major_minor_errata;
|
||||
|
||||
switch (ctrl_num) {
|
||||
case 0:
|
||||
ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR;
|
||||
break;
|
||||
#if defined(CONFIG_SYS_FSL_DDR2_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 1)
|
||||
case 1:
|
||||
ddr = (void *)CONFIG_SYS_FSL_DDR2_ADDR;
|
||||
break;
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_FSL_DDR3_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 2)
|
||||
case 2:
|
||||
ddr = (void *)CONFIG_SYS_FSL_DDR3_ADDR;
|
||||
break;
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_FSL_DDR4_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 3)
|
||||
case 3:
|
||||
ddr = (void *)CONFIG_SYS_FSL_DDR4_ADDR;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
printf("%s unexpected ctrl_num = %u\n", __func__, ctrl_num);
|
||||
return 0;
|
||||
}
|
||||
ver_major_minor_errata = (ddr_in32(&ddr->ip_rev1) & 0xFFFF) << 8;
|
||||
ver_major_minor_errata |= (ddr_in32(&ddr->ip_rev2) & 0xFF00) >> 8;
|
||||
|
||||
return ver_major_minor_errata;
|
||||
}
|
||||
|
||||
/*
|
||||
* Round up mclk_ps to nearest 1 ps in memory controller code
|
||||
* if the error is 0.5ps or more.
|
||||
*
|
||||
* If an imprecise data rate is too high due to rounding error
|
||||
* propagation, compute a suitably rounded mclk_ps to compute
|
||||
* a working memory controller configuration.
|
||||
*/
|
||||
unsigned int get_memory_clk_period_ps(const unsigned int ctrl_num)
|
||||
{
|
||||
unsigned int data_rate = get_ddr_freq(ctrl_num);
|
||||
unsigned int result;
|
||||
|
||||
/* Round to nearest 10ps, being careful about 64-bit multiply/divide */
|
||||
unsigned long long rem, mclk_ps = ULL_2E12;
|
||||
|
||||
/* Now perform the big divide, the result fits in 32-bits */
|
||||
rem = do_div(mclk_ps, data_rate);
|
||||
result = (rem >= (data_rate >> 1)) ? mclk_ps + 1 : mclk_ps;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Convert picoseconds into DRAM clock cycles (rounding up if needed). */
|
||||
unsigned int picos_to_mclk(const unsigned int ctrl_num, unsigned int picos)
|
||||
{
|
||||
unsigned long long clks, clks_rem;
|
||||
unsigned long data_rate = get_ddr_freq(ctrl_num);
|
||||
|
||||
/* Short circuit for zero picos */
|
||||
if (!picos)
|
||||
return 0;
|
||||
|
||||
/* First multiply the time by the data rate (32x32 => 64) */
|
||||
clks = picos * (unsigned long long)data_rate;
|
||||
/*
|
||||
* Now divide by 5^12 and track the 32-bit remainder, then divide
|
||||
* by 2*(2^12) using shifts (and updating the remainder).
|
||||
*/
|
||||
clks_rem = do_div(clks, UL_5POW12);
|
||||
clks_rem += (clks & (UL_2POW13-1)) * UL_5POW12;
|
||||
clks >>= 13;
|
||||
|
||||
/* If we had a remainder greater than the 1ps error, then round up */
|
||||
if (clks_rem > data_rate)
|
||||
clks++;
|
||||
|
||||
/* Clamp to the maximum representable value */
|
||||
if (clks > ULL_8FS)
|
||||
clks = ULL_8FS;
|
||||
return (unsigned int) clks;
|
||||
}
|
||||
|
||||
unsigned int mclk_to_picos(const unsigned int ctrl_num, unsigned int mclk)
|
||||
{
|
||||
return get_memory_clk_period_ps(ctrl_num) * mclk;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PPC
|
||||
void
|
||||
__fsl_ddr_set_lawbar(const common_timing_params_t *memctl_common_params,
|
||||
unsigned int law_memctl,
|
||||
unsigned int ctrl_num)
|
||||
{
|
||||
unsigned long long base = memctl_common_params->base_address;
|
||||
unsigned long long size = memctl_common_params->total_mem;
|
||||
|
||||
/*
|
||||
* If no DIMMs on this controller, do not proceed any further.
|
||||
*/
|
||||
if (!memctl_common_params->ndimms_present) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_PHYS_64BIT)
|
||||
if (base >= CONFIG_MAX_MEM_MAPPED)
|
||||
return;
|
||||
if ((base + size) >= CONFIG_MAX_MEM_MAPPED)
|
||||
size = CONFIG_MAX_MEM_MAPPED - base;
|
||||
#endif
|
||||
if (set_ddr_laws(base, size, law_memctl) < 0) {
|
||||
printf("%s: ERROR (ctrl #%d, TRGT ID=%x)\n", __func__, ctrl_num,
|
||||
law_memctl);
|
||||
return ;
|
||||
}
|
||||
debug("setup ddr law base = 0x%llx, size 0x%llx, TRGT_ID 0x%x\n",
|
||||
base, size, law_memctl);
|
||||
}
|
||||
|
||||
__attribute__((weak, alias("__fsl_ddr_set_lawbar"))) void
|
||||
fsl_ddr_set_lawbar(const common_timing_params_t *memctl_common_params,
|
||||
unsigned int memctl_interleaved,
|
||||
unsigned int ctrl_num);
|
||||
#endif
|
||||
|
||||
void fsl_ddr_set_intl3r(const unsigned int granule_size)
|
||||
{
|
||||
#ifdef CONFIG_E6500
|
||||
u32 *mcintl3r = (void *) (CONFIG_SYS_IMMR + 0x18004);
|
||||
*mcintl3r = 0x80000000 | (granule_size & 0x1f);
|
||||
debug("Enable MCINTL3R with granule size 0x%x\n", granule_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
u32 fsl_ddr_get_intl3r(void)
|
||||
{
|
||||
u32 val = 0;
|
||||
#ifdef CONFIG_E6500
|
||||
u32 *mcintl3r = (void *) (CONFIG_SYS_IMMR + 0x18004);
|
||||
val = *mcintl3r;
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
void print_ddr_info(unsigned int start_ctrl)
|
||||
{
|
||||
struct ccsr_ddr __iomem *ddr =
|
||||
(struct ccsr_ddr __iomem *)(CONFIG_SYS_FSL_DDR_ADDR);
|
||||
|
||||
#if defined(CONFIG_E6500) && (CONFIG_NUM_DDR_CONTROLLERS == 3)
|
||||
u32 *mcintl3r = (void *) (CONFIG_SYS_IMMR + 0x18004);
|
||||
#endif
|
||||
#if (CONFIG_NUM_DDR_CONTROLLERS > 1)
|
||||
uint32_t cs0_config = ddr_in32(&ddr->cs0_config);
|
||||
#endif
|
||||
uint32_t sdram_cfg = ddr_in32(&ddr->sdram_cfg);
|
||||
int cas_lat;
|
||||
|
||||
#if CONFIG_NUM_DDR_CONTROLLERS >= 2
|
||||
if ((!(sdram_cfg & SDRAM_CFG_MEM_EN)) ||
|
||||
(start_ctrl == 1)) {
|
||||
ddr = (void __iomem *)CONFIG_SYS_FSL_DDR2_ADDR;
|
||||
sdram_cfg = ddr_in32(&ddr->sdram_cfg);
|
||||
}
|
||||
#endif
|
||||
#if CONFIG_NUM_DDR_CONTROLLERS >= 3
|
||||
if ((!(sdram_cfg & SDRAM_CFG_MEM_EN)) ||
|
||||
(start_ctrl == 2)) {
|
||||
ddr = (void __iomem *)CONFIG_SYS_FSL_DDR3_ADDR;
|
||||
sdram_cfg = ddr_in32(&ddr->sdram_cfg);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!(sdram_cfg & SDRAM_CFG_MEM_EN)) {
|
||||
puts(" (DDR not enabled)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
puts(" (DDR");
|
||||
switch ((sdram_cfg & SDRAM_CFG_SDRAM_TYPE_MASK) >>
|
||||
SDRAM_CFG_SDRAM_TYPE_SHIFT) {
|
||||
case SDRAM_TYPE_DDR1:
|
||||
puts("1");
|
||||
break;
|
||||
case SDRAM_TYPE_DDR2:
|
||||
puts("2");
|
||||
break;
|
||||
case SDRAM_TYPE_DDR3:
|
||||
puts("3");
|
||||
break;
|
||||
case SDRAM_TYPE_DDR4:
|
||||
puts("4");
|
||||
break;
|
||||
default:
|
||||
puts("?");
|
||||
break;
|
||||
}
|
||||
|
||||
if (sdram_cfg & SDRAM_CFG_32_BE)
|
||||
puts(", 32-bit");
|
||||
else if (sdram_cfg & SDRAM_CFG_16_BE)
|
||||
puts(", 16-bit");
|
||||
else
|
||||
puts(", 64-bit");
|
||||
|
||||
/* Calculate CAS latency based on timing cfg values */
|
||||
cas_lat = ((ddr_in32(&ddr->timing_cfg_1) >> 16) & 0xf);
|
||||
if (fsl_ddr_get_version(0) <= 0x40400)
|
||||
cas_lat += 1;
|
||||
else
|
||||
cas_lat += 2;
|
||||
cas_lat += ((ddr_in32(&ddr->timing_cfg_3) >> 12) & 3) << 4;
|
||||
printf(", CL=%d", cas_lat >> 1);
|
||||
if (cas_lat & 0x1)
|
||||
puts(".5");
|
||||
|
||||
if (sdram_cfg & SDRAM_CFG_ECC_EN)
|
||||
puts(", ECC on)");
|
||||
else
|
||||
puts(", ECC off)");
|
||||
|
||||
#if (CONFIG_NUM_DDR_CONTROLLERS == 3)
|
||||
#ifdef CONFIG_E6500
|
||||
if (*mcintl3r & 0x80000000) {
|
||||
puts("\n");
|
||||
puts(" DDR Controller Interleaving Mode: ");
|
||||
switch (*mcintl3r & 0x1f) {
|
||||
case FSL_DDR_3WAY_1KB_INTERLEAVING:
|
||||
puts("3-way 1KB");
|
||||
break;
|
||||
case FSL_DDR_3WAY_4KB_INTERLEAVING:
|
||||
puts("3-way 4KB");
|
||||
break;
|
||||
case FSL_DDR_3WAY_8KB_INTERLEAVING:
|
||||
puts("3-way 8KB");
|
||||
break;
|
||||
default:
|
||||
puts("3-way UNKNOWN");
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#if (CONFIG_NUM_DDR_CONTROLLERS >= 2)
|
||||
if ((cs0_config & 0x20000000) && (start_ctrl == 0)) {
|
||||
puts("\n");
|
||||
puts(" DDR Controller Interleaving Mode: ");
|
||||
|
||||
switch ((cs0_config >> 24) & 0xf) {
|
||||
case FSL_DDR_256B_INTERLEAVING:
|
||||
puts("256B");
|
||||
break;
|
||||
case FSL_DDR_CACHE_LINE_INTERLEAVING:
|
||||
puts("cache line");
|
||||
break;
|
||||
case FSL_DDR_PAGE_INTERLEAVING:
|
||||
puts("page");
|
||||
break;
|
||||
case FSL_DDR_BANK_INTERLEAVING:
|
||||
puts("bank");
|
||||
break;
|
||||
case FSL_DDR_SUPERBANK_INTERLEAVING:
|
||||
puts("super-bank");
|
||||
break;
|
||||
default:
|
||||
puts("invalid");
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((sdram_cfg >> 8) & 0x7f) {
|
||||
puts("\n");
|
||||
puts(" DDR Chip-Select Interleaving Mode: ");
|
||||
switch(sdram_cfg >> 8 & 0x7f) {
|
||||
case FSL_DDR_CS0_CS1_CS2_CS3:
|
||||
puts("CS0+CS1+CS2+CS3");
|
||||
break;
|
||||
case FSL_DDR_CS0_CS1:
|
||||
puts("CS0+CS1");
|
||||
break;
|
||||
case FSL_DDR_CS2_CS3:
|
||||
puts("CS2+CS3");
|
||||
break;
|
||||
case FSL_DDR_CS0_CS1_AND_CS2_CS3:
|
||||
puts("CS0+CS1 and CS2+CS3");
|
||||
break;
|
||||
default:
|
||||
puts("invalid");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void __weak detail_board_ddr_info(void)
|
||||
{
|
||||
print_ddr_info(0);
|
||||
}
|
||||
|
||||
void board_add_ram_info(int use_default)
|
||||
{
|
||||
detail_board_ddr_info();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FSL_DDR_SYNC_REFRESH
|
||||
#define DDRC_DEBUG20_INIT_DONE 0x80000000
|
||||
#define DDRC_DEBUG2_RF 0x00000040
|
||||
void fsl_ddr_sync_memctl_refresh(unsigned int first_ctrl,
|
||||
unsigned int last_ctrl)
|
||||
{
|
||||
unsigned int i;
|
||||
u32 ddrc_debug20;
|
||||
u32 ddrc_debug2[CONFIG_NUM_DDR_CONTROLLERS] = {};
|
||||
u32 *ddrc_debug2_p[CONFIG_NUM_DDR_CONTROLLERS] = {};
|
||||
struct ccsr_ddr __iomem *ddr;
|
||||
|
||||
for (i = first_ctrl; i <= last_ctrl; i++) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR;
|
||||
break;
|
||||
#if defined(CONFIG_SYS_FSL_DDR2_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 1)
|
||||
case 1:
|
||||
ddr = (void *)CONFIG_SYS_FSL_DDR2_ADDR;
|
||||
break;
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_FSL_DDR3_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 2)
|
||||
case 2:
|
||||
ddr = (void *)CONFIG_SYS_FSL_DDR3_ADDR;
|
||||
break;
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_FSL_DDR4_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 3)
|
||||
case 3:
|
||||
ddr = (void *)CONFIG_SYS_FSL_DDR4_ADDR;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
printf("%s unexpected ctrl = %u\n", __func__, i);
|
||||
return;
|
||||
}
|
||||
ddrc_debug20 = ddr_in32(&ddr->debug[19]);
|
||||
ddrc_debug2_p[i] = &ddr->debug[1];
|
||||
while (!(ddrc_debug20 & DDRC_DEBUG20_INIT_DONE)) {
|
||||
/* keep polling until DDRC init is done */
|
||||
udelay(100);
|
||||
ddrc_debug20 = ddr_in32(&ddr->debug[19]);
|
||||
}
|
||||
ddrc_debug2[i] = ddr_in32(&ddr->debug[1]) | DDRC_DEBUG2_RF;
|
||||
}
|
||||
/*
|
||||
* Sync refresh
|
||||
* This is put together to make sure the refresh reqeusts are sent
|
||||
* closely to each other.
|
||||
*/
|
||||
for (i = first_ctrl; i <= last_ctrl; i++)
|
||||
ddr_out32(ddrc_debug2_p[i], ddrc_debug2[i]);
|
||||
}
|
||||
#endif /* CONFIG_FSL_DDR_SYNC_REFRESH */
|
||||
|
||||
void remove_unused_controllers(fsl_ddr_info_t *info)
|
||||
{
|
||||
#ifdef CONFIG_FSL_LSCH3
|
||||
int i;
|
||||
u64 nodeid;
|
||||
void *hnf_sam_ctrl = (void *)(CCI_HN_F_0_BASE + CCN_HN_F_SAM_CTL);
|
||||
bool ddr0_used = false;
|
||||
bool ddr1_used = false;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
nodeid = in_le64(hnf_sam_ctrl) & CCN_HN_F_SAM_NODEID_MASK;
|
||||
if (nodeid == CCN_HN_F_SAM_NODEID_DDR0) {
|
||||
ddr0_used = true;
|
||||
} else if (nodeid == CCN_HN_F_SAM_NODEID_DDR1) {
|
||||
ddr1_used = true;
|
||||
} else {
|
||||
printf("Unknown nodeid in HN-F SAM control: 0x%llx\n",
|
||||
nodeid);
|
||||
}
|
||||
hnf_sam_ctrl += (CCI_HN_F_1_BASE - CCI_HN_F_0_BASE);
|
||||
}
|
||||
if (!ddr0_used && !ddr1_used) {
|
||||
printf("Invalid configuration in HN-F SAM control\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ddr0_used && info->first_ctrl == 0) {
|
||||
info->first_ctrl = 1;
|
||||
info->num_ctrls = 1;
|
||||
debug("First DDR controller disabled\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ddr1_used && info->first_ctrl + info->num_ctrls > 1) {
|
||||
info->num_ctrls = 1;
|
||||
debug("Second DDR controller disabled\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
Reference in New Issue
Block a user