diff options
Diffstat (limited to 'arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c')
| -rw-r--r-- | arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c | 111 | 
1 files changed, 73 insertions, 38 deletions
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c index 4a282bc52..69c1c7cb8 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c @@ -1201,20 +1201,28 @@ 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 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; -		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. +		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(i, ddr, popts, dimm_params); -			break; +			continue;  		} - -		if (dimm_params[i/2].n_ranks == 0) { +		if (dimm_params[dimm_number].n_ranks == 0) {  			debug("Skipping setup of CS%u "  				"because n_ranks on DIMM %u is 0\n", i, i/2);  			continue; @@ -1222,16 +1230,34 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,  		if (popts->memctl_interleaving && popts->ba_intlv_ctl) {  			/*  			 * This works superbank 2CS -			 * There are 2 memory controllers configured +			 * 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.  			 */ -			unsigned long long rank_density -					= dimm_params[0].capacity; -			ea = (2 * (rank_density >> dbw_cap_adj)) - 1; +			unsigned long long ctlr_density = 0; +			switch (popts->ba_intlv_ctl & FSL_DDR_CS0_CS1_CS2_CS3) { +			case FSL_DDR_CS0_CS1: +			case FSL_DDR_CS0_CS1_AND_CS2_CS3: +				ctlr_density = dimm_params[0].rank_density * 2; +				break; +			case FSL_DDR_CS2_CS3: +				ctlr_density = dimm_params[0].rank_density; +				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) {  			/* @@ -1243,8 +1269,6 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,  			 * controller needs to be programmed into its  			 * respective CS0_BNDS.  			 */ -			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 @@ -1257,9 +1281,13 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,  				/* 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 >> +				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; +				} else { +					sa = dimm_params[dimm_number].base_address; +					ea = sa + (2 * (rank_density >>  						dbw_cap_adj)) - 1;  				}  				break; @@ -1267,16 +1295,31 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,  				/* CS0+CS1 interleaving, CS0_CNDS needs  				 * to be set  				 */ -				sa = common_dimm->base_address; -				ea = sa + (2 * (rank_density >> dbw_cap_adj))-1; +				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); +				} else { +					sa = 0; +					ea = 0; +				} +				if (i == 0) +					ea += (rank_density >> dbw_cap_adj);  				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; +				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); +				} else { +					sa = 0; +					ea = 0;  				} +				if (i == 2) +					ea += (rank_density >> dbw_cap_adj);  				break;  			default:  /* No bank(chip-select) interleaving */  				break; @@ -1292,8 +1335,6 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,  			 * 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;  			} @@ -1303,20 +1344,14 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,  			 * 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; +			sa = dimm_params[dimm_number].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; -				} +			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;  			}  		}  |