Skip to content
Snippets Groups Projects
44x_spd_ddr.c 39.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • 		{0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
    		 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5},
    		{0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
    		 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA},
    		{0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55,
    		 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55}};
    
    	for (bxcr_num = 0; bxcr_num < MAXBXCR; bxcr_num++) {
    		mtdcr(memcfga, mem_b0cr + (bxcr_num << 2));
    		if ((mfdcr(memcfgd) & SDRAM_BXCR_SDBE) == SDRAM_BXCR_SDBE) {
    			/* Bank is enabled */
    			membase = (unsigned long*)
    				(mfdcr(memcfgd) & SDRAM_BXCR_SDBA_MASK);
    
    			/*
    			 * Run the short memory test
    			 */
    			for (i = 0; i < NUMMEMTESTS; i++) {
    				for (j = 0; j < NUMMEMWORDS; j++) {
    
    					/* printf("bank enabled base:%x\n", &membase[j]); */
    
    					membase[j] = test[i][j];
    					ppcDcbf((unsigned long)&(membase[j]));
    				}
    
    				for (j = 0; j < NUMMEMWORDS; j++) {
    					if (membase[j] != test[i][j]) {
    						ppcDcbf((unsigned long)&(membase[j]));
    						return 0;
    					}
    					ppcDcbf((unsigned long)&(membase[j]));
    				}
    
    				if (j < NUMMEMWORDS)
    					return 0;
    			}
    
    			/*
    			 * see if the rdclt value passed
    			 */
    			if (i < NUMMEMTESTS)
    				return 0;
    		}
    	}
    
    	return 1;
    }
    
    static void program_tr1(void)
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    {
    
    	unsigned long tr0;
    	unsigned long tr1;
    	unsigned long cfg0;
    	unsigned long ecc_temp;
    	unsigned long dlycal;
    	unsigned long dly_val;
    
    	unsigned long max_pass_length;
    	unsigned long current_pass_length;
    	unsigned long current_fail_length;
    	unsigned long current_start;
    	unsigned long rdclt;
    	unsigned long rdclt_offset;
    	long max_start;
    	long max_end;
    	long rdclt_average;
    	unsigned char window_found;
    	unsigned char fail_found;
    	unsigned char pass_found;
    	PPC440_SYS_INFO sys_info;
    
    	/*
    	 * get the board info
    	 */
    	get_sys_info(&sys_info);
    
    	/*
    	 * get SDRAM Timing Register 0 (SDRAM_TR0) and clear bits
    	 */
    	mfsdram(mem_tr1, tr1);
    	tr1 &= ~(SDRAM_TR1_RDSS_MASK | SDRAM_TR1_RDSL_MASK |
    		 SDRAM_TR1_RDCD_MASK | SDRAM_TR1_RDCT_MASK);
    
    	mfsdram(mem_tr0, tr0);
    	if (((tr0 & SDRAM_TR0_SDCL_MASK) == SDRAM_TR0_SDCL_2_5_CLK) &&
    	    (sys_info.freqPLB > 100000000)) {
    		tr1 |= SDRAM_TR1_RDSS_TR2;
    		tr1 |= SDRAM_TR1_RDSL_STAGE3;
    		tr1 |= SDRAM_TR1_RDCD_RCD_1_2;
    	} else {
    		tr1 |= SDRAM_TR1_RDSS_TR1;
    		tr1 |= SDRAM_TR1_RDSL_STAGE2;
    		tr1 |= SDRAM_TR1_RDCD_RCD_0_0;
    	}
    
    	/*
    	 * save CFG0 ECC setting to a temporary variable and turn ECC off
    	 */
    	mfsdram(mem_cfg0, cfg0);
    	ecc_temp = cfg0 & SDRAM_CFG0_MCHK_MASK;
    	mtsdram(mem_cfg0, (cfg0 & ~SDRAM_CFG0_MCHK_MASK) | SDRAM_CFG0_MCHK_NON);
    
    	/*
    	 * get the delay line calibration register value
    	 */
    	mfsdram(mem_dlycal, dlycal);
    	dly_val = SDRAM_DLYCAL_DLCV_DECODE(dlycal) << 2;
    
    	max_pass_length = 0;
    	max_start = 0;
    	max_end = 0;
    	current_pass_length = 0;
    	current_fail_length = 0;
    	current_start = 0;
    	rdclt_offset = 0;
    	window_found = FALSE;
    	fail_found = FALSE;
    	pass_found = FALSE;
    
    	for (k = 0; k < NUMHALFCYCLES; k++) {
    
    		for (rdclt = 0; rdclt < dly_val; rdclt++) {
    
    			/*
    			 * Set the timing reg for the test.
    			 */
    			mtsdram(mem_tr1, (tr1 | SDRAM_TR1_RDCT_ENCODE(rdclt)));
    
    
    				if (fail_found == TRUE) {
    					pass_found = TRUE;
    					if (current_pass_length == 0) {
    						current_start = rdclt_offset + rdclt;
    					}
    
    					current_fail_length = 0;
    					current_pass_length++;
    
    					if (current_pass_length > max_pass_length) {
    						max_pass_length = current_pass_length;
    						max_start = current_start;
    						max_end = rdclt_offset + rdclt;
    					}
    				}
    			} else {
    				current_pass_length = 0;
    				current_fail_length++;
    
    				if (current_fail_length >= (dly_val>>2)) {
    					if (fail_found == FALSE) {
    						fail_found = TRUE;
    					} else if (pass_found == TRUE) {
    						window_found = TRUE;
    						break;
    					}
    				}
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    			}
    		}
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    			break;
    		}
    
    
    		tr1 = tr1 ^ SDRAM_TR1_RDCD_MASK;
    		rdclt_offset += dly_val;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	}
    
    
    	/*
    	 * make sure we find the window
    	 */
    	if (window_found == FALSE) {
    		printf("ERROR: Cannot determine a common read delay.\n");
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	}
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    
    	/*
    	 * restore the orignal ECC setting
    	 */
    	mtsdram(mem_cfg0, (cfg0 & ~SDRAM_CFG0_MCHK_MASK) | ecc_temp);
    
    	/*
    	 * set the SDRAM TR1 RDCD value
    	 */
    	tr1 &= ~SDRAM_TR1_RDCD_MASK;
    	if ((tr0 & SDRAM_TR0_SDCL_MASK) == SDRAM_TR0_SDCL_2_5_CLK) {
    		tr1 |= SDRAM_TR1_RDCD_RCD_1_2;
    	} else {
    		tr1 |= SDRAM_TR1_RDCD_RCD_0_0;
    	}
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    
    	/*
    	 * set the SDRAM TR1 RDCLT value
    	 */
    	tr1 &= ~SDRAM_TR1_RDCT_MASK;
    	while (max_end >= (dly_val << 1)) {
    		max_end -= (dly_val << 1);
    		max_start -= (dly_val << 1);
    	}
    
    	rdclt_average = ((max_start + max_end) >> 1);
    	if (rdclt_average >= 0x60)
    		while (1)
    			;
    
    	if (rdclt_average < 0) {
    		rdclt_average = 0;
    	}
    
    	if (rdclt_average >= dly_val) {
    		rdclt_average -= dly_val;
    		tr1 = tr1 ^ SDRAM_TR1_RDCD_MASK;
    	}
    	tr1 |= SDRAM_TR1_RDCT_ENCODE(rdclt_average);
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    
    	/*
    	 * program SDRAM Timing Register 1 TR1
    	 */
    	mtsdram(mem_tr1, tr1);
    
    static unsigned long program_bxcr(unsigned long *dimm_populated,
    				  unsigned char *iic0_dimm_addr,
    				  unsigned long num_dimm_banks)
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    {
    
    	unsigned long dimm_num;
    	unsigned long bank_base_addr;
    	unsigned long cr;
    	unsigned long i;
    
    	unsigned long temp;
    	unsigned char num_row_addr;
    	unsigned char num_col_addr;
    	unsigned char num_banks;
    	unsigned char bank_size_id;
    
    	unsigned long ctrl_bank_num[MAXBANKS];
    	unsigned long bx_cr_num;
    	unsigned long largest_size_index;
    
    	unsigned long largest_size;
    	unsigned long current_size_index;
    
    	BANKPARMS bank_parms[MAXBXCR];
    	unsigned long sorted_bank_num[MAXBXCR]; /* DDR Controller bank number table (sorted by size) */
    	unsigned long sorted_bank_size[MAXBXCR]; /* DDR Controller bank size table (sorted by size)*/
    
    
    	/*
    	 * Set the BxCR regs.  First, wipe out the bank config registers.
    	 */
    
    	for (bx_cr_num = 0; bx_cr_num < MAXBXCR; bx_cr_num++) {
    		mtdcr(memcfga, mem_b0cr + (bx_cr_num << 2));
    
    		bank_parms[bx_cr_num].bank_size_bytes = 0;
    
    
    #ifdef CONFIG_BAMBOO
    	/*
    	 * This next section is hardware dependent and must be programmed
    
    	 * to match the hardware.  For bamboo, the following holds...
    	 * 1. SDRAM0_B0CR: Bank 0 of dimm 0 ctrl_bank_num : 0 (soldered onboard)
    
    	 * 2. SDRAM0_B1CR: Bank 0 of dimm 1 ctrl_bank_num : 1
    	 * 3. SDRAM0_B2CR: Bank 1 of dimm 1 ctrl_bank_num : 1
    	 * 4. SDRAM0_B3CR: Bank 0 of dimm 2 ctrl_bank_num : 3
    	 * ctrl_bank_num corresponds to the first usable DDR controller bank number by DIMM
    	 */
    	ctrl_bank_num[0] = 0;
    	ctrl_bank_num[1] = 1;
    	ctrl_bank_num[2] = 3;
    #else
    
    	/*
    	 * Ocotea, Ebony and the other IBM/AMCC eval boards have
    	 * 2 DIMM slots with each max 2 banks
    	 */
    
    
    	/*
    	 * reset the bank_base address
    	 */
    	bank_base_addr = CFG_SDRAM_BASE;
    
    	for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
    		if (dimm_populated[dimm_num] == TRUE) {
    			num_row_addr = spd_read(iic0_dimm_addr[dimm_num], 3);
    			num_col_addr = spd_read(iic0_dimm_addr[dimm_num], 4);
    			num_banks    = spd_read(iic0_dimm_addr[dimm_num], 5);
    			bank_size_id = spd_read(iic0_dimm_addr[dimm_num], 31);
    
    			debug("DIMM%d: row=%d col=%d banks=%d\n", dimm_num,
    			      num_row_addr, num_col_addr, num_banks);
    
    
    			/*
    			 * Set the SDRAM0_BxCR regs
    			 */
    			cr = 0;
    			switch (bank_size_id) {
    			case 0x02:
    				cr |= SDRAM_BXCR_SDSZ_8;
    				break;
    			case 0x04:
    				cr |= SDRAM_BXCR_SDSZ_16;
    				break;
    			case 0x08:
    				cr |= SDRAM_BXCR_SDSZ_32;
    				break;
    			case 0x10:
    				cr |= SDRAM_BXCR_SDSZ_64;
    				break;
    			case 0x20:
    				cr |= SDRAM_BXCR_SDSZ_128;
    				break;
    			case 0x40:
    				cr |= SDRAM_BXCR_SDSZ_256;
    				break;
    			case 0x80:
    				cr |= SDRAM_BXCR_SDSZ_512;
    				break;
    			default:
    				printf("DDR-SDRAM: DIMM %lu BxCR configuration.\n",
    				       dimm_num);
    				printf("ERROR: Unsupported value for the banksize: %d.\n",
    				       bank_size_id);
    				printf("Replace the DIMM module with a supported DIMM.\n\n");
    
    			}
    
    			switch (num_col_addr) {
    			case 0x08:
    				cr |= SDRAM_BXCR_SDAM_1;
    				break;
    			case 0x09:
    				cr |= SDRAM_BXCR_SDAM_2;
    				break;
    			case 0x0A:
    				cr |= SDRAM_BXCR_SDAM_3;
    				break;
    			case 0x0B:
    				cr |= SDRAM_BXCR_SDAM_4;
    				break;
    			default:
    				printf("DDR-SDRAM: DIMM %lu BxCR configuration.\n",
    				       dimm_num);
    				printf("ERROR: Unsupported value for number of "
    				       "column addresses: %d.\n", num_col_addr);
    				printf("Replace the DIMM module with a supported DIMM.\n\n");
    
    			for (i = 0; i < num_banks; i++) {
    
    				bank_parms[ctrl_bank_num[dimm_num]+i].bank_size_bytes =
    					(4 << 20) * bank_size_id;
    				bank_parms[ctrl_bank_num[dimm_num]+i].cr = cr;
    				debug("DIMM%d-bank %d (SDRAM0_B%dCR): bank_size_bytes=%d\n",
    				      dimm_num, i, ctrl_bank_num[dimm_num]+i,
    				      bank_parms[ctrl_bank_num[dimm_num]+i].bank_size_bytes);
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    		}
    	}
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    
    	/* Initialize sort tables */
    	for (i = 0; i < MAXBXCR; i++) {
    		sorted_bank_num[i] = i;
    		sorted_bank_size[i] = bank_parms[i].bank_size_bytes;
    	}
    
    	for (i = 0; i < MAXBXCR-1; i++) {
    		largest_size = sorted_bank_size[i];
    		largest_size_index = 255;
    
    		/* Find the largest remaining value */
    		for (j = i + 1; j < MAXBXCR; j++) {
    			if (sorted_bank_size[j] > largest_size) {
    				/* Save largest remaining value and its index */
    				largest_size = sorted_bank_size[j];
    				largest_size_index = j;
    			}
    		}
    
    		if (largest_size_index != 255) {
    			/* Swap the current and largest values */
    			current_size_index = sorted_bank_num[largest_size_index];
    			sorted_bank_size[largest_size_index] = sorted_bank_size[i];
    			sorted_bank_size[i] = largest_size;
    			sorted_bank_num[largest_size_index] = sorted_bank_num[i];
    			sorted_bank_num[i] = current_size_index;
    		}
    	}
    
    	/* Set the SDRAM0_BxCR regs thanks to sort tables */
    	for (bx_cr_num = 0, bank_base_addr = 0; bx_cr_num < MAXBXCR; bx_cr_num++) {
    		if (bank_parms[sorted_bank_num[bx_cr_num]].bank_size_bytes) {
    			mtdcr(memcfga, mem_b0cr + (sorted_bank_num[bx_cr_num] << 2));
    			temp = mfdcr(memcfgd) & ~(SDRAM_BXCR_SDBA_MASK | SDRAM_BXCR_SDSZ_MASK |
    						  SDRAM_BXCR_SDAM_MASK | SDRAM_BXCR_SDBE);
    			temp = temp | (bank_base_addr & SDRAM_BXCR_SDBA_MASK) |
    				bank_parms[sorted_bank_num[bx_cr_num]].cr;
    			mtdcr(memcfgd, temp);
    			bank_base_addr += bank_parms[sorted_bank_num[bx_cr_num]].bank_size_bytes;
    
    			debug("SDRAM0_B%dCR=0x%08lx\n", sorted_bank_num[bx_cr_num], temp);
    
    #ifdef CONFIG_DDR_ECC
    static void program_ecc(unsigned long num_bytes)
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    {
    
    	unsigned long bank_base_addr;
    	unsigned long current_address;
    	unsigned long end_address;
    	unsigned long address_increment;
    	unsigned long cfg0;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    
    	/*
    	 * get Memory Controller Options 0 data
    	 */
    	mfsdram(mem_cfg0, cfg0);
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    
    	/*
    	 * reset the bank_base address
    	 */
    	bank_base_addr = CFG_SDRAM_BASE;
    
    	if ((cfg0 & SDRAM_CFG0_MCHK_MASK) != SDRAM_CFG0_MCHK_NON) {
    
    		mtsdram(mem_cfg0, (cfg0 & ~SDRAM_CFG0_MCHK_MASK) | SDRAM_CFG0_MCHK_GEN);
    
    		if ((cfg0 & SDRAM_CFG0_DMWD_MASK) == SDRAM_CFG0_DMWD_32)
    
    			address_increment = 8;
    
    		current_address = (unsigned long)(bank_base_addr);
    		end_address = (unsigned long)(bank_base_addr) + num_bytes;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    
    		while (current_address < end_address) {
    			*((unsigned long*)current_address) = 0x00000000;
    			current_address += address_increment;
    		}
    
    		mtsdram(mem_cfg0, (cfg0 & ~SDRAM_CFG0_MCHK_MASK) |
    			SDRAM_CFG0_MCHK_CHK);
    	}
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    }
    
    #endif /* CONFIG_DDR_ECC */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    #endif /* CONFIG_SPD_EEPROM */