wdenk | 337f565 | 2004-10-28 00:09:35 +0000 | [diff] [blame] | 1 | /* |
| 2 | * (C) Copyright 2004, Freescale, Inc |
| 3 | * TsiChung Liew, Tsi-Chung.Liew@freescale.com |
| 4 | * |
| 5 | * See file CREDITS for list of people who contributed to this |
| 6 | * project. |
| 7 | * |
| 8 | * This program is free software; you can redistribute it and/or |
| 9 | * modify it under the terms of the GNU General Public License as |
| 10 | * published by the Free Software Foundation; either version 2 of |
| 11 | * the License, or (at your option) any later version. |
| 12 | * |
| 13 | * This program is distributed in the hope that it will be useful, |
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | * GNU General Public License for more details. |
| 17 | * |
| 18 | * You should have received a copy of the GNU General Public License |
| 19 | * along with this program; if not, write to the Free Software |
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
| 21 | * MA 02111-1307 USA |
| 22 | */ |
| 23 | |
| 24 | /* |
| 25 | DESCRIPTION |
| 26 | Read Dram spd and base on its information to calculate the memory size, |
| 27 | characteristics to initialize the dram on MPC8220 |
| 28 | */ |
| 29 | |
| 30 | #include <common.h> |
| 31 | #include <mpc8220.h> |
| 32 | #include "i2cCore.h" |
| 33 | #include "dramSetup.h" |
| 34 | |
Wolfgang Denk | 6405a15 | 2006-03-31 18:32:53 +0200 | [diff] [blame] | 35 | DECLARE_GLOBAL_DATA_PTR; |
| 36 | |
Jean-Christophe PLAGNIOL-VILLARD | 0383694 | 2008-10-16 15:01:15 +0200 | [diff] [blame] | 37 | #define SPD_SIZE CONFIG_SYS_SDRAM_SPD_SIZE |
| 38 | #define DRAM_SPD (CONFIG_SYS_SDRAM_SPD_I2C_ADDR)<<1 /* on Board SPD eeprom */ |
| 39 | #define TOTAL_BANK CONFIG_SYS_SDRAM_TOTAL_BANKS |
wdenk | 337f565 | 2004-10-28 00:09:35 +0000 | [diff] [blame] | 40 | |
| 41 | int spd_status (volatile i2c8220_t * pi2c, u8 sta_bit, u8 truefalse) |
| 42 | { |
| 43 | int i; |
| 44 | |
| 45 | for (i = 0; i < I2C_POLL_COUNT; i++) { |
| 46 | if ((pi2c->sr & sta_bit) == (truefalse ? sta_bit : 0)) |
| 47 | return (OK); |
| 48 | } |
| 49 | |
| 50 | return (ERROR); |
| 51 | } |
| 52 | |
| 53 | int spd_clear (volatile i2c8220_t * pi2c) |
| 54 | { |
| 55 | pi2c->adr = 0; |
| 56 | pi2c->fdr = 0; |
| 57 | pi2c->cr = 0; |
| 58 | pi2c->sr = 0; |
| 59 | |
| 60 | return (OK); |
| 61 | } |
| 62 | |
| 63 | int spd_stop (volatile i2c8220_t * pi2c) |
| 64 | { |
| 65 | pi2c->cr &= ~I2C_CTL_STA; /* Generate stop signal */ |
| 66 | if (spd_status (pi2c, I2C_STA_BB, 0) != OK) |
| 67 | return ERROR; |
| 68 | |
| 69 | return (OK); |
| 70 | } |
| 71 | |
| 72 | int spd_readbyte (volatile i2c8220_t * pi2c, u8 * readb, int *index) |
| 73 | { |
| 74 | pi2c->sr &= ~I2C_STA_IF; /* Clear Interrupt Bit */ |
| 75 | *readb = pi2c->dr; /* Read a byte */ |
| 76 | |
| 77 | /* |
| 78 | Set I2C_CTRL_TXAK will cause Transfer pending and |
| 79 | set I2C_CTRL_STA will cause Interrupt pending |
| 80 | */ |
| 81 | if (*index != 2) { |
| 82 | if (spd_status (pi2c, I2C_STA_CF, 1) != OK) /* Transfer not complete? */ |
| 83 | return ERROR; |
| 84 | } |
| 85 | |
| 86 | if (*index != 1) { |
| 87 | if (spd_status (pi2c, I2C_STA_IF, 1) != OK) |
| 88 | return ERROR; |
| 89 | } |
| 90 | |
| 91 | return (OK); |
| 92 | } |
| 93 | |
| 94 | int readSpdData (u8 * spdData) |
| 95 | { |
wdenk | 337f565 | 2004-10-28 00:09:35 +0000 | [diff] [blame] | 96 | volatile i2c8220_t *pi2cReg; |
| 97 | volatile pcfg8220_t *pcfg; |
| 98 | u8 slvAdr = DRAM_SPD; |
| 99 | u8 Tmp; |
| 100 | int Length = SPD_SIZE; |
| 101 | int i = 0; |
| 102 | |
| 103 | /* Enable Port Configuration for SDA and SDL signals */ |
| 104 | pcfg = (volatile pcfg8220_t *) (MMAP_PCFG); |
| 105 | __asm__ ("sync"); |
Jean-Christophe PLAGNIOL-VILLARD | 0383694 | 2008-10-16 15:01:15 +0200 | [diff] [blame] | 106 | pcfg->pcfg3 &= ~CONFIG_SYS_I2C_PORT3_CONFIG; |
wdenk | 337f565 | 2004-10-28 00:09:35 +0000 | [diff] [blame] | 107 | __asm__ ("sync"); |
| 108 | |
| 109 | /* Points the structure to I2c mbar memory offset */ |
| 110 | pi2cReg = (volatile i2c8220_t *) (MMAP_I2C); |
| 111 | |
| 112 | |
| 113 | /* Clear FDR, ADR, SR and CR reg */ |
| 114 | pi2cReg->adr = 0; |
| 115 | pi2cReg->fdr = 0; |
| 116 | pi2cReg->cr = 0; |
| 117 | pi2cReg->sr = 0; |
| 118 | |
| 119 | /* Set for fix XLB Bus Frequency */ |
| 120 | switch (gd->bus_clk) { |
| 121 | case 60000000: |
| 122 | pi2cReg->fdr = 0x15; |
| 123 | break; |
| 124 | case 70000000: |
| 125 | pi2cReg->fdr = 0x16; |
| 126 | break; |
| 127 | case 80000000: |
| 128 | pi2cReg->fdr = 0x3a; |
| 129 | break; |
| 130 | case 90000000: |
| 131 | pi2cReg->fdr = 0x17; |
| 132 | break; |
| 133 | case 100000000: |
| 134 | pi2cReg->fdr = 0x3b; |
| 135 | break; |
| 136 | case 110000000: |
| 137 | pi2cReg->fdr = 0x18; |
| 138 | break; |
| 139 | case 120000000: |
| 140 | pi2cReg->fdr = 0x19; |
| 141 | break; |
| 142 | case 130000000: |
| 143 | pi2cReg->fdr = 0x1a; |
| 144 | break; |
| 145 | } |
| 146 | |
Jean-Christophe PLAGNIOL-VILLARD | 0383694 | 2008-10-16 15:01:15 +0200 | [diff] [blame] | 147 | pi2cReg->adr = CONFIG_SYS_I2C_SLAVE<<1; |
wdenk | 337f565 | 2004-10-28 00:09:35 +0000 | [diff] [blame] | 148 | |
| 149 | pi2cReg->cr = I2C_CTL_EN; /* Set Enable */ |
| 150 | |
| 151 | /* |
| 152 | The I2C bus should be in Idle state. If the bus is busy, |
| 153 | clear the STA bit in control register |
| 154 | */ |
| 155 | if (spd_status (pi2cReg, I2C_STA_BB, 0) != OK) { |
| 156 | if ((pi2cReg->cr & I2C_CTL_STA) == I2C_CTL_STA) |
| 157 | pi2cReg->cr &= ~I2C_CTL_STA; |
| 158 | |
| 159 | /* Check again if it is still busy, return error if found */ |
| 160 | if (spd_status (pi2cReg, I2C_STA_BB, 1) == OK) |
| 161 | return ERROR; |
| 162 | } |
| 163 | |
| 164 | pi2cReg->cr |= I2C_CTL_TX; /* Enable the I2c for TX, Ack */ |
| 165 | pi2cReg->cr |= I2C_CTL_STA; /* Generate start signal */ |
| 166 | |
| 167 | if (spd_status (pi2cReg, I2C_STA_BB, 1) != OK) |
| 168 | return ERROR; |
| 169 | |
| 170 | |
| 171 | /* Write slave address */ |
| 172 | pi2cReg->sr &= ~I2C_STA_IF; /* Clear Interrupt */ |
| 173 | pi2cReg->dr = slvAdr; /* Write a byte */ |
| 174 | |
| 175 | if (spd_status (pi2cReg, I2C_STA_CF, 1) != OK) { /* Transfer not complete? */ |
| 176 | spd_stop (pi2cReg); |
| 177 | return ERROR; |
| 178 | } |
| 179 | |
| 180 | if (spd_status (pi2cReg, I2C_STA_IF, 1) != OK) { |
| 181 | spd_stop (pi2cReg); |
| 182 | return ERROR; |
| 183 | } |
| 184 | |
| 185 | |
| 186 | /* Issue the offset to start */ |
| 187 | pi2cReg->sr &= ~I2C_STA_IF; /* Clear Interrupt */ |
| 188 | pi2cReg->dr = 0; /* Write a byte */ |
| 189 | |
| 190 | if (spd_status (pi2cReg, I2C_STA_CF, 1) != OK) { /* Transfer not complete? */ |
| 191 | spd_stop (pi2cReg); |
| 192 | return ERROR; |
| 193 | } |
| 194 | |
| 195 | if (spd_status (pi2cReg, I2C_STA_IF, 1) != OK) { |
| 196 | spd_stop (pi2cReg); |
| 197 | return ERROR; |
| 198 | } |
| 199 | |
| 200 | |
| 201 | /* Set repeat start */ |
| 202 | pi2cReg->cr |= I2C_CTL_RSTA; /* Repeat Start */ |
| 203 | |
| 204 | pi2cReg->sr &= ~I2C_STA_IF; /* Clear Interrupt */ |
| 205 | pi2cReg->dr = slvAdr | 1; /* Write a byte */ |
| 206 | |
| 207 | if (spd_status (pi2cReg, I2C_STA_CF, 1) != OK) { /* Transfer not complete? */ |
| 208 | spd_stop (pi2cReg); |
| 209 | return ERROR; |
| 210 | } |
| 211 | |
| 212 | if (spd_status (pi2cReg, I2C_STA_IF, 1) != OK) { |
| 213 | spd_stop (pi2cReg); |
| 214 | return ERROR; |
| 215 | } |
| 216 | |
| 217 | if (((pi2cReg->sr & 0x07) == 0x07) || (pi2cReg->sr & 0x01)) |
| 218 | return ERROR; |
| 219 | |
| 220 | pi2cReg->cr &= ~I2C_CTL_TX; /* Set receive mode */ |
| 221 | |
| 222 | if (((pi2cReg->sr & 0x07) == 0x07) || (pi2cReg->sr & 0x01)) |
| 223 | return ERROR; |
| 224 | |
| 225 | /* Dummy Read */ |
| 226 | if (spd_readbyte (pi2cReg, &Tmp, &i) != OK) { |
| 227 | spd_stop (pi2cReg); |
| 228 | return ERROR; |
| 229 | } |
| 230 | |
| 231 | i = 0; |
| 232 | while (Length) { |
| 233 | if (Length == 2) |
| 234 | pi2cReg->cr |= I2C_CTL_TXAK; |
| 235 | |
| 236 | if (Length == 1) |
| 237 | pi2cReg->cr &= ~I2C_CTL_STA; |
| 238 | |
| 239 | if (spd_readbyte (pi2cReg, spdData, &Length) != OK) { |
| 240 | return spd_stop (pi2cReg); |
| 241 | } |
| 242 | i++; |
| 243 | Length--; |
| 244 | spdData++; |
| 245 | } |
| 246 | |
| 247 | /* Stop the service */ |
| 248 | spd_stop (pi2cReg); |
| 249 | |
| 250 | return OK; |
| 251 | } |
| 252 | |
| 253 | int getBankInfo (int bank, draminfo_t * pBank) |
| 254 | { |
| 255 | int status; |
| 256 | int checksum; |
| 257 | int count; |
| 258 | u8 spdData[SPD_SIZE]; |
| 259 | |
| 260 | |
| 261 | if (bank > 2 || pBank == 0) { |
| 262 | /* illegal values */ |
| 263 | return (-42); |
| 264 | } |
| 265 | |
| 266 | status = readSpdData (&spdData[0]); |
| 267 | if (status < 0) |
| 268 | return (-1); |
| 269 | |
| 270 | /* check the checksum */ |
| 271 | for (count = 0, checksum = 0; count < LOC_CHECKSUM; count++) |
| 272 | checksum += spdData[count]; |
| 273 | |
| 274 | checksum = checksum - ((checksum / 256) * 256); |
| 275 | |
| 276 | if (checksum != spdData[LOC_CHECKSUM]) |
| 277 | return (-2); |
| 278 | |
| 279 | /* Get the memory type */ |
| 280 | if (! |
| 281 | ((spdData[LOC_TYPE] == TYPE_DDR) |
| 282 | || (spdData[LOC_TYPE] == TYPE_SDR))) |
| 283 | /* not one of the types we support */ |
| 284 | return (-3); |
| 285 | |
| 286 | pBank->type = spdData[LOC_TYPE]; |
| 287 | |
| 288 | /* Set logical banks */ |
| 289 | pBank->banks = spdData[LOC_LOGICAL_BANKS]; |
| 290 | |
| 291 | /* Check that we have enough physical banks to cover the bank we are |
| 292 | * figuring out. Odd-numbered banks correspond to the second bank |
| 293 | * on the device. |
| 294 | */ |
| 295 | if (bank & 1) { |
| 296 | /* Second bank of a "device" */ |
| 297 | if (spdData[LOC_PHYS_BANKS] < 2) |
| 298 | /* this bank doesn't exist on the "device" */ |
| 299 | return (-4); |
| 300 | |
| 301 | if (spdData[LOC_ROWS] & 0xf0) |
| 302 | /* Two asymmetric banks */ |
| 303 | pBank->rows = spdData[LOC_ROWS] >> 4; |
| 304 | else |
| 305 | pBank->rows = spdData[LOC_ROWS]; |
| 306 | |
| 307 | if (spdData[LOC_COLS] & 0xf0) |
| 308 | /* Two asymmetric banks */ |
| 309 | pBank->cols = spdData[LOC_COLS] >> 4; |
| 310 | else |
| 311 | pBank->cols = spdData[LOC_COLS]; |
| 312 | } else { |
| 313 | /* First bank of a "device" */ |
| 314 | pBank->rows = spdData[LOC_ROWS]; |
| 315 | pBank->cols = spdData[LOC_COLS]; |
| 316 | } |
| 317 | |
| 318 | pBank->width = spdData[LOC_WIDTH_HIGH] << 8 | spdData[LOC_WIDTH_LOW]; |
| 319 | pBank->bursts = spdData[LOC_BURSTS]; |
| 320 | pBank->CAS = spdData[LOC_CAS]; |
| 321 | pBank->CS = spdData[LOC_CS]; |
| 322 | pBank->WE = spdData[LOC_WE]; |
| 323 | pBank->Trp = spdData[LOC_Trp]; |
| 324 | pBank->Trcd = spdData[LOC_Trcd]; |
| 325 | pBank->buffered = spdData[LOC_Buffered] & 1; |
| 326 | pBank->refresh = spdData[LOC_REFRESH]; |
| 327 | |
| 328 | return (0); |
| 329 | } |
| 330 | |
| 331 | |
| 332 | /* checkMuxSetting -- given a row/column device geometry, return a mask |
| 333 | * of the valid DRAM controller addr_mux settings for |
| 334 | * that geometry. |
| 335 | * |
| 336 | * Arguments: u8 rows: number of row addresses in this device |
| 337 | * u8 columns: number of column addresses in this device |
| 338 | * |
| 339 | * Returns: a mask of the allowed addr_mux settings for this |
| 340 | * geometry. Each bit in the mask represents a |
| 341 | * possible addr_mux settings (for example, the |
| 342 | * (1<<2) bit in the mask represents the 0b10 setting)/ |
| 343 | * |
| 344 | */ |
| 345 | u8 checkMuxSetting (u8 rows, u8 columns) |
| 346 | { |
| 347 | muxdesc_t *pIdx, *pMux; |
| 348 | u8 mask; |
| 349 | int lrows, lcolumns; |
| 350 | u32 mux[4] = { 0x00080c04, 0x01080d03, 0x02080e02, 0xffffffff }; |
| 351 | |
| 352 | /* Setup MuxDescriptor in SRAM space */ |
| 353 | /* MUXDESC AddressRuns [] = { |
| 354 | { 0, 8, 12, 4 }, / setting, columns, rows, extra columns / |
| 355 | { 1, 8, 13, 3 }, / setting, columns, rows, extra columns / |
| 356 | { 2, 8, 14, 2 }, / setting, columns, rows, extra columns / |
| 357 | { 0xff } / list terminator / |
| 358 | }; */ |
| 359 | |
| 360 | pIdx = (muxdesc_t *) & mux[0]; |
| 361 | |
| 362 | /* Check rows x columns against each possible address mux setting */ |
| 363 | for (pMux = pIdx, mask = 0;; pMux++) { |
| 364 | lrows = rows; |
| 365 | lcolumns = columns; |
| 366 | |
| 367 | if (pMux->MuxValue == 0xff) |
| 368 | break; /* end of list */ |
| 369 | |
| 370 | /* For a given mux setting, since we want all the memory in a |
| 371 | * device to be contiguous, we want the device "use up" the |
| 372 | * address lines such that there are no extra column or row |
| 373 | * address lines on the device. |
| 374 | */ |
| 375 | |
| 376 | lcolumns -= pMux->Columns; |
| 377 | if (lcolumns < 0) |
| 378 | /* Not enough columns to get to the rows */ |
| 379 | continue; |
| 380 | |
| 381 | lrows -= pMux->Rows; |
| 382 | if (lrows > 0) |
| 383 | /* we have extra rows left -- can't do that! */ |
| 384 | continue; |
| 385 | |
| 386 | /* At this point, we either have to have used up all the |
| 387 | * rows or we have to have no columns left. |
| 388 | */ |
| 389 | |
| 390 | if (lcolumns != 0 && lrows != 0) |
| 391 | /* rows AND columns are left. Bad! */ |
| 392 | continue; |
| 393 | |
| 394 | lcolumns -= pMux->MoreColumns; |
| 395 | |
| 396 | if (lcolumns <= 0) |
| 397 | mask |= (1 << pMux->MuxValue); |
| 398 | } |
| 399 | |
| 400 | return (mask); |
| 401 | } |
| 402 | |
| 403 | |
| 404 | u32 dramSetup (void) |
| 405 | { |
wdenk | 337f565 | 2004-10-28 00:09:35 +0000 | [diff] [blame] | 406 | draminfo_t DramInfo[TOTAL_BANK]; |
| 407 | draminfo_t *pDramInfo; |
| 408 | u32 size, temp, cfg_value, mode_value, refresh; |
| 409 | u8 *ptr; |
| 410 | u8 bursts, Trp, Trcd, type, buffered; |
| 411 | u8 muxmask, rows, columns; |
| 412 | int count, banknum; |
| 413 | u32 *prefresh, *pIdx; |
| 414 | u32 refrate[8] = { 15625, 3900, 7800, 31300, |
| 415 | 62500, 125000, 0xffffffff, 0xffffffff |
| 416 | }; |
| 417 | volatile sysconf8220_t *sysconf; |
| 418 | volatile memctl8220_t *memctl; |
| 419 | |
| 420 | sysconf = (volatile sysconf8220_t *) MMAP_MBAR; |
| 421 | memctl = (volatile memctl8220_t *) MMAP_MEMCTL; |
| 422 | |
| 423 | /* Set everything in the descriptions to zero */ |
| 424 | ptr = (u8 *) & DramInfo[0]; |
| 425 | for (count = 0; count < sizeof (DramInfo); count++) |
| 426 | *ptr++ = 0; |
| 427 | |
| 428 | for (banknum = 0; banknum < TOTAL_BANK; banknum++) |
| 429 | sysconf->cscfg[banknum]; |
| 430 | |
| 431 | /* Descriptions of row/column address muxing for various |
| 432 | * addr_mux settings. |
| 433 | */ |
| 434 | |
| 435 | pIdx = prefresh = (u32 *) & refrate[0]; |
| 436 | |
| 437 | /* Get all the info for all three logical banks */ |
| 438 | bursts = 0xff; |
| 439 | Trp = 0; |
| 440 | Trcd = 0; |
| 441 | type = 0; |
| 442 | buffered = 0xff; |
| 443 | refresh = 0xffffffff; |
| 444 | muxmask = 0xff; |
| 445 | |
| 446 | /* Two bank, CS0 and CS1 */ |
| 447 | for (banknum = 0, pDramInfo = &DramInfo[0]; |
| 448 | banknum < TOTAL_BANK; banknum++, pDramInfo++) { |
| 449 | pDramInfo->ordinal = banknum; /* initial sorting */ |
| 450 | if (getBankInfo (banknum, pDramInfo) < 0) |
| 451 | continue; |
| 452 | |
| 453 | /* get cumulative parameters of all three banks */ |
| 454 | if (type && pDramInfo->type != type) |
| 455 | return 0; |
| 456 | |
| 457 | type = pDramInfo->type; |
| 458 | rows = pDramInfo->rows; |
| 459 | columns = pDramInfo->cols; |
| 460 | |
| 461 | /* This chip only supports 13 DRAM memory lines, but some devices |
| 462 | * have 14 rows. To deal with this, ignore the 14th address line |
| 463 | * by limiting the number of rows (and columns) to 13. This will |
| 464 | * mean that for 14-row devices we will only be able to use |
| 465 | * half of the memory, but it's better than nothing. |
| 466 | */ |
| 467 | if (rows > 13) |
| 468 | rows = 13; |
| 469 | if (columns > 13) |
| 470 | columns = 13; |
| 471 | |
| 472 | pDramInfo->size = |
| 473 | ((1 << (rows + columns)) * pDramInfo->width); |
| 474 | pDramInfo->size *= pDramInfo->banks; |
| 475 | pDramInfo->size >>= 3; |
| 476 | |
| 477 | /* figure out which addr_mux configurations will support this device */ |
| 478 | muxmask &= checkMuxSetting (rows, columns); |
| 479 | if (muxmask == 0) |
| 480 | return 0; |
| 481 | |
| 482 | buffered = pDramInfo->buffered; |
| 483 | bursts &= pDramInfo->bursts; /* union of all bursts */ |
| 484 | if (pDramInfo->Trp > Trp) /* worst case (longest) Trp */ |
| 485 | Trp = pDramInfo->Trp; |
| 486 | |
| 487 | if (pDramInfo->Trcd > Trcd) /* worst case (longest) Trcd */ |
| 488 | Trcd = pDramInfo->Trcd; |
| 489 | |
| 490 | prefresh = pIdx; |
| 491 | /* worst case (shortest) Refresh period */ |
| 492 | if (refresh > prefresh[pDramInfo->refresh & 7]) |
| 493 | refresh = prefresh[pDramInfo->refresh & 7]; |
| 494 | |
| 495 | } /* for loop */ |
| 496 | |
| 497 | |
| 498 | /* We only allow a burst length of 8! */ |
| 499 | if (!(bursts & 8)) |
| 500 | bursts = 8; |
| 501 | |
| 502 | /* Sort the devices. In order to get each chip select region |
| 503 | * aligned properly, put the biggest device at the lowest address. |
| 504 | * A simple bubble sort will do the trick. |
| 505 | */ |
| 506 | for (banknum = 0, pDramInfo = &DramInfo[0]; |
| 507 | banknum < TOTAL_BANK; banknum++, pDramInfo++) { |
| 508 | int i; |
| 509 | |
| 510 | for (i = 0; i < TOTAL_BANK; i++) { |
| 511 | if (pDramInfo->size < DramInfo[i].size && |
| 512 | pDramInfo->ordinal < DramInfo[i].ordinal) { |
| 513 | /* If the current bank is smaller, but if the ordinal is also |
| 514 | * smaller, swap the ordinals |
| 515 | */ |
| 516 | u8 temp8; |
| 517 | |
| 518 | temp8 = DramInfo[i].ordinal; |
| 519 | DramInfo[i].ordinal = pDramInfo->ordinal; |
| 520 | pDramInfo->ordinal = temp8; |
| 521 | } |
| 522 | } |
| 523 | } |
| 524 | |
| 525 | |
| 526 | /* Now figure out the base address for each bank. While |
| 527 | * we're at it, figure out how much memory there is. |
| 528 | * |
| 529 | */ |
| 530 | size = 0; |
| 531 | for (banknum = 0; banknum < TOTAL_BANK; banknum++) { |
| 532 | int i; |
| 533 | |
| 534 | for (i = 0; i < TOTAL_BANK; i++) { |
| 535 | if (DramInfo[i].ordinal == banknum |
| 536 | && DramInfo[i].size != 0) { |
| 537 | DramInfo[i].base = size; |
| 538 | size += DramInfo[i].size; |
| 539 | } |
| 540 | } |
| 541 | } |
| 542 | |
| 543 | /* Set up the Drive Strength register */ |
Jean-Christophe PLAGNIOL-VILLARD | 0383694 | 2008-10-16 15:01:15 +0200 | [diff] [blame] | 544 | sysconf->sdramds = CONFIG_SYS_SDRAM_DRIVE_STRENGTH; |
wdenk | 337f565 | 2004-10-28 00:09:35 +0000 | [diff] [blame] | 545 | |
| 546 | /* ********************** Cfg 1 ************************* */ |
| 547 | |
| 548 | /* Set the single read to read/write/precharge delay */ |
| 549 | cfg_value = CFG1_SRD2RWP ((type == TYPE_DDR) ? 7 : 0xb); |
| 550 | |
| 551 | /* Set the single write to read/write/precharge delay. |
| 552 | * This may or may not be correct. The controller spec |
| 553 | * says "tWR", but "tWR" does not appear in the SPD. It |
| 554 | * always seems to be 15nsec for the class of device we're |
| 555 | * using, which turns out to be 2 clock cycles at 133MHz, |
| 556 | * so that's what we're going to use. |
| 557 | * |
| 558 | * HOWEVER, because of a bug in the controller, for DDR |
| 559 | * we need to set this to be the same as the value |
| 560 | * calculated for bwt2rwp. |
| 561 | */ |
| 562 | cfg_value |= CFG1_SWT2RWP ((type == TYPE_DDR) ? 7 : 2); |
| 563 | |
| 564 | /* Set the Read CAS latency. We're going to use a CL of |
wdenk | ccfe25d | 2005-04-05 21:57:18 +0000 | [diff] [blame] | 565 | * 2.5 for DDR and 2 SDR. |
wdenk | 337f565 | 2004-10-28 00:09:35 +0000 | [diff] [blame] | 566 | */ |
| 567 | cfg_value |= CFG1_RLATENCY ((type == TYPE_DDR) ? 7 : 2); |
| 568 | |
| 569 | |
| 570 | /* Set the Active to Read/Write delay. This depends |
| 571 | * on Trcd which is reported as nanoseconds times 4. |
| 572 | * We want to calculate Trcd (in nanoseconds) times XLB clock (in Hz) |
| 573 | * which gives us a dimensionless quantity. Play games with |
| 574 | * the divisions so we don't run out of dynamic ranges. |
| 575 | */ |
| 576 | /* account for megaherz and the times 4 */ |
| 577 | temp = (Trcd * (gd->bus_clk / 1000000)) / 4; |
| 578 | |
| 579 | /* account for nanoseconds and round up, with a minimum value of 2 */ |
| 580 | temp = ((temp + 999) / 1000) - 1; |
| 581 | if (temp < 2) |
| 582 | temp = 2; |
| 583 | |
| 584 | cfg_value |= CFG1_ACT2WR (temp); |
| 585 | |
| 586 | /* Set the precharge to active delay. This depends |
| 587 | * on Trp which is reported as nanoseconds times 4. |
| 588 | * We want to calculate Trp (in nanoseconds) times XLB clock (in Hz) |
| 589 | * which gives us a dimensionless quantity. Play games with |
| 590 | * the divisions so we don't run out of dynamic ranges. |
| 591 | */ |
| 592 | /* account for megaherz and the times 4 */ |
| 593 | temp = (Trp * (gd->bus_clk / 1000000)) / 4; |
| 594 | |
| 595 | /* account for nanoseconds and round up, then subtract 1, with a |
| 596 | * minumum value of 1 and a maximum value of 7. |
| 597 | */ |
| 598 | temp = (((temp + 999) / 1000) - 1) & 7; |
| 599 | if (temp < 1) |
| 600 | temp = 1; |
| 601 | |
| 602 | cfg_value |= CFG1_PRE2ACT (temp); |
| 603 | |
| 604 | /* Set refresh to active delay. This depends |
| 605 | * on Trfc which is not reported in the SPD. |
| 606 | * We'll use a nominal value of 75nsec which is |
| 607 | * what the controller spec uses. |
| 608 | */ |
| 609 | temp = (75 * (gd->bus_clk / 1000000)); |
| 610 | /* account for nanoseconds and round up, then subtract 1 */ |
| 611 | cfg_value |= CFG1_REF2ACT (((temp + 999) / 1000) - 1); |
| 612 | |
| 613 | /* Set the write latency, using the values given in the controller spec */ |
| 614 | cfg_value |= CFG1_WLATENCY ((type == TYPE_DDR) ? 3 : 0); |
| 615 | memctl->cfg1 = cfg_value; /* cfg 1 */ |
| 616 | asm volatile ("sync"); |
| 617 | |
| 618 | |
| 619 | /* ********************** Cfg 2 ************************* */ |
| 620 | |
| 621 | /* Set the burst read to read/precharge delay */ |
| 622 | cfg_value = CFG2_BRD2RP ((type == TYPE_DDR) ? 5 : 8); |
| 623 | |
| 624 | /* Set the burst write to read/precharge delay. Semi-magic numbers |
| 625 | * based on the controller spec recommendations, assuming tWR is |
| 626 | * two clock cycles. |
| 627 | */ |
| 628 | cfg_value |= CFG2_BWT2RWP ((type == TYPE_DDR) ? 7 : 10); |
| 629 | |
| 630 | /* Set the Burst read to write delay. Semi-magic numbers |
| 631 | * based on the DRAM controller documentation. |
| 632 | */ |
| 633 | cfg_value |= CFG2_BRD2WT ((type == TYPE_DDR) ? 7 : 0xb); |
| 634 | |
| 635 | /* Set the burst length -- must be 8!! Well, 7, actually, becuase |
| 636 | * it's burst lenght minus 1. |
| 637 | */ |
| 638 | cfg_value |= CFG2_BURSTLEN (7); |
| 639 | memctl->cfg2 = cfg_value; /* cfg 2 */ |
| 640 | asm volatile ("sync"); |
| 641 | |
| 642 | |
| 643 | /* ********************** mode ************************* */ |
| 644 | |
| 645 | /* Set enable bit, CKE high/low bits, and the DDR/SDR mode bit, |
| 646 | * disable automatic refresh. |
| 647 | */ |
| 648 | cfg_value = CTL_MODE_ENABLE | CTL_CKE_HIGH | |
| 649 | ((type == TYPE_DDR) ? CTL_DDR_MODE : 0); |
| 650 | |
| 651 | /* Set the address mux based on whichever setting(s) is/are common |
| 652 | * to all the devices we have. If there is more than one, choose |
| 653 | * one arbitrarily. |
| 654 | */ |
| 655 | if (muxmask & 0x4) |
| 656 | cfg_value |= CTL_ADDRMUX (2); |
| 657 | else if (muxmask & 0x2) |
| 658 | cfg_value |= CTL_ADDRMUX (1); |
| 659 | else |
| 660 | cfg_value |= CTL_ADDRMUX (0); |
| 661 | |
| 662 | /* Set the refresh interval. */ |
| 663 | temp = ((refresh * (gd->bus_clk / 1000000)) / (1000 * 64)) - 1; |
| 664 | cfg_value |= CTL_REFRESH_INTERVAL (temp); |
| 665 | |
| 666 | /* Set buffered/non-buffered memory */ |
| 667 | if (buffered) |
| 668 | cfg_value |= CTL_BUFFERED; |
| 669 | |
| 670 | memctl->ctrl = cfg_value; /* ctrl */ |
| 671 | asm volatile ("sync"); |
| 672 | |
| 673 | if (type == TYPE_DDR) { |
| 674 | /* issue precharge all */ |
| 675 | temp = cfg_value | CTL_PRECHARGE_CMD; |
| 676 | memctl->ctrl = temp; /* ctrl */ |
| 677 | asm volatile ("sync"); |
| 678 | } |
| 679 | |
| 680 | |
wdenk | ccfe25d | 2005-04-05 21:57:18 +0000 | [diff] [blame] | 681 | /* Set up mode value for CAS latency */ |
Jean-Christophe PLAGNIOL-VILLARD | 0383694 | 2008-10-16 15:01:15 +0200 | [diff] [blame] | 682 | #if (CONFIG_SYS_SDRAM_CAS_LATENCY==5) /* CL=2.5 */ |
wdenk | ccfe25d | 2005-04-05 21:57:18 +0000 | [diff] [blame] | 683 | mode_value = (MODE_MODE | MODE_BURSTLEN (MODE_BURSTLEN_8) | |
| 684 | MODE_BT_SEQUENTIAL | MODE_CL (MODE_CL_2p5) | MODE_CMD); |
| 685 | #else |
wdenk | 337f565 | 2004-10-28 00:09:35 +0000 | [diff] [blame] | 686 | mode_value = (MODE_MODE | MODE_BURSTLEN (MODE_BURSTLEN_8) | |
| 687 | MODE_BT_SEQUENTIAL | MODE_CL (MODE_CL_2) | MODE_CMD); |
wdenk | ccfe25d | 2005-04-05 21:57:18 +0000 | [diff] [blame] | 688 | #endif |
wdenk | 337f565 | 2004-10-28 00:09:35 +0000 | [diff] [blame] | 689 | asm volatile ("sync"); |
| 690 | |
| 691 | /* Write Extended Mode - enable DLL */ |
| 692 | if (type == TYPE_DDR) { |
| 693 | temp = MODE_EXTENDED | MODE_X_DLL_ENABLE | |
| 694 | MODE_X_DS_NORMAL | MODE_CMD; |
| 695 | memctl->mode = (temp >> 16); /* mode */ |
| 696 | asm volatile ("sync"); |
| 697 | |
wdenk | ccfe25d | 2005-04-05 21:57:18 +0000 | [diff] [blame] | 698 | /* Write Mode - reset DLL, set CAS latency */ |
wdenk | 337f565 | 2004-10-28 00:09:35 +0000 | [diff] [blame] | 699 | temp = mode_value | MODE_OPMODE (MODE_OPMODE_RESETDLL); |
| 700 | memctl->mode = (temp >> 16); /* mode */ |
| 701 | asm volatile ("sync"); |
| 702 | } |
| 703 | |
| 704 | /* Program the chip selects. */ |
| 705 | for (banknum = 0; banknum < TOTAL_BANK; banknum++) { |
| 706 | if (DramInfo[banknum].size != 0) { |
| 707 | u32 mask; |
| 708 | int i; |
| 709 | |
| 710 | for (i = 0, mask = 1; i < 32; mask <<= 1, i++) { |
| 711 | if (DramInfo[banknum].size & mask) |
| 712 | break; |
| 713 | } |
| 714 | temp = (DramInfo[banknum].base & 0xfff00000) | (i - |
| 715 | 1); |
| 716 | |
| 717 | sysconf->cscfg[banknum] = temp; |
| 718 | asm volatile ("sync"); |
| 719 | } |
| 720 | } |
| 721 | |
| 722 | /* Wait for DLL lock */ |
| 723 | udelay (200); |
| 724 | |
| 725 | temp = cfg_value | CTL_PRECHARGE_CMD; /* issue precharge all */ |
| 726 | memctl->ctrl = temp; /* ctrl */ |
| 727 | asm volatile ("sync"); |
| 728 | |
| 729 | temp = cfg_value | CTL_REFRESH_CMD; /* issue precharge all */ |
| 730 | memctl->ctrl = temp; /* ctrl */ |
| 731 | asm volatile ("sync"); |
| 732 | |
| 733 | memctl->ctrl = temp; /* ctrl */ |
| 734 | asm volatile ("sync"); |
| 735 | |
| 736 | /* Write Mode - DLL normal */ |
| 737 | temp = mode_value | MODE_OPMODE (MODE_OPMODE_NORMAL); |
| 738 | memctl->mode = (temp >> 16); /* mode */ |
| 739 | asm volatile ("sync"); |
| 740 | |
| 741 | /* Enable refresh, enable DQS's (if DDR), and lock the control register */ |
| 742 | cfg_value &= ~CTL_MODE_ENABLE; /* lock register */ |
| 743 | cfg_value |= CTL_REFRESH_ENABLE; /* enable refresh */ |
| 744 | |
| 745 | if (type == TYPE_DDR) |
| 746 | cfg_value |= CTL_DQSOEN (0xf); /* enable DQS's for DDR */ |
| 747 | |
| 748 | memctl->ctrl = cfg_value; /* ctrl */ |
| 749 | asm volatile ("sync"); |
| 750 | |
| 751 | return size; |
| 752 | } |