| /* |
| * (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" |
| |
| #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) |
| { |
| DECLARE_GLOBAL_DATA_PTR; |
| |
| 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) |
| { |
| DECLARE_GLOBAL_DATA_PTR; |
| |
| 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; |
| } |