Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 1 | /* |
Stefan Reinauer | 7e61e45 | 2008-01-18 10:35:56 +0000 | [diff] [blame] | 2 | * This file is part of the coreboot project. |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 3 | * |
Marc Jones (marc.jones | e3aeb93 | 2008-04-11 03:20:28 +0000 | [diff] [blame] | 4 | * Copyright (C) 2007-2008 Advanced Micro Devices, Inc. |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +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; version 2 of the License. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | * GNU General Public License for more details. |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License |
| 16 | * along with this program; if not, write to the Free Software |
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| 18 | */ |
| 19 | |
| 20 | /* Call-backs */ |
Marco Schmidt | a774192 | 2009-06-06 11:33:58 +0000 | [diff] [blame] | 21 | #include <delay.h> |
Stefan Reinauer | 6f57b51 | 2010-07-08 16:41:05 +0000 | [diff] [blame] | 22 | |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 23 | static u16 mctGet_NVbits(u8 index) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 24 | { |
| 25 | u16 val = 0; |
| 26 | |
| 27 | switch (index) { |
| 28 | case NV_PACK_TYPE: |
Zheng Bao | db8b411 | 2009-07-01 07:01:32 +0000 | [diff] [blame] | 29 | #if CONFIG_CPU_SOCKET_TYPE == 0x10 /* Socket F */ |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 30 | val = 0; |
Zheng Bao | eb75f65 | 2010-04-23 17:32:48 +0000 | [diff] [blame] | 31 | #elif CONFIG_CPU_SOCKET_TYPE == 0x11 /* AM3 */ |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 32 | val = 1; |
Zheng Bao | eb75f65 | 2010-04-23 17:32:48 +0000 | [diff] [blame] | 33 | #elif CONFIG_CPU_SOCKET_TYPE == 0x13 /* ASB2 */ |
| 34 | val = 4; |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 35 | //#elif SYSTEM_TYPE == MOBILE |
| 36 | // val = 2; |
| 37 | #endif |
| 38 | break; |
| 39 | case NV_MAX_NODES: |
| 40 | val = MAX_NODES_SUPPORTED; |
| 41 | break; |
| 42 | case NV_MAX_DIMMS: |
Kerry She | 99cfa1e | 2010-08-30 07:31:31 +0000 | [diff] [blame] | 43 | val = MAX_DIMMS_SUPPORTED; |
| 44 | //val = 8; |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 45 | break; |
| 46 | case NV_MAX_MEMCLK: |
| 47 | /* Maximum platform supported memclk */ |
| 48 | //val = 200; /* 200MHz(DDR400) */ |
| 49 | //val = 266; /* 266MHz(DDR533) */ |
| 50 | //val = 333; /* 333MHz(DDR667) */ |
Marc Jones | 471f103 | 2011-06-03 19:59:52 +0000 | [diff] [blame] | 51 | val = MEM_MAX_LOAD_FREQ;; /* 400MHz(DDR800) */ |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 52 | break; |
| 53 | case NV_ECC_CAP: |
| 54 | #if SYSTEM_TYPE == SERVER |
| 55 | val = 1; /* memory bus ECC capable */ |
| 56 | #else |
| 57 | val = 0; /* memory bus ECC not capable */ |
| 58 | #endif |
| 59 | break; |
| 60 | case NV_4RANKType: |
| 61 | /* Quad Rank DIMM slot type */ |
| 62 | val = 0; /* normal */ |
| 63 | //val = 1; /* R4 (registered DIMMs in AMD server configuration) */ |
| 64 | //val = 2; /* S4 (Unbuffered SO-DIMMS) */ |
| 65 | break; |
| 66 | case NV_BYPMAX: |
Patrick Georgi | e166782 | 2012-05-05 15:29:32 +0200 | [diff] [blame] | 67 | #if !CONFIG_GFXUMA |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 68 | val = 4; |
Patrick Georgi | f8f0062 | 2012-05-05 15:50:17 +0200 | [diff] [blame] | 69 | #elif CONFIG_GFXUMA |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 70 | val = 7; |
| 71 | #endif |
| 72 | break; |
| 73 | case NV_RDWRQBYP: |
Patrick Georgi | e166782 | 2012-05-05 15:29:32 +0200 | [diff] [blame] | 74 | #if !CONFIG_GFXUMA |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 75 | val = 2; |
Patrick Georgi | f8f0062 | 2012-05-05 15:50:17 +0200 | [diff] [blame] | 76 | #elif CONFIG_GFXUMA |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 77 | val = 3; |
| 78 | #endif |
| 79 | break; |
| 80 | case NV_MCTUSRTMGMODE: |
| 81 | val = 0; /* Automatic (recommended) */ |
| 82 | //val = 1; /* Limited */ |
| 83 | //val = 2; /* Manual */ |
| 84 | break; |
| 85 | case NV_MemCkVal: |
| 86 | //val = 0; /* 200MHz */ |
| 87 | //val = 1; /* 266MHz */ |
| 88 | val = 2; /* 333MHz */ |
| 89 | break; |
| 90 | case NV_BankIntlv: |
| 91 | /* Bank (chip select) interleaving */ |
| 92 | //val = 0; /* disabled */ |
| 93 | val = 1; /* enabled (recommended) */ |
| 94 | break; |
| 95 | case NV_MemHole: |
| 96 | //val = 0; /* Disabled */ |
| 97 | val = 1; /* Enabled (recommended) */ |
| 98 | break; |
| 99 | case NV_AllMemClks: |
| 100 | val = 0; /* Normal (only to slots that have enabled DIMMs) */ |
| 101 | //val = 1; /* Enable all memclocks */ |
| 102 | break; |
| 103 | case NV_SPDCHK_RESTRT: |
| 104 | val = 0; /* Exit current node initialization if any DIMM has SPD checksum error */ |
| 105 | //val = 1; /* Ignore faulty SPD checksum (DIMM will still be disabled), continue current node intialization */ |
| 106 | break; |
| 107 | case NV_DQSTrainCTL: |
| 108 | //val = 0; /*Skip dqs training */ |
| 109 | val = 1; /* Perform dqs training */ |
| 110 | break; |
| 111 | case NV_NodeIntlv: |
| 112 | val = 0; /* Disabled (recommended) */ |
| 113 | //val = 1; /* Enable */ |
| 114 | break; |
| 115 | case NV_BurstLen32: |
Patrick Georgi | e166782 | 2012-05-05 15:29:32 +0200 | [diff] [blame] | 116 | #if !CONFIG_GFXUMA |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 117 | val = 0; /* 64 byte mode */ |
Patrick Georgi | f8f0062 | 2012-05-05 15:50:17 +0200 | [diff] [blame] | 118 | #elif CONFIG_GFXUMA |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 119 | val = 1; /* 32 byte mode */ |
| 120 | #endif |
| 121 | break; |
| 122 | case NV_CKE_PDEN: |
| 123 | //val = 0; /* Disable */ |
| 124 | val = 1; /* Enable */ |
| 125 | break; |
| 126 | case NV_CKE_CTL: |
| 127 | val = 0; /* per channel control */ |
| 128 | //val = 1; /* per chip select control */ |
| 129 | break; |
| 130 | case NV_CLKHZAltVidC3: |
| 131 | val = 0; /* disable */ |
| 132 | //val = 1; /* enable */ |
| 133 | break; |
| 134 | case NV_BottomIO: |
Patrick Georgi | e166782 | 2012-05-05 15:29:32 +0200 | [diff] [blame] | 135 | #if !CONFIG_GFXUMA |
Marc Jones (marc.jones | e3aeb93 | 2008-04-11 03:20:28 +0000 | [diff] [blame] | 136 | val = 0xE0; /* address bits [31:24] */ |
Patrick Georgi | f8f0062 | 2012-05-05 15:50:17 +0200 | [diff] [blame] | 137 | #elif CONFIG_GFXUMA |
Scott Duplichan | f3cce2f | 2010-11-13 19:07:59 +0000 | [diff] [blame] | 138 | val = 0xC0; /* address bits [31:24] */ |
| 139 | #endif |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 140 | break; |
| 141 | case NV_BottomUMA: |
Patrick Georgi | e166782 | 2012-05-05 15:29:32 +0200 | [diff] [blame] | 142 | #if !CONFIG_GFXUMA |
Marc Jones (marc.jones | e3aeb93 | 2008-04-11 03:20:28 +0000 | [diff] [blame] | 143 | val = 0xE0; /* address bits [31:24] */ |
Patrick Georgi | f8f0062 | 2012-05-05 15:50:17 +0200 | [diff] [blame] | 144 | #elif CONFIG_GFXUMA |
Scott Duplichan | f3cce2f | 2010-11-13 19:07:59 +0000 | [diff] [blame] | 145 | val = 0xC0; /* address bits [31:24] */ |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 146 | #endif |
| 147 | break; |
| 148 | case NV_ECC: |
| 149 | #if (SYSTEM_TYPE == SERVER) |
| 150 | val = 1; /* Enable */ |
| 151 | #else |
| 152 | val = 0; /* Disable */ |
| 153 | #endif |
| 154 | break; |
| 155 | case NV_NBECC: |
| 156 | #if (SYSTEM_TYPE == SERVER) |
| 157 | val = 1; /* Enable */ |
| 158 | #else |
| 159 | val = 0; /* Disable */ |
| 160 | #endif |
| 161 | break; |
| 162 | case NV_ChipKill: |
| 163 | #if (SYSTEM_TYPE == SERVER) |
| 164 | val = 1; /* Enable */ |
| 165 | #else |
| 166 | val = 0; /* Disable */ |
| 167 | #endif |
| 168 | break; |
| 169 | case NV_ECCRedir: |
| 170 | val = 0; /* Disable */ |
| 171 | //val = 1; /* Enable */ |
| 172 | break; |
| 173 | case NV_DramBKScrub: |
| 174 | val = 0x00; /* Disabled */ |
| 175 | //val = 0x01; /* 40ns */ |
| 176 | //val = 0x02; /* 80ns */ |
| 177 | //val = 0x03; /* 160ns */ |
| 178 | //val = 0x04; /* 320ns */ |
| 179 | //val = 0x05; /* 640ns */ |
| 180 | //val = 0x06; /* 1.28us */ |
| 181 | //val = 0x07; /* 2.56us */ |
| 182 | //val = 0x08; /* 5.12us */ |
| 183 | //val = 0x09; /* 10.2us */ |
| 184 | //val = 0x0a; /* 20.5us */ |
| 185 | //val = 0x0b; /* 41us */ |
| 186 | //val = 0x0c; /* 81.9us */ |
| 187 | //val = 0x0d; /* 163.8us */ |
| 188 | //val = 0x0e; /* 327.7us */ |
| 189 | //val = 0x0f; /* 655.4us */ |
| 190 | //val = 0x10; /* 1.31ms */ |
| 191 | //val = 0x11; /* 2.62ms */ |
| 192 | //val = 0x12; /* 5.24ms */ |
| 193 | //val = 0x13; /* 10.49ms */ |
| 194 | //val = 0x14; /* 20.97sms */ |
| 195 | //val = 0x15; /* 42ms */ |
| 196 | //val = 0x16; /* 84ms */ |
| 197 | break; |
| 198 | case NV_L2BKScrub: |
| 199 | val = 0; /* Disabled - See L2Scrub in BKDG */ |
| 200 | break; |
| 201 | case NV_DCBKScrub: |
| 202 | val = 0; /* Disabled - See DcacheScrub in BKDG */ |
| 203 | break; |
| 204 | case NV_CS_SpareCTL: |
| 205 | val = 0; /* Disabled */ |
| 206 | //val = 1; /* Enabled */ |
Stefan Reinauer | ce00f1d | 2008-12-05 22:38:18 +0000 | [diff] [blame] | 207 | break; |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 208 | case NV_SyncOnUnEccEn: |
| 209 | val = 0; /* Disabled */ |
| 210 | //val = 1; /* Enabled */ |
Stefan Reinauer | ce00f1d | 2008-12-05 22:38:18 +0000 | [diff] [blame] | 211 | break; |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 212 | case NV_Unganged: |
| 213 | /* channel interleave is better performance than ganged mode at this time */ |
| 214 | val = 1; /* Enabled */ |
| 215 | //val = 0; /* Disabled */ |
Stefan Reinauer | ce00f1d | 2008-12-05 22:38:18 +0000 | [diff] [blame] | 216 | break; |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 217 | case NV_ChannelIntlv: |
Marc Jones (marc.jones | e3aeb93 | 2008-04-11 03:20:28 +0000 | [diff] [blame] | 218 | val = 5; /* Not currently checked in mctchi_d.c */ |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 219 | /* Bit 0 = 0 - Disable |
| 220 | * 1 - Enable |
| 221 | * Bits[2:1] = 00b - Address bits 6 |
| 222 | * 01b - Address bits 1 |
| 223 | * 10b - Hash*, XOR of address bits [20:16, 6] |
| 224 | * 11b - Hash*, XOR of address bits [20:16, 9] |
| 225 | */ |
Stefan Reinauer | ce00f1d | 2008-12-05 22:38:18 +0000 | [diff] [blame] | 226 | break; |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 227 | } |
| 228 | |
| 229 | return val; |
| 230 | } |
| 231 | |
| 232 | |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 233 | static void mctHookAfterDIMMpre(void) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 234 | { |
| 235 | } |
| 236 | |
| 237 | |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 238 | static void mctGet_MaxLoadFreq(struct DCTStatStruc *pDCTstat) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 239 | { |
Marc Jones | 471f103 | 2011-06-03 19:59:52 +0000 | [diff] [blame] | 240 | pDCTstat->PresetmaxFreq = MEM_MAX_LOAD_FREQ; |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 241 | } |
| 242 | |
Stefan Reinauer | d653211 | 2010-04-16 00:31:44 +0000 | [diff] [blame] | 243 | #ifdef UNUSED_CODE |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 244 | static void mctAdjustAutoCycTmg(void) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 245 | { |
| 246 | } |
Stefan Reinauer | d653211 | 2010-04-16 00:31:44 +0000 | [diff] [blame] | 247 | #endif |
| 248 | |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 249 | |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 250 | static void mctAdjustAutoCycTmg_D(void) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 251 | { |
| 252 | } |
| 253 | |
| 254 | |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 255 | static void mctHookAfterAutoCycTmg(void) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 256 | { |
| 257 | } |
| 258 | |
| 259 | |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 260 | static void mctGetCS_ExcludeMap(void) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 261 | { |
| 262 | } |
| 263 | |
| 264 | |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 265 | static void mctHookAfterAutoCfg(void) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 266 | { |
| 267 | } |
| 268 | |
| 269 | |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 270 | static void mctHookAfterPSCfg(void) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 271 | { |
| 272 | } |
| 273 | |
| 274 | |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 275 | static void mctHookAfterHTMap(void) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 276 | { |
| 277 | } |
| 278 | |
| 279 | |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 280 | static void mctHookAfterCPU(void) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 281 | { |
| 282 | } |
| 283 | |
| 284 | |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 285 | static void mctSaveDQSSigTmg_D(void) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 286 | { |
| 287 | } |
| 288 | |
| 289 | |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 290 | static void mctGetDQSSigTmg_D(void) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 291 | { |
| 292 | } |
| 293 | |
| 294 | |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 295 | static void mctHookBeforeECC(void) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 296 | { |
| 297 | } |
| 298 | |
| 299 | |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 300 | static void mctHookAfterECC(void) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 301 | { |
| 302 | } |
| 303 | |
Stefan Reinauer | d653211 | 2010-04-16 00:31:44 +0000 | [diff] [blame] | 304 | #ifdef UNUSED_CODE |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 305 | static void mctInitMemGPIOs_A(void) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 306 | { |
| 307 | } |
Stefan Reinauer | d653211 | 2010-04-16 00:31:44 +0000 | [diff] [blame] | 308 | #endif |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 309 | |
| 310 | |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 311 | static void mctInitMemGPIOs_A_D(void) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 312 | { |
| 313 | } |
| 314 | |
| 315 | |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 316 | static void mctNodeIDDebugPort_D(void) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 317 | { |
| 318 | } |
| 319 | |
| 320 | |
Stefan Reinauer | d653211 | 2010-04-16 00:31:44 +0000 | [diff] [blame] | 321 | #ifdef UNUSED_CODE |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 322 | static void mctWarmReset(void) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 323 | { |
| 324 | } |
Stefan Reinauer | d653211 | 2010-04-16 00:31:44 +0000 | [diff] [blame] | 325 | #endif |
| 326 | |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 327 | |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 328 | static void mctWarmReset_D(void) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 329 | { |
| 330 | } |
| 331 | |
| 332 | |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 333 | static void mctHookBeforeDramInit(void) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 334 | { |
| 335 | } |
| 336 | |
| 337 | |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 338 | static void mctHookAfterDramInit(void) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 339 | { |
| 340 | } |
| 341 | |
Stefan Reinauer | 817d754 | 2010-07-08 00:37:23 +0000 | [diff] [blame] | 342 | #if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005 /* AMD_FAM10_DDR3 */ |
Xavi Drudis Ferran | c313210 | 2011-02-28 03:49:28 +0000 | [diff] [blame] | 343 | static void coreDelay(u32 microseconds) |
| 344 | { |
| 345 | msr_t now; |
| 346 | msr_t end; |
| 347 | u32 cycles; |
| 348 | |
| 349 | /* delay ~40us |
| 350 | This seems like a hack to me... |
| 351 | It would be nice to have a central delay function. */ |
| 352 | |
| 353 | cycles = (microseconds * 100) << 3; /* x8 (number of 1.25ns ticks) */ |
| 354 | |
| 355 | if (!(rdmsr(HWCR).lo & TSC_FREQ_SEL_MASK)) { |
| 356 | msr_t pstate_msr = rdmsr(CUR_PSTATE_MSR); |
| 357 | if (!(rdmsr(0xC0010064+pstate_msr.lo).lo & NB_DID_M_ON)) { |
| 358 | cycles = cycles <<1; // half freq, double cycles |
| 359 | } |
| 360 | } // else should we keep p0 freq at the time of setting TSC_FREQ_SEL_MASK somewhere and check it here ? |
| 361 | |
| 362 | now = rdmsr(TSC_MSR); |
| 363 | // avoid overflow when called near 2^32 ticks ~ 5.3 s boundaries |
| 364 | if (0xffffffff - cycles >= now.lo ) { |
| 365 | end.hi = now.hi; |
| 366 | end.lo = now.lo + cycles; |
| 367 | } else { |
| 368 | end.hi = now.hi +1; // |
| 369 | end.lo = cycles - (1+(0xffffffff - now.lo)); |
| 370 | } |
| 371 | do { |
| 372 | now = rdmsr(TSC_MSR); |
| 373 | } while ((now.hi < end.hi) || ((now.hi == end.hi) && (now.lo < end.lo))); |
| 374 | } |
| 375 | |
Marco Schmidt | a774192 | 2009-06-06 11:33:58 +0000 | [diff] [blame] | 376 | /* Erratum 350 */ |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 377 | static void vErrata350(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 378 | { |
Marco Schmidt | a774192 | 2009-06-06 11:33:58 +0000 | [diff] [blame] | 379 | u8 u8Channel; |
| 380 | u8 u8Receiver; |
| 381 | u32 u32Addr; |
| 382 | u8 u8Valid; |
| 383 | u32 u32DctDev; |
| 384 | |
| 385 | // 1. dummy read for each installed DIMM */ |
| 386 | for (u8Channel = 0; u8Channel < 2; u8Channel++) { |
| 387 | // This will be 0 for vaild DIMMS, eles 8 |
| 388 | u8Receiver = mct_InitReceiver_D(pDCTstat, u8Channel); |
| 389 | |
| 390 | for (; u8Receiver < 8; u8Receiver += 2) { |
| 391 | u32Addr = mct_GetRcvrSysAddr_D(pMCTstat, pDCTstat, u8Channel, u8Receiver, &u8Valid); |
| 392 | |
| 393 | if(!u8Valid) { /* Address not supported on current CS */ |
Zheng Bao | 69a031c | 2009-08-19 07:08:10 +0000 | [diff] [blame] | 394 | print_t("vErrata350: Address not supported on current CS\n"); |
Marco Schmidt | a774192 | 2009-06-06 11:33:58 +0000 | [diff] [blame] | 395 | continue; |
| 396 | } |
Zheng Bao | 69a031c | 2009-08-19 07:08:10 +0000 | [diff] [blame] | 397 | print_t("vErrata350: dummy read \n"); |
Marco Schmidt | a774192 | 2009-06-06 11:33:58 +0000 | [diff] [blame] | 398 | read32_fs(u32Addr); |
| 399 | } |
| 400 | } |
| 401 | |
Zheng Bao | 69a031c | 2009-08-19 07:08:10 +0000 | [diff] [blame] | 402 | print_t("vErrata350: step 2a\n"); |
Marco Schmidt | a774192 | 2009-06-06 11:33:58 +0000 | [diff] [blame] | 403 | |
| 404 | /* 2. Write 0000_8000h to register F2x[1, 0]9C_xD080F0C. */ |
| 405 | u32DctDev = pDCTstat->dev_dct; |
Zheng Bao | 69a031c | 2009-08-19 07:08:10 +0000 | [diff] [blame] | 406 | Set_NB32_index_wait(u32DctDev, 0x098, 0xD080F0C, 0x00008000); |
Marco Schmidt | a774192 | 2009-06-06 11:33:58 +0000 | [diff] [blame] | 407 | /* ^--- value |
Zheng Bao | 69a031c | 2009-08-19 07:08:10 +0000 | [diff] [blame] | 408 | ^---F2x[1, 0]9C_x0D080F0C, No description in BKDG. |
Marco Schmidt | a774192 | 2009-06-06 11:33:58 +0000 | [diff] [blame] | 409 | ^----F2x[1, 0]98 DRAM Controller Additional Data Offset Register */ |
| 410 | |
| 411 | if(!pDCTstat->GangedMode) { |
Zheng Bao | 69a031c | 2009-08-19 07:08:10 +0000 | [diff] [blame] | 412 | print_t("vErrata350: step 2b\n"); |
| 413 | Set_NB32_index_wait(u32DctDev, 0x198, 0xD080F0C, 0x00008000); |
Marco Schmidt | a774192 | 2009-06-06 11:33:58 +0000 | [diff] [blame] | 414 | /* ^--- value |
Zheng Bao | 69a031c | 2009-08-19 07:08:10 +0000 | [diff] [blame] | 415 | ^---F2x[1, 0]9C_x0D080F0C, No description in BKDG |
Marco Schmidt | a774192 | 2009-06-06 11:33:58 +0000 | [diff] [blame] | 416 | ^----F2x[1, 0]98 DRAM Controller Additional Data Offset Register */ |
| 417 | } |
| 418 | |
Zheng Bao | 69a031c | 2009-08-19 07:08:10 +0000 | [diff] [blame] | 419 | print_t("vErrata350: step 3\n"); |
Marco Schmidt | a774192 | 2009-06-06 11:33:58 +0000 | [diff] [blame] | 420 | /* 3. Wait at least 300 nanoseconds. */ |
Xavi Drudis Ferran | c313210 | 2011-02-28 03:49:28 +0000 | [diff] [blame] | 421 | coreDelay(1); |
Marco Schmidt | a774192 | 2009-06-06 11:33:58 +0000 | [diff] [blame] | 422 | |
Zheng Bao | 69a031c | 2009-08-19 07:08:10 +0000 | [diff] [blame] | 423 | print_t("vErrata350: step 4\n"); |
Marco Schmidt | a774192 | 2009-06-06 11:33:58 +0000 | [diff] [blame] | 424 | /* 4. Write 0000_0000h to register F2x[1, 0]9C_xD080F0C. */ |
Zheng Bao | 69a031c | 2009-08-19 07:08:10 +0000 | [diff] [blame] | 425 | Set_NB32_index_wait(u32DctDev, 0x098, 0xD080F0C, 0x00000000); |
Marco Schmidt | a774192 | 2009-06-06 11:33:58 +0000 | [diff] [blame] | 426 | |
| 427 | if(!pDCTstat->GangedMode) { |
Zheng Bao | 69a031c | 2009-08-19 07:08:10 +0000 | [diff] [blame] | 428 | print_t("vErrata350: step 4b\n"); |
| 429 | Set_NB32_index_wait(u32DctDev, 0x198, 0xD080F0C, 0x00000000); |
Marco Schmidt | a774192 | 2009-06-06 11:33:58 +0000 | [diff] [blame] | 430 | } |
| 431 | |
Zheng Bao | 69a031c | 2009-08-19 07:08:10 +0000 | [diff] [blame] | 432 | print_t("vErrata350: step 5\n"); |
Marco Schmidt | a774192 | 2009-06-06 11:33:58 +0000 | [diff] [blame] | 433 | /* 5. Wait at least 2 microseconds. */ |
Xavi Drudis Ferran | c313210 | 2011-02-28 03:49:28 +0000 | [diff] [blame] | 434 | coreDelay(2); |
Marco Schmidt | a774192 | 2009-06-06 11:33:58 +0000 | [diff] [blame] | 435 | |
| 436 | } |
Xavi Drudis Ferran | 213ab94 | 2010-08-22 19:51:34 +0000 | [diff] [blame] | 437 | |
| 438 | static void vErratum372(struct DCTStatStruc *pDCTstat) |
| 439 | { |
| 440 | msr_t msr = rdmsr(NB_CFG_MSR); |
Xavi Drudis Ferran | 19245c9 | 2011-02-28 03:02:40 +0000 | [diff] [blame] | 441 | |
Xavi Drudis Ferran | 213ab94 | 2010-08-22 19:51:34 +0000 | [diff] [blame] | 442 | int nbPstate1supported = ! (msr.hi && (1 << (NB_GfxNbPstateDis -32))) ; |
| 443 | |
Xavi Drudis Ferran | 19245c9 | 2011-02-28 03:02:40 +0000 | [diff] [blame] | 444 | // is this the right way to check for NB pstate 1 or DDR3-1333 ? |
Xavi Drudis Ferran | 213ab94 | 2010-08-22 19:51:34 +0000 | [diff] [blame] | 445 | if (((pDCTstat->PresetmaxFreq==1333)||(nbPstate1supported)) |
| 446 | &&(!pDCTstat->GangedMode)) { |
| 447 | /* DisableCf8ExtCfg */ |
| 448 | msr.hi &= ~(3 << (51 - 32)); |
| 449 | wrmsr(NB_CFG_MSR, msr); |
| 450 | } |
| 451 | } |
Xavi Drudis Ferran | 4793ef1 | 2010-08-22 19:54:26 +0000 | [diff] [blame] | 452 | |
| 453 | static void vErratum414(struct DCTStatStruc *pDCTstat) |
| 454 | { |
| 455 | int dct=0; |
Xavi Drudis Ferran | 19245c9 | 2011-02-28 03:02:40 +0000 | [diff] [blame] | 456 | for(; dct < 2 ; dct++) |
Xavi Drudis Ferran | 4793ef1 | 2010-08-22 19:54:26 +0000 | [diff] [blame] | 457 | { |
Xavi Drudis Ferran | 19245c9 | 2011-02-28 03:02:40 +0000 | [diff] [blame] | 458 | int dRAMConfigHi = Get_NB32(pDCTstat->dev_dct,0x94 + (0x100 * dct)); |
Xavi Drudis Ferran | 4793ef1 | 2010-08-22 19:54:26 +0000 | [diff] [blame] | 459 | int powerDown = dRAMConfigHi && (1 << PowerDownEn ) ; |
| 460 | int ddr3 = dRAMConfigHi && (1 << Ddr3Mode ) ; |
| 461 | int dRAMMRS = Get_NB32(pDCTstat->dev_dct,0x84 + (0x100 * dct)); |
| 462 | int pchgPDModeSel = dRAMMRS && (1 << PchgPDModeSel ) ; |
Xavi Drudis Ferran | 19245c9 | 2011-02-28 03:02:40 +0000 | [diff] [blame] | 463 | if (powerDown && ddr3 && pchgPDModeSel ) |
Xavi Drudis Ferran | 4793ef1 | 2010-08-22 19:54:26 +0000 | [diff] [blame] | 464 | { |
| 465 | Set_NB32(pDCTstat->dev_dct,0x84 + (0x100 * dct), dRAMMRS & ~(1 << PchgPDModeSel) ); |
| 466 | } |
| 467 | } |
| 468 | } |
Stefan Reinauer | 817d754 | 2010-07-08 00:37:23 +0000 | [diff] [blame] | 469 | #endif |
Marco Schmidt | a774192 | 2009-06-06 11:33:58 +0000 | [diff] [blame] | 470 | |
| 471 | |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 472 | static void mctHookBeforeAnyTraining(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA) |
Marco Schmidt | a774192 | 2009-06-06 11:33:58 +0000 | [diff] [blame] | 473 | { |
Zheng Bao | eb75f65 | 2010-04-23 17:32:48 +0000 | [diff] [blame] | 474 | #if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005 /* AMD_FAM10_DDR3 */ |
Xavi Drudis Ferran | 213ab94 | 2010-08-22 19:51:34 +0000 | [diff] [blame] | 475 | /* FIXME : as of 25.6.2010 errata 350 and 372 should apply to ((RB|BL|DA)-C[23])|(HY-D[01])|(PH-E0) but I don't find constants for all of them */ |
| 476 | if (pDCTstatA->LogicalCPUID & AMD_DRBH_Cx) { |
Marco Schmidt | a774192 | 2009-06-06 11:33:58 +0000 | [diff] [blame] | 477 | vErrata350(pMCTstat, pDCTstatA); |
Xavi Drudis Ferran | 213ab94 | 2010-08-22 19:51:34 +0000 | [diff] [blame] | 478 | vErratum372(pDCTstatA); |
Xavi Drudis Ferran | 4793ef1 | 2010-08-22 19:54:26 +0000 | [diff] [blame] | 479 | vErratum414(pDCTstatA); |
Marco Schmidt | a774192 | 2009-06-06 11:33:58 +0000 | [diff] [blame] | 480 | } |
Zheng Bao | eb75f65 | 2010-04-23 17:32:48 +0000 | [diff] [blame] | 481 | #endif |
| 482 | } |
| 483 | |
Stefan Reinauer | 6f57b51 | 2010-07-08 16:41:05 +0000 | [diff] [blame] | 484 | #if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005 /* AMD_FAM10_DDR3 */ |
Zheng Bao | eb75f65 | 2010-04-23 17:32:48 +0000 | [diff] [blame] | 485 | static u32 mct_AdjustSPDTimings(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA, u32 val) |
| 486 | { |
| 487 | if (pDCTstatA->LogicalCPUID & AMD_DR_Bx) { |
| 488 | if (pDCTstatA->Status & (1 << SB_Registered)) { |
| 489 | val ++; |
| 490 | } |
| 491 | } |
| 492 | return val; |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 493 | } |
Stefan Reinauer | 6f57b51 | 2010-07-08 16:41:05 +0000 | [diff] [blame] | 494 | #endif |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 495 | |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 496 | static void mctHookAfterAnyTraining(void) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 497 | { |
| 498 | } |
| 499 | |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 500 | static u32 mctGetLogicalCPUID_D(u8 node) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 501 | { |
| 502 | return mctGetLogicalCPUID(node); |
| 503 | } |
Marc Jones (marc.jones | e3aeb93 | 2008-04-11 03:20:28 +0000 | [diff] [blame] | 504 | |
Stefan Reinauer | 6f57b51 | 2010-07-08 16:41:05 +0000 | [diff] [blame] | 505 | #if (CONFIG_DIMM_SUPPORT & 0x000F)!=0x0005 /* not needed for AMD_FAM10_DDR3 */ |
Myles Watson | 075fbe8 | 2010-04-15 05:19:29 +0000 | [diff] [blame] | 506 | static u8 mctSetNodeBoundary_D(void) |
Marc Jones (marc.jones | e3aeb93 | 2008-04-11 03:20:28 +0000 | [diff] [blame] | 507 | { |
| 508 | return 0; |
| 509 | } |
Stefan Reinauer | 6f57b51 | 2010-07-08 16:41:05 +0000 | [diff] [blame] | 510 | #endif |