|  | /* | 
|  | * (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	CFG_SDRAM_SPD_SIZE | 
|  | #define DRAM_SPD	(CFG_SDRAM_SPD_I2C_ADDR)<<1	/* on Board SPD eeprom */ | 
|  | #define TOTAL_BANK	CFG_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 &= ~CFG_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 = CFG_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 = CFG_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 (CFG_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; | 
|  | } |