blob: 4e3509eb985b54138b061cc8b599843ff684517f [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);
Arthur Heymans70a8e342017-03-09 11:30:23 +010056 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
Stefan Reinauer278534d2008-10-29 04:51:07 +0000232 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
241 if (reg8 & (1<<7)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000242 printk(BIOS_DEBUG, "DRAM initialization was interrupted.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000243 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 */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100260 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000261 reg8 |= (1<<7);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100262 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000263
Peter Stuge751508a2012-01-27 22:17:09 +0100264 /* clear self refresh status if check is disabled or not a resume */
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200265 if (!CONFIG(CHECK_SLFRCS_ON_RESUME) || sysinfo->boot_path != BOOT_PATH_RESUME) {
Patrick Georgi86a11102013-03-15 14:11:37 +0100266 MCHBAR8(SLFRCS) |= 3;
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000267 } else {
268 /* Validate self refresh config */
269 if (((sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED) ||
270 (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)) &&
Patrick Georgi86a11102013-03-15 14:11:37 +0100271 !(MCHBAR8(SLFRCS) & (1<<0))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000272 do_reset = 1;
273 }
274 if (((sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED) ||
275 (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) &&
Patrick Georgi86a11102013-03-15 14:11:37 +0100276 !(MCHBAR8(SLFRCS) & (1<<1))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000277 do_reset = 1;
278 }
279 }
280
281 if (do_reset) {
282 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200283 full_reset();
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000284 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000285}
Stefan Reinauer278534d2008-10-29 04:51:07 +0000286
Arthur Heymans0ab49042017-02-06 22:40:14 +0100287struct timings {
288 u32 min_tCLK_cas[8];
289 u32 min_tRAS;
290 u32 min_tRP;
291 u32 min_tRCD;
292 u32 min_tWR;
293 u32 min_tRFC;
294 u32 max_tRR;
295 u8 cas_mask;
296};
Stefan Reinauer278534d2008-10-29 04:51:07 +0000297
Arthur Heymans0ab49042017-02-06 22:40:14 +0100298/**
299 * @brief loop over dimms and save maximal timings
300 */
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200301static void gather_common_timing(struct sys_info *sysinfo, struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000302{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100303
304 int i, j;
305 u8 raw_spd[SPD_SIZE_MAX_DDR2];
306 u8 dimm_mask = 0;
307
308 memset(saved_timings, 0, sizeof(*saved_timings));
309 saved_timings->max_tRR = UINT32_MAX;
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200310 saved_timings->cas_mask = SPD_CAS_LATENCY_DDR2_3 | SPD_CAS_LATENCY_DDR2_4
311 | SPD_CAS_LATENCY_DDR2_5;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000312
313 /**
314 * i945 supports two DIMMs, in two configurations:
315 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000316 * - single channel with two DIMMs
317 * - dual channel with one DIMM per channel
Stefan Reinauer278534d2008-10-29 04:51:07 +0000318 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000319 * In practice dual channel mainboards have their SPD at 0x50/0x52
320 * whereas single channel configurations have their SPD at 0x50/0x51.
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000321 *
Stefan Reinauer278534d2008-10-29 04:51:07 +0000322 * The capability register knows a lot about the channel configuration
Uwe Hermannd773fd32010-11-20 20:23:08 +0000323 * but for now we stick with the information we gather via SPD.
Stefan Reinauer278534d2008-10-29 04:51:07 +0000324 */
325
Arthur Heymans0ab49042017-02-06 22:40:14 +0100326 printk(BIOS_DEBUG, "This mainboard supports ");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000327 if (sdram_capabilities_dual_channel()) {
328 sysinfo->dual_channel = 1;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100329 printk(BIOS_DEBUG, "Dual Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000330 } else {
331 sysinfo->dual_channel = 0;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100332 printk(BIOS_DEBUG, "only Single Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000333 }
334
Stefan Reinauer278534d2008-10-29 04:51:07 +0000335
Arthur Heymans70a8e342017-03-09 11:30:23 +0100336 for (i = 0; i < (2 * DIMM_SOCKETS); i++) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100337 int device = get_dimm_spd_address(sysinfo, i), bytes_read;
Arthur Heymansfc31e442018-02-12 15:12:34 +0100338 struct dimm_attr_ddr2_st dimm_info;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000339
340 /* Initialize the socket information with a sane value */
341 sysinfo->dimm[i] = SYSINFO_DIMM_NOT_POPULATED;
342
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000343 /* Dual Channel not supported, but Channel 1? Bail out */
344 if (!sdram_capabilities_dual_channel() && (i >> 1))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000345 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000346
Kyösti Mälkkibd659852020-01-05 20:00:18 +0200347 if (smbus_read_byte(device, SPD_MEMORY_TYPE) !=
Arthur Heymans0ab49042017-02-06 22:40:14 +0100348 SPD_MEMORY_TYPE_SDRAM_DDR2) {
349 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: N/A\n",
350 (i >> 1), (i & 1));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000351 continue;
352 }
353
Arthur Heymans0ab49042017-02-06 22:40:14 +0100354 /*
355 * spd_decode_ddr2() needs a 128-byte sized array but
356 * only the first 64 bytes contain data needed for raminit.
357 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000358
Kyösti Mälkkic01a5052019-01-30 09:39:23 +0200359 bytes_read = i2c_eeprom_read(device, 0, 64, raw_spd);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100360 printk(BIOS_DEBUG, "Reading SPD using i2c block operation.\n");
Julius Wernercd49cce2019-03-05 16:53:33 -0800361 if (CONFIG(DEBUG_RAM_SETUP) && bytes_read > 0)
Arthur Heymans0ab49042017-02-06 22:40:14 +0100362 hexdump(raw_spd, bytes_read);
Arthur Heymans56619452017-09-21 09:12:42 +0200363 if (bytes_read != 64) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100364 /* Try again with SMBUS byte read */
365 printk(BIOS_DEBUG, "i2c block operation failed,"
Paul Menzel105e3682017-09-21 08:11:05 +0200366 " trying smbus byte operation.\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100367 for (j = 0; j < 64; j++)
Kyösti Mälkkibd659852020-01-05 20:00:18 +0200368 raw_spd[j] = smbus_read_byte(device, j);
Julius Wernercd49cce2019-03-05 16:53:33 -0800369 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100370 hexdump(raw_spd, 64);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100371 }
Arthur Heymans56619452017-09-21 09:12:42 +0200372
373 if (spd_decode_ddr2(&dimm_info, raw_spd) != SPD_STATUS_OK) {
374 printk(BIOS_WARNING, "Encountered problems with SPD, "
375 "skipping this DIMM.\n");
376 continue;
377 }
378
Julius Wernercd49cce2019-03-05 16:53:33 -0800379 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100380 dram_print_spd_ddr2(&dimm_info);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000381
Arthur Heymans0ab49042017-02-06 22:40:14 +0100382 if (dimm_info.flags.is_ecc)
383 die("\nError: ECC memory not supported by this chipset\n");
384
385 if (spd_dimm_is_registered_ddr2(dimm_info.dimm_type))
386 die("\nError: Registered memory not supported by this chipset\n");
387
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200388 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: ", (i >> 1), (i & 1));
Arthur Heymans0ab49042017-02-06 22:40:14 +0100389 /**
390 * There are 5 different possible populations for a DIMM socket:
391 * 0. x16 double ranked (X16DS)
392 * 1. x8 double ranked (X8DS)
393 * 2. x16 single ranked (X16SS)
394 * 3. x8 double stacked (X8DDS)
395 * 4. Unpopulated
396 */
397 switch (dimm_info.width) {
398 case 8:
399 switch (dimm_info.ranks) {
400 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000401 printk(BIOS_DEBUG, "x8DDS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000402 sysinfo->dimm[i] = SYSINFO_DIMM_X8DDS;
403 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100404 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000405 printk(BIOS_DEBUG, "x8DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000406 sysinfo->dimm[i] = SYSINFO_DIMM_X8DS;
407 break;
408 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000409 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000410 }
411 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100412 case 16:
413 switch (dimm_info.ranks) {
414 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000415 printk(BIOS_DEBUG, "x16DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000416 sysinfo->dimm[i] = SYSINFO_DIMM_X16DS;
417 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100418 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000419 printk(BIOS_DEBUG, "x16SS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000420 sysinfo->dimm[i] = SYSINFO_DIMM_X16SS;
421 break;
422 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000423 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000424 }
425 break;
426 default:
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000427 die("Unsupported DDR-II memory width.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000428 }
429
Arthur Heymans0ab49042017-02-06 22:40:14 +0100430 /* Is the current DIMM a stacked DIMM? */
431 if (dimm_info.flags.stacked)
432 sysinfo->package = SYSINFO_PACKAGE_STACKED;
433
434 if (!dimm_info.flags.bl8)
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100435 die("Only DDR-II RAM with burst length 8 is supported.\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100436
437 if (dimm_info.ranksize_mb < 128)
438 die("DDR-II rank size smaller than 128MB is not supported.\n");
439
440 sysinfo->banksize[i * 2] = dimm_info.ranksize_mb / 32;
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200441 printk(BIOS_DEBUG, "DIMM %d side 0 = %d MB\n", i, sysinfo->banksize[i * 2] * 32);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100442 if (dimm_info.ranks == 2) {
443 sysinfo->banksize[(i * 2) + 1] =
444 dimm_info.ranksize_mb / 32;
445 printk(BIOS_DEBUG, "DIMM %d side 1 = %d MB\n",
446 i, sysinfo->banksize[(i * 2) + 1] * 32);
447 }
448
449
450 sysinfo->rows[i] = dimm_info.row_bits;
451 sysinfo->cols[i] = dimm_info.col_bits;
452 sysinfo->banks[i] = dimm_info.banks;
453
454 /* int min_tRAS, min_tRP, min_tRCD, min_tWR, min_tRFC; */
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200455 saved_timings->min_tRAS = MAX(saved_timings->min_tRAS, dimm_info.tRAS);
456 saved_timings->min_tRP = MAX(saved_timings->min_tRP, dimm_info.tRP);
457 saved_timings->min_tRCD = MAX(saved_timings->min_tRCD, dimm_info.tRCD);
458 saved_timings->min_tWR = MAX(saved_timings->min_tWR, dimm_info.tWR);
459 saved_timings->min_tRFC = MAX(saved_timings->min_tRFC, dimm_info.tRFC);
460 saved_timings->max_tRR = MIN(saved_timings->max_tRR, dimm_info.tRR);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100461 saved_timings->cas_mask &= dimm_info.cas_supported;
462 for (j = 0; j < 8; j++) {
463 if (!(saved_timings->cas_mask & (1 << j)))
464 saved_timings->min_tCLK_cas[j] = 0;
465 else
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200466 saved_timings->min_tCLK_cas[j] = MAX(dimm_info.cycle_time[j],
Arthur Heymans0ab49042017-02-06 22:40:14 +0100467 saved_timings->min_tCLK_cas[j]);
468 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000469 dimm_mask |= (1 << i);
470 }
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200471 if (!dimm_mask)
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000472 die("No memory installed.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000473
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200474 if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1)))
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100475 /* FIXME: Possibly does not boot in this case */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000476 printk(BIOS_INFO, "Channel 0 has no memory populated.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000477}
478
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200479static void choose_tclk(struct sys_info *sysinfo, struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000480{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100481 u32 ctrl_min_tclk;
482 int try_cas;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000483
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200484 ctrl_min_tclk = 2 * 256 * 1000 / sdram_capabilities_max_supported_memory_frequency();
Arthur Heymans0ab49042017-02-06 22:40:14 +0100485 normalize_tck(&ctrl_min_tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000486
Arthur Heymans0ab49042017-02-06 22:40:14 +0100487 try_cas = spd_get_msbs(saved_timings->cas_mask);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000488
Arthur Heymans0ab49042017-02-06 22:40:14 +0100489 while (saved_timings->cas_mask & (1 << try_cas) && try_cas > 0) {
490 sysinfo->cas = try_cas;
491 sysinfo->tclk = saved_timings->min_tCLK_cas[try_cas];
492 if (sysinfo->tclk >= ctrl_min_tclk &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200493 saved_timings->min_tCLK_cas[try_cas] !=
494 saved_timings->min_tCLK_cas[try_cas - 1])
Stefan Reinauer278534d2008-10-29 04:51:07 +0000495 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100496 try_cas--;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000497 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000498
Arthur Heymans0ab49042017-02-06 22:40:14 +0100499 normalize_tck(&sysinfo->tclk);
500
501 if ((sysinfo->cas < 3) || (sysinfo->tclk == 0))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000502 die("Could not find common memory frequency and CAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000503
Arthur Heymans0ab49042017-02-06 22:40:14 +0100504 /*
505 * The loop can still results in a timing too fast for the
506 * memory controller.
507 */
508 if (sysinfo->tclk < ctrl_min_tclk)
509 sysinfo->tclk = ctrl_min_tclk;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000510
Arthur Heymans0ab49042017-02-06 22:40:14 +0100511 switch (sysinfo->tclk) {
512 case TCK_200MHZ:
513 sysinfo->memory_frequency = 400;
514 break;
515 case TCK_266MHZ:
516 sysinfo->memory_frequency = 533;
517 break;
518 case TCK_333MHZ:
519 sysinfo->memory_frequency = 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100520 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000521 }
522
Arthur Heymans0ab49042017-02-06 22:40:14 +0100523 printk(BIOS_DEBUG,
524 "Memory will be driven at %dMT with CAS=%d clocks\n",
525 sysinfo->memory_frequency, sysinfo->cas);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000526}
527
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200528static void derive_timings(struct sys_info *sysinfo, struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000529{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100530 sysinfo->tras = DIV_ROUND_UP(saved_timings->min_tRAS, sysinfo->tclk);
531 if (sysinfo->tras > 0x18)
532 die("DDR-II Module does not support this frequency (tRAS error)\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000533
Arthur Heymans0ab49042017-02-06 22:40:14 +0100534 sysinfo->trp = DIV_ROUND_UP(saved_timings->min_tRP, sysinfo->tclk);
535 if (sysinfo->trp > 6)
536 die("DDR-II Module does not support this frequency (tRP error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000537
Arthur Heymans0ab49042017-02-06 22:40:14 +0100538 sysinfo->trcd = DIV_ROUND_UP(saved_timings->min_tRCD, sysinfo->tclk);
539 if (sysinfo->trcd > 6)
540 die("DDR-II Module does not support this frequency (tRCD error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000541
Arthur Heymans0ab49042017-02-06 22:40:14 +0100542 sysinfo->twr = DIV_ROUND_UP(saved_timings->min_tWR, sysinfo->tclk);
543 if (sysinfo->twr > 5)
544 die("DDR-II Module does not support this frequency (tWR error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000545
Arthur Heymans0ab49042017-02-06 22:40:14 +0100546 sysinfo->trfc = DIV_ROUND_UP(saved_timings->min_tRFC, sysinfo->tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000547
Arthur Heymans0ab49042017-02-06 22:40:14 +0100548 printk(BIOS_DEBUG, "tRAS = %d cycles\n", sysinfo->tras);
549 printk(BIOS_DEBUG, "tRP = %d cycles\n", sysinfo->trp);
550 printk(BIOS_DEBUG, "tRCD = %d cycles\n", sysinfo->trcd);
551 printk(BIOS_DEBUG, "tWR = %d cycles\n", sysinfo->twr);
552 printk(BIOS_DEBUG, "tRFC = %d cycles\n", sysinfo->trfc);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000553
Arthur Heymans0ab49042017-02-06 22:40:14 +0100554 /* Refresh is slower than 15.6us, use 15.6us */
555 /* tRR is decoded in units of 1/256us */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000556
Arthur Heymans0ab49042017-02-06 22:40:14 +0100557#define T_RR_7_8US 2000000
558#define T_RR_15_6US 4000000
559#define REFRESH_7_8US 1
560#define REFRESH_15_6US 0
Stefan Reinauer278534d2008-10-29 04:51:07 +0000561
Arthur Heymans0ab49042017-02-06 22:40:14 +0100562 if (saved_timings->max_tRR < T_RR_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000563 die("DDR-II module has unsupported refresh value\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100564 else if (saved_timings->max_tRR < T_RR_15_6US)
565 sysinfo->refresh = REFRESH_7_8US;
566 else
567 sysinfo->refresh = REFRESH_15_6US;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000568 printk(BIOS_DEBUG, "Refresh: %s\n", sysinfo->refresh?"7.8us":"15.6us");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000569}
570
Arthur Heymans0ab49042017-02-06 22:40:14 +0100571/**
572 * @brief Get generic DIMM parameters.
573 * @param sysinfo Central memory controller information structure
574 *
575 * This function gathers several pieces of information for each system DIMM:
576 * o DIMM width (x8 / x16)
577 * o DIMM rank (single ranked / dual ranked)
578 *
579 * Also, some non-supported scenarios are detected.
580 */
581
582static void sdram_get_dram_configuration(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000583{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100584 struct timings saved_timings;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000585
Arthur Heymans0ab49042017-02-06 22:40:14 +0100586 gather_common_timing(sysinfo, &saved_timings);
587 choose_tclk(sysinfo, &saved_timings);
588 derive_timings(sysinfo, &saved_timings);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000589}
590
Arthur Heymans70a8e342017-03-09 11:30:23 +0100591static void sdram_program_dram_width(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000592{
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200593 u16 c0dramw = 0, c1dramw = 0;
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200594 int i, idx;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000595
596 if (sysinfo->dual_channel)
597 idx = 2;
598 else
599 idx = 1;
600
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200601 for (i = 0; i < DIMM_SOCKETS; i++) { /* Channel 0 */
602 switch (sysinfo->dimm[i]) {
603 case SYSINFO_DIMM_X16DS:
604 c0dramw |= (0x0000) << 4*(i % 2);
605 break;
606 case SYSINFO_DIMM_X8DS:
607 c0dramw |= (0x0001) << 4*(i % 2);
608 break;
609 case SYSINFO_DIMM_X16SS:
610 c0dramw |= (0x0000) << 4*(i % 2);
611 break;
612 case SYSINFO_DIMM_X8DDS:
613 c0dramw |= (0x0005) << 4*(i % 2);
614 break;
615 case SYSINFO_DIMM_NOT_POPULATED:
616 c0dramw |= (0x0000) << 4*(i % 2);
617 break;
618 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000619 }
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200620 for (i = DIMM_SOCKETS; i < idx * DIMM_SOCKETS; i++) { /* Channel 1 */
621 switch (sysinfo->dimm[i]) {
622 case SYSINFO_DIMM_X16DS:
623 c1dramw |= (0x0000) << 4*(i % 2);
624 break;
625 case SYSINFO_DIMM_X8DS:
Patrick Georgi68aed912018-11-16 18:00:12 +0100626 c1dramw |= (0x0010) << 4*(i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200627 break;
628 case SYSINFO_DIMM_X16SS:
629 c1dramw |= (0x0000) << 4*(i % 2);
630 break;
631 case SYSINFO_DIMM_X8DDS:
Patrick Georgi68aed912018-11-16 18:00:12 +0100632 c1dramw |= (0x0050) << 4*(i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200633 break;
634 case SYSINFO_DIMM_NOT_POPULATED:
635 c1dramw |= (0x0000) << 4*(i % 2);
636 break;
637 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000638 }
639
640 MCHBAR16(C0DRAMW) = c0dramw;
641 MCHBAR16(C1DRAMW) = c1dramw;
642}
643
644static void sdram_write_slew_rates(u32 offset, const u32 *slew_rate_table)
645{
646 int i;
647
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200648 for (i = 0; i < 16; i++)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000649 MCHBAR32(offset+(i*4)) = slew_rate_table[i];
650}
651
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000652static const u32 dq2030[] = {
653 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
654 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
655 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
656 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
657};
658
659static const u32 dq2330[] = {
660 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
661 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
662 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
663 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
664};
665
666static const u32 cmd2710[] = {
667 0x07060605, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
668 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
669 0x1110100f, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
670 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
671};
672
673static const u32 cmd3210[] = {
674 0x0f0d0b0a, 0x17151311, 0x1f1d1b19, 0x1f1f1f1f,
675 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
676 0x18171615, 0x1f1f1c1a, 0x1f1f1f1f, 0x1f1f1f1f,
677 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
678};
679
680static const u32 clk2030[] = {
681 0x0e0d0d0c, 0x100f0f0e, 0x100f0e0d, 0x15131211,
682 0x1d1b1917, 0x2523211f, 0x2a282927, 0x32302e2c,
683 0x17161514, 0x1b1a1918, 0x1f1e1d1c, 0x23222120,
684 0x27262524, 0x2d2b2928, 0x3533312f, 0x3d3b3937
685};
686
687static const u32 ctl3215[] = {
688 0x01010000, 0x03020101, 0x07060504, 0x0b0a0908,
689 0x100f0e0d, 0x14131211, 0x18171615, 0x1c1b1a19,
690 0x05040403, 0x07060605, 0x0a090807, 0x0f0d0c0b,
691 0x14131211, 0x18171615, 0x1c1b1a19, 0x201f1e1d
692};
693
694static const u32 ctl3220[] = {
695 0x05040403, 0x07060505, 0x0e0c0a08, 0x1a171411,
696 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e,
697 0x09080807, 0x0b0a0a09, 0x0f0d0c0b, 0x1b171311,
698 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e
699};
700
701static const u32 nc[] = {
702 0x00000000, 0x00000000, 0x00000000, 0x00000000,
703 0x00000000, 0x00000000, 0x00000000, 0x00000000,
704 0x00000000, 0x00000000, 0x00000000, 0x00000000,
705 0x00000000, 0x00000000, 0x00000000, 0x00000000
706};
707
708enum {
709 DQ2030,
710 DQ2330,
711 CMD2710,
712 CMD3210,
713 CLK2030,
714 CTL3215,
715 CTL3220,
716 NC,
717};
718
719static const u8 dual_channel_slew_group_lookup[] = {
720 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
721 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
722 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
723 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
724 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
725
726 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
727 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
728 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
729 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
730 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
731
732 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
733 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
734 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
735 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
736 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
737
738 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
739 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
740 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
741 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
742 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, NC, NC,
743
744 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
745 NC, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
746 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
747 NC, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD2710
748};
749
750static const u8 single_channel_slew_group_lookup[] = {
751 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
752 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
753 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
754 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
755 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
756
757 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
758 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
759 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
760 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
761 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
762
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, DQ2330, CMD3210,
766 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
767 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
768
769 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
770 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
771 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
772 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
773 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
774
775 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
776 DQ2330, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
777 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
778 DQ2330, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD3210
779};
780
781static const u32 *slew_group_lookup(int dual_channel, int index)
782{
783 const u8 *slew_group;
784 /* Dual Channel needs different tables. */
785 if (dual_channel)
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100786 slew_group = dual_channel_slew_group_lookup;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000787 else
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100788 slew_group = single_channel_slew_group_lookup;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000789
790 switch (slew_group[index]) {
791 case DQ2030: return dq2030;
792 case DQ2330: return dq2330;
793 case CMD2710: return cmd2710;
794 case CMD3210: return cmd3210;
795 case CLK2030: return clk2030;
796 case CTL3215: return ctl3215;
797 case CTL3220: return ctl3220;
798 case NC: return nc;
799 }
800
801 return nc;
802}
803
Julius Wernercd49cce2019-03-05 16:53:33 -0800804#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000805/* Strength multiplier tables */
806static const u8 dual_channel_strength_multiplier[] = {
807 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
808 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
809 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
810 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
811 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
812 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
813 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
814 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
815 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
816 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
817 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
818 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
819 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
820 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
821 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
822 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
823 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
824 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
825 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
826 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
827 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
828 0x00, 0x00, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
829 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
830 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x44, 0x22
831};
832
833static const u8 single_channel_strength_multiplier[] = {
834 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
835 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
836 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
837 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
838 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
839 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
840 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
841 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
842 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
843 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
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, 0x33, 0x11,
847 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
848 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
849 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
850 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
851 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
852 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
853 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
854 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
855 0x33, 0x00, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
856 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
857 0x33, 0x00, 0x11, 0x00, 0x44, 0x44, 0x33, 0x11
858};
Julius Wernercd49cce2019-03-05 16:53:33 -0800859#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000860static const u8 dual_channel_strength_multiplier[] = {
861 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
862 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
863 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
864 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
865 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
866 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
867 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
868 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
869 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
870 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
871 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
872 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
873 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
874 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
875 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
876 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
877 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
878 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
879 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
880 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
881 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
882 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
883 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
884 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33
885};
886
887static const u8 single_channel_strength_multiplier[] = {
888 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
889 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
890 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
891 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
892 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
893 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
894 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
895 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
896 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
897 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
898 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
899 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
900 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
901 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
902 0x44, 0x22, 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, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
906 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
907 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
908 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
909 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
910 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
911 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00
912};
913#endif
914
Stefan Reinauer278534d2008-10-29 04:51:07 +0000915static void sdram_rcomp_buffer_strength_and_slew(struct sys_info *sysinfo)
916{
Arthur Heymans70a8e342017-03-09 11:30:23 +0100917 const u8 *strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000918 int idx, dual_channel;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000919
920 /* Set Strength Multipliers */
921
922 /* Dual Channel needs different tables. */
923 if (sdram_capabilities_dual_channel()) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000924 printk(BIOS_DEBUG, "Programming Dual Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000925 strength_multiplier = dual_channel_strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000926 dual_channel = 1;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100927 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[2];
Stefan Reinauer278534d2008-10-29 04:51:07 +0000928 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000929 printk(BIOS_DEBUG, "Programming Single Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000930 strength_multiplier = single_channel_strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000931 dual_channel = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000932 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[1];
933 }
934
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000935 printk(BIOS_DEBUG, "Table Index: %d\n", idx);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000936
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000937 MCHBAR8(G1SC) = strength_multiplier[idx * 8 + 0];
938 MCHBAR8(G2SC) = strength_multiplier[idx * 8 + 1];
939 MCHBAR8(G3SC) = strength_multiplier[idx * 8 + 2];
940 MCHBAR8(G4SC) = strength_multiplier[idx * 8 + 3];
941 MCHBAR8(G5SC) = strength_multiplier[idx * 8 + 4];
942 MCHBAR8(G6SC) = strength_multiplier[idx * 8 + 5];
943 MCHBAR8(G7SC) = strength_multiplier[idx * 8 + 6];
944 MCHBAR8(G8SC) = strength_multiplier[idx * 8 + 7];
Stefan Reinauer278534d2008-10-29 04:51:07 +0000945
946 /* Channel 0 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000947 sdram_write_slew_rates(G1SRPUT, slew_group_lookup(dual_channel, idx * 8 + 0));
948 sdram_write_slew_rates(G2SRPUT, slew_group_lookup(dual_channel, idx * 8 + 1));
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200949 if ((slew_group_lookup(dual_channel, idx * 8 + 2) != nc) &&
950 (sysinfo->package == SYSINFO_PACKAGE_STACKED))
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000951
Stefan Reinauer278534d2008-10-29 04:51:07 +0000952 sdram_write_slew_rates(G3SRPUT, ctl3220);
Arthur Heymans70a8e342017-03-09 11:30:23 +0100953 else
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000954 sdram_write_slew_rates(G3SRPUT, slew_group_lookup(dual_channel, idx * 8 + 2));
Arthur Heymans70a8e342017-03-09 11:30:23 +0100955
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000956 sdram_write_slew_rates(G4SRPUT, slew_group_lookup(dual_channel, idx * 8 + 3));
957 sdram_write_slew_rates(G5SRPUT, slew_group_lookup(dual_channel, idx * 8 + 4));
958 sdram_write_slew_rates(G6SRPUT, slew_group_lookup(dual_channel, idx * 8 + 5));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000959
960 /* Channel 1 */
961 if (sysinfo->dual_channel) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000962 sdram_write_slew_rates(G7SRPUT, slew_group_lookup(dual_channel, idx * 8 + 6));
963 sdram_write_slew_rates(G8SRPUT, slew_group_lookup(dual_channel, idx * 8 + 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000964 } else {
965 sdram_write_slew_rates(G7SRPUT, nc);
966 sdram_write_slew_rates(G8SRPUT, nc);
967 }
968}
969
970static void sdram_enable_rcomp(void)
971{
972 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000973 /* Enable Global Periodic RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000974 udelay(300);
975 reg32 = MCHBAR32(GBRCOMPCTL);
976 reg32 &= ~(1 << 23);
977 MCHBAR32(GBRCOMPCTL) = reg32;
978}
979
980static void sdram_program_dll_timings(struct sys_info *sysinfo)
981{
Elyes HAOUAS44a30662017-02-23 13:14:44 +0100982 u32 channeldll = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000983 int i;
984
Elyes HAOUAS38424982016-08-21 12:01:04 +0200985 printk(BIOS_DEBUG, "Programming DLL Timings...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000986
Arthur Heymans70a8e342017-03-09 11:30:23 +0100987 MCHBAR16(DQSMT) &= ~((3 << 12) | (1 << 10) | (0xf << 0));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000988 MCHBAR16(DQSMT) |= (1 << 13) | (0xc << 0);
989
990 /* We drive both channels with the same speed */
Julius Wernercd49cce2019-03-05 16:53:33 -0800991 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +0100992 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +0100993 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200994 channeldll = 0x26262626;
995 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100996 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200997 channeldll = 0x22222222;
998 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100999 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001000 channeldll = 0x11111111;
1001 break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001002 }
Julius Wernercd49cce2019-03-05 16:53:33 -08001003 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001004 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001005 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001006 channeldll = 0x33333333;
1007 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001008 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001009 channeldll = 0x24242424;
1010 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001011 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001012 channeldll = 0x25252525;
1013 break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001014 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001015 }
1016
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001017 for (i = 0; i < 4; i++) {
Elyes HAOUAS44a30662017-02-23 13:14:44 +01001018 MCHBAR32(C0R0B00DQST + (i * 0x10) + 0) = channeldll;
1019 MCHBAR32(C0R0B00DQST + (i * 0x10) + 4) = channeldll;
1020 MCHBAR32(C1R0B00DQST + (i * 0x10) + 0) = channeldll;
1021 MCHBAR32(C1R0B00DQST + (i * 0x10) + 4) = channeldll;
Julius Wernercd49cce2019-03-05 16:53:33 -08001022 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUAS44a30662017-02-23 13:14:44 +01001023 MCHBAR8(C0R0B00DQST + (i * 0x10) + 8) = channeldll & 0xff;
1024 MCHBAR8(C1R0B00DQST + (i * 0x10) + 8) = channeldll & 0xff;
Paul Menzelbce7e332017-02-22 18:46:27 +01001025 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001026 }
1027}
1028
1029static void sdram_force_rcomp(void)
1030{
1031 u32 reg32;
1032 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001033
Stefan Reinauer278534d2008-10-29 04:51:07 +00001034 reg32 = MCHBAR32(ODTC);
1035 reg32 |= (1 << 28);
1036 MCHBAR32(ODTC) = reg32;
1037
1038 reg32 = MCHBAR32(SMSRCTL);
1039 reg32 |= (1 << 0);
1040 MCHBAR32(SMSRCTL) = reg32;
1041
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001042 /* Start initial RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001043 reg32 = MCHBAR32(GBRCOMPCTL);
1044 reg32 |= (1 << 8);
1045 MCHBAR32(GBRCOMPCTL) = reg32;
1046
1047 reg8 = i945_silicon_revision();
1048 if ((reg8 == 0 && (MCHBAR32(DCC) & (3 << 0)) == 0) || (reg8 == 1)) {
1049 reg32 = MCHBAR32(GBRCOMPCTL);
1050 reg32 |= (3 << 5);
1051 MCHBAR32(GBRCOMPCTL) = reg32;
1052 }
1053}
1054
1055static void sdram_initialize_system_memory_io(struct sys_info *sysinfo)
1056{
1057 u8 reg8;
1058 u32 reg32;
1059
Elyes HAOUAS38424982016-08-21 12:01:04 +02001060 printk(BIOS_DEBUG, "Initializing System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001061 /* Enable Data Half Clock Pushout */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001062 reg8 = MCHBAR8(C0HCTC);
1063 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001064 reg8 |= (1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001065 MCHBAR8(C0HCTC) = reg8;
1066
1067 reg8 = MCHBAR8(C1HCTC);
1068 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001069 reg8 |= (1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001070 MCHBAR8(C1HCTC) = reg8;
1071
Arthur Heymans70a8e342017-03-09 11:30:23 +01001072 MCHBAR16(WDLLBYPMODE) &= ~((1 << 9) | (1 << 6) | (1 << 4) | (1 << 3) | (1 << 1));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001073 MCHBAR16(WDLLBYPMODE) |= (1 << 8) | (1 << 7) | (1 << 5) | (1 << 2) | (1 << 0);
1074
1075 MCHBAR8(C0WDLLCMC) = 0;
1076 MCHBAR8(C1WDLLCMC) = 0;
1077
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001078 /* Program RCOMP Settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001079 sdram_program_dram_width(sysinfo);
1080
1081 sdram_rcomp_buffer_strength_and_slew(sysinfo);
1082
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001083 /* Indicate that RCOMP programming is done */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001084 reg32 = MCHBAR32(GBRCOMPCTL);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001085 reg32 &= ~((1 << 29) | (1 << 26) | (3 << 21) | (3 << 2));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001086 reg32 |= (3 << 27) | (3 << 0);
1087 MCHBAR32(GBRCOMPCTL) = reg32;
1088
1089 MCHBAR32(GBRCOMPCTL) |= (1 << 10);
1090
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001091 /* Program DLL Timings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001092 sdram_program_dll_timings(sysinfo);
1093
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001094 /* Force RCOMP cycle */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001095 sdram_force_rcomp();
1096}
1097
1098static void sdram_enable_system_memory_io(struct sys_info *sysinfo)
1099{
1100 u32 reg32;
1101
Elyes HAOUAS38424982016-08-21 12:01:04 +02001102 printk(BIOS_DEBUG, "Enabling System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001103
Stefan Reinauer278534d2008-10-29 04:51:07 +00001104 reg32 = MCHBAR32(RCVENMT);
1105 reg32 &= ~(0x3f << 6);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001106 MCHBAR32(RCVENMT) = reg32; /* [11:6] = 0 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001107
1108 reg32 |= (1 << 11) | (1 << 9);
1109 MCHBAR32(RCVENMT) = reg32;
1110
1111 reg32 = MCHBAR32(DRTST);
1112 reg32 |= (1 << 3) | (1 << 2);
1113 MCHBAR32(DRTST) = reg32;
1114
1115 reg32 = MCHBAR32(DRTST);
1116 reg32 |= (1 << 6) | (1 << 4);
1117 MCHBAR32(DRTST) = reg32;
1118
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001119 asm volatile ("nop; nop;" ::: "memory");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001120
1121 reg32 = MCHBAR32(DRTST);
1122
1123 /* Is channel 0 populated? */
1124 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001125 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001126 reg32 |= (1 << 7) | (1 << 5);
1127 else
1128 reg32 |= (1 << 31);
1129
1130 /* Is channel 1 populated? */
1131 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001132 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001133 reg32 |= (1 << 9) | (1 << 8);
1134 else
1135 reg32 |= (1 << 30);
1136
1137 MCHBAR32(DRTST) = reg32;
1138
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001139 /* Activate DRAM Channel IO Buffers */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001140 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001141 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001142 reg32 = MCHBAR32(C0DRC1);
1143 reg32 |= (1 << 8);
1144 MCHBAR32(C0DRC1) = reg32;
1145 }
1146 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001147 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001148 reg32 = MCHBAR32(C1DRC1);
1149 reg32 |= (1 << 8);
1150 MCHBAR32(C1DRC1) = reg32;
1151 }
1152}
1153
Stefan Reinauer278534d2008-10-29 04:51:07 +00001154static int sdram_program_row_boundaries(struct sys_info *sysinfo)
1155{
1156 int i;
Arthur Heymans885c2892016-10-03 17:16:48 +02001157 int cum0, cum1, tolud, tom, pci_mmio_size;
1158 const struct device *dev;
1159 const struct northbridge_intel_i945_config *cfg = NULL;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001160
Paul Menzel84283bc2014-07-17 08:16:04 +02001161 printk(BIOS_DEBUG, "Setting RAM size...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001162
1163 cum0 = 0;
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001164 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001165 cum0 += sysinfo->banksize[i];
Stefan Reinauer278534d2008-10-29 04:51:07 +00001166 MCHBAR8(C0DRB0+i) = cum0;
1167 }
1168
1169 /* Assume we continue in Channel 1 where we stopped in Channel 0 */
1170 cum1 = cum0;
1171
1172 /* Exception: Interleaved starts from the beginning */
1173 if (sysinfo->interleaved)
1174 cum1 = 0;
1175
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001176 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001177 cum1 += sysinfo->banksize[i + 4];
Stefan Reinauer278534d2008-10-29 04:51:07 +00001178 MCHBAR8(C1DRB0+i) = cum1;
1179 }
1180
1181 /* Set TOLUD Top Of Low Usable DRAM */
1182 if (sysinfo->interleaved)
1183 tolud = (cum0 + cum1) << 1;
1184 else
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001185 tolud = (cum1 ? cum1 : cum0) << 1;
Stefan Reinauer779b3e32008-11-10 15:43:37 +00001186
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001187 /* The TOM register has a different format */
1188 tom = tolud >> 3;
1189
1190 /* Limit the value of TOLUD to leave some space for PCI memory. */
Kyösti Mälkkic70eed12018-05-22 02:18:00 +03001191 dev = pcidev_on_root(0, 0);
Arthur Heymans885c2892016-10-03 17:16:48 +02001192 if (dev)
1193 cfg = dev->chip_info;
1194
1195 /* Don't use pci mmio sizes smaller than 768M */
1196 if (!cfg || cfg->pci_mmio_size <= DEFAULT_PCI_MMIO_SIZE)
1197 pci_mmio_size = DEFAULT_PCI_MMIO_SIZE;
1198 else
1199 pci_mmio_size = cfg->pci_mmio_size;
1200
1201 tolud = MIN(((4096 - pci_mmio_size) / 128) << 3, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001202
Arthur Heymans70a8e342017-03-09 11:30:23 +01001203 pci_write_config8(PCI_DEV(0, 0, 0), TOLUD, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001204
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001205 printk(BIOS_DEBUG, "C0DRB = 0x%08x\n", MCHBAR32(C0DRB0));
1206 printk(BIOS_DEBUG, "C1DRB = 0x%08x\n", MCHBAR32(C1DRB0));
Arthur Heymans70a8e342017-03-09 11:30:23 +01001207 printk(BIOS_DEBUG, "TOLUD = 0x%04x\n", pci_read_config8(PCI_DEV(0, 0, 0), TOLUD));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001208
Arthur Heymans70a8e342017-03-09 11:30:23 +01001209 pci_write_config16(PCI_DEV(0, 0, 0), TOM, tom);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001210
1211 return 0;
1212}
1213
Stefan Reinauer278534d2008-10-29 04:51:07 +00001214static int sdram_set_row_attributes(struct sys_info *sysinfo)
1215{
Arthur Heymans0ab49042017-02-06 22:40:14 +01001216 int i;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001217 u16 dra0 = 0, dra1 = 0, dra = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001218
Elyes HAOUAS38424982016-08-21 12:01:04 +02001219 printk(BIOS_DEBUG, "Setting row attributes...\n");
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001220 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001221 u8 columnsrows;
1222
Arthur Heymans70a8e342017-03-09 11:30:23 +01001223 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001224 continue;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001225
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001226 columnsrows = (sysinfo->rows[i] & 0x0f) | (sysinfo->cols[i] & 0xf) << 4;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001227
1228 switch (columnsrows) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001229 case 0x9d:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001230 dra = 2;
1231 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001232 case 0xad:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001233 dra = 3;
1234 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001235 case 0xbd:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001236 dra = 4;
1237 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001238 case 0xae:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001239 dra = 3;
1240 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001241 case 0xbe:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001242 dra = 4;
1243 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001244 default:
1245 die("Unsupported Rows/Columns. (DRA)");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001246 }
1247
1248 /* Double Sided DIMMs? */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001249 if (sysinfo->banksize[(2 * i) + 1] != 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001250 dra = (dra << 4) | dra;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001251
Stefan Reinauer278534d2008-10-29 04:51:07 +00001252 if (i < DIMM_SOCKETS)
1253 dra0 |= (dra << (i*8));
1254 else
1255 dra1 |= (dra << ((i - DIMM_SOCKETS)*8));
1256 }
1257
1258 MCHBAR16(C0DRA0) = dra0;
1259 MCHBAR16(C1DRA0) = dra1;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001260
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001261 printk(BIOS_DEBUG, "C0DRA = 0x%04x\n", dra0);
1262 printk(BIOS_DEBUG, "C1DRA = 0x%04x\n", dra1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001263
1264 return 0;
1265}
1266
1267static void sdram_set_bank_architecture(struct sys_info *sysinfo)
1268{
1269 u32 off32;
1270 int i;
1271
1272 MCHBAR16(C1BNKARC) &= 0xff00;
1273 MCHBAR16(C0BNKARC) &= 0xff00;
1274
1275 off32 = C0BNKARC;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001276 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001277 /* Switch to second channel */
1278 if (i == DIMM_SOCKETS)
1279 off32 = C1BNKARC;
1280
1281 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
1282 continue;
1283
1284 if (sysinfo->banks[i] != 8)
1285 continue;
1286
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001287 printk(BIOS_SPEW, "DIMM%d has 8 banks.\n", i);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001288
1289 if (i & 1)
1290 MCHBAR16(off32) |= 0x50;
1291 else
1292 MCHBAR16(off32) |= 0x05;
1293 }
1294}
1295
Stefan Reinauer278534d2008-10-29 04:51:07 +00001296static void sdram_program_refresh_rate(struct sys_info *sysinfo)
1297{
1298 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001299
Arthur Heymans70a8e342017-03-09 11:30:23 +01001300 if (sysinfo->refresh == REFRESH_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001301 reg32 = (2 << 8); /* Refresh enabled at 7.8us */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001302 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001303 reg32 = (1 << 8); /* Refresh enabled at 15.6us */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001304
1305 MCHBAR32(C0DRC0) &= ~(7 << 8);
1306 MCHBAR32(C0DRC0) |= reg32;
1307
1308 MCHBAR32(C1DRC0) &= ~(7 << 8);
1309 MCHBAR32(C1DRC0) |= reg32;
1310}
1311
1312static void sdram_program_cke_tristate(struct sys_info *sysinfo)
1313{
1314 u32 reg32;
1315 int i;
1316
1317 reg32 = MCHBAR32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001318
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001319 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001320 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001321 reg32 |= (1 << (16 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001322 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001323
Stefan Reinauer278534d2008-10-29 04:51:07 +00001324 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001325
Stefan Reinauer278534d2008-10-29 04:51:07 +00001326 reg32 |= (1 << 11);
1327 MCHBAR32(C0DRC1) = reg32;
1328
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001329 /* Do we have to do this if we're in Single Channel Mode? */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001330 reg32 = MCHBAR32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001331
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001332 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001333 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001334 reg32 |= (1 << (12 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001335 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001336
Stefan Reinauer278534d2008-10-29 04:51:07 +00001337 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001338
Stefan Reinauer278534d2008-10-29 04:51:07 +00001339 reg32 |= (1 << 11);
1340 MCHBAR32(C1DRC1) = reg32;
1341}
1342
1343static void sdram_program_odt_tristate(struct sys_info *sysinfo)
1344{
1345 u32 reg32;
1346 int i;
1347
1348 reg32 = MCHBAR32(C0DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001349
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001350 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001351 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001352 reg32 |= (1 << (24 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001353 }
1354 MCHBAR32(C0DRC2) = reg32;
1355
1356 reg32 = MCHBAR32(C1DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001357
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001358 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001359 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001360 reg32 |= (1 << (20 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001361 }
1362 MCHBAR32(C1DRC2) = reg32;
1363}
1364
1365static void sdram_set_timing_and_control(struct sys_info *sysinfo)
1366{
Arthur Heymans25027232017-02-12 23:34:39 +01001367 u32 reg32, tRD_min;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001368 u32 tWTR;
1369 u32 temp_drt;
1370 int i, page_size;
1371
Edward O'Callaghan2f237c12014-05-25 06:24:39 +10001372 static const u8 cas_table[] = {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001373 2, 1, 0, 3
1374 };
1375
1376 reg32 = MCHBAR32(C0DRC0);
1377 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001378 reg32 &= ~((1 << 13) | (1 << 12));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001379 MCHBAR32(C0DRC0) = reg32;
1380
1381 reg32 = MCHBAR32(C1DRC0);
1382 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001383 reg32 &= ~((1 << 13) | (1 << 12));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001384 MCHBAR32(C1DRC0) = reg32;
1385
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001386 if (!sysinfo->dual_channel && sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001387 reg32 = MCHBAR32(C0DRC0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001388 reg32 |= (1 << 15);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001389 MCHBAR32(C0DRC0) = reg32;
1390 }
1391
1392 sdram_program_refresh_rate(sysinfo);
1393
1394 sdram_program_cke_tristate(sysinfo);
1395
1396 sdram_program_odt_tristate(sysinfo);
1397
1398 /* Calculate DRT0 */
1399
1400 temp_drt = 0;
1401
1402 /* B2B Write Precharge (same bank) = CL-1 + BL/2 + tWR */
1403 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + sysinfo->twr;
1404 temp_drt |= (reg32 << 28);
1405
1406 /* Write Auto Precharge (same bank) = CL-1 + BL/2 + tWR + tRP */
1407 reg32 += sysinfo->trp;
1408 temp_drt |= (reg32 << 4);
1409
Arthur Heymans70a8e342017-03-09 11:30:23 +01001410 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001411 tWTR = 3; /* 667MHz */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001412 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001413 tWTR = 2; /* 400 and 533 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001414
1415 /* B2B Write to Read Command Spacing */
1416 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + tWTR;
1417 temp_drt |= (reg32 << 24);
1418
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001419 /* CxDRT0 [23:22], [21:20], [19:18] [16] have fixed values */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001420 temp_drt |= ((1 << 22) | (3 << 20) | (1 << 18) | (0 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001421
Arthur Heymans25027232017-02-12 23:34:39 +01001422 /*
1423 * tRD is the delay the memory controller is waiting on the FSB,
1424 * in mclk domain.
1425 * This parameter is important for stability and performance.
1426 * Those values might not be optimal but seem stable.
1427 */
1428 tRD_min = sysinfo->cas;
Arthur Heymanse1897612016-10-15 23:29:18 +02001429 switch (sysinfo->fsb_frequency) {
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001430 case 533:
Arthur Heymanse1897612016-10-15 23:29:18 +02001431 break;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001432 case 667:
1433 tRD_min += 1;
Arthur Heymanse1897612016-10-15 23:29:18 +02001434 break;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001435 case 800:
1436 tRD_min += 2;
1437 break;
1438 case 1066:
1439 tRD_min += 3;
Arthur Heymanse1897612016-10-15 23:29:18 +02001440 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001441 }
Arthur Heymanse1897612016-10-15 23:29:18 +02001442
Arthur Heymans25027232017-02-12 23:34:39 +01001443 temp_drt |= (tRD_min << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001444
1445 /* Read Auto Precharge to Activate */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001446
Stefan Reinauer278534d2008-10-29 04:51:07 +00001447 temp_drt |= (8 << 0);
1448
1449 MCHBAR32(C0DRT0) = temp_drt;
1450 MCHBAR32(C1DRT0) = temp_drt;
1451
1452 /* Calculate DRT1 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001453
Stefan Reinauer278534d2008-10-29 04:51:07 +00001454 temp_drt = MCHBAR32(C0DRT1) & 0x00020088;
1455
1456 /* DRAM RASB Precharge */
1457 temp_drt |= (sysinfo->trp - 2) << 0;
1458
1459 /* DRAM RASB to CASB Delay */
1460 temp_drt |= (sysinfo->trcd - 2) << 4;
1461
1462 /* CASB Latency */
1463 temp_drt |= (cas_table[sysinfo->cas - 3]) << 8;
1464
1465 /* Refresh Cycle Time */
1466 temp_drt |= (sysinfo->trfc) << 10;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001467
Stefan Reinauer278534d2008-10-29 04:51:07 +00001468 /* Pre-All to Activate Delay */
1469 temp_drt |= (0 << 16);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001470
Stefan Reinauer278534d2008-10-29 04:51:07 +00001471 /* Precharge to Precharge Delay stays at 1 clock */
1472 temp_drt |= (0 << 18);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001473
Stefan Reinauer278534d2008-10-29 04:51:07 +00001474 /* Activate to Precharge Delay */
1475 temp_drt |= (sysinfo->tras << 19);
1476
1477 /* Read to Precharge (tRTP) */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001478 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001479 temp_drt |= (1 << 28);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001480 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001481 temp_drt |= (0 << 28);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001482
1483 /* Determine page size */
1484 reg32 = 0;
1485 page_size = 1; /* Default: 1k pagesize */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001486 for (i = 0; i < 2*DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001487 if (sysinfo->dimm[i] == SYSINFO_DIMM_X16DS ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001488 sysinfo->dimm[i] == SYSINFO_DIMM_X16SS)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001489 page_size = 2; /* 2k pagesize */
1490 }
1491
Arthur Heymans70a8e342017-03-09 11:30:23 +01001492 if (sysinfo->memory_frequency == 533 && page_size == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001493 reg32 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001494 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001495 reg32 = page_size;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001496
Stefan Reinauer278534d2008-10-29 04:51:07 +00001497 temp_drt |= (reg32 << 30);
1498
1499 MCHBAR32(C0DRT1) = temp_drt;
1500 MCHBAR32(C1DRT1) = temp_drt;
1501
1502 /* Program DRT2 */
1503 reg32 = MCHBAR32(C0DRT2);
1504 reg32 &= ~(1 << 8);
1505 MCHBAR32(C0DRT2) = reg32;
1506
1507 reg32 = MCHBAR32(C1DRT2);
1508 reg32 &= ~(1 << 8);
1509 MCHBAR32(C1DRT2) = reg32;
1510
1511 /* Calculate DRT3 */
1512 temp_drt = MCHBAR32(C0DRT3) & ~0x07ffffff;
1513
1514 /* Get old tRFC value */
1515 reg32 = MCHBAR32(C0DRT1) >> 10;
1516 reg32 &= 0x3f;
1517
1518 /* 788nS - tRFC */
1519 switch (sysinfo->memory_frequency) {
1520 case 400: /* 5nS */
1521 reg32 = ((78800 / 500) - reg32) & 0x1ff;
1522 reg32 |= (0x8c << 16) | (0x0c << 10); /* 1 us */
1523 break;
1524 case 533: /* 3.75nS */
1525 reg32 = ((78800 / 375) - reg32) & 0x1ff;
1526 reg32 |= (0xba << 16) | (0x10 << 10); /* 1 us */
1527 break;
1528 case 667: /* 3nS */
1529 reg32 = ((78800 / 300) - reg32) & 0x1ff;
1530 reg32 |= (0xe9 << 16) | (0x14 << 10); /* 1 us */
1531 break;
1532 }
1533
1534 temp_drt |= reg32;
1535
1536 MCHBAR32(C0DRT3) = temp_drt;
1537 MCHBAR32(C1DRT3) = temp_drt;
1538}
1539
1540static void sdram_set_channel_mode(struct sys_info *sysinfo)
1541{
1542 u32 reg32;
1543
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001544 printk(BIOS_DEBUG, "Setting mode of operation for memory channels...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001545
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001546 if (sdram_capabilities_interleave() &&
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001547 ((sysinfo->banksize[0] + sysinfo->banksize[1] +
1548 sysinfo->banksize[2] + sysinfo->banksize[3]) ==
1549 (sysinfo->banksize[4] + sysinfo->banksize[5] +
1550 sysinfo->banksize[6] + sysinfo->banksize[7]))) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001551 /* Both channels equipped with DIMMs of the same size */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001552 sysinfo->interleaved = 1;
1553 } else {
1554 sysinfo->interleaved = 0;
1555 }
1556
1557 reg32 = MCHBAR32(DCC);
1558 reg32 &= ~(7 << 0);
1559
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001560 if (sysinfo->interleaved) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001561 /* Dual Channel Interleaved */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001562 printk(BIOS_DEBUG, "Dual Channel Interleaved.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001563 reg32 |= (1 << 1);
1564 } else if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001565 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001566 /* Channel 1 only */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001567 printk(BIOS_DEBUG, "Single Channel 1 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001568 reg32 |= (1 << 2);
Elyes HAOUAS75da1fb2017-02-16 18:59:13 +01001569 } else if (sdram_capabilities_dual_channel() &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001570 (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1571 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) {
Martin Roth128c1042016-11-18 09:29:03 -07001572 /* Dual Channel Asymmetric */
1573 printk(BIOS_DEBUG, "Dual Channel Asymmetric.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001574 reg32 |= (1 << 0);
1575 } else {
1576 /* All bits 0 means Single Channel 0 operation */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001577 printk(BIOS_DEBUG, "Single Channel 0 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001578 }
1579
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001580 /* Now disable channel XORing */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001581 reg32 |= (1 << 10);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001582
1583 MCHBAR32(DCC) = reg32;
1584
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001585 PRINTK_DEBUG("DCC = 0x%08x\n", MCHBAR32(DCC));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001586}
1587
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001588static void sdram_program_pll_settings(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001589{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001590 MCHBAR32(PLLMON) = 0x80800000;
1591
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001592 sysinfo->fsb_frequency = fsbclk();
Peter Stuge76d91432010-10-01 10:02:33 +00001593 if (sysinfo->fsb_frequency == 0xffff)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001594 die("Unsupported FSB speed");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001595
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001596 /* Program CPCTL according to FSB speed */
1597 /* Only write the lower byte */
1598 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001599 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001600 MCHBAR8(CPCTL) = 0x90;
1601 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001602 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001603 MCHBAR8(CPCTL) = 0x95;
1604 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001605 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001606 MCHBAR8(CPCTL) = 0x8d;
1607 break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001608 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001609
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001610 MCHBAR16(CPCTL) &= ~(1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001611
Paul Menzel0ce5ebf2013-10-21 21:22:09 +02001612 MCHBAR16(CPCTL); /* Read back register to activate settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001613}
1614
1615static void sdram_program_graphics_frequency(struct sys_info *sysinfo)
1616{
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001617 u8 reg8;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001618 u16 reg16;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001619 u8 freq, second_vco, voltage;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001620
1621#define CRCLK_166MHz 0x00
1622#define CRCLK_200MHz 0x01
1623#define CRCLK_250MHz 0x03
1624#define CRCLK_400MHz 0x05
1625
1626#define CDCLK_200MHz 0x00
1627#define CDCLK_320MHz 0x40
1628
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001629#define VOLTAGE_1_05 0x00
1630#define VOLTAGE_1_50 0x01
1631
Paul Menzeldaf9e502014-07-15 23:49:16 +02001632 printk(BIOS_DEBUG, "Setting Graphics Frequency...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001633
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001634 printk(BIOS_DEBUG, "FSB: %d MHz ", sysinfo->fsb_frequency);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001635
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001636 voltage = VOLTAGE_1_05;
1637 if (MCHBAR32(DFT_STRAP1) & (1 << 20))
1638 voltage = VOLTAGE_1_50;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001639 printk(BIOS_DEBUG, "Voltage: %s ", (voltage == VOLTAGE_1_05)?"1.05V":"1.5V");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001640
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001641 /* Gate graphics hardware for frequency change */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001642 reg8 = (1<<3) | (1<<1); /* disable crclk, gate cdclk */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001643 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001644
1645 /* Get graphics frequency capabilities */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001646 reg8 = sdram_capabilities_core_frequencies();
1647
Stefan Reinauer278534d2008-10-29 04:51:07 +00001648 freq = CRCLK_250MHz;
1649 switch (reg8) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001650 case GFX_FREQUENCY_CAP_ALL:
1651 if (voltage == VOLTAGE_1_05)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001652 freq = CRCLK_250MHz;
1653 else
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001654 freq = CRCLK_400MHz; /* 1.5V requires 400MHz */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001655 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001656 case GFX_FREQUENCY_CAP_250MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001657 freq = CRCLK_250MHz;
1658 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001659 case GFX_FREQUENCY_CAP_200MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001660 freq = CRCLK_200MHz;
1661 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001662 case GFX_FREQUENCY_CAP_166MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001663 freq = CRCLK_166MHz;
1664 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001665 }
1666
1667 if (freq != CRCLK_400MHz) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001668 /* What chipset are we? Force 166MHz for GMS */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001669 reg8 = (pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe7) & 0x70) >> 4;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001670 if (reg8 == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001671 freq = CRCLK_166MHz;
1672 }
1673
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001674 printk(BIOS_DEBUG, "Render: ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001675 switch (freq) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001676 case CRCLK_166MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001677 printk(BIOS_DEBUG, "166MHz");
1678 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001679 case CRCLK_200MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001680 printk(BIOS_DEBUG, "200MHz");
1681 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001682 case CRCLK_250MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001683 printk(BIOS_DEBUG, "250MHz");
1684 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001685 case CRCLK_400MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001686 printk(BIOS_DEBUG, "400MHz");
1687 break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001688 }
1689
Arthur Heymans70a8e342017-03-09 11:30:23 +01001690 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001691 sysinfo->mvco4x = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001692 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001693 sysinfo->mvco4x = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001694
Stefan Reinauer278534d2008-10-29 04:51:07 +00001695 second_vco = 0;
1696
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001697 if (voltage == VOLTAGE_1_50) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001698 second_vco = 1;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001699 } else if ((i945_silicon_revision() > 0) && (freq == CRCLK_250MHz)) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001700 u16 mem = sysinfo->memory_frequency;
1701 u16 fsb = sysinfo->fsb_frequency;
1702
Arthur Heymans70a8e342017-03-09 11:30:23 +01001703 if ((fsb == 667 && mem == 533) ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001704 (fsb == 533 && mem == 533) ||
1705 (fsb == 533 && mem == 400)) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001706 second_vco = 1;
1707 }
1708
1709 if (fsb == 667 && mem == 533)
1710 sysinfo->mvco4x = 1;
1711 }
1712
Arthur Heymans70a8e342017-03-09 11:30:23 +01001713 if (second_vco)
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001714 sysinfo->clkcfg_bit7 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001715 else
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001716 sysinfo->clkcfg_bit7 = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001717
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001718 /* Graphics Core Render Clock */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001719 reg16 = pci_read_config16(PCI_DEV(0, 2, 0), GCFC);
1720 reg16 &= ~((7 << 0) | (1 << 13));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001721 reg16 |= freq;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001722 pci_write_config16(PCI_DEV(0, 2, 0), GCFC, reg16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001723
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001724 /* Graphics Core Display Clock */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001725 reg8 = pci_read_config8(PCI_DEV(0, 2, 0), GCFC);
1726 reg8 &= ~((1<<7) | (7<<4));
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001727
1728 if (voltage == VOLTAGE_1_05) {
1729 reg8 |= CDCLK_200MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001730 printk(BIOS_DEBUG, " Display: 200MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001731 } else {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001732 reg8 |= CDCLK_320MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001733 printk(BIOS_DEBUG, " Display: 320MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001734 }
Arthur Heymans70a8e342017-03-09 11:30:23 +01001735 pci_write_config8(PCI_DEV(0, 2, 0), GCFC, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001736
Arthur Heymans70a8e342017-03-09 11:30:23 +01001737 reg8 = pci_read_config8(PCI_DEV(0, 2, 0), GCFC + 1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001738
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001739 reg8 |= (1<<3) | (1<<1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001740 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001741
1742 reg8 |= 0x0f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001743 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001744
1745 /* Ungate core render and display clocks */
1746 reg8 &= 0xf0;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001747 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001748}
1749
1750static void sdram_program_memory_frequency(struct sys_info *sysinfo)
1751{
1752 u32 clkcfg;
1753 u8 reg8;
Julius Wernercd49cce2019-03-05 16:53:33 -08001754 u8 offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001755
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001756 printk(BIOS_DEBUG, "Setting Memory Frequency... ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001757
Stefan Reinauer278534d2008-10-29 04:51:07 +00001758 clkcfg = MCHBAR32(CLKCFG);
1759
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001760 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001761
Arthur Heymans70a8e342017-03-09 11:30:23 +01001762 clkcfg &= ~((1 << 12) | (1 << 7) | (7 << 4));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001763
1764 if (sysinfo->mvco4x) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001765 printk(BIOS_DEBUG, "MVCO 4x, ");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001766 clkcfg &= ~(1 << 12);
1767 }
1768
1769 if (sysinfo->clkcfg_bit7) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001770 printk(BIOS_DEBUG, "second VCO, ");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001771 clkcfg |= (1 << 7);
1772 }
1773
1774 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001775 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001776 clkcfg |= ((1 + offset) << 4);
1777 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001778 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001779 clkcfg |= ((2 + offset) << 4);
1780 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001781 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001782 clkcfg |= ((3 + offset) << 4);
1783 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001784 default:
1785 die("Target Memory Frequency Error");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001786 }
1787
1788 if (MCHBAR32(CLKCFG) == clkcfg) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001789 printk(BIOS_DEBUG, "ok (unchanged)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001790 return;
1791 }
1792
1793 MCHBAR32(CLKCFG) = clkcfg;
1794
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001795 /* Make sure the following code is in the cache before we execute it. */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001796 goto cache_code;
1797vco_update:
Elyes HAOUAS32b9a992019-01-21 14:54:31 +01001798 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001799 reg8 &= ~(1 << 7);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +01001800 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001801
Stefan Reinauer278534d2008-10-29 04:51:07 +00001802 clkcfg &= ~(1 << 10);
1803 MCHBAR32(CLKCFG) = clkcfg;
1804 clkcfg |= (1 << 10);
1805 MCHBAR32(CLKCFG) = clkcfg;
1806
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001807 asm volatile (
Stefan Reinauer278534d2008-10-29 04:51:07 +00001808 " movl $0x100, %%ecx\n"
1809 "delay_update:\n"
1810 " nop\n"
1811 " nop\n"
1812 " nop\n"
1813 " nop\n"
1814 " loop delay_update\n"
1815 : /* No outputs */
1816 : /* No inputs */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001817 : "%ecx", "memory"
Stefan Reinauer278534d2008-10-29 04:51:07 +00001818 );
1819
Stefan Reinauer278534d2008-10-29 04:51:07 +00001820 clkcfg &= ~(1 << 10);
1821 MCHBAR32(CLKCFG) = clkcfg;
1822
1823 goto out;
1824cache_code:
1825 goto vco_update;
1826out:
1827
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001828 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", MCHBAR32(CLKCFG));
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001829 printk(BIOS_DEBUG, "ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001830}
1831
1832static void sdram_program_clock_crossing(void)
1833{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001834 int idx = 0;
1835
1836 /**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001837 * We add the indices according to our clocks from CLKCFG.
Stefan Reinauer278534d2008-10-29 04:51:07 +00001838 */
Julius Wernercd49cce2019-03-05 16:53:33 -08001839#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001840 static const u32 data_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001841 0x00100401, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001842 0xffffffff, 0xffffffff, /* nonexistent */
1843 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001844
Stefan Reinauer278534d2008-10-29 04:51:07 +00001845 0x08040120, 0x00000000, /* DDR400 FSB533 */
1846 0x00100401, 0x00000000, /* DDR533 FSB533 */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001847 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001848
1849 0x04020120, 0x00000010, /* DDR400 FSB667 */
1850 0x10040280, 0x00000040, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001851 0x00100401, 0x00000000, /* DDR667 FSB667 */
1852
Martin Roth2ed0aa22016-01-05 20:58:58 -07001853 0xffffffff, 0xffffffff, /* nonexistent */
1854 0xffffffff, 0xffffffff, /* nonexistent */
1855 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001856
Martin Roth2ed0aa22016-01-05 20:58:58 -07001857 0xffffffff, 0xffffffff, /* nonexistent */
1858 0xffffffff, 0xffffffff, /* nonexistent */
1859 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001860 };
1861
1862 static const u32 command_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001863 0x04020208, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001864 0xffffffff, 0xffffffff, /* nonexistent */
1865 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001866
Stefan Reinauer278534d2008-10-29 04:51:07 +00001867 0x00060108, 0x00000000, /* DDR400 FSB533 */
1868 0x04020108, 0x00000000, /* DDR533 FSB533 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001869 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001870
1871 0x00040318, 0x00000000, /* DDR400 FSB667 */
1872 0x04020118, 0x00000000, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001873 0x02010804, 0x00000000, /* DDR667 FSB667 */
1874
Martin Roth2ed0aa22016-01-05 20:58:58 -07001875 0xffffffff, 0xffffffff, /* nonexistent */
1876 0xffffffff, 0xffffffff, /* nonexistent */
1877 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001878
Martin Roth2ed0aa22016-01-05 20:58:58 -07001879 0xffffffff, 0xffffffff, /* nonexistent */
1880 0xffffffff, 0xffffffff, /* nonexistent */
1881 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001882 };
1883
Julius Wernercd49cce2019-03-05 16:53:33 -08001884#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001885 /* i945 G/P */
1886 static const u32 data_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001887 0xffffffff, 0xffffffff, /* nonexistent */
1888 0xffffffff, 0xffffffff, /* nonexistent */
1889 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001890
1891 0x10080201, 0x00000000, /* DDR400 FSB533 */
1892 0x00100401, 0x00000000, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001893 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001894
Martin Roth2ed0aa22016-01-05 20:58:58 -07001895 0xffffffff, 0xffffffff, /* nonexistent */
1896 0xffffffff, 0xffffffff, /* nonexistent */
1897 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001898
1899 0x04020108, 0x00000000, /* DDR400 FSB800 */
1900 0x00020108, 0x00000000, /* DDR533 FSB800 */
1901 0x00080201, 0x00000000, /* DDR667 FSB800 */
1902
1903 0x00010402, 0x00000000, /* DDR400 FSB1066 */
1904 0x04020108, 0x00000000, /* DDR533 FSB1066 */
1905 0x08040110, 0x00000000, /* DDR667 FSB1066 */
1906 };
1907
1908 static const u32 command_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001909 0xffffffff, 0xffffffff, /* nonexistent */
1910 0xffffffff, 0xffffffff, /* nonexistent */
1911 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001912
1913 0x00010800, 0x00000402, /* DDR400 FSB533 */
1914 0x01000400, 0x00000200, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001915 0x00020904, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001916
Martin Roth2ed0aa22016-01-05 20:58:58 -07001917 0xffffffff, 0xffffffff, /* nonexistent */
1918 0xffffffff, 0xffffffff, /* nonexistent */
1919 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001920
1921 0x02010804, 0x00000000, /* DDR400 FSB800 */
1922 0x00010402, 0x00000000, /* DDR533 FSB800 */
Arthur Heymans8b6df622016-10-16 10:58:01 +02001923 0x04020130, 0x00000008, /* DDR667 FSB800 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001924
1925 0x00020904, 0x00000000, /* DDR400 FSB1066 */
1926 0x02010804, 0x00000000, /* DDR533 FSB1066 */
1927 0x180601c0, 0x00000020, /* DDR667 FSB1066 */
1928 };
1929#endif
1930
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001931 printk(BIOS_DEBUG, "Programming Clock Crossing...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001932
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001933 printk(BIOS_DEBUG, "MEM=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001934 switch (memclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001935 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001936 printk(BIOS_DEBUG, "400");
1937 idx += 0;
1938 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001939 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001940 printk(BIOS_DEBUG, "533");
1941 idx += 2;
1942 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001943 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001944 printk(BIOS_DEBUG, "667");
1945 idx += 4;
1946 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001947 default:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001948 printk(BIOS_DEBUG, "RSVD %x", memclk());
1949 return;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001950 }
1951
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001952 printk(BIOS_DEBUG, " FSB=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001953 switch (fsbclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001954 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001955 printk(BIOS_DEBUG, "400");
1956 idx += 0;
1957 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001958 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001959 printk(BIOS_DEBUG, "533");
1960 idx += 6;
1961 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001962 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001963 printk(BIOS_DEBUG, "667");
1964 idx += 12;
1965 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001966 case 800:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001967 printk(BIOS_DEBUG, "800");
1968 idx += 18;
1969 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001970 case 1066:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001971 printk(BIOS_DEBUG, "1066");
1972 idx += 24;
1973 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001974 default:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001975 printk(BIOS_DEBUG, "RSVD %x\n", fsbclk());
1976 return;
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001977 }
1978
Arthur Heymans70a8e342017-03-09 11:30:23 +01001979 if (command_clock_crossing[idx] == 0xffffffff)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001980 printk(BIOS_DEBUG, "Invalid MEM/FSB combination!\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001981
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001982 MCHBAR32(CCCFT + 0) = command_clock_crossing[idx];
1983 MCHBAR32(CCCFT + 4) = command_clock_crossing[idx + 1];
1984
Stefan Reinauer278534d2008-10-29 04:51:07 +00001985 MCHBAR32(C0DCCFT + 0) = data_clock_crossing[idx];
1986 MCHBAR32(C0DCCFT + 4) = data_clock_crossing[idx + 1];
1987 MCHBAR32(C1DCCFT + 0) = data_clock_crossing[idx];
1988 MCHBAR32(C1DCCFT + 4) = data_clock_crossing[idx + 1];
1989
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001990 printk(BIOS_DEBUG, "... ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001991}
1992
1993static void sdram_disable_fast_dispatch(void)
1994{
1995 u32 reg32;
1996
1997 reg32 = MCHBAR32(FSBPMC3);
1998 reg32 |= (1 << 1);
1999 MCHBAR32(FSBPMC3) = reg32;
2000
2001 reg32 = MCHBAR32(SBTEST);
2002 reg32 |= (3 << 1);
2003 MCHBAR32(SBTEST) = reg32;
2004}
2005
2006static void sdram_pre_jedec_initialization(void)
2007{
2008 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002009
Stefan Reinauer278534d2008-10-29 04:51:07 +00002010 reg32 = MCHBAR32(WCC);
2011 reg32 &= 0x113ff3ff;
2012 reg32 |= (4 << 29) | (3 << 25) | (1 << 10);
2013 MCHBAR32(WCC) = reg32;
2014
2015 MCHBAR32(SMVREFC) |= (1 << 6);
2016
2017 MCHBAR32(MMARB0) &= ~(3 << 17);
2018 MCHBAR32(MMARB0) |= (1 << 21) | (1 << 16);
2019
2020 MCHBAR32(MMARB1) &= ~(7 << 8);
2021 MCHBAR32(MMARB1) |= (3 << 8);
2022
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002023 /* Adaptive Idle Timer Control */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002024 MCHBAR32(C0AIT) = 0x000006c4;
2025 MCHBAR32(C0AIT+4) = 0x871a066d;
2026
2027 MCHBAR32(C1AIT) = 0x000006c4;
2028 MCHBAR32(C1AIT+4) = 0x871a066d;
2029}
2030
2031#define EA_DUALCHANNEL_XOR_BANK_RANK_MODE (0xd4 << 24)
2032#define EA_DUALCHANNEL_XOR_BANK_MODE (0xf4 << 24)
2033#define EA_DUALCHANNEL_BANK_RANK_MODE (0xc2 << 24)
2034#define EA_DUALCHANNEL_BANK_MODE (0xe2 << 24)
2035#define EA_SINGLECHANNEL_XOR_BANK_RANK_MODE (0x91 << 24)
2036#define EA_SINGLECHANNEL_XOR_BANK_MODE (0xb1 << 24)
2037#define EA_SINGLECHANNEL_BANK_RANK_MODE (0x80 << 24)
2038#define EA_SINGLECHANNEL_BANK_MODE (0xa0 << 24)
2039
2040static void sdram_enhanced_addressing_mode(struct sys_info *sysinfo)
2041{
2042 u32 chan0 = 0, chan1 = 0;
Paul Menzeld789b6582020-03-14 11:50:34 +01002043 bool chan0_dualsided, chan1_dualsided, chan0_populated, chan1_populated;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002044
Paul Menzel842dd332020-03-14 10:37:40 +01002045 chan0_populated = (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002046 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED);
Elyes HAOUAS308aeff2017-02-24 12:53:07 +01002047 chan1_populated = (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002048 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002049 chan0_dualsided = (sysinfo->banksize[1] || sysinfo->banksize[3]);
2050 chan1_dualsided = (sysinfo->banksize[5] || sysinfo->banksize[7]);
2051
2052 if (sdram_capabilities_enhanced_addressing_xor()) {
2053 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002054 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002055 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002056 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002057 chan0 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002058 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002059 chan0 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002060 }
2061 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002062 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002063 chan1 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002064 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002065 chan1 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002066 }
2067 } else {
2068 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002069 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002070 chan0 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002071 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002072 chan0 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002073
Arthur Heymans70a8e342017-03-09 11:30:23 +01002074 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002075 chan1 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002076 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002077 chan1 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002078 }
2079 } else {
2080 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002081 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002082 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002083 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002084 chan0 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002085 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002086 chan0 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002087 }
2088 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002089 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002090 chan1 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002091 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002092 chan1 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002093 }
2094 } else {
2095 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002096 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002097 chan0 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002098 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002099 chan0 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002100
Arthur Heymans70a8e342017-03-09 11:30:23 +01002101 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002102 chan1 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002103 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002104 chan1 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002105 }
2106 }
2107
2108 MCHBAR32(C0DRC1) &= 0x00ffffff;
2109 MCHBAR32(C0DRC1) |= chan0;
2110 MCHBAR32(C1DRC1) &= 0x00ffffff;
2111 MCHBAR32(C1DRC1) |= chan1;
2112}
2113
2114static void sdram_post_jedec_initialization(struct sys_info *sysinfo)
2115{
2116 u32 reg32;
2117
2118 /* Enable Channel XORing for Dual Channel Interleave */
2119 if (sysinfo->interleaved) {
2120 reg32 = MCHBAR32(DCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002121 reg32 &= ~(1 << 10);
Stefan Reinauer30140a52009-03-11 16:20:39 +00002122 reg32 |= (1 << 9);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002123 MCHBAR32(DCC) = reg32;
2124 }
2125
2126 /* DRAM mode optimizations */
2127 sdram_enhanced_addressing_mode(sysinfo);
2128
2129 reg32 = MCHBAR32(FSBPMC3);
2130 reg32 &= ~(1 << 1);
2131 MCHBAR32(FSBPMC3) = reg32;
2132
2133 reg32 = MCHBAR32(SBTEST);
2134 reg32 &= ~(1 << 2);
2135 MCHBAR32(SBTEST) = reg32;
2136
2137 reg32 = MCHBAR32(SBOCC);
2138 reg32 &= 0xffbdb6ff;
2139 reg32 |= (0xbdb6 << 8) | (1 << 0);
2140 MCHBAR32(SBOCC) = reg32;
2141}
2142
2143static void sdram_power_management(struct sys_info *sysinfo)
2144{
2145 u8 reg8;
2146 u16 reg16;
2147 u32 reg32;
2148 int integrated_graphics = 1;
2149 int i;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002150
Stefan Reinauer278534d2008-10-29 04:51:07 +00002151 reg32 = MCHBAR32(C0DRT2);
2152 reg32 &= 0xffffff00;
2153 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002154 reg32 |= (1 << 5) | (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002155 MCHBAR32(C0DRT2) = reg32;
2156
2157 reg32 = MCHBAR32(C1DRT2);
2158 reg32 &= 0xffffff00;
2159 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002160 reg32 |= (1 << 5) | (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002161 MCHBAR32(C1DRT2) = reg32;
2162
2163 reg32 = MCHBAR32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002164
2165 reg32 |= (1 << 12) | (1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002166 MCHBAR32(C0DRC1) = reg32;
2167
2168 reg32 = MCHBAR32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002169
2170 reg32 |= (1 << 12) | (1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002171 MCHBAR32(C1DRC1) = reg32;
2172
Julius Wernercd49cce2019-03-05 16:53:33 -08002173 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002174 if (i945_silicon_revision() > 1) {
2175 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2176 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002177
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002178 MCHBAR16(UPMC1) = 0x1010 | peg_bits;
2179 } else {
2180 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2181 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002182
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002183 /* Rev 0 and 1 */
2184 MCHBAR16(UPMC1) = 0x0010 | peg_bits;
2185 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002186 }
2187
2188 reg16 = MCHBAR16(UPMC2);
2189 reg16 &= 0xfc00;
2190 reg16 |= 0x0100;
2191 MCHBAR16(UPMC2) = reg16;
2192
2193 MCHBAR32(UPMC3) = 0x000f06ff;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002194
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002195 for (i = 0; i < 5; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002196 MCHBAR32(UPMC3) &= ~(1 << 16);
2197 MCHBAR32(UPMC3) |= (1 << 16);
2198 }
2199
2200 MCHBAR32(GIPMC1) = 0x8000000c;
2201
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002202 reg16 = MCHBAR16(CPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002203 reg16 &= ~(7 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002204 if (i945_silicon_revision() > 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002205 reg16 |= (6 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002206 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002207 reg16 |= (4 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002208 MCHBAR16(CPCTL) = reg16;
2209
Stefan Reinauer30140a52009-03-11 16:20:39 +00002210#if 0
Stefan Reinauer278534d2008-10-29 04:51:07 +00002211 if ((MCHBAR32(ECO) & (1 << 16)) != 0) {
Stefan Reinauer30140a52009-03-11 16:20:39 +00002212#else
2213 if (i945_silicon_revision() != 0) {
2214#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002215 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002216 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002217 MCHBAR32(HGIPMC2) = 0x0d590d59;
2218 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002219 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002220 MCHBAR32(HGIPMC2) = 0x155b155b;
2221 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002222 }
2223 } else {
2224 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002225 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002226 MCHBAR32(HGIPMC2) = 0x09c409c4;
2227 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002228 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002229 MCHBAR32(HGIPMC2) = 0x0fa00fa0;
2230 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002231 }
2232 }
2233
2234 MCHBAR32(FSBPMC1) = 0x8000000c;
2235
2236 reg32 = MCHBAR32(C2C3TT);
2237 reg32 &= 0xffff0000;
2238 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002239 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002240 reg32 |= 0x0600;
2241 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002242 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002243 reg32 |= 0x0480;
2244 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002245 }
2246 MCHBAR32(C2C3TT) = reg32;
2247
2248 reg32 = MCHBAR32(C3C4TT);
2249 reg32 &= 0xffff0000;
2250 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002251 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002252 reg32 |= 0x0b80;
2253 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002254 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002255 reg32 |= 0x0980;
2256 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002257 }
2258 MCHBAR32(C3C4TT) = reg32;
2259
Arthur Heymans70a8e342017-03-09 11:30:23 +01002260 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002261 MCHBAR32(ECO) &= ~(1 << 16);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002262 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002263 MCHBAR32(ECO) |= (1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002264
2265#if 0
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002266
Arthur Heymans70a8e342017-03-09 11:30:23 +01002267 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002268 MCHBAR32(FSBPMC3) &= ~(1 << 29);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002269 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002270 MCHBAR32(FSBPMC3) |= (1 << 29);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002271#endif
2272 MCHBAR32(FSBPMC3) &= ~(1 << 29);
2273
2274 MCHBAR32(FSBPMC3) |= (1 << 21);
2275
2276 MCHBAR32(FSBPMC3) &= ~(1 << 19);
2277
2278 MCHBAR32(FSBPMC3) &= ~(1 << 13);
2279
2280 reg32 = MCHBAR32(FSBPMC4);
2281 reg32 &= ~(3 << 24);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002282 reg32 |= (2 << 24);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002283 MCHBAR32(FSBPMC4) = reg32;
2284
2285 MCHBAR32(FSBPMC4) |= (1 << 21);
2286
2287 MCHBAR32(FSBPMC4) |= (1 << 5);
2288
Arthur Heymans70a8e342017-03-09 11:30:23 +01002289 if ((i945_silicon_revision() < 2)) { /* || cpuid() = 0x6e8 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002290 /* stepping 0 and 1 or CPUID 6e8 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002291 MCHBAR32(FSBPMC4) &= ~(1 << 4);
2292 } else {
Stefan Reinauer30140a52009-03-11 16:20:39 +00002293 MCHBAR32(FSBPMC4) |= (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002294 }
2295
Arthur Heymans70a8e342017-03-09 11:30:23 +01002296 reg8 = pci_read_config8(PCI_DEV(0, 0x0, 0), 0xfc);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002297 reg8 |= (1 << 4);
2298 pci_write_config8(PCI_DEV(0, 0x0, 0), 0xfc, reg8);
2299
Arthur Heymans70a8e342017-03-09 11:30:23 +01002300 reg8 = pci_read_config8(PCI_DEV(0, 0x2, 0), 0xc1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002301 reg8 |= (1 << 2);
2302 pci_write_config8(PCI_DEV(0, 0x2, 0), 0xc1, reg8);
2303
Stefan Reinauerde3206a2010-02-22 06:09:43 +00002304#ifdef C2_SELF_REFRESH_DISABLE
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002305
Stefan Reinauer278534d2008-10-29 04:51:07 +00002306 if (integrated_graphics) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002307 printk(BIOS_DEBUG, "C2 self-refresh with IGD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002308 MCHBAR16(MIPMC4) = 0x0468;
2309 MCHBAR16(MIPMC5) = 0x046c;
2310 MCHBAR16(MIPMC6) = 0x046c;
2311 } else {
2312 MCHBAR16(MIPMC4) = 0x6468;
2313 MCHBAR16(MIPMC5) = 0x646c;
2314 MCHBAR16(MIPMC6) = 0x646c;
2315 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002316#else
2317 if (integrated_graphics) {
2318 MCHBAR16(MIPMC4) = 0x04f8;
2319 MCHBAR16(MIPMC5) = 0x04fc;
2320 MCHBAR16(MIPMC6) = 0x04fc;
2321 } else {
2322 MCHBAR16(MIPMC4) = 0x64f8;
2323 MCHBAR16(MIPMC5) = 0x64fc;
2324 MCHBAR16(MIPMC6) = 0x64fc;
2325 }
2326
2327#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002328
2329 reg32 = MCHBAR32(PMCFG);
2330 reg32 &= ~(3 << 17);
2331 reg32 |= (2 << 17);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002332 MCHBAR32(PMCFG) = reg32;
2333
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002334 MCHBAR32(PMCFG) |= (1 << 4);
2335
Stefan Reinauer278534d2008-10-29 04:51:07 +00002336 reg32 = MCHBAR32(0xc30);
2337 reg32 &= 0xffffff00;
2338 reg32 |= 0x01;
2339 MCHBAR32(0xc30) = reg32;
2340
2341 MCHBAR32(0xb18) &= ~(1 << 21);
2342}
2343
2344static void sdram_thermal_management(void)
2345{
Stefan Reinauer278534d2008-10-29 04:51:07 +00002346
Stefan Reinauer278534d2008-10-29 04:51:07 +00002347 MCHBAR8(TCO1) = 0x00;
2348 MCHBAR8(TCO0) = 0x00;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002349
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002350 /* The Thermal Sensors for DIMMs at 0x50, 0x52 are at I2C addr 0x30/0x32. */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002351
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002352 /* TODO This is not implemented yet. Volunteers? */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002353}
2354
2355static void sdram_save_receive_enable(void)
2356{
2357 int i;
2358 u32 reg32;
2359 u8 values[4];
2360
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002361 /* The following values are stored to an unused CMOS area and restored instead of
2362 * recalculated in case of an S3 resume.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002363 *
Arthur Heymans70a8e342017-03-09 11:30:23 +01002364 * C0WL0REOST [7:0] -> 8 bit
2365 * C1WL0REOST [7:0] -> 8 bit
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002366 * RCVENMT [11:8] [3:0] -> 8 bit
2367 * C0DRT1 [27:24] -> 4 bit
2368 * C1DRT1 [27:24] -> 4 bit
2369 */
2370
2371 values[0] = MCHBAR8(C0WL0REOST);
2372 values[1] = MCHBAR8(C1WL0REOST);
2373
2374 reg32 = MCHBAR32(RCVENMT);
2375 values[2] = (u8)((reg32 >> (8 - 4)) & 0xf0) | (reg32 & 0x0f);
2376
2377 reg32 = MCHBAR32(C0DRT1);
2378 values[3] = (reg32 >> 24) & 0x0f;
2379 reg32 = MCHBAR32(C1DRT1);
2380 values[3] |= (reg32 >> (24 - 4)) & 0xf0;
2381
2382 /* coreboot only uses bytes 0 - 127 for its CMOS values so far
Edwin Beasanteb50c7d2010-07-06 21:05:04 +00002383 * so we grab bytes 128 - 131 to save the receive enable values
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002384 */
2385
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002386 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002387 cmos_write(values[i], 128 + i);
2388}
2389
2390static void sdram_recover_receive_enable(void)
2391{
2392 int i;
2393 u32 reg32;
2394 u8 values[4];
2395
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002396 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002397 values[i] = cmos_read(128 + i);
2398
2399 MCHBAR8(C0WL0REOST) = values[0];
2400 MCHBAR8(C1WL0REOST) = values[1];
2401
2402 reg32 = MCHBAR32(RCVENMT);
2403 reg32 &= ~((0x0f << 8) | (0x0f << 0));
2404 reg32 |= ((u32)(values[2] & 0xf0) << (8 - 4)) | (values[2] & 0x0f);
2405 MCHBAR32(RCVENMT) = reg32;
2406
2407 reg32 = MCHBAR32(C0DRT1) & ~(0x0f << 24);
2408 reg32 |= (u32)(values[3] & 0x0f) << 24;
2409 MCHBAR32(C0DRT1) = reg32;
2410
2411 reg32 = MCHBAR32(C1DRT1) & ~(0x0f << 24);
2412 reg32 |= (u32)(values[3] & 0xf0) << (24 - 4);
2413 MCHBAR32(C1DRT1) = reg32;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002414}
2415
Stefan Reinauer278534d2008-10-29 04:51:07 +00002416static void sdram_program_receive_enable(struct sys_info *sysinfo)
2417{
2418 MCHBAR32(REPC) |= (1 << 0);
2419
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002420 /* Program Receive Enable Timings */
2421 if (sysinfo->boot_path == BOOT_PATH_RESUME) {
2422 sdram_recover_receive_enable();
2423 } else {
2424 receive_enable_adjust(sysinfo);
2425 sdram_save_receive_enable();
2426 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002427
2428 MCHBAR32(C0DRC1) |= (1 << 6);
2429 MCHBAR32(C1DRC1) |= (1 << 6);
2430 MCHBAR32(C0DRC1) &= ~(1 << 6);
2431 MCHBAR32(C1DRC1) &= ~(1 << 6);
2432
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002433 MCHBAR32(MIPMC3) |= (0x0f << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002434}
2435
2436/**
2437 * @brief Enable On-Die Termination for DDR2.
2438 *
2439 */
2440
2441static void sdram_on_die_termination(struct sys_info *sysinfo)
2442{
2443 static const u32 odt[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002444 0x00024911, 0xe0010000,
2445 0x00049211, 0xe0020000,
2446 0x0006db11, 0xe0030000,
Stefan Reinauer278534d2008-10-29 04:51:07 +00002447 };
2448
2449 u32 reg32;
2450 int cas;
2451
2452 reg32 = MCHBAR32(ODTC);
2453 reg32 &= ~(3 << 16);
2454 reg32 |= (1 << 14) | (1 << 6) | (2 << 16);
2455 MCHBAR32(ODTC) = reg32;
2456
Paul Menzelb4d9f222020-03-14 10:34:29 +01002457 if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002458 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
Elyes HAOUAS38424982016-08-21 12:01:04 +02002459 printk(BIOS_DEBUG, "one dimm per channel config..\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002460
Stefan Reinauer278534d2008-10-29 04:51:07 +00002461 reg32 = MCHBAR32(C0ODT);
2462 reg32 &= ~(7 << 28);
2463 MCHBAR32(C0ODT) = reg32;
2464 reg32 = MCHBAR32(C1ODT);
2465 reg32 &= ~(7 << 28);
2466 MCHBAR32(C1ODT) = reg32;
2467 }
2468
2469 cas = sysinfo->cas;
2470
2471 reg32 = MCHBAR32(C0ODT) & 0xfff00000;
2472 reg32 |= odt[(cas-3) * 2];
2473 MCHBAR32(C0ODT) = reg32;
2474
2475 reg32 = MCHBAR32(C1ODT) & 0xfff00000;
2476 reg32 |= odt[(cas-3) * 2];
2477 MCHBAR32(C1ODT) = reg32;
2478
2479 reg32 = MCHBAR32(C0ODT + 4) & 0x1fc8ffff;
2480 reg32 |= odt[((cas-3) * 2) + 1];
2481 MCHBAR32(C0ODT + 4) = reg32;
2482
2483 reg32 = MCHBAR32(C1ODT + 4) & 0x1fc8ffff;
2484 reg32 |= odt[((cas-3) * 2) + 1];
2485 MCHBAR32(C1ODT + 4) = reg32;
2486}
2487
2488/**
2489 * @brief Enable clocks to populated sockets
2490 */
2491
2492static void sdram_enable_memory_clocks(struct sys_info *sysinfo)
2493{
2494 u8 clocks[2] = { 0, 0 };
2495
Julius Wernercd49cce2019-03-05 16:53:33 -08002496#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002497#define CLOCKS_WIDTH 2
Julius Wernercd49cce2019-03-05 16:53:33 -08002498#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002499#define CLOCKS_WIDTH 3
2500#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002501 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002502 clocks[0] |= (1 << CLOCKS_WIDTH)-1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002503
2504 if (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002505 clocks[0] |= ((1 << CLOCKS_WIDTH)-1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002506
2507 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002508 clocks[1] |= (1 << CLOCKS_WIDTH)-1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002509
2510 if (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002511 clocks[1] |= ((1 << CLOCKS_WIDTH)-1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002512
Julius Wernercd49cce2019-03-05 16:53:33 -08002513#if CONFIG(OVERRIDE_CLOCK_DISABLE)
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002514 /* Usually system firmware turns off system memory clock signals to unused SO-DIMM slots
2515 * to reduce EMI and power consumption.
2516 * However, the Kontron 986LCD-M does not like unused clock signals to be disabled.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002517 */
2518
2519 clocks[0] = 0xf; /* force all clock gate pairs to enable */
2520 clocks[1] = 0xf; /* force all clock gate pairs to enable */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002521#endif
2522
2523 MCHBAR8(C0DCLKDIS) = clocks[0];
2524 MCHBAR8(C1DCLKDIS) = clocks[1];
2525}
2526
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002527#define RTT_ODT_NONE 0
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002528#define RTT_ODT_50_OHM ((1 << 9) | (1 << 5))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002529#define RTT_ODT_75_OHM (1 << 5)
2530#define RTT_ODT_150_OHM (1 << 9)
2531
Arthur Heymans70a8e342017-03-09 11:30:23 +01002532#define EMRS_OCD_DEFAULT ((1 << 12) | (1 << 11) | (1 << 10))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002533
2534#define MRS_CAS_3 (3 << 7)
2535#define MRS_CAS_4 (4 << 7)
2536#define MRS_CAS_5 (5 << 7)
2537
2538#define MRS_TWR_3 (2 << 12)
2539#define MRS_TWR_4 (3 << 12)
2540#define MRS_TWR_5 (4 << 12)
2541
2542#define MRS_BT (1 << 6)
2543
2544#define MRS_BL4 (2 << 3)
2545#define MRS_BL8 (3 << 3)
2546
2547static void sdram_jedec_enable(struct sys_info *sysinfo)
2548{
2549 int i, nonzero;
2550 u32 bankaddr = 0, tmpaddr, mrsaddr = 0;
2551
2552 for (i = 0, nonzero = -1; i < 8; i++) {
Elyes HAOUAS01912202019-01-19 16:36:38 +01002553 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002554 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002555
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002556 printk(BIOS_DEBUG, "jedec enable sequence: bank %d\n", i);
Elyes HAOUAS01912202019-01-19 16:36:38 +01002557
2558 if (nonzero != -1) {
2559 if (sysinfo->interleaved && nonzero < 4 && i >= 4) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002560 bankaddr = 0x40;
Elyes HAOUAS01912202019-01-19 16:36:38 +01002561 } else {
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002562 printk(BIOS_DEBUG, "bankaddr from bank size of rank %d\n",
2563 nonzero);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002564 bankaddr += sysinfo->banksize[nonzero] <<
2565 (sysinfo->interleaved ? 26 : 25);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002566 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002567 }
2568
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002569 /*
2570 * We have a bank with a non-zero size... Remember it
Stefan Reinauer278534d2008-10-29 04:51:07 +00002571 * for the next offset we have to calculate
2572 */
2573 nonzero = i;
2574
2575 /* Get CAS latency set up */
2576 switch (sysinfo->cas) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002577 case 5:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002578 mrsaddr = MRS_CAS_5;
2579 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002580 case 4:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002581 mrsaddr = MRS_CAS_4;
2582 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002583 case 3:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002584 mrsaddr = MRS_CAS_3;
2585 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002586 default:
2587 die("Jedec Error (CAS).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002588 }
2589
2590 /* Get tWR set */
2591 switch (sysinfo->twr) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002592 case 5:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002593 mrsaddr |= MRS_TWR_5;
2594 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002595 case 4:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002596 mrsaddr |= MRS_TWR_4;
2597 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002598 case 3:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002599 mrsaddr |= MRS_TWR_3;
2600 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002601 default:
2602 die("Jedec Error (tWR).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002603 }
2604
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002605 /* Set "Burst Type" */
2606 mrsaddr |= MRS_BT;
2607
Stefan Reinauer278534d2008-10-29 04:51:07 +00002608 /* Interleaved */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002609 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002610 mrsaddr = mrsaddr << 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002611
2612 /* Only burst length 8 supported */
2613 mrsaddr |= MRS_BL8;
2614
2615 /* Apply NOP */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002616 PRINTK_DEBUG("Apply NOP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002617 do_ram_command(RAM_COMMAND_NOP);
2618 ram_read32(bankaddr);
2619
2620 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002621 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002622 do_ram_command(RAM_COMMAND_PRECHARGE);
2623 ram_read32(bankaddr);
2624
2625 /* Extended Mode Register Set (2) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002626 PRINTK_DEBUG("Extended Mode Register Set(2)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002627 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_2);
2628 ram_read32(bankaddr);
2629
2630 /* Extended Mode Register Set (3) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002631 PRINTK_DEBUG("Extended Mode Register Set(3)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002632 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_3);
2633 ram_read32(bankaddr);
2634
2635 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002636 PRINTK_DEBUG("Extended Mode Register Set\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002637 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2638 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002639 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002640 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002641 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002642 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002643 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002644 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002645 ram_read32(tmpaddr);
2646
2647 /* Mode Register Set: Reset DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002648 PRINTK_DEBUG("MRS: Reset DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002649 do_ram_command(RAM_COMMAND_MRS);
2650 tmpaddr = bankaddr;
2651 tmpaddr |= mrsaddr;
2652 /* Set DLL reset bit */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002653 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002654 tmpaddr |= (1 << 12);
2655 else
2656 tmpaddr |= (1 << 11);
2657 ram_read32(tmpaddr);
2658
2659 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002660 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002661 do_ram_command(RAM_COMMAND_PRECHARGE);
2662 ram_read32(bankaddr);
2663
2664 /* CAS before RAS Refresh */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002665 PRINTK_DEBUG("CAS before RAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002666 do_ram_command(RAM_COMMAND_CBR);
2667
2668 /* CBR wants two READs */
2669 ram_read32(bankaddr);
2670 ram_read32(bankaddr);
2671
2672 /* Mode Register Set: Enable DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002673 PRINTK_DEBUG("MRS: Enable DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002674 do_ram_command(RAM_COMMAND_MRS);
2675
2676 tmpaddr = bankaddr;
2677 tmpaddr |= mrsaddr;
2678 ram_read32(tmpaddr);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002679
Stefan Reinauer278534d2008-10-29 04:51:07 +00002680 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002681 PRINTK_DEBUG("Extended Mode Register Set: ODT/OCD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002682 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002683
Stefan Reinauer278534d2008-10-29 04:51:07 +00002684 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002685 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002686 tmpaddr |= RTT_ODT_75_OHM | EMRS_OCD_DEFAULT;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002687 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002688 tmpaddr |= ((RTT_ODT_150_OHM | EMRS_OCD_DEFAULT) << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002689 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002690 tmpaddr |= RTT_ODT_150_OHM | EMRS_OCD_DEFAULT;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002691 ram_read32(tmpaddr);
2692
2693 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002694 PRINTK_DEBUG("Extended Mode Register Set: OCD Exit\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002695 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2696
2697 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002698 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002699 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002700 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002701 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002702 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002703 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002704 ram_read32(tmpaddr);
2705 }
2706}
2707
2708static void sdram_init_complete(void)
2709{
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002710 PRINTK_DEBUG("Normal Operation\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002711 do_ram_command(RAM_COMMAND_NORMAL);
2712}
2713
2714static void sdram_setup_processor_side(void)
2715{
2716 if (i945_silicon_revision() == 0)
2717 MCHBAR32(FSBPMC3) |= (1 << 2);
2718
2719 MCHBAR8(0xb00) |= 1;
2720
2721 if (i945_silicon_revision() == 0)
2722 MCHBAR32(SLPCTL) |= (1 << 8);
2723}
2724
Stefan Reinauer278534d2008-10-29 04:51:07 +00002725/**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002726 * @param boot_path: 0 = normal, 1 = reset, 2 = resume from s3
Martin Rothf4cb4122015-01-06 10:27:39 -07002727 * @param spd_addresses pointer to a list of SPD addresses
Stefan Reinauer278534d2008-10-29 04:51:07 +00002728 */
Sven Schnelle541269b2011-02-21 09:39:17 +00002729void sdram_initialize(int boot_path, const u8 *spd_addresses)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002730{
2731 struct sys_info sysinfo;
Arthur Heymans0ab49042017-02-06 22:40:14 +01002732 u8 reg8;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002733
Patrick Georgi771328f2015-07-13 19:24:07 +02002734 timestamp_add_now(TS_BEFORE_INITRAM);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002735 printk(BIOS_DEBUG, "Setting up RAM controller.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002736
2737 memset(&sysinfo, 0, sizeof(sysinfo));
2738
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002739 sysinfo.boot_path = boot_path;
Sven Schnelle541269b2011-02-21 09:39:17 +00002740 sysinfo.spd_addresses = spd_addresses;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002741
Stefan Reinauer278534d2008-10-29 04:51:07 +00002742 /* Look at the type of DIMMs and verify all DIMMs are x8 or x16 width */
2743 sdram_get_dram_configuration(&sysinfo);
2744
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002745 /* If error, do cold boot */
2746 sdram_detect_errors(&sysinfo);
2747
Stefan Reinauer278534d2008-10-29 04:51:07 +00002748 /* Program PLL settings */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002749 sdram_program_pll_settings(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002750
Arthur Heymans18537812016-12-28 21:20:45 +01002751 /*
2752 * Program Graphics Frequency
2753 * Set core display and render clock on 945GC to the max
2754 */
Julius Wernercd49cce2019-03-05 16:53:33 -08002755 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM))
Arthur Heymans18537812016-12-28 21:20:45 +01002756 sdram_program_graphics_frequency(&sysinfo);
2757 else
2758 pci_write_config16(PCI_DEV(0, 2, 0), GCFC, 0x0534);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002759
2760 /* Program System Memory Frequency */
2761 sdram_program_memory_frequency(&sysinfo);
2762
2763 /* Determine Mode of Operation (Interleaved etc) */
2764 sdram_set_channel_mode(&sysinfo);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002765
Stefan Reinauer278534d2008-10-29 04:51:07 +00002766 /* Program Clock Crossing values */
2767 sdram_program_clock_crossing();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002768
Stefan Reinauer278534d2008-10-29 04:51:07 +00002769 /* Disable fast dispatch */
2770 sdram_disable_fast_dispatch();
2771
2772 /* Enable WIODLL Power Down in ACPI states */
2773 MCHBAR32(C0DMC) |= (1 << 24);
2774 MCHBAR32(C1DMC) |= (1 << 24);
2775
2776 /* Program DRAM Row Boundary/Attribute Registers */
2777
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002778 /* program row size DRB and set TOLUD */
2779 sdram_program_row_boundaries(&sysinfo);
2780
2781 /* program page size DRA */
2782 sdram_set_row_attributes(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002783
2784 /* Program CxBNKARC */
2785 sdram_set_bank_architecture(&sysinfo);
2786
2787 /* Program DRAM Timing and Control registers based on SPD */
2788 sdram_set_timing_and_control(&sysinfo);
2789
2790 /* On-Die Termination Adjustment */
2791 sdram_on_die_termination(&sysinfo);
2792
2793 /* Pre Jedec Initialization */
2794 sdram_pre_jedec_initialization();
2795
2796 /* Perform System Memory IO Initialization */
2797 sdram_initialize_system_memory_io(&sysinfo);
2798
2799 /* Perform System Memory IO Buffer Enable */
2800 sdram_enable_system_memory_io(&sysinfo);
2801
2802 /* Enable System Memory Clocks */
2803 sdram_enable_memory_clocks(&sysinfo);
2804
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002805 if (boot_path == BOOT_PATH_NORMAL) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002806 /* Jedec Initialization sequence */
2807 sdram_jedec_enable(&sysinfo);
2808 }
2809
2810 /* Program Power Management Registers */
2811 sdram_power_management(&sysinfo);
2812
2813 /* Post Jedec Init */
2814 sdram_post_jedec_initialization(&sysinfo);
2815
2816 /* Program DRAM Throttling */
2817 sdram_thermal_management();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002818
Stefan Reinauer278534d2008-10-29 04:51:07 +00002819 /* Normal Operations */
Stefan Reinaueraca6ec62009-10-26 17:12:21 +00002820 sdram_init_complete();
Stefan Reinauer278534d2008-10-29 04:51:07 +00002821
2822 /* Program Receive Enable Timings */
2823 sdram_program_receive_enable(&sysinfo);
2824
2825 /* Enable Periodic RCOMP */
2826 sdram_enable_rcomp();
2827
2828 /* Tell ICH7 that we're done */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +01002829 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002830 reg8 &= ~(1 << 7);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +01002831 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002832
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002833 printk(BIOS_DEBUG, "RAM initialization finished.\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002834
Stefan Reinauer278534d2008-10-29 04:51:07 +00002835 sdram_setup_processor_side();
Patrick Georgi771328f2015-07-13 19:24:07 +02002836 timestamp_add_now(TS_AFTER_INITRAM);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002837}