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