diff options
Diffstat (limited to 'cpu/mpc8xxx/ddr')
-rw-r--r-- | cpu/mpc8xxx/ddr/ctrl_regs.c | 74 | ||||
-rw-r--r-- | cpu/mpc8xxx/ddr/ddr.h | 17 | ||||
-rw-r--r-- | cpu/mpc8xxx/ddr/ddr1_2_dimm_params.h | 84 | ||||
-rw-r--r-- | cpu/mpc8xxx/ddr/main.c | 45 | ||||
-rw-r--r-- | cpu/mpc8xxx/ddr/options.c | 84 |
5 files changed, 193 insertions, 111 deletions
diff --git a/cpu/mpc8xxx/ddr/ctrl_regs.c b/cpu/mpc8xxx/ddr/ctrl_regs.c index e6c2a5c..1783e92 100644 --- a/cpu/mpc8xxx/ddr/ctrl_regs.c +++ b/cpu/mpc8xxx/ddr/ctrl_regs.c @@ -95,16 +95,10 @@ static void set_csn_config(int i, fsl_ddr_cfg_regs_t *ddr, 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) + | ((intlv_ctl & 0xf) << 24) | ((ap_n_en & 0x1) << 23) /* XXX: some implementation only have 1 bit starting at left */ @@ -117,6 +111,7 @@ static void set_csn_config(int i, fsl_ddr_cfg_regs_t *ddr, | ((row_bits_cs_n & 0x7) << 8) | ((col_bits_cs_n & 0x7) << 0) ); + debug("FSLDDR: cs[%d]_config = 0x%08x\n", i,ddr->cs[i].config); } /* Chip Select Configuration 2 (CSn_CONFIG_2) */ @@ -126,6 +121,7 @@ static void set_csn_config_2(int i, fsl_ddr_cfg_regs_t *ddr) unsigned int pasr_cfg = 0; /* Partial array self refresh config */ ddr->cs[i].config_2 = ((pasr_cfg & 7) << 24); + debug("FSLDDR: cs[%d]_config_2 = 0x%08x\n", i, ddr->cs[i].config_2); } /* -3E = 667 CL5, -25 = CL6 800, -25E = CL5 800 */ @@ -196,6 +192,7 @@ static void set_timing_cfg_3(fsl_ddr_cfg_regs_t *ddr, | ((ext_caslat & 0x1) << 12) | ((cntl_adj & 0x7) << 0) ); + debug("FSLDDR: timing_cfg_3 = 0x%08x\n", ddr->timing_cfg_3); } /* DDR SDRAM Timing Configuration 1 (TIMING_CFG_1) */ @@ -263,6 +260,7 @@ static void set_timing_cfg_1(fsl_ddr_cfg_regs_t *ddr, | ((acttoact_mclk & 0x07) << 4) | ((wrtord_mclk & 0x07) << 0) ); + debug("FSLDDR: timing_cfg_1 = 0x%08x\n", ddr->timing_cfg_1); } /* DDR SDRAM Timing Configuration 2 (TIMING_CFG_2) */ @@ -319,6 +317,7 @@ static void set_timing_cfg_2(fsl_ddr_cfg_regs_t *ddr, | ((cke_pls & 0x7) << 6) | ((four_act & 0x1f) << 0) ); + debug("FSLDDR: timing_cfg_2 = 0x%08x\n", ddr->timing_cfg_2); } /* DDR SDRAM control configuration (DDR_SDRAM_CFG) */ @@ -385,6 +384,7 @@ static void set_ddr_sdram_cfg(fsl_ddr_cfg_regs_t *ddr, | ((mem_halt & 0x1) << 1) | ((bi & 0x1) << 0) ); + debug("FSLDDR: ddr_sdram_cfg = 0x%08x\n", ddr->ddr_sdram_cfg); } /* DDR SDRAM control configuration 2 (DDR_SDRAM_CFG_2) */ @@ -449,6 +449,7 @@ static void set_ddr_sdram_cfg_2(fsl_ddr_cfg_regs_t *ddr, | ((rcw_en & 0x1) << 2) | ((md_en & 0x1) << 0) ); + debug("FSLDDR: ddr_sdram_cfg_2 = 0x%08x\n", ddr->ddr_sdram_cfg_2); } /* DDR SDRAM Mode configuration 2 (DDR_SDRAM_MODE_2) */ @@ -461,6 +462,7 @@ static void set_ddr_sdram_mode_2(fsl_ddr_cfg_regs_t *ddr) | ((esdmode2 & 0xFFFF) << 16) | ((esdmode3 & 0xFFFF) << 0) ); + debug("FSLDDR: ddr_sdram_mode_2 = 0x%08x\n", ddr->ddr_sdram_mode_2); } /* DDR SDRAM Interval Configuration (DDR_SDRAM_INTERVAL) */ @@ -480,6 +482,7 @@ static void set_ddr_sdram_interval(fsl_ddr_cfg_regs_t *ddr, | ((refint & 0xFFFF) << 16) | ((bstopre & 0x3FFF) << 0) ); + debug("FSLDDR: ddr_sdram_interval = 0x%08x\n", ddr->ddr_sdram_interval); } /* DDR SDRAM Mode configuration set (DDR_SDRAM_MODE) */ @@ -613,6 +616,7 @@ static void set_ddr_sdram_mode(fsl_ddr_cfg_regs_t *ddr, | ((esdmode & 0xFFFF) << 16) | ((sdmode & 0xFFFF) << 0) ); + debug("FSLDDR: ddr_sdram_mode = 0x%08x\n", ddr->ddr_sdram_mode); } @@ -675,6 +679,7 @@ static void set_timing_cfg_4(fsl_ddr_cfg_regs_t *ddr) | ((wwt & 0xf) << 16) | (dll_lock & 0x3) ); + debug("FSLDDR: timing_cfg_4 = 0x%08x\n", ddr->timing_cfg_4); } /* DDR SDRAM Timing Configuration 5 (TIMING_CFG_5) */ @@ -691,6 +696,7 @@ static void set_timing_cfg_5(fsl_ddr_cfg_regs_t *ddr) | ((wodt_on & 0xf) << 12) | ((wodt_off & 0xf) << 8) ); + debug("FSLDDR: timing_cfg_5 = 0x%08x\n", ddr->timing_cfg_5); } /* DDR ZQ Calibration Control (DDR_ZQ_CNTL) */ @@ -874,8 +880,13 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts, 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 */ + + if (popts->ba_intlv_ctl && (i > 0) && + ((popts->ba_intlv_ctl & 0x60) != FSL_DDR_CS2_CS3 )) { + /* Don't set up boundaries for other CS + * other than CS0, if bank interleaving + * is enabled and not CS2+CS3 interleaved. + */ break; } @@ -894,7 +905,9 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts, * on each controller is twice the amount present on * each controller. */ - ea = (2 * common_dimm->total_mem >> dbw_cap_adj) - 1; + unsigned long long rank_density + = dimm_params[0].capacity; + ea = (2 * (rank_density >> dbw_cap_adj)) - 1; } else if (!popts->memctl_interleaving && popts->ba_intlv_ctl) { /* @@ -906,8 +919,44 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts, * 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; + unsigned long long rank_density + = dimm_params[i/2].rank_density; + switch (popts->ba_intlv_ctl & FSL_DDR_CS0_CS1_CS2_CS3) { + case FSL_DDR_CS0_CS1_CS2_CS3: + /* CS0+CS1+CS2+CS3 interleaving, only CS0_CNDS + * needs to be set. + */ + sa = common_dimm->base_address; + ea = sa + (4 * (rank_density >> dbw_cap_adj))-1; + break; + case FSL_DDR_CS0_CS1_AND_CS2_CS3: + /* CS0+CS1 and CS2+CS3 interleaving, CS0_CNDS + * and CS2_CNDS need to be set. + */ + if (!(i&1)) { + sa = dimm_params[i/2].base_address; + ea = sa + (i * (rank_density >> + dbw_cap_adj)) - 1; + } + break; + case FSL_DDR_CS0_CS1: + /* CS0+CS1 interleaving, CS0_CNDS needs + * to be set + */ + sa = common_dimm->base_address; + ea = sa + (2 * (rank_density >> dbw_cap_adj))-1; + break; + case FSL_DDR_CS2_CS3: + /* CS2+CS3 interleaving*/ + if (i == 2) { + sa = dimm_params[i/2].base_address; + ea = sa + (2 * (rank_density >> + dbw_cap_adj)) - 1; + } + break; + default: /* No bank(chip-select) interleaving */ + break; + } } else if (popts->memctl_interleaving && !popts->ba_intlv_ctl) { /* @@ -955,6 +1004,7 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts, | ((ea & 0xFFF) << 0) /* ending address MSB */ ); + debug("FSLDDR: cs[%d]_bnds = 0x%08x\n", i, ddr->cs[i].bnds); set_csn_config(i, ddr, popts, dimm_params); set_csn_config_2(i, ddr); } diff --git a/cpu/mpc8xxx/ddr/ddr.h b/cpu/mpc8xxx/ddr/ddr.h index f5dc40a..9ffd548 100644 --- a/cpu/mpc8xxx/ddr/ddr.h +++ b/cpu/mpc8xxx/ddr/ddr.h @@ -10,8 +10,8 @@ #define FSL_DDR_MAIN_H #include <asm/fsl_ddr_sdram.h> +#include <asm/fsl_ddr_dimm_params.h> -#include "ddr1_2_dimm_params.h" #include "common_timing_params.h" /* @@ -31,17 +31,17 @@ compute_dimm_parameters(const generic_spd_eeprom_t *spd, * * 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 +#define CONFIG_SYS_NUM_DDR_CTLRS CONFIG_NUM_DDR_CONTROLLERS +#define CONFIG_SYS_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]; + spd_installed_dimms[CONFIG_SYS_NUM_DDR_CTLRS][CONFIG_SYS_DIMM_SLOTS_PER_CTLR]; struct dimm_params_s - 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_ddr_cfg_regs_t fsl_ddr_config_reg[CFG_NUM_DDR_CTLRS]; + dimm_params[CONFIG_SYS_NUM_DDR_CTLRS][CONFIG_SYS_DIMM_SLOTS_PER_CTLR]; + memctl_options_t memctl_opts[CONFIG_SYS_NUM_DDR_CTLRS]; + common_timing_params_t common_timing_params[CONFIG_SYS_NUM_DDR_CTLRS]; + fsl_ddr_cfg_regs_t fsl_ddr_config_reg[CONFIG_SYS_NUM_DDR_CTLRS]; } fsl_ddr_info_t; /* Compute steps */ @@ -71,6 +71,7 @@ compute_lowest_common_dimm_parameters(const dimm_params_t *dimm_params, unsigned int number_of_dimms); extern unsigned int populate_memctl_options(int all_DIMMs_registered, memctl_options_t *popts, + dimm_params_t *pdimm, unsigned int ctrl_num); extern unsigned int mclk_to_picos(unsigned int mclk); diff --git a/cpu/mpc8xxx/ddr/ddr1_2_dimm_params.h b/cpu/mpc8xxx/ddr/ddr1_2_dimm_params.h deleted file mode 100644 index c794eed..0000000 --- a/cpu/mpc8xxx/ddr/ddr1_2_dimm_params.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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 - -/* 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/ddr/main.c b/cpu/mpc8xxx/ddr/main.c index c340d56..21a16d9 100644 --- a/cpu/mpc8xxx/ddr/main.c +++ b/cpu/mpc8xxx/ddr/main.c @@ -164,6 +164,24 @@ int step_assign_addresses(fsl_ddr_info_t *pinfo, } if (j == 2) { *memctl_interleaving = 1; + + printf("\nMemory controller interleaving enabled: "); + + switch (pinfo->memctl_opts[0].memctl_interleaving_mode) { + case FSL_DDR_CACHE_LINE_INTERLEAVING: + printf("Cache-line interleaving!\n"); + break; + case FSL_DDR_PAGE_INTERLEAVING: + printf("Page interleaving!\n"); + break; + case FSL_DDR_BANK_INTERLEAVING: + printf("Bank interleaving!\n"); + break; + case FSL_DDR_SUPERBANK_INTERLEAVING: + printf("Super bank interleaving\n"); + default: + break; + } } /* Check that all controllers are rank interleaving. */ @@ -175,10 +193,30 @@ int step_assign_addresses(fsl_ddr_info_t *pinfo, } if (j == 2) { *rank_interleaving = 1; + + printf("Bank(chip-select) interleaving enabled: "); + + switch (pinfo->memctl_opts[0].ba_intlv_ctl & + FSL_DDR_CS0_CS1_CS2_CS3) { + case FSL_DDR_CS0_CS1_CS2_CS3: + printf("CS0+CS1+CS2+CS3\n"); + break; + case FSL_DDR_CS0_CS1: + printf("CS0+CS1\n"); + break; + case FSL_DDR_CS2_CS3: + printf("CS2+CS3\n"); + break; + case FSL_DDR_CS0_CS1_AND_CS2_CS3: + printf("CS0+CS1 and CS2+CS3\n"); + default: + break; + } } if (*memctl_interleaving) { phys_addr_t addr; + phys_size_t total_mem_per_ctlr = 0; /* * If interleaving between memory controllers, @@ -197,14 +235,18 @@ int step_assign_addresses(fsl_ddr_info_t *pinfo, for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { addr = 0; + pinfo->common_timing_params[i].base_address = + (phys_addr_t)addr; 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]); + total_mem_per_ctlr += cap >> dbw_cap_adj[i]; } } + pinfo->common_timing_params[0].total_mem = total_mem_per_ctlr; } else { /* * Simple linear assignment if memory @@ -314,7 +356,8 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step) */ populate_memctl_options( timing_params[i].all_DIMMs_registered, - &pinfo->memctl_opts[i], i); + &pinfo->memctl_opts[i], + pinfo->dimm_params[i], i); } case STEP_ASSIGN_ADDRESSES: diff --git a/cpu/mpc8xxx/ddr/options.c b/cpu/mpc8xxx/ddr/options.c index 6c2b43c..714e88d 100644 --- a/cpu/mpc8xxx/ddr/options.c +++ b/cpu/mpc8xxx/ddr/options.c @@ -13,13 +13,16 @@ /* Board-specific functions defined in each board's ddr.c */ extern void fsl_ddr_board_options(memctl_options_t *popts, + dimm_params_t *pdimm, unsigned int ctrl_num); unsigned int populate_memctl_options(int all_DIMMs_registered, memctl_options_t *popts, + dimm_params_t *pdimm, unsigned int ctrl_num) { unsigned int i; + const char *p; /* Chip select options. */ @@ -179,19 +182,88 @@ unsigned int populate_memctl_options(int all_DIMMs_registered, #error "FIXME determine four activates for DDR3" #endif - /* ODT should only be used for DDR2 */ - - /* FIXME? */ - /* - * Interleaving checks. + * Check interleaving configuration from environment. + * Please refer to doc/README.fsl-ddr for the detail. * * If memory controller interleaving is enabled, then the data * bus widths must be programmed identically for the 2 memory * controllers. + * + * XXX: Attempt to set both controllers to the same chip select + * interleaving mode. It will do a best effort to get the + * requested ranks interleaved together such that the result + * should be a subset of the requested configuration. */ + if ((p = getenv("memctl_intlv_ctl")) != NULL) { + if (pdimm[0].n_ranks == 0) { + printf("There is no rank on CS0. Because only rank on \ + CS0 and ranks chip-select interleaved with CS0\ + are controller interleaved, force non memory \ + controller interleaving\n"); + popts->memctl_interleaving = 0; + } else { + popts->memctl_interleaving = 1; + if (strcmp(p, "cacheline") == 0) + popts->memctl_interleaving_mode = + FSL_DDR_CACHE_LINE_INTERLEAVING; + else if (strcmp(p, "page") == 0) + popts->memctl_interleaving_mode = + FSL_DDR_PAGE_INTERLEAVING; + else if (strcmp(p, "bank") == 0) + popts->memctl_interleaving_mode = + FSL_DDR_BANK_INTERLEAVING; + else if (strcmp(p, "superbank") == 0) + popts->memctl_interleaving_mode = + FSL_DDR_SUPERBANK_INTERLEAVING; + else + popts->memctl_interleaving_mode = + simple_strtoul(p, NULL, 0); + } + } + + if( (p = getenv("ba_intlv_ctl")) != NULL) { + if (strcmp(p, "cs0_cs1") == 0) + popts->ba_intlv_ctl = FSL_DDR_CS0_CS1; + else if (strcmp(p, "cs2_cs3") == 0) + popts->ba_intlv_ctl = FSL_DDR_CS2_CS3; + else if (strcmp(p, "cs0_cs1_and_cs2_cs3") == 0) + popts->ba_intlv_ctl = FSL_DDR_CS0_CS1_AND_CS2_CS3; + else if (strcmp(p, "cs0_cs1_cs2_cs3") == 0) + popts->ba_intlv_ctl = FSL_DDR_CS0_CS1_CS2_CS3; + else + popts->ba_intlv_ctl = simple_strtoul(p, NULL, 0); + + switch (popts->ba_intlv_ctl & FSL_DDR_CS0_CS1_CS2_CS3) { + case FSL_DDR_CS0_CS1_CS2_CS3: + case FSL_DDR_CS0_CS1: + if (pdimm[0].n_ranks != 2) { + popts->ba_intlv_ctl = 0; + printf("No enough bank(chip-select) for \ + CS0+CS1, force non-interleaving!\n"); + } + break; + case FSL_DDR_CS2_CS3: + if (pdimm[1].n_ranks !=2){ + popts->ba_intlv_ctl = 0; + printf("No enough bank(CS) for CS2+CS3, \ + force non-interleaving!\n"); + } + break; + case FSL_DDR_CS0_CS1_AND_CS2_CS3: + if ((pdimm[0].n_ranks != 2)||(pdimm[1].n_ranks != 2)) { + popts->ba_intlv_ctl = 0; + printf("No enough bank(CS) for CS0+CS1 or \ + CS2+CS3, force non-interleaving!\n"); + } + break; + default: + popts->ba_intlv_ctl = 0; + break; + } + } - fsl_ddr_board_options(popts, ctrl_num); + fsl_ddr_board_options(popts, pdimm, ctrl_num); return 0; } |