blob: 1c7a1f076966941b875d81921c40651e865a136b [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
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000140 reg32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 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
Arthur Heymans70a8e342017-03-09 11:30:23 +0100164 reg32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 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
Arthur Heymans70a8e342017-03-09 11:30:23 +0100180 reg32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 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
191 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
192 reg8 &= (1 << 7);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000193
Stefan Reinauer278534d2008-10-29 04:51:07 +0000194 return (!reg8);
195}
196
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100197/* TODO check if we ever need this function */
Stefan Reinauer53b0ea42010-03-22 11:50:52 +0000198#if 0
Stefan Reinauer278534d2008-10-29 04:51:07 +0000199static int sdram_capabilities_MEM4G_disable(void)
200{
201 u8 reg8;
202
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000203 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000204 reg8 &= (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000205
Stefan Reinauer278534d2008-10-29 04:51:07 +0000206 return (reg8 != 0);
207}
Stefan Reinauer53b0ea42010-03-22 11:50:52 +0000208#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +0000209
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000210#define GFX_FREQUENCY_CAP_166MHZ 0x04
211#define GFX_FREQUENCY_CAP_200MHZ 0x03
212#define GFX_FREQUENCY_CAP_250MHZ 0x02
213#define GFX_FREQUENCY_CAP_ALL 0x00
214
215static int sdram_capabilities_core_frequencies(void)
216{
217 u8 reg8;
218
219 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
220 reg8 &= (1 << 3) | (1 << 2) | (1 << 1);
221 reg8 >>= 1;
222
Arthur Heymans70a8e342017-03-09 11:30:23 +0100223 return reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000224}
225
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000226static void sdram_detect_errors(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000227{
228 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000229 u8 do_reset = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000230
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100231 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000232
Angel Pons30492572020-06-11 13:24:54 +0200233 if (reg8 & ((1 << 7) | (1 << 2))) {
234 if (reg8 & (1 << 2)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000235 printk(BIOS_DEBUG, "SLP S4# Assertion Width Violation.\n");
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000236 /* Write back clears bit 2 */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100237 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000238 do_reset = 1;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000239
Stefan Reinauer278534d2008-10-29 04:51:07 +0000240 }
241
Angel Pons30492572020-06-11 13:24:54 +0200242 if (reg8 & (1 << 7)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000243 printk(BIOS_DEBUG, "DRAM initialization was interrupted.\n");
Angel Pons30492572020-06-11 13:24:54 +0200244 reg8 &= ~(1 << 7);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100245 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000246 do_reset = 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000247 }
248
249 /* Set SLP_S3# Assertion Stretch Enable */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100250 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000251 reg8 |= (1 << 3);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100252 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000253
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000254 if (do_reset) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000255 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200256 full_reset();
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000257 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000258 }
259
260 /* Set DRAM initialization bit in ICH7 */
Angel Ponse3c68d22020-06-08 12:09:03 +0200261 pci_or_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, 1 << 7);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000262
Peter Stuge751508a2012-01-27 22:17:09 +0100263 /* clear self refresh status if check is disabled or not a resume */
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200264 if (!CONFIG(CHECK_SLFRCS_ON_RESUME) || sysinfo->boot_path != BOOT_PATH_RESUME) {
Patrick Georgi86a11102013-03-15 14:11:37 +0100265 MCHBAR8(SLFRCS) |= 3;
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000266 } else {
267 /* Validate self refresh config */
268 if (((sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED) ||
269 (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)) &&
Angel Pons30492572020-06-11 13:24:54 +0200270 !(MCHBAR8(SLFRCS) & (1 << 0))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000271 do_reset = 1;
272 }
273 if (((sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED) ||
274 (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) &&
Angel Pons30492572020-06-11 13:24:54 +0200275 !(MCHBAR8(SLFRCS) & (1 << 1))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000276 do_reset = 1;
277 }
278 }
279
280 if (do_reset) {
281 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200282 full_reset();
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000283 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000284}
Stefan Reinauer278534d2008-10-29 04:51:07 +0000285
Arthur Heymans0ab49042017-02-06 22:40:14 +0100286struct timings {
287 u32 min_tCLK_cas[8];
288 u32 min_tRAS;
289 u32 min_tRP;
290 u32 min_tRCD;
291 u32 min_tWR;
292 u32 min_tRFC;
293 u32 max_tRR;
294 u8 cas_mask;
295};
Stefan Reinauer278534d2008-10-29 04:51:07 +0000296
Arthur Heymans0ab49042017-02-06 22:40:14 +0100297/**
298 * @brief loop over dimms and save maximal timings
299 */
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200300static void gather_common_timing(struct sys_info *sysinfo, struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000301{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100302
303 int i, j;
304 u8 raw_spd[SPD_SIZE_MAX_DDR2];
305 u8 dimm_mask = 0;
306
307 memset(saved_timings, 0, sizeof(*saved_timings));
308 saved_timings->max_tRR = UINT32_MAX;
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200309 saved_timings->cas_mask = SPD_CAS_LATENCY_DDR2_3 | SPD_CAS_LATENCY_DDR2_4
310 | SPD_CAS_LATENCY_DDR2_5;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000311
312 /**
313 * i945 supports two DIMMs, in two configurations:
314 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000315 * - single channel with two DIMMs
316 * - dual channel with one DIMM per channel
Stefan Reinauer278534d2008-10-29 04:51:07 +0000317 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000318 * In practice dual channel mainboards have their SPD at 0x50/0x52
319 * whereas single channel configurations have their SPD at 0x50/0x51.
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000320 *
Stefan Reinauer278534d2008-10-29 04:51:07 +0000321 * The capability register knows a lot about the channel configuration
Uwe Hermannd773fd32010-11-20 20:23:08 +0000322 * but for now we stick with the information we gather via SPD.
Stefan Reinauer278534d2008-10-29 04:51:07 +0000323 */
324
Arthur Heymans0ab49042017-02-06 22:40:14 +0100325 printk(BIOS_DEBUG, "This mainboard supports ");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000326 if (sdram_capabilities_dual_channel()) {
327 sysinfo->dual_channel = 1;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100328 printk(BIOS_DEBUG, "Dual Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000329 } else {
330 sysinfo->dual_channel = 0;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100331 printk(BIOS_DEBUG, "only Single Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000332 }
333
Stefan Reinauer278534d2008-10-29 04:51:07 +0000334
Arthur Heymans70a8e342017-03-09 11:30:23 +0100335 for (i = 0; i < (2 * DIMM_SOCKETS); i++) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100336 int device = get_dimm_spd_address(sysinfo, i), bytes_read;
Arthur Heymansfc31e442018-02-12 15:12:34 +0100337 struct dimm_attr_ddr2_st dimm_info;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000338
339 /* Initialize the socket information with a sane value */
340 sysinfo->dimm[i] = SYSINFO_DIMM_NOT_POPULATED;
341
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000342 /* Dual Channel not supported, but Channel 1? Bail out */
343 if (!sdram_capabilities_dual_channel() && (i >> 1))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000344 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000345
Kyösti Mälkkibd659852020-01-05 20:00:18 +0200346 if (smbus_read_byte(device, SPD_MEMORY_TYPE) !=
Arthur Heymans0ab49042017-02-06 22:40:14 +0100347 SPD_MEMORY_TYPE_SDRAM_DDR2) {
348 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: N/A\n",
349 (i >> 1), (i & 1));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000350 continue;
351 }
352
Arthur Heymans0ab49042017-02-06 22:40:14 +0100353 /*
354 * spd_decode_ddr2() needs a 128-byte sized array but
355 * only the first 64 bytes contain data needed for raminit.
356 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000357
Kyösti Mälkkic01a5052019-01-30 09:39:23 +0200358 bytes_read = i2c_eeprom_read(device, 0, 64, raw_spd);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100359 printk(BIOS_DEBUG, "Reading SPD using i2c block operation.\n");
Julius Wernercd49cce2019-03-05 16:53:33 -0800360 if (CONFIG(DEBUG_RAM_SETUP) && bytes_read > 0)
Arthur Heymans0ab49042017-02-06 22:40:14 +0100361 hexdump(raw_spd, bytes_read);
Arthur Heymans56619452017-09-21 09:12:42 +0200362 if (bytes_read != 64) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100363 /* Try again with SMBUS byte read */
364 printk(BIOS_DEBUG, "i2c block operation failed,"
Paul Menzel105e3682017-09-21 08:11:05 +0200365 " trying smbus byte operation.\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100366 for (j = 0; j < 64; j++)
Kyösti Mälkkibd659852020-01-05 20:00:18 +0200367 raw_spd[j] = smbus_read_byte(device, j);
Julius Wernercd49cce2019-03-05 16:53:33 -0800368 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100369 hexdump(raw_spd, 64);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100370 }
Arthur Heymans56619452017-09-21 09:12:42 +0200371
372 if (spd_decode_ddr2(&dimm_info, raw_spd) != SPD_STATUS_OK) {
373 printk(BIOS_WARNING, "Encountered problems with SPD, "
374 "skipping this DIMM.\n");
375 continue;
376 }
377
Julius Wernercd49cce2019-03-05 16:53:33 -0800378 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100379 dram_print_spd_ddr2(&dimm_info);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000380
Arthur Heymans0ab49042017-02-06 22:40:14 +0100381 if (dimm_info.flags.is_ecc)
382 die("\nError: ECC memory not supported by this chipset\n");
383
384 if (spd_dimm_is_registered_ddr2(dimm_info.dimm_type))
385 die("\nError: Registered memory not supported by this chipset\n");
386
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200387 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: ", (i >> 1), (i & 1));
Arthur Heymans0ab49042017-02-06 22:40:14 +0100388 /**
389 * There are 5 different possible populations for a DIMM socket:
390 * 0. x16 double ranked (X16DS)
391 * 1. x8 double ranked (X8DS)
392 * 2. x16 single ranked (X16SS)
393 * 3. x8 double stacked (X8DDS)
394 * 4. Unpopulated
395 */
396 switch (dimm_info.width) {
397 case 8:
398 switch (dimm_info.ranks) {
399 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000400 printk(BIOS_DEBUG, "x8DDS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000401 sysinfo->dimm[i] = SYSINFO_DIMM_X8DDS;
402 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100403 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000404 printk(BIOS_DEBUG, "x8DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000405 sysinfo->dimm[i] = SYSINFO_DIMM_X8DS;
406 break;
407 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000408 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000409 }
410 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100411 case 16:
412 switch (dimm_info.ranks) {
413 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000414 printk(BIOS_DEBUG, "x16DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000415 sysinfo->dimm[i] = SYSINFO_DIMM_X16DS;
416 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100417 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000418 printk(BIOS_DEBUG, "x16SS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000419 sysinfo->dimm[i] = SYSINFO_DIMM_X16SS;
420 break;
421 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000422 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000423 }
424 break;
425 default:
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000426 die("Unsupported DDR-II memory width.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000427 }
428
Arthur Heymans0ab49042017-02-06 22:40:14 +0100429 /* Is the current DIMM a stacked DIMM? */
430 if (dimm_info.flags.stacked)
431 sysinfo->package = SYSINFO_PACKAGE_STACKED;
432
433 if (!dimm_info.flags.bl8)
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100434 die("Only DDR-II RAM with burst length 8 is supported.\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100435
436 if (dimm_info.ranksize_mb < 128)
437 die("DDR-II rank size smaller than 128MB is not supported.\n");
438
439 sysinfo->banksize[i * 2] = dimm_info.ranksize_mb / 32;
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200440 printk(BIOS_DEBUG, "DIMM %d side 0 = %d MB\n", i, sysinfo->banksize[i * 2] * 32);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100441 if (dimm_info.ranks == 2) {
442 sysinfo->banksize[(i * 2) + 1] =
443 dimm_info.ranksize_mb / 32;
444 printk(BIOS_DEBUG, "DIMM %d side 1 = %d MB\n",
445 i, sysinfo->banksize[(i * 2) + 1] * 32);
446 }
447
448
449 sysinfo->rows[i] = dimm_info.row_bits;
450 sysinfo->cols[i] = dimm_info.col_bits;
451 sysinfo->banks[i] = dimm_info.banks;
452
453 /* int min_tRAS, min_tRP, min_tRCD, min_tWR, min_tRFC; */
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200454 saved_timings->min_tRAS = MAX(saved_timings->min_tRAS, dimm_info.tRAS);
455 saved_timings->min_tRP = MAX(saved_timings->min_tRP, dimm_info.tRP);
456 saved_timings->min_tRCD = MAX(saved_timings->min_tRCD, dimm_info.tRCD);
457 saved_timings->min_tWR = MAX(saved_timings->min_tWR, dimm_info.tWR);
458 saved_timings->min_tRFC = MAX(saved_timings->min_tRFC, dimm_info.tRFC);
459 saved_timings->max_tRR = MIN(saved_timings->max_tRR, dimm_info.tRR);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100460 saved_timings->cas_mask &= dimm_info.cas_supported;
461 for (j = 0; j < 8; j++) {
462 if (!(saved_timings->cas_mask & (1 << j)))
463 saved_timings->min_tCLK_cas[j] = 0;
464 else
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200465 saved_timings->min_tCLK_cas[j] = MAX(dimm_info.cycle_time[j],
Arthur Heymans0ab49042017-02-06 22:40:14 +0100466 saved_timings->min_tCLK_cas[j]);
467 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000468 dimm_mask |= (1 << i);
469 }
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200470 if (!dimm_mask)
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000471 die("No memory installed.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000472
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200473 if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1)))
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100474 /* FIXME: Possibly does not boot in this case */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000475 printk(BIOS_INFO, "Channel 0 has no memory populated.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000476}
477
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200478static void choose_tclk(struct sys_info *sysinfo, struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000479{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100480 u32 ctrl_min_tclk;
481 int try_cas;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000482
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200483 ctrl_min_tclk = 2 * 256 * 1000 / sdram_capabilities_max_supported_memory_frequency();
Arthur Heymans0ab49042017-02-06 22:40:14 +0100484 normalize_tck(&ctrl_min_tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000485
Arthur Heymans0ab49042017-02-06 22:40:14 +0100486 try_cas = spd_get_msbs(saved_timings->cas_mask);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000487
Arthur Heymans0ab49042017-02-06 22:40:14 +0100488 while (saved_timings->cas_mask & (1 << try_cas) && try_cas > 0) {
489 sysinfo->cas = try_cas;
490 sysinfo->tclk = saved_timings->min_tCLK_cas[try_cas];
491 if (sysinfo->tclk >= ctrl_min_tclk &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200492 saved_timings->min_tCLK_cas[try_cas] !=
493 saved_timings->min_tCLK_cas[try_cas - 1])
Stefan Reinauer278534d2008-10-29 04:51:07 +0000494 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100495 try_cas--;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000496 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000497
Arthur Heymans0ab49042017-02-06 22:40:14 +0100498 normalize_tck(&sysinfo->tclk);
499
500 if ((sysinfo->cas < 3) || (sysinfo->tclk == 0))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000501 die("Could not find common memory frequency and CAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000502
Arthur Heymans0ab49042017-02-06 22:40:14 +0100503 /*
504 * The loop can still results in a timing too fast for the
505 * memory controller.
506 */
507 if (sysinfo->tclk < ctrl_min_tclk)
508 sysinfo->tclk = ctrl_min_tclk;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000509
Arthur Heymans0ab49042017-02-06 22:40:14 +0100510 switch (sysinfo->tclk) {
511 case TCK_200MHZ:
512 sysinfo->memory_frequency = 400;
513 break;
514 case TCK_266MHZ:
515 sysinfo->memory_frequency = 533;
516 break;
517 case TCK_333MHZ:
518 sysinfo->memory_frequency = 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100519 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000520 }
521
Arthur Heymans0ab49042017-02-06 22:40:14 +0100522 printk(BIOS_DEBUG,
523 "Memory will be driven at %dMT with CAS=%d clocks\n",
524 sysinfo->memory_frequency, sysinfo->cas);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000525}
526
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200527static void derive_timings(struct sys_info *sysinfo, struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000528{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100529 sysinfo->tras = DIV_ROUND_UP(saved_timings->min_tRAS, sysinfo->tclk);
530 if (sysinfo->tras > 0x18)
531 die("DDR-II Module does not support this frequency (tRAS error)\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000532
Arthur Heymans0ab49042017-02-06 22:40:14 +0100533 sysinfo->trp = DIV_ROUND_UP(saved_timings->min_tRP, sysinfo->tclk);
534 if (sysinfo->trp > 6)
535 die("DDR-II Module does not support this frequency (tRP error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000536
Arthur Heymans0ab49042017-02-06 22:40:14 +0100537 sysinfo->trcd = DIV_ROUND_UP(saved_timings->min_tRCD, sysinfo->tclk);
538 if (sysinfo->trcd > 6)
539 die("DDR-II Module does not support this frequency (tRCD error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000540
Arthur Heymans0ab49042017-02-06 22:40:14 +0100541 sysinfo->twr = DIV_ROUND_UP(saved_timings->min_tWR, sysinfo->tclk);
542 if (sysinfo->twr > 5)
543 die("DDR-II Module does not support this frequency (tWR error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000544
Arthur Heymans0ab49042017-02-06 22:40:14 +0100545 sysinfo->trfc = DIV_ROUND_UP(saved_timings->min_tRFC, sysinfo->tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000546
Arthur Heymans0ab49042017-02-06 22:40:14 +0100547 printk(BIOS_DEBUG, "tRAS = %d cycles\n", sysinfo->tras);
548 printk(BIOS_DEBUG, "tRP = %d cycles\n", sysinfo->trp);
549 printk(BIOS_DEBUG, "tRCD = %d cycles\n", sysinfo->trcd);
550 printk(BIOS_DEBUG, "tWR = %d cycles\n", sysinfo->twr);
551 printk(BIOS_DEBUG, "tRFC = %d cycles\n", sysinfo->trfc);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000552
Arthur Heymans0ab49042017-02-06 22:40:14 +0100553 /* Refresh is slower than 15.6us, use 15.6us */
554 /* tRR is decoded in units of 1/256us */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000555
Arthur Heymans0ab49042017-02-06 22:40:14 +0100556#define T_RR_7_8US 2000000
557#define T_RR_15_6US 4000000
558#define REFRESH_7_8US 1
559#define REFRESH_15_6US 0
Stefan Reinauer278534d2008-10-29 04:51:07 +0000560
Arthur Heymans0ab49042017-02-06 22:40:14 +0100561 if (saved_timings->max_tRR < T_RR_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000562 die("DDR-II module has unsupported refresh value\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100563 else if (saved_timings->max_tRR < T_RR_15_6US)
564 sysinfo->refresh = REFRESH_7_8US;
565 else
566 sysinfo->refresh = REFRESH_15_6US;
Angel Pons30492572020-06-11 13:24:54 +0200567 printk(BIOS_DEBUG, "Refresh: %s\n", sysinfo->refresh ? "7.8us" : "15.6us");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000568}
569
Arthur Heymans0ab49042017-02-06 22:40:14 +0100570/**
571 * @brief Get generic DIMM parameters.
572 * @param sysinfo Central memory controller information structure
573 *
574 * This function gathers several pieces of information for each system DIMM:
575 * o DIMM width (x8 / x16)
576 * o DIMM rank (single ranked / dual ranked)
577 *
578 * Also, some non-supported scenarios are detected.
579 */
580
581static void sdram_get_dram_configuration(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000582{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100583 struct timings saved_timings;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000584
Arthur Heymans0ab49042017-02-06 22:40:14 +0100585 gather_common_timing(sysinfo, &saved_timings);
586 choose_tclk(sysinfo, &saved_timings);
587 derive_timings(sysinfo, &saved_timings);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000588}
589
Arthur Heymans70a8e342017-03-09 11:30:23 +0100590static void sdram_program_dram_width(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000591{
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200592 u16 c0dramw = 0, c1dramw = 0;
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200593 int i, idx;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000594
595 if (sysinfo->dual_channel)
596 idx = 2;
597 else
598 idx = 1;
599
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200600 for (i = 0; i < DIMM_SOCKETS; i++) { /* Channel 0 */
601 switch (sysinfo->dimm[i]) {
602 case SYSINFO_DIMM_X16DS:
Angel Pons30492572020-06-11 13:24:54 +0200603 c0dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200604 break;
605 case SYSINFO_DIMM_X8DS:
Angel Pons30492572020-06-11 13:24:54 +0200606 c0dramw |= (0x0001) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200607 break;
608 case SYSINFO_DIMM_X16SS:
Angel Pons30492572020-06-11 13:24:54 +0200609 c0dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200610 break;
611 case SYSINFO_DIMM_X8DDS:
Angel Pons30492572020-06-11 13:24:54 +0200612 c0dramw |= (0x0005) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200613 break;
614 case SYSINFO_DIMM_NOT_POPULATED:
Angel Pons30492572020-06-11 13:24:54 +0200615 c0dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200616 break;
617 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000618 }
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200619 for (i = DIMM_SOCKETS; i < idx * DIMM_SOCKETS; i++) { /* Channel 1 */
620 switch (sysinfo->dimm[i]) {
621 case SYSINFO_DIMM_X16DS:
Angel Pons30492572020-06-11 13:24:54 +0200622 c1dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200623 break;
624 case SYSINFO_DIMM_X8DS:
Angel Pons30492572020-06-11 13:24:54 +0200625 c1dramw |= (0x0010) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200626 break;
627 case SYSINFO_DIMM_X16SS:
Angel Pons30492572020-06-11 13:24:54 +0200628 c1dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200629 break;
630 case SYSINFO_DIMM_X8DDS:
Angel Pons30492572020-06-11 13:24:54 +0200631 c1dramw |= (0x0050) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200632 break;
633 case SYSINFO_DIMM_NOT_POPULATED:
Angel Pons30492572020-06-11 13:24:54 +0200634 c1dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200635 break;
636 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000637 }
638
639 MCHBAR16(C0DRAMW) = c0dramw;
640 MCHBAR16(C1DRAMW) = c1dramw;
641}
642
643static void sdram_write_slew_rates(u32 offset, const u32 *slew_rate_table)
644{
645 int i;
646
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200647 for (i = 0; i < 16; i++)
Angel Pons30492572020-06-11 13:24:54 +0200648 MCHBAR32(offset+(i * 4)) = slew_rate_table[i];
Stefan Reinauer278534d2008-10-29 04:51:07 +0000649}
650
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000651static const u32 dq2030[] = {
652 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
653 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
654 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
655 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
656};
657
658static const u32 dq2330[] = {
659 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
660 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
661 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
662 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
663};
664
665static const u32 cmd2710[] = {
666 0x07060605, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
667 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
668 0x1110100f, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
669 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
670};
671
672static const u32 cmd3210[] = {
673 0x0f0d0b0a, 0x17151311, 0x1f1d1b19, 0x1f1f1f1f,
674 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
675 0x18171615, 0x1f1f1c1a, 0x1f1f1f1f, 0x1f1f1f1f,
676 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
677};
678
679static const u32 clk2030[] = {
680 0x0e0d0d0c, 0x100f0f0e, 0x100f0e0d, 0x15131211,
681 0x1d1b1917, 0x2523211f, 0x2a282927, 0x32302e2c,
682 0x17161514, 0x1b1a1918, 0x1f1e1d1c, 0x23222120,
683 0x27262524, 0x2d2b2928, 0x3533312f, 0x3d3b3937
684};
685
686static const u32 ctl3215[] = {
687 0x01010000, 0x03020101, 0x07060504, 0x0b0a0908,
688 0x100f0e0d, 0x14131211, 0x18171615, 0x1c1b1a19,
689 0x05040403, 0x07060605, 0x0a090807, 0x0f0d0c0b,
690 0x14131211, 0x18171615, 0x1c1b1a19, 0x201f1e1d
691};
692
693static const u32 ctl3220[] = {
694 0x05040403, 0x07060505, 0x0e0c0a08, 0x1a171411,
695 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e,
696 0x09080807, 0x0b0a0a09, 0x0f0d0c0b, 0x1b171311,
697 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e
698};
699
700static const u32 nc[] = {
701 0x00000000, 0x00000000, 0x00000000, 0x00000000,
702 0x00000000, 0x00000000, 0x00000000, 0x00000000,
703 0x00000000, 0x00000000, 0x00000000, 0x00000000,
704 0x00000000, 0x00000000, 0x00000000, 0x00000000
705};
706
707enum {
708 DQ2030,
709 DQ2330,
710 CMD2710,
711 CMD3210,
712 CLK2030,
713 CTL3215,
714 CTL3220,
715 NC,
716};
717
718static const u8 dual_channel_slew_group_lookup[] = {
719 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
720 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
721 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
722 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
723 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
724
725 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
726 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
727 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
728 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
729 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
730
731 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
732 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
733 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
734 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
735 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
736
737 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
738 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
739 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
740 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
741 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, NC, NC,
742
743 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
744 NC, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
745 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
746 NC, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD2710
747};
748
749static const u8 single_channel_slew_group_lookup[] = {
750 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
751 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
752 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
753 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
754 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
755
756 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
757 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
758 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
759 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
760 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
761
762 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
763 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
764 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
765 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
766 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
767
768 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
769 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
770 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
771 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
772 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
773
774 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
775 DQ2330, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
776 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
777 DQ2330, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD3210
778};
779
780static const u32 *slew_group_lookup(int dual_channel, int index)
781{
782 const u8 *slew_group;
783 /* Dual Channel needs different tables. */
784 if (dual_channel)
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100785 slew_group = dual_channel_slew_group_lookup;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000786 else
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100787 slew_group = single_channel_slew_group_lookup;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000788
789 switch (slew_group[index]) {
790 case DQ2030: return dq2030;
791 case DQ2330: return dq2330;
792 case CMD2710: return cmd2710;
793 case CMD3210: return cmd3210;
794 case CLK2030: return clk2030;
795 case CTL3215: return ctl3215;
796 case CTL3220: return ctl3220;
797 case NC: return nc;
798 }
799
800 return nc;
801}
802
Julius Wernercd49cce2019-03-05 16:53:33 -0800803#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000804/* Strength multiplier tables */
805static const u8 dual_channel_strength_multiplier[] = {
806 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
807 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
808 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
809 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
810 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
811 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
812 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
813 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
814 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
815 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
816 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
817 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
818 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
819 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
820 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
821 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
822 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
823 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
824 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
825 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
826 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
827 0x00, 0x00, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
828 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
829 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x44, 0x22
830};
831
832static const u8 single_channel_strength_multiplier[] = {
833 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
834 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
835 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
836 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
837 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
838 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
839 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
840 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
841 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
842 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
843 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
844 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
845 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
846 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
847 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
848 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
849 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
850 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
851 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
852 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
853 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
854 0x33, 0x00, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
855 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
856 0x33, 0x00, 0x11, 0x00, 0x44, 0x44, 0x33, 0x11
857};
Julius Wernercd49cce2019-03-05 16:53:33 -0800858#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000859static const u8 dual_channel_strength_multiplier[] = {
860 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
861 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
862 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
863 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
864 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
865 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
866 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
867 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
868 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
869 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
870 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
871 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
872 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
873 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
874 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
875 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
876 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
877 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
878 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
879 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
880 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
881 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
882 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
883 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33
884};
885
886static const u8 single_channel_strength_multiplier[] = {
887 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
888 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
889 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
890 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
891 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
892 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
893 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
894 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
895 0x44, 0x88, 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 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
899 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
900 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
901 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
902 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
903 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
904 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
905 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
906 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
907 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
908 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
909 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
910 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00
911};
912#endif
913
Stefan Reinauer278534d2008-10-29 04:51:07 +0000914static void sdram_rcomp_buffer_strength_and_slew(struct sys_info *sysinfo)
915{
Arthur Heymans70a8e342017-03-09 11:30:23 +0100916 const u8 *strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000917 int idx, dual_channel;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000918
919 /* Set Strength Multipliers */
920
921 /* Dual Channel needs different tables. */
922 if (sdram_capabilities_dual_channel()) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000923 printk(BIOS_DEBUG, "Programming Dual Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000924 strength_multiplier = dual_channel_strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000925 dual_channel = 1;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100926 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[2];
Stefan Reinauer278534d2008-10-29 04:51:07 +0000927 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000928 printk(BIOS_DEBUG, "Programming Single Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000929 strength_multiplier = single_channel_strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000930 dual_channel = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000931 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[1];
932 }
933
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000934 printk(BIOS_DEBUG, "Table Index: %d\n", idx);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000935
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000936 MCHBAR8(G1SC) = strength_multiplier[idx * 8 + 0];
937 MCHBAR8(G2SC) = strength_multiplier[idx * 8 + 1];
938 MCHBAR8(G3SC) = strength_multiplier[idx * 8 + 2];
939 MCHBAR8(G4SC) = strength_multiplier[idx * 8 + 3];
940 MCHBAR8(G5SC) = strength_multiplier[idx * 8 + 4];
941 MCHBAR8(G6SC) = strength_multiplier[idx * 8 + 5];
942 MCHBAR8(G7SC) = strength_multiplier[idx * 8 + 6];
943 MCHBAR8(G8SC) = strength_multiplier[idx * 8 + 7];
Stefan Reinauer278534d2008-10-29 04:51:07 +0000944
945 /* Channel 0 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000946 sdram_write_slew_rates(G1SRPUT, slew_group_lookup(dual_channel, idx * 8 + 0));
947 sdram_write_slew_rates(G2SRPUT, slew_group_lookup(dual_channel, idx * 8 + 1));
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200948 if ((slew_group_lookup(dual_channel, idx * 8 + 2) != nc) &&
949 (sysinfo->package == SYSINFO_PACKAGE_STACKED))
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000950
Stefan Reinauer278534d2008-10-29 04:51:07 +0000951 sdram_write_slew_rates(G3SRPUT, ctl3220);
Arthur Heymans70a8e342017-03-09 11:30:23 +0100952 else
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000953 sdram_write_slew_rates(G3SRPUT, slew_group_lookup(dual_channel, idx * 8 + 2));
Arthur Heymans70a8e342017-03-09 11:30:23 +0100954
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000955 sdram_write_slew_rates(G4SRPUT, slew_group_lookup(dual_channel, idx * 8 + 3));
956 sdram_write_slew_rates(G5SRPUT, slew_group_lookup(dual_channel, idx * 8 + 4));
957 sdram_write_slew_rates(G6SRPUT, slew_group_lookup(dual_channel, idx * 8 + 5));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000958
959 /* Channel 1 */
960 if (sysinfo->dual_channel) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000961 sdram_write_slew_rates(G7SRPUT, slew_group_lookup(dual_channel, idx * 8 + 6));
962 sdram_write_slew_rates(G8SRPUT, slew_group_lookup(dual_channel, idx * 8 + 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000963 } else {
964 sdram_write_slew_rates(G7SRPUT, nc);
965 sdram_write_slew_rates(G8SRPUT, nc);
966 }
967}
968
969static void sdram_enable_rcomp(void)
970{
971 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000972 /* Enable Global Periodic RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000973 udelay(300);
974 reg32 = MCHBAR32(GBRCOMPCTL);
975 reg32 &= ~(1 << 23);
976 MCHBAR32(GBRCOMPCTL) = reg32;
977}
978
979static void sdram_program_dll_timings(struct sys_info *sysinfo)
980{
Elyes HAOUAS44a30662017-02-23 13:14:44 +0100981 u32 channeldll = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000982 int i;
983
Elyes HAOUAS38424982016-08-21 12:01:04 +0200984 printk(BIOS_DEBUG, "Programming DLL Timings...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000985
Arthur Heymans70a8e342017-03-09 11:30:23 +0100986 MCHBAR16(DQSMT) &= ~((3 << 12) | (1 << 10) | (0xf << 0));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000987 MCHBAR16(DQSMT) |= (1 << 13) | (0xc << 0);
988
989 /* We drive both channels with the same speed */
Julius Wernercd49cce2019-03-05 16:53:33 -0800990 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +0100991 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +0100992 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200993 channeldll = 0x26262626;
994 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100995 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200996 channeldll = 0x22222222;
997 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100998 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200999 channeldll = 0x11111111;
1000 break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001001 }
Julius Wernercd49cce2019-03-05 16:53:33 -08001002 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001003 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001004 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001005 channeldll = 0x33333333;
1006 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001007 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001008 channeldll = 0x24242424;
1009 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001010 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001011 channeldll = 0x25252525;
1012 break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001013 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001014 }
1015
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001016 for (i = 0; i < 4; i++) {
Elyes HAOUAS44a30662017-02-23 13:14:44 +01001017 MCHBAR32(C0R0B00DQST + (i * 0x10) + 0) = channeldll;
1018 MCHBAR32(C0R0B00DQST + (i * 0x10) + 4) = channeldll;
1019 MCHBAR32(C1R0B00DQST + (i * 0x10) + 0) = channeldll;
1020 MCHBAR32(C1R0B00DQST + (i * 0x10) + 4) = channeldll;
Julius Wernercd49cce2019-03-05 16:53:33 -08001021 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUAS44a30662017-02-23 13:14:44 +01001022 MCHBAR8(C0R0B00DQST + (i * 0x10) + 8) = channeldll & 0xff;
1023 MCHBAR8(C1R0B00DQST + (i * 0x10) + 8) = channeldll & 0xff;
Paul Menzelbce7e332017-02-22 18:46:27 +01001024 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001025 }
1026}
1027
1028static void sdram_force_rcomp(void)
1029{
1030 u32 reg32;
1031 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001032
Stefan Reinauer278534d2008-10-29 04:51:07 +00001033 reg32 = MCHBAR32(ODTC);
1034 reg32 |= (1 << 28);
1035 MCHBAR32(ODTC) = reg32;
1036
1037 reg32 = MCHBAR32(SMSRCTL);
1038 reg32 |= (1 << 0);
1039 MCHBAR32(SMSRCTL) = reg32;
1040
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001041 /* Start initial RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001042 reg32 = MCHBAR32(GBRCOMPCTL);
1043 reg32 |= (1 << 8);
1044 MCHBAR32(GBRCOMPCTL) = reg32;
1045
1046 reg8 = i945_silicon_revision();
1047 if ((reg8 == 0 && (MCHBAR32(DCC) & (3 << 0)) == 0) || (reg8 == 1)) {
1048 reg32 = MCHBAR32(GBRCOMPCTL);
1049 reg32 |= (3 << 5);
1050 MCHBAR32(GBRCOMPCTL) = reg32;
1051 }
1052}
1053
1054static void sdram_initialize_system_memory_io(struct sys_info *sysinfo)
1055{
1056 u8 reg8;
1057 u32 reg32;
1058
Elyes HAOUAS38424982016-08-21 12:01:04 +02001059 printk(BIOS_DEBUG, "Initializing System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001060 /* Enable Data Half Clock Pushout */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001061 reg8 = MCHBAR8(C0HCTC);
1062 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001063 reg8 |= (1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001064 MCHBAR8(C0HCTC) = reg8;
1065
1066 reg8 = MCHBAR8(C1HCTC);
1067 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001068 reg8 |= (1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001069 MCHBAR8(C1HCTC) = reg8;
1070
Arthur Heymans70a8e342017-03-09 11:30:23 +01001071 MCHBAR16(WDLLBYPMODE) &= ~((1 << 9) | (1 << 6) | (1 << 4) | (1 << 3) | (1 << 1));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001072 MCHBAR16(WDLLBYPMODE) |= (1 << 8) | (1 << 7) | (1 << 5) | (1 << 2) | (1 << 0);
1073
1074 MCHBAR8(C0WDLLCMC) = 0;
1075 MCHBAR8(C1WDLLCMC) = 0;
1076
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001077 /* Program RCOMP Settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001078 sdram_program_dram_width(sysinfo);
1079
1080 sdram_rcomp_buffer_strength_and_slew(sysinfo);
1081
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001082 /* Indicate that RCOMP programming is done */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001083 reg32 = MCHBAR32(GBRCOMPCTL);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001084 reg32 &= ~((1 << 29) | (1 << 26) | (3 << 21) | (3 << 2));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001085 reg32 |= (3 << 27) | (3 << 0);
1086 MCHBAR32(GBRCOMPCTL) = reg32;
1087
1088 MCHBAR32(GBRCOMPCTL) |= (1 << 10);
1089
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001090 /* Program DLL Timings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001091 sdram_program_dll_timings(sysinfo);
1092
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001093 /* Force RCOMP cycle */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001094 sdram_force_rcomp();
1095}
1096
1097static void sdram_enable_system_memory_io(struct sys_info *sysinfo)
1098{
1099 u32 reg32;
1100
Elyes HAOUAS38424982016-08-21 12:01:04 +02001101 printk(BIOS_DEBUG, "Enabling System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001102
Stefan Reinauer278534d2008-10-29 04:51:07 +00001103 reg32 = MCHBAR32(RCVENMT);
1104 reg32 &= ~(0x3f << 6);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001105 MCHBAR32(RCVENMT) = reg32; /* [11:6] = 0 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001106
1107 reg32 |= (1 << 11) | (1 << 9);
1108 MCHBAR32(RCVENMT) = reg32;
1109
1110 reg32 = MCHBAR32(DRTST);
1111 reg32 |= (1 << 3) | (1 << 2);
1112 MCHBAR32(DRTST) = reg32;
1113
1114 reg32 = MCHBAR32(DRTST);
1115 reg32 |= (1 << 6) | (1 << 4);
1116 MCHBAR32(DRTST) = reg32;
1117
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001118 asm volatile ("nop; nop;" ::: "memory");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001119
1120 reg32 = MCHBAR32(DRTST);
1121
1122 /* Is channel 0 populated? */
1123 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001124 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001125 reg32 |= (1 << 7) | (1 << 5);
1126 else
1127 reg32 |= (1 << 31);
1128
1129 /* Is channel 1 populated? */
1130 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001131 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001132 reg32 |= (1 << 9) | (1 << 8);
1133 else
1134 reg32 |= (1 << 30);
1135
1136 MCHBAR32(DRTST) = reg32;
1137
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001138 /* Activate DRAM Channel IO Buffers */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001139 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001140 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001141 reg32 = MCHBAR32(C0DRC1);
1142 reg32 |= (1 << 8);
1143 MCHBAR32(C0DRC1) = reg32;
1144 }
1145 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001146 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001147 reg32 = MCHBAR32(C1DRC1);
1148 reg32 |= (1 << 8);
1149 MCHBAR32(C1DRC1) = reg32;
1150 }
1151}
1152
Stefan Reinauer278534d2008-10-29 04:51:07 +00001153static int sdram_program_row_boundaries(struct sys_info *sysinfo)
1154{
1155 int i;
Arthur Heymans885c2892016-10-03 17:16:48 +02001156 int cum0, cum1, tolud, tom, pci_mmio_size;
1157 const struct device *dev;
1158 const struct northbridge_intel_i945_config *cfg = NULL;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001159
Paul Menzel84283bc2014-07-17 08:16:04 +02001160 printk(BIOS_DEBUG, "Setting RAM size...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001161
1162 cum0 = 0;
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001163 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001164 cum0 += sysinfo->banksize[i];
Stefan Reinauer278534d2008-10-29 04:51:07 +00001165 MCHBAR8(C0DRB0+i) = cum0;
1166 }
1167
1168 /* Assume we continue in Channel 1 where we stopped in Channel 0 */
1169 cum1 = cum0;
1170
1171 /* Exception: Interleaved starts from the beginning */
1172 if (sysinfo->interleaved)
1173 cum1 = 0;
1174
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001175 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001176 cum1 += sysinfo->banksize[i + 4];
Stefan Reinauer278534d2008-10-29 04:51:07 +00001177 MCHBAR8(C1DRB0+i) = cum1;
1178 }
1179
1180 /* Set TOLUD Top Of Low Usable DRAM */
1181 if (sysinfo->interleaved)
1182 tolud = (cum0 + cum1) << 1;
1183 else
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001184 tolud = (cum1 ? cum1 : cum0) << 1;
Stefan Reinauer779b3e32008-11-10 15:43:37 +00001185
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001186 /* The TOM register has a different format */
1187 tom = tolud >> 3;
1188
1189 /* Limit the value of TOLUD to leave some space for PCI memory. */
Kyösti Mälkkic70eed12018-05-22 02:18:00 +03001190 dev = pcidev_on_root(0, 0);
Arthur Heymans885c2892016-10-03 17:16:48 +02001191 if (dev)
1192 cfg = dev->chip_info;
1193
1194 /* Don't use pci mmio sizes smaller than 768M */
1195 if (!cfg || cfg->pci_mmio_size <= DEFAULT_PCI_MMIO_SIZE)
1196 pci_mmio_size = DEFAULT_PCI_MMIO_SIZE;
1197 else
1198 pci_mmio_size = cfg->pci_mmio_size;
1199
1200 tolud = MIN(((4096 - pci_mmio_size) / 128) << 3, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001201
Arthur Heymans70a8e342017-03-09 11:30:23 +01001202 pci_write_config8(PCI_DEV(0, 0, 0), TOLUD, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001203
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001204 printk(BIOS_DEBUG, "C0DRB = 0x%08x\n", MCHBAR32(C0DRB0));
1205 printk(BIOS_DEBUG, "C1DRB = 0x%08x\n", MCHBAR32(C1DRB0));
Arthur Heymans70a8e342017-03-09 11:30:23 +01001206 printk(BIOS_DEBUG, "TOLUD = 0x%04x\n", pci_read_config8(PCI_DEV(0, 0, 0), TOLUD));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001207
Arthur Heymans70a8e342017-03-09 11:30:23 +01001208 pci_write_config16(PCI_DEV(0, 0, 0), TOM, tom);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001209
1210 return 0;
1211}
1212
Stefan Reinauer278534d2008-10-29 04:51:07 +00001213static int sdram_set_row_attributes(struct sys_info *sysinfo)
1214{
Arthur Heymans0ab49042017-02-06 22:40:14 +01001215 int i;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001216 u16 dra0 = 0, dra1 = 0, dra = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001217
Elyes HAOUAS38424982016-08-21 12:01:04 +02001218 printk(BIOS_DEBUG, "Setting row attributes...\n");
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001219 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001220 u8 columnsrows;
1221
Arthur Heymans70a8e342017-03-09 11:30:23 +01001222 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001223 continue;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001224
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001225 columnsrows = (sysinfo->rows[i] & 0x0f) | (sysinfo->cols[i] & 0xf) << 4;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001226
1227 switch (columnsrows) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001228 case 0x9d:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001229 dra = 2;
1230 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001231 case 0xad:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001232 dra = 3;
1233 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001234 case 0xbd:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001235 dra = 4;
1236 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001237 case 0xae:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001238 dra = 3;
1239 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001240 case 0xbe:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001241 dra = 4;
1242 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001243 default:
1244 die("Unsupported Rows/Columns. (DRA)");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001245 }
1246
1247 /* Double Sided DIMMs? */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001248 if (sysinfo->banksize[(2 * i) + 1] != 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001249 dra = (dra << 4) | dra;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001250
Stefan Reinauer278534d2008-10-29 04:51:07 +00001251 if (i < DIMM_SOCKETS)
Angel Pons30492572020-06-11 13:24:54 +02001252 dra0 |= (dra << (i * 8));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001253 else
Angel Pons30492572020-06-11 13:24:54 +02001254 dra1 |= (dra << ((i - DIMM_SOCKETS) * 8));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001255 }
1256
1257 MCHBAR16(C0DRA0) = dra0;
1258 MCHBAR16(C1DRA0) = dra1;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001259
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001260 printk(BIOS_DEBUG, "C0DRA = 0x%04x\n", dra0);
1261 printk(BIOS_DEBUG, "C1DRA = 0x%04x\n", dra1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001262
1263 return 0;
1264}
1265
1266static void sdram_set_bank_architecture(struct sys_info *sysinfo)
1267{
1268 u32 off32;
1269 int i;
1270
1271 MCHBAR16(C1BNKARC) &= 0xff00;
1272 MCHBAR16(C0BNKARC) &= 0xff00;
1273
1274 off32 = C0BNKARC;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001275 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001276 /* Switch to second channel */
1277 if (i == DIMM_SOCKETS)
1278 off32 = C1BNKARC;
1279
1280 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
1281 continue;
1282
1283 if (sysinfo->banks[i] != 8)
1284 continue;
1285
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001286 printk(BIOS_SPEW, "DIMM%d has 8 banks.\n", i);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001287
1288 if (i & 1)
1289 MCHBAR16(off32) |= 0x50;
1290 else
1291 MCHBAR16(off32) |= 0x05;
1292 }
1293}
1294
Stefan Reinauer278534d2008-10-29 04:51:07 +00001295static void sdram_program_refresh_rate(struct sys_info *sysinfo)
1296{
1297 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001298
Arthur Heymans70a8e342017-03-09 11:30:23 +01001299 if (sysinfo->refresh == REFRESH_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001300 reg32 = (2 << 8); /* Refresh enabled at 7.8us */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001301 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001302 reg32 = (1 << 8); /* Refresh enabled at 15.6us */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001303
1304 MCHBAR32(C0DRC0) &= ~(7 << 8);
1305 MCHBAR32(C0DRC0) |= reg32;
1306
1307 MCHBAR32(C1DRC0) &= ~(7 << 8);
1308 MCHBAR32(C1DRC0) |= reg32;
1309}
1310
1311static void sdram_program_cke_tristate(struct sys_info *sysinfo)
1312{
1313 u32 reg32;
1314 int i;
1315
1316 reg32 = MCHBAR32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001317
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001318 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001319 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001320 reg32 |= (1 << (16 + 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(C0DRC1) = reg32;
1327
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001328 /* Do we have to do this if we're in Single Channel Mode? */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001329 reg32 = MCHBAR32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001330
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001331 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001332 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001333 reg32 |= (1 << (12 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001334 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001335
Stefan Reinauer278534d2008-10-29 04:51:07 +00001336 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001337
Stefan Reinauer278534d2008-10-29 04:51:07 +00001338 reg32 |= (1 << 11);
1339 MCHBAR32(C1DRC1) = reg32;
1340}
1341
1342static void sdram_program_odt_tristate(struct sys_info *sysinfo)
1343{
1344 u32 reg32;
1345 int i;
1346
1347 reg32 = MCHBAR32(C0DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001348
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001349 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001350 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001351 reg32 |= (1 << (24 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001352 }
1353 MCHBAR32(C0DRC2) = reg32;
1354
1355 reg32 = MCHBAR32(C1DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001356
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001357 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001358 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001359 reg32 |= (1 << (20 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001360 }
1361 MCHBAR32(C1DRC2) = reg32;
1362}
1363
1364static void sdram_set_timing_and_control(struct sys_info *sysinfo)
1365{
Arthur Heymans25027232017-02-12 23:34:39 +01001366 u32 reg32, tRD_min;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001367 u32 tWTR;
1368 u32 temp_drt;
1369 int i, page_size;
1370
Edward O'Callaghan2f237c12014-05-25 06:24:39 +10001371 static const u8 cas_table[] = {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001372 2, 1, 0, 3
1373 };
1374
1375 reg32 = MCHBAR32(C0DRC0);
1376 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001377 reg32 &= ~((1 << 13) | (1 << 12));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001378 MCHBAR32(C0DRC0) = reg32;
1379
1380 reg32 = MCHBAR32(C1DRC0);
1381 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001382 reg32 &= ~((1 << 13) | (1 << 12));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001383 MCHBAR32(C1DRC0) = reg32;
1384
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001385 if (!sysinfo->dual_channel && sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001386 reg32 = MCHBAR32(C0DRC0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001387 reg32 |= (1 << 15);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001388 MCHBAR32(C0DRC0) = reg32;
1389 }
1390
1391 sdram_program_refresh_rate(sysinfo);
1392
1393 sdram_program_cke_tristate(sysinfo);
1394
1395 sdram_program_odt_tristate(sysinfo);
1396
1397 /* Calculate DRT0 */
1398
1399 temp_drt = 0;
1400
1401 /* B2B Write Precharge (same bank) = CL-1 + BL/2 + tWR */
1402 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + sysinfo->twr;
1403 temp_drt |= (reg32 << 28);
1404
1405 /* Write Auto Precharge (same bank) = CL-1 + BL/2 + tWR + tRP */
1406 reg32 += sysinfo->trp;
1407 temp_drt |= (reg32 << 4);
1408
Arthur Heymans70a8e342017-03-09 11:30:23 +01001409 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001410 tWTR = 3; /* 667MHz */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001411 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001412 tWTR = 2; /* 400 and 533 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001413
1414 /* B2B Write to Read Command Spacing */
1415 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + tWTR;
1416 temp_drt |= (reg32 << 24);
1417
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001418 /* CxDRT0 [23:22], [21:20], [19:18] [16] have fixed values */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001419 temp_drt |= ((1 << 22) | (3 << 20) | (1 << 18) | (0 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001420
Arthur Heymans25027232017-02-12 23:34:39 +01001421 /*
1422 * tRD is the delay the memory controller is waiting on the FSB,
1423 * in mclk domain.
1424 * This parameter is important for stability and performance.
1425 * Those values might not be optimal but seem stable.
1426 */
1427 tRD_min = sysinfo->cas;
Arthur Heymanse1897612016-10-15 23:29:18 +02001428 switch (sysinfo->fsb_frequency) {
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001429 case 533:
Arthur Heymanse1897612016-10-15 23:29:18 +02001430 break;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001431 case 667:
1432 tRD_min += 1;
Arthur Heymanse1897612016-10-15 23:29:18 +02001433 break;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001434 case 800:
1435 tRD_min += 2;
1436 break;
1437 case 1066:
1438 tRD_min += 3;
Arthur Heymanse1897612016-10-15 23:29:18 +02001439 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001440 }
Arthur Heymanse1897612016-10-15 23:29:18 +02001441
Arthur Heymans25027232017-02-12 23:34:39 +01001442 temp_drt |= (tRD_min << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001443
1444 /* Read Auto Precharge to Activate */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001445
Stefan Reinauer278534d2008-10-29 04:51:07 +00001446 temp_drt |= (8 << 0);
1447
1448 MCHBAR32(C0DRT0) = temp_drt;
1449 MCHBAR32(C1DRT0) = temp_drt;
1450
1451 /* Calculate DRT1 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001452
Stefan Reinauer278534d2008-10-29 04:51:07 +00001453 temp_drt = MCHBAR32(C0DRT1) & 0x00020088;
1454
1455 /* DRAM RASB Precharge */
1456 temp_drt |= (sysinfo->trp - 2) << 0;
1457
1458 /* DRAM RASB to CASB Delay */
1459 temp_drt |= (sysinfo->trcd - 2) << 4;
1460
1461 /* CASB Latency */
1462 temp_drt |= (cas_table[sysinfo->cas - 3]) << 8;
1463
1464 /* Refresh Cycle Time */
1465 temp_drt |= (sysinfo->trfc) << 10;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001466
Stefan Reinauer278534d2008-10-29 04:51:07 +00001467 /* Pre-All to Activate Delay */
1468 temp_drt |= (0 << 16);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001469
Stefan Reinauer278534d2008-10-29 04:51:07 +00001470 /* Precharge to Precharge Delay stays at 1 clock */
1471 temp_drt |= (0 << 18);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001472
Stefan Reinauer278534d2008-10-29 04:51:07 +00001473 /* Activate to Precharge Delay */
1474 temp_drt |= (sysinfo->tras << 19);
1475
1476 /* Read to Precharge (tRTP) */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001477 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001478 temp_drt |= (1 << 28);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001479 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001480 temp_drt |= (0 << 28);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001481
1482 /* Determine page size */
1483 reg32 = 0;
1484 page_size = 1; /* Default: 1k pagesize */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001485 for (i = 0; i < 2*DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001486 if (sysinfo->dimm[i] == SYSINFO_DIMM_X16DS ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001487 sysinfo->dimm[i] == SYSINFO_DIMM_X16SS)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001488 page_size = 2; /* 2k pagesize */
1489 }
1490
Arthur Heymans70a8e342017-03-09 11:30:23 +01001491 if (sysinfo->memory_frequency == 533 && page_size == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001492 reg32 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001493 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001494 reg32 = page_size;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001495
Stefan Reinauer278534d2008-10-29 04:51:07 +00001496 temp_drt |= (reg32 << 30);
1497
1498 MCHBAR32(C0DRT1) = temp_drt;
1499 MCHBAR32(C1DRT1) = temp_drt;
1500
1501 /* Program DRT2 */
1502 reg32 = MCHBAR32(C0DRT2);
1503 reg32 &= ~(1 << 8);
1504 MCHBAR32(C0DRT2) = reg32;
1505
1506 reg32 = MCHBAR32(C1DRT2);
1507 reg32 &= ~(1 << 8);
1508 MCHBAR32(C1DRT2) = reg32;
1509
1510 /* Calculate DRT3 */
1511 temp_drt = MCHBAR32(C0DRT3) & ~0x07ffffff;
1512
1513 /* Get old tRFC value */
1514 reg32 = MCHBAR32(C0DRT1) >> 10;
1515 reg32 &= 0x3f;
1516
1517 /* 788nS - tRFC */
1518 switch (sysinfo->memory_frequency) {
1519 case 400: /* 5nS */
1520 reg32 = ((78800 / 500) - reg32) & 0x1ff;
1521 reg32 |= (0x8c << 16) | (0x0c << 10); /* 1 us */
1522 break;
1523 case 533: /* 3.75nS */
1524 reg32 = ((78800 / 375) - reg32) & 0x1ff;
1525 reg32 |= (0xba << 16) | (0x10 << 10); /* 1 us */
1526 break;
1527 case 667: /* 3nS */
1528 reg32 = ((78800 / 300) - reg32) & 0x1ff;
1529 reg32 |= (0xe9 << 16) | (0x14 << 10); /* 1 us */
1530 break;
1531 }
1532
1533 temp_drt |= reg32;
1534
1535 MCHBAR32(C0DRT3) = temp_drt;
1536 MCHBAR32(C1DRT3) = temp_drt;
1537}
1538
1539static void sdram_set_channel_mode(struct sys_info *sysinfo)
1540{
1541 u32 reg32;
1542
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001543 printk(BIOS_DEBUG, "Setting mode of operation for memory channels...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001544
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001545 if (sdram_capabilities_interleave() &&
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001546 ((sysinfo->banksize[0] + sysinfo->banksize[1] +
1547 sysinfo->banksize[2] + sysinfo->banksize[3]) ==
1548 (sysinfo->banksize[4] + sysinfo->banksize[5] +
1549 sysinfo->banksize[6] + sysinfo->banksize[7]))) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001550 /* Both channels equipped with DIMMs of the same size */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001551 sysinfo->interleaved = 1;
1552 } else {
1553 sysinfo->interleaved = 0;
1554 }
1555
1556 reg32 = MCHBAR32(DCC);
1557 reg32 &= ~(7 << 0);
1558
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001559 if (sysinfo->interleaved) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001560 /* Dual Channel Interleaved */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001561 printk(BIOS_DEBUG, "Dual Channel Interleaved.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001562 reg32 |= (1 << 1);
1563 } else if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001564 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001565 /* Channel 1 only */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001566 printk(BIOS_DEBUG, "Single Channel 1 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001567 reg32 |= (1 << 2);
Elyes HAOUAS75da1fb2017-02-16 18:59:13 +01001568 } else if (sdram_capabilities_dual_channel() &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001569 (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1570 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) {
Martin Roth128c1042016-11-18 09:29:03 -07001571 /* Dual Channel Asymmetric */
1572 printk(BIOS_DEBUG, "Dual Channel Asymmetric.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001573 reg32 |= (1 << 0);
1574 } else {
1575 /* All bits 0 means Single Channel 0 operation */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001576 printk(BIOS_DEBUG, "Single Channel 0 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001577 }
1578
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001579 /* Now disable channel XORing */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001580 reg32 |= (1 << 10);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001581
1582 MCHBAR32(DCC) = reg32;
1583
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001584 PRINTK_DEBUG("DCC = 0x%08x\n", MCHBAR32(DCC));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001585}
1586
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001587static void sdram_program_pll_settings(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001588{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001589 MCHBAR32(PLLMON) = 0x80800000;
1590
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001591 sysinfo->fsb_frequency = fsbclk();
Peter Stuge76d91432010-10-01 10:02:33 +00001592 if (sysinfo->fsb_frequency == 0xffff)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001593 die("Unsupported FSB speed");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001594
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001595 /* Program CPCTL according to FSB speed */
1596 /* Only write the lower byte */
1597 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001598 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001599 MCHBAR8(CPCTL) = 0x90;
1600 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001601 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001602 MCHBAR8(CPCTL) = 0x95;
1603 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001604 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001605 MCHBAR8(CPCTL) = 0x8d;
1606 break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001607 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001608
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001609 MCHBAR16(CPCTL) &= ~(1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001610
Paul Menzel0ce5ebf2013-10-21 21:22:09 +02001611 MCHBAR16(CPCTL); /* Read back register to activate settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001612}
1613
1614static void sdram_program_graphics_frequency(struct sys_info *sysinfo)
1615{
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001616 u8 reg8;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001617 u8 freq, second_vco, voltage;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001618
1619#define CRCLK_166MHz 0x00
1620#define CRCLK_200MHz 0x01
1621#define CRCLK_250MHz 0x03
1622#define CRCLK_400MHz 0x05
1623
1624#define CDCLK_200MHz 0x00
1625#define CDCLK_320MHz 0x40
1626
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001627#define VOLTAGE_1_05 0x00
1628#define VOLTAGE_1_50 0x01
1629
Paul Menzeldaf9e502014-07-15 23:49:16 +02001630 printk(BIOS_DEBUG, "Setting Graphics Frequency...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001631
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001632 printk(BIOS_DEBUG, "FSB: %d MHz ", sysinfo->fsb_frequency);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001633
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001634 voltage = VOLTAGE_1_05;
1635 if (MCHBAR32(DFT_STRAP1) & (1 << 20))
1636 voltage = VOLTAGE_1_50;
Angel Pons30492572020-06-11 13:24:54 +02001637 printk(BIOS_DEBUG, "Voltage: %s ", (voltage == VOLTAGE_1_05) ? "1.05V" : "1.5V");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001638
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001639 /* Gate graphics hardware for frequency change */
Angel Pons30492572020-06-11 13:24:54 +02001640 reg8 = (1 << 3) | (1 << 1); /* disable crclk, gate cdclk */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001641 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001642
1643 /* Get graphics frequency capabilities */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001644 reg8 = sdram_capabilities_core_frequencies();
1645
Stefan Reinauer278534d2008-10-29 04:51:07 +00001646 freq = CRCLK_250MHz;
1647 switch (reg8) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001648 case GFX_FREQUENCY_CAP_ALL:
1649 if (voltage == VOLTAGE_1_05)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001650 freq = CRCLK_250MHz;
1651 else
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001652 freq = CRCLK_400MHz; /* 1.5V requires 400MHz */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001653 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001654 case GFX_FREQUENCY_CAP_250MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001655 freq = CRCLK_250MHz;
1656 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001657 case GFX_FREQUENCY_CAP_200MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001658 freq = CRCLK_200MHz;
1659 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001660 case GFX_FREQUENCY_CAP_166MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001661 freq = CRCLK_166MHz;
1662 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001663 }
1664
1665 if (freq != CRCLK_400MHz) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001666 /* What chipset are we? Force 166MHz for GMS */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001667 reg8 = (pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe7) & 0x70) >> 4;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001668 if (reg8 == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001669 freq = CRCLK_166MHz;
1670 }
1671
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001672 printk(BIOS_DEBUG, "Render: ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001673 switch (freq) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001674 case CRCLK_166MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001675 printk(BIOS_DEBUG, "166MHz");
1676 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001677 case CRCLK_200MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001678 printk(BIOS_DEBUG, "200MHz");
1679 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001680 case CRCLK_250MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001681 printk(BIOS_DEBUG, "250MHz");
1682 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001683 case CRCLK_400MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001684 printk(BIOS_DEBUG, "400MHz");
1685 break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001686 }
1687
Arthur Heymans70a8e342017-03-09 11:30:23 +01001688 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001689 sysinfo->mvco4x = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001690 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001691 sysinfo->mvco4x = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001692
Stefan Reinauer278534d2008-10-29 04:51:07 +00001693 second_vco = 0;
1694
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001695 if (voltage == VOLTAGE_1_50) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001696 second_vco = 1;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001697 } else if ((i945_silicon_revision() > 0) && (freq == CRCLK_250MHz)) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001698 u16 mem = sysinfo->memory_frequency;
1699 u16 fsb = sysinfo->fsb_frequency;
1700
Arthur Heymans70a8e342017-03-09 11:30:23 +01001701 if ((fsb == 667 && mem == 533) ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001702 (fsb == 533 && mem == 533) ||
1703 (fsb == 533 && mem == 400)) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001704 second_vco = 1;
1705 }
1706
1707 if (fsb == 667 && mem == 533)
1708 sysinfo->mvco4x = 1;
1709 }
1710
Arthur Heymans70a8e342017-03-09 11:30:23 +01001711 if (second_vco)
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001712 sysinfo->clkcfg_bit7 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001713 else
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001714 sysinfo->clkcfg_bit7 = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001715
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001716 /* Graphics Core Render Clock */
Angel Ponse3c68d22020-06-08 12:09:03 +02001717 pci_update_config16(PCI_DEV(0, 2, 0), GCFC, ~((7 << 0) | (1 << 13)), freq);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001718
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001719 /* Graphics Core Display Clock */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001720 reg8 = pci_read_config8(PCI_DEV(0, 2, 0), GCFC);
Angel Ponse3c68d22020-06-08 12:09:03 +02001721 reg8 &= ~((1 << 7) | (7 << 4));
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001722
1723 if (voltage == VOLTAGE_1_05) {
1724 reg8 |= CDCLK_200MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001725 printk(BIOS_DEBUG, " Display: 200MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001726 } else {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001727 reg8 |= CDCLK_320MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001728 printk(BIOS_DEBUG, " Display: 320MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001729 }
Arthur Heymans70a8e342017-03-09 11:30:23 +01001730 pci_write_config8(PCI_DEV(0, 2, 0), GCFC, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001731
Arthur Heymans70a8e342017-03-09 11:30:23 +01001732 reg8 = pci_read_config8(PCI_DEV(0, 2, 0), GCFC + 1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001733
Angel Ponse3c68d22020-06-08 12:09:03 +02001734 reg8 |= (1 << 3) | (1 << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001735 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001736
1737 reg8 |= 0x0f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001738 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001739
1740 /* Ungate core render and display clocks */
1741 reg8 &= 0xf0;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001742 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001743}
1744
1745static void sdram_program_memory_frequency(struct sys_info *sysinfo)
1746{
1747 u32 clkcfg;
Julius Wernercd49cce2019-03-05 16:53:33 -08001748 u8 offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001749
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001750 printk(BIOS_DEBUG, "Setting Memory Frequency... ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001751
Stefan Reinauer278534d2008-10-29 04:51:07 +00001752 clkcfg = MCHBAR32(CLKCFG);
1753
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001754 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001755
Arthur Heymans70a8e342017-03-09 11:30:23 +01001756 clkcfg &= ~((1 << 12) | (1 << 7) | (7 << 4));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001757
1758 if (sysinfo->mvco4x) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001759 printk(BIOS_DEBUG, "MVCO 4x, ");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001760 clkcfg &= ~(1 << 12);
1761 }
1762
1763 if (sysinfo->clkcfg_bit7) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001764 printk(BIOS_DEBUG, "second VCO, ");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001765 clkcfg |= (1 << 7);
1766 }
1767
1768 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001769 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001770 clkcfg |= ((1 + offset) << 4);
1771 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001772 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001773 clkcfg |= ((2 + offset) << 4);
1774 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001775 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001776 clkcfg |= ((3 + offset) << 4);
1777 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001778 default:
1779 die("Target Memory Frequency Error");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001780 }
1781
1782 if (MCHBAR32(CLKCFG) == clkcfg) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001783 printk(BIOS_DEBUG, "ok (unchanged)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001784 return;
1785 }
1786
1787 MCHBAR32(CLKCFG) = clkcfg;
1788
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001789 /* Make sure the following code is in the cache before we execute it. */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001790 goto cache_code;
1791vco_update:
Angel Ponse3c68d22020-06-08 12:09:03 +02001792 pci_and_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, (u8)~(1 << 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001793
Stefan Reinauer278534d2008-10-29 04:51:07 +00001794 clkcfg &= ~(1 << 10);
1795 MCHBAR32(CLKCFG) = clkcfg;
1796 clkcfg |= (1 << 10);
1797 MCHBAR32(CLKCFG) = clkcfg;
1798
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001799 asm volatile (
Stefan Reinauer278534d2008-10-29 04:51:07 +00001800 " movl $0x100, %%ecx\n"
1801 "delay_update:\n"
1802 " nop\n"
1803 " nop\n"
1804 " nop\n"
1805 " nop\n"
1806 " loop delay_update\n"
1807 : /* No outputs */
1808 : /* No inputs */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001809 : "%ecx", "memory"
Stefan Reinauer278534d2008-10-29 04:51:07 +00001810 );
1811
Stefan Reinauer278534d2008-10-29 04:51:07 +00001812 clkcfg &= ~(1 << 10);
1813 MCHBAR32(CLKCFG) = clkcfg;
1814
1815 goto out;
1816cache_code:
1817 goto vco_update;
1818out:
1819
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001820 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", MCHBAR32(CLKCFG));
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001821 printk(BIOS_DEBUG, "ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001822}
1823
1824static void sdram_program_clock_crossing(void)
1825{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001826 int idx = 0;
1827
1828 /**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001829 * We add the indices according to our clocks from CLKCFG.
Stefan Reinauer278534d2008-10-29 04:51:07 +00001830 */
Julius Wernercd49cce2019-03-05 16:53:33 -08001831#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001832 static const u32 data_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001833 0x00100401, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001834 0xffffffff, 0xffffffff, /* nonexistent */
1835 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001836
Stefan Reinauer278534d2008-10-29 04:51:07 +00001837 0x08040120, 0x00000000, /* DDR400 FSB533 */
1838 0x00100401, 0x00000000, /* DDR533 FSB533 */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001839 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001840
1841 0x04020120, 0x00000010, /* DDR400 FSB667 */
1842 0x10040280, 0x00000040, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001843 0x00100401, 0x00000000, /* DDR667 FSB667 */
1844
Martin Roth2ed0aa22016-01-05 20:58:58 -07001845 0xffffffff, 0xffffffff, /* nonexistent */
1846 0xffffffff, 0xffffffff, /* nonexistent */
1847 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001848
Martin Roth2ed0aa22016-01-05 20:58:58 -07001849 0xffffffff, 0xffffffff, /* nonexistent */
1850 0xffffffff, 0xffffffff, /* nonexistent */
1851 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001852 };
1853
1854 static const u32 command_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001855 0x04020208, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001856 0xffffffff, 0xffffffff, /* nonexistent */
1857 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001858
Stefan Reinauer278534d2008-10-29 04:51:07 +00001859 0x00060108, 0x00000000, /* DDR400 FSB533 */
1860 0x04020108, 0x00000000, /* DDR533 FSB533 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001861 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001862
1863 0x00040318, 0x00000000, /* DDR400 FSB667 */
1864 0x04020118, 0x00000000, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001865 0x02010804, 0x00000000, /* DDR667 FSB667 */
1866
Martin Roth2ed0aa22016-01-05 20:58:58 -07001867 0xffffffff, 0xffffffff, /* nonexistent */
1868 0xffffffff, 0xffffffff, /* nonexistent */
1869 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001870
Martin Roth2ed0aa22016-01-05 20:58:58 -07001871 0xffffffff, 0xffffffff, /* nonexistent */
1872 0xffffffff, 0xffffffff, /* nonexistent */
1873 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001874 };
1875
Julius Wernercd49cce2019-03-05 16:53:33 -08001876#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001877 /* i945 G/P */
1878 static const u32 data_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001879 0xffffffff, 0xffffffff, /* nonexistent */
1880 0xffffffff, 0xffffffff, /* nonexistent */
1881 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001882
1883 0x10080201, 0x00000000, /* DDR400 FSB533 */
1884 0x00100401, 0x00000000, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001885 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001886
Martin Roth2ed0aa22016-01-05 20:58:58 -07001887 0xffffffff, 0xffffffff, /* nonexistent */
1888 0xffffffff, 0xffffffff, /* nonexistent */
1889 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001890
1891 0x04020108, 0x00000000, /* DDR400 FSB800 */
1892 0x00020108, 0x00000000, /* DDR533 FSB800 */
1893 0x00080201, 0x00000000, /* DDR667 FSB800 */
1894
1895 0x00010402, 0x00000000, /* DDR400 FSB1066 */
1896 0x04020108, 0x00000000, /* DDR533 FSB1066 */
1897 0x08040110, 0x00000000, /* DDR667 FSB1066 */
1898 };
1899
1900 static const u32 command_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001901 0xffffffff, 0xffffffff, /* nonexistent */
1902 0xffffffff, 0xffffffff, /* nonexistent */
1903 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001904
1905 0x00010800, 0x00000402, /* DDR400 FSB533 */
1906 0x01000400, 0x00000200, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001907 0x00020904, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001908
Martin Roth2ed0aa22016-01-05 20:58:58 -07001909 0xffffffff, 0xffffffff, /* nonexistent */
1910 0xffffffff, 0xffffffff, /* nonexistent */
1911 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001912
1913 0x02010804, 0x00000000, /* DDR400 FSB800 */
1914 0x00010402, 0x00000000, /* DDR533 FSB800 */
Arthur Heymans8b6df622016-10-16 10:58:01 +02001915 0x04020130, 0x00000008, /* DDR667 FSB800 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001916
1917 0x00020904, 0x00000000, /* DDR400 FSB1066 */
1918 0x02010804, 0x00000000, /* DDR533 FSB1066 */
1919 0x180601c0, 0x00000020, /* DDR667 FSB1066 */
1920 };
1921#endif
1922
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001923 printk(BIOS_DEBUG, "Programming Clock Crossing...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001924
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001925 printk(BIOS_DEBUG, "MEM=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001926 switch (memclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001927 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001928 printk(BIOS_DEBUG, "400");
1929 idx += 0;
1930 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001931 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001932 printk(BIOS_DEBUG, "533");
1933 idx += 2;
1934 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001935 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001936 printk(BIOS_DEBUG, "667");
1937 idx += 4;
1938 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001939 default:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001940 printk(BIOS_DEBUG, "RSVD %x", memclk());
1941 return;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001942 }
1943
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001944 printk(BIOS_DEBUG, " FSB=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001945 switch (fsbclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001946 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001947 printk(BIOS_DEBUG, "400");
1948 idx += 0;
1949 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001950 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001951 printk(BIOS_DEBUG, "533");
1952 idx += 6;
1953 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001954 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001955 printk(BIOS_DEBUG, "667");
1956 idx += 12;
1957 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001958 case 800:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001959 printk(BIOS_DEBUG, "800");
1960 idx += 18;
1961 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001962 case 1066:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001963 printk(BIOS_DEBUG, "1066");
1964 idx += 24;
1965 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001966 default:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001967 printk(BIOS_DEBUG, "RSVD %x\n", fsbclk());
1968 return;
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001969 }
1970
Arthur Heymans70a8e342017-03-09 11:30:23 +01001971 if (command_clock_crossing[idx] == 0xffffffff)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001972 printk(BIOS_DEBUG, "Invalid MEM/FSB combination!\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001973
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001974 MCHBAR32(CCCFT + 0) = command_clock_crossing[idx];
1975 MCHBAR32(CCCFT + 4) = command_clock_crossing[idx + 1];
1976
Stefan Reinauer278534d2008-10-29 04:51:07 +00001977 MCHBAR32(C0DCCFT + 0) = data_clock_crossing[idx];
1978 MCHBAR32(C0DCCFT + 4) = data_clock_crossing[idx + 1];
1979 MCHBAR32(C1DCCFT + 0) = data_clock_crossing[idx];
1980 MCHBAR32(C1DCCFT + 4) = data_clock_crossing[idx + 1];
1981
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001982 printk(BIOS_DEBUG, "... ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001983}
1984
1985static void sdram_disable_fast_dispatch(void)
1986{
1987 u32 reg32;
1988
1989 reg32 = MCHBAR32(FSBPMC3);
1990 reg32 |= (1 << 1);
1991 MCHBAR32(FSBPMC3) = reg32;
1992
1993 reg32 = MCHBAR32(SBTEST);
1994 reg32 |= (3 << 1);
1995 MCHBAR32(SBTEST) = reg32;
1996}
1997
1998static void sdram_pre_jedec_initialization(void)
1999{
2000 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002001
Stefan Reinauer278534d2008-10-29 04:51:07 +00002002 reg32 = MCHBAR32(WCC);
2003 reg32 &= 0x113ff3ff;
2004 reg32 |= (4 << 29) | (3 << 25) | (1 << 10);
2005 MCHBAR32(WCC) = reg32;
2006
2007 MCHBAR32(SMVREFC) |= (1 << 6);
2008
2009 MCHBAR32(MMARB0) &= ~(3 << 17);
2010 MCHBAR32(MMARB0) |= (1 << 21) | (1 << 16);
2011
2012 MCHBAR32(MMARB1) &= ~(7 << 8);
2013 MCHBAR32(MMARB1) |= (3 << 8);
2014
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002015 /* Adaptive Idle Timer Control */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002016 MCHBAR32(C0AIT) = 0x000006c4;
2017 MCHBAR32(C0AIT+4) = 0x871a066d;
2018
2019 MCHBAR32(C1AIT) = 0x000006c4;
2020 MCHBAR32(C1AIT+4) = 0x871a066d;
2021}
2022
2023#define EA_DUALCHANNEL_XOR_BANK_RANK_MODE (0xd4 << 24)
2024#define EA_DUALCHANNEL_XOR_BANK_MODE (0xf4 << 24)
2025#define EA_DUALCHANNEL_BANK_RANK_MODE (0xc2 << 24)
2026#define EA_DUALCHANNEL_BANK_MODE (0xe2 << 24)
2027#define EA_SINGLECHANNEL_XOR_BANK_RANK_MODE (0x91 << 24)
2028#define EA_SINGLECHANNEL_XOR_BANK_MODE (0xb1 << 24)
2029#define EA_SINGLECHANNEL_BANK_RANK_MODE (0x80 << 24)
2030#define EA_SINGLECHANNEL_BANK_MODE (0xa0 << 24)
2031
2032static void sdram_enhanced_addressing_mode(struct sys_info *sysinfo)
2033{
2034 u32 chan0 = 0, chan1 = 0;
Paul Menzeld789b6582020-03-14 11:50:34 +01002035 bool chan0_dualsided, chan1_dualsided, chan0_populated, chan1_populated;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002036
Paul Menzel842dd332020-03-14 10:37:40 +01002037 chan0_populated = (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002038 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED);
Elyes HAOUAS308aeff2017-02-24 12:53:07 +01002039 chan1_populated = (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002040 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002041 chan0_dualsided = (sysinfo->banksize[1] || sysinfo->banksize[3]);
2042 chan1_dualsided = (sysinfo->banksize[5] || sysinfo->banksize[7]);
2043
2044 if (sdram_capabilities_enhanced_addressing_xor()) {
2045 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002046 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002047 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002048 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002049 chan0 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002050 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002051 chan0 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002052 }
2053 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002054 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002055 chan1 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002056 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002057 chan1 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002058 }
2059 } else {
2060 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002061 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002062 chan0 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002063 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002064 chan0 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002065
Arthur Heymans70a8e342017-03-09 11:30:23 +01002066 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002067 chan1 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002068 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002069 chan1 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002070 }
2071 } else {
2072 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002073 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002074 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002075 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002076 chan0 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002077 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002078 chan0 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002079 }
2080 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002081 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002082 chan1 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002083 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002084 chan1 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002085 }
2086 } else {
2087 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002088 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002089 chan0 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002090 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002091 chan0 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002092
Arthur Heymans70a8e342017-03-09 11:30:23 +01002093 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002094 chan1 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002095 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002096 chan1 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002097 }
2098 }
2099
2100 MCHBAR32(C0DRC1) &= 0x00ffffff;
2101 MCHBAR32(C0DRC1) |= chan0;
2102 MCHBAR32(C1DRC1) &= 0x00ffffff;
2103 MCHBAR32(C1DRC1) |= chan1;
2104}
2105
2106static void sdram_post_jedec_initialization(struct sys_info *sysinfo)
2107{
2108 u32 reg32;
2109
2110 /* Enable Channel XORing for Dual Channel Interleave */
2111 if (sysinfo->interleaved) {
2112 reg32 = MCHBAR32(DCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002113 reg32 &= ~(1 << 10);
Stefan Reinauer30140a52009-03-11 16:20:39 +00002114 reg32 |= (1 << 9);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002115 MCHBAR32(DCC) = reg32;
2116 }
2117
2118 /* DRAM mode optimizations */
2119 sdram_enhanced_addressing_mode(sysinfo);
2120
2121 reg32 = MCHBAR32(FSBPMC3);
2122 reg32 &= ~(1 << 1);
2123 MCHBAR32(FSBPMC3) = reg32;
2124
2125 reg32 = MCHBAR32(SBTEST);
2126 reg32 &= ~(1 << 2);
2127 MCHBAR32(SBTEST) = reg32;
2128
2129 reg32 = MCHBAR32(SBOCC);
2130 reg32 &= 0xffbdb6ff;
2131 reg32 |= (0xbdb6 << 8) | (1 << 0);
2132 MCHBAR32(SBOCC) = reg32;
2133}
2134
2135static void sdram_power_management(struct sys_info *sysinfo)
2136{
Stefan Reinauer278534d2008-10-29 04:51:07 +00002137 u16 reg16;
2138 u32 reg32;
2139 int integrated_graphics = 1;
2140 int i;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002141
Stefan Reinauer278534d2008-10-29 04:51:07 +00002142 reg32 = MCHBAR32(C0DRT2);
2143 reg32 &= 0xffffff00;
2144 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002145 reg32 |= (1 << 5) | (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002146 MCHBAR32(C0DRT2) = reg32;
2147
2148 reg32 = MCHBAR32(C1DRT2);
2149 reg32 &= 0xffffff00;
2150 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002151 reg32 |= (1 << 5) | (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002152 MCHBAR32(C1DRT2) = reg32;
2153
2154 reg32 = MCHBAR32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002155
2156 reg32 |= (1 << 12) | (1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002157 MCHBAR32(C0DRC1) = reg32;
2158
2159 reg32 = MCHBAR32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002160
2161 reg32 |= (1 << 12) | (1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002162 MCHBAR32(C1DRC1) = reg32;
2163
Julius Wernercd49cce2019-03-05 16:53:33 -08002164 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002165 if (i945_silicon_revision() > 1) {
2166 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2167 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002168
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002169 MCHBAR16(UPMC1) = 0x1010 | peg_bits;
2170 } else {
2171 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2172 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002173
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002174 /* Rev 0 and 1 */
2175 MCHBAR16(UPMC1) = 0x0010 | peg_bits;
2176 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002177 }
2178
2179 reg16 = MCHBAR16(UPMC2);
2180 reg16 &= 0xfc00;
2181 reg16 |= 0x0100;
2182 MCHBAR16(UPMC2) = reg16;
2183
2184 MCHBAR32(UPMC3) = 0x000f06ff;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002185
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002186 for (i = 0; i < 5; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002187 MCHBAR32(UPMC3) &= ~(1 << 16);
2188 MCHBAR32(UPMC3) |= (1 << 16);
2189 }
2190
2191 MCHBAR32(GIPMC1) = 0x8000000c;
2192
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002193 reg16 = MCHBAR16(CPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002194 reg16 &= ~(7 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002195 if (i945_silicon_revision() > 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002196 reg16 |= (6 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002197 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002198 reg16 |= (4 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002199 MCHBAR16(CPCTL) = reg16;
2200
Stefan Reinauer30140a52009-03-11 16:20:39 +00002201#if 0
Stefan Reinauer278534d2008-10-29 04:51:07 +00002202 if ((MCHBAR32(ECO) & (1 << 16)) != 0) {
Stefan Reinauer30140a52009-03-11 16:20:39 +00002203#else
2204 if (i945_silicon_revision() != 0) {
2205#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002206 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002207 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002208 MCHBAR32(HGIPMC2) = 0x0d590d59;
2209 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002210 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002211 MCHBAR32(HGIPMC2) = 0x155b155b;
2212 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002213 }
2214 } else {
2215 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002216 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002217 MCHBAR32(HGIPMC2) = 0x09c409c4;
2218 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002219 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002220 MCHBAR32(HGIPMC2) = 0x0fa00fa0;
2221 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002222 }
2223 }
2224
2225 MCHBAR32(FSBPMC1) = 0x8000000c;
2226
2227 reg32 = MCHBAR32(C2C3TT);
2228 reg32 &= 0xffff0000;
2229 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002230 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002231 reg32 |= 0x0600;
2232 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002233 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002234 reg32 |= 0x0480;
2235 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002236 }
2237 MCHBAR32(C2C3TT) = reg32;
2238
2239 reg32 = MCHBAR32(C3C4TT);
2240 reg32 &= 0xffff0000;
2241 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002242 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002243 reg32 |= 0x0b80;
2244 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002245 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002246 reg32 |= 0x0980;
2247 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002248 }
2249 MCHBAR32(C3C4TT) = reg32;
2250
Arthur Heymans70a8e342017-03-09 11:30:23 +01002251 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002252 MCHBAR32(ECO) &= ~(1 << 16);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002253 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002254 MCHBAR32(ECO) |= (1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002255
2256#if 0
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002257
Arthur Heymans70a8e342017-03-09 11:30:23 +01002258 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002259 MCHBAR32(FSBPMC3) &= ~(1 << 29);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002260 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002261 MCHBAR32(FSBPMC3) |= (1 << 29);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002262#endif
2263 MCHBAR32(FSBPMC3) &= ~(1 << 29);
2264
2265 MCHBAR32(FSBPMC3) |= (1 << 21);
2266
2267 MCHBAR32(FSBPMC3) &= ~(1 << 19);
2268
2269 MCHBAR32(FSBPMC3) &= ~(1 << 13);
2270
2271 reg32 = MCHBAR32(FSBPMC4);
2272 reg32 &= ~(3 << 24);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002273 reg32 |= (2 << 24);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002274 MCHBAR32(FSBPMC4) = reg32;
2275
2276 MCHBAR32(FSBPMC4) |= (1 << 21);
2277
2278 MCHBAR32(FSBPMC4) |= (1 << 5);
2279
Arthur Heymans70a8e342017-03-09 11:30:23 +01002280 if ((i945_silicon_revision() < 2)) { /* || cpuid() = 0x6e8 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002281 /* stepping 0 and 1 or CPUID 6e8 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002282 MCHBAR32(FSBPMC4) &= ~(1 << 4);
2283 } else {
Stefan Reinauer30140a52009-03-11 16:20:39 +00002284 MCHBAR32(FSBPMC4) |= (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002285 }
2286
Angel Ponse3c68d22020-06-08 12:09:03 +02002287 pci_or_config8(PCI_DEV(0, 0x0, 0), 0xfc, 1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002288
Angel Ponse3c68d22020-06-08 12:09:03 +02002289 pci_or_config8(PCI_DEV(0, 0x2, 0), 0xc1, 1 << 2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002290
Stefan Reinauerde3206a2010-02-22 06:09:43 +00002291#ifdef C2_SELF_REFRESH_DISABLE
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002292
Stefan Reinauer278534d2008-10-29 04:51:07 +00002293 if (integrated_graphics) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002294 printk(BIOS_DEBUG, "C2 self-refresh with IGD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002295 MCHBAR16(MIPMC4) = 0x0468;
2296 MCHBAR16(MIPMC5) = 0x046c;
2297 MCHBAR16(MIPMC6) = 0x046c;
2298 } else {
2299 MCHBAR16(MIPMC4) = 0x6468;
2300 MCHBAR16(MIPMC5) = 0x646c;
2301 MCHBAR16(MIPMC6) = 0x646c;
2302 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002303#else
2304 if (integrated_graphics) {
2305 MCHBAR16(MIPMC4) = 0x04f8;
2306 MCHBAR16(MIPMC5) = 0x04fc;
2307 MCHBAR16(MIPMC6) = 0x04fc;
2308 } else {
2309 MCHBAR16(MIPMC4) = 0x64f8;
2310 MCHBAR16(MIPMC5) = 0x64fc;
2311 MCHBAR16(MIPMC6) = 0x64fc;
2312 }
2313
2314#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002315
2316 reg32 = MCHBAR32(PMCFG);
2317 reg32 &= ~(3 << 17);
2318 reg32 |= (2 << 17);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002319 MCHBAR32(PMCFG) = reg32;
2320
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002321 MCHBAR32(PMCFG) |= (1 << 4);
2322
Stefan Reinauer278534d2008-10-29 04:51:07 +00002323 reg32 = MCHBAR32(0xc30);
2324 reg32 &= 0xffffff00;
2325 reg32 |= 0x01;
2326 MCHBAR32(0xc30) = reg32;
2327
2328 MCHBAR32(0xb18) &= ~(1 << 21);
2329}
2330
2331static void sdram_thermal_management(void)
2332{
Stefan Reinauer278534d2008-10-29 04:51:07 +00002333
Stefan Reinauer278534d2008-10-29 04:51:07 +00002334 MCHBAR8(TCO1) = 0x00;
2335 MCHBAR8(TCO0) = 0x00;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002336
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002337 /* The Thermal Sensors for DIMMs at 0x50, 0x52 are at I2C addr 0x30/0x32. */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002338
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002339 /* TODO This is not implemented yet. Volunteers? */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002340}
2341
2342static void sdram_save_receive_enable(void)
2343{
2344 int i;
2345 u32 reg32;
2346 u8 values[4];
2347
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002348 /* The following values are stored to an unused CMOS area and restored instead of
2349 * recalculated in case of an S3 resume.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002350 *
Arthur Heymans70a8e342017-03-09 11:30:23 +01002351 * C0WL0REOST [7:0] -> 8 bit
2352 * C1WL0REOST [7:0] -> 8 bit
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002353 * RCVENMT [11:8] [3:0] -> 8 bit
2354 * C0DRT1 [27:24] -> 4 bit
2355 * C1DRT1 [27:24] -> 4 bit
2356 */
2357
2358 values[0] = MCHBAR8(C0WL0REOST);
2359 values[1] = MCHBAR8(C1WL0REOST);
2360
2361 reg32 = MCHBAR32(RCVENMT);
2362 values[2] = (u8)((reg32 >> (8 - 4)) & 0xf0) | (reg32 & 0x0f);
2363
2364 reg32 = MCHBAR32(C0DRT1);
2365 values[3] = (reg32 >> 24) & 0x0f;
2366 reg32 = MCHBAR32(C1DRT1);
2367 values[3] |= (reg32 >> (24 - 4)) & 0xf0;
2368
2369 /* coreboot only uses bytes 0 - 127 for its CMOS values so far
Edwin Beasanteb50c7d2010-07-06 21:05:04 +00002370 * so we grab bytes 128 - 131 to save the receive enable values
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002371 */
2372
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002373 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002374 cmos_write(values[i], 128 + i);
2375}
2376
2377static void sdram_recover_receive_enable(void)
2378{
2379 int i;
2380 u32 reg32;
2381 u8 values[4];
2382
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002383 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002384 values[i] = cmos_read(128 + i);
2385
2386 MCHBAR8(C0WL0REOST) = values[0];
2387 MCHBAR8(C1WL0REOST) = values[1];
2388
2389 reg32 = MCHBAR32(RCVENMT);
2390 reg32 &= ~((0x0f << 8) | (0x0f << 0));
2391 reg32 |= ((u32)(values[2] & 0xf0) << (8 - 4)) | (values[2] & 0x0f);
2392 MCHBAR32(RCVENMT) = reg32;
2393
2394 reg32 = MCHBAR32(C0DRT1) & ~(0x0f << 24);
2395 reg32 |= (u32)(values[3] & 0x0f) << 24;
2396 MCHBAR32(C0DRT1) = reg32;
2397
2398 reg32 = MCHBAR32(C1DRT1) & ~(0x0f << 24);
2399 reg32 |= (u32)(values[3] & 0xf0) << (24 - 4);
2400 MCHBAR32(C1DRT1) = reg32;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002401}
2402
Stefan Reinauer278534d2008-10-29 04:51:07 +00002403static void sdram_program_receive_enable(struct sys_info *sysinfo)
2404{
2405 MCHBAR32(REPC) |= (1 << 0);
2406
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002407 /* Program Receive Enable Timings */
2408 if (sysinfo->boot_path == BOOT_PATH_RESUME) {
2409 sdram_recover_receive_enable();
2410 } else {
2411 receive_enable_adjust(sysinfo);
2412 sdram_save_receive_enable();
2413 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002414
2415 MCHBAR32(C0DRC1) |= (1 << 6);
2416 MCHBAR32(C1DRC1) |= (1 << 6);
2417 MCHBAR32(C0DRC1) &= ~(1 << 6);
2418 MCHBAR32(C1DRC1) &= ~(1 << 6);
2419
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002420 MCHBAR32(MIPMC3) |= (0x0f << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002421}
2422
2423/**
2424 * @brief Enable On-Die Termination for DDR2.
2425 *
2426 */
2427
2428static void sdram_on_die_termination(struct sys_info *sysinfo)
2429{
2430 static const u32 odt[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002431 0x00024911, 0xe0010000,
2432 0x00049211, 0xe0020000,
2433 0x0006db11, 0xe0030000,
Stefan Reinauer278534d2008-10-29 04:51:07 +00002434 };
2435
2436 u32 reg32;
2437 int cas;
2438
2439 reg32 = MCHBAR32(ODTC);
2440 reg32 &= ~(3 << 16);
2441 reg32 |= (1 << 14) | (1 << 6) | (2 << 16);
2442 MCHBAR32(ODTC) = reg32;
2443
Paul Menzelb4d9f222020-03-14 10:34:29 +01002444 if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002445 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
Elyes HAOUAS38424982016-08-21 12:01:04 +02002446 printk(BIOS_DEBUG, "one dimm per channel config..\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002447
Stefan Reinauer278534d2008-10-29 04:51:07 +00002448 reg32 = MCHBAR32(C0ODT);
2449 reg32 &= ~(7 << 28);
2450 MCHBAR32(C0ODT) = reg32;
2451 reg32 = MCHBAR32(C1ODT);
2452 reg32 &= ~(7 << 28);
2453 MCHBAR32(C1ODT) = reg32;
2454 }
2455
2456 cas = sysinfo->cas;
2457
2458 reg32 = MCHBAR32(C0ODT) & 0xfff00000;
Angel Pons30492572020-06-11 13:24:54 +02002459 reg32 |= odt[(cas - 3) * 2];
Stefan Reinauer278534d2008-10-29 04:51:07 +00002460 MCHBAR32(C0ODT) = reg32;
2461
2462 reg32 = MCHBAR32(C1ODT) & 0xfff00000;
Angel Pons30492572020-06-11 13:24:54 +02002463 reg32 |= odt[(cas - 3) * 2];
Stefan Reinauer278534d2008-10-29 04:51:07 +00002464 MCHBAR32(C1ODT) = reg32;
2465
2466 reg32 = MCHBAR32(C0ODT + 4) & 0x1fc8ffff;
Angel Pons30492572020-06-11 13:24:54 +02002467 reg32 |= odt[((cas - 3) * 2) + 1];
Stefan Reinauer278534d2008-10-29 04:51:07 +00002468 MCHBAR32(C0ODT + 4) = reg32;
2469
2470 reg32 = MCHBAR32(C1ODT + 4) & 0x1fc8ffff;
Angel Pons30492572020-06-11 13:24:54 +02002471 reg32 |= odt[((cas - 3) * 2) + 1];
Stefan Reinauer278534d2008-10-29 04:51:07 +00002472 MCHBAR32(C1ODT + 4) = reg32;
2473}
2474
2475/**
2476 * @brief Enable clocks to populated sockets
2477 */
2478
2479static void sdram_enable_memory_clocks(struct sys_info *sysinfo)
2480{
2481 u8 clocks[2] = { 0, 0 };
2482
Julius Wernercd49cce2019-03-05 16:53:33 -08002483#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002484#define CLOCKS_WIDTH 2
Julius Wernercd49cce2019-03-05 16:53:33 -08002485#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002486#define CLOCKS_WIDTH 3
2487#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002488 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002489 clocks[0] |= (1 << CLOCKS_WIDTH) - 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002490
2491 if (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002492 clocks[0] |= ((1 << CLOCKS_WIDTH) - 1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002493
2494 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002495 clocks[1] |= (1 << CLOCKS_WIDTH) - 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002496
2497 if (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002498 clocks[1] |= ((1 << CLOCKS_WIDTH) - 1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002499
Julius Wernercd49cce2019-03-05 16:53:33 -08002500#if CONFIG(OVERRIDE_CLOCK_DISABLE)
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002501 /* Usually system firmware turns off system memory clock signals to unused SO-DIMM slots
2502 * to reduce EMI and power consumption.
2503 * However, the Kontron 986LCD-M does not like unused clock signals to be disabled.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002504 */
2505
2506 clocks[0] = 0xf; /* force all clock gate pairs to enable */
2507 clocks[1] = 0xf; /* force all clock gate pairs to enable */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002508#endif
2509
2510 MCHBAR8(C0DCLKDIS) = clocks[0];
2511 MCHBAR8(C1DCLKDIS) = clocks[1];
2512}
2513
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002514#define RTT_ODT_NONE 0
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002515#define RTT_ODT_50_OHM ((1 << 9) | (1 << 5))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002516#define RTT_ODT_75_OHM (1 << 5)
2517#define RTT_ODT_150_OHM (1 << 9)
2518
Arthur Heymans70a8e342017-03-09 11:30:23 +01002519#define EMRS_OCD_DEFAULT ((1 << 12) | (1 << 11) | (1 << 10))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002520
2521#define MRS_CAS_3 (3 << 7)
2522#define MRS_CAS_4 (4 << 7)
2523#define MRS_CAS_5 (5 << 7)
2524
2525#define MRS_TWR_3 (2 << 12)
2526#define MRS_TWR_4 (3 << 12)
2527#define MRS_TWR_5 (4 << 12)
2528
2529#define MRS_BT (1 << 6)
2530
2531#define MRS_BL4 (2 << 3)
2532#define MRS_BL8 (3 << 3)
2533
2534static void sdram_jedec_enable(struct sys_info *sysinfo)
2535{
2536 int i, nonzero;
2537 u32 bankaddr = 0, tmpaddr, mrsaddr = 0;
2538
2539 for (i = 0, nonzero = -1; i < 8; i++) {
Elyes HAOUAS01912202019-01-19 16:36:38 +01002540 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002541 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002542
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002543 printk(BIOS_DEBUG, "jedec enable sequence: bank %d\n", i);
Elyes HAOUAS01912202019-01-19 16:36:38 +01002544
2545 if (nonzero != -1) {
2546 if (sysinfo->interleaved && nonzero < 4 && i >= 4) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002547 bankaddr = 0x40;
Elyes HAOUAS01912202019-01-19 16:36:38 +01002548 } else {
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002549 printk(BIOS_DEBUG, "bankaddr from bank size of rank %d\n",
2550 nonzero);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002551 bankaddr += sysinfo->banksize[nonzero] <<
2552 (sysinfo->interleaved ? 26 : 25);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002553 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002554 }
2555
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002556 /*
2557 * We have a bank with a non-zero size... Remember it
Stefan Reinauer278534d2008-10-29 04:51:07 +00002558 * for the next offset we have to calculate
2559 */
2560 nonzero = i;
2561
2562 /* Get CAS latency set up */
2563 switch (sysinfo->cas) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002564 case 5:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002565 mrsaddr = MRS_CAS_5;
2566 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002567 case 4:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002568 mrsaddr = MRS_CAS_4;
2569 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002570 case 3:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002571 mrsaddr = MRS_CAS_3;
2572 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002573 default:
2574 die("Jedec Error (CAS).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002575 }
2576
2577 /* Get tWR set */
2578 switch (sysinfo->twr) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002579 case 5:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002580 mrsaddr |= MRS_TWR_5;
2581 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002582 case 4:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002583 mrsaddr |= MRS_TWR_4;
2584 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002585 case 3:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002586 mrsaddr |= MRS_TWR_3;
2587 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002588 default:
2589 die("Jedec Error (tWR).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002590 }
2591
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002592 /* Set "Burst Type" */
2593 mrsaddr |= MRS_BT;
2594
Stefan Reinauer278534d2008-10-29 04:51:07 +00002595 /* Interleaved */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002596 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002597 mrsaddr = mrsaddr << 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002598
2599 /* Only burst length 8 supported */
2600 mrsaddr |= MRS_BL8;
2601
2602 /* Apply NOP */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002603 PRINTK_DEBUG("Apply NOP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002604 do_ram_command(RAM_COMMAND_NOP);
2605 ram_read32(bankaddr);
2606
2607 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002608 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002609 do_ram_command(RAM_COMMAND_PRECHARGE);
2610 ram_read32(bankaddr);
2611
2612 /* Extended Mode Register Set (2) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002613 PRINTK_DEBUG("Extended Mode Register Set(2)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002614 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_2);
2615 ram_read32(bankaddr);
2616
2617 /* Extended Mode Register Set (3) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002618 PRINTK_DEBUG("Extended Mode Register Set(3)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002619 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_3);
2620 ram_read32(bankaddr);
2621
2622 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002623 PRINTK_DEBUG("Extended Mode Register Set\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002624 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2625 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002626 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002627 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002628 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002629 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002630 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002631 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002632 ram_read32(tmpaddr);
2633
2634 /* Mode Register Set: Reset DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002635 PRINTK_DEBUG("MRS: Reset DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002636 do_ram_command(RAM_COMMAND_MRS);
2637 tmpaddr = bankaddr;
2638 tmpaddr |= mrsaddr;
2639 /* Set DLL reset bit */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002640 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002641 tmpaddr |= (1 << 12);
2642 else
2643 tmpaddr |= (1 << 11);
2644 ram_read32(tmpaddr);
2645
2646 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002647 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002648 do_ram_command(RAM_COMMAND_PRECHARGE);
2649 ram_read32(bankaddr);
2650
2651 /* CAS before RAS Refresh */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002652 PRINTK_DEBUG("CAS before RAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002653 do_ram_command(RAM_COMMAND_CBR);
2654
2655 /* CBR wants two READs */
2656 ram_read32(bankaddr);
2657 ram_read32(bankaddr);
2658
2659 /* Mode Register Set: Enable DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002660 PRINTK_DEBUG("MRS: Enable DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002661 do_ram_command(RAM_COMMAND_MRS);
2662
2663 tmpaddr = bankaddr;
2664 tmpaddr |= mrsaddr;
2665 ram_read32(tmpaddr);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002666
Stefan Reinauer278534d2008-10-29 04:51:07 +00002667 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002668 PRINTK_DEBUG("Extended Mode Register Set: ODT/OCD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002669 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002670
Stefan Reinauer278534d2008-10-29 04:51:07 +00002671 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002672 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002673 tmpaddr |= RTT_ODT_75_OHM | EMRS_OCD_DEFAULT;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002674 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002675 tmpaddr |= ((RTT_ODT_150_OHM | EMRS_OCD_DEFAULT) << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002676 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002677 tmpaddr |= RTT_ODT_150_OHM | EMRS_OCD_DEFAULT;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002678 ram_read32(tmpaddr);
2679
2680 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002681 PRINTK_DEBUG("Extended Mode Register Set: OCD Exit\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002682 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2683
2684 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002685 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002686 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002687 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002688 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002689 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002690 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002691 ram_read32(tmpaddr);
2692 }
2693}
2694
2695static void sdram_init_complete(void)
2696{
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002697 PRINTK_DEBUG("Normal Operation\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002698 do_ram_command(RAM_COMMAND_NORMAL);
2699}
2700
2701static void sdram_setup_processor_side(void)
2702{
2703 if (i945_silicon_revision() == 0)
2704 MCHBAR32(FSBPMC3) |= (1 << 2);
2705
2706 MCHBAR8(0xb00) |= 1;
2707
2708 if (i945_silicon_revision() == 0)
2709 MCHBAR32(SLPCTL) |= (1 << 8);
2710}
2711
Stefan Reinauer278534d2008-10-29 04:51:07 +00002712/**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002713 * @param boot_path: 0 = normal, 1 = reset, 2 = resume from s3
Martin Rothf4cb4122015-01-06 10:27:39 -07002714 * @param spd_addresses pointer to a list of SPD addresses
Stefan Reinauer278534d2008-10-29 04:51:07 +00002715 */
Sven Schnelle541269b2011-02-21 09:39:17 +00002716void sdram_initialize(int boot_path, const u8 *spd_addresses)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002717{
2718 struct sys_info sysinfo;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002719
Patrick Georgi771328f2015-07-13 19:24:07 +02002720 timestamp_add_now(TS_BEFORE_INITRAM);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002721 printk(BIOS_DEBUG, "Setting up RAM controller.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002722
2723 memset(&sysinfo, 0, sizeof(sysinfo));
2724
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002725 sysinfo.boot_path = boot_path;
Sven Schnelle541269b2011-02-21 09:39:17 +00002726 sysinfo.spd_addresses = spd_addresses;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002727
Stefan Reinauer278534d2008-10-29 04:51:07 +00002728 /* Look at the type of DIMMs and verify all DIMMs are x8 or x16 width */
2729 sdram_get_dram_configuration(&sysinfo);
2730
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002731 /* If error, do cold boot */
2732 sdram_detect_errors(&sysinfo);
2733
Stefan Reinauer278534d2008-10-29 04:51:07 +00002734 /* Program PLL settings */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002735 sdram_program_pll_settings(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002736
Arthur Heymans18537812016-12-28 21:20:45 +01002737 /*
2738 * Program Graphics Frequency
2739 * Set core display and render clock on 945GC to the max
2740 */
Julius Wernercd49cce2019-03-05 16:53:33 -08002741 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM))
Arthur Heymans18537812016-12-28 21:20:45 +01002742 sdram_program_graphics_frequency(&sysinfo);
2743 else
2744 pci_write_config16(PCI_DEV(0, 2, 0), GCFC, 0x0534);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002745
2746 /* Program System Memory Frequency */
2747 sdram_program_memory_frequency(&sysinfo);
2748
2749 /* Determine Mode of Operation (Interleaved etc) */
2750 sdram_set_channel_mode(&sysinfo);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002751
Stefan Reinauer278534d2008-10-29 04:51:07 +00002752 /* Program Clock Crossing values */
2753 sdram_program_clock_crossing();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002754
Stefan Reinauer278534d2008-10-29 04:51:07 +00002755 /* Disable fast dispatch */
2756 sdram_disable_fast_dispatch();
2757
2758 /* Enable WIODLL Power Down in ACPI states */
2759 MCHBAR32(C0DMC) |= (1 << 24);
2760 MCHBAR32(C1DMC) |= (1 << 24);
2761
2762 /* Program DRAM Row Boundary/Attribute Registers */
2763
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002764 /* program row size DRB and set TOLUD */
2765 sdram_program_row_boundaries(&sysinfo);
2766
2767 /* program page size DRA */
2768 sdram_set_row_attributes(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002769
2770 /* Program CxBNKARC */
2771 sdram_set_bank_architecture(&sysinfo);
2772
2773 /* Program DRAM Timing and Control registers based on SPD */
2774 sdram_set_timing_and_control(&sysinfo);
2775
2776 /* On-Die Termination Adjustment */
2777 sdram_on_die_termination(&sysinfo);
2778
2779 /* Pre Jedec Initialization */
2780 sdram_pre_jedec_initialization();
2781
2782 /* Perform System Memory IO Initialization */
2783 sdram_initialize_system_memory_io(&sysinfo);
2784
2785 /* Perform System Memory IO Buffer Enable */
2786 sdram_enable_system_memory_io(&sysinfo);
2787
2788 /* Enable System Memory Clocks */
2789 sdram_enable_memory_clocks(&sysinfo);
2790
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002791 if (boot_path == BOOT_PATH_NORMAL) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002792 /* Jedec Initialization sequence */
2793 sdram_jedec_enable(&sysinfo);
2794 }
2795
2796 /* Program Power Management Registers */
2797 sdram_power_management(&sysinfo);
2798
2799 /* Post Jedec Init */
2800 sdram_post_jedec_initialization(&sysinfo);
2801
2802 /* Program DRAM Throttling */
2803 sdram_thermal_management();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002804
Stefan Reinauer278534d2008-10-29 04:51:07 +00002805 /* Normal Operations */
Stefan Reinaueraca6ec62009-10-26 17:12:21 +00002806 sdram_init_complete();
Stefan Reinauer278534d2008-10-29 04:51:07 +00002807
2808 /* Program Receive Enable Timings */
2809 sdram_program_receive_enable(&sysinfo);
2810
2811 /* Enable Periodic RCOMP */
2812 sdram_enable_rcomp();
2813
2814 /* Tell ICH7 that we're done */
Angel Ponse3c68d22020-06-08 12:09:03 +02002815 pci_and_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, (u8)~(1 << 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +00002816
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002817 printk(BIOS_DEBUG, "RAM initialization finished.\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002818
Stefan Reinauer278534d2008-10-29 04:51:07 +00002819 sdram_setup_processor_side();
Patrick Georgi771328f2015-07-13 19:24:07 +02002820 timestamp_add_now(TS_AFTER_INITRAM);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002821}