nb/intel/ironlake: Split out some QuickPath init code
The platform performs a CPU-only reset after initializing QPI (QuickPath Interconnect) and before actually performing raminit. The state is saved in the sticky scratchpad register at MCHBAR + 0x2ca8. Relocate some QuickPath init to a separate file. All moved functions are only used within QPI init code, and had to be relocated in one commit. Tested on out-of-tree HP 630, still boots. Change-Id: I48e3517285d8fd4b448add131cd8bfb80641e7ef Signed-off-by: Angel Pons <th3fanbus@gmail.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/49582 Reviewed-by: Arthur Heymans <arthur@aheymans.xyz> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
		
				
					committed by
					
						 Patrick Georgi
						Patrick Georgi
					
				
			
			
				
	
			
			
			
						parent
						
							a65ff854cd
						
					
				
				
					commit
					7a87c9203e
				
			| @@ -16,6 +16,7 @@ romstage-y += raminit.c | ||||
| romstage-y += raminit_tables.c | ||||
| romstage-y += early_init.c | ||||
| romstage-y += romstage.c | ||||
| romstage-y += quickpath.c | ||||
|  | ||||
| smm-y += finalize.c | ||||
|  | ||||
|   | ||||
							
								
								
									
										660
									
								
								src/northbridge/intel/ironlake/quickpath.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										660
									
								
								src/northbridge/intel/ironlake/quickpath.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,660 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||||
|  | ||||
| #include <console/console.h> | ||||
| #include <delay.h> | ||||
| #include <device/pci_def.h> | ||||
| #include <device/pci_ops.h> | ||||
| #include <northbridge/intel/ironlake/raminit.h> | ||||
| #include <types.h> | ||||
|  | ||||
| #define NORTHBRIDGE PCI_DEV(0, 0, 0) | ||||
|  | ||||
| static unsigned int gcd(unsigned int a, unsigned int b) | ||||
| { | ||||
| 	unsigned int t; | ||||
| 	if (a > b) { | ||||
| 		t = a; | ||||
| 		a = b; | ||||
| 		b = t; | ||||
| 	} | ||||
| 	/* invariant a < b.  */ | ||||
| 	while (a) { | ||||
| 		t = b % a; | ||||
| 		b = a; | ||||
| 		a = t; | ||||
| 	} | ||||
| 	return b; | ||||
| } | ||||
|  | ||||
| static inline int div_roundup(int a, int b) | ||||
| { | ||||
| 	return DIV_ROUND_UP(a, b); | ||||
| } | ||||
|  | ||||
| static unsigned int lcm(unsigned int a, unsigned int b) | ||||
| { | ||||
| 	return (a * b) / gcd(a, b); | ||||
| } | ||||
|  | ||||
| struct stru1 { | ||||
| 	u8 freqs_reversed; | ||||
| 	u8 freq_diff_reduced; | ||||
| 	u8 freq_min_reduced; | ||||
| 	u8 divisor_f4_to_fmax; | ||||
| 	u8 divisor_f3_to_fmax; | ||||
| 	u8 freq4_to_max_remainder; | ||||
| 	u8 freq3_to_2_remainder; | ||||
| 	u8 freq3_to_2_remaindera; | ||||
| 	u8 freq4_to_2_remainder; | ||||
| 	int divisor_f3_to_f1, divisor_f4_to_f2; | ||||
| 	int common_time_unit_ps; | ||||
| 	int freq_max_reduced; | ||||
| }; | ||||
|  | ||||
| static void | ||||
| compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2, | ||||
| 			 int num_cycles_2, int num_cycles_1, int round_it, | ||||
| 			 int add_freqs, struct stru1 *result) | ||||
| { | ||||
| 	int g; | ||||
| 	int common_time_unit_ps; | ||||
| 	int freq1_reduced, freq2_reduced; | ||||
| 	int freq_min_reduced; | ||||
| 	int freq_max_reduced; | ||||
| 	int freq3, freq4; | ||||
|  | ||||
| 	g = gcd(freq1, freq2); | ||||
| 	freq1_reduced = freq1 / g; | ||||
| 	freq2_reduced = freq2 / g; | ||||
| 	freq_min_reduced = MIN(freq1_reduced, freq2_reduced); | ||||
| 	freq_max_reduced = MAX(freq1_reduced, freq2_reduced); | ||||
|  | ||||
| 	common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2)); | ||||
| 	freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1; | ||||
| 	freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1; | ||||
| 	if (add_freqs) { | ||||
| 		freq3 += freq2_reduced; | ||||
| 		freq4 += freq1_reduced; | ||||
| 	} | ||||
|  | ||||
| 	if (round_it) { | ||||
| 		result->freq3_to_2_remainder = 0; | ||||
| 		result->freq3_to_2_remaindera = 0; | ||||
| 		result->freq4_to_max_remainder = 0; | ||||
| 		result->divisor_f4_to_f2 = 0; | ||||
| 		result->divisor_f3_to_f1 = 0; | ||||
| 	} else { | ||||
| 		if (freq2_reduced < freq1_reduced) { | ||||
| 			result->freq3_to_2_remainder = | ||||
| 			    result->freq3_to_2_remaindera = | ||||
| 			    freq3 % freq1_reduced - freq1_reduced + 1; | ||||
| 			result->freq4_to_max_remainder = | ||||
| 			    -(freq4 % freq1_reduced); | ||||
| 			result->divisor_f3_to_f1 = freq3 / freq1_reduced; | ||||
| 			result->divisor_f4_to_f2 = | ||||
| 			    (freq4 - | ||||
| 			     (freq1_reduced - freq2_reduced)) / freq2_reduced; | ||||
| 			result->freq4_to_2_remainder = | ||||
| 			    -(char)((freq1_reduced - freq2_reduced) + | ||||
| 				    ((u8) freq4 - | ||||
| 				     (freq1_reduced - | ||||
| 				      freq2_reduced)) % (u8) freq2_reduced); | ||||
| 		} else { | ||||
| 			if (freq2_reduced > freq1_reduced) { | ||||
| 				result->freq4_to_max_remainder = | ||||
| 				    (freq4 % freq2_reduced) - freq2_reduced + 1; | ||||
| 				result->freq4_to_2_remainder = | ||||
| 				    freq4 % freq_max_reduced - | ||||
| 				    freq_max_reduced + 1; | ||||
| 			} else { | ||||
| 				result->freq4_to_max_remainder = | ||||
| 				    -(freq4 % freq2_reduced); | ||||
| 				result->freq4_to_2_remainder = | ||||
| 				    -(char)(freq4 % freq_max_reduced); | ||||
| 			} | ||||
| 			result->divisor_f4_to_f2 = freq4 / freq2_reduced; | ||||
| 			result->divisor_f3_to_f1 = | ||||
| 			    (freq3 - | ||||
| 			     (freq2_reduced - freq1_reduced)) / freq1_reduced; | ||||
| 			result->freq3_to_2_remainder = -(freq3 % freq2_reduced); | ||||
| 			result->freq3_to_2_remaindera = | ||||
| 			    -(char)((freq_max_reduced - freq_min_reduced) + | ||||
| 				    (freq3 - | ||||
| 				     (freq_max_reduced - | ||||
| 				      freq_min_reduced)) % freq1_reduced); | ||||
| 		} | ||||
| 	} | ||||
| 	result->divisor_f3_to_fmax = freq3 / freq_max_reduced; | ||||
| 	result->divisor_f4_to_fmax = freq4 / freq_max_reduced; | ||||
| 	if (round_it) { | ||||
| 		if (freq2_reduced > freq1_reduced) { | ||||
| 			if (freq3 % freq_max_reduced) | ||||
| 				result->divisor_f3_to_fmax++; | ||||
| 		} | ||||
| 		if (freq2_reduced < freq1_reduced) { | ||||
| 			if (freq4 % freq_max_reduced) | ||||
| 				result->divisor_f4_to_fmax++; | ||||
| 		} | ||||
| 	} | ||||
| 	result->freqs_reversed = (freq2_reduced < freq1_reduced); | ||||
| 	result->freq_diff_reduced = freq_max_reduced - freq_min_reduced; | ||||
| 	result->freq_min_reduced = freq_min_reduced; | ||||
| 	result->common_time_unit_ps = common_time_unit_ps; | ||||
| 	result->freq_max_reduced = freq_max_reduced; | ||||
| } | ||||
|  | ||||
| static void set_274265(struct raminfo *info) | ||||
| { | ||||
| 	int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps; | ||||
| 	int delay_e_ps, delay_e_cycles, delay_f_cycles; | ||||
| 	int delay_e_over_cycle_ps; | ||||
| 	int cycletime_ps; | ||||
| 	int channel; | ||||
|  | ||||
| 	delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info); | ||||
| 	info->training.reg2ca9_bit0 = 0; | ||||
| 	for (channel = 0; channel < NUM_CHANNELS; channel++) { | ||||
| 		cycletime_ps = | ||||
| 		    900000 / lcm(2 * info->fsb_frequency, frequency_11(info)); | ||||
| 		delay_d_ps = | ||||
| 		    (halfcycle_ps(info) * get_max_timing(info, channel) >> 6) | ||||
| 		    - info->some_delay_3_ps_rounded + 200; | ||||
| 		if (! | ||||
| 		    ((info->silicon_revision == 0 | ||||
| 		      || info->silicon_revision == 1) | ||||
| 		     && (info->revision >= 8))) | ||||
| 			delay_d_ps += halfcycle_ps(info) * 2; | ||||
| 		delay_d_ps += | ||||
| 		    halfcycle_ps(info) * (!info->revision_flag_1 + | ||||
| 					  info->some_delay_2_halfcycles_ceil + | ||||
| 					  2 * info->some_delay_1_cycle_floor + | ||||
| 					  info->clock_speed_index + | ||||
| 					  2 * info->cas_latency - 7 + 11); | ||||
| 		delay_d_ps += info->revision >= 8 ? 2758 : 4428; | ||||
|  | ||||
| 		MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000); | ||||
| 		MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000); | ||||
| 		if ((MCHBAR8(0x144) & 0x1f) > 0x13) | ||||
| 			delay_d_ps += 650; | ||||
| 		delay_c_ps = delay_d_ps + 1800; | ||||
| 		if (delay_c_ps <= delay_a_ps) | ||||
| 			delay_e_ps = 0; | ||||
| 		else | ||||
| 			delay_e_ps = | ||||
| 			    cycletime_ps * div_roundup(delay_c_ps - delay_a_ps, | ||||
| 						       cycletime_ps); | ||||
|  | ||||
| 		delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info)); | ||||
| 		delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info)); | ||||
| 		delay_f_cycles = | ||||
| 		    div_roundup(2500 - delay_e_over_cycle_ps, | ||||
| 				2 * halfcycle_ps(info)); | ||||
| 		if (delay_f_cycles > delay_e_cycles) { | ||||
| 			info->delay46_ps[channel] = delay_e_ps; | ||||
| 			delay_e_cycles = 0; | ||||
| 		} else { | ||||
| 			info->delay46_ps[channel] = | ||||
| 			    delay_e_over_cycle_ps + | ||||
| 			    2 * halfcycle_ps(info) * delay_f_cycles; | ||||
| 			delay_e_cycles -= delay_f_cycles; | ||||
| 		} | ||||
|  | ||||
| 		if (info->delay46_ps[channel] < 2500) { | ||||
| 			info->delay46_ps[channel] = 2500; | ||||
| 			info->training.reg2ca9_bit0 = 1; | ||||
| 		} | ||||
| 		delay_b_ps = halfcycle_ps(info) + delay_c_ps; | ||||
| 		if (delay_b_ps <= delay_a_ps) | ||||
| 			delay_b_ps = 0; | ||||
| 		else | ||||
| 			delay_b_ps -= delay_a_ps; | ||||
| 		info->delay54_ps[channel] = | ||||
| 		    cycletime_ps * div_roundup(delay_b_ps, | ||||
| 					       cycletime_ps) - | ||||
| 		    2 * halfcycle_ps(info) * delay_e_cycles; | ||||
| 		if (info->delay54_ps[channel] < 2500) | ||||
| 			info->delay54_ps[channel] = 2500; | ||||
| 		info->training.reg274265[channel][0] = delay_e_cycles; | ||||
| 		if (delay_d_ps + 7 * halfcycle_ps(info) <= | ||||
| 		    24 * halfcycle_ps(info)) | ||||
| 			info->training.reg274265[channel][1] = 0; | ||||
| 		else | ||||
| 			info->training.reg274265[channel][1] = | ||||
| 				div_roundup(delay_d_ps + 7 * halfcycle_ps(info), | ||||
| 				4 * halfcycle_ps(info)) - 6; | ||||
| 		MCHBAR32((channel << 10) + 0x274) = | ||||
| 			info->training.reg274265[channel][1] | | ||||
| 			(info->training.reg274265[channel][0] << 16); | ||||
| 		info->training.reg274265[channel][2] = | ||||
| 			div_roundup(delay_c_ps + 3 * fsbcycle_ps(info), | ||||
| 			4 * halfcycle_ps(info)) + 1; | ||||
| 		MCHBAR16((channel << 10) + 0x265) = | ||||
| 			info->training.reg274265[channel][2] << 8; | ||||
| 	} | ||||
| 	if (info->training.reg2ca9_bit0) | ||||
| 		MCHBAR8_OR(0x2ca9, 1); | ||||
| 	else | ||||
| 		MCHBAR8_AND(0x2ca9, ~1); | ||||
| } | ||||
|  | ||||
| static void restore_274265(struct raminfo *info) | ||||
| { | ||||
| 	int channel; | ||||
|  | ||||
| 	for (channel = 0; channel < NUM_CHANNELS; channel++) { | ||||
| 		MCHBAR32((channel << 10) + 0x274) = | ||||
| 			(info->cached_training->reg274265[channel][0] << 16) | | ||||
| 			info->cached_training->reg274265[channel][1]; | ||||
| 		MCHBAR16((channel << 10) + 0x265) = | ||||
| 			info->cached_training->reg274265[channel][2] << 8; | ||||
| 	} | ||||
| 	if (info->cached_training->reg2ca9_bit0) | ||||
| 		MCHBAR8_OR(0x2ca9, 1); | ||||
| 	else | ||||
| 		MCHBAR8_AND(0x2ca9, ~1); | ||||
| } | ||||
|  | ||||
| static void | ||||
| set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2, | ||||
| 	     int num_cycles_2, int num_cycles_1, int num_cycles_3, | ||||
| 	     int num_cycles_4, int reverse) | ||||
| { | ||||
| 	struct stru1 vv; | ||||
| 	char multiplier; | ||||
|  | ||||
| 	compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1, | ||||
| 				 0, 1, &vv); | ||||
|  | ||||
| 	multiplier = | ||||
| 	    div_roundup(MAX | ||||
| 			(div_roundup(num_cycles_2, vv.common_time_unit_ps) + | ||||
| 			 div_roundup(num_cycles_3, vv.common_time_unit_ps), | ||||
| 			 div_roundup(num_cycles_1, | ||||
| 				     vv.common_time_unit_ps) + | ||||
| 			 div_roundup(num_cycles_4, vv.common_time_unit_ps)) | ||||
| 			+ vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1; | ||||
|  | ||||
| 	u32 y = | ||||
| 	    (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) + | ||||
| 		  vv.freq_max_reduced * multiplier) | ||||
| 	    | (vv. | ||||
| 	       freqs_reversed << 8) | ((u8) (vv.freq_min_reduced * | ||||
| 					     multiplier) << 16) | ((u8) (vv. | ||||
| 									 freq_min_reduced | ||||
| 									 * | ||||
| 									 multiplier) | ||||
| 								   << 24); | ||||
| 	u32 x = | ||||
| 	    vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv. | ||||
| 									 divisor_f3_to_f1 | ||||
| 									 << 16) | ||||
| 	    | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24); | ||||
| 	if (reverse) { | ||||
| 		MCHBAR32(reg) = y; | ||||
| 		MCHBAR32(reg + 4) = x; | ||||
| 	} else { | ||||
| 		MCHBAR32(reg + 4) = y; | ||||
| 		MCHBAR32(reg) = x; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void | ||||
| set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2, | ||||
| 	   int num_cycles_1, int num_cycles_2, int num_cycles_3, | ||||
| 	   int num_cycles_4) | ||||
| { | ||||
| 	struct stru1 ratios1; | ||||
| 	struct stru1 ratios2; | ||||
|  | ||||
| 	compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2, | ||||
| 				 0, 1, &ratios2); | ||||
| 	compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4, | ||||
| 				 0, 1, &ratios1); | ||||
| 	printk(RAM_SPEW, "[%x] <= %x\n", reg, | ||||
| 		       ratios1.freq4_to_max_remainder | (ratios2. | ||||
| 							 freq4_to_max_remainder | ||||
| 							 << 8) | ||||
| 		       | (ratios1.divisor_f4_to_fmax << 16) | (ratios2. | ||||
| 							       divisor_f4_to_fmax | ||||
| 							       << 20)); | ||||
| 	MCHBAR32(reg) = ratios1.freq4_to_max_remainder | | ||||
| 		(ratios2.freq4_to_max_remainder << 8) | | ||||
| 		(ratios1.divisor_f4_to_fmax << 16) | | ||||
| 		(ratios2.divisor_f4_to_fmax << 20); | ||||
| } | ||||
|  | ||||
| static void | ||||
| set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2, | ||||
| 	     int num_cycles_2, int num_cycles_1, int round_it, int add_freqs) | ||||
| { | ||||
| 	struct stru1 ratios; | ||||
|  | ||||
| 	compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1, | ||||
| 				 round_it, add_freqs, &ratios); | ||||
| 	switch (mode) { | ||||
| 	case 0: | ||||
| 		MCHBAR32(reg + 4) = ratios.freq_diff_reduced | | ||||
| 			(ratios.freqs_reversed << 8); | ||||
| 		MCHBAR32(reg) = ratios.freq3_to_2_remainder | | ||||
| 			(ratios.freq4_to_max_remainder << 8) | | ||||
| 			(ratios.divisor_f3_to_fmax << 16) | | ||||
| 			(ratios.divisor_f4_to_fmax << 20) | | ||||
| 			(ratios.freq_min_reduced << 24); | ||||
| 		break; | ||||
|  | ||||
| 	case 1: | ||||
| 		MCHBAR32(reg) = ratios.freq3_to_2_remainder | | ||||
| 			(ratios.divisor_f3_to_fmax << 16); | ||||
| 		break; | ||||
|  | ||||
| 	case 2: | ||||
| 		MCHBAR32(reg) = ratios.freq3_to_2_remainder | | ||||
| 			(ratios.freq4_to_max_remainder << 8) | | ||||
| 			(ratios.divisor_f3_to_fmax << 16) | | ||||
| 			(ratios.divisor_f4_to_fmax << 20); | ||||
| 		break; | ||||
|  | ||||
| 	case 4: | ||||
| 		MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) | | ||||
| 			(ratios.divisor_f4_to_fmax << 8) | | ||||
| 			(ratios.freqs_reversed << 12) | | ||||
| 			(ratios.freq_min_reduced << 16) | | ||||
| 			(ratios.freq_diff_reduced << 24); | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void set_2dxx_series(struct raminfo *info, int s3resume) | ||||
| { | ||||
| 	set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005, | ||||
| 		     0, 1); | ||||
| 	set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1); | ||||
| 	set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0, | ||||
| 		     1); | ||||
| 	set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency, | ||||
| 		     frequency_11(info), 1231, 1524, 0, 1); | ||||
| 	set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency, | ||||
| 		     frequency_11(info) / 2, 1278, 2008, 0, 1); | ||||
| 	set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info), | ||||
| 		     1167, 1539, 0, 1); | ||||
| 	set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency, | ||||
| 		     frequency_11(info) / 2, 1403, 1318, 0, 1); | ||||
| 	set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1, | ||||
| 		     1); | ||||
| 	set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1, | ||||
| 		     1); | ||||
| 	set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610, | ||||
| 		     1, 1); | ||||
| 	set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1, | ||||
| 		     1); | ||||
| 	set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency, | ||||
| 		     frequency_11(info) / 2, 4000, 0, 0, 0); | ||||
| 	set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency, | ||||
| 		     frequency_11(info) / 2, 4000, 4000, 0, 0); | ||||
|  | ||||
| 	if (s3resume) { | ||||
| 		printk(RAM_SPEW, "[6dc] <= %x\n", | ||||
| 			info->cached_training->reg_6dc); | ||||
| 		MCHBAR32(0x6dc) = info->cached_training->reg_6dc; | ||||
| 	} else | ||||
| 		set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0, | ||||
| 			   info->delay46_ps[0], 0, | ||||
| 			   info->delay54_ps[0]); | ||||
| 	set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency, | ||||
| 		     frequency_11(info), 2500, 0, 0, 0); | ||||
| 	set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency, | ||||
| 		     frequency_11(info) / 2, 3500, 0, 0, 0); | ||||
| 	if (s3resume) { | ||||
| 		printk(RAM_SPEW, "[6e8] <= %x\n", | ||||
| 			info->cached_training->reg_6e8); | ||||
| 		MCHBAR32(0x6e8) = info->cached_training->reg_6e8; | ||||
| 	} else | ||||
| 		set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0, | ||||
| 			   info->delay46_ps[1], 0, | ||||
| 			   info->delay54_ps[1]); | ||||
| 	set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0); | ||||
| 	set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455, | ||||
| 		     470, 0); | ||||
| 	set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0); | ||||
| 	set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758, | ||||
| 		     454, 459, 0); | ||||
| 	set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0); | ||||
| 	set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579, | ||||
| 		     2588, 0); | ||||
| 	set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405, | ||||
| 		     2405, 0); | ||||
| 	set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0); | ||||
| 	set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484, | ||||
| 		     480, 0); | ||||
| 	set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0); | ||||
| 	MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000; | ||||
| 	MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77; | ||||
| } | ||||
|  | ||||
| void late_quickpath_init(struct raminfo *info, const int s3resume) | ||||
| { | ||||
| 	const u16 deven = pci_read_config16(NORTHBRIDGE, DEVEN); | ||||
|  | ||||
| 	int i, j; | ||||
| 	if (s3resume && info->cached_training) { | ||||
| 		restore_274265(info); | ||||
| 		printk(RAM_SPEW, "reg2ca9_bit0 = %x\n", | ||||
| 		       info->cached_training->reg2ca9_bit0); | ||||
| 		for (i = 0; i < 2; i++) | ||||
| 			for (j = 0; j < 3; j++) | ||||
| 				printk(RAM_SPEW, "reg274265[%d][%d] = %x\n", | ||||
| 				       i, j, info->cached_training->reg274265[i][j]); | ||||
| 	} else { | ||||
| 		set_274265(info); | ||||
| 		printk(RAM_SPEW, "reg2ca9_bit0 = %x\n", | ||||
| 		       info->training.reg2ca9_bit0); | ||||
| 		for (i = 0; i < 2; i++) | ||||
| 			for (j = 0; j < 3; j++) | ||||
| 				printk(RAM_SPEW, "reg274265[%d][%d] = %x\n", | ||||
| 				       i, j, info->training.reg274265[i][j]); | ||||
| 	} | ||||
|  | ||||
| 	set_2dxx_series(info, s3resume); | ||||
|  | ||||
| 	if (!(deven & 8)) { | ||||
| 		MCHBAR32_AND_OR(0x2cb0, 0, 0x40); | ||||
| 	} | ||||
|  | ||||
| 	udelay(1000); | ||||
|  | ||||
| 	if (deven & 8) { | ||||
| 		MCHBAR32_OR(0xff8, 0x1800); | ||||
| 		MCHBAR32_AND(0x2cb0, 0x00); | ||||
| 		pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c); | ||||
| 		pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c); | ||||
| 		pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e); | ||||
|  | ||||
| 		MCHBAR8(0x1150); | ||||
| 		MCHBAR8(0x1151); | ||||
| 		MCHBAR8(0x1022); | ||||
| 		MCHBAR8(0x16d0); | ||||
| 		MCHBAR32(0x1300) = 0x60606060; | ||||
| 		MCHBAR32(0x1304) = 0x60606060; | ||||
| 		MCHBAR32(0x1308) = 0x78797a7b; | ||||
| 		MCHBAR32(0x130c) = 0x7c7d7e7f; | ||||
| 		MCHBAR32(0x1310) = 0x60606060; | ||||
| 		MCHBAR32(0x1314) = 0x60606060; | ||||
| 		MCHBAR32(0x1318) = 0x60606060; | ||||
| 		MCHBAR32(0x131c) = 0x60606060; | ||||
| 		MCHBAR32(0x1320) = 0x50515253; | ||||
| 		MCHBAR32(0x1324) = 0x54555657; | ||||
| 		MCHBAR32(0x1328) = 0x58595a5b; | ||||
| 		MCHBAR32(0x132c) = 0x5c5d5e5f; | ||||
| 		MCHBAR32(0x1330) = 0x40414243; | ||||
| 		MCHBAR32(0x1334) = 0x44454647; | ||||
| 		MCHBAR32(0x1338) = 0x48494a4b; | ||||
| 		MCHBAR32(0x133c) = 0x4c4d4e4f; | ||||
| 		MCHBAR32(0x1340) = 0x30313233; | ||||
| 		MCHBAR32(0x1344) = 0x34353637; | ||||
| 		MCHBAR32(0x1348) = 0x38393a3b; | ||||
| 		MCHBAR32(0x134c) = 0x3c3d3e3f; | ||||
| 		MCHBAR32(0x1350) = 0x20212223; | ||||
| 		MCHBAR32(0x1354) = 0x24252627; | ||||
| 		MCHBAR32(0x1358) = 0x28292a2b; | ||||
| 		MCHBAR32(0x135c) = 0x2c2d2e2f; | ||||
| 		MCHBAR32(0x1360) = 0x10111213; | ||||
| 		MCHBAR32(0x1364) = 0x14151617; | ||||
| 		MCHBAR32(0x1368) = 0x18191a1b; | ||||
| 		MCHBAR32(0x136c) = 0x1c1d1e1f; | ||||
| 		MCHBAR32(0x1370) = 0x10203; | ||||
| 		MCHBAR32(0x1374) = 0x4050607; | ||||
| 		MCHBAR32(0x1378) = 0x8090a0b; | ||||
| 		MCHBAR32(0x137c) = 0xc0d0e0f; | ||||
| 		MCHBAR8(0x11cc) = 0x4e; | ||||
| 		MCHBAR32(0x1110) = 0x73970404; | ||||
| 		MCHBAR32(0x1114) = 0x72960404; | ||||
| 		MCHBAR32(0x1118) = 0x6f950404; | ||||
| 		MCHBAR32(0x111c) = 0x6d940404; | ||||
| 		MCHBAR32(0x1120) = 0x6a930404; | ||||
| 		MCHBAR32(0x1124) = 0x68a41404; | ||||
| 		MCHBAR32(0x1128) = 0x66a21404; | ||||
| 		MCHBAR32(0x112c) = 0x63a01404; | ||||
| 		MCHBAR32(0x1130) = 0x609e1404; | ||||
| 		MCHBAR32(0x1134) = 0x5f9c1404; | ||||
| 		MCHBAR32(0x1138) = 0x5c961404; | ||||
| 		MCHBAR32(0x113c) = 0x58a02404; | ||||
| 		MCHBAR32(0x1140) = 0x54942404; | ||||
| 		MCHBAR32(0x1190) = 0x900080a; | ||||
| 		MCHBAR16(0x11c0) = 0xc40b; | ||||
| 		MCHBAR16(0x11c2) = 0x303; | ||||
| 		MCHBAR16(0x11c4) = 0x301; | ||||
| 		MCHBAR32_AND_OR(0x1190, 0, 0x8900080a); | ||||
| 		MCHBAR32(0x11b8) = 0x70c3000; | ||||
| 		MCHBAR8(0x11ec) = 0xa; | ||||
| 		MCHBAR16(0x1100) = 0x800; | ||||
| 		MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800); | ||||
| 		MCHBAR16(0x11ca) = 0xfa; | ||||
| 		MCHBAR32(0x11e4) = 0x4e20; | ||||
| 		MCHBAR8(0x11bc) = 0xf; | ||||
| 		MCHBAR16(0x11da) = 0x19; | ||||
| 		MCHBAR16(0x11ba) = 0x470c; | ||||
| 		MCHBAR32(0x1680) = 0xe6ffe4ff; | ||||
| 		MCHBAR32(0x1684) = 0xdeffdaff; | ||||
| 		MCHBAR32(0x1688) = 0xd4ffd0ff; | ||||
| 		MCHBAR32(0x168c) = 0xccffc6ff; | ||||
| 		MCHBAR32(0x1690) = 0xc0ffbeff; | ||||
| 		MCHBAR32(0x1694) = 0xb8ffb0ff; | ||||
| 		MCHBAR32(0x1698) = 0xa8ff0000; | ||||
| 		MCHBAR32(0x169c) = 0xc00; | ||||
| 		MCHBAR32(0x1290) = 0x5000000; | ||||
| 	} | ||||
|  | ||||
| 	MCHBAR32(0x124c) = 0x15040d00; | ||||
| 	MCHBAR32(0x1250) = 0x7f0000; | ||||
| 	MCHBAR32(0x1254) = 0x1e220004; | ||||
| 	MCHBAR32(0x1258) = 0x4000004; | ||||
| 	MCHBAR32(0x1278) = 0x0; | ||||
| 	MCHBAR32(0x125c) = 0x0; | ||||
| 	MCHBAR32(0x1260) = 0x0; | ||||
| 	MCHBAR32(0x1264) = 0x0; | ||||
| 	MCHBAR32(0x1268) = 0x0; | ||||
| 	MCHBAR32(0x126c) = 0x0; | ||||
| 	MCHBAR32(0x1270) = 0x0; | ||||
| 	MCHBAR32(0x1274) = 0x0; | ||||
|  | ||||
| 	if (deven & 8) { | ||||
| 		MCHBAR16(0x1214) = 0x320; | ||||
| 		MCHBAR32(0x1600) = 0x40000000; | ||||
| 		MCHBAR32_AND_OR(0x11f4, 0, 0x10000000); | ||||
| 		MCHBAR16_AND_OR(0x1230, 0, 0x8000); | ||||
| 		MCHBAR32(0x1400) = 0x13040020; | ||||
| 		MCHBAR32(0x1404) = 0xe090120; | ||||
| 		MCHBAR32(0x1408) = 0x5120220; | ||||
| 		MCHBAR32(0x140c) = 0x5120330; | ||||
| 		MCHBAR32(0x1410) = 0xe090220; | ||||
| 		MCHBAR32(0x1414) = 0x1010001; | ||||
| 		MCHBAR32(0x1418) = 0x1110000; | ||||
| 		MCHBAR32(0x141c) = 0x9020020; | ||||
| 		MCHBAR32(0x1420) = 0xd090220; | ||||
| 		MCHBAR32(0x1424) = 0x2090220; | ||||
| 		MCHBAR32(0x1428) = 0x2090330; | ||||
| 		MCHBAR32(0x142c) = 0xd090220; | ||||
| 		MCHBAR32(0x1430) = 0x1010001; | ||||
| 		MCHBAR32(0x1434) = 0x1110000; | ||||
| 		MCHBAR32(0x1438) = 0x11040020; | ||||
| 		MCHBAR32(0x143c) = 0x4030220; | ||||
| 		MCHBAR32(0x1440) = 0x1060220; | ||||
| 		MCHBAR32(0x1444) = 0x1060330; | ||||
| 		MCHBAR32(0x1448) = 0x4030220; | ||||
| 		MCHBAR32(0x144c) = 0x1010001; | ||||
| 		MCHBAR32(0x1450) = 0x1110000; | ||||
| 		MCHBAR32(0x1454) = 0x4010020; | ||||
| 		MCHBAR32(0x1458) = 0xb090220; | ||||
| 		MCHBAR32(0x145c) = 0x1090220; | ||||
| 		MCHBAR32(0x1460) = 0x1090330; | ||||
| 		MCHBAR32(0x1464) = 0xb090220; | ||||
| 		MCHBAR32(0x1468) = 0x1010001; | ||||
| 		MCHBAR32(0x146c) = 0x1110000; | ||||
| 		MCHBAR32(0x1470) = 0xf040020; | ||||
| 		MCHBAR32(0x1474) = 0xa090220; | ||||
| 		MCHBAR32(0x1478) = 0x1120220; | ||||
| 		MCHBAR32(0x147c) = 0x1120330; | ||||
| 		MCHBAR32(0x1480) = 0xa090220; | ||||
| 		MCHBAR32(0x1484) = 0x1010001; | ||||
| 		MCHBAR32(0x1488) = 0x1110000; | ||||
| 		MCHBAR32(0x148c) = 0x7020020; | ||||
| 		MCHBAR32(0x1490) = 0x1010220; | ||||
| 		MCHBAR32(0x1494) = 0x10210; | ||||
| 		MCHBAR32(0x1498) = 0x10320; | ||||
| 		MCHBAR32(0x149c) = 0x1010220; | ||||
| 		MCHBAR32(0x14a0) = 0x1010001; | ||||
| 		MCHBAR32(0x14a4) = 0x1110000; | ||||
| 		MCHBAR32(0x14a8) = 0xd040020; | ||||
| 		MCHBAR32(0x14ac) = 0x8090220; | ||||
| 		MCHBAR32(0x14b0) = 0x1111310; | ||||
| 		MCHBAR32(0x14b4) = 0x1111420; | ||||
| 		MCHBAR32(0x14b8) = 0x8090220; | ||||
| 		MCHBAR32(0x14bc) = 0x1010001; | ||||
| 		MCHBAR32(0x14c0) = 0x1110000; | ||||
| 		MCHBAR32(0x14c4) = 0x3010020; | ||||
| 		MCHBAR32(0x14c8) = 0x7090220; | ||||
| 		MCHBAR32(0x14cc) = 0x1081310; | ||||
| 		MCHBAR32(0x14d0) = 0x1081420; | ||||
| 		MCHBAR32(0x14d4) = 0x7090220; | ||||
| 		MCHBAR32(0x14d8) = 0x1010001; | ||||
| 		MCHBAR32(0x14dc) = 0x1110000; | ||||
| 		MCHBAR32(0x14e0) = 0xb040020; | ||||
| 		MCHBAR32(0x14e4) = 0x2030220; | ||||
| 		MCHBAR32(0x14e8) = 0x1051310; | ||||
| 		MCHBAR32(0x14ec) = 0x1051420; | ||||
| 		MCHBAR32(0x14f0) = 0x2030220; | ||||
| 		MCHBAR32(0x14f4) = 0x1010001; | ||||
| 		MCHBAR32(0x14f8) = 0x1110000; | ||||
| 		MCHBAR32(0x14fc) = 0x5020020; | ||||
| 		MCHBAR32(0x1500) = 0x5090220; | ||||
| 		MCHBAR32(0x1504) = 0x2071310; | ||||
| 		MCHBAR32(0x1508) = 0x2071420; | ||||
| 		MCHBAR32(0x150c) = 0x5090220; | ||||
| 		MCHBAR32(0x1510) = 0x1010001; | ||||
| 		MCHBAR32(0x1514) = 0x1110000; | ||||
| 		MCHBAR32(0x1518) = 0x7040120; | ||||
| 		MCHBAR32(0x151c) = 0x2090220; | ||||
| 		MCHBAR32(0x1520) = 0x70b1210; | ||||
| 		MCHBAR32(0x1524) = 0x70b1310; | ||||
| 		MCHBAR32(0x1528) = 0x2090220; | ||||
| 		MCHBAR32(0x152c) = 0x1010001; | ||||
| 		MCHBAR32(0x1530) = 0x1110000; | ||||
| 		MCHBAR32(0x1534) = 0x1010110; | ||||
| 		MCHBAR32(0x1538) = 0x1081310; | ||||
| 		MCHBAR32(0x153c) = 0x5041200; | ||||
| 		MCHBAR32(0x1540) = 0x5041310; | ||||
| 		MCHBAR32(0x1544) = 0x1081310; | ||||
| 		MCHBAR32(0x1548) = 0x1010001; | ||||
| 		MCHBAR32(0x154c) = 0x1110000; | ||||
| 		MCHBAR32(0x1550) = 0x1040120; | ||||
| 		MCHBAR32(0x1554) = 0x4051210; | ||||
| 		MCHBAR32(0x1558) = 0xd051200; | ||||
| 		MCHBAR32(0x155c) = 0xd051200; | ||||
| 		MCHBAR32(0x1560) = 0x4051210; | ||||
| 		MCHBAR32(0x1564) = 0x1010001; | ||||
| 		MCHBAR32(0x1568) = 0x1110000; | ||||
| 		MCHBAR16(0x1222) = 0x220a; | ||||
| 		MCHBAR16(0x123c) = 0x1fc0; | ||||
| 		MCHBAR16(0x1220) = 0x1388; | ||||
| 	} | ||||
| } | ||||
| @@ -55,33 +55,6 @@ | ||||
|       for (rank = 0; rank < NUM_RANKS; rank++)			\ | ||||
| 	if (info->populated_ranks[channel][slot][rank]) | ||||
|  | ||||
| /* [REG_178][CHANNEL][2 * SLOT + RANK][LANE] */ | ||||
| typedef struct { | ||||
| 	u8 smallest; | ||||
| 	u8 largest; | ||||
| } timing_bounds_t[2][2][2][9]; | ||||
|  | ||||
| #define MRC_CACHE_VERSION 3 | ||||
|  | ||||
| struct ram_training { | ||||
| 	/* [TM][CHANNEL][SLOT][RANK][LANE] */ | ||||
| 	u16 lane_timings[4][2][2][2][9]; | ||||
| 	u16 reg_178; | ||||
| 	u16 reg_10b; | ||||
|  | ||||
| 	u8 reg178_center; | ||||
| 	u8 reg178_smallest; | ||||
| 	u8 reg178_largest; | ||||
| 	timing_bounds_t timing_bounds[2]; | ||||
| 	u16 timing_offset[2][2][2][9]; | ||||
| 	u16 timing2_offset[2][2][2][9]; | ||||
| 	u16 timing2_bounds[2][2][2][9][2]; | ||||
| 	u8 reg274265[2][3];	/* [CHANNEL][REGISTER] */ | ||||
| 	u8 reg2ca9_bit0; | ||||
| 	u32 reg_6dc; | ||||
| 	u32 reg_6e8; | ||||
| }; | ||||
|  | ||||
| #include <lib.h>		/* Prototypes */ | ||||
|  | ||||
| typedef struct _u128 { | ||||
| @@ -177,45 +150,6 @@ static u32 gav_real(int line, u32 in) | ||||
|  | ||||
| #define gav(x) gav_real (__LINE__, (x)) | ||||
|  | ||||
| struct raminfo { | ||||
| 	u16 clock_speed_index;	/* clock_speed (REAL, not DDR) / 133.(3) - 3 */ | ||||
| 	u16 fsb_frequency;	/* in 1.(1)/2 MHz.  */ | ||||
| 	u8 is_x16_module[2][2];	/* [CHANNEL][SLOT] */ | ||||
| 	u8 density[2][2];	/* [CHANNEL][SLOT] */ | ||||
| 	u8 populated_ranks[2][2][2];	/* [CHANNEL][SLOT][RANK] */ | ||||
| 	int rank_start[2][2][2]; | ||||
| 	u8 cas_latency; | ||||
| 	u8 board_lane_delay[9]; | ||||
| 	u8 use_ecc; | ||||
| 	u8 revision; | ||||
| 	u8 max_supported_clock_speed_index; | ||||
| 	u8 uma_enabled; | ||||
| 	u8 spd[2][2][151];	/* [CHANNEL][SLOT][BYTE]  */ | ||||
| 	u8 silicon_revision; | ||||
| 	u8 populated_ranks_mask[2]; | ||||
| 	u8 max_slots_used_in_channel; | ||||
| 	u8 mode4030[2]; | ||||
| 	u16 avg4044[2]; | ||||
| 	u16 max4048[2]; | ||||
| 	unsigned int total_memory_mb; | ||||
| 	unsigned int interleaved_part_mb; | ||||
| 	unsigned int non_interleaved_part_mb; | ||||
|  | ||||
| 	unsigned int memory_reserved_for_heci_mb; | ||||
|  | ||||
| 	struct ram_training training; | ||||
| 	u32 last_500_command[2]; | ||||
|  | ||||
| 	u32 delay46_ps[2]; | ||||
| 	u32 delay54_ps[2]; | ||||
| 	u8 revision_flag_1; | ||||
| 	u8 some_delay_1_cycle_floor; | ||||
| 	u8 some_delay_2_halfcycles_ceil; | ||||
| 	u8 some_delay_3_ps_rounded; | ||||
|  | ||||
| 	const struct ram_training *cached_training; | ||||
| }; | ||||
|  | ||||
| /* Global allocation of timings_car */ | ||||
| timing_bounds_t timings_car[64]; | ||||
|  | ||||
| @@ -351,9 +285,6 @@ static u32 get_580(int channel, u8 addr) | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| #define NUM_CHANNELS 2 | ||||
| #define NUM_SLOTS 2 | ||||
| #define NUM_RANKS 2 | ||||
| #define RANK_SHIFT 28 | ||||
| #define CHANNEL_SHIFT 10 | ||||
|  | ||||
| @@ -768,29 +699,12 @@ static void program_base_timings(struct raminfo *info) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static unsigned int fsbcycle_ps(struct raminfo *info) | ||||
| { | ||||
| 	return 900000 / info->fsb_frequency; | ||||
| } | ||||
|  | ||||
| /* The time of DDR transfer in ps.  */ | ||||
| static unsigned int halfcycle_ps(struct raminfo *info) | ||||
| { | ||||
| 	return 3750 / (info->clock_speed_index + 3); | ||||
| } | ||||
|  | ||||
| /* The time of clock cycle in ps.  */ | ||||
| static unsigned int cycle_ps(struct raminfo *info) | ||||
| { | ||||
| 	return 2 * halfcycle_ps(info); | ||||
| } | ||||
|  | ||||
| /* Frequency in 1.(1)=10/9 MHz units. */ | ||||
| static unsigned int frequency_11(struct raminfo *info) | ||||
| { | ||||
| 	return (info->clock_speed_index + 3) * 120; | ||||
| } | ||||
|  | ||||
| /* Frequency in 0.1 MHz units. */ | ||||
| static unsigned int frequency_01(struct raminfo *info) | ||||
| { | ||||
| @@ -3168,318 +3082,7 @@ static void ram_training(struct raminfo *info) | ||||
| 	MCHBAR16(0xfc4) = saved_fc4; | ||||
| } | ||||
|  | ||||
| static unsigned int gcd(unsigned int a, unsigned int b) | ||||
| { | ||||
| 	unsigned int t; | ||||
| 	if (a > b) { | ||||
| 		t = a; | ||||
| 		a = b; | ||||
| 		b = t; | ||||
| 	} | ||||
| 	/* invariant a < b.  */ | ||||
| 	while (a) { | ||||
| 		t = b % a; | ||||
| 		b = a; | ||||
| 		a = t; | ||||
| 	} | ||||
| 	return b; | ||||
| } | ||||
|  | ||||
| static inline int div_roundup(int a, int b) | ||||
| { | ||||
| 	return DIV_ROUND_UP(a, b); | ||||
| } | ||||
|  | ||||
| static unsigned int lcm(unsigned int a, unsigned int b) | ||||
| { | ||||
| 	return (a * b) / gcd(a, b); | ||||
| } | ||||
|  | ||||
| struct stru1 { | ||||
| 	u8 freqs_reversed; | ||||
| 	u8 freq_diff_reduced; | ||||
| 	u8 freq_min_reduced; | ||||
| 	u8 divisor_f4_to_fmax; | ||||
| 	u8 divisor_f3_to_fmax; | ||||
| 	u8 freq4_to_max_remainder; | ||||
| 	u8 freq3_to_2_remainder; | ||||
| 	u8 freq3_to_2_remaindera; | ||||
| 	u8 freq4_to_2_remainder; | ||||
| 	int divisor_f3_to_f1, divisor_f4_to_f2; | ||||
| 	int common_time_unit_ps; | ||||
| 	int freq_max_reduced; | ||||
| }; | ||||
|  | ||||
| static void | ||||
| compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2, | ||||
| 			 int num_cycles_2, int num_cycles_1, int round_it, | ||||
| 			 int add_freqs, struct stru1 *result) | ||||
| { | ||||
| 	int g; | ||||
| 	int common_time_unit_ps; | ||||
| 	int freq1_reduced, freq2_reduced; | ||||
| 	int freq_min_reduced; | ||||
| 	int freq_max_reduced; | ||||
| 	int freq3, freq4; | ||||
|  | ||||
| 	g = gcd(freq1, freq2); | ||||
| 	freq1_reduced = freq1 / g; | ||||
| 	freq2_reduced = freq2 / g; | ||||
| 	freq_min_reduced = MIN(freq1_reduced, freq2_reduced); | ||||
| 	freq_max_reduced = MAX(freq1_reduced, freq2_reduced); | ||||
|  | ||||
| 	common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2)); | ||||
| 	freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1; | ||||
| 	freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1; | ||||
| 	if (add_freqs) { | ||||
| 		freq3 += freq2_reduced; | ||||
| 		freq4 += freq1_reduced; | ||||
| 	} | ||||
|  | ||||
| 	if (round_it) { | ||||
| 		result->freq3_to_2_remainder = 0; | ||||
| 		result->freq3_to_2_remaindera = 0; | ||||
| 		result->freq4_to_max_remainder = 0; | ||||
| 		result->divisor_f4_to_f2 = 0; | ||||
| 		result->divisor_f3_to_f1 = 0; | ||||
| 	} else { | ||||
| 		if (freq2_reduced < freq1_reduced) { | ||||
| 			result->freq3_to_2_remainder = | ||||
| 			    result->freq3_to_2_remaindera = | ||||
| 			    freq3 % freq1_reduced - freq1_reduced + 1; | ||||
| 			result->freq4_to_max_remainder = | ||||
| 			    -(freq4 % freq1_reduced); | ||||
| 			result->divisor_f3_to_f1 = freq3 / freq1_reduced; | ||||
| 			result->divisor_f4_to_f2 = | ||||
| 			    (freq4 - | ||||
| 			     (freq1_reduced - freq2_reduced)) / freq2_reduced; | ||||
| 			result->freq4_to_2_remainder = | ||||
| 			    -(char)((freq1_reduced - freq2_reduced) + | ||||
| 				    ((u8) freq4 - | ||||
| 				     (freq1_reduced - | ||||
| 				      freq2_reduced)) % (u8) freq2_reduced); | ||||
| 		} else { | ||||
| 			if (freq2_reduced > freq1_reduced) { | ||||
| 				result->freq4_to_max_remainder = | ||||
| 				    (freq4 % freq2_reduced) - freq2_reduced + 1; | ||||
| 				result->freq4_to_2_remainder = | ||||
| 				    freq4 % freq_max_reduced - | ||||
| 				    freq_max_reduced + 1; | ||||
| 			} else { | ||||
| 				result->freq4_to_max_remainder = | ||||
| 				    -(freq4 % freq2_reduced); | ||||
| 				result->freq4_to_2_remainder = | ||||
| 				    -(char)(freq4 % freq_max_reduced); | ||||
| 			} | ||||
| 			result->divisor_f4_to_f2 = freq4 / freq2_reduced; | ||||
| 			result->divisor_f3_to_f1 = | ||||
| 			    (freq3 - | ||||
| 			     (freq2_reduced - freq1_reduced)) / freq1_reduced; | ||||
| 			result->freq3_to_2_remainder = -(freq3 % freq2_reduced); | ||||
| 			result->freq3_to_2_remaindera = | ||||
| 			    -(char)((freq_max_reduced - freq_min_reduced) + | ||||
| 				    (freq3 - | ||||
| 				     (freq_max_reduced - | ||||
| 				      freq_min_reduced)) % freq1_reduced); | ||||
| 		} | ||||
| 	} | ||||
| 	result->divisor_f3_to_fmax = freq3 / freq_max_reduced; | ||||
| 	result->divisor_f4_to_fmax = freq4 / freq_max_reduced; | ||||
| 	if (round_it) { | ||||
| 		if (freq2_reduced > freq1_reduced) { | ||||
| 			if (freq3 % freq_max_reduced) | ||||
| 				result->divisor_f3_to_fmax++; | ||||
| 		} | ||||
| 		if (freq2_reduced < freq1_reduced) { | ||||
| 			if (freq4 % freq_max_reduced) | ||||
| 				result->divisor_f4_to_fmax++; | ||||
| 		} | ||||
| 	} | ||||
| 	result->freqs_reversed = (freq2_reduced < freq1_reduced); | ||||
| 	result->freq_diff_reduced = freq_max_reduced - freq_min_reduced; | ||||
| 	result->freq_min_reduced = freq_min_reduced; | ||||
| 	result->common_time_unit_ps = common_time_unit_ps; | ||||
| 	result->freq_max_reduced = freq_max_reduced; | ||||
| } | ||||
|  | ||||
| static void | ||||
| set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2, | ||||
| 	     int num_cycles_2, int num_cycles_1, int num_cycles_3, | ||||
| 	     int num_cycles_4, int reverse) | ||||
| { | ||||
| 	struct stru1 vv; | ||||
| 	char multiplier; | ||||
|  | ||||
| 	compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1, | ||||
| 				 0, 1, &vv); | ||||
|  | ||||
| 	multiplier = | ||||
| 	    div_roundup(MAX | ||||
| 			(div_roundup(num_cycles_2, vv.common_time_unit_ps) + | ||||
| 			 div_roundup(num_cycles_3, vv.common_time_unit_ps), | ||||
| 			 div_roundup(num_cycles_1, | ||||
| 				     vv.common_time_unit_ps) + | ||||
| 			 div_roundup(num_cycles_4, vv.common_time_unit_ps)) | ||||
| 			+ vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1; | ||||
|  | ||||
| 	u32 y = | ||||
| 	    (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) + | ||||
| 		  vv.freq_max_reduced * multiplier) | ||||
| 	    | (vv. | ||||
| 	       freqs_reversed << 8) | ((u8) (vv.freq_min_reduced * | ||||
| 					     multiplier) << 16) | ((u8) (vv. | ||||
| 									 freq_min_reduced | ||||
| 									 * | ||||
| 									 multiplier) | ||||
| 								   << 24); | ||||
| 	u32 x = | ||||
| 	    vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv. | ||||
| 									 divisor_f3_to_f1 | ||||
| 									 << 16) | ||||
| 	    | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24); | ||||
| 	if (reverse) { | ||||
| 		MCHBAR32(reg) = y; | ||||
| 		MCHBAR32(reg + 4) = x; | ||||
| 	} else { | ||||
| 		MCHBAR32(reg + 4) = y; | ||||
| 		MCHBAR32(reg) = x; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void | ||||
| set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2, | ||||
| 	   int num_cycles_1, int num_cycles_2, int num_cycles_3, | ||||
| 	   int num_cycles_4) | ||||
| { | ||||
| 	struct stru1 ratios1; | ||||
| 	struct stru1 ratios2; | ||||
|  | ||||
| 	compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2, | ||||
| 				 0, 1, &ratios2); | ||||
| 	compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4, | ||||
| 				 0, 1, &ratios1); | ||||
| 	printk(RAM_SPEW, "[%x] <= %x\n", reg, | ||||
| 		       ratios1.freq4_to_max_remainder | (ratios2. | ||||
| 							 freq4_to_max_remainder | ||||
| 							 << 8) | ||||
| 		       | (ratios1.divisor_f4_to_fmax << 16) | (ratios2. | ||||
| 							       divisor_f4_to_fmax | ||||
| 							       << 20)); | ||||
| 	MCHBAR32(reg) = ratios1.freq4_to_max_remainder | | ||||
| 		(ratios2.freq4_to_max_remainder << 8) | | ||||
| 		(ratios1.divisor_f4_to_fmax << 16) | | ||||
| 		(ratios2.divisor_f4_to_fmax << 20); | ||||
| } | ||||
|  | ||||
| static void | ||||
| set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2, | ||||
| 	     int num_cycles_2, int num_cycles_1, int round_it, int add_freqs) | ||||
| { | ||||
| 	struct stru1 ratios; | ||||
|  | ||||
| 	compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1, | ||||
| 				 round_it, add_freqs, &ratios); | ||||
| 	switch (mode) { | ||||
| 	case 0: | ||||
| 		MCHBAR32(reg + 4) = ratios.freq_diff_reduced | | ||||
| 			(ratios.freqs_reversed << 8); | ||||
| 		MCHBAR32(reg) = ratios.freq3_to_2_remainder | | ||||
| 			(ratios.freq4_to_max_remainder << 8) | | ||||
| 			(ratios.divisor_f3_to_fmax << 16) | | ||||
| 			(ratios.divisor_f4_to_fmax << 20) | | ||||
| 			(ratios.freq_min_reduced << 24); | ||||
| 		break; | ||||
|  | ||||
| 	case 1: | ||||
| 		MCHBAR32(reg) = ratios.freq3_to_2_remainder | | ||||
| 			(ratios.divisor_f3_to_fmax << 16); | ||||
| 		break; | ||||
|  | ||||
| 	case 2: | ||||
| 		MCHBAR32(reg) = ratios.freq3_to_2_remainder | | ||||
| 			(ratios.freq4_to_max_remainder << 8) | | ||||
| 			(ratios.divisor_f3_to_fmax << 16) | | ||||
| 			(ratios.divisor_f4_to_fmax << 20); | ||||
| 		break; | ||||
|  | ||||
| 	case 4: | ||||
| 		MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) | | ||||
| 			(ratios.divisor_f4_to_fmax << 8) | | ||||
| 			(ratios.freqs_reversed << 12) | | ||||
| 			(ratios.freq_min_reduced << 16) | | ||||
| 			(ratios.freq_diff_reduced << 24); | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void set_2dxx_series(struct raminfo *info, int s3resume) | ||||
| { | ||||
| 	set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005, | ||||
| 		     0, 1); | ||||
| 	set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1); | ||||
| 	set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0, | ||||
| 		     1); | ||||
| 	set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency, | ||||
| 		     frequency_11(info), 1231, 1524, 0, 1); | ||||
| 	set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency, | ||||
| 		     frequency_11(info) / 2, 1278, 2008, 0, 1); | ||||
| 	set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info), | ||||
| 		     1167, 1539, 0, 1); | ||||
| 	set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency, | ||||
| 		     frequency_11(info) / 2, 1403, 1318, 0, 1); | ||||
| 	set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1, | ||||
| 		     1); | ||||
| 	set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1, | ||||
| 		     1); | ||||
| 	set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610, | ||||
| 		     1, 1); | ||||
| 	set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1, | ||||
| 		     1); | ||||
| 	set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency, | ||||
| 		     frequency_11(info) / 2, 4000, 0, 0, 0); | ||||
| 	set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency, | ||||
| 		     frequency_11(info) / 2, 4000, 4000, 0, 0); | ||||
|  | ||||
| 	if (s3resume) { | ||||
| 		printk(RAM_SPEW, "[6dc] <= %x\n", | ||||
| 			info->cached_training->reg_6dc); | ||||
| 		MCHBAR32(0x6dc) = info->cached_training->reg_6dc; | ||||
| 	} else | ||||
| 		set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0, | ||||
| 			   info->delay46_ps[0], 0, | ||||
| 			   info->delay54_ps[0]); | ||||
| 	set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency, | ||||
| 		     frequency_11(info), 2500, 0, 0, 0); | ||||
| 	set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency, | ||||
| 		     frequency_11(info) / 2, 3500, 0, 0, 0); | ||||
| 	if (s3resume) { | ||||
| 		printk(RAM_SPEW, "[6e8] <= %x\n", | ||||
| 			info->cached_training->reg_6e8); | ||||
| 		MCHBAR32(0x6e8) = info->cached_training->reg_6e8; | ||||
| 	} else | ||||
| 		set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0, | ||||
| 			   info->delay46_ps[1], 0, | ||||
| 			   info->delay54_ps[1]); | ||||
| 	set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0); | ||||
| 	set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455, | ||||
| 		     470, 0); | ||||
| 	set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0); | ||||
| 	set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758, | ||||
| 		     454, 459, 0); | ||||
| 	set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0); | ||||
| 	set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579, | ||||
| 		     2588, 0); | ||||
| 	set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405, | ||||
| 		     2405, 0); | ||||
| 	set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0); | ||||
| 	set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484, | ||||
| 		     480, 0); | ||||
| 	set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0); | ||||
| 	MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000; | ||||
| 	MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77; | ||||
| } | ||||
|  | ||||
| static u16 get_max_timing(struct raminfo *info, int channel) | ||||
| u16 get_max_timing(struct raminfo *info, int channel) | ||||
| { | ||||
| 	int slot, rank, lane; | ||||
| 	u16 ret = 0; | ||||
| @@ -3501,117 +3104,6 @@ static u16 get_max_timing(struct raminfo *info, int channel) | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| static void set_274265(struct raminfo *info) | ||||
| { | ||||
| 	int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps; | ||||
| 	int delay_e_ps, delay_e_cycles, delay_f_cycles; | ||||
| 	int delay_e_over_cycle_ps; | ||||
| 	int cycletime_ps; | ||||
| 	int channel; | ||||
|  | ||||
| 	delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info); | ||||
| 	info->training.reg2ca9_bit0 = 0; | ||||
| 	for (channel = 0; channel < NUM_CHANNELS; channel++) { | ||||
| 		cycletime_ps = | ||||
| 		    900000 / lcm(2 * info->fsb_frequency, frequency_11(info)); | ||||
| 		delay_d_ps = | ||||
| 		    (halfcycle_ps(info) * get_max_timing(info, channel) >> 6) | ||||
| 		    - info->some_delay_3_ps_rounded + 200; | ||||
| 		if (! | ||||
| 		    ((info->silicon_revision == 0 | ||||
| 		      || info->silicon_revision == 1) | ||||
| 		     && (info->revision >= 8))) | ||||
| 			delay_d_ps += halfcycle_ps(info) * 2; | ||||
| 		delay_d_ps += | ||||
| 		    halfcycle_ps(info) * (!info->revision_flag_1 + | ||||
| 					  info->some_delay_2_halfcycles_ceil + | ||||
| 					  2 * info->some_delay_1_cycle_floor + | ||||
| 					  info->clock_speed_index + | ||||
| 					  2 * info->cas_latency - 7 + 11); | ||||
| 		delay_d_ps += info->revision >= 8 ? 2758 : 4428; | ||||
|  | ||||
| 		MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000); | ||||
| 		MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000); | ||||
| 		if ((MCHBAR8(0x144) & 0x1f) > 0x13) | ||||
| 			delay_d_ps += 650; | ||||
| 		delay_c_ps = delay_d_ps + 1800; | ||||
| 		if (delay_c_ps <= delay_a_ps) | ||||
| 			delay_e_ps = 0; | ||||
| 		else | ||||
| 			delay_e_ps = | ||||
| 			    cycletime_ps * div_roundup(delay_c_ps - delay_a_ps, | ||||
| 						       cycletime_ps); | ||||
|  | ||||
| 		delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info)); | ||||
| 		delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info)); | ||||
| 		delay_f_cycles = | ||||
| 		    div_roundup(2500 - delay_e_over_cycle_ps, | ||||
| 				2 * halfcycle_ps(info)); | ||||
| 		if (delay_f_cycles > delay_e_cycles) { | ||||
| 			info->delay46_ps[channel] = delay_e_ps; | ||||
| 			delay_e_cycles = 0; | ||||
| 		} else { | ||||
| 			info->delay46_ps[channel] = | ||||
| 			    delay_e_over_cycle_ps + | ||||
| 			    2 * halfcycle_ps(info) * delay_f_cycles; | ||||
| 			delay_e_cycles -= delay_f_cycles; | ||||
| 		} | ||||
|  | ||||
| 		if (info->delay46_ps[channel] < 2500) { | ||||
| 			info->delay46_ps[channel] = 2500; | ||||
| 			info->training.reg2ca9_bit0 = 1; | ||||
| 		} | ||||
| 		delay_b_ps = halfcycle_ps(info) + delay_c_ps; | ||||
| 		if (delay_b_ps <= delay_a_ps) | ||||
| 			delay_b_ps = 0; | ||||
| 		else | ||||
| 			delay_b_ps -= delay_a_ps; | ||||
| 		info->delay54_ps[channel] = | ||||
| 		    cycletime_ps * div_roundup(delay_b_ps, | ||||
| 					       cycletime_ps) - | ||||
| 		    2 * halfcycle_ps(info) * delay_e_cycles; | ||||
| 		if (info->delay54_ps[channel] < 2500) | ||||
| 			info->delay54_ps[channel] = 2500; | ||||
| 		info->training.reg274265[channel][0] = delay_e_cycles; | ||||
| 		if (delay_d_ps + 7 * halfcycle_ps(info) <= | ||||
| 		    24 * halfcycle_ps(info)) | ||||
| 			info->training.reg274265[channel][1] = 0; | ||||
| 		else | ||||
| 			info->training.reg274265[channel][1] = | ||||
| 				div_roundup(delay_d_ps + 7 * halfcycle_ps(info), | ||||
| 				4 * halfcycle_ps(info)) - 6; | ||||
| 		MCHBAR32((channel << 10) + 0x274) = | ||||
| 			info->training.reg274265[channel][1] | | ||||
| 			(info->training.reg274265[channel][0] << 16); | ||||
| 		info->training.reg274265[channel][2] = | ||||
| 			div_roundup(delay_c_ps + 3 * fsbcycle_ps(info), | ||||
| 			4 * halfcycle_ps(info)) + 1; | ||||
| 		MCHBAR16((channel << 10) + 0x265) = | ||||
| 			info->training.reg274265[channel][2] << 8; | ||||
| 	} | ||||
| 	if (info->training.reg2ca9_bit0) | ||||
| 		MCHBAR8_OR(0x2ca9, 1); | ||||
| 	else | ||||
| 		MCHBAR8_AND(0x2ca9, ~1); | ||||
| } | ||||
|  | ||||
| static void restore_274265(struct raminfo *info) | ||||
| { | ||||
| 	int channel; | ||||
|  | ||||
| 	for (channel = 0; channel < NUM_CHANNELS; channel++) { | ||||
| 		MCHBAR32((channel << 10) + 0x274) = | ||||
| 			(info->cached_training->reg274265[channel][0] << 16) | | ||||
| 			info->cached_training->reg274265[channel][1]; | ||||
| 		MCHBAR16((channel << 10) + 0x265) = | ||||
| 			info->cached_training->reg274265[channel][2] << 8; | ||||
| 	} | ||||
| 	if (info->cached_training->reg2ca9_bit0) | ||||
| 		MCHBAR8_OR(0x2ca9, 1); | ||||
| 	else | ||||
| 		MCHBAR8_AND(0x2ca9, ~1); | ||||
| } | ||||
|  | ||||
| static void dmi_setup(void) | ||||
| { | ||||
| 	gav(DMIBAR8(0x254)); | ||||
| @@ -3691,18 +3183,14 @@ static u8 get_bits_420(const u32 reg32) | ||||
| void raminit(const int s3resume, const u8 *spd_addrmap) | ||||
| { | ||||
| 	unsigned int channel, slot, lane, rank; | ||||
| 	int i; | ||||
| 	struct raminfo info; | ||||
| 	u8 x2ca8; | ||||
| 	u16 deven; | ||||
| 	int cbmem_wasnot_inited; | ||||
|  | ||||
| 	x2ca8 = MCHBAR8(0x2ca8); | ||||
|  | ||||
| 	printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8); | ||||
|  | ||||
| 	deven = pci_read_config16(NORTHBRIDGE, DEVEN); | ||||
|  | ||||
| 	memset(&info, 0x5a, sizeof(info)); | ||||
|  | ||||
| 	info.last_500_command[0] = 0; | ||||
| @@ -3971,230 +3459,8 @@ void raminit(const int s3resume, const u8 *spd_addrmap) | ||||
|  | ||||
| 	info.cached_training = get_cached_training(); | ||||
|  | ||||
| 	if (x2ca8 == 0) { | ||||
| 		int j; | ||||
| 		if (s3resume && info.cached_training) { | ||||
| 			restore_274265(&info); | ||||
| 			printk(RAM_SPEW, "reg2ca9_bit0 = %x\n", | ||||
| 			       info.cached_training->reg2ca9_bit0); | ||||
| 			for (i = 0; i < 2; i++) | ||||
| 				for (j = 0; j < 3; j++) | ||||
| 					printk(RAM_SPEW, "reg274265[%d][%d] = %x\n", | ||||
| 					       i, j, info.cached_training->reg274265[i][j]); | ||||
| 		} else { | ||||
| 			set_274265(&info); | ||||
| 			printk(RAM_SPEW, "reg2ca9_bit0 = %x\n", | ||||
| 			       info.training.reg2ca9_bit0); | ||||
| 			for (i = 0; i < 2; i++) | ||||
| 				for (j = 0; j < 3; j++) | ||||
| 					printk(RAM_SPEW, "reg274265[%d][%d] = %x\n", | ||||
| 					       i, j, info.training.reg274265[i][j]); | ||||
| 		} | ||||
|  | ||||
| 		set_2dxx_series(&info, s3resume); | ||||
|  | ||||
| 		if (!(deven & 8)) { | ||||
| 			MCHBAR32_AND_OR(0x2cb0, 0, 0x40); | ||||
| 		} | ||||
|  | ||||
| 		udelay(1000); | ||||
|  | ||||
| 		if (deven & 8) { | ||||
| 			MCHBAR32_OR(0xff8, 0x1800); | ||||
| 			MCHBAR32_AND(0x2cb0, 0x00); | ||||
| 			pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c); | ||||
| 			pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c); | ||||
| 			pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e); | ||||
|  | ||||
| 			MCHBAR8(0x1150); | ||||
| 			MCHBAR8(0x1151); | ||||
| 			MCHBAR8(0x1022); | ||||
| 			MCHBAR8(0x16d0); | ||||
| 			MCHBAR32(0x1300) = 0x60606060; | ||||
| 			MCHBAR32(0x1304) = 0x60606060; | ||||
| 			MCHBAR32(0x1308) = 0x78797a7b; | ||||
| 			MCHBAR32(0x130c) = 0x7c7d7e7f; | ||||
| 			MCHBAR32(0x1310) = 0x60606060; | ||||
| 			MCHBAR32(0x1314) = 0x60606060; | ||||
| 			MCHBAR32(0x1318) = 0x60606060; | ||||
| 			MCHBAR32(0x131c) = 0x60606060; | ||||
| 			MCHBAR32(0x1320) = 0x50515253; | ||||
| 			MCHBAR32(0x1324) = 0x54555657; | ||||
| 			MCHBAR32(0x1328) = 0x58595a5b; | ||||
| 			MCHBAR32(0x132c) = 0x5c5d5e5f; | ||||
| 			MCHBAR32(0x1330) = 0x40414243; | ||||
| 			MCHBAR32(0x1334) = 0x44454647; | ||||
| 			MCHBAR32(0x1338) = 0x48494a4b; | ||||
| 			MCHBAR32(0x133c) = 0x4c4d4e4f; | ||||
| 			MCHBAR32(0x1340) = 0x30313233; | ||||
| 			MCHBAR32(0x1344) = 0x34353637; | ||||
| 			MCHBAR32(0x1348) = 0x38393a3b; | ||||
| 			MCHBAR32(0x134c) = 0x3c3d3e3f; | ||||
| 			MCHBAR32(0x1350) = 0x20212223; | ||||
| 			MCHBAR32(0x1354) = 0x24252627; | ||||
| 			MCHBAR32(0x1358) = 0x28292a2b; | ||||
| 			MCHBAR32(0x135c) = 0x2c2d2e2f; | ||||
| 			MCHBAR32(0x1360) = 0x10111213; | ||||
| 			MCHBAR32(0x1364) = 0x14151617; | ||||
| 			MCHBAR32(0x1368) = 0x18191a1b; | ||||
| 			MCHBAR32(0x136c) = 0x1c1d1e1f; | ||||
| 			MCHBAR32(0x1370) = 0x10203; | ||||
| 			MCHBAR32(0x1374) = 0x4050607; | ||||
| 			MCHBAR32(0x1378) = 0x8090a0b; | ||||
| 			MCHBAR32(0x137c) = 0xc0d0e0f; | ||||
| 			MCHBAR8(0x11cc) = 0x4e; | ||||
| 			MCHBAR32(0x1110) = 0x73970404; | ||||
| 			MCHBAR32(0x1114) = 0x72960404; | ||||
| 			MCHBAR32(0x1118) = 0x6f950404; | ||||
| 			MCHBAR32(0x111c) = 0x6d940404; | ||||
| 			MCHBAR32(0x1120) = 0x6a930404; | ||||
| 			MCHBAR32(0x1124) = 0x68a41404; | ||||
| 			MCHBAR32(0x1128) = 0x66a21404; | ||||
| 			MCHBAR32(0x112c) = 0x63a01404; | ||||
| 			MCHBAR32(0x1130) = 0x609e1404; | ||||
| 			MCHBAR32(0x1134) = 0x5f9c1404; | ||||
| 			MCHBAR32(0x1138) = 0x5c961404; | ||||
| 			MCHBAR32(0x113c) = 0x58a02404; | ||||
| 			MCHBAR32(0x1140) = 0x54942404; | ||||
| 			MCHBAR32(0x1190) = 0x900080a; | ||||
| 			MCHBAR16(0x11c0) = 0xc40b; | ||||
| 			MCHBAR16(0x11c2) = 0x303; | ||||
| 			MCHBAR16(0x11c4) = 0x301; | ||||
| 			MCHBAR32_AND_OR(0x1190, 0, 0x8900080a); | ||||
| 			MCHBAR32(0x11b8) = 0x70c3000; | ||||
| 			MCHBAR8(0x11ec) = 0xa; | ||||
| 			MCHBAR16(0x1100) = 0x800; | ||||
| 			MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800); | ||||
| 			MCHBAR16(0x11ca) = 0xfa; | ||||
| 			MCHBAR32(0x11e4) = 0x4e20; | ||||
| 			MCHBAR8(0x11bc) = 0xf; | ||||
| 			MCHBAR16(0x11da) = 0x19; | ||||
| 			MCHBAR16(0x11ba) = 0x470c; | ||||
| 			MCHBAR32(0x1680) = 0xe6ffe4ff; | ||||
| 			MCHBAR32(0x1684) = 0xdeffdaff; | ||||
| 			MCHBAR32(0x1688) = 0xd4ffd0ff; | ||||
| 			MCHBAR32(0x168c) = 0xccffc6ff; | ||||
| 			MCHBAR32(0x1690) = 0xc0ffbeff; | ||||
| 			MCHBAR32(0x1694) = 0xb8ffb0ff; | ||||
| 			MCHBAR32(0x1698) = 0xa8ff0000; | ||||
| 			MCHBAR32(0x169c) = 0xc00; | ||||
| 			MCHBAR32(0x1290) = 0x5000000; | ||||
| 		} | ||||
|  | ||||
| 		MCHBAR32(0x124c) = 0x15040d00; | ||||
| 		MCHBAR32(0x1250) = 0x7f0000; | ||||
| 		MCHBAR32(0x1254) = 0x1e220004; | ||||
| 		MCHBAR32(0x1258) = 0x4000004; | ||||
| 		MCHBAR32(0x1278) = 0x0; | ||||
| 		MCHBAR32(0x125c) = 0x0; | ||||
| 		MCHBAR32(0x1260) = 0x0; | ||||
| 		MCHBAR32(0x1264) = 0x0; | ||||
| 		MCHBAR32(0x1268) = 0x0; | ||||
| 		MCHBAR32(0x126c) = 0x0; | ||||
| 		MCHBAR32(0x1270) = 0x0; | ||||
| 		MCHBAR32(0x1274) = 0x0; | ||||
| 	} | ||||
|  | ||||
| 	if ((deven & 8) && x2ca8 == 0) { | ||||
| 		MCHBAR16(0x1214) = 0x320; | ||||
| 		MCHBAR32(0x1600) = 0x40000000; | ||||
| 		MCHBAR32_AND_OR(0x11f4, 0, 0x10000000); | ||||
| 		MCHBAR16_AND_OR(0x1230, 0, 0x8000); | ||||
| 		MCHBAR32(0x1400) = 0x13040020; | ||||
| 		MCHBAR32(0x1404) = 0xe090120; | ||||
| 		MCHBAR32(0x1408) = 0x5120220; | ||||
| 		MCHBAR32(0x140c) = 0x5120330; | ||||
| 		MCHBAR32(0x1410) = 0xe090220; | ||||
| 		MCHBAR32(0x1414) = 0x1010001; | ||||
| 		MCHBAR32(0x1418) = 0x1110000; | ||||
| 		MCHBAR32(0x141c) = 0x9020020; | ||||
| 		MCHBAR32(0x1420) = 0xd090220; | ||||
| 		MCHBAR32(0x1424) = 0x2090220; | ||||
| 		MCHBAR32(0x1428) = 0x2090330; | ||||
| 		MCHBAR32(0x142c) = 0xd090220; | ||||
| 		MCHBAR32(0x1430) = 0x1010001; | ||||
| 		MCHBAR32(0x1434) = 0x1110000; | ||||
| 		MCHBAR32(0x1438) = 0x11040020; | ||||
| 		MCHBAR32(0x143c) = 0x4030220; | ||||
| 		MCHBAR32(0x1440) = 0x1060220; | ||||
| 		MCHBAR32(0x1444) = 0x1060330; | ||||
| 		MCHBAR32(0x1448) = 0x4030220; | ||||
| 		MCHBAR32(0x144c) = 0x1010001; | ||||
| 		MCHBAR32(0x1450) = 0x1110000; | ||||
| 		MCHBAR32(0x1454) = 0x4010020; | ||||
| 		MCHBAR32(0x1458) = 0xb090220; | ||||
| 		MCHBAR32(0x145c) = 0x1090220; | ||||
| 		MCHBAR32(0x1460) = 0x1090330; | ||||
| 		MCHBAR32(0x1464) = 0xb090220; | ||||
| 		MCHBAR32(0x1468) = 0x1010001; | ||||
| 		MCHBAR32(0x146c) = 0x1110000; | ||||
| 		MCHBAR32(0x1470) = 0xf040020; | ||||
| 		MCHBAR32(0x1474) = 0xa090220; | ||||
| 		MCHBAR32(0x1478) = 0x1120220; | ||||
| 		MCHBAR32(0x147c) = 0x1120330; | ||||
| 		MCHBAR32(0x1480) = 0xa090220; | ||||
| 		MCHBAR32(0x1484) = 0x1010001; | ||||
| 		MCHBAR32(0x1488) = 0x1110000; | ||||
| 		MCHBAR32(0x148c) = 0x7020020; | ||||
| 		MCHBAR32(0x1490) = 0x1010220; | ||||
| 		MCHBAR32(0x1494) = 0x10210; | ||||
| 		MCHBAR32(0x1498) = 0x10320; | ||||
| 		MCHBAR32(0x149c) = 0x1010220; | ||||
| 		MCHBAR32(0x14a0) = 0x1010001; | ||||
| 		MCHBAR32(0x14a4) = 0x1110000; | ||||
| 		MCHBAR32(0x14a8) = 0xd040020; | ||||
| 		MCHBAR32(0x14ac) = 0x8090220; | ||||
| 		MCHBAR32(0x14b0) = 0x1111310; | ||||
| 		MCHBAR32(0x14b4) = 0x1111420; | ||||
| 		MCHBAR32(0x14b8) = 0x8090220; | ||||
| 		MCHBAR32(0x14bc) = 0x1010001; | ||||
| 		MCHBAR32(0x14c0) = 0x1110000; | ||||
| 		MCHBAR32(0x14c4) = 0x3010020; | ||||
| 		MCHBAR32(0x14c8) = 0x7090220; | ||||
| 		MCHBAR32(0x14cc) = 0x1081310; | ||||
| 		MCHBAR32(0x14d0) = 0x1081420; | ||||
| 		MCHBAR32(0x14d4) = 0x7090220; | ||||
| 		MCHBAR32(0x14d8) = 0x1010001; | ||||
| 		MCHBAR32(0x14dc) = 0x1110000; | ||||
| 		MCHBAR32(0x14e0) = 0xb040020; | ||||
| 		MCHBAR32(0x14e4) = 0x2030220; | ||||
| 		MCHBAR32(0x14e8) = 0x1051310; | ||||
| 		MCHBAR32(0x14ec) = 0x1051420; | ||||
| 		MCHBAR32(0x14f0) = 0x2030220; | ||||
| 		MCHBAR32(0x14f4) = 0x1010001; | ||||
| 		MCHBAR32(0x14f8) = 0x1110000; | ||||
| 		MCHBAR32(0x14fc) = 0x5020020; | ||||
| 		MCHBAR32(0x1500) = 0x5090220; | ||||
| 		MCHBAR32(0x1504) = 0x2071310; | ||||
| 		MCHBAR32(0x1508) = 0x2071420; | ||||
| 		MCHBAR32(0x150c) = 0x5090220; | ||||
| 		MCHBAR32(0x1510) = 0x1010001; | ||||
| 		MCHBAR32(0x1514) = 0x1110000; | ||||
| 		MCHBAR32(0x1518) = 0x7040120; | ||||
| 		MCHBAR32(0x151c) = 0x2090220; | ||||
| 		MCHBAR32(0x1520) = 0x70b1210; | ||||
| 		MCHBAR32(0x1524) = 0x70b1310; | ||||
| 		MCHBAR32(0x1528) = 0x2090220; | ||||
| 		MCHBAR32(0x152c) = 0x1010001; | ||||
| 		MCHBAR32(0x1530) = 0x1110000; | ||||
| 		MCHBAR32(0x1534) = 0x1010110; | ||||
| 		MCHBAR32(0x1538) = 0x1081310; | ||||
| 		MCHBAR32(0x153c) = 0x5041200; | ||||
| 		MCHBAR32(0x1540) = 0x5041310; | ||||
| 		MCHBAR32(0x1544) = 0x1081310; | ||||
| 		MCHBAR32(0x1548) = 0x1010001; | ||||
| 		MCHBAR32(0x154c) = 0x1110000; | ||||
| 		MCHBAR32(0x1550) = 0x1040120; | ||||
| 		MCHBAR32(0x1554) = 0x4051210; | ||||
| 		MCHBAR32(0x1558) = 0xd051200; | ||||
| 		MCHBAR32(0x155c) = 0xd051200; | ||||
| 		MCHBAR32(0x1560) = 0x4051210; | ||||
| 		MCHBAR32(0x1564) = 0x1010001; | ||||
| 		MCHBAR32(0x1568) = 0x1110000; | ||||
| 		MCHBAR16(0x1222) = 0x220a; | ||||
| 		MCHBAR16(0x123c) = 0x1fc0; | ||||
| 		MCHBAR16(0x1220) = 0x1388; | ||||
| 	} | ||||
| 	if (x2ca8 == 0) | ||||
| 		late_quickpath_init(&info, s3resume); | ||||
|  | ||||
| 	MCHBAR32_OR(0x2c80, (1 << 24)); | ||||
| 	MCHBAR32(0x1804) = MCHBAR32(0x1c04) & ~(1 << 27); | ||||
| @@ -4214,6 +3480,7 @@ void raminit(const int s3resume, const u8 *spd_addrmap) | ||||
| 		MCHBAR32_OR(0x1af0, 0x10); | ||||
| 		halt(); | ||||
| 	} | ||||
|  | ||||
| 	MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);	// !!!! | ||||
|  | ||||
| 	MCHBAR32_AND(0x2c80, ~(1 << 24)); | ||||
|   | ||||
| @@ -5,6 +5,93 @@ | ||||
|  | ||||
| #include "ironlake.h" | ||||
|  | ||||
| #define NUM_CHANNELS	2 | ||||
| #define NUM_SLOTS	2 | ||||
| #define NUM_RANKS	2 | ||||
|  | ||||
| /* [REG_178][CHANNEL][2 * SLOT + RANK][LANE] */ | ||||
| typedef struct { | ||||
| 	u8 smallest; | ||||
| 	u8 largest; | ||||
| } timing_bounds_t[2][2][2][9]; | ||||
|  | ||||
| #define MRC_CACHE_VERSION 3 | ||||
|  | ||||
| struct ram_training { | ||||
| 	/* [TM][CHANNEL][SLOT][RANK][LANE] */ | ||||
| 	u16 lane_timings[4][2][2][2][9]; | ||||
| 	u16 reg_178; | ||||
| 	u16 reg_10b; | ||||
|  | ||||
| 	u8 reg178_center; | ||||
| 	u8 reg178_smallest; | ||||
| 	u8 reg178_largest; | ||||
| 	timing_bounds_t timing_bounds[2]; | ||||
| 	u16 timing_offset[2][2][2][9]; | ||||
| 	u16 timing2_offset[2][2][2][9]; | ||||
| 	u16 timing2_bounds[2][2][2][9][2]; | ||||
| 	u8 reg274265[2][3];	/* [CHANNEL][REGISTER] */ | ||||
| 	u8 reg2ca9_bit0; | ||||
| 	u32 reg_6dc; | ||||
| 	u32 reg_6e8; | ||||
| }; | ||||
|  | ||||
| struct raminfo { | ||||
| 	u16 clock_speed_index;	/* clock_speed (REAL, not DDR) / 133.(3) - 3 */ | ||||
| 	u16 fsb_frequency;	/* in 1.(1)/2 MHz.  */ | ||||
| 	u8 is_x16_module[2][2];	/* [CHANNEL][SLOT] */ | ||||
| 	u8 density[2][2];	/* [CHANNEL][SLOT] */ | ||||
| 	u8 populated_ranks[2][2][2];	/* [CHANNEL][SLOT][RANK] */ | ||||
| 	int rank_start[2][2][2]; | ||||
| 	u8 cas_latency; | ||||
| 	u8 board_lane_delay[9]; | ||||
| 	u8 use_ecc; | ||||
| 	u8 revision; | ||||
| 	u8 max_supported_clock_speed_index; | ||||
| 	u8 uma_enabled; | ||||
| 	u8 spd[2][2][151];	/* [CHANNEL][SLOT][BYTE]  */ | ||||
| 	u8 silicon_revision; | ||||
| 	u8 populated_ranks_mask[2]; | ||||
| 	u8 max_slots_used_in_channel; | ||||
| 	u8 mode4030[2]; | ||||
| 	u16 avg4044[2]; | ||||
| 	u16 max4048[2]; | ||||
| 	unsigned int total_memory_mb; | ||||
| 	unsigned int interleaved_part_mb; | ||||
| 	unsigned int non_interleaved_part_mb; | ||||
|  | ||||
| 	unsigned int memory_reserved_for_heci_mb; | ||||
|  | ||||
| 	struct ram_training training; | ||||
| 	u32 last_500_command[2]; | ||||
|  | ||||
| 	u32 delay46_ps[2]; | ||||
| 	u32 delay54_ps[2]; | ||||
| 	u8 revision_flag_1; | ||||
| 	u8 some_delay_1_cycle_floor; | ||||
| 	u8 some_delay_2_halfcycles_ceil; | ||||
| 	u8 some_delay_3_ps_rounded; | ||||
|  | ||||
| 	const struct ram_training *cached_training; | ||||
| }; | ||||
|  | ||||
| static inline unsigned int fsbcycle_ps(struct raminfo *info) | ||||
| { | ||||
| 	return 900000 / info->fsb_frequency; | ||||
| } | ||||
|  | ||||
| /* The time of DDR transfer in ps.  */ | ||||
| static inline unsigned int halfcycle_ps(struct raminfo *info) | ||||
| { | ||||
| 	return 3750 / (info->clock_speed_index + 3); | ||||
| } | ||||
|  | ||||
| /* Frequency in 1.(1)=10/9 MHz units. */ | ||||
| static inline unsigned int frequency_11(struct raminfo *info) | ||||
| { | ||||
| 	return (info->clock_speed_index + 3) * 120; | ||||
| } | ||||
|  | ||||
| void chipset_init(const int s3resume); | ||||
| /* spd_addrmap is array of 4 elements: | ||||
|    Channel 0 Slot 0 | ||||
| @@ -15,4 +102,7 @@ void chipset_init(const int s3resume); | ||||
| */ | ||||
| void raminit(const int s3resume, const u8 *spd_addrmap); | ||||
|  | ||||
| u16 get_max_timing(struct raminfo *info, int channel); | ||||
| void late_quickpath_init(struct raminfo *info, const int s3resume); | ||||
|  | ||||
| #endif				/* RAMINIT_H */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user