diff options
Diffstat (limited to 'arch/powerpc/cpu/mpc8xxx/ddr/main.c')
| -rw-r--r-- | arch/powerpc/cpu/mpc8xxx/ddr/main.c | 307 | 
1 files changed, 173 insertions, 134 deletions
| 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. */ |