Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 1 | /* |
| 2 | * This file is part of the coreboot project. |
| 3 | * |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 4 | * Copyright (C) 2008 VIA Technologies, Inc. |
| 5 | * (Written by Aaron Lwe <aaron.lwe@gmail.com> for VIA) |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 6 | * Copyright (C) 2007 Corey Osgood <corey.osgood@gmail.com> |
| 7 | * |
| 8 | * This program is free software; you can redistribute it and/or modify |
| 9 | * it under the terms of the GNU General Public License as published by |
| 10 | * the Free Software Foundation; either version 2 of the License, or |
| 11 | * (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 |
Patrick Georgi | b890a12 | 2015-03-26 15:17:45 +0100 | [diff] [blame] | 20 | * Foundation, Inc. |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 21 | */ |
| 22 | |
| 23 | #include <spd.h> |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 24 | #include <delay.h> |
| 25 | #include "cn700.h" |
| 26 | |
Stefan Reinauer | d4814bd | 2011-04-21 20:45:45 +0000 | [diff] [blame] | 27 | #if CONFIG_DEBUG_RAM_SETUP |
Stefan Reinauer | 65b72ab | 2015-01-05 12:59:54 -0800 | [diff] [blame] | 28 | #define PRINT_DEBUG_MEM(x) printk(BIOS_DEBUG, x) |
| 29 | #define PRINT_DEBUG_MEM_HEX8(x) printk(BIOS_DEBUG, "%02x", x) |
| 30 | #define PRINT_DEBUG_MEM_HEX16(x) printk(BIOS_DEBUG, "%04x", x) |
| 31 | #define PRINT_DEBUG_MEM_HEX32(x) printk(BIOS_DEBUG, "%08x", x) |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 32 | #define DUMPNORTH() dump_pci_device(PCI_DEV(0, 0, 0)) |
| 33 | #else |
| 34 | #define PRINT_DEBUG_MEM(x) |
| 35 | #define PRINT_DEBUG_MEM_HEX8(x) |
| 36 | #define PRINT_DEBUG_MEM_HEX16(x) |
| 37 | #define PRINT_DEBUG_MEM_HEX32(x) |
| 38 | #define DUMPNORTH() |
| 39 | #endif |
| 40 | |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 41 | static void do_ram_command(device_t dev, u8 command) |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 42 | { |
| 43 | u8 reg; |
| 44 | |
| 45 | /* TODO: Support for multiple DIMMs. */ |
| 46 | |
| 47 | reg = pci_read_config8(dev, DRAM_MISC_CTL); |
| 48 | reg &= 0xf8; /* Clear bits 2-0. */ |
| 49 | reg |= command; |
| 50 | pci_write_config8(dev, DRAM_MISC_CTL, reg); |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 51 | } |
| 52 | |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 53 | /** |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 54 | * Configure the bus between the CPU and the northbridge. This might be able to |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 55 | * be moved to post-ram code in the future. For the most part, these registers |
| 56 | * should not be messed around with. These are too complex to explain short of |
| 57 | * copying the datasheets into the comments, but most of these values are from |
| 58 | * the BIOS Porting Guide, so they should work on any board. If they don't, |
| 59 | * try the values from your factory BIOS. |
| 60 | * |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 61 | * TODO: Changing the DRAM frequency doesn't work (hard lockup). |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 62 | * |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 63 | * @param dev The northbridge's CPU Host Interface (D0F2). |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 64 | */ |
| 65 | static void c7_cpu_setup(device_t dev) |
| 66 | { |
| 67 | /* Host bus interface registers (D0F2 0x50-0x67) */ |
| 68 | /* Request phase control */ |
| 69 | pci_write_config8(dev, 0x50, 0x88); |
| 70 | /* CPU Interface Control */ |
| 71 | pci_write_config8(dev, 0x51, 0x7a); |
| 72 | pci_write_config8(dev, 0x52, 0x6f); |
| 73 | /* Arbitration */ |
| 74 | pci_write_config8(dev, 0x53, 0x88); |
| 75 | /* Miscellaneous Control */ |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 76 | pci_write_config8(dev, 0x54, 0x1e); |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 77 | pci_write_config8(dev, 0x55, 0x16); |
| 78 | /* Write Policy */ |
| 79 | pci_write_config8(dev, 0x56, 0x01); |
| 80 | /* Miscellaneous Control */ |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 81 | /* |
| 82 | * DRAM Operating Frequency (bits 7:5) |
| 83 | * 000 : 100MHz 001 : 133MHz |
| 84 | * 010 : 166MHz 011 : 200MHz |
| 85 | * 100 : 266MHz 101 : 333MHz |
| 86 | * 110/111 : Reserved |
| 87 | */ |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 88 | /* CPU Miscellaneous Control */ |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 89 | pci_write_config8(dev, 0x59, 0x44); |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 90 | /* Write Policy */ |
| 91 | pci_write_config8(dev, 0x5d, 0xb2); |
| 92 | /* Bandwidth Timer */ |
| 93 | pci_write_config8(dev, 0x5e, 0x88); |
| 94 | /* CPU Miscellaneous Control */ |
| 95 | pci_write_config8(dev, 0x5f, 0xc7); |
| 96 | |
| 97 | /* Line DRDY# Timing Control */ |
| 98 | pci_write_config8(dev, 0x60, 0xff); |
| 99 | pci_write_config8(dev, 0x61, 0xff); |
| 100 | pci_write_config8(dev, 0x62, 0x0f); |
| 101 | /* QW DRDY# Timing Control */ |
| 102 | pci_write_config8(dev, 0x63, 0xff); |
| 103 | pci_write_config8(dev, 0x64, 0xff); |
| 104 | pci_write_config8(dev, 0x65, 0x0f); |
| 105 | /* Read Line Burst DRDY# Timing Control */ |
| 106 | pci_write_config8(dev, 0x66, 0xff); |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 107 | pci_write_config8(dev, 0x67, 0x30); |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 108 | |
| 109 | /* Host Bus I/O Circuit (see datasheet) */ |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 110 | /* Host Address Pullup/down Driving */ |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 111 | pci_write_config8(dev, 0x70, 0x11); |
| 112 | pci_write_config8(dev, 0x71, 0x11); |
| 113 | pci_write_config8(dev, 0x72, 0x11); |
| 114 | pci_write_config8(dev, 0x73, 0x11); |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 115 | /* Miscellaneous Control */ |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 116 | pci_write_config8(dev, 0x74, 0x35); |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 117 | /* AGTL+ I/O Circuit */ |
| 118 | pci_write_config8(dev, 0x75, 0x28); |
| 119 | /* AGTL+ Compensation Status */ |
| 120 | pci_write_config8(dev, 0x76, 0x74); |
| 121 | /* AGTL+ Auto Compensation Offest */ |
| 122 | pci_write_config8(dev, 0x77, 0x00); |
| 123 | /* Host FSB CKG Control */ |
| 124 | pci_write_config8(dev, 0x78, 0x0a); |
| 125 | /* Address/Address Clock Output Delay Control */ |
| 126 | pci_write_config8(dev, 0x79, 0xaa); |
| 127 | /* Address Strobe Input Delay Control */ |
| 128 | pci_write_config8(dev, 0x7a, 0x24); |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 129 | /* Address CKG Rising/Falling Time Control */ |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 130 | pci_write_config8(dev, 0x7b, 0xaa); |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 131 | /* Address CKG Clock Rising/Falling Time Control */ |
| 132 | pci_write_config8(dev, 0x7c, 0x00); |
| 133 | /* Undefined (can't remember why I did this) */ |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 134 | pci_write_config8(dev, 0x7d, 0x6d); |
| 135 | pci_write_config8(dev, 0x7e, 0x00); |
| 136 | pci_write_config8(dev, 0x7f, 0x00); |
| 137 | pci_write_config8(dev, 0x80, 0x1b); |
| 138 | pci_write_config8(dev, 0x81, 0x0a); |
| 139 | pci_write_config8(dev, 0x82, 0x0a); |
| 140 | pci_write_config8(dev, 0x83, 0x0a); |
| 141 | } |
| 142 | |
| 143 | /** |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 144 | * Set up DRAM size according to SPD data. Eventually, DRAM timings should be |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 145 | * done in a similar manner. |
| 146 | * |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 147 | * @param ctrl The northbridge devices and SPD addresses. |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 148 | */ |
| 149 | static void sdram_set_size(const struct mem_controller *ctrl) |
| 150 | { |
| 151 | u8 density, ranks, result, col; |
| 152 | |
| 153 | ranks = spd_read_byte(ctrl->channel0[0], SPD_NUM_DIMM_BANKS); |
| 154 | ranks = (ranks & 0x07) + 1; |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 155 | density = spd_read_byte(ctrl->channel0[0], |
| 156 | SPD_DENSITY_OF_EACH_ROW_ON_MODULE); |
| 157 | switch (density) { |
| 158 | case 0x80: |
| 159 | result = 0x08; /* 512MB / 64MB = 0x08 */ |
| 160 | break; |
| 161 | case 0x40: |
| 162 | result = 0x04; |
| 163 | break; |
| 164 | case 0x20: |
| 165 | result = 0x02; |
| 166 | break; |
| 167 | case 0x10: |
| 168 | result = 0xff; /* 16GB */ |
| 169 | break; |
| 170 | case 0x08: |
| 171 | result = 0xff; /* 8GB */ |
| 172 | break; |
| 173 | case 0x04: |
| 174 | result = 0xff; /* 4GB */ |
| 175 | break; |
| 176 | case 0x02: |
| 177 | result = 0x20; /* 2GB */ |
| 178 | break; |
| 179 | case 0x01: |
| 180 | result = 0x10; /* 1GB */ |
| 181 | break; |
Stefan Reinauer | 89fcdec | 2011-10-13 17:03:04 -0700 | [diff] [blame] | 182 | default: |
| 183 | result = 0; |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 184 | } |
| 185 | |
Stefan Reinauer | 89fcdec | 2011-10-13 17:03:04 -0700 | [diff] [blame] | 186 | switch (result) { |
| 187 | case 0xff: |
Stefan Reinauer | 64ed2b7 | 2010-03-31 14:47:43 +0000 | [diff] [blame] | 188 | die("DRAM module size too big, not supported by CN700\n"); |
Stefan Reinauer | 89fcdec | 2011-10-13 17:03:04 -0700 | [diff] [blame] | 189 | break; |
| 190 | case 0: |
| 191 | die("DRAM module has unknown density\n"); |
| 192 | break; |
| 193 | default: |
Corey Osgood | f976548 | 2010-08-01 17:20:20 +0000 | [diff] [blame] | 194 | printk(BIOS_DEBUG, "Found %iMB of ram\n", result * ranks * 64); |
Stefan Reinauer | 89fcdec | 2011-10-13 17:03:04 -0700 | [diff] [blame] | 195 | } |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 196 | |
| 197 | pci_write_config8(ctrl->d0f3, 0x40, result); |
| 198 | pci_write_config8(ctrl->d0f3, 0x48, 0x00); |
| 199 | if (ranks == 2) { |
| 200 | pci_write_config8(ctrl->d0f3, 0x41, result * ranks); |
| 201 | pci_write_config8(ctrl->d0f3, 0x49, result); |
| 202 | } |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 203 | /* Size mirror */ |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 204 | pci_write_config8(ctrl->d0f7, 0xe5, (result * ranks) << 2); |
| 205 | pci_write_config8(ctrl->d0f7, 0x57, (result * ranks) << 2); |
| 206 | /* Low Top Address */ |
| 207 | pci_write_config8(ctrl->d0f3, 0x84, 0x00); |
| 208 | pci_write_config8(ctrl->d0f3, 0x85, (result * ranks) << 2); |
| 209 | pci_write_config8(ctrl->d0f3, 0x88, (result * ranks) << 2); |
| 210 | |
| 211 | /* Physical-Virtual Mapping */ |
| 212 | if (ranks == 2) |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 213 | pci_write_config8(ctrl->d0f3, 0x54, |
| 214 | 1 << 7 | 0 << 4 | 1 << 3 | 1 << 0); |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 215 | if (ranks == 1) |
| 216 | pci_write_config8(ctrl->d0f3, 0x54, 1 << 7 | 0 << 4); |
| 217 | pci_write_config8(ctrl->d0f3, 0x55, 0x00); |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 218 | /* Virtual rank interleave, disable */ |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 219 | pci_write_config32(ctrl->d0f3, 0x58, 0x00); |
| 220 | |
| 221 | /* MA Map Type */ |
| 222 | result = spd_read_byte(ctrl->channel0[0], SPD_NUM_BANKS_PER_SDRAM); |
| 223 | if (result == 8) { |
| 224 | col = spd_read_byte(ctrl->channel0[0], SPD_NUM_COLUMNS); |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 225 | switch (col) { |
| 226 | case 10: |
| 227 | pci_write_config8(ctrl->d0f3, 0x50, 0xa0); |
| 228 | break; |
| 229 | case 11: |
| 230 | pci_write_config8(ctrl->d0f3, 0x50, 0xc0); |
| 231 | break; |
| 232 | case 12: |
| 233 | pci_write_config8(ctrl->d0f3, 0x50, 0xe0); |
| 234 | break; |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 235 | } |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 236 | } else if (result == 4) { |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 237 | col = spd_read_byte(ctrl->channel0[0], SPD_NUM_COLUMNS); |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 238 | switch (col) { |
| 239 | case 9: |
| 240 | pci_write_config8(ctrl->d0f3, 0x50, 0x00); |
| 241 | break; |
| 242 | case 10: |
| 243 | pci_write_config8(ctrl->d0f3, 0x50, 0x20); |
| 244 | break; |
| 245 | case 11: |
| 246 | pci_write_config8(ctrl->d0f3, 0x50, 0x40); |
| 247 | break; |
| 248 | case 12: |
| 249 | pci_write_config8(ctrl->d0f3, 0x50, 0x60); |
| 250 | break; |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 251 | } |
| 252 | } |
| 253 | pci_write_config8(ctrl->d0f3, 0x51, 0x00); |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 254 | } |
| 255 | |
| 256 | /** |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 257 | * Set up various RAM and other control registers statically. Some of these may |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 258 | * not be needed, other should be done with SPD info, but that's a project for |
| 259 | * the future. |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 260 | */ |
| 261 | static void sdram_set_registers(const struct mem_controller *ctrl) |
| 262 | { |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 263 | u8 reg; |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 264 | |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 265 | /* Set WR=5 */ |
| 266 | pci_write_config8(ctrl->d0f3, 0x61, 0xe0); |
| 267 | /* Set CAS=4 */ |
| 268 | pci_write_config8(ctrl->d0f3, 0x62, 0xfa); |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 269 | /* DRAM timing-3 */ |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 270 | pci_write_config8(ctrl->d0f3, 0x63, 0xca); |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 271 | /* DRAM timing-4 */ |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 272 | pci_write_config8(ctrl->d0f3, 0x64, 0xcc); |
| 273 | /* DIMM command / Address Selection */ |
| 274 | pci_write_config8(ctrl->d0f3, 0x67, 0x00); |
| 275 | /* Disable cross bank/multi page mode */ |
| 276 | pci_write_config8(ctrl->d0f3, 0x69, 0x00); |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 277 | /* Disable refresh now */ |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 278 | pci_write_config8(ctrl->d0f3, 0x6a, 0x00); |
| 279 | |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 280 | /* Frequency 100 MHz */ |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 281 | pci_write_config8(ctrl->d0f3, 0x90, 0x00); |
| 282 | pci_write_config8(ctrl->d0f2, 0x57, 0x18); |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 283 | /* Allow manual DLL reset */ |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 284 | pci_write_config8(ctrl->d0f3, 0x6b, 0x10); |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 285 | |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 286 | /* Bank/Rank Interleave Address Select */ |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 287 | pci_write_config8(ctrl->d0f3, 0x52, 0x33); |
| 288 | pci_write_config8(ctrl->d0f3, 0x53, 0x3f); |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 289 | |
| 290 | /* Set to DDR2 SDRAM, BL=8 (0xc8, 0xc0 for bl=4) */ |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 291 | pci_write_config8(ctrl->d0f3, 0x6c, 0xc8); |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 292 | |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 293 | /* DRAM Bus Turn-Around Setting */ |
| 294 | pci_write_config8(ctrl->d0f3, 0x60, 0x03); |
| 295 | /* DRAM Arbitration Control */ |
| 296 | pci_write_config8(ctrl->d0f3, 0x66, 0x80); |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 297 | /* |
| 298 | * DQS Tuning: testing on a couple different boards has shown this is |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 299 | * static, or close enough that it can be. Which is good, because the |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 300 | * tuning function used too many registers. |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 301 | */ |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 302 | /* DQS Output Delay for Channel A */ |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 303 | pci_write_config8(ctrl->d0f3, 0x70, 0x00); |
| 304 | /* MD Output Delay for Channel A */ |
| 305 | pci_write_config8(ctrl->d0f3, 0x71, 0x01); |
| 306 | pci_write_config8(ctrl->d0f3, 0x73, 0x01); |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 307 | |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 308 | /* DRAM arbitration timer */ |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 309 | pci_write_config8(ctrl->d0f3, 0x65, 0xd9); |
| 310 | |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 311 | /* DRAM signal timing control */ |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 312 | pci_write_config8(ctrl->d0f3, 0x74, 0x01); |
| 313 | pci_write_config8(ctrl->d0f3, 0x75, 0x01); |
| 314 | pci_write_config8(ctrl->d0f3, 0x76, 0x06); |
| 315 | pci_write_config8(ctrl->d0f3, 0x77, 0x92); |
| 316 | pci_write_config8(ctrl->d0f3, 0x78, 0x83); |
| 317 | pci_write_config8(ctrl->d0f3, 0x79, 0x83); |
| 318 | pci_write_config8(ctrl->d0f3, 0x7a, 0x00); |
| 319 | pci_write_config8(ctrl->d0f3, 0x7b, 0x10); |
| 320 | |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 321 | /* DRAM clocking control */ |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 322 | pci_write_config8(ctrl->d0f3, 0x91, 0x01); |
| 323 | /* CS/CKE Clock Phase Control */ |
| 324 | pci_write_config8(ctrl->d0f3, 0x92, 0x02); |
| 325 | /* SCMD/MA Clock Phase Control */ |
| 326 | pci_write_config8(ctrl->d0f3, 0x93, 0x02); |
| 327 | /* DCLKO Feedback Mode Output Control */ |
| 328 | pci_write_config8(ctrl->d0f3, 0x94, 0x00); |
| 329 | pci_write_config8(ctrl->d0f3, 0x9d, 0x0f); |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 330 | |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 331 | /* SDRAM ODT Control */ |
| 332 | pci_write_config8(ctrl->d0f3, 0xda, 0x80); |
| 333 | /* Channel A DQ/DQS CKG Output Delay Control */ |
| 334 | pci_write_config8(ctrl->d0f3, 0xdc, 0x54); |
| 335 | /* Channel A DQ/DQS CKG Output Delay Control */ |
| 336 | pci_write_config8(ctrl->d0f3, 0xdd, 0x55); |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 337 | /* ODT lookup table */ |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 338 | pci_write_config8(ctrl->d0f3, 0xd8, 0x01); |
| 339 | pci_write_config8(ctrl->d0f3, 0xd9, 0x0a); |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 340 | |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 341 | /* DDR SDRAM control */ |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 342 | pci_write_config8(ctrl->d0f3, 0x6d, 0xc0); |
| 343 | pci_write_config8(ctrl->d0f3, 0x6f, 0x41); |
| 344 | |
| 345 | /* DQ/DQS Strength Control */ |
| 346 | pci_write_config8(ctrl->d0f3, 0xd0, 0xaa); |
| 347 | |
| 348 | /* Compensation Control */ |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 349 | pci_write_config8(ctrl->d0f3, 0xd3, 0x01); /* Enable autocompensation */ |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 350 | /* ODT (some are set with driving select above) */ |
| 351 | pci_write_config8(ctrl->d0f3, 0xd4, 0x80); |
| 352 | pci_write_config8(ctrl->d0f3, 0xd5, 0x8a); |
| 353 | /* Memory Pads Driving and Range Select */ |
| 354 | pci_write_config8(ctrl->d0f3, 0xd6, 0xaa); |
| 355 | |
| 356 | pci_write_config8(ctrl->d0f3, 0xe0, 0xee); |
| 357 | pci_write_config8(ctrl->d0f3, 0xe2, 0xac); |
| 358 | pci_write_config8(ctrl->d0f3, 0xe4, 0x66); |
| 359 | pci_write_config8(ctrl->d0f3, 0xe6, 0x33); |
| 360 | pci_write_config8(ctrl->d0f3, 0xe8, 0x86); |
| 361 | /* DQS / DQ CKG Duty Cycle Control */ |
| 362 | pci_write_config8(ctrl->d0f3, 0xec, 0x00); |
| 363 | /* MCLK Output Duty Control */ |
| 364 | pci_write_config8(ctrl->d0f3, 0xee, 0x00); |
| 365 | /* DQS CKG Input Delay Control */ |
| 366 | pci_write_config8(ctrl->d0f3, 0xef, 0x10); |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 367 | |
| 368 | /* DRAM duty control */ |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 369 | pci_write_config8(ctrl->d0f3, 0xed, 0x10); |
| 370 | |
Bari Ari | d4759d0 | 2008-09-01 01:48:07 +0000 | [diff] [blame] | 371 | /* SMM and APIC decoding, we do not use SMM */ |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 372 | reg = 0x29; |
| 373 | pci_write_config8(ctrl->d0f3, 0x86, reg); |
| 374 | /* SMM and APIC decoding mirror */ |
| 375 | pci_write_config8(ctrl->d0f7, 0xe6, reg); |
| 376 | |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 377 | /* DRAM module configuration */ |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 378 | pci_write_config8(ctrl->d0f3, 0x6e, 0x89); |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 379 | } |
| 380 | |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 381 | static void sdram_set_post(const struct mem_controller *ctrl) |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 382 | { |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 383 | device_t dev = ctrl->d0f3; |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 384 | |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 385 | /* Enable multipage mode. */ |
| 386 | pci_write_config8(dev, 0x69, 0x03); |
| 387 | |
| 388 | /* Enable refresh. */ |
| 389 | pci_write_config8(dev, 0x6a, 0x32); |
| 390 | |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 391 | /* VGA device. */ |
| 392 | pci_write_config16(dev, 0xa0, (1 << 15)); |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 393 | pci_write_config16(dev, 0xa4, 0x0010); |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 394 | } |
| 395 | |
Kevin Paul Herbert | bde6d30 | 2014-12-24 18:43:20 -0800 | [diff] [blame] | 396 | static void sdram_enable(device_t dev, u8 *rank_address) |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 397 | { |
| 398 | u8 i; |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 399 | |
| 400 | /* 1. Apply NOP. */ |
Stefan Reinauer | 64ed2b7 | 2010-03-31 14:47:43 +0000 | [diff] [blame] | 401 | PRINT_DEBUG_MEM("RAM Enable 1: Apply NOP\n"); |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 402 | do_ram_command(dev, RAM_COMMAND_NOP); |
| 403 | udelay(100); |
| 404 | read32(rank_address + 0x10); |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 405 | |
| 406 | /* 2. Precharge all. */ |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 407 | udelay(400); |
Stefan Reinauer | 64ed2b7 | 2010-03-31 14:47:43 +0000 | [diff] [blame] | 408 | PRINT_DEBUG_MEM("RAM Enable 2: Precharge all\n"); |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 409 | do_ram_command(dev, RAM_COMMAND_PRECHARGE); |
| 410 | read32(rank_address + 0x10); |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 411 | |
| 412 | /* 3. Mode register set. */ |
Corey Osgood | f976548 | 2010-08-01 17:20:20 +0000 | [diff] [blame] | 413 | PRINT_DEBUG_MEM("RAM Enable 3: Mode register set\n"); |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 414 | do_ram_command(dev, RAM_COMMAND_MRS); |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 415 | read32(rank_address + 0x120000); /* EMRS DLL Enable */ |
Kevin Paul Herbert | bde6d30 | 2014-12-24 18:43:20 -0800 | [diff] [blame] | 416 | read32(rank_address + 0x800); /* MRS DLL Reset */ |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 417 | |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 418 | /* 4. Precharge all again. */ |
Corey Osgood | f976548 | 2010-08-01 17:20:20 +0000 | [diff] [blame] | 419 | PRINT_DEBUG_MEM("RAM Enable 4: Precharge all\n"); |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 420 | do_ram_command(dev, RAM_COMMAND_PRECHARGE); |
| 421 | read32(rank_address + 0x0); |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 422 | |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 423 | /* 5. Perform 8 refresh cycles. Wait tRC each time. */ |
Corey Osgood | f976548 | 2010-08-01 17:20:20 +0000 | [diff] [blame] | 424 | PRINT_DEBUG_MEM("RAM Enable 5: CBR\n"); |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 425 | do_ram_command(dev, RAM_COMMAND_CBR); |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 426 | for (i = 0; i < 8; i++) { |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 427 | read32(rank_address + 0x20); |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 428 | udelay(100); |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 429 | } |
| 430 | |
| 431 | /* 6. Mode register set. */ |
Corey Osgood | f976548 | 2010-08-01 17:20:20 +0000 | [diff] [blame] | 432 | PRINT_DEBUG_MEM("RAM Enable 6: Mode register set\n"); |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 433 | /* Safe value for now, BL=8, WR=5, CAS=4 */ |
| 434 | /* |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 435 | * (E)MRS values are from the BPG. No direct explanation is given, but |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 436 | * they should somehow conform to the JEDEC DDR2 SDRAM Specification |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 437 | * (JESD79-2C). |
| 438 | */ |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 439 | do_ram_command(dev, RAM_COMMAND_MRS); |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 440 | read32(rank_address + 0x002258); /* MRS command */ |
| 441 | read32(rank_address + 0x121c20); /* EMRS OCD Default */ |
| 442 | read32(rank_address + 0x120020); /* EMRS OCD Calibration Mode Exit */ |
| 443 | |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 444 | /* 8. Normal operation */ |
Corey Osgood | f976548 | 2010-08-01 17:20:20 +0000 | [diff] [blame] | 445 | PRINT_DEBUG_MEM("RAM Enable 7: Normal operation\n"); |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 446 | do_ram_command(dev, RAM_COMMAND_NORMAL); |
| 447 | read32(rank_address + 0x30); |
Corey Osgood | bd3f93e | 2008-02-21 00:56:14 +0000 | [diff] [blame] | 448 | } |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 449 | |
| 450 | /* |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 451 | * Support one DIMM with up to 2 ranks. |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 452 | */ |
| 453 | static void ddr_ram_setup(const struct mem_controller *ctrl) |
| 454 | { |
| 455 | u8 reg; |
| 456 | |
| 457 | c7_cpu_setup(ctrl->d0f2); |
| 458 | sdram_set_registers(ctrl); |
| 459 | sdram_set_size(ctrl); |
Kevin Paul Herbert | bde6d30 | 2014-12-24 18:43:20 -0800 | [diff] [blame] | 460 | sdram_enable(ctrl->d0f3, (u8 *)0); |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 461 | reg = pci_read_config8(ctrl->d0f3, 0x41); |
| 462 | if (reg != 0) |
Uwe Hermann | ea7b518 | 2008-10-09 17:08:32 +0000 | [diff] [blame] | 463 | sdram_enable(ctrl->d0f3, |
Kevin Paul Herbert | bde6d30 | 2014-12-24 18:43:20 -0800 | [diff] [blame] | 464 | (u8 *)(pci_read_config8(ctrl->d0f3, 0x40) << 26)); |
Aaron Lwe | fcb2a31 | 2008-05-19 12:17:43 +0000 | [diff] [blame] | 465 | sdram_set_post(ctrl); |
| 466 | } |