blob: 0cf03ae605c998d9e8441e3e884388522c8f48b2 [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
Arthur Heymans0ab49042017-02-06 22:40:14 +01005 * Copyright (C) 2017 Arthur Heymans <arthur@aheymans.xyz>
Stefan Reinauer278534d2008-10-29 04:51:07 +00006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Stefan Reinauer278534d2008-10-29 04:51:07 +000015 */
16
Patrick Georgid0835952010-10-05 09:07:10 +000017#include <console/console.h>
Stefan Reinauer278534d2008-10-29 04:51:07 +000018#include <cpu/x86/cache.h>
Arthur Heymans885c2892016-10-03 17:16:48 +020019#include <device/pci_def.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020020#include <device/pci_ops.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020021#include <arch/io.h>
Elyes HAOUAS420d7e02019-04-21 18:39:34 +020022#include <cf9_reset.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020023#include <device/mmio.h>
Arthur Heymans885c2892016-10-03 17:16:48 +020024#include <device/device.h>
Julius Werner7a8a4ab2015-05-22 16:26:40 -070025#include <lib.h>
Edwin Beasanteb50c7d2010-07-06 21:05:04 +000026#include <pc80/mc146818rtc.h>
Stefan Reinauer278534d2008-10-29 04:51:07 +000027#include <spd.h>
Patrick Georgid0835952010-10-05 09:07:10 +000028#include <string.h>
Stefan Reinauer278534d2008-10-29 04:51:07 +000029#include "raminit.h"
30#include "i945.h"
Arthur Heymans885c2892016-10-03 17:16:48 +020031#include "chip.h"
Arthur Heymans0ab49042017-02-06 22:40:14 +010032#include <device/dram/ddr2.h>
Patrick Georgi771328f2015-07-13 19:24:07 +020033#include <timestamp.h>
Rudolf Marekc4369532010-12-13 19:59:13 +000034
Stefan Reinauer278534d2008-10-29 04:51:07 +000035/* Debugging macros. */
Julius Wernercd49cce2019-03-05 16:53:33 -080036#if CONFIG(DEBUG_RAM_SETUP)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000037#define PRINTK_DEBUG(x...) printk(BIOS_DEBUG, x)
Stefan Reinauer278534d2008-10-29 04:51:07 +000038#else
39#define PRINTK_DEBUG(x...)
40#endif
41
Stefan Reinauer278534d2008-10-29 04:51:07 +000042#define RAM_INITIALIZATION_COMPLETE (1 << 19)
43
44#define RAM_COMMAND_SELF_REFRESH (0x0 << 16)
45#define RAM_COMMAND_NOP (0x1 << 16)
46#define RAM_COMMAND_PRECHARGE (0x2 << 16)
47#define RAM_COMMAND_MRS (0x3 << 16)
48#define RAM_COMMAND_EMRS (0x4 << 16)
49#define RAM_COMMAND_CBR (0x6 << 16)
50#define RAM_COMMAND_NORMAL (0x7 << 16)
51
52#define RAM_EMRS_1 (0x0 << 21)
53#define RAM_EMRS_2 (0x1 << 21)
54#define RAM_EMRS_3 (0x2 << 21)
55
Arthur Heymans885c2892016-10-03 17:16:48 +020056#define DEFAULT_PCI_MMIO_SIZE 768
Sven Schnelle541269b2011-02-21 09:39:17 +000057static int get_dimm_spd_address(struct sys_info *sysinfo, int device)
58{
59 if (sysinfo->spd_addresses)
60 return sysinfo->spd_addresses[device];
61 else
62 return DIMM0 + device;
63
64}
65
Arthur Heymans70a8e342017-03-09 11:30:23 +010066static inline int spd_read_byte(unsigned int device, unsigned int address)
Patrick Georgid0835952010-10-05 09:07:10 +000067{
68 return smbus_read_byte(device, address);
69}
70
Stefan Reinauerbc8613e2010-08-25 18:35:42 +000071static __attribute__((noinline)) void do_ram_command(u32 command)
Stefan Reinauer278534d2008-10-29 04:51:07 +000072{
73 u32 reg32;
74
75 reg32 = MCHBAR32(DCC);
Arthur Heymans70a8e342017-03-09 11:30:23 +010076 reg32 &= ~((3<<21) | (1<<20) | (1<<19) | (7 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +000077 reg32 |= command;
78
79 /* Also set Init Complete */
80 if (command == RAM_COMMAND_NORMAL)
81 reg32 |= RAM_INITIALIZATION_COMPLETE;
82
83 PRINTK_DEBUG(" Sending RAM command 0x%08x", reg32);
84
85 MCHBAR32(DCC) = reg32; /* This is the actual magic */
86
Stefan Reinauer779b3e32008-11-10 15:43:37 +000087 PRINTK_DEBUG("...done\n");
Stefan Reinauerd058ad12010-08-26 12:43:58 +000088
89 udelay(1);
Stefan Reinauer278534d2008-10-29 04:51:07 +000090}
91
Stefan Reinauer278534d2008-10-29 04:51:07 +000092static void ram_read32(u32 offset)
93{
Elyes HAOUAS15279a92016-07-28 21:05:26 +020094 PRINTK_DEBUG(" RAM read: %08x\n", offset);
Stefan Reinauer278534d2008-10-29 04:51:07 +000095
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080096 read32((void *)offset);
Stefan Reinauer278534d2008-10-29 04:51:07 +000097}
98
Stefan Reinauer3c0bfaf2010-12-27 11:34:57 +000099void sdram_dump_mchbar_registers(void)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000100{
101 int i;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000102 printk(BIOS_DEBUG, "Dumping MCHBAR Registers\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000103
Arthur Heymans70a8e342017-03-09 11:30:23 +0100104 for (i = 0; i < 0xfff; i += 4) {
Stefan Reinauer278534d2008-10-29 04:51:07 +0000105 if (MCHBAR32(i) == 0)
106 continue;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000107 printk(BIOS_DEBUG, "0x%04x: 0x%08x\n", i, MCHBAR32(i));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000108 }
109}
Stefan Reinauer278534d2008-10-29 04:51:07 +0000110
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000111static int memclk(void)
112{
Julius Wernercd49cce2019-03-05 16:53:33 -0800113 int offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200114
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000115 switch (((MCHBAR32(CLKCFG) >> 4) & 7) - offset) {
116 case 1: return 400;
117 case 2: return 533;
118 case 3: return 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100119 default:
120 printk(BIOS_DEBUG, "memclk: unknown register value %x\n",
121 ((MCHBAR32(CLKCFG) >> 4) & 7) - offset);
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000122 }
123 return -1;
124}
125
Peter Stuge76d91432010-10-01 10:02:33 +0000126static u16 fsbclk(void)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000127{
Julius Wernercd49cce2019-03-05 16:53:33 -0800128 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200129 switch (MCHBAR32(CLKCFG) & 7) {
130 case 0: return 400;
131 case 1: return 533;
132 case 3: return 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100133 default:
134 printk(BIOS_DEBUG, "fsbclk: unknown register value %x\n",
135 MCHBAR32(CLKCFG) & 7);
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200136 }
137 return 0xffff;
Julius Wernercd49cce2019-03-05 16:53:33 -0800138 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200139 switch (MCHBAR32(CLKCFG) & 7) {
140 case 0: return 1066;
141 case 1: return 533;
142 case 2: return 800;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100143 default:
144 printk(BIOS_DEBUG, "fsbclk: unknown register value %x\n",
145 MCHBAR32(CLKCFG) & 7);
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200146 }
147 return 0xffff;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000148 }
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000149}
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000150
Stefan Reinauer278534d2008-10-29 04:51:07 +0000151static int sdram_capabilities_max_supported_memory_frequency(void)
152{
153 u32 reg32;
154
Patrick Georgi77d66832010-10-01 08:02:45 +0000155#if CONFIG_MAXIMUM_SUPPORTED_FREQUENCY
156 return CONFIG_MAXIMUM_SUPPORTED_FREQUENCY;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000157#endif
158
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000159 reg32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000160 reg32 &= (7 << 0);
161
162 switch (reg32) {
163 case 4: return 400;
164 case 3: return 533;
165 case 2: return 667;
166 }
167 /* Newer revisions of this chipset rather support faster memory clocks,
168 * so if it's a reserved value, return the fastest memory clock that we
169 * know of and can handle
170 */
171 return 667;
172}
173
174/**
175 * @brief determine whether chipset is capable of dual channel interleaved mode
176 *
177 * @return 1 if interleaving is supported, 0 otherwise
178 */
179static int sdram_capabilities_interleave(void)
180{
181 u32 reg32;
182
Arthur Heymans70a8e342017-03-09 11:30:23 +0100183 reg32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000184 reg32 >>= 25;
185 reg32 &= 1;
186
187 return (!reg32);
188}
189
190/**
191 * @brief determine whether chipset is capable of two memory channels
192 *
193 * @return 1 if dual channel operation is supported, 0 otherwise
194 */
195static int sdram_capabilities_dual_channel(void)
196{
197 u32 reg32;
198
Arthur Heymans70a8e342017-03-09 11:30:23 +0100199 reg32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000200 reg32 >>= 24;
201 reg32 &= 1;
202
203 return (!reg32);
204}
205
206static int sdram_capabilities_enhanced_addressing_xor(void)
207{
208 u8 reg8;
209
210 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
211 reg8 &= (1 << 7);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000212
Stefan Reinauer278534d2008-10-29 04:51:07 +0000213 return (!reg8);
214}
215
Stefan Reinauer14e22772010-04-27 06:56:47 +0000216// TODO check if we ever need this function
Stefan Reinauer53b0ea42010-03-22 11:50:52 +0000217#if 0
Stefan Reinauer278534d2008-10-29 04:51:07 +0000218static int sdram_capabilities_MEM4G_disable(void)
219{
220 u8 reg8;
221
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000222 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000223 reg8 &= (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000224
Stefan Reinauer278534d2008-10-29 04:51:07 +0000225 return (reg8 != 0);
226}
Stefan Reinauer53b0ea42010-03-22 11:50:52 +0000227#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +0000228
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000229#define GFX_FREQUENCY_CAP_166MHZ 0x04
230#define GFX_FREQUENCY_CAP_200MHZ 0x03
231#define GFX_FREQUENCY_CAP_250MHZ 0x02
232#define GFX_FREQUENCY_CAP_ALL 0x00
233
234static int sdram_capabilities_core_frequencies(void)
235{
236 u8 reg8;
237
238 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
239 reg8 &= (1 << 3) | (1 << 2) | (1 << 1);
240 reg8 >>= 1;
241
Arthur Heymans70a8e342017-03-09 11:30:23 +0100242 return reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000243}
244
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000245static void sdram_detect_errors(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000246{
247 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000248 u8 do_reset = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000249
250 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000251
Stefan Reinauer278534d2008-10-29 04:51:07 +0000252 if (reg8 & ((1<<7)|(1<<2))) {
253 if (reg8 & (1<<2)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000254 printk(BIOS_DEBUG, "SLP S4# Assertion Width Violation.\n");
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000255 /* Write back clears bit 2 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000256 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa2, reg8);
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000257 do_reset = 1;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000258
Stefan Reinauer278534d2008-10-29 04:51:07 +0000259 }
260
261 if (reg8 & (1<<7)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000262 printk(BIOS_DEBUG, "DRAM initialization was interrupted.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000263 reg8 &= ~(1<<7);
264 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa2, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000265 do_reset = 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000266 }
267
268 /* Set SLP_S3# Assertion Stretch Enable */
269 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4); /* GEN_PMCON_3 */
270 reg8 |= (1 << 3);
271 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8);
272
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000273 if (do_reset) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000274 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200275 full_reset();
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000276 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000277 }
278
279 /* Set DRAM initialization bit in ICH7 */
280 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa2);
281 reg8 |= (1<<7);
282 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa2, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000283
Peter Stuge751508a2012-01-27 22:17:09 +0100284 /* clear self refresh status if check is disabled or not a resume */
Julius Werner5d1f9a02019-03-07 17:07:26 -0800285 if (!CONFIG(CHECK_SLFRCS_ON_RESUME)
Arthur Heymans0ab49042017-02-06 22:40:14 +0100286 || sysinfo->boot_path != BOOT_PATH_RESUME) {
Patrick Georgi86a11102013-03-15 14:11:37 +0100287 MCHBAR8(SLFRCS) |= 3;
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000288 } else {
289 /* Validate self refresh config */
290 if (((sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED) ||
291 (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)) &&
Patrick Georgi86a11102013-03-15 14:11:37 +0100292 !(MCHBAR8(SLFRCS) & (1<<0))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000293 do_reset = 1;
294 }
295 if (((sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED) ||
296 (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) &&
Patrick Georgi86a11102013-03-15 14:11:37 +0100297 !(MCHBAR8(SLFRCS) & (1<<1))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000298 do_reset = 1;
299 }
300 }
301
302 if (do_reset) {
303 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200304 full_reset();
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000305 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000306}
Stefan Reinauer278534d2008-10-29 04:51:07 +0000307
Arthur Heymans0ab49042017-02-06 22:40:14 +0100308struct timings {
309 u32 min_tCLK_cas[8];
310 u32 min_tRAS;
311 u32 min_tRP;
312 u32 min_tRCD;
313 u32 min_tWR;
314 u32 min_tRFC;
315 u32 max_tRR;
316 u8 cas_mask;
317};
Stefan Reinauer278534d2008-10-29 04:51:07 +0000318
Arthur Heymans0ab49042017-02-06 22:40:14 +0100319/**
320 * @brief loop over dimms and save maximal timings
321 */
322static void gather_common_timing(struct sys_info *sysinfo,
323 struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000324{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100325
326 int i, j;
327 u8 raw_spd[SPD_SIZE_MAX_DDR2];
328 u8 dimm_mask = 0;
329
330 memset(saved_timings, 0, sizeof(*saved_timings));
331 saved_timings->max_tRR = UINT32_MAX;
332 saved_timings->cas_mask = SPD_CAS_LATENCY_DDR2_3
333 | SPD_CAS_LATENCY_DDR2_4 | SPD_CAS_LATENCY_DDR2_5;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000334
335 /**
336 * i945 supports two DIMMs, in two configurations:
337 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000338 * - single channel with two DIMMs
339 * - dual channel with one DIMM per channel
Stefan Reinauer278534d2008-10-29 04:51:07 +0000340 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000341 * In practice dual channel mainboards have their SPD at 0x50/0x52
342 * whereas single channel configurations have their SPD at 0x50/0x51.
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000343 *
Stefan Reinauer278534d2008-10-29 04:51:07 +0000344 * The capability register knows a lot about the channel configuration
Uwe Hermannd773fd32010-11-20 20:23:08 +0000345 * but for now we stick with the information we gather via SPD.
Stefan Reinauer278534d2008-10-29 04:51:07 +0000346 */
347
Arthur Heymans0ab49042017-02-06 22:40:14 +0100348 printk(BIOS_DEBUG, "This mainboard supports ");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000349 if (sdram_capabilities_dual_channel()) {
350 sysinfo->dual_channel = 1;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100351 printk(BIOS_DEBUG, "Dual Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000352 } else {
353 sysinfo->dual_channel = 0;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100354 printk(BIOS_DEBUG, "only Single Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000355 }
356
Stefan Reinauer278534d2008-10-29 04:51:07 +0000357
Arthur Heymans70a8e342017-03-09 11:30:23 +0100358 for (i = 0; i < (2 * DIMM_SOCKETS); i++) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100359 int device = get_dimm_spd_address(sysinfo, i), bytes_read;
Arthur Heymansfc31e442018-02-12 15:12:34 +0100360 struct dimm_attr_ddr2_st dimm_info;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000361
362 /* Initialize the socket information with a sane value */
363 sysinfo->dimm[i] = SYSINFO_DIMM_NOT_POPULATED;
364
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000365 /* Dual Channel not supported, but Channel 1? Bail out */
366 if (!sdram_capabilities_dual_channel() && (i >> 1))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000367 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000368
Arthur Heymans0ab49042017-02-06 22:40:14 +0100369 if (spd_read_byte(device, SPD_MEMORY_TYPE) !=
370 SPD_MEMORY_TYPE_SDRAM_DDR2) {
371 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: N/A\n",
372 (i >> 1), (i & 1));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000373 continue;
374 }
375
Arthur Heymans0ab49042017-02-06 22:40:14 +0100376 /*
377 * spd_decode_ddr2() needs a 128-byte sized array but
378 * only the first 64 bytes contain data needed for raminit.
379 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000380
Kyösti Mälkkic01a5052019-01-30 09:39:23 +0200381 bytes_read = i2c_eeprom_read(device, 0, 64, raw_spd);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100382 printk(BIOS_DEBUG, "Reading SPD using i2c block operation.\n");
Julius Wernercd49cce2019-03-05 16:53:33 -0800383 if (CONFIG(DEBUG_RAM_SETUP) && bytes_read > 0)
Arthur Heymans0ab49042017-02-06 22:40:14 +0100384 hexdump(raw_spd, bytes_read);
Arthur Heymans56619452017-09-21 09:12:42 +0200385 if (bytes_read != 64) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100386 /* Try again with SMBUS byte read */
387 printk(BIOS_DEBUG, "i2c block operation failed,"
Paul Menzel105e3682017-09-21 08:11:05 +0200388 " trying smbus byte operation.\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100389 for (j = 0; j < 64; j++)
390 raw_spd[j] = spd_read_byte(device, j);
Julius Wernercd49cce2019-03-05 16:53:33 -0800391 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100392 hexdump(raw_spd, 64);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100393 }
Arthur Heymans56619452017-09-21 09:12:42 +0200394
395 if (spd_decode_ddr2(&dimm_info, raw_spd) != SPD_STATUS_OK) {
396 printk(BIOS_WARNING, "Encountered problems with SPD, "
397 "skipping this DIMM.\n");
398 continue;
399 }
400
Julius Wernercd49cce2019-03-05 16:53:33 -0800401 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100402 dram_print_spd_ddr2(&dimm_info);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000403
Arthur Heymans0ab49042017-02-06 22:40:14 +0100404 if (dimm_info.flags.is_ecc)
405 die("\nError: ECC memory not supported by this chipset\n");
406
407 if (spd_dimm_is_registered_ddr2(dimm_info.dimm_type))
408 die("\nError: Registered memory not supported by this chipset\n");
409
410 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: ", (i >> 1),
411 (i & 1));
412 /**
413 * There are 5 different possible populations for a DIMM socket:
414 * 0. x16 double ranked (X16DS)
415 * 1. x8 double ranked (X8DS)
416 * 2. x16 single ranked (X16SS)
417 * 3. x8 double stacked (X8DDS)
418 * 4. Unpopulated
419 */
420 switch (dimm_info.width) {
421 case 8:
422 switch (dimm_info.ranks) {
423 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000424 printk(BIOS_DEBUG, "x8DDS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000425 sysinfo->dimm[i] = SYSINFO_DIMM_X8DDS;
426 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100427 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000428 printk(BIOS_DEBUG, "x8DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000429 sysinfo->dimm[i] = SYSINFO_DIMM_X8DS;
430 break;
431 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000432 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000433 }
434 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100435 case 16:
436 switch (dimm_info.ranks) {
437 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000438 printk(BIOS_DEBUG, "x16DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000439 sysinfo->dimm[i] = SYSINFO_DIMM_X16DS;
440 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100441 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000442 printk(BIOS_DEBUG, "x16SS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000443 sysinfo->dimm[i] = SYSINFO_DIMM_X16SS;
444 break;
445 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000446 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000447 }
448 break;
449 default:
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000450 die("Unsupported DDR-II memory width.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000451 }
452
Arthur Heymans0ab49042017-02-06 22:40:14 +0100453 /* Is the current DIMM a stacked DIMM? */
454 if (dimm_info.flags.stacked)
455 sysinfo->package = SYSINFO_PACKAGE_STACKED;
456
457 if (!dimm_info.flags.bl8)
458 die("Only DDR-II RAM with burst length 8 is supported by this chipset.\n");
459
460 if (dimm_info.ranksize_mb < 128)
461 die("DDR-II rank size smaller than 128MB is not supported.\n");
462
463 sysinfo->banksize[i * 2] = dimm_info.ranksize_mb / 32;
464 printk(BIOS_DEBUG, "DIMM %d side 0 = %d MB\n", i,
465 sysinfo->banksize[i * 2] * 32);
466 if (dimm_info.ranks == 2) {
467 sysinfo->banksize[(i * 2) + 1] =
468 dimm_info.ranksize_mb / 32;
469 printk(BIOS_DEBUG, "DIMM %d side 1 = %d MB\n",
470 i, sysinfo->banksize[(i * 2) + 1] * 32);
471 }
472
473
474 sysinfo->rows[i] = dimm_info.row_bits;
475 sysinfo->cols[i] = dimm_info.col_bits;
476 sysinfo->banks[i] = dimm_info.banks;
477
478 /* int min_tRAS, min_tRP, min_tRCD, min_tWR, min_tRFC; */
479 saved_timings->min_tRAS = MAX(saved_timings->min_tRAS,
480 dimm_info.tRAS);
481 saved_timings->min_tRP = MAX(saved_timings->min_tRP,
482 dimm_info.tRP);
483 saved_timings->min_tRCD = MAX(saved_timings->min_tRCD,
484 dimm_info.tRCD);
485 saved_timings->min_tWR = MAX(saved_timings->min_tWR,
486 dimm_info.tWR);
487 saved_timings->min_tRFC = MAX(saved_timings->min_tRFC,
488 dimm_info.tRFC);
489 saved_timings->max_tRR = MIN(saved_timings->max_tRR,
490 dimm_info.tRR);
491 saved_timings->cas_mask &= dimm_info.cas_supported;
492 for (j = 0; j < 8; j++) {
493 if (!(saved_timings->cas_mask & (1 << j)))
494 saved_timings->min_tCLK_cas[j] = 0;
495 else
496 saved_timings->min_tCLK_cas[j] =
497 MAX(dimm_info.cycle_time[j],
498 saved_timings->min_tCLK_cas[j]);
499 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000500 dimm_mask |= (1 << i);
501 }
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200502 if (!dimm_mask)
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000503 die("No memory installed.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000504
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200505 if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1)))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100506 /* Possibly does not boot in this case */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000507 printk(BIOS_INFO, "Channel 0 has no memory populated.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000508}
509
Arthur Heymans0ab49042017-02-06 22:40:14 +0100510static void choose_tclk(struct sys_info *sysinfo,
511 struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000512{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100513 u32 ctrl_min_tclk;
514 int try_cas;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000515
Arthur Heymans0ab49042017-02-06 22:40:14 +0100516 ctrl_min_tclk = 2 * 256 * 1000
517 / sdram_capabilities_max_supported_memory_frequency();
518 normalize_tck(&ctrl_min_tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000519
Arthur Heymans0ab49042017-02-06 22:40:14 +0100520 try_cas = spd_get_msbs(saved_timings->cas_mask);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000521
Arthur Heymans0ab49042017-02-06 22:40:14 +0100522 while (saved_timings->cas_mask & (1 << try_cas) && try_cas > 0) {
523 sysinfo->cas = try_cas;
524 sysinfo->tclk = saved_timings->min_tCLK_cas[try_cas];
525 if (sysinfo->tclk >= ctrl_min_tclk &&
526 saved_timings->min_tCLK_cas[try_cas] !=
527 saved_timings->min_tCLK_cas[try_cas - 1])
Stefan Reinauer278534d2008-10-29 04:51:07 +0000528 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100529 try_cas--;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000530 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000531
Arthur Heymans0ab49042017-02-06 22:40:14 +0100532 normalize_tck(&sysinfo->tclk);
533
534 if ((sysinfo->cas < 3) || (sysinfo->tclk == 0))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000535 die("Could not find common memory frequency and CAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000536
Arthur Heymans0ab49042017-02-06 22:40:14 +0100537 /*
538 * The loop can still results in a timing too fast for the
539 * memory controller.
540 */
541 if (sysinfo->tclk < ctrl_min_tclk)
542 sysinfo->tclk = ctrl_min_tclk;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000543
Arthur Heymans0ab49042017-02-06 22:40:14 +0100544 switch (sysinfo->tclk) {
545 case TCK_200MHZ:
546 sysinfo->memory_frequency = 400;
547 break;
548 case TCK_266MHZ:
549 sysinfo->memory_frequency = 533;
550 break;
551 case TCK_333MHZ:
552 sysinfo->memory_frequency = 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100553 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000554 }
555
Arthur Heymans0ab49042017-02-06 22:40:14 +0100556 printk(BIOS_DEBUG,
557 "Memory will be driven at %dMT with CAS=%d clocks\n",
558 sysinfo->memory_frequency, sysinfo->cas);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000559}
560
Arthur Heymans0ab49042017-02-06 22:40:14 +0100561static void derive_timings(struct sys_info *sysinfo,
562 struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000563{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100564 sysinfo->tras = DIV_ROUND_UP(saved_timings->min_tRAS, sysinfo->tclk);
565 if (sysinfo->tras > 0x18)
566 die("DDR-II Module does not support this frequency (tRAS error)\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000567
Arthur Heymans0ab49042017-02-06 22:40:14 +0100568 sysinfo->trp = DIV_ROUND_UP(saved_timings->min_tRP, sysinfo->tclk);
569 if (sysinfo->trp > 6)
570 die("DDR-II Module does not support this frequency (tRP error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000571
Arthur Heymans0ab49042017-02-06 22:40:14 +0100572 sysinfo->trcd = DIV_ROUND_UP(saved_timings->min_tRCD, sysinfo->tclk);
573 if (sysinfo->trcd > 6)
574 die("DDR-II Module does not support this frequency (tRCD error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000575
Arthur Heymans0ab49042017-02-06 22:40:14 +0100576 sysinfo->twr = DIV_ROUND_UP(saved_timings->min_tWR, sysinfo->tclk);
577 if (sysinfo->twr > 5)
578 die("DDR-II Module does not support this frequency (tWR error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000579
Arthur Heymans0ab49042017-02-06 22:40:14 +0100580 sysinfo->trfc = DIV_ROUND_UP(saved_timings->min_tRFC, sysinfo->tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000581
Arthur Heymans0ab49042017-02-06 22:40:14 +0100582 printk(BIOS_DEBUG, "tRAS = %d cycles\n", sysinfo->tras);
583 printk(BIOS_DEBUG, "tRP = %d cycles\n", sysinfo->trp);
584 printk(BIOS_DEBUG, "tRCD = %d cycles\n", sysinfo->trcd);
585 printk(BIOS_DEBUG, "tWR = %d cycles\n", sysinfo->twr);
586 printk(BIOS_DEBUG, "tRFC = %d cycles\n", sysinfo->trfc);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000587
Arthur Heymans0ab49042017-02-06 22:40:14 +0100588 /* Refresh is slower than 15.6us, use 15.6us */
589 /* tRR is decoded in units of 1/256us */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000590
Arthur Heymans0ab49042017-02-06 22:40:14 +0100591#define T_RR_7_8US 2000000
592#define T_RR_15_6US 4000000
593#define REFRESH_7_8US 1
594#define REFRESH_15_6US 0
Stefan Reinauer278534d2008-10-29 04:51:07 +0000595
Arthur Heymans0ab49042017-02-06 22:40:14 +0100596 if (saved_timings->max_tRR < T_RR_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000597 die("DDR-II module has unsupported refresh value\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100598 else if (saved_timings->max_tRR < T_RR_15_6US)
599 sysinfo->refresh = REFRESH_7_8US;
600 else
601 sysinfo->refresh = REFRESH_15_6US;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000602 printk(BIOS_DEBUG, "Refresh: %s\n", sysinfo->refresh?"7.8us":"15.6us");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000603}
604
Arthur Heymans0ab49042017-02-06 22:40:14 +0100605/**
606 * @brief Get generic DIMM parameters.
607 * @param sysinfo Central memory controller information structure
608 *
609 * This function gathers several pieces of information for each system DIMM:
610 * o DIMM width (x8 / x16)
611 * o DIMM rank (single ranked / dual ranked)
612 *
613 * Also, some non-supported scenarios are detected.
614 */
615
616static void sdram_get_dram_configuration(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000617{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100618 struct timings saved_timings;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000619
Arthur Heymans0ab49042017-02-06 22:40:14 +0100620 gather_common_timing(sysinfo, &saved_timings);
621 choose_tclk(sysinfo, &saved_timings);
622 derive_timings(sysinfo, &saved_timings);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000623}
624
Arthur Heymans70a8e342017-03-09 11:30:23 +0100625static void sdram_program_dram_width(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000626{
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200627 u16 c0dramw = 0, c1dramw = 0;
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200628 int i, idx;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000629
630 if (sysinfo->dual_channel)
631 idx = 2;
632 else
633 idx = 1;
634
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200635 for (i = 0; i < DIMM_SOCKETS; i++) { /* Channel 0 */
636 switch (sysinfo->dimm[i]) {
637 case SYSINFO_DIMM_X16DS:
638 c0dramw |= (0x0000) << 4*(i % 2);
639 break;
640 case SYSINFO_DIMM_X8DS:
641 c0dramw |= (0x0001) << 4*(i % 2);
642 break;
643 case SYSINFO_DIMM_X16SS:
644 c0dramw |= (0x0000) << 4*(i % 2);
645 break;
646 case SYSINFO_DIMM_X8DDS:
647 c0dramw |= (0x0005) << 4*(i % 2);
648 break;
649 case SYSINFO_DIMM_NOT_POPULATED:
650 c0dramw |= (0x0000) << 4*(i % 2);
651 break;
652 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000653 }
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200654 for (i = DIMM_SOCKETS; i < idx * DIMM_SOCKETS; i++) { /* Channel 1 */
655 switch (sysinfo->dimm[i]) {
656 case SYSINFO_DIMM_X16DS:
657 c1dramw |= (0x0000) << 4*(i % 2);
658 break;
659 case SYSINFO_DIMM_X8DS:
Patrick Georgi68aed912018-11-16 18:00:12 +0100660 c1dramw |= (0x0010) << 4*(i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200661 break;
662 case SYSINFO_DIMM_X16SS:
663 c1dramw |= (0x0000) << 4*(i % 2);
664 break;
665 case SYSINFO_DIMM_X8DDS:
Patrick Georgi68aed912018-11-16 18:00:12 +0100666 c1dramw |= (0x0050) << 4*(i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200667 break;
668 case SYSINFO_DIMM_NOT_POPULATED:
669 c1dramw |= (0x0000) << 4*(i % 2);
670 break;
671 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000672 }
673
674 MCHBAR16(C0DRAMW) = c0dramw;
675 MCHBAR16(C1DRAMW) = c1dramw;
676}
677
678static void sdram_write_slew_rates(u32 offset, const u32 *slew_rate_table)
679{
680 int i;
681
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200682 for (i = 0; i < 16; i++)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000683 MCHBAR32(offset+(i*4)) = slew_rate_table[i];
684}
685
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000686static const u32 dq2030[] = {
687 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
688 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
689 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
690 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
691};
692
693static const u32 dq2330[] = {
694 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
695 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
696 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
697 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
698};
699
700static const u32 cmd2710[] = {
701 0x07060605, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
702 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
703 0x1110100f, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
704 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
705};
706
707static const u32 cmd3210[] = {
708 0x0f0d0b0a, 0x17151311, 0x1f1d1b19, 0x1f1f1f1f,
709 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
710 0x18171615, 0x1f1f1c1a, 0x1f1f1f1f, 0x1f1f1f1f,
711 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
712};
713
714static const u32 clk2030[] = {
715 0x0e0d0d0c, 0x100f0f0e, 0x100f0e0d, 0x15131211,
716 0x1d1b1917, 0x2523211f, 0x2a282927, 0x32302e2c,
717 0x17161514, 0x1b1a1918, 0x1f1e1d1c, 0x23222120,
718 0x27262524, 0x2d2b2928, 0x3533312f, 0x3d3b3937
719};
720
721static const u32 ctl3215[] = {
722 0x01010000, 0x03020101, 0x07060504, 0x0b0a0908,
723 0x100f0e0d, 0x14131211, 0x18171615, 0x1c1b1a19,
724 0x05040403, 0x07060605, 0x0a090807, 0x0f0d0c0b,
725 0x14131211, 0x18171615, 0x1c1b1a19, 0x201f1e1d
726};
727
728static const u32 ctl3220[] = {
729 0x05040403, 0x07060505, 0x0e0c0a08, 0x1a171411,
730 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e,
731 0x09080807, 0x0b0a0a09, 0x0f0d0c0b, 0x1b171311,
732 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e
733};
734
735static const u32 nc[] = {
736 0x00000000, 0x00000000, 0x00000000, 0x00000000,
737 0x00000000, 0x00000000, 0x00000000, 0x00000000,
738 0x00000000, 0x00000000, 0x00000000, 0x00000000,
739 0x00000000, 0x00000000, 0x00000000, 0x00000000
740};
741
742enum {
743 DQ2030,
744 DQ2330,
745 CMD2710,
746 CMD3210,
747 CLK2030,
748 CTL3215,
749 CTL3220,
750 NC,
751};
752
753static const u8 dual_channel_slew_group_lookup[] = {
754 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
755 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
756 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
757 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
758 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
759
760 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
761 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
762 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
763 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
764 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
765
766 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
767 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
768 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
769 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
770 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
771
772 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
773 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
774 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
775 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
776 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, NC, NC,
777
778 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
779 NC, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
780 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
781 NC, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD2710
782};
783
784static const u8 single_channel_slew_group_lookup[] = {
785 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
786 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
787 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
788 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
789 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
790
791 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
792 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
793 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
794 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
795 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
796
797 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
798 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
799 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
800 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
801 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
802
803 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
804 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
805 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
806 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
807 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
808
809 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
810 DQ2330, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
811 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
812 DQ2330, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD3210
813};
814
815static const u32 *slew_group_lookup(int dual_channel, int index)
816{
817 const u8 *slew_group;
818 /* Dual Channel needs different tables. */
819 if (dual_channel)
820 slew_group = dual_channel_slew_group_lookup;
821 else
822 slew_group = single_channel_slew_group_lookup;
823
824 switch (slew_group[index]) {
825 case DQ2030: return dq2030;
826 case DQ2330: return dq2330;
827 case CMD2710: return cmd2710;
828 case CMD3210: return cmd3210;
829 case CLK2030: return clk2030;
830 case CTL3215: return ctl3215;
831 case CTL3220: return ctl3220;
832 case NC: return nc;
833 }
834
835 return nc;
836}
837
Julius Wernercd49cce2019-03-05 16:53:33 -0800838#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000839/* Strength multiplier tables */
840static const u8 dual_channel_strength_multiplier[] = {
841 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
842 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
843 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
844 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
845 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
846 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
847 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
848 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
849 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
850 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
851 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
852 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
853 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
854 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
855 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
856 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
857 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
858 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
859 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
860 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
861 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
862 0x00, 0x00, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
863 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
864 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x44, 0x22
865};
866
867static const u8 single_channel_strength_multiplier[] = {
868 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
869 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
870 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
871 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
872 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
873 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
874 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
875 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
876 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
877 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
878 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
879 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
880 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
881 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
882 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
883 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
884 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
885 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
886 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
887 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
888 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
889 0x33, 0x00, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
890 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
891 0x33, 0x00, 0x11, 0x00, 0x44, 0x44, 0x33, 0x11
892};
Julius Wernercd49cce2019-03-05 16:53:33 -0800893#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000894static const u8 dual_channel_strength_multiplier[] = {
895 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
896 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
897 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
898 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
899 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
900 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
901 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
902 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
903 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
904 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
905 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
906 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
907 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
908 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
909 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
910 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
911 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
912 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
913 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
914 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
915 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
916 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
917 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
918 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33
919};
920
921static const u8 single_channel_strength_multiplier[] = {
922 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
923 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
924 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
925 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
926 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
927 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
928 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
929 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
930 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
931 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
932 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
933 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
934 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
935 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
936 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
937 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
938 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
939 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
940 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
941 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
942 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
943 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
944 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
945 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00
946};
947#endif
948
Stefan Reinauer278534d2008-10-29 04:51:07 +0000949static void sdram_rcomp_buffer_strength_and_slew(struct sys_info *sysinfo)
950{
Arthur Heymans70a8e342017-03-09 11:30:23 +0100951 const u8 *strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000952 int idx, dual_channel;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000953
954 /* Set Strength Multipliers */
955
956 /* Dual Channel needs different tables. */
957 if (sdram_capabilities_dual_channel()) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000958 printk(BIOS_DEBUG, "Programming Dual Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000959 strength_multiplier = dual_channel_strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000960 dual_channel = 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000961 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[2];
962 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000963 printk(BIOS_DEBUG, "Programming Single Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000964 strength_multiplier = single_channel_strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000965 dual_channel = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000966 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[1];
967 }
968
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000969 printk(BIOS_DEBUG, "Table Index: %d\n", idx);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000970
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000971 MCHBAR8(G1SC) = strength_multiplier[idx * 8 + 0];
972 MCHBAR8(G2SC) = strength_multiplier[idx * 8 + 1];
973 MCHBAR8(G3SC) = strength_multiplier[idx * 8 + 2];
974 MCHBAR8(G4SC) = strength_multiplier[idx * 8 + 3];
975 MCHBAR8(G5SC) = strength_multiplier[idx * 8 + 4];
976 MCHBAR8(G6SC) = strength_multiplier[idx * 8 + 5];
977 MCHBAR8(G7SC) = strength_multiplier[idx * 8 + 6];
978 MCHBAR8(G8SC) = strength_multiplier[idx * 8 + 7];
Stefan Reinauer278534d2008-10-29 04:51:07 +0000979
980 /* Channel 0 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000981 sdram_write_slew_rates(G1SRPUT, slew_group_lookup(dual_channel, idx * 8 + 0));
982 sdram_write_slew_rates(G2SRPUT, slew_group_lookup(dual_channel, idx * 8 + 1));
Arthur Heymans70a8e342017-03-09 11:30:23 +0100983 if ((slew_group_lookup(dual_channel, idx * 8 + 2) != nc) && (sysinfo->package == SYSINFO_PACKAGE_STACKED))
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000984
Stefan Reinauer278534d2008-10-29 04:51:07 +0000985 sdram_write_slew_rates(G3SRPUT, ctl3220);
Arthur Heymans70a8e342017-03-09 11:30:23 +0100986 else
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000987 sdram_write_slew_rates(G3SRPUT, slew_group_lookup(dual_channel, idx * 8 + 2));
Arthur Heymans70a8e342017-03-09 11:30:23 +0100988
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000989 sdram_write_slew_rates(G4SRPUT, slew_group_lookup(dual_channel, idx * 8 + 3));
990 sdram_write_slew_rates(G5SRPUT, slew_group_lookup(dual_channel, idx * 8 + 4));
991 sdram_write_slew_rates(G6SRPUT, slew_group_lookup(dual_channel, idx * 8 + 5));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000992
993 /* Channel 1 */
994 if (sysinfo->dual_channel) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000995 sdram_write_slew_rates(G7SRPUT, slew_group_lookup(dual_channel, idx * 8 + 6));
996 sdram_write_slew_rates(G8SRPUT, slew_group_lookup(dual_channel, idx * 8 + 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000997 } else {
998 sdram_write_slew_rates(G7SRPUT, nc);
999 sdram_write_slew_rates(G8SRPUT, nc);
1000 }
1001}
1002
1003static void sdram_enable_rcomp(void)
1004{
1005 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001006 /* Enable Global Periodic RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001007 udelay(300);
1008 reg32 = MCHBAR32(GBRCOMPCTL);
1009 reg32 &= ~(1 << 23);
1010 MCHBAR32(GBRCOMPCTL) = reg32;
1011}
1012
1013static void sdram_program_dll_timings(struct sys_info *sysinfo)
1014{
Elyes HAOUAS44a30662017-02-23 13:14:44 +01001015 u32 channeldll = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001016 int i;
1017
Elyes HAOUAS38424982016-08-21 12:01:04 +02001018 printk(BIOS_DEBUG, "Programming DLL Timings...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001019
Arthur Heymans70a8e342017-03-09 11:30:23 +01001020 MCHBAR16(DQSMT) &= ~((3 << 12) | (1 << 10) | (0xf << 0));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001021 MCHBAR16(DQSMT) |= (1 << 13) | (0xc << 0);
1022
1023 /* We drive both channels with the same speed */
Julius Wernercd49cce2019-03-05 16:53:33 -08001024 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001025 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001026 case 400:
1027 channeldll = 0x26262626; break;
1028 case 533:
1029 channeldll = 0x22222222; break;
1030 case 667:
1031 channeldll = 0x11111111; break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001032 }
Julius Wernercd49cce2019-03-05 16:53:33 -08001033 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001034 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001035 case 400:
1036 channeldll = 0x33333333; break;
1037 case 533:
1038 channeldll = 0x24242424; break;
1039 case 667:
1040 channeldll = 0x25252525; break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001041 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001042 }
1043
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001044 for (i = 0; i < 4; i++) {
Elyes HAOUAS44a30662017-02-23 13:14:44 +01001045 MCHBAR32(C0R0B00DQST + (i * 0x10) + 0) = channeldll;
1046 MCHBAR32(C0R0B00DQST + (i * 0x10) + 4) = channeldll;
1047 MCHBAR32(C1R0B00DQST + (i * 0x10) + 0) = channeldll;
1048 MCHBAR32(C1R0B00DQST + (i * 0x10) + 4) = channeldll;
Julius Wernercd49cce2019-03-05 16:53:33 -08001049 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUAS44a30662017-02-23 13:14:44 +01001050 MCHBAR8(C0R0B00DQST + (i * 0x10) + 8) = channeldll & 0xff;
1051 MCHBAR8(C1R0B00DQST + (i * 0x10) + 8) = channeldll & 0xff;
Paul Menzelbce7e332017-02-22 18:46:27 +01001052 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001053 }
1054}
1055
1056static void sdram_force_rcomp(void)
1057{
1058 u32 reg32;
1059 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001060
Stefan Reinauer278534d2008-10-29 04:51:07 +00001061 reg32 = MCHBAR32(ODTC);
1062 reg32 |= (1 << 28);
1063 MCHBAR32(ODTC) = reg32;
1064
1065 reg32 = MCHBAR32(SMSRCTL);
1066 reg32 |= (1 << 0);
1067 MCHBAR32(SMSRCTL) = reg32;
1068
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001069 /* Start initial RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001070 reg32 = MCHBAR32(GBRCOMPCTL);
1071 reg32 |= (1 << 8);
1072 MCHBAR32(GBRCOMPCTL) = reg32;
1073
1074 reg8 = i945_silicon_revision();
1075 if ((reg8 == 0 && (MCHBAR32(DCC) & (3 << 0)) == 0) || (reg8 == 1)) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001076
Stefan Reinauer278534d2008-10-29 04:51:07 +00001077 reg32 = MCHBAR32(GBRCOMPCTL);
1078 reg32 |= (3 << 5);
1079 MCHBAR32(GBRCOMPCTL) = reg32;
1080 }
1081}
1082
1083static void sdram_initialize_system_memory_io(struct sys_info *sysinfo)
1084{
1085 u8 reg8;
1086 u32 reg32;
1087
Elyes HAOUAS38424982016-08-21 12:01:04 +02001088 printk(BIOS_DEBUG, "Initializing System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001089 /* Enable Data Half Clock Pushout */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001090 reg8 = MCHBAR8(C0HCTC);
1091 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001092 reg8 |= (1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001093 MCHBAR8(C0HCTC) = reg8;
1094
1095 reg8 = MCHBAR8(C1HCTC);
1096 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001097 reg8 |= (1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001098 MCHBAR8(C1HCTC) = reg8;
1099
Arthur Heymans70a8e342017-03-09 11:30:23 +01001100 MCHBAR16(WDLLBYPMODE) &= ~((1 << 9) | (1 << 6) | (1 << 4) | (1 << 3) | (1 << 1));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001101 MCHBAR16(WDLLBYPMODE) |= (1 << 8) | (1 << 7) | (1 << 5) | (1 << 2) | (1 << 0);
1102
1103 MCHBAR8(C0WDLLCMC) = 0;
1104 MCHBAR8(C1WDLLCMC) = 0;
1105
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001106 /* Program RCOMP Settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001107 sdram_program_dram_width(sysinfo);
1108
1109 sdram_rcomp_buffer_strength_and_slew(sysinfo);
1110
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001111 /* Indicate that RCOMP programming is done */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001112 reg32 = MCHBAR32(GBRCOMPCTL);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001113 reg32 &= ~((1 << 29) | (1 << 26) | (3 << 21) | (3 << 2));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001114 reg32 |= (3 << 27) | (3 << 0);
1115 MCHBAR32(GBRCOMPCTL) = reg32;
1116
1117 MCHBAR32(GBRCOMPCTL) |= (1 << 10);
1118
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001119 /* Program DLL Timings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001120 sdram_program_dll_timings(sysinfo);
1121
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001122 /* Force RCOMP cycle */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001123 sdram_force_rcomp();
1124}
1125
1126static void sdram_enable_system_memory_io(struct sys_info *sysinfo)
1127{
1128 u32 reg32;
1129
Elyes HAOUAS38424982016-08-21 12:01:04 +02001130 printk(BIOS_DEBUG, "Enabling System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001131
Stefan Reinauer278534d2008-10-29 04:51:07 +00001132 reg32 = MCHBAR32(RCVENMT);
1133 reg32 &= ~(0x3f << 6);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001134 MCHBAR32(RCVENMT) = reg32; /* [11:6] = 0 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001135
1136 reg32 |= (1 << 11) | (1 << 9);
1137 MCHBAR32(RCVENMT) = reg32;
1138
1139 reg32 = MCHBAR32(DRTST);
1140 reg32 |= (1 << 3) | (1 << 2);
1141 MCHBAR32(DRTST) = reg32;
1142
1143 reg32 = MCHBAR32(DRTST);
1144 reg32 |= (1 << 6) | (1 << 4);
1145 MCHBAR32(DRTST) = reg32;
1146
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001147 asm volatile ("nop; nop;" ::: "memory");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001148
1149 reg32 = MCHBAR32(DRTST);
1150
1151 /* Is channel 0 populated? */
1152 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
1153 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
1154 reg32 |= (1 << 7) | (1 << 5);
1155 else
1156 reg32 |= (1 << 31);
1157
1158 /* Is channel 1 populated? */
1159 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1160 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
1161 reg32 |= (1 << 9) | (1 << 8);
1162 else
1163 reg32 |= (1 << 30);
1164
1165 MCHBAR32(DRTST) = reg32;
1166
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001167 /* Activate DRAM Channel IO Buffers */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001168 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
1169 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) {
1170 reg32 = MCHBAR32(C0DRC1);
1171 reg32 |= (1 << 8);
1172 MCHBAR32(C0DRC1) = reg32;
1173 }
1174 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1175 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED) {
1176 reg32 = MCHBAR32(C1DRC1);
1177 reg32 |= (1 << 8);
1178 MCHBAR32(C1DRC1) = reg32;
1179 }
1180}
1181
Stefan Reinauer278534d2008-10-29 04:51:07 +00001182static int sdram_program_row_boundaries(struct sys_info *sysinfo)
1183{
1184 int i;
Arthur Heymans885c2892016-10-03 17:16:48 +02001185 int cum0, cum1, tolud, tom, pci_mmio_size;
1186 const struct device *dev;
1187 const struct northbridge_intel_i945_config *cfg = NULL;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001188
Paul Menzel84283bc2014-07-17 08:16:04 +02001189 printk(BIOS_DEBUG, "Setting RAM size...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001190
1191 cum0 = 0;
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001192 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001193 cum0 += sysinfo->banksize[i];
Stefan Reinauer278534d2008-10-29 04:51:07 +00001194 MCHBAR8(C0DRB0+i) = cum0;
1195 }
1196
1197 /* Assume we continue in Channel 1 where we stopped in Channel 0 */
1198 cum1 = cum0;
1199
1200 /* Exception: Interleaved starts from the beginning */
1201 if (sysinfo->interleaved)
1202 cum1 = 0;
1203
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001204 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001205 cum1 += sysinfo->banksize[i + 4];
Stefan Reinauer278534d2008-10-29 04:51:07 +00001206 MCHBAR8(C1DRB0+i) = cum1;
1207 }
1208
1209 /* Set TOLUD Top Of Low Usable DRAM */
1210 if (sysinfo->interleaved)
1211 tolud = (cum0 + cum1) << 1;
1212 else
1213 tolud = (cum1 ? cum1 : cum0) << 1;
Stefan Reinauer779b3e32008-11-10 15:43:37 +00001214
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001215 /* The TOM register has a different format */
1216 tom = tolud >> 3;
1217
1218 /* Limit the value of TOLUD to leave some space for PCI memory. */
Kyösti Mälkkic70eed12018-05-22 02:18:00 +03001219 dev = pcidev_on_root(0, 0);
Arthur Heymans885c2892016-10-03 17:16:48 +02001220 if (dev)
1221 cfg = dev->chip_info;
1222
1223 /* Don't use pci mmio sizes smaller than 768M */
1224 if (!cfg || cfg->pci_mmio_size <= DEFAULT_PCI_MMIO_SIZE)
1225 pci_mmio_size = DEFAULT_PCI_MMIO_SIZE;
1226 else
1227 pci_mmio_size = cfg->pci_mmio_size;
1228
1229 tolud = MIN(((4096 - pci_mmio_size) / 128) << 3, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001230
Arthur Heymans70a8e342017-03-09 11:30:23 +01001231 pci_write_config8(PCI_DEV(0, 0, 0), TOLUD, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001232
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001233 printk(BIOS_DEBUG, "C0DRB = 0x%08x\n", MCHBAR32(C0DRB0));
1234 printk(BIOS_DEBUG, "C1DRB = 0x%08x\n", MCHBAR32(C1DRB0));
Arthur Heymans70a8e342017-03-09 11:30:23 +01001235 printk(BIOS_DEBUG, "TOLUD = 0x%04x\n", pci_read_config8(PCI_DEV(0, 0, 0), TOLUD));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001236
Arthur Heymans70a8e342017-03-09 11:30:23 +01001237 pci_write_config16(PCI_DEV(0, 0, 0), TOM, tom);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001238
1239 return 0;
1240}
1241
Stefan Reinauer278534d2008-10-29 04:51:07 +00001242static int sdram_set_row_attributes(struct sys_info *sysinfo)
1243{
Arthur Heymans0ab49042017-02-06 22:40:14 +01001244 int i;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001245 u16 dra0 = 0, dra1 = 0, dra = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001246
Elyes HAOUAS38424982016-08-21 12:01:04 +02001247 printk(BIOS_DEBUG, "Setting row attributes...\n");
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001248 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001249 u8 columnsrows;
1250
Arthur Heymans70a8e342017-03-09 11:30:23 +01001251 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001252 continue;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001253
Arthur Heymans0ab49042017-02-06 22:40:14 +01001254 columnsrows = (sysinfo->rows[i] & 0x0f)
1255 | (sysinfo->cols[i] & 0xf) << 4;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001256
1257 switch (columnsrows) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001258 case 0x9d:
1259 dra = 2; break;
1260 case 0xad:
1261 dra = 3; break;
1262 case 0xbd:
1263 dra = 4; break;
1264 case 0xae:
1265 dra = 3; break;
1266 case 0xbe:
1267 dra = 4; break;
1268 default:
1269 die("Unsupported Rows/Columns. (DRA)");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001270 }
1271
1272 /* Double Sided DIMMs? */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001273 if (sysinfo->banksize[(2 * i) + 1] != 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001274 dra = (dra << 4) | dra;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001275
Stefan Reinauer278534d2008-10-29 04:51:07 +00001276 if (i < DIMM_SOCKETS)
1277 dra0 |= (dra << (i*8));
1278 else
1279 dra1 |= (dra << ((i - DIMM_SOCKETS)*8));
1280 }
1281
1282 MCHBAR16(C0DRA0) = dra0;
1283 MCHBAR16(C1DRA0) = dra1;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001284
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001285 printk(BIOS_DEBUG, "C0DRA = 0x%04x\n", dra0);
1286 printk(BIOS_DEBUG, "C1DRA = 0x%04x\n", dra1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001287
1288 return 0;
1289}
1290
1291static void sdram_set_bank_architecture(struct sys_info *sysinfo)
1292{
1293 u32 off32;
1294 int i;
1295
1296 MCHBAR16(C1BNKARC) &= 0xff00;
1297 MCHBAR16(C0BNKARC) &= 0xff00;
1298
1299 off32 = C0BNKARC;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001300 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001301 /* Switch to second channel */
1302 if (i == DIMM_SOCKETS)
1303 off32 = C1BNKARC;
1304
1305 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
1306 continue;
1307
1308 if (sysinfo->banks[i] != 8)
1309 continue;
1310
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001311 printk(BIOS_SPEW, "DIMM%d has 8 banks.\n", i);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001312
1313 if (i & 1)
1314 MCHBAR16(off32) |= 0x50;
1315 else
1316 MCHBAR16(off32) |= 0x05;
1317 }
1318}
1319
Stefan Reinauer278534d2008-10-29 04:51:07 +00001320static void sdram_program_refresh_rate(struct sys_info *sysinfo)
1321{
1322 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001323
Arthur Heymans70a8e342017-03-09 11:30:23 +01001324 if (sysinfo->refresh == REFRESH_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001325 reg32 = (2 << 8); /* Refresh enabled at 7.8us */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001326 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001327 reg32 = (1 << 8); /* Refresh enabled at 15.6us */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001328
1329 MCHBAR32(C0DRC0) &= ~(7 << 8);
1330 MCHBAR32(C0DRC0) |= reg32;
1331
1332 MCHBAR32(C1DRC0) &= ~(7 << 8);
1333 MCHBAR32(C1DRC0) |= reg32;
1334}
1335
1336static void sdram_program_cke_tristate(struct sys_info *sysinfo)
1337{
1338 u32 reg32;
1339 int i;
1340
1341 reg32 = MCHBAR32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001342
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001343 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001344 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001345 reg32 |= (1 << (16 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001346 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001347
Stefan Reinauer278534d2008-10-29 04:51:07 +00001348 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001349
Stefan Reinauer278534d2008-10-29 04:51:07 +00001350 reg32 |= (1 << 11);
1351 MCHBAR32(C0DRC1) = reg32;
1352
1353 /* Do we have to do this if we're in Single Channel Mode? */
1354 reg32 = MCHBAR32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001355
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001356 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001357 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001358 reg32 |= (1 << (12 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001359 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001360
Stefan Reinauer278534d2008-10-29 04:51:07 +00001361 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001362
Stefan Reinauer278534d2008-10-29 04:51:07 +00001363 reg32 |= (1 << 11);
1364 MCHBAR32(C1DRC1) = reg32;
1365}
1366
1367static void sdram_program_odt_tristate(struct sys_info *sysinfo)
1368{
1369 u32 reg32;
1370 int i;
1371
1372 reg32 = MCHBAR32(C0DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001373
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001374 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001375 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001376 reg32 |= (1 << (24 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001377 }
1378 MCHBAR32(C0DRC2) = reg32;
1379
1380 reg32 = MCHBAR32(C1DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001381
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001382 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001383 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001384 reg32 |= (1 << (20 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001385 }
1386 MCHBAR32(C1DRC2) = reg32;
1387}
1388
1389static void sdram_set_timing_and_control(struct sys_info *sysinfo)
1390{
Arthur Heymans25027232017-02-12 23:34:39 +01001391 u32 reg32, tRD_min;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001392 u32 tWTR;
1393 u32 temp_drt;
1394 int i, page_size;
1395
Edward O'Callaghan2f237c12014-05-25 06:24:39 +10001396 static const u8 cas_table[] = {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001397 2, 1, 0, 3
1398 };
1399
1400 reg32 = MCHBAR32(C0DRC0);
1401 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001402 reg32 &= ~((1 << 13) | (1 << 12));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001403 MCHBAR32(C0DRC0) = reg32;
1404
1405 reg32 = MCHBAR32(C1DRC0);
1406 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001407 reg32 &= ~((1 << 13) | (1 << 12));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001408 MCHBAR32(C1DRC0) = reg32;
1409
1410 if (!sysinfo->dual_channel && sysinfo->dimm[1] !=
1411 SYSINFO_DIMM_NOT_POPULATED) {
1412 reg32 = MCHBAR32(C0DRC0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001413 reg32 |= (1 << 15);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001414 MCHBAR32(C0DRC0) = reg32;
1415 }
1416
1417 sdram_program_refresh_rate(sysinfo);
1418
1419 sdram_program_cke_tristate(sysinfo);
1420
1421 sdram_program_odt_tristate(sysinfo);
1422
1423 /* Calculate DRT0 */
1424
1425 temp_drt = 0;
1426
1427 /* B2B Write Precharge (same bank) = CL-1 + BL/2 + tWR */
1428 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + sysinfo->twr;
1429 temp_drt |= (reg32 << 28);
1430
1431 /* Write Auto Precharge (same bank) = CL-1 + BL/2 + tWR + tRP */
1432 reg32 += sysinfo->trp;
1433 temp_drt |= (reg32 << 4);
1434
Arthur Heymans70a8e342017-03-09 11:30:23 +01001435 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001436 tWTR = 3; /* 667MHz */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001437 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001438 tWTR = 2; /* 400 and 533 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001439
1440 /* B2B Write to Read Command Spacing */
1441 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + tWTR;
1442 temp_drt |= (reg32 << 24);
1443
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001444 /* CxDRT0 [23:22], [21:20], [19:18] [16] have fixed values */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001445 temp_drt |= ((1 << 22) | (3 << 20) | (1 << 18) | (0 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001446
Arthur Heymans25027232017-02-12 23:34:39 +01001447 /*
1448 * tRD is the delay the memory controller is waiting on the FSB,
1449 * in mclk domain.
1450 * This parameter is important for stability and performance.
1451 * Those values might not be optimal but seem stable.
1452 */
1453 tRD_min = sysinfo->cas;
Arthur Heymanse1897612016-10-15 23:29:18 +02001454 switch (sysinfo->fsb_frequency) {
Arthur Heymans25027232017-02-12 23:34:39 +01001455 case 533: break;
1456 case 667: tRD_min += 1;
Arthur Heymanse1897612016-10-15 23:29:18 +02001457 break;
Arthur Heymans25027232017-02-12 23:34:39 +01001458 case 800: tRD_min += 2;
Arthur Heymanse1897612016-10-15 23:29:18 +02001459 break;
Arthur Heymans25027232017-02-12 23:34:39 +01001460 case 1066: tRD_min += 3;
Arthur Heymanse1897612016-10-15 23:29:18 +02001461 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001462 }
Arthur Heymanse1897612016-10-15 23:29:18 +02001463
Arthur Heymans25027232017-02-12 23:34:39 +01001464 temp_drt |= (tRD_min << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001465
1466 /* Read Auto Precharge to Activate */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001467
Stefan Reinauer278534d2008-10-29 04:51:07 +00001468 temp_drt |= (8 << 0);
1469
1470 MCHBAR32(C0DRT0) = temp_drt;
1471 MCHBAR32(C1DRT0) = temp_drt;
1472
1473 /* Calculate DRT1 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001474
Stefan Reinauer278534d2008-10-29 04:51:07 +00001475 temp_drt = MCHBAR32(C0DRT1) & 0x00020088;
1476
1477 /* DRAM RASB Precharge */
1478 temp_drt |= (sysinfo->trp - 2) << 0;
1479
1480 /* DRAM RASB to CASB Delay */
1481 temp_drt |= (sysinfo->trcd - 2) << 4;
1482
1483 /* CASB Latency */
1484 temp_drt |= (cas_table[sysinfo->cas - 3]) << 8;
1485
1486 /* Refresh Cycle Time */
1487 temp_drt |= (sysinfo->trfc) << 10;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001488
Stefan Reinauer278534d2008-10-29 04:51:07 +00001489 /* Pre-All to Activate Delay */
1490 temp_drt |= (0 << 16);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001491
Stefan Reinauer278534d2008-10-29 04:51:07 +00001492 /* Precharge to Precharge Delay stays at 1 clock */
1493 temp_drt |= (0 << 18);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001494
Stefan Reinauer278534d2008-10-29 04:51:07 +00001495 /* Activate to Precharge Delay */
1496 temp_drt |= (sysinfo->tras << 19);
1497
1498 /* Read to Precharge (tRTP) */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001499 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001500 temp_drt |= (1 << 28);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001501 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001502 temp_drt |= (0 << 28);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001503
1504 /* Determine page size */
1505 reg32 = 0;
1506 page_size = 1; /* Default: 1k pagesize */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001507 for (i = 0; i < 2*DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001508 if (sysinfo->dimm[i] == SYSINFO_DIMM_X16DS ||
1509 sysinfo->dimm[i] == SYSINFO_DIMM_X16SS)
1510 page_size = 2; /* 2k pagesize */
1511 }
1512
Arthur Heymans70a8e342017-03-09 11:30:23 +01001513 if (sysinfo->memory_frequency == 533 && page_size == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001514 reg32 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001515 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001516 reg32 = page_size;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001517
Stefan Reinauer278534d2008-10-29 04:51:07 +00001518 temp_drt |= (reg32 << 30);
1519
1520 MCHBAR32(C0DRT1) = temp_drt;
1521 MCHBAR32(C1DRT1) = temp_drt;
1522
1523 /* Program DRT2 */
1524 reg32 = MCHBAR32(C0DRT2);
1525 reg32 &= ~(1 << 8);
1526 MCHBAR32(C0DRT2) = reg32;
1527
1528 reg32 = MCHBAR32(C1DRT2);
1529 reg32 &= ~(1 << 8);
1530 MCHBAR32(C1DRT2) = reg32;
1531
1532 /* Calculate DRT3 */
1533 temp_drt = MCHBAR32(C0DRT3) & ~0x07ffffff;
1534
1535 /* Get old tRFC value */
1536 reg32 = MCHBAR32(C0DRT1) >> 10;
1537 reg32 &= 0x3f;
1538
1539 /* 788nS - tRFC */
1540 switch (sysinfo->memory_frequency) {
1541 case 400: /* 5nS */
1542 reg32 = ((78800 / 500) - reg32) & 0x1ff;
1543 reg32 |= (0x8c << 16) | (0x0c << 10); /* 1 us */
1544 break;
1545 case 533: /* 3.75nS */
1546 reg32 = ((78800 / 375) - reg32) & 0x1ff;
1547 reg32 |= (0xba << 16) | (0x10 << 10); /* 1 us */
1548 break;
1549 case 667: /* 3nS */
1550 reg32 = ((78800 / 300) - reg32) & 0x1ff;
1551 reg32 |= (0xe9 << 16) | (0x14 << 10); /* 1 us */
1552 break;
1553 }
1554
1555 temp_drt |= reg32;
1556
1557 MCHBAR32(C0DRT3) = temp_drt;
1558 MCHBAR32(C1DRT3) = temp_drt;
1559}
1560
1561static void sdram_set_channel_mode(struct sys_info *sysinfo)
1562{
1563 u32 reg32;
1564
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001565 printk(BIOS_DEBUG, "Setting mode of operation for memory channels...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001566
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001567 if (sdram_capabilities_interleave() &&
Arthur Heymans70a8e342017-03-09 11:30:23 +01001568 ((sysinfo->banksize[0] + sysinfo->banksize[1] +
1569 sysinfo->banksize[2] + sysinfo->banksize[3]) ==
1570 (sysinfo->banksize[4] + sysinfo->banksize[5] +
1571 sysinfo->banksize[6] + sysinfo->banksize[7]))) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001572 /* Both channels equipped with DIMMs of the same size */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001573 sysinfo->interleaved = 1;
1574 } else {
1575 sysinfo->interleaved = 0;
1576 }
1577
1578 reg32 = MCHBAR32(DCC);
1579 reg32 &= ~(7 << 0);
1580
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001581 if (sysinfo->interleaved) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001582 /* Dual Channel Interleaved */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001583 printk(BIOS_DEBUG, "Dual Channel Interleaved.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001584 reg32 |= (1 << 1);
1585 } else if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED &&
1586 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
1587 /* Channel 1 only */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001588 printk(BIOS_DEBUG, "Single Channel 1 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001589 reg32 |= (1 << 2);
Elyes HAOUAS75da1fb2017-02-16 18:59:13 +01001590 } else if (sdram_capabilities_dual_channel() &&
1591 (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1592 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) {
Martin Roth128c1042016-11-18 09:29:03 -07001593 /* Dual Channel Asymmetric */
1594 printk(BIOS_DEBUG, "Dual Channel Asymmetric.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001595 reg32 |= (1 << 0);
1596 } else {
1597 /* All bits 0 means Single Channel 0 operation */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001598 printk(BIOS_DEBUG, "Single Channel 0 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001599 }
1600
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001601 /* Now disable channel XORing */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001602 reg32 |= (1 << 10);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001603
1604 MCHBAR32(DCC) = reg32;
1605
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001606 PRINTK_DEBUG("DCC = 0x%08x\n", MCHBAR32(DCC));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001607}
1608
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001609static void sdram_program_pll_settings(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001610{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001611 MCHBAR32(PLLMON) = 0x80800000;
1612
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001613 sysinfo->fsb_frequency = fsbclk();
Peter Stuge76d91432010-10-01 10:02:33 +00001614 if (sysinfo->fsb_frequency == 0xffff)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001615 die("Unsupported FSB speed");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001616
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001617 /* Program CPCTL according to FSB speed */
1618 /* Only write the lower byte */
1619 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001620 case 400:
1621 MCHBAR8(CPCTL) = 0x90; break; /* FSB400 */
1622 case 533:
1623 MCHBAR8(CPCTL) = 0x95; break; /* FSB533 */
1624 case 667:
1625 MCHBAR8(CPCTL) = 0x8d; break; /* FSB667 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001626 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001627
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001628 MCHBAR16(CPCTL) &= ~(1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001629
Paul Menzel0ce5ebf2013-10-21 21:22:09 +02001630 MCHBAR16(CPCTL); /* Read back register to activate settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001631}
1632
1633static void sdram_program_graphics_frequency(struct sys_info *sysinfo)
1634{
1635 u8 reg8;
1636 u16 reg16;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001637 u8 freq, second_vco, voltage;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001638
1639#define CRCLK_166MHz 0x00
1640#define CRCLK_200MHz 0x01
1641#define CRCLK_250MHz 0x03
1642#define CRCLK_400MHz 0x05
1643
1644#define CDCLK_200MHz 0x00
1645#define CDCLK_320MHz 0x40
1646
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001647#define VOLTAGE_1_05 0x00
1648#define VOLTAGE_1_50 0x01
1649
Paul Menzeldaf9e502014-07-15 23:49:16 +02001650 printk(BIOS_DEBUG, "Setting Graphics Frequency...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001651
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001652 printk(BIOS_DEBUG, "FSB: %d MHz ", sysinfo->fsb_frequency);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001653
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001654 voltage = VOLTAGE_1_05;
1655 if (MCHBAR32(DFT_STRAP1) & (1 << 20))
1656 voltage = VOLTAGE_1_50;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001657 printk(BIOS_DEBUG, "Voltage: %s ", (voltage == VOLTAGE_1_05)?"1.05V":"1.5V");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001658
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001659 /* Gate graphics hardware for frequency change */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001660 reg8 = pci_read_config16(PCI_DEV(0, 2, 0), GCFC + 1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001661 reg8 = (1<<3) | (1<<1); /* disable crclk, gate cdclk */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001662 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001663
1664 /* Get graphics frequency capabilities */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001665 reg8 = sdram_capabilities_core_frequencies();
1666
Stefan Reinauer278534d2008-10-29 04:51:07 +00001667 freq = CRCLK_250MHz;
1668 switch (reg8) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001669 case GFX_FREQUENCY_CAP_ALL:
1670 if (voltage == VOLTAGE_1_05)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001671 freq = CRCLK_250MHz;
1672 else
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001673 freq = CRCLK_400MHz; /* 1.5V requires 400MHz */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001674 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001675 case GFX_FREQUENCY_CAP_250MHZ:
1676 freq = CRCLK_250MHz; break;
1677 case GFX_FREQUENCY_CAP_200MHZ:
1678 freq = CRCLK_200MHz; break;
1679 case GFX_FREQUENCY_CAP_166MHZ:
1680 freq = CRCLK_166MHz; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001681 }
1682
1683 if (freq != CRCLK_400MHz) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001684 /* What chipset are we? Force 166MHz for GMS */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001685 reg8 = (pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe7) & 0x70) >> 4;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001686 if (reg8 == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001687 freq = CRCLK_166MHz;
1688 }
1689
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001690 printk(BIOS_DEBUG, "Render: ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001691 switch (freq) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001692 case CRCLK_166MHz:
1693 printk(BIOS_DEBUG, "166MHz"); break;
1694 case CRCLK_200MHz:
1695 printk(BIOS_DEBUG, "200MHz"); break;
1696 case CRCLK_250MHz:
1697 printk(BIOS_DEBUG, "250MHz"); break;
1698 case CRCLK_400MHz:
1699 printk(BIOS_DEBUG, "400MHz"); break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001700 }
1701
Arthur Heymans70a8e342017-03-09 11:30:23 +01001702 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001703 sysinfo->mvco4x = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001704 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001705 sysinfo->mvco4x = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001706
Stefan Reinauer278534d2008-10-29 04:51:07 +00001707 second_vco = 0;
1708
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001709 if (voltage == VOLTAGE_1_50) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001710 second_vco = 1;
1711 } else if ((i945_silicon_revision() > 0) && (freq == CRCLK_250MHz)) {
1712 u16 mem = sysinfo->memory_frequency;
1713 u16 fsb = sysinfo->fsb_frequency;
1714
Arthur Heymans70a8e342017-03-09 11:30:23 +01001715 if ((fsb == 667 && mem == 533) ||
1716 (fsb == 533 && mem == 533) ||
1717 (fsb == 533 && mem == 400)) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001718 second_vco = 1;
1719 }
1720
1721 if (fsb == 667 && mem == 533)
1722 sysinfo->mvco4x = 1;
1723 }
1724
Arthur Heymans70a8e342017-03-09 11:30:23 +01001725 if (second_vco)
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001726 sysinfo->clkcfg_bit7 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001727 else
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001728 sysinfo->clkcfg_bit7 = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001729
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001730 /* Graphics Core Render Clock */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001731 reg16 = pci_read_config16(PCI_DEV(0, 2, 0), GCFC);
1732 reg16 &= ~((7 << 0) | (1 << 13));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001733 reg16 |= freq;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001734 pci_write_config16(PCI_DEV(0, 2, 0), GCFC, reg16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001735
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001736 /* Graphics Core Display Clock */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001737 reg8 = pci_read_config8(PCI_DEV(0, 2, 0), GCFC);
1738 reg8 &= ~((1<<7) | (7<<4));
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001739
1740 if (voltage == VOLTAGE_1_05) {
1741 reg8 |= CDCLK_200MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001742 printk(BIOS_DEBUG, " Display: 200MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001743 } else {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001744 reg8 |= CDCLK_320MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001745 printk(BIOS_DEBUG, " Display: 320MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001746 }
Arthur Heymans70a8e342017-03-09 11:30:23 +01001747 pci_write_config8(PCI_DEV(0, 2, 0), GCFC, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001748
Arthur Heymans70a8e342017-03-09 11:30:23 +01001749 reg8 = pci_read_config8(PCI_DEV(0, 2, 0), GCFC + 1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001750
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001751 reg8 |= (1<<3) | (1<<1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001752 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001753
1754 reg8 |= 0x0f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001755 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001756
1757 /* Ungate core render and display clocks */
1758 reg8 &= 0xf0;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001759 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001760}
1761
1762static void sdram_program_memory_frequency(struct sys_info *sysinfo)
1763{
1764 u32 clkcfg;
1765 u8 reg8;
Julius Wernercd49cce2019-03-05 16:53:33 -08001766 u8 offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001767
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001768 printk(BIOS_DEBUG, "Setting Memory Frequency... ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001769
Stefan Reinauer278534d2008-10-29 04:51:07 +00001770 clkcfg = MCHBAR32(CLKCFG);
1771
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001772 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001773
Arthur Heymans70a8e342017-03-09 11:30:23 +01001774 clkcfg &= ~((1 << 12) | (1 << 7) | (7 << 4));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001775
1776 if (sysinfo->mvco4x) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001777 printk(BIOS_DEBUG, "MVCO 4x, ");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001778 clkcfg &= ~(1 << 12);
1779 }
1780
1781 if (sysinfo->clkcfg_bit7) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001782 printk(BIOS_DEBUG, "second VCO, ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001783
Stefan Reinauer278534d2008-10-29 04:51:07 +00001784 clkcfg |= (1 << 7);
1785 }
1786
1787 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001788 case 400:
1789 clkcfg |= ((1 + offset) << 4); break;
1790 case 533:
1791 clkcfg |= ((2 + offset) << 4); break;
1792 case 667:
1793 clkcfg |= ((3 + offset) << 4); break;
1794 default:
1795 die("Target Memory Frequency Error");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001796 }
1797
1798 if (MCHBAR32(CLKCFG) == clkcfg) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001799 printk(BIOS_DEBUG, "ok (unchanged)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001800 return;
1801 }
1802
1803 MCHBAR32(CLKCFG) = clkcfg;
1804
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001805 /* Make sure the following code is in the
Stefan Reinauer278534d2008-10-29 04:51:07 +00001806 * cache before we execute it.
1807 */
1808 goto cache_code;
1809vco_update:
Arthur Heymans70a8e342017-03-09 11:30:23 +01001810 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001811 reg8 &= ~(1 << 7);
1812 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa2, reg8);
1813
Stefan Reinauer278534d2008-10-29 04:51:07 +00001814 clkcfg &= ~(1 << 10);
1815 MCHBAR32(CLKCFG) = clkcfg;
1816 clkcfg |= (1 << 10);
1817 MCHBAR32(CLKCFG) = clkcfg;
1818
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001819 asm volatile (
Stefan Reinauer278534d2008-10-29 04:51:07 +00001820 " movl $0x100, %%ecx\n"
1821 "delay_update:\n"
1822 " nop\n"
1823 " nop\n"
1824 " nop\n"
1825 " nop\n"
1826 " loop delay_update\n"
1827 : /* No outputs */
1828 : /* No inputs */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001829 : "%ecx", "memory"
Stefan Reinauer278534d2008-10-29 04:51:07 +00001830 );
1831
Stefan Reinauer278534d2008-10-29 04:51:07 +00001832 clkcfg &= ~(1 << 10);
1833 MCHBAR32(CLKCFG) = clkcfg;
1834
1835 goto out;
1836cache_code:
1837 goto vco_update;
1838out:
1839
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001840 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", MCHBAR32(CLKCFG));
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001841 printk(BIOS_DEBUG, "ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001842}
1843
1844static void sdram_program_clock_crossing(void)
1845{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001846 int idx = 0;
1847
1848 /**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001849 * We add the indices according to our clocks from CLKCFG.
Stefan Reinauer278534d2008-10-29 04:51:07 +00001850 */
Julius Wernercd49cce2019-03-05 16:53:33 -08001851#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001852 static const u32 data_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001853 0x00100401, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001854 0xffffffff, 0xffffffff, /* nonexistent */
1855 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001856
Stefan Reinauer278534d2008-10-29 04:51:07 +00001857 0x08040120, 0x00000000, /* DDR400 FSB533 */
1858 0x00100401, 0x00000000, /* DDR533 FSB533 */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001859 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001860
1861 0x04020120, 0x00000010, /* DDR400 FSB667 */
1862 0x10040280, 0x00000040, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001863 0x00100401, 0x00000000, /* DDR667 FSB667 */
1864
Martin Roth2ed0aa22016-01-05 20:58:58 -07001865 0xffffffff, 0xffffffff, /* nonexistent */
1866 0xffffffff, 0xffffffff, /* nonexistent */
1867 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001868
Martin Roth2ed0aa22016-01-05 20:58:58 -07001869 0xffffffff, 0xffffffff, /* nonexistent */
1870 0xffffffff, 0xffffffff, /* nonexistent */
1871 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001872 };
1873
1874 static const u32 command_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001875 0x04020208, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001876 0xffffffff, 0xffffffff, /* nonexistent */
1877 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001878
Stefan Reinauer278534d2008-10-29 04:51:07 +00001879 0x00060108, 0x00000000, /* DDR400 FSB533 */
1880 0x04020108, 0x00000000, /* DDR533 FSB533 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001881 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001882
1883 0x00040318, 0x00000000, /* DDR400 FSB667 */
1884 0x04020118, 0x00000000, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001885 0x02010804, 0x00000000, /* DDR667 FSB667 */
1886
Martin Roth2ed0aa22016-01-05 20:58:58 -07001887 0xffffffff, 0xffffffff, /* nonexistent */
1888 0xffffffff, 0xffffffff, /* nonexistent */
1889 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001890
Martin Roth2ed0aa22016-01-05 20:58:58 -07001891 0xffffffff, 0xffffffff, /* nonexistent */
1892 0xffffffff, 0xffffffff, /* nonexistent */
1893 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001894 };
1895
Julius Wernercd49cce2019-03-05 16:53:33 -08001896#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001897 /* i945 G/P */
1898 static const u32 data_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001899 0xffffffff, 0xffffffff, /* nonexistent */
1900 0xffffffff, 0xffffffff, /* nonexistent */
1901 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001902
1903 0x10080201, 0x00000000, /* DDR400 FSB533 */
1904 0x00100401, 0x00000000, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001905 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001906
Martin Roth2ed0aa22016-01-05 20:58:58 -07001907 0xffffffff, 0xffffffff, /* nonexistent */
1908 0xffffffff, 0xffffffff, /* nonexistent */
1909 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001910
1911 0x04020108, 0x00000000, /* DDR400 FSB800 */
1912 0x00020108, 0x00000000, /* DDR533 FSB800 */
1913 0x00080201, 0x00000000, /* DDR667 FSB800 */
1914
1915 0x00010402, 0x00000000, /* DDR400 FSB1066 */
1916 0x04020108, 0x00000000, /* DDR533 FSB1066 */
1917 0x08040110, 0x00000000, /* DDR667 FSB1066 */
1918 };
1919
1920 static const u32 command_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001921 0xffffffff, 0xffffffff, /* nonexistent */
1922 0xffffffff, 0xffffffff, /* nonexistent */
1923 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001924
1925 0x00010800, 0x00000402, /* DDR400 FSB533 */
1926 0x01000400, 0x00000200, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001927 0x00020904, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001928
Martin Roth2ed0aa22016-01-05 20:58:58 -07001929 0xffffffff, 0xffffffff, /* nonexistent */
1930 0xffffffff, 0xffffffff, /* nonexistent */
1931 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001932
1933 0x02010804, 0x00000000, /* DDR400 FSB800 */
1934 0x00010402, 0x00000000, /* DDR533 FSB800 */
Arthur Heymans8b6df622016-10-16 10:58:01 +02001935 0x04020130, 0x00000008, /* DDR667 FSB800 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001936
1937 0x00020904, 0x00000000, /* DDR400 FSB1066 */
1938 0x02010804, 0x00000000, /* DDR533 FSB1066 */
1939 0x180601c0, 0x00000020, /* DDR667 FSB1066 */
1940 };
1941#endif
1942
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001943 printk(BIOS_DEBUG, "Programming Clock Crossing...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001944
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001945 printk(BIOS_DEBUG, "MEM=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001946 switch (memclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001947 case 400:
1948 printk(BIOS_DEBUG, "400"); idx += 0; break;
1949 case 533:
1950 printk(BIOS_DEBUG, "533"); idx += 2; break;
1951 case 667:
1952 printk(BIOS_DEBUG, "667"); idx += 4; break;
1953 default:
1954 printk(BIOS_DEBUG, "RSVD %x", memclk()); return;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001955 }
1956
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001957 printk(BIOS_DEBUG, " FSB=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001958 switch (fsbclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001959 case 400:
1960 printk(BIOS_DEBUG, "400"); idx += 0; break;
1961 case 533:
1962 printk(BIOS_DEBUG, "533"); idx += 6; break;
1963 case 667:
1964 printk(BIOS_DEBUG, "667"); idx += 12; break;
1965 case 800:
1966 printk(BIOS_DEBUG, "800"); idx += 18; break;
1967 case 1066:
1968 printk(BIOS_DEBUG, "1066"); idx += 24; break;
1969 default:
1970 printk(BIOS_DEBUG, "RSVD %x\n", fsbclk()); return;
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001971 }
1972
Arthur Heymans70a8e342017-03-09 11:30:23 +01001973 if (command_clock_crossing[idx] == 0xffffffff)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001974 printk(BIOS_DEBUG, "Invalid MEM/FSB combination!\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001975
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001976 MCHBAR32(CCCFT + 0) = command_clock_crossing[idx];
1977 MCHBAR32(CCCFT + 4) = command_clock_crossing[idx + 1];
1978
Stefan Reinauer278534d2008-10-29 04:51:07 +00001979 MCHBAR32(C0DCCFT + 0) = data_clock_crossing[idx];
1980 MCHBAR32(C0DCCFT + 4) = data_clock_crossing[idx + 1];
1981 MCHBAR32(C1DCCFT + 0) = data_clock_crossing[idx];
1982 MCHBAR32(C1DCCFT + 4) = data_clock_crossing[idx + 1];
1983
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001984 printk(BIOS_DEBUG, "... ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001985}
1986
1987static void sdram_disable_fast_dispatch(void)
1988{
1989 u32 reg32;
1990
1991 reg32 = MCHBAR32(FSBPMC3);
1992 reg32 |= (1 << 1);
1993 MCHBAR32(FSBPMC3) = reg32;
1994
1995 reg32 = MCHBAR32(SBTEST);
1996 reg32 |= (3 << 1);
1997 MCHBAR32(SBTEST) = reg32;
1998}
1999
2000static void sdram_pre_jedec_initialization(void)
2001{
2002 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002003
Stefan Reinauer278534d2008-10-29 04:51:07 +00002004 reg32 = MCHBAR32(WCC);
2005 reg32 &= 0x113ff3ff;
2006 reg32 |= (4 << 29) | (3 << 25) | (1 << 10);
2007 MCHBAR32(WCC) = reg32;
2008
2009 MCHBAR32(SMVREFC) |= (1 << 6);
2010
2011 MCHBAR32(MMARB0) &= ~(3 << 17);
2012 MCHBAR32(MMARB0) |= (1 << 21) | (1 << 16);
2013
2014 MCHBAR32(MMARB1) &= ~(7 << 8);
2015 MCHBAR32(MMARB1) |= (3 << 8);
2016
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002017 /* Adaptive Idle Timer Control */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002018 MCHBAR32(C0AIT) = 0x000006c4;
2019 MCHBAR32(C0AIT+4) = 0x871a066d;
2020
2021 MCHBAR32(C1AIT) = 0x000006c4;
2022 MCHBAR32(C1AIT+4) = 0x871a066d;
2023}
2024
2025#define EA_DUALCHANNEL_XOR_BANK_RANK_MODE (0xd4 << 24)
2026#define EA_DUALCHANNEL_XOR_BANK_MODE (0xf4 << 24)
2027#define EA_DUALCHANNEL_BANK_RANK_MODE (0xc2 << 24)
2028#define EA_DUALCHANNEL_BANK_MODE (0xe2 << 24)
2029#define EA_SINGLECHANNEL_XOR_BANK_RANK_MODE (0x91 << 24)
2030#define EA_SINGLECHANNEL_XOR_BANK_MODE (0xb1 << 24)
2031#define EA_SINGLECHANNEL_BANK_RANK_MODE (0x80 << 24)
2032#define EA_SINGLECHANNEL_BANK_MODE (0xa0 << 24)
2033
2034static void sdram_enhanced_addressing_mode(struct sys_info *sysinfo)
2035{
2036 u32 chan0 = 0, chan1 = 0;
2037 int chan0_dualsided, chan1_dualsided, chan0_populated, chan1_populated;
2038
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002039 chan0_populated = (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Stefan Reinauer278534d2008-10-29 04:51:07 +00002040 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED);
Elyes HAOUAS308aeff2017-02-24 12:53:07 +01002041 chan1_populated = (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
2042 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002043 chan0_dualsided = (sysinfo->banksize[1] || sysinfo->banksize[3]);
2044 chan1_dualsided = (sysinfo->banksize[5] || sysinfo->banksize[7]);
2045
2046 if (sdram_capabilities_enhanced_addressing_xor()) {
2047 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002048 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002049 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002050 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002051 chan0 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002052 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002053 chan0 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002054 }
2055 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002056 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002057 chan1 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002058 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002059 chan1 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002060 }
2061 } else {
2062 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002063 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002064 chan0 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002065 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002066 chan0 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002067
Arthur Heymans70a8e342017-03-09 11:30:23 +01002068 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002069 chan1 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002070 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002071 chan1 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002072 }
2073 } else {
2074 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002075 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002076 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002077 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002078 chan0 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002079 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002080 chan0 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002081 }
2082 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002083 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002084 chan1 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002085 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002086 chan1 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002087 }
2088 } else {
2089 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002090 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002091 chan0 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002092 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002093 chan0 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002094
Arthur Heymans70a8e342017-03-09 11:30:23 +01002095 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002096 chan1 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002097 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002098 chan1 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002099 }
2100 }
2101
2102 MCHBAR32(C0DRC1) &= 0x00ffffff;
2103 MCHBAR32(C0DRC1) |= chan0;
2104 MCHBAR32(C1DRC1) &= 0x00ffffff;
2105 MCHBAR32(C1DRC1) |= chan1;
2106}
2107
2108static void sdram_post_jedec_initialization(struct sys_info *sysinfo)
2109{
2110 u32 reg32;
2111
2112 /* Enable Channel XORing for Dual Channel Interleave */
2113 if (sysinfo->interleaved) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002114
Stefan Reinauer278534d2008-10-29 04:51:07 +00002115 reg32 = MCHBAR32(DCC);
Julius Wernercd49cce2019-03-05 16:53:33 -08002116#if CONFIG(CHANNEL_XOR_RANDOMIZATION)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002117 reg32 &= ~(1 << 10);
Stefan Reinauer30140a52009-03-11 16:20:39 +00002118 reg32 |= (1 << 9);
2119#else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002120 reg32 &= ~(1 << 9);
Stefan Reinauer30140a52009-03-11 16:20:39 +00002121#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002122 MCHBAR32(DCC) = reg32;
2123 }
2124
2125 /* DRAM mode optimizations */
2126 sdram_enhanced_addressing_mode(sysinfo);
2127
2128 reg32 = MCHBAR32(FSBPMC3);
2129 reg32 &= ~(1 << 1);
2130 MCHBAR32(FSBPMC3) = reg32;
2131
2132 reg32 = MCHBAR32(SBTEST);
2133 reg32 &= ~(1 << 2);
2134 MCHBAR32(SBTEST) = reg32;
2135
2136 reg32 = MCHBAR32(SBOCC);
2137 reg32 &= 0xffbdb6ff;
2138 reg32 |= (0xbdb6 << 8) | (1 << 0);
2139 MCHBAR32(SBOCC) = reg32;
2140}
2141
2142static void sdram_power_management(struct sys_info *sysinfo)
2143{
2144 u8 reg8;
2145 u16 reg16;
2146 u32 reg32;
2147 int integrated_graphics = 1;
2148 int i;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002149
Stefan Reinauer278534d2008-10-29 04:51:07 +00002150 reg32 = MCHBAR32(C0DRT2);
2151 reg32 &= 0xffffff00;
2152 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002153 reg32 |= (1 << 5) | (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002154 MCHBAR32(C0DRT2) = reg32;
2155
2156 reg32 = MCHBAR32(C1DRT2);
2157 reg32 &= 0xffffff00;
2158 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002159 reg32 |= (1 << 5) | (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002160 MCHBAR32(C1DRT2) = reg32;
2161
2162 reg32 = MCHBAR32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002163
2164 reg32 |= (1 << 12) | (1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002165 MCHBAR32(C0DRC1) = reg32;
2166
2167 reg32 = MCHBAR32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002168
2169 reg32 |= (1 << 12) | (1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002170 MCHBAR32(C1DRC1) = reg32;
2171
Julius Wernercd49cce2019-03-05 16:53:33 -08002172 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002173 if (i945_silicon_revision() > 1) {
2174 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2175 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002176
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002177 MCHBAR16(UPMC1) = 0x1010 | peg_bits;
2178 } else {
2179 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2180 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002181
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002182 /* Rev 0 and 1 */
2183 MCHBAR16(UPMC1) = 0x0010 | peg_bits;
2184 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002185 }
2186
2187 reg16 = MCHBAR16(UPMC2);
2188 reg16 &= 0xfc00;
2189 reg16 |= 0x0100;
2190 MCHBAR16(UPMC2) = reg16;
2191
2192 MCHBAR32(UPMC3) = 0x000f06ff;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002193
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002194 for (i = 0; i < 5; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002195 MCHBAR32(UPMC3) &= ~(1 << 16);
2196 MCHBAR32(UPMC3) |= (1 << 16);
2197 }
2198
2199 MCHBAR32(GIPMC1) = 0x8000000c;
2200
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002201 reg16 = MCHBAR16(CPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002202 reg16 &= ~(7 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002203 if (i945_silicon_revision() > 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002204 reg16 |= (6 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002205 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002206 reg16 |= (4 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002207 MCHBAR16(CPCTL) = reg16;
2208
Stefan Reinauer30140a52009-03-11 16:20:39 +00002209#if 0
Stefan Reinauer278534d2008-10-29 04:51:07 +00002210 if ((MCHBAR32(ECO) & (1 << 16)) != 0) {
Stefan Reinauer30140a52009-03-11 16:20:39 +00002211#else
2212 if (i945_silicon_revision() != 0) {
2213#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002214 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002215 case 667:
2216 MCHBAR32(HGIPMC2) = 0x0d590d59; break;
2217 case 533:
2218 MCHBAR32(HGIPMC2) = 0x155b155b; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002219 }
2220 } else {
2221 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002222 case 667:
2223 MCHBAR32(HGIPMC2) = 0x09c409c4; break;
2224 case 533:
2225 MCHBAR32(HGIPMC2) = 0x0fa00fa0; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002226 }
2227 }
2228
2229 MCHBAR32(FSBPMC1) = 0x8000000c;
2230
2231 reg32 = MCHBAR32(C2C3TT);
2232 reg32 &= 0xffff0000;
2233 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002234 case 667:
2235 reg32 |= 0x0600; break;
2236 case 533:
2237 reg32 |= 0x0480; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002238 }
2239 MCHBAR32(C2C3TT) = reg32;
2240
2241 reg32 = MCHBAR32(C3C4TT);
2242 reg32 &= 0xffff0000;
2243 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002244 case 667:
2245 reg32 |= 0x0b80; break;
2246 case 533:
2247 reg32 |= 0x0980; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002248 }
2249 MCHBAR32(C3C4TT) = reg32;
2250
Arthur Heymans70a8e342017-03-09 11:30:23 +01002251 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002252 MCHBAR32(ECO) &= ~(1 << 16);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002253 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002254 MCHBAR32(ECO) |= (1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002255
2256#if 0
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002257
Arthur Heymans70a8e342017-03-09 11:30:23 +01002258 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002259 MCHBAR32(FSBPMC3) &= ~(1 << 29);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002260 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002261 MCHBAR32(FSBPMC3) |= (1 << 29);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002262#endif
2263 MCHBAR32(FSBPMC3) &= ~(1 << 29);
2264
2265 MCHBAR32(FSBPMC3) |= (1 << 21);
2266
2267 MCHBAR32(FSBPMC3) &= ~(1 << 19);
2268
2269 MCHBAR32(FSBPMC3) &= ~(1 << 13);
2270
2271 reg32 = MCHBAR32(FSBPMC4);
2272 reg32 &= ~(3 << 24);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002273 reg32 |= (2 << 24);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002274 MCHBAR32(FSBPMC4) = reg32;
2275
2276 MCHBAR32(FSBPMC4) |= (1 << 21);
2277
2278 MCHBAR32(FSBPMC4) |= (1 << 5);
2279
Arthur Heymans70a8e342017-03-09 11:30:23 +01002280 if ((i945_silicon_revision() < 2)) { /* || cpuid() = 0x6e8 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002281 /* stepping 0 and 1 or CPUID 6e8 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002282 MCHBAR32(FSBPMC4) &= ~(1 << 4);
2283 } else {
Stefan Reinauer30140a52009-03-11 16:20:39 +00002284 MCHBAR32(FSBPMC4) |= (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002285 }
2286
Arthur Heymans70a8e342017-03-09 11:30:23 +01002287 reg8 = pci_read_config8(PCI_DEV(0, 0x0, 0), 0xfc);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002288 reg8 |= (1 << 4);
2289 pci_write_config8(PCI_DEV(0, 0x0, 0), 0xfc, reg8);
2290
Arthur Heymans70a8e342017-03-09 11:30:23 +01002291 reg8 = pci_read_config8(PCI_DEV(0, 0x2, 0), 0xc1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002292 reg8 |= (1 << 2);
2293 pci_write_config8(PCI_DEV(0, 0x2, 0), 0xc1, reg8);
2294
Stefan Reinauerde3206a2010-02-22 06:09:43 +00002295#ifdef C2_SELF_REFRESH_DISABLE
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002296
Stefan Reinauer278534d2008-10-29 04:51:07 +00002297 if (integrated_graphics) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002298 printk(BIOS_DEBUG, "C2 self-refresh with IGD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002299 MCHBAR16(MIPMC4) = 0x0468;
2300 MCHBAR16(MIPMC5) = 0x046c;
2301 MCHBAR16(MIPMC6) = 0x046c;
2302 } else {
2303 MCHBAR16(MIPMC4) = 0x6468;
2304 MCHBAR16(MIPMC5) = 0x646c;
2305 MCHBAR16(MIPMC6) = 0x646c;
2306 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002307#else
2308 if (integrated_graphics) {
2309 MCHBAR16(MIPMC4) = 0x04f8;
2310 MCHBAR16(MIPMC5) = 0x04fc;
2311 MCHBAR16(MIPMC6) = 0x04fc;
2312 } else {
2313 MCHBAR16(MIPMC4) = 0x64f8;
2314 MCHBAR16(MIPMC5) = 0x64fc;
2315 MCHBAR16(MIPMC6) = 0x64fc;
2316 }
2317
2318#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002319
2320 reg32 = MCHBAR32(PMCFG);
2321 reg32 &= ~(3 << 17);
2322 reg32 |= (2 << 17);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002323 MCHBAR32(PMCFG) = reg32;
2324
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002325 MCHBAR32(PMCFG) |= (1 << 4);
2326
Stefan Reinauer278534d2008-10-29 04:51:07 +00002327 reg32 = MCHBAR32(0xc30);
2328 reg32 &= 0xffffff00;
2329 reg32 |= 0x01;
2330 MCHBAR32(0xc30) = reg32;
2331
2332 MCHBAR32(0xb18) &= ~(1 << 21);
2333}
2334
2335static void sdram_thermal_management(void)
2336{
Stefan Reinauer278534d2008-10-29 04:51:07 +00002337
Stefan Reinauer278534d2008-10-29 04:51:07 +00002338 MCHBAR8(TCO1) = 0x00;
2339 MCHBAR8(TCO0) = 0x00;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002340
2341 /* The Thermal Sensors for DIMMs at 0x50, 0x52 are at I2C addr
2342 * 0x30/0x32.
2343 */
2344
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002345 /* TODO This is not implemented yet. Volunteers? */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002346}
2347
2348static void sdram_save_receive_enable(void)
2349{
2350 int i;
2351 u32 reg32;
2352 u8 values[4];
2353
2354 /* The following values are stored to an unused CMOS
2355 * area and restored instead of recalculated in case
2356 * of an S3 resume.
2357 *
Arthur Heymans70a8e342017-03-09 11:30:23 +01002358 * C0WL0REOST [7:0] -> 8 bit
2359 * C1WL0REOST [7:0] -> 8 bit
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002360 * RCVENMT [11:8] [3:0] -> 8 bit
2361 * C0DRT1 [27:24] -> 4 bit
2362 * C1DRT1 [27:24] -> 4 bit
2363 */
2364
2365 values[0] = MCHBAR8(C0WL0REOST);
2366 values[1] = MCHBAR8(C1WL0REOST);
2367
2368 reg32 = MCHBAR32(RCVENMT);
2369 values[2] = (u8)((reg32 >> (8 - 4)) & 0xf0) | (reg32 & 0x0f);
2370
2371 reg32 = MCHBAR32(C0DRT1);
2372 values[3] = (reg32 >> 24) & 0x0f;
2373 reg32 = MCHBAR32(C1DRT1);
2374 values[3] |= (reg32 >> (24 - 4)) & 0xf0;
2375
2376 /* coreboot only uses bytes 0 - 127 for its CMOS values so far
Edwin Beasanteb50c7d2010-07-06 21:05:04 +00002377 * so we grab bytes 128 - 131 to save the receive enable values
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002378 */
2379
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002380 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002381 cmos_write(values[i], 128 + i);
2382}
2383
2384static void sdram_recover_receive_enable(void)
2385{
2386 int i;
2387 u32 reg32;
2388 u8 values[4];
2389
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002390 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002391 values[i] = cmos_read(128 + i);
2392
2393 MCHBAR8(C0WL0REOST) = values[0];
2394 MCHBAR8(C1WL0REOST) = values[1];
2395
2396 reg32 = MCHBAR32(RCVENMT);
2397 reg32 &= ~((0x0f << 8) | (0x0f << 0));
2398 reg32 |= ((u32)(values[2] & 0xf0) << (8 - 4)) | (values[2] & 0x0f);
2399 MCHBAR32(RCVENMT) = reg32;
2400
2401 reg32 = MCHBAR32(C0DRT1) & ~(0x0f << 24);
2402 reg32 |= (u32)(values[3] & 0x0f) << 24;
2403 MCHBAR32(C0DRT1) = reg32;
2404
2405 reg32 = MCHBAR32(C1DRT1) & ~(0x0f << 24);
2406 reg32 |= (u32)(values[3] & 0xf0) << (24 - 4);
2407 MCHBAR32(C1DRT1) = reg32;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002408}
2409
Stefan Reinauer278534d2008-10-29 04:51:07 +00002410static void sdram_program_receive_enable(struct sys_info *sysinfo)
2411{
2412 MCHBAR32(REPC) |= (1 << 0);
2413
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002414 /* Program Receive Enable Timings */
2415 if (sysinfo->boot_path == BOOT_PATH_RESUME) {
2416 sdram_recover_receive_enable();
2417 } else {
2418 receive_enable_adjust(sysinfo);
2419 sdram_save_receive_enable();
2420 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002421
2422 MCHBAR32(C0DRC1) |= (1 << 6);
2423 MCHBAR32(C1DRC1) |= (1 << 6);
2424 MCHBAR32(C0DRC1) &= ~(1 << 6);
2425 MCHBAR32(C1DRC1) &= ~(1 << 6);
2426
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002427 MCHBAR32(MIPMC3) |= (0x0f << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002428}
2429
2430/**
2431 * @brief Enable On-Die Termination for DDR2.
2432 *
2433 */
2434
2435static void sdram_on_die_termination(struct sys_info *sysinfo)
2436{
2437 static const u32 odt[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002438 0x00024911, 0xe0010000,
2439 0x00049211, 0xe0020000,
2440 0x0006db11, 0xe0030000,
Stefan Reinauer278534d2008-10-29 04:51:07 +00002441 };
2442
2443 u32 reg32;
2444 int cas;
2445
2446 reg32 = MCHBAR32(ODTC);
2447 reg32 &= ~(3 << 16);
2448 reg32 |= (1 << 14) | (1 << 6) | (2 << 16);
2449 MCHBAR32(ODTC) = reg32;
2450
Arthur Heymans70a8e342017-03-09 11:30:23 +01002451 if (!(sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED &&
2452 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)) {
Elyes HAOUAS38424982016-08-21 12:01:04 +02002453 printk(BIOS_DEBUG, "one dimm per channel config..\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002454
Stefan Reinauer278534d2008-10-29 04:51:07 +00002455 reg32 = MCHBAR32(C0ODT);
2456 reg32 &= ~(7 << 28);
2457 MCHBAR32(C0ODT) = reg32;
2458 reg32 = MCHBAR32(C1ODT);
2459 reg32 &= ~(7 << 28);
2460 MCHBAR32(C1ODT) = reg32;
2461 }
2462
2463 cas = sysinfo->cas;
2464
2465 reg32 = MCHBAR32(C0ODT) & 0xfff00000;
2466 reg32 |= odt[(cas-3) * 2];
2467 MCHBAR32(C0ODT) = reg32;
2468
2469 reg32 = MCHBAR32(C1ODT) & 0xfff00000;
2470 reg32 |= odt[(cas-3) * 2];
2471 MCHBAR32(C1ODT) = reg32;
2472
2473 reg32 = MCHBAR32(C0ODT + 4) & 0x1fc8ffff;
2474 reg32 |= odt[((cas-3) * 2) + 1];
2475 MCHBAR32(C0ODT + 4) = reg32;
2476
2477 reg32 = MCHBAR32(C1ODT + 4) & 0x1fc8ffff;
2478 reg32 |= odt[((cas-3) * 2) + 1];
2479 MCHBAR32(C1ODT + 4) = reg32;
2480}
2481
2482/**
2483 * @brief Enable clocks to populated sockets
2484 */
2485
2486static void sdram_enable_memory_clocks(struct sys_info *sysinfo)
2487{
2488 u8 clocks[2] = { 0, 0 };
2489
Julius Wernercd49cce2019-03-05 16:53:33 -08002490#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002491#define CLOCKS_WIDTH 2
Julius Wernercd49cce2019-03-05 16:53:33 -08002492#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002493#define CLOCKS_WIDTH 3
2494#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002495 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002496 clocks[0] |= (1 << CLOCKS_WIDTH)-1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002497
2498 if (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002499 clocks[0] |= ((1 << CLOCKS_WIDTH)-1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002500
2501 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002502 clocks[1] |= (1 << CLOCKS_WIDTH)-1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002503
2504 if (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002505 clocks[1] |= ((1 << CLOCKS_WIDTH)-1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002506
Julius Wernercd49cce2019-03-05 16:53:33 -08002507#if CONFIG(OVERRIDE_CLOCK_DISABLE)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002508 /* Usually system firmware turns off system memory clock signals
2509 * to unused SO-DIMM slots to reduce EMI and power consumption.
2510 * However, the Kontron 986LCD-M does not like unused clock
2511 * signals to be disabled.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002512 */
2513
2514 clocks[0] = 0xf; /* force all clock gate pairs to enable */
2515 clocks[1] = 0xf; /* force all clock gate pairs to enable */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002516#endif
2517
2518 MCHBAR8(C0DCLKDIS) = clocks[0];
2519 MCHBAR8(C1DCLKDIS) = clocks[1];
2520}
2521
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002522#define RTT_ODT_NONE 0
Arthur Heymans70a8e342017-03-09 11:30:23 +01002523#define RTT_ODT_50_OHM ((1 << 9) | (1 << 5))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002524#define RTT_ODT_75_OHM (1 << 5)
2525#define RTT_ODT_150_OHM (1 << 9)
2526
Arthur Heymans70a8e342017-03-09 11:30:23 +01002527#define EMRS_OCD_DEFAULT ((1 << 12) | (1 << 11) | (1 << 10))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002528
2529#define MRS_CAS_3 (3 << 7)
2530#define MRS_CAS_4 (4 << 7)
2531#define MRS_CAS_5 (5 << 7)
2532
2533#define MRS_TWR_3 (2 << 12)
2534#define MRS_TWR_4 (3 << 12)
2535#define MRS_TWR_5 (4 << 12)
2536
2537#define MRS_BT (1 << 6)
2538
2539#define MRS_BL4 (2 << 3)
2540#define MRS_BL8 (3 << 3)
2541
2542static void sdram_jedec_enable(struct sys_info *sysinfo)
2543{
2544 int i, nonzero;
2545 u32 bankaddr = 0, tmpaddr, mrsaddr = 0;
2546
2547 for (i = 0, nonzero = -1; i < 8; i++) {
Elyes HAOUAS01912202019-01-19 16:36:38 +01002548 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002549 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002550
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002551 printk(BIOS_DEBUG, "jedec enable sequence: bank %d\n", i);
Elyes HAOUAS01912202019-01-19 16:36:38 +01002552
2553 if (nonzero != -1) {
2554 if (sysinfo->interleaved && nonzero < 4 && i >= 4) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002555 bankaddr = 0x40;
Elyes HAOUAS01912202019-01-19 16:36:38 +01002556 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002557 printk(BIOS_DEBUG, "bankaddr from bank size of rank %d\n", nonzero);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002558 bankaddr += sysinfo->banksize[nonzero] <<
2559 (sysinfo->interleaved ? 26 : 25);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002560 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002561 }
2562
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002563 /* We have a bank with a non-zero size.. Remember it
Stefan Reinauer278534d2008-10-29 04:51:07 +00002564 * for the next offset we have to calculate
2565 */
2566 nonzero = i;
2567
2568 /* Get CAS latency set up */
2569 switch (sysinfo->cas) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002570 case 5:
2571 mrsaddr = MRS_CAS_5; break;
2572 case 4:
2573 mrsaddr = MRS_CAS_4; break;
2574 case 3:
2575 mrsaddr = MRS_CAS_3; break;
2576 default:
2577 die("Jedec Error (CAS).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002578 }
2579
2580 /* Get tWR set */
2581 switch (sysinfo->twr) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002582 case 5:
2583 mrsaddr |= MRS_TWR_5; break;
2584 case 4:
2585 mrsaddr |= MRS_TWR_4; break;
2586 case 3:
2587 mrsaddr |= MRS_TWR_3; break;
2588 default:
2589 die("Jedec Error (tWR).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002590 }
2591
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002592 /* Set "Burst Type" */
2593 mrsaddr |= MRS_BT;
2594
Stefan Reinauer278534d2008-10-29 04:51:07 +00002595 /* Interleaved */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002596 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002597 mrsaddr = mrsaddr << 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002598
2599 /* Only burst length 8 supported */
2600 mrsaddr |= MRS_BL8;
2601
2602 /* Apply NOP */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002603 PRINTK_DEBUG("Apply NOP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002604 do_ram_command(RAM_COMMAND_NOP);
2605 ram_read32(bankaddr);
2606
2607 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002608 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002609 do_ram_command(RAM_COMMAND_PRECHARGE);
2610 ram_read32(bankaddr);
2611
2612 /* Extended Mode Register Set (2) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002613 PRINTK_DEBUG("Extended Mode Register Set(2)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002614 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_2);
2615 ram_read32(bankaddr);
2616
2617 /* Extended Mode Register Set (3) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002618 PRINTK_DEBUG("Extended Mode Register Set(3)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002619 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_3);
2620 ram_read32(bankaddr);
2621
2622 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002623 PRINTK_DEBUG("Extended Mode Register Set\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002624 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2625 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002626 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002627 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002628 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002629 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002630 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002631 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002632 ram_read32(tmpaddr);
2633
2634 /* Mode Register Set: Reset DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002635 PRINTK_DEBUG("MRS: Reset DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002636 do_ram_command(RAM_COMMAND_MRS);
2637 tmpaddr = bankaddr;
2638 tmpaddr |= mrsaddr;
2639 /* Set DLL reset bit */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002640 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002641 tmpaddr |= (1 << 12);
2642 else
2643 tmpaddr |= (1 << 11);
2644 ram_read32(tmpaddr);
2645
2646 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002647 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002648 do_ram_command(RAM_COMMAND_PRECHARGE);
2649 ram_read32(bankaddr);
2650
2651 /* CAS before RAS Refresh */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002652 PRINTK_DEBUG("CAS before RAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002653 do_ram_command(RAM_COMMAND_CBR);
2654
2655 /* CBR wants two READs */
2656 ram_read32(bankaddr);
2657 ram_read32(bankaddr);
2658
2659 /* Mode Register Set: Enable DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002660 PRINTK_DEBUG("MRS: Enable DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002661 do_ram_command(RAM_COMMAND_MRS);
2662
2663 tmpaddr = bankaddr;
2664 tmpaddr |= mrsaddr;
2665 ram_read32(tmpaddr);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002666
Stefan Reinauer278534d2008-10-29 04:51:07 +00002667 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002668 PRINTK_DEBUG("Extended Mode Register Set: ODT/OCD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002669 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002670
Stefan Reinauer278534d2008-10-29 04:51:07 +00002671 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002672 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002673 tmpaddr |= RTT_ODT_75_OHM | EMRS_OCD_DEFAULT;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002674 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002675 tmpaddr |= ((RTT_ODT_150_OHM | EMRS_OCD_DEFAULT) << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002676 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002677 tmpaddr |= RTT_ODT_150_OHM | EMRS_OCD_DEFAULT;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002678 ram_read32(tmpaddr);
2679
2680 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002681 PRINTK_DEBUG("Extended Mode Register Set: OCD Exit\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002682 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2683
2684 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002685 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002686 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002687 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002688 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002689 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002690 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002691 ram_read32(tmpaddr);
2692 }
2693}
2694
2695static void sdram_init_complete(void)
2696{
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002697 PRINTK_DEBUG("Normal Operation\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002698 do_ram_command(RAM_COMMAND_NORMAL);
2699}
2700
2701static void sdram_setup_processor_side(void)
2702{
2703 if (i945_silicon_revision() == 0)
2704 MCHBAR32(FSBPMC3) |= (1 << 2);
2705
2706 MCHBAR8(0xb00) |= 1;
2707
2708 if (i945_silicon_revision() == 0)
2709 MCHBAR32(SLPCTL) |= (1 << 8);
2710}
2711
Stefan Reinauer278534d2008-10-29 04:51:07 +00002712/**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002713 * @param boot_path: 0 = normal, 1 = reset, 2 = resume from s3
Martin Rothf4cb4122015-01-06 10:27:39 -07002714 * @param spd_addresses pointer to a list of SPD addresses
Stefan Reinauer278534d2008-10-29 04:51:07 +00002715 */
Sven Schnelle541269b2011-02-21 09:39:17 +00002716void sdram_initialize(int boot_path, const u8 *spd_addresses)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002717{
2718 struct sys_info sysinfo;
Arthur Heymans0ab49042017-02-06 22:40:14 +01002719 u8 reg8;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002720
Patrick Georgi771328f2015-07-13 19:24:07 +02002721 timestamp_add_now(TS_BEFORE_INITRAM);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002722 printk(BIOS_DEBUG, "Setting up RAM controller.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002723
2724 memset(&sysinfo, 0, sizeof(sysinfo));
2725
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002726 sysinfo.boot_path = boot_path;
Sven Schnelle541269b2011-02-21 09:39:17 +00002727 sysinfo.spd_addresses = spd_addresses;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002728
Stefan Reinauer278534d2008-10-29 04:51:07 +00002729 /* Look at the type of DIMMs and verify all DIMMs are x8 or x16 width */
2730 sdram_get_dram_configuration(&sysinfo);
2731
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002732 /* If error, do cold boot */
2733 sdram_detect_errors(&sysinfo);
2734
Stefan Reinauer278534d2008-10-29 04:51:07 +00002735 /* Program PLL settings */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002736 sdram_program_pll_settings(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002737
Arthur Heymans18537812016-12-28 21:20:45 +01002738 /*
2739 * Program Graphics Frequency
2740 * Set core display and render clock on 945GC to the max
2741 */
Julius Wernercd49cce2019-03-05 16:53:33 -08002742 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM))
Arthur Heymans18537812016-12-28 21:20:45 +01002743 sdram_program_graphics_frequency(&sysinfo);
2744 else
2745 pci_write_config16(PCI_DEV(0, 2, 0), GCFC, 0x0534);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002746
2747 /* Program System Memory Frequency */
2748 sdram_program_memory_frequency(&sysinfo);
2749
2750 /* Determine Mode of Operation (Interleaved etc) */
2751 sdram_set_channel_mode(&sysinfo);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002752
Stefan Reinauer278534d2008-10-29 04:51:07 +00002753 /* Program Clock Crossing values */
2754 sdram_program_clock_crossing();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002755
Stefan Reinauer278534d2008-10-29 04:51:07 +00002756 /* Disable fast dispatch */
2757 sdram_disable_fast_dispatch();
2758
2759 /* Enable WIODLL Power Down in ACPI states */
2760 MCHBAR32(C0DMC) |= (1 << 24);
2761 MCHBAR32(C1DMC) |= (1 << 24);
2762
2763 /* Program DRAM Row Boundary/Attribute Registers */
2764
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002765 /* program row size DRB and set TOLUD */
2766 sdram_program_row_boundaries(&sysinfo);
2767
2768 /* program page size DRA */
2769 sdram_set_row_attributes(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002770
2771 /* Program CxBNKARC */
2772 sdram_set_bank_architecture(&sysinfo);
2773
2774 /* Program DRAM Timing and Control registers based on SPD */
2775 sdram_set_timing_and_control(&sysinfo);
2776
2777 /* On-Die Termination Adjustment */
2778 sdram_on_die_termination(&sysinfo);
2779
2780 /* Pre Jedec Initialization */
2781 sdram_pre_jedec_initialization();
2782
2783 /* Perform System Memory IO Initialization */
2784 sdram_initialize_system_memory_io(&sysinfo);
2785
2786 /* Perform System Memory IO Buffer Enable */
2787 sdram_enable_system_memory_io(&sysinfo);
2788
2789 /* Enable System Memory Clocks */
2790 sdram_enable_memory_clocks(&sysinfo);
2791
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002792 if (boot_path == BOOT_PATH_NORMAL) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002793 /* Jedec Initialization sequence */
2794 sdram_jedec_enable(&sysinfo);
2795 }
2796
2797 /* Program Power Management Registers */
2798 sdram_power_management(&sysinfo);
2799
2800 /* Post Jedec Init */
2801 sdram_post_jedec_initialization(&sysinfo);
2802
2803 /* Program DRAM Throttling */
2804 sdram_thermal_management();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002805
Stefan Reinauer278534d2008-10-29 04:51:07 +00002806 /* Normal Operations */
Stefan Reinaueraca6ec62009-10-26 17:12:21 +00002807 sdram_init_complete();
Stefan Reinauer278534d2008-10-29 04:51:07 +00002808
2809 /* Program Receive Enable Timings */
2810 sdram_program_receive_enable(&sysinfo);
2811
2812 /* Enable Periodic RCOMP */
2813 sdram_enable_rcomp();
2814
2815 /* Tell ICH7 that we're done */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002816 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002817 reg8 &= ~(1 << 7);
2818 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa2, reg8);
2819
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002820 printk(BIOS_DEBUG, "RAM initialization finished.\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002821
Stefan Reinauer278534d2008-10-29 04:51:07 +00002822 sdram_setup_processor_side();
Patrick Georgi771328f2015-07-13 19:24:07 +02002823 timestamp_add_now(TS_AFTER_INITRAM);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002824}