blob: c668e7982107a348056586cff88c7fdfcfc9348d [file] [log] [blame]
Angel Pons4b429832020-04-02 23:48:50 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002
Patrick Georgid0835952010-10-05 09:07:10 +00003#include <console/console.h>
Kyösti Mälkki7fbed222019-07-11 08:14:07 +03004#include <delay.h>
Arthur Heymans885c2892016-10-03 17:16:48 +02005#include <device/pci_def.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +02006#include <device/pci_ops.h>
Elyes HAOUAS420d7e02019-04-21 18:39:34 +02007#include <cf9_reset.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02008#include <device/mmio.h>
Arthur Heymans885c2892016-10-03 17:16:48 +02009#include <device/device.h>
Julius Werner7a8a4ab2015-05-22 16:26:40 -070010#include <lib.h>
Edwin Beasanteb50c7d2010-07-06 21:05:04 +000011#include <pc80/mc146818rtc.h>
Stefan Reinauer278534d2008-10-29 04:51:07 +000012#include <spd.h>
Patrick Georgid0835952010-10-05 09:07:10 +000013#include <string.h>
Stefan Reinauer278534d2008-10-29 04:51:07 +000014#include "raminit.h"
15#include "i945.h"
Arthur Heymans885c2892016-10-03 17:16:48 +020016#include "chip.h"
Arthur Heymans0ab49042017-02-06 22:40:14 +010017#include <device/dram/ddr2.h>
Patrick Georgi771328f2015-07-13 19:24:07 +020018#include <timestamp.h>
Rudolf Marekc4369532010-12-13 19:59:13 +000019
Stefan Reinauer278534d2008-10-29 04:51:07 +000020/* Debugging macros. */
Julius Wernercd49cce2019-03-05 16:53:33 -080021#if CONFIG(DEBUG_RAM_SETUP)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000022#define PRINTK_DEBUG(x...) printk(BIOS_DEBUG, x)
Stefan Reinauer278534d2008-10-29 04:51:07 +000023#else
24#define PRINTK_DEBUG(x...)
25#endif
26
Stefan Reinauer278534d2008-10-29 04:51:07 +000027#define RAM_INITIALIZATION_COMPLETE (1 << 19)
28
29#define RAM_COMMAND_SELF_REFRESH (0x0 << 16)
30#define RAM_COMMAND_NOP (0x1 << 16)
31#define RAM_COMMAND_PRECHARGE (0x2 << 16)
32#define RAM_COMMAND_MRS (0x3 << 16)
33#define RAM_COMMAND_EMRS (0x4 << 16)
34#define RAM_COMMAND_CBR (0x6 << 16)
35#define RAM_COMMAND_NORMAL (0x7 << 16)
36
37#define RAM_EMRS_1 (0x0 << 21)
38#define RAM_EMRS_2 (0x1 << 21)
39#define RAM_EMRS_3 (0x2 << 21)
40
Arthur Heymans885c2892016-10-03 17:16:48 +020041#define DEFAULT_PCI_MMIO_SIZE 768
Sven Schnelle541269b2011-02-21 09:39:17 +000042static int get_dimm_spd_address(struct sys_info *sysinfo, int device)
43{
44 if (sysinfo->spd_addresses)
45 return sysinfo->spd_addresses[device];
46 else
47 return DIMM0 + device;
48
49}
50
Stefan Reinauerbc8613e2010-08-25 18:35:42 +000051static __attribute__((noinline)) void do_ram_command(u32 command)
Stefan Reinauer278534d2008-10-29 04:51:07 +000052{
53 u32 reg32;
54
55 reg32 = MCHBAR32(DCC);
Angel Pons30492572020-06-11 13:24:54 +020056 reg32 &= ~((3 << 21) | (1 << 20) | (1 << 19) | (7 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +000057 reg32 |= command;
58
59 /* Also set Init Complete */
60 if (command == RAM_COMMAND_NORMAL)
61 reg32 |= RAM_INITIALIZATION_COMPLETE;
62
63 PRINTK_DEBUG(" Sending RAM command 0x%08x", reg32);
64
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +010065 MCHBAR32(DCC) = reg32; /* This is the actual magic */
Stefan Reinauer278534d2008-10-29 04:51:07 +000066
Stefan Reinauer779b3e32008-11-10 15:43:37 +000067 PRINTK_DEBUG("...done\n");
Stefan Reinauerd058ad12010-08-26 12:43:58 +000068
69 udelay(1);
Stefan Reinauer278534d2008-10-29 04:51:07 +000070}
71
Stefan Reinauer278534d2008-10-29 04:51:07 +000072static void ram_read32(u32 offset)
73{
Elyes HAOUAS15279a92016-07-28 21:05:26 +020074 PRINTK_DEBUG(" RAM read: %08x\n", offset);
Stefan Reinauer278534d2008-10-29 04:51:07 +000075
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080076 read32((void *)offset);
Stefan Reinauer278534d2008-10-29 04:51:07 +000077}
78
Stefan Reinauer3c0bfaf2010-12-27 11:34:57 +000079void sdram_dump_mchbar_registers(void)
Stefan Reinauer278534d2008-10-29 04:51:07 +000080{
81 int i;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000082 printk(BIOS_DEBUG, "Dumping MCHBAR Registers\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +000083
Arthur Heymans70a8e342017-03-09 11:30:23 +010084 for (i = 0; i < 0xfff; i += 4) {
Stefan Reinauer278534d2008-10-29 04:51:07 +000085 if (MCHBAR32(i) == 0)
86 continue;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000087 printk(BIOS_DEBUG, "0x%04x: 0x%08x\n", i, MCHBAR32(i));
Stefan Reinauer278534d2008-10-29 04:51:07 +000088 }
89}
Stefan Reinauer278534d2008-10-29 04:51:07 +000090
Stefan Reinauer24b4df52010-01-17 13:47:35 +000091static int memclk(void)
92{
Julius Wernercd49cce2019-03-05 16:53:33 -080093 int offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Elyes HAOUASc9848a82016-10-09 20:24:20 +020094
Stefan Reinauer24b4df52010-01-17 13:47:35 +000095 switch (((MCHBAR32(CLKCFG) >> 4) & 7) - offset) {
96 case 1: return 400;
97 case 2: return 533;
98 case 3: return 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +010099 default:
Elyes HAOUAS3cd43272020-03-05 22:01:17 +0100100 printk(BIOS_DEBUG, "%s: unknown register value %x\n", __func__,
Arthur Heymans70a8e342017-03-09 11:30:23 +0100101 ((MCHBAR32(CLKCFG) >> 4) & 7) - offset);
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000102 }
103 return -1;
104}
105
Peter Stuge76d91432010-10-01 10:02:33 +0000106static u16 fsbclk(void)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000107{
Julius Wernercd49cce2019-03-05 16:53:33 -0800108 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200109 switch (MCHBAR32(CLKCFG) & 7) {
110 case 0: return 400;
111 case 1: return 533;
112 case 3: return 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100113 default:
Elyes HAOUAS3cd43272020-03-05 22:01:17 +0100114 printk(BIOS_DEBUG, "%s: unknown register value %x\n", __func__,
Arthur Heymans70a8e342017-03-09 11:30:23 +0100115 MCHBAR32(CLKCFG) & 7);
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200116 }
117 return 0xffff;
Julius Wernercd49cce2019-03-05 16:53:33 -0800118 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200119 switch (MCHBAR32(CLKCFG) & 7) {
120 case 0: return 1066;
121 case 1: return 533;
122 case 2: return 800;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100123 default:
Elyes HAOUAS3cd43272020-03-05 22:01:17 +0100124 printk(BIOS_DEBUG, "%s: unknown register value %x\n", __func__,
Arthur Heymans70a8e342017-03-09 11:30:23 +0100125 MCHBAR32(CLKCFG) & 7);
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200126 }
127 return 0xffff;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000128 }
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000129}
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000130
Stefan Reinauer278534d2008-10-29 04:51:07 +0000131static int sdram_capabilities_max_supported_memory_frequency(void)
132{
133 u32 reg32;
134
Patrick Georgi77d66832010-10-01 08:02:45 +0000135#if CONFIG_MAXIMUM_SUPPORTED_FREQUENCY
136 return CONFIG_MAXIMUM_SUPPORTED_FREQUENCY;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000137#endif
138
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000139 reg32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000140 reg32 &= (7 << 0);
141
142 switch (reg32) {
143 case 4: return 400;
144 case 3: return 533;
145 case 2: return 667;
146 }
147 /* Newer revisions of this chipset rather support faster memory clocks,
148 * so if it's a reserved value, return the fastest memory clock that we
149 * know of and can handle
150 */
151 return 667;
152}
153
154/**
155 * @brief determine whether chipset is capable of dual channel interleaved mode
156 *
157 * @return 1 if interleaving is supported, 0 otherwise
158 */
159static int sdram_capabilities_interleave(void)
160{
161 u32 reg32;
162
Arthur Heymans70a8e342017-03-09 11:30:23 +0100163 reg32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000164 reg32 >>= 25;
165 reg32 &= 1;
166
167 return (!reg32);
168}
169
170/**
171 * @brief determine whether chipset is capable of two memory channels
172 *
173 * @return 1 if dual channel operation is supported, 0 otherwise
174 */
175static int sdram_capabilities_dual_channel(void)
176{
177 u32 reg32;
178
Arthur Heymans70a8e342017-03-09 11:30:23 +0100179 reg32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000180 reg32 >>= 24;
181 reg32 &= 1;
182
183 return (!reg32);
184}
185
186static int sdram_capabilities_enhanced_addressing_xor(void)
187{
188 u8 reg8;
189
190 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
191 reg8 &= (1 << 7);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000192
Stefan Reinauer278534d2008-10-29 04:51:07 +0000193 return (!reg8);
194}
195
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100196/* TODO check if we ever need this function */
Stefan Reinauer53b0ea42010-03-22 11:50:52 +0000197#if 0
Stefan Reinauer278534d2008-10-29 04:51:07 +0000198static int sdram_capabilities_MEM4G_disable(void)
199{
200 u8 reg8;
201
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000202 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000203 reg8 &= (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000204
Stefan Reinauer278534d2008-10-29 04:51:07 +0000205 return (reg8 != 0);
206}
Stefan Reinauer53b0ea42010-03-22 11:50:52 +0000207#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +0000208
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000209#define GFX_FREQUENCY_CAP_166MHZ 0x04
210#define GFX_FREQUENCY_CAP_200MHZ 0x03
211#define GFX_FREQUENCY_CAP_250MHZ 0x02
212#define GFX_FREQUENCY_CAP_ALL 0x00
213
214static int sdram_capabilities_core_frequencies(void)
215{
216 u8 reg8;
217
218 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
219 reg8 &= (1 << 3) | (1 << 2) | (1 << 1);
220 reg8 >>= 1;
221
Arthur Heymans70a8e342017-03-09 11:30:23 +0100222 return reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000223}
224
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000225static void sdram_detect_errors(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000226{
227 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000228 u8 do_reset = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000229
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100230 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000231
Angel Pons30492572020-06-11 13:24:54 +0200232 if (reg8 & ((1 << 7) | (1 << 2))) {
233 if (reg8 & (1 << 2)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000234 printk(BIOS_DEBUG, "SLP S4# Assertion Width Violation.\n");
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000235 /* Write back clears bit 2 */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100236 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000237 do_reset = 1;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000238
Stefan Reinauer278534d2008-10-29 04:51:07 +0000239 }
240
Angel Pons30492572020-06-11 13:24:54 +0200241 if (reg8 & (1 << 7)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000242 printk(BIOS_DEBUG, "DRAM initialization was interrupted.\n");
Angel Pons30492572020-06-11 13:24:54 +0200243 reg8 &= ~(1 << 7);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100244 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000245 do_reset = 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000246 }
247
248 /* Set SLP_S3# Assertion Stretch Enable */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100249 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000250 reg8 |= (1 << 3);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100251 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000252
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000253 if (do_reset) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000254 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200255 full_reset();
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000256 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000257 }
258
259 /* Set DRAM initialization bit in ICH7 */
Angel Ponse3c68d22020-06-08 12:09:03 +0200260 pci_or_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, 1 << 7);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000261
Peter Stuge751508a2012-01-27 22:17:09 +0100262 /* clear self refresh status if check is disabled or not a resume */
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200263 if (!CONFIG(CHECK_SLFRCS_ON_RESUME) || sysinfo->boot_path != BOOT_PATH_RESUME) {
Patrick Georgi86a11102013-03-15 14:11:37 +0100264 MCHBAR8(SLFRCS) |= 3;
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000265 } else {
266 /* Validate self refresh config */
267 if (((sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED) ||
268 (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)) &&
Angel Pons30492572020-06-11 13:24:54 +0200269 !(MCHBAR8(SLFRCS) & (1 << 0))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000270 do_reset = 1;
271 }
272 if (((sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED) ||
273 (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) &&
Angel Pons30492572020-06-11 13:24:54 +0200274 !(MCHBAR8(SLFRCS) & (1 << 1))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000275 do_reset = 1;
276 }
277 }
278
279 if (do_reset) {
280 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200281 full_reset();
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000282 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000283}
Stefan Reinauer278534d2008-10-29 04:51:07 +0000284
Arthur Heymans0ab49042017-02-06 22:40:14 +0100285struct timings {
286 u32 min_tCLK_cas[8];
287 u32 min_tRAS;
288 u32 min_tRP;
289 u32 min_tRCD;
290 u32 min_tWR;
291 u32 min_tRFC;
292 u32 max_tRR;
293 u8 cas_mask;
294};
Stefan Reinauer278534d2008-10-29 04:51:07 +0000295
Arthur Heymans0ab49042017-02-06 22:40:14 +0100296/**
297 * @brief loop over dimms and save maximal timings
298 */
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200299static void gather_common_timing(struct sys_info *sysinfo, struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000300{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100301
302 int i, j;
303 u8 raw_spd[SPD_SIZE_MAX_DDR2];
304 u8 dimm_mask = 0;
305
306 memset(saved_timings, 0, sizeof(*saved_timings));
307 saved_timings->max_tRR = UINT32_MAX;
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200308 saved_timings->cas_mask = SPD_CAS_LATENCY_DDR2_3 | SPD_CAS_LATENCY_DDR2_4
309 | SPD_CAS_LATENCY_DDR2_5;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000310
311 /**
312 * i945 supports two DIMMs, in two configurations:
313 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000314 * - single channel with two DIMMs
315 * - dual channel with one DIMM per channel
Stefan Reinauer278534d2008-10-29 04:51:07 +0000316 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000317 * In practice dual channel mainboards have their SPD at 0x50/0x52
318 * whereas single channel configurations have their SPD at 0x50/0x51.
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000319 *
Stefan Reinauer278534d2008-10-29 04:51:07 +0000320 * The capability register knows a lot about the channel configuration
Uwe Hermannd773fd32010-11-20 20:23:08 +0000321 * but for now we stick with the information we gather via SPD.
Stefan Reinauer278534d2008-10-29 04:51:07 +0000322 */
323
Arthur Heymans0ab49042017-02-06 22:40:14 +0100324 printk(BIOS_DEBUG, "This mainboard supports ");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000325 if (sdram_capabilities_dual_channel()) {
326 sysinfo->dual_channel = 1;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100327 printk(BIOS_DEBUG, "Dual Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000328 } else {
329 sysinfo->dual_channel = 0;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100330 printk(BIOS_DEBUG, "only Single Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000331 }
332
Stefan Reinauer278534d2008-10-29 04:51:07 +0000333
Arthur Heymans70a8e342017-03-09 11:30:23 +0100334 for (i = 0; i < (2 * DIMM_SOCKETS); i++) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100335 int device = get_dimm_spd_address(sysinfo, i), bytes_read;
Arthur Heymansfc31e442018-02-12 15:12:34 +0100336 struct dimm_attr_ddr2_st dimm_info;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000337
338 /* Initialize the socket information with a sane value */
339 sysinfo->dimm[i] = SYSINFO_DIMM_NOT_POPULATED;
340
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000341 /* Dual Channel not supported, but Channel 1? Bail out */
342 if (!sdram_capabilities_dual_channel() && (i >> 1))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000343 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000344
Kyösti Mälkkibd659852020-01-05 20:00:18 +0200345 if (smbus_read_byte(device, SPD_MEMORY_TYPE) !=
Arthur Heymans0ab49042017-02-06 22:40:14 +0100346 SPD_MEMORY_TYPE_SDRAM_DDR2) {
347 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: N/A\n",
348 (i >> 1), (i & 1));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000349 continue;
350 }
351
Arthur Heymans0ab49042017-02-06 22:40:14 +0100352 /*
353 * spd_decode_ddr2() needs a 128-byte sized array but
354 * only the first 64 bytes contain data needed for raminit.
355 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000356
Kyösti Mälkkic01a5052019-01-30 09:39:23 +0200357 bytes_read = i2c_eeprom_read(device, 0, 64, raw_spd);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100358 printk(BIOS_DEBUG, "Reading SPD using i2c block operation.\n");
Julius Wernercd49cce2019-03-05 16:53:33 -0800359 if (CONFIG(DEBUG_RAM_SETUP) && bytes_read > 0)
Arthur Heymans0ab49042017-02-06 22:40:14 +0100360 hexdump(raw_spd, bytes_read);
Arthur Heymans56619452017-09-21 09:12:42 +0200361 if (bytes_read != 64) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100362 /* Try again with SMBUS byte read */
363 printk(BIOS_DEBUG, "i2c block operation failed,"
Paul Menzel105e3682017-09-21 08:11:05 +0200364 " trying smbus byte operation.\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100365 for (j = 0; j < 64; j++)
Kyösti Mälkkibd659852020-01-05 20:00:18 +0200366 raw_spd[j] = smbus_read_byte(device, j);
Julius Wernercd49cce2019-03-05 16:53:33 -0800367 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100368 hexdump(raw_spd, 64);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100369 }
Arthur Heymans56619452017-09-21 09:12:42 +0200370
371 if (spd_decode_ddr2(&dimm_info, raw_spd) != SPD_STATUS_OK) {
372 printk(BIOS_WARNING, "Encountered problems with SPD, "
373 "skipping this DIMM.\n");
374 continue;
375 }
376
Julius Wernercd49cce2019-03-05 16:53:33 -0800377 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100378 dram_print_spd_ddr2(&dimm_info);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000379
Arthur Heymans0ab49042017-02-06 22:40:14 +0100380 if (dimm_info.flags.is_ecc)
381 die("\nError: ECC memory not supported by this chipset\n");
382
383 if (spd_dimm_is_registered_ddr2(dimm_info.dimm_type))
384 die("\nError: Registered memory not supported by this chipset\n");
385
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200386 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: ", (i >> 1), (i & 1));
Arthur Heymans0ab49042017-02-06 22:40:14 +0100387 /**
388 * There are 5 different possible populations for a DIMM socket:
389 * 0. x16 double ranked (X16DS)
390 * 1. x8 double ranked (X8DS)
391 * 2. x16 single ranked (X16SS)
392 * 3. x8 double stacked (X8DDS)
393 * 4. Unpopulated
394 */
395 switch (dimm_info.width) {
396 case 8:
397 switch (dimm_info.ranks) {
398 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000399 printk(BIOS_DEBUG, "x8DDS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000400 sysinfo->dimm[i] = SYSINFO_DIMM_X8DDS;
401 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100402 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000403 printk(BIOS_DEBUG, "x8DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000404 sysinfo->dimm[i] = SYSINFO_DIMM_X8DS;
405 break;
406 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000407 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000408 }
409 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100410 case 16:
411 switch (dimm_info.ranks) {
412 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000413 printk(BIOS_DEBUG, "x16DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000414 sysinfo->dimm[i] = SYSINFO_DIMM_X16DS;
415 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100416 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000417 printk(BIOS_DEBUG, "x16SS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000418 sysinfo->dimm[i] = SYSINFO_DIMM_X16SS;
419 break;
420 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000421 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000422 }
423 break;
424 default:
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000425 die("Unsupported DDR-II memory width.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000426 }
427
Arthur Heymans0ab49042017-02-06 22:40:14 +0100428 /* Is the current DIMM a stacked DIMM? */
429 if (dimm_info.flags.stacked)
430 sysinfo->package = SYSINFO_PACKAGE_STACKED;
431
432 if (!dimm_info.flags.bl8)
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100433 die("Only DDR-II RAM with burst length 8 is supported.\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100434
435 if (dimm_info.ranksize_mb < 128)
436 die("DDR-II rank size smaller than 128MB is not supported.\n");
437
438 sysinfo->banksize[i * 2] = dimm_info.ranksize_mb / 32;
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200439 printk(BIOS_DEBUG, "DIMM %d side 0 = %d MB\n", i, sysinfo->banksize[i * 2] * 32);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100440 if (dimm_info.ranks == 2) {
441 sysinfo->banksize[(i * 2) + 1] =
442 dimm_info.ranksize_mb / 32;
443 printk(BIOS_DEBUG, "DIMM %d side 1 = %d MB\n",
444 i, sysinfo->banksize[(i * 2) + 1] * 32);
445 }
446
447
448 sysinfo->rows[i] = dimm_info.row_bits;
449 sysinfo->cols[i] = dimm_info.col_bits;
450 sysinfo->banks[i] = dimm_info.banks;
451
452 /* int min_tRAS, min_tRP, min_tRCD, min_tWR, min_tRFC; */
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200453 saved_timings->min_tRAS = MAX(saved_timings->min_tRAS, dimm_info.tRAS);
454 saved_timings->min_tRP = MAX(saved_timings->min_tRP, dimm_info.tRP);
455 saved_timings->min_tRCD = MAX(saved_timings->min_tRCD, dimm_info.tRCD);
456 saved_timings->min_tWR = MAX(saved_timings->min_tWR, dimm_info.tWR);
457 saved_timings->min_tRFC = MAX(saved_timings->min_tRFC, dimm_info.tRFC);
458 saved_timings->max_tRR = MIN(saved_timings->max_tRR, dimm_info.tRR);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100459 saved_timings->cas_mask &= dimm_info.cas_supported;
460 for (j = 0; j < 8; j++) {
461 if (!(saved_timings->cas_mask & (1 << j)))
462 saved_timings->min_tCLK_cas[j] = 0;
463 else
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200464 saved_timings->min_tCLK_cas[j] = MAX(dimm_info.cycle_time[j],
Arthur Heymans0ab49042017-02-06 22:40:14 +0100465 saved_timings->min_tCLK_cas[j]);
466 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000467 dimm_mask |= (1 << i);
468 }
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200469 if (!dimm_mask)
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000470 die("No memory installed.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000471
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200472 if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1)))
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100473 /* FIXME: Possibly does not boot in this case */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000474 printk(BIOS_INFO, "Channel 0 has no memory populated.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000475}
476
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200477static void choose_tclk(struct sys_info *sysinfo, struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000478{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100479 u32 ctrl_min_tclk;
480 int try_cas;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000481
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200482 ctrl_min_tclk = 2 * 256 * 1000 / sdram_capabilities_max_supported_memory_frequency();
Arthur Heymans0ab49042017-02-06 22:40:14 +0100483 normalize_tck(&ctrl_min_tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000484
Arthur Heymans0ab49042017-02-06 22:40:14 +0100485 try_cas = spd_get_msbs(saved_timings->cas_mask);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000486
Arthur Heymans0ab49042017-02-06 22:40:14 +0100487 while (saved_timings->cas_mask & (1 << try_cas) && try_cas > 0) {
488 sysinfo->cas = try_cas;
489 sysinfo->tclk = saved_timings->min_tCLK_cas[try_cas];
490 if (sysinfo->tclk >= ctrl_min_tclk &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200491 saved_timings->min_tCLK_cas[try_cas] !=
492 saved_timings->min_tCLK_cas[try_cas - 1])
Stefan Reinauer278534d2008-10-29 04:51:07 +0000493 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100494 try_cas--;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000495 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000496
Arthur Heymans0ab49042017-02-06 22:40:14 +0100497 normalize_tck(&sysinfo->tclk);
498
499 if ((sysinfo->cas < 3) || (sysinfo->tclk == 0))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000500 die("Could not find common memory frequency and CAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000501
Arthur Heymans0ab49042017-02-06 22:40:14 +0100502 /*
503 * The loop can still results in a timing too fast for the
504 * memory controller.
505 */
506 if (sysinfo->tclk < ctrl_min_tclk)
507 sysinfo->tclk = ctrl_min_tclk;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000508
Arthur Heymans0ab49042017-02-06 22:40:14 +0100509 switch (sysinfo->tclk) {
510 case TCK_200MHZ:
511 sysinfo->memory_frequency = 400;
512 break;
513 case TCK_266MHZ:
514 sysinfo->memory_frequency = 533;
515 break;
516 case TCK_333MHZ:
517 sysinfo->memory_frequency = 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100518 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000519 }
520
Arthur Heymans0ab49042017-02-06 22:40:14 +0100521 printk(BIOS_DEBUG,
522 "Memory will be driven at %dMT with CAS=%d clocks\n",
523 sysinfo->memory_frequency, sysinfo->cas);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000524}
525
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200526static void derive_timings(struct sys_info *sysinfo, struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000527{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100528 sysinfo->tras = DIV_ROUND_UP(saved_timings->min_tRAS, sysinfo->tclk);
529 if (sysinfo->tras > 0x18)
530 die("DDR-II Module does not support this frequency (tRAS error)\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000531
Arthur Heymans0ab49042017-02-06 22:40:14 +0100532 sysinfo->trp = DIV_ROUND_UP(saved_timings->min_tRP, sysinfo->tclk);
533 if (sysinfo->trp > 6)
534 die("DDR-II Module does not support this frequency (tRP error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000535
Arthur Heymans0ab49042017-02-06 22:40:14 +0100536 sysinfo->trcd = DIV_ROUND_UP(saved_timings->min_tRCD, sysinfo->tclk);
537 if (sysinfo->trcd > 6)
538 die("DDR-II Module does not support this frequency (tRCD error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000539
Arthur Heymans0ab49042017-02-06 22:40:14 +0100540 sysinfo->twr = DIV_ROUND_UP(saved_timings->min_tWR, sysinfo->tclk);
541 if (sysinfo->twr > 5)
542 die("DDR-II Module does not support this frequency (tWR error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000543
Arthur Heymans0ab49042017-02-06 22:40:14 +0100544 sysinfo->trfc = DIV_ROUND_UP(saved_timings->min_tRFC, sysinfo->tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000545
Arthur Heymans0ab49042017-02-06 22:40:14 +0100546 printk(BIOS_DEBUG, "tRAS = %d cycles\n", sysinfo->tras);
547 printk(BIOS_DEBUG, "tRP = %d cycles\n", sysinfo->trp);
548 printk(BIOS_DEBUG, "tRCD = %d cycles\n", sysinfo->trcd);
549 printk(BIOS_DEBUG, "tWR = %d cycles\n", sysinfo->twr);
550 printk(BIOS_DEBUG, "tRFC = %d cycles\n", sysinfo->trfc);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000551
Arthur Heymans0ab49042017-02-06 22:40:14 +0100552 /* Refresh is slower than 15.6us, use 15.6us */
553 /* tRR is decoded in units of 1/256us */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000554
Arthur Heymans0ab49042017-02-06 22:40:14 +0100555#define T_RR_7_8US 2000000
556#define T_RR_15_6US 4000000
557#define REFRESH_7_8US 1
558#define REFRESH_15_6US 0
Stefan Reinauer278534d2008-10-29 04:51:07 +0000559
Arthur Heymans0ab49042017-02-06 22:40:14 +0100560 if (saved_timings->max_tRR < T_RR_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000561 die("DDR-II module has unsupported refresh value\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100562 else if (saved_timings->max_tRR < T_RR_15_6US)
563 sysinfo->refresh = REFRESH_7_8US;
564 else
565 sysinfo->refresh = REFRESH_15_6US;
Angel Pons30492572020-06-11 13:24:54 +0200566 printk(BIOS_DEBUG, "Refresh: %s\n", sysinfo->refresh ? "7.8us" : "15.6us");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000567}
568
Arthur Heymans0ab49042017-02-06 22:40:14 +0100569/**
570 * @brief Get generic DIMM parameters.
571 * @param sysinfo Central memory controller information structure
572 *
573 * This function gathers several pieces of information for each system DIMM:
574 * o DIMM width (x8 / x16)
575 * o DIMM rank (single ranked / dual ranked)
576 *
577 * Also, some non-supported scenarios are detected.
578 */
579
580static void sdram_get_dram_configuration(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000581{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100582 struct timings saved_timings;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000583
Arthur Heymans0ab49042017-02-06 22:40:14 +0100584 gather_common_timing(sysinfo, &saved_timings);
585 choose_tclk(sysinfo, &saved_timings);
586 derive_timings(sysinfo, &saved_timings);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000587}
588
Arthur Heymans70a8e342017-03-09 11:30:23 +0100589static void sdram_program_dram_width(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000590{
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200591 u16 c0dramw = 0, c1dramw = 0;
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200592 int i, idx;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000593
594 if (sysinfo->dual_channel)
595 idx = 2;
596 else
597 idx = 1;
598
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200599 for (i = 0; i < DIMM_SOCKETS; i++) { /* Channel 0 */
600 switch (sysinfo->dimm[i]) {
601 case SYSINFO_DIMM_X16DS:
Angel Pons30492572020-06-11 13:24:54 +0200602 c0dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200603 break;
604 case SYSINFO_DIMM_X8DS:
Angel Pons30492572020-06-11 13:24:54 +0200605 c0dramw |= (0x0001) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200606 break;
607 case SYSINFO_DIMM_X16SS:
Angel Pons30492572020-06-11 13:24:54 +0200608 c0dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200609 break;
610 case SYSINFO_DIMM_X8DDS:
Angel Pons30492572020-06-11 13:24:54 +0200611 c0dramw |= (0x0005) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200612 break;
613 case SYSINFO_DIMM_NOT_POPULATED:
Angel Pons30492572020-06-11 13:24:54 +0200614 c0dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200615 break;
616 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000617 }
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200618 for (i = DIMM_SOCKETS; i < idx * DIMM_SOCKETS; i++) { /* Channel 1 */
619 switch (sysinfo->dimm[i]) {
620 case SYSINFO_DIMM_X16DS:
Angel Pons30492572020-06-11 13:24:54 +0200621 c1dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200622 break;
623 case SYSINFO_DIMM_X8DS:
Angel Pons30492572020-06-11 13:24:54 +0200624 c1dramw |= (0x0010) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200625 break;
626 case SYSINFO_DIMM_X16SS:
Angel Pons30492572020-06-11 13:24:54 +0200627 c1dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200628 break;
629 case SYSINFO_DIMM_X8DDS:
Angel Pons30492572020-06-11 13:24:54 +0200630 c1dramw |= (0x0050) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200631 break;
632 case SYSINFO_DIMM_NOT_POPULATED:
Angel Pons30492572020-06-11 13:24:54 +0200633 c1dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200634 break;
635 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000636 }
637
638 MCHBAR16(C0DRAMW) = c0dramw;
639 MCHBAR16(C1DRAMW) = c1dramw;
640}
641
642static void sdram_write_slew_rates(u32 offset, const u32 *slew_rate_table)
643{
644 int i;
645
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200646 for (i = 0; i < 16; i++)
Angel Pons30492572020-06-11 13:24:54 +0200647 MCHBAR32(offset+(i * 4)) = slew_rate_table[i];
Stefan Reinauer278534d2008-10-29 04:51:07 +0000648}
649
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000650static const u32 dq2030[] = {
651 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
652 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
653 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
654 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
655};
656
657static const u32 dq2330[] = {
658 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
659 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
660 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
661 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
662};
663
664static const u32 cmd2710[] = {
665 0x07060605, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
666 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
667 0x1110100f, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
668 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
669};
670
671static const u32 cmd3210[] = {
672 0x0f0d0b0a, 0x17151311, 0x1f1d1b19, 0x1f1f1f1f,
673 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
674 0x18171615, 0x1f1f1c1a, 0x1f1f1f1f, 0x1f1f1f1f,
675 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
676};
677
678static const u32 clk2030[] = {
679 0x0e0d0d0c, 0x100f0f0e, 0x100f0e0d, 0x15131211,
680 0x1d1b1917, 0x2523211f, 0x2a282927, 0x32302e2c,
681 0x17161514, 0x1b1a1918, 0x1f1e1d1c, 0x23222120,
682 0x27262524, 0x2d2b2928, 0x3533312f, 0x3d3b3937
683};
684
685static const u32 ctl3215[] = {
686 0x01010000, 0x03020101, 0x07060504, 0x0b0a0908,
687 0x100f0e0d, 0x14131211, 0x18171615, 0x1c1b1a19,
688 0x05040403, 0x07060605, 0x0a090807, 0x0f0d0c0b,
689 0x14131211, 0x18171615, 0x1c1b1a19, 0x201f1e1d
690};
691
692static const u32 ctl3220[] = {
693 0x05040403, 0x07060505, 0x0e0c0a08, 0x1a171411,
694 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e,
695 0x09080807, 0x0b0a0a09, 0x0f0d0c0b, 0x1b171311,
696 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e
697};
698
699static const u32 nc[] = {
700 0x00000000, 0x00000000, 0x00000000, 0x00000000,
701 0x00000000, 0x00000000, 0x00000000, 0x00000000,
702 0x00000000, 0x00000000, 0x00000000, 0x00000000,
703 0x00000000, 0x00000000, 0x00000000, 0x00000000
704};
705
706enum {
707 DQ2030,
708 DQ2330,
709 CMD2710,
710 CMD3210,
711 CLK2030,
712 CTL3215,
713 CTL3220,
714 NC,
715};
716
717static const u8 dual_channel_slew_group_lookup[] = {
718 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
719 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
720 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
721 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
722 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
723
724 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
725 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
726 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
727 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
728 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
729
730 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
731 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
732 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
733 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
734 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
735
736 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
737 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
738 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
739 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
740 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, NC, NC,
741
742 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
743 NC, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
744 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
745 NC, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD2710
746};
747
748static const u8 single_channel_slew_group_lookup[] = {
749 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
750 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
751 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
752 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
753 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
754
755 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
756 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
757 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
758 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
759 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
760
761 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
762 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
763 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
764 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
765 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
766
767 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
768 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
769 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
770 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
771 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
772
773 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
774 DQ2330, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
775 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
776 DQ2330, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD3210
777};
778
779static const u32 *slew_group_lookup(int dual_channel, int index)
780{
781 const u8 *slew_group;
782 /* Dual Channel needs different tables. */
783 if (dual_channel)
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100784 slew_group = dual_channel_slew_group_lookup;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000785 else
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100786 slew_group = single_channel_slew_group_lookup;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000787
788 switch (slew_group[index]) {
789 case DQ2030: return dq2030;
790 case DQ2330: return dq2330;
791 case CMD2710: return cmd2710;
792 case CMD3210: return cmd3210;
793 case CLK2030: return clk2030;
794 case CTL3215: return ctl3215;
795 case CTL3220: return ctl3220;
796 case NC: return nc;
797 }
798
799 return nc;
800}
801
Julius Wernercd49cce2019-03-05 16:53:33 -0800802#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000803/* Strength multiplier tables */
804static const u8 dual_channel_strength_multiplier[] = {
805 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
806 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
807 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
808 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
809 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
810 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
811 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
812 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
813 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
814 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
815 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
816 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
817 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
818 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
819 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
820 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
821 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
822 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
823 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
824 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
825 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
826 0x00, 0x00, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
827 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
828 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x44, 0x22
829};
830
831static const u8 single_channel_strength_multiplier[] = {
832 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
833 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
834 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
835 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
836 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
837 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
838 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
839 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
840 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
841 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
842 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
843 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
844 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
845 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
846 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
847 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
848 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
849 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
850 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
851 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
852 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
853 0x33, 0x00, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
854 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
855 0x33, 0x00, 0x11, 0x00, 0x44, 0x44, 0x33, 0x11
856};
Julius Wernercd49cce2019-03-05 16:53:33 -0800857#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000858static const u8 dual_channel_strength_multiplier[] = {
859 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
860 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
861 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
862 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
863 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
864 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
865 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
866 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
867 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
868 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
869 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
870 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
871 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
872 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
873 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
874 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
875 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
876 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
877 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
878 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
879 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
880 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
881 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
882 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33
883};
884
885static const u8 single_channel_strength_multiplier[] = {
886 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
887 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
888 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
889 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
890 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
891 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
892 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
893 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
894 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
895 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
896 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
897 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
898 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
899 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
900 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
901 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
902 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
903 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
904 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
905 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
906 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
907 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
908 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
909 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00
910};
911#endif
912
Stefan Reinauer278534d2008-10-29 04:51:07 +0000913static void sdram_rcomp_buffer_strength_and_slew(struct sys_info *sysinfo)
914{
Arthur Heymans70a8e342017-03-09 11:30:23 +0100915 const u8 *strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000916 int idx, dual_channel;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000917
918 /* Set Strength Multipliers */
919
920 /* Dual Channel needs different tables. */
921 if (sdram_capabilities_dual_channel()) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000922 printk(BIOS_DEBUG, "Programming Dual Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000923 strength_multiplier = dual_channel_strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000924 dual_channel = 1;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100925 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[2];
Stefan Reinauer278534d2008-10-29 04:51:07 +0000926 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000927 printk(BIOS_DEBUG, "Programming Single Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000928 strength_multiplier = single_channel_strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000929 dual_channel = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000930 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[1];
931 }
932
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000933 printk(BIOS_DEBUG, "Table Index: %d\n", idx);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000934
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000935 MCHBAR8(G1SC) = strength_multiplier[idx * 8 + 0];
936 MCHBAR8(G2SC) = strength_multiplier[idx * 8 + 1];
937 MCHBAR8(G3SC) = strength_multiplier[idx * 8 + 2];
938 MCHBAR8(G4SC) = strength_multiplier[idx * 8 + 3];
939 MCHBAR8(G5SC) = strength_multiplier[idx * 8 + 4];
940 MCHBAR8(G6SC) = strength_multiplier[idx * 8 + 5];
941 MCHBAR8(G7SC) = strength_multiplier[idx * 8 + 6];
942 MCHBAR8(G8SC) = strength_multiplier[idx * 8 + 7];
Stefan Reinauer278534d2008-10-29 04:51:07 +0000943
944 /* Channel 0 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000945 sdram_write_slew_rates(G1SRPUT, slew_group_lookup(dual_channel, idx * 8 + 0));
946 sdram_write_slew_rates(G2SRPUT, slew_group_lookup(dual_channel, idx * 8 + 1));
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200947 if ((slew_group_lookup(dual_channel, idx * 8 + 2) != nc) &&
948 (sysinfo->package == SYSINFO_PACKAGE_STACKED))
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000949
Stefan Reinauer278534d2008-10-29 04:51:07 +0000950 sdram_write_slew_rates(G3SRPUT, ctl3220);
Arthur Heymans70a8e342017-03-09 11:30:23 +0100951 else
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000952 sdram_write_slew_rates(G3SRPUT, slew_group_lookup(dual_channel, idx * 8 + 2));
Arthur Heymans70a8e342017-03-09 11:30:23 +0100953
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000954 sdram_write_slew_rates(G4SRPUT, slew_group_lookup(dual_channel, idx * 8 + 3));
955 sdram_write_slew_rates(G5SRPUT, slew_group_lookup(dual_channel, idx * 8 + 4));
956 sdram_write_slew_rates(G6SRPUT, slew_group_lookup(dual_channel, idx * 8 + 5));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000957
958 /* Channel 1 */
959 if (sysinfo->dual_channel) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000960 sdram_write_slew_rates(G7SRPUT, slew_group_lookup(dual_channel, idx * 8 + 6));
961 sdram_write_slew_rates(G8SRPUT, slew_group_lookup(dual_channel, idx * 8 + 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000962 } else {
963 sdram_write_slew_rates(G7SRPUT, nc);
964 sdram_write_slew_rates(G8SRPUT, nc);
965 }
966}
967
968static void sdram_enable_rcomp(void)
969{
970 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000971 /* Enable Global Periodic RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000972 udelay(300);
973 reg32 = MCHBAR32(GBRCOMPCTL);
974 reg32 &= ~(1 << 23);
975 MCHBAR32(GBRCOMPCTL) = reg32;
976}
977
978static void sdram_program_dll_timings(struct sys_info *sysinfo)
979{
Elyes HAOUAS44a30662017-02-23 13:14:44 +0100980 u32 channeldll = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000981 int i;
982
Elyes HAOUAS38424982016-08-21 12:01:04 +0200983 printk(BIOS_DEBUG, "Programming DLL Timings...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000984
Arthur Heymans70a8e342017-03-09 11:30:23 +0100985 MCHBAR16(DQSMT) &= ~((3 << 12) | (1 << 10) | (0xf << 0));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000986 MCHBAR16(DQSMT) |= (1 << 13) | (0xc << 0);
987
988 /* We drive both channels with the same speed */
Julius Wernercd49cce2019-03-05 16:53:33 -0800989 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +0100990 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +0100991 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200992 channeldll = 0x26262626;
993 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100994 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200995 channeldll = 0x22222222;
996 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100997 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200998 channeldll = 0x11111111;
999 break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001000 }
Julius Wernercd49cce2019-03-05 16:53:33 -08001001 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001002 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001003 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001004 channeldll = 0x33333333;
1005 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001006 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001007 channeldll = 0x24242424;
1008 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001009 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001010 channeldll = 0x25252525;
1011 break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001012 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001013 }
1014
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001015 for (i = 0; i < 4; i++) {
Elyes HAOUAS44a30662017-02-23 13:14:44 +01001016 MCHBAR32(C0R0B00DQST + (i * 0x10) + 0) = channeldll;
1017 MCHBAR32(C0R0B00DQST + (i * 0x10) + 4) = channeldll;
1018 MCHBAR32(C1R0B00DQST + (i * 0x10) + 0) = channeldll;
1019 MCHBAR32(C1R0B00DQST + (i * 0x10) + 4) = channeldll;
Julius Wernercd49cce2019-03-05 16:53:33 -08001020 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUAS44a30662017-02-23 13:14:44 +01001021 MCHBAR8(C0R0B00DQST + (i * 0x10) + 8) = channeldll & 0xff;
1022 MCHBAR8(C1R0B00DQST + (i * 0x10) + 8) = channeldll & 0xff;
Paul Menzelbce7e332017-02-22 18:46:27 +01001023 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001024 }
1025}
1026
1027static void sdram_force_rcomp(void)
1028{
1029 u32 reg32;
1030 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001031
Stefan Reinauer278534d2008-10-29 04:51:07 +00001032 reg32 = MCHBAR32(ODTC);
1033 reg32 |= (1 << 28);
1034 MCHBAR32(ODTC) = reg32;
1035
1036 reg32 = MCHBAR32(SMSRCTL);
1037 reg32 |= (1 << 0);
1038 MCHBAR32(SMSRCTL) = reg32;
1039
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001040 /* Start initial RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001041 reg32 = MCHBAR32(GBRCOMPCTL);
1042 reg32 |= (1 << 8);
1043 MCHBAR32(GBRCOMPCTL) = reg32;
1044
1045 reg8 = i945_silicon_revision();
1046 if ((reg8 == 0 && (MCHBAR32(DCC) & (3 << 0)) == 0) || (reg8 == 1)) {
1047 reg32 = MCHBAR32(GBRCOMPCTL);
1048 reg32 |= (3 << 5);
1049 MCHBAR32(GBRCOMPCTL) = reg32;
1050 }
1051}
1052
1053static void sdram_initialize_system_memory_io(struct sys_info *sysinfo)
1054{
1055 u8 reg8;
1056 u32 reg32;
1057
Elyes HAOUAS38424982016-08-21 12:01:04 +02001058 printk(BIOS_DEBUG, "Initializing System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001059 /* Enable Data Half Clock Pushout */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001060 reg8 = MCHBAR8(C0HCTC);
1061 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001062 reg8 |= (1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001063 MCHBAR8(C0HCTC) = reg8;
1064
1065 reg8 = MCHBAR8(C1HCTC);
1066 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001067 reg8 |= (1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001068 MCHBAR8(C1HCTC) = reg8;
1069
Arthur Heymans70a8e342017-03-09 11:30:23 +01001070 MCHBAR16(WDLLBYPMODE) &= ~((1 << 9) | (1 << 6) | (1 << 4) | (1 << 3) | (1 << 1));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001071 MCHBAR16(WDLLBYPMODE) |= (1 << 8) | (1 << 7) | (1 << 5) | (1 << 2) | (1 << 0);
1072
1073 MCHBAR8(C0WDLLCMC) = 0;
1074 MCHBAR8(C1WDLLCMC) = 0;
1075
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001076 /* Program RCOMP Settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001077 sdram_program_dram_width(sysinfo);
1078
1079 sdram_rcomp_buffer_strength_and_slew(sysinfo);
1080
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001081 /* Indicate that RCOMP programming is done */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001082 reg32 = MCHBAR32(GBRCOMPCTL);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001083 reg32 &= ~((1 << 29) | (1 << 26) | (3 << 21) | (3 << 2));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001084 reg32 |= (3 << 27) | (3 << 0);
1085 MCHBAR32(GBRCOMPCTL) = reg32;
1086
1087 MCHBAR32(GBRCOMPCTL) |= (1 << 10);
1088
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001089 /* Program DLL Timings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001090 sdram_program_dll_timings(sysinfo);
1091
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001092 /* Force RCOMP cycle */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001093 sdram_force_rcomp();
1094}
1095
1096static void sdram_enable_system_memory_io(struct sys_info *sysinfo)
1097{
1098 u32 reg32;
1099
Elyes HAOUAS38424982016-08-21 12:01:04 +02001100 printk(BIOS_DEBUG, "Enabling System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001101
Stefan Reinauer278534d2008-10-29 04:51:07 +00001102 reg32 = MCHBAR32(RCVENMT);
1103 reg32 &= ~(0x3f << 6);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001104 MCHBAR32(RCVENMT) = reg32; /* [11:6] = 0 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001105
1106 reg32 |= (1 << 11) | (1 << 9);
1107 MCHBAR32(RCVENMT) = reg32;
1108
1109 reg32 = MCHBAR32(DRTST);
1110 reg32 |= (1 << 3) | (1 << 2);
1111 MCHBAR32(DRTST) = reg32;
1112
1113 reg32 = MCHBAR32(DRTST);
1114 reg32 |= (1 << 6) | (1 << 4);
1115 MCHBAR32(DRTST) = reg32;
1116
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001117 asm volatile ("nop; nop;" ::: "memory");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001118
1119 reg32 = MCHBAR32(DRTST);
1120
1121 /* Is channel 0 populated? */
1122 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001123 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001124 reg32 |= (1 << 7) | (1 << 5);
1125 else
1126 reg32 |= (1 << 31);
1127
1128 /* Is channel 1 populated? */
1129 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001130 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001131 reg32 |= (1 << 9) | (1 << 8);
1132 else
1133 reg32 |= (1 << 30);
1134
1135 MCHBAR32(DRTST) = reg32;
1136
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001137 /* Activate DRAM Channel IO Buffers */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001138 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001139 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001140 reg32 = MCHBAR32(C0DRC1);
1141 reg32 |= (1 << 8);
1142 MCHBAR32(C0DRC1) = reg32;
1143 }
1144 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001145 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001146 reg32 = MCHBAR32(C1DRC1);
1147 reg32 |= (1 << 8);
1148 MCHBAR32(C1DRC1) = reg32;
1149 }
1150}
1151
Stefan Reinauer278534d2008-10-29 04:51:07 +00001152static int sdram_program_row_boundaries(struct sys_info *sysinfo)
1153{
1154 int i;
Arthur Heymans885c2892016-10-03 17:16:48 +02001155 int cum0, cum1, tolud, tom, pci_mmio_size;
1156 const struct device *dev;
1157 const struct northbridge_intel_i945_config *cfg = NULL;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001158
Paul Menzel84283bc2014-07-17 08:16:04 +02001159 printk(BIOS_DEBUG, "Setting RAM size...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001160
1161 cum0 = 0;
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001162 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001163 cum0 += sysinfo->banksize[i];
Stefan Reinauer278534d2008-10-29 04:51:07 +00001164 MCHBAR8(C0DRB0+i) = cum0;
1165 }
1166
1167 /* Assume we continue in Channel 1 where we stopped in Channel 0 */
1168 cum1 = cum0;
1169
1170 /* Exception: Interleaved starts from the beginning */
1171 if (sysinfo->interleaved)
1172 cum1 = 0;
1173
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001174 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001175 cum1 += sysinfo->banksize[i + 4];
Stefan Reinauer278534d2008-10-29 04:51:07 +00001176 MCHBAR8(C1DRB0+i) = cum1;
1177 }
1178
1179 /* Set TOLUD Top Of Low Usable DRAM */
1180 if (sysinfo->interleaved)
1181 tolud = (cum0 + cum1) << 1;
1182 else
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001183 tolud = (cum1 ? cum1 : cum0) << 1;
Stefan Reinauer779b3e32008-11-10 15:43:37 +00001184
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001185 /* The TOM register has a different format */
1186 tom = tolud >> 3;
1187
1188 /* Limit the value of TOLUD to leave some space for PCI memory. */
Kyösti Mälkkic70eed12018-05-22 02:18:00 +03001189 dev = pcidev_on_root(0, 0);
Arthur Heymans885c2892016-10-03 17:16:48 +02001190 if (dev)
1191 cfg = dev->chip_info;
1192
1193 /* Don't use pci mmio sizes smaller than 768M */
1194 if (!cfg || cfg->pci_mmio_size <= DEFAULT_PCI_MMIO_SIZE)
1195 pci_mmio_size = DEFAULT_PCI_MMIO_SIZE;
1196 else
1197 pci_mmio_size = cfg->pci_mmio_size;
1198
1199 tolud = MIN(((4096 - pci_mmio_size) / 128) << 3, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001200
Arthur Heymans70a8e342017-03-09 11:30:23 +01001201 pci_write_config8(PCI_DEV(0, 0, 0), TOLUD, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001202
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001203 printk(BIOS_DEBUG, "C0DRB = 0x%08x\n", MCHBAR32(C0DRB0));
1204 printk(BIOS_DEBUG, "C1DRB = 0x%08x\n", MCHBAR32(C1DRB0));
Arthur Heymans70a8e342017-03-09 11:30:23 +01001205 printk(BIOS_DEBUG, "TOLUD = 0x%04x\n", pci_read_config8(PCI_DEV(0, 0, 0), TOLUD));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001206
Arthur Heymans70a8e342017-03-09 11:30:23 +01001207 pci_write_config16(PCI_DEV(0, 0, 0), TOM, tom);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001208
1209 return 0;
1210}
1211
Stefan Reinauer278534d2008-10-29 04:51:07 +00001212static int sdram_set_row_attributes(struct sys_info *sysinfo)
1213{
Arthur Heymans0ab49042017-02-06 22:40:14 +01001214 int i;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001215 u16 dra0 = 0, dra1 = 0, dra = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001216
Elyes HAOUAS38424982016-08-21 12:01:04 +02001217 printk(BIOS_DEBUG, "Setting row attributes...\n");
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001218 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001219 u8 columnsrows;
1220
Arthur Heymans70a8e342017-03-09 11:30:23 +01001221 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001222 continue;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001223
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001224 columnsrows = (sysinfo->rows[i] & 0x0f) | (sysinfo->cols[i] & 0xf) << 4;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001225
1226 switch (columnsrows) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001227 case 0x9d:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001228 dra = 2;
1229 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001230 case 0xad:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001231 dra = 3;
1232 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001233 case 0xbd:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001234 dra = 4;
1235 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001236 case 0xae:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001237 dra = 3;
1238 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001239 case 0xbe:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001240 dra = 4;
1241 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001242 default:
1243 die("Unsupported Rows/Columns. (DRA)");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001244 }
1245
1246 /* Double Sided DIMMs? */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001247 if (sysinfo->banksize[(2 * i) + 1] != 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001248 dra = (dra << 4) | dra;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001249
Stefan Reinauer278534d2008-10-29 04:51:07 +00001250 if (i < DIMM_SOCKETS)
Angel Pons30492572020-06-11 13:24:54 +02001251 dra0 |= (dra << (i * 8));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001252 else
Angel Pons30492572020-06-11 13:24:54 +02001253 dra1 |= (dra << ((i - DIMM_SOCKETS) * 8));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001254 }
1255
1256 MCHBAR16(C0DRA0) = dra0;
1257 MCHBAR16(C1DRA0) = dra1;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001258
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001259 printk(BIOS_DEBUG, "C0DRA = 0x%04x\n", dra0);
1260 printk(BIOS_DEBUG, "C1DRA = 0x%04x\n", dra1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001261
1262 return 0;
1263}
1264
1265static void sdram_set_bank_architecture(struct sys_info *sysinfo)
1266{
1267 u32 off32;
1268 int i;
1269
1270 MCHBAR16(C1BNKARC) &= 0xff00;
1271 MCHBAR16(C0BNKARC) &= 0xff00;
1272
1273 off32 = C0BNKARC;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001274 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001275 /* Switch to second channel */
1276 if (i == DIMM_SOCKETS)
1277 off32 = C1BNKARC;
1278
1279 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
1280 continue;
1281
1282 if (sysinfo->banks[i] != 8)
1283 continue;
1284
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001285 printk(BIOS_SPEW, "DIMM%d has 8 banks.\n", i);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001286
1287 if (i & 1)
1288 MCHBAR16(off32) |= 0x50;
1289 else
1290 MCHBAR16(off32) |= 0x05;
1291 }
1292}
1293
Stefan Reinauer278534d2008-10-29 04:51:07 +00001294static void sdram_program_refresh_rate(struct sys_info *sysinfo)
1295{
1296 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001297
Arthur Heymans70a8e342017-03-09 11:30:23 +01001298 if (sysinfo->refresh == REFRESH_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001299 reg32 = (2 << 8); /* Refresh enabled at 7.8us */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001300 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001301 reg32 = (1 << 8); /* Refresh enabled at 15.6us */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001302
1303 MCHBAR32(C0DRC0) &= ~(7 << 8);
1304 MCHBAR32(C0DRC0) |= reg32;
1305
1306 MCHBAR32(C1DRC0) &= ~(7 << 8);
1307 MCHBAR32(C1DRC0) |= reg32;
1308}
1309
1310static void sdram_program_cke_tristate(struct sys_info *sysinfo)
1311{
1312 u32 reg32;
1313 int i;
1314
1315 reg32 = MCHBAR32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001316
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001317 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001318 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001319 reg32 |= (1 << (16 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001320 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001321
Stefan Reinauer278534d2008-10-29 04:51:07 +00001322 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001323
Stefan Reinauer278534d2008-10-29 04:51:07 +00001324 reg32 |= (1 << 11);
1325 MCHBAR32(C0DRC1) = reg32;
1326
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001327 /* Do we have to do this if we're in Single Channel Mode? */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001328 reg32 = MCHBAR32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001329
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001330 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001331 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001332 reg32 |= (1 << (12 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001333 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001334
Stefan Reinauer278534d2008-10-29 04:51:07 +00001335 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001336
Stefan Reinauer278534d2008-10-29 04:51:07 +00001337 reg32 |= (1 << 11);
1338 MCHBAR32(C1DRC1) = reg32;
1339}
1340
1341static void sdram_program_odt_tristate(struct sys_info *sysinfo)
1342{
1343 u32 reg32;
1344 int i;
1345
1346 reg32 = MCHBAR32(C0DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001347
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001348 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001349 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001350 reg32 |= (1 << (24 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001351 }
1352 MCHBAR32(C0DRC2) = reg32;
1353
1354 reg32 = MCHBAR32(C1DRC2);
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 << (20 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001359 }
1360 MCHBAR32(C1DRC2) = reg32;
1361}
1362
1363static void sdram_set_timing_and_control(struct sys_info *sysinfo)
1364{
Arthur Heymans25027232017-02-12 23:34:39 +01001365 u32 reg32, tRD_min;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001366 u32 tWTR;
1367 u32 temp_drt;
1368 int i, page_size;
1369
Edward O'Callaghan2f237c12014-05-25 06:24:39 +10001370 static const u8 cas_table[] = {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001371 2, 1, 0, 3
1372 };
1373
1374 reg32 = MCHBAR32(C0DRC0);
1375 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001376 reg32 &= ~((1 << 13) | (1 << 12));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001377 MCHBAR32(C0DRC0) = reg32;
1378
1379 reg32 = MCHBAR32(C1DRC0);
1380 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001381 reg32 &= ~((1 << 13) | (1 << 12));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001382 MCHBAR32(C1DRC0) = reg32;
1383
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001384 if (!sysinfo->dual_channel && sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001385 reg32 = MCHBAR32(C0DRC0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001386 reg32 |= (1 << 15);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001387 MCHBAR32(C0DRC0) = reg32;
1388 }
1389
1390 sdram_program_refresh_rate(sysinfo);
1391
1392 sdram_program_cke_tristate(sysinfo);
1393
1394 sdram_program_odt_tristate(sysinfo);
1395
1396 /* Calculate DRT0 */
1397
1398 temp_drt = 0;
1399
1400 /* B2B Write Precharge (same bank) = CL-1 + BL/2 + tWR */
1401 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + sysinfo->twr;
1402 temp_drt |= (reg32 << 28);
1403
1404 /* Write Auto Precharge (same bank) = CL-1 + BL/2 + tWR + tRP */
1405 reg32 += sysinfo->trp;
1406 temp_drt |= (reg32 << 4);
1407
Arthur Heymans70a8e342017-03-09 11:30:23 +01001408 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001409 tWTR = 3; /* 667MHz */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001410 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001411 tWTR = 2; /* 400 and 533 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001412
1413 /* B2B Write to Read Command Spacing */
1414 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + tWTR;
1415 temp_drt |= (reg32 << 24);
1416
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001417 /* CxDRT0 [23:22], [21:20], [19:18] [16] have fixed values */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001418 temp_drt |= ((1 << 22) | (3 << 20) | (1 << 18) | (0 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001419
Arthur Heymans25027232017-02-12 23:34:39 +01001420 /*
1421 * tRD is the delay the memory controller is waiting on the FSB,
1422 * in mclk domain.
1423 * This parameter is important for stability and performance.
1424 * Those values might not be optimal but seem stable.
1425 */
1426 tRD_min = sysinfo->cas;
Arthur Heymanse1897612016-10-15 23:29:18 +02001427 switch (sysinfo->fsb_frequency) {
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001428 case 533:
Arthur Heymanse1897612016-10-15 23:29:18 +02001429 break;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001430 case 667:
1431 tRD_min += 1;
Arthur Heymanse1897612016-10-15 23:29:18 +02001432 break;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001433 case 800:
1434 tRD_min += 2;
1435 break;
1436 case 1066:
1437 tRD_min += 3;
Arthur Heymanse1897612016-10-15 23:29:18 +02001438 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001439 }
Arthur Heymanse1897612016-10-15 23:29:18 +02001440
Arthur Heymans25027232017-02-12 23:34:39 +01001441 temp_drt |= (tRD_min << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001442
1443 /* Read Auto Precharge to Activate */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001444
Stefan Reinauer278534d2008-10-29 04:51:07 +00001445 temp_drt |= (8 << 0);
1446
1447 MCHBAR32(C0DRT0) = temp_drt;
1448 MCHBAR32(C1DRT0) = temp_drt;
1449
1450 /* Calculate DRT1 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001451
Stefan Reinauer278534d2008-10-29 04:51:07 +00001452 temp_drt = MCHBAR32(C0DRT1) & 0x00020088;
1453
1454 /* DRAM RASB Precharge */
1455 temp_drt |= (sysinfo->trp - 2) << 0;
1456
1457 /* DRAM RASB to CASB Delay */
1458 temp_drt |= (sysinfo->trcd - 2) << 4;
1459
1460 /* CASB Latency */
1461 temp_drt |= (cas_table[sysinfo->cas - 3]) << 8;
1462
1463 /* Refresh Cycle Time */
1464 temp_drt |= (sysinfo->trfc) << 10;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001465
Stefan Reinauer278534d2008-10-29 04:51:07 +00001466 /* Pre-All to Activate Delay */
1467 temp_drt |= (0 << 16);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001468
Stefan Reinauer278534d2008-10-29 04:51:07 +00001469 /* Precharge to Precharge Delay stays at 1 clock */
1470 temp_drt |= (0 << 18);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001471
Stefan Reinauer278534d2008-10-29 04:51:07 +00001472 /* Activate to Precharge Delay */
1473 temp_drt |= (sysinfo->tras << 19);
1474
1475 /* Read to Precharge (tRTP) */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001476 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001477 temp_drt |= (1 << 28);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001478 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001479 temp_drt |= (0 << 28);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001480
1481 /* Determine page size */
1482 reg32 = 0;
1483 page_size = 1; /* Default: 1k pagesize */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001484 for (i = 0; i < 2*DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001485 if (sysinfo->dimm[i] == SYSINFO_DIMM_X16DS ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001486 sysinfo->dimm[i] == SYSINFO_DIMM_X16SS)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001487 page_size = 2; /* 2k pagesize */
1488 }
1489
Arthur Heymans70a8e342017-03-09 11:30:23 +01001490 if (sysinfo->memory_frequency == 533 && page_size == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001491 reg32 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001492 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001493 reg32 = page_size;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001494
Stefan Reinauer278534d2008-10-29 04:51:07 +00001495 temp_drt |= (reg32 << 30);
1496
1497 MCHBAR32(C0DRT1) = temp_drt;
1498 MCHBAR32(C1DRT1) = temp_drt;
1499
1500 /* Program DRT2 */
1501 reg32 = MCHBAR32(C0DRT2);
1502 reg32 &= ~(1 << 8);
1503 MCHBAR32(C0DRT2) = reg32;
1504
1505 reg32 = MCHBAR32(C1DRT2);
1506 reg32 &= ~(1 << 8);
1507 MCHBAR32(C1DRT2) = reg32;
1508
1509 /* Calculate DRT3 */
1510 temp_drt = MCHBAR32(C0DRT3) & ~0x07ffffff;
1511
1512 /* Get old tRFC value */
1513 reg32 = MCHBAR32(C0DRT1) >> 10;
1514 reg32 &= 0x3f;
1515
1516 /* 788nS - tRFC */
1517 switch (sysinfo->memory_frequency) {
1518 case 400: /* 5nS */
1519 reg32 = ((78800 / 500) - reg32) & 0x1ff;
1520 reg32 |= (0x8c << 16) | (0x0c << 10); /* 1 us */
1521 break;
1522 case 533: /* 3.75nS */
1523 reg32 = ((78800 / 375) - reg32) & 0x1ff;
1524 reg32 |= (0xba << 16) | (0x10 << 10); /* 1 us */
1525 break;
1526 case 667: /* 3nS */
1527 reg32 = ((78800 / 300) - reg32) & 0x1ff;
1528 reg32 |= (0xe9 << 16) | (0x14 << 10); /* 1 us */
1529 break;
1530 }
1531
1532 temp_drt |= reg32;
1533
1534 MCHBAR32(C0DRT3) = temp_drt;
1535 MCHBAR32(C1DRT3) = temp_drt;
1536}
1537
1538static void sdram_set_channel_mode(struct sys_info *sysinfo)
1539{
1540 u32 reg32;
1541
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001542 printk(BIOS_DEBUG, "Setting mode of operation for memory channels...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001543
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001544 if (sdram_capabilities_interleave() &&
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001545 ((sysinfo->banksize[0] + sysinfo->banksize[1] +
1546 sysinfo->banksize[2] + sysinfo->banksize[3]) ==
1547 (sysinfo->banksize[4] + sysinfo->banksize[5] +
1548 sysinfo->banksize[6] + sysinfo->banksize[7]))) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001549 /* Both channels equipped with DIMMs of the same size */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001550 sysinfo->interleaved = 1;
1551 } else {
1552 sysinfo->interleaved = 0;
1553 }
1554
1555 reg32 = MCHBAR32(DCC);
1556 reg32 &= ~(7 << 0);
1557
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001558 if (sysinfo->interleaved) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001559 /* Dual Channel Interleaved */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001560 printk(BIOS_DEBUG, "Dual Channel Interleaved.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001561 reg32 |= (1 << 1);
1562 } else if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001563 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001564 /* Channel 1 only */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001565 printk(BIOS_DEBUG, "Single Channel 1 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001566 reg32 |= (1 << 2);
Elyes HAOUAS75da1fb2017-02-16 18:59:13 +01001567 } else if (sdram_capabilities_dual_channel() &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001568 (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1569 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) {
Martin Roth128c1042016-11-18 09:29:03 -07001570 /* Dual Channel Asymmetric */
1571 printk(BIOS_DEBUG, "Dual Channel Asymmetric.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001572 reg32 |= (1 << 0);
1573 } else {
1574 /* All bits 0 means Single Channel 0 operation */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001575 printk(BIOS_DEBUG, "Single Channel 0 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001576 }
1577
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001578 /* Now disable channel XORing */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001579 reg32 |= (1 << 10);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001580
1581 MCHBAR32(DCC) = reg32;
1582
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001583 PRINTK_DEBUG("DCC = 0x%08x\n", MCHBAR32(DCC));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001584}
1585
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001586static void sdram_program_pll_settings(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001587{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001588 MCHBAR32(PLLMON) = 0x80800000;
1589
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001590 sysinfo->fsb_frequency = fsbclk();
Peter Stuge76d91432010-10-01 10:02:33 +00001591 if (sysinfo->fsb_frequency == 0xffff)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001592 die("Unsupported FSB speed");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001593
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001594 /* Program CPCTL according to FSB speed */
1595 /* Only write the lower byte */
1596 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001597 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001598 MCHBAR8(CPCTL) = 0x90;
1599 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001600 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001601 MCHBAR8(CPCTL) = 0x95;
1602 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001603 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001604 MCHBAR8(CPCTL) = 0x8d;
1605 break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001606 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001607
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001608 MCHBAR16(CPCTL) &= ~(1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001609
Paul Menzel0ce5ebf2013-10-21 21:22:09 +02001610 MCHBAR16(CPCTL); /* Read back register to activate settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001611}
1612
1613static void sdram_program_graphics_frequency(struct sys_info *sysinfo)
1614{
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001615 u8 reg8;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001616 u8 freq, second_vco, voltage;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001617
1618#define CRCLK_166MHz 0x00
1619#define CRCLK_200MHz 0x01
1620#define CRCLK_250MHz 0x03
1621#define CRCLK_400MHz 0x05
1622
1623#define CDCLK_200MHz 0x00
1624#define CDCLK_320MHz 0x40
1625
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001626#define VOLTAGE_1_05 0x00
1627#define VOLTAGE_1_50 0x01
1628
Paul Menzeldaf9e502014-07-15 23:49:16 +02001629 printk(BIOS_DEBUG, "Setting Graphics Frequency...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001630
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001631 printk(BIOS_DEBUG, "FSB: %d MHz ", sysinfo->fsb_frequency);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001632
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001633 voltage = VOLTAGE_1_05;
1634 if (MCHBAR32(DFT_STRAP1) & (1 << 20))
1635 voltage = VOLTAGE_1_50;
Angel Pons30492572020-06-11 13:24:54 +02001636 printk(BIOS_DEBUG, "Voltage: %s ", (voltage == VOLTAGE_1_05) ? "1.05V" : "1.5V");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001637
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001638 /* Gate graphics hardware for frequency change */
Angel Pons30492572020-06-11 13:24:54 +02001639 reg8 = (1 << 3) | (1 << 1); /* disable crclk, gate cdclk */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001640 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001641
1642 /* Get graphics frequency capabilities */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001643 reg8 = sdram_capabilities_core_frequencies();
1644
Stefan Reinauer278534d2008-10-29 04:51:07 +00001645 freq = CRCLK_250MHz;
1646 switch (reg8) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001647 case GFX_FREQUENCY_CAP_ALL:
1648 if (voltage == VOLTAGE_1_05)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001649 freq = CRCLK_250MHz;
1650 else
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001651 freq = CRCLK_400MHz; /* 1.5V requires 400MHz */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001652 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001653 case GFX_FREQUENCY_CAP_250MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001654 freq = CRCLK_250MHz;
1655 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001656 case GFX_FREQUENCY_CAP_200MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001657 freq = CRCLK_200MHz;
1658 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001659 case GFX_FREQUENCY_CAP_166MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001660 freq = CRCLK_166MHz;
1661 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001662 }
1663
1664 if (freq != CRCLK_400MHz) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001665 /* What chipset are we? Force 166MHz for GMS */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001666 reg8 = (pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe7) & 0x70) >> 4;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001667 if (reg8 == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001668 freq = CRCLK_166MHz;
1669 }
1670
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001671 printk(BIOS_DEBUG, "Render: ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001672 switch (freq) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001673 case CRCLK_166MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001674 printk(BIOS_DEBUG, "166MHz");
1675 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001676 case CRCLK_200MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001677 printk(BIOS_DEBUG, "200MHz");
1678 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001679 case CRCLK_250MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001680 printk(BIOS_DEBUG, "250MHz");
1681 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001682 case CRCLK_400MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001683 printk(BIOS_DEBUG, "400MHz");
1684 break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001685 }
1686
Arthur Heymans70a8e342017-03-09 11:30:23 +01001687 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001688 sysinfo->mvco4x = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001689 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001690 sysinfo->mvco4x = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001691
Stefan Reinauer278534d2008-10-29 04:51:07 +00001692 second_vco = 0;
1693
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001694 if (voltage == VOLTAGE_1_50) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001695 second_vco = 1;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001696 } else if ((i945_silicon_revision() > 0) && (freq == CRCLK_250MHz)) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001697 u16 mem = sysinfo->memory_frequency;
1698 u16 fsb = sysinfo->fsb_frequency;
1699
Arthur Heymans70a8e342017-03-09 11:30:23 +01001700 if ((fsb == 667 && mem == 533) ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001701 (fsb == 533 && mem == 533) ||
1702 (fsb == 533 && mem == 400)) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001703 second_vco = 1;
1704 }
1705
1706 if (fsb == 667 && mem == 533)
1707 sysinfo->mvco4x = 1;
1708 }
1709
Arthur Heymans70a8e342017-03-09 11:30:23 +01001710 if (second_vco)
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001711 sysinfo->clkcfg_bit7 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001712 else
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001713 sysinfo->clkcfg_bit7 = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001714
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001715 /* Graphics Core Render Clock */
Angel Ponse3c68d22020-06-08 12:09:03 +02001716 pci_update_config16(PCI_DEV(0, 2, 0), GCFC, ~((7 << 0) | (1 << 13)), freq);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001717
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001718 /* Graphics Core Display Clock */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001719 reg8 = pci_read_config8(PCI_DEV(0, 2, 0), GCFC);
Angel Ponse3c68d22020-06-08 12:09:03 +02001720 reg8 &= ~((1 << 7) | (7 << 4));
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001721
1722 if (voltage == VOLTAGE_1_05) {
1723 reg8 |= CDCLK_200MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001724 printk(BIOS_DEBUG, " Display: 200MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001725 } else {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001726 reg8 |= CDCLK_320MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001727 printk(BIOS_DEBUG, " Display: 320MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001728 }
Arthur Heymans70a8e342017-03-09 11:30:23 +01001729 pci_write_config8(PCI_DEV(0, 2, 0), GCFC, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001730
Arthur Heymans70a8e342017-03-09 11:30:23 +01001731 reg8 = pci_read_config8(PCI_DEV(0, 2, 0), GCFC + 1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001732
Angel Ponse3c68d22020-06-08 12:09:03 +02001733 reg8 |= (1 << 3) | (1 << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001734 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001735
1736 reg8 |= 0x0f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001737 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001738
1739 /* Ungate core render and display clocks */
1740 reg8 &= 0xf0;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001741 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001742}
1743
1744static void sdram_program_memory_frequency(struct sys_info *sysinfo)
1745{
1746 u32 clkcfg;
Julius Wernercd49cce2019-03-05 16:53:33 -08001747 u8 offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001748
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001749 printk(BIOS_DEBUG, "Setting Memory Frequency... ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001750
Stefan Reinauer278534d2008-10-29 04:51:07 +00001751 clkcfg = MCHBAR32(CLKCFG);
1752
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001753 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001754
Arthur Heymans70a8e342017-03-09 11:30:23 +01001755 clkcfg &= ~((1 << 12) | (1 << 7) | (7 << 4));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001756
1757 if (sysinfo->mvco4x) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001758 printk(BIOS_DEBUG, "MVCO 4x, ");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001759 clkcfg &= ~(1 << 12);
1760 }
1761
1762 if (sysinfo->clkcfg_bit7) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001763 printk(BIOS_DEBUG, "second VCO, ");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001764 clkcfg |= (1 << 7);
1765 }
1766
1767 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001768 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001769 clkcfg |= ((1 + offset) << 4);
1770 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001771 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001772 clkcfg |= ((2 + offset) << 4);
1773 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001774 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001775 clkcfg |= ((3 + offset) << 4);
1776 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001777 default:
1778 die("Target Memory Frequency Error");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001779 }
1780
1781 if (MCHBAR32(CLKCFG) == clkcfg) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001782 printk(BIOS_DEBUG, "ok (unchanged)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001783 return;
1784 }
1785
1786 MCHBAR32(CLKCFG) = clkcfg;
1787
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001788 /* Make sure the following code is in the cache before we execute it. */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001789 goto cache_code;
1790vco_update:
Angel Ponse3c68d22020-06-08 12:09:03 +02001791 pci_and_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, (u8)~(1 << 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001792
Stefan Reinauer278534d2008-10-29 04:51:07 +00001793 clkcfg &= ~(1 << 10);
1794 MCHBAR32(CLKCFG) = clkcfg;
1795 clkcfg |= (1 << 10);
1796 MCHBAR32(CLKCFG) = clkcfg;
1797
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001798 asm volatile (
Stefan Reinauer278534d2008-10-29 04:51:07 +00001799 " movl $0x100, %%ecx\n"
1800 "delay_update:\n"
1801 " nop\n"
1802 " nop\n"
1803 " nop\n"
1804 " nop\n"
1805 " loop delay_update\n"
1806 : /* No outputs */
1807 : /* No inputs */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001808 : "%ecx", "memory"
Stefan Reinauer278534d2008-10-29 04:51:07 +00001809 );
1810
Stefan Reinauer278534d2008-10-29 04:51:07 +00001811 clkcfg &= ~(1 << 10);
1812 MCHBAR32(CLKCFG) = clkcfg;
1813
1814 goto out;
1815cache_code:
1816 goto vco_update;
1817out:
1818
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001819 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", MCHBAR32(CLKCFG));
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001820 printk(BIOS_DEBUG, "ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001821}
1822
1823static void sdram_program_clock_crossing(void)
1824{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001825 int idx = 0;
1826
1827 /**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001828 * We add the indices according to our clocks from CLKCFG.
Stefan Reinauer278534d2008-10-29 04:51:07 +00001829 */
Julius Wernercd49cce2019-03-05 16:53:33 -08001830#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001831 static const u32 data_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001832 0x00100401, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001833 0xffffffff, 0xffffffff, /* nonexistent */
1834 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001835
Stefan Reinauer278534d2008-10-29 04:51:07 +00001836 0x08040120, 0x00000000, /* DDR400 FSB533 */
1837 0x00100401, 0x00000000, /* DDR533 FSB533 */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001838 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001839
1840 0x04020120, 0x00000010, /* DDR400 FSB667 */
1841 0x10040280, 0x00000040, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001842 0x00100401, 0x00000000, /* DDR667 FSB667 */
1843
Martin Roth2ed0aa22016-01-05 20:58:58 -07001844 0xffffffff, 0xffffffff, /* nonexistent */
1845 0xffffffff, 0xffffffff, /* nonexistent */
1846 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001847
Martin Roth2ed0aa22016-01-05 20:58:58 -07001848 0xffffffff, 0xffffffff, /* nonexistent */
1849 0xffffffff, 0xffffffff, /* nonexistent */
1850 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001851 };
1852
1853 static const u32 command_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001854 0x04020208, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001855 0xffffffff, 0xffffffff, /* nonexistent */
1856 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001857
Stefan Reinauer278534d2008-10-29 04:51:07 +00001858 0x00060108, 0x00000000, /* DDR400 FSB533 */
1859 0x04020108, 0x00000000, /* DDR533 FSB533 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001860 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001861
1862 0x00040318, 0x00000000, /* DDR400 FSB667 */
1863 0x04020118, 0x00000000, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001864 0x02010804, 0x00000000, /* DDR667 FSB667 */
1865
Martin Roth2ed0aa22016-01-05 20:58:58 -07001866 0xffffffff, 0xffffffff, /* nonexistent */
1867 0xffffffff, 0xffffffff, /* nonexistent */
1868 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001869
Martin Roth2ed0aa22016-01-05 20:58:58 -07001870 0xffffffff, 0xffffffff, /* nonexistent */
1871 0xffffffff, 0xffffffff, /* nonexistent */
1872 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001873 };
1874
Julius Wernercd49cce2019-03-05 16:53:33 -08001875#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001876 /* i945 G/P */
1877 static const u32 data_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001878 0xffffffff, 0xffffffff, /* nonexistent */
1879 0xffffffff, 0xffffffff, /* nonexistent */
1880 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001881
1882 0x10080201, 0x00000000, /* DDR400 FSB533 */
1883 0x00100401, 0x00000000, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001884 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001885
Martin Roth2ed0aa22016-01-05 20:58:58 -07001886 0xffffffff, 0xffffffff, /* nonexistent */
1887 0xffffffff, 0xffffffff, /* nonexistent */
1888 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001889
1890 0x04020108, 0x00000000, /* DDR400 FSB800 */
1891 0x00020108, 0x00000000, /* DDR533 FSB800 */
1892 0x00080201, 0x00000000, /* DDR667 FSB800 */
1893
1894 0x00010402, 0x00000000, /* DDR400 FSB1066 */
1895 0x04020108, 0x00000000, /* DDR533 FSB1066 */
1896 0x08040110, 0x00000000, /* DDR667 FSB1066 */
1897 };
1898
1899 static const u32 command_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001900 0xffffffff, 0xffffffff, /* nonexistent */
1901 0xffffffff, 0xffffffff, /* nonexistent */
1902 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001903
1904 0x00010800, 0x00000402, /* DDR400 FSB533 */
1905 0x01000400, 0x00000200, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001906 0x00020904, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001907
Martin Roth2ed0aa22016-01-05 20:58:58 -07001908 0xffffffff, 0xffffffff, /* nonexistent */
1909 0xffffffff, 0xffffffff, /* nonexistent */
1910 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001911
1912 0x02010804, 0x00000000, /* DDR400 FSB800 */
1913 0x00010402, 0x00000000, /* DDR533 FSB800 */
Arthur Heymans8b6df622016-10-16 10:58:01 +02001914 0x04020130, 0x00000008, /* DDR667 FSB800 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001915
1916 0x00020904, 0x00000000, /* DDR400 FSB1066 */
1917 0x02010804, 0x00000000, /* DDR533 FSB1066 */
1918 0x180601c0, 0x00000020, /* DDR667 FSB1066 */
1919 };
1920#endif
1921
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001922 printk(BIOS_DEBUG, "Programming Clock Crossing...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001923
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001924 printk(BIOS_DEBUG, "MEM=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001925 switch (memclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001926 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001927 printk(BIOS_DEBUG, "400");
1928 idx += 0;
1929 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001930 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001931 printk(BIOS_DEBUG, "533");
1932 idx += 2;
1933 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001934 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001935 printk(BIOS_DEBUG, "667");
1936 idx += 4;
1937 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001938 default:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001939 printk(BIOS_DEBUG, "RSVD %x", memclk());
1940 return;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001941 }
1942
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001943 printk(BIOS_DEBUG, " FSB=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001944 switch (fsbclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001945 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001946 printk(BIOS_DEBUG, "400");
1947 idx += 0;
1948 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001949 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001950 printk(BIOS_DEBUG, "533");
1951 idx += 6;
1952 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001953 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001954 printk(BIOS_DEBUG, "667");
1955 idx += 12;
1956 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001957 case 800:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001958 printk(BIOS_DEBUG, "800");
1959 idx += 18;
1960 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001961 case 1066:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001962 printk(BIOS_DEBUG, "1066");
1963 idx += 24;
1964 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001965 default:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001966 printk(BIOS_DEBUG, "RSVD %x\n", fsbclk());
1967 return;
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001968 }
1969
Arthur Heymans70a8e342017-03-09 11:30:23 +01001970 if (command_clock_crossing[idx] == 0xffffffff)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001971 printk(BIOS_DEBUG, "Invalid MEM/FSB combination!\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001972
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001973 MCHBAR32(CCCFT + 0) = command_clock_crossing[idx];
1974 MCHBAR32(CCCFT + 4) = command_clock_crossing[idx + 1];
1975
Stefan Reinauer278534d2008-10-29 04:51:07 +00001976 MCHBAR32(C0DCCFT + 0) = data_clock_crossing[idx];
1977 MCHBAR32(C0DCCFT + 4) = data_clock_crossing[idx + 1];
1978 MCHBAR32(C1DCCFT + 0) = data_clock_crossing[idx];
1979 MCHBAR32(C1DCCFT + 4) = data_clock_crossing[idx + 1];
1980
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001981 printk(BIOS_DEBUG, "... ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001982}
1983
1984static void sdram_disable_fast_dispatch(void)
1985{
1986 u32 reg32;
1987
1988 reg32 = MCHBAR32(FSBPMC3);
1989 reg32 |= (1 << 1);
1990 MCHBAR32(FSBPMC3) = reg32;
1991
1992 reg32 = MCHBAR32(SBTEST);
1993 reg32 |= (3 << 1);
1994 MCHBAR32(SBTEST) = reg32;
1995}
1996
1997static void sdram_pre_jedec_initialization(void)
1998{
1999 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002000
Stefan Reinauer278534d2008-10-29 04:51:07 +00002001 reg32 = MCHBAR32(WCC);
2002 reg32 &= 0x113ff3ff;
2003 reg32 |= (4 << 29) | (3 << 25) | (1 << 10);
2004 MCHBAR32(WCC) = reg32;
2005
2006 MCHBAR32(SMVREFC) |= (1 << 6);
2007
2008 MCHBAR32(MMARB0) &= ~(3 << 17);
2009 MCHBAR32(MMARB0) |= (1 << 21) | (1 << 16);
2010
2011 MCHBAR32(MMARB1) &= ~(7 << 8);
2012 MCHBAR32(MMARB1) |= (3 << 8);
2013
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002014 /* Adaptive Idle Timer Control */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002015 MCHBAR32(C0AIT) = 0x000006c4;
2016 MCHBAR32(C0AIT+4) = 0x871a066d;
2017
2018 MCHBAR32(C1AIT) = 0x000006c4;
2019 MCHBAR32(C1AIT+4) = 0x871a066d;
2020}
2021
2022#define EA_DUALCHANNEL_XOR_BANK_RANK_MODE (0xd4 << 24)
2023#define EA_DUALCHANNEL_XOR_BANK_MODE (0xf4 << 24)
2024#define EA_DUALCHANNEL_BANK_RANK_MODE (0xc2 << 24)
2025#define EA_DUALCHANNEL_BANK_MODE (0xe2 << 24)
2026#define EA_SINGLECHANNEL_XOR_BANK_RANK_MODE (0x91 << 24)
2027#define EA_SINGLECHANNEL_XOR_BANK_MODE (0xb1 << 24)
2028#define EA_SINGLECHANNEL_BANK_RANK_MODE (0x80 << 24)
2029#define EA_SINGLECHANNEL_BANK_MODE (0xa0 << 24)
2030
2031static void sdram_enhanced_addressing_mode(struct sys_info *sysinfo)
2032{
2033 u32 chan0 = 0, chan1 = 0;
Paul Menzeld789b6582020-03-14 11:50:34 +01002034 bool chan0_dualsided, chan1_dualsided, chan0_populated, chan1_populated;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002035
Paul Menzel842dd332020-03-14 10:37:40 +01002036 chan0_populated = (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002037 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED);
Elyes HAOUAS308aeff2017-02-24 12:53:07 +01002038 chan1_populated = (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002039 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002040 chan0_dualsided = (sysinfo->banksize[1] || sysinfo->banksize[3]);
2041 chan1_dualsided = (sysinfo->banksize[5] || sysinfo->banksize[7]);
2042
2043 if (sdram_capabilities_enhanced_addressing_xor()) {
2044 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002045 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002046 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002047 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002048 chan0 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002049 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002050 chan0 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002051 }
2052 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002053 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002054 chan1 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002055 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002056 chan1 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002057 }
2058 } else {
2059 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002060 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002061 chan0 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002062 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002063 chan0 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002064
Arthur Heymans70a8e342017-03-09 11:30:23 +01002065 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002066 chan1 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002067 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002068 chan1 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002069 }
2070 } else {
2071 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002072 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002073 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002074 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002075 chan0 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002076 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002077 chan0 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002078 }
2079 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002080 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002081 chan1 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002082 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002083 chan1 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002084 }
2085 } else {
2086 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002087 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002088 chan0 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002089 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002090 chan0 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002091
Arthur Heymans70a8e342017-03-09 11:30:23 +01002092 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002093 chan1 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002094 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002095 chan1 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002096 }
2097 }
2098
2099 MCHBAR32(C0DRC1) &= 0x00ffffff;
2100 MCHBAR32(C0DRC1) |= chan0;
2101 MCHBAR32(C1DRC1) &= 0x00ffffff;
2102 MCHBAR32(C1DRC1) |= chan1;
2103}
2104
2105static void sdram_post_jedec_initialization(struct sys_info *sysinfo)
2106{
2107 u32 reg32;
2108
2109 /* Enable Channel XORing for Dual Channel Interleave */
2110 if (sysinfo->interleaved) {
2111 reg32 = MCHBAR32(DCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002112 reg32 &= ~(1 << 10);
Stefan Reinauer30140a52009-03-11 16:20:39 +00002113 reg32 |= (1 << 9);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002114 MCHBAR32(DCC) = reg32;
2115 }
2116
2117 /* DRAM mode optimizations */
2118 sdram_enhanced_addressing_mode(sysinfo);
2119
2120 reg32 = MCHBAR32(FSBPMC3);
2121 reg32 &= ~(1 << 1);
2122 MCHBAR32(FSBPMC3) = reg32;
2123
2124 reg32 = MCHBAR32(SBTEST);
2125 reg32 &= ~(1 << 2);
2126 MCHBAR32(SBTEST) = reg32;
2127
2128 reg32 = MCHBAR32(SBOCC);
2129 reg32 &= 0xffbdb6ff;
2130 reg32 |= (0xbdb6 << 8) | (1 << 0);
2131 MCHBAR32(SBOCC) = reg32;
2132}
2133
2134static void sdram_power_management(struct sys_info *sysinfo)
2135{
Stefan Reinauer278534d2008-10-29 04:51:07 +00002136 u16 reg16;
2137 u32 reg32;
2138 int integrated_graphics = 1;
2139 int i;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002140
Stefan Reinauer278534d2008-10-29 04:51:07 +00002141 reg32 = MCHBAR32(C0DRT2);
2142 reg32 &= 0xffffff00;
2143 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002144 reg32 |= (1 << 5) | (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002145 MCHBAR32(C0DRT2) = reg32;
2146
2147 reg32 = MCHBAR32(C1DRT2);
2148 reg32 &= 0xffffff00;
2149 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002150 reg32 |= (1 << 5) | (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002151 MCHBAR32(C1DRT2) = reg32;
2152
2153 reg32 = MCHBAR32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002154
2155 reg32 |= (1 << 12) | (1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002156 MCHBAR32(C0DRC1) = reg32;
2157
2158 reg32 = MCHBAR32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002159
2160 reg32 |= (1 << 12) | (1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002161 MCHBAR32(C1DRC1) = reg32;
2162
Julius Wernercd49cce2019-03-05 16:53:33 -08002163 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002164 if (i945_silicon_revision() > 1) {
2165 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2166 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002167
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002168 MCHBAR16(UPMC1) = 0x1010 | peg_bits;
2169 } else {
2170 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2171 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002172
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002173 /* Rev 0 and 1 */
2174 MCHBAR16(UPMC1) = 0x0010 | peg_bits;
2175 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002176 }
2177
2178 reg16 = MCHBAR16(UPMC2);
2179 reg16 &= 0xfc00;
2180 reg16 |= 0x0100;
2181 MCHBAR16(UPMC2) = reg16;
2182
2183 MCHBAR32(UPMC3) = 0x000f06ff;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002184
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002185 for (i = 0; i < 5; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002186 MCHBAR32(UPMC3) &= ~(1 << 16);
2187 MCHBAR32(UPMC3) |= (1 << 16);
2188 }
2189
2190 MCHBAR32(GIPMC1) = 0x8000000c;
2191
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002192 reg16 = MCHBAR16(CPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002193 reg16 &= ~(7 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002194 if (i945_silicon_revision() > 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002195 reg16 |= (6 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002196 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002197 reg16 |= (4 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002198 MCHBAR16(CPCTL) = reg16;
2199
Stefan Reinauer30140a52009-03-11 16:20:39 +00002200#if 0
Stefan Reinauer278534d2008-10-29 04:51:07 +00002201 if ((MCHBAR32(ECO) & (1 << 16)) != 0) {
Stefan Reinauer30140a52009-03-11 16:20:39 +00002202#else
2203 if (i945_silicon_revision() != 0) {
2204#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002205 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002206 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002207 MCHBAR32(HGIPMC2) = 0x0d590d59;
2208 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002209 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002210 MCHBAR32(HGIPMC2) = 0x155b155b;
2211 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002212 }
2213 } else {
2214 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002215 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002216 MCHBAR32(HGIPMC2) = 0x09c409c4;
2217 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002218 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002219 MCHBAR32(HGIPMC2) = 0x0fa00fa0;
2220 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002221 }
2222 }
2223
2224 MCHBAR32(FSBPMC1) = 0x8000000c;
2225
2226 reg32 = MCHBAR32(C2C3TT);
2227 reg32 &= 0xffff0000;
2228 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002229 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002230 reg32 |= 0x0600;
2231 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002232 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002233 reg32 |= 0x0480;
2234 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002235 }
2236 MCHBAR32(C2C3TT) = reg32;
2237
2238 reg32 = MCHBAR32(C3C4TT);
2239 reg32 &= 0xffff0000;
2240 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002241 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002242 reg32 |= 0x0b80;
2243 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002244 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002245 reg32 |= 0x0980;
2246 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002247 }
2248 MCHBAR32(C3C4TT) = reg32;
2249
Arthur Heymans70a8e342017-03-09 11:30:23 +01002250 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002251 MCHBAR32(ECO) &= ~(1 << 16);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002252 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002253 MCHBAR32(ECO) |= (1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002254
2255#if 0
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002256
Arthur Heymans70a8e342017-03-09 11:30:23 +01002257 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002258 MCHBAR32(FSBPMC3) &= ~(1 << 29);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002259 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002260 MCHBAR32(FSBPMC3) |= (1 << 29);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002261#endif
2262 MCHBAR32(FSBPMC3) &= ~(1 << 29);
2263
2264 MCHBAR32(FSBPMC3) |= (1 << 21);
2265
2266 MCHBAR32(FSBPMC3) &= ~(1 << 19);
2267
2268 MCHBAR32(FSBPMC3) &= ~(1 << 13);
2269
2270 reg32 = MCHBAR32(FSBPMC4);
2271 reg32 &= ~(3 << 24);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002272 reg32 |= (2 << 24);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002273 MCHBAR32(FSBPMC4) = reg32;
2274
2275 MCHBAR32(FSBPMC4) |= (1 << 21);
2276
2277 MCHBAR32(FSBPMC4) |= (1 << 5);
2278
Arthur Heymans70a8e342017-03-09 11:30:23 +01002279 if ((i945_silicon_revision() < 2)) { /* || cpuid() = 0x6e8 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002280 /* stepping 0 and 1 or CPUID 6e8 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002281 MCHBAR32(FSBPMC4) &= ~(1 << 4);
2282 } else {
Stefan Reinauer30140a52009-03-11 16:20:39 +00002283 MCHBAR32(FSBPMC4) |= (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002284 }
2285
Angel Ponse3c68d22020-06-08 12:09:03 +02002286 pci_or_config8(PCI_DEV(0, 0x0, 0), 0xfc, 1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002287
Angel Ponse3c68d22020-06-08 12:09:03 +02002288 pci_or_config8(PCI_DEV(0, 0x2, 0), 0xc1, 1 << 2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002289
Stefan Reinauerde3206a2010-02-22 06:09:43 +00002290#ifdef C2_SELF_REFRESH_DISABLE
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002291
Stefan Reinauer278534d2008-10-29 04:51:07 +00002292 if (integrated_graphics) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002293 printk(BIOS_DEBUG, "C2 self-refresh with IGD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002294 MCHBAR16(MIPMC4) = 0x0468;
2295 MCHBAR16(MIPMC5) = 0x046c;
2296 MCHBAR16(MIPMC6) = 0x046c;
2297 } else {
2298 MCHBAR16(MIPMC4) = 0x6468;
2299 MCHBAR16(MIPMC5) = 0x646c;
2300 MCHBAR16(MIPMC6) = 0x646c;
2301 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002302#else
2303 if (integrated_graphics) {
2304 MCHBAR16(MIPMC4) = 0x04f8;
2305 MCHBAR16(MIPMC5) = 0x04fc;
2306 MCHBAR16(MIPMC6) = 0x04fc;
2307 } else {
2308 MCHBAR16(MIPMC4) = 0x64f8;
2309 MCHBAR16(MIPMC5) = 0x64fc;
2310 MCHBAR16(MIPMC6) = 0x64fc;
2311 }
2312
2313#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002314
2315 reg32 = MCHBAR32(PMCFG);
2316 reg32 &= ~(3 << 17);
2317 reg32 |= (2 << 17);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002318 MCHBAR32(PMCFG) = reg32;
2319
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002320 MCHBAR32(PMCFG) |= (1 << 4);
2321
Stefan Reinauer278534d2008-10-29 04:51:07 +00002322 reg32 = MCHBAR32(0xc30);
2323 reg32 &= 0xffffff00;
2324 reg32 |= 0x01;
2325 MCHBAR32(0xc30) = reg32;
2326
2327 MCHBAR32(0xb18) &= ~(1 << 21);
2328}
2329
2330static void sdram_thermal_management(void)
2331{
Stefan Reinauer278534d2008-10-29 04:51:07 +00002332
Stefan Reinauer278534d2008-10-29 04:51:07 +00002333 MCHBAR8(TCO1) = 0x00;
2334 MCHBAR8(TCO0) = 0x00;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002335
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002336 /* The Thermal Sensors for DIMMs at 0x50, 0x52 are at I2C addr 0x30/0x32. */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002337
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002338 /* TODO This is not implemented yet. Volunteers? */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002339}
2340
2341static void sdram_save_receive_enable(void)
2342{
2343 int i;
2344 u32 reg32;
2345 u8 values[4];
2346
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002347 /* The following values are stored to an unused CMOS area and restored instead of
2348 * recalculated in case of an S3 resume.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002349 *
Arthur Heymans70a8e342017-03-09 11:30:23 +01002350 * C0WL0REOST [7:0] -> 8 bit
2351 * C1WL0REOST [7:0] -> 8 bit
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002352 * RCVENMT [11:8] [3:0] -> 8 bit
2353 * C0DRT1 [27:24] -> 4 bit
2354 * C1DRT1 [27:24] -> 4 bit
2355 */
2356
2357 values[0] = MCHBAR8(C0WL0REOST);
2358 values[1] = MCHBAR8(C1WL0REOST);
2359
2360 reg32 = MCHBAR32(RCVENMT);
2361 values[2] = (u8)((reg32 >> (8 - 4)) & 0xf0) | (reg32 & 0x0f);
2362
2363 reg32 = MCHBAR32(C0DRT1);
2364 values[3] = (reg32 >> 24) & 0x0f;
2365 reg32 = MCHBAR32(C1DRT1);
2366 values[3] |= (reg32 >> (24 - 4)) & 0xf0;
2367
2368 /* coreboot only uses bytes 0 - 127 for its CMOS values so far
Edwin Beasanteb50c7d2010-07-06 21:05:04 +00002369 * so we grab bytes 128 - 131 to save the receive enable values
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002370 */
2371
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002372 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002373 cmos_write(values[i], 128 + i);
2374}
2375
2376static void sdram_recover_receive_enable(void)
2377{
2378 int i;
2379 u32 reg32;
2380 u8 values[4];
2381
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002382 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002383 values[i] = cmos_read(128 + i);
2384
2385 MCHBAR8(C0WL0REOST) = values[0];
2386 MCHBAR8(C1WL0REOST) = values[1];
2387
2388 reg32 = MCHBAR32(RCVENMT);
2389 reg32 &= ~((0x0f << 8) | (0x0f << 0));
2390 reg32 |= ((u32)(values[2] & 0xf0) << (8 - 4)) | (values[2] & 0x0f);
2391 MCHBAR32(RCVENMT) = reg32;
2392
2393 reg32 = MCHBAR32(C0DRT1) & ~(0x0f << 24);
2394 reg32 |= (u32)(values[3] & 0x0f) << 24;
2395 MCHBAR32(C0DRT1) = reg32;
2396
2397 reg32 = MCHBAR32(C1DRT1) & ~(0x0f << 24);
2398 reg32 |= (u32)(values[3] & 0xf0) << (24 - 4);
2399 MCHBAR32(C1DRT1) = reg32;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002400}
2401
Stefan Reinauer278534d2008-10-29 04:51:07 +00002402static void sdram_program_receive_enable(struct sys_info *sysinfo)
2403{
2404 MCHBAR32(REPC) |= (1 << 0);
2405
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002406 /* Program Receive Enable Timings */
2407 if (sysinfo->boot_path == BOOT_PATH_RESUME) {
2408 sdram_recover_receive_enable();
2409 } else {
2410 receive_enable_adjust(sysinfo);
2411 sdram_save_receive_enable();
2412 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002413
2414 MCHBAR32(C0DRC1) |= (1 << 6);
2415 MCHBAR32(C1DRC1) |= (1 << 6);
2416 MCHBAR32(C0DRC1) &= ~(1 << 6);
2417 MCHBAR32(C1DRC1) &= ~(1 << 6);
2418
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002419 MCHBAR32(MIPMC3) |= (0x0f << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002420}
2421
2422/**
2423 * @brief Enable On-Die Termination for DDR2.
2424 *
2425 */
2426
2427static void sdram_on_die_termination(struct sys_info *sysinfo)
2428{
2429 static const u32 odt[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002430 0x00024911, 0xe0010000,
2431 0x00049211, 0xe0020000,
2432 0x0006db11, 0xe0030000,
Stefan Reinauer278534d2008-10-29 04:51:07 +00002433 };
2434
2435 u32 reg32;
2436 int cas;
2437
2438 reg32 = MCHBAR32(ODTC);
2439 reg32 &= ~(3 << 16);
2440 reg32 |= (1 << 14) | (1 << 6) | (2 << 16);
2441 MCHBAR32(ODTC) = reg32;
2442
Paul Menzelb4d9f222020-03-14 10:34:29 +01002443 if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002444 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
Elyes HAOUAS38424982016-08-21 12:01:04 +02002445 printk(BIOS_DEBUG, "one dimm per channel config..\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002446
Stefan Reinauer278534d2008-10-29 04:51:07 +00002447 reg32 = MCHBAR32(C0ODT);
2448 reg32 &= ~(7 << 28);
2449 MCHBAR32(C0ODT) = reg32;
2450 reg32 = MCHBAR32(C1ODT);
2451 reg32 &= ~(7 << 28);
2452 MCHBAR32(C1ODT) = reg32;
2453 }
2454
2455 cas = sysinfo->cas;
2456
2457 reg32 = MCHBAR32(C0ODT) & 0xfff00000;
Angel Pons30492572020-06-11 13:24:54 +02002458 reg32 |= odt[(cas - 3) * 2];
Stefan Reinauer278534d2008-10-29 04:51:07 +00002459 MCHBAR32(C0ODT) = reg32;
2460
2461 reg32 = MCHBAR32(C1ODT) & 0xfff00000;
Angel Pons30492572020-06-11 13:24:54 +02002462 reg32 |= odt[(cas - 3) * 2];
Stefan Reinauer278534d2008-10-29 04:51:07 +00002463 MCHBAR32(C1ODT) = reg32;
2464
2465 reg32 = MCHBAR32(C0ODT + 4) & 0x1fc8ffff;
Angel Pons30492572020-06-11 13:24:54 +02002466 reg32 |= odt[((cas - 3) * 2) + 1];
Stefan Reinauer278534d2008-10-29 04:51:07 +00002467 MCHBAR32(C0ODT + 4) = reg32;
2468
2469 reg32 = MCHBAR32(C1ODT + 4) & 0x1fc8ffff;
Angel Pons30492572020-06-11 13:24:54 +02002470 reg32 |= odt[((cas - 3) * 2) + 1];
Stefan Reinauer278534d2008-10-29 04:51:07 +00002471 MCHBAR32(C1ODT + 4) = reg32;
2472}
2473
2474/**
2475 * @brief Enable clocks to populated sockets
2476 */
2477
2478static void sdram_enable_memory_clocks(struct sys_info *sysinfo)
2479{
2480 u8 clocks[2] = { 0, 0 };
2481
Julius Wernercd49cce2019-03-05 16:53:33 -08002482#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002483#define CLOCKS_WIDTH 2
Julius Wernercd49cce2019-03-05 16:53:33 -08002484#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002485#define CLOCKS_WIDTH 3
2486#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002487 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002488 clocks[0] |= (1 << CLOCKS_WIDTH) - 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002489
2490 if (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002491 clocks[0] |= ((1 << CLOCKS_WIDTH) - 1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002492
2493 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002494 clocks[1] |= (1 << CLOCKS_WIDTH) - 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002495
2496 if (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002497 clocks[1] |= ((1 << CLOCKS_WIDTH) - 1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002498
Julius Wernercd49cce2019-03-05 16:53:33 -08002499#if CONFIG(OVERRIDE_CLOCK_DISABLE)
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002500 /* Usually system firmware turns off system memory clock signals to unused SO-DIMM slots
2501 * to reduce EMI and power consumption.
2502 * However, the Kontron 986LCD-M does not like unused clock signals to be disabled.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002503 */
2504
2505 clocks[0] = 0xf; /* force all clock gate pairs to enable */
2506 clocks[1] = 0xf; /* force all clock gate pairs to enable */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002507#endif
2508
2509 MCHBAR8(C0DCLKDIS) = clocks[0];
2510 MCHBAR8(C1DCLKDIS) = clocks[1];
2511}
2512
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002513#define RTT_ODT_NONE 0
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002514#define RTT_ODT_50_OHM ((1 << 9) | (1 << 5))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002515#define RTT_ODT_75_OHM (1 << 5)
2516#define RTT_ODT_150_OHM (1 << 9)
2517
Arthur Heymans70a8e342017-03-09 11:30:23 +01002518#define EMRS_OCD_DEFAULT ((1 << 12) | (1 << 11) | (1 << 10))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002519
2520#define MRS_CAS_3 (3 << 7)
2521#define MRS_CAS_4 (4 << 7)
2522#define MRS_CAS_5 (5 << 7)
2523
2524#define MRS_TWR_3 (2 << 12)
2525#define MRS_TWR_4 (3 << 12)
2526#define MRS_TWR_5 (4 << 12)
2527
2528#define MRS_BT (1 << 6)
2529
2530#define MRS_BL4 (2 << 3)
2531#define MRS_BL8 (3 << 3)
2532
2533static void sdram_jedec_enable(struct sys_info *sysinfo)
2534{
2535 int i, nonzero;
2536 u32 bankaddr = 0, tmpaddr, mrsaddr = 0;
2537
2538 for (i = 0, nonzero = -1; i < 8; i++) {
Elyes HAOUAS01912202019-01-19 16:36:38 +01002539 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002540 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002541
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002542 printk(BIOS_DEBUG, "jedec enable sequence: bank %d\n", i);
Elyes HAOUAS01912202019-01-19 16:36:38 +01002543
2544 if (nonzero != -1) {
2545 if (sysinfo->interleaved && nonzero < 4 && i >= 4) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002546 bankaddr = 0x40;
Elyes HAOUAS01912202019-01-19 16:36:38 +01002547 } else {
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002548 printk(BIOS_DEBUG, "bankaddr from bank size of rank %d\n",
2549 nonzero);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002550 bankaddr += sysinfo->banksize[nonzero] <<
2551 (sysinfo->interleaved ? 26 : 25);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002552 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002553 }
2554
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002555 /*
2556 * We have a bank with a non-zero size... Remember it
Stefan Reinauer278534d2008-10-29 04:51:07 +00002557 * for the next offset we have to calculate
2558 */
2559 nonzero = i;
2560
2561 /* Get CAS latency set up */
2562 switch (sysinfo->cas) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002563 case 5:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002564 mrsaddr = MRS_CAS_5;
2565 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002566 case 4:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002567 mrsaddr = MRS_CAS_4;
2568 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002569 case 3:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002570 mrsaddr = MRS_CAS_3;
2571 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002572 default:
2573 die("Jedec Error (CAS).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002574 }
2575
2576 /* Get tWR set */
2577 switch (sysinfo->twr) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002578 case 5:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002579 mrsaddr |= MRS_TWR_5;
2580 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002581 case 4:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002582 mrsaddr |= MRS_TWR_4;
2583 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002584 case 3:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002585 mrsaddr |= MRS_TWR_3;
2586 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002587 default:
2588 die("Jedec Error (tWR).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002589 }
2590
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002591 /* Set "Burst Type" */
2592 mrsaddr |= MRS_BT;
2593
Stefan Reinauer278534d2008-10-29 04:51:07 +00002594 /* Interleaved */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002595 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002596 mrsaddr = mrsaddr << 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002597
2598 /* Only burst length 8 supported */
2599 mrsaddr |= MRS_BL8;
2600
2601 /* Apply NOP */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002602 PRINTK_DEBUG("Apply NOP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002603 do_ram_command(RAM_COMMAND_NOP);
2604 ram_read32(bankaddr);
2605
2606 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002607 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002608 do_ram_command(RAM_COMMAND_PRECHARGE);
2609 ram_read32(bankaddr);
2610
2611 /* Extended Mode Register Set (2) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002612 PRINTK_DEBUG("Extended Mode Register Set(2)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002613 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_2);
2614 ram_read32(bankaddr);
2615
2616 /* Extended Mode Register Set (3) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002617 PRINTK_DEBUG("Extended Mode Register Set(3)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002618 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_3);
2619 ram_read32(bankaddr);
2620
2621 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002622 PRINTK_DEBUG("Extended Mode Register Set\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002623 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2624 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002625 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002626 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002627 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002628 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002629 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002630 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002631 ram_read32(tmpaddr);
2632
2633 /* Mode Register Set: Reset DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002634 PRINTK_DEBUG("MRS: Reset DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002635 do_ram_command(RAM_COMMAND_MRS);
2636 tmpaddr = bankaddr;
2637 tmpaddr |= mrsaddr;
2638 /* Set DLL reset bit */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002639 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002640 tmpaddr |= (1 << 12);
2641 else
2642 tmpaddr |= (1 << 11);
2643 ram_read32(tmpaddr);
2644
2645 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002646 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002647 do_ram_command(RAM_COMMAND_PRECHARGE);
2648 ram_read32(bankaddr);
2649
2650 /* CAS before RAS Refresh */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002651 PRINTK_DEBUG("CAS before RAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002652 do_ram_command(RAM_COMMAND_CBR);
2653
2654 /* CBR wants two READs */
2655 ram_read32(bankaddr);
2656 ram_read32(bankaddr);
2657
2658 /* Mode Register Set: Enable DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002659 PRINTK_DEBUG("MRS: Enable DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002660 do_ram_command(RAM_COMMAND_MRS);
2661
2662 tmpaddr = bankaddr;
2663 tmpaddr |= mrsaddr;
2664 ram_read32(tmpaddr);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002665
Stefan Reinauer278534d2008-10-29 04:51:07 +00002666 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002667 PRINTK_DEBUG("Extended Mode Register Set: ODT/OCD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002668 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002669
Stefan Reinauer278534d2008-10-29 04:51:07 +00002670 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002671 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002672 tmpaddr |= RTT_ODT_75_OHM | EMRS_OCD_DEFAULT;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002673 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002674 tmpaddr |= ((RTT_ODT_150_OHM | EMRS_OCD_DEFAULT) << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002675 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002676 tmpaddr |= RTT_ODT_150_OHM | EMRS_OCD_DEFAULT;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002677 ram_read32(tmpaddr);
2678
2679 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002680 PRINTK_DEBUG("Extended Mode Register Set: OCD Exit\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002681 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2682
2683 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002684 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002685 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002686 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002687 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002688 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002689 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002690 ram_read32(tmpaddr);
2691 }
2692}
2693
2694static void sdram_init_complete(void)
2695{
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002696 PRINTK_DEBUG("Normal Operation\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002697 do_ram_command(RAM_COMMAND_NORMAL);
2698}
2699
2700static void sdram_setup_processor_side(void)
2701{
2702 if (i945_silicon_revision() == 0)
2703 MCHBAR32(FSBPMC3) |= (1 << 2);
2704
2705 MCHBAR8(0xb00) |= 1;
2706
2707 if (i945_silicon_revision() == 0)
2708 MCHBAR32(SLPCTL) |= (1 << 8);
2709}
2710
Stefan Reinauer278534d2008-10-29 04:51:07 +00002711/**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002712 * @param boot_path: 0 = normal, 1 = reset, 2 = resume from s3
Martin Rothf4cb4122015-01-06 10:27:39 -07002713 * @param spd_addresses pointer to a list of SPD addresses
Stefan Reinauer278534d2008-10-29 04:51:07 +00002714 */
Sven Schnelle541269b2011-02-21 09:39:17 +00002715void sdram_initialize(int boot_path, const u8 *spd_addresses)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002716{
2717 struct sys_info sysinfo;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002718
Patrick Georgi771328f2015-07-13 19:24:07 +02002719 timestamp_add_now(TS_BEFORE_INITRAM);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002720 printk(BIOS_DEBUG, "Setting up RAM controller.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002721
2722 memset(&sysinfo, 0, sizeof(sysinfo));
2723
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002724 sysinfo.boot_path = boot_path;
Sven Schnelle541269b2011-02-21 09:39:17 +00002725 sysinfo.spd_addresses = spd_addresses;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002726
Stefan Reinauer278534d2008-10-29 04:51:07 +00002727 /* Look at the type of DIMMs and verify all DIMMs are x8 or x16 width */
2728 sdram_get_dram_configuration(&sysinfo);
2729
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002730 /* If error, do cold boot */
2731 sdram_detect_errors(&sysinfo);
2732
Stefan Reinauer278534d2008-10-29 04:51:07 +00002733 /* Program PLL settings */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002734 sdram_program_pll_settings(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002735
Arthur Heymans18537812016-12-28 21:20:45 +01002736 /*
2737 * Program Graphics Frequency
2738 * Set core display and render clock on 945GC to the max
2739 */
Julius Wernercd49cce2019-03-05 16:53:33 -08002740 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM))
Arthur Heymans18537812016-12-28 21:20:45 +01002741 sdram_program_graphics_frequency(&sysinfo);
2742 else
2743 pci_write_config16(PCI_DEV(0, 2, 0), GCFC, 0x0534);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002744
2745 /* Program System Memory Frequency */
2746 sdram_program_memory_frequency(&sysinfo);
2747
2748 /* Determine Mode of Operation (Interleaved etc) */
2749 sdram_set_channel_mode(&sysinfo);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002750
Stefan Reinauer278534d2008-10-29 04:51:07 +00002751 /* Program Clock Crossing values */
2752 sdram_program_clock_crossing();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002753
Stefan Reinauer278534d2008-10-29 04:51:07 +00002754 /* Disable fast dispatch */
2755 sdram_disable_fast_dispatch();
2756
2757 /* Enable WIODLL Power Down in ACPI states */
2758 MCHBAR32(C0DMC) |= (1 << 24);
2759 MCHBAR32(C1DMC) |= (1 << 24);
2760
2761 /* Program DRAM Row Boundary/Attribute Registers */
2762
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002763 /* program row size DRB and set TOLUD */
2764 sdram_program_row_boundaries(&sysinfo);
2765
2766 /* program page size DRA */
2767 sdram_set_row_attributes(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002768
2769 /* Program CxBNKARC */
2770 sdram_set_bank_architecture(&sysinfo);
2771
2772 /* Program DRAM Timing and Control registers based on SPD */
2773 sdram_set_timing_and_control(&sysinfo);
2774
2775 /* On-Die Termination Adjustment */
2776 sdram_on_die_termination(&sysinfo);
2777
2778 /* Pre Jedec Initialization */
2779 sdram_pre_jedec_initialization();
2780
2781 /* Perform System Memory IO Initialization */
2782 sdram_initialize_system_memory_io(&sysinfo);
2783
2784 /* Perform System Memory IO Buffer Enable */
2785 sdram_enable_system_memory_io(&sysinfo);
2786
2787 /* Enable System Memory Clocks */
2788 sdram_enable_memory_clocks(&sysinfo);
2789
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002790 if (boot_path == BOOT_PATH_NORMAL) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002791 /* Jedec Initialization sequence */
2792 sdram_jedec_enable(&sysinfo);
2793 }
2794
2795 /* Program Power Management Registers */
2796 sdram_power_management(&sysinfo);
2797
2798 /* Post Jedec Init */
2799 sdram_post_jedec_initialization(&sysinfo);
2800
2801 /* Program DRAM Throttling */
2802 sdram_thermal_management();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002803
Stefan Reinauer278534d2008-10-29 04:51:07 +00002804 /* Normal Operations */
Stefan Reinaueraca6ec62009-10-26 17:12:21 +00002805 sdram_init_complete();
Stefan Reinauer278534d2008-10-29 04:51:07 +00002806
2807 /* Program Receive Enable Timings */
2808 sdram_program_receive_enable(&sysinfo);
2809
2810 /* Enable Periodic RCOMP */
2811 sdram_enable_rcomp();
2812
2813 /* Tell ICH7 that we're done */
Angel Ponse3c68d22020-06-08 12:09:03 +02002814 pci_and_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, (u8)~(1 << 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +00002815
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002816 printk(BIOS_DEBUG, "RAM initialization finished.\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002817
Stefan Reinauer278534d2008-10-29 04:51:07 +00002818 sdram_setup_processor_side();
Patrick Georgi771328f2015-07-13 19:24:07 +02002819 timestamp_add_now(TS_AFTER_INITRAM);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002820}