diff options
Diffstat (limited to 'arch/powerpc/cpu/mpc8xxx/ddr')
| -rw-r--r-- | arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c | 221 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc8xxx/ddr/ddr3_dimm_params.c | 25 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc8xxx/ddr/interactive.c | 22 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c | 18 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc8xxx/ddr/main.c | 307 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc8xxx/ddr/options.c | 212 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc8xxx/ddr/util.c | 67 | 
7 files changed, 514 insertions, 358 deletions
| diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c index 2067d53ad..2592873c9 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c @@ -1,5 +1,5 @@  /* - * Copyright 2008-2011 Freescale Semiconductor, Inc. + * Copyright 2008-2012 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 as published by the Free @@ -151,8 +151,19 @@ static void set_csn_config(int dimm_number, int i, fsl_ddr_cfg_regs_t *ddr,  		if (dimm_params[dimm_number].n_ranks > 0) {  			go_config = 1;  			/* These fields only available in CS0_CONFIG */ -			intlv_en = popts->memctl_interleaving; -			intlv_ctl = popts->memctl_interleaving_mode; +			if (!popts->memctl_interleaving) +				break; +			switch (popts->memctl_interleaving_mode) { +			case FSL_DDR_CACHE_LINE_INTERLEAVING: +			case FSL_DDR_PAGE_INTERLEAVING: +			case FSL_DDR_BANK_INTERLEAVING: +			case FSL_DDR_SUPERBANK_INTERLEAVING: +				intlv_en = popts->memctl_interleaving; +				intlv_ctl = popts->memctl_interleaving_mode; +				break; +			default: +				break; +			}  		}  		break;  	case 1: @@ -302,29 +313,41 @@ static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr,  /* DDR SDRAM Timing Configuration 3 (TIMING_CFG_3) */  static void set_timing_cfg_3(fsl_ddr_cfg_regs_t *ddr, +			       const memctl_options_t *popts,  			       const common_timing_params_t *common_dimm,  			       unsigned int cas_latency)  { +	/* Extended precharge to activate interval (tRP) */ +	unsigned int ext_pretoact = 0;  	/* 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 */ - -	/* If the tRAS > 19 MCLK, we use the ext mode */ -	if (picos_to_mclk(common_dimm->tRAS_ps) > 0x13) -		ext_acttopre = 1; +	/* Extended activate to read/write interval (tRCD) */ +	unsigned int ext_acttorw = 0; +	/* Extended refresh recovery time (tRFC) */ +	unsigned int ext_refrec; +	/* Extended MCAS latency from READ cmd */ +	unsigned int ext_caslat = 0; +	/* Extended last data to precharge interval (tWR) */ +	unsigned int ext_wrrec = 0; +	/* Control Adjust */ +	unsigned int cntl_adj = 0; +	ext_pretoact = picos_to_mclk(common_dimm->tRP_ps) >> 4; +	ext_acttopre = picos_to_mclk(common_dimm->tRAS_ps) >> 4; +	ext_acttorw = picos_to_mclk(common_dimm->tRCD_ps) >> 4; +	ext_caslat = (2 * cas_latency - 1) >> 4;  	ext_refrec = (picos_to_mclk(common_dimm->tRFC_ps) - 8) >> 4; - -	/* If the CAS latency more than 8, use the ext mode */ -	if (cas_latency > 8) -		ext_caslat = 1; +	/* ext_wrrec only deals with 16 clock and above, or 14 with OTF */ +	ext_wrrec = (picos_to_mclk(common_dimm->tWR_ps) + +		(popts->OTF_burst_chop_en ? 2 : 0)) >> 4;  	ddr->timing_cfg_3 = (0 -		| ((ext_acttopre & 0x1) << 24) -		| ((ext_refrec & 0xF) << 16) -		| ((ext_caslat & 0x1) << 12) +		| ((ext_pretoact & 0x1) << 28) +		| ((ext_acttopre & 0x2) << 24) +		| ((ext_acttorw & 0x1) << 22) +		| ((ext_refrec & 0x1F) << 16) +		| ((ext_caslat & 0x3) << 12) +		| ((ext_wrrec & 0x1) << 8)  		| ((cntl_adj & 0x7) << 0)  		);  	debug("FSLDDR: timing_cfg_3 = 0x%08x\n", ddr->timing_cfg_3); @@ -386,15 +409,16 @@ static void set_timing_cfg_1(fsl_ddr_cfg_regs_t *ddr,  	 * we need set extend bit for it at  	 * TIMING_CFG_3[EXT_CASLAT]  	 */ -	if (cas_latency > 8) -		cas_latency -= 8;  	caslat_ctrl = 2 * cas_latency - 1;  #endif  	refrec_ctrl = picos_to_mclk(common_dimm->tRFC_ps) - 8;  	wrrec_mclk = picos_to_mclk(common_dimm->tWR_ps); -	wrrec_mclk = wrrec_table[wrrec_mclk - 1]; +	if (wrrec_mclk > 16) +		printf("Error: WRREC doesn't support more than 16 clocks\n"); +	else +		wrrec_mclk = wrrec_table[wrrec_mclk - 1];  	if (popts->OTF_burst_chop_en)  		wrrec_mclk += 2; @@ -825,7 +849,7 @@ static void set_ddr_sdram_mode(fsl_ddr_cfg_regs_t *ddr,  	/* Mode Register - MR0 */  	unsigned int dll_on;	/* DLL control for precharge PD, 0=off, 1=on */ -	unsigned int wr;	/* Write Recovery */ +	unsigned int wr = 0;	/* Write Recovery */  	unsigned int dll_rst;	/* DLL Reset */  	unsigned int mode;	/* Normal=0 or Test=1 */  	unsigned int caslat = 4;/* CAS# latency, default set as 6 cycles */ @@ -885,24 +909,37 @@ static void set_ddr_sdram_mode(fsl_ddr_cfg_regs_t *ddr,  	dll_on = 1;  	wr_mclk = (common_dimm->tWR_ps + mclk_ps - 1) / mclk_ps; -	wr = wr_table[wr_mclk - 5]; +	if (wr_mclk <= 16) { +		wr = wr_table[wr_mclk - 5]; +	} else { +		printf("Error: unsupported write recovery for mode register " +		       "wr_mclk = %d\n", wr_mclk); +	}  	dll_rst = 0;	/* dll no reset */  	mode = 0;	/* normal mode */  	/* look up table to get the cas latency bits */ -	if (cas_latency >= 5 && cas_latency <= 11) { -		unsigned char cas_latency_table[7] = { +	if (cas_latency >= 5 && cas_latency <= 16) { +		unsigned char cas_latency_table[] = {  			0x2,	/* 5 clocks */  			0x4,	/* 6 clocks */  			0x6,	/* 7 clocks */  			0x8,	/* 8 clocks */  			0xa,	/* 9 clocks */  			0xc,	/* 10 clocks */ -			0xe	/* 11 clocks */ +			0xe,	/* 11 clocks */ +			0x1,	/* 12 clocks */ +			0x3,	/* 13 clocks */ +			0x5,	/* 14 clocks */ +			0x7,	/* 15 clocks */ +			0x9,	/* 16 clocks */  		};  		caslat = cas_latency_table[cas_latency - 5]; +	} else { +		printf("Error: unsupported cas latency for mode register\n");  	} +  	bt = 0;	/* Nibble sequential */  	switch (popts->burst_length) { @@ -930,6 +967,7 @@ static void set_ddr_sdram_mode(fsl_ddr_cfg_regs_t *ddr,  		  | ((mode & 0x1) << 7)  		  | (((caslat >> 1) & 0x7) << 4)  		  | ((bt & 0x1) << 3) +		  | ((caslat & 1) << 2)  		  | ((bl & 0x3) << 0)  		  ); @@ -1399,73 +1437,37 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,  	/* Chip Select Memory Bounds (CSn_BNDS) */  	for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { -		unsigned long long ea = 0, sa = 0; +		unsigned long long ea, sa;  		unsigned int cs_per_dimm  			= CONFIG_CHIP_SELECTS_PER_CTRL / CONFIG_DIMM_SLOTS_PER_CTLR;  		unsigned int dimm_number  			= i / cs_per_dimm;  		unsigned long long rank_density -			= dimm_params[dimm_number].rank_density; +			= dimm_params[dimm_number].rank_density >> dbw_cap_adj; -		if (((i == 1) && (popts->ba_intlv_ctl & FSL_DDR_CS0_CS1)) || -			((i == 2) && (popts->ba_intlv_ctl & 0x04)) || -			((i == 3) && (popts->ba_intlv_ctl & FSL_DDR_CS2_CS3))) { -			/* -			 * Don't set up boundaries for unused CS -			 * cs1 for cs0_cs1, cs0_cs1_and_cs2_cs3, cs0_cs1_cs2_cs3 -			 * cs2 for cs0_cs1_cs2_cs3 -			 * cs3 for cs2_cs3, cs0_cs1_and_cs2_cs3, cs0_cs1_cs2_cs3 -			 * But we need to set the ODT_RD_CFG and -			 * ODT_WR_CFG for CS1_CONFIG here. -			 */ -			set_csn_config(dimm_number, i, ddr, popts, dimm_params); -			continue; -		}  		if (dimm_params[dimm_number].n_ranks == 0) {  			debug("Skipping setup of CS%u "  				"because n_ranks on DIMM %u is 0\n", i, dimm_number);  			continue;  		} -		if (popts->memctl_interleaving && popts->ba_intlv_ctl) { -			/* -			 * This works superbank 2CS -			 * There are 2 or more 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. If any CS is not included in the -			 * interleaving, the memory on that CS is not accssible -			 * and the total memory size is reduced. The CS is also -			 * disabled. -			 */ -			unsigned long long ctlr_density = 0; +		if (popts->memctl_interleaving) {  			switch (popts->ba_intlv_ctl & FSL_DDR_CS0_CS1_CS2_CS3) { +			case FSL_DDR_CS0_CS1_CS2_CS3: +				break;  			case FSL_DDR_CS0_CS1:  			case FSL_DDR_CS0_CS1_AND_CS2_CS3: -				ctlr_density = dimm_params[0].rank_density * 2;  				if (i > 1)  					cs_en = 0;  				break;  			case FSL_DDR_CS2_CS3: -				ctlr_density = dimm_params[0].rank_density; +			default:  				if (i > 0)  					cs_en = 0;  				break; -			case FSL_DDR_CS0_CS1_CS2_CS3: -				/* -				 * The four CS interleaving should have been verified by -				 * populate_memctl_options() -				 */ -				ctlr_density = dimm_params[0].rank_density * 4; -				break; -			default: -				break;  			} -			ea = (CONFIG_NUM_DDR_CONTROLLERS * -				(ctlr_density >> dbw_cap_adj)) - 1; -		} -		else if (!popts->memctl_interleaving && popts->ba_intlv_ctl) { +			sa = common_dimm->base_address; +			ea = common_dimm->total_mem - 1; +		} else if (!popts->memctl_interleaving) {  			/*  			 * If memory interleaving between controllers is NOT  			 * enabled, the starting address for each memory @@ -1477,49 +1479,40 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,  			 */  			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; +				ea = common_dimm->total_mem - 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 == 2) && (dimm_number == 0)) { +				if ((i >= 2) && (dimm_number == 0)) {  					sa = dimm_params[dimm_number].base_address + -					      2 * (rank_density >> dbw_cap_adj); -					ea = sa + 2 * (rank_density >> dbw_cap_adj) - 1; +					      2 * rank_density; +					ea = sa + 2 * rank_density - 1;  				} else {  					sa = dimm_params[dimm_number].base_address; -					ea = sa + (2 * (rank_density >> -						dbw_cap_adj)) - 1; +					ea = sa + 2 * rank_density - 1;  				}  				break;  			case FSL_DDR_CS0_CS1: -				/* CS0+CS1 interleaving, CS0_CNDS needs -				 * to be set -				 */  				if (dimm_params[dimm_number].n_ranks > (i % cs_per_dimm)) {  					sa = dimm_params[dimm_number].base_address; -					ea = sa + (rank_density >> dbw_cap_adj) - 1; -					sa += (i % cs_per_dimm) * (rank_density >> dbw_cap_adj); -					ea += (i % cs_per_dimm) * (rank_density >> dbw_cap_adj); +					ea = sa + rank_density - 1; +					if (i != 1) +						sa += (i % cs_per_dimm) * rank_density; +					ea += (i % cs_per_dimm) * rank_density;  				} else {  					sa = 0;  					ea = 0;  				}  				if (i == 0) -					ea += (rank_density >> dbw_cap_adj); +					ea += rank_density;  				break;  			case FSL_DDR_CS2_CS3: -				/* CS2+CS3 interleaving*/  				if (dimm_params[dimm_number].n_ranks > (i % cs_per_dimm)) {  					sa = dimm_params[dimm_number].base_address; -					ea = sa + (rank_density >> dbw_cap_adj) - 1; -					sa += (i % cs_per_dimm) * (rank_density >> dbw_cap_adj); -					ea += (i % cs_per_dimm) * (rank_density >> dbw_cap_adj); +					ea = sa + rank_density - 1; +					if (i != 3) +						sa += (i % cs_per_dimm) * rank_density; +					ea += (i % cs_per_dimm) * rank_density;  				} else {  					sa = 0;  					ea = 0; @@ -1528,38 +1521,18 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,  					ea += (rank_density >> dbw_cap_adj);  				break;  			default:  /* No bank(chip-select) interleaving */ +				sa = dimm_params[dimm_number].base_address; +				ea = sa + rank_density - 1; +				if (dimm_params[dimm_number].n_ranks > (i % cs_per_dimm)) { +					sa += (i % cs_per_dimm) * rank_density; +					ea += (i % cs_per_dimm) * rank_density; +				} else { +					sa = 0; +					ea = 0; +				}  				break;  			}  		} -		else if (popts->memctl_interleaving && !popts->ba_intlv_ctl) { -			/* -			 * Only the rank on CS0 of each memory controller may -			 * be used if memory controller interleaving is used -			 * without rank interleaving within each memory -			 * controller.  However, the ending address programmed -			 * into each CS0 must be the sum of the amount of -			 * memory in the two CS0 ranks. -			 */ -			if (i == 0) { -				ea = (2 * (rank_density >> dbw_cap_adj)) - 1; -			} - -		} -		else if (!popts->memctl_interleaving && !popts->ba_intlv_ctl) { -			/* -			 * No rank interleaving and no memory controller -			 * interleaving. -			 */ -			sa = dimm_params[dimm_number].base_address; -			ea = sa + (rank_density >> dbw_cap_adj) - 1; -			if (dimm_params[dimm_number].n_ranks > (i % cs_per_dimm)) { -				sa += (i % cs_per_dimm) * (rank_density >> dbw_cap_adj); -				ea += (i % cs_per_dimm) * (rank_density >> dbw_cap_adj); -			} else { -				sa = 0; -				ea = 0; -			} -		}  		sa >>= 24;  		ea >>= 24; @@ -1574,7 +1547,7 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,  			set_csn_config(dimm_number, i, ddr, popts, dimm_params);  			set_csn_config_2(i, ddr);  		} else -			printf("CS%d is disabled.\n", i); +			debug("CS%d is disabled.\n", i);  	}  	/* @@ -1590,7 +1563,7 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,  	set_timing_cfg_0(ddr, popts);  #endif -	set_timing_cfg_3(ddr, common_dimm, cas_latency); +	set_timing_cfg_3(ddr, popts, common_dimm, cas_latency);  	set_timing_cfg_1(ddr, popts, common_dimm, cas_latency);  	set_timing_cfg_2(ddr, popts, common_dimm,  				cas_latency, additive_latency); diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/ddr3_dimm_params.c b/arch/powerpc/cpu/mpc8xxx/ddr/ddr3_dimm_params.c index d0a546610..3e7c269e4 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/ddr3_dimm_params.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/ddr3_dimm_params.c @@ -1,5 +1,5 @@  /* - * Copyright 2008-2009 Freescale Semiconductor, Inc. + * Copyright 2008-2012 Freescale Semiconductor, Inc.   *	Dave Liu <daveliu@freescale.com>   *   * calculate the organization and timing parameter @@ -90,6 +90,7 @@ ddr_compute_dimm_parameters(const ddr3_spd_eeprom_t *spd,  {  	unsigned int retval;  	unsigned int mtb_ps; +	int ftb_10th_ps;  	int i;  	if (spd->mem_type) { @@ -197,6 +198,14 @@ ddr_compute_dimm_parameters(const ddr3_spd_eeprom_t *spd,  	pdimm->mtb_ps = mtb_ps;  	/* +	 * FTB - fine timebase +	 * use 1/10th of ps as our unit to avoid floating point +	 * eg, 10 for 1ps, 25 for 2.5ps, 50 for 5ps +	 */ +	ftb_10th_ps = +		((spd->ftb_div & 0xf0) >> 4) * 10 / (spd->ftb_div & 0x0f); +	pdimm->ftb_10th_ps = ftb_10th_ps; +	/*  	 * sdram minimum cycle time  	 * we assume the MTB is 0.125ns  	 * eg: @@ -204,7 +213,8 @@ ddr_compute_dimm_parameters(const ddr3_spd_eeprom_t *spd,  	 *        =12 MTB (1.5ns) ->DDR3-1333  	 *        =10 MTB (1.25ns) ->DDR3-1600  	 */ -	pdimm->tCKmin_X_ps = spd->tCK_min * mtb_ps; +	pdimm->tCKmin_X_ps = spd->tCK_min * mtb_ps + +		(spd->fine_tCK_min * ftb_10th_ps) / 10;  	/*  	 * CAS latency supported @@ -222,7 +232,8 @@ ddr_compute_dimm_parameters(const ddr3_spd_eeprom_t *spd,  	 * DDR3-1333H	108 MTB (13.5ns)  	 * DDR3-1600H	90 MTB (11.25ns)  	 */ -	pdimm->tAA_ps = spd->tAA_min * mtb_ps; +	pdimm->tAA_ps = spd->tAA_min * mtb_ps + +		(spd->fine_tAA_min * ftb_10th_ps) / 10;  	/*  	 * min write recovery time @@ -239,7 +250,8 @@ ddr_compute_dimm_parameters(const ddr3_spd_eeprom_t *spd,  	 * DDR3-1333H	108 MTB (13.5ns)  	 * DDR3-1600H	90 MTB (11.25)  	 */ -	pdimm->tRCD_ps = spd->tRCD_min * mtb_ps; +	pdimm->tRCD_ps = spd->tRCD_min * mtb_ps + +		(spd->fine_tRCD_min * ftb_10th_ps) / 10;  	/*  	 * min row active to row active delay time @@ -257,7 +269,8 @@ ddr_compute_dimm_parameters(const ddr3_spd_eeprom_t *spd,  	 * DDR3-1333H	108 MTB (13.5ns)  	 * DDR3-1600H	90 MTB (11.25ns)  	 */ -	pdimm->tRP_ps = spd->tRP_min * mtb_ps; +	pdimm->tRP_ps = spd->tRP_min * mtb_ps + +		(spd->fine_tRP_min * ftb_10th_ps) / 10;  	/* min active to precharge delay time  	 * eg: tRAS_min = @@ -277,7 +290,7 @@ ddr_compute_dimm_parameters(const ddr3_spd_eeprom_t *spd,  	 * DDR3-1600H	370 MTB (46.25ns)  	 */  	pdimm->tRC_ps = (((spd->tRAS_tRC_ext & 0xf0) << 4) | spd->tRC_min_lsb) -			* mtb_ps; +			* mtb_ps + (spd->fine_tRC_min * ftb_10th_ps) / 10;  	/*  	 * min refresh recovery delay time  	 * eg: tRFC_min = diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c b/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c index 5b724371f..f59d1051b 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c @@ -1,5 +1,5 @@  /* - * Copyright 2010-2011 Freescale Semiconductor, Inc. + * Copyright 2010-2012 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 @@ -1047,7 +1047,7 @@ void ddr3_spd_dump(const ddr3_spd_eeprom_t *spd)  	/* General Section: Bytes 0-59 */ -#define PRINT_NXS(x, y, z...) printf("%-3d    : %02x " z "\n", x, y); +#define PRINT_NXS(x, y, z...) printf("%-3d    : %02x " z "\n", x, (u8)y);  #define PRINT_NNXXS(n0, n1, x0, x1, s) \  	printf("%-3d-%3d: %02x %02x " s "\n", n0, n1, x0, x1); @@ -1121,11 +1121,21 @@ void ddr3_spd_dump(const ddr3_spd_eeprom_t *spd)  		"therm_sensor  SDRAM Thermal Sensor");  	PRINT_NXS(33, spd->device_type,  		"device_type  SDRAM Device Type"); +	PRINT_NXS(34, spd->fine_tCK_min, +		"fine_tCK_min  Fine offset for tCKmin"); +	PRINT_NXS(35, spd->fine_tAA_min, +		"fine_tAA_min  Fine offset for tAAmin"); +	PRINT_NXS(36, spd->fine_tRCD_min, +		"fine_tRCD_min Fine offset for tRCDmin"); +	PRINT_NXS(37, spd->fine_tRP_min, +		"fine_tRP_min  Fine offset for tRPmin"); +	PRINT_NXS(38, spd->fine_tRC_min, +		"fine_tRC_min  Fine offset for tRCmin"); -	printf("%-3d-%3d: ",  34, 59);  /* Reserved, General Section */ +	printf("%-3d-%3d: ",  39, 59);  /* Reserved, General Section */ -	for (i = 34; i <= 59; i++) -		printf("%02x ", spd->res_34_59[i - 34]); +	for (i = 39; i <= 59; i++) +		printf("%02x ", spd->res_39_59[i - 39]);  	puts("\n"); @@ -1388,7 +1398,7 @@ unsigned long long fsl_ddr_interactive(fsl_ddr_info_t *pinfo)  		 * No need to worry for buffer overflow here in  		 * this function;  readline() maxes out at CFG_CBSIZE  		 */ -		readline_into_buffer(prompt,  buffer); +		readline_into_buffer(prompt, buffer, 0);  		argc = parse_line(buffer, argv);  		if (argc == 0)  			continue; diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c b/arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c index 20c7db03e..03a784cd4 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c @@ -1,5 +1,5 @@  /* - * Copyright 2008-2011 Freescale Semiconductor, Inc. + * Copyright 2008-2012 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 @@ -27,8 +27,10 @@ compute_cas_latency_ddr3(const dimm_params_t *dimm_params,  	/* compute the common CAS latency supported between slots */  	tmp = dimm_params[0].caslat_X; -	for (i = 1; i < number_of_dimms; i++) -		 tmp &= dimm_params[i].caslat_X; +	for (i = 1; i < number_of_dimms; i++) { +		if (dimm_params[i].n_ranks) +			tmp &= dimm_params[i].caslat_X; +	}  	common_caslat = tmp;  	/* compute the max tAAmin tCKmin between slots */ @@ -491,5 +493,15 @@ compute_lowest_common_dimm_parameters(const dimm_params_t *dimm_params,  	 */  	outpdimm->additive_latency = additive_latency; +	debug("tCKmin_ps = %u\n", outpdimm->tCKmin_X_ps); +	debug("tRCD_ps   = %u\n", outpdimm->tRCD_ps); +	debug("tRP_ps    = %u\n", outpdimm->tRP_ps); +	debug("tRAS_ps   = %u\n", outpdimm->tRAS_ps); +	debug("tWR_ps    = %u\n", outpdimm->tWR_ps); +	debug("tWTR_ps   = %u\n", outpdimm->tWTR_ps); +	debug("tRFC_ps   = %u\n", outpdimm->tRFC_ps); +	debug("tRRD_ps   = %u\n", outpdimm->tRRD_ps); +	debug("tRC_ps    = %u\n", outpdimm->tRC_ps); +  	return 0;  } diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/main.c b/arch/powerpc/cpu/mpc8xxx/ddr/main.c index c2a03e334..b47268c20 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/main.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/main.c @@ -1,5 +1,5 @@  /* - * Copyright 2008-2011 Freescale Semiconductor, Inc. + * Copyright 2008-2012 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 @@ -15,13 +15,15 @@  #include <common.h>  #include <i2c.h>  #include <asm/fsl_ddr_sdram.h> +#include <asm/fsl_law.h>  #include "ddr.h" -extern void 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); +void fsl_ddr_set_intl3r(const unsigned int granule_size);  /* processor specific function */  extern void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, @@ -51,6 +53,22 @@ u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = {  	[1][0] = SPD_EEPROM_ADDRESS3,	/* controller 2 */  	[1][1] = SPD_EEPROM_ADDRESS4,	/* controller 2 */  }; +#elif (CONFIG_NUM_DDR_CONTROLLERS == 3) && (CONFIG_DIMM_SLOTS_PER_CTLR == 1) +u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = { +	[0][0] = SPD_EEPROM_ADDRESS1,	/* controller 1 */ +	[1][0] = SPD_EEPROM_ADDRESS2,	/* controller 2 */ +	[2][0] = SPD_EEPROM_ADDRESS3,	/* controller 3 */ +}; +#elif (CONFIG_NUM_DDR_CONTROLLERS == 3) && (CONFIG_DIMM_SLOTS_PER_CTLR == 2) +u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = { +	[0][0] = SPD_EEPROM_ADDRESS1,	/* controller 1 */ +	[0][1] = SPD_EEPROM_ADDRESS2,	/* controller 1 */ +	[1][0] = SPD_EEPROM_ADDRESS3,	/* controller 2 */ +	[1][1] = SPD_EEPROM_ADDRESS4,	/* controller 2 */ +	[2][0] = SPD_EEPROM_ADDRESS5,	/* controller 3 */ +	[2][1] = SPD_EEPROM_ADDRESS6,	/* controller 3 */ +}; +  #endif  static void __get_spd(generic_spd_eeprom_t *spd, u8 i2c_address) @@ -156,12 +174,12 @@ const char * step_to_string(unsigned int step) {  	return step_string_tbl[s];  } -int step_assign_addresses(fsl_ddr_info_t *pinfo, -			  unsigned int dbw_cap_adj[], -			  unsigned int *all_memctl_interleaving, -			  unsigned int *all_ctlr_rank_interleaving) +unsigned long long step_assign_addresses(fsl_ddr_info_t *pinfo, +			  unsigned int dbw_cap_adj[])  {  	int i, j; +	unsigned long long total_mem, current_mem_base, total_ctlr_mem; +	unsigned long long rank_density, ctlr_density = 0;  	/*  	 * If a reduced data width is requested, but the SPD @@ -220,86 +238,108 @@ int step_assign_addresses(fsl_ddr_info_t *pinfo,  				"specified controller %u\n", i);  			return 1;  		} +		debug("dbw_cap_adj[%d]=%d\n", i, dbw_cap_adj[i]);  	} -	j = 0; -	for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) -		if (pinfo->memctl_opts[i].memctl_interleaving) -			j++; -	/* -	 * Not support less than all memory controllers interleaving -	 * if more than two controllers -	 */ -	if (j == CONFIG_NUM_DDR_CONTROLLERS) -		*all_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++; -	/* -	 * All memory controllers must be populated to qualify for -	 * all controller rank interleaving -	 */ -	 if (j == CONFIG_NUM_DDR_CONTROLLERS) -		*all_ctlr_rank_interleaving = 1; - -	if (*all_memctl_interleaving) { -		unsigned long long addr, total_mem_per_ctlr = 0; -		/* -		 * 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. -		 */ - +	current_mem_base = 0ull; +	total_mem = 0; +	if (pinfo->memctl_opts[0].memctl_interleaving) { +		rank_density = pinfo->dimm_params[0][0].rank_density >> +					dbw_cap_adj[0]; +		switch (pinfo->memctl_opts[0].ba_intlv_ctl & +					FSL_DDR_CS0_CS1_CS2_CS3) { +		case FSL_DDR_CS0_CS1_CS2_CS3: +			ctlr_density = 4 * rank_density; +			break; +		case FSL_DDR_CS0_CS1: +		case FSL_DDR_CS0_CS1_AND_CS2_CS3: +			ctlr_density = 2 * rank_density; +			break; +		case FSL_DDR_CS2_CS3: +		default: +			ctlr_density = rank_density; +			break; +		} +		debug("rank density is 0x%llx, ctlr density is 0x%llx\n", +			rank_density, ctlr_density);  		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { -			addr = 0; -			pinfo->common_timing_params[i].base_address = 0ull; -			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 += cap >> dbw_cap_adj[i]; -				total_mem_per_ctlr += cap >> dbw_cap_adj[i]; +			if (pinfo->memctl_opts[i].memctl_interleaving) { +				switch (pinfo->memctl_opts[i].memctl_interleaving_mode) { +				case FSL_DDR_CACHE_LINE_INTERLEAVING: +				case FSL_DDR_PAGE_INTERLEAVING: +				case FSL_DDR_BANK_INTERLEAVING: +				case FSL_DDR_SUPERBANK_INTERLEAVING: +					total_ctlr_mem = 2 * ctlr_density; +					break; +				case FSL_DDR_3WAY_1KB_INTERLEAVING: +				case FSL_DDR_3WAY_4KB_INTERLEAVING: +				case FSL_DDR_3WAY_8KB_INTERLEAVING: +					total_ctlr_mem = 3 * ctlr_density; +					break; +				case FSL_DDR_4WAY_1KB_INTERLEAVING: +				case FSL_DDR_4WAY_4KB_INTERLEAVING: +				case FSL_DDR_4WAY_8KB_INTERLEAVING: +					total_ctlr_mem = 4 * ctlr_density; +					break; +				default: +					panic("Unknown interleaving mode"); +				} +				pinfo->common_timing_params[i].base_address = +							current_mem_base; +				pinfo->common_timing_params[i].total_mem = +							total_ctlr_mem; +				total_mem = current_mem_base + total_ctlr_mem; +				debug("ctrl %d base 0x%llx\n", i, current_mem_base); +				debug("ctrl %d total 0x%llx\n", i, total_ctlr_mem); +			} else { +				/* when 3rd controller not interleaved */ +				current_mem_base = total_mem; +				total_ctlr_mem = 0; +				pinfo->common_timing_params[i].base_address = +							current_mem_base; +				for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { +					unsigned long long cap = +						pinfo->dimm_params[i][j].capacity >> dbw_cap_adj[i]; +					pinfo->dimm_params[i][j].base_address = +						current_mem_base; +					debug("ctrl %d dimm %d base 0x%llx\n", i, j, current_mem_base); +					current_mem_base += cap; +					total_ctlr_mem += cap; +				} +				debug("ctrl %d total 0x%llx\n", i, total_ctlr_mem); +				pinfo->common_timing_params[i].total_mem = +							total_ctlr_mem; +				total_mem += total_ctlr_mem;  			}  		} -		pinfo->common_timing_params[0].total_mem = total_mem_per_ctlr;  	} else {  		/*  		 * Simple linear assignment if memory  		 * controllers are not interleaved.  		 */ -		unsigned long long cur_memsize = 0;  		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { -			u64 total_mem_per_ctlr = 0; +			total_ctlr_mem = 0;  			pinfo->common_timing_params[i].base_address = -						cur_memsize; +						current_mem_base;  			for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {  				/* Compute DIMM base addresses. */  				unsigned long long cap = -					pinfo->dimm_params[i][j].capacity; +					pinfo->dimm_params[i][j].capacity >> dbw_cap_adj[i];  				pinfo->dimm_params[i][j].base_address = -					cur_memsize; -				cur_memsize += cap >> dbw_cap_adj[i]; -				total_mem_per_ctlr += cap >> dbw_cap_adj[i]; +					current_mem_base; +				debug("ctrl %d dimm %d base 0x%llx\n", i, j, current_mem_base); +				current_mem_base += cap; +				total_ctlr_mem += cap;  			} +			debug("ctrl %d total 0x%llx\n", i, total_ctlr_mem);  			pinfo->common_timing_params[i].total_mem = -							total_mem_per_ctlr; +							total_ctlr_mem; +			total_mem += total_ctlr_mem;  		}  	} +	debug("Total mem by %s is 0x%llx\n", __func__, total_mem); -	return 0; +	return total_mem;  }  unsigned long long @@ -307,8 +347,6 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,  				       unsigned int size_only)  {  	unsigned int i, j; -	unsigned int all_controllers_memctl_interleaving = 0; -	unsigned int all_controllers_rank_interleaving = 0;  	unsigned long long total_mem = 0;  	fsl_ddr_cfg_regs_t *ddr_reg = pinfo->fsl_ddr_config_reg; @@ -345,9 +383,10 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,  				retval = compute_dimm_parameters(spd, pdimm, i);  #ifdef CONFIG_SYS_DDR_RAW_TIMING -				if (retval != 0) { -					printf("SPD error! Trying fallback to " -					"raw timing calculation\n"); +				if (!i && !j && retval) { +					printf("SPD error on controller %d! " +					"Trying fallback to raw timing " +					"calculation\n", i);  					fsl_ddr_get_dimm_params(pdimm, i, j);  				}  #else @@ -407,17 +446,14 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,  					&pinfo->memctl_opts[i],  					pinfo->dimm_params[i], i);  		} -		check_interleaving_options(pinfo);  	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); +		check_interleaving_options(pinfo); +		total_mem = step_assign_addresses(pinfo, dbw_capacity_adjust);  	case STEP_COMPUTE_REGS:  		/* STEP 6:  compute controller register values */ -		debug("FSL Memory ctrl cg register computation\n"); +		debug("FSL Memory ctrl register computation\n");  		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {  			if (timing_params[i].ndimms_present == 0) {  				memset(&ddr_reg[i], 0, @@ -437,21 +473,7 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,  		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. @@ -489,7 +511,7 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,  phys_size_t fsl_ddr_sdram(void)  {  	unsigned int i; -	unsigned int memctl_interleaved; +	unsigned int law_memctl = LAW_TRGT_IF_DDR_1;  	unsigned long long total_memory;  	fsl_ddr_info_t info; @@ -504,34 +526,6 @@ phys_size_t fsl_ddr_sdram(void)  #endif  		total_memory = fsl_ddr_compute(&info, STEP_GET_SPD, 0); -	/* 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("Warning: memctl interleaving not " -				"properly configured on all controllers\n"); -			memctl_interleaved = 0; -			for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) -				info.memctl_opts[i].memctl_interleaving = 0; -			debug("Recomputing with memctl_interleaving off.\n"); -			total_memory = fsl_ddr_compute(&info, -						       STEP_ASSIGN_ADDRESSES, -						       0); -		} -	} -  	/* Program configuration registers. */  	for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {  		debug("Programming controller %u\n", i); @@ -544,24 +538,69 @@ phys_size_t fsl_ddr_sdram(void)  		fsl_ddr_set_memctl_regs(&(info.fsl_ddr_config_reg[i]), i);  	} -	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++) { +	/* program LAWs */ +	for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { +		if (info.memctl_opts[i].memctl_interleaving) { +			switch (info.memctl_opts[i].memctl_interleaving_mode) { +			case FSL_DDR_CACHE_LINE_INTERLEAVING: +			case FSL_DDR_PAGE_INTERLEAVING: +			case FSL_DDR_BANK_INTERLEAVING: +			case FSL_DDR_SUPERBANK_INTERLEAVING: +				if (i == 0) { +					law_memctl = LAW_TRGT_IF_DDR_INTRLV; +					fsl_ddr_set_lawbar(&info.common_timing_params[i], +						law_memctl, i); +				} else if (i == 2) { +					law_memctl = LAW_TRGT_IF_DDR_INTLV_34; +					fsl_ddr_set_lawbar(&info.common_timing_params[i], +						law_memctl, i); +				} +				break; +			case FSL_DDR_3WAY_1KB_INTERLEAVING: +			case FSL_DDR_3WAY_4KB_INTERLEAVING: +			case FSL_DDR_3WAY_8KB_INTERLEAVING: +				law_memctl = LAW_TRGT_IF_DDR_INTLV_123; +				if (i == 0) { +					fsl_ddr_set_intl3r(info.memctl_opts[i].memctl_interleaving_mode); +					fsl_ddr_set_lawbar(&info.common_timing_params[i], +						law_memctl, i); +				} +				break; +			case FSL_DDR_4WAY_1KB_INTERLEAVING: +			case FSL_DDR_4WAY_4KB_INTERLEAVING: +			case FSL_DDR_4WAY_8KB_INTERLEAVING: +				law_memctl = LAW_TRGT_IF_DDR_INTLV_1234; +				if (i == 0) +					fsl_ddr_set_lawbar(&info.common_timing_params[i], +						law_memctl, i); +				/* place holder for future 4-way interleaving */ +				break; +			default: +				break; +			} +		} else { +			switch (i) { +			case 0: +				law_memctl = LAW_TRGT_IF_DDR_1; +				break; +			case 1: +				law_memctl = LAW_TRGT_IF_DDR_2; +				break; +			case 2: +				law_memctl = LAW_TRGT_IF_DDR_3; +				break; +			case 3: +				law_memctl = LAW_TRGT_IF_DDR_4; +				break; +			default: +				break; +			}  			fsl_ddr_set_lawbar(&info.common_timing_params[i], -						 0, i); +					law_memctl, i);  		}  	} -	debug("total_memory = %llu\n", total_memory); +	debug("total_memory by %s = %llu\n", __func__, total_memory);  #if !defined(CONFIG_PHYS_64BIT)  	/* Check for 4G or more.  Bad. */ diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/options.c b/arch/powerpc/cpu/mpc8xxx/ddr/options.c index 00ec57be1..13e482527 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/options.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/options.c @@ -1,5 +1,5 @@  /* - * Copyright 2008, 2010-2011 Freescale Semiconductor, Inc. + * Copyright 2008, 2010-2012 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 as published by the Free @@ -19,7 +19,6 @@   * This is pretty fragile on both the use of stack and if the buffer is big   * enough. However we will get a warning from getenv_f for the later.   */ -#define HWCONFIG_BUFFER_SIZE	128  /* Board-specific functions defined in each board's ddr.c */  extern void fsl_ddr_board_options(memctl_options_t *popts, @@ -790,46 +789,97 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,  	 * should be a subset of the requested configuration.  	 */  #if (CONFIG_NUM_DDR_CONTROLLERS > 1) -	if (hwconfig_sub_f("fsl_ddr", "ctlr_intlv", buf)) { -		if (pdimm[0].n_ranks == 0) { -			printf("There is no rank on CS0 for controller %d. Because only" -				" rank on CS0 and ranks chip-select interleaved with CS0" -				" are controller interleaved, force non memory " -				"controller interleaving\n", ctrl_num); -			popts->memctl_interleaving = 0; -		} else { -			popts->memctl_interleaving = 1; -			/* -			 * test null first. if CONFIG_HWCONFIG is not defined -			 * hwconfig_arg_cmp returns non-zero -			 */ -			if (hwconfig_subarg_cmp_f("fsl_ddr", "ctlr_intlv", -						    "null", buf)) { -				popts->memctl_interleaving = 0; -				debug("memory controller interleaving disabled.\n"); -			} else if (hwconfig_subarg_cmp_f("fsl_ddr", -							 "ctlr_intlv", -							 "cacheline", buf)) -				popts->memctl_interleaving_mode = -					FSL_DDR_CACHE_LINE_INTERLEAVING; -			else if (hwconfig_subarg_cmp_f("fsl_ddr", "ctlr_intlv", -						       "page", buf)) -				popts->memctl_interleaving_mode = -					FSL_DDR_PAGE_INTERLEAVING; -			else if (hwconfig_subarg_cmp_f("fsl_ddr", "ctlr_intlv", -						       "bank", buf)) -				popts->memctl_interleaving_mode = -					FSL_DDR_BANK_INTERLEAVING; -			else if (hwconfig_subarg_cmp_f("fsl_ddr", "ctlr_intlv", -						       "superbank", buf)) -				popts->memctl_interleaving_mode = -					FSL_DDR_SUPERBANK_INTERLEAVING; -			else { -				popts->memctl_interleaving = 0; -				printf("hwconfig has unrecognized parameter for ctlr_intlv.\n"); -			} -		} +	if (!hwconfig_sub_f("fsl_ddr", "ctlr_intlv", buf)) +		goto done; + +	if (pdimm[0].n_ranks == 0) { +		printf("There is no rank on CS0 for controller %d.\n", ctrl_num); +		popts->memctl_interleaving = 0; +		goto done; +	} +	popts->memctl_interleaving = 1; +	/* +	 * test null first. if CONFIG_HWCONFIG is not defined +	 * hwconfig_arg_cmp returns non-zero +	 */ +	if (hwconfig_subarg_cmp_f("fsl_ddr", "ctlr_intlv", +				    "null", buf)) { +		popts->memctl_interleaving = 0; +		debug("memory controller interleaving disabled.\n"); +	} else if (hwconfig_subarg_cmp_f("fsl_ddr", +					"ctlr_intlv", +					"cacheline", buf)) { +		popts->memctl_interleaving_mode = +			((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ? +			0 : FSL_DDR_CACHE_LINE_INTERLEAVING; +		popts->memctl_interleaving = +			((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ? +			0 : 1; +	} else if (hwconfig_subarg_cmp_f("fsl_ddr", +					"ctlr_intlv", +					"page", buf)) { +		popts->memctl_interleaving_mode = +			((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ? +			0 : FSL_DDR_PAGE_INTERLEAVING; +		popts->memctl_interleaving = +			((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ? +			0 : 1; +	} else if (hwconfig_subarg_cmp_f("fsl_ddr", +					"ctlr_intlv", +					"bank", buf)) { +		popts->memctl_interleaving_mode = +			((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ? +			0 : FSL_DDR_BANK_INTERLEAVING; +		popts->memctl_interleaving = +			((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ? +			0 : 1; +	} else if (hwconfig_subarg_cmp_f("fsl_ddr", +					"ctlr_intlv", +					"superbank", buf)) { +		popts->memctl_interleaving_mode = +			((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ? +			0 : FSL_DDR_SUPERBANK_INTERLEAVING; +		popts->memctl_interleaving = +			((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ? +			0 : 1; +#if (CONFIG_NUM_DDR_CONTROLLERS == 3) +	} else if (hwconfig_subarg_cmp_f("fsl_ddr", +					"ctlr_intlv", +					"3way_1KB", buf)) { +		popts->memctl_interleaving_mode = +			FSL_DDR_3WAY_1KB_INTERLEAVING; +	} else if (hwconfig_subarg_cmp_f("fsl_ddr", +					"ctlr_intlv", +					"3way_4KB", buf)) { +		popts->memctl_interleaving_mode = +			FSL_DDR_3WAY_4KB_INTERLEAVING; +	} else if (hwconfig_subarg_cmp_f("fsl_ddr", +					"ctlr_intlv", +					"3way_8KB", buf)) { +		popts->memctl_interleaving_mode = +			FSL_DDR_3WAY_8KB_INTERLEAVING; +#elif (CONFIG_NUM_DDR_CONTROLLERS == 4) +	} else if (hwconfig_subarg_cmp_f("fsl_ddr", +					"ctlr_intlv", +					"4way_1KB", buf)) { +		popts->memctl_interleaving_mode = +			FSL_DDR_4WAY_1KB_INTERLEAVING; +	} else if (hwconfig_subarg_cmp_f("fsl_ddr", +					"ctlr_intlv", +					"4way_4KB", buf)) { +		popts->memctl_interleaving_mode = +			FSL_DDR_4WAY_4KB_INTERLEAVING; +	} else if (hwconfig_subarg_cmp_f("fsl_ddr", +					"ctlr_intlv", +					"4way_8KB", buf)) { +		popts->memctl_interleaving_mode = +			FSL_DDR_4WAY_8KB_INTERLEAVING; +#endif +	} else { +		popts->memctl_interleaving = 0; +		printf("hwconfig has unrecognized parameter for ctlr_intlv.\n");  	} +done:  #endif  	if ((hwconfig_sub_f("fsl_ddr", "bank_intlv", buf)) &&  		(CONFIG_CHIP_SELECTS_PER_CTRL > 1)) { @@ -859,20 +909,20 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,  				popts->ba_intlv_ctl = 0;  				printf("Not enough bank(chip-select) for "  					"CS0+CS1+CS2+CS3 on controller %d, " -					"force non-interleaving!\n", ctrl_num); +					"interleaving disabled!\n", ctrl_num);  			}  #elif (CONFIG_DIMM_SLOTS_PER_CTLR == 2)  			if ((pdimm[0].n_ranks < 2) && (pdimm[1].n_ranks < 2)) {  				popts->ba_intlv_ctl = 0;  				printf("Not enough bank(chip-select) for "  					"CS0+CS1+CS2+CS3 on controller %d, " -					"force non-interleaving!\n", ctrl_num); +					"interleaving disabled!\n", ctrl_num);  			}  			if (pdimm[0].capacity != pdimm[1].capacity) {  				popts->ba_intlv_ctl = 0;  				printf("Not identical DIMM size for "  					"CS0+CS1+CS2+CS3 on controller %d, " -					"force non-interleaving!\n", ctrl_num); +					"interleaving disabled!\n", ctrl_num);  			}  #endif  			break; @@ -881,7 +931,7 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,  				popts->ba_intlv_ctl = 0;  				printf("Not enough bank(chip-select) for "  					"CS0+CS1 on controller %d, " -					"force non-interleaving!\n", ctrl_num); +					"interleaving disabled!\n", ctrl_num);  			}  			break;  		case FSL_DDR_CS2_CS3: @@ -889,13 +939,13 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,  			if (pdimm[0].n_ranks < 4) {  				popts->ba_intlv_ctl = 0;  				printf("Not enough bank(chip-select) for CS2+CS3 " -					"on controller %d, force non-interleaving!\n", ctrl_num); +					"on controller %d, interleaving disabled!\n", ctrl_num);  			}  #elif (CONFIG_DIMM_SLOTS_PER_CTLR == 2)  			if (pdimm[1].n_ranks < 2) {  				popts->ba_intlv_ctl = 0;  				printf("Not enough bank(chip-select) for CS2+CS3 " -					"on controller %d, force non-interleaving!\n", ctrl_num); +					"on controller %d, interleaving disabled!\n", ctrl_num);  			}  #endif  			break; @@ -905,14 +955,14 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,  				popts->ba_intlv_ctl = 0;  				printf("Not enough bank(CS) for CS0+CS1 and "  					"CS2+CS3 on controller %d, " -					"force non-interleaving!\n", ctrl_num); +					"interleaving disabled!\n", ctrl_num);  			}  #elif (CONFIG_DIMM_SLOTS_PER_CTLR == 2)  			if ((pdimm[0].n_ranks < 2) || (pdimm[1].n_ranks < 2)) {  				popts->ba_intlv_ctl = 0;  				printf("Not enough bank(CS) for CS0+CS1 and "  					"CS2+CS3 on controller %d, " -					"force non-interleaving!\n", ctrl_num); +					"interleaving disabled!\n", ctrl_num);  			}  #endif  			break; @@ -954,33 +1004,73 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,  void check_interleaving_options(fsl_ddr_info_t *pinfo)  { -	int i, j, check_n_ranks, intlv_fixed = 0; +	int i, j, k, check_n_ranks, intlv_invalid = 0; +	unsigned int check_intlv, check_n_row_addr, check_n_col_addr;  	unsigned long long check_rank_density; +	struct dimm_params_s *dimm;  	/*  	 * Check if all controllers are configured for memory  	 * controller interleaving. Identical dimms are recommended. At least -	 * the size should be checked. +	 * the size, row and col address should be checked.  	 */  	j = 0;  	check_n_ranks = pinfo->dimm_params[0][0].n_ranks;  	check_rank_density = pinfo->dimm_params[0][0].rank_density; +	check_n_row_addr =  pinfo->dimm_params[0][0].n_row_addr; +	check_n_col_addr = pinfo->dimm_params[0][0].n_col_addr; +	check_intlv = pinfo->memctl_opts[0].memctl_interleaving_mode;  	for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { -		if ((pinfo->memctl_opts[i].memctl_interleaving) && \ -		    (check_rank_density == pinfo->dimm_params[i][0].rank_density) && \ -		    (check_n_ranks == pinfo->dimm_params[i][0].n_ranks)) { +		dimm = &pinfo->dimm_params[i][0]; +		if (!pinfo->memctl_opts[i].memctl_interleaving) { +			continue; +		} else if (((check_rank_density != dimm->rank_density) || +		     (check_n_ranks != dimm->n_ranks) || +		     (check_n_row_addr != dimm->n_row_addr) || +		     (check_n_col_addr != dimm->n_col_addr) || +		     (check_intlv != +			pinfo->memctl_opts[i].memctl_interleaving_mode))){ +			intlv_invalid = 1; +			break; +		} else {  			j++;  		} +  	} -	if (j != CONFIG_NUM_DDR_CONTROLLERS) { +	if (intlv_invalid) {  		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) -			if (pinfo->memctl_opts[i].memctl_interleaving) { +			pinfo->memctl_opts[i].memctl_interleaving = 0; +		printf("Not all DIMMs are identical. " +			"Memory controller interleaving disabled.\n"); +	} else { +		switch (check_intlv) { +		case FSL_DDR_CACHE_LINE_INTERLEAVING: +		case FSL_DDR_PAGE_INTERLEAVING: +		case FSL_DDR_BANK_INTERLEAVING: +		case FSL_DDR_SUPERBANK_INTERLEAVING: +			if (3 == CONFIG_NUM_DDR_CONTROLLERS) +				k = 2; +			else +				k = CONFIG_NUM_DDR_CONTROLLERS; +			break; +		case FSL_DDR_3WAY_1KB_INTERLEAVING: +		case FSL_DDR_3WAY_4KB_INTERLEAVING: +		case FSL_DDR_3WAY_8KB_INTERLEAVING: +		case FSL_DDR_4WAY_1KB_INTERLEAVING: +		case FSL_DDR_4WAY_4KB_INTERLEAVING: +		case FSL_DDR_4WAY_8KB_INTERLEAVING: +		default: +			k = CONFIG_NUM_DDR_CONTROLLERS; +			break; +		} +		debug("%d of %d controllers are interleaving.\n", j, k); +		if (j != k) { +			for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++)  				pinfo->memctl_opts[i].memctl_interleaving = 0; -				intlv_fixed = 1; -			} -		if (intlv_fixed) -			printf("Not all DIMMs are identical in size. " -				"Memory controller interleaving disabled.\n"); +			printf("Not all controllers have compatible " +				"interleaving mode. All disabled.\n"); +		}  	} +	debug("Checking interleaving options completed\n");  }  int fsl_use_spd(void) diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/util.c b/arch/powerpc/cpu/mpc8xxx/ddr/util.c index eb6a17a85..664ad0929 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/util.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/util.c @@ -1,5 +1,5 @@  /* - * Copyright 2008-2011 Freescale Semiconductor, Inc. + * Copyright 2008-2012 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 @@ -79,7 +79,7 @@ unsigned int mclk_to_picos(unsigned int mclk)  void  __fsl_ddr_set_lawbar(const common_timing_params_t *memctl_common_params, -			   unsigned int memctl_interleaved, +			   unsigned int law_memctl,  			   unsigned int ctrl_num)  {  	unsigned long long base = memctl_common_params->base_address; @@ -98,28 +98,13 @@ __fsl_ddr_set_lawbar(const common_timing_params_t *memctl_common_params,  	if ((base + size) >= CONFIG_MAX_MEM_MAPPED)  		size = CONFIG_MAX_MEM_MAPPED - base;  #endif - -	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(base, size, lawbar1_target_id) < 0) { -			printf("%s: ERROR (ctrl #0, intrlv=%d)\n", __func__, -				memctl_interleaved); -			return ; -		} -	} else if (ctrl_num == 1) { -		if (set_ddr_laws(base, size, LAW_TRGT_IF_DDR_2) < 0) { -			printf("%s: ERROR (ctrl #1)\n", __func__); -			return ; -		} -	} else { -		printf("%s: unexpected DDR controller number (%u)\n", __func__, -			ctrl_num); +	if (set_ddr_laws(base, size, law_memctl) < 0) { +		printf("%s: ERROR (ctrl #%d, TRGT ID=%x)\n", __func__, ctrl_num, +			law_memctl); +		return ;  	} +	debug("setup ddr law base = 0x%llx, size 0x%llx, TRGT_ID 0x%x\n", +		base, size, law_memctl);  }  __attribute__((weak, alias("__fsl_ddr_set_lawbar"))) void @@ -127,6 +112,15 @@ fsl_ddr_set_lawbar(const common_timing_params_t *memctl_common_params,  			 unsigned int memctl_interleaved,  			 unsigned int ctrl_num); +void fsl_ddr_set_intl3r(const unsigned int granule_size) +{ +#ifdef CONFIG_E6500 +	u32 *mcintl3r = (void *) (CONFIG_SYS_IMMR + 0x18004); +	*mcintl3r = 0x80000000 | (granule_size & 0x1f); +	debug("Enable MCINTL3R with granule size 0x%x\n", granule_size); +#endif +} +  void board_add_ram_info(int use_default)  {  #if defined(CONFIG_MPC83xx) @@ -137,6 +131,9 @@ void board_add_ram_info(int use_default)  #elif defined(CONFIG_MPC86xx)  	ccsr_ddr_t *ddr = (void *)(CONFIG_SYS_MPC86xx_DDR_ADDR);  #endif +#if	defined(CONFIG_E6500) && (CONFIG_NUM_DDR_CONTROLLERS == 3) +	u32 *mcintl3r = (void *) (CONFIG_SYS_IMMR + 0x18004); +#endif  #if (CONFIG_NUM_DDR_CONTROLLERS > 1)  	uint32_t cs0_config = in_be32(&ddr->cs0_config);  #endif @@ -180,7 +177,29 @@ void board_add_ram_info(int use_default)  	else  		puts(", ECC off)"); -#if (CONFIG_NUM_DDR_CONTROLLERS > 1) +#if (CONFIG_NUM_DDR_CONTROLLERS == 3) +#ifdef CONFIG_E6500 +	if (*mcintl3r & 0x80000000) { +		puts("\n"); +		puts("       DDR Controller Interleaving Mode: "); +		switch (*mcintl3r & 0x1f) { +		case FSL_DDR_3WAY_1KB_INTERLEAVING: +			puts("3-way 1KB"); +			break; +		case FSL_DDR_3WAY_4KB_INTERLEAVING: +			puts("3-way 4KB"); +			break; +		case FSL_DDR_3WAY_8KB_INTERLEAVING: +			puts("3-way 8KB"); +			break; +		default: +			puts("3-way UNKNOWN"); +			break; +		} +	} +#endif +#endif +#if (CONFIG_NUM_DDR_CONTROLLERS >= 2)  	if (cs0_config & 0x20000000) {  		puts("\n");  		puts("       DDR Controller Interleaving Mode: "); |