[U-Boot-Users] [RFC][FSL DDR 0/8] Freescale DDR rewrite

This is a series of patches that are a work-in-progress towards a new DDR initialization for the Freescale 8{3,5,6}xxx devices that have a common DDR controller.
These patches are also available at:
git://git.kernel.org/pub/scm/boot/u-boot/galak/u-boot.git fsl_ddr
and patch 0002 since its large is at:
http://gate.crashing.org/~galak/fsl_ddr.20080609/0002-Rewrite-the-FSL-mpc8xx...
- k

Also added a few helper functions for DDR1 & DDR2 to print SPD info and verify the checksum.
Signed-off-by: Kumar Gala galak@kernel.crashing.org --- common/Makefile | 1 + common/ddr_spd.c | 504 +++++++++++++++++++++++++++++++++++++++++++++++++++++ include/ddr_spd.h | 249 ++++++++++++++++++++++++++ 3 files changed, 754 insertions(+), 0 deletions(-) create mode 100644 common/ddr_spd.c create mode 100644 include/ddr_spd.h
diff --git a/common/Makefile b/common/Makefile index b425795..503c3b5 100644 --- a/common/Makefile +++ b/common/Makefile @@ -145,6 +145,7 @@ COBJS-y += cmd_mac.o COBJS-$(CONFIG_CMD_MFSL) += cmd_mfsl.o COBJS-$(CONFIG_MP) += cmd_mp.o COBJS-$(CONFIG_CMD_SF) += cmd_sf.o +COBJS-$(CONFIG_DDR_SPD) += ddr_spd.o
COBJS := $(COBJS-y) SRCS := $(AOBJS:.o=.S) $(COBJS:.o=.c) diff --git a/common/ddr_spd.c b/common/ddr_spd.c new file mode 100644 index 0000000..bfabb93 --- /dev/null +++ b/common/ddr_spd.c @@ -0,0 +1,504 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#include <common.h> +#include <ddr_spd.h> + +void +ddr1_spd_dump(const ddr1_spd_eeprom_t *spd) +{ + unsigned int i; + + printf("%-3d : %02x %s\n", + 0, spd->info_size, + " spd->info_size, * 0 # bytes written into serial memory *"); + printf("%-3d : %02x %s\n", + 1, spd->chip_size, + " spd->chip_size, * 1 Total # bytes of SPD memory device *"); + printf("%-3d : %02x %s\n", + 2, spd->mem_type, + " spd->mem_type, * 2 Fundamental memory type *"); + printf("%-3d : %02x %s\n", + 3, spd->nrow_addr, + " spd->nrow_addr, * 3 # of Row Addresses on this assembly *"); + printf("%-3d : %02x %s\n", + 4, spd->ncol_addr, + " spd->ncol_addr, * 4 # of Column Addrs on this assembly *"); + printf("%-3d : %02x %s\n", + 5, spd->nrows, + " spd->nrows * 5 # of DIMM Banks *"); + printf("%-3d : %02x %s\n", + 6, spd->dataw_lsb, + " spd->dataw_lsb, * 6 Data Width lsb of this assembly *"); + printf("%-3d : %02x %s\n", + 7, spd->dataw_msb, + " spd->dataw_msb, * 7 Data Width msb of this assembly *"); + printf("%-3d : %02x %s\n", + 8, spd->voltage, + " spd->voltage, * 8 Voltage intf std of this assembly *"); + printf("%-3d : %02x %s\n", + 9, spd->clk_cycle, + " spd->clk_cycle, * 9 SDRAM Cycle time at CL=X *"); + printf("%-3d : %02x %s\n", + 10, spd->clk_access, + " spd->clk_access, * 10 SDRAM Access from Clock at CL=X *"); + printf("%-3d : %02x %s\n", + 11, spd->config, + " spd->config, * 11 DIMM Configuration type *"); + printf("%-3d : %02x %s\n", + 12, spd->refresh, + " spd->refresh, * 12 Refresh Rate/Type *"); + printf("%-3d : %02x %s\n", + 13, spd->primw, + " spd->primw, * 13 Primary SDRAM Width *"); + printf("%-3d : %02x %s\n", + 14, spd->ecw, + " spd->ecw, * 14 Error Checking SDRAM width *"); + printf("%-3d : %02x %s\n", + 15, spd->min_delay, + " spd->min_delay, * 15 Back to Back Random Access *"); + printf("%-3d : %02x %s\n", + 16, spd->burstl, + " spd->burstl, * 16 Burst Lengths Supported *"); + printf("%-3d : %02x %s\n", + 17, spd->nbanks, + " spd->nbanks, * 17 # of Banks on Each SDRAM Device *"); + printf("%-3d : %02x %s\n", + 18, spd->cas_lat, + " spd->cas_lat, * 18 CAS# Latencies Supported *"); + printf("%-3d : %02x %s\n", + 19, spd->cs_lat, + " spd->cs_lat, * 19 Chip Select Latency *"); + printf("%-3d : %02x %s\n", + 20, spd->write_lat, + " spd->write_lat, * 20 Write Latency/Recovery *"); + printf("%-3d : %02x %s\n", + 21, spd->mod_attr, + " spd->mod_attr, * 21 SDRAM Module Attributes *"); + printf("%-3d : %02x %s\n", + 22, spd->dev_attr, + " spd->dev_attr, * 22 SDRAM Device Attributes *"); + printf("%-3d : %02x %s\n", + 23, spd->clk_cycle2, + " spd->clk_cycle2, * 23 Min SDRAM Cycle time at CL=X-1 *"); + printf("%-3d : %02x %s\n", + 24, spd->clk_access2, + " spd->clk_access2, * 24 SDRAM Access from Clock at CL=X-1 *"); + printf("%-3d : %02x %s\n", + 25, spd->clk_cycle3, + " spd->clk_cycle3, * 25 Min SDRAM Cycle time at CL=X-2 *"); + printf("%-3d : %02x %s\n", + 26, spd->clk_access3, + " spd->clk_access3, * 26 Max Access from Clock at CL=X-2 *"); + printf("%-3d : %02x %s\n", + 27, spd->trp, + " spd->trp, * 27 Min Row Precharge Time (tRP)*"); + printf("%-3d : %02x %s\n", + 28, spd->trrd, + " spd->trrd, * 28 Min Row Active to Row Active (tRRD) *"); + printf("%-3d : %02x %s\n", + 29, spd->trcd, + " spd->trcd, * 29 Min RAS to CAS Delay (tRCD) *"); + printf("%-3d : %02x %s\n", + 30, spd->tras, + " spd->tras, * 30 Minimum RAS Pulse Width (tRAS) *"); + printf("%-3d : %02x %s\n", + 31, spd->bank_dens, + " spd->bank_dens, * 31 Density of each bank on module *"); + printf("%-3d : %02x %s\n", + 32, spd->ca_setup, + " spd->ca_setup, * 32 Cmd + Addr signal input setup time *"); + printf("%-3d : %02x %s\n", + 33, spd->ca_hold, + " spd->ca_hold, * 33 Cmd and Addr signal input hold time *"); + printf("%-3d : %02x %s\n", + 34, spd->data_setup, + " spd->data_setup, * 34 Data signal input setup time *"); + printf("%-3d : %02x %s\n", + 35, spd->data_hold, + " spd->data_hold, * 35 Data signal input hold time *"); + printf("%-3d : %02x %s\n", + 36, spd->res_36_40[0], + " spd->res_36_40[0], * 36 Reserved / tWR *"); + printf("%-3d : %02x %s\n", + 37, spd->res_36_40[1], + " spd->res_36_40[1], * 37 Reserved / tWTR *"); + printf("%-3d : %02x %s\n", + 38, spd->res_36_40[2], + " spd->res_36_40[2], * 38 Reserved / tRTP *"); + printf("%-3d : %02x %s\n", + 39, spd->res_36_40[3], + " spd->res_36_40[3], * 39 Reserved / mem_probe *"); + printf("%-3d : %02x %s\n", + 40, spd->res_36_40[4], + " spd->res_36_40[4], * 40 Reserved / trc,trfc extensions *"); + printf("%-3d : %02x %s\n", + 41, spd->trc, + " spd->trc, * 41 Min Active to Auto refresh time tRC *"); + printf("%-3d : %02x %s\n", + 42, spd->trfc, + " spd->trfc, * 42 Min Auto to Active period tRFC *"); + printf("%-3d : %02x %s\n", + 43, spd->tckmax, + " spd->tckmax, * 43 Max device cycle time tCKmax *"); + printf("%-3d : %02x %s\n", + 44, spd->tdqsq, + " spd->tdqsq, * 44 Max DQS to DQ skew *"); + printf("%-3d : %02x %s\n", + 45, spd->tqhs, + " spd->tqhs, * 45 Max Read DataHold skew tQHS *"); + printf("%-3d : %02x %s\n", + 46, spd->res_46, + " spd->res_46, * 46 Reserved/ PLL Relock time *"); + printf("%-3d : %02x %s\n", + 47, spd->dimm_height, + " spd->dimm_height * 47 SDRAM DIMM Height *"); + + printf("%-3d-%3d: ", 48, 61); + for (i = 0; i < 14; i++) { + printf("%02x", spd->res_48_61[i]); + } + printf(" * 48-61 IDD in SPD and Reserved space *\n"); + + printf("%-3d : %02x %s\n", + 62, spd->spd_rev, + " spd->spd_rev, * 62 SPD Data Revision Code *"); + printf("%-3d : %02x %s\n", + 63, spd->cksum, + " spd->cksum, * 63 Checksum for bytes 0-62 *"); + printf("%-3d-%3d: ", 64, 71); + + for (i = 0; i < 8; i++) { + printf("%02x", spd->mid[i]); + } + + printf("* 64 Mfr's JEDEC ID code per JEP-108E *\n"); + printf("%-3d : %02x %s\n", + 72, spd->mloc, + " spd->mloc, * 72 Manufacturing Location *"); + + printf("%-3d-%3d: >>", 73, 90); +// for (i = 0; i < 18; i++) { +// printf("%02x", spd->mpart[i]); +// } + for (i = 0; i < 18; i++) { + printf("%c", spd->mpart[i]); + } + + printf("<<* 73 Manufacturer's Part Number *\n"); + + printf("%-3d-%3d: %02x %02x %s\n", + 91, 92, spd->rev[0], spd->rev[1], + "* 91 Revision Code *"); + printf("%-3d-%3d: %02x %02x %s\n", + 93, 94, spd->mdate[0], spd->mdate[1], + "* 93 Manufacturing Date *"); + printf("%-3d-%3d: ", 95, 98); + + for (i = 0; i < 4; i++) { + printf("%02x", spd->sernum[i]); + } + printf("* 95 Assembly Serial Number *\n"); + + printf("%-3d-%3d: ", 99, 127); + for (i = 0; i < 27; i++) { + printf("%02x", spd->mspec[i]); + } + + printf("* 99 Manufacturer Specific Data *\n"); +} + +void +ddr2_spd_dump(const ddr2_spd_eeprom_t *spd) +{ + unsigned int i; + + printf("%-3d : %02x %s\n", + 0, spd->info_size, + " spd->info_size, * 0 # bytes written into serial memory *"); + printf("%-3d : %02x %s\n", + 1, spd->chip_size, + " spd->chip_size, * 1 Total # bytes of SPD memory device *"); + printf("%-3d : %02x %s\n", + 2, spd->mem_type, + " spd->mem_type, * 2 Fundamental memory type *"); + printf("%-3d : %02x %s\n", + 3, spd->nrow_addr, + " spd->nrow_addr, * 3 # of Row Addresses on this assembly *"); + printf("%-3d : %02x %s\n", + 4, spd->ncol_addr, + " spd->ncol_addr, * 4 # of Column Addrs on this assembly *"); + printf("%-3d : %02x %s\n", + 5, spd->mod_ranks, + " spd->mod_ranks * 5 # of Module Rows on this assembly *"); + printf("%-3d : %02x %s\n", + 6, spd->dataw, + " spd->dataw, * 6 Data Width of this assembly *"); + printf("%-3d : %02x %s\n", + 7, spd->res_7, + " spd->res_7, * 7 Reserved *"); + printf("%-3d : %02x %s\n", + 8, spd->voltage, + " spd->voltage, * 8 Voltage intf std of this assembly *"); + printf("%-3d : %02x %s\n", + 9, spd->clk_cycle, + " spd->clk_cycle, * 9 SDRAM Cycle time at CL=X *"); + printf("%-3d : %02x %s\n", + 10, spd->clk_access, + " spd->clk_access, * 10 SDRAM Access from Clock at CL=X *"); + printf("%-3d : %02x %s\n", + 11, spd->config, + " spd->config, * 11 DIMM Configuration type *"); + printf("%-3d : %02x %s\n", + 12, spd->refresh, + " spd->refresh, * 12 Refresh Rate/Type *"); + printf("%-3d : %02x %s\n", + 13, spd->primw, + " spd->primw, * 13 Primary SDRAM Width *"); + printf("%-3d : %02x %s\n", + 14, spd->ecw, + " spd->ecw, * 14 Error Checking SDRAM width *"); + printf("%-3d : %02x %s\n", + 15, spd->res_15, + " spd->res_15, * 15 Reserved *"); + printf("%-3d : %02x %s\n", + 16, spd->burstl, + " spd->burstl, * 16 Burst Lengths Supported *"); + printf("%-3d : %02x %s\n", + 17, spd->nbanks, + " spd->nbanks, * 17 # of Banks on Each SDRAM Device *"); + printf("%-3d : %02x %s\n", + 18, spd->cas_lat, + " spd->cas_lat, * 18 CAS# Latencies Supported *"); + printf("%-3d : %02x %s\n", + 19, spd->mech_char, + " spd->mech_char, * 19 Mechanical Characteristics *"); + printf("%-3d : %02x %s\n", + 20, spd->dimm_type, + " spd->dimm_type, * 20 DIMM type *"); + printf("%-3d : %02x %s\n", + 21, spd->mod_attr, + " spd->mod_attr, * 21 SDRAM Module Attributes *"); + printf("%-3d : %02x %s\n", + 22, spd->dev_attr, + " spd->dev_attr, * 22 SDRAM Device Attributes *"); + printf("%-3d : %02x %s\n", + 23, spd->clk_cycle2, + " spd->clk_cycle2, * 23 Min SDRAM Cycle time at CL=X-1 *"); + printf("%-3d : %02x %s\n", + 24, spd->clk_access2, + " spd->clk_access2, * 24 SDRAM Access from Clock at CL=X-1 *"); + printf("%-3d : %02x %s\n", + 25, spd->clk_cycle3, + " spd->clk_cycle3, * 25 Min SDRAM Cycle time at CL=X-2 *"); + printf("%-3d : %02x %s\n", + 26, spd->clk_access3, + " spd->clk_access3, * 26 Max Access from Clock at CL=X-2 *"); + printf("%-3d : %02x %s\n", + 27, spd->trp, + " spd->trp, * 27 Min Row Precharge Time (tRP)*"); + printf("%-3d : %02x %s\n", + 28, spd->trrd, + " spd->trrd, * 28 Min Row Active to Row Active (tRRD) *"); + printf("%-3d : %02x %s\n", + 29, spd->trcd, + " spd->trcd, * 29 Min RAS to CAS Delay (tRCD) *"); + printf("%-3d : %02x %s\n", + 30, spd->tras, + " spd->tras, * 30 Minimum RAS Pulse Width (tRAS) *"); + printf("%-3d : %02x %s\n", + 31, spd->rank_dens, + " spd->rank_dens, * 31 Density of each rank on module *"); + printf("%-3d : %02x %s\n", + 32, spd->ca_setup, + " spd->ca_setup, * 32 Cmd + Addr signal input setup time *"); + printf("%-3d : %02x %s\n", + 33, spd->ca_hold, + " spd->ca_hold, * 33 Cmd and Addr signal input hold time *"); + printf("%-3d : %02x %s\n", + 34, spd->data_setup, + " spd->data_setup, * 34 Data signal input setup time *"); + printf("%-3d : %02x %s\n", + 35, spd->data_hold, + " spd->data_hold, * 35 Data signal input hold time *"); + printf("%-3d : %02x %s\n", + 36, spd->twr, + " spd->twr, * 36 Write Recovery time tWR *"); + printf("%-3d : %02x %s\n", + 37, spd->twtr, + " spd->twtr, * 37 Int write to read delay tWTR *"); + printf("%-3d : %02x %s\n", + 38, spd->trtp, + " spd->trtp, * 38 Int read to precharge delay tRTP *"); + printf("%-3d : %02x %s\n", + 39, spd->mem_probe, + " spd->mem_probe, * 39 Mem analysis probe characteristics *"); + printf("%-3d : %02x %s\n", + 40, spd->trctrfc_ext, + " spd->trctrfc_ext, * 40 Extensions to trc and trfc *"); + printf("%-3d : %02x %s\n", + 41, spd->trc, + " spd->trc, * 41 Min Active to Auto refresh time tRC *"); + printf("%-3d : %02x %s\n", + 42, spd->trfc, + " spd->trfc, * 42 Min Auto to Active period tRFC *"); + printf("%-3d : %02x %s\n", + 43, spd->tckmax, + " spd->tckmax, * 43 Max device cycle time tCKmax *"); + printf("%-3d : %02x %s\n", + 44, spd->tdqsq, + " spd->tdqsq, * 44 Max DQS to DQ skew *"); + printf("%-3d : %02x %s\n", + 45, spd->tqhs, + " spd->tqhs, * 45 Max Read DataHold skew tQHS *"); + printf("%-3d : %02x %s\n", + 46, spd->pll_relock, + " spd->pll_relock, * 46 PLL Relock time *"); + printf("%-3d : %02x %s\n", + 47, spd->Tcasemax, + " spd->Tcasemax, * 47 Tcasemax *"); + printf("%-3d : %02x %s\n", + 48, spd->psiTAdram, + " spd->psiTAdram, * 48 Thermal Resistance of DRAM Package from Top (Case) to Ambient (Psi T-A DRAM) *"); + printf("%-3d : %02x %s\n", + 49, spd->dt0_mode, + " spd->dt0_mode, * 49 DRAM Case Temperature Rise from Ambient due to Activate-Precharge/Mode Bits (DT0/Mode Bits) *)"); + printf("%-3d : %02x %s\n", + 50, spd->dt2n_dt2q, + " spd->dt2n_dt2q, * 50 DRAM Case Temperature Rise from Ambient due to Precharge/Quiet Standby (DT2N/DT2Q) *"); + printf("%-3d : %02x %s\n", + 51, spd->dt2p, + " spd->dt2p, * 51 DRAM Case Temperature Rise from Ambient due to Precharge Power-Down (DT2P) *"); + printf("%-3d : %02x %s\n", + 52, spd->dt3n, + " spd->dt3n, * 52 DRAM Case Temperature Rise from Ambient due to Active Standby (DT3N) *"); + printf("%-3d : %02x %s\n", + 53, spd->dt3pfast, + " spd->dt3pfast, * 53 DRAM Case Temperature Rise from Ambient due to Active Power-Down with Fast PDN Exit (DT3Pfast) *"); + printf("%-3d : %02x %s\n", + 54, spd->dt3pslow, + " spd->dt3pslow, * 54 DRAM Case Temperature Rise from Ambient due to Active Power-Down with Slow PDN Exit (DT3Pslow) *"); + printf("%-3d : %02x %s\n", + 55, spd->dt4r_dt4r4w, + " spd->dt4r_dt4r4w, * 55 DRAM Case Temperature Rise from Ambient due to Page Open Burst Read/DT4R4W Mode Bit (DT4R/DT4R4W Mode Bit) *"); + printf("%-3d : %02x %s\n", + 56, spd->dt5b, + " spd->dt5b, * 56 DRAM Case Temperature Rise from Ambient due to Burst Refresh (DT5B) *"); + printf("%-3d : %02x %s\n", + 57, spd->dt7, + " spd->dt7, * 57 DRAM Case Temperature Rise from Ambient due to Bank Interleave Reads with Auto-Precharge (DT7) *"); + printf("%-3d : %02x %s\n", + 58, spd->psiTApll, + " spd->psiTApll, * 58 Thermal Resistance of PLL Package form Top (Case) to Ambient (Psi T-A PLL) *"); + printf("%-3d : %02x %s\n", + 59, spd->psiTAreg, + " spd->psiTAreg, * 59 Thermal Reisitance of Register Package from Top (Case) to Ambient (Psi T-A Register) *"); + printf("%-3d : %02x %s\n", + 60, spd->dtpllactive, + " spd->dtpllactive, * 60 PLL Case Temperature Rise from Ambient due to PLL Active (DT PLL Active) *"); + printf("%-3d : %02x %s\n", + 61, spd->dtregact, + " spd->dtregact, * 61 Register Case Temperature Rise from Ambient due to Register Active/Mode Bit (DT Register Active/Mode Bit) *"); + printf("%-3d : %02x %s\n", + 62, spd->spd_rev, + " spd->spd_rev, * 62 SPD Data Revision Code *"); + printf("%-3d : %02x %s\n", + 63, spd->cksum, + " spd->cksum, * 63 Checksum for bytes 0-62 *"); + printf("%-3d-%3d: ", 64, 71); + + for (i = 0; i < 8; i++) { + printf("%02x", spd->mid[i]); + } + + printf("* 64 Mfr's JEDEC ID code per JEP-108E *\n"); + printf("%-3d : %02x %s\n", + 72, spd->mloc, + " spd->mloc, * 72 Manufacturing Location *"); + + printf("%-3d-%3d: >>", 73, 90); +// for (i = 0; i < 18; i++) { +// printf("%02x", spd->mpart[i]); +// } + for (i = 0; i < 18; i++) { + printf("%c", spd->mpart[i]); + } + + printf("<<* 73 Manufacturer's Part Number *\n"); + + printf("%-3d-%3d: %02x %02x %s\n", + 91, 92, spd->rev[0], spd->rev[1], + "* 91 Revision Code *"); + printf("%-3d-%3d: %02x %02x %s\n", + 93, 94, spd->mdate[0], spd->mdate[1], + "* 93 Manufacturing Date *"); + printf("%-3d-%3d: ", 95, 98); + + for (i = 0; i < 4; i++) { + printf("%02x", spd->sernum[i]); + } + printf("* 95 Assembly Serial Number *\n"); + + printf("%-3d-%3d: ", 99, 127); + for (i = 0; i < 27; i++) { + printf("%02x", spd->mspec[i]); + } + + printf("* 99 Manufacturer Specific Data *\n"); +} + +/* used for ddr1 and ddr2 spd */ +static int +spd_check(const u8 *buf, u8 spd_rev, u8 spd_cksum) +{ + unsigned int cksum = 0; + unsigned int i; + + /* + * Check SPD revision supported + * Rev 1.2 or less supported by this code + */ + if (spd_rev > 0x12) { + printf("SPD revision %02X not supported by this code\n", + spd_rev); + return 1; + } + + /* + * Calculate checksum + */ + for (i = 0; i < 63; i++) { + cksum += *buf++; + } + cksum &= 0xFF; + + if (cksum != spd_cksum) { + printf("SPD checksum unexpected. " + "Checksum in SPD = %02X, computed SPD = %02X\n", + spd_cksum, cksum); + return 1; + } + + return 0; +} + +unsigned int +ddr1_spd_check(const ddr1_spd_eeprom_t *spd) +{ + const u8 *p = (const u8 *)spd; + + return spd_check(p, spd->spd_rev, spd->cksum); +} + +unsigned int +ddr2_spd_check(const ddr2_spd_eeprom_t *spd) +{ + const u8 *p = (const u8 *)spd; + + return spd_check(p, spd->spd_rev, spd->cksum); +} diff --git a/include/ddr_spd.h b/include/ddr_spd.h new file mode 100644 index 0000000..1a1c99b --- /dev/null +++ b/include/ddr_spd.h @@ -0,0 +1,249 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#ifndef _DDR_SPD_H_ +#define _DDR_SPD_H_ + +/* + * Format from "JEDEC Standard No. 21-C, + * Appendix D: Rev 1.0: SPD's for DDR SDRAM + */ +typedef struct ddr1_spd_eeprom_s { + unsigned char info_size; /* 0 # bytes written into serial memory */ + unsigned char chip_size; /* 1 Total # bytes of SPD memory device */ + unsigned char mem_type; /* 2 Fundamental memory type */ + unsigned char nrow_addr; /* 3 # of Row Addresses on this assembly */ + unsigned char ncol_addr; /* 4 # of Column Addrs on this assembly */ + unsigned char nrows; /* 5 Number of DIMM Banks */ + unsigned char dataw_lsb; /* 6 Data Width of this assembly */ + unsigned char dataw_msb; /* 7 ... Data Width continuation */ + unsigned char voltage; /* 8 Voltage intf std of this assembly */ + unsigned char clk_cycle; /* 9 SDRAM Cycle time at CL=X */ + unsigned char clk_access; /* 10 SDRAM Access from Clock at CL=X (tAC) */ + unsigned char config; /* 11 DIMM Configuration type */ + unsigned char refresh; /* 12 Refresh Rate/Type */ + unsigned char primw; /* 13 Primary SDRAM Width */ + unsigned char ecw; /* 14 Error Checking SDRAM width */ + unsigned char min_delay; /* 15 for Back to Back Random Address */ + unsigned char burstl; /* 16 Burst Lengths Supported */ + unsigned char nbanks; /* 17 # of Banks on SDRAM Device */ + unsigned char cas_lat; /* 18 CAS# Latencies Supported */ + unsigned char cs_lat; /* 19 CS# Latency */ + unsigned char write_lat; /* 20 Write Latency (aka Write Recovery) */ + unsigned char mod_attr; /* 21 SDRAM Module Attributes */ + unsigned char dev_attr; /* 22 SDRAM Device Attributes */ + unsigned char clk_cycle2; /* 23 Min SDRAM Cycle time at CL=X-0.5 */ + unsigned char clk_access2; /* 24 SDRAM Access from Clock at CL=X-0.5 (tAC) */ + unsigned char clk_cycle3; /* 25 Min SDRAM Cycle time at CL=X-1 */ + unsigned char clk_access3; /* 26 Max Access from Clock at CL=X-1 (tAC) */ + unsigned char trp; /* 27 Min Row Precharge Time (tRP)*/ + unsigned char trrd; /* 28 Min Row Active to Row Active (tRRD) */ + unsigned char trcd; /* 29 Min RAS to CAS Delay (tRCD) */ + unsigned char tras; /* 30 Minimum RAS Pulse Width (tRAS) */ + unsigned char bank_dens; /* 31 Density of each bank on module */ + unsigned char ca_setup; /* 32 Addr + Cmd Setup Time Before Clock */ + unsigned char ca_hold; /* 33 Addr + Cmd Hold Time After Clock */ + unsigned char data_setup; /* 34 Data Input Setup Time Before Strobe */ + unsigned char data_hold; /* 35 Data Input Hold Time After Strobe */ + unsigned char res_36_40[5];/* 36-40 reserved for VCSDRAM */ + unsigned char trc; /* 41 Min Active to Auto refresh time tRC */ + unsigned char trfc; /* 42 Min Auto to Active period tRFC */ + unsigned char tckmax; /* 43 Max device cycle time tCKmax */ + unsigned char tdqsq; /* 44 Max DQS to DQ skew (tDQSQ max) */ + unsigned char tqhs; /* 45 Max Read DataHold skew (tQHS) */ + unsigned char res_46; /* 46 Reserved */ + unsigned char dimm_height; /* 47 DDR SDRAM DIMM Height */ + unsigned char res_48_61[14]; /* 48-61 Reserved */ + unsigned char spd_rev; /* 62 SPD Data Revision Code */ + unsigned char cksum; /* 63 Checksum for bytes 0-62 */ + unsigned char mid[8]; /* 64-71 Mfr's JEDEC ID code per JEP-106 */ + unsigned char mloc; /* 72 Manufacturing Location */ + unsigned char mpart[18]; /* 73 Manufacturer's Part Number */ + unsigned char rev[2]; /* 91 Revision Code */ + unsigned char mdate[2]; /* 93 Manufacturing Date */ + unsigned char sernum[4]; /* 95 Assembly Serial Number */ + unsigned char mspec[27]; /* 99-127 Manufacturer Specific Data */ + +} ddr1_spd_eeprom_t; + +/* + * Format from "JEDEC Appendix X: Serial Presence Detects for DDR2 SDRAM", + * SPD Revision 1.2 + */ +typedef struct ddr2_spd_eeprom_s { + unsigned char info_size; /* 0 # bytes written into serial memory */ + unsigned char chip_size; /* 1 Total # bytes of SPD memory device */ + unsigned char mem_type; /* 2 Fundamental memory type */ + unsigned char nrow_addr; /* 3 # of Row Addresses on this assembly */ + unsigned char ncol_addr; /* 4 # of Column Addrs on this assembly */ + unsigned char mod_ranks; /* 5 Number of DIMM Ranks */ + unsigned char dataw; /* 6 Module Data Width */ + unsigned char res_7; /* 7 Reserved */ + unsigned char voltage; /* 8 Voltage intf std of this assembly */ + unsigned char clk_cycle; /* 9 SDRAM Cycle time at CL=X */ + unsigned char clk_access; /* 10 SDRAM Access from Clock at CL=X (tAC) */ + unsigned char config; /* 11 DIMM Configuration type */ + unsigned char refresh; /* 12 Refresh Rate/Type */ + unsigned char primw; /* 13 Primary SDRAM Width */ + unsigned char ecw; /* 14 Error Checking SDRAM width */ + unsigned char res_15; /* 15 Reserved */ + unsigned char burstl; /* 16 Burst Lengths Supported */ + unsigned char nbanks; /* 17 # of Banks on Each SDRAM Device */ + unsigned char cas_lat; /* 18 CAS# Latencies Supported */ + unsigned char mech_char; /* 19 DIMM Mechanical Characteristics */ + unsigned char dimm_type; /* 20 DIMM type information */ + unsigned char mod_attr; /* 21 SDRAM Module Attributes */ + unsigned char dev_attr; /* 22 SDRAM Device Attributes */ + unsigned char clk_cycle2; /* 23 Min SDRAM Cycle time at CL=X-1 */ + unsigned char clk_access2; /* 24 SDRAM Access from Clock at CL=X-1 (tAC) */ + unsigned char clk_cycle3; /* 25 Min SDRAM Cycle time at CL=X-2 */ + unsigned char clk_access3; /* 26 Max Access from Clock at CL=X-2 (tAC) */ + unsigned char trp; /* 27 Min Row Precharge Time (tRP)*/ + unsigned char trrd; /* 28 Min Row Active to Row Active (tRRD) */ + unsigned char trcd; /* 29 Min RAS to CAS Delay (tRCD) */ + unsigned char tras; /* 30 Minimum RAS Pulse Width (tRAS) */ + unsigned char rank_dens; /* 31 Density of each rank on module */ + unsigned char ca_setup; /* 32 Addr + Cmd Setup Time Before Clock (tIS) */ + unsigned char ca_hold; /* 33 Addr + Cmd Hold Time After Clock (tIH) */ + unsigned char data_setup; /* 34 Data Input Setup Time Before Strobe (tDS) */ + unsigned char data_hold; /* 35 Data Input Hold Time After Strobe (tDH) */ + unsigned char twr; /* 36 Write Recovery time tWR */ + unsigned char twtr; /* 37 Int write to read delay tWTR */ + unsigned char trtp; /* 38 Int read to precharge delay tRTP */ + unsigned char mem_probe; /* 39 Mem analysis probe characteristics */ + unsigned char trctrfc_ext; /* 40 Extensions to trc and trfc */ + unsigned char trc; /* 41 Min Active to Auto refresh time tRC */ + unsigned char trfc; /* 42 Min Auto to Active period tRFC */ + unsigned char tckmax; /* 43 Max device cycle time tCKmax */ + unsigned char tdqsq; /* 44 Max DQS to DQ skew (tDQSQ max) */ + unsigned char tqhs; /* 45 Max Read DataHold skew (tQHS) */ + unsigned char pll_relock; /* 46 PLL Relock time */ + unsigned char Tcasemax; /* 47 Tcasemax */ + unsigned char psiTAdram; /* 48 Thermal Resistance of DRAM Package from Top (Case) to Ambient (Psi T-A DRAM) */ + unsigned char dt0_mode; /* 49 DRAM Case Temperature Rise from Ambient due to Activate-Precharge/Mode Bits (DT0/Mode Bits) */ + unsigned char dt2n_dt2q; /* 50 DRAM Case Temperature Rise from Ambient due to Precharge/Quiet Standby (DT2N/DT2Q) */ + unsigned char dt2p; /* 51 DRAM Case Temperature Rise from Ambient due to Precharge Power-Down (DT2P) */ + unsigned char dt3n; /* 52 DRAM Case Temperature Rise from Ambient due to Active Standby (DT3N) */ + unsigned char dt3pfast; /* 53 DRAM Case Temperature Rise from Ambient due to Active Power-Down with Fast PDN Exit (DT3Pfast) */ + unsigned char dt3pslow; /* 54 DRAM Case Temperature Rise from Ambient due to Active Power-Down with Slow PDN Exit (DT3Pslow) */ + unsigned char dt4r_dt4r4w; /* 55 DRAM Case Temperature Rise from Ambient due to Page Open Burst Read/DT4R4W Mode Bit (DT4R/DT4R4W Mode Bit) */ + unsigned char dt5b; /* 56 DRAM Case Temperature Rise from Ambient due to Burst Refresh (DT5B) */ + unsigned char dt7; /* 57 DRAM Case Temperature Rise from Ambient due to Bank Interleave Reads with Auto-Precharge (DT7) */ + unsigned char psiTApll; /* 58 Thermal Resistance of PLL Package form Top (Case) to Ambient (Psi T-A PLL) */ + unsigned char psiTAreg; /* 59 Thermal Reisitance of Register Package from Top (Case) to Ambient (Psi T-A Register) */ + unsigned char dtpllactive; /* 60 PLL Case Temperature Rise from Ambient due to PLL Active (DT PLL Active) */ + unsigned char dtregact; /* 61 Register Case Temperature Rise from Ambient due to Register Active/Mode Bit (DT Register Active/Mode Bit) */ + + unsigned char spd_rev; /* 62 SPD Data Revision Code */ + unsigned char cksum; /* 63 Checksum for bytes 0-62 */ + unsigned char mid[8]; /* 64 Mfr's JEDEC ID code per JEP-106 */ + unsigned char mloc; /* 72 Manufacturing Location */ + unsigned char mpart[18]; /* 73 Manufacturer's Part Number */ + unsigned char rev[2]; /* 91 Revision Code */ + unsigned char mdate[2]; /* 93 Manufacturing Date */ + unsigned char sernum[4]; /* 95 Assembly Serial Number */ + unsigned char mspec[27]; /* 99-127 Manufacturer Specific Data */ + +} ddr2_spd_eeprom_t; + +typedef struct ddr3_spd_eeprom_s { + /* General Section: Bytes 0-59 */ + unsigned char info_size_crc; /* 0 # bytes written into serial memory, CRC coverage */ + unsigned char spd_rev; /* 1 Total # bytes of SPD memory device */ + unsigned char mem_type; /* 2 Key Byte / Fundamental memory type */ + unsigned char module_type; /* 3 Key Byte / Module Type */ + unsigned char density_banks; /* 4 SDRAM Density and Banks */ + unsigned char addressing; /* 5 SDRAM Addressing */ + unsigned char res_6; /* 6 Reserved */ + unsigned char organization; /* 7 Module Organization */ + unsigned char bus_width; /* 8 Module Memory Bus Width */ + unsigned char ftb_div; /* 9 Fine Timebase (FTB) Dividend / Divisor */ + unsigned char mtb_dividend; /* 10 Medium Timebase (MTB) Dividend */ + unsigned char mtb_divisor; /* 11 Medium Timebase (MTB) Divisor */ + unsigned char tCK_min; /* 12 SDRAM Minimum Cycle Time (tCK_min) */ + unsigned char res_13; /* 13 Reserved */ + unsigned char caslat_lsb; /* 14 CAS Latencies Supported, Least Significant Byte */ + unsigned char caslat_msb; /* 15 CAS Latencies Supported, Most Significant Byte */ + unsigned char tAA_min; /* 16 Minimum CAS Latency Time (tAA_min) */ + unsigned char tWR_min; /* 17 Minimum WRite REcovery Time (tWR_min) */ + unsigned char tRCD_min; /* 18 Minimum RAS# to CAS# Delay Time (tRCD_min) */ + unsigned char tRRD_min; /* 19 Minimum Row Active to Row Active Delay Time (tRRD_min) */ + unsigned char tRP_min; /* 20 Minimum Row Precharge Delay Time (tRP_min) */ + unsigned char tRAS_tRC_ext; /* 21 Upper Nibbles for tRAS and tRC */ + unsigned char tRAS_min_lsb; /* 22 Minimum Active to Precharge Delay Time (tRAS_min), LSB */ + unsigned char tRC_min_lsb; /* 23 Minimum Active to Active/Refresh Delay Time (tRC_min), LSB */ + unsigned char tRFC_min_lsb; /* 24 Minimum Refresh Recovery Delay Time (tRFC_min), LSB */ + unsigned char tRFC_min_msb; /* 25 Minimum Refresh Recovery Delay Time (tRFC_min), MSB */ + unsigned char tWTR_min; /* 26 Minimum Internal Write to Read Command Delay Time (tWTR_min) */ + unsigned char tRTP_min; /* 27 Minimum Internal Read to Precharge Command Delay Time (tRTP_min) */ + unsigned char tFAW_msb; /* 28 Upper Nibble for tFAW */ + unsigned char tFAW_min; /* 29 Minimum Four Activate Window Delay Time (tFAW_min), LSB */ + unsigned char opt_features; /* 30 SDRAM Optional Features */ + unsigned char therm_ref_opt; /* 31 SDRAM Thermal and Refresh Options */ + unsigned char res_32_59[28]; /* 32-59 Reserved, General Section */ + + /* Module-Specific Section: Bytes 60-116 */ + union { + struct { + unsigned char mod_height; /* 60 (Unbuffered) Module Nominal Height */ + unsigned char mod_thickness; /* 61 (Unbuffered) Module Maximum Thickness */ + unsigned char ref_raw_card; /* 62 (Unbuffered) Reference Raw Card Used */ + unsigned char addr_mapping; /* 63 (Unbuffered) Address Mapping from Edge Connector to DRAM */ + unsigned char res_64_116[53]; /* 64-116 (Unbuffered) Reserved */ + } unbuffered; + struct { + unsigned char mod_height; /* 60 (Registered) Module Nominal Height */ + unsigned char mod_thickness; /* 61 (Registered) Module Maximum Thickness */ + unsigned char ref_raw_card; /* 62 (Registered) Reference Raw Card Used */ + } registered; + unsigned char uc[57]; /* 60-116 Module-Specific Section */ + } mod_section; + + /* Unique Module ID: Bytes 117-125 */ + unsigned char mmid_lsb; /* 117 Module Manufacturer ID Code LSB - JEP-106 */ + unsigned char mmid_msb; /* 118 Module Manufacturer ID Code MSB - JEP-106 */ + unsigned char mloc; /* 119 Manufacturing Location */ + unsigned char mdate[2]; /* 120-121 Manufacturing Date */ + unsigned char sernum[4]; /* 122-125 Module Serial Number */ + + /* CRC: Bytes 126-127 */ + unsigned char crc[2]; /* 126-127 SPD Cyclical Redundancy Code (CRC) */ + + /* Other Manufacturer Fields and User Space: Bytes 128-255 */ + unsigned char mpart[18]; /* 128-145 Manufacturer's Module Part Number */ + unsigned char mrev[2]; /* 146-147 Module Revision Code */ + + unsigned char dmid_lsb; /* 148 DRAM Manufacturer ID Code LSB - JEP-106 */ + unsigned char dmid_msb; /* 149 DRAM Manufacturer ID Code MSB - JEP-106 */ + + unsigned char msd[26]; /* 150-175 Manufacturer's Specific Data */ + unsigned char cust[80]; /* 176-255 Open for Customer Use */ + +} ddr3_spd_eeprom_t; + +extern unsigned int ddr1_spd_check(const ddr1_spd_eeprom_t *spd); +extern void ddr1_spd_dump(const ddr1_spd_eeprom_t *spd); +extern unsigned int ddr2_spd_check(const ddr2_spd_eeprom_t *spd); +extern void ddr2_spd_dump(const ddr2_spd_eeprom_t *spd); + +/* + * Byte 2 Fundamental Memory Types. + */ +#define SPD_MEMTYPE_FPM (0x01) +#define SPD_MEMTYPE_EDO (0x02) +#define SPD_MEMTYPE_PIPE_NIBBLE (0x03) +#define SPD_MEMTYPE_SDRAM (0x04) +#define SPD_MEMTYPE_ROM (0x05) +#define SPD_MEMTYPE_SGRAM (0x06) +#define SPD_MEMTYPE_DDR (0x07) +#define SPD_MEMTYPE_DDR2 (0x08) +#define SPD_MEMTYPE_DDR2_FBDIMM (0x09) +#define SPD_MEMTYPE_DDR2_FBDIMM_PROBE (0x0A) +#define SPD_MEMTYPE_DDR3 (0x0B) + +#endif /* _DDR_SPD_H_ */

From: James Yang James.Yang@freescale.com
--- cpu/mpc85xx/Makefile | 9 + cpu/mpc86xx/Makefile | 4 + cpu/mpc8xxx/Makefile | 30 + cpu/mpc8xxx/common_timing_params.h | 54 + cpu/mpc8xxx/ddr2_dimm_params.h | 99 ++ cpu/mpc8xxx/fsl_ddr1.c | 365 ++++++ cpu/mpc8xxx/fsl_ddr2.c | 384 ++++++ cpu/mpc8xxx/fsl_ddr_sdram.c | 2448 ++++++++++++++++++++++++++++++++++++ cpu/mpc8xxx/fsl_ddr_sdram.h | 87 ++ cpu/mpc8xxx/fsl_memctrl.h | 48 + cpu/mpc8xxx/memctl_options.h | 100 ++ 11 files changed, 3628 insertions(+), 0 deletions(-) create mode 100644 cpu/mpc8xxx/Makefile create mode 100644 cpu/mpc8xxx/common_timing_params.h create mode 100644 cpu/mpc8xxx/ddr2_dimm_params.h create mode 100644 cpu/mpc8xxx/fsl_ddr1.c create mode 100644 cpu/mpc8xxx/fsl_ddr2.c create mode 100644 cpu/mpc8xxx/fsl_ddr_sdram.c create mode 100644 cpu/mpc8xxx/fsl_ddr_sdram.h create mode 100644 cpu/mpc8xxx/fsl_memctrl.h create mode 100644 cpu/mpc8xxx/memctl_options.h
diff --git a/cpu/mpc85xx/Makefile b/cpu/mpc85xx/Makefile index adbc585..c180dbd 100644 --- a/cpu/mpc85xx/Makefile +++ b/cpu/mpc85xx/Makefile @@ -33,6 +33,15 @@ SOBJS-$(CONFIG_MP) += release.o SOBJS = $(SOBJS-y) COBJS-$(CONFIG_MP) += mp.o COBJS-$(CONFIG_OF_LIBFDT) += fdt.o + +ifneq ($(CONFIG_FSL_DDR3),y) +ifneq ($(CONFIG_FSL_DDR2),y) +ifneq ($(CONFIG_FSL_DDR1),y) +COBJS-y += spd_sdram.o +endif +endif +endif + COBJS = traps.o cpu.o cpu_init.o speed.o interrupts.o tlb.o \ pci.o serial_scc.o commproc.o ether_fcc.o spd_sdram.o qe_io.o \ $(COBJS-y) diff --git a/cpu/mpc86xx/Makefile b/cpu/mpc86xx/Makefile index 537f62a..4227053 100644 --- a/cpu/mpc86xx/Makefile +++ b/cpu/mpc86xx/Makefile @@ -40,6 +40,10 @@ COBJS-y += spd_sdram.o
COBJS-$(CONFIG_OF_LIBFDT) += fdt.o
+ifneq ($(CONFIG_FSL_DDR2),y) +COBJS-y += spd_sdram.o +endif + SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS-y:.o=.c) OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS-y)) START := $(addprefix $(obj),$(START)) diff --git a/cpu/mpc8xxx/Makefile b/cpu/mpc8xxx/Makefile new file mode 100644 index 0000000..30f81ff --- /dev/null +++ b/cpu/mpc8xxx/Makefile @@ -0,0 +1,30 @@ +# +# Copyright 2008 Freescale Semiconductor, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# Version 2 as published by the Free Software Foundation. +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)libmpc8xxx.a + +COBJS-$(CONFIG_FSL_DDR1) += fsl_ddr_sdram.o +COBJS-$(CONFIG_FSL_DDR1) += fsl_ddr1.o + +COBJS-$(CONFIG_FSL_DDR2) += fsl_ddr_sdram.o +COBJS-$(CONFIG_FSL_DDR2) += fsl_ddr2.o + + +SRCS := $(START:.o=.S) $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c) +OBJS := $(addprefix $(obj),$(SOBJS-y) $(COBJS-y)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend diff --git a/cpu/mpc8xxx/common_timing_params.h b/cpu/mpc8xxx/common_timing_params.h new file mode 100644 index 0000000..6201e78 --- /dev/null +++ b/cpu/mpc8xxx/common_timing_params.h @@ -0,0 +1,54 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#ifndef COMMON_TIMING_PARAMS_H +#define COMMON_TIMING_PARAMS_H + +#include "fsl_ddr_sdram.h" + +typedef struct { + /* parameters to constrict */ + + unsigned int tCKmin_X_ps; + unsigned int tCKmax_ps; + unsigned int tCKmax_max_ps; + unsigned int tRCD_ps; + unsigned int tRP_ps; + unsigned int tRAS_ps; + + unsigned int tWR_ps; /* maximum = 63750 ps */ + unsigned int tWTR_ps; /* maximum = 63750 ps */ + unsigned int tRFC_ps; /* maximum = 255 ns + 256 ns + .75 ns = 511750 ps */ + + unsigned int tRRD_ps; /* maximum = 63750 ps */ + unsigned int tRC_ps; /* maximum = 254 ns + .75 ns = 254750 ps */ + + unsigned int refresh_rate_ns; + + unsigned int tIS_ps; /* byte 32, spd->ca_setup */ + unsigned int tIH_ps; /* byte 33, spd->ca_hold */ + unsigned int tDS_ps; /* byte 34, spd->data_setup */ + unsigned int tDH_ps; /* byte 35, spd->data_hold */ + unsigned int tRTP_ps; /* byte 38, spd->trtp */ + unsigned int tDQSQ_max_ps; /* byte 44, spd->tdqsq */ + unsigned int tQHS_ps; /* byte 45, spd->tqhs */ + + unsigned int ndimms_present; + unsigned int lowest_common_SPD_caslat; + unsigned int highest_common_derated_caslat; + unsigned int additive_latency; + unsigned int all_DIMMs_burst_lengths_bitmask; + unsigned int all_DIMMs_registered; + unsigned int all_DIMMs_unbuffered; + unsigned int all_DIMMs_ECC_capable; + + unsigned long long total_mem; + unsigned long long base_address; +} common_timing_params_t; + +#endif diff --git a/cpu/mpc8xxx/ddr2_dimm_params.h b/cpu/mpc8xxx/ddr2_dimm_params.h new file mode 100644 index 0000000..478dc85 --- /dev/null +++ b/cpu/mpc8xxx/ddr2_dimm_params.h @@ -0,0 +1,99 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#ifndef DDR2_DIMM_PARAMS_H +#define DDR2_DIMM_PARAMS_H + +#include "fsl_ddr_sdram.h" + + +/* + * Parameters for a DDR2 dimm computed from the SPD + */ +typedef struct dimm_params_s { + + /* + * DIMM organization parameters + */ + char mpart[19]; /* guaranteed null terminated */ + + unsigned int n_ranks; + unsigned long long rank_density; + unsigned long long dimm_capacity; + unsigned int data_width; + unsigned int primary_sdram_width; + unsigned int ec_sdram_width; + unsigned int registered_dimm; + + /* + * SDRAM device parameters + */ + unsigned int n_row_addr; + unsigned int n_col_addr; + unsigned int edc_config; /* 0 = none, 1 = parity, 2 = ECC */ + unsigned int n_banks_per_sdram_device; + unsigned int burst_lengths_bitmask; /* BL=4 bit 2, BL=8 = bit 3 */ + unsigned int row_density; + + /* used in computing base address of DIMMs */ + unsigned long long base_address; + + /* + * DIMM timing parameters + */ + + /* + * SDRAM clock periods + * The range for these are 1000-10000 so a short should be sufficient + */ + unsigned int tCKmin_X_ps; + unsigned int tCKmin_X_minus_1_ps; + unsigned int tCKmin_X_minus_2_ps; + unsigned int tCKmax_ps; + + /* + * SPD-defined CAS latencies + */ + unsigned int caslat_X; + unsigned int caslat_X_minus_1; + unsigned int caslat_X_minus_2; + + unsigned int caslat_lowest_derated; /* Derated CAS latency */ + + /* basic timing parameters */ + unsigned int tRCD_ps; + unsigned int tRP_ps; + unsigned int tRAS_ps; + + unsigned int tWR_ps; /* maximum = 63750 ps */ + unsigned int tWTR_ps; /* maximum = 63750 ps */ + unsigned int tRFC_ps; /* max = 255 ns + 256 ns + .75 ns = 511750 ps */ + + unsigned int tRRD_ps; /* maximum = 63750 ps */ + unsigned int tRC_ps; /* maximum = 254 ns + .75 ns = 254750 ps */ + + unsigned int refresh_rate_ns; + + unsigned int tIS_ps; /* byte 32, spd->ca_setup */ + unsigned int tIH_ps; /* byte 33, spd->ca_hold */ + unsigned int tDS_ps; /* byte 34, spd->data_setup */ + unsigned int tDH_ps; /* byte 35, spd->data_hold */ + unsigned int tRTP_ps; /* byte 38, spd->trtp */ + unsigned int tDQSQ_max_ps; /* byte 44, spd->tdqsq */ + unsigned int tQHS_ps; /* byte 45, spd->tqhs */ +} dimm_params_t; + + +extern unsigned int ddr2_compute_dimm_parameters( + const generic_spd_eeprom_t *spd, + dimm_params_t *pdimm, + unsigned int dimm_number); + +extern void reset_dimm_parameters(dimm_params_t *pdimm); + +#endif diff --git a/cpu/mpc8xxx/fsl_ddr1.c b/cpu/mpc8xxx/fsl_ddr1.c new file mode 100644 index 0000000..7483cb8 --- /dev/null +++ b/cpu/mpc8xxx/fsl_ddr1.c @@ -0,0 +1,365 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#include <common.h> + +#include "fsl_ddr_sdram.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. + * + * FIXME: Should this go into a memory technology specific file? + * FIXME: This currently handles DDR 1 and 2, so might be left here. + * FIXME: Can DDR 3 be added to it easily? spd_utils.c? + */ + +static phys_size_t +compute_ranksize(unsigned int mem_type, unsigned char row_dens) +{ + phys_size_t bsize; + + if (mem_type == SPD_MEMTYPE_DDR) { + /* Bottom 2 bits up to the top. */ + bsize = ((row_dens >> 2) | ((row_dens & 3) << 6)); + bsize <<= 24ULL; + debug("DDR: DDR I rank density = 0x%08x\n", bsize); + } else { + /* Bottom 5 bits up to the top. */ + bsize = ((row_dens >> 5) | ((row_dens & 31) << 3)); + bsize <<= 27ULL; + debug("DDR: DDR II rank density = 0x%08x\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_ns(const unsigned int spd_refresh) +{ + unsigned int refresh_time_ns[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_ns[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 alwqys 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 */ +unsigned short ddr2_speed_bins[] = { 0, 5000, 3750, 3000, 2500 }; + +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; +} + + +/* + * ddr2_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 +ddr2_compute_dimm_parameters(const ddr1_spd_eeprom_t *spd, + dimm_params_t *pdimm, + unsigned int dimm_number) +{ + unsigned int retval; + + /* + * FIXME debate: shouldn't have to dynamically determine memory type + * This ought to be determined through a config #define + */ + + if (spd->mem_type) { + if (spd->mem_type != SPD_MEMTYPE_DDR2) { + /* + * FIXME; this code does not currently support + * anything but DDR2 + */ + printf("DIMM %u: is not a DDR2 SPD.\n", dimm_number); + return 1; + } + } else { + reset_dimm_parameters(pdimm); + 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->dimm_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 = 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()); + + /* + * 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(3); + pdimm->tWTR_ps = mclk_to_picos(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_ns = determine_refresh_rate_ns(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(2); /* By the book. */ + pdimm->tDQSQ_max_ps = spd->tdqsq * 10; + pdimm->tQHS_ps = spd->tqhs * 10; + + return 0; +} diff --git a/cpu/mpc8xxx/fsl_ddr2.c b/cpu/mpc8xxx/fsl_ddr2.c new file mode 100644 index 0000000..1a13d76 --- /dev/null +++ b/cpu/mpc8xxx/fsl_ddr2.c @@ -0,0 +1,384 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#include <common.h> + +#include "fsl_ddr_sdram.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. + * + * FIXME: Should this go into a memory technology specific file? + * FIXME: This currently handles DDR 1 and 2, so might be left here. + * FIXME: Can DDR 3 be added to it easily? ddr_utils.c? + */ + +static phys_size_t +compute_ranksize(unsigned int mem_type, unsigned char row_dens) +{ + phys_size_t bsize; + + if (mem_type == SPD_MEMTYPE_DDR) { + /* Bottom 2 bits up to the top. */ + bsize = ((row_dens >> 2) | ((row_dens & 3) << 6)); + bsize <<= 24ULL; + debug("DDR: DDR I rank density = 0x%08x\n", bsize); + } else { + /* Bottom 5 bits up to the top. */ + bsize = ((row_dens >> 5) | ((row_dens & 31) << 3)); + bsize <<= 27ULL; + debug("DDR: DDR II rank density = 0x%08x\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_ns(const unsigned int spd_refresh) +{ + unsigned int refresh_time_ns[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_ns[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 alwqys 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 */ +unsigned short ddr2_speed_bins[] = { 0, 5000, 3750, 3000, 2500 }; + +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; +} + + +/* + * ddr2_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 +ddr2_compute_dimm_parameters(const ddr2_spd_eeprom_t *spd, + dimm_params_t *pdimm, + unsigned int dimm_number) +{ + unsigned int retval; + + /* + * FIXME debate: shouldn't have to dynamically determine memory type + * This ought to be determined through a config #define + */ + + if (spd->mem_type) { + if (spd->mem_type != SPD_MEMTYPE_DDR2) { + /* + * FIXME; this code does not currently support + * anything but DDR2 + */ + printf("DIMM %u: is not a DDR2 SPD.\n", dimm_number); + return 1; + } + } else { + reset_dimm_parameters(pdimm); + 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->dimm_capacity = pdimm->n_ranks * pdimm->rank_density; + pdimm->data_width = spd->dataw; + pdimm->primary_sdram_width = spd->primw; + pdimm->ec_sdram_width = spd->ecw; + + { + unsigned char dimm_type = spd->dimm_type; + + /* + * FIXME: what about registered SO-DIMM? + */ + switch (dimm_type) { + case 0x01: /* RDIMM */ + case 0x10: /* Mini-RDIMM */ + pdimm->registered_dimm = 1; /* register buffered */ + break; + + case 0x02: /* UDIMM */ + case 0x04: /* SO-DIMM */ + case 0x08: /* Micro-DIMM */ + case 0x20: /* Mini-UDIMM */ + pdimm->registered_dimm = 0; /* unbuffered */ + break; + + default: + printf("unknown dimm_type 0x%02X\n", dimm_type); + return 1; + break; + } + } + + /* + * 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()); + + /* + * 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_ns = determine_refresh_rate_ns(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; +} diff --git a/cpu/mpc8xxx/fsl_ddr_sdram.c b/cpu/mpc8xxx/fsl_ddr_sdram.c new file mode 100644 index 0000000..72af6ac --- /dev/null +++ b/cpu/mpc8xxx/fsl_ddr_sdram.c @@ -0,0 +1,2448 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +/* + * 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 "fsl_ddr_sdram.h" + +/* + * Board-specific functions defined in each board's ddr.c + */ + +unsigned int fsl_ddr_sdram_get_mem_data_rate(void); +void fsl_ddr_sdram_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd, + unsigned int ctrl_num); +void fsl_ddr_sdram_dump_memctl_regs(unsigned int ctrl_num); +void fsl_ddr_sdram_set_memctl_regs(const fsl_memctl_config_regs_t *regs, + unsigned int ctrl_num); +void fsl_ddr_sdram_set_lawbar( + const common_timing_params_t *memctl_common_params, + unsigned int memctl_interleaved, + unsigned int ctrl_num); +unsigned int fsl_ddr_sdram_type_function(void); +unsigned int fsl_ddr_sdram_clk_adjust_function(void); +unsigned int fsl_ddr_sdram_cpo_override_function(void); +unsigned int fsl_ddr_sdram_write_data_delay_function(void); +unsigned int fsl_ddr_sdram_half_strength_driver_enable_function(void); + + +/* + * 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" /* FIXME: probably shouldn't be here */ +}; + +const char * step_to_string(unsigned int step) { + return step_string_tbl[step]; +} + +/* + * Round mclk_ps to nearest 10 ps in memory controller code. + * + * 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(void) +{ + unsigned int mclk_ps; + + mclk_ps = 2000000000000ULL / fsl_ddr_sdram_get_mem_data_rate(); + /* round to nearest 10 ps */ + return 10 * ((mclk_ps + 5) / 10); +} + +/* + * Convert picoseconds into DRAM clock cycles (rounding up if needed). + */ +static unsigned int picos_to_mclk(unsigned int picos) +{ + const unsigned long long ULL_2e12 = 2000000000000ULL; + const unsigned long long ULL_8Fs = 0xFFFFFFFFULL; + unsigned long long clks; + unsigned long long clks_temp; + + if (!picos) + return 0; + + clks = fsl_ddr_sdram_get_mem_data_rate() * (unsigned long long) picos; + clks_temp = clks; + clks = clks / ULL_2e12; + if (clks_temp % ULL_2e12) { + clks++; + } + + if (clks > ULL_8Fs) { + clks = ULL_8Fs; + } + + return (unsigned int) clks; +} + +unsigned int mclk_to_picos(unsigned int mclk) +{ + return get_memory_clk_period_ps() * mclk; +} + +void reset_dimm_parameters(dimm_params_t *pdimm) +{ + memset(pdimm, 0, sizeof(dimm_params_t)); +} + +/* + * 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. + */ + +static unsigned int +compute_lowest_common_dimm_parameters(const dimm_params_t *dimm_params, + common_timing_params_t *outpdimm, + unsigned int number_of_dimms) +{ + unsigned int i; + + unsigned int tCKmin_X_ps = 0; + unsigned int tCKmax_ps = 0xFFFFFFFF; + unsigned int tCKmax_max_ps = 0; + unsigned int tRCD_ps = 0; + unsigned int tRP_ps = 0; + unsigned int tRAS_ps = 0; + unsigned int tWR_ps = 0; + unsigned int tWTR_ps = 0; + unsigned int tRFC_ps = 0; + unsigned int tRRD_ps = 0; + unsigned int tRC_ps = 0; + unsigned int refresh_rate_ns = 0; + unsigned int tIS_ps = 0; + unsigned int tIH_ps = 0; + unsigned int tDS_ps = 0; + unsigned int tDH_ps = 0; + unsigned int tRTP_ps = 0; + unsigned int tDQSQ_max_ps = 0; + unsigned int tQHS_ps = 0; + + unsigned int temp1, temp2; + unsigned int lowest_good_caslat; + unsigned int additive_latency = 0; + const unsigned int mclk_ps = get_memory_clk_period_ps(); + unsigned int not_ok; + + debug("using mclk_ps = %u\n", mclk_ps); + + 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; + } + + /* + * Find maximum tCKmin_X_ps to find slowest DIMM. + */ + tCKmin_X_ps = max(tCKmin_X_ps, dimm_params[i].tCKmin_X_ps); + + /* + * 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, dimm_params[i].tCKmax_ps); + + /* + * Find maximum tCKmax_ps to find slowest slow speed, + * i.e., this is the slowest any dimm can go. + */ + tCKmax_max_ps = max(tCKmax_max_ps, dimm_params[i].tCKmax_ps); + + /* + * Find maximum tRCD_ps to find slowest ras-to-cas delay. + */ + tRCD_ps = max(tRCD_ps, dimm_params[i].tRCD_ps); + + /* + * Find maximum tRP_ps to find slowest row precharge time. + */ + tRP_ps = max(tRP_ps, dimm_params[i].tRP_ps); + + /* + * Find maximum tRAS_ps to find slowest active to + * precharge time. + */ + tRAS_ps = max(tRAS_ps, dimm_params[i].tRAS_ps); + + /* + * Find maximum tWR_ps to find slowest write recovery time. + */ + tWR_ps = max(tWR_ps, dimm_params[i].tWR_ps); + + /* + * Find maximum tWTR_ps to find slowest write-to-read + * command delay. + */ + tWTR_ps = max(tWTR_ps, dimm_params[i].tWTR_ps); + + /* + * Find maximum tRFC_ps to find slowest auto-refresh to + * active/auto refresh command period. + */ + tRFC_ps = max(tRFC_ps, dimm_params[i].tRFC_ps); + + /* + * Find maximum tRRD_ps to find slowest row active to + * row active delay. + */ + tRRD_ps = max(tRRD_ps, dimm_params[i].tRRD_ps); + + /* + * Find maximum tRC_ps to find slowest + * active/auto-refresh time. + */ + tRC_ps = max(tRC_ps, dimm_params[i].tRC_ps); + + /* + * Find maximum refresh_rate_ns to find slowest refresh time. + */ + refresh_rate_ns = max(refresh_rate_ns, + dimm_params[i].refresh_rate_ns); + + /* + * Find maximum tIS_ps to find slowest. + */ + tIS_ps = max(tIS_ps, dimm_params[i].tIS_ps); + + /* + * Find maximum tIH_ps to find slowest. + */ + tIH_ps = max(tIH_ps, dimm_params[i].tIH_ps); + + /* + * Find maximum tDS_ps to find slowest. + */ + tDS_ps = max(tDS_ps, dimm_params[i].tDS_ps); + + /* + * Find maximum tDH_ps to find slowest. + */ + tDH_ps = max(tDH_ps, dimm_params[i].tDH_ps); + + /* + * Find maximum tRTP_ps to find slowest. + */ + tRTP_ps = max(tRTP_ps, dimm_params[i].tRTP_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, dimm_params[i].tDQSQ_max_ps); + + /* + * Find maximum tQHS_ps to find slowest. + */ + tQHS_ps = max(tQHS_ps, dimm_params[i].tQHS_ps); + } + + 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; + outpdimm->tCKmax_max_ps = tCKmax_max_ps; + outpdimm->tRCD_ps = tRCD_ps; + outpdimm->tRP_ps = tRP_ps; + outpdimm->tRAS_ps = tRAS_ps; + outpdimm->tWR_ps = tWR_ps; + outpdimm->tWTR_ps = tWTR_ps; + outpdimm->tRFC_ps = tRFC_ps; + outpdimm->tRRD_ps = tRRD_ps; + outpdimm->tRC_ps = tRC_ps; + outpdimm->refresh_rate_ns = refresh_rate_ns; + outpdimm->tIS_ps = tIS_ps; + outpdimm->tIH_ps = tIH_ps; + outpdimm->tDS_ps = tDS_ps; + outpdimm->tDH_ps = tDH_ps; + outpdimm->tRTP_ps = tRTP_ps; + outpdimm->tDQSQ_max_ps = tDQSQ_max_ps; + outpdimm->tQHS_ps = tQHS_ps; + + /* + * 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; + if (!dimm_params[i].registered_dimm) + temp2 = 1; + } + } + + outpdimm->all_DIMMs_registered = 0; + if (temp1 && !temp2) { + outpdimm->all_DIMMs_registered = 1; + } + + outpdimm->all_DIMMs_unbuffered = 0; + if (!temp1 && temp2) { + outpdimm->all_DIMMs_unbuffered = 1; + } + + /* CHECKME: */ + if (!outpdimm->all_DIMMs_registered + && !outpdimm->all_DIMMs_unbuffered) { + printf("ERROR: Mix of registered buffered and unbuffered DIMMs detected!\n"); + } + + + /* + * 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; + /* + * FIXME: 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 retursn 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 its 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) { + if (mclk_ps >= dimm_params[i].tCKmin_X_minus_1_ps) { + debug("CL = %u ok on DIMM %u at tCK=%u ps with its tCKmin_X_minus_1_ps of %u\n", + temp2, i, mclk_ps, dimm_params[i].tCKmin_X_minus_1_ps); + continue; + } else { + not_ok++; + } + } + + if (dimm_params[i].caslat_X_minus_2 == temp2) { + if (mclk_ps >= dimm_params[i].tCKmin_X_minus_2_ps) { + debug("CL = %u ok on DIMM %u at tCK=%u ps with its tCKmin_X_minus_2_ps of %u\n", + temp2, i, mclk_ps, dimm_params[i].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); + + + /* + * 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 != 2) { + temp1 = 0; + break; + } + } + if (temp1) { + debug("all DIMMs ECC capable\n"); + } else { + debug("Warning: not all DIMMs ECC capable, can't enable ECC\n"); + } + outpdimm->all_DIMMs_ECC_capable = temp1; + + + /* + * FIXME: move to somewhere else to validate. + */ + if (mclk_ps > tCKmax_max_ps) { + printf("Warning: ome of the installed DIMMs can not operate this slowly.\n"); + return 1; + } + + /* + * 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, FIXME additive latency determination + * + * 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_FSL_DDR2) + if (lowest_good_caslat < 4) { + additive_latency = picos_to_mclk(tRCD_ps) - lowest_good_caslat; + if (mclk_to_picos(additive_latency) > tRCD_ps) { + additive_latency = picos_to_mclk(tRCD_ps); + debug("setting additive_latency to %u because it was greater than tRCD_ps\n", additive_latency); + } + } + +#elif defined(CONFIG_FSL_DDR3) +error "FIXME determine additive latency for DDR3" +#endif + + /* + * Validate additive latency + * FIXME: move to somewhere else to validate + * + * AL <= tRCD(min) + */ + if (mclk_to_picos(additive_latency) > tRCD_ps) { + printf("Error: invalid additive latency exceeds tRCD(min).\n"); + return 1; + } + + /* + * FIXME: RL = CL + AL; RL >= 3 for ODT_RD_CFG to be enabled + * FIXME: WL = RL - 1; WL >= 3 for ODT_WL_CFG to be enabled + * FIXME: ADD_LAT (the register) must be set to a value less + * FIXME: than ACTTORW if WL = 1, then AL must be set to 1 + * FIXME: RD_TO_PRE (the register) must be set to a minimum + * FIXME: tRTP + AL if AL is nonzero + */ + + /* + * Additive latency will be applied only if the memctl option to + * use it. + */ + outpdimm->additive_latency = additive_latency; + + return 0; +} + +/* + * Dummy function to init memctl options -- ultimately want an + * interactive version of this function + */ +unsigned int +populate_memctl_options(const common_timing_params_t *pcommon_params, + memctl_options_t *popts, + unsigned int ctrl_num) +{ + unsigned int i; + + /* + * Chip select options. + */ + + /* + * Pick chip-select local options. + */ + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + /* + * If not DDR2, odt_rd_cfg and odt_wr_cfg need to be 0. + */ + + /* only for single CS? */ + popts->cs_local_opts[i].odt_rd_cfg = 0; + + popts->cs_local_opts[i].odt_wr_cfg = 1; + popts->cs_local_opts[i].auto_precharge = 0; + } + + /* + * Pick interleaving mode. + */ + + /* + * 0 = no interleaving + * 1 = interleaving between 2 controllers + */ + popts->memctl_interleaving = 0; + + /* + * 0 = cacheline + * 1 = page + * 2 = (logical) bank + * 3 = superbank (only if CS interleaving is enabled) + */ + popts->memctl_interleaving_mode = 0; + + /* + * 0: cacheline: bit 30 of the 36-bit physical addr selects the memctl + * 1: page: bit to the left of the column bits selects the memctl + * 2: bank: bit to the left of the bank bits selects the memctl + * 3: superbank: bit to the left of the chip select selects the memctl + * + * NOTE: ba_intlv (rank interleaving) is independent of memory + * controller interleaving; it is only within a memory controller. + * Must use superbank interleaving if rank interleaving is used and + * memory controller interleaving is enabled. + */ + + /* + * 0 = no + * 0x40 = CS0,CS1 + * 0x20 = CS2,CS3 + * 0x60 = CS0,CS1 + CS2,CS3 + * 0x04 = CS0,CS1,CS2,CS3 + */ + popts->ba_intlv_ctl = 0; + + + /* + * Memory Organization Parameters + */ + popts->registered_dimm_en = pcommon_params->all_DIMMs_registered; + + + /* + * Operational Mode Paramters + */ + + /* + * Pick SDRAM type + * + * 2 = DDR1 + * 3 = DDR2 + * 6 = LPDDR1 + * 7 = DDR3 + */ + popts->sdram_type = fsl_ddr_sdram_type_function(); + + /* + * Pick ECC modes + */ + popts->ECC_mode = 0; /* 0 = disabled, 1 = enabled */ + popts->ECC_init_using_memctl = 1; /* 0 = use DMA, 1 = use memctl */ + + + /* + * Choose DQS config + */ + popts->DQS_config = 1; /* 0 for DDR1, 1 for DDR2 */ + + /* + * Choose self-refresh during sleep. + */ + popts->self_refresh_in_sleep = 1; + + /* + * Choose dynamic power management mode. + */ + popts->dynamic_power = 0; + + /* + * Choose dynamic power management mode. + * + * 0 = 64-bit + * 1 = 32-bit + * 2 = 16-bit + */ + popts->data_bus_width = 0; + + + /* + * Choose burst length. + */ + popts->burst_length = 4; /* has to be 4 for DDR2 */ + + /* + * Global Timing Parameters. + */ + debug("mclk_ps = %u ps\n", get_memory_clk_period_ps()); + + /* + * Pick a caslat override. + */ + popts->cas_latency_override = 0; + popts->cas_latency_override_value = 3; + if (popts->cas_latency_override) { + debug("using caslat override value = %u\n", + popts->cas_latency_override_value); + } + + /* + * Decide whether to use the computed dereated latency + */ + popts->use_derated_caslat = 0; // XXX: ought to be board-specific? + + /* + * Choose an additive latency. + */ + popts->additive_latency_override = 0; + popts->additive_latency_override_value = 3; + if (popts->additive_latency_override) { + debug("using additive latency override value = %u\n", + popts->additive_latency_override_value); + } + + /* + * Compute write latency. + * + * Total write latency = WR_LAT + ADD_LAT + * WL = Read latency - 1 = CL + AL - 1 + */ + + /* + * popts->write_latency = popts->cas_latency + * + popts->additive_latency - 1; + */ + + /* + * Select clock adjust + * + * Factors to consider for clock adjust: + * - number of chips on bus + * - position of slot + * - DDR1 vs. DDR2? + * - ??? + * + * This needs to be determined on a board-by-board basis. + */ + popts->clk_adjust = fsl_ddr_sdram_clk_adjust_function(); + + /* + * Select CPO override + * + * Dactors to consider for CPO: + * - frequency + * - ddr1 vs. ddr2 + */ + popts->cpo_override = fsl_ddr_sdram_cpo_override_function(); + + /* + * Select write data delay + * + * Factors to consider for write data delay: + * - number of DIMMs + * + * 1 = 1/4 clock delay + * 2 = 1/2 clock delay + * 3 = 3/4 clock delay + * 4 = 1 clock delay + * 5 = 5/4 clock delay + * 6 = 3/2 clock delay + */ + popts->write_data_delay = fsl_ddr_sdram_write_data_delay_function(); + + /* + * FIXME -- Move to a board-specific file + * + * Half-strength driver enable + * + * Factors to consider for half-strength driver enable: + * - number of DIMMs installed + */ + popts->half_strength_driver_enable + = fsl_ddr_sdram_half_strength_driver_enable_function(); + + + /* + * 2T_EN setting + * + * Factors to consider for 2T_EN: + * - number of DIMMs installed + * - number of components, number of active ranks + * - how much time you want to spend playing around + */ + +// popts->twoT_en = 0; + popts->twoT_en = 1; +// popts->threeT_en = 1; /* XXX: 3T_EN, 8572 */ + popts->threeT_en = 0; /* XXX: 3T_EN, 8572 */ + + /* + * BSTTOPRE precharge interval + * + * Set this to 0 for global auto precharge + * + * FIXME: Should this be configured in picoseconds? + * Why it should be in ps: better understanding of this + * relative to actual DRAM timing parameters such as tRAS. + * e.g. tRAS(min) = 40 ns + */ + popts->bstopre = 1000; + + /* + * Minimum CKE pulse width -- tCKE(MIN) + */ + popts->tCKE_clock_pulse_width_ps + = mclk_to_picos(FSL_DDR_MIN_TCKE_PULSE_WIDTH_DDR); + + /* + * Window for four activates -- tFAW + * + * FIXME: UM: applies only to DDR2/DDR3 with eight logical banks only + * FIXME: varies depending upon number of column addresses or data + * FIXME: width, was considering looking at pdimm->primary_sdram_width + */ +#if defined(CONFIG_FSL_DDR1) + popts->tFAW_window_four_activates_ps = mclk_to_picos(1); + +#elif defined(CONFIG_FSL_DDR2) + // x4/x8; some datasheets have 35000 + popts->tFAW_window_four_activates_ps = 37500; + // x16 wide columns only? +// popts->tFAW_window_four_activates_ps = 50000; + +#elif defined(CONFIG_FSL_DDR3) +#error "FIXME determine four activates for DDR3" +#endif + + + /* + * Checks + */ + + /* + * CAS latency plus additive latency must be at least 3 cycles + * for ODT_RD_CFG to be enabled. + */ +#if 0 + /* + * This check should be in fsl ddr regs. + */ + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + if (popts->cs_local_opts[i].odt_rd_cfg) { + if (popts->cas_latency_override_value + popts->additive_latency_override_value < 3) { + printf("CHECKME: CAS latency and Additive latency must be at least 3 cycles for ODT_RD_CFG to be enabled (chip select = %u)\n", i); + } + } + } +#endif + +#if 0 + /* + * This check should be in fsl ddr regs. + */ + + /* + * Write latency plus additive latency must be at least 3 cycles + * for ODT_WR_CFG to be enabled. + */ + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + if (popts->cs_local_opts[i].odt_wr_cfg) { + if (popts->write_latency + popts->additive_latency < 3) { + printf("CHECKME: Write Latency plus Additive Latency must be at least 3 cycles for ODT_WR_CFG to be enabled\n"); + } + } + } +#endif + + /* + * ODT should only be used for DDR2 + */ + + /* FIXME? */ + + /* + * Interleaving checks. + * + * If memory controller interleaving is enabled, then the data + * bus widths must be programmed identically for the 2 memory + * controllers. + */ + + return 0; +} + + + +/* + * Maybe all of these register related functions should go into + * chip-specific file. + */ + +void +reset_fsl_memctl_config_regs(fsl_memctl_config_regs_t *ddr) +{ + unsigned int i; + + /* FIMME: why not just memset */ + + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + ddr->cs[i].bnds = 0; + ddr->cs[i].config = 0; + ddr->cs[i].config_2 = 0; + } + + ddr->timing_cfg_3 = 0; + ddr->timing_cfg_0 = 0; + ddr->timing_cfg_1 = 0; + ddr->timing_cfg_2 = 0; + ddr->ddr_sdram_cfg = 0; + ddr->ddr_sdram_cfg_2 = 0; + ddr->ddr_sdram_mode = 0; + ddr->ddr_sdram_mode_2 = 0; + ddr->ddr_sdram_interval = 0; + ddr->ddr_data_init = 0; + ddr->ddr_sdram_clk_cntl = 0; + ddr->ddr_init_addr = 0; + ddr->ddr_init_ext_addr = 0; + ddr->timing_cfg_4 = 0; + ddr->timing_cfg_5 = 0; + ddr->ddr_zq_cntl = 0; + ddr->ddr_wrlvl_cntl = 0; + ddr->ddr_pd_cntl = 0; + ddr->ddr_sr_cntr = 0; + ddr->ddr_sdram_rcw_1 = 0; + ddr->ddr_sdram_rcw_2 = 0; +} + +unsigned int +check_fsl_memctl_config_regs(const fsl_memctl_config_regs_t *ddr) +{ + unsigned int res = 0; + + /* + * Check that DDR_SDRAM_CFG[RD_EN] and DDR_SDRAM_CFG[2T_EN] are + * not set at the same time. + */ + if (ddr->ddr_sdram_cfg & 0x10000000 + && ddr->ddr_sdram_cfg & 0x00008000) { + printf("Error: DDR_SDRAM_CFG[RD_EN] and DDR_SDRAM_CFG[2T_EN] should not be set at the same time.\n"); + res++; + } + + return res; +} + +static unsigned int +compute_fsl_memctl_config_regs(const memctl_options_t *popts, + fsl_memctl_config_regs_t *ddr, + const common_timing_params_t *common_dimm, + const dimm_params_t *dimm_parameters, + unsigned int dbw_capacity_adjust) +{ + unsigned int i; + unsigned int cas_latency; + unsigned int additive_latency; + + reset_fsl_memctl_config_regs(ddr); + + if (common_dimm == NULL) { + printf("Error: subset DIMM params struct null pointer\n"); + return 1; + } + + /* + * Process overrides first. + * + * FIXME: somehow add dereated caslat to this + */ + cas_latency = (popts->cas_latency_override) + ? popts->cas_latency_override_value + : common_dimm->lowest_common_SPD_caslat; + + additive_latency = (popts->additive_latency_override) + ? popts->additive_latency_override_value + : common_dimm->additive_latency; + + /* + * Chip Select Memory Bounds (CSn_BNDS) + */ + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + if (popts->ba_intlv_ctl && i > 0) { + /* + * Do not set up boundaries if bank interleaving + * is used. + */ + break; + } + + if (dimm_parameters[i/2].n_ranks == 0) { + debug("Skipping setup of CS%u because n_ranks on DIMM %u is 0\n", i, i/2); + continue; + } + + { + phys_size_t sa = 0; + phys_size_t ea = 0; + + if (dimm_parameters[i/2].n_ranks) { + + if (popts->memctl_interleaving + && popts->ba_intlv_ctl) { + /* + * This works superbank 2CS + * There are 2 memory + * controllers configured + * identically, memory is + * interleaved between them, and + * each controller uses rank + * interleaving within itself. + * Therefore the starting and + * ending address on each + * controller is twice the + * amount present on each + * controller. + */ + ea = (2 * common_dimm->total_mem >> dbw_capacity_adjust) - 1; + + } else if (! popts->memctl_interleaving + && popts->ba_intlv_ctl) { + /* + * If memory interleaving + * between controllers is NOT + * enabled, the starting address + * for each memory controller is + * distinct. However, because + * rank interleaving is enabled, + * the starting and ending + * addresses of the total memory + * on that memory controller + * needs to be programmed into + * its respective CS0_BNDS. + */ + sa = common_dimm->base_address; + ea = sa + (common_dimm->total_mem >> dbw_capacity_adjust)- 1; + + } else if (popts->memctl_interleaving + && !popts->ba_intlv_ctl) { + /* + * Only the rank on CS0 of each + * memory controller may be used + * if memory controller + * interleaving is used without + * rank interleaving within each + * memory controller. However, + * the ending address programmed + * into each CS0 must be the sum + * of the amount of memory in + * the two CS0 ranks. + */ + if (i == 0) { + ea = (2 * (dimm_parameters[0].rank_density >> dbw_capacity_adjust)) - 1; + } + + } else if (!popts->memctl_interleaving + && !popts->ba_intlv_ctl) { + /* + * No rank interleaving and no + * memory controller + * interleaving. + */ + sa = dimm_parameters[i/2].base_address; + ea = sa + (dimm_parameters[i/2].rank_density >> dbw_capacity_adjust) - 1; + if (i&1) { + if ((dimm_parameters[i/2].n_ranks == 1)) { + /* + * Odd chip select, + * single-rank dimm + */ + sa = 0; + ea = 0; + } else { + /* + * Odd chip select, + * dual-rank DIMM + */ + sa += dimm_parameters[i/2].rank_density >> dbw_capacity_adjust; + ea += dimm_parameters[i/2].rank_density >> dbw_capacity_adjust; + } + } + } + } + + sa >>= 24; + ea >>= 24; + + /* + * FIXME: 32-bit physical ram versions use 2 nibbles + * FIXME: 36-bit physical ram versions use 3 nibbles + */ + ddr->cs[i].bnds = (0 + | ((sa & 0xFFF) << 16) /* starting address MSB */ + | ((ea & 0xFFF) << 0) /* ending address MSB */ + ); + } + + /* + * Chip Select Configuration (CSn_CONFIG) + */ + { + /* CS_n_EN: Chip Select enable */ + unsigned int cs_n_en; + /* INTLV_EN: Memory controller interleave enable */ + unsigned int intlv_en; + /* INTLV_CTL: Interleaving control */ + unsigned int intlv_ctl; + /* AP_n_EN: Chip select n auto-precharge enable */ + unsigned int ap_n_en; + /* ODT_RD_CFG: ODT for reads configuration */ + unsigned int odt_rd_cfg; + /* ODT_WR_CFG: ODT for writes configuration */ + unsigned int odt_wr_cfg; + /* BA_BITS_CS_n: Number of bank bits for SDRAM on chip select n */ + unsigned int ba_bits_cs_n; + /* ROW_BITS_CS_n: Number of row bits for SDRAM on chip select n */ + unsigned int row_bits_cs_n; + /* + * COL_BITS_CS_n: Number of ocl bits for + * SDRAM on chip select n + */ + unsigned int col_bits_cs_n; + + cs_n_en = 0; + intlv_en = 0; + intlv_ctl = 0; + ap_n_en = 0; + odt_rd_cfg = 0; + odt_wr_cfg = 0; + ba_bits_cs_n = 0; + row_bits_cs_n = 0; + col_bits_cs_n = 0; + + /* + * Compute CS_CONFIG only for existing ranks + * of each DIMM. + */ + if ((((i&1) == 0) + && (dimm_parameters[i/2].n_ranks == 1)) + || (dimm_parameters[i/2].n_ranks == 2)) { + cs_n_en = 1; + if (i == 0) { + /* + * These fields only available + * in CS0_CONFIG + */ + intlv_en = popts->memctl_interleaving; + intlv_ctl = popts->memctl_interleaving_mode; + } + ap_n_en = popts->cs_local_opts[i].auto_precharge; + odt_rd_cfg = popts->cs_local_opts[i].odt_rd_cfg; + odt_wr_cfg = popts->cs_local_opts[i].odt_wr_cfg; + ba_bits_cs_n = __ilog2(dimm_parameters[i/2].n_banks_per_sdram_device) - 2; + row_bits_cs_n = dimm_parameters[i/2].n_row_addr - 12; + col_bits_cs_n = dimm_parameters[i/2].n_col_addr - 8; + } + + /* + * FIXME: intlv_en, intlv_ctl only on CS0_CONFIG + */ + if (i != 0) { + intlv_en = 0; + intlv_ctl = 0; + } + + ddr->cs[i].config = (0 + | ((cs_n_en & 0x1) << 31) + | ((intlv_en & 0x3) << 29) + | ((intlv_en & 0xf) << 24) + | ((ap_n_en & 0x1) << 23) + + /* + * XXX: some implementation only have 1 bit + * starting at left. + */ + | ((odt_rd_cfg & 0x7) << 20) + + /* + * FIXME: Some implementation + * only have 1 bit starting at left. + */ + | ((odt_wr_cfg & 0x7) << 16) + + | ((ba_bits_cs_n & 0x3) << 14) + | ((row_bits_cs_n & 0x7) << 8) + | ((col_bits_cs_n & 0x7) << 0) + ); + } + + /* + * Chip Select Configuration 2 (CSn_CONFIG_2) + */ + + /* FIXME: 8572 */ + + { + /* PASR_CFG: Partial array self refresh config */ + unsigned int pasr_cfg; + + pasr_cfg = 0; + ddr->cs[i].config_2 = ((pasr_cfg & 7) << 24); + } + } + + /* + * -3E = 667 CL5, -25 = CL6 800, -25E = CL5 800 + */ + +#if defined(CONFIG_FSL_DDR2) + /* + * DDR SDRAM Timing Configuration 0 (TIMING_CFG_0) + * + * Avoid writing for DDR I. The new PQ38 DDR controller + * dreams up non-zero default values to be backwards compatible. + */ + { + unsigned char trwt_mclk; /* RWT: Read-to-write turnaround */ + unsigned char twrt_mclk; /* WRT: Write-to-read turnaround */ + + /* 7.5 ns on -3E; 0 means WL - CL + BL/2 + 1 */ + unsigned char trrt_mclk; /* RRT: Read-to-read turnaround */ + unsigned char twwt_mclk; /* WWT: Write-to-write turnaround */ + + /* + * ACT_PD_EXIT: Active powerdown exit timing + * (tXARD and tXARDS). Empirical? + */ + unsigned char act_pd_exit_mclk; + + /* + * FIXME: tXARD = 2, tXARDS = 7 - AL + * PRE_PD_EXIT: Precharge powerdown exit timing (tXP). + * Empirical? + */ + unsigned char pre_pd_exit_mclk; + + /* FIXME: tXP = 2 on Micron 667 MHz DIMM */ + /* ODT_PD_EXIT: Precharge powerdown exit timing (tAXPD). */ + unsigned char taxpd_mclk; + + /* MRS_CYC: Mode register set cycle time (tMRD). */ + unsigned char tmrd_mclk; + + /* + * FIXME: Are these configurable? + */ + trwt_mclk = 0; /* RWT: Read-to-write turnaround */ + twrt_mclk = 0; /* WRT: Write-to-read turnaround */ + /* 7.5 ns on -3E; 0 means WL - CL + BL/2 + 1 */ + trrt_mclk = 0; /* RRT: Read-to-read turnaround */ + twwt_mclk = 0; /* WWT: Write-to-write turnaround */ + + /* + * ACT_PD_EXIT: Active powerdown exit timing + * (tXARD and tXARDS). Empirical? + */ + act_pd_exit_mclk = 2; + + /* + * XXX: tXARD = 2, tXARDS = 7 - AL + * + * PRE_PD_EXIT: Precharge powerdown exit timing (tXP). + * Empirical? + */ + pre_pd_exit_mclk = 6; + + /* + * FIXME: tXP = 2 on Micron 667 MHz DIMM + * + * ODT_PD_EXIT: Precharge powerdown exit timing (tAXPD). + * FIXME: configurable? + */ + taxpd_mclk = 8; + + /* + * MRS_CYC: Mode register set cycle time (tMRD). + * FIXME: configurable? + */ + tmrd_mclk = 2; + + ddr->timing_cfg_0 = (0 + | ((trwt_mclk & 0x3) << 30) /* RWT */ + | ((twrt_mclk & 0x3) << 28) /* WRT */ + | ((trrt_mclk & 0x3) << 26) /* RRT */ + | ((twwt_mclk & 0x3) << 24) /* WWT */ + | ((act_pd_exit_mclk & 0x7) << 20) /* ACT_PD_EXIT */ + | ((pre_pd_exit_mclk & 0x7) << 16) /* PRE_PD_EXIT */ + | ((taxpd_mclk & 0xf) << 8) /* ODT_PD_EXIT */ + | ((tmrd_mclk & 0xf) << 0) /* MRS_CYC */ + ); +// printf("FSLDDR: timing_cfg_0 = 0x%08x\n", ddr->timing_cfg_0); + } +#endif /* defined(CONFIG_FSL_DDR2) */ + + + /* + * DDR SDRAM Timing Configuration 3 (TIMING_CFG_3) + */ + { + /* + * EXT_ACTTOPRE: Extended Activate to precharge interval + * (tRAS) + */ + unsigned int ext_refrec; + + ext_refrec = (picos_to_mclk(common_dimm->tRFC_ps) - 8) >> 4; + ddr->timing_cfg_3 = (0 + | ((ext_refrec & 0x7) << 16) /* EXT_ACTTOPRE */ + ); + } + + /* + * DDR SDRAM Timing Configuration 1 (TIMING_CFG_1) + */ + { + /* PRETOACT: Precharge-to-activate interval (tRP) */ + unsigned char pretoact_mclk; + /* ACTTOPRE: Activate to precharge interval (tRAS) */ + unsigned char acttopre_mclk; + /* ACTTORW: Activate to read/write interval (tRCD) */ + unsigned char acttorw_mclk; + /* CASLAT */ + unsigned char caslat_ctrl; + /* REFREC: Refresh recovery time (tRFC) ; trfc_low */ + unsigned char refrec_ctrl; + /* WRREC: Last data to precharge minimum interval (tWR) */ + unsigned char wrrec_mclk; + /* ACTTOACT: Activate-to-activate interval (tRRD) */ + unsigned char acttoact_mclk; + /* + * WRTTORD: Last write data pair to read + * command issue interval (tWTR) + */ + unsigned char wrtord_mclk; + + pretoact_mclk = picos_to_mclk(common_dimm->tRP_ps); + acttopre_mclk = picos_to_mclk(common_dimm->tRAS_ps); + acttorw_mclk = picos_to_mclk(common_dimm->tRCD_ps); + +#if defined(CONFIG_FSL_DDR1) + caslat_ctrl = (cas_latency + 1) & 0x07; +#elif defined(CONFIG_FSL_DDR2) + caslat_ctrl = 2 * cas_latency - 1; +#elif defiend(CONFIG_FSL_DDR2) +#error "Need CAS Latency help for DDR3 in fsl_ddr_sdram.c" +#endif + + refrec_ctrl = picos_to_mclk(common_dimm->tRFC_ps) - 8; + wrrec_mclk = picos_to_mclk(common_dimm->tWR_ps); + acttoact_mclk = picos_to_mclk(common_dimm->tRRD_ps); + wrtord_mclk = picos_to_mclk(common_dimm->tWTR_ps); + + ddr->timing_cfg_1 = (0 + | ((pretoact_mclk & 0x07) << 28) /* PRETOACT */ + | ((acttopre_mclk & 0x0F) << 24) /* ACTTOPRE */ + | ((acttorw_mclk & 0x7) << 20) /* ACTTORW */ + | ((caslat_ctrl & 0xF) << 16) /* CASLAT */ + | ((refrec_ctrl & 0xF) << 12) /* REFEC */ + | ((wrrec_mclk & 0x07) << 8) /* WRRREC */ + | ((acttoact_mclk & 0x07) << 4) /* ACTTOACT */ + | ((wrtord_mclk & 0x07) << 0) /* WRTORD */ + ); + } + + /* + * DDR SDRAM Timing Configuration 2 (TIMING_CFG_2) + */ + { + /* ADD_LAT: Additive latency */ + unsigned char add_lat_mclk; + /* CPO: CAS-to-preamble override */ + unsigned short cpo; + /* WR_LAT: Write latency */ + unsigned char wr_lat; + /* RD_TO_PRE: Read to precharge (tRTP) */ + unsigned char rd_to_pre; + /* + * WR_DATA_DELAY: Write command to write data + * strobe timing adjustment + */ + unsigned char wr_data_delay; + /* CKE_PLS: Minimum CKE pulse width (tCKE) */ + unsigned char cke_pls; + /* Window for four activates (tFAW) */ + unsigned short four_act; + + /* FIXME add check that this must be less than acttorw_mclk */ + add_lat_mclk = additive_latency; + cpo = popts->cpo_override; +#if 0 + wr_lat = popts->write_latency; +#endif + wr_lat = cas_latency + additive_latency - 1; + + rd_to_pre = picos_to_mclk(common_dimm->tRTP_ps); + wr_data_delay = popts->write_data_delay; + cke_pls = picos_to_mclk(popts->tCKE_clock_pulse_width_ps); + four_act = picos_to_mclk(popts->tFAW_window_four_activates_ps); + + + ddr->timing_cfg_2 = (0 + | ((add_lat_mclk & 0x7) << 28) /* ADD_LAT */ + | ((cpo & 0x1f) << 23) /* CPO */ + | ((wr_lat & 0x7) << 19) /* WR_LAT */ + | ((rd_to_pre & 0x7) << 13) /* RD_TO_PRE */ + | ((wr_data_delay & 0x7) << 10) /* WR_DATA_DELAY */ + | ((cke_pls & 0x7) << 6) /* CKE_PLS */ + | ((four_act & 0x1f) << 0) /* FOUR_ACT */ + ); + } + + /* + * DDR SDRAM control configuration (DDR_SDRAM_CFG) + */ + { + /* MEM_EN: DDR SDRAM interface logic enable */ + unsigned int mem_en; + /* SREN: Self refresh enable (during sleep) */ + unsigned int sren; + unsigned int ecc_en; /* ECC_EN: ECC enable. */ + unsigned int rd_en; /* RD_EN: Registered DIMM enable */ + unsigned int sdram_type; /* SDRAM_TYPE: Type of SDRAM */ + /* DYN_PWR: Dynamic power management mode */ + unsigned int dyn_pwr; + unsigned int dbw; /* DBW: DRAM dta bus width */ + unsigned int eight_be; /* 8_BE: 8-beat burst enable */ + unsigned int ncap; /* NCAP: Non-concurrent auto-precharge */ + unsigned int threeT_en; /* 3T_EN: Enable 3T timing */ + unsigned int twoT_en; /* 2T_EN: Enable 2T timing */ + /* BA_INTLV_CTL: Bank (chip select) interleaving control */ + unsigned int ba_intlv_ctl; + unsigned int x32_en; /* X32_EN: x32 enable */ + unsigned int pchb8; /* PCHB8: precharge bit 8 enable */ + unsigned int hse; /* HSE: Global half strength override */ + /* MEM_HALT: DDR memory controller halt */ + unsigned int mem_halt; + unsigned int bi; /* BI: Bypass initialization */ + + mem_en = 1; + sren = popts->self_refresh_in_sleep; + if (common_dimm->all_DIMMs_ECC_capable) { + /* + * Allow setting of ECC only if all DIMMs are ECC. + */ + ecc_en = popts->ECC_mode; + } else { + ecc_en = 0; + } + +// rd_en = popts->registered_dimm_en; + + rd_en = (common_dimm->all_DIMMs_registered + && !common_dimm->all_DIMMs_unbuffered); + + sdram_type = 3; /* 3 = DDR2 */ + dyn_pwr = popts->dynamic_power; + dbw = popts->data_bus_width; + eight_be = 0; /* always 0 for DDR2 */ + ncap = 0; + threeT_en = 0; /* FIXME: make this configurable */ + twoT_en = popts->twoT_en; + ba_intlv_ctl = popts->ba_intlv_ctl; + x32_en = 0; + pchb8 = 0; + hse = popts->half_strength_driver_enable; + mem_halt = 0; + bi = 0; + + ddr->ddr_sdram_cfg = (0 + | ((mem_en & 0x1) << 31) /* MEM_EN */ + | ((sren & 0x1) << 30) /* SREN */ + | ((ecc_en & 0x1) << 29) /* ECC_EN */ + | ((rd_en & 0x1) << 28) /* RD_EN */ + | ((sdram_type & 0x7) << 24) /* SDRAM_TYPE*/ + | ((dyn_pwr & 0x1) << 21) /* DYN_PWR */ + | ((dbw & 0x3) << 19) /* DBW */ + | ((eight_be & 0x1) << 18) /* 8_BE */ + | ((ncap & 0x1) << 17) /* NCAP */ + | ((threeT_en & 0x1) << 16) /* 3T_EN */ + | ((twoT_en & 0x1) << 15) /* 2T_EN */ + | ((ba_intlv_ctl & 0x7F) << 8) /*BA_INTLV_CTL*/ + | ((x32_en & 0x1) << 5) /* x32_EN */ + | ((pchb8 & 0x1) << 4) /* PCHB8 */ + | ((hse & 0x1) << 3) /* HSE */ + | ((mem_halt & 0x1) << 1) /* MEM_HALT */ + | ((bi & 0x1) << 0) /* BI */ + ); + } + + /* + * DDR SDRAM control configuration 2 (DDR_SDRAM_CFG_2) + */ + { + unsigned int frc_sr; /* FRC_SR: Force self refresh */ + unsigned int sr_ie; /* SR_IE: Self-refresh interrupt enable */ + unsigned int dll_rst_dis; /* DLL_RST_DIS: DLL reset disable */ + unsigned int dqs_cfg; /* DQS_CFG: DQS configuration */ + unsigned int odt_cfg; /* ODT_CFG: ODT configuration */ + unsigned int num_pr; /* NUM_PR: Number of posted refreshes */ + unsigned int obc_cfg; /* On-The-Fly Burst Chop Configuration */ + unsigned int ap_en; /* AP_EN: Address Parity Enable */ + unsigned int d_init; /* D_INIT: DRAM data initialization */ + unsigned int rcw_en; /* Register Control Word Enable */ + unsigned int md_en; /* MD_EN: Mirrored DIMM Enable */ + + frc_sr = 0; + sr_ie = 0; +// dll_rst_dis = 0; + dll_rst_dis = 1; /* Make this configurable */ + dqs_cfg = popts->DQS_config; + if (popts->cs_local_opts[0].odt_rd_cfg + || popts->cs_local_opts[0].odt_wr_cfg) { + /* FIXME */ + odt_cfg = 2; + } else { + odt_cfg = 0; + } + + num_pr = 1; /* Make this configurable */ + + /* + * 8572 manual says + * {TIMING_CFG_1[PRETOACT] + * + [DDR_SDRAM_CFG_2[NUM_PR] + * * ({EXT_REFREC || REFREC} + 8 + 2)]} + * << DDR_SDRAM_INTERVAL[REFINT] + */ + + obc_cfg = 0; /* Make this configurable? */ + ap_en = 0; /* Make this configurable? */ + d_init = 1; /* Make this configurable? */ +// d_init = 0; /* Make this configurable? */ + rcw_en = 0; + md_en = 0; + + ddr->ddr_sdram_cfg_2 = (0 + | ((frc_sr & 0x1) << 31) /* FRC_SR */ + | ((sr_ie & 0x1) << 30) /* SR_IE */ + | ((dll_rst_dis & 0x1) << 29) /* DLL_RST_DIS */ + | ((dqs_cfg & 0x3) << 26) /* DQS_CFG */ + | ((odt_cfg & 0x3) << 21) /* ODT_CFG */ + | ((num_pr & 0xf) << 12) /* NUM_PR */ + | ((obc_cfg & 0x1) << 6) /* OBC_CFG */ + | ((ap_en & 0x1) << 5) /* AP_EN */ + | ((d_init & 0x1) << 4) /* D_INIT */ + | ((rcw_en & 0x1) << 2) /* RCW_EN */ + | ((md_en & 0x1) << 0) /* MD_EN */ + ); + } + + /* + * DDR SDRAM Mode configuration set (DDR_SDRAM_MODE) + */ + { + unsigned short esdmode; /* Extended SDRAM mode */ + unsigned short sdmode; /* SDRAM mode */ + + /* + * FIXME: This ought to be pre-calculated in a + * technology-specific routine, + * e.g. compute_DDR2_mode_register(), and then the + * sdmode and esdmode passed in as part of common_dimm. + */ + + /* + * Extended Mode Register + */ + { + unsigned int mrs; /* MRS: Mode Register Set */ + unsigned int outputs; /* Outputs: 0=Enabled, 1=Disabled */ + unsigned int rdqs_en; /* RDQS Enable; 0=no, 1=yes */ + unsigned int dqs_en; /* DQS# Enable; 0=enable, 1=disable */ + unsigned int ocd; /* OCD Operation: 0x0=OCD not supported, 0x7=OCD default state */ + unsigned int rtt; /* Rtt(nominal): 0 = Rtt disabled, 1=75 ohm, 2=150 ohm, 3=50 ohm */ + unsigned int al; /* Posted CAS# additive latency (AL) */ + unsigned int ods; /* ODS: Output Drive Strength; 0 = Full strength (18ohm), 1=Reduced strength (4ohm) */ + unsigned int dll_en; /* DLL Enable; 0=Enable (Normal), 1=Disable (Test/Debug) */ + + mrs = 0; /* XXX: should this be 1? old code had it as 0 */ + outputs = 0; /* XXX: make this configurable? */ + rdqs_en = 0; /* XXX: make this configurable */ + dqs_en = 0; /* XXX: make this configurable */ + ocd = 0; /* XXX: make this configurable */ +//8641 rtt = 2; /* XXX: make this configurable -- this needs to be calculated */ + rtt = 3; /* XXX: make this configurable -- this needs to be calculated */ + +#if 0 + { + unsigned int i; + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL/2; i++) { + if (popts->dimmslot[i].num_valid_cs && (popts->cs_local_opts[2*i].odt_rd_cfg || popts->cs_local_opts[2*i].odt_wr_cfg)) { + rtt = 2; /* XXX: old code sez if 667 MHz or higher, use 3 on 8572 */ + break; + } + } + } +#endif + + al = additive_latency; + ods = 0; /* XXX: make this configurable */ + dll_en = 0; /* XXX: make this configurable */ + + esdmode = (0 + | ((mrs & 0x3) << 14) + | ((outputs & 0x1) << 12) + | ((rdqs_en & 0x1) << 11) + | ((dqs_en & 0x1) << 10) + | ((ocd & 0x7) << 7) + | ((rtt & 0x2) << 5) /* rtt field is split */ + | ((al & 0x7) << 3) + | ((rtt & 0x1) << 2) /* rtt field is split */ + | ((ods & 0x1) << 1) + | ((dll_en & 0x1) << 0) + ); + } + + /* + * Mode Register (MR) + */ + { + unsigned int mr; /* Mode Register Definition */ + unsigned int pd; /* PD: Power-Down Mode */ + unsigned int wr; /* WR: Write Recovery */ + unsigned int dll_res; /* DLL: DLL Reset */ + unsigned int mode; /* Mode: Normal=0 or Test=1 */ + unsigned int caslat; /* CAS# latency */ + /* BT: Burst Type (0=Sequential, 1=Interleaved) */ + unsigned int bt; + unsigned int bl; /* BL: Burst Length */ + + const unsigned int mclk_ps + = get_memory_clk_period_ps(); + + /* FIXME: CHECKME */ + + mr = 0; + + /* + * 0 = Fast Exit (Normal) + * 1 = Slow Exit (Low Power) + * FIXME: make this configurable + */ + pd = 0; + +// wr = 2; /* XXX: hack */ + /* + * FIXME: doesn't match old code? + * FIXME: need to look at this further + */ +// wr = (common_dimm->tWR_ps + mclk_ps - 1) / mclk_ps - 1; + wr = (common_dimm->tWR_ps + mclk_ps - 1) / mclk_ps - 1; + + dll_res = 0; /* FIXME: make this configurable */ + mode = 0; /* FIXME: make this configurable */ + + caslat = cas_latency; + bt = 0; /* FIXME: make this configurable? */ + + switch (popts->burst_length) { + case 4: + bl = 2; + break; + case 8: + bl = 3; + break; + default: + printf("Error: invalid burst length of %u specified. Defaulting to 4 beats.\n", popts->burst_length); + bl = 2; + break; + } + + sdmode = (0 + | ((mr & 0x3) << 14) + | ((pd & 0x1) << 12) + | ((wr & 0x7) << 9) + | ((dll_res & 0x1) << 8) + | ((mode & 0x1) << 7) + | ((caslat & 0x7) << 4) + | ((bt & 0x1) << 3) + | ((bl & 0x7) << 0) + ); + } + + ddr->ddr_sdram_mode = (0 + | ((esdmode & 0xFFFF) << 16) + | ((sdmode & 0xFFFF) << 0) + ); + } + + /* + * DDR SDRAM Mode configuration 2 (DDR_SDRAM_MODE_2) + */ + { + unsigned short esdmode2; /* Extended SDRAM mode 2 */ + unsigned short esdmode3; /* Extended SDRAM mode 3 */ + + esdmode2 = 0; /* FIXME: for now OK */ + esdmode3 = 0; + + ddr->ddr_sdram_mode_2 = (0 + | ((esdmode2 & 0xFFFF) << 16) + | ((esdmode3 & 0xFFFF) << 0) + ); + } + + /* + * DDR SDRAM Interval Configuration (DDR_SDRAM_INTERVAL) + */ + { + unsigned int refint; /* REFINT: Refresh interval */ + unsigned int bstopre; /* BSTOPRE: Precharge interval */ + +// refint = picos_to_mclk(pdimm->refresh_rate_ns * 1000); + refint = 1755; /* FIXME */ + + bstopre = popts->bstopre; + + /* + * FIXME: refint field used 0x3FFF in earlier controllers + */ + ddr->ddr_sdram_interval = (0 + | ((refint & 0xFFFF) << 16) + | ((bstopre & 0x3FFF) << 0) + ); + } + + /* + * DDR SDRAM Data Initialization (DDR_DATA_INIT) + */ + { + unsigned int init_value; /* Initialization value */ + + init_value = 0xDEADBEEF; /* FIXME: should be configurable */ + ddr->ddr_data_init = init_value; + } + + /* + * DDR SDRAM Clock Control (DDR_SDRAM_CLK_CNTL) + */ + { + unsigned int clk_adjust; /* Clock adjust */ + + clk_adjust = popts->clk_adjust; + ddr->ddr_sdram_clk_cntl = (clk_adjust & 0xF) << 23; + } + + /* + * DDR Initialization Address (DDR_INIT_ADDR) + */ + { + unsigned int init_addr; /* Initialization address */ + + init_addr = 0; + ddr->ddr_init_addr = init_addr; + } + + /* + * DDR Initialization Address (DDR_INIT_EXT_ADDR) + */ + { + unsigned int uia; /* Use initialization address */ + unsigned int init_ext_addr; /* Initialization address */ + + uia = 0; + init_ext_addr = 0; + + ddr->ddr_init_ext_addr = (0 + | ((uia & 0x1) << 31) + | (init_ext_addr & 0xF) + ); + } + + /* + * DDR SDRAM Timing Configuration 4 (TIMING_CFG_4) + */ + { + /* Read-to-write turnaround for same chip select */ + unsigned int rwt; + /* Write-to-read turnaround for same chip select */ + unsigned int wrt; + /* Read-to-read turnaround for same chip select */ + unsigned int rrt; + /* Write-to-write turnaround for same chip select */ + unsigned int wwt; + /* DDR SDRAM DLL Lock Time */ + unsigned int dll_lock; + + rwt = 0; + wrt = 0; + rrt = 0; + wwt = 0; + dll_lock = 0; + + ddr->timing_cfg_4 = (0 + | ((rwt & 0xf) << 28) + | ((wrt & 0xf) << 24) + | ((rrt & 0xf) << 20) + | ((wwt & 0xf) << 16) + | (dll_lock & 0x3) + ); + } + + /* + * DDR SDRAM Timing Configuration 5 (TIMING_CFG_5) + */ + { + unsigned int rodt_on; /* RODT_ON: Read to ODT on */ + unsigned int rodt_off; /* RODT_OFF: Read to ODT off */ + unsigned int wodt_on; /* WODT_ON: Write to ODT on */ + unsigned int wodt_off; /* WODT_OFF: Write to ODT off */ + + rodt_on = 0; + rodt_off = 0; + wodt_on = 0; + wodt_off = 0; + + ddr->timing_cfg_5 = (0 + | ((rodt_on & 0xf) << 24) + | ((rodt_off & 0xf) << 20) + | ((wodt_on & 0xf) << 12) + | ((wodt_off & 0xf) << 8) + ); + } + + /* + * DDR ZQ Calibration Control (DDR_ZQ_CNTL) + */ + { + unsigned int zq_en; /* ZE_EN: ZQ Calibration Enable */ + unsigned int zqinit; /* POR ZQ Calibration Time (tZQinit) */ + /* Normal Operation Full Calibration Time (tZQoper) */ + unsigned int zqoper; + /* ZQCS: Normal Operation Short Calibration Time (tZQCS) */ + unsigned int zqcs; + + zq_en = 0; + zqinit = 0; + zqoper = 0; + zqcs = 0; + + ddr->ddr_zq_cntl = (0 + | ((zq_en & 0x1) << 31) + | ((zqinit & 0xF) << 24) + | ((zqoper & 0xF) << 16) + | ((zqcs & 0xF) << 8) + ); + } + + /* + * DDR Write Leveling Control (DDR_WRLVL_CNTL) + */ + { + /* WRLVL_EN: Write Leveling Enable */ + unsigned int wrlvl_en; + /* + * First DQS pulse rising edge after margining mode + * is programmed (tWL_MRD) + */ + unsigned int wrlvl_mrd; + /* ODT delay after margining mode is programmed (tWL_ODTEN) */ + unsigned int wrlvl_odten; + /* + * DQS/DQS_ delay after margining mode is programmed + * (tWL_DQSEN) + */ + unsigned int wrlvl_dqsen; + /* WRLVL_SMPL: Write leveling sample time */ + unsigned int wrlvl_smpl; + /* WRLVL_WLR: Write leveling repeition time */ + unsigned int wrlvl_wlr; + /* WRLVL_START: Write leveling start time */ + unsigned int wrlvl_start; + + wrlvl_en = 0; + wrlvl_mrd = 0; + wrlvl_odten = 0; + wrlvl_dqsen = 0; + wrlvl_smpl = 0; + wrlvl_wlr = 0; + wrlvl_start = 0; + + ddr->ddr_wrlvl_cntl = (0 + | ((wrlvl_en & 0x1) << 31) + | ((wrlvl_mrd & 0x7) << 24) + | ((wrlvl_odten & 0x7) << 20) + | ((wrlvl_dqsen & 0x7) << 16) + | ((wrlvl_smpl & 0xf) << 12) + | ((wrlvl_wlr & 0x7) << 8) + | ((wrlvl_start & 0xF) << 0) + ); + } + + /* + * DDR Pre-Drive Conditioning Control (DDR_PD_CNTL) + */ + { + /* Termination value during pre-drive conditioning */ + unsigned int tvpd; + unsigned int pd_en; /* Pre-Drive Conditioning Enable */ + unsigned int pdar; /* Pre-Drive After Read */ + unsigned int pdaw; /* Pre-Drive After Write */ + unsigned int pd_on; /* Pre-Drive Conditioning On */ + unsigned int pd_off; /* Pre-Drive Conditioning Off */ + + pd_en = 0; + tvpd = 0; + pdar = 0; + pdaw = 0; + pd_on = 0; + pd_off = 0; + + ddr->ddr_pd_cntl = (0 + | ((pd_en & 0x1) << 31) + | ((tvpd & 0x7) << 28) + | ((pdar & 0x7F) << 20) + | ((pdaw & 0x7F) << 12) + | ((pd_on & 0x1F) << 6) + | ((pd_off & 0x1F) << 0) + ); + } + + /* + * DDR Self Refresh Counter (DDR_SR_CNTR) + */ + { + unsigned int sr_it; /* Self Refresh Idle Threshold */ + + sr_it = 0; + ddr->ddr_sr_cntr = (sr_it & 0xF) << 16; + } + + /* + * DDR SDRAM Register Control Word 1 (DDR_SDRAM_RCW_1) + */ + { + unsigned int rcw0; /* RCW0: Register Control Word 0 */ + unsigned int rcw1; /* RCW1: Register Control Word 1 */ + unsigned int rcw2; /* RCW2: Register Control Word 2 */ + unsigned int rcw3; /* RCW3: Register Control Word 3 */ + unsigned int rcw4; /* RCW4: Register Control Word 4 */ + unsigned int rcw5; /* RCW5: Register Control Word 5 */ + unsigned int rcw6; /* RCW6: Register Control Word 6 */ + unsigned int rcw7; /* RCW7: Register Control Word 7 */ + + rcw0 = 0; + rcw1 = 0; + rcw2 = 0; + rcw3 = 0; + rcw4 = 0; + rcw5 = 0; + rcw6 = 0; + rcw7 = 0; + + ddr->ddr_sdram_rcw_1 = (0 + | ((rcw0 & 0xF) << 28) + | ((rcw1 & 0xF) << 24) + | ((rcw2 & 0xF) << 20) + | ((rcw3 & 0xF) << 16) + | ((rcw4 & 0xF) << 12) + | ((rcw5 & 0xF) << 8) + | ((rcw6 & 0xF) << 4) + | ((rcw7 & 0xF) << 0) + ); + } + + /* + * DDR SDRAM Register Control Word 2 (DDR_SDRAM_RCW_2) + */ + { + unsigned int rcw8; /* RCW0: Register Control Word 8 */ + unsigned int rcw9; /* RCW1: Register Control Word 9 */ + unsigned int rcw10; /* RCW2: Register Control Word 10 */ + unsigned int rcw11; /* RCW3: Register Control Word 11 */ + unsigned int rcw12; /* RCW4: Register Control Word 12 */ + unsigned int rcw13; /* RCW5: Register Control Word 13 */ + unsigned int rcw14; /* RCW6: Register Control Word 14 */ + unsigned int rcw15; /* RCW7: Register Control Word 15 */ + + rcw8 = 0; + rcw9 = 0; + rcw10 = 0; + rcw11 = 0; + rcw12 = 0; + rcw13 = 0; + rcw14 = 0; + rcw15 = 0; + + ddr->ddr_sdram_rcw_2 = (0 + | ((rcw8 & 0xF) << 28) + | ((rcw9 & 0xF) << 24) + | ((rcw10 & 0xF) << 20) + | ((rcw11 & 0xF) << 16) + | ((rcw12 & 0xF) << 12) + | ((rcw13 & 0xF) << 8) + | ((rcw14 & 0xF) << 4) + | ((rcw15 & 0xF) << 0) + ); + } + + return 0; +} + +phys_size_t +fsl_ddr_sdram_compute(fsl_ddr_sdram_info_t *pinfo, unsigned int start_step) +{ + unsigned int i; + unsigned int j; + unsigned int all_controllers_memctl_interleaving = 0; + unsigned int all_controllers_rank_interleaving = 0; + phys_size_t cur_memsize = 0; + phys_size_t total_memory = 0; + + /* data bus width capacity adjust shift amount */ + unsigned int dbw_capacity_adjust[CONFIG_NUM_DDR_CONTROLLERS]; + + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + dbw_capacity_adjust[i] = 0; + } + + debug("starting at step %u (%s)\n", + start_step, step_to_string(__ilog2(start_step))); + + switch (start_step) { + case STEP_GET_SPD: + /* + * STEP 1: Gather all DIMM SPD data + */ + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + fsl_ddr_sdram_get_spd(pinfo->spd_installed_dimms[i], + i); + } + + case STEP_COMPUTE_DIMM_PARMS: + /* + * STEP 2: Compute DIMM parameters from SPD data + */ + + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { + unsigned int retval; + + retval = compute_dimm_parameters( + &(pinfo->spd_installed_dimms[i][j]), + &(pinfo->dimm_params[i][j]), + i); + if (retval) { + if (retval == 2) { + printf("Error: compute_dimm_parameters non-zero returned FATAL value for memctl=%u dimm=%u\n", i, j); + return 0; + } + debug("Warning: compute_dimm_parameters non-zero return value for memctl=%u dimm=%u\n", i, j); + } + } + } + + 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 = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + debug("Computing lowest common DIMM parameters for memctl=%u\n", i); + compute_lowest_common_dimm_parameters( + pinfo->dimm_params[i], + &pinfo->common_timing_params[i], + CONFIG_DIMM_SLOTS_PER_CTLR); + } + + case STEP_GATHER_OPTS: + /* + * STEP 4: Gather configuration requirements from user + */ + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; 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( + &pinfo->common_timing_params[i], + &pinfo->memctl_options[i], + i); + } + + case STEP_ASSIGN_ADDRESSES: + /* + * STEP 5: Assign addresses to chip selects + * FIXME + */ + + /* + * 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 = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + unsigned int found = 0; + + switch (pinfo->memctl_options[i].data_bus_width) { + case 2: + /* 16-bit */ + printf("can't handle 16-bit mode yet\n"); + break; + + case 1: + /* 32-bit */ + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { + if (pinfo->dimm_params[i][j].n_ranks + && (pinfo->dimm_params[i][j].data_width == 72 + || pinfo->dimm_params[i][j].data_width == 64)) { + /* + * FIXME: can't really do + * it like this because + * this just further + * reduces the memory + */ + found = 1; + break; + } + } + if (found) { + dbw_capacity_adjust[i] = 1; + /* FIXME: 2 for 16-bit bus? */ + } + break; + + case 0: + /* 64-bit */ + break; + + default: + printf("unexpected data bus width specified controller %u\n", i); + return 0; + break; + } + } + + /* + * Check if all controllers are configured for memory + * controller interleaving. + */ + j = 0; + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (pinfo->memctl_options[i].memctl_interleaving) { + j++; + } + } + if (j == 2) { + all_controllers_memctl_interleaving = 1; + } + + /* + * Check that all controllers are rank interleaving. + */ + j = 0; + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (pinfo->memctl_options[i].ba_intlv_ctl) { + j++; + } + } + if (j == 2) { + all_controllers_rank_interleaving = 1; + } + + if (all_controllers_memctl_interleaving) { + phys_addr_t addr; + + /* + * If interleaving between memory controllers, + * make each controller start at a base address + * of 0. + * + * Also, if bank interleaving (chip select + * interleaving) is enabled on each memory + * controller, CS0 needs to be programmed to + * cover the entire memory range on that memory + * controller + * + * Bank interleaving also implies that each + * addressed chip select is identical in size. + */ + + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + addr = 0; +/* pinfo->common_timing_params[i].base_address = addr; */ + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { + pinfo->dimm_params[i][j].base_address = addr; + addr += (phys_addr_t)(pinfo->dimm_params[i][j].dimm_capacity >> dbw_capacity_adjust[i]); + } + } + } else { + /* + * Simple linear assignment if memory + * controllers are not interleaved. + */ + cur_memsize = 0; + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + phys_size_t total_mem_per_memctl = 0; + pinfo->common_timing_params[i].base_address = (phys_addr_t)cur_memsize; + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { + /* + * Compute DIMM base addresses. + */ + pinfo->dimm_params[i][j].base_address = (phys_addr_t)cur_memsize; + cur_memsize+= pinfo->dimm_params[i][j].dimm_capacity >> dbw_capacity_adjust[i]; + total_mem_per_memctl += pinfo->dimm_params[i][j].dimm_capacity >> dbw_capacity_adjust[i]; + } + pinfo->common_timing_params[i].total_mem = total_mem_per_memctl; + } + } + + + case STEP_COMPUTE_REGS: + /* + * STEP 6: compute controller register values + */ + debug("FSL Memory controller configuration register computation\n"); + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + unsigned int retval; + + if (pinfo->common_timing_params[i].ndimms_present == 0) { + reset_fsl_memctl_config_regs( + &pinfo->fsl_ddr_config_reg[i]); + continue; + } + + compute_fsl_memctl_config_regs( + &pinfo->memctl_options[i], + &pinfo->fsl_ddr_config_reg[i], + &pinfo->common_timing_params[i], + pinfo->dimm_params[i], + dbw_capacity_adjust[i]); + + retval = check_fsl_memctl_config_regs( + &pinfo->fsl_ddr_config_reg[i]); + if (retval) { + printf("check_fsl_memctl_config_regs result = %u\n", retval); + } + } + + default: + break; + } + + + /* + * Compute the total amount of memory. + */ + + /* + * If bank interleaving but NOT memory controller interleaving + * CS_BNDS describe the quantity of memory on each memory + * controller, so the total is the sum across. + */ + if (!all_controllers_memctl_interleaving + && all_controllers_rank_interleaving) { + total_memory = 0; + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + total_memory += pinfo->common_timing_params[i].total_mem; + } + + } else { + /* + * 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 = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + for (j = 0; j < CONFIG_CHIP_SELECTS_PER_CTRL; j++) { + if (pinfo->fsl_ddr_config_reg[i].cs[j].config & 0x80000000) { + unsigned int end = pinfo->fsl_ddr_config_reg[i].cs[j].bnds & 0xFFF; + if (end > max_end) { + max_end = end; + } + } + } + } + + /* + * FIXME: do we need to reduce this if reduced memory width? + */ + total_memory = 1 + (((unsigned long long)max_end << 24ULL) | 0xFFFFFFULL); + } + + return total_memory; +} + +/* + * fsl_ddr_sdram() -- 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) +{ + unsigned int i; + unsigned int memctl_interleaved; + phys_size_t total_memory; + fsl_ddr_sdram_info_t info; + + /* + * Reset info structure. + */ + memset(&info, 0, sizeof(fsl_ddr_sdram_info_t)); + + /* + * Compute it once normally. + */ + total_memory = fsl_ddr_sdram_compute(&info, STEP_GET_SPD); + + /* + * Check for memory controller interleaving. + */ + memctl_interleaved = 0; + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + memctl_interleaved += + info.memctl_options[i].memctl_interleaving; + } + + if (memctl_interleaved) { + if (memctl_interleaved == CONFIG_NUM_DDR_CONTROLLERS) { + debug("memctl interleaving\n"); + /* + * Change the meaning of memctl_interleaved + * to be "boolean". + */ + memctl_interleaved = 1; + } else { + printf("Error: memctl interleaving not properly configured on all controllers\n"); + while (1); + } + } + + /* + * Program configuration registers. + */ + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + debug("Programming controller %u\n", i); + if (info.common_timing_params[i].ndimms_present == 0) { + debug("No dimms present on controller %u; skipping programming\n", i); + continue; + } + + fsl_ddr_sdram_set_memctl_regs(&(info.fsl_ddr_config_reg[i]), + i); + +#ifdef DEBUG + fsl_ddr_sdram_dump_memctl_regs(i); +#endif + } + + if (memctl_interleaved) { + const unsigned int ctrl_num = 0; + + /* + * Only set LAWBAR1 if memory controller interleaving is on. + */ + fsl_ddr_sdram_set_lawbar(&info.common_timing_params[0], + memctl_interleaved, ctrl_num); + } else { + /* + * Memory controller interleaving is NOT on; + * set each lawbar individually. + */ + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + fsl_ddr_sdram_set_lawbar(&info.common_timing_params[i], + 0, i); + } + } + +#ifdef CONFIG_PHYS_64BIT + if (total_memory > 0xFFFFFFFFULL) { + printf("XXX: 4GB+ memory not supported by this version of u-boot, capping to 0xFFFFFFFF...\n"); + /* + * FIXME: Does capping to 0xFFFFFFFF work? + * FIXME: Maybe the cap should be a power of 2 value? + * FIXME: Proper support requires u-boot to be FIXED + */ + total_memory = 0xFFFFFFFFULL; + } +#endif + + debug("total_memory = %llu\n", (u64)total_memory); + + return total_memory; +} diff --git a/cpu/mpc8xxx/fsl_ddr_sdram.h b/cpu/mpc8xxx/fsl_ddr_sdram.h new file mode 100644 index 0000000..0ac44a7 --- /dev/null +++ b/cpu/mpc8xxx/fsl_ddr_sdram.h @@ -0,0 +1,87 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#ifndef FSL_DDR_MEMCTL_H +#define FSL_DDR_MEMCTL_H + +/* + * Pick a basic DDR Technology. + */ +#include <ddr_spd.h> + +#if defined(CONFIG_FSL_DDR1) +#define FSL_DDR_MIN_TCKE_PULSE_WIDTH_DDR (1) +typedef ddr1_spd_eeprom_t generic_spd_eeprom_t; +#elif defined(CONFIG_FSL_DDR2) +#define FSL_DDR_MIN_TCKE_PULSE_WIDTH_DDR (3) +typedef ddr2_spd_eeprom_t generic_spd_eeprom_t; +#elif defined(CONFIG_FSL_DDR3) +#define FSL_DDR_MIN_TCKE_PULSE_WIDTH_DDR (3) /* FIXME */ +typedef ddr3_spd_eeprom_t generic_spd_eeprom_t; +#endif + +/* FIXME: Trying to make this be generic... */ +#include "ddr2_dimm_params.h" + +#include "memctl_options.h" +#include "common_timing_params.h" +#include "fsl_memctrl.h" + +phys_size_t fsl_ddr_sdram(void); + +unsigned int mclk_to_picos(unsigned int mclk); +unsigned int get_memory_clk_period_ps(void); + +/* + * Data Structures + * + * All data structures have to be on the stack + */ + + +typedef struct { + generic_spd_eeprom_t spd_installed_dimms[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR]; + dimm_params_t dimm_params[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR]; + memctl_options_t memctl_options[CONFIG_NUM_DDR_CONTROLLERS]; + common_timing_params_t common_timing_params[CONFIG_NUM_DDR_CONTROLLERS]; + fsl_memctl_config_regs_t fsl_ddr_config_reg[CONFIG_NUM_DDR_CONTROLLERS]; +} fsl_ddr_sdram_info_t; + + +extern phys_size_t +fsl_ddr_sdram_compute(fsl_ddr_sdram_info_t *pinfo, + unsigned int start_step); + + +extern const char * step_to_string(unsigned int step); +/* + * Compute steps + */ +#define STEP_GET_SPD (1 << 0) +#define STEP_COMPUTE_DIMM_PARMS (1 << 1) +#define STEP_COMPUTE_COMMON_PARMS (1 << 2) +#define STEP_GATHER_OPTS (1 << 3) +#define STEP_ASSIGN_ADDRESSES (1 << 4) +#define STEP_COMPUTE_REGS (1 << 5) +#define STEP_PROGRAM_REGS (1 << 6) +#define STEP_ALL 0xFFF + +/* + * Bind the main DDR setup driver's generic names + * to this specific DDR technology. + */ + +static __inline__ int +compute_dimm_parameters(const generic_spd_eeprom_t *spd, + dimm_params_t *pdimm, + unsigned int dimm_number) +{ + /* FIXME: Squeek by callong this generic yet? */ + return ddr2_compute_dimm_parameters(spd, pdimm, dimm_number); +} +#endif diff --git a/cpu/mpc8xxx/fsl_memctrl.h b/cpu/mpc8xxx/fsl_memctrl.h new file mode 100644 index 0000000..ec97dab --- /dev/null +++ b/cpu/mpc8xxx/fsl_memctrl.h @@ -0,0 +1,48 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#ifndef FSL_MEMCTRL_H +#define FSL_MEMCTRL_H + +/* + * Record of register values computed + */ +typedef struct fsl_memctl_config_regs_s { + struct { + unsigned int bnds; + unsigned int config; + unsigned int config_2; + } cs[CONFIG_CHIP_SELECTS_PER_CTRL]; + unsigned int timing_cfg_3; + unsigned int timing_cfg_0; + unsigned int timing_cfg_1; + unsigned int timing_cfg_2; + unsigned int ddr_sdram_cfg; + unsigned int ddr_sdram_cfg_2; + unsigned int ddr_sdram_mode; + unsigned int ddr_sdram_mode_2; + unsigned int ddr_sdram_interval; + unsigned int ddr_data_init; + unsigned int ddr_sdram_clk_cntl; + unsigned int ddr_init_addr; + unsigned int ddr_init_ext_addr; + unsigned int timing_cfg_4; + unsigned int timing_cfg_5; + unsigned int ddr_zq_cntl; + unsigned int ddr_wrlvl_cntl; + unsigned int ddr_pd_cntl; + unsigned int ddr_sr_cntr; + unsigned int ddr_sdram_rcw_1; + unsigned int ddr_sdram_rcw_2; +} fsl_memctl_config_regs_t; + + +void reset_fsl_memctl_config_regs(fsl_memctl_config_regs_t *ddr); +unsigned int check_fsl_memctl_config_regs(const fsl_memctl_config_regs_t *ddr); + +#endif /* FSL_MEMCTRL_H */ diff --git a/cpu/mpc8xxx/memctl_options.h b/cpu/mpc8xxx/memctl_options.h new file mode 100644 index 0000000..08779f7 --- /dev/null +++ b/cpu/mpc8xxx/memctl_options.h @@ -0,0 +1,100 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#ifndef MEMCTL_OPTIONS_H +#define MEMCTL_OPTIONS_H + +// #include "ddr2_dimm_params.h" +#include "common_timing_params.h" + +typedef struct memctl_options_partial_s { + unsigned int all_DIMMs_ECC_capable; + unsigned int all_DIMMs_tCKmax_ps; + unsigned int all_DIMMs_burst_lengths_bitmask; + unsigned int all_DIMMs_registered; + unsigned int all_DIMMs_unbuffered; +// unsigned int lowest_common_SPD_caslat; + unsigned int all_DIMMs_minimum_tRCD_ps; +} memctl_options_partial_t; + + +/* + * Generalized parameters for memory controller configuration, + * might be a little specific to the FSL memory controller + */ +typedef struct memctl_options_s { + /* + * Memory organization parameters + * + * if DIMM is present in the system + * where DIMMs are with respect to chip select + * where chip selects are with respect to memory boundaries + */ + unsigned int registered_dimm_en; /* use registered DIMM support */ + + /* + * Options local to a Chip Select + */ + struct cs_local_opts_s { + unsigned int auto_precharge; + unsigned int odt_rd_cfg; + unsigned int odt_wr_cfg; + } cs_local_opts[CONFIG_CHIP_SELECTS_PER_CTRL]; + + /* + * Special configurations for chip select + */ + unsigned int memctl_interleaving; + unsigned int memctl_interleaving_mode; + unsigned int ba_intlv_ctl; + + /* + * Operational mode parameters + */ + unsigned int sdram_type; /* 2 = DDR1, 3 = DDR2, 6 = LPDDR1, 7 = DDR3 */ + unsigned int ECC_mode; /* Use ECC? */ + /* Initialize ECC using memory controller? */ + unsigned int ECC_init_using_memctl; + unsigned int DQS_config; /* Use DQS? maybe only with DDR2? */ + /* SREN - self-refresh during sleep */ + unsigned int self_refresh_in_sleep; + unsigned int dynamic_power; /* DYN_PWR */ + /* memory data width to use (16-bit, 32-bit, 64-bit) */ + unsigned int data_bus_width; + unsigned int burst_length; /* 4, 8 */ + + /* + * Global Timing Parameters + */ + unsigned int cas_latency_override; + unsigned int cas_latency_override_value; + unsigned int use_derated_caslat; + unsigned int additive_latency_override; + unsigned int additive_latency_override_value; + + /* + * this should be computed in the fsl ddr code; for DDR2 this is + * always read latency -1 + * unsigned int write_latency; + */ + unsigned int clk_adjust; /* */ + unsigned int cpo_override; + unsigned int write_data_delay; /* DQS adjust */ + unsigned int half_strength_driver_enable; + unsigned int twoT_en; + unsigned int threeT_en; + unsigned int bstopre; + unsigned int tCKE_clock_pulse_width_ps; /* tCKE */ + unsigned int tFAW_window_four_activates_ps; /* tFAW -- FOUR_ACT */ +} memctl_options_t; + +unsigned int populate_memctl_options( + const common_timing_params_t *ppartial_opts, + memctl_options_t *popts, + unsigned int ctrl_num); +#endif

From: James Yang James.Yang@freescale.com
Provide a mechanism to allow interactive configuration of DDR params. This is useful when trying to test various DDR settings to determine optimal configuration values for a given board.
--- cpu/mpc8xxx/Makefile | 1 + cpu/mpc8xxx/fsl_ddr_interactive.c | 1281 +++++++++++++++++++++++++++++++++++++ cpu/mpc8xxx/fsl_ddr_sdram.c | 10 + cpu/mpc8xxx/fsl_ddr_sdram.h | 3 + 4 files changed, 1295 insertions(+), 0 deletions(-) create mode 100644 cpu/mpc8xxx/fsl_ddr_interactive.c
diff --git a/cpu/mpc8xxx/Makefile b/cpu/mpc8xxx/Makefile index 30f81ff..0ceac5b 100644 --- a/cpu/mpc8xxx/Makefile +++ b/cpu/mpc8xxx/Makefile @@ -10,6 +10,7 @@ include $(TOPDIR)/config.mk
LIB = $(obj)libmpc8xxx.a
+COBJS-$(CONFIG_FSL_DDR_INTERACTIVE) += fsl_ddr_interactive.o COBJS-$(CONFIG_FSL_DDR1) += fsl_ddr_sdram.o COBJS-$(CONFIG_FSL_DDR1) += fsl_ddr1.o
diff --git a/cpu/mpc8xxx/fsl_ddr_interactive.c b/cpu/mpc8xxx/fsl_ddr_interactive.c new file mode 100644 index 0000000..419deac --- /dev/null +++ b/cpu/mpc8xxx/fsl_ddr_interactive.c @@ -0,0 +1,1281 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +/* + * 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 <asm/types.h> + +#include "fsl_ddr_sdram.h" +/* + * Option parameter Structures + */ +typedef struct { + const char *option_name; + unsigned long long *pointer; +} options_strings_ulonglong_t; + +typedef struct { + const char *option_name; + unsigned int *pointer; +} options_strings_uint_t; + + +extern int do_reset(void *cmdtp, int flag, int argc, char *argv[]); + +/* + * interactive prompt + */ + +static int is_a_num_char(const char c) +{ + return c >= '0' && c <= '9'; +} + +static unsigned int picos_to_mhz(unsigned int picos) +{ + return 1000000 / picos; +} + +static int +handle_uint_option_table(options_strings_uint_t *table, + int table_size, + const char *opt, + const char *val) +{ + unsigned int i; + unsigned int value; + + for (i = 0; i < table_size; i++) { + if (strcmp(table[i].option_name, opt) == 0) { + value = simple_strtoul(val, NULL, 0); + *table[i].pointer = value; + return 1; + } + } + + return 0; +} + + +static int +handle_ull_option_table(options_strings_ulonglong_t *table, + int table_size, + const char *opt, + const char *val) +{ + unsigned int i; + unsigned long long value; + + for (i = 0; i < table_size; i++) { + if (strcmp(table[i].option_name, opt) == 0) { + value = simple_strtoull(val, NULL, 0); + *table[i].pointer = value; + return 1; + } + } + + return 0; +} + +static void +fsl_ddr_sdram_generic_edit(void *pdata, + void *pend, + unsigned int element_size, + unsigned int element_num, + unsigned int value) +{ + // XXX: BIG ENDIAN ONLY + char *pcdata = (char *)pdata; + + pcdata += element_num * element_size; + if ((pcdata + element_size) > (char *) pend) { + debug("trying to write past end of data\n"); + return; + } + + switch (element_size) { + case 1: + asm volatile ("stb %0,0(%1)" : : "r" (value) , "b" (pcdata)); + break; + case 2: + asm volatile ("sth %0,0(%1)" : : "r" (value) , "b" (pcdata)); + break; + case 4: + asm volatile ("stw %0,0(%1)" : : "r" (value) , "b" (pcdata)); + break; + default: + debug("unexpected element size %u\n", element_size); + break; + } +} + + +static void +fsl_ddr_sdram_spd_edit(fsl_ddr_sdram_info_t *pinfo, + unsigned int ctrl_num, + unsigned int dimm_num, + unsigned int element_num, + unsigned int value) +{ + generic_spd_eeprom_t *pspd; + + pspd = &(pinfo->spd_installed_dimms[ctrl_num][dimm_num]); + fsl_ddr_sdram_generic_edit(pspd, pspd + 1, + sizeof(char), element_num, value); +} + +static void +fsl_ddr_sdram_lowest_common_dimm_parameters_edit(fsl_ddr_sdram_info_t *pinfo, + unsigned int ctrl_num, + const char *optname_str, + const char * value_str) +{ + common_timing_params_t *p = &pinfo->common_timing_params[ctrl_num]; + + options_strings_uint_t options_uint[] = { + {"tCKmin_X_ps", &p->tCKmin_X_ps}, + {"tCKmax_ps", &p->tCKmax_ps}, + {"tCKmax_max_ps", &p->tCKmax_max_ps}, + {"tRCD_ps", &p->tRCD_ps}, + {"tRP_ps", &p->tRP_ps}, + {"tRAS_ps", &p->tRAS_ps}, + {"tWR_ps", &p->tWR_ps}, + {"tWTR_ps", &p->tWTR_ps}, + {"tRFC_ps", &p->tRFC_ps}, + {"tRRD_ps", &p->tRRD_ps}, + {"tRC_ps", &p->tRC_ps}, + {"refresh_rate_ns", &p->refresh_rate_ns}, + {"tIS_ps", &p->tIS_ps}, + {"tIH_ps", &p->tIH_ps}, + {"tDS_ps", &p->tDS_ps}, + {"tDH_ps", &p->tDH_ps}, + {"tRTP_ps", &p->tRTP_ps}, + {"tDQSQ_max_ps", &p->tDQSQ_max_ps}, + {"tQHS_ps", &p->tQHS_ps}, + {"ndimms_present", &p->ndimms_present}, + {"lowest_common_SPD_caslat", + &p->lowest_common_SPD_caslat}, + {"highest_common_derated_caslat", + &p->highest_common_derated_caslat}, + {"additive_latency", &p->additive_latency}, + {"all_DIMMs_burst_lengths_bitmask", + &p->all_DIMMs_burst_lengths_bitmask}, + {"all_DIMMs_registered", &p->all_DIMMs_registered}, + {"all_DIMMs_unbuffered", &p->all_DIMMs_unbuffered}, + {"all_DIMMs_ECC_capable", &p->all_DIMMs_ECC_capable} + }; + + const unsigned int n_uint_opts = ARRAY_SIZE(options_uint); + + options_strings_ulonglong_t options_ull[] = { + {"total_mem", &p->total_mem}, + {"base_address", &p->base_address} + }; + + const unsigned int n_ull_opts = ARRAY_SIZE(options_ull); + + if (handle_uint_option_table(options_uint, n_uint_opts, + optname_str, value_str)) + return; + + if (handle_ull_option_table(options_ull, n_ull_opts, + optname_str, value_str)) + return; + + printf("Error: couldn't find option string %s\n", optname_str); +} + +static void +fsl_ddr_sdram_dimm_parameters_edit(fsl_ddr_sdram_info_t *pinfo, + unsigned int ctrl_num, + unsigned int dimm_num, + const char *optname_str, + const char *value_str) +{ + dimm_params_t *p = &(pinfo->dimm_params[ctrl_num][dimm_num]); + + options_strings_uint_t options_uint[] = { + {"n_ranks", &p->n_ranks}, + {"data_width", &p->data_width}, + {"primary_sdram_width", &p->primary_sdram_width}, + {"ec_sdram_width", &p->ec_sdram_width}, + {"registered_dimm", &p->registered_dimm}, + + {"n_row_addr", &p->n_row_addr}, + {"n_col_addr", &p->n_col_addr}, + {"edc_config", &p->edc_config}, + {"n_banks_per_sdram_device", &p->n_banks_per_sdram_device}, + {"burst_lengths_bitmask", &p->burst_lengths_bitmask}, + {"row_density", &p->row_density}, + + {"tCKmin_X_ps", &p->tCKmin_X_ps}, + {"tCKmin_X_minus_1_ps", &p->tCKmin_X_minus_1_ps}, + {"tCKmin_X_minus_2_ps", &p->tCKmin_X_minus_2_ps}, + {"tCKmax_ps", &p->tCKmax_ps}, + + {"caslat_X", &p->caslat_X}, + {"caslat_X_minus_1", &p->caslat_X_minus_1}, + {"caslat_X_minus_2", &p->caslat_X_minus_2}, + + {"caslat_lowest_derated", &p->caslat_lowest_derated}, + + {"tRCD_ps", &p->tRCD_ps}, + {"tRP_ps", &p->tRP_ps}, + {"tRAS_ps", &p->tRAS_ps}, + {"tWR_ps", &p->tWR_ps}, + {"tWTR_ps", &p->tWTR_ps}, + {"tRFC_ps", &p->tRFC_ps}, + {"tRRD_ps", &p->tRRD_ps}, + {"tRC_ps", &p->tRC_ps}, + {"refresh_rate_ns", &p->refresh_rate_ns}, + + {"tIS_ps", &p->tIS_ps}, + {"tIH_ps", &p->tIH_ps}, + {"tDS_ps", &p->tDS_ps}, + {"tDH_ps", &p->tDH_ps}, + {"tRTP_ps", &p->tRTP_ps}, + {"tDQSQ_max_ps", &p->tDQSQ_max_ps}, + {"tQHS_ps", &p->tQHS_ps}, + }; + + const unsigned int n_uint_opts = ARRAY_SIZE(options_uint); + + options_strings_ulonglong_t options_ull[] = { + {"rank_density", &p->rank_density}, + {"dimm_capacity", &p->dimm_capacity}, + {"base_address", &p->base_address}, + }; + + const unsigned int n_ull_opts = ARRAY_SIZE(options_ull); + + if (handle_uint_option_table(options_uint, n_uint_opts, + optname_str, value_str)) + return; + + if (handle_ull_option_table(options_ull, n_ull_opts, + optname_str, value_str)) + return; + + printf("couldn't find option string %s\n", optname_str); +} + +static void +print_dimm_parameters(const dimm_params_t *pdimm) +{ + if (pdimm->n_ranks == 0) { + printf("DIMM not present\n"); + return; + } + + printf("DIMM organization parameters:\n"); + + printf("module part name = %s\n", pdimm->mpart); + printf("n_ranks = %u\n", pdimm->n_ranks); + printf("rank_density = %llu bytes (%llu megabytes)\n", + pdimm->rank_density, pdimm->rank_density / 0x100000); + printf("dimm_capacity = %llu bytes (%llu megabytes)\n", + pdimm->dimm_capacity, pdimm->dimm_capacity / 0x100000); + printf("data_width = %u\n", pdimm->data_width); + printf("primary_sdram_width = %u\n", pdimm->primary_sdram_width); + printf("ec_sdram_width = %u\n", pdimm->ec_sdram_width); + printf("registered_dimm = %u\n", pdimm->registered_dimm); + + printf("SDRAM device parameters:\n"); + printf("n_row_addr = %u\n", pdimm->n_row_addr); + printf("n_col_addr = %u\n", pdimm->n_col_addr); + printf("edc_config = %u\n", pdimm->edc_config); + printf("n_banks_per_sdram_device = %u\n", + pdimm->n_banks_per_sdram_device); + printf("burst_lengths_bitmask = %02X\n", + pdimm->burst_lengths_bitmask); + + printf("base_addresss = %llu (%08llX %08llX)\n", + pdimm->base_address, + (pdimm->base_address >> 32), + pdimm->base_address & 0xFFFFFFFF); + + printf("SDRAM clock periods:\n"); + printf("tCKmin_X_ps = %u ps\n", pdimm->tCKmin_X_ps); + printf("tCKmin_X_minus_1_ps = %u ps\n", pdimm->tCKmin_X_minus_1_ps); + printf("tCKmin_X_minus_2_ps = %u ps\n", pdimm->tCKmin_X_minus_2_ps); + printf("tCKmax_ps = %u ps\n", pdimm->tCKmax_ps); + + printf("SDRAM CAS latencies:\n"); + printf("caslat_X = %u\n", pdimm->caslat_X); + printf("caslat_X_minus_1 = %u\n", pdimm->caslat_X_minus_1); + printf("caslat_X_minus_2 = %u\n", pdimm->caslat_X_minus_2); + printf("caslat_lowest_derated = %u\n", pdimm->caslat_lowest_derated); + + printf("SDRAM timing parameters:\n"); + printf("tRCD_ps = %u\n", pdimm->tRCD_ps); + printf("tRP_ps = %u\n", pdimm->tRP_ps); + printf("tRAS_ps = %u\n", pdimm->tRAS_ps); + printf("tWR_ps = %u\n", pdimm->tWR_ps); + printf("tWTR_ps = %u\n", pdimm->tWTR_ps); + printf("tRFC_ps = %u\n", pdimm->tRFC_ps); + printf("tRC_ps = %u\n", pdimm->tRC_ps); + printf("tRRD_ps = %u\n", pdimm->tRRD_ps); + printf("refresh_rate_ns = %u\n", pdimm->refresh_rate_ns); + + printf("SDRAM even more timing parameters:\n"); + printf("tIS_ps = %u\n", pdimm->tIS_ps); + printf("tIH_ps = %u\n", pdimm->tIH_ps); + printf("tDS_ps = %u\n", pdimm->tDS_ps); + printf("tDH_ps = %u\n", pdimm->tDH_ps); + printf("tRTP_ps = %u\n", pdimm->tRTP_ps); + printf("tDQSQ_max_ps = %u\n", pdimm->tDQSQ_max_ps); + printf("tQHS_ps = %u\n", pdimm->tQHS_ps); +} + +static void +print_lowest_common_dimm_parameters( + const common_timing_params_t *plcd_dimm_params) +{ + + /* + * Clock frequencies + */ + printf("tCKmin_X_ps = %u (%u MHz)\n", + plcd_dimm_params->tCKmin_X_ps, + picos_to_mhz(plcd_dimm_params->tCKmin_X_ps)); + printf("tCKmax_ps = %u (%u MHz)\n", + plcd_dimm_params->tCKmax_ps, + picos_to_mhz(plcd_dimm_params->tCKmax_ps)); + printf("tCKmax_max_ps = %u\n", plcd_dimm_params->tCKmax_max_ps); + + /* + * Basic timing parameters + */ + printf("tRCD_ps = %u\n", plcd_dimm_params->tRCD_ps); + printf("tRP_ps = %u\n", plcd_dimm_params->tRP_ps); + printf("tRAS_ps = %u\n", plcd_dimm_params->tRAS_ps); + + /* maximum = 63750 ps */ + printf("tWR_ps = %u\n", plcd_dimm_params->tWR_ps); + + /* maximum = 63750 ps */ + printf("tWTR_ps = %u\n", plcd_dimm_params->tWTR_ps ); + + /* maximum = 255 ns + 256 ns + .75 ns = 511750 ps */ + printf("tRFC_ps = %u\n", plcd_dimm_params->tRFC_ps); + + /* maximum = 63750 ps */ + printf("tRRD_ps = %u\n", plcd_dimm_params->tRRD_ps); + + /* maximum = 254 ns + .75 ns = 254750 ps */ + printf("tRC_ps = %u\n", plcd_dimm_params->tRC_ps); + + printf("refresh_rate_ns = %u\n", plcd_dimm_params->refresh_rate_ns ); + + /* byte 32, spd->ca_setup */ + printf("tIS_ps = %u\n", plcd_dimm_params->tIS_ps); + /* byte 33, spd->ca_hold */ + printf("tIH_ps = %u\n", plcd_dimm_params->tIH_ps); + /* byte 34, spd->data_setup */ + printf("tDS_ps = %u\n", plcd_dimm_params->tDS_ps); + /* byte 35, spd->data_hold */ + printf("tDH_ps = %u\n", plcd_dimm_params->tDH_ps); + /* byte 38, spd->trtp */ + printf("tRTP_ps = %u\n", plcd_dimm_params->tRTP_ps); + /* byte 44, spd->tdqsq */ + printf("tDQSQ_max_ps = %u\n", plcd_dimm_params->tDQSQ_max_ps); + /* byte 45, spd->tqhs */ + printf("tQHS_ps = %u\n", plcd_dimm_params->tQHS_ps ); + + + printf("lowest_common_SPD_caslat = %u\n", + plcd_dimm_params->lowest_common_SPD_caslat); + printf("highest_common_derated_caslat = %u\n", + plcd_dimm_params->highest_common_derated_caslat); + printf("additive_latency = %u\n", plcd_dimm_params->additive_latency); + + printf("ndimms_present = %u\n", plcd_dimm_params->ndimms_present); + printf("all_DIMMs_burst_lengths_bitmask = %02X\n", + plcd_dimm_params->all_DIMMs_burst_lengths_bitmask); + printf("all_DIMMs_registered = %u\n", + plcd_dimm_params->all_DIMMs_registered); + printf("all_DIMMs_unbuffered = %u\n", + plcd_dimm_params->all_DIMMs_unbuffered); + printf("all_DIMMs_ECC_capable = %u\n", + plcd_dimm_params->all_DIMMs_ECC_capable); + + printf("total_mem = %llu (%llu megabytes)\n", + plcd_dimm_params->total_mem, + plcd_dimm_params->total_mem / 0x100000); + printf("base_address = %llu (%llu megabytes)\n", + plcd_dimm_params->base_address, + plcd_dimm_params->base_address / 0x100000); +} + +static void +fsl_ddr_sdram_options_edit(fsl_ddr_sdram_info_t *pinfo, + unsigned int ctrl_num, + const char *optname_str, + const char *value_str) +{ + + /* + * This array all on the stack and *computed* each time this + * function is rung. + */ + options_strings_uint_t options[] = { + {"memctl_interleaving", + &pinfo->memctl_options[ctrl_num].memctl_interleaving}, + {"memctl_interleaving_mode", + &pinfo->memctl_options[ctrl_num].memctl_interleaving_mode}, + {"ba_intlv_ctl", + &pinfo->memctl_options[ctrl_num].ba_intlv_ctl}, + {"ecc_mode", &pinfo->memctl_options[ctrl_num].ECC_mode}, + {"ECC_mode", &pinfo->memctl_options[ctrl_num].ECC_mode}, + {"self_refresh_in_sleep", + &pinfo->memctl_options[ctrl_num].self_refresh_in_sleep}, + {"dynamic_power", + &pinfo->memctl_options[ctrl_num].dynamic_power}, + {"data_bus_width", + &pinfo->memctl_options[ctrl_num].data_bus_width}, + {"burst_length", + &pinfo->memctl_options[ctrl_num].burst_length}, + {"cas_latency_override", + &pinfo->memctl_options[ctrl_num].cas_latency_override}, + {"cas_latency_override_value", + &pinfo->memctl_options[ctrl_num].cas_latency_override_value}, + {"use_derated_caslat", + &pinfo->memctl_options[ctrl_num].use_derated_caslat}, + {"additive_latency_override", + &pinfo->memctl_options[ctrl_num].additive_latency_override}, + {"additive_latency_override_value", + &pinfo->memctl_options[ctrl_num].additive_latency_override_value}, + {"clk_adjust", &pinfo->memctl_options[ctrl_num].clk_adjust}, + {"cpo_override", + &pinfo->memctl_options[ctrl_num].cpo_override}, + {"write_data_delay", + &pinfo->memctl_options[ctrl_num].write_data_delay}, + {"half_strength_driver_enable", + &pinfo->memctl_options[ctrl_num].half_strength_driver_enable}, + + /* + * These can probably be changed to 2T_EN and 3T_EN + * (using a leading numerical character) without problem + */ + {"twoT_en", &pinfo->memctl_options[ctrl_num].twoT_en}, + {"threeT_en", &pinfo->memctl_options[ctrl_num].threeT_en}, + {"bstopre", &pinfo->memctl_options[ctrl_num].bstopre}, + {"tCKE_clock_pulse_width_ps", + &pinfo->memctl_options[ctrl_num].tCKE_clock_pulse_width_ps}, + {"tFAW_window_four_activates_ps", + &pinfo->memctl_options[ctrl_num].tFAW_window_four_activates_ps} + }; + + const unsigned int nopts = ARRAY_SIZE(options); + + if (handle_uint_option_table(options, nopts, optname_str, value_str)) + return; + + printf("couldn't find option string %s\n", optname_str); +} + +static void +print_fsl_memctl_config_regs(const fsl_memctl_config_regs_t *ddr) +{ + unsigned int i; + + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + printf("cs%u_bnds = %08X\n", i, ddr->cs[i].bnds); + printf("cs%u_config = %08X\n", i, ddr->cs[i].config); + printf("cs%u_config_2 = %08X\n", i, ddr->cs[i].config_2); + } + + printf("timing_cfg_3 = %08X\n", ddr->timing_cfg_3); + printf("timing_cfg_0 = %08X\n", ddr->timing_cfg_0); + printf("timing_cfg_1 = %08X\n", ddr->timing_cfg_1); + printf("timing_cfg_2 = %08X\n", ddr->timing_cfg_2); + printf("ddr_sdram_cfg = %08X\n", ddr->ddr_sdram_cfg); + printf("ddr_sdram_cfg_2 = %08X\n", ddr->ddr_sdram_cfg_2); + printf("ddr_sdram_mode = %08X\n", ddr->ddr_sdram_mode); + printf("ddr_sdram_mode_2 = %08X\n", ddr->ddr_sdram_mode_2); + printf("ddr_sdram_interval = %08X\n", ddr->ddr_sdram_interval); + printf("ddr_data_init = %08X\n", ddr->ddr_data_init); + printf("ddr_sdram_clk_cntl = %08X\n", ddr->ddr_sdram_clk_cntl); + printf("ddr_init_addr = %08X\n", ddr->ddr_init_addr); + printf("ddr_init_ext_addr = %08X\n", ddr->ddr_init_ext_addr); + printf("timing_cfg_4 = %08X\n", ddr->timing_cfg_4); + printf("timing_cfg_5 = %08X\n", ddr->timing_cfg_5); + printf("ddr_zq_cntl = %08X\n", ddr->ddr_zq_cntl); + printf("ddr_wrlvl_cntl = %08X\n", ddr->ddr_wrlvl_cntl); + printf("ddr_pd_cntl = %08X\n", ddr->ddr_pd_cntl); + printf("ddr_sr_cntr = %08X\n", ddr->ddr_sr_cntr); + printf("ddr_sdram_rcw_1 = %08X\n", ddr->ddr_sdram_rcw_1); + printf("ddr_sdram_rcw_2 = %08X\n", ddr->ddr_sdram_rcw_2); +} + +static void +fsl_ddr_sdram_regs_edit(fsl_ddr_sdram_info_t *pinfo, + unsigned int ctrl_num, + const char *regname, + unsigned int value) +{ + unsigned int i; + fsl_memctl_config_regs_t *ddr; + char buf[20]; + + debug("fsl_ddr_sdram_regs_edit: ctrl_num = %u, regname = %s, value = 0x%08X\n", + ctrl_num, regname, value); + if (ctrl_num > CONFIG_NUM_DDR_CONTROLLERS) { + return; + } + + /* + * FIXME: Change this into struct like the other editing functions + */ + ddr = &(pinfo->fsl_ddr_config_reg[ctrl_num]); + + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + sprintf(buf, "cs%u_bnds", i); + if (strcmp(buf, regname) == 0) { + ddr->cs[i].bnds = value; + return; + } + + sprintf(buf, "cs%u_config", i); + if (strcmp(buf, regname) == 0) { + ddr->cs[i].config = value; + return; + } + + sprintf(buf, "cs%u_config_2", i); + if (strcmp(buf, regname) == 0) { + ddr->cs[i].config_2 = value; + return; + } + } + + if (strcmp("timing_cfg_3", regname) == 0) { + ddr->timing_cfg_3 = value; + return; + } + + if (strcmp("timing_cfg_0", regname) == 0) { + ddr->timing_cfg_0 = value; + return; + } + + if (strcmp("timing_cfg_1", regname) == 0) { + ddr->timing_cfg_1 = value; + return; + } + + if (strcmp("timing_cfg_2", regname) == 0) { + ddr->timing_cfg_2 = value; + return; + } + + if (strcmp("ddr_sdram_cfg", regname) == 0) { + ddr->ddr_sdram_cfg = value; + return; + } + + if (strcmp("ddr_sdram_cfg_2", regname) == 0) { + ddr->ddr_sdram_cfg_2 = value; + return; + } + + if (strcmp("ddr_sdram_mode", regname) == 0) { + ddr->ddr_sdram_mode = value; + return; + } + + if (strcmp("ddr_sdram_mode_2", regname) == 0) { + ddr->ddr_sdram_mode_2 = value; + return; + } + + if (strcmp("ddr_sdram_interval", regname) == 0) { + ddr->ddr_sdram_interval = value; + return; + } + + if (strcmp("ddr_data_init", regname) == 0) { + ddr->ddr_data_init = value; + return; + } + + if (strcmp("ddr_sdram_clk_cntl", regname) == 0) { + ddr->ddr_sdram_clk_cntl = value; + return; + } + + if (strcmp("ddr_init_addr", regname) == 0) { + ddr->ddr_init_addr = value; + return; + } + + if (strcmp("ddr_init_ext_addr", regname) == 0) { + ddr->ddr_init_ext_addr = value; + return; + } + + if (strcmp("timing_cfg_4", regname) == 0) { + ddr->timing_cfg_4 = value; + return; + } + + if (strcmp("timing_cfg_5", regname) == 0) { + ddr->timing_cfg_5 = value; + return; + } + + if (strcmp("ddr_zq_cntl", regname) == 0) { + ddr->ddr_zq_cntl = value; + return; + } + + if (strcmp("ddr_wrlvl_cntl", regname) == 0) { + ddr->ddr_wrlvl_cntl = value; + return; + } + + if (strcmp("ddr_pd_cntl", regname) == 0) { + ddr->ddr_pd_cntl = value; + return; + } + + if (strcmp("ddr_sr_cntr", regname) == 0) { + ddr->ddr_sr_cntr = value; + return; + } + + if (strcmp("ddr_sdram_rcw_1", regname) == 0) { + ddr->ddr_sdram_rcw_1 = value; + return; + } + + if (strcmp("ddr_sdram_rcw_2", regname) == 0) { + ddr->ddr_sdram_rcw_2 = value; + return; + } +} + +static const char * +get_sdram_type(unsigned int sdram_type) +{ + switch (sdram_type) { + case 2: + return "DDR1"; + case 3: + return "DDR2"; + case 6: + return "LPDDR1"; + case 7: + return "DDR3"; + } + + return "unknown SDRAM type"; +} + +static void +print_memctl_options(const memctl_options_t *popts) +{ + + /* + * Special configurations for chip select + */ + printf("memctl_interleaving = %u\n", popts->memctl_interleaving ); + printf("memctl_interleaving_mode = %u\n", + popts->memctl_interleaving_mode); + printf("ba_intlv_ctl = 0x%02X\n", popts->ba_intlv_ctl ); + + /* + * Operational mode parameters + */ + /* 2 = DDR1, 3 = DDR2, 6 = LPDDR1, 7 = DDR3 */ + printf("sdram_type = %u (%s)\n", + popts->sdram_type, get_sdram_type(popts->sdram_type)); + + printf("ECC_mode = %u\n", popts->ECC_mode ); /* Use ECC? */ + + /* Initialize ECC using memory controller? */ + printf("ECC_init_using_memctl = %u\n", popts->ECC_init_using_memctl); + + /* Use DQS? maybe only with DDR2? */ + printf("DQS_config = %u\n", popts->DQS_config); + + /* SREN - self-refresh during sleep */ + printf("self_refresh_in_sleep = %u\n", popts->self_refresh_in_sleep); + + /* DYN_PWR */ + printf("dynamic_power = %u\n", popts->dynamic_power); + + /* memory data width to use (16-bit, 32-bit, 64-bit) */ + printf("data_bus_width = %u\n", popts->data_bus_width); + + /* 4, 8 */ + printf("burst_length = %u\n", popts->burst_length); + + /* + * Global Timing Parameters + */ + printf("cas_latency_override = %u\n", popts->cas_latency_override); + printf("cas_latency_override_value = %u\n", + popts->cas_latency_override_value); + printf("use_derated_caslat = %u\n", popts->use_derated_caslat); + printf("additive_latency_override = %u\n", + popts->additive_latency_override); + printf("additive_latency_override_value = %u\n", + popts->additive_latency_override_value); + printf("clk_adjust = %u\n", popts->clk_adjust); + printf("cpo_override = %u\n", popts->cpo_override); + /* DQS adjust */ + printf("write_data_delay = %u\n", popts->write_data_delay); + printf("half_strength_driver_enable = %u\n", + popts->half_strength_driver_enable); + printf("twoT_en = %u\n", popts->twoT_en); + printf("threeT_en = %u\n", popts->threeT_en); + printf("bstopre = %u\n", popts->bstopre); + /* tCKE */ + printf("tCKE_clock_pulse_width_ps = %u\n", + popts->tCKE_clock_pulse_width_ps); + /* tFAW -- FOUR_ACT */ + printf("tFAW_window_four_activates_ps = %u\n", + popts->tFAW_window_four_activates_ps); +} + +static __inline__ void +generic_spd_dump(const generic_spd_eeprom_t *spd) +{ +#if defined(CONFIG_FSL_DDR1) + ddr1_spd_dump(spd); +#elif defined(CONFIG_FSL_DDR2) + ddr2_spd_dump(spd); +#elif defined(CONFIG_FSL_DDR3) +#error "Implement generic_spd_dump() for DDR3" +#endif +} + +static void +fsl_ddr_sdram_printinfo(const fsl_ddr_sdram_info_t *pinfo, + unsigned int ctrl_mask, + unsigned int dimm_mask, + unsigned int do_mask) +{ + unsigned int i; + unsigned int j; + unsigned int retval; + + /* + * INFO 1: DIMM SPD data + */ + if (do_mask & STEP_GET_SPD) { + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (ctrl_mask & (1 << i)) { + /* + * FIXME: find a way to make this + * generate more optimal powerpc code + * (i.e. rlwimi.) + */ + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { + if (dimm_mask & (1 << j)) { + printf("SPD info: Controller=%u DIMM=%u\n", i, j); + generic_spd_dump(&(pinfo->spd_installed_dimms[i][j])); + printf("\n"); + } + } + printf("\n"); + } + } + printf("\n"); + } + + /* + * INFO 2: DIMM Parameters + */ + if (do_mask & STEP_COMPUTE_DIMM_PARMS) { + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (ctrl_mask & (1 << i)) { + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { + if (dimm_mask & (1 << j)) { + printf("DIMM parameters: Controller=%u DIMM=%u\n", i, j); + print_dimm_parameters(&(pinfo->dimm_params[i][j])); + printf("\n"); + } + } + printf("\n"); + } + } + printf("\n"); + } + + /* + * INFO 3: Common Parameters + */ + if (do_mask & STEP_COMPUTE_COMMON_PARMS) { + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (ctrl_mask & (1 << i)) { + printf(""lowest common" DIMM parameters: Controller=%u\n", i); + print_lowest_common_dimm_parameters(&pinfo->common_timing_params[i]); + printf("\n"); + } + } + printf("\n"); + } + + /* + * STEP 4: User Configuration Options + */ + if (do_mask & STEP_GATHER_OPTS) { + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (ctrl_mask & (1 << i)) { + printf("User Config Options: Controller=%u\n", i); + print_memctl_options(&pinfo->memctl_options[i]); + printf("\n"); + } + } + printf("\n"); + } + + /* + * STEP 5: Address assignment + */ + if (do_mask & STEP_ASSIGN_ADDRESSES) { + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (ctrl_mask & (1 << i)) { + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { + printf("Address Assignment: Controller=%u DIMM=%u\n", i, j); + printf("Don't have this functionality yet\n"); + } + printf("\n"); + } + } + printf("\n"); + } + + /* + * STEP 6: computed controller register values + */ + if (do_mask & STEP_COMPUTE_REGS) { + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (ctrl_mask & (1 << i)) { + printf("Computed Register Values: Controller=%u\n", i); + print_fsl_memctl_config_regs(&pinfo->fsl_ddr_config_reg[i]); + retval = check_fsl_memctl_config_regs(&pinfo->fsl_ddr_config_reg[i]); + if (retval) { + printf("check_fsl_memctl_config_regs result = %u\n", retval); + } + printf("\n"); + } + } + printf("\n"); + } +} + + + + +phys_size_t +fsl_ddr_interactive(fsl_ddr_sdram_info_t *pinfo) +{ + phys_size_t ddrsize; + const char *prompt = "FSL DDR>"; + unsigned int len; + char buffer[CFG_CBSIZE]; + char *argv[CFG_MAXARGS + 1]; /* NULL terminated */ + int argc; + unsigned int next_step = STEP_GET_SPD; + + /* + * The strategy for next_step is that it points to the next + * step in the computation process that needs to be done. + */ + while (1) { + /* + * No need to worry for buffer overflow here in + * this function; readline() maxes out at CFG_CBSIZE + */ + len = readline_into_buffer(prompt, buffer); + argc = parse_line(buffer, argv); + if (argc == 0) { + continue; + } + + if (strcmp(argv[0], "help") == 0) { + + /* + * FIXME: For some reason printing this whole + * thing causes the machine to freeze. + * Splitting it into two printfs seems to make + * it work Does printf() have limits on the + * length of the string? + */ + printf( + "commands:\n" + "print print SPD and intermediate computed data\n" + "reset reboot machine\n" + "recompute reload SPD and options to default and recompute registers\n"); + printf( + "compute recompute registers from current next_step to end\n" + "next_step shows current next_step\n" + "help this message\n" + "go program the memory controller and continue with u-boot\n" + ); + continue; + } + + if (strcmp(argv[0], "next_step") == 0) { + printf("next_step = 0x%02X (%s)\n", + next_step, + step_to_string(__ilog2(next_step))); + continue; + } + + if (strcmp(argv[0], "edit") == 0) { + unsigned int i; + unsigned int error = 0; + unsigned int step_mask = 0; + unsigned int ctlr_mask = 0; + unsigned int dimm_mask = 0; + char *p_element = NULL; + char *p_value = NULL; + unsigned int dimm_number_required = 0; + unsigned int ctrl_num; + unsigned int dimm_num; + + if (argc == 1) { + /* + * Only the element and value must be last + */ + printf("edit <c#> <d#> <spd|dimmparms|commonparms|opts|addresses|regs> <element> <value>\n"); + continue; + } + + for (i = 1; i < argc - 2; i++) { + if (strcmp(argv[i], "spd") == 0) { + step_mask |= STEP_GET_SPD; + dimm_number_required = 1; + continue; + } + + if (strcmp(argv[i], "dimmparms") == 0) { + step_mask |= STEP_COMPUTE_DIMM_PARMS; + dimm_number_required = 1; + continue; + } + + if (strcmp(argv[i], "commonparms") == 0) { + step_mask |= STEP_COMPUTE_COMMON_PARMS; + continue; + } + + if (strcmp(argv[i], "opts") == 0) { + step_mask |= STEP_GATHER_OPTS; + continue; + } + + if (strcmp(argv[i], "addresses") == 0) { + step_mask |= STEP_ASSIGN_ADDRESSES; + /* FIXME: not done yet */ + continue; + } + + if (strcmp(argv[i], "regs") == 0) { + step_mask |= STEP_COMPUTE_REGS; + continue; + } + + if (argv[i][0] == 'c') { + char c = argv[i][1]; + if (is_a_num_char(c)) { + ctlr_mask |= 1 << (c - '0'); + } + continue; + } + + if (argv[i][0] == 'd') { + char c = argv[i][1]; + if (is_a_num_char(c)) { + dimm_mask |= 1 << (c - '0'); + } + continue; + } + + printf("unknown arg %s\n", argv[i]); + step_mask = 0; + error = 1; + break; + } + + + if (error) { + continue; + } + + + /* + * Check arguments + */ + + /* + * ERROR: If no steps were found + */ + if (step_mask == 0) { + printf("Error: No valid steps were specified in argument.\n"); + continue; + } + + /* + * ERROR: If multiple steps were found + */ + if (step_mask & (step_mask - 1)) { + printf("Error: Multiple steps specified in argument.\n"); + continue; + } + + /* + * ERROR: Controller not specified + */ + if (ctlr_mask == 0) { + printf("Error: controller number not specified or no element and value specified\n"); + continue; + } + + if (ctlr_mask & (ctlr_mask - 1)) { + printf("Error: multiple controllers specified, %X\n", ctlr_mask); + continue; + } + + /* + * ERROR: DIMM number not specified + */ + if (dimm_number_required && dimm_mask == 0) { + printf("Error: DIMM number number not specified or no element and value specified\n"); + continue; + } + + if (dimm_mask & (dimm_mask - 1)) { + printf("Error: multipled DIMMs specified\n"); + continue; + } + + p_element = argv[argc - 2]; + p_value = argv[argc - 1]; + + ctrl_num = __ilog2(ctlr_mask); + dimm_num = __ilog2(dimm_mask); + + switch (step_mask) { + case STEP_GET_SPD: + { + unsigned int element_num; + unsigned int value; + + element_num = simple_strtoul(p_element, + NULL, 0); + value = simple_strtoul(p_value, + NULL, 0); + fsl_ddr_sdram_spd_edit(pinfo, + ctrl_num, + dimm_num, + element_num, + value); + next_step = STEP_COMPUTE_DIMM_PARMS; + } + break; + + case STEP_COMPUTE_DIMM_PARMS: + fsl_ddr_sdram_dimm_parameters_edit( + pinfo, ctrl_num, dimm_num, + p_element, p_value); + next_step = STEP_COMPUTE_COMMON_PARMS; + break; + + case STEP_COMPUTE_COMMON_PARMS: + fsl_ddr_sdram_lowest_common_dimm_parameters_edit(pinfo, ctrl_num, p_element, p_value); + next_step = STEP_GATHER_OPTS; + break; + + case STEP_GATHER_OPTS: + fsl_ddr_sdram_options_edit(pinfo, ctrl_num, + p_element, p_value); + next_step = STEP_ASSIGN_ADDRESSES; + break; + + case STEP_ASSIGN_ADDRESSES: + printf("editing of address assignment not yet implemented\n"); + break; + + case STEP_COMPUTE_REGS: + { + unsigned int value; + + value = simple_strtoul(p_value, + NULL, 0); + fsl_ddr_sdram_regs_edit(pinfo, + ctrl_num, + p_element, + value); + next_step = STEP_PROGRAM_REGS; + } + break; + + default: + printf("programming error\n"); + while (1); + break; + } + continue; + } + + if (strcmp(argv[0], "reset") == 0) { + /* + * Reboot machine. + * Args don't seem to matter because this + * doesn't return + */ + do_reset(NULL, 0, 0, NULL); + } + + if (strcmp(argv[0], "recompute") == 0) { + /* + * Recalculate everything, starting with + * loading SPD EEPROM from DIMMs + */ + next_step = STEP_GET_SPD; + ddrsize = fsl_ddr_sdram_compute(pinfo, next_step); + /* + * FIXME: There some problems with this. + * For exmaple, what happens if there is + * an error inside fsl_ddr_sdram_compute? + */ + continue; + } + + if (strcmp(argv[0], "compute") == 0) { + /* + * Compute rest of steps starting at + * the current next_step/ + */ + ddrsize = fsl_ddr_sdram_compute(pinfo, next_step); + continue; + } + + if (strcmp(argv[0], "print") == 0) { + unsigned int i; + unsigned int error = 0; + unsigned int step_mask = 0; + unsigned int ctlr_mask = 0; + unsigned int dimm_mask = 0; + + if (argc == 1) { + printf("print [c<n>] [d<n>] [spd] [dimmparms] [commonparms] [opts] [addresses] [regs]\n"); + continue; + } + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "spd") == 0) { + step_mask |= STEP_GET_SPD; + continue; + } + + if (strcmp(argv[i], "dimmparms") == 0) { + step_mask |= STEP_COMPUTE_DIMM_PARMS; + continue; + } + + if (strcmp(argv[i], "commonparms") == 0) { + step_mask |= STEP_COMPUTE_COMMON_PARMS; + continue; + } + + if (strcmp(argv[i], "opts") == 0) { + step_mask |= STEP_GATHER_OPTS; + continue; + } + + if (strcmp(argv[i], "addresses") == 0) { + step_mask |= STEP_ASSIGN_ADDRESSES; + continue; + } + + if (strcmp(argv[i], "regs") == 0) { + step_mask |= STEP_COMPUTE_REGS; + continue; + } + + if (argv[i][0] == 'c') { + char c = argv[i][1]; + if (c >= '0' && c <= '9') { + ctlr_mask |= 1 << (c - '0'); + } + continue; + } + + if (argv[i][0] == 'd') { + char c = argv[i][1]; + if (c >= '0' && c <= '9') { + dimm_mask |= 1 << (c - '0'); + } + continue; + } + + printf("unknown arg %s\n", argv[i]); + step_mask = 0; + error = 1; + break; + } + + if (error) { + continue; + } + + /* + * If no particular controller was found, + * print all controllers. + */ + if (ctlr_mask == 0) { + ctlr_mask = 0xFF; + } + + /* + * If no particular dimm was found, print all dimms. + */ + if (dimm_mask == 0) { + dimm_mask = 0xFF; + } + + /* + * If no steps were found, print all steps. + */ + if (step_mask == 0) { + step_mask = STEP_ALL; + } + + fsl_ddr_sdram_printinfo(pinfo, ctlr_mask, + dimm_mask, step_mask); + continue; + } + + if (strcmp(argv[0], "go") == 0) { + if (next_step) { + ddrsize = fsl_ddr_sdram_compute(pinfo, + next_step); + } + break; + } + + printf("unknown command %s\n", argv[0]); + } + + debug("end of memory = %llu\n", (u64)ddrsize); + + return ddrsize; +} + + diff --git a/cpu/mpc8xxx/fsl_ddr_sdram.c b/cpu/mpc8xxx/fsl_ddr_sdram.c index 72af6ac..457cff3 100644 --- a/cpu/mpc8xxx/fsl_ddr_sdram.c +++ b/cpu/mpc8xxx/fsl_ddr_sdram.c @@ -2370,6 +2370,16 @@ phys_size_t fsl_ddr_sdram(void) */ total_memory = fsl_ddr_sdram_compute(&info, STEP_GET_SPD);
+#ifdef CONFIG_FSL_DDR_INTERACTIVE + /* + * The presence of the environment variable "ddrsetup" + * causes the interactive DDR setup prompt to appear. + */ + if (getenv("ddrsetup")) { + total_memory = fsl_ddr_interactive(&info); + } +#endif + /* * Check for memory controller interleaving. */ diff --git a/cpu/mpc8xxx/fsl_ddr_sdram.h b/cpu/mpc8xxx/fsl_ddr_sdram.h index 0ac44a7..4034e9c 100644 --- a/cpu/mpc8xxx/fsl_ddr_sdram.h +++ b/cpu/mpc8xxx/fsl_ddr_sdram.h @@ -54,6 +54,9 @@ typedef struct {
extern phys_size_t +fsl_ddr_interactive(fsl_ddr_sdram_info_t *pinfo); + +extern phys_size_t fsl_ddr_sdram_compute(fsl_ddr_sdram_info_t *pinfo, unsigned int start_step);

Make fsl_ddr_sdram_set_lawbar() a weak function to allow board code to override if desired.
Signed-off-by: Kumar Gala galak@kernel.crashing.org --- drivers/misc/fsl_law.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 63 insertions(+), 0 deletions(-)
diff --git a/drivers/misc/fsl_law.c b/drivers/misc/fsl_law.c index dca6a4d..f9bdf10 100644 --- a/drivers/misc/fsl_law.c +++ b/drivers/misc/fsl_law.c @@ -72,6 +72,69 @@ void print_laws(void) return; }
+#if defined(CONFIG_FSL_DDR1) || \ + defined(CONFIG_FSL_DDR2) || \ + defined(CONFIG_FSL_DDR3) +#include <../cpu/mpc8xxx/fsl_ddr_sdram.h> + +void +__fsl_ddr_sdram_set_lawbar(const common_timing_params_t *memctl_common_params, + unsigned int memctl_interleaved, + unsigned int ctrl_num) +{ + unsigned long law_base_address; + unsigned long memsize_MB; + unsigned int law_size; + + /* + * If no DIMMs on this controller, do not proceed any further. + */ + if (!memctl_common_params->ndimms_present) { + return; + } + + law_base_address = memctl_common_params->base_address; + + /* + * Compute LAWBARn[SIZE] value for 2**(SIZE + 1) bytes. + * If interleaving is used, the memory size must represent + * the combined total of both controllers. + * The first supported LAW size is 16M, at LAWAR_SIZE_16M == 23. + * Fnord. + */ + memsize_MB = memctl_common_params->total_mem / 0x100000; + law_size = 19 + __ilog2(memsize_MB << memctl_interleaved); + + if (ctrl_num == 0) { + /* + * Set up LAWBAR1 for DDR controller 1 space. + */ + unsigned int lawbar1_target_id = memctl_interleaved + ? LAW_TRGT_IF_DDR_INTRLV : LAW_TRGT_IF_DDR_1; + + set_law(1, law_base_address, law_size, lawbar1_target_id); + debug("ctl0 law_base_address = 0x%08X, law_size = 0x%x\n", + law_base_address, law_size); + + } else if (ctrl_num == 1) { + /* + * Set up LAWBAR2 for DDR controller 2 space. + */ + set_law(2, law_base_address, law_size, LAW_TRGT_IF_DDR_2); + debug("ctl1 law_base_address = 0x%08X, law_size = 0x%x\n", + law_base_address, law_size); + + } else { + printf("unexpected controller number %u in fsl_ddr_sdram_set_lawbar()\n", ctrl_num); + } +} + +__attribute__((weak, alias("__fsl_ddr_sdram_set_lawbar"))) void +fsl_ddr_sdram_set_lawbar(const common_timing_params_t *memctl_common_params, + unsigned int memctl_interleaved, + unsigned int ctrl_num); +#endif + void init_laws(void) { int i;

Provide a helper function that board code can call to map TLBs when setting up DDR.
Signed-off-by: Kumar Gala galak@kernel.crashing.org --- cpu/mpc85xx/tlb.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++ include/asm-ppc/mmu.h | 1 + 2 files changed, 64 insertions(+), 0 deletions(-)
diff --git a/cpu/mpc85xx/tlb.c b/cpu/mpc85xx/tlb.c index 3d15d50..63f34e6 100644 --- a/cpu/mpc85xx/tlb.c +++ b/cpu/mpc85xx/tlb.c @@ -90,3 +90,66 @@ void init_tlbs(void)
return ; } + +unsigned int setup_ddr_tlbs(unsigned int memsize_in_meg) +{ + unsigned int tlb_size; + unsigned int ram_tlb_index; + unsigned int ram_tlb_address; + + /* + * Determine size of each TLB1 entry. + */ + switch (memsize_in_meg) { + case 16: + case 32: + tlb_size = BOOKE_PAGESZ_16M; + break; + case 64: + case 128: + tlb_size = BOOKE_PAGESZ_64M; + break; + case 256: + case 512: + tlb_size = BOOKE_PAGESZ_256M; + break; + case 1024: + case 2048: + if (PVR_VER(get_pvr()) > PVR_VER(PVR_85xx)) + tlb_size = BOOKE_PAGESZ_1G; + else + tlb_size = BOOKE_PAGESZ_256M; + break; + default: + puts("DDR: only 16M,32M,64M,128M,256M,512M,1G and 2G are supported.\n"); + + /* + * The memory was not able to be mapped. + * Default to a small size. + */ + tlb_size = BOOKE_PAGESZ_64M; + memsize_in_meg = 64; + break; + } + + /* + * Configure DDR TLB1 entries. + * Starting at TLB1 8, use no more than 8 TLB1 entries. + */ + ram_tlb_index = 8; + ram_tlb_address = (unsigned int)CFG_DDR_SDRAM_BASE; + while (ram_tlb_address < (memsize_in_meg * 1024 * 1024) + && ram_tlb_index < 16) { + set_tlb(1, ram_tlb_address, ram_tlb_address, + MAS3_SX|MAS3_SW|MAS3_SR, 0, + 0, ram_tlb_index, tlb_size, 1); + + ram_tlb_address += (0x1000 << ((tlb_size - 1) * 2)); + ram_tlb_index++; + } + + /* + * Confirm that the requested amount of memory was mapped. + */ + return memsize_in_meg; +} diff --git a/include/asm-ppc/mmu.h b/include/asm-ppc/mmu.h index 050a7b6..8975e6c 100644 --- a/include/asm-ppc/mmu.h +++ b/include/asm-ppc/mmu.h @@ -431,6 +431,7 @@ extern void set_tlb(u8 tlb, u32 epn, u64 rpn, extern void disable_tlb(u8 esel); extern void invalidate_tlb(u8 tlb); extern void init_tlbs(void); +extern unsigned int setup_ddr_tlbs(unsigned int memsize_in_meg);
#define SET_TLB_ENTRY(_tlb, _epn, _rpn, _perms, _wimge, _ts, _esel, _sz, _iprot) \ { .tlb = _tlb, .epn = _epn, .rpn = _rpn, .perms = _perms, \

From: Jon Loeliger jdl@freescale.com
Signed-off-by: Jon Loeliger jdl@freescale.com Signed-off-by: Kumar Gala galak@kernel.crashing.org --- Makefile | 3 + board/freescale/mpc8641hpcn/Makefile | 8 +- board/freescale/mpc8641hpcn/ddr.c | 288 +++++++++++++++++++++++++++++ board/freescale/mpc8641hpcn/mpc8641hpcn.c | 5 +- cpu/mpc86xx/Makefile | 1 - include/configs/MPC8641HPCN.h | 127 ++++++++------ 6 files changed, 371 insertions(+), 61 deletions(-) create mode 100644 board/freescale/mpc8641hpcn/ddr.c
diff --git a/Makefile b/Makefile index cc988e1..39fc369 100644 --- a/Makefile +++ b/Makefile @@ -236,6 +236,9 @@ endif ifeq ($(CPU),mpc85xx) LIBS += drivers/qe/qe.a endif +ifeq ($(CPU),mpc86xx) +LIBS += cpu/mpc8xxx/libmpc8xxx.a +endif LIBS += drivers/rtc/librtc.a LIBS += drivers/serial/libserial.a LIBS += drivers/usb/libusb.a diff --git a/board/freescale/mpc8641hpcn/Makefile b/board/freescale/mpc8641hpcn/Makefile index 115df05..bbc64d1 100644 --- a/board/freescale/mpc8641hpcn/Makefile +++ b/board/freescale/mpc8641hpcn/Makefile @@ -25,10 +25,12 @@ include $(TOPDIR)/config.mk
LIB = $(obj)lib$(BOARD).a
-COBJS := $(BOARD).o law.o +COBJS-y += $(BOARD).o +COBJS-y += law.o +COBJS-y += ddr.o
-SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) -OBJS := $(addprefix $(obj),$(COBJS)) +SRCS := $(SOBJS:.o=.S) $(COBJS-y:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS-y)) SOBJS := $(addprefix $(obj),$(SOBJS))
$(LIB): $(obj).depend $(OBJS) $(SOBJS) diff --git a/board/freescale/mpc8641hpcn/ddr.c b/board/freescale/mpc8641hpcn/ddr.c new file mode 100644 index 0000000..e02d1fd --- /dev/null +++ b/board/freescale/mpc8641hpcn/ddr.c @@ -0,0 +1,288 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#include <common.h> +#include <i2c.h> + +#include <../cpu/mpc8xxx/fsl_ddr_sdram.h> + +#define SDRAM_TYPE_DDR1 2 +#define SDRAM_TYPE_DDR2 3 +#define SDRAM_TYPE_LPDDR1 6 +#define SDRAM_TYPE_DDR3 7 + + +static void +get_spd(ddr2_spd_eeprom_t *spd, unsigned char i2c_address) +{ + i2c_read(i2c_address, 0, 1, (uchar *)spd, sizeof(ddr2_spd_eeprom_t)); +} + + +unsigned int +fsl_ddr_sdram_get_mem_data_rate(void) +{ + return get_bus_freq(0); +} + + +void +fsl_ddr_sdram_get_spd(ddr2_spd_eeprom_t *ctrl_dimms_spd, + unsigned int ctrl_num) +{ + unsigned int i; + unsigned int i2c_address = 0; + + for (i = 0; i < CONFIG_DIMM_SLOTS_PER_CTLR; i++) { + if (ctrl_num == 0 && i == 0) { + i2c_address = SPD_EEPROM_ADDRESS1; + } + if (ctrl_num == 0 && i == 1) { + i2c_address = SPD_EEPROM_ADDRESS2; + } + if (ctrl_num == 1 && i == 0) { + i2c_address = SPD_EEPROM_ADDRESS3; + } + if (ctrl_num == 1 && i == 1) { + i2c_address = SPD_EEPROM_ADDRESS4; + } + get_spd(&(ctrl_dimms_spd[i]), i2c_address); + } +} + + +void +fsl_ddr_sdram_dump_memctl_regs(unsigned int ctrl_num) +{ + unsigned int i; + volatile ccsr_ddr_t *ddr; + + if (ctrl_num == 0) + ddr = (void *)CFG_MPC86xx_DDR_ADDR; + else + ddr = (void *)CFG_MPC86xx_DDR2_ADDR; + + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + unsigned int bnds = 0; + unsigned int config = 0; + + if (i == 0) { + bnds = ddr->cs0_bnds; + config = ddr->cs0_config; + + } else if (i == 1) { + bnds = ddr->cs1_bnds; + config = ddr->cs1_config; + + } else if (i == 2) { + bnds = ddr->cs2_bnds; + config = ddr->cs2_config; + + } else if (i == 3) { + bnds = ddr->cs3_bnds; + config = ddr->cs3_config; + + } else { + /* + * FIXME what happens when CONFIG_CHIP_SELECTS_PER_CTRL > 4 + */ + } + + printf("cs%u_bnds = %08X\n", i, bnds); + printf("cs%u_config = %08X\n", i, config); + } + + printf("timing_cfg_3 = %08X\n", ddr->timing_cfg_3); + printf("timing_cfg_0 = %08X\n", ddr->timing_cfg_0); + printf("timing_cfg_1 = %08X\n", ddr->timing_cfg_1); + printf("timing_cfg_2 = %08X\n", ddr->timing_cfg_2); + printf("ddr_sdram_cfg = %08X\n", ddr->sdram_cfg_1); + printf("ddr_sdram_cfg_2 = %08X\n", ddr->sdram_cfg_2); + printf("ddr_sdram_mode = %08X\n", ddr->sdram_mode_1); + printf("ddr_sdram_mode_2 = %08X\n", ddr->sdram_mode_2); + printf("ddr_sdram_interval = %08X\n", ddr->sdram_interval); + printf("ddr_data_init = %08X\n", ddr->sdram_data_init); + printf("ddr_sdram_clk_cntl = %08X\n", ddr->sdram_clk_cntl); + printf("ddr_init_addr = %08X\n", ddr->init_addr); + +// FIXME cleanup +// printf("timing_cfg_4 = %08X\n", ddr->timing_cfg_4); +// printf("timing_cfg_5 = %08X\n", ddr->timing_cfg_5); +// printf("ddr_zq_cntl = %08X\n", ddr->ddr_zq_cntl); +// printf("ddr_wrlvl_cntl = %08X\n", ddr->ddr_wrlvl_cntl); +// printf("ddr_pd_cntl = %08X\n", ddr->ddr_pd_cntl); +// printf("ddr_sr_cntr = %08X\n", ddr->ddr_sr_cntr); +// printf("ddr_sdram_rcw_1 = %08X\n", ddr->ddr_sdram_rcw_1); +// printf("ddr_sdram_rcw_2 = %08X\n", ddr->ddr_sdram_rcw_2); +} + + +void +fsl_ddr_sdram_set_memctl_regs(const fsl_memctl_config_regs_t *regs, + unsigned int ctrl_num) +{ + unsigned int i; + volatile ccsr_ddr_t *ddr; + + switch (ctrl_num) { + case 0: + ddr = (void *)CFG_MPC86xx_DDR_ADDR; + break; + case 1: + ddr = (void *)CFG_MPC86xx_DDR2_ADDR; + break; + default: + printf("fsl_ddr_sdram_set_memctl_regs() unexpected ctrl_num = %u\n", ctrl_num); + return; + } + + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + if (i == 0) { + ddr->cs0_bnds = regs->cs[i].bnds; + ddr->cs0_config = regs->cs[i].config; +// ddr->cs0_config_2 = regs->cs[i].config_2; + + } else if (i == 1) { + ddr->cs1_bnds = regs->cs[i].bnds; + ddr->cs1_config = regs->cs[i].config; +// ddr->cs1_config_2 = regs->cs[i].config_2; + + } else if (i == 2) { + ddr->cs2_bnds = regs->cs[i].bnds; + ddr->cs2_config = regs->cs[i].config; +// ddr->cs2_config_2 = regs->cs[i].config_2; + + } else if (i == 3) { + ddr->cs3_bnds = regs->cs[i].bnds; + ddr->cs3_config = regs->cs[i].config; +// ddr->cs3_config_2 = regs->cs[i].config_2; + } + } + + /* + * Someone decided to use different names from the documentation... + */ + ddr->timing_cfg_3 = regs->timing_cfg_3; + ddr->timing_cfg_0 = regs->timing_cfg_0; + ddr->timing_cfg_1 = regs->timing_cfg_1; + ddr->timing_cfg_2 = regs->timing_cfg_2; + ddr->sdram_cfg_2 = regs->ddr_sdram_cfg_2; + ddr->sdram_mode_1 = regs->ddr_sdram_mode; + ddr->sdram_mode_2 = regs->ddr_sdram_mode_2; + ddr->sdram_interval = regs->ddr_sdram_interval; + ddr->sdram_data_init = regs->ddr_data_init; + ddr->sdram_clk_cntl = regs->ddr_sdram_clk_cntl; + ddr->init_addr = regs->ddr_init_addr; + ddr->init_ext_addr = regs->ddr_init_ext_addr; + + + /* + * FIXME: ECC? Need to program err_disable, err_sbe, and err_int_en + */ +#if 0 + /* 8572 */ + ddr->timing_cfg_4 = regs->timing_cfg_4; + ddr->timing_cfg_5 = regs->timing_cfg_5; + ddr->ddr_zq_cntl = regs->ddr_zq_cntl; + ddr->ddr_wrlvl_cntl = regs->ddr_wrlvl_cntl; + ddr->ddr_pd_cntl = regs->ddr_pd_cntl; + ddr->ddr_sr_cntr = regs->ddr_sr_cntr; + ddr->ddr_sdram_rcw_1 = regs->ddr_sdram_rcw_1; + ddr->ddr_sdram_rcw_2 = regs->ddr_sdram_rcw_2; +#endif + + printf("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"); + + ddr->sdram_cfg_1 = regs->ddr_sdram_cfg; + + + /* + * Poll DDR_SDRAM_CFG_2[D_INIT] bit until auto-data init is done + */ + while (ddr->sdram_cfg_2 & 0x10) { + udelay(10000); /* throttle polling rate */ + } +} + + +unsigned int +fsl_ddr_sdram_type_function(void) +{ + return SDRAM_TYPE_DDR2; +} + + +/* + * factors to consider for clock adjust: + * - number of chips on bus + * - position of slot + * - DDR1 vs. DDR2? + * - ??? + * + * FIXME: need to figure out the function parameters necessary to compute + * FIXME: a clock adjust value + */ + +unsigned int +fsl_ddr_sdram_clk_adjust_function(void) +{ + return 7; +} + + +/* + * factors to consider for CPO: + * - frequency + * - ddr1 vs. ddr2 + * + * FIXME: figure out how to compute or tabulate good values for this + */ + +unsigned int +fsl_ddr_sdram_cpo_override_function(void) +{ + return 10; +} + + +/* + * factors to consider for write data delay: + * - number of DIMMs + * + * 1 = 1/4 clock delay + * 2 = 1/2 clock delay + * 3 = 3/4 clock delay + * 4 = 1 clock delay + * 5 = 5/4 clock delay + * 6 = 3/2 clock delay + */ + +unsigned int +fsl_ddr_sdram_write_data_delay_function(void) +{ + return 3; +} + + +/* + * factors to consider for half-strength driver enable: + * - number of DIMMs installed + */ + +unsigned int +fsl_ddr_sdram_half_strength_driver_enable_function(void) +{ + return 0; +} diff --git a/board/freescale/mpc8641hpcn/mpc8641hpcn.c b/board/freescale/mpc8641hpcn/mpc8641hpcn.c index bb1f927..755c967 100644 --- a/board/freescale/mpc8641hpcn/mpc8641hpcn.c +++ b/board/freescale/mpc8641hpcn/mpc8641hpcn.c @@ -25,18 +25,17 @@ #include <asm/processor.h> #include <asm/immap_86xx.h> #include <asm/immap_fsl_pci.h> -#include <spd_sdram.h> #include <asm/io.h> #include <libfdt.h> #include <fdt_support.h>
#include "../common/pixis.h" +#include "../cpu/mpc8xxx/fsl_ddr_sdram.h"
#if defined(CONFIG_DDR_ECC) && !defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER) extern void ddr_enable_ecc(unsigned int dram_size); #endif
-void sdram_init(void); long int fixed_sdram(void);
@@ -59,7 +58,7 @@ initdram(int board_type) long dram_size = 0;
#if defined(CONFIG_SPD_EEPROM) - dram_size = spd_sdram(); + dram_size = fsl_ddr_sdram(); #else dram_size = fixed_sdram(); #endif diff --git a/cpu/mpc86xx/Makefile b/cpu/mpc86xx/Makefile index 4227053..454c728 100644 --- a/cpu/mpc86xx/Makefile +++ b/cpu/mpc86xx/Makefile @@ -36,7 +36,6 @@ COBJS-y += cpu.o COBJS-y += cpu_init.o COBJS-y += speed.o COBJS-y += interrupts.o -COBJS-y += spd_sdram.o
COBJS-$(CONFIG_OF_LIBFDT) += fdt.o
diff --git a/include/configs/MPC8641HPCN.h b/include/configs/MPC8641HPCN.h index 49ee7ff..7366b50 100644 --- a/include/configs/MPC8641HPCN.h +++ b/include/configs/MPC8641HPCN.h @@ -54,19 +54,6 @@ #define CONFIG_TSEC_ENET /* tsec ethernet support */ #define CONFIG_ENV_OVERWRITE
-#define CONFIG_SPD_EEPROM /* Use SPD EEPROM for DDR setup*/ -#undef CONFIG_DDR_DLL /* possible DLL fix needed */ -#define CONFIG_DDR_2T_TIMING /* Sets the 2T timing bit */ -#define CONFIG_DDR_ECC /* only for ECC DDR module */ -#define CONFIG_ECC_INIT_VIA_DDRCONTROLLER /* DDR controller or DMA? */ -#define CONFIG_MEM_INIT_VALUE 0xDeadBeef -#define CONFIG_NUM_DDR_CONTROLLERS 2 -/* #define CONFIG_DDR_INTERLEAVE 1 */ -#define CACHE_LINE_INTERLEAVING 0x20000000 -#define PAGE_INTERLEAVING 0x21000000 -#define BANK_INTERLEAVING 0x22000000 -#define SUPER_BANK_INTERLEAVING 0x23000000 - #define CONFIG_HIGH_BATS 1 /* High BATs supported and enabled */
#define CONFIG_ALTIVEC 1 @@ -105,53 +92,85 @@ extern unsigned long get_board_sys_clk(unsigned long dummy); /* * DDR Setup */ +#define CONFIG_FSL_DDR2 +#undef CONFIG_FSL_DDR_INTERACTIVE +#define CONFIG_SPD_EEPROM /* Use SPD EEPROM for DDR setup */ +#define CONFIG_DDR_SPD +#undef CONFIG_DDR_DLL + +//#define CONFIG_DDR_2T_TIMING /* Sets the 2T timing bit */ +//#define CONFIG_DDR_ECC /* only for ECC DDR module */ + +//#define CONFIG_DDR_INTERLEAVE 1 +//#define CACHE_LINE_INTERLEAVING 0x20000000 +//#define PAGE_INTERLEAVING 0x21000000 +//#define BANK_INTERLEAVING 0x22000000 +//#define SUPER_BANK_INTERLEAVING 0x23000000 + +#define CONFIG_ECC_INIT_VIA_DDRCONTROLLER /* DDR controller or DMA? */ +#define CONFIG_MEM_INIT_VALUE 0xDeadBeef + #define CFG_DDR_SDRAM_BASE 0x00000000 /* DDR is system memory*/ #define CFG_SDRAM_BASE CFG_DDR_SDRAM_BASE #define CONFIG_VERY_BIG_RAM
#define MPC86xx_DDR_SDRAM_CLK_CNTL
-#if defined(CONFIG_SPD_EEPROM) - /* - * Determine DDR configuration from I2C interface. - */ - #define SPD_EEPROM_ADDRESS1 0x51 /* DDR DIMM */ - #define SPD_EEPROM_ADDRESS2 0x52 /* DDR DIMM */ - #define SPD_EEPROM_ADDRESS3 0x53 /* DDR DIMM */ - #define SPD_EEPROM_ADDRESS4 0x54 /* DDR DIMM */
-#else - /* - * Manually set up DDR1 parameters - */ - - #define CFG_SDRAM_SIZE 256 /* DDR is 256MB */ - - #define CFG_DDR_CS0_BNDS 0x0000000F - #define CFG_DDR_CS0_CONFIG 0x80010102 /* Enable, no interleaving */ - #define CFG_DDR_EXT_REFRESH 0x00000000 - #define CFG_DDR_TIMING_0 0x00260802 - #define CFG_DDR_TIMING_1 0x39357322 - #define CFG_DDR_TIMING_2 0x14904cc8 - #define CFG_DDR_MODE_1 0x00480432 - #define CFG_DDR_MODE_2 0x00000000 - #define CFG_DDR_INTERVAL 0x06090100 - #define CFG_DDR_DATA_INIT 0xdeadbeef - #define CFG_DDR_CLK_CTRL 0x03800000 - #define CFG_DDR_OCD_CTRL 0x00000000 - #define CFG_DDR_OCD_STATUS 0x00000000 - #define CFG_DDR_CONTROL 0xe3008000 /* Type = DDR2 */ - #define CFG_DDR_CONTROL2 0x04400000 - - /* Not used in fixed_sdram function */ - - #define CFG_DDR_MODE 0x00000022 - #define CFG_DDR_CS1_BNDS 0x00000000 - #define CFG_DDR_CS2_BNDS 0x00000FFF /* Not done */ - #define CFG_DDR_CS3_BNDS 0x00000FFF /* Not done */ - #define CFG_DDR_CS4_BNDS 0x00000FFF /* Not done */ - #define CFG_DDR_CS5_BNDS 0x00000FFF /* Not done */ -#endif +/* + * Number of memory controllers on device + */ +#define CONFIG_NUM_DDR_CONTROLLERS 2 + +/* + * Number of DIMM slots per memory controller + */ +#define CONFIG_DIMM_SLOTS_PER_CTLR 2 + +/* + * Number of chip selects per memory controller + */ +#define CONFIG_CHIP_SELECTS_PER_CTRL (2 * CONFIG_DIMM_SLOTS_PER_CTLR) + +/* + * I2C addresses of SPD EEPROMs + */ +#define SPD_EEPROM_ADDRESS1 0x51 /* CTLR 0 DIMM 0 */ +#define SPD_EEPROM_ADDRESS2 0x52 /* CTLR 0 DIMM 1 */ +#define SPD_EEPROM_ADDRESS3 0x53 /* CTLR 1 DIMM 0 */ +#define SPD_EEPROM_ADDRESS4 0x54 /* CTLR 1 DIMM 1 */ + + +/* + * These are used when DDR doesn't use SPD. + */ +#define CFG_SDRAM_SIZE 256 /* DDR is 256MB */ +#define CFG_DDR_CS0_BNDS 0x0000000F +#define CFG_DDR_CS0_CONFIG 0x80010102 /* Enable, no interleaving */ +#define CFG_DDR_TIMING_3 0x00000000 +#define CFG_DDR_TIMING_0 0x00260802 +#define CFG_DDR_TIMING_1 0x39357322 +#define CFG_DDR_TIMING_2 0x14904cc8 +#define CFG_DDR_MODE_1 0x00480432 +#define CFG_DDR_MODE_2 0x00000000 +#define CFG_DDR_INTERVAL 0x06090100 +#define CFG_DDR_DATA_INIT 0xdeadbeef +#define CFG_DDR_CLK_CTRL 0x03800000 +#define CFG_DDR_OCD_CTRL 0x00000000 +#define CFG_DDR_OCD_STATUS 0x00000000 +#define CFG_DDR_CONTROL 0xe3008000 /* Type = DDR2 */ +#define CFG_DDR_CONTROL2 0x04400000 + +/* + * FIXME: Not used in fixed_sdram function + */ +#define CFG_DDR_MODE 0x00000022 +#define CFG_DDR_CS1_BNDS 0x00000000 +#define CFG_DDR_CS2_BNDS 0x00000FFF /* Not done */ +#define CFG_DDR_CS3_BNDS 0x00000FFF /* Not done */ +#define CFG_DDR_CS4_BNDS 0x00000FFF /* Not done */ +#define CFG_DDR_CS5_BNDS 0x00000FFF /* Not done */ +
#define CFG_ID_EEPROM 1 #ifdef CFG_ID_EEPROM

From: Jon Loeliger jdl@freescale.com
Signed-off-by: Jon Loeliger jdl@freescale.com Signed-off-by: Kumar Gala galak@kernel.crashing.org --- board/freescale/mpc8610hpcd/Makefile | 10 +- board/freescale/mpc8610hpcd/ddr.c | 279 +++++++++++++++++++++++++++++ board/freescale/mpc8610hpcd/mpc8610hpcd.c | 3 +- include/configs/MPC8610HPCD.h | 54 ++++-- 4 files changed, 324 insertions(+), 22 deletions(-) create mode 100644 board/freescale/mpc8610hpcd/ddr.c
diff --git a/board/freescale/mpc8610hpcd/Makefile b/board/freescale/mpc8610hpcd/Makefile index e17a9cb..9236364 100644 --- a/board/freescale/mpc8610hpcd/Makefile +++ b/board/freescale/mpc8610hpcd/Makefile @@ -23,14 +23,14 @@ include $(TOPDIR)/config.mk
LIB = $(obj)lib$(BOARD).a
-COBJS := $(BOARD).o law.o +COBJS-y += $(BOARD).o +COBJS-y += ddr.o +COBJS-y += law.o
COBJS-${CONFIG_FSL_DIU_FB} += mpc8610hpcd_diu.o
-COBJS += ${COBJS-y} - -SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) -OBJS := $(addprefix $(obj),$(COBJS)) +SRCS := $(SOBJS:.o=.S) $(COBJS-y:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS-y)) SOBJS := $(addprefix $(obj),$(SOBJS))
$(LIB): $(obj).depend $(OBJS) $(SOBJS) diff --git a/board/freescale/mpc8610hpcd/ddr.c b/board/freescale/mpc8610hpcd/ddr.c new file mode 100644 index 0000000..de389d8 --- /dev/null +++ b/board/freescale/mpc8610hpcd/ddr.c @@ -0,0 +1,279 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#include <common.h> +#include <i2c.h> + +#include <../cpu/mpc8xxx/fsl_ddr_sdram.h> + +#define SDRAM_TYPE_DDR1 2 +#define SDRAM_TYPE_DDR2 3 +#define SDRAM_TYPE_LPDDR1 6 +#define SDRAM_TYPE_DDR3 7 + + +static void +get_spd(ddr2_spd_eeprom_t *spd, unsigned char i2c_address) +{ + i2c_read(i2c_address, 0, 1, (uchar *)spd, sizeof(ddr2_spd_eeprom_t)); +} + + +unsigned int +fsl_ddr_sdram_get_mem_data_rate(void) +{ + return get_bus_freq(0); +} + + +void +fsl_ddr_sdram_get_spd(ddr2_spd_eeprom_t *ctrl_dimms_spd, + unsigned int ctrl_num) +{ + unsigned int i; + unsigned int i2c_address = 0; + + for (i = 0; i < CONFIG_DIMM_SLOTS_PER_CTLR; i++) { + if (ctrl_num == 0 && i == 0) { + i2c_address = SPD_EEPROM_ADDRESS1; + } + get_spd(&(ctrl_dimms_spd[i]), i2c_address); + } +} + + +void +fsl_ddr_sdram_dump_memctl_regs(unsigned int ctrl_num) +{ + unsigned int i; + volatile ccsr_ddr_t *ddr; + + if (ctrl_num == 0) + ddr = (void *)CFG_MPC86xx_DDR_ADDR; + else + ddr = (void *)CFG_MPC86xx_DDR2_ADDR; + + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + unsigned int bnds = 0; + unsigned int config = 0; + + if (i == 0) { + bnds = ddr->cs0_bnds; + config = ddr->cs0_config; + + } else if (i == 1) { + bnds = ddr->cs1_bnds; + config = ddr->cs1_config; + + } else if (i == 2) { + bnds = ddr->cs2_bnds; + config = ddr->cs2_config; + + } else if (i == 3) { + bnds = ddr->cs3_bnds; + config = ddr->cs3_config; + + } else { + /* + * FIXME what happens when CONFIG_CHIP_SELECTS_PER_CTRL > 4 + */ + } + + printf("cs%u_bnds = %08X\n", i, bnds); + printf("cs%u_config = %08X\n", i, config); + } + + printf("timing_cfg_3 = %08X\n", ddr->timing_cfg_3); + printf("timing_cfg_0 = %08X\n", ddr->timing_cfg_0); + printf("timing_cfg_1 = %08X\n", ddr->timing_cfg_1); + printf("timing_cfg_2 = %08X\n", ddr->timing_cfg_2); + printf("ddr_sdram_cfg = %08X\n", ddr->sdram_cfg_1); + printf("ddr_sdram_cfg_2 = %08X\n", ddr->sdram_cfg_2); + printf("ddr_sdram_mode = %08X\n", ddr->sdram_mode_1); + printf("ddr_sdram_mode_2 = %08X\n", ddr->sdram_mode_2); + printf("ddr_sdram_interval = %08X\n", ddr->sdram_interval); + printf("ddr_data_init = %08X\n", ddr->sdram_data_init); + printf("ddr_sdram_clk_cntl = %08X\n", ddr->sdram_clk_cntl); + printf("ddr_init_addr = %08X\n", ddr->init_addr); + +// FIXME cleanup +// printf("timing_cfg_4 = %08X\n", ddr->timing_cfg_4); +// printf("timing_cfg_5 = %08X\n", ddr->timing_cfg_5); +// printf("ddr_zq_cntl = %08X\n", ddr->ddr_zq_cntl); +// printf("ddr_wrlvl_cntl = %08X\n", ddr->ddr_wrlvl_cntl); +// printf("ddr_pd_cntl = %08X\n", ddr->ddr_pd_cntl); +// printf("ddr_sr_cntr = %08X\n", ddr->ddr_sr_cntr); +// printf("ddr_sdram_rcw_1 = %08X\n", ddr->ddr_sdram_rcw_1); +// printf("ddr_sdram_rcw_2 = %08X\n", ddr->ddr_sdram_rcw_2); +} + + +void +fsl_ddr_sdram_set_memctl_regs(const fsl_memctl_config_regs_t *regs, + unsigned int ctrl_num) +{ + unsigned int i; + volatile ccsr_ddr_t *ddr; + + switch (ctrl_num) { + case 0: + ddr = (void *)CFG_MPC86xx_DDR_ADDR; + break; + case 1: + ddr = (void *)CFG_MPC86xx_DDR2_ADDR; + break; + default: + printf("fsl_ddr_sdram_set_memctl_regs() unexpected ctrl_num = %u\n", ctrl_num); + return; + } + + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + if (i == 0) { + ddr->cs0_bnds = regs->cs[i].bnds; + ddr->cs0_config = regs->cs[i].config; +// ddr->cs0_config_2 = regs->cs[i].config_2; + + } else if (i == 1) { + ddr->cs1_bnds = regs->cs[i].bnds; + ddr->cs1_config = regs->cs[i].config; +// ddr->cs1_config_2 = regs->cs[i].config_2; + + } else if (i == 2) { + ddr->cs2_bnds = regs->cs[i].bnds; + ddr->cs2_config = regs->cs[i].config; +// ddr->cs2_config_2 = regs->cs[i].config_2; + + } else if (i == 3) { + ddr->cs3_bnds = regs->cs[i].bnds; + ddr->cs3_config = regs->cs[i].config; +// ddr->cs3_config_2 = regs->cs[i].config_2; + } + } + + /* + * Someone decided to use different names from the documentation... + */ + ddr->timing_cfg_3 = regs->timing_cfg_3; + ddr->timing_cfg_0 = regs->timing_cfg_0; + ddr->timing_cfg_1 = regs->timing_cfg_1; + ddr->timing_cfg_2 = regs->timing_cfg_2; + ddr->sdram_cfg_2 = regs->ddr_sdram_cfg_2; + ddr->sdram_mode_1 = regs->ddr_sdram_mode; + ddr->sdram_mode_2 = regs->ddr_sdram_mode_2; + ddr->sdram_interval = regs->ddr_sdram_interval; + ddr->sdram_data_init = regs->ddr_data_init; + ddr->sdram_clk_cntl = regs->ddr_sdram_clk_cntl; + ddr->init_addr = regs->ddr_init_addr; + ddr->init_ext_addr = regs->ddr_init_ext_addr; + + + /* + * FIXME: ECC? Need to program err_disable, err_sbe, and err_int_en + */ +#if 0 + /* 8572 */ + ddr->timing_cfg_4 = regs->timing_cfg_4; + ddr->timing_cfg_5 = regs->timing_cfg_5; + ddr->ddr_zq_cntl = regs->ddr_zq_cntl; + ddr->ddr_wrlvl_cntl = regs->ddr_wrlvl_cntl; + ddr->ddr_pd_cntl = regs->ddr_pd_cntl; + ddr->ddr_sr_cntr = regs->ddr_sr_cntr; + ddr->ddr_sdram_rcw_1 = regs->ddr_sdram_rcw_1; + ddr->ddr_sdram_rcw_2 = regs->ddr_sdram_rcw_2; +#endif + + printf("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"); + + ddr->sdram_cfg_1 = regs->ddr_sdram_cfg; + + + /* + * Poll DDR_SDRAM_CFG_2[D_INIT] bit until auto-data init is done + */ + while (ddr->sdram_cfg_2 & 0x10) { + udelay(10000); /* throttle polling rate */ + } +} + + +unsigned int +fsl_ddr_sdram_type_function(void) +{ + return SDRAM_TYPE_DDR2; +} + + +/* + * factors to consider for clock adjust: + * - number of chips on bus + * - position of slot + * - DDR1 vs. DDR2? + * - ??? + * + * FIXME: need to figure out the function parameters necessary to compute + * FIXME: a clock adjust value + */ + +unsigned int +fsl_ddr_sdram_clk_adjust_function(void) +{ + return 7; +} + + +/* + * factors to consider for CPO: + * - frequency + * - ddr1 vs. ddr2 + * + * FIXME: figure out how to compute or tabulate good values for this + */ + +unsigned int +fsl_ddr_sdram_cpo_override_function(void) +{ + return 10; +} + + +/* + * factors to consider for write data delay: + * - number of DIMMs + * + * 1 = 1/4 clock delay + * 2 = 1/2 clock delay + * 3 = 3/4 clock delay + * 4 = 1 clock delay + * 5 = 5/4 clock delay + * 6 = 3/2 clock delay + */ + +unsigned int +fsl_ddr_sdram_write_data_delay_function(void) +{ + return 3; +} + + +/* + * factors to consider for half-strength driver enable: + * - number of DIMMs installed + */ + +unsigned int +fsl_ddr_sdram_half_strength_driver_enable_function(void) +{ + return 0; +} diff --git a/board/freescale/mpc8610hpcd/mpc8610hpcd.c b/board/freescale/mpc8610hpcd/mpc8610hpcd.c index 3a855b5..f8d8707 100644 --- a/board/freescale/mpc8610hpcd/mpc8610hpcd.c +++ b/board/freescale/mpc8610hpcd/mpc8610hpcd.c @@ -33,6 +33,7 @@ #include <spd_sdram.h>
#include "../common/pixis.h" +#include "../cpu/mpc8xxx/fsl_ddr_sdram.h"
#if defined(CONFIG_DDR_ECC) && !defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER) extern void ddr_enable_ecc(unsigned int dram_size); @@ -119,7 +120,7 @@ initdram(int board_type) long dram_size = 0;
#if defined(CONFIG_SPD_EEPROM) - dram_size = spd_sdram(); + dram_size = fsl_ddr_sdram(); #else dram_size = fixed_sdram(); #endif diff --git a/include/configs/MPC8610HPCD.h b/include/configs/MPC8610HPCD.h index a051b6d..6b3942d 100644 --- a/include/configs/MPC8610HPCD.h +++ b/include/configs/MPC8610HPCD.h @@ -8,7 +8,6 @@
/* * MPC8610HPCD board configuration file - * */
#ifndef __CONFIG_H @@ -45,14 +44,6 @@ #define CONFIG_FSL_LAW 1 /* Use common FSL init code */
#define CONFIG_ENV_OVERWRITE - -#define CONFIG_SPD_EEPROM /* Use SPD for DDR */ -#undef CONFIG_DDR_DLL /* possible DLL fix needed */ -#define CONFIG_DDR_2T_TIMING /* Sets the 2T timing bit */ -#undef CONFIG_DDR_ECC /* only for ECC DDR module */ -#define CONFIG_ECC_INIT_VIA_DDRCONTROLLER /* DDR controller or DMA? */ -#define CONFIG_MEM_INIT_VALUE 0xDeadBeef -#define CONFIG_NUM_DDR_CONTROLLERS 1 #define CONFIG_INTERRUPTS /* enable pci, srio, ddr interrupts */
#define CONFIG_HIGH_BATS 1 /* High BATs supported & enabled */ @@ -94,22 +85,50 @@ /* * DDR Setup */ +#define CONFIG_FSL_DDR2 +#undef CONFIG_FSL_DDR_INTERACTIVE +#define CONFIG_SPD_EEPROM /* Use SPD for DDR */ +#define CONFIG_DDR_SPD +#undef CONFIG_DDR_DLL /* possible DLL fix needed */ + +//#define CONFIG_DDR_2T_TIMING /* Sets the 2T timing bit */ +//#undef CONFIG_DDR_ECC /* only for ECC DDR module */ + +#define CONFIG_ECC_INIT_VIA_DDRCONTROLLER /* DDR controller or DMA? */ +#define CONFIG_MEM_INIT_VALUE 0xDeadBeef + #define CFG_DDR_SDRAM_BASE 0x00000000 /* DDR is system memory*/ #define CFG_SDRAM_BASE CFG_DDR_SDRAM_BASE #define CONFIG_VERY_BIG_RAM
#define MPC86xx_DDR_SDRAM_CLK_CNTL
-#if defined(CONFIG_SPD_EEPROM) + /* - * Determine DDR configuration from I2C interface. + * Number of memory controllers on device */ -#define SPD_EEPROM_ADDRESS1 0x51 /* DDR DIMM */ -#else +#define CONFIG_NUM_DDR_CONTROLLERS 1 + /* - * Manually set up DDR1 parameters + * Number of DIMM slots per memory controller */ +#define CONFIG_DIMM_SLOTS_PER_CTLR 1
+/* + * Number of chip selects per memory controller + */ +#define CONFIG_CHIP_SELECTS_PER_CTRL (2 * CONFIG_DIMM_SLOTS_PER_CTLR) + + +/* + * I2C addresses of SPD EEPROMs + */ +#define SPD_EEPROM_ADDRESS1 0x51 /* CTLR 0 DIMM 0 */ + + +/* + * These are used when DDR doesn't use SPD. + */ #define CFG_SDRAM_SIZE 256 /* DDR is 256MB */
#if 0 /* TODO */ @@ -132,7 +151,10 @@ #define CFG_DDR_ERR_INT_EN 0x00000000 #define CFG_DDR_ERR_DIS 0x00000000 #define CFG_DDR_SBE 0x000f0000 - /* Not used in fixed_sdram function */ + +/* + * FIXME: Not used in fixed_sdram function + */ #define CFG_DDR_MODE 0x00000022 #define CFG_DDR_CS1_BNDS 0x00000000 #define CFG_DDR_CS2_BNDS 0x00000FFF /* Not done */ @@ -140,7 +162,7 @@ #define CFG_DDR_CS4_BNDS 0x00000FFF /* Not done */ #define CFG_DDR_CS5_BNDS 0x00000FFF /* Not done */ #endif -#endif +
#define CFG_ID_EEPROM #ifdef CFG_ID_EEPROM

Signed-off-by: Kumar Gala galak@kernel.crashing.org --- Makefile | 1 + board/freescale/mpc8544ds/Makefile | 9 +- board/freescale/mpc8544ds/ddr.c | 268 +++++++++++++++++++++++++++++++++ board/freescale/mpc8544ds/mpc8544ds.c | 21 ++- cpu/mpc85xx/Makefile | 2 +- include/configs/MPC8544DS.h | 59 ++++++-- 6 files changed, 339 insertions(+), 21 deletions(-) create mode 100644 board/freescale/mpc8544ds/ddr.c
diff --git a/Makefile b/Makefile index 39fc369..d0499ba 100644 --- a/Makefile +++ b/Makefile @@ -235,6 +235,7 @@ LIBS += drivers/qe/qe.a endif ifeq ($(CPU),mpc85xx) LIBS += drivers/qe/qe.a +LIBS += cpu/mpc8xxx/libmpc8xxx.a endif ifeq ($(CPU),mpc86xx) LIBS += cpu/mpc8xxx/libmpc8xxx.a diff --git a/board/freescale/mpc8544ds/Makefile b/board/freescale/mpc8544ds/Makefile index 53368b2..3e82bbf 100644 --- a/board/freescale/mpc8544ds/Makefile +++ b/board/freescale/mpc8544ds/Makefile @@ -26,10 +26,13 @@ include $(TOPDIR)/config.mk
LIB = $(obj)lib$(BOARD).a
-COBJS := $(BOARD).o law.o tlb.o +COBJS-y += $(BOARD).o +COBJS-y += ddr.o +COBJS-y += law.o +COBJS-y += tlb.o
-SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) -OBJS := $(addprefix $(obj),$(COBJS)) +SRCS := $(SOBJS:.o=.S) $(COBJS-y:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS-y)) SOBJS := $(addprefix $(obj),$(SOBJS))
$(LIB): $(obj).depend $(OBJS) $(SOBJS) diff --git a/board/freescale/mpc8544ds/ddr.c b/board/freescale/mpc8544ds/ddr.c new file mode 100644 index 0000000..b18ccc7 --- /dev/null +++ b/board/freescale/mpc8544ds/ddr.c @@ -0,0 +1,268 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#include <common.h> +#include <i2c.h> + +#include <../cpu/mpc8xxx/fsl_ddr_sdram.h> + +#define SDRAM_TYPE_DDR1 2 +#define SDRAM_TYPE_DDR2 3 + + +static void +get_spd(ddr2_spd_eeprom_t *spd, unsigned char i2c_address) +{ + i2c_read(i2c_address, 0, 1, (uchar *)spd, sizeof(ddr2_spd_eeprom_t)); +} + + +unsigned int +fsl_ddr_sdram_get_mem_data_rate(void) +{ + return get_ddr_freq(0); +} + + +void +fsl_ddr_sdram_get_spd(ddr2_spd_eeprom_t *ctrl_dimms_spd, + unsigned int ctrl_num) +{ + unsigned int i; + + if (ctrl_num) { + printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num); + return; + } + + for (i = 0; i < CONFIG_DIMM_SLOTS_PER_CTLR; i++) { + get_spd(&(ctrl_dimms_spd[i]), SPD_EEPROM_ADDRESS1); + } +} + + +void +fsl_ddr_sdram_dump_memctl_regs(unsigned int ctrl_num) +{ + unsigned int i; + volatile ccsr_ddr_t *ddr = (void *)CFG_MPC85xx_DDR_ADDR; + + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + unsigned int bnds = 0; + unsigned int config = 0; + unsigned int *pbnds = NULL; + unsigned int *pconfig = NULL; + + if (i == 0) { + bnds = ddr->cs0_bnds; + config = ddr->cs0_config; + pbnds = (unsigned int *)&ddr->cs0_bnds; + pconfig = (unsigned int *)&ddr->cs0_config; + + } else if (i == 1) { + bnds = ddr->cs1_bnds; + config = ddr->cs1_config; + pbnds = (unsigned int *)&ddr->cs1_bnds; + pconfig = (unsigned int *)&ddr->cs1_config; + + } else if (i == 2) { + bnds = ddr->cs2_bnds; + config = ddr->cs2_config; + pbnds = (unsigned int *)&ddr->cs2_bnds; + pconfig = (unsigned int *)&ddr->cs2_config; + + } else if (i == 3) { + bnds = ddr->cs3_bnds; + config = ddr->cs3_config; + pbnds = (unsigned int *) &ddr->cs3_bnds; + pconfig = (unsigned int *) &ddr->cs3_config; + + } else { + /* + * FIXME what happens if CONFIG_CHIP_SELECTS_PER_CTRL > 4 + */ + } + + printf("cs%u_bnds = %08X\t%p\n", i, bnds, pbnds); + printf("cs%u_config = %08X\t%p\n", i, config, pconfig); + } + + /* + * Due to inconsistencies between immap_85xx.h and immap_86xx.h, + * you will have to modify the structure member names by hand + * between architectures. + */ + printf("timing_cfg_3 = %08X\t%p\n", + ddr->timing_cfg_3, &ddr->timing_cfg_3); + printf("timing_cfg_0 = %08X\t%p\n", + ddr->timing_cfg_0, &ddr->timing_cfg_0); + printf("timing_cfg_1 = %08X\t%p\n", + ddr->timing_cfg_1, &ddr->timing_cfg_1); + printf("timing_cfg_2 = %08X\t%p\n", + ddr->timing_cfg_2, &ddr->timing_cfg_2); + printf("ddr_sdram_cfg = %08X\t%p\n", + ddr->sdram_cfg, &ddr->sdram_cfg); + printf("ddr_sdram_cfg_2 = %08X\t%p\n", + ddr->sdram_cfg_2, &ddr->sdram_cfg_2); + printf("ddr_sdram_mode = %08X\t%p\n", + ddr->sdram_mode, &ddr->sdram_mode); + printf("ddr_sdram_mode_2 = %08X\t%p\n", + ddr->sdram_mode_2, &ddr->sdram_mode_2); + printf("ddr_sdram_md_cntl = %08X\t%p\n", + ddr->sdram_md_cntl, &ddr->sdram_md_cntl); + printf("ddr_sdram_interval = %08X\t%p\n", + ddr->sdram_interval, &ddr->sdram_interval); + printf("ddr_data_init = %08X\t%p\n", + ddr->sdram_data_init, &ddr->sdram_data_init); + printf("ddr_sdram_clk_cntl = %08X\t%p\n", + ddr->sdram_clk_cntl, &ddr->sdram_clk_cntl); + printf("ddr_init_addr = %08X\t%p\n", + ddr->init_addr, &ddr->init_addr); + printf("ddr_init_ext_addr = %08X\t%p\n", + ddr->init_ext_addr, &ddr->init_ext_addr); +} + + +void +fsl_ddr_sdram_set_memctl_regs(const fsl_memctl_config_regs_t *regs, + unsigned int ctrl_num) +{ + unsigned int i; + volatile ccsr_ddr_t *ddr = (void *)CFG_MPC85xx_DDR_ADDR; + + if (ctrl_num) { + printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num); + return; + } + + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + if (i == 0) { + ddr->cs0_bnds = regs->cs[i].bnds; + ddr->cs0_config = regs->cs[i].config; + + } else if (i == 1) { + ddr->cs1_bnds = regs->cs[i].bnds; + ddr->cs1_config = regs->cs[i].config; + + } else if (i == 2) { + ddr->cs2_bnds = regs->cs[i].bnds; + ddr->cs2_config = regs->cs[i].config; + + } else if (i == 3) { + ddr->cs3_bnds = regs->cs[i].bnds; + ddr->cs3_config = regs->cs[i].config; + } + } + + /* + * Someone decided to use different names from the documentation... + */ + ddr->timing_cfg_3 = regs->timing_cfg_3; + ddr->timing_cfg_0 = regs->timing_cfg_0; + ddr->timing_cfg_1 = regs->timing_cfg_1; + ddr->timing_cfg_2 = regs->timing_cfg_2; + ddr->sdram_cfg_2 = regs->ddr_sdram_cfg_2; + ddr->sdram_mode = regs->ddr_sdram_mode; + ddr->sdram_mode_2 = regs->ddr_sdram_mode_2; + ddr->sdram_interval = regs->ddr_sdram_interval; + ddr->sdram_data_init = regs->ddr_data_init; + ddr->sdram_clk_cntl = regs->ddr_sdram_clk_cntl; + ddr->init_addr = regs->ddr_init_addr; + ddr->init_ext_addr = regs->ddr_init_ext_addr; + + /* + * FIXME: ECC? Need to program err_disable, err_sbe, and err_int_en + */ + + /* + * 200 painful micro-seconds must elapse between + * the DDR clock setup and the DDR config enable. + */ + udelay(200); + asm volatile("sync;isync"); + + ddr->sdram_cfg = regs->ddr_sdram_cfg; + + /* + * Poll DDR_SDRAM_CFG_2[D_INIT] bit until auto-data init is done. + */ + while (ddr->sdram_cfg_2 & 0x10) { + udelay(10000); /* throttle polling rate */ + } +} + + +unsigned int +fsl_ddr_sdram_type_function(void) +{ + return SDRAM_TYPE_DDR2; +} + + +/* + * factors to consider for clock adjust: + * - number of chips on bus + * - position of slot + * - DDR1 vs. DDR2? + * - ??? + * + * FIXME: need to figure out the function parameters necessary to compute + * FIXME: a clock adjust value + */ + +unsigned int +fsl_ddr_sdram_clk_adjust_function(void) +{ + return 7; +} + + +/* + * factors to consider for CPO: + * - frequency + * - ddr1 vs. ddr2 + * + * FIXME: figure out how to compute or tabulate good values for this + */ + +unsigned int +fsl_ddr_sdram_cpo_override_function(void) +{ + return 10; +} + + +/* + * factors to consider for write data delay: + * - number of DIMMs + * + * 1 = 1/4 clock delay + * 2 = 1/2 clock delay + * 3 = 3/4 clock delay + * 4 = 1 clock delay + * 5 = 5/4 clock delay + * 6 = 3/2 clock delay + */ + +unsigned int +fsl_ddr_sdram_write_data_delay_function(void) +{ + return 5; +} + + +/* + * factors to consider for half-strength driver enable: + * - number of DIMMs installed + */ + +unsigned int +fsl_ddr_sdram_half_strength_driver_enable_function(void) +{ + return 0; +} diff --git a/board/freescale/mpc8544ds/mpc8544ds.c b/board/freescale/mpc8544ds/mpc8544ds.c index dd10af8..d3b2f94 100644 --- a/board/freescale/mpc8544ds/mpc8544ds.c +++ b/board/freescale/mpc8544ds/mpc8544ds.c @@ -24,22 +24,21 @@ #include <command.h> #include <pci.h> #include <asm/processor.h> +#include <asm/mmu.h> #include <asm/immap_85xx.h> #include <asm/immap_fsl_pci.h> #include <asm/io.h> -#include <spd_sdram.h> #include <miiphy.h> #include <libfdt.h> #include <fdt_support.h>
#include "../common/pixis.h" +#include "../cpu/mpc8xxx/fsl_ddr_sdram.h"
#if defined(CONFIG_DDR_ECC) && !defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER) extern void ddr_enable_ecc(unsigned int dram_size); #endif
-void sdram_init(void); - int board_early_init_f (void) { return 0; @@ -71,7 +70,13 @@ initdram(int board_type)
puts("Initializing\n");
- dram_size = spd_sdram(); + dram_size = fsl_ddr_sdram(); + printf("dram_size = %u\n", dram_size); + + dram_size = setup_ddr_tlbs(dram_size / 0x100000); + printf("dram_size = %u after setup_ddr_tlbs\n", dram_size); + + dram_size *= 0x100000;
#if defined(CONFIG_DDR_ECC) && !defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER) /* @@ -96,10 +101,14 @@ testdram(void) CFG_MEMTEST_END);
printf("DRAM test phase 1:\n"); - for (p = pstart; p < pend; p++) + for (p = pstart; p < pend; p++) { + if ((((unsigned int) p) & 0xffff) == 0) { + printf ("%p\n", p); + } *p = 0xaaaaaaaa; + }
- for (p = pstart; p < pend; p++) { + for (p = pstart; p < pend; p++) { if (*p != 0xaaaaaaaa) { printf ("DRAM test fails at: %08x\n", (uint) p); return 1; diff --git a/cpu/mpc85xx/Makefile b/cpu/mpc85xx/Makefile index c180dbd..d51a6dd 100644 --- a/cpu/mpc85xx/Makefile +++ b/cpu/mpc85xx/Makefile @@ -43,7 +43,7 @@ endif endif
COBJS = traps.o cpu.o cpu_init.o speed.o interrupts.o tlb.o \ - pci.o serial_scc.o commproc.o ether_fcc.o spd_sdram.o qe_io.o \ + pci.o serial_scc.o commproc.o ether_fcc.o qe_io.o \ $(COBJS-y)
SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) diff --git a/include/configs/MPC8544DS.h b/include/configs/MPC8544DS.h index ffe9e00..7878877 100644 --- a/include/configs/MPC8544DS.h +++ b/include/configs/MPC8544DS.h @@ -46,15 +46,6 @@
#define CONFIG_TSEC_ENET /* tsec ethernet support */ #define CONFIG_ENV_OVERWRITE -#define CONFIG_SPD_EEPROM /* Use SPD EEPROM for DDR setup */ -#undef CONFIG_DDR_DLL -#define CONFIG_DDR_2T_TIMING /* Sets the 2T timing bit */ - -#define CONFIG_DDR_ECC /* only for ECC DDR module */ -#define CONFIG_ECC_INIT_VIA_DDRCONTROLLER /* DDR controller or DMA? */ -#define CONFIG_MEM_INIT_VALUE 0xDeadBeef - -#define CONFIG_DDR_ECC_CMD #define CONFIG_INTERRUPTS /* enable pci, srio, ddr interrupts */
/* @@ -87,8 +78,8 @@ extern unsigned long get_board_sys_clk(unsigned long dummy); #define CONFIG_BOARD_EARLY_INIT_F 1 /* Call board_pre_init */
#undef CFG_DRAM_TEST /* memory test, takes time */ -#define CFG_MEMTEST_START 0x00200000 /* memtest works on */ -#define CFG_MEMTEST_END 0x00400000 +#define CFG_MEMTEST_START 0x00000000 /* memtest works on */ +#define CFG_MEMTEST_END 0x7fffffff #define CFG_ALT_MEMTEST #define CONFIG_PANIC_HANG /* do not reset board on panic */
@@ -109,6 +100,49 @@ extern unsigned long get_board_sys_clk(unsigned long dummy); /* * DDR Setup */ +#define CONFIG_FSL_DDR2 +#undef CONFIG_FSL_DDR_INTERACTIVE +#define CONFIG_SPD_EEPROM /* Use SPD EEPROM for DDR setup */ +#define CONFIG_DDR_SPD +#undef CONFIG_DDR_DLL + +//#define CONFIG_DDR_2T_TIMING /* Sets the 2T timing bit */ +//#define CONFIG_DDR_ECC /* only for ECC DDR module */ +//#define CONFIG_DDR_ECC_CMD + +//#define CONFIG_ECC_INIT_VIA_DDRCONTROLLER /* DDR controller or DMA? */ +#define CONFIG_MEM_INIT_VALUE 0xDeadBeef + +#define CFG_DDR_SDRAM_BASE 0x00000000 +#define CFG_SDRAM_BASE CFG_DDR_SDRAM_BASE +#define CONFIG_VERY_BIG_RAM + +/* + * Number of memory controllers on device + */ +#define CONFIG_NUM_DDR_CONTROLLERS 1 + +/* + * Number of DIMM slots per memory controller + */ +#define CONFIG_DIMM_SLOTS_PER_CTLR 1 + +/* + * Number of chip selects per memory controller + * + * The MPC8544 (the chip) has 4 chip selects per memory controller. + * However, the MPC8544DS (the board) has only 1 DIMM slot per memory + * controller, so therefore it only has 2 chip selects per memory + * controller that are actually connected. + */ +#define CONFIG_CHIP_SELECTS_PER_CTRL 2 + +/* + * I2C addresses of SPD EEPROMs + */ +#define SPD_EEPROM_ADDRESS1 0x51 /* CTLR 0 DIMM 0 */ + + #define CFG_DDR_SDRAM_BASE 0x00000000 /* DDR is system memory*/ #define CFG_SDRAM_BASE CFG_DDR_SDRAM_BASE
@@ -260,6 +294,9 @@ extern unsigned long get_board_sys_clk(unsigned long dummy); #define CONFIG_OF_BOARD_SETUP 1 #define CONFIG_OF_STDOUT_VIA_ALIAS 1
+#define CFG_64BIT_STRTOUL 1 +#define CFG_64BIT_VSPRINTF 1 + /* I2C */ #define CONFIG_FSL_I2C /* Use FSL common I2C driver */ #define CONFIG_HARD_I2C /* I2C with hardware support */

Kumar Gala wrote:
Also added a few helper functions for DDR1 & DDR2 to print SPD info and verify the checksum.
Signed-off-by: Kumar Gala galak@kernel.crashing.org
common/Makefile | 1 + common/ddr_spd.c | 504 +++++++++++++++++++++++++++++++++++++++++++++++++++++ include/ddr_spd.h | 249 ++++++++++++++++++++++++++ 3 files changed, 754 insertions(+), 0 deletions(-) create mode 100644 common/ddr_spd.c create mode 100644 include/ddr_spd.h
diff --git a/common/Makefile b/common/Makefile index b425795..503c3b5 100644 --- a/common/Makefile +++ b/common/Makefile @@ -145,6 +145,7 @@ COBJS-y += cmd_mac.o COBJS-$(CONFIG_CMD_MFSL) += cmd_mfsl.o COBJS-$(CONFIG_MP) += cmd_mp.o COBJS-$(CONFIG_CMD_SF) += cmd_sf.o +COBJS-$(CONFIG_DDR_SPD) += ddr_spd.o
COBJS := $(COBJS-y) SRCS := $(AOBJS:.o=.S) $(COBJS:.o=.c) diff --git a/common/ddr_spd.c b/common/ddr_spd.c new file mode 100644 index 0000000..bfabb93 --- /dev/null +++ b/common/ddr_spd.c @@ -0,0 +1,504 @@ +/*
- Copyright 2008 Freescale Semiconductor, Inc.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- Version 2 as published by the Free Software Foundation.
- */
+#include <common.h> +#include <ddr_spd.h>
+void +ddr1_spd_dump(const ddr1_spd_eeprom_t *spd)
[major snippage]
Hi Kumar,
There is a "do_sdram" command in common/cmd_i2c.c that I believe is doing the same thing, but probably a lot less (I suspect the command is showing its age).
#if defined(CONFIG_CMD_SDRAM) U_BOOT_CMD( isdram, 2, 1, do_sdram, "isdram - print SDRAM configuration information\n", "chip\n - print SDRAM configuration information\n" " (valid chip values 50..57)\n" ); #endif
Are you aware of that command? Is your SPD dump going to supersede it?
Best regards, gvb

Dear Kumar,
in message 1213041322-5456-1-git-send-email-galak@kernel.crashing.org you wrote:
This is a series of patches that are a work-in-progress towards a new DDR initialization for the Freescale 8{3,5,6}xxx devices that have a common DDR controller.
Just to avoid misunderstandings: I understand these patches as RFC only (as the subject says), i. e. this is not an attempt yet to get this included in the upcoming release. Please confirm.
Best regards,
Wolfgang Denk

On Sun, 2008-07-06 at 00:32 +0200, Wolfgang Denk wrote:
Dear Kumar,
in message 1213041322-5456-1-git-send-email-galak@kernel.crashing.org you wrote:
This is a series of patches that are a work-in-progress towards a new DDR initialization for the Freescale 8{3,5,6}xxx devices that have a common DDR controller.
Just to avoid misunderstandings: I understand these patches as RFC only (as the subject says), i. e. this is not an attempt yet to get this included in the upcoming release. Please confirm.
That is correct. In the meantime, there has been some further development on this code base as well.
jdl

On Jul 7, 2008, at 10:48 AM, Jon Loeliger wrote:
On Sun, 2008-07-06 at 00:32 +0200, Wolfgang Denk wrote:
Dear Kumar,
in message <1213041322-5456-1-git-send-email-galak@kernel.crashing.org
you wrote: This is a series of patches that are a work-in-progress towards a new DDR initialization for the Freescale 8{3,5,6}xxx devices that have a common DDR controller.
Just to avoid misunderstandings: I understand these patches as RFC only (as the subject says), i. e. this is not an attempt yet to get this included in the upcoming release. Please confirm.
That is correct. In the meantime, there has been some further development on this code base as well.
Agreed, the hope is to get something in shape for the 1.3.5 window.
- k
participants (4)
-
Jerry Van Baren
-
Jon Loeliger
-
Kumar Gala
-
Wolfgang Denk