753 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			753 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
 * (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;
 | 
						|
}
 |