blob: a8bb5e7d1c2b20aad805688cba3ee1e30b938c18 [file] [log] [blame]
Stefan Reinauer278534d2008-10-29 04:51:07 +00001/*
2 * This file is part of the coreboot project.
3 *
Stefan Reinauer71a3d962009-07-21 21:44:24 +00004 * Copyright (C) 2007-2009 coresystems GmbH
Stefan Reinauer278534d2008-10-29 04:51:07 +00005 *
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.
Stefan Reinauer278534d2008-10-29 04:51:07 +000014 */
15
Patrick Georgid0835952010-10-05 09:07:10 +000016#include <console/console.h>
Stefan Reinauer278534d2008-10-29 04:51:07 +000017#include <cpu/x86/mtrr.h>
18#include <cpu/x86/cache.h>
Arthur Heymans885c2892016-10-03 17:16:48 +020019#include <device/pci_def.h>
20#include <device/device.h>
Julius Werner7a8a4ab2015-05-22 16:26:40 -070021#include <lib.h>
Edwin Beasanteb50c7d2010-07-06 21:05:04 +000022#include <pc80/mc146818rtc.h>
Stefan Reinauer278534d2008-10-29 04:51:07 +000023#include <spd.h>
Patrick Georgid0835952010-10-05 09:07:10 +000024#include <string.h>
Patrick Georgi546953c2014-11-29 10:38:17 +010025#include <halt.h>
Alexandru Gagniucaf4bd592014-01-12 15:42:58 -060026#include <lib.h>
Stefan Reinauer278534d2008-10-29 04:51:07 +000027#include "raminit.h"
28#include "i945.h"
Arthur Heymans885c2892016-10-03 17:16:48 +020029#include "chip.h"
Rudolf Marekc4369532010-12-13 19:59:13 +000030#include <cbmem.h>
31
Stefan Reinauer278534d2008-10-29 04:51:07 +000032/* Debugging macros. */
Uwe Hermann01ce6012010-03-05 10:03:50 +000033#if CONFIG_DEBUG_RAM_SETUP
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000034#define PRINTK_DEBUG(x...) printk(BIOS_DEBUG, x)
Stefan Reinauer278534d2008-10-29 04:51:07 +000035#else
36#define PRINTK_DEBUG(x...)
37#endif
38
Stefan Reinauer278534d2008-10-29 04:51:07 +000039#define RAM_INITIALIZATION_COMPLETE (1 << 19)
40
41#define RAM_COMMAND_SELF_REFRESH (0x0 << 16)
42#define RAM_COMMAND_NOP (0x1 << 16)
43#define RAM_COMMAND_PRECHARGE (0x2 << 16)
44#define RAM_COMMAND_MRS (0x3 << 16)
45#define RAM_COMMAND_EMRS (0x4 << 16)
46#define RAM_COMMAND_CBR (0x6 << 16)
47#define RAM_COMMAND_NORMAL (0x7 << 16)
48
49#define RAM_EMRS_1 (0x0 << 21)
50#define RAM_EMRS_2 (0x1 << 21)
51#define RAM_EMRS_3 (0x2 << 21)
52
Arthur Heymans885c2892016-10-03 17:16:48 +020053#define DEFAULT_PCI_MMIO_SIZE 768
Sven Schnelle541269b2011-02-21 09:39:17 +000054static int get_dimm_spd_address(struct sys_info *sysinfo, int device)
55{
56 if (sysinfo->spd_addresses)
57 return sysinfo->spd_addresses[device];
58 else
59 return DIMM0 + device;
60
61}
62
Patrick Georgid0835952010-10-05 09:07:10 +000063static inline int spd_read_byte(unsigned device, unsigned address)
64{
65 return smbus_read_byte(device, address);
66}
67
Stefan Reinauerbc8613e2010-08-25 18:35:42 +000068static __attribute__((noinline)) void do_ram_command(u32 command)
Stefan Reinauer278534d2008-10-29 04:51:07 +000069{
70 u32 reg32;
71
72 reg32 = MCHBAR32(DCC);
73 reg32 &= ~( (3<<21) | (1<<20) | (1<<19) | (7 << 16) );
74 reg32 |= command;
75
76 /* Also set Init Complete */
77 if (command == RAM_COMMAND_NORMAL)
78 reg32 |= RAM_INITIALIZATION_COMPLETE;
79
80 PRINTK_DEBUG(" Sending RAM command 0x%08x", reg32);
81
82 MCHBAR32(DCC) = reg32; /* This is the actual magic */
83
Stefan Reinauer779b3e32008-11-10 15:43:37 +000084 PRINTK_DEBUG("...done\n");
Stefan Reinauerd058ad12010-08-26 12:43:58 +000085
86 udelay(1);
Stefan Reinauer278534d2008-10-29 04:51:07 +000087}
88
Stefan Reinauer278534d2008-10-29 04:51:07 +000089static void ram_read32(u32 offset)
90{
Elyes HAOUAS15279a92016-07-28 21:05:26 +020091 PRINTK_DEBUG(" RAM read: %08x\n", offset);
Stefan Reinauer278534d2008-10-29 04:51:07 +000092
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080093 read32((void *)offset);
Stefan Reinauer278534d2008-10-29 04:51:07 +000094}
95
Uwe Hermann01ce6012010-03-05 10:03:50 +000096#if CONFIG_DEBUG_RAM_SETUP
Stefan Reinauer3c0bfaf2010-12-27 11:34:57 +000097void sdram_dump_mchbar_registers(void)
Stefan Reinauer278534d2008-10-29 04:51:07 +000098{
99 int i;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000100 printk(BIOS_DEBUG, "Dumping MCHBAR Registers\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000101
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200102 for (i = 0; i < 0xfff; i+=4) {
Stefan Reinauer278534d2008-10-29 04:51:07 +0000103 if (MCHBAR32(i) == 0)
104 continue;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000105 printk(BIOS_DEBUG, "0x%04x: 0x%08x\n", i, MCHBAR32(i));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000106 }
107}
108#endif
109
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000110static int memclk(void)
111{
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200112 int offset = IS_ENABLED(CONFIG_NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
113
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000114 switch (((MCHBAR32(CLKCFG) >> 4) & 7) - offset) {
115 case 1: return 400;
116 case 2: return 533;
117 case 3: return 667;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000118 default: printk(BIOS_DEBUG, "memclk: unknown register value %x\n", ((MCHBAR32(CLKCFG) >> 4) & 7) - offset);
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000119 }
120 return -1;
121}
122
Peter Stuge76d91432010-10-01 10:02:33 +0000123static u16 fsbclk(void)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000124{
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200125 if (IS_ENABLED(CONFIG_NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
126 switch (MCHBAR32(CLKCFG) & 7) {
127 case 0: return 400;
128 case 1: return 533;
129 case 3: return 667;
130 default: printk(BIOS_DEBUG, "fsbclk: unknown register value %x\n", MCHBAR32(CLKCFG) & 7);
131 }
132 return 0xffff;
133 } else if (IS_ENABLED(CONFIG_NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
134 switch (MCHBAR32(CLKCFG) & 7) {
135 case 0: return 1066;
136 case 1: return 533;
137 case 2: return 800;
138 default: printk(BIOS_DEBUG, "fsbclk: unknown register value %x\n", MCHBAR32(CLKCFG) & 7);
139 }
140 return 0xffff;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000141 }
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000142}
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000143
Stefan Reinauer278534d2008-10-29 04:51:07 +0000144static int sdram_capabilities_max_supported_memory_frequency(void)
145{
146 u32 reg32;
147
Patrick Georgi77d66832010-10-01 08:02:45 +0000148#if CONFIG_MAXIMUM_SUPPORTED_FREQUENCY
149 return CONFIG_MAXIMUM_SUPPORTED_FREQUENCY;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000150#endif
151
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000152 reg32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000153 reg32 &= (7 << 0);
154
155 switch (reg32) {
156 case 4: return 400;
157 case 3: return 533;
158 case 2: return 667;
159 }
160 /* Newer revisions of this chipset rather support faster memory clocks,
161 * so if it's a reserved value, return the fastest memory clock that we
162 * know of and can handle
163 */
164 return 667;
165}
166
167/**
168 * @brief determine whether chipset is capable of dual channel interleaved mode
169 *
170 * @return 1 if interleaving is supported, 0 otherwise
171 */
172static int sdram_capabilities_interleave(void)
173{
174 u32 reg32;
175
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000176 reg32 = pci_read_config32(PCI_DEV(0, 0x00,0), 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000177 reg32 >>= 25;
178 reg32 &= 1;
179
180 return (!reg32);
181}
182
183/**
184 * @brief determine whether chipset is capable of two memory channels
185 *
186 * @return 1 if dual channel operation is supported, 0 otherwise
187 */
188static int sdram_capabilities_dual_channel(void)
189{
190 u32 reg32;
191
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000192 reg32 = pci_read_config32(PCI_DEV(0, 0x00,0), 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000193 reg32 >>= 24;
194 reg32 &= 1;
195
196 return (!reg32);
197}
198
199static int sdram_capabilities_enhanced_addressing_xor(void)
200{
201 u8 reg8;
202
203 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
204 reg8 &= (1 << 7);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000205
Stefan Reinauer278534d2008-10-29 04:51:07 +0000206 return (!reg8);
207}
208
Stefan Reinauer14e22772010-04-27 06:56:47 +0000209// TODO check if we ever need this function
Stefan Reinauer53b0ea42010-03-22 11:50:52 +0000210#if 0
Stefan Reinauer278534d2008-10-29 04:51:07 +0000211static int sdram_capabilities_MEM4G_disable(void)
212{
213 u8 reg8;
214
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000215 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000216 reg8 &= (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000217
Stefan Reinauer278534d2008-10-29 04:51:07 +0000218 return (reg8 != 0);
219}
Stefan Reinauer53b0ea42010-03-22 11:50:52 +0000220#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +0000221
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000222#define GFX_FREQUENCY_CAP_166MHZ 0x04
223#define GFX_FREQUENCY_CAP_200MHZ 0x03
224#define GFX_FREQUENCY_CAP_250MHZ 0x02
225#define GFX_FREQUENCY_CAP_ALL 0x00
226
227static int sdram_capabilities_core_frequencies(void)
228{
229 u8 reg8;
230
231 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
232 reg8 &= (1 << 3) | (1 << 2) | (1 << 1);
233 reg8 >>= 1;
234
235 return (reg8);
236}
237
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000238static void sdram_detect_errors(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000239{
240 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000241 u8 do_reset = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000242
243 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000244
Stefan Reinauer278534d2008-10-29 04:51:07 +0000245 if (reg8 & ((1<<7)|(1<<2))) {
246 if (reg8 & (1<<2)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000247 printk(BIOS_DEBUG, "SLP S4# Assertion Width Violation.\n");
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000248 /* Write back clears bit 2 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000249 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa2, reg8);
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000250 do_reset = 1;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000251
Stefan Reinauer278534d2008-10-29 04:51:07 +0000252 }
253
254 if (reg8 & (1<<7)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000255 printk(BIOS_DEBUG, "DRAM initialization was interrupted.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000256 reg8 &= ~(1<<7);
257 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa2, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000258 do_reset = 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000259 }
260
261 /* Set SLP_S3# Assertion Stretch Enable */
262 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4); /* GEN_PMCON_3 */
263 reg8 |= (1 << 3);
264 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8);
265
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000266 if (do_reset) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000267 printk(BIOS_DEBUG, "Reset required.\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000268 outb(0x00, 0xcf9);
269 outb(0x0e, 0xcf9);
Patrick Georgi546953c2014-11-29 10:38:17 +0100270 halt(); /* Wait for reset! */
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000271 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000272 }
273
274 /* Set DRAM initialization bit in ICH7 */
275 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa2);
276 reg8 |= (1<<7);
277 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa2, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000278
Peter Stuge751508a2012-01-27 22:17:09 +0100279 /* clear self refresh status if check is disabled or not a resume */
Patrick Georgi86a11102013-03-15 14:11:37 +0100280 if (!CONFIG_CHECK_SLFRCS_ON_RESUME || sysinfo->boot_path != BOOT_PATH_RESUME) {
281 MCHBAR8(SLFRCS) |= 3;
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000282 } else {
283 /* Validate self refresh config */
284 if (((sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED) ||
285 (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)) &&
Patrick Georgi86a11102013-03-15 14:11:37 +0100286 !(MCHBAR8(SLFRCS) & (1<<0))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000287 do_reset = 1;
288 }
289 if (((sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED) ||
290 (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) &&
Patrick Georgi86a11102013-03-15 14:11:37 +0100291 !(MCHBAR8(SLFRCS) & (1<<1))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000292 do_reset = 1;
293 }
294 }
295
296 if (do_reset) {
297 printk(BIOS_DEBUG, "Reset required.\n");
298 outb(0x00, 0xcf9);
299 outb(0x0e, 0xcf9);
Patrick Georgi546953c2014-11-29 10:38:17 +0100300 halt(); /* Wait for reset! */
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000301 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000302}
Stefan Reinauer278534d2008-10-29 04:51:07 +0000303
304/**
305 * @brief Get generic DIMM parameters.
306 * @param sysinfo Central memory controller information structure
307 *
308 * This function gathers several pieces of information for each system DIMM:
309 * o DIMM width (x8 / x16)
310 * o DIMM sides (single sided / dual sided)
311 *
312 * Also, some non-supported scenarios are detected.
313 */
314
315static void sdram_get_dram_configuration(struct sys_info *sysinfo)
316{
317 u32 dimm_mask = 0;
318 int i;
319
320 /**
321 * i945 supports two DIMMs, in two configurations:
322 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000323 * - single channel with two DIMMs
324 * - dual channel with one DIMM per channel
Stefan Reinauer278534d2008-10-29 04:51:07 +0000325 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000326 * In practice dual channel mainboards have their SPD at 0x50/0x52
327 * whereas single channel configurations have their SPD at 0x50/0x51.
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000328 *
Stefan Reinauer278534d2008-10-29 04:51:07 +0000329 * The capability register knows a lot about the channel configuration
Uwe Hermannd773fd32010-11-20 20:23:08 +0000330 * but for now we stick with the information we gather via SPD.
Stefan Reinauer278534d2008-10-29 04:51:07 +0000331 */
332
333 if (sdram_capabilities_dual_channel()) {
334 sysinfo->dual_channel = 1;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000335 printk(BIOS_DEBUG, "This mainboard supports Dual Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000336 } else {
337 sysinfo->dual_channel = 0;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000338 printk(BIOS_DEBUG, "This mainboard supports only Single Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000339 }
340
341 /**
342 * Since we only support two DIMMs in total, there is a limited number
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000343 * of combinations. This function returns the type of DIMMs.
Stefan Reinauer278534d2008-10-29 04:51:07 +0000344 * return value:
345 * [0:7] lower DIMM population
346 * [8-15] higher DIMM population
347 * [16] dual channel?
348 *
349 * There are 5 different possible populations for a DIMM socket:
350 * 1. x16 double sided (X16DS)
351 * 2. x8 double sided (X8DS)
352 * 3. x16 single sided (X16SS)
353 * 4. x8 double stacked (X8DDS)
354 * 5. not populated (NC)
355 *
356 * For the return value we start counting at zero.
357 *
358 */
359
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200360 for (i = 0; i<(2 * DIMM_SOCKETS); i++) {
Sven Schnelle541269b2011-02-21 09:39:17 +0000361 int device = get_dimm_spd_address(sysinfo, i);
362 u8 reg8;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000363
364 /* Initialize the socket information with a sane value */
365 sysinfo->dimm[i] = SYSINFO_DIMM_NOT_POPULATED;
366
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000367 /* Dual Channel not supported, but Channel 1? Bail out */
368 if (!sdram_capabilities_dual_channel() && (i >> 1))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000369 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000370
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000371 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: ", (i >> 1), (i & 1));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000372
373 if (spd_read_byte(device, SPD_MEMORY_TYPE) != SPD_MEMORY_TYPE_SDRAM_DDR2) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000374 printk(BIOS_DEBUG, "N/A\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000375 continue;
376 }
377
378 reg8 = spd_read_byte(device, SPD_DIMM_CONFIG_TYPE);
379 if (reg8 == ERROR_SCHEME_ECC)
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000380 die("Error: ECC memory not supported by this chipset\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000381
382 reg8 = spd_read_byte(device, SPD_MODULE_ATTRIBUTES);
383 if (reg8 & MODULE_BUFFERED)
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000384 die("Error: Buffered memory not supported by this chipset\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000385 if (reg8 & MODULE_REGISTERED)
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000386 die("Error: Registered memory not supported by this chipset\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000387
388 switch (spd_read_byte(device, SPD_PRIMARY_SDRAM_WIDTH)) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000389 case 0x08:
Stefan Reinauer278534d2008-10-29 04:51:07 +0000390 switch (spd_read_byte(device, SPD_NUM_DIMM_BANKS) & 0x0f) {
391 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000392 printk(BIOS_DEBUG, "x8DDS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000393 sysinfo->dimm[i] = SYSINFO_DIMM_X8DDS;
394 break;
395 case 0:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000396 printk(BIOS_DEBUG, "x8DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000397 sysinfo->dimm[i] = SYSINFO_DIMM_X8DS;
398 break;
399 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000400 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000401 }
402 break;
403 case 0x10:
404 switch (spd_read_byte(device, SPD_NUM_DIMM_BANKS) & 0x0f) {
405 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000406 printk(BIOS_DEBUG, "x16DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000407 sysinfo->dimm[i] = SYSINFO_DIMM_X16DS;
408 break;
409 case 0:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000410 printk(BIOS_DEBUG, "x16SS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000411 sysinfo->dimm[i] = SYSINFO_DIMM_X16SS;
412 break;
413 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000414 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000415 }
416 break;
417 default:
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000418 die("Unsupported DDR-II memory width.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000419 }
420
421 dimm_mask |= (1 << i);
422 }
423
424 if (!dimm_mask) {
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000425 die("No memory installed.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000426 }
427
Stefan Reinauer278534d2008-10-29 04:51:07 +0000428 if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1))) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000429 printk(BIOS_INFO, "Channel 0 has no memory populated.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000430 }
431}
432
433/**
434 * @brief determine if any DIMMs are stacked
435 *
436 * @param sysinfo central sysinfo data structure.
437 */
438static void sdram_verify_package_type(struct sys_info * sysinfo)
439{
440 int i;
441
442 /* Assume no stacked DIMMs are available until we find one */
443 sysinfo->package = 0;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200444 for (i = 0; i < 2*DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +0000445 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
446 continue;
447
448 /* Is the current DIMM a stacked DIMM? */
Sven Schnelle541269b2011-02-21 09:39:17 +0000449 if (spd_read_byte(get_dimm_spd_address(sysinfo, i), SPD_NUM_DIMM_BANKS) & (1 << 4))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000450 sysinfo->package = 1;
451 }
452}
453
454static u8 sdram_possible_cas_latencies(struct sys_info * sysinfo)
455{
456 int i;
457 u8 cas_mask;
458
459 /* Setup CAS mask with all supported CAS Latencies */
460 cas_mask = SPD_CAS_LATENCY_DDR2_3 |
461 SPD_CAS_LATENCY_DDR2_4 |
462 SPD_CAS_LATENCY_DDR2_5;
463
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200464 for (i = 0; i < 2*DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +0000465 if (sysinfo->dimm[i] != SYSINFO_DIMM_NOT_POPULATED)
Sven Schnelle541269b2011-02-21 09:39:17 +0000466 cas_mask &= spd_read_byte(get_dimm_spd_address(sysinfo, i),
467 SPD_ACCEPTABLE_CAS_LATENCIES);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000468 }
469
Elyes HAOUAS12df9502016-08-23 21:29:48 +0200470 if (!cas_mask) {
Stefan Reinauer278534d2008-10-29 04:51:07 +0000471 die("No DDR-II modules with accepted CAS latencies found.\n");
472 }
473
474 return cas_mask;
475}
476
477static void sdram_detect_cas_latency_and_ram_speed(struct sys_info * sysinfo, u8 cas_mask)
478{
479 int i, j, idx;
480 int lowest_common_cas = 0;
Stefan Reinauerde3206a2010-02-22 06:09:43 +0000481 int max_ram_speed = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000482
483 const u8 ddr2_speeds_table[] = {
484 0x50, 0x60, /* DDR2 400: tCLK = 5.0ns tAC = 0.6ns */
485 0x3d, 0x50, /* DDR2 533: tCLK = 3.75ns tAC = 0.5ns */
486 0x30, 0x45, /* DDR2 667: tCLK = 3.0ns tAC = 0.45ns */
487 };
488
489 const u8 spd_lookup_table[] = {
490 SPD_MIN_CYCLE_TIME_AT_CAS_MAX, SPD_ACCESS_TIME_FROM_CLOCK,
491 SPD_SDRAM_CYCLE_TIME_2ND, SPD_ACCESS_TIME_FROM_CLOCK_2ND,
492 SPD_SDRAM_CYCLE_TIME_3RD, SPD_ACCESS_TIME_FROM_CLOCK_3RD
493 };
494
495 switch (sdram_capabilities_max_supported_memory_frequency()) {
496 case 400: max_ram_speed = 0; break;
497 case 533: max_ram_speed = 1; break;
498 case 667: max_ram_speed = 2; break;
499 }
500
501 sysinfo->memory_frequency = 0;
502 sysinfo->cas = 0;
503
504 if (cas_mask & SPD_CAS_LATENCY_DDR2_3) {
505 lowest_common_cas = 3;
506 } else if (cas_mask & SPD_CAS_LATENCY_DDR2_4) {
507 lowest_common_cas = 4;
508 } else if (cas_mask & SPD_CAS_LATENCY_DDR2_5) {
509 lowest_common_cas = 5;
510 }
511 PRINTK_DEBUG("lowest common cas = %d\n", lowest_common_cas);
512
513 for (j = max_ram_speed; j>=0; j--) {
514 int freq_cas_mask = cas_mask;
515
516 PRINTK_DEBUG("Probing Speed %d\n", j);
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200517 for (i = 0; i < 2*DIMM_SOCKETS; i++) {
Sven Schnelle541269b2011-02-21 09:39:17 +0000518 int device = get_dimm_spd_address(sysinfo, i);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000519 int current_cas_mask;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000520
Stefan Reinauer278534d2008-10-29 04:51:07 +0000521 PRINTK_DEBUG(" DIMM: %d\n", i);
522 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED) {
523 continue;
524 }
525
Sven Schnelle541269b2011-02-21 09:39:17 +0000526 current_cas_mask = spd_read_byte(device, SPD_ACCEPTABLE_CAS_LATENCIES);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000527
528 while (current_cas_mask) {
529 int highest_supported_cas = 0, current_cas = 0;
530 PRINTK_DEBUG(" Current CAS mask: %04x; ", current_cas_mask);
531 if (current_cas_mask & SPD_CAS_LATENCY_DDR2_5) {
532 highest_supported_cas = 5;
533 } else if (current_cas_mask & SPD_CAS_LATENCY_DDR2_4) {
534 highest_supported_cas = 4;
535 } else if (current_cas_mask & SPD_CAS_LATENCY_DDR2_3) {
536 highest_supported_cas = 3;
Stefan Reinauer2b9070a2010-12-11 22:12:32 +0000537 } else {
538 die("Invalid max. CAS.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000539 }
540 if (current_cas_mask & SPD_CAS_LATENCY_DDR2_3) {
541 current_cas = 3;
542 } else if (current_cas_mask & SPD_CAS_LATENCY_DDR2_4) {
543 current_cas = 4;
544 } else if (current_cas_mask & SPD_CAS_LATENCY_DDR2_5) {
545 current_cas = 5;
Stefan Reinauer2b9070a2010-12-11 22:12:32 +0000546 } else {
547 die("Invalid CAS.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000548 }
549
550 idx = highest_supported_cas - current_cas;
551 PRINTK_DEBUG("idx=%d, ", idx);
Sven Schnelle541269b2011-02-21 09:39:17 +0000552 PRINTK_DEBUG("tCLK=%x, ", spd_read_byte(device, spd_lookup_table[2*idx]));
553 PRINTK_DEBUG("tAC=%x", spd_read_byte(device, spd_lookup_table[(2*idx)+1]));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000554
Sven Schnelle541269b2011-02-21 09:39:17 +0000555 if (spd_read_byte(device, spd_lookup_table[2*idx]) <= ddr2_speeds_table[2*j] &&
556 spd_read_byte(device, spd_lookup_table[(2*idx)+1]) <= ddr2_speeds_table[(2*j)+1]) {
Stefan Reinauer278534d2008-10-29 04:51:07 +0000557 PRINTK_DEBUG(": OK\n");
558 break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000559 }
560
Stefan Reinauer278534d2008-10-29 04:51:07 +0000561 PRINTK_DEBUG(": Not fast enough!\n");
562
563 current_cas_mask &= ~(1 << (current_cas));
564 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000565
Stefan Reinauer278534d2008-10-29 04:51:07 +0000566 freq_cas_mask &= current_cas_mask;
567 if (!current_cas_mask) {
568 PRINTK_DEBUG(" No valid CAS for this speed on DIMM %d\n", i);
569 break;
570 }
571 }
572 PRINTK_DEBUG(" freq_cas_mask for speed %d: %04x\n", j, freq_cas_mask);
573 if (freq_cas_mask) {
574 switch (j) {
575 case 0: sysinfo->memory_frequency = 400; break;
576 case 1: sysinfo->memory_frequency = 533; break;
577 case 2: sysinfo->memory_frequency = 667; break;
578 }
579 if (freq_cas_mask & SPD_CAS_LATENCY_DDR2_3) {
580 sysinfo->cas = 3;
581 } else if (freq_cas_mask & SPD_CAS_LATENCY_DDR2_4) {
582 sysinfo->cas = 4;
583 } else if (freq_cas_mask & SPD_CAS_LATENCY_DDR2_5) {
584 sysinfo->cas = 5;
585 }
586 break;
587 }
588 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000589
Stefan Reinauer278534d2008-10-29 04:51:07 +0000590 if (sysinfo->memory_frequency && sysinfo->cas) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000591 printk(BIOS_DEBUG, "Memory will be driven at %dMHz with CAS=%d clocks\n",
Stefan Reinauer278534d2008-10-29 04:51:07 +0000592 sysinfo->memory_frequency, sysinfo->cas);
593 } else {
594 die("Could not find common memory frequency and CAS\n");
595 }
596}
597
598static void sdram_detect_smallest_tRAS(struct sys_info * sysinfo)
599{
600 int i;
601 int tRAS_time;
602 int tRAS_cycles;
603 int freq_multiplier = 0;
604
605 switch (sysinfo->memory_frequency) {
606 case 400: freq_multiplier = 0x14; break; /* 5ns */
607 case 533: freq_multiplier = 0x0f; break; /* 3.75ns */
608 case 667: freq_multiplier = 0x0c; break; /* 3ns */
609 }
610
611 tRAS_cycles = 4; /* 4 clocks minimum */
612 tRAS_time = tRAS_cycles * freq_multiplier;
613
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200614 for (i = 0; i < 2*DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +0000615 u8 reg8;
616
617 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
618 continue;
619
Sven Schnelle541269b2011-02-21 09:39:17 +0000620 reg8 = spd_read_byte(get_dimm_spd_address(sysinfo, i), SPD_MIN_ACTIVE_TO_PRECHARGE_DELAY);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000621 if (!reg8) {
622 die("Invalid tRAS value.\n");
623 }
624
625 while ((tRAS_time >> 2) < reg8) {
626 tRAS_time += freq_multiplier;
627 tRAS_cycles++;
628 }
629 }
Elyes HAOUAS12df9502016-08-23 21:29:48 +0200630 if (tRAS_cycles > 0x18) {
Stefan Reinauer278534d2008-10-29 04:51:07 +0000631 die("DDR-II Module does not support this frequency (tRAS error)\n");
632 }
633
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000634 printk(BIOS_DEBUG, "tRAS = %d cycles\n", tRAS_cycles);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000635 sysinfo->tras = tRAS_cycles;
636}
637
638static void sdram_detect_smallest_tRP(struct sys_info * sysinfo)
639{
640 int i;
641 int tRP_time;
642 int tRP_cycles;
643 int freq_multiplier = 0;
644
645 switch (sysinfo->memory_frequency) {
646 case 400: freq_multiplier = 0x14; break; /* 5ns */
647 case 533: freq_multiplier = 0x0f; break; /* 3.75ns */
648 case 667: freq_multiplier = 0x0c; break; /* 3ns */
649 }
650
651 tRP_cycles = 2; /* 2 clocks minimum */
652 tRP_time = tRP_cycles * freq_multiplier;
653
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200654 for (i = 0; i < 2*DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +0000655 u8 reg8;
656
657 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
658 continue;
659
Sven Schnelle541269b2011-02-21 09:39:17 +0000660 reg8 = spd_read_byte(get_dimm_spd_address(sysinfo, i), SPD_MIN_ROW_PRECHARGE_TIME);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000661 if (!reg8) {
662 die("Invalid tRP value.\n");
663 }
664
665 while (tRP_time < reg8) {
666 tRP_time += freq_multiplier;
667 tRP_cycles++;
668 }
669 }
670
Elyes HAOUAS12df9502016-08-23 21:29:48 +0200671 if (tRP_cycles > 6) {
Stefan Reinauer278534d2008-10-29 04:51:07 +0000672 die("DDR-II Module does not support this frequency (tRP error)\n");
673 }
674
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000675 printk(BIOS_DEBUG, "tRP = %d cycles\n", tRP_cycles);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000676 sysinfo->trp = tRP_cycles;
677}
678
679static void sdram_detect_smallest_tRCD(struct sys_info * sysinfo)
680{
681 int i;
682 int tRCD_time;
683 int tRCD_cycles;
684 int freq_multiplier = 0;
685
686 switch (sysinfo->memory_frequency) {
687 case 400: freq_multiplier = 0x14; break; /* 5ns */
688 case 533: freq_multiplier = 0x0f; break; /* 3.75ns */
689 case 667: freq_multiplier = 0x0c; break; /* 3ns */
690 }
691
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000692 tRCD_cycles = 2; /* 2 clocks minimum */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000693 tRCD_time = tRCD_cycles * freq_multiplier;
694
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200695 for (i = 0; i < 2*DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +0000696 u8 reg8;
697
698 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
699 continue;
700
Sven Schnelle541269b2011-02-21 09:39:17 +0000701 reg8 = spd_read_byte(get_dimm_spd_address(sysinfo, i), SPD_MIN_RAS_TO_CAS_DELAY);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000702 if (!reg8) {
703 die("Invalid tRCD value.\n");
704 }
705
706 while (tRCD_time < reg8) {
707 tRCD_time += freq_multiplier;
708 tRCD_cycles++;
709 }
710 }
Elyes HAOUAS12df9502016-08-23 21:29:48 +0200711 if (tRCD_cycles > 6) {
Stefan Reinauer278534d2008-10-29 04:51:07 +0000712 die("DDR-II Module does not support this frequency (tRCD error)\n");
713 }
714
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000715 printk(BIOS_DEBUG, "tRCD = %d cycles\n", tRCD_cycles);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000716 sysinfo->trcd = tRCD_cycles;
717}
718
719static void sdram_detect_smallest_tWR(struct sys_info * sysinfo)
720{
721 int i;
722 int tWR_time;
723 int tWR_cycles;
724 int freq_multiplier = 0;
725
726 switch (sysinfo->memory_frequency) {
727 case 400: freq_multiplier = 0x14; break; /* 5ns */
728 case 533: freq_multiplier = 0x0f; break; /* 3.75ns */
729 case 667: freq_multiplier = 0x0c; break; /* 3ns */
730 }
731
732 tWR_cycles = 2; /* 2 clocks minimum */
733 tWR_time = tWR_cycles * freq_multiplier;
734
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200735 for (i = 0; i < 2*DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +0000736 u8 reg8;
737
738 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
739 continue;
740
Sven Schnelle541269b2011-02-21 09:39:17 +0000741 reg8 = spd_read_byte(get_dimm_spd_address(sysinfo, i), SPD_WRITE_RECOVERY_TIME);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000742 if (!reg8) {
743 die("Invalid tWR value.\n");
744 }
745
746 while (tWR_time < reg8) {
747 tWR_time += freq_multiplier;
748 tWR_cycles++;
749 }
750 }
Elyes HAOUAS12df9502016-08-23 21:29:48 +0200751 if (tWR_cycles > 5) {
Stefan Reinauer278534d2008-10-29 04:51:07 +0000752 die("DDR-II Module does not support this frequency (tWR error)\n");
753 }
754
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000755 printk(BIOS_DEBUG, "tWR = %d cycles\n", tWR_cycles);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000756 sysinfo->twr = tWR_cycles;
757}
758
759static void sdram_detect_smallest_tRFC(struct sys_info * sysinfo)
760{
761 int i, index = 0;
762
763 const u8 tRFC_cycles[] = {
764 /* 75 105 127.5 */
765 15, 21, 26, /* DDR2-400 */
766 20, 28, 34, /* DDR2-533 */
767 25, 35, 43 /* DDR2-667 */
768 };
769
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200770 for (i = 0; i < 2*DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +0000771 u8 reg8;
772
773 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
774 continue;
775
776 reg8 = sysinfo->banksize[i*2];
777 switch (reg8) {
778 case 0x04: reg8 = 0; break;
779 case 0x08: reg8 = 1; break;
780 case 0x10: reg8 = 2; break;
781 case 0x20: reg8 = 3; break;
782 }
783
784 if (sysinfo->dimm[i] == SYSINFO_DIMM_X16DS || sysinfo->dimm[i] == SYSINFO_DIMM_X16SS)
785 reg8++;
786
787 if (reg8 > 3) {
788 /* Can this happen? Go back to 127.5ns just to be sure
789 * we don't run out of the array. This may be wrong
790 */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000791 printk(BIOS_DEBUG, "DIMM %d is 1Gb x16.. Please report.\n", i);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000792 reg8 = 3;
793 }
794
795 if (reg8 > index)
796 index = reg8;
797
798 }
799 index--;
800 switch (sysinfo->memory_frequency) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000801 case 667: index += 3; /* Fallthrough */
802 case 533: index += 3; /* Fallthrough */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000803 case 400: break;
804 }
805
806 sysinfo->trfc = tRFC_cycles[index];
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000807 printk(BIOS_DEBUG, "tRFC = %d cycles\n", tRFC_cycles[index]);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000808}
809
Stefan Reinauer278534d2008-10-29 04:51:07 +0000810static void sdram_detect_smallest_refresh(struct sys_info * sysinfo)
811{
812 int i;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000813
Stefan Reinauer278534d2008-10-29 04:51:07 +0000814 sysinfo->refresh = 0;
815
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200816 for (i = 0; i < 2*DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +0000817 int refresh;
818
819 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
820 continue;
821
Sven Schnelle541269b2011-02-21 09:39:17 +0000822 refresh = spd_read_byte(get_dimm_spd_address(sysinfo, i),
823 SPD_REFRESH) & ~(1 << 7);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000824
825 /* 15.6us */
826 if (!refresh)
827 continue;
828
829 /* Refresh is slower than 15.6us, use 15.6us */
830 if (refresh > 2)
831 continue;
832
833 if (refresh == 2) {
834 sysinfo->refresh = 1;
835 break;
836 }
837
838 die("DDR-II module has unsupported refresh value\n");
839 }
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000840 printk(BIOS_DEBUG, "Refresh: %s\n", sysinfo->refresh?"7.8us":"15.6us");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000841}
842
843static void sdram_verify_burst_length(struct sys_info * sysinfo)
844{
845 int i;
846
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200847 for (i = 0; i < 2*DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +0000848 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
849 continue;
850
Sven Schnelle541269b2011-02-21 09:39:17 +0000851 if (!(spd_read_byte(get_dimm_spd_address(sysinfo, i),
852 SPD_SUPPORTED_BURST_LENGTHS) & SPD_BURST_LENGTH_8))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000853 die("Only DDR-II RAM with burst length 8 is supported by this chipset.\n");
854 }
855}
856
857static void sdram_program_dram_width(struct sys_info * sysinfo)
858{
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200859 u16 c0dramw = 0, c1dramw = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000860 int idx;
861
862 if (sysinfo->dual_channel)
863 idx = 2;
864 else
865 idx = 1;
866
867 switch (sysinfo->dimm[0]) {
868 case 0: c0dramw = 0x0000; break; /* x16DS */
869 case 1: c0dramw = 0x0001; break; /* x8DS */
870 case 2: c0dramw = 0x0000; break; /* x16SS */
871 case 3: c0dramw = 0x0005; break; /* x8DDS */
872 case 4: c0dramw = 0x0000; break; /* NC */
873 }
874
875 switch (sysinfo->dimm[idx]) {
876 case 0: c1dramw = 0x0000; break; /* x16DS */
877 case 1: c1dramw = 0x0010; break; /* x8DS */
878 case 2: c1dramw = 0x0000; break; /* x16SS */
879 case 3: c1dramw = 0x0050; break; /* x8DDS */
880 case 4: c1dramw = 0x0000; break; /* NC */
881 }
882
883 if ( !sdram_capabilities_dual_channel() ) {
884 /* Single Channel */
885 c0dramw |= c1dramw;
886 c1dramw = 0;
887 }
888
889 MCHBAR16(C0DRAMW) = c0dramw;
890 MCHBAR16(C1DRAMW) = c1dramw;
891}
892
893static void sdram_write_slew_rates(u32 offset, const u32 *slew_rate_table)
894{
895 int i;
896
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200897 for (i = 0; i < 16; i++)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000898 MCHBAR32(offset+(i*4)) = slew_rate_table[i];
899}
900
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000901static const u32 dq2030[] = {
902 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
903 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
904 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
905 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
906};
907
908static const u32 dq2330[] = {
909 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
910 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
911 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
912 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
913};
914
915static const u32 cmd2710[] = {
916 0x07060605, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
917 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
918 0x1110100f, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
919 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
920};
921
922static const u32 cmd3210[] = {
923 0x0f0d0b0a, 0x17151311, 0x1f1d1b19, 0x1f1f1f1f,
924 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
925 0x18171615, 0x1f1f1c1a, 0x1f1f1f1f, 0x1f1f1f1f,
926 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
927};
928
929static const u32 clk2030[] = {
930 0x0e0d0d0c, 0x100f0f0e, 0x100f0e0d, 0x15131211,
931 0x1d1b1917, 0x2523211f, 0x2a282927, 0x32302e2c,
932 0x17161514, 0x1b1a1918, 0x1f1e1d1c, 0x23222120,
933 0x27262524, 0x2d2b2928, 0x3533312f, 0x3d3b3937
934};
935
936static const u32 ctl3215[] = {
937 0x01010000, 0x03020101, 0x07060504, 0x0b0a0908,
938 0x100f0e0d, 0x14131211, 0x18171615, 0x1c1b1a19,
939 0x05040403, 0x07060605, 0x0a090807, 0x0f0d0c0b,
940 0x14131211, 0x18171615, 0x1c1b1a19, 0x201f1e1d
941};
942
943static const u32 ctl3220[] = {
944 0x05040403, 0x07060505, 0x0e0c0a08, 0x1a171411,
945 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e,
946 0x09080807, 0x0b0a0a09, 0x0f0d0c0b, 0x1b171311,
947 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e
948};
949
950static const u32 nc[] = {
951 0x00000000, 0x00000000, 0x00000000, 0x00000000,
952 0x00000000, 0x00000000, 0x00000000, 0x00000000,
953 0x00000000, 0x00000000, 0x00000000, 0x00000000,
954 0x00000000, 0x00000000, 0x00000000, 0x00000000
955};
956
957enum {
958 DQ2030,
959 DQ2330,
960 CMD2710,
961 CMD3210,
962 CLK2030,
963 CTL3215,
964 CTL3220,
965 NC,
966};
967
968static const u8 dual_channel_slew_group_lookup[] = {
969 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
970 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
971 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
972 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
973 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
974
975 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
976 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
977 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
978 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
979 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
980
981 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
982 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
983 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
984 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
985 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
986
987 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
988 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
989 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
990 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
991 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, NC, NC,
992
993 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
994 NC, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
995 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
996 NC, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD2710
997};
998
999static const u8 single_channel_slew_group_lookup[] = {
1000 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
1001 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
1002 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
1003 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
1004 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
1005
1006 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
1007 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
1008 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
1009 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
1010 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
1011
1012 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
1013 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
1014 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
1015 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
1016 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
1017
1018 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
1019 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
1020 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
1021 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
1022 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
1023
1024 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
1025 DQ2330, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
1026 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
1027 DQ2330, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD3210
1028};
1029
1030static const u32 *slew_group_lookup(int dual_channel, int index)
1031{
1032 const u8 *slew_group;
1033 /* Dual Channel needs different tables. */
1034 if (dual_channel)
1035 slew_group = dual_channel_slew_group_lookup;
1036 else
1037 slew_group = single_channel_slew_group_lookup;
1038
1039 switch (slew_group[index]) {
1040 case DQ2030: return dq2030;
1041 case DQ2330: return dq2330;
1042 case CMD2710: return cmd2710;
1043 case CMD3210: return cmd3210;
1044 case CLK2030: return clk2030;
1045 case CTL3215: return ctl3215;
1046 case CTL3220: return ctl3220;
1047 case NC: return nc;
1048 }
1049
1050 return nc;
1051}
1052
Kyösti Mälkkieb5e28f2012-02-24 16:08:18 +02001053#if CONFIG_NORTHBRIDGE_INTEL_SUBTYPE_I945GM
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001054/* Strength multiplier tables */
1055static const u8 dual_channel_strength_multiplier[] = {
1056 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
1057 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
1058 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
1059 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
1060 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
1061 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
1062 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
1063 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
1064 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
1065 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
1066 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
1067 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
1068 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
1069 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
1070 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
1071 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
1072 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
1073 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
1074 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
1075 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
1076 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
1077 0x00, 0x00, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
1078 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
1079 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x44, 0x22
1080};
1081
1082static const u8 single_channel_strength_multiplier[] = {
1083 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
1084 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
1085 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
1086 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
1087 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
1088 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
1089 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
1090 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
1091 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
1092 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
1093 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
1094 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
1095 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
1096 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
1097 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
1098 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
1099 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
1100 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
1101 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
1102 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
1103 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
1104 0x33, 0x00, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
1105 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
1106 0x33, 0x00, 0x11, 0x00, 0x44, 0x44, 0x33, 0x11
1107};
Kyösti Mälkkieb5e28f2012-02-24 16:08:18 +02001108#elif CONFIG_NORTHBRIDGE_INTEL_SUBTYPE_I945GC
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001109static const u8 dual_channel_strength_multiplier[] = {
1110 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
1111 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
1112 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
1113 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
1114 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1115 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
1116 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
1117 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
1118 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
1119 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1120 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
1121 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
1122 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
1123 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
1124 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1125 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
1126 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
1127 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
1128 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
1129 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1130 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
1131 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
1132 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
1133 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33
1134};
1135
1136static const u8 single_channel_strength_multiplier[] = {
1137 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1138 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1139 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1140 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1141 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1142 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1143 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1144 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1145 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1146 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1147 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1148 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1149 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1150 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1151 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1152 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1153 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1154 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1155 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1156 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1157 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1158 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1159 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
1160 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00
1161};
1162#endif
1163
Stefan Reinauer278534d2008-10-29 04:51:07 +00001164static void sdram_rcomp_buffer_strength_and_slew(struct sys_info *sysinfo)
1165{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001166 const u8 * strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001167 int idx, dual_channel;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001168
1169 /* Set Strength Multipliers */
1170
1171 /* Dual Channel needs different tables. */
1172 if (sdram_capabilities_dual_channel()) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001173 printk(BIOS_DEBUG, "Programming Dual Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001174 strength_multiplier = dual_channel_strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001175 dual_channel = 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001176 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[2];
1177 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001178 printk(BIOS_DEBUG, "Programming Single Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001179 strength_multiplier = single_channel_strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001180 dual_channel = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001181 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[1];
1182 }
1183
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001184 printk(BIOS_DEBUG, "Table Index: %d\n", idx);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001185
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001186 MCHBAR8(G1SC) = strength_multiplier[idx * 8 + 0];
1187 MCHBAR8(G2SC) = strength_multiplier[idx * 8 + 1];
1188 MCHBAR8(G3SC) = strength_multiplier[idx * 8 + 2];
1189 MCHBAR8(G4SC) = strength_multiplier[idx * 8 + 3];
1190 MCHBAR8(G5SC) = strength_multiplier[idx * 8 + 4];
1191 MCHBAR8(G6SC) = strength_multiplier[idx * 8 + 5];
1192 MCHBAR8(G7SC) = strength_multiplier[idx * 8 + 6];
1193 MCHBAR8(G8SC) = strength_multiplier[idx * 8 + 7];
Stefan Reinauer278534d2008-10-29 04:51:07 +00001194
1195 /* Channel 0 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001196 sdram_write_slew_rates(G1SRPUT, slew_group_lookup(dual_channel, idx * 8 + 0));
1197 sdram_write_slew_rates(G2SRPUT, slew_group_lookup(dual_channel, idx * 8 + 1));
1198 if ((slew_group_lookup(dual_channel, idx * 8 + 2) != nc) && (sysinfo->package == SYSINFO_PACKAGE_STACKED)) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001199
Stefan Reinauer278534d2008-10-29 04:51:07 +00001200 sdram_write_slew_rates(G3SRPUT, ctl3220);
1201 } else {
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001202 sdram_write_slew_rates(G3SRPUT, slew_group_lookup(dual_channel, idx * 8 + 2));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001203 }
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001204 sdram_write_slew_rates(G4SRPUT, slew_group_lookup(dual_channel, idx * 8 + 3));
1205 sdram_write_slew_rates(G5SRPUT, slew_group_lookup(dual_channel, idx * 8 + 4));
1206 sdram_write_slew_rates(G6SRPUT, slew_group_lookup(dual_channel, idx * 8 + 5));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001207
1208 /* Channel 1 */
1209 if (sysinfo->dual_channel) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001210 sdram_write_slew_rates(G7SRPUT, slew_group_lookup(dual_channel, idx * 8 + 6));
1211 sdram_write_slew_rates(G8SRPUT, slew_group_lookup(dual_channel, idx * 8 + 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001212 } else {
1213 sdram_write_slew_rates(G7SRPUT, nc);
1214 sdram_write_slew_rates(G8SRPUT, nc);
1215 }
1216}
1217
1218static void sdram_enable_rcomp(void)
1219{
1220 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001221 /* Enable Global Periodic RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001222 udelay(300);
1223 reg32 = MCHBAR32(GBRCOMPCTL);
1224 reg32 &= ~(1 << 23);
1225 MCHBAR32(GBRCOMPCTL) = reg32;
1226}
1227
1228static void sdram_program_dll_timings(struct sys_info *sysinfo)
1229{
1230 u32 chan0dll = 0, chan1dll = 0;
1231 int i;
1232
Elyes HAOUAS38424982016-08-21 12:01:04 +02001233 printk(BIOS_DEBUG, "Programming DLL Timings...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001234
Stefan Reinauer278534d2008-10-29 04:51:07 +00001235 MCHBAR16(DQSMT) &= ~( (3 << 12) | (1 << 10) | ( 0xf << 0) );
1236 MCHBAR16(DQSMT) |= (1 << 13) | (0xc << 0);
1237
1238 /* We drive both channels with the same speed */
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001239 if (IS_ENABLED(CONFIG_NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
1240 switch (sysinfo->memory_frequency) {
Paul Menzelbce7e332017-02-22 18:46:27 +01001241 case 400: chan0dll = 0x26262626; chan1dll = 0x26262626; break; /* 400MHz */
1242 case 533: chan0dll = 0x22222222; chan1dll = 0x22222222; break; /* 533MHz */
1243 case 667: chan0dll = 0x11111111; chan1dll = 0x11111111; break; /* 667MHz */
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001244 }
1245 } else if (IS_ENABLED(CONFIG_NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
1246 switch (sysinfo->memory_frequency) {
Paul Menzelbce7e332017-02-22 18:46:27 +01001247 case 400: chan0dll = 0x33333333; chan1dll = 0x33333333; break; /* 400MHz */
1248 case 533: chan0dll = 0x24242424; chan1dll = 0x24242424; break; /* 533MHz */
1249 case 667: chan0dll = 0x25252525; chan1dll = 0x25252525; break; /* 667MHz */
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001250 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001251 }
1252
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001253 for (i = 0; i < 4; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001254 MCHBAR32(C0R0B00DQST + (i * 0x10) + 0) = chan0dll;
1255 MCHBAR32(C0R0B00DQST + (i * 0x10) + 4) = chan0dll;
1256 MCHBAR32(C1R0B00DQST + (i * 0x10) + 0) = chan1dll;
1257 MCHBAR32(C1R0B00DQST + (i * 0x10) + 4) = chan1dll;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001258 if (IS_ENABLED(CONFIG_NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
1259 MCHBAR8(C0R0B00DQST + (i * 0x10) + 8) = chan0dll & 0xff;
1260 MCHBAR8(C1R0B00DQST + (i * 0x10) + 8) = chan1dll & 0xff;
Paul Menzelbce7e332017-02-22 18:46:27 +01001261 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001262 }
1263}
1264
1265static void sdram_force_rcomp(void)
1266{
1267 u32 reg32;
1268 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001269
Stefan Reinauer278534d2008-10-29 04:51:07 +00001270 reg32 = MCHBAR32(ODTC);
1271 reg32 |= (1 << 28);
1272 MCHBAR32(ODTC) = reg32;
1273
1274 reg32 = MCHBAR32(SMSRCTL);
1275 reg32 |= (1 << 0);
1276 MCHBAR32(SMSRCTL) = reg32;
1277
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001278 /* Start initial RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001279 reg32 = MCHBAR32(GBRCOMPCTL);
1280 reg32 |= (1 << 8);
1281 MCHBAR32(GBRCOMPCTL) = reg32;
1282
1283 reg8 = i945_silicon_revision();
1284 if ((reg8 == 0 && (MCHBAR32(DCC) & (3 << 0)) == 0) || (reg8 == 1)) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001285
Stefan Reinauer278534d2008-10-29 04:51:07 +00001286 reg32 = MCHBAR32(GBRCOMPCTL);
1287 reg32 |= (3 << 5);
1288 MCHBAR32(GBRCOMPCTL) = reg32;
1289 }
1290}
1291
1292static void sdram_initialize_system_memory_io(struct sys_info *sysinfo)
1293{
1294 u8 reg8;
1295 u32 reg32;
1296
Elyes HAOUAS38424982016-08-21 12:01:04 +02001297 printk(BIOS_DEBUG, "Initializing System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001298 /* Enable Data Half Clock Pushout */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001299 reg8 = MCHBAR8(C0HCTC);
1300 reg8 &= ~0x1f;
1301 reg8 |= ( 1 << 0);
1302 MCHBAR8(C0HCTC) = reg8;
1303
1304 reg8 = MCHBAR8(C1HCTC);
1305 reg8 &= ~0x1f;
1306 reg8 |= ( 1 << 0);
1307 MCHBAR8(C1HCTC) = reg8;
1308
Stefan Reinauer278534d2008-10-29 04:51:07 +00001309 MCHBAR16(WDLLBYPMODE) &= ~( (1 << 9) | (1 << 6) | (1 << 4) | (1 << 3) | (1 << 1) );
1310 MCHBAR16(WDLLBYPMODE) |= (1 << 8) | (1 << 7) | (1 << 5) | (1 << 2) | (1 << 0);
1311
1312 MCHBAR8(C0WDLLCMC) = 0;
1313 MCHBAR8(C1WDLLCMC) = 0;
1314
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001315 /* Program RCOMP Settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001316 sdram_program_dram_width(sysinfo);
1317
1318 sdram_rcomp_buffer_strength_and_slew(sysinfo);
1319
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001320 /* Indicate that RCOMP programming is done */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001321 reg32 = MCHBAR32(GBRCOMPCTL);
1322 reg32 &= ~( (1 << 29) | (1 << 26) | (3 << 21) | (3 << 2) );
1323 reg32 |= (3 << 27) | (3 << 0);
1324 MCHBAR32(GBRCOMPCTL) = reg32;
1325
1326 MCHBAR32(GBRCOMPCTL) |= (1 << 10);
1327
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001328 /* Program DLL Timings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001329 sdram_program_dll_timings(sysinfo);
1330
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001331 /* Force RCOMP cycle */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001332 sdram_force_rcomp();
1333}
1334
1335static void sdram_enable_system_memory_io(struct sys_info *sysinfo)
1336{
1337 u32 reg32;
1338
Elyes HAOUAS38424982016-08-21 12:01:04 +02001339 printk(BIOS_DEBUG, "Enabling System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001340
Stefan Reinauer278534d2008-10-29 04:51:07 +00001341 reg32 = MCHBAR32(RCVENMT);
1342 reg32 &= ~(0x3f << 6);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001343 MCHBAR32(RCVENMT) = reg32; /* [11:6] = 0 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001344
1345 reg32 |= (1 << 11) | (1 << 9);
1346 MCHBAR32(RCVENMT) = reg32;
1347
1348 reg32 = MCHBAR32(DRTST);
1349 reg32 |= (1 << 3) | (1 << 2);
1350 MCHBAR32(DRTST) = reg32;
1351
1352 reg32 = MCHBAR32(DRTST);
1353 reg32 |= (1 << 6) | (1 << 4);
1354 MCHBAR32(DRTST) = reg32;
1355
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001356 asm volatile ("nop; nop;" ::: "memory");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001357
1358 reg32 = MCHBAR32(DRTST);
1359
1360 /* Is channel 0 populated? */
1361 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
1362 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
1363 reg32 |= (1 << 7) | (1 << 5);
1364 else
1365 reg32 |= (1 << 31);
1366
1367 /* Is channel 1 populated? */
1368 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1369 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
1370 reg32 |= (1 << 9) | (1 << 8);
1371 else
1372 reg32 |= (1 << 30);
1373
1374 MCHBAR32(DRTST) = reg32;
1375
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001376 /* Activate DRAM Channel IO Buffers */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001377 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
1378 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) {
1379 reg32 = MCHBAR32(C0DRC1);
1380 reg32 |= (1 << 8);
1381 MCHBAR32(C0DRC1) = reg32;
1382 }
1383 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1384 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED) {
1385 reg32 = MCHBAR32(C1DRC1);
1386 reg32 |= (1 << 8);
1387 MCHBAR32(C1DRC1) = reg32;
1388 }
1389}
1390
1391struct dimm_size {
1392 unsigned long side1;
1393 unsigned long side2;
1394};
1395
Sven Schnelle541269b2011-02-21 09:39:17 +00001396static struct dimm_size sdram_get_dimm_size(struct sys_info *sysinfo, u16 dimmno)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001397{
1398 /* Calculate the log base 2 size of a DIMM in bits */
1399 struct dimm_size sz;
Sven Schnelle541269b2011-02-21 09:39:17 +00001400 int value, low, rows, columns, device;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001401
Sven Schnelle541269b2011-02-21 09:39:17 +00001402 device = get_dimm_spd_address(sysinfo, dimmno);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001403 sz.side1 = 0;
1404 sz.side2 = 0;
1405
1406 rows = spd_read_byte(device, SPD_NUM_ROWS); /* rows */
1407 if (rows < 0) goto hw_err;
1408 if ((rows & 0xf) == 0) goto val_err;
1409 sz.side1 += rows & 0xf;
1410
1411 columns = spd_read_byte(device, SPD_NUM_COLUMNS); /* columns */
1412 if (columns < 0) goto hw_err;
1413 if ((columns & 0xf) == 0) goto val_err;
1414 sz.side1 += columns & 0xf;
1415
1416 value = spd_read_byte(device, SPD_NUM_BANKS_PER_SDRAM); /* banks */
1417 if (value < 0) goto hw_err;
1418 if ((value & 0xff) == 0) goto val_err;
1419 sz.side1 += log2(value & 0xff);
1420
1421 /* Get the module data width and convert it to a power of two */
1422 value = spd_read_byte(device, SPD_MODULE_DATA_WIDTH_MSB); /* (high byte) */
1423 if (value < 0) goto hw_err;
1424 value &= 0xff;
1425 value <<= 8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001426
Stefan Reinauer278534d2008-10-29 04:51:07 +00001427 low = spd_read_byte(device, SPD_MODULE_DATA_WIDTH_LSB); /* (low byte) */
1428 if (low < 0) goto hw_err;
1429 value = value | (low & 0xff);
1430 if ((value != 72) && (value != 64)) goto val_err;
1431 sz.side1 += log2(value);
1432
1433 /* side 2 */
1434 value = spd_read_byte(device, SPD_NUM_DIMM_BANKS); /* number of physical banks */
1435
1436 if (value < 0) goto hw_err;
1437 value &= 7;
1438 value++;
1439 if (value == 1) goto out;
1440 if (value != 2) goto val_err;
1441
1442 /* Start with the symmetrical case */
1443 sz.side2 = sz.side1;
1444
1445 if ((rows & 0xf0) == 0) goto out; /* If symmetrical we are done */
1446
1447 /* Don't die here, I have not come across any of these to test what
1448 * actually happens.
1449 */
Martin Roth128c1042016-11-18 09:29:03 -07001450 printk(BIOS_ERR, "Asymmetric DIMMs are not supported by this chipset\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001451
1452 sz.side2 -= (rows & 0x0f); /* Subtract out rows on side 1 */
1453 sz.side2 += ((rows >> 4) & 0x0f); /* Add in rows on side 2 */
1454
1455 sz.side2 -= (columns & 0x0f); /* Subtract out columns on side 1 */
1456 sz.side2 += ((columns >> 4) & 0x0f); /* Add in columns on side 2 */
1457
1458 goto out;
1459
1460 val_err:
Stefan Reinauer779b3e32008-11-10 15:43:37 +00001461 die("Bad SPD value\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001462 hw_err:
Elyes HAOUAS15279a92016-07-28 21:05:26 +02001463 /* If a hardware error occurs the spd ROM probably does not exist.
Stefan Reinauer278534d2008-10-29 04:51:07 +00001464 * In this case report that there is no memory
1465 */
1466 sz.side1 = 0;
1467 sz.side2 = 0;
Patrick Georgic5fc7db2012-03-07 15:55:47 +01001468out:
Stefan Reinauer278534d2008-10-29 04:51:07 +00001469 return sz;
1470}
1471
1472static void sdram_detect_dimm_size(struct sys_info * sysinfo)
1473{
1474 int i;
1475
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001476 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001477 struct dimm_size sz;
1478
1479 sysinfo->banksize[i * 2] = 0;
1480 sysinfo->banksize[(i * 2) + 1] = 0;
1481
1482 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
1483 continue;
1484
Sven Schnelle541269b2011-02-21 09:39:17 +00001485 sz = sdram_get_dimm_size(sysinfo, i);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001486
Sven Schnelle541269b2011-02-21 09:39:17 +00001487 sysinfo->banks[i] = spd_read_byte(get_dimm_spd_address(sysinfo, i),
1488 SPD_NUM_BANKS_PER_SDRAM); /* banks */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001489
1490 if (sz.side1 < 30)
1491 die("DDR-II rank size smaller than 128MB is not supported.\n");
1492
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001493 sysinfo->banksize[i * 2] = 1 << (sz.side1 - 28);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001494
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001495 printk(BIOS_DEBUG, "DIMM %d side 0 = %d MB\n", i, sysinfo->banksize[i * 2] * 32 );
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001496
Stefan Reinauer278534d2008-10-29 04:51:07 +00001497 if (!sz.side2)
1498 continue;
1499
1500 /* If there is a second side, it has to have at least 128M, too */
1501 if (sz.side2 < 30)
1502 die("DDR-II rank size smaller than 128MB is not supported.\n");
1503
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001504 sysinfo->banksize[(i * 2) + 1] = 1 << (sz.side2 - 28);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001505
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001506 printk(BIOS_DEBUG, "DIMM %d side 1 = %d MB\n", i, sysinfo->banksize[(i * 2) + 1] * 32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001507 }
1508}
1509
1510static int sdram_program_row_boundaries(struct sys_info *sysinfo)
1511{
1512 int i;
Arthur Heymans885c2892016-10-03 17:16:48 +02001513 int cum0, cum1, tolud, tom, pci_mmio_size;
1514 const struct device *dev;
1515 const struct northbridge_intel_i945_config *cfg = NULL;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001516
Paul Menzel84283bc2014-07-17 08:16:04 +02001517 printk(BIOS_DEBUG, "Setting RAM size...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001518
1519 cum0 = 0;
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001520 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001521 cum0 += sysinfo->banksize[i];
Stefan Reinauer278534d2008-10-29 04:51:07 +00001522 MCHBAR8(C0DRB0+i) = cum0;
1523 }
1524
1525 /* Assume we continue in Channel 1 where we stopped in Channel 0 */
1526 cum1 = cum0;
1527
1528 /* Exception: Interleaved starts from the beginning */
1529 if (sysinfo->interleaved)
1530 cum1 = 0;
1531
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001532#if 0
Stefan Reinauer278534d2008-10-29 04:51:07 +00001533 /* Exception: Channel 1 is not populated. C1DRB stays zero */
1534 if (sysinfo->dimm[2] == SYSINFO_DIMM_NOT_POPULATED &&
1535 sysinfo->dimm[3] == SYSINFO_DIMM_NOT_POPULATED)
1536 cum1 = 0;
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001537#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00001538
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001539 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001540 cum1 += sysinfo->banksize[i + 4];
Stefan Reinauer278534d2008-10-29 04:51:07 +00001541 MCHBAR8(C1DRB0+i) = cum1;
1542 }
1543
1544 /* Set TOLUD Top Of Low Usable DRAM */
1545 if (sysinfo->interleaved)
1546 tolud = (cum0 + cum1) << 1;
1547 else
1548 tolud = (cum1 ? cum1 : cum0) << 1;
Stefan Reinauer779b3e32008-11-10 15:43:37 +00001549
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001550 /* The TOM register has a different format */
1551 tom = tolud >> 3;
1552
1553 /* Limit the value of TOLUD to leave some space for PCI memory. */
Arthur Heymans885c2892016-10-03 17:16:48 +02001554 dev = dev_find_slot(0, PCI_DEVFN(0, 0));
1555 if (dev)
1556 cfg = dev->chip_info;
1557
1558 /* Don't use pci mmio sizes smaller than 768M */
1559 if (!cfg || cfg->pci_mmio_size <= DEFAULT_PCI_MMIO_SIZE)
1560 pci_mmio_size = DEFAULT_PCI_MMIO_SIZE;
1561 else
1562 pci_mmio_size = cfg->pci_mmio_size;
1563
1564 tolud = MIN(((4096 - pci_mmio_size) / 128) << 3, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001565
1566 pci_write_config8(PCI_DEV(0,0,0), TOLUD, tolud);
1567
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001568 printk(BIOS_DEBUG, "C0DRB = 0x%08x\n", MCHBAR32(C0DRB0));
1569 printk(BIOS_DEBUG, "C1DRB = 0x%08x\n", MCHBAR32(C1DRB0));
1570 printk(BIOS_DEBUG, "TOLUD = 0x%04x\n", pci_read_config8(PCI_DEV(0,0,0), TOLUD));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001571
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001572 pci_write_config16(PCI_DEV(0,0,0), TOM, tom);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001573
1574 return 0;
1575}
1576
Stefan Reinauer278534d2008-10-29 04:51:07 +00001577static int sdram_set_row_attributes(struct sys_info *sysinfo)
1578{
1579 int i, value;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001580 u16 dra0 = 0, dra1 = 0, dra = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001581
Elyes HAOUAS38424982016-08-21 12:01:04 +02001582 printk(BIOS_DEBUG, "Setting row attributes...\n");
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001583 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001584 u16 device;
1585 u8 columnsrows;
1586
1587 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED) {
1588 continue;
1589 }
1590
Sven Schnelle541269b2011-02-21 09:39:17 +00001591 device = get_dimm_spd_address(sysinfo, i);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001592
1593 value = spd_read_byte(device, SPD_NUM_ROWS); /* rows */
1594 columnsrows = (value & 0x0f);
1595
1596 value = spd_read_byte(device, SPD_NUM_COLUMNS); /* columns */
1597 columnsrows |= (value & 0xf) << 4;
1598
1599 switch (columnsrows) {
1600 case 0x9d: dra = 2; break;
1601 case 0xad: dra = 3; break;
1602 case 0xbd: dra = 4; break;
1603 case 0xae: dra = 3; break;
1604 case 0xbe: dra = 4; break;
1605 default: die("Unsupported Rows/Columns. (DRA)");
1606 }
1607
1608 /* Double Sided DIMMs? */
1609 if (sysinfo->banksize[(2 * i) + 1] != 0) {
1610 dra = (dra << 4) | dra;
1611 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001612
Stefan Reinauer278534d2008-10-29 04:51:07 +00001613 if (i < DIMM_SOCKETS)
1614 dra0 |= (dra << (i*8));
1615 else
1616 dra1 |= (dra << ((i - DIMM_SOCKETS)*8));
1617 }
1618
1619 MCHBAR16(C0DRA0) = dra0;
1620 MCHBAR16(C1DRA0) = dra1;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001621
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001622 printk(BIOS_DEBUG, "C0DRA = 0x%04x\n", dra0);
1623 printk(BIOS_DEBUG, "C1DRA = 0x%04x\n", dra1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001624
1625 return 0;
1626}
1627
1628static void sdram_set_bank_architecture(struct sys_info *sysinfo)
1629{
1630 u32 off32;
1631 int i;
1632
1633 MCHBAR16(C1BNKARC) &= 0xff00;
1634 MCHBAR16(C0BNKARC) &= 0xff00;
1635
1636 off32 = C0BNKARC;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001637 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001638 /* Switch to second channel */
1639 if (i == DIMM_SOCKETS)
1640 off32 = C1BNKARC;
1641
1642 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
1643 continue;
1644
1645 if (sysinfo->banks[i] != 8)
1646 continue;
1647
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001648 printk(BIOS_SPEW, "DIMM%d has 8 banks.\n", i);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001649
1650 if (i & 1)
1651 MCHBAR16(off32) |= 0x50;
1652 else
1653 MCHBAR16(off32) |= 0x05;
1654 }
1655}
1656
1657#define REFRESH_7_8US 1
1658#define REFRESH_15_6US 0
1659static void sdram_program_refresh_rate(struct sys_info *sysinfo)
1660{
1661 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001662
Stefan Reinauer278534d2008-10-29 04:51:07 +00001663 if (sysinfo->refresh == REFRESH_7_8US) {
1664 reg32 = (2 << 8); /* Refresh enabled at 7.8us */
1665 } else {
1666 reg32 = (1 << 8); /* Refresh enabled at 15.6us */
1667 }
1668
1669 MCHBAR32(C0DRC0) &= ~(7 << 8);
1670 MCHBAR32(C0DRC0) |= reg32;
1671
1672 MCHBAR32(C1DRC0) &= ~(7 << 8);
1673 MCHBAR32(C1DRC0) |= reg32;
1674}
1675
1676static void sdram_program_cke_tristate(struct sys_info *sysinfo)
1677{
1678 u32 reg32;
1679 int i;
1680
1681 reg32 = MCHBAR32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001682
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001683 for (i = 0; i < 4; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001684 if (sysinfo->banksize[i] == 0) {
1685 reg32 |= (1 << (16 + i));
1686 }
1687 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001688
Stefan Reinauer278534d2008-10-29 04:51:07 +00001689 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001690
Stefan Reinauer278534d2008-10-29 04:51:07 +00001691 reg32 |= (1 << 11);
1692 MCHBAR32(C0DRC1) = reg32;
1693
1694 /* Do we have to do this if we're in Single Channel Mode? */
1695 reg32 = MCHBAR32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001696
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001697 for (i = 4; i < 8; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001698 if (sysinfo->banksize[i] == 0) {
1699 reg32 |= (1 << (12 + i));
1700 }
1701 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001702
Stefan Reinauer278534d2008-10-29 04:51:07 +00001703 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001704
Stefan Reinauer278534d2008-10-29 04:51:07 +00001705 reg32 |= (1 << 11);
1706 MCHBAR32(C1DRC1) = reg32;
1707}
1708
1709static void sdram_program_odt_tristate(struct sys_info *sysinfo)
1710{
1711 u32 reg32;
1712 int i;
1713
1714 reg32 = MCHBAR32(C0DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001715
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001716 for (i = 0; i < 4; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001717 if (sysinfo->banksize[i] == 0) {
1718 reg32 |= (1 << (24 + i));
1719 }
1720 }
1721 MCHBAR32(C0DRC2) = reg32;
1722
1723 reg32 = MCHBAR32(C1DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001724
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001725 for (i = 4; i < 8; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001726 if (sysinfo->banksize[i] == 0) {
1727 reg32 |= (1 << (20 + i));
1728 }
1729 }
1730 MCHBAR32(C1DRC2) = reg32;
1731}
1732
1733static void sdram_set_timing_and_control(struct sys_info *sysinfo)
1734{
1735 u32 reg32, off32;
1736 u32 tWTR;
1737 u32 temp_drt;
1738 int i, page_size;
1739
Edward O'Callaghan2f237c12014-05-25 06:24:39 +10001740 static const u8 drt0_table[] = {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001741 /* CL 3, 4, 5 */
Arthur Heymanse1897612016-10-15 23:29:18 +02001742 3, 4, 5, /* FSB533, DDR667/533/400 */
1743 4, 5, 6, /* FSB667, DDR667/533/400 */
1744 5, 6, 7, /* FSB800, DDR400/533 */
1745 6, 7, 8, /* FSB800, DDR667 */
1746 5, 6, 7, /* FSB1066, DDR400 */
1747 7, 8, 9, /* FSB1066, DDR533/DDR667 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001748 };
1749
Edward O'Callaghan2f237c12014-05-25 06:24:39 +10001750 static const u8 cas_table[] = {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001751 2, 1, 0, 3
1752 };
1753
1754 reg32 = MCHBAR32(C0DRC0);
1755 reg32 |= (1 << 2); /* Burst Length 8 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001756 reg32 &= ~( (1 << 13) | (1 << 12) );
Stefan Reinauer278534d2008-10-29 04:51:07 +00001757 MCHBAR32(C0DRC0) = reg32;
1758
1759 reg32 = MCHBAR32(C1DRC0);
1760 reg32 |= (1 << 2); /* Burst Length 8 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001761 reg32 &= ~( (1 << 13) | (1 << 12) );
Stefan Reinauer278534d2008-10-29 04:51:07 +00001762 MCHBAR32(C1DRC0) = reg32;
1763
1764 if (!sysinfo->dual_channel && sysinfo->dimm[1] !=
1765 SYSINFO_DIMM_NOT_POPULATED) {
1766 reg32 = MCHBAR32(C0DRC0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001767 reg32 |= (1 << 15);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001768 MCHBAR32(C0DRC0) = reg32;
1769 }
1770
1771 sdram_program_refresh_rate(sysinfo);
1772
1773 sdram_program_cke_tristate(sysinfo);
1774
1775 sdram_program_odt_tristate(sysinfo);
1776
1777 /* Calculate DRT0 */
1778
1779 temp_drt = 0;
1780
1781 /* B2B Write Precharge (same bank) = CL-1 + BL/2 + tWR */
1782 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + sysinfo->twr;
1783 temp_drt |= (reg32 << 28);
1784
1785 /* Write Auto Precharge (same bank) = CL-1 + BL/2 + tWR + tRP */
1786 reg32 += sysinfo->trp;
1787 temp_drt |= (reg32 << 4);
1788
1789 if (sysinfo->memory_frequency == 667) {
1790 tWTR = 3; /* 667MHz */
1791 } else {
1792 tWTR = 2; /* 400 and 533 */
1793 }
1794
1795 /* B2B Write to Read Command Spacing */
1796 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + tWTR;
1797 temp_drt |= (reg32 << 24);
1798
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001799 /* CxDRT0 [23:22], [21:20], [19:18] [16] have fixed values */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001800 temp_drt |= ( (1 << 22) | (3 << 20) | (1 << 18) | (0 << 16) );
1801
1802 /* Program Write Auto Precharge to Activate */
1803 off32 = 0;
Arthur Heymanse1897612016-10-15 23:29:18 +02001804 switch (sysinfo->fsb_frequency) {
1805 case 533:
1806 off32 = 0;
1807 break;
1808 case 667:
1809 off32 = 3;
1810 break;
1811 case 800:
1812 if (sysinfo->memory_frequency <= 533) {
1813 off32 = 6;
1814 break;
1815 }
1816 off32 = 9;
1817 break;
1818 case 1066:
1819 if (sysinfo->memory_frequency == 400) {
1820 off32 = 12;
1821 break;
1822 }
1823 off32 = 15;
1824 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001825 }
Arthur Heymanse1897612016-10-15 23:29:18 +02001826
Stefan Reinauer278534d2008-10-29 04:51:07 +00001827 off32 += sysinfo->cas - 3;
1828 reg32 = drt0_table[off32];
1829 temp_drt |= (reg32 << 11);
1830
1831 /* Read Auto Precharge to Activate */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001832
Stefan Reinauer278534d2008-10-29 04:51:07 +00001833 temp_drt |= (8 << 0);
1834
1835 MCHBAR32(C0DRT0) = temp_drt;
1836 MCHBAR32(C1DRT0) = temp_drt;
1837
1838 /* Calculate DRT1 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001839
Stefan Reinauer278534d2008-10-29 04:51:07 +00001840 temp_drt = MCHBAR32(C0DRT1) & 0x00020088;
1841
1842 /* DRAM RASB Precharge */
1843 temp_drt |= (sysinfo->trp - 2) << 0;
1844
1845 /* DRAM RASB to CASB Delay */
1846 temp_drt |= (sysinfo->trcd - 2) << 4;
1847
1848 /* CASB Latency */
1849 temp_drt |= (cas_table[sysinfo->cas - 3]) << 8;
1850
1851 /* Refresh Cycle Time */
1852 temp_drt |= (sysinfo->trfc) << 10;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001853
Stefan Reinauer278534d2008-10-29 04:51:07 +00001854 /* Pre-All to Activate Delay */
1855 temp_drt |= (0 << 16);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001856
Stefan Reinauer278534d2008-10-29 04:51:07 +00001857 /* Precharge to Precharge Delay stays at 1 clock */
1858 temp_drt |= (0 << 18);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001859
Stefan Reinauer278534d2008-10-29 04:51:07 +00001860 /* Activate to Precharge Delay */
1861 temp_drt |= (sysinfo->tras << 19);
1862
1863 /* Read to Precharge (tRTP) */
1864 if (sysinfo->memory_frequency == 667) {
1865 temp_drt |= (1 << 28);
1866 } else {
1867 temp_drt |= (0 << 28);
1868 }
1869
1870 /* Determine page size */
1871 reg32 = 0;
1872 page_size = 1; /* Default: 1k pagesize */
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001873 for (i = 0; i< 2*DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001874 if (sysinfo->dimm[i] == SYSINFO_DIMM_X16DS ||
1875 sysinfo->dimm[i] == SYSINFO_DIMM_X16SS)
1876 page_size = 2; /* 2k pagesize */
1877 }
1878
1879 if (sysinfo->memory_frequency == 533 && page_size == 2) {
1880 reg32 = 1;
1881 }
1882 if (sysinfo->memory_frequency == 667) {
1883 reg32 = page_size;
1884 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001885
Stefan Reinauer278534d2008-10-29 04:51:07 +00001886 temp_drt |= (reg32 << 30);
1887
1888 MCHBAR32(C0DRT1) = temp_drt;
1889 MCHBAR32(C1DRT1) = temp_drt;
1890
1891 /* Program DRT2 */
1892 reg32 = MCHBAR32(C0DRT2);
1893 reg32 &= ~(1 << 8);
1894 MCHBAR32(C0DRT2) = reg32;
1895
1896 reg32 = MCHBAR32(C1DRT2);
1897 reg32 &= ~(1 << 8);
1898 MCHBAR32(C1DRT2) = reg32;
1899
1900 /* Calculate DRT3 */
1901 temp_drt = MCHBAR32(C0DRT3) & ~0x07ffffff;
1902
1903 /* Get old tRFC value */
1904 reg32 = MCHBAR32(C0DRT1) >> 10;
1905 reg32 &= 0x3f;
1906
1907 /* 788nS - tRFC */
1908 switch (sysinfo->memory_frequency) {
1909 case 400: /* 5nS */
1910 reg32 = ((78800 / 500) - reg32) & 0x1ff;
1911 reg32 |= (0x8c << 16) | (0x0c << 10); /* 1 us */
1912 break;
1913 case 533: /* 3.75nS */
1914 reg32 = ((78800 / 375) - reg32) & 0x1ff;
1915 reg32 |= (0xba << 16) | (0x10 << 10); /* 1 us */
1916 break;
1917 case 667: /* 3nS */
1918 reg32 = ((78800 / 300) - reg32) & 0x1ff;
1919 reg32 |= (0xe9 << 16) | (0x14 << 10); /* 1 us */
1920 break;
1921 }
1922
1923 temp_drt |= reg32;
1924
1925 MCHBAR32(C0DRT3) = temp_drt;
1926 MCHBAR32(C1DRT3) = temp_drt;
1927}
1928
1929static void sdram_set_channel_mode(struct sys_info *sysinfo)
1930{
1931 u32 reg32;
1932
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001933 printk(BIOS_DEBUG, "Setting mode of operation for memory channels...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001934
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001935 if (sdram_capabilities_interleave() &&
Stefan Reinauer278534d2008-10-29 04:51:07 +00001936 ( ( sysinfo->banksize[0] + sysinfo->banksize[1] +
1937 sysinfo->banksize[2] + sysinfo->banksize[3] ) ==
1938 ( sysinfo->banksize[4] + sysinfo->banksize[5] +
1939 sysinfo->banksize[6] + sysinfo->banksize[7] ) ) ) {
1940 /* Both channels equipped with DIMMs of the same size */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001941 sysinfo->interleaved = 1;
1942 } else {
1943 sysinfo->interleaved = 0;
1944 }
1945
1946 reg32 = MCHBAR32(DCC);
1947 reg32 &= ~(7 << 0);
1948
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001949 if (sysinfo->interleaved) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001950 /* Dual Channel Interleaved */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001951 printk(BIOS_DEBUG, "Dual Channel Interleaved.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001952 reg32 |= (1 << 1);
1953 } else if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED &&
1954 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
1955 /* Channel 1 only */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001956 printk(BIOS_DEBUG, "Single Channel 1 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001957 reg32 |= (1 << 2);
Elyes HAOUAS75da1fb2017-02-16 18:59:13 +01001958 } else if (sdram_capabilities_dual_channel() &&
1959 (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1960 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) {
Martin Roth128c1042016-11-18 09:29:03 -07001961 /* Dual Channel Asymmetric */
1962 printk(BIOS_DEBUG, "Dual Channel Asymmetric.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001963 reg32 |= (1 << 0);
1964 } else {
1965 /* All bits 0 means Single Channel 0 operation */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001966 printk(BIOS_DEBUG, "Single Channel 0 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001967 }
1968
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001969 /* Now disable channel XORing */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001970 reg32 |= (1 << 10);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001971
1972 MCHBAR32(DCC) = reg32;
1973
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001974 PRINTK_DEBUG("DCC = 0x%08x\n", MCHBAR32(DCC));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001975}
1976
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001977static void sdram_program_pll_settings(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001978{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001979 MCHBAR32(PLLMON) = 0x80800000;
1980
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001981 sysinfo->fsb_frequency = fsbclk();
Peter Stuge76d91432010-10-01 10:02:33 +00001982 if (sysinfo->fsb_frequency == 0xffff)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001983 die("Unsupported FSB speed");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001984
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001985 /* Program CPCTL according to FSB speed */
1986 /* Only write the lower byte */
1987 switch (sysinfo->fsb_frequency) {
1988 case 400: MCHBAR8(CPCTL) = 0x90; break; /* FSB400 */
1989 case 533: MCHBAR8(CPCTL) = 0x95; break; /* FSB533 */
1990 case 667: MCHBAR8(CPCTL) = 0x8d; break; /* FSB667 */
1991 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001992
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001993 MCHBAR16(CPCTL) &= ~(1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001994
Paul Menzel0ce5ebf2013-10-21 21:22:09 +02001995 MCHBAR16(CPCTL); /* Read back register to activate settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001996}
1997
1998static void sdram_program_graphics_frequency(struct sys_info *sysinfo)
1999{
2000 u8 reg8;
2001 u16 reg16;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002002 u8 freq, second_vco, voltage;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002003
2004#define CRCLK_166MHz 0x00
2005#define CRCLK_200MHz 0x01
2006#define CRCLK_250MHz 0x03
2007#define CRCLK_400MHz 0x05
2008
2009#define CDCLK_200MHz 0x00
2010#define CDCLK_320MHz 0x40
2011
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002012#define VOLTAGE_1_05 0x00
2013#define VOLTAGE_1_50 0x01
2014
Paul Menzeldaf9e502014-07-15 23:49:16 +02002015 printk(BIOS_DEBUG, "Setting Graphics Frequency...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002016
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002017 printk(BIOS_DEBUG, "FSB: %d MHz ", sysinfo->fsb_frequency);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002018
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002019 voltage = VOLTAGE_1_05;
2020 if (MCHBAR32(DFT_STRAP1) & (1 << 20))
2021 voltage = VOLTAGE_1_50;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002022 printk(BIOS_DEBUG, "Voltage: %s ", (voltage == VOLTAGE_1_05)?"1.05V":"1.5V");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002023
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002024 /* Gate graphics hardware for frequency change */
2025 reg8 = pci_read_config16(PCI_DEV(0,2,0), GCFC + 1);
2026 reg8 = (1<<3) | (1<<1); /* disable crclk, gate cdclk */
2027 pci_write_config8(PCI_DEV(0,2,0), GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002028
2029 /* Get graphics frequency capabilities */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002030 reg8 = sdram_capabilities_core_frequencies();
2031
Stefan Reinauer278534d2008-10-29 04:51:07 +00002032 freq = CRCLK_250MHz;
2033 switch (reg8) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002034 case GFX_FREQUENCY_CAP_ALL:
2035 if (voltage == VOLTAGE_1_05)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002036 freq = CRCLK_250MHz;
2037 else
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002038 freq = CRCLK_400MHz; /* 1.5V requires 400MHz */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002039 break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002040 case GFX_FREQUENCY_CAP_250MHZ: freq = CRCLK_250MHz; break;
2041 case GFX_FREQUENCY_CAP_200MHZ: freq = CRCLK_200MHz; break;
2042 case GFX_FREQUENCY_CAP_166MHZ: freq = CRCLK_166MHz; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002043 }
2044
2045 if (freq != CRCLK_400MHz) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002046 /* What chipset are we? Force 166MHz for GMS */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002047 reg8 = (pci_read_config8(PCI_DEV(0, 0x00,0), 0xe7) & 0x70) >> 4;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002048 if (reg8 == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002049 freq = CRCLK_166MHz;
2050 }
2051
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002052 printk(BIOS_DEBUG, "Render: ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002053 switch (freq) {
Elyes HAOUAS0f92f632014-07-27 19:37:31 +02002054 case CRCLK_166MHz: printk(BIOS_DEBUG, "166MHz"); break;
2055 case CRCLK_200MHz: printk(BIOS_DEBUG, "200MHz"); break;
2056 case CRCLK_250MHz: printk(BIOS_DEBUG, "250MHz"); break;
2057 case CRCLK_400MHz: printk(BIOS_DEBUG, "400MHz"); break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002058 }
2059
Stefan Reinauer278534d2008-10-29 04:51:07 +00002060 if (i945_silicon_revision() == 0) {
2061 sysinfo->mvco4x = 1;
2062 } else {
2063 sysinfo->mvco4x = 0;
2064 }
2065
Stefan Reinauer278534d2008-10-29 04:51:07 +00002066 second_vco = 0;
2067
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002068 if (voltage == VOLTAGE_1_50) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002069 second_vco = 1;
2070 } else if ((i945_silicon_revision() > 0) && (freq == CRCLK_250MHz)) {
2071 u16 mem = sysinfo->memory_frequency;
2072 u16 fsb = sysinfo->fsb_frequency;
2073
2074 if ( (fsb == 667 && mem == 533) ||
2075 (fsb == 533 && mem == 533) ||
2076 (fsb == 533 && mem == 400)) {
2077 second_vco = 1;
2078 }
2079
2080 if (fsb == 667 && mem == 533)
2081 sysinfo->mvco4x = 1;
2082 }
2083
2084 if (second_vco) {
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002085 sysinfo->clkcfg_bit7 = 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002086 } else {
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002087 sysinfo->clkcfg_bit7 = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002088 }
2089
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002090 /* Graphics Core Render Clock */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002091 reg16 = pci_read_config16(PCI_DEV(0,2,0), GCFC);
2092 reg16 &= ~( (7 << 0) | (1 << 13) );
2093 reg16 |= freq;
2094 pci_write_config16(PCI_DEV(0,2,0), GCFC, reg16);
2095
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002096 /* Graphics Core Display Clock */
2097 reg8 = pci_read_config8(PCI_DEV(0,2,0), GCFC);
2098 reg8 &= ~( (1<<7) | (7<<4) );
2099
2100 if (voltage == VOLTAGE_1_05) {
2101 reg8 |= CDCLK_200MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002102 printk(BIOS_DEBUG, " Display: 200MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002103 } else {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002104 reg8 |= CDCLK_320MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002105 printk(BIOS_DEBUG, " Display: 320MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002106 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002107 pci_write_config8(PCI_DEV(0,2,0), GCFC, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002108
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002109 reg8 = pci_read_config8(PCI_DEV(0,2,0), GCFC + 1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002110
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002111 reg8 |= (1<<3) | (1<<1);
2112 pci_write_config8(PCI_DEV(0,2,0), GCFC + 1, reg8);
2113
2114 reg8 |= 0x0f;
2115 pci_write_config8(PCI_DEV(0,2,0), GCFC + 1, reg8);
2116
2117 /* Ungate core render and display clocks */
2118 reg8 &= 0xf0;
2119 pci_write_config8(PCI_DEV(0,2,0), GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002120}
2121
2122static void sdram_program_memory_frequency(struct sys_info *sysinfo)
2123{
2124 u32 clkcfg;
2125 u8 reg8;
Arthur Heymans626f8c82016-10-08 21:37:13 +02002126 u8 offset = IS_ENABLED(CONFIG_NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002127
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002128 printk(BIOS_DEBUG, "Setting Memory Frequency... ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002129
Stefan Reinauer278534d2008-10-29 04:51:07 +00002130 clkcfg = MCHBAR32(CLKCFG);
2131
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002132 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002133
2134 clkcfg &= ~( (1 << 12) | (1 << 7) | ( 7 << 4) );
2135
2136 if (sysinfo->mvco4x) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002137 printk(BIOS_DEBUG, "MVCO 4x, ");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002138 clkcfg &= ~(1 << 12);
2139 }
2140
2141 if (sysinfo->clkcfg_bit7) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002142 printk(BIOS_DEBUG, "second VCO, ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002143
Stefan Reinauer278534d2008-10-29 04:51:07 +00002144 clkcfg |= (1 << 7);
2145 }
2146
2147 switch (sysinfo->memory_frequency) {
Arthur Heymans626f8c82016-10-08 21:37:13 +02002148 case 400: clkcfg |= ((1 + offset) << 4); break;
2149 case 533: clkcfg |= ((2 + offset) << 4); break;
2150 case 667: clkcfg |= ((3 + offset) << 4); break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002151 default: die("Target Memory Frequency Error");
2152 }
2153
2154 if (MCHBAR32(CLKCFG) == clkcfg) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002155 printk(BIOS_DEBUG, "ok (unchanged)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002156 return;
2157 }
2158
2159 MCHBAR32(CLKCFG) = clkcfg;
2160
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002161 /* Make sure the following code is in the
Stefan Reinauer278534d2008-10-29 04:51:07 +00002162 * cache before we execute it.
2163 */
2164 goto cache_code;
2165vco_update:
2166 reg8 = pci_read_config8(PCI_DEV(0,0x1f,0), 0xa2);
2167 reg8 &= ~(1 << 7);
2168 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa2, reg8);
2169
Stefan Reinauer278534d2008-10-29 04:51:07 +00002170 clkcfg &= ~(1 << 10);
2171 MCHBAR32(CLKCFG) = clkcfg;
2172 clkcfg |= (1 << 10);
2173 MCHBAR32(CLKCFG) = clkcfg;
2174
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002175 asm volatile (
Stefan Reinauer278534d2008-10-29 04:51:07 +00002176 " movl $0x100, %%ecx\n"
2177 "delay_update:\n"
2178 " nop\n"
2179 " nop\n"
2180 " nop\n"
2181 " nop\n"
2182 " loop delay_update\n"
2183 : /* No outputs */
2184 : /* No inputs */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002185 : "%ecx", "memory"
Stefan Reinauer278534d2008-10-29 04:51:07 +00002186 );
2187
Stefan Reinauer278534d2008-10-29 04:51:07 +00002188 clkcfg &= ~(1 << 10);
2189 MCHBAR32(CLKCFG) = clkcfg;
2190
2191 goto out;
2192cache_code:
2193 goto vco_update;
2194out:
2195
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002196 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", MCHBAR32(CLKCFG));
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002197 printk(BIOS_DEBUG, "ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002198}
2199
2200static void sdram_program_clock_crossing(void)
2201{
Stefan Reinauer278534d2008-10-29 04:51:07 +00002202 int idx = 0;
2203
2204 /**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002205 * We add the indices according to our clocks from CLKCFG.
Stefan Reinauer278534d2008-10-29 04:51:07 +00002206 */
Kyösti Mälkkieb5e28f2012-02-24 16:08:18 +02002207#if CONFIG_NORTHBRIDGE_INTEL_SUBTYPE_I945GM
Stefan Reinauer278534d2008-10-29 04:51:07 +00002208 static const u32 data_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002209 0x00100401, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07002210 0xffffffff, 0xffffffff, /* nonexistent */
2211 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002212
Stefan Reinauer278534d2008-10-29 04:51:07 +00002213 0x08040120, 0x00000000, /* DDR400 FSB533 */
2214 0x00100401, 0x00000000, /* DDR533 FSB533 */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002215 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002216
2217 0x04020120, 0x00000010, /* DDR400 FSB667 */
2218 0x10040280, 0x00000040, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002219 0x00100401, 0x00000000, /* DDR667 FSB667 */
2220
Martin Roth2ed0aa22016-01-05 20:58:58 -07002221 0xffffffff, 0xffffffff, /* nonexistent */
2222 0xffffffff, 0xffffffff, /* nonexistent */
2223 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002224
Martin Roth2ed0aa22016-01-05 20:58:58 -07002225 0xffffffff, 0xffffffff, /* nonexistent */
2226 0xffffffff, 0xffffffff, /* nonexistent */
2227 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002228 };
2229
2230 static const u32 command_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002231 0x04020208, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07002232 0xffffffff, 0xffffffff, /* nonexistent */
2233 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002234
Stefan Reinauer278534d2008-10-29 04:51:07 +00002235 0x00060108, 0x00000000, /* DDR400 FSB533 */
2236 0x04020108, 0x00000000, /* DDR533 FSB533 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07002237 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002238
2239 0x00040318, 0x00000000, /* DDR400 FSB667 */
2240 0x04020118, 0x00000000, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002241 0x02010804, 0x00000000, /* DDR667 FSB667 */
2242
Martin Roth2ed0aa22016-01-05 20:58:58 -07002243 0xffffffff, 0xffffffff, /* nonexistent */
2244 0xffffffff, 0xffffffff, /* nonexistent */
2245 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002246
Martin Roth2ed0aa22016-01-05 20:58:58 -07002247 0xffffffff, 0xffffffff, /* nonexistent */
2248 0xffffffff, 0xffffffff, /* nonexistent */
2249 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002250 };
2251
Kyösti Mälkkieb5e28f2012-02-24 16:08:18 +02002252#elif CONFIG_NORTHBRIDGE_INTEL_SUBTYPE_I945GC
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002253 /* i945 G/P */
2254 static const u32 data_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07002255 0xffffffff, 0xffffffff, /* nonexistent */
2256 0xffffffff, 0xffffffff, /* nonexistent */
2257 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002258
2259 0x10080201, 0x00000000, /* DDR400 FSB533 */
2260 0x00100401, 0x00000000, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00002261 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002262
Martin Roth2ed0aa22016-01-05 20:58:58 -07002263 0xffffffff, 0xffffffff, /* nonexistent */
2264 0xffffffff, 0xffffffff, /* nonexistent */
2265 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002266
2267 0x04020108, 0x00000000, /* DDR400 FSB800 */
2268 0x00020108, 0x00000000, /* DDR533 FSB800 */
2269 0x00080201, 0x00000000, /* DDR667 FSB800 */
2270
2271 0x00010402, 0x00000000, /* DDR400 FSB1066 */
2272 0x04020108, 0x00000000, /* DDR533 FSB1066 */
2273 0x08040110, 0x00000000, /* DDR667 FSB1066 */
2274 };
2275
2276 static const u32 command_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07002277 0xffffffff, 0xffffffff, /* nonexistent */
2278 0xffffffff, 0xffffffff, /* nonexistent */
2279 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002280
2281 0x00010800, 0x00000402, /* DDR400 FSB533 */
2282 0x01000400, 0x00000200, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00002283 0x00020904, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002284
Martin Roth2ed0aa22016-01-05 20:58:58 -07002285 0xffffffff, 0xffffffff, /* nonexistent */
2286 0xffffffff, 0xffffffff, /* nonexistent */
2287 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002288
2289 0x02010804, 0x00000000, /* DDR400 FSB800 */
2290 0x00010402, 0x00000000, /* DDR533 FSB800 */
Arthur Heymans8b6df622016-10-16 10:58:01 +02002291 0x04020130, 0x00000008, /* DDR667 FSB800 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002292
2293 0x00020904, 0x00000000, /* DDR400 FSB1066 */
2294 0x02010804, 0x00000000, /* DDR533 FSB1066 */
2295 0x180601c0, 0x00000020, /* DDR667 FSB1066 */
2296 };
2297#endif
2298
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002299 printk(BIOS_DEBUG, "Programming Clock Crossing...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002300
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002301 printk(BIOS_DEBUG, "MEM=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002302 switch (memclk()) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002303 case 400: printk(BIOS_DEBUG, "400"); idx += 0; break;
2304 case 533: printk(BIOS_DEBUG, "533"); idx += 2; break;
2305 case 667: printk(BIOS_DEBUG, "667"); idx += 4; break;
2306 default: printk(BIOS_DEBUG, "RSVD %x", memclk()); return;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002307 }
2308
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002309 printk(BIOS_DEBUG, " FSB=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002310 switch (fsbclk()) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002311 case 400: printk(BIOS_DEBUG, "400"); idx += 0; break;
2312 case 533: printk(BIOS_DEBUG, "533"); idx += 6; break;
2313 case 667: printk(BIOS_DEBUG, "667"); idx += 12; break;
2314 case 800: printk(BIOS_DEBUG, "800"); idx += 18; break;
2315 case 1066: printk(BIOS_DEBUG, "1066"); idx += 24; break;
2316 default: printk(BIOS_DEBUG, "RSVD %x\n", fsbclk()); return;
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002317 }
2318
2319 if (command_clock_crossing[idx]==0xffffffff) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002320 printk(BIOS_DEBUG, "Invalid MEM/FSB combination!\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002321 }
2322
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002323 MCHBAR32(CCCFT + 0) = command_clock_crossing[idx];
2324 MCHBAR32(CCCFT + 4) = command_clock_crossing[idx + 1];
2325
Stefan Reinauer278534d2008-10-29 04:51:07 +00002326 MCHBAR32(C0DCCFT + 0) = data_clock_crossing[idx];
2327 MCHBAR32(C0DCCFT + 4) = data_clock_crossing[idx + 1];
2328 MCHBAR32(C1DCCFT + 0) = data_clock_crossing[idx];
2329 MCHBAR32(C1DCCFT + 4) = data_clock_crossing[idx + 1];
2330
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002331 printk(BIOS_DEBUG, "... ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002332}
2333
2334static void sdram_disable_fast_dispatch(void)
2335{
2336 u32 reg32;
2337
2338 reg32 = MCHBAR32(FSBPMC3);
2339 reg32 |= (1 << 1);
2340 MCHBAR32(FSBPMC3) = reg32;
2341
2342 reg32 = MCHBAR32(SBTEST);
2343 reg32 |= (3 << 1);
2344 MCHBAR32(SBTEST) = reg32;
2345}
2346
2347static void sdram_pre_jedec_initialization(void)
2348{
2349 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002350
Stefan Reinauer278534d2008-10-29 04:51:07 +00002351 reg32 = MCHBAR32(WCC);
2352 reg32 &= 0x113ff3ff;
2353 reg32 |= (4 << 29) | (3 << 25) | (1 << 10);
2354 MCHBAR32(WCC) = reg32;
2355
2356 MCHBAR32(SMVREFC) |= (1 << 6);
2357
2358 MCHBAR32(MMARB0) &= ~(3 << 17);
2359 MCHBAR32(MMARB0) |= (1 << 21) | (1 << 16);
2360
2361 MCHBAR32(MMARB1) &= ~(7 << 8);
2362 MCHBAR32(MMARB1) |= (3 << 8);
2363
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002364 /* Adaptive Idle Timer Control */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002365 MCHBAR32(C0AIT) = 0x000006c4;
2366 MCHBAR32(C0AIT+4) = 0x871a066d;
2367
2368 MCHBAR32(C1AIT) = 0x000006c4;
2369 MCHBAR32(C1AIT+4) = 0x871a066d;
2370}
2371
2372#define EA_DUALCHANNEL_XOR_BANK_RANK_MODE (0xd4 << 24)
2373#define EA_DUALCHANNEL_XOR_BANK_MODE (0xf4 << 24)
2374#define EA_DUALCHANNEL_BANK_RANK_MODE (0xc2 << 24)
2375#define EA_DUALCHANNEL_BANK_MODE (0xe2 << 24)
2376#define EA_SINGLECHANNEL_XOR_BANK_RANK_MODE (0x91 << 24)
2377#define EA_SINGLECHANNEL_XOR_BANK_MODE (0xb1 << 24)
2378#define EA_SINGLECHANNEL_BANK_RANK_MODE (0x80 << 24)
2379#define EA_SINGLECHANNEL_BANK_MODE (0xa0 << 24)
2380
2381static void sdram_enhanced_addressing_mode(struct sys_info *sysinfo)
2382{
2383 u32 chan0 = 0, chan1 = 0;
2384 int chan0_dualsided, chan1_dualsided, chan0_populated, chan1_populated;
2385
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002386 chan0_populated = (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Stefan Reinauer278534d2008-10-29 04:51:07 +00002387 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002388 chan1_populated = (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Stefan Reinauer278534d2008-10-29 04:51:07 +00002389 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED);
2390 chan0_dualsided = (sysinfo->banksize[1] || sysinfo->banksize[3]);
2391 chan1_dualsided = (sysinfo->banksize[5] || sysinfo->banksize[7]);
2392
2393 if (sdram_capabilities_enhanced_addressing_xor()) {
2394 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002395 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002396 if (chan0_populated) {
2397 if (chan0_dualsided) {
2398 chan0 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
2399 } else {
2400 chan0 = EA_SINGLECHANNEL_XOR_BANK_MODE;
2401 }
2402 }
2403 if (chan1_populated) {
2404 if (chan1_dualsided) {
2405 chan1 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
2406 } else {
2407 chan1 = EA_SINGLECHANNEL_XOR_BANK_MODE;
2408 }
2409 }
2410 } else {
2411 /* Interleaved has always both channels populated */
2412 if (chan0_dualsided) {
2413 chan0 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
2414 } else {
2415 chan0 = EA_DUALCHANNEL_XOR_BANK_MODE;
2416 }
2417
2418 if (chan1_dualsided) {
2419 chan1 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
2420 } else {
2421 chan1 = EA_DUALCHANNEL_XOR_BANK_MODE;
2422 }
2423 }
2424 } else {
2425 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002426 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002427 if (chan0_populated) {
2428 if (chan0_dualsided) {
2429 chan0 = EA_SINGLECHANNEL_BANK_RANK_MODE;
2430 } else {
2431 chan0 = EA_SINGLECHANNEL_BANK_MODE;
2432 }
2433 }
2434 if (chan1_populated) {
2435 if (chan1_dualsided) {
2436 chan1 = EA_SINGLECHANNEL_BANK_RANK_MODE;
2437 } else {
2438 chan1 = EA_SINGLECHANNEL_BANK_MODE;
2439 }
2440 }
2441 } else {
2442 /* Interleaved has always both channels populated */
2443 if (chan0_dualsided) {
2444 chan0 = EA_DUALCHANNEL_BANK_RANK_MODE;
2445 } else {
2446 chan0 = EA_DUALCHANNEL_BANK_MODE;
2447 }
2448
2449 if (chan1_dualsided) {
2450 chan1 = EA_DUALCHANNEL_BANK_RANK_MODE;
2451 } else {
2452 chan1 = EA_DUALCHANNEL_BANK_MODE;
2453 }
2454 }
2455 }
2456
2457 MCHBAR32(C0DRC1) &= 0x00ffffff;
2458 MCHBAR32(C0DRC1) |= chan0;
2459 MCHBAR32(C1DRC1) &= 0x00ffffff;
2460 MCHBAR32(C1DRC1) |= chan1;
2461}
2462
2463static void sdram_post_jedec_initialization(struct sys_info *sysinfo)
2464{
2465 u32 reg32;
2466
2467 /* Enable Channel XORing for Dual Channel Interleave */
2468 if (sysinfo->interleaved) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002469
Stefan Reinauer278534d2008-10-29 04:51:07 +00002470 reg32 = MCHBAR32(DCC);
Patrick Georgi77d66832010-10-01 08:02:45 +00002471#if CONFIG_CHANNEL_XOR_RANDOMIZATION
Stefan Reinauer278534d2008-10-29 04:51:07 +00002472 reg32 &= ~(1 << 10);
Stefan Reinauer30140a52009-03-11 16:20:39 +00002473 reg32 |= (1 << 9);
2474#else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002475 reg32 &= ~(1 << 9);
Stefan Reinauer30140a52009-03-11 16:20:39 +00002476#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002477 MCHBAR32(DCC) = reg32;
2478 }
2479
2480 /* DRAM mode optimizations */
2481 sdram_enhanced_addressing_mode(sysinfo);
2482
2483 reg32 = MCHBAR32(FSBPMC3);
2484 reg32 &= ~(1 << 1);
2485 MCHBAR32(FSBPMC3) = reg32;
2486
2487 reg32 = MCHBAR32(SBTEST);
2488 reg32 &= ~(1 << 2);
2489 MCHBAR32(SBTEST) = reg32;
2490
2491 reg32 = MCHBAR32(SBOCC);
2492 reg32 &= 0xffbdb6ff;
2493 reg32 |= (0xbdb6 << 8) | (1 << 0);
2494 MCHBAR32(SBOCC) = reg32;
2495}
2496
2497static void sdram_power_management(struct sys_info *sysinfo)
2498{
2499 u8 reg8;
2500 u16 reg16;
2501 u32 reg32;
2502 int integrated_graphics = 1;
2503 int i;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002504
Stefan Reinauer278534d2008-10-29 04:51:07 +00002505 reg32 = MCHBAR32(C0DRT2);
2506 reg32 &= 0xffffff00;
2507 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002508 reg32 |= (1 << 5) | (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002509 MCHBAR32(C0DRT2) = reg32;
2510
2511 reg32 = MCHBAR32(C1DRT2);
2512 reg32 &= 0xffffff00;
2513 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002514 reg32 |= (1 << 5) | (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002515 MCHBAR32(C1DRT2) = reg32;
2516
2517 reg32 = MCHBAR32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002518
2519 reg32 |= (1 << 12) | (1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002520 MCHBAR32(C0DRC1) = reg32;
2521
2522 reg32 = MCHBAR32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002523
2524 reg32 |= (1 << 12) | (1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002525 MCHBAR32(C1DRC1) = reg32;
2526
2527 if (i945_silicon_revision()>1) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002528 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2529 u16 peg_bits = (1 << 5) | (1 << 0);
2530
2531 MCHBAR16(UPMC1) = 0x1010 | peg_bits;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002532 } else {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002533 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2534 u16 peg_bits = (1 << 5) | (1 << 0);
2535
Stefan Reinauer278534d2008-10-29 04:51:07 +00002536 /* Rev 0 and 1 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002537 MCHBAR16(UPMC1) = 0x0010 | peg_bits;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002538 }
2539
2540 reg16 = MCHBAR16(UPMC2);
2541 reg16 &= 0xfc00;
2542 reg16 |= 0x0100;
2543 MCHBAR16(UPMC2) = reg16;
2544
2545 MCHBAR32(UPMC3) = 0x000f06ff;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002546
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002547 for (i = 0; i < 5; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002548 MCHBAR32(UPMC3) &= ~(1 << 16);
2549 MCHBAR32(UPMC3) |= (1 << 16);
2550 }
2551
2552 MCHBAR32(GIPMC1) = 0x8000000c;
2553
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002554 reg16 = MCHBAR16(CPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002555 reg16 &= ~(7 << 11);
2556 if (i945_silicon_revision()>2) {
2557 reg16 |= (6 << 11);
2558 } else {
2559 reg16 |= (4 << 11);
2560 }
2561 MCHBAR16(CPCTL) = reg16;
2562
Stefan Reinauer30140a52009-03-11 16:20:39 +00002563#if 0
Stefan Reinauer278534d2008-10-29 04:51:07 +00002564 if ((MCHBAR32(ECO) & (1 << 16)) != 0) {
Stefan Reinauer30140a52009-03-11 16:20:39 +00002565#else
2566 if (i945_silicon_revision() != 0) {
2567#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002568 switch (sysinfo->fsb_frequency) {
2569 case 667: MCHBAR32(HGIPMC2) = 0x0d590d59; break;
2570 case 533: MCHBAR32(HGIPMC2) = 0x155b155b; break;
2571 }
2572 } else {
2573 switch (sysinfo->fsb_frequency) {
2574 case 667: MCHBAR32(HGIPMC2) = 0x09c409c4; break;
2575 case 533: MCHBAR32(HGIPMC2) = 0x0fa00fa0; break;
2576 }
2577 }
2578
2579 MCHBAR32(FSBPMC1) = 0x8000000c;
2580
2581 reg32 = MCHBAR32(C2C3TT);
2582 reg32 &= 0xffff0000;
2583 switch (sysinfo->fsb_frequency) {
2584 case 667: reg32 |= 0x0600; break;
2585 case 533: reg32 |= 0x0480; break;
2586 }
2587 MCHBAR32(C2C3TT) = reg32;
2588
2589 reg32 = MCHBAR32(C3C4TT);
2590 reg32 &= 0xffff0000;
2591 switch (sysinfo->fsb_frequency) {
2592 case 667: reg32 |= 0x0b80; break;
2593 case 533: reg32 |= 0x0980; break;
2594 }
2595 MCHBAR32(C3C4TT) = reg32;
2596
2597 if (i945_silicon_revision() == 0) {
2598 MCHBAR32(ECO) &= ~(1 << 16);
2599 } else {
2600 MCHBAR32(ECO) |= (1 << 16);
2601 }
2602
2603#if 0
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002604
Stefan Reinauer278534d2008-10-29 04:51:07 +00002605 if (i945_silicon_revision() == 0) {
2606 MCHBAR32(FSBPMC3) &= ~(1 << 29);
2607 } else {
2608 MCHBAR32(FSBPMC3) |= (1 << 29);
2609 }
2610#endif
2611 MCHBAR32(FSBPMC3) &= ~(1 << 29);
2612
2613 MCHBAR32(FSBPMC3) |= (1 << 21);
2614
2615 MCHBAR32(FSBPMC3) &= ~(1 << 19);
2616
2617 MCHBAR32(FSBPMC3) &= ~(1 << 13);
2618
2619 reg32 = MCHBAR32(FSBPMC4);
2620 reg32 &= ~(3 << 24);
2621 reg32 |= ( 2 << 24);
2622 MCHBAR32(FSBPMC4) = reg32;
2623
2624 MCHBAR32(FSBPMC4) |= (1 << 21);
2625
2626 MCHBAR32(FSBPMC4) |= (1 << 5);
2627
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002628 if ((i945_silicon_revision() < 2) /* || cpuid() = 0x6e8 */ ) {
2629 /* stepping 0 and 1 or CPUID 6e8 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002630 MCHBAR32(FSBPMC4) &= ~(1 << 4);
2631 } else {
Stefan Reinauer30140a52009-03-11 16:20:39 +00002632 MCHBAR32(FSBPMC4) |= (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002633 }
2634
2635 reg8 = pci_read_config8(PCI_DEV(0,0x0,0), 0xfc);
2636 reg8 |= (1 << 4);
2637 pci_write_config8(PCI_DEV(0, 0x0, 0), 0xfc, reg8);
2638
2639 reg8 = pci_read_config8(PCI_DEV(0,0x2,0), 0xc1);
2640 reg8 |= (1 << 2);
2641 pci_write_config8(PCI_DEV(0, 0x2, 0), 0xc1, reg8);
2642
Stefan Reinauerde3206a2010-02-22 06:09:43 +00002643#ifdef C2_SELF_REFRESH_DISABLE
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002644
Stefan Reinauer278534d2008-10-29 04:51:07 +00002645 if (integrated_graphics) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002646 printk(BIOS_DEBUG, "C2 self-refresh with IGD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002647 MCHBAR16(MIPMC4) = 0x0468;
2648 MCHBAR16(MIPMC5) = 0x046c;
2649 MCHBAR16(MIPMC6) = 0x046c;
2650 } else {
2651 MCHBAR16(MIPMC4) = 0x6468;
2652 MCHBAR16(MIPMC5) = 0x646c;
2653 MCHBAR16(MIPMC6) = 0x646c;
2654 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002655#else
2656 if (integrated_graphics) {
2657 MCHBAR16(MIPMC4) = 0x04f8;
2658 MCHBAR16(MIPMC5) = 0x04fc;
2659 MCHBAR16(MIPMC6) = 0x04fc;
2660 } else {
2661 MCHBAR16(MIPMC4) = 0x64f8;
2662 MCHBAR16(MIPMC5) = 0x64fc;
2663 MCHBAR16(MIPMC6) = 0x64fc;
2664 }
2665
2666#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002667
2668 reg32 = MCHBAR32(PMCFG);
2669 reg32 &= ~(3 << 17);
2670 reg32 |= (2 << 17);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002671 MCHBAR32(PMCFG) = reg32;
2672
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002673 MCHBAR32(PMCFG) |= (1 << 4);
2674
Stefan Reinauer278534d2008-10-29 04:51:07 +00002675 reg32 = MCHBAR32(0xc30);
2676 reg32 &= 0xffffff00;
2677 reg32 |= 0x01;
2678 MCHBAR32(0xc30) = reg32;
2679
2680 MCHBAR32(0xb18) &= ~(1 << 21);
2681}
2682
2683static void sdram_thermal_management(void)
2684{
Stefan Reinauer278534d2008-10-29 04:51:07 +00002685
Stefan Reinauer278534d2008-10-29 04:51:07 +00002686 MCHBAR8(TCO1) = 0x00;
2687 MCHBAR8(TCO0) = 0x00;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002688
2689 /* The Thermal Sensors for DIMMs at 0x50, 0x52 are at I2C addr
2690 * 0x30/0x32.
2691 */
2692
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002693 /* TODO This is not implemented yet. Volunteers? */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002694}
2695
2696static void sdram_save_receive_enable(void)
2697{
2698 int i;
2699 u32 reg32;
2700 u8 values[4];
2701
2702 /* The following values are stored to an unused CMOS
2703 * area and restored instead of recalculated in case
2704 * of an S3 resume.
2705 *
2706 * C0WL0REOST [7:0] -> 8 bit
2707 * C1WL0REOST [7:0] -> 8 bit
2708 * RCVENMT [11:8] [3:0] -> 8 bit
2709 * C0DRT1 [27:24] -> 4 bit
2710 * C1DRT1 [27:24] -> 4 bit
2711 */
2712
2713 values[0] = MCHBAR8(C0WL0REOST);
2714 values[1] = MCHBAR8(C1WL0REOST);
2715
2716 reg32 = MCHBAR32(RCVENMT);
2717 values[2] = (u8)((reg32 >> (8 - 4)) & 0xf0) | (reg32 & 0x0f);
2718
2719 reg32 = MCHBAR32(C0DRT1);
2720 values[3] = (reg32 >> 24) & 0x0f;
2721 reg32 = MCHBAR32(C1DRT1);
2722 values[3] |= (reg32 >> (24 - 4)) & 0xf0;
2723
2724 /* coreboot only uses bytes 0 - 127 for its CMOS values so far
Edwin Beasanteb50c7d2010-07-06 21:05:04 +00002725 * so we grab bytes 128 - 131 to save the receive enable values
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002726 */
2727
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002728 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002729 cmos_write(values[i], 128 + i);
2730}
2731
2732static void sdram_recover_receive_enable(void)
2733{
2734 int i;
2735 u32 reg32;
2736 u8 values[4];
2737
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002738 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002739 values[i] = cmos_read(128 + i);
2740
2741 MCHBAR8(C0WL0REOST) = values[0];
2742 MCHBAR8(C1WL0REOST) = values[1];
2743
2744 reg32 = MCHBAR32(RCVENMT);
2745 reg32 &= ~((0x0f << 8) | (0x0f << 0));
2746 reg32 |= ((u32)(values[2] & 0xf0) << (8 - 4)) | (values[2] & 0x0f);
2747 MCHBAR32(RCVENMT) = reg32;
2748
2749 reg32 = MCHBAR32(C0DRT1) & ~(0x0f << 24);
2750 reg32 |= (u32)(values[3] & 0x0f) << 24;
2751 MCHBAR32(C0DRT1) = reg32;
2752
2753 reg32 = MCHBAR32(C1DRT1) & ~(0x0f << 24);
2754 reg32 |= (u32)(values[3] & 0xf0) << (24 - 4);
2755 MCHBAR32(C1DRT1) = reg32;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002756}
2757
Stefan Reinauer278534d2008-10-29 04:51:07 +00002758static void sdram_program_receive_enable(struct sys_info *sysinfo)
2759{
2760 MCHBAR32(REPC) |= (1 << 0);
2761
Stefan Reinaueraca6ec62009-10-26 17:12:21 +00002762 /* enable upper CMOS */
2763 RCBA32(0x3400) = (1 << 2);
2764
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002765 /* Program Receive Enable Timings */
2766 if (sysinfo->boot_path == BOOT_PATH_RESUME) {
2767 sdram_recover_receive_enable();
2768 } else {
2769 receive_enable_adjust(sysinfo);
2770 sdram_save_receive_enable();
2771 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002772
2773 MCHBAR32(C0DRC1) |= (1 << 6);
2774 MCHBAR32(C1DRC1) |= (1 << 6);
2775 MCHBAR32(C0DRC1) &= ~(1 << 6);
2776 MCHBAR32(C1DRC1) &= ~(1 << 6);
2777
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002778 MCHBAR32(MIPMC3) |= (0x0f << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002779}
2780
2781/**
2782 * @brief Enable On-Die Termination for DDR2.
2783 *
2784 */
2785
2786static void sdram_on_die_termination(struct sys_info *sysinfo)
2787{
2788 static const u32 odt[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002789 0x00024911, 0xe0010000,
2790 0x00049211, 0xe0020000,
2791 0x0006db11, 0xe0030000,
Stefan Reinauer278534d2008-10-29 04:51:07 +00002792 };
2793
2794 u32 reg32;
2795 int cas;
2796
2797 reg32 = MCHBAR32(ODTC);
2798 reg32 &= ~(3 << 16);
2799 reg32 |= (1 << 14) | (1 << 6) | (2 << 16);
2800 MCHBAR32(ODTC) = reg32;
2801
2802 if ( !(sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED &&
2803 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) ) {
Elyes HAOUAS38424982016-08-21 12:01:04 +02002804 printk(BIOS_DEBUG, "one dimm per channel config..\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002805
Stefan Reinauer278534d2008-10-29 04:51:07 +00002806 reg32 = MCHBAR32(C0ODT);
2807 reg32 &= ~(7 << 28);
2808 MCHBAR32(C0ODT) = reg32;
2809 reg32 = MCHBAR32(C1ODT);
2810 reg32 &= ~(7 << 28);
2811 MCHBAR32(C1ODT) = reg32;
2812 }
2813
2814 cas = sysinfo->cas;
2815
2816 reg32 = MCHBAR32(C0ODT) & 0xfff00000;
2817 reg32 |= odt[(cas-3) * 2];
2818 MCHBAR32(C0ODT) = reg32;
2819
2820 reg32 = MCHBAR32(C1ODT) & 0xfff00000;
2821 reg32 |= odt[(cas-3) * 2];
2822 MCHBAR32(C1ODT) = reg32;
2823
2824 reg32 = MCHBAR32(C0ODT + 4) & 0x1fc8ffff;
2825 reg32 |= odt[((cas-3) * 2) + 1];
2826 MCHBAR32(C0ODT + 4) = reg32;
2827
2828 reg32 = MCHBAR32(C1ODT + 4) & 0x1fc8ffff;
2829 reg32 |= odt[((cas-3) * 2) + 1];
2830 MCHBAR32(C1ODT + 4) = reg32;
2831}
2832
2833/**
2834 * @brief Enable clocks to populated sockets
2835 */
2836
2837static void sdram_enable_memory_clocks(struct sys_info *sysinfo)
2838{
2839 u8 clocks[2] = { 0, 0 };
2840
Kyösti Mälkkieb5e28f2012-02-24 16:08:18 +02002841#if CONFIG_NORTHBRIDGE_INTEL_SUBTYPE_I945GM
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002842#define CLOCKS_WIDTH 2
Kyösti Mälkkieb5e28f2012-02-24 16:08:18 +02002843#elif CONFIG_NORTHBRIDGE_INTEL_SUBTYPE_I945GC
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002844#define CLOCKS_WIDTH 3
2845#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002846 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002847 clocks[0] |= (1 << CLOCKS_WIDTH)-1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002848
2849 if (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002850 clocks[0] |= ((1 << CLOCKS_WIDTH)-1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002851
2852 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002853 clocks[1] |= (1 << CLOCKS_WIDTH)-1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002854
2855 if (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002856 clocks[1] |= ((1 << CLOCKS_WIDTH)-1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002857
Patrick Georgi77d66832010-10-01 08:02:45 +00002858#if CONFIG_OVERRIDE_CLOCK_DISABLE
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002859 /* Usually system firmware turns off system memory clock signals
2860 * to unused SO-DIMM slots to reduce EMI and power consumption.
2861 * However, the Kontron 986LCD-M does not like unused clock
2862 * signals to be disabled.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002863 */
2864
2865 clocks[0] = 0xf; /* force all clock gate pairs to enable */
2866 clocks[1] = 0xf; /* force all clock gate pairs to enable */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002867#endif
2868
2869 MCHBAR8(C0DCLKDIS) = clocks[0];
2870 MCHBAR8(C1DCLKDIS) = clocks[1];
2871}
2872
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002873#define RTT_ODT_NONE 0
2874#define RTT_ODT_50_OHM ( (1 << 9) | (1 << 5) )
Stefan Reinauer278534d2008-10-29 04:51:07 +00002875#define RTT_ODT_75_OHM (1 << 5)
2876#define RTT_ODT_150_OHM (1 << 9)
2877
2878#define EMRS_OCD_DEFAULT ( (1 << 12) | (1 << 11) | (1 << 10) )
2879
2880#define MRS_CAS_3 (3 << 7)
2881#define MRS_CAS_4 (4 << 7)
2882#define MRS_CAS_5 (5 << 7)
2883
2884#define MRS_TWR_3 (2 << 12)
2885#define MRS_TWR_4 (3 << 12)
2886#define MRS_TWR_5 (4 << 12)
2887
2888#define MRS_BT (1 << 6)
2889
2890#define MRS_BL4 (2 << 3)
2891#define MRS_BL8 (3 << 3)
2892
2893static void sdram_jedec_enable(struct sys_info *sysinfo)
2894{
2895 int i, nonzero;
2896 u32 bankaddr = 0, tmpaddr, mrsaddr = 0;
2897
2898 for (i = 0, nonzero = -1; i < 8; i++) {
2899 if (sysinfo->banksize[i] == 0) {
2900 continue;
2901 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002902
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002903 printk(BIOS_DEBUG, "jedec enable sequence: bank %d\n", i);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002904 switch (i) {
2905 case 0:
2906 /* Start at address 0 */
2907 bankaddr = 0;
2908 break;
2909 case 4:
2910 if (sysinfo->interleaved) {
2911 bankaddr = 0x40;
2912 break;
2913 }
2914 default:
2915 if (nonzero != -1) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002916 printk(BIOS_DEBUG, "bankaddr from bank size of rank %d\n", nonzero);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002917 bankaddr += sysinfo->banksize[nonzero] <<
2918 (sysinfo->interleaved ? 26 : 25);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002919 break;
2920 }
2921 /* No populated bank hit before. Start at address 0 */
2922 bankaddr = 0;
2923 }
2924
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002925 /* We have a bank with a non-zero size.. Remember it
Stefan Reinauer278534d2008-10-29 04:51:07 +00002926 * for the next offset we have to calculate
2927 */
2928 nonzero = i;
2929
2930 /* Get CAS latency set up */
2931 switch (sysinfo->cas) {
2932 case 5: mrsaddr = MRS_CAS_5; break;
2933 case 4: mrsaddr = MRS_CAS_4; break;
2934 case 3: mrsaddr = MRS_CAS_3; break;
2935 default: die("Jedec Error (CAS).\n");
2936 }
2937
2938 /* Get tWR set */
2939 switch (sysinfo->twr) {
2940 case 5: mrsaddr |= MRS_TWR_5; break;
2941 case 4: mrsaddr |= MRS_TWR_4; break;
2942 case 3: mrsaddr |= MRS_TWR_3; break;
2943 default: die("Jedec Error (tWR).\n");
2944 }
2945
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002946 /* Set "Burst Type" */
2947 mrsaddr |= MRS_BT;
2948
Stefan Reinauer278534d2008-10-29 04:51:07 +00002949 /* Interleaved */
2950 if (sysinfo->interleaved) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002951 mrsaddr = mrsaddr << 1;
2952 }
2953
2954 /* Only burst length 8 supported */
2955 mrsaddr |= MRS_BL8;
2956
2957 /* Apply NOP */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002958 PRINTK_DEBUG("Apply NOP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002959 do_ram_command(RAM_COMMAND_NOP);
2960 ram_read32(bankaddr);
2961
2962 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002963 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002964 do_ram_command(RAM_COMMAND_PRECHARGE);
2965 ram_read32(bankaddr);
2966
2967 /* Extended Mode Register Set (2) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002968 PRINTK_DEBUG("Extended Mode Register Set(2)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002969 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_2);
2970 ram_read32(bankaddr);
2971
2972 /* Extended Mode Register Set (3) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002973 PRINTK_DEBUG("Extended Mode Register Set(3)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002974 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_3);
2975 ram_read32(bankaddr);
2976
2977 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002978 PRINTK_DEBUG("Extended Mode Register Set\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002979 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2980 tmpaddr = bankaddr;
2981 if (!sdram_capabilities_dual_channel()) {
2982 tmpaddr |= RTT_ODT_75_OHM;
2983 } else if (sysinfo->interleaved) {
2984 tmpaddr |= (RTT_ODT_150_OHM << 1);
2985 } else {
2986 tmpaddr |= RTT_ODT_150_OHM;
2987 }
2988 ram_read32(tmpaddr);
2989
2990 /* Mode Register Set: Reset DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002991 PRINTK_DEBUG("MRS: Reset DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002992 do_ram_command(RAM_COMMAND_MRS);
2993 tmpaddr = bankaddr;
2994 tmpaddr |= mrsaddr;
2995 /* Set DLL reset bit */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002996 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002997 tmpaddr |= (1 << 12);
2998 else
2999 tmpaddr |= (1 << 11);
3000 ram_read32(tmpaddr);
3001
3002 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00003003 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00003004 do_ram_command(RAM_COMMAND_PRECHARGE);
3005 ram_read32(bankaddr);
3006
3007 /* CAS before RAS Refresh */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00003008 PRINTK_DEBUG("CAS before RAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00003009 do_ram_command(RAM_COMMAND_CBR);
3010
3011 /* CBR wants two READs */
3012 ram_read32(bankaddr);
3013 ram_read32(bankaddr);
3014
3015 /* Mode Register Set: Enable DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00003016 PRINTK_DEBUG("MRS: Enable DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00003017 do_ram_command(RAM_COMMAND_MRS);
3018
3019 tmpaddr = bankaddr;
3020 tmpaddr |= mrsaddr;
3021 ram_read32(tmpaddr);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00003022
Stefan Reinauer278534d2008-10-29 04:51:07 +00003023 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00003024 PRINTK_DEBUG("Extended Mode Register Set: ODT/OCD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00003025 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00003026
Stefan Reinauer278534d2008-10-29 04:51:07 +00003027 tmpaddr = bankaddr;
3028 if (!sdram_capabilities_dual_channel()) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00003029
Stefan Reinauer278534d2008-10-29 04:51:07 +00003030 tmpaddr |= RTT_ODT_75_OHM | EMRS_OCD_DEFAULT;
3031 } else if (sysinfo->interleaved) {
3032 tmpaddr |= ((RTT_ODT_150_OHM | EMRS_OCD_DEFAULT) << 1);
3033 } else {
3034 tmpaddr |= RTT_ODT_150_OHM | EMRS_OCD_DEFAULT;
3035 }
3036 ram_read32(tmpaddr);
3037
3038 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00003039 PRINTK_DEBUG("Extended Mode Register Set: OCD Exit\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00003040 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
3041
3042 tmpaddr = bankaddr;
3043 if (!sdram_capabilities_dual_channel()) {
3044 tmpaddr |= RTT_ODT_75_OHM;
3045 } else if (sysinfo->interleaved) {
3046 tmpaddr |= (RTT_ODT_150_OHM << 1);
3047 } else {
3048 tmpaddr |= RTT_ODT_150_OHM;
3049 }
3050 ram_read32(tmpaddr);
3051 }
3052}
3053
3054static void sdram_init_complete(void)
3055{
Stefan Reinauer779b3e32008-11-10 15:43:37 +00003056 PRINTK_DEBUG("Normal Operation\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00003057 do_ram_command(RAM_COMMAND_NORMAL);
3058}
3059
3060static void sdram_setup_processor_side(void)
3061{
3062 if (i945_silicon_revision() == 0)
3063 MCHBAR32(FSBPMC3) |= (1 << 2);
3064
3065 MCHBAR8(0xb00) |= 1;
3066
3067 if (i945_silicon_revision() == 0)
3068 MCHBAR32(SLPCTL) |= (1 << 8);
3069}
3070
Stefan Reinauer278534d2008-10-29 04:51:07 +00003071/**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00003072 * @param boot_path: 0 = normal, 1 = reset, 2 = resume from s3
Martin Rothf4cb4122015-01-06 10:27:39 -07003073 * @param spd_addresses pointer to a list of SPD addresses
Stefan Reinauer278534d2008-10-29 04:51:07 +00003074 */
Sven Schnelle541269b2011-02-21 09:39:17 +00003075void sdram_initialize(int boot_path, const u8 *spd_addresses)
Stefan Reinauer278534d2008-10-29 04:51:07 +00003076{
3077 struct sys_info sysinfo;
3078 u8 reg8, cas_mask;
3079
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00003080 printk(BIOS_DEBUG, "Setting up RAM controller.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00003081
3082 memset(&sysinfo, 0, sizeof(sysinfo));
3083
Stefan Reinauer71a3d962009-07-21 21:44:24 +00003084 sysinfo.boot_path = boot_path;
Sven Schnelle541269b2011-02-21 09:39:17 +00003085 sysinfo.spd_addresses = spd_addresses;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00003086
Stefan Reinauer278534d2008-10-29 04:51:07 +00003087 /* Look at the type of DIMMs and verify all DIMMs are x8 or x16 width */
3088 sdram_get_dram_configuration(&sysinfo);
3089
Stefan Reinauerbf264e92010-05-14 19:09:20 +00003090 /* If error, do cold boot */
3091 sdram_detect_errors(&sysinfo);
3092
Stefan Reinauer278534d2008-10-29 04:51:07 +00003093 /* Check whether we have stacked DIMMs */
3094 sdram_verify_package_type(&sysinfo);
3095
3096 /* Determine common CAS */
3097 cas_mask = sdram_possible_cas_latencies(&sysinfo);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00003098
Stefan Reinauer278534d2008-10-29 04:51:07 +00003099 /* Choose Common Frequency */
3100 sdram_detect_cas_latency_and_ram_speed(&sysinfo, cas_mask);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00003101
Stefan Reinauer278534d2008-10-29 04:51:07 +00003102 /* Determine smallest common tRAS */
3103 sdram_detect_smallest_tRAS(&sysinfo);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00003104
Stefan Reinauer278534d2008-10-29 04:51:07 +00003105 /* Determine tRP */
3106 sdram_detect_smallest_tRP(&sysinfo);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00003107
Stefan Reinauer278534d2008-10-29 04:51:07 +00003108 /* Determine tRCD */
3109 sdram_detect_smallest_tRCD(&sysinfo);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00003110
Stefan Reinauer278534d2008-10-29 04:51:07 +00003111 /* Determine smallest refresh period */
3112 sdram_detect_smallest_refresh(&sysinfo);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00003113
Stefan Reinauer278534d2008-10-29 04:51:07 +00003114 /* Verify all DIMMs support burst length 8 */
3115 sdram_verify_burst_length(&sysinfo);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00003116
Stefan Reinauer278534d2008-10-29 04:51:07 +00003117 /* determine tWR */
3118 sdram_detect_smallest_tWR(&sysinfo);
3119
3120 /* Determine DIMM size parameters (rows, columns banks) */
3121 sdram_detect_dimm_size(&sysinfo);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00003122
Stefan Reinauer278534d2008-10-29 04:51:07 +00003123 /* determine tRFC */
3124 sdram_detect_smallest_tRFC(&sysinfo);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00003125
Stefan Reinauer278534d2008-10-29 04:51:07 +00003126 /* Program PLL settings */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00003127 sdram_program_pll_settings(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00003128
Arthur Heymans18537812016-12-28 21:20:45 +01003129 /*
3130 * Program Graphics Frequency
3131 * Set core display and render clock on 945GC to the max
3132 */
3133 if (IS_ENABLED(CONFIG_NORTHBRIDGE_INTEL_SUBTYPE_I945GM))
3134 sdram_program_graphics_frequency(&sysinfo);
3135 else
3136 pci_write_config16(PCI_DEV(0, 2, 0), GCFC, 0x0534);
Stefan Reinauer278534d2008-10-29 04:51:07 +00003137
3138 /* Program System Memory Frequency */
3139 sdram_program_memory_frequency(&sysinfo);
3140
3141 /* Determine Mode of Operation (Interleaved etc) */
3142 sdram_set_channel_mode(&sysinfo);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00003143
Stefan Reinauer278534d2008-10-29 04:51:07 +00003144 /* Program Clock Crossing values */
3145 sdram_program_clock_crossing();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00003146
Stefan Reinauer278534d2008-10-29 04:51:07 +00003147 /* Disable fast dispatch */
3148 sdram_disable_fast_dispatch();
3149
3150 /* Enable WIODLL Power Down in ACPI states */
3151 MCHBAR32(C0DMC) |= (1 << 24);
3152 MCHBAR32(C1DMC) |= (1 << 24);
3153
3154 /* Program DRAM Row Boundary/Attribute Registers */
3155
Stefan Reinauer71a3d962009-07-21 21:44:24 +00003156 /* program row size DRB and set TOLUD */
3157 sdram_program_row_boundaries(&sysinfo);
3158
3159 /* program page size DRA */
3160 sdram_set_row_attributes(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00003161
3162 /* Program CxBNKARC */
3163 sdram_set_bank_architecture(&sysinfo);
3164
3165 /* Program DRAM Timing and Control registers based on SPD */
3166 sdram_set_timing_and_control(&sysinfo);
3167
3168 /* On-Die Termination Adjustment */
3169 sdram_on_die_termination(&sysinfo);
3170
3171 /* Pre Jedec Initialization */
3172 sdram_pre_jedec_initialization();
3173
3174 /* Perform System Memory IO Initialization */
3175 sdram_initialize_system_memory_io(&sysinfo);
3176
3177 /* Perform System Memory IO Buffer Enable */
3178 sdram_enable_system_memory_io(&sysinfo);
3179
3180 /* Enable System Memory Clocks */
3181 sdram_enable_memory_clocks(&sysinfo);
3182
Stefan Reinauer71a3d962009-07-21 21:44:24 +00003183 if (boot_path == BOOT_PATH_NORMAL) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00003184 /* Jedec Initialization sequence */
3185 sdram_jedec_enable(&sysinfo);
3186 }
3187
3188 /* Program Power Management Registers */
3189 sdram_power_management(&sysinfo);
3190
3191 /* Post Jedec Init */
3192 sdram_post_jedec_initialization(&sysinfo);
3193
3194 /* Program DRAM Throttling */
3195 sdram_thermal_management();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00003196
Stefan Reinauer278534d2008-10-29 04:51:07 +00003197 /* Normal Operations */
Stefan Reinaueraca6ec62009-10-26 17:12:21 +00003198 sdram_init_complete();
Stefan Reinauer278534d2008-10-29 04:51:07 +00003199
3200 /* Program Receive Enable Timings */
3201 sdram_program_receive_enable(&sysinfo);
3202
3203 /* Enable Periodic RCOMP */
3204 sdram_enable_rcomp();
3205
3206 /* Tell ICH7 that we're done */
3207 reg8 = pci_read_config8(PCI_DEV(0,0x1f,0), 0xa2);
3208 reg8 &= ~(1 << 7);
3209 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa2, reg8);
3210
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00003211 printk(BIOS_DEBUG, "RAM initialization finished.\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00003212
Stefan Reinauer278534d2008-10-29 04:51:07 +00003213 sdram_setup_processor_side();
3214}