Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 1 | /* |
| 2 | * This file is part of the coreboot project. |
| 3 | * |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 4 | * Copyright (C) 2008-2010 Joseph Smith <joe@settoplinux.org> |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; either version 2 of the License, or |
| 9 | * (at your option) any later version. |
| 10 | * |
| 11 | * This program is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | * GNU General Public License for more details. |
| 15 | * |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 16 | */ |
| 17 | |
| 18 | #include <spd.h> |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 19 | #include <delay.h> |
Uwe Hermann | 598ba43 | 2008-10-12 22:34:08 +0000 | [diff] [blame] | 20 | #include "lib/debug.c" |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 21 | #include "i82830.h" |
| 22 | |
| 23 | /*----------------------------------------------------------------------------- |
| 24 | Macros and definitions. |
| 25 | -----------------------------------------------------------------------------*/ |
| 26 | |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 27 | /* Debugging macros. */ |
Uwe Hermann | 01ce601 | 2010-03-05 10:03:50 +0000 | [diff] [blame] | 28 | #if CONFIG_DEBUG_RAM_SETUP |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 29 | #define PRINTK_DEBUG(x...) printk(BIOS_DEBUG, x) |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 30 | #define DUMPNORTH() dump_pci_device(PCI_DEV(0, 0, 0)) |
| 31 | #else |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 32 | #define PRINTK_DEBUG(x...) |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 33 | #define DUMPNORTH() |
| 34 | #endif |
| 35 | |
| 36 | /* DRC[10:8] - Refresh Mode Select (RMS). |
| 37 | * 0x0 for Refresh Disabled (Self Refresh) |
| 38 | * 0x1 for Refresh interval 15.6 us for 133MHz |
| 39 | * 0x2 for Refresh interval 7.8 us for 133MHz |
Joseph Smith | 0d7a996 | 2010-03-17 03:18:29 +0000 | [diff] [blame] | 40 | * 0x7 for Refresh interval 128 Clocks. (Fast Refresh Mode) |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 41 | */ |
Joseph Smith | 14669ae | 2008-06-22 04:22:46 +0000 | [diff] [blame] | 42 | #define RAM_COMMAND_REFRESH 0x1 |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 43 | |
| 44 | /* DRC[6:4] - SDRAM Mode Select (SMS). */ |
| 45 | #define RAM_COMMAND_SELF_REFRESH 0x0 |
| 46 | #define RAM_COMMAND_NOP 0x1 |
| 47 | #define RAM_COMMAND_PRECHARGE 0x2 |
| 48 | #define RAM_COMMAND_MRS 0x3 |
| 49 | #define RAM_COMMAND_CBR 0x6 |
| 50 | #define RAM_COMMAND_NORMAL 0x7 |
| 51 | |
| 52 | /* DRC[29] - Initialization Complete (IC). */ |
| 53 | #define RAM_COMMAND_IC 0x1 |
| 54 | |
| 55 | /*----------------------------------------------------------------------------- |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 56 | DIMM-initialization functions. |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 57 | -----------------------------------------------------------------------------*/ |
| 58 | |
Stefan Reinauer | 3ac400e | 2010-03-30 22:12:59 +0000 | [diff] [blame] | 59 | static void do_ram_command(u32 command) |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 60 | { |
Stefan Reinauer | 3ac400e | 2010-03-30 22:12:59 +0000 | [diff] [blame] | 61 | u32 reg32; |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 62 | |
| 63 | /* Configure the RAM command. */ |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 64 | reg32 = pci_read_config32(NORTHBRIDGE, DRC); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 65 | /* Clear bits 29, 10-8, 6-4. */ |
| 66 | reg32 &= 0xdffff88f; |
| 67 | reg32 |= command << 4; |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 68 | PRINTK_DEBUG(" Sending RAM command 0x%08x", reg32); |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 69 | pci_write_config32(NORTHBRIDGE, DRC, reg32); |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 70 | } |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 71 | |
Stefan Reinauer | 3ac400e | 2010-03-30 22:12:59 +0000 | [diff] [blame] | 72 | static void ram_read32(u8 dimm_start, u32 offset) |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 73 | { |
Stefan Reinauer | d93af23 | 2010-04-11 18:54:47 +0000 | [diff] [blame] | 74 | u32 reg32, base_addr = 32 * 1024 * 1024 * dimm_start; |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 75 | if (offset == 0x55aa55aa) { |
Kevin Paul Herbert | bde6d30 | 2014-12-24 18:43:20 -0800 | [diff] [blame] | 76 | reg32 = read32((u32 *)base_addr); |
Stefan Reinauer | d93af23 | 2010-04-11 18:54:47 +0000 | [diff] [blame] | 77 | PRINTK_DEBUG(" Reading RAM at 0x%08x => 0x%08x\n", base_addr, reg32); |
| 78 | PRINTK_DEBUG(" Writing RAM at 0x%08x <= 0x%08x\n", base_addr, offset); |
Kevin Paul Herbert | bde6d30 | 2014-12-24 18:43:20 -0800 | [diff] [blame] | 79 | write32((u32 *)base_addr, offset); |
| 80 | reg32 = read32((u32 *)base_addr); |
Stefan Reinauer | d93af23 | 2010-04-11 18:54:47 +0000 | [diff] [blame] | 81 | PRINTK_DEBUG(" Reading RAM at 0x%08x => 0x%08x\n", base_addr, reg32); |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 82 | } else { |
Stefan Reinauer | d93af23 | 2010-04-11 18:54:47 +0000 | [diff] [blame] | 83 | PRINTK_DEBUG(" to 0x%08x\n", base_addr + offset); |
Kevin Paul Herbert | bde6d30 | 2014-12-24 18:43:20 -0800 | [diff] [blame] | 84 | read32((u32 *)(base_addr + offset)); |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 85 | } |
| 86 | } |
| 87 | |
| 88 | static void initialize_dimm_rows(void) |
| 89 | { |
| 90 | int i, row; |
Stefan Reinauer | 3ac400e | 2010-03-30 22:12:59 +0000 | [diff] [blame] | 91 | u8 dimm_start, dimm_end; |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 92 | unsigned device; |
| 93 | |
Joseph Smith | 14669ae | 2008-06-22 04:22:46 +0000 | [diff] [blame] | 94 | dimm_start = 0; |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 95 | |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 96 | for (row = 0; row < (DIMM_SOCKETS * 2); row++) { |
| 97 | |
| 98 | switch (row) { |
| 99 | case 0: |
Uwe Hermann | d773fd3 | 2010-11-20 20:23:08 +0000 | [diff] [blame] | 100 | device = DIMM0; |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 101 | break; |
| 102 | case 1: |
Uwe Hermann | d773fd3 | 2010-11-20 20:23:08 +0000 | [diff] [blame] | 103 | device = DIMM0; |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 104 | break; |
| 105 | case 2: |
Uwe Hermann | d773fd3 | 2010-11-20 20:23:08 +0000 | [diff] [blame] | 106 | device = DIMM0 + 1; |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 107 | break; |
| 108 | case 3: |
Uwe Hermann | d773fd3 | 2010-11-20 20:23:08 +0000 | [diff] [blame] | 109 | device = DIMM0 + 1; |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 110 | break; |
| 111 | } |
| 112 | |
| 113 | dimm_end = pci_read_config8(NORTHBRIDGE, DRB + row); |
| 114 | |
Joseph Smith | 14669ae | 2008-06-22 04:22:46 +0000 | [diff] [blame] | 115 | if (dimm_end > dimm_start) { |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 116 | printk(BIOS_DEBUG, "Initializing SDRAM Row %u\n", row); |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 117 | |
| 118 | /* NOP command */ |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 119 | PRINTK_DEBUG(" NOP\n"); |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 120 | do_ram_command(RAM_COMMAND_NOP); |
| 121 | ram_read32(dimm_start, 0); |
| 122 | udelay(200); |
| 123 | |
| 124 | /* Pre-charge all banks (at least 200 us after NOP) */ |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 125 | PRINTK_DEBUG(" Pre-charging all banks\n"); |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 126 | do_ram_command(RAM_COMMAND_PRECHARGE); |
| 127 | ram_read32(dimm_start, 0); |
| 128 | udelay(1); |
| 129 | |
| 130 | /* 8 CBR refreshes (Auto Refresh) */ |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 131 | PRINTK_DEBUG(" 8 CBR refreshes\n"); |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 132 | for (i = 0; i < 8; i++) { |
| 133 | do_ram_command(RAM_COMMAND_CBR); |
| 134 | ram_read32(dimm_start, 0); |
| 135 | udelay(1); |
| 136 | } |
| 137 | |
| 138 | /* MRS command */ |
| 139 | /* TODO: Set offset 0x1d0 according to DRT values */ |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 140 | PRINTK_DEBUG(" MRS\n"); |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 141 | do_ram_command(RAM_COMMAND_MRS); |
| 142 | ram_read32(dimm_start, 0x1d0); |
| 143 | udelay(2); |
| 144 | |
| 145 | /* Set GMCH-M Mode Select bits back to NORMAL operation mode */ |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 146 | PRINTK_DEBUG(" Normal operation mode\n"); |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 147 | do_ram_command(RAM_COMMAND_NORMAL); |
| 148 | ram_read32(dimm_start, 0); |
| 149 | udelay(1); |
| 150 | |
| 151 | /* Perform a dummy memory read/write cycle */ |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 152 | PRINTK_DEBUG(" Performing dummy read/write\n"); |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 153 | ram_read32(dimm_start, 0x55aa55aa); |
| 154 | udelay(1); |
Joseph Smith | 14669ae | 2008-06-22 04:22:46 +0000 | [diff] [blame] | 155 | } |
| 156 | /* Set the start of the next DIMM. */ |
| 157 | dimm_start = dimm_end; |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 158 | } |
| 159 | } |
| 160 | |
| 161 | /*----------------------------------------------------------------------------- |
| 162 | DIMM-independant configuration functions. |
| 163 | -----------------------------------------------------------------------------*/ |
| 164 | |
| 165 | struct dimm_size { |
Joseph Smith | 7488e04 | 2010-04-09 11:10:25 +0000 | [diff] [blame] | 166 | unsigned int side1; |
| 167 | unsigned int side2; |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 168 | }; |
| 169 | |
| 170 | static struct dimm_size spd_get_dimm_size(unsigned device) |
| 171 | { |
| 172 | struct dimm_size sz; |
| 173 | int i, module_density, dimm_banks; |
| 174 | sz.side1 = 0; |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 175 | module_density = spd_read_byte(device, SPD_DENSITY_OF_EACH_ROW_ON_MODULE); |
| 176 | dimm_banks = spd_read_byte(device, SPD_NUM_DIMM_BANKS); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 177 | |
| 178 | /* Find the size of side1. */ |
| 179 | /* Find the larger value. The larger value is always side1. */ |
| 180 | for (i = 512; i >= 0; i >>= 1) { |
| 181 | if ((module_density & i) == i) { |
| 182 | sz.side1 = i; |
| 183 | break; |
| 184 | } |
| 185 | } |
| 186 | |
| 187 | /* Set to 0 in case it's single sided. */ |
| 188 | sz.side2 = 0; |
| 189 | |
| 190 | /* Test if it's a dual-sided DIMM. */ |
| 191 | if (dimm_banks > 1) { |
| 192 | /* Test to see if there's a second value, if so it's asymmetrical. */ |
| 193 | if (module_density != i) { |
| 194 | /* Find the second value, picking up where we left off. */ |
| 195 | /* i >>= 1 done initially to make sure we don't get the same value again. */ |
| 196 | for (i >>= 1; i >= 0; i >>= 1) { |
| 197 | if (module_density == (sz.side1 | i)) { |
| 198 | sz.side2 = i; |
| 199 | break; |
| 200 | } |
| 201 | } |
| 202 | /* If not, it's symmetrical */ |
| 203 | } else { |
| 204 | sz.side2 = sz.side1; |
| 205 | } |
| 206 | } |
| 207 | |
| 208 | /* SPD byte 31 is the memory size divided by 4 so we |
| 209 | * need to muliply by 4 to get the total size. |
| 210 | */ |
| 211 | sz.side1 *= 4; |
| 212 | sz.side2 *= 4; |
| 213 | return sz; |
| 214 | } |
| 215 | |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 216 | static void set_dram_row_boundaries(void) |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 217 | { |
| 218 | int i, value, drb1, drb2; |
| 219 | |
| 220 | for (i = 0; i < DIMM_SOCKETS; i++) { |
| 221 | struct dimm_size sz; |
| 222 | unsigned device; |
Uwe Hermann | d773fd3 | 2010-11-20 20:23:08 +0000 | [diff] [blame] | 223 | device = DIMM0 + i; |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 224 | drb1 = 0; |
| 225 | drb2 = 0; |
| 226 | |
| 227 | /* First check if a DIMM is actually present. */ |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 228 | if (spd_read_byte(device, SPD_MEMORY_TYPE) == 0x4) { |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 229 | printk(BIOS_DEBUG, "Found DIMM in slot %u\n", i); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 230 | sz = spd_get_dimm_size(device); |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 231 | printk(BIOS_DEBUG, " DIMM is %uMB on side 1\n", sz.side1); |
| 232 | printk(BIOS_DEBUG, " DIMM is %uMB on side 2\n", sz.side2); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 233 | |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 234 | /* - Memory compatibility checks - */ |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 235 | |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 236 | /* Test for PC133 (i82830 only supports PC133) */ |
| 237 | /* PC133 SPD9 - cycle time is always 75 */ |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 238 | if (spd_read_byte(device, SPD_MIN_CYCLE_TIME_AT_CAS_MAX) != 0x75) { |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 239 | printk(BIOS_ERR, "SPD9 DIMM Is Not PC133 Compatable\n"); |
Stefan Reinauer | 64ed2b7 | 2010-03-31 14:47:43 +0000 | [diff] [blame] | 240 | die("HALT\n"); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 241 | } |
| 242 | /* PC133 SPD10 - access time is always 54 */ |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 243 | if (spd_read_byte(device, SPD_ACCESS_TIME_FROM_CLOCK) != 0x54) { |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 244 | printk(BIOS_ERR, "SPD10 DIMM Is Not PC133 Compatable\n"); |
Stefan Reinauer | 64ed2b7 | 2010-03-31 14:47:43 +0000 | [diff] [blame] | 245 | die("HALT\n"); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 246 | } |
| 247 | |
| 248 | /* The i82830 only supports a symmetrical dual-sided dimms |
| 249 | * and can't handle DIMMs smaller than 32MB per |
| 250 | * side or larger than 256MB per side. |
| 251 | */ |
| 252 | if ((sz.side2 != 0) && (sz.side1 != sz.side2)) { |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 253 | printk(BIOS_ERR, "This northbridge only supports\n"); |
| 254 | printk(BIOS_ERR, "symmetrical dual-sided DIMMs\n"); |
| 255 | printk(BIOS_ERR, "booting as a single-sided DIMM\n"); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 256 | sz.side2 = 0; |
| 257 | } |
| 258 | if ((sz.side1 < 32)) { |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 259 | printk(BIOS_ERR, "DIMMs smaller than 32MB per side\n"); |
| 260 | printk(BIOS_ERR, "are not supported on this northbridge\n"); |
Stefan Reinauer | 64ed2b7 | 2010-03-31 14:47:43 +0000 | [diff] [blame] | 261 | die("HALT\n"); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 262 | } |
| 263 | |
| 264 | if ((sz.side1 > 256)) { |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 265 | printk(BIOS_ERR, "DIMMs larger than 256MB per side\n"); |
| 266 | printk(BIOS_ERR, "are not supported on this northbridge\n"); |
Stefan Reinauer | 64ed2b7 | 2010-03-31 14:47:43 +0000 | [diff] [blame] | 267 | die("HALT\n"); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 268 | } |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 269 | /* - End Memory compatibility checks - */ |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 270 | |
| 271 | /* We need to divide size by 32 to set up the |
| 272 | * DRB registers. |
| 273 | */ |
| 274 | if (sz.side1) |
| 275 | drb1 = sz.side1 / 32; |
| 276 | if (sz.side2) |
| 277 | drb2 = sz.side2 / 32; |
| 278 | } else { |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 279 | printk(BIOS_DEBUG, "No DIMM found in slot %u\n", i); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 280 | |
| 281 | /* If there's no DIMM in the slot, set value to 0. */ |
| 282 | drb1 = 0; |
| 283 | drb2 = 0; |
| 284 | } |
| 285 | /* Set the value for DRAM Row Boundary Registers */ |
| 286 | if (i == 0) { |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 287 | pci_write_config8(NORTHBRIDGE, DRB, drb1); |
| 288 | pci_write_config8(NORTHBRIDGE, DRB + 1, drb1 + drb2); |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 289 | PRINTK_DEBUG(" DRB 0x%02x has been set to 0x%02x\n", DRB, drb1); |
| 290 | PRINTK_DEBUG(" DRB1 0x%02x has been set to 0x%02x\n", DRB + 1, drb1 + drb2); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 291 | } else if (i == 1) { |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 292 | value = pci_read_config8(NORTHBRIDGE, DRB + 1); |
| 293 | pci_write_config8(NORTHBRIDGE, DRB + 2, value + drb1); |
| 294 | pci_write_config8(NORTHBRIDGE, DRB + 3, value + drb1 + drb2); |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 295 | PRINTK_DEBUG(" DRB2 0x%02x has been set to 0x%02x\n", DRB + 2, value + drb1); |
| 296 | PRINTK_DEBUG(" DRB3 0x%02x has been set to 0x%02x\n", DRB + 3, value + drb1 + drb2); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 297 | |
| 298 | /* We need to set the highest DRB value to 0x64 and 0x65. |
| 299 | * These are supposed to be "Reserved" but memory will |
| 300 | * not initialize properly if we don't. |
| 301 | */ |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 302 | value = pci_read_config8(NORTHBRIDGE, DRB + 3); |
| 303 | pci_write_config8(NORTHBRIDGE, DRB + 4, value); |
| 304 | pci_write_config8(NORTHBRIDGE, DRB + 5, value); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 305 | } |
| 306 | } |
| 307 | } |
| 308 | |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 309 | static void set_dram_row_attributes(void) |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 310 | { |
| 311 | int i, dra, col, width, value; |
| 312 | |
| 313 | for (i = 0; i < DIMM_SOCKETS; i++) { |
| 314 | unsigned device; |
Uwe Hermann | d773fd3 | 2010-11-20 20:23:08 +0000 | [diff] [blame] | 315 | device = DIMM0 + i; |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 316 | |
| 317 | /* First check if a DIMM is actually present. */ |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 318 | if (spd_read_byte(device, SPD_MEMORY_TYPE) == 0x4) { |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 319 | PRINTK_DEBUG("Found DIMM in slot %u\n", i); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 320 | |
| 321 | dra = 0x00; |
| 322 | |
| 323 | /* columns */ |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 324 | col = spd_read_byte(device, SPD_NUM_COLUMNS); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 325 | |
| 326 | /* data width */ |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 327 | width = spd_read_byte(device, SPD_MODULE_DATA_WIDTH_LSB); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 328 | |
| 329 | /* calculate page size in bits */ |
| 330 | value = ((1 << col) * width); |
| 331 | |
| 332 | /* convert to Kilobytes */ |
| 333 | dra = ((value / 8) >> 10); |
| 334 | |
| 335 | /* # of banks of DIMM (single or double sided) */ |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 336 | value = spd_read_byte(device, SPD_NUM_DIMM_BANKS); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 337 | |
| 338 | if (value == 1) { |
Joseph Smith | 14669ae | 2008-06-22 04:22:46 +0000 | [diff] [blame] | 339 | if (dra == 2) { |
| 340 | dra = 0xF0; /* 2KB */ |
| 341 | } else if (dra == 4) { |
| 342 | dra = 0xF1; /* 4KB */ |
| 343 | } else if (dra == 8) { |
| 344 | dra = 0xF2; /* 8KB */ |
| 345 | } else if (dra == 16) { |
| 346 | dra = 0xF3; /* 16KB */ |
| 347 | } else { |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 348 | printk(BIOS_ERR, "Page size not supported\n"); |
Stefan Reinauer | 64ed2b7 | 2010-03-31 14:47:43 +0000 | [diff] [blame] | 349 | die("HALT\n"); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 350 | } |
| 351 | } else if (value == 2) { |
Joseph Smith | 14669ae | 2008-06-22 04:22:46 +0000 | [diff] [blame] | 352 | if (dra == 2) { |
| 353 | dra = 0x00; /* 2KB */ |
| 354 | } else if (dra == 4) { |
| 355 | dra = 0x11; /* 4KB */ |
| 356 | } else if (dra == 8) { |
| 357 | dra = 0x22; /* 8KB */ |
| 358 | } else if (dra == 16) { |
| 359 | dra = 0x33; /* 16KB */ |
| 360 | } else { |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 361 | printk(BIOS_ERR, "Page size not supported\n"); |
Stefan Reinauer | 64ed2b7 | 2010-03-31 14:47:43 +0000 | [diff] [blame] | 362 | die("HALT\n"); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 363 | } |
| 364 | } else { |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 365 | printk(BIOS_ERR, "# of banks of DIMM not supported\n"); |
Stefan Reinauer | 64ed2b7 | 2010-03-31 14:47:43 +0000 | [diff] [blame] | 366 | die("HALT\n"); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 367 | } |
| 368 | |
| 369 | } else { |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 370 | PRINTK_DEBUG("No DIMM found in slot %u\n", i); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 371 | |
| 372 | /* If there's no DIMM in the slot, set dra value to 0xFF. */ |
| 373 | dra = 0xFF; |
| 374 | } |
| 375 | |
| 376 | /* Set the value for DRAM Row Attribute Registers */ |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 377 | pci_write_config8(NORTHBRIDGE, DRA + i, dra); |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 378 | PRINTK_DEBUG(" DRA 0x%02x has been set to 0x%02x\n", DRA + i, dra); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 379 | } |
| 380 | } |
| 381 | |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 382 | static void set_dram_timing(void) |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 383 | { |
| 384 | /* Set the value for DRAM Timing Register */ |
| 385 | /* TODO: Configure the value according to SPD values. */ |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 386 | pci_write_config32(NORTHBRIDGE, DRT, 0x00000010); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 387 | } |
| 388 | |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 389 | static void set_dram_buffer_strength(void) |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 390 | { |
| 391 | /* TODO: This needs to be set according to the DRAM tech |
| 392 | * (x8, x16, or x32). Argh, Intel provides no docs on this! |
| 393 | * Currently, it needs to be pulled from the output of |
| 394 | * lspci -xxx Rx92 |
| 395 | */ |
| 396 | |
| 397 | /* Set the value for System Memory Buffer Strength Control Registers */ |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 398 | pci_write_config32(NORTHBRIDGE, BUFF_SC, 0xFC9B491B); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 399 | } |
| 400 | |
| 401 | /*----------------------------------------------------------------------------- |
| 402 | Public interface. |
| 403 | -----------------------------------------------------------------------------*/ |
| 404 | |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 405 | static void sdram_set_registers(void) |
| 406 | { |
Joseph Smith | 77d31ec | 2010-04-11 16:36:13 +0000 | [diff] [blame] | 407 | printk(BIOS_DEBUG, "Setting initial SDRAM registers....\n"); |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 408 | |
| 409 | /* Calculate the value for DRT DRAM Timing Register */ |
| 410 | set_dram_timing(); |
| 411 | |
| 412 | /* Setup System Memory Buffer Strength Control Registers */ |
| 413 | set_dram_buffer_strength(); |
| 414 | |
| 415 | /* Setup DRAM Row Boundary Registers */ |
| 416 | set_dram_row_boundaries(); |
| 417 | |
| 418 | /* Setup DRAM Row Attribute Registers */ |
| 419 | set_dram_row_attributes(); |
| 420 | |
Joseph Smith | 77d31ec | 2010-04-11 16:36:13 +0000 | [diff] [blame] | 421 | printk(BIOS_DEBUG, "Initial SDRAM registers have been set.\n"); |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 422 | } |
| 423 | |
| 424 | static void northbridge_set_registers(void) |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 425 | { |
Stefan Reinauer | 3ac400e | 2010-03-30 22:12:59 +0000 | [diff] [blame] | 426 | u16 value; |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 427 | int igd_memory = 0; |
| 428 | |
Joseph Smith | 77d31ec | 2010-04-11 16:36:13 +0000 | [diff] [blame] | 429 | printk(BIOS_DEBUG, "Setting initial Nothbridge registers....\n"); |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 430 | |
| 431 | /* Set the value for Fixed DRAM Hole Control Register */ |
| 432 | pci_write_config8(NORTHBRIDGE, FDHC, 0x00); |
| 433 | |
| 434 | /* Set the value for Programable Attribute Map Registers |
| 435 | * Ideally, this should be R/W for as many ranges as possible. |
| 436 | */ |
| 437 | pci_write_config8(NORTHBRIDGE, PAM0, 0x30); |
| 438 | pci_write_config8(NORTHBRIDGE, PAM1, 0x33); |
| 439 | pci_write_config8(NORTHBRIDGE, PAM2, 0x33); |
| 440 | pci_write_config8(NORTHBRIDGE, PAM3, 0x33); |
| 441 | pci_write_config8(NORTHBRIDGE, PAM4, 0x33); |
| 442 | pci_write_config8(NORTHBRIDGE, PAM5, 0x33); |
| 443 | pci_write_config8(NORTHBRIDGE, PAM6, 0x33); |
| 444 | |
| 445 | /* Set the value for System Management RAM Control Register */ |
| 446 | pci_write_config8(NORTHBRIDGE, SMRAM, 0x02); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 447 | |
| 448 | /* Set the value for GMCH Control Register #0 */ |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 449 | pci_write_config16(NORTHBRIDGE, GCC0, 0xA072); |
| 450 | |
| 451 | /* Set the value for Aperture Base Configuration Register */ |
| 452 | pci_write_config32(NORTHBRIDGE, APBASE, 0x00000008); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 453 | |
| 454 | /* Set the value for GMCH Control Register #1 */ |
| 455 | switch (CONFIG_VIDEO_MB) { |
| 456 | case 512: /* 512K of memory */ |
| 457 | igd_memory = 0x2; |
| 458 | break; |
| 459 | case 1: /* 1M of memory */ |
| 460 | igd_memory = 0x3; |
| 461 | break; |
| 462 | case 8: /* 8M of memory */ |
| 463 | igd_memory = 0x4; |
| 464 | break; |
| 465 | default: /* No memory */ |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 466 | pci_write_config16(NORTHBRIDGE, GCC1, 0x0002); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 467 | igd_memory = 0x0; |
| 468 | } |
| 469 | |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 470 | value = pci_read_config16(NORTHBRIDGE, GCC1); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 471 | value |= igd_memory << 4; |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 472 | value |= 1; // 64MB aperture |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 473 | pci_write_config16(NORTHBRIDGE, GCC1, value); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 474 | |
Joseph Smith | 77d31ec | 2010-04-11 16:36:13 +0000 | [diff] [blame] | 475 | printk(BIOS_DEBUG, "Initial Northbridge registers have been set.\n"); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 476 | } |
| 477 | |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 478 | static void sdram_initialize(void) |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 479 | { |
Stefan Reinauer | 3ac400e | 2010-03-30 22:12:59 +0000 | [diff] [blame] | 480 | u32 reg32; |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 481 | |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 482 | /* Setup Initial SDRAM Registers */ |
| 483 | sdram_set_registers(); |
| 484 | |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 485 | /* Wait until power/voltages and clocks are stable (200us). */ |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 486 | udelay(200); |
| 487 | |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 488 | /* Initialize each row of memory one at a time */ |
| 489 | initialize_dimm_rows(); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 490 | |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 491 | /* Enable Refresh */ |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 492 | PRINTK_DEBUG("Enabling Refresh\n"); |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 493 | reg32 = pci_read_config32(NORTHBRIDGE, DRC); |
| 494 | reg32 |= (RAM_COMMAND_REFRESH << 8); |
| 495 | pci_write_config32(NORTHBRIDGE, DRC, reg32); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 496 | |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 497 | /* Set initialization complete */ |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 498 | PRINTK_DEBUG("Setting initialization complete\n"); |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 499 | reg32 = pci_read_config32(NORTHBRIDGE, DRC); |
| 500 | reg32 |= (RAM_COMMAND_IC << 29); |
| 501 | pci_write_config32(NORTHBRIDGE, DRC, reg32); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 502 | |
Joseph Smith | fa742da | 2010-02-01 22:51:18 +0000 | [diff] [blame] | 503 | /* Setup Initial Northbridge Registers */ |
| 504 | northbridge_set_registers(); |
Joseph Smith | 14669ae | 2008-06-22 04:22:46 +0000 | [diff] [blame] | 505 | |
Joseph Smith | bdf26a6 | 2010-04-11 05:50:08 +0000 | [diff] [blame] | 506 | PRINTK_DEBUG("Northbridge following SDRAM init:\n"); |
Joseph Smith | 6a1dc86 | 2008-03-09 13:24:46 +0000 | [diff] [blame] | 507 | DUMPNORTH(); |
| 508 | } |