diff options
Diffstat (limited to 'arch/powerpc/cpu/mpc8220/dramSetup.c')
| -rw-r--r-- | arch/powerpc/cpu/mpc8220/dramSetup.c | 752 | 
1 files changed, 752 insertions, 0 deletions
| diff --git a/arch/powerpc/cpu/mpc8220/dramSetup.c b/arch/powerpc/cpu/mpc8220/dramSetup.c new file mode 100644 index 000000000..52cf1333f --- /dev/null +++ b/arch/powerpc/cpu/mpc8220/dramSetup.c @@ -0,0 +1,752 @@ +/* + * (C) Copyright 2004, Freescale, Inc + * TsiChung Liew, Tsi-Chung.Liew@freescale.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* +DESCRIPTION +Read Dram spd and base on its information to calculate the memory size, +characteristics to initialize the dram on MPC8220 +*/ + +#include <common.h> +#include <mpc8220.h> +#include "i2cCore.h" +#include "dramSetup.h" + +DECLARE_GLOBAL_DATA_PTR; + +#define SPD_SIZE	CONFIG_SYS_SDRAM_SPD_SIZE +#define DRAM_SPD	(CONFIG_SYS_SDRAM_SPD_I2C_ADDR)<<1	/* on Board SPD eeprom */ +#define TOTAL_BANK	CONFIG_SYS_SDRAM_TOTAL_BANKS + +int spd_status (volatile i2c8220_t * pi2c, u8 sta_bit, u8 truefalse) +{ +	int i; + +	for (i = 0; i < I2C_POLL_COUNT; i++) { +		if ((pi2c->sr & sta_bit) == (truefalse ? sta_bit : 0)) +			return (OK); +	} + +	return (ERROR); +} + +int spd_clear (volatile i2c8220_t * pi2c) +{ +	pi2c->adr = 0; +	pi2c->fdr = 0; +	pi2c->cr = 0; +	pi2c->sr = 0; + +	return (OK); +} + +int spd_stop (volatile i2c8220_t * pi2c) +{ +	pi2c->cr &= ~I2C_CTL_STA;	/* Generate stop signal         */ +	if (spd_status (pi2c, I2C_STA_BB, 0) != OK) +		return ERROR; + +	return (OK); +} + +int spd_readbyte (volatile i2c8220_t * pi2c, u8 * readb, int *index) +{ +	pi2c->sr &= ~I2C_STA_IF;	/* Clear Interrupt Bit          */ +	*readb = pi2c->dr;	/* Read a byte                  */ + +	/* +	   Set I2C_CTRL_TXAK will cause Transfer pending and +	   set I2C_CTRL_STA will cause Interrupt pending +	 */ +	if (*index != 2) { +		if (spd_status (pi2c, I2C_STA_CF, 1) != OK)	/* Transfer not complete?       */ +			return ERROR; +	} + +	if (*index != 1) { +		if (spd_status (pi2c, I2C_STA_IF, 1) != OK) +			return ERROR; +	} + +	return (OK); +} + +int readSpdData (u8 * spdData) +{ +	volatile i2c8220_t *pi2cReg; +	volatile pcfg8220_t *pcfg; +	u8 slvAdr = DRAM_SPD; +	u8 Tmp; +	int Length = SPD_SIZE; +	int i = 0; + +	/* Enable Port Configuration for SDA and SDL signals */ +	pcfg = (volatile pcfg8220_t *) (MMAP_PCFG); +	__asm__ ("sync"); +	pcfg->pcfg3 &= ~CONFIG_SYS_I2C_PORT3_CONFIG; +	__asm__ ("sync"); + +	/* Points the structure to I2c mbar memory offset */ +	pi2cReg = (volatile i2c8220_t *) (MMAP_I2C); + + +	/* Clear FDR, ADR, SR and CR reg */ +	pi2cReg->adr = 0; +	pi2cReg->fdr = 0; +	pi2cReg->cr = 0; +	pi2cReg->sr = 0; + +	/* Set for fix XLB Bus Frequency */ +	switch (gd->bus_clk) { +	case 60000000: +		pi2cReg->fdr = 0x15; +		break; +	case 70000000: +		pi2cReg->fdr = 0x16; +		break; +	case 80000000: +		pi2cReg->fdr = 0x3a; +		break; +	case 90000000: +		pi2cReg->fdr = 0x17; +		break; +	case 100000000: +		pi2cReg->fdr = 0x3b; +		break; +	case 110000000: +		pi2cReg->fdr = 0x18; +		break; +	case 120000000: +		pi2cReg->fdr = 0x19; +		break; +	case 130000000: +		pi2cReg->fdr = 0x1a; +		break; +	} + +	pi2cReg->adr = CONFIG_SYS_I2C_SLAVE<<1; + +	pi2cReg->cr = I2C_CTL_EN;	/* Set Enable         */ + +	/* +	   The I2C bus should be in Idle state. If the bus is busy, +	   clear the STA bit in control register +	 */ +	if (spd_status (pi2cReg, I2C_STA_BB, 0) != OK) { +		if ((pi2cReg->cr & I2C_CTL_STA) == I2C_CTL_STA) +			pi2cReg->cr &= ~I2C_CTL_STA; + +		/* Check again if it is still busy, return error if found */ +		if (spd_status (pi2cReg, I2C_STA_BB, 1) == OK) +			return ERROR; +	} + +	pi2cReg->cr |= I2C_CTL_TX;	/* Enable the I2c for TX, Ack   */ +	pi2cReg->cr |= I2C_CTL_STA;	/* Generate start signal        */ + +	if (spd_status (pi2cReg, I2C_STA_BB, 1) != OK) +		return ERROR; + + +	/* Write slave address */ +	pi2cReg->sr &= ~I2C_STA_IF;	/* Clear Interrupt              */ +	pi2cReg->dr = slvAdr;	/* Write a byte                 */ + +	if (spd_status (pi2cReg, I2C_STA_CF, 1) != OK) {	/* Transfer not complete?       */ +		spd_stop (pi2cReg); +		return ERROR; +	} + +	if (spd_status (pi2cReg, I2C_STA_IF, 1) != OK) { +		spd_stop (pi2cReg); +		return ERROR; +	} + + +	/* Issue the offset to start */ +	pi2cReg->sr &= ~I2C_STA_IF;	/* Clear Interrupt              */ +	pi2cReg->dr = 0;	/* Write a byte                 */ + +	if (spd_status (pi2cReg, I2C_STA_CF, 1) != OK) {	/* Transfer not complete?       */ +		spd_stop (pi2cReg); +		return ERROR; +	} + +	if (spd_status (pi2cReg, I2C_STA_IF, 1) != OK) { +		spd_stop (pi2cReg); +		return ERROR; +	} + + +	/* Set repeat start */ +	pi2cReg->cr |= I2C_CTL_RSTA;	/* Repeat Start                 */ + +	pi2cReg->sr &= ~I2C_STA_IF;	/* Clear Interrupt              */ +	pi2cReg->dr = slvAdr | 1;	/* Write a byte                 */ + +	if (spd_status (pi2cReg, I2C_STA_CF, 1) != OK) {	/* Transfer not complete?       */ +		spd_stop (pi2cReg); +		return ERROR; +	} + +	if (spd_status (pi2cReg, I2C_STA_IF, 1) != OK) { +		spd_stop (pi2cReg); +		return ERROR; +	} + +	if (((pi2cReg->sr & 0x07) == 0x07) || (pi2cReg->sr & 0x01)) +		return ERROR; + +	pi2cReg->cr &= ~I2C_CTL_TX;	/* Set receive mode             */ + +	if (((pi2cReg->sr & 0x07) == 0x07) || (pi2cReg->sr & 0x01)) +		return ERROR; + +	/* Dummy Read */ +	if (spd_readbyte (pi2cReg, &Tmp, &i) != OK) { +		spd_stop (pi2cReg); +		return ERROR; +	} + +	i = 0; +	while (Length) { +		if (Length == 2) +			pi2cReg->cr |= I2C_CTL_TXAK; + +		if (Length == 1) +			pi2cReg->cr &= ~I2C_CTL_STA; + +		if (spd_readbyte (pi2cReg, spdData, &Length) != OK) { +			return spd_stop (pi2cReg); +		} +		i++; +		Length--; +		spdData++; +	} + +	/* Stop the service */ +	spd_stop (pi2cReg); + +	return OK; +} + +int getBankInfo (int bank, draminfo_t * pBank) +{ +	int status; +	int checksum; +	int count; +	u8 spdData[SPD_SIZE]; + + +	if (bank > 2 || pBank == 0) { +		/* illegal values */ +		return (-42); +	} + +	status = readSpdData (&spdData[0]); +	if (status < 0) +		return (-1); + +	/* check the checksum */ +	for (count = 0, checksum = 0; count < LOC_CHECKSUM; count++) +		checksum += spdData[count]; + +	checksum = checksum - ((checksum / 256) * 256); + +	if (checksum != spdData[LOC_CHECKSUM]) +		return (-2); + +	/* Get the memory type */ +	if (! +	    ((spdData[LOC_TYPE] == TYPE_DDR) +	     || (spdData[LOC_TYPE] == TYPE_SDR))) +		/* not one of the types we support */ +		return (-3); + +	pBank->type = spdData[LOC_TYPE]; + +	/* Set logical banks */ +	pBank->banks = spdData[LOC_LOGICAL_BANKS]; + +	/* Check that we have enough physical banks to cover the bank we are +	 * figuring out.  Odd-numbered banks correspond to the second bank +	 * on the device. +	 */ +	if (bank & 1) { +		/* Second bank of a "device" */ +		if (spdData[LOC_PHYS_BANKS] < 2) +			/* this bank doesn't exist on the "device" */ +			return (-4); + +		if (spdData[LOC_ROWS] & 0xf0) +			/* Two asymmetric banks */ +			pBank->rows = spdData[LOC_ROWS] >> 4; +		else +			pBank->rows = spdData[LOC_ROWS]; + +		if (spdData[LOC_COLS] & 0xf0) +			/* Two asymmetric banks */ +			pBank->cols = spdData[LOC_COLS] >> 4; +		else +			pBank->cols = spdData[LOC_COLS]; +	} else { +		/* First bank of a "device" */ +		pBank->rows = spdData[LOC_ROWS]; +		pBank->cols = spdData[LOC_COLS]; +	} + +	pBank->width = spdData[LOC_WIDTH_HIGH] << 8 | spdData[LOC_WIDTH_LOW]; +	pBank->bursts = spdData[LOC_BURSTS]; +	pBank->CAS = spdData[LOC_CAS]; +	pBank->CS = spdData[LOC_CS]; +	pBank->WE = spdData[LOC_WE]; +	pBank->Trp = spdData[LOC_Trp]; +	pBank->Trcd = spdData[LOC_Trcd]; +	pBank->buffered = spdData[LOC_Buffered] & 1; +	pBank->refresh = spdData[LOC_REFRESH]; + +	return (0); +} + + +/* checkMuxSetting -- given a row/column device geometry, return a mask + *                    of the valid DRAM controller addr_mux settings for + *                    that geometry. + * + *  Arguments:        u8 rows:     number of row addresses in this device + *                    u8 columns:  number of column addresses in this device + * + *  Returns:          a mask of the allowed addr_mux settings for this + *                    geometry.  Each bit in the mask represents a + *                    possible addr_mux settings (for example, the + *                    (1<<2) bit in the mask represents the 0b10 setting)/ + * + */ +u8 checkMuxSetting (u8 rows, u8 columns) +{ +	muxdesc_t *pIdx, *pMux; +	u8 mask; +	int lrows, lcolumns; +	u32 mux[4] = { 0x00080c04, 0x01080d03, 0x02080e02, 0xffffffff }; + +	/* Setup MuxDescriptor in SRAM space */ +	/* MUXDESC AddressRuns [] = { +	   { 0, 8, 12, 4 },         / setting, columns, rows, extra columns / +	   { 1, 8, 13, 3 },         / setting, columns, rows, extra columns / +	   { 2, 8, 14, 2 },         / setting, columns, rows, extra columns / +	   { 0xff }                 / list terminator / +	   }; */ + +	pIdx = (muxdesc_t *) & mux[0]; + +	/* Check rows x columns against each possible address mux setting */ +	for (pMux = pIdx, mask = 0;; pMux++) { +		lrows = rows; +		lcolumns = columns; + +		if (pMux->MuxValue == 0xff) +			break;	/* end of list */ + +		/* For a given mux setting, since we want all the memory in a +		 * device to be contiguous, we want the device "use up" the +		 * address lines such that there are no extra column or row +		 * address lines on the device. +		 */ + +		lcolumns -= pMux->Columns; +		if (lcolumns < 0) +			/* Not enough columns to get to the rows */ +			continue; + +		lrows -= pMux->Rows; +		if (lrows > 0) +			/* we have extra rows left -- can't do that! */ +			continue; + +		/* At this point, we either have to have used up all the +		 * rows or we have to have no columns left. +		 */ + +		if (lcolumns != 0 && lrows != 0) +			/* rows AND columns are left.  Bad! */ +			continue; + +		lcolumns -= pMux->MoreColumns; + +		if (lcolumns <= 0) +			mask |= (1 << pMux->MuxValue); +	} + +	return (mask); +} + + +u32 dramSetup (void) +{ +	draminfo_t DramInfo[TOTAL_BANK]; +	draminfo_t *pDramInfo; +	u32 size, temp, cfg_value, mode_value, refresh; +	u8 *ptr; +	u8 bursts, Trp, Trcd, type, buffered; +	u8 muxmask, rows, columns; +	int count, banknum; +	u32 *prefresh, *pIdx; +	u32 refrate[8] = { 15625, 3900, 7800, 31300, +		62500, 125000, 0xffffffff, 0xffffffff +	}; +	volatile sysconf8220_t *sysconf; +	volatile memctl8220_t *memctl; + +	sysconf = (volatile sysconf8220_t *) MMAP_MBAR; +	memctl = (volatile memctl8220_t *) MMAP_MEMCTL; + +	/* Set everything in the descriptions to zero */ +	ptr = (u8 *) & DramInfo[0]; +	for (count = 0; count < sizeof (DramInfo); count++) +		*ptr++ = 0; + +	for (banknum = 0; banknum < TOTAL_BANK; banknum++) +		sysconf->cscfg[banknum]; + +	/* Descriptions of row/column address muxing for various +	 * addr_mux settings. +	 */ + +	pIdx = prefresh = (u32 *) & refrate[0]; + +	/* Get all the info for all three logical banks */ +	bursts = 0xff; +	Trp = 0; +	Trcd = 0; +	type = 0; +	buffered = 0xff; +	refresh = 0xffffffff; +	muxmask = 0xff; + +	/* Two bank, CS0 and CS1 */ +	for (banknum = 0, pDramInfo = &DramInfo[0]; +	     banknum < TOTAL_BANK; banknum++, pDramInfo++) { +		pDramInfo->ordinal = banknum;	/* initial sorting */ +		if (getBankInfo (banknum, pDramInfo) < 0) +			continue; + +		/* get cumulative parameters of all three banks */ +		if (type && pDramInfo->type != type) +			return 0; + +		type = pDramInfo->type; +		rows = pDramInfo->rows; +		columns = pDramInfo->cols; + +		/* This chip only supports 13 DRAM memory lines, but some devices +		 * have 14 rows.  To deal with this, ignore the 14th address line +		 * by limiting the number of rows (and columns) to 13.  This will +		 * mean that for 14-row devices we will only be able to use +		 * half of the memory, but it's better than nothing. +		 */ +		if (rows > 13) +			rows = 13; +		if (columns > 13) +			columns = 13; + +		pDramInfo->size = +			((1 << (rows + columns)) * pDramInfo->width); +		pDramInfo->size *= pDramInfo->banks; +		pDramInfo->size >>= 3; + +		/* figure out which addr_mux configurations will support this device */ +		muxmask &= checkMuxSetting (rows, columns); +		if (muxmask == 0) +			return 0; + +		buffered = pDramInfo->buffered; +		bursts &= pDramInfo->bursts;	/* union of all bursts */ +		if (pDramInfo->Trp > Trp)	/* worst case (longest) Trp */ +			Trp = pDramInfo->Trp; + +		if (pDramInfo->Trcd > Trcd)	/* worst case (longest) Trcd */ +			Trcd = pDramInfo->Trcd; + +		prefresh = pIdx; +		/* worst case (shortest) Refresh period */ +		if (refresh > prefresh[pDramInfo->refresh & 7]) +			refresh = prefresh[pDramInfo->refresh & 7]; + +	}			/* for loop */ + + +	/* We only allow a burst length of 8! */ +	if (!(bursts & 8)) +		bursts = 8; + +	/* Sort the devices.  In order to get each chip select region +	 * aligned properly, put the biggest device at the lowest address. +	 * A simple bubble sort will do the trick. +	 */ +	for (banknum = 0, pDramInfo = &DramInfo[0]; +	     banknum < TOTAL_BANK; banknum++, pDramInfo++) { +		int i; + +		for (i = 0; i < TOTAL_BANK; i++) { +			if (pDramInfo->size < DramInfo[i].size && +			    pDramInfo->ordinal < DramInfo[i].ordinal) { +				/* If the current bank is smaller, but if the ordinal is also +				 * smaller, swap the ordinals +				 */ +				u8 temp8; + +				temp8 = DramInfo[i].ordinal; +				DramInfo[i].ordinal = pDramInfo->ordinal; +				pDramInfo->ordinal = temp8; +			} +		} +	} + + +	/* Now figure out the base address for each bank.  While +	 * we're at it, figure out how much memory there is. +	 * +	 */ +	size = 0; +	for (banknum = 0; banknum < TOTAL_BANK; banknum++) { +		int i; + +		for (i = 0; i < TOTAL_BANK; i++) { +			if (DramInfo[i].ordinal == banknum +			    && DramInfo[i].size != 0) { +				DramInfo[i].base = size; +				size += DramInfo[i].size; +			} +		} +	} + +	/* Set up the Drive Strength register */ +	sysconf->sdramds = CONFIG_SYS_SDRAM_DRIVE_STRENGTH; + +	/* ********************** Cfg 1 ************************* */ + +	/* Set the single read to read/write/precharge delay */ +	cfg_value = CFG1_SRD2RWP ((type == TYPE_DDR) ? 7 : 0xb); + +	/* Set the single write to read/write/precharge delay. +	 * This may or may not be correct.  The controller spec +	 * says "tWR", but "tWR" does not appear in the SPD.  It +	 * always seems to be 15nsec for the class of device we're +	 * using, which turns out to be 2 clock cycles at 133MHz, +	 * so that's what we're going to use. +	 * +	 * HOWEVER, because of a bug in the controller, for DDR +	 * we need to set this to be the same as the value +	 * calculated for bwt2rwp. +	 */ +	cfg_value |= CFG1_SWT2RWP ((type == TYPE_DDR) ? 7 : 2); + +	/* Set the Read CAS latency.  We're going to use a CL of +	 * 2.5 for DDR and 2 SDR. +	 */ +	cfg_value |= CFG1_RLATENCY ((type == TYPE_DDR) ? 7 : 2); + + +	/* Set the Active to Read/Write delay.  This depends +	 * on Trcd which is reported as nanoseconds times 4. +	 * We want to calculate Trcd (in nanoseconds) times XLB clock (in Hz) +	 * which gives us a dimensionless quantity.  Play games with +	 * the divisions so we don't run out of dynamic ranges. +	 */ +	/* account for megaherz and the times 4 */ +	temp = (Trcd * (gd->bus_clk / 1000000)) / 4; + +	/* account for nanoseconds and round up, with a minimum value of 2 */ +	temp = ((temp + 999) / 1000) - 1; +	if (temp < 2) +		temp = 2; + +	cfg_value |= CFG1_ACT2WR (temp); + +	/* Set the precharge to active delay.  This depends +	 * on Trp which is reported as nanoseconds times 4. +	 * We want to calculate Trp (in nanoseconds) times XLB clock (in Hz) +	 * which gives us a dimensionless quantity.  Play games with +	 * the divisions so we don't run out of dynamic ranges. +	 */ +	/* account for megaherz and the times 4 */ +	temp = (Trp * (gd->bus_clk / 1000000)) / 4; + +	/* account for nanoseconds and round up, then subtract 1, with a +	 * minumum value of 1 and a maximum value of 7. +	 */ +	temp = (((temp + 999) / 1000) - 1) & 7; +	if (temp < 1) +		temp = 1; + +	cfg_value |= CFG1_PRE2ACT (temp); + +	/* Set refresh to active delay.  This depends +	 * on Trfc which is not reported in the SPD. +	 * We'll use a nominal value of 75nsec which is +	 * what the controller spec uses. +	 */ +	temp = (75 * (gd->bus_clk / 1000000)); +	/* account for nanoseconds and round up, then subtract 1 */ +	cfg_value |= CFG1_REF2ACT (((temp + 999) / 1000) - 1); + +	/* Set the write latency, using the values given in the controller spec */ +	cfg_value |= CFG1_WLATENCY ((type == TYPE_DDR) ? 3 : 0); +	memctl->cfg1 = cfg_value;	/* cfg 1 */ +	asm volatile ("sync"); + + +	/* ********************** Cfg 2 ************************* */ + +	/* Set the burst read to read/precharge delay */ +	cfg_value = CFG2_BRD2RP ((type == TYPE_DDR) ? 5 : 8); + +	/* Set the burst write to read/precharge delay.  Semi-magic numbers +	 * based on the controller spec recommendations, assuming tWR is +	 * two clock cycles. +	 */ +	cfg_value |= CFG2_BWT2RWP ((type == TYPE_DDR) ? 7 : 10); + +	/* Set the Burst read to write delay.  Semi-magic numbers +	 * based on the DRAM controller documentation. +	 */ +	cfg_value |= CFG2_BRD2WT ((type == TYPE_DDR) ? 7 : 0xb); + +	/* Set the burst length -- must be 8!! Well, 7, actually, becuase +	 * it's burst lenght minus 1. +	 */ +	cfg_value |= CFG2_BURSTLEN (7); +	memctl->cfg2 = cfg_value;	/* cfg 2 */ +	asm volatile ("sync"); + + +	/* ********************** mode ************************* */ + +	/* Set enable bit, CKE high/low bits, and the DDR/SDR mode bit, +	 * disable automatic refresh. +	 */ +	cfg_value = CTL_MODE_ENABLE | CTL_CKE_HIGH | +		((type == TYPE_DDR) ? CTL_DDR_MODE : 0); + +	/* Set the address mux based on whichever setting(s) is/are common +	 * to all the devices we have.  If there is more than one, choose +	 * one arbitrarily. +	 */ +	if (muxmask & 0x4) +		cfg_value |= CTL_ADDRMUX (2); +	else if (muxmask & 0x2) +		cfg_value |= CTL_ADDRMUX (1); +	else +		cfg_value |= CTL_ADDRMUX (0); + +	/* Set the refresh interval. */ +	temp = ((refresh * (gd->bus_clk / 1000000)) / (1000 * 64)) - 1; +	cfg_value |= CTL_REFRESH_INTERVAL (temp); + +	/* Set buffered/non-buffered memory */ +	if (buffered) +		cfg_value |= CTL_BUFFERED; + +	memctl->ctrl = cfg_value;	/* ctrl */ +	asm volatile ("sync"); + +	if (type == TYPE_DDR) { +		/* issue precharge all */ +		temp = cfg_value | CTL_PRECHARGE_CMD; +		memctl->ctrl = temp;	/* ctrl */ +		asm volatile ("sync"); +	} + + +	/* Set up mode value for CAS latency */ +#if (CONFIG_SYS_SDRAM_CAS_LATENCY==5) /* CL=2.5 */ +	mode_value = (MODE_MODE | MODE_BURSTLEN (MODE_BURSTLEN_8) | +		MODE_BT_SEQUENTIAL | MODE_CL (MODE_CL_2p5) | MODE_CMD); +#else +	mode_value = (MODE_MODE | MODE_BURSTLEN (MODE_BURSTLEN_8) | +		      MODE_BT_SEQUENTIAL | MODE_CL (MODE_CL_2) | MODE_CMD); +#endif +	asm volatile ("sync"); + +	/* Write Extended Mode  - enable DLL */ +	if (type == TYPE_DDR) { +		temp = MODE_EXTENDED | MODE_X_DLL_ENABLE | +			MODE_X_DS_NORMAL | MODE_CMD; +		memctl->mode = (temp >> 16);	/* mode */ +		asm volatile ("sync"); + +		/* Write Mode - reset DLL, set CAS latency */ +		temp = mode_value | MODE_OPMODE (MODE_OPMODE_RESETDLL); +		memctl->mode = (temp >> 16);	/* mode */ +		asm volatile ("sync"); +	} + +	/* Program the chip selects. */ +	for (banknum = 0; banknum < TOTAL_BANK; banknum++) { +		if (DramInfo[banknum].size != 0) { +			u32 mask; +			int i; + +			for (i = 0, mask = 1; i < 32; mask <<= 1, i++) { +				if (DramInfo[banknum].size & mask) +					break; +			} +			temp = (DramInfo[banknum].base & 0xfff00000) | (i - +									1); + +			sysconf->cscfg[banknum] = temp; +			asm volatile ("sync"); +		} +	} + +	/* Wait for DLL lock */ +	udelay (200); + +	temp = cfg_value | CTL_PRECHARGE_CMD;	/* issue precharge all */ +	memctl->ctrl = temp;	/* ctrl */ +	asm volatile ("sync"); + +	temp = cfg_value | CTL_REFRESH_CMD;	/* issue precharge all */ +	memctl->ctrl = temp;	/* ctrl */ +	asm volatile ("sync"); + +	memctl->ctrl = temp;	/* ctrl */ +	asm volatile ("sync"); + +	/* Write Mode - DLL normal */ +	temp = mode_value | MODE_OPMODE (MODE_OPMODE_NORMAL); +	memctl->mode = (temp >> 16);	/* mode */ +	asm volatile ("sync"); + +	/* Enable refresh, enable DQS's (if DDR), and lock the control register */ +	cfg_value &= ~CTL_MODE_ENABLE;	/* lock register */ +	cfg_value |= CTL_REFRESH_ENABLE;	/* enable refresh */ + +	if (type == TYPE_DDR) +		cfg_value |= CTL_DQSOEN (0xf);	/* enable DQS's for DDR */ + +	memctl->ctrl = cfg_value;	/* ctrl */ +	asm volatile ("sync"); + +	return size; +} |