blob: 2a8a42bedbec3840f060b15229a71796c85fc97f [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>
Kyösti Mälkki1a1b04e2020-01-07 22:34:33 +02007#include <device/smbus_host.h>
Elyes HAOUAS420d7e02019-04-21 18:39:34 +02008#include <cf9_reset.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02009#include <device/mmio.h>
Arthur Heymans885c2892016-10-03 17:16:48 +020010#include <device/device.h>
Julius Werner7a8a4ab2015-05-22 16:26:40 -070011#include <lib.h>
Edwin Beasanteb50c7d2010-07-06 21:05:04 +000012#include <pc80/mc146818rtc.h>
Stefan Reinauer278534d2008-10-29 04:51:07 +000013#include <spd.h>
Patrick Georgid0835952010-10-05 09:07:10 +000014#include <string.h>
Stefan Reinauer278534d2008-10-29 04:51:07 +000015#include "raminit.h"
16#include "i945.h"
Arthur Heymans885c2892016-10-03 17:16:48 +020017#include "chip.h"
Arthur Heymans0ab49042017-02-06 22:40:14 +010018#include <device/dram/ddr2.h>
Patrick Georgi771328f2015-07-13 19:24:07 +020019#include <timestamp.h>
Rudolf Marekc4369532010-12-13 19:59:13 +000020
Stefan Reinauer278534d2008-10-29 04:51:07 +000021/* Debugging macros. */
Julius Wernercd49cce2019-03-05 16:53:33 -080022#if CONFIG(DEBUG_RAM_SETUP)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000023#define PRINTK_DEBUG(x...) printk(BIOS_DEBUG, x)
Stefan Reinauer278534d2008-10-29 04:51:07 +000024#else
25#define PRINTK_DEBUG(x...)
26#endif
27
Stefan Reinauer278534d2008-10-29 04:51:07 +000028#define RAM_INITIALIZATION_COMPLETE (1 << 19)
29
30#define RAM_COMMAND_SELF_REFRESH (0x0 << 16)
31#define RAM_COMMAND_NOP (0x1 << 16)
32#define RAM_COMMAND_PRECHARGE (0x2 << 16)
33#define RAM_COMMAND_MRS (0x3 << 16)
34#define RAM_COMMAND_EMRS (0x4 << 16)
35#define RAM_COMMAND_CBR (0x6 << 16)
36#define RAM_COMMAND_NORMAL (0x7 << 16)
37
38#define RAM_EMRS_1 (0x0 << 21)
39#define RAM_EMRS_2 (0x1 << 21)
40#define RAM_EMRS_3 (0x2 << 21)
41
Arthur Heymans885c2892016-10-03 17:16:48 +020042#define DEFAULT_PCI_MMIO_SIZE 768
Sven Schnelle541269b2011-02-21 09:39:17 +000043static int get_dimm_spd_address(struct sys_info *sysinfo, int device)
44{
45 if (sysinfo->spd_addresses)
46 return sysinfo->spd_addresses[device];
47 else
48 return DIMM0 + device;
49
50}
51
Stefan Reinauerbc8613e2010-08-25 18:35:42 +000052static __attribute__((noinline)) void do_ram_command(u32 command)
Stefan Reinauer278534d2008-10-29 04:51:07 +000053{
54 u32 reg32;
55
56 reg32 = MCHBAR32(DCC);
Angel Pons30492572020-06-11 13:24:54 +020057 reg32 &= ~((3 << 21) | (1 << 20) | (1 << 19) | (7 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +000058 reg32 |= command;
59
60 /* Also set Init Complete */
61 if (command == RAM_COMMAND_NORMAL)
62 reg32 |= RAM_INITIALIZATION_COMPLETE;
63
64 PRINTK_DEBUG(" Sending RAM command 0x%08x", reg32);
65
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +010066 MCHBAR32(DCC) = reg32; /* This is the actual magic */
Stefan Reinauer278534d2008-10-29 04:51:07 +000067
Stefan Reinauer779b3e32008-11-10 15:43:37 +000068 PRINTK_DEBUG("...done\n");
Stefan Reinauerd058ad12010-08-26 12:43:58 +000069
70 udelay(1);
Stefan Reinauer278534d2008-10-29 04:51:07 +000071}
72
Stefan Reinauer278534d2008-10-29 04:51:07 +000073static void ram_read32(u32 offset)
74{
Elyes HAOUAS15279a92016-07-28 21:05:26 +020075 PRINTK_DEBUG(" RAM read: %08x\n", offset);
Stefan Reinauer278534d2008-10-29 04:51:07 +000076
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080077 read32((void *)offset);
Stefan Reinauer278534d2008-10-29 04:51:07 +000078}
79
Stefan Reinauer3c0bfaf2010-12-27 11:34:57 +000080void sdram_dump_mchbar_registers(void)
Stefan Reinauer278534d2008-10-29 04:51:07 +000081{
82 int i;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000083 printk(BIOS_DEBUG, "Dumping MCHBAR Registers\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +000084
Arthur Heymans70a8e342017-03-09 11:30:23 +010085 for (i = 0; i < 0xfff; i += 4) {
Stefan Reinauer278534d2008-10-29 04:51:07 +000086 if (MCHBAR32(i) == 0)
87 continue;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000088 printk(BIOS_DEBUG, "0x%04x: 0x%08x\n", i, MCHBAR32(i));
Stefan Reinauer278534d2008-10-29 04:51:07 +000089 }
90}
Stefan Reinauer278534d2008-10-29 04:51:07 +000091
Stefan Reinauer24b4df52010-01-17 13:47:35 +000092static int memclk(void)
93{
Julius Wernercd49cce2019-03-05 16:53:33 -080094 int offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Elyes HAOUASc9848a82016-10-09 20:24:20 +020095
Stefan Reinauer24b4df52010-01-17 13:47:35 +000096 switch (((MCHBAR32(CLKCFG) >> 4) & 7) - offset) {
97 case 1: return 400;
98 case 2: return 533;
99 case 3: return 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100100 default:
Elyes HAOUAS3cd43272020-03-05 22:01:17 +0100101 printk(BIOS_DEBUG, "%s: unknown register value %x\n", __func__,
Arthur Heymans70a8e342017-03-09 11:30:23 +0100102 ((MCHBAR32(CLKCFG) >> 4) & 7) - offset);
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000103 }
104 return -1;
105}
106
Peter Stuge76d91432010-10-01 10:02:33 +0000107static u16 fsbclk(void)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000108{
Julius Wernercd49cce2019-03-05 16:53:33 -0800109 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200110 switch (MCHBAR32(CLKCFG) & 7) {
111 case 0: return 400;
112 case 1: return 533;
113 case 3: return 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100114 default:
Elyes HAOUAS3cd43272020-03-05 22:01:17 +0100115 printk(BIOS_DEBUG, "%s: unknown register value %x\n", __func__,
Arthur Heymans70a8e342017-03-09 11:30:23 +0100116 MCHBAR32(CLKCFG) & 7);
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200117 }
118 return 0xffff;
Julius Wernercd49cce2019-03-05 16:53:33 -0800119 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200120 switch (MCHBAR32(CLKCFG) & 7) {
121 case 0: return 1066;
122 case 1: return 533;
123 case 2: return 800;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100124 default:
Elyes HAOUAS3cd43272020-03-05 22:01:17 +0100125 printk(BIOS_DEBUG, "%s: unknown register value %x\n", __func__,
Arthur Heymans70a8e342017-03-09 11:30:23 +0100126 MCHBAR32(CLKCFG) & 7);
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200127 }
128 return 0xffff;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000129 }
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000130}
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000131
Stefan Reinauer278534d2008-10-29 04:51:07 +0000132static int sdram_capabilities_max_supported_memory_frequency(void)
133{
134 u32 reg32;
135
Patrick Georgi77d66832010-10-01 08:02:45 +0000136#if CONFIG_MAXIMUM_SUPPORTED_FREQUENCY
137 return CONFIG_MAXIMUM_SUPPORTED_FREQUENCY;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000138#endif
139
Angel Pons3580d812020-06-11 14:13:33 +0200140 reg32 = pci_read_config32(HOST_BRIDGE, 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000141 reg32 &= (7 << 0);
142
143 switch (reg32) {
144 case 4: return 400;
145 case 3: return 533;
146 case 2: return 667;
147 }
148 /* Newer revisions of this chipset rather support faster memory clocks,
149 * so if it's a reserved value, return the fastest memory clock that we
150 * know of and can handle
151 */
152 return 667;
153}
154
155/**
156 * @brief determine whether chipset is capable of dual channel interleaved mode
157 *
158 * @return 1 if interleaving is supported, 0 otherwise
159 */
160static int sdram_capabilities_interleave(void)
161{
162 u32 reg32;
163
Angel Pons3580d812020-06-11 14:13:33 +0200164 reg32 = pci_read_config32(HOST_BRIDGE, 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000165 reg32 >>= 25;
166 reg32 &= 1;
167
168 return (!reg32);
169}
170
171/**
172 * @brief determine whether chipset is capable of two memory channels
173 *
174 * @return 1 if dual channel operation is supported, 0 otherwise
175 */
176static int sdram_capabilities_dual_channel(void)
177{
178 u32 reg32;
179
Angel Pons3580d812020-06-11 14:13:33 +0200180 reg32 = pci_read_config32(HOST_BRIDGE, 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000181 reg32 >>= 24;
182 reg32 &= 1;
183
184 return (!reg32);
185}
186
187static int sdram_capabilities_enhanced_addressing_xor(void)
188{
189 u8 reg8;
190
Angel Pons3580d812020-06-11 14:13:33 +0200191 reg8 = pci_read_config8(HOST_BRIDGE, 0xe5); /* CAPID0 + 5 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000192 reg8 &= (1 << 7);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000193
Stefan Reinauer278534d2008-10-29 04:51:07 +0000194 return (!reg8);
195}
196
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000197#define GFX_FREQUENCY_CAP_166MHZ 0x04
198#define GFX_FREQUENCY_CAP_200MHZ 0x03
199#define GFX_FREQUENCY_CAP_250MHZ 0x02
200#define GFX_FREQUENCY_CAP_ALL 0x00
201
202static int sdram_capabilities_core_frequencies(void)
203{
204 u8 reg8;
205
Angel Pons3580d812020-06-11 14:13:33 +0200206 reg8 = pci_read_config8(HOST_BRIDGE, 0xe5); /* CAPID0 + 5 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000207 reg8 &= (1 << 3) | (1 << 2) | (1 << 1);
208 reg8 >>= 1;
209
Arthur Heymans70a8e342017-03-09 11:30:23 +0100210 return reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000211}
212
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000213static void sdram_detect_errors(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000214{
215 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000216 u8 do_reset = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000217
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100218 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000219
Angel Pons30492572020-06-11 13:24:54 +0200220 if (reg8 & ((1 << 7) | (1 << 2))) {
221 if (reg8 & (1 << 2)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000222 printk(BIOS_DEBUG, "SLP S4# Assertion Width Violation.\n");
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000223 /* Write back clears bit 2 */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100224 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000225 do_reset = 1;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000226
Stefan Reinauer278534d2008-10-29 04:51:07 +0000227 }
228
Angel Pons30492572020-06-11 13:24:54 +0200229 if (reg8 & (1 << 7)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000230 printk(BIOS_DEBUG, "DRAM initialization was interrupted.\n");
Angel Pons30492572020-06-11 13:24:54 +0200231 reg8 &= ~(1 << 7);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100232 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000233 do_reset = 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000234 }
235
236 /* Set SLP_S3# Assertion Stretch Enable */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100237 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000238 reg8 |= (1 << 3);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100239 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000240
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000241 if (do_reset) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000242 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200243 full_reset();
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000244 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000245 }
246
247 /* Set DRAM initialization bit in ICH7 */
Angel Ponse3c68d22020-06-08 12:09:03 +0200248 pci_or_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, 1 << 7);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000249
Peter Stuge751508a2012-01-27 22:17:09 +0100250 /* clear self refresh status if check is disabled or not a resume */
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200251 if (!CONFIG(CHECK_SLFRCS_ON_RESUME) || sysinfo->boot_path != BOOT_PATH_RESUME) {
Patrick Georgi86a11102013-03-15 14:11:37 +0100252 MCHBAR8(SLFRCS) |= 3;
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000253 } else {
254 /* Validate self refresh config */
255 if (((sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED) ||
256 (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)) &&
Angel Pons30492572020-06-11 13:24:54 +0200257 !(MCHBAR8(SLFRCS) & (1 << 0))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000258 do_reset = 1;
259 }
260 if (((sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED) ||
261 (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) &&
Angel Pons30492572020-06-11 13:24:54 +0200262 !(MCHBAR8(SLFRCS) & (1 << 1))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000263 do_reset = 1;
264 }
265 }
266
267 if (do_reset) {
268 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200269 full_reset();
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000270 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000271}
Stefan Reinauer278534d2008-10-29 04:51:07 +0000272
Arthur Heymans0ab49042017-02-06 22:40:14 +0100273struct timings {
274 u32 min_tCLK_cas[8];
275 u32 min_tRAS;
276 u32 min_tRP;
277 u32 min_tRCD;
278 u32 min_tWR;
279 u32 min_tRFC;
280 u32 max_tRR;
281 u8 cas_mask;
282};
Stefan Reinauer278534d2008-10-29 04:51:07 +0000283
Arthur Heymans0ab49042017-02-06 22:40:14 +0100284/**
285 * @brief loop over dimms and save maximal timings
286 */
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200287static void gather_common_timing(struct sys_info *sysinfo, struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000288{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100289
290 int i, j;
291 u8 raw_spd[SPD_SIZE_MAX_DDR2];
292 u8 dimm_mask = 0;
293
294 memset(saved_timings, 0, sizeof(*saved_timings));
295 saved_timings->max_tRR = UINT32_MAX;
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200296 saved_timings->cas_mask = SPD_CAS_LATENCY_DDR2_3 | SPD_CAS_LATENCY_DDR2_4
297 | SPD_CAS_LATENCY_DDR2_5;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000298
299 /**
300 * i945 supports two DIMMs, in two configurations:
301 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000302 * - single channel with two DIMMs
303 * - dual channel with one DIMM per channel
Stefan Reinauer278534d2008-10-29 04:51:07 +0000304 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000305 * In practice dual channel mainboards have their SPD at 0x50/0x52
306 * whereas single channel configurations have their SPD at 0x50/0x51.
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000307 *
Stefan Reinauer278534d2008-10-29 04:51:07 +0000308 * The capability register knows a lot about the channel configuration
Uwe Hermannd773fd32010-11-20 20:23:08 +0000309 * but for now we stick with the information we gather via SPD.
Stefan Reinauer278534d2008-10-29 04:51:07 +0000310 */
311
Arthur Heymans0ab49042017-02-06 22:40:14 +0100312 printk(BIOS_DEBUG, "This mainboard supports ");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000313 if (sdram_capabilities_dual_channel()) {
314 sysinfo->dual_channel = 1;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100315 printk(BIOS_DEBUG, "Dual Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000316 } else {
317 sysinfo->dual_channel = 0;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100318 printk(BIOS_DEBUG, "only Single Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000319 }
320
Stefan Reinauer278534d2008-10-29 04:51:07 +0000321
Arthur Heymans70a8e342017-03-09 11:30:23 +0100322 for (i = 0; i < (2 * DIMM_SOCKETS); i++) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100323 int device = get_dimm_spd_address(sysinfo, i), bytes_read;
Arthur Heymansfc31e442018-02-12 15:12:34 +0100324 struct dimm_attr_ddr2_st dimm_info;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000325
326 /* Initialize the socket information with a sane value */
327 sysinfo->dimm[i] = SYSINFO_DIMM_NOT_POPULATED;
328
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000329 /* Dual Channel not supported, but Channel 1? Bail out */
330 if (!sdram_capabilities_dual_channel() && (i >> 1))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000331 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000332
Kyösti Mälkkibd659852020-01-05 20:00:18 +0200333 if (smbus_read_byte(device, SPD_MEMORY_TYPE) !=
Arthur Heymans0ab49042017-02-06 22:40:14 +0100334 SPD_MEMORY_TYPE_SDRAM_DDR2) {
335 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: N/A\n",
336 (i >> 1), (i & 1));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000337 continue;
338 }
339
Arthur Heymans0ab49042017-02-06 22:40:14 +0100340 /*
341 * spd_decode_ddr2() needs a 128-byte sized array but
342 * only the first 64 bytes contain data needed for raminit.
343 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000344
Kyösti Mälkkic01a5052019-01-30 09:39:23 +0200345 bytes_read = i2c_eeprom_read(device, 0, 64, raw_spd);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100346 printk(BIOS_DEBUG, "Reading SPD using i2c block operation.\n");
Julius Wernercd49cce2019-03-05 16:53:33 -0800347 if (CONFIG(DEBUG_RAM_SETUP) && bytes_read > 0)
Arthur Heymans0ab49042017-02-06 22:40:14 +0100348 hexdump(raw_spd, bytes_read);
Arthur Heymans56619452017-09-21 09:12:42 +0200349 if (bytes_read != 64) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100350 /* Try again with SMBUS byte read */
351 printk(BIOS_DEBUG, "i2c block operation failed,"
Paul Menzel105e3682017-09-21 08:11:05 +0200352 " trying smbus byte operation.\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100353 for (j = 0; j < 64; j++)
Kyösti Mälkkibd659852020-01-05 20:00:18 +0200354 raw_spd[j] = smbus_read_byte(device, j);
Julius Wernercd49cce2019-03-05 16:53:33 -0800355 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100356 hexdump(raw_spd, 64);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100357 }
Arthur Heymans56619452017-09-21 09:12:42 +0200358
359 if (spd_decode_ddr2(&dimm_info, raw_spd) != SPD_STATUS_OK) {
360 printk(BIOS_WARNING, "Encountered problems with SPD, "
361 "skipping this DIMM.\n");
362 continue;
363 }
364
Julius Wernercd49cce2019-03-05 16:53:33 -0800365 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100366 dram_print_spd_ddr2(&dimm_info);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000367
Arthur Heymans0ab49042017-02-06 22:40:14 +0100368 if (dimm_info.flags.is_ecc)
369 die("\nError: ECC memory not supported by this chipset\n");
370
371 if (spd_dimm_is_registered_ddr2(dimm_info.dimm_type))
372 die("\nError: Registered memory not supported by this chipset\n");
373
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200374 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: ", (i >> 1), (i & 1));
Arthur Heymans0ab49042017-02-06 22:40:14 +0100375 /**
376 * There are 5 different possible populations for a DIMM socket:
377 * 0. x16 double ranked (X16DS)
378 * 1. x8 double ranked (X8DS)
379 * 2. x16 single ranked (X16SS)
380 * 3. x8 double stacked (X8DDS)
381 * 4. Unpopulated
382 */
383 switch (dimm_info.width) {
384 case 8:
385 switch (dimm_info.ranks) {
386 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000387 printk(BIOS_DEBUG, "x8DDS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000388 sysinfo->dimm[i] = SYSINFO_DIMM_X8DDS;
389 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100390 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000391 printk(BIOS_DEBUG, "x8DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000392 sysinfo->dimm[i] = SYSINFO_DIMM_X8DS;
393 break;
394 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000395 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000396 }
397 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100398 case 16:
399 switch (dimm_info.ranks) {
400 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000401 printk(BIOS_DEBUG, "x16DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000402 sysinfo->dimm[i] = SYSINFO_DIMM_X16DS;
403 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100404 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000405 printk(BIOS_DEBUG, "x16SS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000406 sysinfo->dimm[i] = SYSINFO_DIMM_X16SS;
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;
412 default:
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000413 die("Unsupported DDR-II memory width.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000414 }
415
Arthur Heymans0ab49042017-02-06 22:40:14 +0100416 /* Is the current DIMM a stacked DIMM? */
417 if (dimm_info.flags.stacked)
418 sysinfo->package = SYSINFO_PACKAGE_STACKED;
419
420 if (!dimm_info.flags.bl8)
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100421 die("Only DDR-II RAM with burst length 8 is supported.\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100422
423 if (dimm_info.ranksize_mb < 128)
424 die("DDR-II rank size smaller than 128MB is not supported.\n");
425
426 sysinfo->banksize[i * 2] = dimm_info.ranksize_mb / 32;
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200427 printk(BIOS_DEBUG, "DIMM %d side 0 = %d MB\n", i, sysinfo->banksize[i * 2] * 32);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100428 if (dimm_info.ranks == 2) {
429 sysinfo->banksize[(i * 2) + 1] =
430 dimm_info.ranksize_mb / 32;
431 printk(BIOS_DEBUG, "DIMM %d side 1 = %d MB\n",
432 i, sysinfo->banksize[(i * 2) + 1] * 32);
433 }
434
435
436 sysinfo->rows[i] = dimm_info.row_bits;
437 sysinfo->cols[i] = dimm_info.col_bits;
438 sysinfo->banks[i] = dimm_info.banks;
439
440 /* int min_tRAS, min_tRP, min_tRCD, min_tWR, min_tRFC; */
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200441 saved_timings->min_tRAS = MAX(saved_timings->min_tRAS, dimm_info.tRAS);
442 saved_timings->min_tRP = MAX(saved_timings->min_tRP, dimm_info.tRP);
443 saved_timings->min_tRCD = MAX(saved_timings->min_tRCD, dimm_info.tRCD);
444 saved_timings->min_tWR = MAX(saved_timings->min_tWR, dimm_info.tWR);
445 saved_timings->min_tRFC = MAX(saved_timings->min_tRFC, dimm_info.tRFC);
446 saved_timings->max_tRR = MIN(saved_timings->max_tRR, dimm_info.tRR);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100447 saved_timings->cas_mask &= dimm_info.cas_supported;
448 for (j = 0; j < 8; j++) {
449 if (!(saved_timings->cas_mask & (1 << j)))
450 saved_timings->min_tCLK_cas[j] = 0;
451 else
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200452 saved_timings->min_tCLK_cas[j] = MAX(dimm_info.cycle_time[j],
Arthur Heymans0ab49042017-02-06 22:40:14 +0100453 saved_timings->min_tCLK_cas[j]);
454 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000455 dimm_mask |= (1 << i);
456 }
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200457 if (!dimm_mask)
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000458 die("No memory installed.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000459
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200460 if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1)))
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100461 /* FIXME: Possibly does not boot in this case */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000462 printk(BIOS_INFO, "Channel 0 has no memory populated.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000463}
464
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200465static void choose_tclk(struct sys_info *sysinfo, struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000466{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100467 u32 ctrl_min_tclk;
468 int try_cas;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000469
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200470 ctrl_min_tclk = 2 * 256 * 1000 / sdram_capabilities_max_supported_memory_frequency();
Arthur Heymans0ab49042017-02-06 22:40:14 +0100471 normalize_tck(&ctrl_min_tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000472
Arthur Heymans0ab49042017-02-06 22:40:14 +0100473 try_cas = spd_get_msbs(saved_timings->cas_mask);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000474
Arthur Heymans0ab49042017-02-06 22:40:14 +0100475 while (saved_timings->cas_mask & (1 << try_cas) && try_cas > 0) {
476 sysinfo->cas = try_cas;
477 sysinfo->tclk = saved_timings->min_tCLK_cas[try_cas];
478 if (sysinfo->tclk >= ctrl_min_tclk &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200479 saved_timings->min_tCLK_cas[try_cas] !=
480 saved_timings->min_tCLK_cas[try_cas - 1])
Stefan Reinauer278534d2008-10-29 04:51:07 +0000481 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100482 try_cas--;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000483 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000484
Arthur Heymans0ab49042017-02-06 22:40:14 +0100485 normalize_tck(&sysinfo->tclk);
486
487 if ((sysinfo->cas < 3) || (sysinfo->tclk == 0))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000488 die("Could not find common memory frequency and CAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000489
Arthur Heymans0ab49042017-02-06 22:40:14 +0100490 /*
491 * The loop can still results in a timing too fast for the
492 * memory controller.
493 */
494 if (sysinfo->tclk < ctrl_min_tclk)
495 sysinfo->tclk = ctrl_min_tclk;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000496
Arthur Heymans0ab49042017-02-06 22:40:14 +0100497 switch (sysinfo->tclk) {
498 case TCK_200MHZ:
499 sysinfo->memory_frequency = 400;
500 break;
501 case TCK_266MHZ:
502 sysinfo->memory_frequency = 533;
503 break;
504 case TCK_333MHZ:
505 sysinfo->memory_frequency = 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100506 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000507 }
508
Arthur Heymans0ab49042017-02-06 22:40:14 +0100509 printk(BIOS_DEBUG,
510 "Memory will be driven at %dMT with CAS=%d clocks\n",
511 sysinfo->memory_frequency, sysinfo->cas);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000512}
513
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200514static void derive_timings(struct sys_info *sysinfo, struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000515{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100516 sysinfo->tras = DIV_ROUND_UP(saved_timings->min_tRAS, sysinfo->tclk);
517 if (sysinfo->tras > 0x18)
518 die("DDR-II Module does not support this frequency (tRAS error)\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000519
Arthur Heymans0ab49042017-02-06 22:40:14 +0100520 sysinfo->trp = DIV_ROUND_UP(saved_timings->min_tRP, sysinfo->tclk);
521 if (sysinfo->trp > 6)
522 die("DDR-II Module does not support this frequency (tRP error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000523
Arthur Heymans0ab49042017-02-06 22:40:14 +0100524 sysinfo->trcd = DIV_ROUND_UP(saved_timings->min_tRCD, sysinfo->tclk);
525 if (sysinfo->trcd > 6)
526 die("DDR-II Module does not support this frequency (tRCD error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000527
Arthur Heymans0ab49042017-02-06 22:40:14 +0100528 sysinfo->twr = DIV_ROUND_UP(saved_timings->min_tWR, sysinfo->tclk);
529 if (sysinfo->twr > 5)
530 die("DDR-II Module does not support this frequency (tWR error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000531
Arthur Heymans0ab49042017-02-06 22:40:14 +0100532 sysinfo->trfc = DIV_ROUND_UP(saved_timings->min_tRFC, sysinfo->tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000533
Arthur Heymans0ab49042017-02-06 22:40:14 +0100534 printk(BIOS_DEBUG, "tRAS = %d cycles\n", sysinfo->tras);
535 printk(BIOS_DEBUG, "tRP = %d cycles\n", sysinfo->trp);
536 printk(BIOS_DEBUG, "tRCD = %d cycles\n", sysinfo->trcd);
537 printk(BIOS_DEBUG, "tWR = %d cycles\n", sysinfo->twr);
538 printk(BIOS_DEBUG, "tRFC = %d cycles\n", sysinfo->trfc);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000539
Arthur Heymans0ab49042017-02-06 22:40:14 +0100540 /* Refresh is slower than 15.6us, use 15.6us */
541 /* tRR is decoded in units of 1/256us */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000542
Arthur Heymans0ab49042017-02-06 22:40:14 +0100543#define T_RR_7_8US 2000000
544#define T_RR_15_6US 4000000
545#define REFRESH_7_8US 1
546#define REFRESH_15_6US 0
Stefan Reinauer278534d2008-10-29 04:51:07 +0000547
Arthur Heymans0ab49042017-02-06 22:40:14 +0100548 if (saved_timings->max_tRR < T_RR_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000549 die("DDR-II module has unsupported refresh value\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100550 else if (saved_timings->max_tRR < T_RR_15_6US)
551 sysinfo->refresh = REFRESH_7_8US;
552 else
553 sysinfo->refresh = REFRESH_15_6US;
Angel Pons30492572020-06-11 13:24:54 +0200554 printk(BIOS_DEBUG, "Refresh: %s\n", sysinfo->refresh ? "7.8us" : "15.6us");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000555}
556
Arthur Heymans0ab49042017-02-06 22:40:14 +0100557/**
558 * @brief Get generic DIMM parameters.
559 * @param sysinfo Central memory controller information structure
560 *
561 * This function gathers several pieces of information for each system DIMM:
562 * o DIMM width (x8 / x16)
563 * o DIMM rank (single ranked / dual ranked)
564 *
565 * Also, some non-supported scenarios are detected.
566 */
567
568static void sdram_get_dram_configuration(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000569{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100570 struct timings saved_timings;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000571
Arthur Heymans0ab49042017-02-06 22:40:14 +0100572 gather_common_timing(sysinfo, &saved_timings);
573 choose_tclk(sysinfo, &saved_timings);
574 derive_timings(sysinfo, &saved_timings);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000575}
576
Arthur Heymans70a8e342017-03-09 11:30:23 +0100577static void sdram_program_dram_width(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000578{
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200579 u16 c0dramw = 0, c1dramw = 0;
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200580 int i, idx;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000581
582 if (sysinfo->dual_channel)
583 idx = 2;
584 else
585 idx = 1;
586
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200587 for (i = 0; i < DIMM_SOCKETS; i++) { /* Channel 0 */
588 switch (sysinfo->dimm[i]) {
589 case SYSINFO_DIMM_X16DS:
Angel Pons30492572020-06-11 13:24:54 +0200590 c0dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200591 break;
592 case SYSINFO_DIMM_X8DS:
Angel Pons30492572020-06-11 13:24:54 +0200593 c0dramw |= (0x0001) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200594 break;
595 case SYSINFO_DIMM_X16SS:
Angel Pons30492572020-06-11 13:24:54 +0200596 c0dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200597 break;
598 case SYSINFO_DIMM_X8DDS:
Angel Pons30492572020-06-11 13:24:54 +0200599 c0dramw |= (0x0005) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200600 break;
601 case SYSINFO_DIMM_NOT_POPULATED:
Angel Pons30492572020-06-11 13:24:54 +0200602 c0dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200603 break;
604 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000605 }
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200606 for (i = DIMM_SOCKETS; i < idx * DIMM_SOCKETS; i++) { /* Channel 1 */
607 switch (sysinfo->dimm[i]) {
608 case SYSINFO_DIMM_X16DS:
Angel Pons30492572020-06-11 13:24:54 +0200609 c1dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200610 break;
611 case SYSINFO_DIMM_X8DS:
Angel Pons30492572020-06-11 13:24:54 +0200612 c1dramw |= (0x0010) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200613 break;
614 case SYSINFO_DIMM_X16SS:
Angel Pons30492572020-06-11 13:24:54 +0200615 c1dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200616 break;
617 case SYSINFO_DIMM_X8DDS:
Angel Pons30492572020-06-11 13:24:54 +0200618 c1dramw |= (0x0050) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200619 break;
620 case SYSINFO_DIMM_NOT_POPULATED:
Angel Pons30492572020-06-11 13:24:54 +0200621 c1dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200622 break;
623 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000624 }
625
626 MCHBAR16(C0DRAMW) = c0dramw;
627 MCHBAR16(C1DRAMW) = c1dramw;
628}
629
630static void sdram_write_slew_rates(u32 offset, const u32 *slew_rate_table)
631{
632 int i;
633
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200634 for (i = 0; i < 16; i++)
Angel Pons30492572020-06-11 13:24:54 +0200635 MCHBAR32(offset+(i * 4)) = slew_rate_table[i];
Stefan Reinauer278534d2008-10-29 04:51:07 +0000636}
637
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000638static const u32 dq2030[] = {
639 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
640 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
641 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
642 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
643};
644
645static const u32 dq2330[] = {
646 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
647 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
648 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
649 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
650};
651
652static const u32 cmd2710[] = {
653 0x07060605, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
654 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
655 0x1110100f, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
656 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
657};
658
659static const u32 cmd3210[] = {
660 0x0f0d0b0a, 0x17151311, 0x1f1d1b19, 0x1f1f1f1f,
661 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
662 0x18171615, 0x1f1f1c1a, 0x1f1f1f1f, 0x1f1f1f1f,
663 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
664};
665
666static const u32 clk2030[] = {
667 0x0e0d0d0c, 0x100f0f0e, 0x100f0e0d, 0x15131211,
668 0x1d1b1917, 0x2523211f, 0x2a282927, 0x32302e2c,
669 0x17161514, 0x1b1a1918, 0x1f1e1d1c, 0x23222120,
670 0x27262524, 0x2d2b2928, 0x3533312f, 0x3d3b3937
671};
672
673static const u32 ctl3215[] = {
674 0x01010000, 0x03020101, 0x07060504, 0x0b0a0908,
675 0x100f0e0d, 0x14131211, 0x18171615, 0x1c1b1a19,
676 0x05040403, 0x07060605, 0x0a090807, 0x0f0d0c0b,
677 0x14131211, 0x18171615, 0x1c1b1a19, 0x201f1e1d
678};
679
680static const u32 ctl3220[] = {
681 0x05040403, 0x07060505, 0x0e0c0a08, 0x1a171411,
682 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e,
683 0x09080807, 0x0b0a0a09, 0x0f0d0c0b, 0x1b171311,
684 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e
685};
686
687static const u32 nc[] = {
688 0x00000000, 0x00000000, 0x00000000, 0x00000000,
689 0x00000000, 0x00000000, 0x00000000, 0x00000000,
690 0x00000000, 0x00000000, 0x00000000, 0x00000000,
691 0x00000000, 0x00000000, 0x00000000, 0x00000000
692};
693
694enum {
695 DQ2030,
696 DQ2330,
697 CMD2710,
698 CMD3210,
699 CLK2030,
700 CTL3215,
701 CTL3220,
702 NC,
703};
704
705static const u8 dual_channel_slew_group_lookup[] = {
706 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
707 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
708 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
709 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
710 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
711
712 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
713 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
714 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
715 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
716 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
717
718 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
719 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
720 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
721 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
722 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
723
724 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
725 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
726 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
727 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
728 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, NC, NC,
729
730 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
731 NC, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
732 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
733 NC, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD2710
734};
735
736static const u8 single_channel_slew_group_lookup[] = {
737 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
738 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
739 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
740 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
741 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
742
743 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
744 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
745 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
746 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
747 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
748
749 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
750 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
751 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
752 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
753 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
754
755 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
756 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
757 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
758 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
759 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
760
761 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
762 DQ2330, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
763 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
764 DQ2330, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD3210
765};
766
767static const u32 *slew_group_lookup(int dual_channel, int index)
768{
769 const u8 *slew_group;
770 /* Dual Channel needs different tables. */
771 if (dual_channel)
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100772 slew_group = dual_channel_slew_group_lookup;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000773 else
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100774 slew_group = single_channel_slew_group_lookup;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000775
776 switch (slew_group[index]) {
777 case DQ2030: return dq2030;
778 case DQ2330: return dq2330;
779 case CMD2710: return cmd2710;
780 case CMD3210: return cmd3210;
781 case CLK2030: return clk2030;
782 case CTL3215: return ctl3215;
783 case CTL3220: return ctl3220;
784 case NC: return nc;
785 }
786
787 return nc;
788}
789
Julius Wernercd49cce2019-03-05 16:53:33 -0800790#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000791/* Strength multiplier tables */
792static const u8 dual_channel_strength_multiplier[] = {
793 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
794 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
795 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
796 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
797 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
798 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
799 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
800 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
801 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
802 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
803 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
804 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
805 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
806 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
807 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
808 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
809 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
810 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
811 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
812 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
813 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
814 0x00, 0x00, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
815 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
816 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x44, 0x22
817};
818
819static const u8 single_channel_strength_multiplier[] = {
820 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
821 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
822 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
823 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
824 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
825 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
826 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
827 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
828 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
829 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
830 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
831 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
832 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
833 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
834 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
835 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
836 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
837 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
838 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
839 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
840 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
841 0x33, 0x00, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
842 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
843 0x33, 0x00, 0x11, 0x00, 0x44, 0x44, 0x33, 0x11
844};
Julius Wernercd49cce2019-03-05 16:53:33 -0800845#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000846static const u8 dual_channel_strength_multiplier[] = {
847 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
848 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
849 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
850 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
851 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
852 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
853 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
854 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
855 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
856 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
857 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
858 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
859 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
860 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
861 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
862 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
863 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
864 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
865 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
866 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
867 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
868 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
869 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
870 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33
871};
872
873static const u8 single_channel_strength_multiplier[] = {
874 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
875 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
876 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
877 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
878 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
879 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
880 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
881 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
882 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
883 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
884 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
885 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
886 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
887 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
888 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
889 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
890 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
891 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
892 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
893 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
894 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
895 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
896 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
897 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00
898};
899#endif
900
Stefan Reinauer278534d2008-10-29 04:51:07 +0000901static void sdram_rcomp_buffer_strength_and_slew(struct sys_info *sysinfo)
902{
Arthur Heymans70a8e342017-03-09 11:30:23 +0100903 const u8 *strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000904 int idx, dual_channel;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000905
906 /* Set Strength Multipliers */
907
908 /* Dual Channel needs different tables. */
909 if (sdram_capabilities_dual_channel()) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000910 printk(BIOS_DEBUG, "Programming Dual Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000911 strength_multiplier = dual_channel_strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000912 dual_channel = 1;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100913 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[2];
Stefan Reinauer278534d2008-10-29 04:51:07 +0000914 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000915 printk(BIOS_DEBUG, "Programming Single Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000916 strength_multiplier = single_channel_strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000917 dual_channel = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000918 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[1];
919 }
920
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000921 printk(BIOS_DEBUG, "Table Index: %d\n", idx);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000922
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000923 MCHBAR8(G1SC) = strength_multiplier[idx * 8 + 0];
924 MCHBAR8(G2SC) = strength_multiplier[idx * 8 + 1];
925 MCHBAR8(G3SC) = strength_multiplier[idx * 8 + 2];
926 MCHBAR8(G4SC) = strength_multiplier[idx * 8 + 3];
927 MCHBAR8(G5SC) = strength_multiplier[idx * 8 + 4];
928 MCHBAR8(G6SC) = strength_multiplier[idx * 8 + 5];
929 MCHBAR8(G7SC) = strength_multiplier[idx * 8 + 6];
930 MCHBAR8(G8SC) = strength_multiplier[idx * 8 + 7];
Stefan Reinauer278534d2008-10-29 04:51:07 +0000931
932 /* Channel 0 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000933 sdram_write_slew_rates(G1SRPUT, slew_group_lookup(dual_channel, idx * 8 + 0));
934 sdram_write_slew_rates(G2SRPUT, slew_group_lookup(dual_channel, idx * 8 + 1));
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200935 if ((slew_group_lookup(dual_channel, idx * 8 + 2) != nc) &&
936 (sysinfo->package == SYSINFO_PACKAGE_STACKED))
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000937
Stefan Reinauer278534d2008-10-29 04:51:07 +0000938 sdram_write_slew_rates(G3SRPUT, ctl3220);
Arthur Heymans70a8e342017-03-09 11:30:23 +0100939 else
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000940 sdram_write_slew_rates(G3SRPUT, slew_group_lookup(dual_channel, idx * 8 + 2));
Arthur Heymans70a8e342017-03-09 11:30:23 +0100941
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000942 sdram_write_slew_rates(G4SRPUT, slew_group_lookup(dual_channel, idx * 8 + 3));
943 sdram_write_slew_rates(G5SRPUT, slew_group_lookup(dual_channel, idx * 8 + 4));
944 sdram_write_slew_rates(G6SRPUT, slew_group_lookup(dual_channel, idx * 8 + 5));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000945
946 /* Channel 1 */
947 if (sysinfo->dual_channel) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000948 sdram_write_slew_rates(G7SRPUT, slew_group_lookup(dual_channel, idx * 8 + 6));
949 sdram_write_slew_rates(G8SRPUT, slew_group_lookup(dual_channel, idx * 8 + 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000950 } else {
951 sdram_write_slew_rates(G7SRPUT, nc);
952 sdram_write_slew_rates(G8SRPUT, nc);
953 }
954}
955
956static void sdram_enable_rcomp(void)
957{
958 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000959 /* Enable Global Periodic RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000960 udelay(300);
961 reg32 = MCHBAR32(GBRCOMPCTL);
962 reg32 &= ~(1 << 23);
963 MCHBAR32(GBRCOMPCTL) = reg32;
964}
965
966static void sdram_program_dll_timings(struct sys_info *sysinfo)
967{
Elyes HAOUAS44a30662017-02-23 13:14:44 +0100968 u32 channeldll = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000969 int i;
970
Elyes HAOUAS38424982016-08-21 12:01:04 +0200971 printk(BIOS_DEBUG, "Programming DLL Timings...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000972
Arthur Heymans70a8e342017-03-09 11:30:23 +0100973 MCHBAR16(DQSMT) &= ~((3 << 12) | (1 << 10) | (0xf << 0));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000974 MCHBAR16(DQSMT) |= (1 << 13) | (0xc << 0);
975
976 /* We drive both channels with the same speed */
Julius Wernercd49cce2019-03-05 16:53:33 -0800977 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +0100978 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +0100979 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200980 channeldll = 0x26262626;
981 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100982 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200983 channeldll = 0x22222222;
984 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100985 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200986 channeldll = 0x11111111;
987 break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +0100988 }
Julius Wernercd49cce2019-03-05 16:53:33 -0800989 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +0100990 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +0100991 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200992 channeldll = 0x33333333;
993 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100994 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200995 channeldll = 0x24242424;
996 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100997 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200998 channeldll = 0x25252525;
999 break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001000 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001001 }
1002
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001003 for (i = 0; i < 4; i++) {
Elyes HAOUAS44a30662017-02-23 13:14:44 +01001004 MCHBAR32(C0R0B00DQST + (i * 0x10) + 0) = channeldll;
1005 MCHBAR32(C0R0B00DQST + (i * 0x10) + 4) = channeldll;
1006 MCHBAR32(C1R0B00DQST + (i * 0x10) + 0) = channeldll;
1007 MCHBAR32(C1R0B00DQST + (i * 0x10) + 4) = channeldll;
Julius Wernercd49cce2019-03-05 16:53:33 -08001008 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUAS44a30662017-02-23 13:14:44 +01001009 MCHBAR8(C0R0B00DQST + (i * 0x10) + 8) = channeldll & 0xff;
1010 MCHBAR8(C1R0B00DQST + (i * 0x10) + 8) = channeldll & 0xff;
Paul Menzelbce7e332017-02-22 18:46:27 +01001011 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001012 }
1013}
1014
1015static void sdram_force_rcomp(void)
1016{
1017 u32 reg32;
1018 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001019
Stefan Reinauer278534d2008-10-29 04:51:07 +00001020 reg32 = MCHBAR32(ODTC);
1021 reg32 |= (1 << 28);
1022 MCHBAR32(ODTC) = reg32;
1023
1024 reg32 = MCHBAR32(SMSRCTL);
1025 reg32 |= (1 << 0);
1026 MCHBAR32(SMSRCTL) = reg32;
1027
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001028 /* Start initial RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001029 reg32 = MCHBAR32(GBRCOMPCTL);
1030 reg32 |= (1 << 8);
1031 MCHBAR32(GBRCOMPCTL) = reg32;
1032
1033 reg8 = i945_silicon_revision();
1034 if ((reg8 == 0 && (MCHBAR32(DCC) & (3 << 0)) == 0) || (reg8 == 1)) {
1035 reg32 = MCHBAR32(GBRCOMPCTL);
1036 reg32 |= (3 << 5);
1037 MCHBAR32(GBRCOMPCTL) = reg32;
1038 }
1039}
1040
1041static void sdram_initialize_system_memory_io(struct sys_info *sysinfo)
1042{
1043 u8 reg8;
1044 u32 reg32;
1045
Elyes HAOUAS38424982016-08-21 12:01:04 +02001046 printk(BIOS_DEBUG, "Initializing System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001047 /* Enable Data Half Clock Pushout */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001048 reg8 = MCHBAR8(C0HCTC);
1049 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001050 reg8 |= (1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001051 MCHBAR8(C0HCTC) = reg8;
1052
1053 reg8 = MCHBAR8(C1HCTC);
1054 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001055 reg8 |= (1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001056 MCHBAR8(C1HCTC) = reg8;
1057
Arthur Heymans70a8e342017-03-09 11:30:23 +01001058 MCHBAR16(WDLLBYPMODE) &= ~((1 << 9) | (1 << 6) | (1 << 4) | (1 << 3) | (1 << 1));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001059 MCHBAR16(WDLLBYPMODE) |= (1 << 8) | (1 << 7) | (1 << 5) | (1 << 2) | (1 << 0);
1060
1061 MCHBAR8(C0WDLLCMC) = 0;
1062 MCHBAR8(C1WDLLCMC) = 0;
1063
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001064 /* Program RCOMP Settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001065 sdram_program_dram_width(sysinfo);
1066
1067 sdram_rcomp_buffer_strength_and_slew(sysinfo);
1068
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001069 /* Indicate that RCOMP programming is done */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001070 reg32 = MCHBAR32(GBRCOMPCTL);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001071 reg32 &= ~((1 << 29) | (1 << 26) | (3 << 21) | (3 << 2));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001072 reg32 |= (3 << 27) | (3 << 0);
1073 MCHBAR32(GBRCOMPCTL) = reg32;
1074
1075 MCHBAR32(GBRCOMPCTL) |= (1 << 10);
1076
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001077 /* Program DLL Timings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001078 sdram_program_dll_timings(sysinfo);
1079
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001080 /* Force RCOMP cycle */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001081 sdram_force_rcomp();
1082}
1083
1084static void sdram_enable_system_memory_io(struct sys_info *sysinfo)
1085{
1086 u32 reg32;
1087
Elyes HAOUAS38424982016-08-21 12:01:04 +02001088 printk(BIOS_DEBUG, "Enabling System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001089
Stefan Reinauer278534d2008-10-29 04:51:07 +00001090 reg32 = MCHBAR32(RCVENMT);
1091 reg32 &= ~(0x3f << 6);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001092 MCHBAR32(RCVENMT) = reg32; /* [11:6] = 0 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001093
1094 reg32 |= (1 << 11) | (1 << 9);
1095 MCHBAR32(RCVENMT) = reg32;
1096
1097 reg32 = MCHBAR32(DRTST);
1098 reg32 |= (1 << 3) | (1 << 2);
1099 MCHBAR32(DRTST) = reg32;
1100
1101 reg32 = MCHBAR32(DRTST);
1102 reg32 |= (1 << 6) | (1 << 4);
1103 MCHBAR32(DRTST) = reg32;
1104
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001105 asm volatile ("nop; nop;" ::: "memory");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001106
1107 reg32 = MCHBAR32(DRTST);
1108
1109 /* Is channel 0 populated? */
1110 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001111 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001112 reg32 |= (1 << 7) | (1 << 5);
1113 else
1114 reg32 |= (1 << 31);
1115
1116 /* Is channel 1 populated? */
1117 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001118 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001119 reg32 |= (1 << 9) | (1 << 8);
1120 else
1121 reg32 |= (1 << 30);
1122
1123 MCHBAR32(DRTST) = reg32;
1124
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001125 /* Activate DRAM Channel IO Buffers */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001126 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001127 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001128 reg32 = MCHBAR32(C0DRC1);
1129 reg32 |= (1 << 8);
1130 MCHBAR32(C0DRC1) = reg32;
1131 }
1132 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001133 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001134 reg32 = MCHBAR32(C1DRC1);
1135 reg32 |= (1 << 8);
1136 MCHBAR32(C1DRC1) = reg32;
1137 }
1138}
1139
Stefan Reinauer278534d2008-10-29 04:51:07 +00001140static int sdram_program_row_boundaries(struct sys_info *sysinfo)
1141{
1142 int i;
Arthur Heymans885c2892016-10-03 17:16:48 +02001143 int cum0, cum1, tolud, tom, pci_mmio_size;
1144 const struct device *dev;
1145 const struct northbridge_intel_i945_config *cfg = NULL;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001146
Paul Menzel84283bc2014-07-17 08:16:04 +02001147 printk(BIOS_DEBUG, "Setting RAM size...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001148
1149 cum0 = 0;
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001150 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001151 cum0 += sysinfo->banksize[i];
Stefan Reinauer278534d2008-10-29 04:51:07 +00001152 MCHBAR8(C0DRB0+i) = cum0;
1153 }
1154
1155 /* Assume we continue in Channel 1 where we stopped in Channel 0 */
1156 cum1 = cum0;
1157
1158 /* Exception: Interleaved starts from the beginning */
1159 if (sysinfo->interleaved)
1160 cum1 = 0;
1161
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001162 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001163 cum1 += sysinfo->banksize[i + 4];
Stefan Reinauer278534d2008-10-29 04:51:07 +00001164 MCHBAR8(C1DRB0+i) = cum1;
1165 }
1166
1167 /* Set TOLUD Top Of Low Usable DRAM */
1168 if (sysinfo->interleaved)
1169 tolud = (cum0 + cum1) << 1;
1170 else
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001171 tolud = (cum1 ? cum1 : cum0) << 1;
Stefan Reinauer779b3e32008-11-10 15:43:37 +00001172
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001173 /* The TOM register has a different format */
1174 tom = tolud >> 3;
1175
1176 /* Limit the value of TOLUD to leave some space for PCI memory. */
Kyösti Mälkkic70eed12018-05-22 02:18:00 +03001177 dev = pcidev_on_root(0, 0);
Arthur Heymans885c2892016-10-03 17:16:48 +02001178 if (dev)
1179 cfg = dev->chip_info;
1180
1181 /* Don't use pci mmio sizes smaller than 768M */
1182 if (!cfg || cfg->pci_mmio_size <= DEFAULT_PCI_MMIO_SIZE)
1183 pci_mmio_size = DEFAULT_PCI_MMIO_SIZE;
1184 else
1185 pci_mmio_size = cfg->pci_mmio_size;
1186
1187 tolud = MIN(((4096 - pci_mmio_size) / 128) << 3, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001188
Angel Pons3580d812020-06-11 14:13:33 +02001189 pci_write_config8(HOST_BRIDGE, TOLUD, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001190
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001191 printk(BIOS_DEBUG, "C0DRB = 0x%08x\n", MCHBAR32(C0DRB0));
1192 printk(BIOS_DEBUG, "C1DRB = 0x%08x\n", MCHBAR32(C1DRB0));
Angel Pons3580d812020-06-11 14:13:33 +02001193 printk(BIOS_DEBUG, "TOLUD = 0x%04x\n", pci_read_config8(HOST_BRIDGE, TOLUD));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001194
Angel Pons3580d812020-06-11 14:13:33 +02001195 pci_write_config16(HOST_BRIDGE, TOM, tom);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001196
1197 return 0;
1198}
1199
Stefan Reinauer278534d2008-10-29 04:51:07 +00001200static int sdram_set_row_attributes(struct sys_info *sysinfo)
1201{
Arthur Heymans0ab49042017-02-06 22:40:14 +01001202 int i;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001203 u16 dra0 = 0, dra1 = 0, dra = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001204
Elyes HAOUAS38424982016-08-21 12:01:04 +02001205 printk(BIOS_DEBUG, "Setting row attributes...\n");
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001206 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001207 u8 columnsrows;
1208
Arthur Heymans70a8e342017-03-09 11:30:23 +01001209 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001210 continue;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001211
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001212 columnsrows = (sysinfo->rows[i] & 0x0f) | (sysinfo->cols[i] & 0xf) << 4;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001213
1214 switch (columnsrows) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001215 case 0x9d:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001216 dra = 2;
1217 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001218 case 0xad:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001219 dra = 3;
1220 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001221 case 0xbd:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001222 dra = 4;
1223 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001224 case 0xae:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001225 dra = 3;
1226 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001227 case 0xbe:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001228 dra = 4;
1229 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001230 default:
1231 die("Unsupported Rows/Columns. (DRA)");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001232 }
1233
1234 /* Double Sided DIMMs? */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001235 if (sysinfo->banksize[(2 * i) + 1] != 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001236 dra = (dra << 4) | dra;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001237
Stefan Reinauer278534d2008-10-29 04:51:07 +00001238 if (i < DIMM_SOCKETS)
Angel Pons30492572020-06-11 13:24:54 +02001239 dra0 |= (dra << (i * 8));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001240 else
Angel Pons30492572020-06-11 13:24:54 +02001241 dra1 |= (dra << ((i - DIMM_SOCKETS) * 8));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001242 }
1243
1244 MCHBAR16(C0DRA0) = dra0;
1245 MCHBAR16(C1DRA0) = dra1;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001246
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001247 printk(BIOS_DEBUG, "C0DRA = 0x%04x\n", dra0);
1248 printk(BIOS_DEBUG, "C1DRA = 0x%04x\n", dra1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001249
1250 return 0;
1251}
1252
1253static void sdram_set_bank_architecture(struct sys_info *sysinfo)
1254{
1255 u32 off32;
1256 int i;
1257
1258 MCHBAR16(C1BNKARC) &= 0xff00;
1259 MCHBAR16(C0BNKARC) &= 0xff00;
1260
1261 off32 = C0BNKARC;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001262 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001263 /* Switch to second channel */
1264 if (i == DIMM_SOCKETS)
1265 off32 = C1BNKARC;
1266
1267 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
1268 continue;
1269
1270 if (sysinfo->banks[i] != 8)
1271 continue;
1272
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001273 printk(BIOS_SPEW, "DIMM%d has 8 banks.\n", i);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001274
1275 if (i & 1)
1276 MCHBAR16(off32) |= 0x50;
1277 else
1278 MCHBAR16(off32) |= 0x05;
1279 }
1280}
1281
Stefan Reinauer278534d2008-10-29 04:51:07 +00001282static void sdram_program_refresh_rate(struct sys_info *sysinfo)
1283{
1284 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001285
Arthur Heymans70a8e342017-03-09 11:30:23 +01001286 if (sysinfo->refresh == REFRESH_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001287 reg32 = (2 << 8); /* Refresh enabled at 7.8us */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001288 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001289 reg32 = (1 << 8); /* Refresh enabled at 15.6us */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001290
1291 MCHBAR32(C0DRC0) &= ~(7 << 8);
1292 MCHBAR32(C0DRC0) |= reg32;
1293
1294 MCHBAR32(C1DRC0) &= ~(7 << 8);
1295 MCHBAR32(C1DRC0) |= reg32;
1296}
1297
1298static void sdram_program_cke_tristate(struct sys_info *sysinfo)
1299{
1300 u32 reg32;
1301 int i;
1302
1303 reg32 = MCHBAR32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001304
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001305 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001306 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001307 reg32 |= (1 << (16 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001308 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001309
Stefan Reinauer278534d2008-10-29 04:51:07 +00001310 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001311
Stefan Reinauer278534d2008-10-29 04:51:07 +00001312 reg32 |= (1 << 11);
1313 MCHBAR32(C0DRC1) = reg32;
1314
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001315 /* Do we have to do this if we're in Single Channel Mode? */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001316 reg32 = MCHBAR32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001317
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001318 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001319 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001320 reg32 |= (1 << (12 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001321 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001322
Stefan Reinauer278534d2008-10-29 04:51:07 +00001323 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001324
Stefan Reinauer278534d2008-10-29 04:51:07 +00001325 reg32 |= (1 << 11);
1326 MCHBAR32(C1DRC1) = reg32;
1327}
1328
1329static void sdram_program_odt_tristate(struct sys_info *sysinfo)
1330{
1331 u32 reg32;
1332 int i;
1333
1334 reg32 = MCHBAR32(C0DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001335
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001336 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001337 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001338 reg32 |= (1 << (24 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001339 }
1340 MCHBAR32(C0DRC2) = reg32;
1341
1342 reg32 = MCHBAR32(C1DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001343
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001344 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001345 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001346 reg32 |= (1 << (20 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001347 }
1348 MCHBAR32(C1DRC2) = reg32;
1349}
1350
1351static void sdram_set_timing_and_control(struct sys_info *sysinfo)
1352{
Arthur Heymans25027232017-02-12 23:34:39 +01001353 u32 reg32, tRD_min;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001354 u32 tWTR;
1355 u32 temp_drt;
1356 int i, page_size;
1357
Edward O'Callaghan2f237c12014-05-25 06:24:39 +10001358 static const u8 cas_table[] = {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001359 2, 1, 0, 3
1360 };
1361
1362 reg32 = MCHBAR32(C0DRC0);
1363 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001364 reg32 &= ~((1 << 13) | (1 << 12));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001365 MCHBAR32(C0DRC0) = reg32;
1366
1367 reg32 = MCHBAR32(C1DRC0);
1368 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001369 reg32 &= ~((1 << 13) | (1 << 12));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001370 MCHBAR32(C1DRC0) = reg32;
1371
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001372 if (!sysinfo->dual_channel && sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001373 reg32 = MCHBAR32(C0DRC0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001374 reg32 |= (1 << 15);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001375 MCHBAR32(C0DRC0) = reg32;
1376 }
1377
1378 sdram_program_refresh_rate(sysinfo);
1379
1380 sdram_program_cke_tristate(sysinfo);
1381
1382 sdram_program_odt_tristate(sysinfo);
1383
1384 /* Calculate DRT0 */
1385
1386 temp_drt = 0;
1387
1388 /* B2B Write Precharge (same bank) = CL-1 + BL/2 + tWR */
1389 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + sysinfo->twr;
1390 temp_drt |= (reg32 << 28);
1391
1392 /* Write Auto Precharge (same bank) = CL-1 + BL/2 + tWR + tRP */
1393 reg32 += sysinfo->trp;
1394 temp_drt |= (reg32 << 4);
1395
Arthur Heymans70a8e342017-03-09 11:30:23 +01001396 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001397 tWTR = 3; /* 667MHz */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001398 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001399 tWTR = 2; /* 400 and 533 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001400
1401 /* B2B Write to Read Command Spacing */
1402 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + tWTR;
1403 temp_drt |= (reg32 << 24);
1404
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001405 /* CxDRT0 [23:22], [21:20], [19:18] [16] have fixed values */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001406 temp_drt |= ((1 << 22) | (3 << 20) | (1 << 18) | (0 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001407
Arthur Heymans25027232017-02-12 23:34:39 +01001408 /*
1409 * tRD is the delay the memory controller is waiting on the FSB,
1410 * in mclk domain.
1411 * This parameter is important for stability and performance.
1412 * Those values might not be optimal but seem stable.
1413 */
1414 tRD_min = sysinfo->cas;
Arthur Heymanse1897612016-10-15 23:29:18 +02001415 switch (sysinfo->fsb_frequency) {
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001416 case 533:
Arthur Heymanse1897612016-10-15 23:29:18 +02001417 break;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001418 case 667:
1419 tRD_min += 1;
Arthur Heymanse1897612016-10-15 23:29:18 +02001420 break;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001421 case 800:
1422 tRD_min += 2;
1423 break;
1424 case 1066:
1425 tRD_min += 3;
Arthur Heymanse1897612016-10-15 23:29:18 +02001426 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001427 }
Arthur Heymanse1897612016-10-15 23:29:18 +02001428
Arthur Heymans25027232017-02-12 23:34:39 +01001429 temp_drt |= (tRD_min << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001430
1431 /* Read Auto Precharge to Activate */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001432
Stefan Reinauer278534d2008-10-29 04:51:07 +00001433 temp_drt |= (8 << 0);
1434
1435 MCHBAR32(C0DRT0) = temp_drt;
1436 MCHBAR32(C1DRT0) = temp_drt;
1437
1438 /* Calculate DRT1 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001439
Stefan Reinauer278534d2008-10-29 04:51:07 +00001440 temp_drt = MCHBAR32(C0DRT1) & 0x00020088;
1441
1442 /* DRAM RASB Precharge */
1443 temp_drt |= (sysinfo->trp - 2) << 0;
1444
1445 /* DRAM RASB to CASB Delay */
1446 temp_drt |= (sysinfo->trcd - 2) << 4;
1447
1448 /* CASB Latency */
1449 temp_drt |= (cas_table[sysinfo->cas - 3]) << 8;
1450
1451 /* Refresh Cycle Time */
1452 temp_drt |= (sysinfo->trfc) << 10;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001453
Stefan Reinauer278534d2008-10-29 04:51:07 +00001454 /* Pre-All to Activate Delay */
1455 temp_drt |= (0 << 16);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001456
Stefan Reinauer278534d2008-10-29 04:51:07 +00001457 /* Precharge to Precharge Delay stays at 1 clock */
1458 temp_drt |= (0 << 18);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001459
Stefan Reinauer278534d2008-10-29 04:51:07 +00001460 /* Activate to Precharge Delay */
1461 temp_drt |= (sysinfo->tras << 19);
1462
1463 /* Read to Precharge (tRTP) */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001464 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001465 temp_drt |= (1 << 28);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001466 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001467 temp_drt |= (0 << 28);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001468
1469 /* Determine page size */
1470 reg32 = 0;
1471 page_size = 1; /* Default: 1k pagesize */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001472 for (i = 0; i < 2*DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001473 if (sysinfo->dimm[i] == SYSINFO_DIMM_X16DS ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001474 sysinfo->dimm[i] == SYSINFO_DIMM_X16SS)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001475 page_size = 2; /* 2k pagesize */
1476 }
1477
Arthur Heymans70a8e342017-03-09 11:30:23 +01001478 if (sysinfo->memory_frequency == 533 && page_size == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001479 reg32 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001480 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001481 reg32 = page_size;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001482
Stefan Reinauer278534d2008-10-29 04:51:07 +00001483 temp_drt |= (reg32 << 30);
1484
1485 MCHBAR32(C0DRT1) = temp_drt;
1486 MCHBAR32(C1DRT1) = temp_drt;
1487
1488 /* Program DRT2 */
1489 reg32 = MCHBAR32(C0DRT2);
1490 reg32 &= ~(1 << 8);
1491 MCHBAR32(C0DRT2) = reg32;
1492
1493 reg32 = MCHBAR32(C1DRT2);
1494 reg32 &= ~(1 << 8);
1495 MCHBAR32(C1DRT2) = reg32;
1496
1497 /* Calculate DRT3 */
1498 temp_drt = MCHBAR32(C0DRT3) & ~0x07ffffff;
1499
1500 /* Get old tRFC value */
1501 reg32 = MCHBAR32(C0DRT1) >> 10;
1502 reg32 &= 0x3f;
1503
1504 /* 788nS - tRFC */
1505 switch (sysinfo->memory_frequency) {
1506 case 400: /* 5nS */
1507 reg32 = ((78800 / 500) - reg32) & 0x1ff;
1508 reg32 |= (0x8c << 16) | (0x0c << 10); /* 1 us */
1509 break;
1510 case 533: /* 3.75nS */
1511 reg32 = ((78800 / 375) - reg32) & 0x1ff;
1512 reg32 |= (0xba << 16) | (0x10 << 10); /* 1 us */
1513 break;
1514 case 667: /* 3nS */
1515 reg32 = ((78800 / 300) - reg32) & 0x1ff;
1516 reg32 |= (0xe9 << 16) | (0x14 << 10); /* 1 us */
1517 break;
1518 }
1519
1520 temp_drt |= reg32;
1521
1522 MCHBAR32(C0DRT3) = temp_drt;
1523 MCHBAR32(C1DRT3) = temp_drt;
1524}
1525
1526static void sdram_set_channel_mode(struct sys_info *sysinfo)
1527{
1528 u32 reg32;
1529
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001530 printk(BIOS_DEBUG, "Setting mode of operation for memory channels...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001531
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001532 if (sdram_capabilities_interleave() &&
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001533 ((sysinfo->banksize[0] + sysinfo->banksize[1] +
1534 sysinfo->banksize[2] + sysinfo->banksize[3]) ==
1535 (sysinfo->banksize[4] + sysinfo->banksize[5] +
1536 sysinfo->banksize[6] + sysinfo->banksize[7]))) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001537 /* Both channels equipped with DIMMs of the same size */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001538 sysinfo->interleaved = 1;
1539 } else {
1540 sysinfo->interleaved = 0;
1541 }
1542
1543 reg32 = MCHBAR32(DCC);
1544 reg32 &= ~(7 << 0);
1545
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001546 if (sysinfo->interleaved) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001547 /* Dual Channel Interleaved */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001548 printk(BIOS_DEBUG, "Dual Channel Interleaved.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001549 reg32 |= (1 << 1);
1550 } else if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001551 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001552 /* Channel 1 only */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001553 printk(BIOS_DEBUG, "Single Channel 1 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001554 reg32 |= (1 << 2);
Elyes HAOUAS75da1fb2017-02-16 18:59:13 +01001555 } else if (sdram_capabilities_dual_channel() &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001556 (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1557 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) {
Martin Roth128c1042016-11-18 09:29:03 -07001558 /* Dual Channel Asymmetric */
1559 printk(BIOS_DEBUG, "Dual Channel Asymmetric.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001560 reg32 |= (1 << 0);
1561 } else {
1562 /* All bits 0 means Single Channel 0 operation */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001563 printk(BIOS_DEBUG, "Single Channel 0 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001564 }
1565
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001566 /* Now disable channel XORing */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001567 reg32 |= (1 << 10);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001568
1569 MCHBAR32(DCC) = reg32;
1570
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001571 PRINTK_DEBUG("DCC = 0x%08x\n", MCHBAR32(DCC));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001572}
1573
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001574static void sdram_program_pll_settings(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001575{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001576 MCHBAR32(PLLMON) = 0x80800000;
1577
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001578 sysinfo->fsb_frequency = fsbclk();
Peter Stuge76d91432010-10-01 10:02:33 +00001579 if (sysinfo->fsb_frequency == 0xffff)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001580 die("Unsupported FSB speed");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001581
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001582 /* Program CPCTL according to FSB speed */
1583 /* Only write the lower byte */
1584 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001585 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001586 MCHBAR8(CPCTL) = 0x90;
1587 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001588 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001589 MCHBAR8(CPCTL) = 0x95;
1590 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001591 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001592 MCHBAR8(CPCTL) = 0x8d;
1593 break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001594 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001595
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001596 MCHBAR16(CPCTL) &= ~(1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001597
Paul Menzel0ce5ebf2013-10-21 21:22:09 +02001598 MCHBAR16(CPCTL); /* Read back register to activate settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001599}
1600
1601static void sdram_program_graphics_frequency(struct sys_info *sysinfo)
1602{
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001603 u8 reg8;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001604 u8 freq, second_vco, voltage;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001605
1606#define CRCLK_166MHz 0x00
1607#define CRCLK_200MHz 0x01
1608#define CRCLK_250MHz 0x03
1609#define CRCLK_400MHz 0x05
1610
1611#define CDCLK_200MHz 0x00
1612#define CDCLK_320MHz 0x40
1613
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001614#define VOLTAGE_1_05 0x00
1615#define VOLTAGE_1_50 0x01
1616
Paul Menzeldaf9e502014-07-15 23:49:16 +02001617 printk(BIOS_DEBUG, "Setting Graphics Frequency...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001618
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001619 printk(BIOS_DEBUG, "FSB: %d MHz ", sysinfo->fsb_frequency);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001620
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001621 voltage = VOLTAGE_1_05;
1622 if (MCHBAR32(DFT_STRAP1) & (1 << 20))
1623 voltage = VOLTAGE_1_50;
Angel Pons30492572020-06-11 13:24:54 +02001624 printk(BIOS_DEBUG, "Voltage: %s ", (voltage == VOLTAGE_1_05) ? "1.05V" : "1.5V");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001625
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001626 /* Gate graphics hardware for frequency change */
Angel Pons30492572020-06-11 13:24:54 +02001627 reg8 = (1 << 3) | (1 << 1); /* disable crclk, gate cdclk */
Angel Pons3580d812020-06-11 14:13:33 +02001628 pci_write_config8(IGD_DEV, GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001629
1630 /* Get graphics frequency capabilities */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001631 reg8 = sdram_capabilities_core_frequencies();
1632
Stefan Reinauer278534d2008-10-29 04:51:07 +00001633 freq = CRCLK_250MHz;
1634 switch (reg8) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001635 case GFX_FREQUENCY_CAP_ALL:
1636 if (voltage == VOLTAGE_1_05)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001637 freq = CRCLK_250MHz;
1638 else
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001639 freq = CRCLK_400MHz; /* 1.5V requires 400MHz */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001640 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001641 case GFX_FREQUENCY_CAP_250MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001642 freq = CRCLK_250MHz;
1643 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001644 case GFX_FREQUENCY_CAP_200MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001645 freq = CRCLK_200MHz;
1646 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001647 case GFX_FREQUENCY_CAP_166MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001648 freq = CRCLK_166MHz;
1649 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001650 }
1651
1652 if (freq != CRCLK_400MHz) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001653 /* What chipset are we? Force 166MHz for GMS */
Angel Pons3580d812020-06-11 14:13:33 +02001654 reg8 = (pci_read_config8(HOST_BRIDGE, 0xe7) & 0x70) >> 4;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001655 if (reg8 == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001656 freq = CRCLK_166MHz;
1657 }
1658
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001659 printk(BIOS_DEBUG, "Render: ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001660 switch (freq) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001661 case CRCLK_166MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001662 printk(BIOS_DEBUG, "166MHz");
1663 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001664 case CRCLK_200MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001665 printk(BIOS_DEBUG, "200MHz");
1666 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001667 case CRCLK_250MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001668 printk(BIOS_DEBUG, "250MHz");
1669 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001670 case CRCLK_400MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001671 printk(BIOS_DEBUG, "400MHz");
1672 break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001673 }
1674
Arthur Heymans70a8e342017-03-09 11:30:23 +01001675 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001676 sysinfo->mvco4x = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001677 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001678 sysinfo->mvco4x = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001679
Stefan Reinauer278534d2008-10-29 04:51:07 +00001680 second_vco = 0;
1681
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001682 if (voltage == VOLTAGE_1_50) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001683 second_vco = 1;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001684 } else if ((i945_silicon_revision() > 0) && (freq == CRCLK_250MHz)) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001685 u16 mem = sysinfo->memory_frequency;
1686 u16 fsb = sysinfo->fsb_frequency;
1687
Arthur Heymans70a8e342017-03-09 11:30:23 +01001688 if ((fsb == 667 && mem == 533) ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001689 (fsb == 533 && mem == 533) ||
1690 (fsb == 533 && mem == 400)) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001691 second_vco = 1;
1692 }
1693
1694 if (fsb == 667 && mem == 533)
1695 sysinfo->mvco4x = 1;
1696 }
1697
Arthur Heymans70a8e342017-03-09 11:30:23 +01001698 if (second_vco)
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001699 sysinfo->clkcfg_bit7 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001700 else
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001701 sysinfo->clkcfg_bit7 = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001702
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001703 /* Graphics Core Render Clock */
Angel Pons3580d812020-06-11 14:13:33 +02001704 pci_update_config16(IGD_DEV, GCFC, ~((7 << 0) | (1 << 13)), freq);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001705
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001706 /* Graphics Core Display Clock */
Angel Pons3580d812020-06-11 14:13:33 +02001707 reg8 = pci_read_config8(IGD_DEV, GCFC);
Angel Ponse3c68d22020-06-08 12:09:03 +02001708 reg8 &= ~((1 << 7) | (7 << 4));
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001709
1710 if (voltage == VOLTAGE_1_05) {
1711 reg8 |= CDCLK_200MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001712 printk(BIOS_DEBUG, " Display: 200MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001713 } else {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001714 reg8 |= CDCLK_320MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001715 printk(BIOS_DEBUG, " Display: 320MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001716 }
Angel Pons3580d812020-06-11 14:13:33 +02001717 pci_write_config8(IGD_DEV, GCFC, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001718
Angel Pons3580d812020-06-11 14:13:33 +02001719 reg8 = pci_read_config8(IGD_DEV, GCFC + 1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001720
Angel Ponse3c68d22020-06-08 12:09:03 +02001721 reg8 |= (1 << 3) | (1 << 1);
Angel Pons3580d812020-06-11 14:13:33 +02001722 pci_write_config8(IGD_DEV, GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001723
1724 reg8 |= 0x0f;
Angel Pons3580d812020-06-11 14:13:33 +02001725 pci_write_config8(IGD_DEV, GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001726
1727 /* Ungate core render and display clocks */
1728 reg8 &= 0xf0;
Angel Pons3580d812020-06-11 14:13:33 +02001729 pci_write_config8(IGD_DEV, GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001730}
1731
1732static void sdram_program_memory_frequency(struct sys_info *sysinfo)
1733{
1734 u32 clkcfg;
Julius Wernercd49cce2019-03-05 16:53:33 -08001735 u8 offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001736
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001737 printk(BIOS_DEBUG, "Setting Memory Frequency... ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001738
Stefan Reinauer278534d2008-10-29 04:51:07 +00001739 clkcfg = MCHBAR32(CLKCFG);
1740
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001741 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001742
Arthur Heymans70a8e342017-03-09 11:30:23 +01001743 clkcfg &= ~((1 << 12) | (1 << 7) | (7 << 4));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001744
1745 if (sysinfo->mvco4x) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001746 printk(BIOS_DEBUG, "MVCO 4x, ");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001747 clkcfg &= ~(1 << 12);
1748 }
1749
1750 if (sysinfo->clkcfg_bit7) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001751 printk(BIOS_DEBUG, "second VCO, ");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001752 clkcfg |= (1 << 7);
1753 }
1754
1755 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001756 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001757 clkcfg |= ((1 + offset) << 4);
1758 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001759 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001760 clkcfg |= ((2 + offset) << 4);
1761 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001762 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001763 clkcfg |= ((3 + offset) << 4);
1764 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001765 default:
1766 die("Target Memory Frequency Error");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001767 }
1768
1769 if (MCHBAR32(CLKCFG) == clkcfg) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001770 printk(BIOS_DEBUG, "ok (unchanged)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001771 return;
1772 }
1773
1774 MCHBAR32(CLKCFG) = clkcfg;
1775
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001776 /* Make sure the following code is in the cache before we execute it. */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001777 goto cache_code;
1778vco_update:
Angel Ponse3c68d22020-06-08 12:09:03 +02001779 pci_and_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, (u8)~(1 << 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001780
Stefan Reinauer278534d2008-10-29 04:51:07 +00001781 clkcfg &= ~(1 << 10);
1782 MCHBAR32(CLKCFG) = clkcfg;
1783 clkcfg |= (1 << 10);
1784 MCHBAR32(CLKCFG) = clkcfg;
1785
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001786 asm volatile (
Stefan Reinauer278534d2008-10-29 04:51:07 +00001787 " movl $0x100, %%ecx\n"
1788 "delay_update:\n"
1789 " nop\n"
1790 " nop\n"
1791 " nop\n"
1792 " nop\n"
1793 " loop delay_update\n"
1794 : /* No outputs */
1795 : /* No inputs */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001796 : "%ecx", "memory"
Stefan Reinauer278534d2008-10-29 04:51:07 +00001797 );
1798
Stefan Reinauer278534d2008-10-29 04:51:07 +00001799 clkcfg &= ~(1 << 10);
1800 MCHBAR32(CLKCFG) = clkcfg;
1801
1802 goto out;
1803cache_code:
1804 goto vco_update;
1805out:
1806
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001807 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", MCHBAR32(CLKCFG));
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001808 printk(BIOS_DEBUG, "ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001809}
1810
1811static void sdram_program_clock_crossing(void)
1812{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001813 int idx = 0;
1814
1815 /**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001816 * We add the indices according to our clocks from CLKCFG.
Stefan Reinauer278534d2008-10-29 04:51:07 +00001817 */
Julius Wernercd49cce2019-03-05 16:53:33 -08001818#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001819 static const u32 data_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001820 0x00100401, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001821 0xffffffff, 0xffffffff, /* nonexistent */
1822 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001823
Stefan Reinauer278534d2008-10-29 04:51:07 +00001824 0x08040120, 0x00000000, /* DDR400 FSB533 */
1825 0x00100401, 0x00000000, /* DDR533 FSB533 */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001826 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001827
1828 0x04020120, 0x00000010, /* DDR400 FSB667 */
1829 0x10040280, 0x00000040, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001830 0x00100401, 0x00000000, /* DDR667 FSB667 */
1831
Martin Roth2ed0aa22016-01-05 20:58:58 -07001832 0xffffffff, 0xffffffff, /* nonexistent */
1833 0xffffffff, 0xffffffff, /* nonexistent */
1834 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001835
Martin Roth2ed0aa22016-01-05 20:58:58 -07001836 0xffffffff, 0xffffffff, /* nonexistent */
1837 0xffffffff, 0xffffffff, /* nonexistent */
1838 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001839 };
1840
1841 static const u32 command_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001842 0x04020208, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001843 0xffffffff, 0xffffffff, /* nonexistent */
1844 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001845
Stefan Reinauer278534d2008-10-29 04:51:07 +00001846 0x00060108, 0x00000000, /* DDR400 FSB533 */
1847 0x04020108, 0x00000000, /* DDR533 FSB533 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001848 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001849
1850 0x00040318, 0x00000000, /* DDR400 FSB667 */
1851 0x04020118, 0x00000000, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001852 0x02010804, 0x00000000, /* DDR667 FSB667 */
1853
Martin Roth2ed0aa22016-01-05 20:58:58 -07001854 0xffffffff, 0xffffffff, /* nonexistent */
1855 0xffffffff, 0xffffffff, /* nonexistent */
1856 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001857
Martin Roth2ed0aa22016-01-05 20:58:58 -07001858 0xffffffff, 0xffffffff, /* nonexistent */
1859 0xffffffff, 0xffffffff, /* nonexistent */
1860 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001861 };
1862
Julius Wernercd49cce2019-03-05 16:53:33 -08001863#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001864 /* i945 G/P */
1865 static const u32 data_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001866 0xffffffff, 0xffffffff, /* nonexistent */
1867 0xffffffff, 0xffffffff, /* nonexistent */
1868 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001869
1870 0x10080201, 0x00000000, /* DDR400 FSB533 */
1871 0x00100401, 0x00000000, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001872 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001873
Martin Roth2ed0aa22016-01-05 20:58:58 -07001874 0xffffffff, 0xffffffff, /* nonexistent */
1875 0xffffffff, 0xffffffff, /* nonexistent */
1876 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001877
1878 0x04020108, 0x00000000, /* DDR400 FSB800 */
1879 0x00020108, 0x00000000, /* DDR533 FSB800 */
1880 0x00080201, 0x00000000, /* DDR667 FSB800 */
1881
1882 0x00010402, 0x00000000, /* DDR400 FSB1066 */
1883 0x04020108, 0x00000000, /* DDR533 FSB1066 */
1884 0x08040110, 0x00000000, /* DDR667 FSB1066 */
1885 };
1886
1887 static const u32 command_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001888 0xffffffff, 0xffffffff, /* nonexistent */
1889 0xffffffff, 0xffffffff, /* nonexistent */
1890 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001891
1892 0x00010800, 0x00000402, /* DDR400 FSB533 */
1893 0x01000400, 0x00000200, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001894 0x00020904, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001895
Martin Roth2ed0aa22016-01-05 20:58:58 -07001896 0xffffffff, 0xffffffff, /* nonexistent */
1897 0xffffffff, 0xffffffff, /* nonexistent */
1898 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001899
1900 0x02010804, 0x00000000, /* DDR400 FSB800 */
1901 0x00010402, 0x00000000, /* DDR533 FSB800 */
Arthur Heymans8b6df622016-10-16 10:58:01 +02001902 0x04020130, 0x00000008, /* DDR667 FSB800 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001903
1904 0x00020904, 0x00000000, /* DDR400 FSB1066 */
1905 0x02010804, 0x00000000, /* DDR533 FSB1066 */
1906 0x180601c0, 0x00000020, /* DDR667 FSB1066 */
1907 };
1908#endif
1909
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001910 printk(BIOS_DEBUG, "Programming Clock Crossing...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001911
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001912 printk(BIOS_DEBUG, "MEM=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001913 switch (memclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001914 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001915 printk(BIOS_DEBUG, "400");
1916 idx += 0;
1917 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001918 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001919 printk(BIOS_DEBUG, "533");
1920 idx += 2;
1921 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001922 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001923 printk(BIOS_DEBUG, "667");
1924 idx += 4;
1925 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001926 default:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001927 printk(BIOS_DEBUG, "RSVD %x", memclk());
1928 return;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001929 }
1930
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001931 printk(BIOS_DEBUG, " FSB=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001932 switch (fsbclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001933 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001934 printk(BIOS_DEBUG, "400");
1935 idx += 0;
1936 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001937 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001938 printk(BIOS_DEBUG, "533");
1939 idx += 6;
1940 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001941 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001942 printk(BIOS_DEBUG, "667");
1943 idx += 12;
1944 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001945 case 800:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001946 printk(BIOS_DEBUG, "800");
1947 idx += 18;
1948 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001949 case 1066:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001950 printk(BIOS_DEBUG, "1066");
1951 idx += 24;
1952 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001953 default:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001954 printk(BIOS_DEBUG, "RSVD %x\n", fsbclk());
1955 return;
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001956 }
1957
Arthur Heymans70a8e342017-03-09 11:30:23 +01001958 if (command_clock_crossing[idx] == 0xffffffff)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001959 printk(BIOS_DEBUG, "Invalid MEM/FSB combination!\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001960
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001961 MCHBAR32(CCCFT + 0) = command_clock_crossing[idx];
1962 MCHBAR32(CCCFT + 4) = command_clock_crossing[idx + 1];
1963
Stefan Reinauer278534d2008-10-29 04:51:07 +00001964 MCHBAR32(C0DCCFT + 0) = data_clock_crossing[idx];
1965 MCHBAR32(C0DCCFT + 4) = data_clock_crossing[idx + 1];
1966 MCHBAR32(C1DCCFT + 0) = data_clock_crossing[idx];
1967 MCHBAR32(C1DCCFT + 4) = data_clock_crossing[idx + 1];
1968
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001969 printk(BIOS_DEBUG, "... ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001970}
1971
1972static void sdram_disable_fast_dispatch(void)
1973{
1974 u32 reg32;
1975
1976 reg32 = MCHBAR32(FSBPMC3);
1977 reg32 |= (1 << 1);
1978 MCHBAR32(FSBPMC3) = reg32;
1979
1980 reg32 = MCHBAR32(SBTEST);
1981 reg32 |= (3 << 1);
1982 MCHBAR32(SBTEST) = reg32;
1983}
1984
1985static void sdram_pre_jedec_initialization(void)
1986{
1987 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001988
Stefan Reinauer278534d2008-10-29 04:51:07 +00001989 reg32 = MCHBAR32(WCC);
1990 reg32 &= 0x113ff3ff;
1991 reg32 |= (4 << 29) | (3 << 25) | (1 << 10);
1992 MCHBAR32(WCC) = reg32;
1993
1994 MCHBAR32(SMVREFC) |= (1 << 6);
1995
1996 MCHBAR32(MMARB0) &= ~(3 << 17);
1997 MCHBAR32(MMARB0) |= (1 << 21) | (1 << 16);
1998
1999 MCHBAR32(MMARB1) &= ~(7 << 8);
2000 MCHBAR32(MMARB1) |= (3 << 8);
2001
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002002 /* Adaptive Idle Timer Control */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002003 MCHBAR32(C0AIT) = 0x000006c4;
2004 MCHBAR32(C0AIT+4) = 0x871a066d;
2005
2006 MCHBAR32(C1AIT) = 0x000006c4;
2007 MCHBAR32(C1AIT+4) = 0x871a066d;
2008}
2009
2010#define EA_DUALCHANNEL_XOR_BANK_RANK_MODE (0xd4 << 24)
2011#define EA_DUALCHANNEL_XOR_BANK_MODE (0xf4 << 24)
2012#define EA_DUALCHANNEL_BANK_RANK_MODE (0xc2 << 24)
2013#define EA_DUALCHANNEL_BANK_MODE (0xe2 << 24)
2014#define EA_SINGLECHANNEL_XOR_BANK_RANK_MODE (0x91 << 24)
2015#define EA_SINGLECHANNEL_XOR_BANK_MODE (0xb1 << 24)
2016#define EA_SINGLECHANNEL_BANK_RANK_MODE (0x80 << 24)
2017#define EA_SINGLECHANNEL_BANK_MODE (0xa0 << 24)
2018
2019static void sdram_enhanced_addressing_mode(struct sys_info *sysinfo)
2020{
2021 u32 chan0 = 0, chan1 = 0;
Paul Menzeld789b6582020-03-14 11:50:34 +01002022 bool chan0_dualsided, chan1_dualsided, chan0_populated, chan1_populated;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002023
Paul Menzel842dd332020-03-14 10:37:40 +01002024 chan0_populated = (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002025 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED);
Elyes HAOUAS308aeff2017-02-24 12:53:07 +01002026 chan1_populated = (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002027 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002028 chan0_dualsided = (sysinfo->banksize[1] || sysinfo->banksize[3]);
2029 chan1_dualsided = (sysinfo->banksize[5] || sysinfo->banksize[7]);
2030
2031 if (sdram_capabilities_enhanced_addressing_xor()) {
2032 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002033 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002034 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002035 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002036 chan0 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002037 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002038 chan0 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002039 }
2040 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002041 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002042 chan1 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002043 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002044 chan1 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002045 }
2046 } else {
2047 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002048 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002049 chan0 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002050 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002051 chan0 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002052
Arthur Heymans70a8e342017-03-09 11:30:23 +01002053 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002054 chan1 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002055 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002056 chan1 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002057 }
2058 } else {
2059 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002060 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002061 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002062 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002063 chan0 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002064 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002065 chan0 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002066 }
2067 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002068 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002069 chan1 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002070 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002071 chan1 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002072 }
2073 } else {
2074 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002075 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002076 chan0 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002077 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002078 chan0 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002079
Arthur Heymans70a8e342017-03-09 11:30:23 +01002080 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002081 chan1 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002082 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002083 chan1 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002084 }
2085 }
2086
2087 MCHBAR32(C0DRC1) &= 0x00ffffff;
2088 MCHBAR32(C0DRC1) |= chan0;
2089 MCHBAR32(C1DRC1) &= 0x00ffffff;
2090 MCHBAR32(C1DRC1) |= chan1;
2091}
2092
2093static void sdram_post_jedec_initialization(struct sys_info *sysinfo)
2094{
2095 u32 reg32;
2096
2097 /* Enable Channel XORing for Dual Channel Interleave */
2098 if (sysinfo->interleaved) {
2099 reg32 = MCHBAR32(DCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002100 reg32 &= ~(1 << 10);
Stefan Reinauer30140a52009-03-11 16:20:39 +00002101 reg32 |= (1 << 9);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002102 MCHBAR32(DCC) = reg32;
2103 }
2104
2105 /* DRAM mode optimizations */
2106 sdram_enhanced_addressing_mode(sysinfo);
2107
2108 reg32 = MCHBAR32(FSBPMC3);
2109 reg32 &= ~(1 << 1);
2110 MCHBAR32(FSBPMC3) = reg32;
2111
2112 reg32 = MCHBAR32(SBTEST);
2113 reg32 &= ~(1 << 2);
2114 MCHBAR32(SBTEST) = reg32;
2115
2116 reg32 = MCHBAR32(SBOCC);
2117 reg32 &= 0xffbdb6ff;
2118 reg32 |= (0xbdb6 << 8) | (1 << 0);
2119 MCHBAR32(SBOCC) = reg32;
2120}
2121
2122static void sdram_power_management(struct sys_info *sysinfo)
2123{
Stefan Reinauer278534d2008-10-29 04:51:07 +00002124 u16 reg16;
2125 u32 reg32;
2126 int integrated_graphics = 1;
2127 int i;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002128
Stefan Reinauer278534d2008-10-29 04:51:07 +00002129 reg32 = MCHBAR32(C0DRT2);
2130 reg32 &= 0xffffff00;
2131 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002132 reg32 |= (1 << 5) | (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002133 MCHBAR32(C0DRT2) = reg32;
2134
2135 reg32 = MCHBAR32(C1DRT2);
2136 reg32 &= 0xffffff00;
2137 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002138 reg32 |= (1 << 5) | (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002139 MCHBAR32(C1DRT2) = reg32;
2140
2141 reg32 = MCHBAR32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002142
2143 reg32 |= (1 << 12) | (1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002144 MCHBAR32(C0DRC1) = reg32;
2145
2146 reg32 = MCHBAR32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002147
2148 reg32 |= (1 << 12) | (1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002149 MCHBAR32(C1DRC1) = reg32;
2150
Julius Wernercd49cce2019-03-05 16:53:33 -08002151 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002152 if (i945_silicon_revision() > 1) {
2153 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2154 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002155
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002156 MCHBAR16(UPMC1) = 0x1010 | peg_bits;
2157 } else {
2158 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2159 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002160
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002161 /* Rev 0 and 1 */
2162 MCHBAR16(UPMC1) = 0x0010 | peg_bits;
2163 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002164 }
2165
2166 reg16 = MCHBAR16(UPMC2);
2167 reg16 &= 0xfc00;
2168 reg16 |= 0x0100;
2169 MCHBAR16(UPMC2) = reg16;
2170
2171 MCHBAR32(UPMC3) = 0x000f06ff;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002172
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002173 for (i = 0; i < 5; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002174 MCHBAR32(UPMC3) &= ~(1 << 16);
2175 MCHBAR32(UPMC3) |= (1 << 16);
2176 }
2177
2178 MCHBAR32(GIPMC1) = 0x8000000c;
2179
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002180 reg16 = MCHBAR16(CPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002181 reg16 &= ~(7 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002182 if (i945_silicon_revision() > 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002183 reg16 |= (6 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002184 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002185 reg16 |= (4 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002186 MCHBAR16(CPCTL) = reg16;
2187
Angel Pons3580d812020-06-11 14:13:33 +02002188#if 0
2189 if ((MCHBAR32(ECO) & (1 << 16)) != 0) {
2190#else
Stefan Reinauer30140a52009-03-11 16:20:39 +00002191 if (i945_silicon_revision() != 0) {
Angel Pons3580d812020-06-11 14:13:33 +02002192#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002193 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002194 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002195 MCHBAR32(HGIPMC2) = 0x0d590d59;
2196 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002197 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002198 MCHBAR32(HGIPMC2) = 0x155b155b;
2199 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002200 }
2201 } else {
2202 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002203 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002204 MCHBAR32(HGIPMC2) = 0x09c409c4;
2205 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002206 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002207 MCHBAR32(HGIPMC2) = 0x0fa00fa0;
2208 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002209 }
2210 }
2211
2212 MCHBAR32(FSBPMC1) = 0x8000000c;
2213
2214 reg32 = MCHBAR32(C2C3TT);
2215 reg32 &= 0xffff0000;
2216 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002217 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002218 reg32 |= 0x0600;
2219 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002220 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002221 reg32 |= 0x0480;
2222 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002223 }
2224 MCHBAR32(C2C3TT) = reg32;
2225
2226 reg32 = MCHBAR32(C3C4TT);
2227 reg32 &= 0xffff0000;
2228 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002229 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002230 reg32 |= 0x0b80;
2231 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002232 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002233 reg32 |= 0x0980;
2234 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002235 }
2236 MCHBAR32(C3C4TT) = reg32;
2237
Arthur Heymans70a8e342017-03-09 11:30:23 +01002238 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002239 MCHBAR32(ECO) &= ~(1 << 16);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002240 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002241 MCHBAR32(ECO) |= (1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002242
Stefan Reinauer278534d2008-10-29 04:51:07 +00002243 MCHBAR32(FSBPMC3) &= ~(1 << 29);
2244
2245 MCHBAR32(FSBPMC3) |= (1 << 21);
2246
2247 MCHBAR32(FSBPMC3) &= ~(1 << 19);
2248
2249 MCHBAR32(FSBPMC3) &= ~(1 << 13);
2250
2251 reg32 = MCHBAR32(FSBPMC4);
2252 reg32 &= ~(3 << 24);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002253 reg32 |= (2 << 24);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002254 MCHBAR32(FSBPMC4) = reg32;
2255
2256 MCHBAR32(FSBPMC4) |= (1 << 21);
2257
2258 MCHBAR32(FSBPMC4) |= (1 << 5);
2259
Arthur Heymans70a8e342017-03-09 11:30:23 +01002260 if ((i945_silicon_revision() < 2)) { /* || cpuid() = 0x6e8 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002261 /* stepping 0 and 1 or CPUID 6e8 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002262 MCHBAR32(FSBPMC4) &= ~(1 << 4);
2263 } else {
Stefan Reinauer30140a52009-03-11 16:20:39 +00002264 MCHBAR32(FSBPMC4) |= (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002265 }
2266
Angel Pons3580d812020-06-11 14:13:33 +02002267 pci_or_config8(HOST_BRIDGE, 0xfc, 1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002268
Angel Pons3580d812020-06-11 14:13:33 +02002269 pci_or_config8(IGD_DEV, 0xc1, 1 << 2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002270
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002271 if (integrated_graphics) {
2272 MCHBAR16(MIPMC4) = 0x04f8;
2273 MCHBAR16(MIPMC5) = 0x04fc;
2274 MCHBAR16(MIPMC6) = 0x04fc;
2275 } else {
2276 MCHBAR16(MIPMC4) = 0x64f8;
2277 MCHBAR16(MIPMC5) = 0x64fc;
2278 MCHBAR16(MIPMC6) = 0x64fc;
2279 }
2280
Stefan Reinauer278534d2008-10-29 04:51:07 +00002281 reg32 = MCHBAR32(PMCFG);
2282 reg32 &= ~(3 << 17);
2283 reg32 |= (2 << 17);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002284 MCHBAR32(PMCFG) = reg32;
2285
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002286 MCHBAR32(PMCFG) |= (1 << 4);
2287
Stefan Reinauer278534d2008-10-29 04:51:07 +00002288 reg32 = MCHBAR32(0xc30);
2289 reg32 &= 0xffffff00;
2290 reg32 |= 0x01;
2291 MCHBAR32(0xc30) = reg32;
2292
2293 MCHBAR32(0xb18) &= ~(1 << 21);
2294}
2295
2296static void sdram_thermal_management(void)
2297{
Stefan Reinauer278534d2008-10-29 04:51:07 +00002298
Stefan Reinauer278534d2008-10-29 04:51:07 +00002299 MCHBAR8(TCO1) = 0x00;
2300 MCHBAR8(TCO0) = 0x00;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002301
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002302 /* The Thermal Sensors for DIMMs at 0x50, 0x52 are at I2C addr 0x30/0x32. */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002303
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002304 /* TODO This is not implemented yet. Volunteers? */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002305}
2306
2307static void sdram_save_receive_enable(void)
2308{
2309 int i;
2310 u32 reg32;
2311 u8 values[4];
2312
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002313 /* The following values are stored to an unused CMOS area and restored instead of
2314 * recalculated in case of an S3 resume.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002315 *
Arthur Heymans70a8e342017-03-09 11:30:23 +01002316 * C0WL0REOST [7:0] -> 8 bit
2317 * C1WL0REOST [7:0] -> 8 bit
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002318 * RCVENMT [11:8] [3:0] -> 8 bit
2319 * C0DRT1 [27:24] -> 4 bit
2320 * C1DRT1 [27:24] -> 4 bit
2321 */
2322
2323 values[0] = MCHBAR8(C0WL0REOST);
2324 values[1] = MCHBAR8(C1WL0REOST);
2325
2326 reg32 = MCHBAR32(RCVENMT);
2327 values[2] = (u8)((reg32 >> (8 - 4)) & 0xf0) | (reg32 & 0x0f);
2328
2329 reg32 = MCHBAR32(C0DRT1);
2330 values[3] = (reg32 >> 24) & 0x0f;
2331 reg32 = MCHBAR32(C1DRT1);
2332 values[3] |= (reg32 >> (24 - 4)) & 0xf0;
2333
2334 /* coreboot only uses bytes 0 - 127 for its CMOS values so far
Edwin Beasanteb50c7d2010-07-06 21:05:04 +00002335 * so we grab bytes 128 - 131 to save the receive enable values
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002336 */
2337
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002338 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002339 cmos_write(values[i], 128 + i);
2340}
2341
2342static void sdram_recover_receive_enable(void)
2343{
2344 int i;
2345 u32 reg32;
2346 u8 values[4];
2347
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002348 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002349 values[i] = cmos_read(128 + i);
2350
2351 MCHBAR8(C0WL0REOST) = values[0];
2352 MCHBAR8(C1WL0REOST) = values[1];
2353
2354 reg32 = MCHBAR32(RCVENMT);
2355 reg32 &= ~((0x0f << 8) | (0x0f << 0));
2356 reg32 |= ((u32)(values[2] & 0xf0) << (8 - 4)) | (values[2] & 0x0f);
2357 MCHBAR32(RCVENMT) = reg32;
2358
2359 reg32 = MCHBAR32(C0DRT1) & ~(0x0f << 24);
2360 reg32 |= (u32)(values[3] & 0x0f) << 24;
2361 MCHBAR32(C0DRT1) = reg32;
2362
2363 reg32 = MCHBAR32(C1DRT1) & ~(0x0f << 24);
2364 reg32 |= (u32)(values[3] & 0xf0) << (24 - 4);
2365 MCHBAR32(C1DRT1) = reg32;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002366}
2367
Stefan Reinauer278534d2008-10-29 04:51:07 +00002368static void sdram_program_receive_enable(struct sys_info *sysinfo)
2369{
2370 MCHBAR32(REPC) |= (1 << 0);
2371
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002372 /* Program Receive Enable Timings */
2373 if (sysinfo->boot_path == BOOT_PATH_RESUME) {
2374 sdram_recover_receive_enable();
2375 } else {
2376 receive_enable_adjust(sysinfo);
2377 sdram_save_receive_enable();
2378 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002379
2380 MCHBAR32(C0DRC1) |= (1 << 6);
2381 MCHBAR32(C1DRC1) |= (1 << 6);
2382 MCHBAR32(C0DRC1) &= ~(1 << 6);
2383 MCHBAR32(C1DRC1) &= ~(1 << 6);
2384
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002385 MCHBAR32(MIPMC3) |= (0x0f << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002386}
2387
2388/**
2389 * @brief Enable On-Die Termination for DDR2.
2390 *
2391 */
2392
2393static void sdram_on_die_termination(struct sys_info *sysinfo)
2394{
2395 static const u32 odt[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002396 0x00024911, 0xe0010000,
2397 0x00049211, 0xe0020000,
2398 0x0006db11, 0xe0030000,
Stefan Reinauer278534d2008-10-29 04:51:07 +00002399 };
2400
2401 u32 reg32;
2402 int cas;
2403
2404 reg32 = MCHBAR32(ODTC);
2405 reg32 &= ~(3 << 16);
2406 reg32 |= (1 << 14) | (1 << 6) | (2 << 16);
2407 MCHBAR32(ODTC) = reg32;
2408
Paul Menzelb4d9f222020-03-14 10:34:29 +01002409 if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002410 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
Elyes HAOUAS38424982016-08-21 12:01:04 +02002411 printk(BIOS_DEBUG, "one dimm per channel config..\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002412
Stefan Reinauer278534d2008-10-29 04:51:07 +00002413 reg32 = MCHBAR32(C0ODT);
2414 reg32 &= ~(7 << 28);
2415 MCHBAR32(C0ODT) = reg32;
2416 reg32 = MCHBAR32(C1ODT);
2417 reg32 &= ~(7 << 28);
2418 MCHBAR32(C1ODT) = reg32;
2419 }
2420
2421 cas = sysinfo->cas;
2422
2423 reg32 = MCHBAR32(C0ODT) & 0xfff00000;
Angel Pons30492572020-06-11 13:24:54 +02002424 reg32 |= odt[(cas - 3) * 2];
Stefan Reinauer278534d2008-10-29 04:51:07 +00002425 MCHBAR32(C0ODT) = reg32;
2426
2427 reg32 = MCHBAR32(C1ODT) & 0xfff00000;
Angel Pons30492572020-06-11 13:24:54 +02002428 reg32 |= odt[(cas - 3) * 2];
Stefan Reinauer278534d2008-10-29 04:51:07 +00002429 MCHBAR32(C1ODT) = reg32;
2430
2431 reg32 = MCHBAR32(C0ODT + 4) & 0x1fc8ffff;
Angel Pons30492572020-06-11 13:24:54 +02002432 reg32 |= odt[((cas - 3) * 2) + 1];
Stefan Reinauer278534d2008-10-29 04:51:07 +00002433 MCHBAR32(C0ODT + 4) = reg32;
2434
2435 reg32 = MCHBAR32(C1ODT + 4) & 0x1fc8ffff;
Angel Pons30492572020-06-11 13:24:54 +02002436 reg32 |= odt[((cas - 3) * 2) + 1];
Stefan Reinauer278534d2008-10-29 04:51:07 +00002437 MCHBAR32(C1ODT + 4) = reg32;
2438}
2439
2440/**
2441 * @brief Enable clocks to populated sockets
2442 */
2443
2444static void sdram_enable_memory_clocks(struct sys_info *sysinfo)
2445{
2446 u8 clocks[2] = { 0, 0 };
2447
Julius Wernercd49cce2019-03-05 16:53:33 -08002448#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002449#define CLOCKS_WIDTH 2
Julius Wernercd49cce2019-03-05 16:53:33 -08002450#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002451#define CLOCKS_WIDTH 3
2452#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002453 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002454 clocks[0] |= (1 << CLOCKS_WIDTH) - 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002455
2456 if (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002457 clocks[0] |= ((1 << CLOCKS_WIDTH) - 1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002458
2459 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002460 clocks[1] |= (1 << CLOCKS_WIDTH) - 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002461
2462 if (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002463 clocks[1] |= ((1 << CLOCKS_WIDTH) - 1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002464
Julius Wernercd49cce2019-03-05 16:53:33 -08002465#if CONFIG(OVERRIDE_CLOCK_DISABLE)
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002466 /* Usually system firmware turns off system memory clock signals to unused SO-DIMM slots
2467 * to reduce EMI and power consumption.
2468 * However, the Kontron 986LCD-M does not like unused clock signals to be disabled.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002469 */
2470
2471 clocks[0] = 0xf; /* force all clock gate pairs to enable */
2472 clocks[1] = 0xf; /* force all clock gate pairs to enable */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002473#endif
2474
2475 MCHBAR8(C0DCLKDIS) = clocks[0];
2476 MCHBAR8(C1DCLKDIS) = clocks[1];
2477}
2478
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002479#define RTT_ODT_NONE 0
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002480#define RTT_ODT_50_OHM ((1 << 9) | (1 << 5))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002481#define RTT_ODT_75_OHM (1 << 5)
2482#define RTT_ODT_150_OHM (1 << 9)
2483
Arthur Heymans70a8e342017-03-09 11:30:23 +01002484#define EMRS_OCD_DEFAULT ((1 << 12) | (1 << 11) | (1 << 10))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002485
2486#define MRS_CAS_3 (3 << 7)
2487#define MRS_CAS_4 (4 << 7)
2488#define MRS_CAS_5 (5 << 7)
2489
2490#define MRS_TWR_3 (2 << 12)
2491#define MRS_TWR_4 (3 << 12)
2492#define MRS_TWR_5 (4 << 12)
2493
2494#define MRS_BT (1 << 6)
2495
2496#define MRS_BL4 (2 << 3)
2497#define MRS_BL8 (3 << 3)
2498
2499static void sdram_jedec_enable(struct sys_info *sysinfo)
2500{
2501 int i, nonzero;
2502 u32 bankaddr = 0, tmpaddr, mrsaddr = 0;
2503
2504 for (i = 0, nonzero = -1; i < 8; i++) {
Elyes HAOUAS01912202019-01-19 16:36:38 +01002505 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002506 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002507
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002508 printk(BIOS_DEBUG, "jedec enable sequence: bank %d\n", i);
Elyes HAOUAS01912202019-01-19 16:36:38 +01002509
2510 if (nonzero != -1) {
2511 if (sysinfo->interleaved && nonzero < 4 && i >= 4) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002512 bankaddr = 0x40;
Elyes HAOUAS01912202019-01-19 16:36:38 +01002513 } else {
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002514 printk(BIOS_DEBUG, "bankaddr from bank size of rank %d\n",
2515 nonzero);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002516 bankaddr += sysinfo->banksize[nonzero] <<
2517 (sysinfo->interleaved ? 26 : 25);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002518 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002519 }
2520
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002521 /*
2522 * We have a bank with a non-zero size... Remember it
Stefan Reinauer278534d2008-10-29 04:51:07 +00002523 * for the next offset we have to calculate
2524 */
2525 nonzero = i;
2526
2527 /* Get CAS latency set up */
2528 switch (sysinfo->cas) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002529 case 5:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002530 mrsaddr = MRS_CAS_5;
2531 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002532 case 4:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002533 mrsaddr = MRS_CAS_4;
2534 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002535 case 3:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002536 mrsaddr = MRS_CAS_3;
2537 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002538 default:
2539 die("Jedec Error (CAS).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002540 }
2541
2542 /* Get tWR set */
2543 switch (sysinfo->twr) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002544 case 5:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002545 mrsaddr |= MRS_TWR_5;
2546 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002547 case 4:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002548 mrsaddr |= MRS_TWR_4;
2549 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002550 case 3:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002551 mrsaddr |= MRS_TWR_3;
2552 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002553 default:
2554 die("Jedec Error (tWR).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002555 }
2556
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002557 /* Set "Burst Type" */
2558 mrsaddr |= MRS_BT;
2559
Stefan Reinauer278534d2008-10-29 04:51:07 +00002560 /* Interleaved */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002561 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002562 mrsaddr = mrsaddr << 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002563
2564 /* Only burst length 8 supported */
2565 mrsaddr |= MRS_BL8;
2566
2567 /* Apply NOP */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002568 PRINTK_DEBUG("Apply NOP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002569 do_ram_command(RAM_COMMAND_NOP);
2570 ram_read32(bankaddr);
2571
2572 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002573 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002574 do_ram_command(RAM_COMMAND_PRECHARGE);
2575 ram_read32(bankaddr);
2576
2577 /* Extended Mode Register Set (2) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002578 PRINTK_DEBUG("Extended Mode Register Set(2)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002579 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_2);
2580 ram_read32(bankaddr);
2581
2582 /* Extended Mode Register Set (3) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002583 PRINTK_DEBUG("Extended Mode Register Set(3)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002584 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_3);
2585 ram_read32(bankaddr);
2586
2587 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002588 PRINTK_DEBUG("Extended Mode Register Set\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002589 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2590 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002591 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002592 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002593 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002594 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002595 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002596 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002597 ram_read32(tmpaddr);
2598
2599 /* Mode Register Set: Reset DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002600 PRINTK_DEBUG("MRS: Reset DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002601 do_ram_command(RAM_COMMAND_MRS);
2602 tmpaddr = bankaddr;
2603 tmpaddr |= mrsaddr;
2604 /* Set DLL reset bit */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002605 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002606 tmpaddr |= (1 << 12);
2607 else
2608 tmpaddr |= (1 << 11);
2609 ram_read32(tmpaddr);
2610
2611 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002612 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002613 do_ram_command(RAM_COMMAND_PRECHARGE);
2614 ram_read32(bankaddr);
2615
2616 /* CAS before RAS Refresh */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002617 PRINTK_DEBUG("CAS before RAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002618 do_ram_command(RAM_COMMAND_CBR);
2619
2620 /* CBR wants two READs */
2621 ram_read32(bankaddr);
2622 ram_read32(bankaddr);
2623
2624 /* Mode Register Set: Enable DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002625 PRINTK_DEBUG("MRS: Enable DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002626 do_ram_command(RAM_COMMAND_MRS);
2627
2628 tmpaddr = bankaddr;
2629 tmpaddr |= mrsaddr;
2630 ram_read32(tmpaddr);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002631
Stefan Reinauer278534d2008-10-29 04:51:07 +00002632 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002633 PRINTK_DEBUG("Extended Mode Register Set: ODT/OCD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002634 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002635
Stefan Reinauer278534d2008-10-29 04:51:07 +00002636 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002637 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002638 tmpaddr |= RTT_ODT_75_OHM | EMRS_OCD_DEFAULT;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002639 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002640 tmpaddr |= ((RTT_ODT_150_OHM | EMRS_OCD_DEFAULT) << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002641 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002642 tmpaddr |= RTT_ODT_150_OHM | EMRS_OCD_DEFAULT;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002643 ram_read32(tmpaddr);
2644
2645 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002646 PRINTK_DEBUG("Extended Mode Register Set: OCD Exit\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002647 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2648
2649 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002650 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002651 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002652 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002653 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002654 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002655 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002656 ram_read32(tmpaddr);
2657 }
2658}
2659
2660static void sdram_init_complete(void)
2661{
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002662 PRINTK_DEBUG("Normal Operation\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002663 do_ram_command(RAM_COMMAND_NORMAL);
2664}
2665
2666static void sdram_setup_processor_side(void)
2667{
2668 if (i945_silicon_revision() == 0)
2669 MCHBAR32(FSBPMC3) |= (1 << 2);
2670
2671 MCHBAR8(0xb00) |= 1;
2672
2673 if (i945_silicon_revision() == 0)
2674 MCHBAR32(SLPCTL) |= (1 << 8);
2675}
2676
Stefan Reinauer278534d2008-10-29 04:51:07 +00002677/**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002678 * @param boot_path: 0 = normal, 1 = reset, 2 = resume from s3
Martin Rothf4cb4122015-01-06 10:27:39 -07002679 * @param spd_addresses pointer to a list of SPD addresses
Stefan Reinauer278534d2008-10-29 04:51:07 +00002680 */
Sven Schnelle541269b2011-02-21 09:39:17 +00002681void sdram_initialize(int boot_path, const u8 *spd_addresses)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002682{
2683 struct sys_info sysinfo;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002684
Patrick Georgi771328f2015-07-13 19:24:07 +02002685 timestamp_add_now(TS_BEFORE_INITRAM);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002686 printk(BIOS_DEBUG, "Setting up RAM controller.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002687
2688 memset(&sysinfo, 0, sizeof(sysinfo));
2689
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002690 sysinfo.boot_path = boot_path;
Sven Schnelle541269b2011-02-21 09:39:17 +00002691 sysinfo.spd_addresses = spd_addresses;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002692
Stefan Reinauer278534d2008-10-29 04:51:07 +00002693 /* Look at the type of DIMMs and verify all DIMMs are x8 or x16 width */
2694 sdram_get_dram_configuration(&sysinfo);
2695
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002696 /* If error, do cold boot */
2697 sdram_detect_errors(&sysinfo);
2698
Stefan Reinauer278534d2008-10-29 04:51:07 +00002699 /* Program PLL settings */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002700 sdram_program_pll_settings(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002701
Arthur Heymans18537812016-12-28 21:20:45 +01002702 /*
2703 * Program Graphics Frequency
2704 * Set core display and render clock on 945GC to the max
2705 */
Julius Wernercd49cce2019-03-05 16:53:33 -08002706 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM))
Arthur Heymans18537812016-12-28 21:20:45 +01002707 sdram_program_graphics_frequency(&sysinfo);
2708 else
Angel Pons3580d812020-06-11 14:13:33 +02002709 pci_write_config16(IGD_DEV, GCFC, 0x0534);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002710
2711 /* Program System Memory Frequency */
2712 sdram_program_memory_frequency(&sysinfo);
2713
2714 /* Determine Mode of Operation (Interleaved etc) */
2715 sdram_set_channel_mode(&sysinfo);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002716
Stefan Reinauer278534d2008-10-29 04:51:07 +00002717 /* Program Clock Crossing values */
2718 sdram_program_clock_crossing();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002719
Stefan Reinauer278534d2008-10-29 04:51:07 +00002720 /* Disable fast dispatch */
2721 sdram_disable_fast_dispatch();
2722
2723 /* Enable WIODLL Power Down in ACPI states */
2724 MCHBAR32(C0DMC) |= (1 << 24);
2725 MCHBAR32(C1DMC) |= (1 << 24);
2726
2727 /* Program DRAM Row Boundary/Attribute Registers */
2728
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002729 /* program row size DRB and set TOLUD */
2730 sdram_program_row_boundaries(&sysinfo);
2731
2732 /* program page size DRA */
2733 sdram_set_row_attributes(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002734
2735 /* Program CxBNKARC */
2736 sdram_set_bank_architecture(&sysinfo);
2737
2738 /* Program DRAM Timing and Control registers based on SPD */
2739 sdram_set_timing_and_control(&sysinfo);
2740
2741 /* On-Die Termination Adjustment */
2742 sdram_on_die_termination(&sysinfo);
2743
2744 /* Pre Jedec Initialization */
2745 sdram_pre_jedec_initialization();
2746
2747 /* Perform System Memory IO Initialization */
2748 sdram_initialize_system_memory_io(&sysinfo);
2749
2750 /* Perform System Memory IO Buffer Enable */
2751 sdram_enable_system_memory_io(&sysinfo);
2752
2753 /* Enable System Memory Clocks */
2754 sdram_enable_memory_clocks(&sysinfo);
2755
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002756 if (boot_path == BOOT_PATH_NORMAL) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002757 /* Jedec Initialization sequence */
2758 sdram_jedec_enable(&sysinfo);
2759 }
2760
2761 /* Program Power Management Registers */
2762 sdram_power_management(&sysinfo);
2763
2764 /* Post Jedec Init */
2765 sdram_post_jedec_initialization(&sysinfo);
2766
2767 /* Program DRAM Throttling */
2768 sdram_thermal_management();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002769
Stefan Reinauer278534d2008-10-29 04:51:07 +00002770 /* Normal Operations */
Stefan Reinaueraca6ec62009-10-26 17:12:21 +00002771 sdram_init_complete();
Stefan Reinauer278534d2008-10-29 04:51:07 +00002772
2773 /* Program Receive Enable Timings */
2774 sdram_program_receive_enable(&sysinfo);
2775
2776 /* Enable Periodic RCOMP */
2777 sdram_enable_rcomp();
2778
2779 /* Tell ICH7 that we're done */
Angel Ponse3c68d22020-06-08 12:09:03 +02002780 pci_and_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, (u8)~(1 << 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +00002781
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002782 printk(BIOS_DEBUG, "RAM initialization finished.\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002783
Stefan Reinauer278534d2008-10-29 04:51:07 +00002784 sdram_setup_processor_side();
Patrick Georgi771328f2015-07-13 19:24:07 +02002785 timestamp_add_now(TS_AFTER_INITRAM);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002786}