Richard Smith | cb8eab4 | 2006-07-24 04:25:47 +0000 | [diff] [blame] | 1 | #include <cpu/x86/mtrr.h> |
| 2 | #include "raminit.h" |
| 3 | |
| 4 | /* |
| 5 | This software and ancillary information (herein called SOFTWARE ) |
| 6 | called LinuxBIOS is made available under the terms described |
| 7 | here. The SOFTWARE has been approved for release with associated |
| 8 | LA-CC Number 00-34 . Unless otherwise indicated, this SOFTWARE has |
| 9 | been authored by an employee or employees of the University of |
| 10 | California, operator of the Los Alamos National Laboratory under |
| 11 | Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The |
| 12 | U.S. Government has rights to use, reproduce, and distribute this |
| 13 | SOFTWARE. The public may copy, distribute, prepare derivative works |
| 14 | and publicly display this SOFTWARE without charge, provided that this |
| 15 | Notice and any statement of authorship are reproduced on all copies. |
| 16 | Neither the Government nor the University makes any warranty, express |
| 17 | or implied, or assumes any liability or responsibility for the use of |
| 18 | this SOFTWARE. If SOFTWARE is modified to produce derivative works, |
| 19 | such modified SOFTWARE should be clearly marked, so as not to confuse |
| 20 | it with the version available from LANL. |
| 21 | */ |
| 22 | /* Copyright 2000, Ron Minnich, Advanced Computing Lab, LANL |
| 23 | * rminnich@lanl.gov |
| 24 | */ |
| 25 | /* |
| 26 | * 11/26/02 - kevinh@ispiri.com - The existing comments implied that |
| 27 | * this didn't work yet. Therefore, I've updated it so that it works |
| 28 | * correctly - at least on my VIA epia motherboard. 64MB DIMM in slot 0. |
| 29 | */ |
| 30 | |
| 31 | /* Added automatic detection of first equipped bank and its MA mapping type. |
| 32 | * (Rest of configuration is done in C) |
| 33 | * 5/19/03 by SONE Takeshi <ts1@tsn.or.jp> |
| 34 | */ |
| 35 | /* converted to C 9/2003 Ron Minnich */ |
| 36 | |
| 37 | /* Modified for the i440bx Richard Smith 01/2005 */ |
| 38 | |
| 39 | /* Set to 1 if your DIMMs are PC133 Note that I'm assuming CPU's FSB |
| 40 | * frequency is 133MHz. If your CPU runs at another bus speed, you |
| 41 | * might need to change some of register values. |
| 42 | */ |
| 43 | #ifndef DIMM_PC133 |
| 44 | #define DIMM_PC133 0 |
| 45 | #endif |
| 46 | |
| 47 | // Set to 1 if your DIMMs are CL=2 |
| 48 | #ifndef DIMM_CL2 |
| 49 | #define DIMM_CL2 0 |
| 50 | #endif |
| 51 | |
| 52 | void dimms_read(unsigned long x) |
| 53 | { |
| 54 | uint8_t c; |
| 55 | unsigned long eax; |
| 56 | volatile unsigned long y; |
| 57 | eax = x; |
| 58 | for(c = 0; c < 6; c++) { |
| 59 | y = * (volatile unsigned long *) eax; |
| 60 | eax += 0x10000000; |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | void dimms_write(int x) |
| 65 | { |
| 66 | uint8_t c; |
| 67 | unsigned long eax = x; |
| 68 | for(c = 0; c < 6; c++) { |
| 69 | *(volatile unsigned long *) eax = 0; |
| 70 | eax += 0x10000000; |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | |
| 75 | |
| 76 | #ifdef DEBUG_SETNORTHB |
| 77 | void setnorthb(device_t north, uint8_t reg, uint8_t val) |
| 78 | { |
| 79 | print_debug("setnorth: reg "); |
| 80 | print_debug_hex8(reg); |
| 81 | print_debug(" to "); |
| 82 | print_debug_hex8(val); |
| 83 | print_debug("\r\n"); |
| 84 | pci_write_config8(north, reg, val); |
| 85 | } |
| 86 | #else |
| 87 | #define setnorthb pci_write_config8 |
| 88 | #endif |
| 89 | |
| 90 | void |
| 91 | dumpnorth(device_t north) |
| 92 | { |
| 93 | unsigned int r, c; |
| 94 | for(r = 0; ; r += 16) { |
| 95 | print_debug_hex8(r); |
| 96 | print_debug(":"); |
| 97 | for(c = 0; c < 16; c++) { |
| 98 | print_debug_hex8(pci_read_config8(north, r+c)); |
| 99 | print_debug(" "); |
| 100 | } |
| 101 | print_debug("\r\n"); |
| 102 | if (r >= 240) |
| 103 | break; |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | static void sdram_set_registers(const struct mem_controller *ctrl) |
| 108 | { |
| 109 | device_t north = (device_t) 0; |
| 110 | uint8_t c, r; |
| 111 | |
| 112 | print_err("vt8601 init starting\r\n"); |
| 113 | north = pci_locate_device(PCI_ID(0x1106, 0x8601), 0); |
| 114 | north = 0; |
| 115 | print_debug_hex32(north); |
| 116 | print_debug(" is the north\n"); |
| 117 | print_debug_hex16(pci_read_config16(north, 0)); |
| 118 | print_debug(" "); |
| 119 | print_debug_hex16(pci_read_config16(north, 2)); |
| 120 | print_debug("\r\n"); |
| 121 | |
| 122 | /* All we are doing now is setting initial known-good values that will |
| 123 | * be revised later as we read SPD |
| 124 | */ |
| 125 | // memory clk enable. We are not using ECC |
| 126 | pci_write_config8(north,0x78, 0x01); |
| 127 | print_debug_hex8(pci_read_config8(north, 0x78)); |
| 128 | // dram control, see the book. |
| 129 | #if DIMM_PC133 |
| 130 | pci_write_config8(north,0x68, 0x52); |
| 131 | #else |
| 132 | pci_write_config8(north,0x68, 0x42); |
| 133 | #endif |
| 134 | // dram control, see the book. |
| 135 | pci_write_config8(north,0x6B, 0x0c); |
| 136 | // Initial setting, 256MB in each bank, will be rewritten later. |
| 137 | pci_write_config8(north,0x5A, 0x20); |
| 138 | print_debug_hex8(pci_read_config8(north, 0x5a)); |
| 139 | pci_write_config8(north,0x5B, 0x40); |
| 140 | pci_write_config8(north,0x5C, 0x60); |
| 141 | pci_write_config8(north,0x5D, 0x80); |
| 142 | pci_write_config8(north,0x5E, 0xA0); |
| 143 | pci_write_config8(north,0x5F, 0xC0); |
| 144 | // It seems we have to take care of these 2 registers as if |
| 145 | // they are bank 6 and 7. |
| 146 | pci_write_config8(north,0x56, 0xC0); |
| 147 | pci_write_config8(north,0x57, 0xC0); |
| 148 | |
| 149 | // SDRAM in all banks |
| 150 | pci_write_config8(north,0x60, 0x3F); |
| 151 | // DRAM timing. I'm suspicious of this |
| 152 | // This is for all banks, 64 is 0,1. 65 is 2,3. 66 is 4,5. |
| 153 | // ras precharge 4T, RAS pulse 5T |
| 154 | // cas2 is 0xd6, cas3 is 0xe6 |
| 155 | // we're also backing off write pulse width to 2T, so result is 0xee |
| 156 | #if DIMM_CL2 |
| 157 | pci_write_config8(north,0x64, 0xd4); |
| 158 | pci_write_config8(north,0x65, 0xd4); |
| 159 | pci_write_config8(north,0x66, 0xd4); |
| 160 | #else // CL=3 |
| 161 | pci_write_config8(north,0x64, 0xe4); |
| 162 | pci_write_config8(north,0x65, 0xe4); |
| 163 | pci_write_config8(north,0x66, 0xe4); |
| 164 | #endif |
| 165 | |
| 166 | // dram frequency select. |
| 167 | // enable 4K pages for 64M dram. |
| 168 | #if DIMM_PC133 |
| 169 | pci_write_config8(north,0x69, 0x3c); |
| 170 | #else |
| 171 | pci_write_config8(north,0x69, 0xac); |
| 172 | #endif |
| 173 | |
| 174 | /* IMPORTANT -- disable refresh counter */ |
| 175 | // refresh counter, disabled. |
| 176 | pci_write_config8(north,0x6A, 0x00); |
| 177 | |
| 178 | |
| 179 | // clkenable configuration. kevinh FIXME - add precharge |
| 180 | pci_write_config8(north,0x6C, 0x00); |
| 181 | // dram read latch delay of 1 ns, MD drive 8 mA, |
| 182 | // high drive strength on MA[2: 13], we#, cas#, ras# |
| 183 | // As per Cindy Lee, set to 0x37, not 0x57 |
| 184 | pci_write_config8(north,0x6D, 0x7f); |
| 185 | } |
| 186 | |
| 187 | /* slot is the dram slot. Return size of side0 in lower 16-bit, |
| 188 | * side1 in upper 16-bit, in units of 8MB */ |
| 189 | static unsigned long |
| 190 | spd_module_size(unsigned char slot) |
| 191 | { |
| 192 | /* for all the DRAMS, see if they are there and get the size of each |
| 193 | * module. This is just a very early first cut at sizing. |
| 194 | */ |
| 195 | /* we may run out of registers ... */ |
| 196 | unsigned int banks, rows, cols, reg; |
| 197 | unsigned int value = 0; |
| 198 | /* unsigned int module = ((0x50 + slot) << 1) + 1; */ |
| 199 | unsigned int module = 0x50 + slot; |
| 200 | /* is the module there? if byte 2 is not 4, then we'll assume it |
| 201 | * is useless. |
| 202 | */ |
| 203 | print_info("Slot "); |
| 204 | print_info_hex8(slot); |
| 205 | if (smbus_read_byte(module, 2) != 4) { |
| 206 | print_info(" is empty\r\n"); |
| 207 | return 0; |
| 208 | } |
| 209 | print_info(" is SDRAM "); |
| 210 | |
| 211 | banks = smbus_read_byte(module, 17); |
| 212 | /* we're going to assume symmetric banks. Sorry. */ |
| 213 | cols = smbus_read_byte(module, 4) & 0xf; |
| 214 | rows = smbus_read_byte(module, 3) & 0xf; |
| 215 | /* grand total. You have rows+cols addressing, * times of banks, times |
| 216 | * width of data in bytes */ |
| 217 | /* Width is assumed to be 64 bits == 8 bytes */ |
| 218 | value = (1 << (cols + rows)) * banks * 8; |
| 219 | print_info_hex32(value); |
| 220 | print_info(" bytes "); |
| 221 | /* Return in 8MB units */ |
| 222 | value >>= 23; |
| 223 | |
| 224 | /* We should have single or double side */ |
| 225 | if (smbus_read_byte(module, 5) == 2) { |
| 226 | print_info("x2"); |
| 227 | value = (value << 16) | value; |
| 228 | } |
| 229 | print_info("\r\n"); |
| 230 | return value; |
| 231 | |
| 232 | } |
| 233 | |
| 234 | static int |
| 235 | spd_num_chips(unsigned char slot) |
| 236 | { |
| 237 | /* unsigned int module = ((0x50 + slot) << 1) + 1; */ |
| 238 | unsigned int module = 0x50 + slot; |
| 239 | unsigned int width; |
| 240 | |
| 241 | width = smbus_read_byte(module, 13); |
| 242 | if (width == 0) |
| 243 | width = 8; |
| 244 | return 64 / width; |
| 245 | } |
| 246 | |
| 247 | static void sdram_set_spd_registers(const struct mem_controller *ctrl) |
| 248 | { |
| 249 | #define T133 7 |
| 250 | unsigned char Trp = 1, Tras = 1, casl = 2, val; |
| 251 | unsigned char timing = 0xe4; |
| 252 | /* read Trp */ |
| 253 | val = smbus_read_byte(0x50, 27); |
| 254 | if (val < 2*T133) |
| 255 | Trp = 1; |
| 256 | val = smbus_read_byte(0x50, 30); |
| 257 | if (val < 5*T133) |
| 258 | Tras = 0; |
| 259 | val = smbus_read_byte(0x50, 18); |
| 260 | if (val < 8) |
| 261 | casl = 1; |
| 262 | if (val < 4) |
| 263 | casl = 0; |
| 264 | |
| 265 | val = (Trp << 7) | (Tras << 6) | (casl << 4) | 4; |
| 266 | |
| 267 | print_debug_hex8(val); print_debug(" is the computed timing\n"); |
| 268 | /* don't set it. Experience shows that this screwy chipset should just |
| 269 | * be run with the most conservative timing. |
| 270 | * pci_write_config8(0, 0x64, val); |
| 271 | */ |
| 272 | } |
| 273 | |
| 274 | static void set_ma_mapping(device_t north, int slot, int type) |
| 275 | { |
| 276 | unsigned char reg, val; |
| 277 | int shift; |
| 278 | |
| 279 | reg = 0x58 + slot/2; |
| 280 | if (slot%2 >= 1) |
| 281 | shift = 0; |
| 282 | else |
| 283 | shift = 4; |
| 284 | |
| 285 | val = pci_read_config8(north, reg); |
| 286 | val &= ~(0xf << shift); |
| 287 | val |= type << shift; |
| 288 | pci_write_config8(north, reg, val); |
| 289 | } |
| 290 | |
| 291 | |
| 292 | static void sdram_enable(int controllers, const struct mem_controller *ctrl) |
| 293 | { |
| 294 | unsigned char i; |
| 295 | static const uint8_t ramregs[] = { |
| 296 | 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x56, 0x57 |
| 297 | }; |
| 298 | device_t north = 0; |
| 299 | uint32_t size, base, slot, ma; |
| 300 | /* begin to initialize*/ |
| 301 | // I forget why we need this, but we do |
| 302 | dimms_write(0xa55a5aa5); |
| 303 | |
| 304 | /* set NOP*/ |
| 305 | pci_write_config8(north,0x6C, 0x01); |
| 306 | print_debug("NOP\r\n"); |
| 307 | /* wait 200us*/ |
| 308 | // You need to do the memory reference. That causes the nop cycle. |
| 309 | dimms_read(0); |
| 310 | udelay(400); |
| 311 | print_debug("PRECHARGE\r\n"); |
| 312 | /* set precharge */ |
| 313 | pci_write_config8(north,0x6C, 0x02); |
| 314 | print_debug("DUMMY READS\r\n"); |
| 315 | /* dummy reads*/ |
| 316 | dimms_read(0); |
| 317 | udelay(200); |
| 318 | print_debug("CBR\r\n"); |
| 319 | /* set CBR*/ |
| 320 | pci_write_config8(north,0x6C, 0x04); |
| 321 | |
| 322 | /* do 8 reads and wait >100us between each - from via*/ |
| 323 | dimms_read(0); |
| 324 | udelay(200); |
| 325 | dimms_read(0); |
| 326 | udelay(200); |
| 327 | dimms_read(0); |
| 328 | udelay(200); |
| 329 | dimms_read(0); |
| 330 | udelay(200); |
| 331 | dimms_read(0); |
| 332 | udelay(200); |
| 333 | dimms_read(0); |
| 334 | udelay(200); |
| 335 | dimms_read(0); |
| 336 | udelay(200); |
| 337 | dimms_read(0); |
| 338 | udelay(200); |
| 339 | print_debug("MRS\r\n"); |
| 340 | /* set MRS*/ |
| 341 | pci_write_config8(north,0x6c, 0x03); |
| 342 | #if DIMM_CL2 |
| 343 | dimms_read(0x150); |
| 344 | #else // CL=3 |
| 345 | dimms_read(0x1d0); |
| 346 | #endif |
| 347 | udelay(200); |
| 348 | print_debug("NORMAL\r\n"); |
| 349 | /* set to normal mode */ |
| 350 | pci_write_config8(north,0x6C, 0x08); |
| 351 | |
| 352 | dimms_write(0x55aa55aa); |
| 353 | dimms_read(0); |
| 354 | udelay(200); |
| 355 | print_debug("set ref. rate\r\n"); |
| 356 | // Set the refresh rate. |
| 357 | #if DIMM_PC133 |
| 358 | pci_write_config8(north,0x6A, 0x86); |
| 359 | #else |
| 360 | pci_write_config8(north,0x6A, 0x65); |
| 361 | #endif |
| 362 | print_debug("enable multi-page open\r\n"); |
| 363 | // enable multi-page open |
| 364 | pci_write_config8(north,0x6B, 0x0d); |
| 365 | |
| 366 | base = 0; |
| 367 | for(slot = 0; slot < 4; slot++) { |
| 368 | size = spd_module_size(slot); |
| 369 | /* side 0 */ |
| 370 | base += size & 0xffff; |
| 371 | pci_write_config8(north, ramregs[2*slot], base); |
| 372 | /* side 1 */ |
| 373 | base += size >> 16; |
| 374 | if (base > 0xff) |
| 375 | base = 0xff; |
| 376 | pci_write_config8(north, ramregs[2*slot + 1], base); |
| 377 | |
| 378 | if (!size) |
| 379 | continue; |
| 380 | |
| 381 | /* Calculate the value of MA mapping type register, |
| 382 | * based on size of SDRAM chips. */ |
| 383 | size = (size & 0xffff) << (3 + 3); |
| 384 | /* convert module size to be in Mbits */ |
| 385 | size /= spd_num_chips(slot); |
| 386 | print_debug_hex16(size); |
| 387 | print_debug(" is the chip size\r\n"); |
| 388 | if (size < 64) |
| 389 | ma = 0; |
| 390 | if (size < 256) |
| 391 | ma = 8; |
| 392 | else |
| 393 | ma = 0xe; |
| 394 | print_debug_hex16(ma); |
| 395 | print_debug(" is the MA type\r\n"); |
| 396 | set_ma_mapping(north, slot, ma); |
| 397 | } |
| 398 | print_err("vt8601 done\r\n"); |
| 399 | } |