[U-Boot] [PATCH v3 01/16] Add proper SPD definitions for DDR1/2/3

From: James Yang James.Yang@freescale.com
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 | 519 +++++++++++++++++++++++++++++++++++++++++++++++++++++ include/ddr_spd.h | 292 ++++++++++++++++++++++++++++++ 3 files changed, 812 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 dd139d6..8048341 100644 --- a/common/Makefile +++ b/common/Makefile @@ -150,6 +150,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..03cbe1d --- /dev/null +++ b/common/ddr_spd.c @@ -0,0 +1,519 @@ +/* + * 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("%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("%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..6fdcef0 --- /dev/null +++ b/include/ddr_spd.h @@ -0,0 +1,292 @@ +/* + * 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 @ CL=X */ + unsigned char clk_access; /* 10 SDRAM Access from Clk @ 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 @ CL=X-0.5 */ + unsigned char clk_access2; /* 24 SDRAM Access from + Clk @ CL=X-0.5 (tAC) */ + unsigned char clk_cycle3; /* 25 Min SDRAM Cycle time @ CL=X-1 */ + unsigned char clk_access3; /* 26 Max Access from Clk @ 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 Clk */ + unsigned char ca_hold; /* 33 Addr + Cmd Hold Time After Clk */ + 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 @ CL=X */ + unsigned char clk_access; /* 10 SDRAM Access from Clk @ 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 @ CL=X-1 */ + unsigned char clk_access2; /* 24 SDRAM Access from Clk @ CL=X-1 (tAC) */ + unsigned char clk_cycle3; /* 25 Min SDRAM Cycle time @ CL=X-2 */ + unsigned char clk_access3; /* 26 Max Access from Clk @ 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 Clk (tIS) */ + unsigned char ca_hold; /* 33 Addr+Cmd Hold Time After Clk (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 mem device */ + unsigned char mem_type; /* 2 Key Byte / Fundamental mem 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 */ + 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 Min CAS Latency Time */ + unsigned char tWR_min; /* 17 Min Write REcovery Time */ + unsigned char tRCD_min; /* 18 Min RAS# to CAS# Delay Time */ + unsigned char tRRD_min; /* 19 Min Row Active to + Row Active Delay Time */ + unsigned char tRP_min; /* 20 Min Row Precharge Delay Time */ + unsigned char tRAS_tRC_ext; /* 21 Upper Nibbles for tRAS and tRC */ + unsigned char tRAS_min_lsb; /* 22 Min Active to Precharge + Delay Time */ + unsigned char tRC_min_lsb; /* 23 Min Active to Active/Refresh + Delay Time, LSB */ + unsigned char tRFC_min_lsb; /* 24 Min Refresh Recovery Delay Time */ + unsigned char tRFC_min_msb; /* 25 Min Refresh Recovery Delay Time */ + unsigned char tWTR_min; /* 26 Min Internal Write to + Read Command Delay Time */ + unsigned char tRTP_min; /* 27 Min Internal Read to Precharge + Command Delay Time */ + unsigned char tFAW_msb; /* 28 Upper Nibble for tFAW */ + unsigned char tFAW_min; /* 29 Min Four Activate Window + Delay Time*/ + unsigned char opt_features; /* 30 SDRAM Optional Features */ + unsigned char therm_ref_opt; /* 31 SDRAM Thermal and Refresh Opts */ + unsigned char res_32_59[28]; /* 32-59 Reserved, General Section */ + + /* Module-Specific Section: Bytes 60-116 */ + union { + struct { + /* 60 (Unbuffered) Module Nominal Height */ + unsigned char mod_height; + /* 61 (Unbuffered) Module Maximum Thickness */ + unsigned char mod_thickness; + /* 62 (Unbuffered) Reference Raw Card Used */ + unsigned char ref_raw_card; + /* 63 (Unbuffered) Address Mapping from + Edge Connector to DRAM */ + unsigned char addr_mapping; + /* 64-116 (Unbuffered) Reserved */ + unsigned char res_64_116[53]; + } unbuffered; + struct { + /* 60 (Registered) Module Nominal Height */ + unsigned char mod_height; + /* 61 (Registered) Module Maximum Thickness */ + unsigned char mod_thickness; + /* 62 (Registered) Reference Raw Card Used */ + unsigned char ref_raw_card; + } registered; + unsigned char uc[57]; /* 60-116 Module-Specific Section */ + } mod_section; + + /* Unique Module ID: Bytes 117-125 */ + unsigned char mmid_lsb; /* 117 Module MfgID Code LSB - JEP-106 */ + unsigned char mmid_msb; /* 118 Module MfgID Code MSB - JEP-106 */ + unsigned char mloc; /* 119 Mfg Location */ + unsigned char mdate[2]; /* 120-121 Mfg Date */ + unsigned char sernum[4]; /* 122-125 Module Serial Number */ + + /* CRC: Bytes 126-127 */ + unsigned char crc[2]; /* 126-127 SPD CRC */ + + /* Other Manufacturer Fields and User Space: Bytes 128-255 */ + unsigned char mpart[18]; /* 128-145 Mfg's Module Part Number */ + unsigned char mrev[2]; /* 146-147 Module Revision Code */ + + unsigned char dmid_lsb; /* 148 DRAM MfgID Code LSB - JEP-106 */ + unsigned char dmid_msb; /* 149 DRAM MfgID Code MSB - JEP-106 */ + + unsigned char msd[26]; /* 150-175 Mfg'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_ */

Signed-off-by: James Yang James.Yang@freescale.com Signed-off-by: Jon Loeliger jdl@freescale.com Signed-off-by: Becky Bruce becky.bruce@freescale.com Signed-off-by: Ed Swarthout Ed.Swarthout@freescale.com Signed-off-by: Kumar Gala galak@kernel.crashing.org --- cpu/mpc85xx/Makefile | 9 + cpu/mpc86xx/Makefile | 4 + cpu/mpc8xxx/Makefile | 29 + cpu/mpc8xxx/common_timing_params.h | 55 ++ cpu/mpc8xxx/ddr2_dimm_params.h | 86 +++ cpu/mpc8xxx/fsl_ddr_ctrl.c | 1002 +++++++++++++++++++++++++++++++ cpu/mpc8xxx/fsl_ddr_sdram.c | 1134 ++++++++++++++++++++++++++++++++++++ cpu/mpc8xxx/fsl_ddr_sdram.h | 90 +++ cpu/mpc8xxx/fsl_memctrl.h | 44 ++ cpu/mpc8xxx/fsl_util.c | 59 ++ cpu/mpc8xxx/memctl_options.h | 85 +++ 11 files changed, 2597 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_ddr_ctrl.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/fsl_util.c 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..888ebfe --- /dev/null +++ b/cpu/mpc8xxx/Makefile @@ -0,0 +1,29 @@ +# +# 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 fsl_util.o fsl_ddr_ctrl.o +COBJS-$(CONFIG_FSL_DDR1) += fsl_ddr1.o + +COBJS-$(CONFIG_FSL_DDR2) += fsl_ddr_sdram.o fsl_util.o fsl_ddr_ctrl.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..611ffe1 --- /dev/null +++ b/cpu/mpc8xxx/common_timing_params.h @@ -0,0 +1,55 @@ +/* + * 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_ps; + + 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..2ac8183 --- /dev/null +++ b/cpu/mpc8xxx/ddr2_dimm_params.h @@ -0,0 +1,86 @@ +/* + * 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 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_ps; + + 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 ddr_compute_dimm_parameters( + const generic_spd_eeprom_t *spd, + dimm_params_t *pdimm, + unsigned int dimm_number); + +#endif diff --git a/cpu/mpc8xxx/fsl_ddr_ctrl.c b/cpu/mpc8xxx/fsl_ddr_ctrl.c new file mode 100644 index 0000000..4eca701 --- /dev/null +++ b/cpu/mpc8xxx/fsl_ddr_ctrl.c @@ -0,0 +1,1002 @@ +/* + * 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" + +extern unsigned int picos_to_mclk(unsigned int picos); +extern unsigned int fsl_ddr_type_function(void); +/* + * Determine Rtt value. + * + * This should likely be either board or controller specific. + * + * Rtt(nominal): + * 0 = Rtt disabled + * 1 = 75 ohm + * 2 = 150 ohm + * 3 = 50 ohm + * + * FIXME: Apparently 8641 needs a value of 2 + * FIXME: Old code seys if 667 MHz or higher, use 3 on 8572 + * + * FIXME: There was some effort down this line earlier: + * + * 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; + * break; + * } + * } + */ +static inline int fsl_ddr_get_rtt(void) +{ + int rtt; + +#if defined(CONFIG_FSL_DDR1) + rtt = 0; +#elif defined(CONFIG_FSL_DDR2) + rtt = 3; +#else +#error "Need Rtt value for DDR3" +#endif + + return rtt; +} + +/* Chip Select Configuration (CSn_CONFIG) */ +static void set_csn_config(int i, fsl_memctl_config_regs_t *ddr, + const memctl_options_t *popts, + const dimm_params_t *dimm_params) +{ + unsigned int cs_n_en = 0; /* Chip Select enable */ + unsigned int intlv_en = 0; /* Memory controller interleave enable */ + unsigned int intlv_ctl = 0; /* Interleaving control */ + unsigned int ap_n_en = 0; /* Chip select n auto-precharge enable */ + unsigned int odt_rd_cfg = 0; /* ODT for reads configuration */ + unsigned int odt_wr_cfg = 0; /* ODT for writes configuration */ + unsigned int ba_bits_cs_n = 0; /* Num of bank bits for SDRAM on CSn */ + unsigned int row_bits_cs_n = 0; /* Num of row bits for SDRAM on CSn */ + unsigned int col_bits_cs_n = 0; /* Num of ocl bits for SDRAM on CSn */ + + /* Compute CS_CONFIG only for existing ranks of each DIMM. */ + if ((((i&1) == 0) + && (dimm_params[i/2].n_ranks == 1)) + || (dimm_params[i/2].n_ranks == 2)) { + unsigned int n_banks_per_sdram_device; + 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; + n_banks_per_sdram_device + = dimm_params[i/2].n_banks_per_sdram_device; + ba_bits_cs_n = __ilog2(n_banks_per_sdram_device) - 2; + row_bits_cs_n = dimm_params[i/2].n_row_addr - 12; + col_bits_cs_n = dimm_params[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) + + /* XXX: 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 */ +static void set_csn_config_2(int i, fsl_memctl_config_regs_t *ddr) +{ + unsigned int pasr_cfg = 0; /* Partial array self refresh config */ + + 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. + */ +static void set_timing_cfg_0(fsl_memctl_config_regs_t *ddr) +{ + unsigned char trwt_mclk = 0; /* Read-to-write turnaround */ + unsigned char twrt_mclk = 0; /* Write-to-read turnaround */ + /* 7.5 ns on -3E; 0 means WL - CL + BL/2 + 1 */ + unsigned char trrt_mclk = 0; /* Read-to-read turnaround */ + unsigned char twwt_mclk = 0; /* Write-to-write turnaround */ + + /* Active powerdown exit timing (tXARD and tXARDS). */ + unsigned char act_pd_exit_mclk; + /* Precharge powerdown exit timing (tXP). */ + unsigned char pre_pd_exit_mclk; + /* Precharge powerdown exit timing (tAXPD). */ + unsigned char taxpd_mclk; + /* Mode register set cycle time (tMRD). */ + unsigned char tmrd_mclk; + + /* (tXARD and tXARDS). Empirical? */ + act_pd_exit_mclk = 2; + + /* XXX: tXARD = 2, tXARDS = 7 - AL. * Empirical? */ + pre_pd_exit_mclk = 6; + + /* + * FIXME: tXP = 2 on Micron 667 MHz DIMM + * FIXME: configurable? + */ + taxpd_mclk = 8; + + /* 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 */ + ); + debug("FSLDDR: timing_cfg_0 = 0x%08x\n", ddr->timing_cfg_0); +} +#endif /* defined(CONFIG_FSL_DDR2) */ + +/* DDR SDRAM Timing Configuration 3 (TIMING_CFG_3) */ +static void set_timing_cfg_3(fsl_memctl_config_regs_t *ddr, + const common_timing_params_t *common_dimm) +{ + /* Extended Activate to precharge interval (tRAS) */ + unsigned int ext_acttopre = 0; + unsigned int ext_refrec; /* Extended refresh recovery time (tRFC) */ + unsigned int ext_caslat = 0; /* Extended MCAS latency from READ cmd */ + unsigned int cntl_adj = 0; /* Control Adjust */ + + ext_refrec = (picos_to_mclk(common_dimm->tRFC_ps) - 8) >> 4; + ddr->timing_cfg_3 = (0 + | ((ext_acttopre & 0x1) << 24) + | ((ext_refrec & 0x7) << 16) + | ((ext_caslat & 0x1) << 12) + | ((cntl_adj & 0x7) << 0) + ); +} + +/* DDR SDRAM Timing Configuration 1 (TIMING_CFG_1) */ +static void set_timing_cfg_1(fsl_memctl_config_regs_t *ddr, + const common_timing_params_t *common_dimm, + unsigned int cas_latency) +{ + /* Precharge-to-activate interval (tRP) */ + unsigned char pretoact_mclk; + /* Activate to precharge interval (tRAS) */ + unsigned char acttopre_mclk; + /* Activate to read/write interval (tRCD) */ + unsigned char acttorw_mclk; + /* CASLAT */ + unsigned char caslat_ctrl; + /* Refresh recovery time (tRFC) ; trfc_low */ + unsigned char refrec_ctrl; + /* Last data to precharge minimum interval (tWR) */ + unsigned char wrrec_mclk; + /* Activate-to-activate interval (tRRD) */ + unsigned char acttoact_mclk; + /* 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); + + /* + * Translate CAS Latency to a DDR controller field value: + * + * CAS Lat DDR I DDR II Ctrl + * Clocks SPD Bit SPD Bit Value + * ------- ------- ------- ----- + * 1.0 0 0001 + * 1.5 1 0010 + * 2.0 2 2 0011 + * 2.5 3 0100 + * 3.0 4 3 0101 + * 3.5 5 0110 + * 4.0 4 0111 + * 4.5 1000 + * 5.0 5 1001 + */ +#if defined(CONFIG_FSL_DDR1) + caslat_ctrl = (cas_latency + 1) & 0x07; +#elif defined(CONFIG_FSL_DDR2) + caslat_ctrl = 2 * cas_latency - 1; +#else +#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) + | ((acttopre_mclk & 0x0F) << 24) + | ((acttorw_mclk & 0x7) << 20) + | ((caslat_ctrl & 0xF) << 16) + | ((refrec_ctrl & 0xF) << 12) + | ((wrrec_mclk & 0x07) << 8) + | ((acttoact_mclk & 0x07) << 4) + | ((wrtord_mclk & 0x07) << 0) + ); +} + +/* DDR SDRAM Timing Configuration 2 (TIMING_CFG_2) */ +static void set_timing_cfg_2(fsl_memctl_config_regs_t *ddr, + const memctl_options_t *popts, + const common_timing_params_t *common_dimm, + unsigned int cas_latency, + unsigned int additive_latency) +{ + /* Additive latency */ + unsigned char add_lat_mclk; + /* CAS-to-preamble override */ + unsigned short cpo; + /* Write latency */ + unsigned char wr_lat; + /* Read to precharge (tRTP) */ + unsigned char rd_to_pre; + /* Write command to write data strobe timing adjustment */ + unsigned char wr_data_delay; + /* 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 defined(CONFIG_FSL_DDR1) + /* + * This is a lie. It should really be 1, but if it is + * set to 1, bits overlap into the old controller's + * otherwise unused ACSM field. If we leave it 0, then + * the HW will magically treat it as 1 for DDR 1. Oh Yea. + */ + wr_lat = 0; +#elif defined(CONFIG_FSL_DDR2) + wr_lat = cas_latency + additive_latency - 1; +#else +#error "Fix WR_LAT for DDR3" +#endif + + 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) + | ((cpo & 0x1f) << 23) + | ((wr_lat & 0x7) << 19) + | ((rd_to_pre & 0x7) << 13) + | ((wr_data_delay & 0x7) << 10) + | ((cke_pls & 0x7) << 6) + | ((four_act & 0x1f) << 0) + ); +} + +/* DDR SDRAM control configuration (DDR_SDRAM_CFG) */ +static void set_ddr_sdram_cfg(fsl_memctl_config_regs_t *ddr, + const memctl_options_t *popts, + const common_timing_params_t *common_dimm) +{ + unsigned int mem_en; /* DDR SDRAM interface logic enable */ + unsigned int sren; /* Self refresh enable (during sleep) */ + unsigned int ecc_en; /* ECC enable. */ + unsigned int rd_en; /* Registered DIMM enable */ + unsigned int sdram_type; /* Type of SDRAM */ + unsigned int dyn_pwr; /* Dynamic power management mode */ + unsigned int dbw; /* DRAM dta bus width */ + unsigned int eight_be; /* 8-beat burst enable */ + unsigned int ncap = 0; /* Non-concurrent auto-precharge */ + unsigned int threeT_en; /* Enable 3T timing */ + unsigned int twoT_en; /* Enable 2T timing */ + unsigned int ba_intlv_ctl; /* Bank (CS) interleaving control */ + unsigned int x32_en = 0; /* x32 enable */ + unsigned int pchb8 = 0; /* precharge bit 8 enable */ + unsigned int hse; /* Global half strength override */ + unsigned int mem_halt = 0; /* memory controller halt */ + unsigned int bi = 0; /* 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 = (common_dimm->all_DIMMs_registered + && !common_dimm->all_DIMMs_unbuffered); + + sdram_type = fsl_ddr_type_function(); + + dyn_pwr = popts->dynamic_power; + dbw = popts->data_bus_width; + eight_be = 0; /* always 0 for DDR2 */ + threeT_en = 0; /* FIXME: make this configurable */ + twoT_en = popts->twoT_en; + ba_intlv_ctl = popts->ba_intlv_ctl; + hse = popts->half_strength_driver_enable; + + ddr->ddr_sdram_cfg = (0 + | ((mem_en & 0x1) << 31) + | ((sren & 0x1) << 30) + | ((ecc_en & 0x1) << 29) + | ((rd_en & 0x1) << 28) + | ((sdram_type & 0x7) << 24) + | ((dyn_pwr & 0x1) << 21) + | ((dbw & 0x3) << 19) + | ((eight_be & 0x1) << 18) + | ((ncap & 0x1) << 17) + | ((threeT_en & 0x1) << 16) + | ((twoT_en & 0x1) << 15) + | ((ba_intlv_ctl & 0x7F) << 8) + | ((x32_en & 0x1) << 5) + | ((pchb8 & 0x1) << 4) + | ((hse & 0x1) << 3) + | ((mem_halt & 0x1) << 1) + | ((bi & 0x1) << 0) + ); +} + +/* DDR SDRAM control configuration 2 (DDR_SDRAM_CFG_2) */ +static void set_ddr_sdram_cfg_2(fsl_memctl_config_regs_t *ddr, + const memctl_options_t *popts) +{ + unsigned int frc_sr = 0; /* Force self refresh */ + unsigned int sr_ie = 0; /* Self-refresh interrupt enable */ + unsigned int dll_rst_dis; /* DLL reset disable */ + unsigned int dqs_cfg; /* DQS configuration */ + unsigned int odt_cfg; /* ODT configuration */ + unsigned int num_pr; /* Number of posted refreshes */ + unsigned int obc_cfg; /* On-The-Fly Burst Chop Cfg */ + unsigned int ap_en; /* Address Parity Enable */ + unsigned int d_init; /* DRAM data initialization */ + unsigned int rcw_en = 0; /* Register Control Word Enable */ + unsigned int md_en = 0; /* Mirrored DIMM Enable */ + + 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? */ + +#if defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER) + /* Use the DDR controller to auto initialize memory. */ + d_init = 1; + ddr->ddr_data_init = CONFIG_MEM_INIT_VALUE; + debug("DDR: ddr_data_init = 0x%08x\n", ddr->ddr_data_init); +#else + /* Memory will be initialized via DMA, or not at all. */ + d_init = 0; +#endif + + ddr->ddr_sdram_cfg_2 = (0 + | ((frc_sr & 0x1) << 31) + | ((sr_ie & 0x1) << 30) + | ((dll_rst_dis & 0x1) << 29) + | ((dqs_cfg & 0x3) << 26) + | ((odt_cfg & 0x3) << 21) + | ((num_pr & 0xf) << 12) + | ((obc_cfg & 0x1) << 6) + | ((ap_en & 0x1) << 5) + | ((d_init & 0x1) << 4) + | ((rcw_en & 0x1) << 2) + | ((md_en & 0x1) << 0) + ); +} + +/* DDR SDRAM Mode configuration 2 (DDR_SDRAM_MODE_2) */ +static void set_ddr_sdram_mode_2(fsl_memctl_config_regs_t *ddr) +{ + unsigned short esdmode2 = 0; /* Extended SDRAM mode 2 */ + unsigned short esdmode3 = 0; /* Extended SDRAM mode 3 */ + + ddr->ddr_sdram_mode_2 = (0 + | ((esdmode2 & 0xFFFF) << 16) + | ((esdmode3 & 0xFFFF) << 0) + ); +} + +/* DDR SDRAM Interval Configuration (DDR_SDRAM_INTERVAL) */ +static void set_ddr_sdram_interval(fsl_memctl_config_regs_t *ddr, + const memctl_options_t *popts, + const common_timing_params_t *common_dimm) +{ + unsigned int refint; /* Refresh interval */ + unsigned int bstopre; /* Precharge interval */ + + refint = picos_to_mclk(common_dimm->refresh_rate_ps); + + bstopre = popts->bstopre; + + /* FIXME: refint field used 0x3FFF in earlier controllers */ + ddr->ddr_sdram_interval = (0 + | ((refint & 0xFFFF) << 16) + | ((bstopre & 0x3FFF) << 0) + ); +} + +/* DDR SDRAM Mode configuration set (DDR_SDRAM_MODE) */ +static void set_ddr_sdram_mode(fsl_memctl_config_regs_t *ddr, + const memctl_options_t *popts, + const common_timing_params_t *common_dimm, + unsigned int cas_latency, + unsigned int additive_latency) +{ + 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 = 0; /* Mode Register Set */ + unsigned int outputs = 0; /* 0=Enabled, 1=Disabled */ + unsigned int rdqs_en = 0; /* RDQS Enable: 0=no, 1=yes */ + unsigned int dqs_en = 0; /* DQS# Enable: 0=enable, 1=disable */ + unsigned int ocd = 0; /* 0x0=OCD not supported, + 0x7=OCD default state */ + unsigned int rtt; + unsigned int al; /* Posted CAS# additive latency (AL) */ + unsigned int ods = 0; /* Output Drive Strength: + 0 = Full strength (18ohm) + 1 = Reduced strength (4ohm) */ + unsigned int dll_en = 0; /* DLL Enable 0=Enable (Normal), + 1=Disable (Test/Debug) */ + + /* Mode Register (MR) */ + unsigned int mr; /* Mode Register Definition */ + unsigned int pd; /* Power-Down Mode */ + unsigned int wr; /* Write Recovery */ + unsigned int dll_res; /* DLL Reset */ + unsigned int 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 */ + +#if defined(CONFIG_FSL_DDR2) + const unsigned int mclk_ps = get_memory_clk_period_ps(); +#endif + + rtt = fsl_ddr_get_rtt(); + + al = additive_latency; + + 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) + ); + + mr = 0; /* FIXME: CHECKME */ + + /* + * 0 = Fast Exit (Normal) + * 1 = Slow Exit (Low Power) + * FIXME: make this configurable + */ + pd = 0; + +#if defined(CONFIG_FSL_DDR1) + wr = 0; /* Historical */ +#elif defined(CONFIG_FSL_DDR2) + wr = (common_dimm->tWR_ps + mclk_ps - 1) / mclk_ps - 1; +#else +#error "Write tWR_auto for DDR3" +#endif + dll_res = 0; /* FIXME: make this configurable */ + mode = 0; /* FIXME: make this configurable */ + +#if defined(CONFIG_FSL_DDR1) + if (1 <= cas_latency && cas_latency <= 4) { + unsigned char mode_caslat_table[4] = { + 0x5, /* 1.5 clocks */ + 0x2, /* 2.0 clocks */ + 0x6, /* 2.5 clocks */ + 0x3 /* 3.0 clocks */ + }; + caslat = mode_caslat_table[cas_latency - 1]; + } +#elif defined(CONFIG_FSL_DDR2) + caslat = cas_latency; +#else +#error "Fix the mode CAS Latency for DDR3" +#endif + 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 Data Initialization (DDR_DATA_INIT) */ +static void set_ddr_data_init(fsl_memctl_config_regs_t *ddr) +{ + 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) + * The old controller on the 8540/60 doesn't have this register. + * Hope it's OK to set it (to 0) anyway. + */ +static void set_ddr_sdram_clk_cntl(fsl_memctl_config_regs_t *ddr, + const memctl_options_t *popts) +{ + 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) */ +static void set_ddr_init_addr(fsl_memctl_config_regs_t *ddr) +{ + unsigned int init_addr = 0; /* Initialization address */ + + ddr->ddr_init_addr = init_addr; +} + +/* DDR Initialization Address (DDR_INIT_EXT_ADDR) */ +static void set_ddr_init_ext_addr(fsl_memctl_config_regs_t *ddr) +{ + unsigned int uia = 0; /* Use initialization address */ + unsigned int init_ext_addr = 0; /* Initialization address */ + + ddr->ddr_init_ext_addr = (0 + | ((uia & 0x1) << 31) + | (init_ext_addr & 0xF) + ); +} + +/* DDR SDRAM Timing Configuration 4 (TIMING_CFG_4) */ +static void set_timing_cfg_4(fsl_memctl_config_regs_t *ddr) +{ + unsigned int rwt = 0; /* Read-to-write turnaround for same CS */ + unsigned int wrt = 0; /* Write-to-read turnaround for same CS */ + unsigned int rrt = 0; /* Read-to-read turnaround for same CS */ + unsigned int wwt = 0; /* Write-to-write turnaround for same CS */ + unsigned int dll_lock = 0; /* DDR SDRAM DLL Lock Time */ + + 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) */ +static void set_timing_cfg_5(fsl_memctl_config_regs_t *ddr) +{ + unsigned int rodt_on = 0; /* Read to ODT on */ + unsigned int rodt_off = 0; /* Read to ODT off */ + unsigned int wodt_on = 0; /* Write to ODT on */ + unsigned int wodt_off = 0; /* Write to ODT off */ + + 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) */ +static void set_ddr_zq_cntl(fsl_memctl_config_regs_t *ddr) +{ + unsigned int zq_en = 0; /* ZQ Calibration Enable */ + unsigned int zqinit = 0;/* POR ZQ Calibration Time (tZQinit) */ + /* Normal Operation Full Calibration Time (tZQoper) */ + unsigned int zqoper = 0; + /* Normal Operation Short Calibration Time (tZQCS) */ + unsigned int 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) */ +static void set_ddr_wrlvl_cntl(fsl_memctl_config_regs_t *ddr) +{ + unsigned int wrlvl_en = 0; /* Write Leveling Enable */ + /* + * First DQS pulse rising edge after margining mode + * is programmed (tWL_MRD) + */ + unsigned int wrlvl_mrd = 0; + /* ODT delay after margining mode is programmed (tWL_ODTEN) */ + unsigned int wrlvl_odten = 0; + /* DQS/DQS_ delay after margining mode is programmed (tWL_DQSEN) */ + unsigned int wrlvl_dqsen = 0; + /* WRLVL_SMPL: Write leveling sample time */ + unsigned int wrlvl_smpl = 0; + /* WRLVL_WLR: Write leveling repeition time */ + unsigned int wrlvl_wlr = 0; + /* WRLVL_START: Write leveling start time */ + unsigned int 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 Self Refresh Counter (DDR_SR_CNTR) */ +static void set_ddr_sr_cntr(fsl_memctl_config_regs_t *ddr) +{ + unsigned int sr_it = 0; /* Self Refresh Idle Threshold */ + + ddr->ddr_sr_cntr = (sr_it & 0xF) << 16; +} + +/* DDR Pre-Drive Conditioning Control (DDR_PD_CNTL) */ +static void set_ddr_pd_cntl(fsl_memctl_config_regs_t *ddr) +{ + /* Termination value during pre-drive conditioning */ + unsigned int tvpd = 0; + unsigned int pd_en = 0; /* Pre-Drive Conditioning Enable */ + unsigned int pdar = 0; /* Pre-Drive After Read */ + unsigned int pdaw = 0; /* Pre-Drive After Write */ + unsigned int pd_on = 0; /* Pre-Drive Conditioning On */ + unsigned int pd_off = 0; /* Pre-Drive Conditioning Off */ + + 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 SDRAM Register Control Word 1 (DDR_SDRAM_RCW_1) */ +static void set_ddr_sdram_rcw_1(fsl_memctl_config_regs_t *ddr) +{ + unsigned int rcw0 = 0; /* RCW0: Register Control Word 0 */ + unsigned int rcw1 = 0; /* RCW1: Register Control Word 1 */ + unsigned int rcw2 = 0; /* RCW2: Register Control Word 2 */ + unsigned int rcw3 = 0; /* RCW3: Register Control Word 3 */ + unsigned int rcw4 = 0; /* RCW4: Register Control Word 4 */ + unsigned int rcw5 = 0; /* RCW5: Register Control Word 5 */ + unsigned int rcw6 = 0; /* RCW6: Register Control Word 6 */ + unsigned int rcw7 = 0; /* RCW7: Register Control Word 7 */ + + 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) */ +static void set_ddr_sdram_rcw_2(fsl_memctl_config_regs_t *ddr) +{ + unsigned int rcw8 = 0; /* RCW0: Register Control Word 8 */ + unsigned int rcw9 = 0; /* RCW1: Register Control Word 9 */ + unsigned int rcw10 = 0; /* RCW2: Register Control Word 10 */ + unsigned int rcw11 = 0; /* RCW3: Register Control Word 11 */ + unsigned int rcw12 = 0; /* RCW4: Register Control Word 12 */ + unsigned int rcw13 = 0; /* RCW5: Register Control Word 13 */ + unsigned int rcw14 = 0; /* RCW6: Register Control Word 14 */ + unsigned int rcw15 = 0; /* RCW7: Register Control Word 15 */ + + 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) + ); +} + +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; +} + +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_params, + unsigned int dbw_cap_adj) +{ + unsigned int i; + unsigned int cas_latency; + unsigned int additive_latency; + + memset(ddr, 0, sizeof(fsl_memctl_config_regs_t)); + + 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++) { + phys_size_t sa = 0; + phys_size_t ea = 0; + if (popts->ba_intlv_ctl && i > 0) { + /* Don't set up boundaries if bank interleaving */ + break; + } + + if (dimm_params[i/2].n_ranks == 0) { + debug("Skipping setup of CS%u " + "because n_ranks on DIMM %u is 0\n", i, i/2); + continue; + } + 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_cap_adj) - 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_cap_adj) - 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) { + unsigned long long rank_density + = dimm_params[0].rank_density; + ea = (2 * (rank_density >> dbw_cap_adj)) - 1; + } + + } + else if (!popts->memctl_interleaving && !popts->ba_intlv_ctl) { + /* + * No rank interleaving and no memory controller + * interleaving. + */ + unsigned long long rank_density + = dimm_params[i/2].rank_density; + sa = dimm_params[i/2].base_address; + ea = sa + (rank_density >> dbw_cap_adj) - 1; + if (i&1) { + if ((dimm_params[i/2].n_ranks == 1)) { + /* Odd chip select, single-rank dimm */ + sa = 0; + ea = 0; + } else { + /* Odd chip select, dual-rank DIMM */ + sa += rank_density >> dbw_cap_adj; + ea += rank_density >> dbw_cap_adj; + } + } + } + + 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 */ + ); + + set_csn_config(i, ddr, popts, dimm_params); + set_csn_config_2(i, ddr); + } + +#if defined(CONFIG_FSL_DDR2) + set_timing_cfg_0(ddr); +#endif + + set_timing_cfg_3(ddr, common_dimm); + set_timing_cfg_1(ddr, common_dimm, cas_latency); + set_timing_cfg_2(ddr, popts, common_dimm, + cas_latency, additive_latency); + + set_ddr_sdram_cfg(ddr, popts, common_dimm); + + set_ddr_sdram_cfg_2(ddr, popts); + set_ddr_sdram_mode(ddr, popts, common_dimm, + cas_latency, additive_latency); + set_ddr_sdram_mode_2(ddr); + set_ddr_sdram_interval(ddr, popts, common_dimm); + set_ddr_data_init(ddr); + set_ddr_sdram_clk_cntl(ddr, popts); + set_ddr_init_addr(ddr); + set_ddr_init_ext_addr(ddr); + set_timing_cfg_4(ddr); + set_timing_cfg_5(ddr); + + set_ddr_zq_cntl(ddr); + set_ddr_wrlvl_cntl(ddr); + + set_ddr_pd_cntl(ddr); + set_ddr_sr_cntr(ddr); + + set_ddr_sdram_rcw_1(ddr); + set_ddr_sdram_rcw_2(ddr); + + return check_fsl_memctl_config_regs(ddr); +} diff --git a/cpu/mpc8xxx/fsl_ddr_sdram.c b/cpu/mpc8xxx/fsl_ddr_sdram.c new file mode 100644 index 0000000..0663609 --- /dev/null +++ b/cpu/mpc8xxx/fsl_ddr_sdram.c @@ -0,0 +1,1134 @@ +/* + * 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 */ +void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd, + unsigned int ctrl_num); +void fsl_ddr_dump_memctl_regs(unsigned int ctrl_num); +void fsl_ddr_set_memctl_regs(const fsl_memctl_config_regs_t *regs, + unsigned int ctrl_num); +void fsl_ddr_set_lawbar( + const common_timing_params_t *memctl_common_params, + unsigned int memctl_interleaved, + unsigned int ctrl_num); +unsigned int fsl_ddr_type_function(void); +unsigned int fsl_ddr_clk_adjust_function(void); +unsigned int fsl_ddr_cpo_override_function(void); +unsigned int fsl_ddr_write_data_delay_function(void); +unsigned int fsl_ddr_half_strength_driver_enable_function(void); + +extern 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); + +/* + * 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 + */ + +#ifdef DEBUG +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]; +} +#endif + +/* + * compute_lowest_common_dimm_parameters() + * + * Determine the worst-case DIMM timing parameters from the set of DIMMs + * whose parameters have been computed into the array pointed to + * by dimm_params. + */ +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_ps = 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 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); + + /* Either find maximum value to determine slowest + * speed, delay, time, period, etc */ + tCKmin_X_ps = max(tCKmin_X_ps, dimm_params[i].tCKmin_X_ps); + tCKmax_max_ps = max(tCKmax_max_ps, dimm_params[i].tCKmax_ps); + tRCD_ps = max(tRCD_ps, dimm_params[i].tRCD_ps); + tRP_ps = max(tRP_ps, dimm_params[i].tRP_ps); + tRAS_ps = max(tRAS_ps, dimm_params[i].tRAS_ps); + tWR_ps = max(tWR_ps, dimm_params[i].tWR_ps); + tWTR_ps = max(tWTR_ps, dimm_params[i].tWTR_ps); + tRFC_ps = max(tRFC_ps, dimm_params[i].tRFC_ps); + tRRD_ps = max(tRRD_ps, dimm_params[i].tRRD_ps); + tRC_ps = max(tRC_ps, dimm_params[i].tRC_ps); + tIS_ps = max(tIS_ps, dimm_params[i].tIS_ps); + tIH_ps = max(tIH_ps, dimm_params[i].tIH_ps); + tDS_ps = max(tDS_ps, dimm_params[i].tDS_ps); + tDH_ps = max(tDH_ps, dimm_params[i].tDH_ps); + tRTP_ps = max(tRTP_ps, dimm_params[i].tRTP_ps); + tQHS_ps = max(tQHS_ps, dimm_params[i].tQHS_ps); + refresh_rate_ps = max(refresh_rate_ps, + dimm_params[i].refresh_rate_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); + } + + 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_ps = refresh_rate_ps; + 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 returns for an input of 0. + * On 32-bit PowerPC, left shift counts with bit + * 26 set (that the value of 255 or 0xFFFFFFFF + * will have), cause the destination register to + * be 0. That is why this works. + */ + temp1 &= temp2; + } + } + + /* + * Step 2: check each common CAS latency against tCK of each + * DIMM's SPD. + */ + lowest_good_caslat = 0; + temp2 = 0; + while (temp1) { + not_ok = 0; + temp2 = __ilog2(temp1); + debug("checking common caslat = %u\n", temp2); + + /* Check if this CAS latency will work on all DIMMs at tCK. */ + for (i = 0; i < number_of_dimms; i++) { + if (!dimm_params[i].n_ranks) { + continue; + } + if (dimm_params[i].caslat_X == temp2) { + if (mclk_ps >= dimm_params[i].tCKmin_X_ps) { + debug("CL = %u ok on DIMM %u at tCK=%u" + " ps with 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) { + unsigned int tCKmin_X_minus_1_ps + = dimm_params[i].tCKmin_X_minus_1_ps; + if (mclk_ps >= tCKmin_X_minus_1_ps) { + debug("CL = %u ok on DIMM %u at " + "tCK=%u ps with its " + "tCKmin_X_minus_1_ps of %u\n", + temp2, i, mclk_ps, + tCKmin_X_minus_1_ps); + continue; + } else { + not_ok++; + } + } + + if (dimm_params[i].caslat_X_minus_2 == temp2) { + unsigned int tCKmin_X_minus_2_ps + = dimm_params[i].tCKmin_X_minus_2_ps; + if (mclk_ps >= tCKmin_X_minus_2_ps) { + debug("CL = %u ok on DIMM %u at " + "tCK=%u ps with its " + "tCKmin_X_minus_2_ps of %u\n", + temp2, i, mclk_ps, + tCKmin_X_minus_2_ps); + continue; + } else { + not_ok++; + } + } + } + + if (!not_ok) { + lowest_good_caslat = temp2; + } + + temp1 &= ~(1 << temp2); + } + + debug("lowest common SPD-defined CAS latency = %u\n", + lowest_good_caslat); + outpdimm->lowest_common_SPD_caslat = lowest_good_caslat; + + + /* + * Compute a common 'de-rated' CAS latency. + * + * The strategy here is to find the *highest* dereated cas latency + * with the assumption that all of the DIMMs will support a dereated + * CAS latency higher than or equal to their lowest dereated value. + */ + temp1 = 0; + for (i = 0; i < number_of_dimms; i++) { + temp1 = max(temp1, dimm_params[i].caslat_lowest_derated); + } + outpdimm->highest_common_derated_caslat = temp1; + debug("highest common dereated CAS latency = %u\n", temp1); + + /* 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, cant enable ECC\n"); + } + outpdimm->all_DIMMs_ECC_capable = temp1; + + + /* FIXME: move to somewhere else to validate. */ + if (mclk_ps > tCKmax_max_ps) { + printf("Warning: some 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_type_function(); + + /* Pick ECC modes */ +#ifdef CONFIG_DDR_ECC + popts->ECC_mode = 1; /* 0 = disabled, 1 = enabled */ +#else + popts->ECC_mode = 0; /* 0 = disabled, 1 = enabled */ +#endif + popts->ECC_init_using_memctl = 1; /* 0 = use DMA, 1 = use memctl */ + + /* + * Choose DQS config + * 0 for DDR1 + * 1 for DDR2 + */ +#if defined(CONFIG_FSL_DDR1) + popts->DQS_config = 0; +#elif defined(CONFIG_FSL_DDR2) + popts->DQS_config = 1; +#else +#error "Fix DQS for DDR3" +#endif + + /* 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 derated latency + * Should this be board specific? + */ + popts->use_derated_caslat = 0; + + /* 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 + */ + + /* + * 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. + * 0110 3/4 cycle late + * 0111 7/8 cycle late + */ + popts->clk_adjust = fsl_ddr_clk_adjust_function(); + + /* + * Select CPO override + * + * Factors to consider for CPO: + * - frequency + * - ddr1 vs. ddr2 + */ + popts->cpo_override = fsl_ddr_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_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_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 = 1; + popts->threeT_en = 0; + + /* + * 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 = 0x100; + + /* 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 + * x16 wide columns only? Use 50000? + */ + popts->tFAW_window_four_activates_ps = 37500; + +#elif defined(CONFIG_FSL_DDR3) +#error "FIXME determine four activates for DDR3" +#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; +} + +int step_assign_addresses(fsl_ddr_info_t *pinfo, + unsigned int dbw_cap_adj[], + unsigned int *memctl_interleaving, + unsigned int *rank_interleaving) +{ + int i, j; + + /* + * 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_opts[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++) { + unsigned int dw; + dw = pinfo->dimm_params[i][j].data_width; + if (pinfo->dimm_params[i][j].n_ranks + && (dw == 72 || dw == 64)) { + /* + * FIXME: can't really do it + * like this because this just + * further reduces the memory + */ + found = 1; + break; + } + } + if (found) { + dbw_cap_adj[i] = 1; + /* FIXME: 2 for 16-bit bus? */ + } + break; + + case 0: + /* 64-bit */ + break; + + default: + printf("unexpected data bus width " + "specified controller %u\n", i); + return 1; + } + } + + /* + * Check if all controllers are configured for memory + * controller interleaving. + */ + j = 0; + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (pinfo->memctl_opts[i].memctl_interleaving) { + j++; + } + } + if (j == 2) { + *memctl_interleaving = 1; + } + + /* Check that all controllers are rank interleaving. */ + j = 0; + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (pinfo->memctl_opts[i].ba_intlv_ctl) { + j++; + } + } + if (j == 2) { + *rank_interleaving = 1; + } + + if (*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; + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { + unsigned long long cap + = pinfo->dimm_params[i][j].capacity; + + pinfo->dimm_params[i][j].base_address = addr; + addr += (phys_addr_t)(cap >> dbw_cap_adj[i]); + } + } + } else { + /* + * Simple linear assignment if memory + * controllers are not interleaved. + */ + phys_size_t cur_memsize = 0; + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + phys_size_t total_mem_per_ctlr = 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. */ + unsigned long long cap = + pinfo->dimm_params[i][j].capacity; + + pinfo->dimm_params[i][j].base_address = + (phys_addr_t)cur_memsize; + cur_memsize += cap >> dbw_cap_adj[i]; + total_mem_per_ctlr += cap >> dbw_cap_adj[i]; + } + pinfo->common_timing_params[i].total_mem = + total_mem_per_ctlr; + } + } + + return 0; +} + +phys_size_t +fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step) +{ + unsigned int i, j; + unsigned int all_controllers_memctl_interleaving = 0; + unsigned int all_controllers_rank_interleaving = 0; + phys_size_t total_mem = 0; + + fsl_memctl_config_regs_t *ddr_reg = pinfo->fsl_ddr_config_reg; + common_timing_params_t *timing_params = pinfo->common_timing_params; + + /* 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_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; + generic_spd_eeprom_t *spd = + &(pinfo->spd_installed_dimms[i][j]); + dimm_params_t *pdimm = + &(pinfo->dimm_params[i][j]); + + retval = compute_dimm_parameters(spd, pdimm, i); + if (retval == 2) { + printf("Error: compute_dimm_parameters" + " non-zero returned FATAL value " + "for memctl=%u dimm=%u\n", i, j); + return 0; + } + if (retval) { + 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], + &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( + &timing_params[i], &pinfo->memctl_opts[i], i); + } + + case STEP_ASSIGN_ADDRESSES: + /* STEP 5: Assign addresses to chip selects */ + step_assign_addresses(pinfo, + dbw_capacity_adjust, + &all_controllers_memctl_interleaving, + &all_controllers_rank_interleaving); + + case STEP_COMPUTE_REGS: + /* STEP 6: compute controller register values */ + debug("FSL Memory ctrl cg register computation\n"); + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (timing_params[i].ndimms_present == 0) { + memset(&ddr_reg[i], 0, + sizeof(fsl_memctl_config_regs_t)); + continue; + } + + compute_fsl_memctl_config_regs( + &pinfo->memctl_opts[i], + &ddr_reg[i], &timing_params[i], + pinfo->dimm_params[i], + dbw_capacity_adjust[i]); + } + + 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_mem = 0; + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + total_mem += 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++) { + fsl_memctl_config_regs_t *reg = &ddr_reg[i]; + if (reg->cs[j].config & 0x80000000) { + unsigned int end; + end = reg->cs[j].bnds & 0xFFF; + if (end > max_end) { + max_end = end; + } + } + } + } + +#if !defined(CONFIG_PHYS_64BIT) + /* Check for 4G or more with a 32-bit phys_addr_t. Bad. */ + if (max_end >= 0xff) { + printf("This U-Boot only supports < 4G of DDR\n"); + printf("You could rebuild it with CONFIG_PHYS_64BIT\n"); + return 0; /* Ensure DDR setup failure. */ + } +#endif + + total_mem = 1 + (((unsigned long long)max_end << 24ULL) + | 0xFFFFFFULL); + } + + return total_mem; +} + +/* + * 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_info_t info; + + /* Reset info structure. */ + memset(&info, 0, sizeof(fsl_ddr_info_t)); + + /* Compute it once normally. */ + total_memory = fsl_ddr_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_opts[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_set_memctl_regs(&(info.fsl_ddr_config_reg[i]), + i); + +#ifdef DEBUG + fsl_ddr_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_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_set_lawbar(&info.common_timing_params[i], + 0, i); + } + } + + 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..58cac09 --- /dev/null +++ b/cpu/mpc8xxx/fsl_ddr_sdram.h @@ -0,0 +1,90 @@ +/* + * 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); +unsigned int picos_to_mclk(unsigned int picos); + +/* + * Data Structures + * + * All data structures have to be on the stack + */ + +#define CFG_NUM_DDR_CTLRS CONFIG_NUM_DDR_CONTROLLERS +#define CFG_DIMM_SLOTS_PER_CTLR CONFIG_DIMM_SLOTS_PER_CTLR + +typedef struct { + generic_spd_eeprom_t + spd_installed_dimms[CFG_NUM_DDR_CTLRS][CFG_DIMM_SLOTS_PER_CTLR]; + dimm_params_t + dimm_params[CFG_NUM_DDR_CTLRS][CFG_DIMM_SLOTS_PER_CTLR]; + memctl_options_t memctl_opts[CFG_NUM_DDR_CTLRS]; + common_timing_params_t common_timing_params[CFG_NUM_DDR_CTLRS]; + fsl_memctl_config_regs_t fsl_ddr_config_reg[CFG_NUM_DDR_CTLRS]; +} fsl_ddr_info_t; + + +extern phys_size_t +fsl_ddr_compute(fsl_ddr_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) +{ + return ddr_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..b3f45a7 --- /dev/null +++ b/cpu/mpc8xxx/fsl_memctrl.h @@ -0,0 +1,44 @@ +/* + * 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; + +unsigned int check_fsl_memctl_config_regs(const fsl_memctl_config_regs_t *ddr); + +#endif /* FSL_MEMCTRL_H */ diff --git a/cpu/mpc8xxx/fsl_util.c b/cpu/mpc8xxx/fsl_util.c new file mode 100644 index 0000000..aa1562d --- /dev/null +++ b/cpu/mpc8xxx/fsl_util.c @@ -0,0 +1,59 @@ +/* + * 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> + +unsigned int fsl_ddr_get_mem_data_rate(void); + +/* + * 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_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). */ +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_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; +} + + diff --git a/cpu/mpc8xxx/memctl_options.h b/cpu/mpc8xxx/memctl_options.h new file mode 100644 index 0000000..0cdce1d --- /dev/null +++ b/cpu/mpc8xxx/memctl_options.h @@ -0,0 +1,85 @@ +/* + * 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 "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; + + 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

Signed-off-by: James Yang James.Yang@freescale.com Signed-off-by: Jon Loeliger jdl@freescale.com Signed-off-by: Kumar Gala galak@kernel.crashing.org --- cpu/mpc8xxx/fsl_ddr1.c | 342 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 342 insertions(+), 0 deletions(-) create mode 100644 cpu/mpc8xxx/fsl_ddr1.c
diff --git a/cpu/mpc8xxx/fsl_ddr1.c b/cpu/mpc8xxx/fsl_ddr1.c new file mode 100644 index 0000000..48308d0 --- /dev/null +++ b/cpu/mpc8xxx/fsl_ddr1.c @@ -0,0 +1,342 @@ +/* + * 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. + */ + +static phys_size_t +compute_ranksize(unsigned int mem_type, unsigned char row_dens) +{ + phys_size_t bsize; + + /* Bottom 2 bits up to the top. */ + bsize = ((row_dens >> 2) | ((row_dens & 3) << 6)); + bsize <<= 24ULL; + debug("DDR: DDR I rank density = 0x%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; +} + +/* + * tCKmax from DDR I SPD Byte 43 + * + * Bits 7:2 == whole ns + * Bits 1:0 == quarter ns + * 00 == 0.00 ns + * 01 == 0.25 ns + * 10 == 0.50 ns + * 11 == 0.75 ns + * + * Returns picoseconds. + */ +static unsigned int +compute_tckmax_from_spd_ps(unsigned int byte43) +{ + return (byte43 >> 2) * 1000 + (byte43 & 0x3) * 250; +} + +/* + * Determine Refresh Rate. Ignore self refresh bit on DDR I. + * Table from SPD Spec, Byte 12, converted to picoseconds and + * filled in with "default" normal values. + */ +static unsigned int +determine_refresh_rate_ps(const unsigned int spd_refresh) +{ + unsigned int refresh_time_ps[8] = { + 15625000, /* 0 Normal 1.00x */ + 3900000, /* 1 Reduced .25x */ + 7800000, /* 2 Extended .50x */ + 31300000, /* 3 Extended 2.00x */ + 62500000, /* 4 Extended 4.00x */ + 125000000, /* 5 Extended 8.00x */ + 15625000, /* 6 Normal 1.00x filler */ + 15625000, /* 7 Normal 1.00x filler */ + }; + + return refresh_time_ps[spd_refresh & 0x7]; +} + +/* + * The purpose of this function is to compute a suitable + * CAS latency given the DRAM clock period. The SPD only + * defines at most 3 CAS latencies. Typically the slower in + * frequency the DIMM runs at, the shorter its CAS latency can be. + * If the DIMM is operating at a sufficiently low frequency, + * it may be able to run at a CAS latency shorter than the + * shortest SPD-defined CAS latency. + * + * If a CAS latency is not found, 0 is returned. + * + * Do this by finding in the standard speed bin table the longest + * tCKmin that doesn't exceed the value of mclk_ps (tCK). + * + * An assumption made is that the SDRAM device allows the + * CL to be programmed for a value that is lower than those + * advertised by the SPD. This is not always the case, + * as those modes not defined in the SPD are optional. + * + * CAS latency de-rating based upon values JEDEC Standard No. 79-E + * Table 11. + * + * ordinal 2, ddr1_speed_bins[1] contains tCK for CL=2 + */ + /* CL2.0 CL2.5 CL3.0 */ +unsigned short ddr1_speed_bins[] = {0, 7500, 6000, 5000 }; + +unsigned int +compute_derated_DDR1_CAS_latency(unsigned int mclk_ps) +{ + const unsigned int num_speed_bins = ARRAY_SIZE(ddr1_speed_bins); + unsigned int lowest_tCKmin_found = 0; + unsigned int lowest_tCKmin_CL = 0; + unsigned int i; + + debug("mclk_ps = %u\n", mclk_ps); + + for (i = 0; i < num_speed_bins; i++) { + unsigned int x = ddr1_speed_bins[i]; + debug("i=%u, x = %u, lowest_tCKmin_found = %u\n", + i, x, lowest_tCKmin_found); + if (x && lowest_tCKmin_found <= x && x <= mclk_ps) { + lowest_tCKmin_found = x; + lowest_tCKmin_CL = i + 1; + } + } + + debug("lowest_tCKmin_CL = %u\n", lowest_tCKmin_CL); + + return lowest_tCKmin_CL; +} + +/* + * ddr_compute_dimm_parameters for DDR1 SPD + * + * Compute DIMM parameters based upon the SPD information in spd. + * Writes the results to the dimm_params_t structure pointed by pdimm. + * + * FIXME: use #define for the retvals + */ +unsigned int +ddr_compute_dimm_parameters(const ddr1_spd_eeprom_t *spd, + dimm_params_t *pdimm, + unsigned int dimm_number) +{ + unsigned int retval; + + if (spd->mem_type) { + if (spd->mem_type != SPD_MEMTYPE_DDR) { + printf("DIMM %u: is not a DDR1 SPD.\n", dimm_number); + return 1; + } + } else { + memset(pdimm, 0, sizeof(dimm_params_t)); + return 1; + } + + retval = ddr1_spd_check(spd); + if (retval) { + printf("DIMM %u: failed checksum\n", dimm_number); + return 2; + } + + /* + * The part name in ASCII in the SPD EEPROM is not null terminated. + * Guarantee null termination here by presetting all bytes to 0 + * and copying the part name in ASCII from the SPD onto it + */ + memset(pdimm->mpart, 0, sizeof(pdimm->mpart)); + memcpy(pdimm->mpart, spd->mpart, sizeof(pdimm->mpart) - 1); + + /* DIMM organization parameters */ + pdimm->n_ranks = spd->nrows; + pdimm->rank_density = compute_ranksize(spd->mem_type, spd->bank_dens); + pdimm->capacity = pdimm->n_ranks * pdimm->rank_density; + pdimm->data_width = spd->dataw_lsb; + pdimm->primary_sdram_width = spd->primw; + pdimm->ec_sdram_width = spd->ecw; + + /* + * FIXME: Need to determine registered_dimm status. + * 1 == register buffered + * 0 == unbuffered + */ + pdimm->registered_dimm = 0; /* unbuffered */ + + /* SDRAM device parameters */ + pdimm->n_row_addr = spd->nrow_addr; + pdimm->n_col_addr = spd->ncol_addr; + pdimm->n_banks_per_sdram_device = spd->nbanks; + pdimm->edc_config = spd->config; + pdimm->burst_lengths_bitmask = spd->burstl; + pdimm->row_density = spd->bank_dens; + + /* + * Calculate the Maximum Data Rate based on the Minimum Cycle time. + * The SPD clk_cycle field (tCKmin) is measured in tenths of + * nanoseconds and represented as BCD. + */ + pdimm->tCKmin_X_ps + = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle); + pdimm->tCKmin_X_minus_1_ps + = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle2); + pdimm->tCKmin_X_minus_2_ps + = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle3); + + pdimm->tCKmax_ps = compute_tckmax_from_spd_ps(spd->tckmax); + + /* + * Compute CAS latencies defined by SPD + * The SPD caslat_X should have at least 1 and at most 3 bits set. + * + * If cas_lat after masking is 0, the __ilog2 function returns + * 255 into the variable. This behavior is abused once. + */ + pdimm->caslat_X = __ilog2(spd->cas_lat); + pdimm->caslat_X_minus_1 = __ilog2(spd->cas_lat + & ~(1 << pdimm->caslat_X)); + pdimm->caslat_X_minus_2 = __ilog2(spd->cas_lat + & ~(1 << pdimm->caslat_X) + & ~(1 << pdimm->caslat_X_minus_1)); + + /* Compute CAS latencies below that defined by SPD */ + pdimm->caslat_lowest_derated + = compute_derated_DDR1_CAS_latency(get_memory_clk_period_ps()); + + /* 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_ps = determine_refresh_rate_ps(spd->refresh); + + pdimm->tIS_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_setup); + pdimm->tIH_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_hold); + pdimm->tDS_ps + = convert_bcd_hundredths_to_cycle_time_ps(spd->data_setup); + pdimm->tDH_ps + = convert_bcd_hundredths_to_cycle_time_ps(spd->data_hold); + + pdimm->tRTP_ps = mclk_to_picos(2); /* By the book. */ + pdimm->tDQSQ_max_ps = spd->tdqsq * 10; + pdimm->tQHS_ps = spd->tqhs * 10; + + return 0; +}

Signed-off-by: James Yang James.Yang@freescale.com Signed-off-by: Jon Loeliger jdl@freescale.com Signed-off-by: Kumar Gala galak@kernel.crashing.org --- cpu/mpc8xxx/fsl_ddr2.c | 339 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 339 insertions(+), 0 deletions(-) create mode 100644 cpu/mpc8xxx/fsl_ddr2.c
diff --git a/cpu/mpc8xxx/fsl_ddr2.c b/cpu/mpc8xxx/fsl_ddr2.c new file mode 100644 index 0000000..6b516e9 --- /dev/null +++ b/cpu/mpc8xxx/fsl_ddr2.c @@ -0,0 +1,339 @@ +/* + * 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. + * + */ +static phys_size_t +compute_ranksize(unsigned int mem_type, unsigned char row_dens) +{ + phys_size_t bsize; + + /* Bottom 5 bits up to the top. */ + bsize = ((row_dens >> 5) | ((row_dens & 31) << 3)); + bsize <<= 27ULL; + debug("DDR: DDR II rank density = 0x%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_ps(const unsigned int spd_refresh) +{ + unsigned int refresh_time_ps[8] = { + 15625000, /* 0 Normal 1.00x */ + 3900000, /* 1 Reduced .25x */ + 7800000, /* 2 Extended .50x */ + 31300000, /* 3 Extended 2.00x */ + 62500000, /* 4 Extended 4.00x */ + 125000000, /* 5 Extended 8.00x */ + 15625000, /* 6 Normal 1.00x filler */ + 15625000, /* 7 Normal 1.00x filler */ + }; + + return refresh_time_ps[spd_refresh & 0x7]; +} + +/* + * The purpose of this function is to compute a suitable + * CAS latency given the DRAM clock period. The SPD only + * defines at most 3 CAS latencies. Typically the slower in + * frequency the DIMM runs at, the shorter its CAS latency can. + * be. If the DIMM is operating at a sufficiently low frequency, + * it may be able to run at a CAS latency shorter than the + * shortest SPD-defined CAS latency. + * + * If a CAS latency is not found, 0 is returned. + * + * Do this by finding in the standard speed bin table the longest + * tCKmin that doesn't exceed the value of mclk_ps (tCK). + * + * An assumption made is that the SDRAM device allows the + * CL to be programmed for a value that is lower than those + * advertised by the SPD. This is not always the case, + * as those modes not defined in the SPD are optional. + * + * CAS latency de-rating based upon values JEDEC Standard No. 79-2C + * Table 40, "DDR2 SDRAM stanadard speed bins and tCK, tRCD, tRP, tRAS, + * and tRC for corresponding bin" + * + * ordinal 2, ddr2_speed_bins[1] contains tCK for CL=3 + * Not certain if any good value exists for CL=2 + */ + /* CL2 CL3 CL4 CL5 CL6 */ +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; +} + +/* + * ddr_compute_dimm_parameters for DDR2 SPD + * + * Compute DIMM parameters based upon the SPD information in spd. + * Writes the results to the dimm_params_t structure pointed by pdimm. + * + * FIXME: use #define for the retvals + */ +unsigned int +ddr_compute_dimm_parameters(const ddr2_spd_eeprom_t *spd, + dimm_params_t *pdimm, + unsigned int dimm_number) +{ + unsigned int retval; + + if (spd->mem_type) { + if (spd->mem_type != SPD_MEMTYPE_DDR2) { + printf("DIMM %u: is not a DDR2 SPD.\n", dimm_number); + return 1; + } + } else { + memset(pdimm, 0, sizeof(dimm_params_t)); + return 1; + } + + retval = ddr2_spd_check(spd); + if (retval) { + printf("DIMM %u: failed checksum\n", dimm_number); + return 2; + } + + /* + * The part name in ASCII in the SPD EEPROM is not null terminated. + * Guarantee null termination here by presetting all bytes to 0 + * and copying the part name in ASCII from the SPD onto it + */ + memset(pdimm->mpart, 0, sizeof(pdimm->mpart)); + memcpy(pdimm->mpart, spd->mpart, sizeof(pdimm->mpart) - 1); + + /* DIMM organization parameters */ + pdimm->n_ranks = (spd->mod_ranks & 0x7) + 1; + pdimm->rank_density = compute_ranksize(spd->mem_type, spd->rank_dens); + pdimm->capacity = pdimm->n_ranks * pdimm->rank_density; + pdimm->data_width = spd->dataw; + pdimm->primary_sdram_width = spd->primw; + pdimm->ec_sdram_width = spd->ecw; + + /* FIXME: what about registered SO-DIMM? */ + switch (spd->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", spd->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_ps = determine_refresh_rate_ps(spd->refresh); + + pdimm->tIS_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_setup); + pdimm->tIH_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_hold); + pdimm->tDS_ps + = convert_bcd_hundredths_to_cycle_time_ps(spd->data_setup); + pdimm->tDH_ps + = convert_bcd_hundredths_to_cycle_time_ps(spd->data_hold); + + pdimm->tRTP_ps = spd->trtp * 250; + pdimm->tDQSQ_max_ps = spd->tdqsq * 10; + pdimm->tQHS_ps = spd->tqhs * 10; + + return 0; +}

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.
Signed-off-by: James Yang James.Yang@freescale.com Signed-off-by: Jon Loeliger jdl@freescale.com Signed-off-by: Kumar Gala galak@kernel.crashing.org --- cpu/mpc8xxx/Makefile | 2 + cpu/mpc8xxx/fsl_ddr_interactive.c | 1238 +++++++++++++++++++++++++++++++++++++ cpu/mpc8xxx/fsl_ddr_sdram.c | 12 +- cpu/mpc8xxx/fsl_ddr_sdram.h | 3 + 4 files changed, 1254 insertions(+), 1 deletions(-) create mode 100644 cpu/mpc8xxx/fsl_ddr_interactive.c
diff --git a/cpu/mpc8xxx/Makefile b/cpu/mpc8xxx/Makefile index 888ebfe..660ab54 100644 --- a/cpu/mpc8xxx/Makefile +++ b/cpu/mpc8xxx/Makefile @@ -10,6 +10,8 @@ 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 fsl_util.o fsl_ddr_ctrl.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..4e12756 --- /dev/null +++ b/cpu/mpc8xxx/fsl_ddr_interactive.c @@ -0,0 +1,1238 @@ +/* + * 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 <linux/ctype.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[]); + +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_generic_edit(void *pdata, + void *pend, + unsigned int element_size, + unsigned int element_num, + unsigned int value) +{ + char *pcdata = (char *)pdata; /* BIG ENDIAN ONLY */ + + 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_spd_edit(fsl_ddr_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_generic_edit(pspd, pspd + 1, + sizeof(char), element_num, value); +} + +static void +lowest_common_dimm_parameters_edit(fsl_ddr_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_ps", &p->refresh_rate_ps}, + {"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_dimm_parameters_edit(fsl_ddr_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_ps", &p->refresh_rate_ps}, + + {"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}, + {"capacity", &p->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("capacity = %llu bytes (%llu megabytes)\n", + pdimm->capacity, pdimm->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_ps = %u\n", pdimm->refresh_rate_ps); + + 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_ps = %u\n", plcd_dimm_params->refresh_rate_ps); + + /* 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_options_edit(fsl_ddr_info_t *pinfo, + unsigned int ctl_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_opts[ctl_num].memctl_interleaving}, + {"memctl_interleaving_mode", + &pinfo->memctl_opts[ctl_num].memctl_interleaving_mode}, + {"ba_intlv_ctl", + &pinfo->memctl_opts[ctl_num].ba_intlv_ctl}, + {"ecc_mode", &pinfo->memctl_opts[ctl_num].ECC_mode}, + {"ECC_mode", &pinfo->memctl_opts[ctl_num].ECC_mode}, + {"self_refresh_in_sleep", + &pinfo->memctl_opts[ctl_num].self_refresh_in_sleep}, + {"dynamic_power", + &pinfo->memctl_opts[ctl_num].dynamic_power}, + {"data_bus_width", + &pinfo->memctl_opts[ctl_num].data_bus_width}, + {"burst_length", + &pinfo->memctl_opts[ctl_num].burst_length}, + {"cas_latency_override", + &pinfo->memctl_opts[ctl_num].cas_latency_override}, + {"cas_latency_override_value", + &pinfo->memctl_opts[ctl_num].cas_latency_override_value}, + {"use_derated_caslat", + &pinfo->memctl_opts[ctl_num].use_derated_caslat}, + {"additive_latency_override", + &pinfo->memctl_opts[ctl_num].additive_latency_override}, + {"additive_latency_override_value", + &pinfo->memctl_opts[ctl_num].additive_latency_override_value}, + {"clk_adjust", &pinfo->memctl_opts[ctl_num].clk_adjust}, + {"cpo_override", + &pinfo->memctl_opts[ctl_num].cpo_override}, + {"write_data_delay", + &pinfo->memctl_opts[ctl_num].write_data_delay}, + {"half_strength_driver_enable", + &pinfo->memctl_opts[ctl_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_opts[ctl_num].twoT_en}, + {"threeT_en", &pinfo->memctl_opts[ctl_num].threeT_en}, + {"bstopre", &pinfo->memctl_opts[ctl_num].bstopre}, + {"tCKE_clock_pulse_width_ps", + &pinfo->memctl_opts[ctl_num].tCKE_clock_pulse_width_ps}, + {"tFAW_window_four_activates_ps", + &pinfo->memctl_opts[ctl_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_regs_edit(fsl_ddr_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_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_printinfo(const fsl_ddr_info_t *pinfo, + unsigned int ctrl_mask, + unsigned int dimm_mask, + unsigned int do_mask) +{ + unsigned int i, j, retval; + + /* STEP 1: DIMM SPD data */ + if (do_mask & STEP_GET_SPD) { + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (!(ctrl_mask & (1 << i))) + continue; + + /* + * 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))) + continue; + + 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"); + } + + /* STEP 2: DIMM Parameters */ + if (do_mask & STEP_COMPUTE_DIMM_PARMS) { + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (!(ctrl_mask & (1 << i))) + continue; + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { + if (!(dimm_mask & (1 << j))) + continue; + printf("DIMM parameters: Controller=%u " + "DIMM=%u\n", i, j); + print_dimm_parameters( + &(pinfo->dimm_params[i][j])); + printf("\n"); + } + printf("\n"); + } + printf("\n"); + } + + /* STEP 3: Common Parameters */ + if (do_mask & STEP_COMPUTE_COMMON_PARMS) { + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (!(ctrl_mask & (1 << i))) + continue; + 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))) + continue; + printf("User Config Options: Controller=%u\n", i); + print_memctl_options(&pinfo->memctl_opts[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))) + continue; + 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))) + continue; + 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_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 regs\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 (isdigit(c)) { + ctlr_mask |= 1 << (c - '0'); + } + continue; + } + + if (argv[i][0] == 'd') { + char c = argv[i][1]; + if (isdigit(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_spd_edit(pinfo, + ctrl_num, + dimm_num, + element_num, + value); + next_step = STEP_COMPUTE_DIMM_PARMS; + } + break; + + case STEP_COMPUTE_DIMM_PARMS: + fsl_ddr_dimm_parameters_edit( + pinfo, ctrl_num, dimm_num, + p_element, p_value); + next_step = STEP_COMPUTE_COMMON_PARMS; + break; + + case STEP_COMPUTE_COMMON_PARMS: + lowest_common_dimm_parameters_edit(pinfo, + ctrl_num, p_element, p_value); + next_step = STEP_GATHER_OPTS; + break; + + case STEP_GATHER_OPTS: + fsl_ddr_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_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_compute(pinfo, next_step); + /* + * FIXME: There some problems with this. + * For exmaple, what happens if there is + * an error inside fsl_ddr_compute? + */ + continue; + } + + if (strcmp(argv[0], "compute") == 0) { + /* + * Compute rest of steps starting at + * the current next_step/ + */ + ddrsize = fsl_ddr_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 (isdigit(c)) { + ctlr_mask |= 1 << (c - '0'); + } + continue; + } + + if (argv[i][0] == 'd') { + char c = argv[i][1]; + if (isdigit(c)) { + 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 */ + 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_printinfo(pinfo, ctlr_mask, + dimm_mask, step_mask); + continue; + } + + if (strcmp(argv[0], "go") == 0) { + if (next_step) { + ddrsize = fsl_ddr_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 0663609..c0b5dfd 100644 --- a/cpu/mpc8xxx/fsl_ddr_sdram.c +++ b/cpu/mpc8xxx/fsl_ddr_sdram.c @@ -84,7 +84,7 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts, * | interleaving */
-#ifdef DEBUG +#if defined(DEBUG) || defined (CONFIG_FSL_DDR_INTERACTIVE) const char *step_string_tbl[] = { "STEP_GET_SPD", "STEP_COMPUTE_DIMM_PARMS", @@ -1072,6 +1072,16 @@ phys_size_t fsl_ddr_sdram(void) /* Compute it once normally. */ total_memory = fsl_ddr_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. */ memctl_interleaved = 0; for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { diff --git a/cpu/mpc8xxx/fsl_ddr_sdram.h b/cpu/mpc8xxx/fsl_ddr_sdram.h index 58cac09..8823114 100644 --- a/cpu/mpc8xxx/fsl_ddr_sdram.h +++ b/cpu/mpc8xxx/fsl_ddr_sdram.h @@ -61,6 +61,9 @@ typedef struct { extern phys_size_t fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step);
+extern phys_size_t +fsl_ddr_interactive(fsl_ddr_info_t *pinfo); + extern const char * step_to_string(unsigned int step); /* * Compute steps

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 | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 88 insertions(+), 0 deletions(-)
diff --git a/drivers/misc/fsl_law.c b/drivers/misc/fsl_law.c index 48ece4f..24a0340 100644 --- a/drivers/misc/fsl_law.c +++ b/drivers/misc/fsl_law.c @@ -121,6 +121,94 @@ 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> + +/* use up to 2 LAWs for DDR, used the last available LAWs */ +int __set_ddr_laws(u64 start, u64 sz, enum law_trgt_if id) +{ + u64 start_align, law_sz; + int law_sz_enc; + + if (start == 0) + start_align = 1ull << (LAW_SIZE_32G + 1); + else + start_align = 1ull << (ffs64(start) - 1); + law_sz = min(start_align, sz); + law_sz_enc = __ilog2_u64(law_sz) - 1; + + if (set_last_law(start, law_sz_enc, id) < 0) + return -1; + + /* do we still have anything to map */ + sz = sz - law_sz; + if (sz) { + start += law_sz; + + start_align = 1ull << (ffs64(start) - 1); + law_sz = min(start_align, sz); + law_sz_enc = __ilog2_u64(law_sz) - 1; + + if (set_last_law(start, law_sz_enc, id) < 0) + return -1; + } else { + return 0; + } + + /* do we still have anything to map */ + sz = sz - law_sz; + if (sz) + return 1; + + return 0; +} + +void +__fsl_ddr_set_lawbar(const common_timing_params_t *memctl_common_params, + unsigned int memctl_interleaved, + unsigned int ctrl_num) +{ + /* + * If no DIMMs on this controller, do not proceed any further. + */ + if (!memctl_common_params->ndimms_present) { + return; + } + + if (ctrl_num == 0) { + /* + * Set up LAW for DDR controller 1 space. + */ + unsigned int lawbar1_target_id = memctl_interleaved + ? LAW_TRGT_IF_DDR_INTRLV : LAW_TRGT_IF_DDR_1; + + if (__set_ddr_laws(memctl_common_params->base_address, + memctl_common_params->total_mem, + lawbar1_target_id) < 0) { + printf("ERROR\n"); + return ; + } + } else if (ctrl_num == 1) { + if (__set_ddr_laws(memctl_common_params->base_address, + memctl_common_params->total_mem, + LAW_TRGT_IF_DDR_2) < 0) { + printf("ERROR\n"); + return ; + } + } else { + printf("unexpected controller number %u in %s\n", + ctrl_num, __FUNCTION__); + } +} + +__attribute__((weak, alias("__fsl_ddr_set_lawbar"))) void +fsl_ddr_set_lawbar(const common_timing_params_t *memctl_common_params, + unsigned int memctl_interleaved, + unsigned int ctrl_num); +#endif + void 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 | 64 +++++++++++++++++++++++++++++++++++++++++++++++++ include/asm-ppc/mmu.h | 1 + 2 files changed, 65 insertions(+), 0 deletions(-)
diff --git a/cpu/mpc85xx/tlb.c b/cpu/mpc85xx/tlb.c index 3d15d50..7ce7a14 100644 --- a/cpu/mpc85xx/tlb.c +++ b/cpu/mpc85xx/tlb.c @@ -90,3 +90,67 @@ 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 | 234 +++++++++++++++++++++++++++++ board/freescale/mpc8641hpcn/mpc8641hpcn.c | 5 +- cpu/mpc86xx/Makefile | 1 - include/configs/MPC8641HPCN.h | 117 ++++++++------- 6 files changed, 307 insertions(+), 61 deletions(-) create mode 100644 board/freescale/mpc8641hpcn/ddr.c
diff --git a/Makefile b/Makefile index 24700f9..7da88dc 100644 --- a/Makefile +++ b/Makefile @@ -237,6 +237,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 c096e15..27d20a0 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..127c05b --- /dev/null +++ b/board/freescale/mpc8641hpcn/ddr.c @@ -0,0 +1,234 @@ +/* + * 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_get_mem_data_rate(void) +{ + return get_bus_freq(0); +} + +void fsl_ddr_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); + } +} + +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4) +#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL +#endif + +void +fsl_ddr_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 { + bnds = ddr->cs3_bnds; + config = ddr->cs3_config; + } + + 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); +} + +void fsl_ddr_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("%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_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 */ + debug("before go\n"); + + /* + * 200 painful micro-seconds must elapse between + * the DDR clock setup and the DDR config enable. + */ + udelay(200); + asm volatile("sync;isync"); + + 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_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_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_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_write_data_delay_function(void) +{ + return 3; +} + +/* + * factors to consider for half-strength driver enable: + * - number of DIMMs installed + */ +unsigned int fsl_ddr_half_strength_driver_enable_function(void) +{ + return 0; +} diff --git a/board/freescale/mpc8641hpcn/mpc8641hpcn.c b/board/freescale/mpc8641hpcn/mpc8641hpcn.c index db46953..96bb908 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);
@@ -61,7 +60,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 468fd08..e013e70 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 @@ -104,53 +91,75 @@ 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 + +#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 CONFIG_ID_EEPROM #define CFG_I2C_EEPROM_NXID

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 | 223 +++++++++++++++++++++++++++++ board/freescale/mpc8610hpcd/mpc8610hpcd.c | 3 +- include/configs/MPC8610HPCD.h | 50 +++++-- 4 files changed, 264 insertions(+), 22 deletions(-) create mode 100644 board/freescale/mpc8610hpcd/ddr.c
diff --git a/board/freescale/mpc8610hpcd/Makefile b/board/freescale/mpc8610hpcd/Makefile index a457c32..dc97c33 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..fca2918 --- /dev/null +++ b/board/freescale/mpc8610hpcd/ddr.c @@ -0,0 +1,223 @@ +/* + * 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_get_mem_data_rate(void) +{ + return get_bus_freq(0); +} + + +void fsl_ddr_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); + } +} + +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4) +#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL +#endif + +void fsl_ddr_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 { + bnds = ddr->cs3_bnds; + config = ddr->cs3_config; + + } + + 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); +} + +void fsl_ddr_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("%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_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 */ + 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_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_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_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_write_data_delay_function(void) +{ + return 3; +} + +/* + * factors to consider for half-strength driver enable: + * - number of DIMMs installed + */ +unsigned int fsl_ddr_half_strength_driver_enable_function(void) +{ + return 0; +} diff --git a/board/freescale/mpc8610hpcd/mpc8610hpcd.c b/board/freescale/mpc8610hpcd/mpc8610hpcd.c index ff1b892..34f845e 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); @@ -122,7 +123,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 e9371a2..e8d80b1 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 */ @@ -92,22 +83,46 @@ /* * DDR Setup */ +#define CONFIG_FSL_DDR2 +#undef CONFIG_FSL_DDR_INTERACTIVE +#define CONFIG_SPD_EEPROM /* Use SPD for DDR */ +#define CONFIG_DDR_SPD + +#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 + +/* + * Number of DIMM slots per memory controller + */ +#define CONFIG_DIMM_SLOTS_PER_CTLR 1 + /* - * Manually set up DDR1 parameters + * 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 */ @@ -130,7 +145,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 */ @@ -138,7 +156,7 @@ #define CFG_DDR_CS4_BNDS 0x00000FFF /* Not done */ #define CFG_DDR_CS5_BNDS 0x00000FFF /* Not done */ #endif -#endif +
#define CONFIG_ID_EEPROM #define CFG_I2C_EEPROM_NXID

Signed-off-by: Kumar Gala galak@kernel.crashing.org --- Makefile | 1 + board/freescale/mpc8544ds/Makefile | 9 +- board/freescale/mpc8544ds/ddr.c | 242 +++++++++++++++++++++++++++++++++ board/freescale/mpc8544ds/mpc8544ds.c | 11 +- cpu/mpc85xx/Makefile | 2 +- include/configs/MPC8544DS.h | 52 ++++++-- 6 files changed, 298 insertions(+), 19 deletions(-) create mode 100644 board/freescale/mpc8544ds/ddr.c
diff --git a/Makefile b/Makefile index 7da88dc..65ca5e2 100644 --- a/Makefile +++ b/Makefile @@ -236,6 +236,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 3a5ea00..3997994 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..d3e0ca8 --- /dev/null +++ b/board/freescale/mpc8544ds/ddr.c @@ -0,0 +1,242 @@ +/* + * 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_get_mem_data_rate(void) +{ + return get_ddr_freq(0); +} + + +void fsl_ddr_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); + } +} + +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4) +#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL +#endif + +void fsl_ddr_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 { + bnds = ddr->cs3_bnds; + config = ddr->cs3_config; + pbnds = (unsigned int *) &ddr->cs3_bnds; + pconfig = (unsigned int *) &ddr->cs3_config; + } + + 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_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_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_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_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_write_data_delay_function(void) +{ + return 3; +} + +/* + * factors to consider for half-strength driver enable: + * - number of DIMMs installed + */ +unsigned int fsl_ddr_half_strength_driver_enable_function(void) +{ + return 0; +} diff --git a/board/freescale/mpc8544ds/mpc8544ds.c b/board/freescale/mpc8544ds/mpc8544ds.c index c39ce11..213539e 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 checkboard (void) { volatile ccsr_gur_t *gur = (void *)(CFG_MPC85xx_GUTS_ADDR); @@ -69,7 +68,11 @@ initdram(int board_type)
puts("Initializing\n");
- dram_size = spd_sdram(); + dram_size = fsl_ddr_sdram(); + + dram_size = setup_ddr_tlbs(dram_size / 0x100000); + + dram_size *= 0x100000;
#if defined(CONFIG_DDR_ECC) && !defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER) /* 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 9a77b7b..8feda9b 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 */
/* @@ -64,8 +55,6 @@ */ #define CONFIG_ASSUME_AMD_FLASH
-#define MPC85xx_DDR_SDRAM_CLK_CNTL /* 85xx has clock control reg */ - #ifndef __ASSEMBLY__ extern unsigned long get_board_sys_clk(unsigned long dummy); #endif @@ -104,6 +93,44 @@ 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_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
@@ -242,6 +269,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 */

Signed-off-by: Kumar Gala galak@kernel.crashing.org --- board/freescale/mpc8540ads/Makefile | 13 +- board/freescale/mpc8540ads/ddr.c | 282 +++++++++++++++++++++++++++++++ board/freescale/mpc8540ads/mpc8540ads.c | 16 ++- include/configs/MPC8540ADS.h | 70 +++++--- 4 files changed, 346 insertions(+), 35 deletions(-) create mode 100644 board/freescale/mpc8540ads/ddr.c
diff --git a/board/freescale/mpc8540ads/Makefile b/board/freescale/mpc8540ads/Makefile index 2d71cbc..4c6da4d 100644 --- a/board/freescale/mpc8540ads/Makefile +++ b/board/freescale/mpc8540ads/Makefile @@ -25,11 +25,14 @@ include $(TOPDIR)/config.mk
LIB = $(obj)lib$(BOARD).a
-COBJS := $(BOARD).o law.o tlb.o - -SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) -OBJS := $(addprefix $(obj),$(COBJS)) -SOBJS := $(addprefix $(obj),$(SOBJS)) +COBJS-y += $(BOARD).o +COBJS-y += ddr.o +COBJS-y += law.o +COBJS-y += tlb.o + +SRCS := $(SOBJS:.o=.S) $(COBJS-y:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS-y)) +SOBJS := $(addprefix $(obj),$(SOBJS-y))
$(LIB): $(obj).depend $(OBJS) $(SOBJS) $(AR) $(ARFLAGS) $@ $(OBJS) diff --git a/board/freescale/mpc8540ads/ddr.c b/board/freescale/mpc8540ads/ddr.c new file mode 100644 index 0000000..ab59bf6 --- /dev/null +++ b/board/freescale/mpc8540ads/ddr.c @@ -0,0 +1,282 @@ +/* + * 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(ddr1_spd_eeprom_t *spd, unsigned char i2c_address) +{ + i2c_read(i2c_address, 0, 1, (uchar *)spd, sizeof(ddr1_spd_eeprom_t)); +} + + +unsigned int +fsl_ddr_get_mem_data_rate(void) +{ + return get_ddr_freq(0); +} + + +void +fsl_ddr_get_spd(ddr1_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); + } +} + +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4) +#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL +#endif + +void +fsl_ddr_dump_memctl_regs(unsigned int ctrl_num) +{ + unsigned int i; + volatile ccsr_ddr_t *ddr; + + if (ctrl_num == 0) + ddr = (void *)CFG_MPC85xx_DDR_ADDR; + else + ddr = (void *)CFG_MPC85xx_DDR2_ADDR; + + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + unsigned int bnds = 0; + unsigned int config = 0; + unsigned int config_2 = 0; + unsigned int *pbnds = NULL; + unsigned int *pconfig = NULL; + unsigned int *pconfig_2 = NULL; + + if (i == 0) { + bnds = ddr->cs0_bnds; + config = ddr->cs0_config; + config_2 = ddr->cs0_config_2; + pbnds = (unsigned int *)&ddr->cs0_bnds; + pconfig = (unsigned int *)&ddr->cs0_config; + pconfig_2= (unsigned int *)&ddr->cs0_config_2; + + } else if (i == 1) { + bnds = ddr->cs1_bnds; + config = ddr->cs1_config; + config_2 = ddr->cs1_config_2; + pbnds = (unsigned int *)&ddr->cs1_bnds; + pconfig = (unsigned int *)&ddr->cs1_config; + pconfig_2= (unsigned int *)&ddr->cs1_config_2; + + } else if (i == 2) { + bnds = ddr->cs2_bnds; + config = ddr->cs2_config; + config_2 = ddr->cs2_config_2; + pbnds = (unsigned int *)&ddr->cs2_bnds; + pconfig = (unsigned int *)&ddr->cs2_config; + pconfig_2= (unsigned int *)&ddr->cs2_config_2; + + } else { + bnds = ddr->cs3_bnds; + config = ddr->cs3_config; + config_2 = ddr->cs3_config_2; + pbnds = (unsigned int *) &ddr->cs3_bnds; + pconfig = (unsigned int *) &ddr->cs3_config; + pconfig_2= (unsigned int *) &ddr->cs3_config_2; + + } + + printf("cs%u_bnds = %08X\t%p\n", i, bnds, pbnds); + printf("cs%u_config = %08X\t%p\n", i, config, pconfig); + printf("cs%u_config_2 = %08X\t%p\n", + i, config_2, pconfig_2); + } + + /* + * 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_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); + + printf("timing_cfg_4 = %08X\t%p\n", + ddr->timing_cfg_4, &ddr->timing_cfg_4); + printf("timing_cfg_5 = %08X\t%p\n", + ddr->timing_cfg_5, &ddr->timing_cfg_5); + printf("ddr_zq_cntl = %08X\t%p\n", + ddr->ddr_zq_cntl, &ddr->ddr_zq_cntl); + printf("ddr_wrlvl_cntl = %08X\t%p\n", + ddr->ddr_wrlvl_cntl, &ddr->ddr_wrlvl_cntl); + printf("ddr_pd_cntl = %08X\t%p\n", + ddr->ddr_pd_cntl, &ddr->ddr_pd_cntl); + printf("ddr_sr_cntr = %08X\t%p\n", + ddr->ddr_sr_cntr, &ddr->ddr_sr_cntr); + printf("ddr_sdram_rcw_1 = %08X\t%p\n", + ddr->ddr_sdram_rcw_1, &ddr->ddr_sdram_rcw_1); + printf("ddr_sdram_rcw_2 = %08X\t%p\n", + ddr->ddr_sdram_rcw_2, &ddr->ddr_sdram_rcw_2); + + printf("debug_1 = %08X\t%p\n", + ddr->debug_1, &ddr->debug_1); +} + +void +fsl_ddr_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_MPC85xx_DDR_ADDR; + break; + case 1: + ddr = (void *)CFG_MPC85xx_DDR2_ADDR; + break; + default: + printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num); + return; + } + + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + if (i == 0) { + 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_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; + + asm("sync;isync;msync"); + udelay(500); +} + +unsigned int fsl_ddr_type_function(void) +{ + return SDRAM_TYPE_DDR1; +} + +/* + * Technically, the memory controller on this part doesn't even + * have the clk_adjust field for lack of the SDRAM_CLK_CNTL register. + */ + +unsigned int fsl_ddr_clk_adjust_function(void) +{ + return 0; +} + +unsigned int fsl_ddr_cpo_override_function(void) +{ + return 0; /* Should be 0 for DDR1 */ +} + +/* + * 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_write_data_delay_function(void) +{ + return 3; +} + +/* + * factors to consider for half-strength driver enable: + * - number of DIMMs installed + */ +unsigned int fsl_ddr_half_strength_driver_enable_function(void) +{ + return 0; +} diff --git a/board/freescale/mpc8540ads/mpc8540ads.c b/board/freescale/mpc8540ads/mpc8540ads.c index 4f068cc..926d9a6 100644 --- a/board/freescale/mpc8540ads/mpc8540ads.c +++ b/board/freescale/mpc8540ads/mpc8540ads.c @@ -28,11 +28,13 @@ #include <common.h> #include <pci.h> #include <asm/processor.h> +#include <asm/mmu.h> #include <asm/immap_85xx.h> -#include <spd_sdram.h> #include <libfdt.h> #include <fdt_support.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 @@ -82,10 +84,16 @@ initdram(int board_type) } #endif
-#if defined(CONFIG_SPD_EEPROM) - dram_size = spd_sdram (); +#ifdef CONFIG_SPD_EEPROM + 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; #else - dram_size = fixed_sdram (); + dram_size = fixed_sdram(); #endif
#if defined(CONFIG_DDR_ECC) && !defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER) diff --git a/include/configs/MPC8540ADS.h b/include/configs/MPC8540ADS.h index 6351925..4c10171 100644 --- a/include/configs/MPC8540ADS.h +++ b/include/configs/MPC8540ADS.h @@ -48,13 +48,6 @@ #define CONFIG_PCI #define CONFIG_TSEC_ENET /* tsec ethernet support */ #define CONFIG_ENV_OVERWRITE -#define CONFIG_SPD_EEPROM /* Use SPD EEPROM for DDR setup*/ -#define 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_MEM_INIT_VALUE 0xDeadBeef - #define CONFIG_FSL_LAW 1 /* Use common FSL init code */
/* @@ -104,28 +97,53 @@ /* * DDR Setup */ +#define CONFIG_FSL_DDR1 +#define CONFIG_SPD_EEPROM /* Use SPD EEPROM for DDR setup*/ +#define CONFIG_DDR_SPD +#undef CONFIG_FSL_DDR_INTERACTIVE + +#define CONFIG_MEM_INIT_VALUE 0xDeadBeef + #define CFG_DDR_SDRAM_BASE 0x00000000 /* DDR is system memory*/ #define CFG_SDRAM_BASE CFG_DDR_SDRAM_BASE
-#if defined(CONFIG_SPD_EEPROM) - /* - * Determine DDR configuration from I2C interface. - */ - #define SPD_EEPROM_ADDRESS 0x51 /* DDR DIMM */ +/* + * Number of memory controllers on device + */ +#define CONFIG_NUM_DDR_CONTROLLERS 1
-#else - /* - * Manually set up DDR parameters - */ - #define CFG_SDRAM_SIZE 128 /* DDR is 128MB */ - #define CFG_DDR_CS0_BNDS 0x00000007 /* 0-128MB */ - #define CFG_DDR_CS0_CONFIG 0x80000002 - #define CFG_DDR_TIMING_1 0x37344321 - #define CFG_DDR_TIMING_2 0x00000800 /* P9-45,may need tuning */ - #define CFG_DDR_CONTROL 0xc2000000 /* unbuffered,no DYN_PWR */ - #define CFG_DDR_MODE 0x00000062 /* DLL,normal,seq,4/2.5 */ - #define CFG_DDR_INTERVAL 0x05200100 /* autocharge,no open page */ -#endif +/* + * Number of DIMM slots per memory controller + */ +#define CONFIG_DIMM_SLOTS_PER_CTLR 1 + +/* + * Number of chip selects per memory controller + * + * The MPC8540 (the chip) has 4 chip selects per memory controller. + * However, the MPC8540ADS (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 * 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 128 /* DDR is 128MB */ +#define CFG_DDR_CS0_BNDS 0x00000007 /* 0-128MB */ +#define CFG_DDR_CS0_CONFIG 0x80000002 +#define CFG_DDR_TIMING_1 0x37344321 +#define CFG_DDR_TIMING_2 0x00000800 /* P9-45,may need tuning */ +#define CFG_DDR_CONTROL 0xc2000000 /* unbuffered,no DYN_PWR */ +#define CFG_DDR_MODE 0x00000062 /* DLL,normal,seq,4/2.5 */ +#define CFG_DDR_INTERVAL 0x05200100 /* autocharge,no open page */
/*

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/mpc8560ads/Makefile | 13 +- board/freescale/mpc8560ads/ddr.c | 282 +++++++++++++++++++++++++++++++ board/freescale/mpc8560ads/mpc8560ads.c | 15 ++- include/configs/MPC8560ADS.h | 71 +++++--- 4 files changed, 348 insertions(+), 33 deletions(-) create mode 100644 board/freescale/mpc8560ads/ddr.c
diff --git a/board/freescale/mpc8560ads/Makefile b/board/freescale/mpc8560ads/Makefile index 2d71cbc..67dbdeb 100644 --- a/board/freescale/mpc8560ads/Makefile +++ b/board/freescale/mpc8560ads/Makefile @@ -25,11 +25,14 @@ include $(TOPDIR)/config.mk
LIB = $(obj)lib$(BOARD).a
-COBJS := $(BOARD).o law.o tlb.o - -SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) -OBJS := $(addprefix $(obj),$(COBJS)) -SOBJS := $(addprefix $(obj),$(SOBJS)) +COBJS-y += $(BOARD).o +COBJS-y += ddr.o +COBJS-y += law.o +COBJS-y += tlb.o + +SRCS := $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS-y)) +SOBJS := $(addprefix $(obj),$(SOBJS-y))
$(LIB): $(obj).depend $(OBJS) $(SOBJS) $(AR) $(ARFLAGS) $@ $(OBJS) diff --git a/board/freescale/mpc8560ads/ddr.c b/board/freescale/mpc8560ads/ddr.c new file mode 100644 index 0000000..ab59bf6 --- /dev/null +++ b/board/freescale/mpc8560ads/ddr.c @@ -0,0 +1,282 @@ +/* + * 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(ddr1_spd_eeprom_t *spd, unsigned char i2c_address) +{ + i2c_read(i2c_address, 0, 1, (uchar *)spd, sizeof(ddr1_spd_eeprom_t)); +} + + +unsigned int +fsl_ddr_get_mem_data_rate(void) +{ + return get_ddr_freq(0); +} + + +void +fsl_ddr_get_spd(ddr1_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); + } +} + +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4) +#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL +#endif + +void +fsl_ddr_dump_memctl_regs(unsigned int ctrl_num) +{ + unsigned int i; + volatile ccsr_ddr_t *ddr; + + if (ctrl_num == 0) + ddr = (void *)CFG_MPC85xx_DDR_ADDR; + else + ddr = (void *)CFG_MPC85xx_DDR2_ADDR; + + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + unsigned int bnds = 0; + unsigned int config = 0; + unsigned int config_2 = 0; + unsigned int *pbnds = NULL; + unsigned int *pconfig = NULL; + unsigned int *pconfig_2 = NULL; + + if (i == 0) { + bnds = ddr->cs0_bnds; + config = ddr->cs0_config; + config_2 = ddr->cs0_config_2; + pbnds = (unsigned int *)&ddr->cs0_bnds; + pconfig = (unsigned int *)&ddr->cs0_config; + pconfig_2= (unsigned int *)&ddr->cs0_config_2; + + } else if (i == 1) { + bnds = ddr->cs1_bnds; + config = ddr->cs1_config; + config_2 = ddr->cs1_config_2; + pbnds = (unsigned int *)&ddr->cs1_bnds; + pconfig = (unsigned int *)&ddr->cs1_config; + pconfig_2= (unsigned int *)&ddr->cs1_config_2; + + } else if (i == 2) { + bnds = ddr->cs2_bnds; + config = ddr->cs2_config; + config_2 = ddr->cs2_config_2; + pbnds = (unsigned int *)&ddr->cs2_bnds; + pconfig = (unsigned int *)&ddr->cs2_config; + pconfig_2= (unsigned int *)&ddr->cs2_config_2; + + } else { + bnds = ddr->cs3_bnds; + config = ddr->cs3_config; + config_2 = ddr->cs3_config_2; + pbnds = (unsigned int *) &ddr->cs3_bnds; + pconfig = (unsigned int *) &ddr->cs3_config; + pconfig_2= (unsigned int *) &ddr->cs3_config_2; + + } + + printf("cs%u_bnds = %08X\t%p\n", i, bnds, pbnds); + printf("cs%u_config = %08X\t%p\n", i, config, pconfig); + printf("cs%u_config_2 = %08X\t%p\n", + i, config_2, pconfig_2); + } + + /* + * 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_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); + + printf("timing_cfg_4 = %08X\t%p\n", + ddr->timing_cfg_4, &ddr->timing_cfg_4); + printf("timing_cfg_5 = %08X\t%p\n", + ddr->timing_cfg_5, &ddr->timing_cfg_5); + printf("ddr_zq_cntl = %08X\t%p\n", + ddr->ddr_zq_cntl, &ddr->ddr_zq_cntl); + printf("ddr_wrlvl_cntl = %08X\t%p\n", + ddr->ddr_wrlvl_cntl, &ddr->ddr_wrlvl_cntl); + printf("ddr_pd_cntl = %08X\t%p\n", + ddr->ddr_pd_cntl, &ddr->ddr_pd_cntl); + printf("ddr_sr_cntr = %08X\t%p\n", + ddr->ddr_sr_cntr, &ddr->ddr_sr_cntr); + printf("ddr_sdram_rcw_1 = %08X\t%p\n", + ddr->ddr_sdram_rcw_1, &ddr->ddr_sdram_rcw_1); + printf("ddr_sdram_rcw_2 = %08X\t%p\n", + ddr->ddr_sdram_rcw_2, &ddr->ddr_sdram_rcw_2); + + printf("debug_1 = %08X\t%p\n", + ddr->debug_1, &ddr->debug_1); +} + +void +fsl_ddr_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_MPC85xx_DDR_ADDR; + break; + case 1: + ddr = (void *)CFG_MPC85xx_DDR2_ADDR; + break; + default: + printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num); + return; + } + + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + if (i == 0) { + 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_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; + + asm("sync;isync;msync"); + udelay(500); +} + +unsigned int fsl_ddr_type_function(void) +{ + return SDRAM_TYPE_DDR1; +} + +/* + * Technically, the memory controller on this part doesn't even + * have the clk_adjust field for lack of the SDRAM_CLK_CNTL register. + */ + +unsigned int fsl_ddr_clk_adjust_function(void) +{ + return 0; +} + +unsigned int fsl_ddr_cpo_override_function(void) +{ + return 0; /* Should be 0 for DDR1 */ +} + +/* + * 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_write_data_delay_function(void) +{ + return 3; +} + +/* + * factors to consider for half-strength driver enable: + * - number of DIMMs installed + */ +unsigned int fsl_ddr_half_strength_driver_enable_function(void) +{ + return 0; +} diff --git a/board/freescale/mpc8560ads/mpc8560ads.c b/board/freescale/mpc8560ads/mpc8560ads.c index 2c14a88..9b0c854 100644 --- a/board/freescale/mpc8560ads/mpc8560ads.c +++ b/board/freescale/mpc8560ads/mpc8560ads.c @@ -28,6 +28,7 @@ #include <common.h> #include <pci.h> #include <asm/processor.h> +#include <asm/mmu.h> #include <asm/immap_85xx.h> #include <ioports.h> #include <spd_sdram.h> @@ -35,6 +36,8 @@ #include <libfdt.h> #include <fdt_support.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 @@ -285,10 +288,16 @@ initdram(int board_type) } #endif
-#if defined(CONFIG_SPD_EEPROM) - dram_size = spd_sdram (); +#ifdef CONFIG_SPD_EEPROM + 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; #else - dram_size = fixed_sdram (); + dram_size = fixed_sdram(); #endif
#if defined(CONFIG_DDR_ECC) && !defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER) diff --git a/include/configs/MPC8560ADS.h b/include/configs/MPC8560ADS.h index 3567d1c..98d829b 100644 --- a/include/configs/MPC8560ADS.h +++ b/include/configs/MPC8560ADS.h @@ -46,13 +46,6 @@ #define CONFIG_TSEC_ENET /* tsec ethernet support */ #undef CONFIG_ETHER_ON_FCC /* cpm FCC ethernet support */ #define CONFIG_ENV_OVERWRITE -#define CONFIG_SPD_EEPROM /* Use SPD EEPROM for DDR setup*/ -#define 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_MEM_INIT_VALUE 0xDeadBeef - #define CONFIG_FSL_LAW 1 /* Use common FSL init code */
/* @@ -100,28 +93,53 @@ /* * DDR Setup */ +#define CONFIG_FSL_DDR1 +#define CONFIG_SPD_EEPROM /* Use SPD EEPROM for DDR setup*/ +#define CONFIG_DDR_SPD +#undef CONFIG_FSL_DDR_INTERACTIVE + +#define CONFIG_MEM_INIT_VALUE 0xDeadBeef + #define CFG_DDR_SDRAM_BASE 0x00000000 /* DDR is system memory*/ #define CFG_SDRAM_BASE CFG_DDR_SDRAM_BASE
-#if defined(CONFIG_SPD_EEPROM) - /* - * Determine DDR configuration from I2C interface. - */ - #define SPD_EEPROM_ADDRESS 0x51 /* DDR DIMM */ +/* + * Number of memory controllers on device + */ +#define CONFIG_NUM_DDR_CONTROLLERS 1
-#else - /* - * Manually set up DDR parameters - */ - #define CFG_SDRAM_SIZE 128 /* DDR is 128MB */ - #define CFG_DDR_CS0_BNDS 0x00000007 /* 0-128MB */ - #define CFG_DDR_CS0_CONFIG 0x80000002 - #define CFG_DDR_TIMING_1 0x37344321 - #define CFG_DDR_TIMING_2 0x00000800 /* P9-45,may need tuning */ - #define CFG_DDR_CONTROL 0xc2000000 /* unbuffered,no DYN_PWR */ - #define CFG_DDR_MODE 0x00000062 /* DLL,normal,seq,4/2.5 */ - #define CFG_DDR_INTERVAL 0x05200100 /* autocharge,no open page */ -#endif +/* + * Number of DIMM slots per memory controller + */ +#define CONFIG_DIMM_SLOTS_PER_CTLR 1 + +/* + * Number of chip selects per memory controller + * + * The MPC8540 (the chip) has 4 chip selects per memory controller. + * However, the MPC8540ADS (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 * 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 128 /* DDR is 128MB */ +#define CFG_DDR_CS0_BNDS 0x00000007 /* 0-128MB */ +#define CFG_DDR_CS0_CONFIG 0x80000002 +#define CFG_DDR_TIMING_1 0x37344321 +#define CFG_DDR_TIMING_2 0x00000800 /* P9-45,may need tuning */ +#define CFG_DDR_CONTROL 0xc2000000 /* unbuffered,no DYN_PWR */ +#define CFG_DDR_MODE 0x00000062 /* DLL,normal,seq,4/2.5 */ +#define CFG_DDR_INTERVAL 0x05200100 /* autocharge,no open page */
/* @@ -293,6 +311,9 @@ #define CONFIG_OF_BOARD_SETUP 1 #define CONFIG_OF_STDOUT_VIA_ALIAS 1
+#define CFG_64BIT_VSPRINTF 1 +#define CFG_64BIT_STRTOUL 1 + /* * I2C */

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/mpc8555cds/Makefile | 1 + board/freescale/mpc8555cds/ddr.c | 293 +++++++++++++++++++++++++++++++ board/freescale/mpc8555cds/mpc8555cds.c | 12 ++- include/configs/MPC8555CDS.h | 46 ++++- 4 files changed, 341 insertions(+), 11 deletions(-) create mode 100644 board/freescale/mpc8555cds/ddr.c
diff --git a/board/freescale/mpc8555cds/Makefile b/board/freescale/mpc8555cds/Makefile index 98f1530..c19a527 100644 --- a/board/freescale/mpc8555cds/Makefile +++ b/board/freescale/mpc8555cds/Makefile @@ -27,6 +27,7 @@ include $(TOPDIR)/config.mk LIB = $(obj)lib$(BOARD).a
COBJS-y += $(BOARD).o +COBJS-y += ddr.o COBJS-y += law.o COBJS-y += tlb.o
diff --git a/board/freescale/mpc8555cds/ddr.c b/board/freescale/mpc8555cds/ddr.c new file mode 100644 index 0000000..588bf9c --- /dev/null +++ b/board/freescale/mpc8555cds/ddr.c @@ -0,0 +1,293 @@ +/* + * 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(ddr1_spd_eeprom_t *spd, unsigned char i2c_address) +{ + i2c_read(i2c_address, 0, 1, (uchar *)spd, sizeof(ddr1_spd_eeprom_t)); +} + +unsigned int fsl_ddr_get_mem_data_rate(void) +{ + return get_ddr_freq(0); +} + +void fsl_ddr_get_spd(ddr1_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); + } +} + +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4) +#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL +#endif + +void +fsl_ddr_dump_memctl_regs(unsigned int ctrl_num) +{ + unsigned int i; + volatile ccsr_ddr_t *ddr; + + if (ctrl_num == 0) + ddr = (void *)CFG_MPC85xx_DDR_ADDR; + else + ddr = (void *)CFG_MPC85xx_DDR2_ADDR; + + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + unsigned int bnds = 0; + unsigned int config = 0; + unsigned int config_2 = 0; + unsigned int *pbnds = NULL; + unsigned int *pconfig = NULL; + unsigned int *pconfig_2 = NULL; + + if (i == 0) { + bnds = ddr->cs0_bnds; + config = ddr->cs0_config; + config_2 = ddr->cs0_config_2; + pbnds = (unsigned int *)&ddr->cs0_bnds; + pconfig = (unsigned int *)&ddr->cs0_config; + pconfig_2= (unsigned int *)&ddr->cs0_config_2; + + } else if (i == 1) { + bnds = ddr->cs1_bnds; + config = ddr->cs1_config; + config_2 = ddr->cs1_config_2; + pbnds = (unsigned int *)&ddr->cs1_bnds; + pconfig = (unsigned int *)&ddr->cs1_config; + pconfig_2= (unsigned int *)&ddr->cs1_config_2; + + } else if (i == 2) { + bnds = ddr->cs2_bnds; + config = ddr->cs2_config; + config_2 = ddr->cs2_config_2; + pbnds = (unsigned int *)&ddr->cs2_bnds; + pconfig = (unsigned int *)&ddr->cs2_config; + pconfig_2= (unsigned int *)&ddr->cs2_config_2; + + } else { + bnds = ddr->cs3_bnds; + config = ddr->cs3_config; + config_2 = ddr->cs3_config_2; + pbnds = (unsigned int *) &ddr->cs3_bnds; + pconfig = (unsigned int *) &ddr->cs3_config; + pconfig_2= (unsigned int *) &ddr->cs3_config_2; + + } + + printf("cs%u_bnds = %08X\t%p\n", i, bnds, pbnds); + printf("cs%u_config = %08X\t%p\n", i, config, pconfig); + printf("cs%u_config_2 = %08X\t%p\n", + i, config_2, pconfig_2); + } + + /* + * 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_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); + + printf("timing_cfg_4 = %08X\t%p\n", + ddr->timing_cfg_4, &ddr->timing_cfg_4); + printf("timing_cfg_5 = %08X\t%p\n", + ddr->timing_cfg_5, &ddr->timing_cfg_5); + printf("ddr_zq_cntl = %08X\t%p\n", + ddr->ddr_zq_cntl, &ddr->ddr_zq_cntl); + printf("ddr_wrlvl_cntl = %08X\t%p\n", + ddr->ddr_wrlvl_cntl, &ddr->ddr_wrlvl_cntl); + printf("ddr_pd_cntl = %08X\t%p\n", + ddr->ddr_pd_cntl, &ddr->ddr_pd_cntl); + printf("ddr_sr_cntr = %08X\t%p\n", + ddr->ddr_sr_cntr, &ddr->ddr_sr_cntr); + printf("ddr_sdram_rcw_1 = %08X\t%p\n", + ddr->ddr_sdram_rcw_1, &ddr->ddr_sdram_rcw_1); + printf("ddr_sdram_rcw_2 = %08X\t%p\n", + ddr->ddr_sdram_rcw_2, &ddr->ddr_sdram_rcw_2); + + printf("debug_1 = %08X\t%p\n", + ddr->debug_1, &ddr->debug_1); +} + +void fsl_ddr_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_MPC85xx_DDR_ADDR; + break; + case 1: + ddr = (void *)CFG_MPC85xx_DDR2_ADDR; + break; + default: + printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num); + return; + } + + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + if (i == 0) { + 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 = 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 */ + /* 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; + + /* + * 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_type_function(void) +{ + return SDRAM_TYPE_DDR1; +} + +/* + * 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_clk_adjust_function(void) +{ + return 6; +} + +unsigned int fsl_ddr_cpo_override_function(void) +{ + return 0; /* Should be 0 for DDR1 */ +} + +/* + * 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_write_data_delay_function(void) +{ + return 3; +} + +/* + * factors to consider for half-strength driver enable: + * - number of DIMMs installed + */ +unsigned int fsl_ddr_half_strength_driver_enable_function(void) +{ + return 0; +} diff --git a/board/freescale/mpc8555cds/mpc8555cds.c b/board/freescale/mpc8555cds/mpc8555cds.c index 9a65101..25ac0aa 100644 --- a/board/freescale/mpc8555cds/mpc8555cds.c +++ b/board/freescale/mpc8555cds/mpc8555cds.c @@ -23,6 +23,7 @@ #include <common.h> #include <pci.h> #include <asm/processor.h> +#include <asm/mmu.h> #include <asm/immap_85xx.h> #include <ioports.h> #include <spd_sdram.h> @@ -32,6 +33,7 @@ #include "../common/cadmus.h" #include "../common/eeprom.h" #include "../common/via.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); @@ -261,7 +263,14 @@ initdram(int board_type) udelay(200); } #endif - 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) /* @@ -269,6 +278,7 @@ initdram(int board_type) */ ddr_enable_ecc(dram_size); #endif + /* * SDRAM Initialization */ diff --git a/include/configs/MPC8555CDS.h b/include/configs/MPC8555CDS.h index 85c235c..4e393aa 100644 --- a/include/configs/MPC8555CDS.h +++ b/include/configs/MPC8555CDS.h @@ -40,13 +40,6 @@ #define CONFIG_PCI #define CONFIG_TSEC_ENET /* tsec ethernet support */ #define CONFIG_ENV_OVERWRITE -#define CONFIG_SPD_EEPROM /* Use SPD EEPROM for DDR setup*/ -#define CONFIG_DDR_DLL /* possible DLL fix needed */ -#undef CONFIG_DDR_2T_TIMING /* Sets the 2T timing bit */ - -#define CONFIG_DDR_ECC /* only for ECC DDR module */ -#define CONFIG_MEM_INIT_VALUE 0xDeadBeef - #define CONFIG_FSL_LAW 1 /* Use common FSL init code */
#define CONFIG_FSL_VIA @@ -59,8 +52,6 @@ */ #define CONFIG_ASSUME_AMD_FLASH
-#define MPC85xx_DDR_SDRAM_CLK_CNTL /* 85xx has clock control reg */ - #ifndef __ASSEMBLY__ extern unsigned long get_clock_freq(void); #endif @@ -85,13 +76,45 @@ extern unsigned long get_clock_freq(void); #define CFG_CCSRBAR_PHYS CFG_CCSRBAR /* physical addr of CCSRBAR */ #define CFG_IMMR CFG_CCSRBAR /* PQII uses CFG_IMMR */
+ /* * DDR Setup */ +#define CONFIG_FSL_DDR1 +#define CONFIG_SPD_EEPROM /* Use SPD EEPROM for DDR setup*/ +#define CONFIG_DDR_SPD +#undef CONFIG_FSL_DDR_INTERACTIVE + +#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 SPD_EEPROM_ADDRESS 0x51 /* DDR DIMM */ +/* + * 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 MPC8540 (the chip) has 4 chip selects per memory controller. + * However, the MPC8540ADS (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 * CONFIG_DIMM_SLOTS_PER_CTLR) + +/* + * I2C addresses of SPD EEPROMs + */ +#define SPD_EEPROM_ADDRESS1 0x51 /* CTLR 0 DIMM 0 */ +
/* * Make sure required options are set @@ -317,6 +340,9 @@ extern unsigned long get_clock_freq(void); #define CONFIG_OF_BOARD_SETUP 1 #define CONFIG_OF_STDOUT_VIA_ALIAS 1
+#define CFG_64BIT_VSPRINTF 1 +#define CFG_64BIT_STRTOUL 1 + /* * I2C */

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/mpc8541cds/Makefile | 1 + board/freescale/mpc8541cds/ddr.c | 293 +++++++++++++++++++++++++++++++ board/freescale/mpc8541cds/mpc8541cds.c | 10 +- include/configs/MPC8541CDS.h | 44 ++++- 4 files changed, 338 insertions(+), 10 deletions(-) create mode 100644 board/freescale/mpc8541cds/ddr.c
diff --git a/board/freescale/mpc8541cds/Makefile b/board/freescale/mpc8541cds/Makefile index 98f1530..c19a527 100644 --- a/board/freescale/mpc8541cds/Makefile +++ b/board/freescale/mpc8541cds/Makefile @@ -27,6 +27,7 @@ include $(TOPDIR)/config.mk LIB = $(obj)lib$(BOARD).a
COBJS-y += $(BOARD).o +COBJS-y += ddr.o COBJS-y += law.o COBJS-y += tlb.o
diff --git a/board/freescale/mpc8541cds/ddr.c b/board/freescale/mpc8541cds/ddr.c new file mode 100644 index 0000000..588bf9c --- /dev/null +++ b/board/freescale/mpc8541cds/ddr.c @@ -0,0 +1,293 @@ +/* + * 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(ddr1_spd_eeprom_t *spd, unsigned char i2c_address) +{ + i2c_read(i2c_address, 0, 1, (uchar *)spd, sizeof(ddr1_spd_eeprom_t)); +} + +unsigned int fsl_ddr_get_mem_data_rate(void) +{ + return get_ddr_freq(0); +} + +void fsl_ddr_get_spd(ddr1_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); + } +} + +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4) +#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL +#endif + +void +fsl_ddr_dump_memctl_regs(unsigned int ctrl_num) +{ + unsigned int i; + volatile ccsr_ddr_t *ddr; + + if (ctrl_num == 0) + ddr = (void *)CFG_MPC85xx_DDR_ADDR; + else + ddr = (void *)CFG_MPC85xx_DDR2_ADDR; + + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + unsigned int bnds = 0; + unsigned int config = 0; + unsigned int config_2 = 0; + unsigned int *pbnds = NULL; + unsigned int *pconfig = NULL; + unsigned int *pconfig_2 = NULL; + + if (i == 0) { + bnds = ddr->cs0_bnds; + config = ddr->cs0_config; + config_2 = ddr->cs0_config_2; + pbnds = (unsigned int *)&ddr->cs0_bnds; + pconfig = (unsigned int *)&ddr->cs0_config; + pconfig_2= (unsigned int *)&ddr->cs0_config_2; + + } else if (i == 1) { + bnds = ddr->cs1_bnds; + config = ddr->cs1_config; + config_2 = ddr->cs1_config_2; + pbnds = (unsigned int *)&ddr->cs1_bnds; + pconfig = (unsigned int *)&ddr->cs1_config; + pconfig_2= (unsigned int *)&ddr->cs1_config_2; + + } else if (i == 2) { + bnds = ddr->cs2_bnds; + config = ddr->cs2_config; + config_2 = ddr->cs2_config_2; + pbnds = (unsigned int *)&ddr->cs2_bnds; + pconfig = (unsigned int *)&ddr->cs2_config; + pconfig_2= (unsigned int *)&ddr->cs2_config_2; + + } else { + bnds = ddr->cs3_bnds; + config = ddr->cs3_config; + config_2 = ddr->cs3_config_2; + pbnds = (unsigned int *) &ddr->cs3_bnds; + pconfig = (unsigned int *) &ddr->cs3_config; + pconfig_2= (unsigned int *) &ddr->cs3_config_2; + + } + + printf("cs%u_bnds = %08X\t%p\n", i, bnds, pbnds); + printf("cs%u_config = %08X\t%p\n", i, config, pconfig); + printf("cs%u_config_2 = %08X\t%p\n", + i, config_2, pconfig_2); + } + + /* + * 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_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); + + printf("timing_cfg_4 = %08X\t%p\n", + ddr->timing_cfg_4, &ddr->timing_cfg_4); + printf("timing_cfg_5 = %08X\t%p\n", + ddr->timing_cfg_5, &ddr->timing_cfg_5); + printf("ddr_zq_cntl = %08X\t%p\n", + ddr->ddr_zq_cntl, &ddr->ddr_zq_cntl); + printf("ddr_wrlvl_cntl = %08X\t%p\n", + ddr->ddr_wrlvl_cntl, &ddr->ddr_wrlvl_cntl); + printf("ddr_pd_cntl = %08X\t%p\n", + ddr->ddr_pd_cntl, &ddr->ddr_pd_cntl); + printf("ddr_sr_cntr = %08X\t%p\n", + ddr->ddr_sr_cntr, &ddr->ddr_sr_cntr); + printf("ddr_sdram_rcw_1 = %08X\t%p\n", + ddr->ddr_sdram_rcw_1, &ddr->ddr_sdram_rcw_1); + printf("ddr_sdram_rcw_2 = %08X\t%p\n", + ddr->ddr_sdram_rcw_2, &ddr->ddr_sdram_rcw_2); + + printf("debug_1 = %08X\t%p\n", + ddr->debug_1, &ddr->debug_1); +} + +void fsl_ddr_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_MPC85xx_DDR_ADDR; + break; + case 1: + ddr = (void *)CFG_MPC85xx_DDR2_ADDR; + break; + default: + printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num); + return; + } + + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + if (i == 0) { + 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 = 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 */ + /* 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; + + /* + * 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_type_function(void) +{ + return SDRAM_TYPE_DDR1; +} + +/* + * 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_clk_adjust_function(void) +{ + return 6; +} + +unsigned int fsl_ddr_cpo_override_function(void) +{ + return 0; /* Should be 0 for DDR1 */ +} + +/* + * 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_write_data_delay_function(void) +{ + return 3; +} + +/* + * factors to consider for half-strength driver enable: + * - number of DIMMs installed + */ +unsigned int fsl_ddr_half_strength_driver_enable_function(void) +{ + return 0; +} diff --git a/board/freescale/mpc8541cds/mpc8541cds.c b/board/freescale/mpc8541cds/mpc8541cds.c index 3669ba9..313111e 100644 --- a/board/freescale/mpc8541cds/mpc8541cds.c +++ b/board/freescale/mpc8541cds/mpc8541cds.c @@ -25,6 +25,7 @@ #include <common.h> #include <pci.h> #include <asm/processor.h> +#include <asm/mmu.h> #include <asm/immap_85xx.h> #include <ioports.h> #include <spd_sdram.h> @@ -34,6 +35,7 @@ #include "../common/cadmus.h" #include "../common/eeprom.h" #include "../common/via.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); @@ -263,7 +265,13 @@ initdram(int board_type) udelay(200); } #endif - 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) /* diff --git a/include/configs/MPC8541CDS.h b/include/configs/MPC8541CDS.h index d948d76..7a21b78 100644 --- a/include/configs/MPC8541CDS.h +++ b/include/configs/MPC8541CDS.h @@ -40,12 +40,6 @@ #define CONFIG_PCI #define CONFIG_TSEC_ENET /* tsec ethernet support */ #define CONFIG_ENV_OVERWRITE -#define CONFIG_SPD_EEPROM /* Use SPD EEPROM for DDR setup*/ -#define CONFIG_DDR_DLL /* possible DLL fix needed */ -#undef CONFIG_DDR_2T_TIMING /* Sets the 2T timing bit */ - -#define CONFIG_DDR_ECC /* only for ECC DDR module */ -#define CONFIG_MEM_INIT_VALUE 0xDeadBeef
#define CONFIG_FSL_LAW 1 /* Use common FSL init code */
@@ -59,8 +53,6 @@ */ #define CONFIG_ASSUME_AMD_FLASH
-#define MPC85xx_DDR_SDRAM_CLK_CNTL /* 85xx has clock control reg */ - #ifndef __ASSEMBLY__ extern unsigned long get_clock_freq(void); #endif @@ -88,10 +80,41 @@ extern unsigned long get_clock_freq(void); /* * DDR Setup */ +#define CONFIG_FSL_DDR1 +#define CONFIG_SPD_EEPROM /* Use SPD EEPROM for DDR setup*/ +#define CONFIG_DDR_SPD +#undef CONFIG_FSL_DDR_INTERACTIVE + +#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 SPD_EEPROM_ADDRESS 0x51 /* DDR DIMM */ +/* + * 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 MPC8540 (the chip) has 4 chip selects per memory controller. + * However, the MPC8540ADS (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 * CONFIG_DIMM_SLOTS_PER_CTLR) + +/* + * I2C addresses of SPD EEPROMs + */ +#define SPD_EEPROM_ADDRESS1 0x51 /* CTLR 0 DIMM 0 */ +
/* * Make sure required options are set @@ -317,6 +340,9 @@ extern unsigned long get_clock_freq(void); #define CONFIG_OF_BOARD_SETUP 1 #define CONFIG_OF_STDOUT_VIA_ALIAS 1
+#define CFG_64BIT_VSPRINTF 1 +#define CFG_64BIT_STRTOUL 1 + /* * I2C */

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/mpc8568mds/Makefile | 14 +- board/freescale/mpc8568mds/ddr.c | 248 +++++++++++++++++++++++++++++++ board/freescale/mpc8568mds/mpc8568mds.c | 12 ++- include/configs/MPC8568MDS.h | 49 +++++-- 4 files changed, 306 insertions(+), 17 deletions(-) create mode 100644 board/freescale/mpc8568mds/ddr.c
diff --git a/board/freescale/mpc8568mds/Makefile b/board/freescale/mpc8568mds/Makefile index ecdc4d3..d499fb3 100644 --- a/board/freescale/mpc8568mds/Makefile +++ b/board/freescale/mpc8568mds/Makefile @@ -26,11 +26,15 @@ include $(TOPDIR)/config.mk
LIB = $(obj)lib$(BOARD).a
-COBJS := $(BOARD).o bcsr.o law.o tlb.o - -SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) -OBJS := $(addprefix $(obj),$(COBJS)) -SOBJS := $(addprefix $(obj),$(SOBJS)) +COBJS-y += $(BOARD).o +COBJS-y += bcsr.o +COBJS-y += ddr.o +COBJS-y += law.o +COBJS-y += tlb.o + +SRCS := $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS-y)) +SOBJS := $(addprefix $(obj),$(SOBJS-y))
$(LIB): $(obj).depend $(OBJS) $(SOBJS) $(AR) $(ARFLAGS) $@ $(OBJS) diff --git a/board/freescale/mpc8568mds/ddr.c b/board/freescale/mpc8568mds/ddr.c new file mode 100644 index 0000000..cd280be --- /dev/null +++ b/board/freescale/mpc8568mds/ddr.c @@ -0,0 +1,248 @@ +/* + * 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_get_mem_data_rate(void) +{ + return get_ddr_freq(0); +} + +void fsl_ddr_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); + } +} + +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4) +#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL +#endif + +void fsl_ddr_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 { + bnds = ddr->cs3_bnds; + config = ddr->cs3_config; + pbnds = (unsigned int *) &ddr->cs3_bnds; + pconfig = (unsigned int *) &ddr->cs3_config; + + } + + 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_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_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_clk_adjust_function(void) +{ + return 6; +} + +/* + * 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_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_write_data_delay_function(void) +{ + return 3; +} + +/* + * factors to consider for half-strength driver enable: + * - number of DIMMs installed + */ +unsigned int fsl_ddr_half_strength_driver_enable_function(void) +{ + return 0; +} diff --git a/board/freescale/mpc8568mds/mpc8568mds.c b/board/freescale/mpc8568mds/mpc8568mds.c index 2ccff7d..9cc2b2d 100644 --- a/board/freescale/mpc8568mds/mpc8568mds.c +++ b/board/freescale/mpc8568mds/mpc8568mds.c @@ -25,6 +25,7 @@ #include <common.h> #include <pci.h> #include <asm/processor.h> +#include <asm/mmu.h> #include <asm/immap_85xx.h> #include <asm/immap_fsl_pci.h> #include <spd_sdram.h> @@ -34,6 +35,7 @@ #include <fdt_support.h>
#include "bcsr.h" +#include "../cpu/mpc8xxx/fsl_ddr_sdram.h"
const qe_iop_conf_t qe_iop_conf_tab[] = { /* GETH1 */ @@ -163,7 +165,14 @@ initdram(int board_type) udelay(200); } #endif - 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) /* @@ -171,6 +180,7 @@ initdram(int board_type) */ ddr_enable_ecc(dram_size); #endif + /* * SDRAM Initialization */ diff --git a/include/configs/MPC8568MDS.h b/include/configs/MPC8568MDS.h index a82d528..53dfb50 100644 --- a/include/configs/MPC8568MDS.h +++ b/include/configs/MPC8568MDS.h @@ -41,14 +41,6 @@ #define CONFIG_TSEC_ENET /* tsec ethernet support */ #define CONFIG_QE /* Enable QE */ #define CONFIG_ENV_OVERWRITE -#define CONFIG_SPD_EEPROM /* Use SPD EEPROM for DDR setup*/ -#define 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_FSL_LAW 1 /* Use common FSL init code */
/* @@ -58,8 +50,6 @@ */ #define CONFIG_ASSUME_AMD_FLASH
-#define MPC85xx_DDR_SDRAM_CLK_CNTL /* 85xx has clock control reg */ - #ifndef __ASSEMBLY__ extern unsigned long get_clock_freq(void); #endif /*Replace a call to get_clock_freq (after it is implemented)*/ @@ -98,10 +88,44 @@ extern unsigned long get_clock_freq(void); /* * 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 +#define CONFIG_DDR_DLL /* possible DLL fix needed */ +#undef 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 SPD_EEPROM_ADDRESS 0x51 /* DDR DIMM */ + +/* + * 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 MPC8568 (the chip) has 4 chip selects per memory controller. + * However, the MPC8568DS (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 * CONFIG_DIMM_SLOTS_PER_CTLR) + + /* + * I2C addresses of SPD EEPROMs + */ +#define SPD_EEPROM_ADDRESS1 0x51 /* CTLR 0 DIMM 0 */ +
/* * Make sure required options are set @@ -302,6 +326,9 @@ extern unsigned long get_clock_freq(void); #define CONFIG_OF_BOARD_SETUP 1 #define CONFIG_OF_STDOUT_VIA_ALIAS 1
+#define CFG_64BIT_VSPRINTF 1 +#define CFG_64BIT_STRTOUL 1 + /* * I2C */

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/mpc8548cds/Makefile | 1 + board/freescale/mpc8548cds/ddr.c | 239 +++++++++++++++++++++++++++++++ board/freescale/mpc8548cds/mpc8548cds.c | 12 ++- include/configs/MPC8548CDS.h | 49 +++++-- 4 files changed, 289 insertions(+), 12 deletions(-) create mode 100644 board/freescale/mpc8548cds/ddr.c
diff --git a/board/freescale/mpc8548cds/Makefile b/board/freescale/mpc8548cds/Makefile index 98f1530..c19a527 100644 --- a/board/freescale/mpc8548cds/Makefile +++ b/board/freescale/mpc8548cds/Makefile @@ -27,6 +27,7 @@ include $(TOPDIR)/config.mk LIB = $(obj)lib$(BOARD).a
COBJS-y += $(BOARD).o +COBJS-y += ddr.o COBJS-y += law.o COBJS-y += tlb.o
diff --git a/board/freescale/mpc8548cds/ddr.c b/board/freescale/mpc8548cds/ddr.c new file mode 100644 index 0000000..1856ebc --- /dev/null +++ b/board/freescale/mpc8548cds/ddr.c @@ -0,0 +1,239 @@ +/* + * 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_get_mem_data_rate(void) +{ + return get_ddr_freq(0); +} + +void fsl_ddr_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); + } +} + +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4) +#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL +#endif + +void fsl_ddr_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 { + bnds = ddr->cs3_bnds; + config = ddr->cs3_config; + pbnds = (unsigned int *) &ddr->cs3_bnds; + pconfig = (unsigned int *) &ddr->cs3_config; + } + + 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_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_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_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_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_write_data_delay_function(void) +{ + return 3; +} + +/* + * factors to consider for half-strength driver enable: + * - number of DIMMs installed + */ +unsigned int fsl_ddr_half_strength_driver_enable_function(void) +{ + return 0; +} diff --git a/board/freescale/mpc8548cds/mpc8548cds.c b/board/freescale/mpc8548cds/mpc8548cds.c index 0b037cc..98752b8 100644 --- a/board/freescale/mpc8548cds/mpc8548cds.c +++ b/board/freescale/mpc8548cds/mpc8548cds.c @@ -25,6 +25,7 @@ #include <common.h> #include <pci.h> #include <asm/processor.h> +#include <asm/mmu.h> #include <asm/immap_85xx.h> #include <asm/immap_fsl_pci.h> #include <spd_sdram.h> @@ -35,6 +36,7 @@ #include "../common/cadmus.h" #include "../common/eeprom.h" #include "../common/via.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); @@ -111,7 +113,14 @@ initdram(int board_type) udelay(200); } #endif - 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) /* @@ -119,6 +128,7 @@ initdram(int board_type) */ ddr_enable_ecc(dram_size); #endif + /* * SDRAM Initialization */ diff --git a/include/configs/MPC8548CDS.h b/include/configs/MPC8548CDS.h index 33c5c93..ce1b00b 100644 --- a/include/configs/MPC8548CDS.h +++ b/include/configs/MPC8548CDS.h @@ -46,15 +46,7 @@
#define CONFIG_TSEC_ENET /* tsec ethernet support */ #define CONFIG_ENV_OVERWRITE -#define CONFIG_SPD_EEPROM /* Use SPD EEPROM for DDR setup*/ -#define CONFIG_DDR_DLL /* possible DLL fix needed */ -#undef 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_INTERRUPTS /* enable pci, srio, ddr interrupts */ - #define CONFIG_FSL_LAW 1 /* Use common FSL init code */
#define CONFIG_FSL_VIA @@ -67,8 +59,6 @@ */ #define CONFIG_ASSUME_AMD_FLASH
-#define MPC85xx_DDR_SDRAM_CLK_CNTL /* 85xx has clock control reg */ - #ifndef __ASSEMBLY__ extern unsigned long get_clock_freq(void); #endif @@ -106,10 +96,44 @@ extern unsigned long get_clock_freq(void); /* * 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 +#define CONFIG_DDR_DLL /* possible DLL fix needed */ + +#undef 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 SPD_EEPROM_ADDRESS 0x51 /* DDR DIMM */ + +/* + * 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 MPC8568 (the chip) has 4 chip selects per memory controller. + * However, the MPC8568DS (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 * CONFIG_DIMM_SLOTS_PER_CTLR) + + /* + * I2C addresses of SPD EEPROMs + */ +#define SPD_EEPROM_ADDRESS1 0x51 /* CTLR 0 DIMM 0 */ +
/* * Make sure required options are set @@ -342,6 +366,9 @@ extern unsigned long get_clock_freq(void); #define CONFIG_OF_BOARD_SETUP 1 #define CONFIG_OF_STDOUT_VIA_ALIAS 1
+#define CFG_64BIT_VSPRINTF 1 +#define CFG_64BIT_STRTOUL 1 + /* * I2C */

Dear Kumar Gala,
In message 1219274578-30322-16-git-send-email-galak@kernel.crashing.org you wrote:
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/mpc8548cds/Makefile | 1 + board/freescale/mpc8548cds/ddr.c | 239 +++++++++++++++++++++++++++++++ board/freescale/mpc8548cds/mpc8548cds.c | 12 ++- include/configs/MPC8548CDS.h | 49 +++++-- 4 files changed, 289 insertions(+), 12 deletions(-) create mode 100644 board/freescale/mpc8548cds/ddr.c
Applied, thanks.
Best regards,
Wolfgang Denk

Dear Kumar Gala,
In message 1219274578-30322-15-git-send-email-galak@kernel.crashing.org you wrote:
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/mpc8568mds/Makefile | 14 +- board/freescale/mpc8568mds/ddr.c | 248 +++++++++++++++++++++++++++++++ board/freescale/mpc8568mds/mpc8568mds.c | 12 ++- include/configs/MPC8568MDS.h | 49 +++++-- 4 files changed, 306 insertions(+), 17 deletions(-) create mode 100644 board/freescale/mpc8568mds/ddr.c
Applied, thanks.
Best regards,
Wolfgang Denk

Dear Kumar Gala,
In message 1219274578-30322-14-git-send-email-galak@kernel.crashing.org you wrote:
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/mpc8541cds/Makefile | 1 + board/freescale/mpc8541cds/ddr.c | 293 +++++++++++++++++++++++++++++++ board/freescale/mpc8541cds/mpc8541cds.c | 10 +- include/configs/MPC8541CDS.h | 44 ++++- 4 files changed, 338 insertions(+), 10 deletions(-) create mode 100644 board/freescale/mpc8541cds/ddr.c
Applied, thanks.
Best regards,
Wolfgang Denk

Dear Kumar Gala,
In message 1219274578-30322-13-git-send-email-galak@kernel.crashing.org you wrote:
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/mpc8555cds/Makefile | 1 + board/freescale/mpc8555cds/ddr.c | 293 +++++++++++++++++++++++++++++++ board/freescale/mpc8555cds/mpc8555cds.c | 12 ++- include/configs/MPC8555CDS.h | 46 ++++- 4 files changed, 341 insertions(+), 11 deletions(-) create mode 100644 board/freescale/mpc8555cds/ddr.c
Applied, thanks.
Best regards,
Wolfgang Denk

Dear Kumar Gala,
In message 1219274578-30322-12-git-send-email-galak@kernel.crashing.org you wrote:
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/mpc8560ads/Makefile | 13 +- board/freescale/mpc8560ads/ddr.c | 282 +++++++++++++++++++++++++++++++ board/freescale/mpc8560ads/mpc8560ads.c | 15 ++- include/configs/MPC8560ADS.h | 71 +++++--- 4 files changed, 348 insertions(+), 33 deletions(-) create mode 100644 board/freescale/mpc8560ads/ddr.c
Applied, thanks.
Best regards,
Wolfgang Denk

Dear Kumar Gala,
In message 1219274578-30322-11-git-send-email-galak@kernel.crashing.org you wrote:
Signed-off-by: Kumar Gala galak@kernel.crashing.org
board/freescale/mpc8540ads/Makefile | 13 +- board/freescale/mpc8540ads/ddr.c | 282 +++++++++++++++++++++++++++++++ board/freescale/mpc8540ads/mpc8540ads.c | 16 ++- include/configs/MPC8540ADS.h | 70 +++++--- 4 files changed, 346 insertions(+), 35 deletions(-) create mode 100644 board/freescale/mpc8540ads/ddr.c
Applied, thanks.
Best regards,
Wolfgang Denk

Dear Kumar Gala,
In message 1219274578-30322-10-git-send-email-galak@kernel.crashing.org you wrote:
Signed-off-by: Kumar Gala galak@kernel.crashing.org
Makefile | 1 + board/freescale/mpc8544ds/Makefile | 9 +- board/freescale/mpc8544ds/ddr.c | 242 +++++++++++++++++++++++++++++++++ board/freescale/mpc8544ds/mpc8544ds.c | 11 +- cpu/mpc85xx/Makefile | 2 +- include/configs/MPC8544DS.h | 52 ++++++-- 6 files changed, 298 insertions(+), 19 deletions(-) create mode 100644 board/freescale/mpc8544ds/ddr.c
Applied, thanks.
Best regards,
Wolfgang Denk

Dear Kumar Gala,
In message 1219274578-30322-9-git-send-email-galak@kernel.crashing.org you wrote:
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 | 223 +++++++++++++++++++++++++++++ board/freescale/mpc8610hpcd/mpc8610hpcd.c | 3 +- include/configs/MPC8610HPCD.h | 50 +++++-- 4 files changed, 264 insertions(+), 22 deletions(-) create mode 100644 board/freescale/mpc8610hpcd/ddr.c
Applied, thanks.
Best regards,
Wolfgang Denk

Dear Kumar Gala,
In message 1219274578-30322-8-git-send-email-galak@kernel.crashing.org you wrote:
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 | 234 +++++++++++++++++++++++++++++ board/freescale/mpc8641hpcn/mpc8641hpcn.c | 5 +- cpu/mpc86xx/Makefile | 1 - include/configs/MPC8641HPCN.h | 117 ++++++++------- 6 files changed, 307 insertions(+), 61 deletions(-) create mode 100644 board/freescale/mpc8641hpcn/ddr.c
Applied, thanks.
Best regards,
Wolfgang Denk

Dear Kumar Gala,
In message 1219274578-30322-7-git-send-email-galak@kernel.crashing.org you wrote:
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 | 64 +++++++++++++++++++++++++++++++++++++++++++++++++ include/asm-ppc/mmu.h | 1 + 2 files changed, 65 insertions(+), 0 deletions(-)
Applied, thanks.
Best regards,
Wolfgang Denk

Dear Kumar Gala,
In message 1219274578-30322-6-git-send-email-galak@kernel.crashing.org you wrote:
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 | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 88 insertions(+), 0 deletions(-)
Applied, thanks.
Best regards,
Wolfgang Denk

Dear Kumar Gala,
In message 1219274578-30322-5-git-send-email-galak@kernel.crashing.org you wrote:
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.
Signed-off-by: James Yang James.Yang@freescale.com Signed-off-by: Jon Loeliger jdl@freescale.com Signed-off-by: Kumar Gala galak@kernel.crashing.org
cpu/mpc8xxx/Makefile | 2 + cpu/mpc8xxx/fsl_ddr_interactive.c | 1238 +++++++++++++++++++++++++++++++++++++ cpu/mpc8xxx/fsl_ddr_sdram.c | 12 +- cpu/mpc8xxx/fsl_ddr_sdram.h | 3 + 4 files changed, 1254 insertions(+), 1 deletions(-) create mode 100644 cpu/mpc8xxx/fsl_ddr_interactive.c
Applied, thanks.
Best regards,
Wolfgang Denk

Dear Kumar Gala,
In message 1219274578-30322-4-git-send-email-galak@kernel.crashing.org you wrote:
Signed-off-by: James Yang James.Yang@freescale.com Signed-off-by: Jon Loeliger jdl@freescale.com Signed-off-by: Kumar Gala galak@kernel.crashing.org
cpu/mpc8xxx/fsl_ddr2.c | 339 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 339 insertions(+), 0 deletions(-) create mode 100644 cpu/mpc8xxx/fsl_ddr2.c
Applied, thanks.
Best regards,
Wolfgang Denk

Dear Kumar Gala,
In message 1219274578-30322-3-git-send-email-galak@kernel.crashing.org you wrote:
Signed-off-by: James Yang James.Yang@freescale.com Signed-off-by: Jon Loeliger jdl@freescale.com Signed-off-by: Kumar Gala galak@kernel.crashing.org
cpu/mpc8xxx/fsl_ddr1.c | 342 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 342 insertions(+), 0 deletions(-) create mode 100644 cpu/mpc8xxx/fsl_ddr1.c
Applied, thanks.
Best regards,
Wolfgang Denk

Dear Kumar Gala,
In message 1219274578-30322-2-git-send-email-galak@kernel.crashing.org you wrote:
Signed-off-by: James Yang James.Yang@freescale.com Signed-off-by: Jon Loeliger jdl@freescale.com Signed-off-by: Becky Bruce becky.bruce@freescale.com Signed-off-by: Ed Swarthout Ed.Swarthout@freescale.com Signed-off-by: Kumar Gala galak@kernel.crashing.org
cpu/mpc85xx/Makefile | 9 + cpu/mpc86xx/Makefile | 4 + cpu/mpc8xxx/Makefile | 29 + cpu/mpc8xxx/common_timing_params.h | 55 ++ cpu/mpc8xxx/ddr2_dimm_params.h | 86 +++ cpu/mpc8xxx/fsl_ddr_ctrl.c | 1002 +++++++++++++++++++++++++++++++ cpu/mpc8xxx/fsl_ddr_sdram.c | 1134 ++++++++++++++++++++++++++++++++++++ cpu/mpc8xxx/fsl_ddr_sdram.h | 90 +++ cpu/mpc8xxx/fsl_memctrl.h | 44 ++ cpu/mpc8xxx/fsl_util.c | 59 ++ cpu/mpc8xxx/memctl_options.h | 85 +++ 11 files changed, 2597 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_ddr_ctrl.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/fsl_util.c create mode 100644 cpu/mpc8xxx/memctl_options.h
Applied, thanks.
Best regards,
Wolfgang Denk

Hello,
[snip]
+/* DDR SDRAM control configuration 2 (DDR_SDRAM_CFG_2) */ +static void set_ddr_sdram_cfg_2(fsl_memctl_config_regs_t *ddr,
const memctl_options_t *popts)
+{
- unsigned int frc_sr = 0; /* Force self refresh */
- unsigned int sr_ie = 0; /* Self-refresh interrupt enable */
- unsigned int dll_rst_dis; /* DLL reset disable */
- unsigned int dqs_cfg; /* DQS configuration */
- unsigned int odt_cfg; /* ODT configuration */
- unsigned int num_pr; /* Number of posted refreshes */
- unsigned int obc_cfg; /* On-The-Fly Burst Chop Cfg */
- unsigned int ap_en; /* Address Parity Enable */
- unsigned int d_init; /* DRAM data initialization */
- unsigned int rcw_en = 0; /* Register Control Word Enable */
- unsigned int md_en = 0; /* Mirrored DIMM Enable */
- 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? */
+#if defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER)
- /* Use the DDR controller to auto initialize memory. */
- d_init = 1;
- ddr->ddr_data_init = CONFIG_MEM_INIT_VALUE;
- debug("DDR: ddr_data_init = 0x%08x\n", ddr->ddr_data_init);
+#else
- /* Memory will be initialized via DMA, or not at all. */
- d_init = 0;
+#endif
I'm using the current head (33aa4eac66b71c797bbc13b3afe432a2132947d4) on a mpc8572-based board. It uses DDR2 and has support for ECC. While enabling ECC support, I noticed that the "old" CONFIG_ECC_INIT_VIA_DDRCONTROLLER define is still being used to enable memory initialization on bootup while a new ECC_init_using_memctl field in the memctl_options_s structure is also present.
Currently it looks like ECC_init_using_memctl doesn't do anything and is only referenced in one location below:
- /* Pick ECC modes */
+#ifdef CONFIG_DDR_ECC
- popts->ECC_mode = 1; /* 0 = disabled, 1 = enabled */
+#else
- popts->ECC_mode = 0; /* 0 = disabled, 1 = enabled */
+#endif
- popts->ECC_init_using_memctl = 1; /* 0 = use DMA, 1 = use memctl */
The intended functionality of CONFIG_ECC_INIT_VIA_DDRCONTROLLER and ECC_init_using_memctl seem to be the same, but only one of them is being used, and they currently are unrelated which is a bit confusing.
Should the ECC_init_using_memctl field be removed, or is the intention to replace CONFIG_ECC_INIT_VIA_DDRCONTROLLER functionality with ECC_init_using_memctl as some point?
Thanks for any insight, Peter

On Aug 29, 2008, at 5:16 PM, Peter Tyser wrote:
Hello,
[snip]
+/* DDR SDRAM control configuration 2 (DDR_SDRAM_CFG_2) */ +static void set_ddr_sdram_cfg_2(fsl_memctl_config_regs_t *ddr,
const memctl_options_t *popts)
+{
- unsigned int frc_sr = 0; /* Force self refresh */
- unsigned int sr_ie = 0; /* Self-refresh interrupt enable */
- unsigned int dll_rst_dis; /* DLL reset disable */
- unsigned int dqs_cfg; /* DQS configuration */
- unsigned int odt_cfg; /* ODT configuration */
- unsigned int num_pr; /* Number of posted refreshes */
- unsigned int obc_cfg; /* On-The-Fly Burst Chop Cfg */
- unsigned int ap_en; /* Address Parity Enable */
- unsigned int d_init; /* DRAM data initialization */
- unsigned int rcw_en = 0; /* Register Control Word Enable */
- unsigned int md_en = 0; /* Mirrored DIMM Enable */
- 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? */
+#if defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER)
- /* Use the DDR controller to auto initialize memory. */
- d_init = 1;
- ddr->ddr_data_init = CONFIG_MEM_INIT_VALUE;
- debug("DDR: ddr_data_init = 0x%08x\n", ddr->ddr_data_init);
+#else
- /* Memory will be initialized via DMA, or not at all. */
- d_init = 0;
+#endif
I'm using the current head (33aa4eac66b71c797bbc13b3afe432a2132947d4) on a mpc8572-based board. It uses DDR2 and has support for ECC. While enabling ECC support, I noticed that the "old" CONFIG_ECC_INIT_VIA_DDRCONTROLLER define is still being used to enable memory initialization on bootup while a new ECC_init_using_memctl field in the memctl_options_s structure is also present.
Currently it looks like ECC_init_using_memctl doesn't do anything and is only referenced in one location below:
- /* Pick ECC modes */
+#ifdef CONFIG_DDR_ECC
- popts->ECC_mode = 1; /* 0 = disabled, 1 = enabled */
+#else
- popts->ECC_mode = 0; /* 0 = disabled, 1 = enabled */
+#endif
- popts->ECC_init_using_memctl = 1; /* 0 = use DMA, 1 = use memctl */
The intended functionality of CONFIG_ECC_INIT_VIA_DDRCONTROLLER and ECC_init_using_memctl seem to be the same, but only one of them is being used, and they currently are unrelated which is a bit confusing.
Should the ECC_init_using_memctl field be removed, or is the intention to replace CONFIG_ECC_INIT_VIA_DDRCONTROLLER functionality with ECC_init_using_memctl as some point?
Now that the code is unified its will be easier to clean this up. I need to look at the ECC bits a little more to provide a better answer.
- k

Dear Kumar Gala,
In message 1219274578-30322-1-git-send-email-galak@kernel.crashing.org you wrote:
From: James Yang James.Yang@freescale.com
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 | 519 +++++++++++++++++++++++++++++++++++++++++++++++++++++ include/ddr_spd.h | 292 ++++++++++++++++++++++++++++++ 3 files changed, 812 insertions(+), 0 deletions(-) create mode 100644 common/ddr_spd.c create mode 100644 include/ddr_spd.h
Applied, thanks.
Best regards,
Wolfgang Denk
participants (3)
-
Kumar Gala
-
Peter Tyser
-
Wolfgang Denk