blob: 1e8cf655814ec52ed5a6e75982d69ef9d401edb2 [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>
Arthur Heymans885c2892016-10-03 17:16:48 +020019#include <device/pci_def.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020020#include <device/pci_ops.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020021#include <arch/io.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>
Patrick Georgi546953c2014-11-29 10:38:17 +010029#include <halt.h>
Stefan Reinauer278534d2008-10-29 04:51:07 +000030#include "raminit.h"
31#include "i945.h"
Arthur Heymans885c2892016-10-03 17:16:48 +020032#include "chip.h"
Arthur Heymans0ab49042017-02-06 22:40:14 +010033#include <device/dram/ddr2.h>
Patrick Georgi771328f2015-07-13 19:24:07 +020034#include <timestamp.h>
Rudolf Marekc4369532010-12-13 19:59:13 +000035
Stefan Reinauer278534d2008-10-29 04:51:07 +000036/* Debugging macros. */
Julius Wernercd49cce2019-03-05 16:53:33 -080037#if CONFIG(DEBUG_RAM_SETUP)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000038#define PRINTK_DEBUG(x...) printk(BIOS_DEBUG, x)
Stefan Reinauer278534d2008-10-29 04:51:07 +000039#else
40#define PRINTK_DEBUG(x...)
41#endif
42
Stefan Reinauer278534d2008-10-29 04:51:07 +000043#define RAM_INITIALIZATION_COMPLETE (1 << 19)
44
45#define RAM_COMMAND_SELF_REFRESH (0x0 << 16)
46#define RAM_COMMAND_NOP (0x1 << 16)
47#define RAM_COMMAND_PRECHARGE (0x2 << 16)
48#define RAM_COMMAND_MRS (0x3 << 16)
49#define RAM_COMMAND_EMRS (0x4 << 16)
50#define RAM_COMMAND_CBR (0x6 << 16)
51#define RAM_COMMAND_NORMAL (0x7 << 16)
52
53#define RAM_EMRS_1 (0x0 << 21)
54#define RAM_EMRS_2 (0x1 << 21)
55#define RAM_EMRS_3 (0x2 << 21)
56
Arthur Heymans885c2892016-10-03 17:16:48 +020057#define DEFAULT_PCI_MMIO_SIZE 768
Sven Schnelle541269b2011-02-21 09:39:17 +000058static int get_dimm_spd_address(struct sys_info *sysinfo, int device)
59{
60 if (sysinfo->spd_addresses)
61 return sysinfo->spd_addresses[device];
62 else
63 return DIMM0 + device;
64
65}
66
Arthur Heymans70a8e342017-03-09 11:30:23 +010067static inline int spd_read_byte(unsigned int device, unsigned int address)
Patrick Georgid0835952010-10-05 09:07:10 +000068{
69 return smbus_read_byte(device, address);
70}
71
Stefan Reinauerbc8613e2010-08-25 18:35:42 +000072static __attribute__((noinline)) void do_ram_command(u32 command)
Stefan Reinauer278534d2008-10-29 04:51:07 +000073{
74 u32 reg32;
75
76 reg32 = MCHBAR32(DCC);
Arthur Heymans70a8e342017-03-09 11:30:23 +010077 reg32 &= ~((3<<21) | (1<<20) | (1<<19) | (7 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +000078 reg32 |= command;
79
80 /* Also set Init Complete */
81 if (command == RAM_COMMAND_NORMAL)
82 reg32 |= RAM_INITIALIZATION_COMPLETE;
83
84 PRINTK_DEBUG(" Sending RAM command 0x%08x", reg32);
85
86 MCHBAR32(DCC) = reg32; /* This is the actual magic */
87
Stefan Reinauer779b3e32008-11-10 15:43:37 +000088 PRINTK_DEBUG("...done\n");
Stefan Reinauerd058ad12010-08-26 12:43:58 +000089
90 udelay(1);
Stefan Reinauer278534d2008-10-29 04:51:07 +000091}
92
Stefan Reinauer278534d2008-10-29 04:51:07 +000093static void ram_read32(u32 offset)
94{
Elyes HAOUAS15279a92016-07-28 21:05:26 +020095 PRINTK_DEBUG(" RAM read: %08x\n", offset);
Stefan Reinauer278534d2008-10-29 04:51:07 +000096
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080097 read32((void *)offset);
Stefan Reinauer278534d2008-10-29 04:51:07 +000098}
99
Stefan Reinauer3c0bfaf2010-12-27 11:34:57 +0000100void sdram_dump_mchbar_registers(void)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000101{
102 int i;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000103 printk(BIOS_DEBUG, "Dumping MCHBAR Registers\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000104
Arthur Heymans70a8e342017-03-09 11:30:23 +0100105 for (i = 0; i < 0xfff; i += 4) {
Stefan Reinauer278534d2008-10-29 04:51:07 +0000106 if (MCHBAR32(i) == 0)
107 continue;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000108 printk(BIOS_DEBUG, "0x%04x: 0x%08x\n", i, MCHBAR32(i));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000109 }
110}
Stefan Reinauer278534d2008-10-29 04:51:07 +0000111
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000112static int memclk(void)
113{
Julius Wernercd49cce2019-03-05 16:53:33 -0800114 int offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200115
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000116 switch (((MCHBAR32(CLKCFG) >> 4) & 7) - offset) {
117 case 1: return 400;
118 case 2: return 533;
119 case 3: return 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100120 default:
121 printk(BIOS_DEBUG, "memclk: unknown register value %x\n",
122 ((MCHBAR32(CLKCFG) >> 4) & 7) - offset);
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000123 }
124 return -1;
125}
126
Peter Stuge76d91432010-10-01 10:02:33 +0000127static u16 fsbclk(void)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000128{
Julius Wernercd49cce2019-03-05 16:53:33 -0800129 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200130 switch (MCHBAR32(CLKCFG) & 7) {
131 case 0: return 400;
132 case 1: return 533;
133 case 3: return 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100134 default:
135 printk(BIOS_DEBUG, "fsbclk: unknown register value %x\n",
136 MCHBAR32(CLKCFG) & 7);
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200137 }
138 return 0xffff;
Julius Wernercd49cce2019-03-05 16:53:33 -0800139 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200140 switch (MCHBAR32(CLKCFG) & 7) {
141 case 0: return 1066;
142 case 1: return 533;
143 case 2: return 800;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100144 default:
145 printk(BIOS_DEBUG, "fsbclk: unknown register value %x\n",
146 MCHBAR32(CLKCFG) & 7);
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200147 }
148 return 0xffff;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000149 }
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000150}
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000151
Stefan Reinauer278534d2008-10-29 04:51:07 +0000152static int sdram_capabilities_max_supported_memory_frequency(void)
153{
154 u32 reg32;
155
Patrick Georgi77d66832010-10-01 08:02:45 +0000156#if CONFIG_MAXIMUM_SUPPORTED_FREQUENCY
157 return CONFIG_MAXIMUM_SUPPORTED_FREQUENCY;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000158#endif
159
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000160 reg32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000161 reg32 &= (7 << 0);
162
163 switch (reg32) {
164 case 4: return 400;
165 case 3: return 533;
166 case 2: return 667;
167 }
168 /* Newer revisions of this chipset rather support faster memory clocks,
169 * so if it's a reserved value, return the fastest memory clock that we
170 * know of and can handle
171 */
172 return 667;
173}
174
175/**
176 * @brief determine whether chipset is capable of dual channel interleaved mode
177 *
178 * @return 1 if interleaving is supported, 0 otherwise
179 */
180static int sdram_capabilities_interleave(void)
181{
182 u32 reg32;
183
Arthur Heymans70a8e342017-03-09 11:30:23 +0100184 reg32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000185 reg32 >>= 25;
186 reg32 &= 1;
187
188 return (!reg32);
189}
190
191/**
192 * @brief determine whether chipset is capable of two memory channels
193 *
194 * @return 1 if dual channel operation is supported, 0 otherwise
195 */
196static int sdram_capabilities_dual_channel(void)
197{
198 u32 reg32;
199
Arthur Heymans70a8e342017-03-09 11:30:23 +0100200 reg32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000201 reg32 >>= 24;
202 reg32 &= 1;
203
204 return (!reg32);
205}
206
207static int sdram_capabilities_enhanced_addressing_xor(void)
208{
209 u8 reg8;
210
211 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
212 reg8 &= (1 << 7);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000213
Stefan Reinauer278534d2008-10-29 04:51:07 +0000214 return (!reg8);
215}
216
Stefan Reinauer14e22772010-04-27 06:56:47 +0000217// TODO check if we ever need this function
Stefan Reinauer53b0ea42010-03-22 11:50:52 +0000218#if 0
Stefan Reinauer278534d2008-10-29 04:51:07 +0000219static int sdram_capabilities_MEM4G_disable(void)
220{
221 u8 reg8;
222
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000223 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000224 reg8 &= (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000225
Stefan Reinauer278534d2008-10-29 04:51:07 +0000226 return (reg8 != 0);
227}
Stefan Reinauer53b0ea42010-03-22 11:50:52 +0000228#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +0000229
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000230#define GFX_FREQUENCY_CAP_166MHZ 0x04
231#define GFX_FREQUENCY_CAP_200MHZ 0x03
232#define GFX_FREQUENCY_CAP_250MHZ 0x02
233#define GFX_FREQUENCY_CAP_ALL 0x00
234
235static int sdram_capabilities_core_frequencies(void)
236{
237 u8 reg8;
238
239 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
240 reg8 &= (1 << 3) | (1 << 2) | (1 << 1);
241 reg8 >>= 1;
242
Arthur Heymans70a8e342017-03-09 11:30:23 +0100243 return reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000244}
245
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000246static void sdram_detect_errors(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000247{
248 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000249 u8 do_reset = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000250
251 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000252
Stefan Reinauer278534d2008-10-29 04:51:07 +0000253 if (reg8 & ((1<<7)|(1<<2))) {
254 if (reg8 & (1<<2)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000255 printk(BIOS_DEBUG, "SLP S4# Assertion Width Violation.\n");
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000256 /* Write back clears bit 2 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000257 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa2, reg8);
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000258 do_reset = 1;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000259
Stefan Reinauer278534d2008-10-29 04:51:07 +0000260 }
261
262 if (reg8 & (1<<7)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000263 printk(BIOS_DEBUG, "DRAM initialization was interrupted.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000264 reg8 &= ~(1<<7);
265 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa2, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000266 do_reset = 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000267 }
268
269 /* Set SLP_S3# Assertion Stretch Enable */
270 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4); /* GEN_PMCON_3 */
271 reg8 |= (1 << 3);
272 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8);
273
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000274 if (do_reset) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000275 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200276 full_reset();
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000277 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000278 }
279
280 /* Set DRAM initialization bit in ICH7 */
281 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa2);
282 reg8 |= (1<<7);
283 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa2, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000284
Peter Stuge751508a2012-01-27 22:17:09 +0100285 /* clear self refresh status if check is disabled or not a resume */
Julius Werner5d1f9a02019-03-07 17:07:26 -0800286 if (!CONFIG(CHECK_SLFRCS_ON_RESUME)
Arthur Heymans0ab49042017-02-06 22:40:14 +0100287 || sysinfo->boot_path != BOOT_PATH_RESUME) {
Patrick Georgi86a11102013-03-15 14:11:37 +0100288 MCHBAR8(SLFRCS) |= 3;
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000289 } else {
290 /* Validate self refresh config */
291 if (((sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED) ||
292 (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)) &&
Patrick Georgi86a11102013-03-15 14:11:37 +0100293 !(MCHBAR8(SLFRCS) & (1<<0))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000294 do_reset = 1;
295 }
296 if (((sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED) ||
297 (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) &&
Patrick Georgi86a11102013-03-15 14:11:37 +0100298 !(MCHBAR8(SLFRCS) & (1<<1))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000299 do_reset = 1;
300 }
301 }
302
303 if (do_reset) {
304 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200305 full_reset();
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000306 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000307}
Stefan Reinauer278534d2008-10-29 04:51:07 +0000308
Arthur Heymans0ab49042017-02-06 22:40:14 +0100309struct timings {
310 u32 min_tCLK_cas[8];
311 u32 min_tRAS;
312 u32 min_tRP;
313 u32 min_tRCD;
314 u32 min_tWR;
315 u32 min_tRFC;
316 u32 max_tRR;
317 u8 cas_mask;
318};
Stefan Reinauer278534d2008-10-29 04:51:07 +0000319
Arthur Heymans0ab49042017-02-06 22:40:14 +0100320/**
321 * @brief loop over dimms and save maximal timings
322 */
323static void gather_common_timing(struct sys_info *sysinfo,
324 struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000325{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100326
327 int i, j;
328 u8 raw_spd[SPD_SIZE_MAX_DDR2];
329 u8 dimm_mask = 0;
330
331 memset(saved_timings, 0, sizeof(*saved_timings));
332 saved_timings->max_tRR = UINT32_MAX;
333 saved_timings->cas_mask = SPD_CAS_LATENCY_DDR2_3
334 | SPD_CAS_LATENCY_DDR2_4 | SPD_CAS_LATENCY_DDR2_5;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000335
336 /**
337 * i945 supports two DIMMs, in two configurations:
338 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000339 * - single channel with two DIMMs
340 * - dual channel with one DIMM per channel
Stefan Reinauer278534d2008-10-29 04:51:07 +0000341 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000342 * In practice dual channel mainboards have their SPD at 0x50/0x52
343 * whereas single channel configurations have their SPD at 0x50/0x51.
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000344 *
Stefan Reinauer278534d2008-10-29 04:51:07 +0000345 * The capability register knows a lot about the channel configuration
Uwe Hermannd773fd32010-11-20 20:23:08 +0000346 * but for now we stick with the information we gather via SPD.
Stefan Reinauer278534d2008-10-29 04:51:07 +0000347 */
348
Arthur Heymans0ab49042017-02-06 22:40:14 +0100349 printk(BIOS_DEBUG, "This mainboard supports ");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000350 if (sdram_capabilities_dual_channel()) {
351 sysinfo->dual_channel = 1;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100352 printk(BIOS_DEBUG, "Dual Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000353 } else {
354 sysinfo->dual_channel = 0;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100355 printk(BIOS_DEBUG, "only Single Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000356 }
357
Stefan Reinauer278534d2008-10-29 04:51:07 +0000358
Arthur Heymans70a8e342017-03-09 11:30:23 +0100359 for (i = 0; i < (2 * DIMM_SOCKETS); i++) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100360 int device = get_dimm_spd_address(sysinfo, i), bytes_read;
Arthur Heymansfc31e442018-02-12 15:12:34 +0100361 struct dimm_attr_ddr2_st dimm_info;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000362
363 /* Initialize the socket information with a sane value */
364 sysinfo->dimm[i] = SYSINFO_DIMM_NOT_POPULATED;
365
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000366 /* Dual Channel not supported, but Channel 1? Bail out */
367 if (!sdram_capabilities_dual_channel() && (i >> 1))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000368 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000369
Arthur Heymans0ab49042017-02-06 22:40:14 +0100370 if (spd_read_byte(device, SPD_MEMORY_TYPE) !=
371 SPD_MEMORY_TYPE_SDRAM_DDR2) {
372 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: N/A\n",
373 (i >> 1), (i & 1));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000374 continue;
375 }
376
Arthur Heymans0ab49042017-02-06 22:40:14 +0100377 /*
378 * spd_decode_ddr2() needs a 128-byte sized array but
379 * only the first 64 bytes contain data needed for raminit.
380 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000381
Kyösti Mälkkic01a5052019-01-30 09:39:23 +0200382 bytes_read = i2c_eeprom_read(device, 0, 64, raw_spd);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100383 printk(BIOS_DEBUG, "Reading SPD using i2c block operation.\n");
Julius Wernercd49cce2019-03-05 16:53:33 -0800384 if (CONFIG(DEBUG_RAM_SETUP) && bytes_read > 0)
Arthur Heymans0ab49042017-02-06 22:40:14 +0100385 hexdump(raw_spd, bytes_read);
Arthur Heymans56619452017-09-21 09:12:42 +0200386 if (bytes_read != 64) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100387 /* Try again with SMBUS byte read */
388 printk(BIOS_DEBUG, "i2c block operation failed,"
Paul Menzel105e3682017-09-21 08:11:05 +0200389 " trying smbus byte operation.\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100390 for (j = 0; j < 64; j++)
391 raw_spd[j] = spd_read_byte(device, j);
Julius Wernercd49cce2019-03-05 16:53:33 -0800392 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100393 hexdump(raw_spd, 64);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100394 }
Arthur Heymans56619452017-09-21 09:12:42 +0200395
396 if (spd_decode_ddr2(&dimm_info, raw_spd) != SPD_STATUS_OK) {
397 printk(BIOS_WARNING, "Encountered problems with SPD, "
398 "skipping this DIMM.\n");
399 continue;
400 }
401
Julius Wernercd49cce2019-03-05 16:53:33 -0800402 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100403 dram_print_spd_ddr2(&dimm_info);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000404
Arthur Heymans0ab49042017-02-06 22:40:14 +0100405 if (dimm_info.flags.is_ecc)
406 die("\nError: ECC memory not supported by this chipset\n");
407
408 if (spd_dimm_is_registered_ddr2(dimm_info.dimm_type))
409 die("\nError: Registered memory not supported by this chipset\n");
410
411 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: ", (i >> 1),
412 (i & 1));
413 /**
414 * There are 5 different possible populations for a DIMM socket:
415 * 0. x16 double ranked (X16DS)
416 * 1. x8 double ranked (X8DS)
417 * 2. x16 single ranked (X16SS)
418 * 3. x8 double stacked (X8DDS)
419 * 4. Unpopulated
420 */
421 switch (dimm_info.width) {
422 case 8:
423 switch (dimm_info.ranks) {
424 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000425 printk(BIOS_DEBUG, "x8DDS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000426 sysinfo->dimm[i] = SYSINFO_DIMM_X8DDS;
427 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100428 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000429 printk(BIOS_DEBUG, "x8DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000430 sysinfo->dimm[i] = SYSINFO_DIMM_X8DS;
431 break;
432 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000433 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000434 }
435 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100436 case 16:
437 switch (dimm_info.ranks) {
438 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000439 printk(BIOS_DEBUG, "x16DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000440 sysinfo->dimm[i] = SYSINFO_DIMM_X16DS;
441 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100442 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000443 printk(BIOS_DEBUG, "x16SS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000444 sysinfo->dimm[i] = SYSINFO_DIMM_X16SS;
445 break;
446 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000447 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000448 }
449 break;
450 default:
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000451 die("Unsupported DDR-II memory width.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000452 }
453
Arthur Heymans0ab49042017-02-06 22:40:14 +0100454 /* Is the current DIMM a stacked DIMM? */
455 if (dimm_info.flags.stacked)
456 sysinfo->package = SYSINFO_PACKAGE_STACKED;
457
458 if (!dimm_info.flags.bl8)
459 die("Only DDR-II RAM with burst length 8 is supported by this chipset.\n");
460
461 if (dimm_info.ranksize_mb < 128)
462 die("DDR-II rank size smaller than 128MB is not supported.\n");
463
464 sysinfo->banksize[i * 2] = dimm_info.ranksize_mb / 32;
465 printk(BIOS_DEBUG, "DIMM %d side 0 = %d MB\n", i,
466 sysinfo->banksize[i * 2] * 32);
467 if (dimm_info.ranks == 2) {
468 sysinfo->banksize[(i * 2) + 1] =
469 dimm_info.ranksize_mb / 32;
470 printk(BIOS_DEBUG, "DIMM %d side 1 = %d MB\n",
471 i, sysinfo->banksize[(i * 2) + 1] * 32);
472 }
473
474
475 sysinfo->rows[i] = dimm_info.row_bits;
476 sysinfo->cols[i] = dimm_info.col_bits;
477 sysinfo->banks[i] = dimm_info.banks;
478
479 /* int min_tRAS, min_tRP, min_tRCD, min_tWR, min_tRFC; */
480 saved_timings->min_tRAS = MAX(saved_timings->min_tRAS,
481 dimm_info.tRAS);
482 saved_timings->min_tRP = MAX(saved_timings->min_tRP,
483 dimm_info.tRP);
484 saved_timings->min_tRCD = MAX(saved_timings->min_tRCD,
485 dimm_info.tRCD);
486 saved_timings->min_tWR = MAX(saved_timings->min_tWR,
487 dimm_info.tWR);
488 saved_timings->min_tRFC = MAX(saved_timings->min_tRFC,
489 dimm_info.tRFC);
490 saved_timings->max_tRR = MIN(saved_timings->max_tRR,
491 dimm_info.tRR);
492 saved_timings->cas_mask &= dimm_info.cas_supported;
493 for (j = 0; j < 8; j++) {
494 if (!(saved_timings->cas_mask & (1 << j)))
495 saved_timings->min_tCLK_cas[j] = 0;
496 else
497 saved_timings->min_tCLK_cas[j] =
498 MAX(dimm_info.cycle_time[j],
499 saved_timings->min_tCLK_cas[j]);
500 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000501 dimm_mask |= (1 << i);
502 }
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200503 if (!dimm_mask)
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000504 die("No memory installed.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000505
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200506 if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1)))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100507 /* Possibly does not boot in this case */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000508 printk(BIOS_INFO, "Channel 0 has no memory populated.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000509}
510
Arthur Heymans0ab49042017-02-06 22:40:14 +0100511static void choose_tclk(struct sys_info *sysinfo,
512 struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000513{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100514 u32 ctrl_min_tclk;
515 int try_cas;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000516
Arthur Heymans0ab49042017-02-06 22:40:14 +0100517 ctrl_min_tclk = 2 * 256 * 1000
518 / sdram_capabilities_max_supported_memory_frequency();
519 normalize_tck(&ctrl_min_tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000520
Arthur Heymans0ab49042017-02-06 22:40:14 +0100521 try_cas = spd_get_msbs(saved_timings->cas_mask);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000522
Arthur Heymans0ab49042017-02-06 22:40:14 +0100523 while (saved_timings->cas_mask & (1 << try_cas) && try_cas > 0) {
524 sysinfo->cas = try_cas;
525 sysinfo->tclk = saved_timings->min_tCLK_cas[try_cas];
526 if (sysinfo->tclk >= ctrl_min_tclk &&
527 saved_timings->min_tCLK_cas[try_cas] !=
528 saved_timings->min_tCLK_cas[try_cas - 1])
Stefan Reinauer278534d2008-10-29 04:51:07 +0000529 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100530 try_cas--;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000531 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000532
Arthur Heymans0ab49042017-02-06 22:40:14 +0100533 normalize_tck(&sysinfo->tclk);
534
535 if ((sysinfo->cas < 3) || (sysinfo->tclk == 0))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000536 die("Could not find common memory frequency and CAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000537
Arthur Heymans0ab49042017-02-06 22:40:14 +0100538 /*
539 * The loop can still results in a timing too fast for the
540 * memory controller.
541 */
542 if (sysinfo->tclk < ctrl_min_tclk)
543 sysinfo->tclk = ctrl_min_tclk;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000544
Arthur Heymans0ab49042017-02-06 22:40:14 +0100545 switch (sysinfo->tclk) {
546 case TCK_200MHZ:
547 sysinfo->memory_frequency = 400;
548 break;
549 case TCK_266MHZ:
550 sysinfo->memory_frequency = 533;
551 break;
552 case TCK_333MHZ:
553 sysinfo->memory_frequency = 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100554 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000555 }
556
Arthur Heymans0ab49042017-02-06 22:40:14 +0100557 printk(BIOS_DEBUG,
558 "Memory will be driven at %dMT with CAS=%d clocks\n",
559 sysinfo->memory_frequency, sysinfo->cas);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000560}
561
Arthur Heymans0ab49042017-02-06 22:40:14 +0100562static void derive_timings(struct sys_info *sysinfo,
563 struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000564{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100565 sysinfo->tras = DIV_ROUND_UP(saved_timings->min_tRAS, sysinfo->tclk);
566 if (sysinfo->tras > 0x18)
567 die("DDR-II Module does not support this frequency (tRAS error)\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000568
Arthur Heymans0ab49042017-02-06 22:40:14 +0100569 sysinfo->trp = DIV_ROUND_UP(saved_timings->min_tRP, sysinfo->tclk);
570 if (sysinfo->trp > 6)
571 die("DDR-II Module does not support this frequency (tRP error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000572
Arthur Heymans0ab49042017-02-06 22:40:14 +0100573 sysinfo->trcd = DIV_ROUND_UP(saved_timings->min_tRCD, sysinfo->tclk);
574 if (sysinfo->trcd > 6)
575 die("DDR-II Module does not support this frequency (tRCD error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000576
Arthur Heymans0ab49042017-02-06 22:40:14 +0100577 sysinfo->twr = DIV_ROUND_UP(saved_timings->min_tWR, sysinfo->tclk);
578 if (sysinfo->twr > 5)
579 die("DDR-II Module does not support this frequency (tWR error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000580
Arthur Heymans0ab49042017-02-06 22:40:14 +0100581 sysinfo->trfc = DIV_ROUND_UP(saved_timings->min_tRFC, sysinfo->tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000582
Arthur Heymans0ab49042017-02-06 22:40:14 +0100583 printk(BIOS_DEBUG, "tRAS = %d cycles\n", sysinfo->tras);
584 printk(BIOS_DEBUG, "tRP = %d cycles\n", sysinfo->trp);
585 printk(BIOS_DEBUG, "tRCD = %d cycles\n", sysinfo->trcd);
586 printk(BIOS_DEBUG, "tWR = %d cycles\n", sysinfo->twr);
587 printk(BIOS_DEBUG, "tRFC = %d cycles\n", sysinfo->trfc);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000588
Arthur Heymans0ab49042017-02-06 22:40:14 +0100589 /* Refresh is slower than 15.6us, use 15.6us */
590 /* tRR is decoded in units of 1/256us */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000591
Arthur Heymans0ab49042017-02-06 22:40:14 +0100592#define T_RR_7_8US 2000000
593#define T_RR_15_6US 4000000
594#define REFRESH_7_8US 1
595#define REFRESH_15_6US 0
Stefan Reinauer278534d2008-10-29 04:51:07 +0000596
Arthur Heymans0ab49042017-02-06 22:40:14 +0100597 if (saved_timings->max_tRR < T_RR_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000598 die("DDR-II module has unsupported refresh value\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100599 else if (saved_timings->max_tRR < T_RR_15_6US)
600 sysinfo->refresh = REFRESH_7_8US;
601 else
602 sysinfo->refresh = REFRESH_15_6US;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000603 printk(BIOS_DEBUG, "Refresh: %s\n", sysinfo->refresh?"7.8us":"15.6us");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000604}
605
Arthur Heymans0ab49042017-02-06 22:40:14 +0100606/**
607 * @brief Get generic DIMM parameters.
608 * @param sysinfo Central memory controller information structure
609 *
610 * This function gathers several pieces of information for each system DIMM:
611 * o DIMM width (x8 / x16)
612 * o DIMM rank (single ranked / dual ranked)
613 *
614 * Also, some non-supported scenarios are detected.
615 */
616
617static void sdram_get_dram_configuration(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000618{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100619 struct timings saved_timings;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000620
Arthur Heymans0ab49042017-02-06 22:40:14 +0100621 gather_common_timing(sysinfo, &saved_timings);
622 choose_tclk(sysinfo, &saved_timings);
623 derive_timings(sysinfo, &saved_timings);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000624}
625
Arthur Heymans70a8e342017-03-09 11:30:23 +0100626static void sdram_program_dram_width(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000627{
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200628 u16 c0dramw = 0, c1dramw = 0;
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200629 int i, idx;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000630
631 if (sysinfo->dual_channel)
632 idx = 2;
633 else
634 idx = 1;
635
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200636 for (i = 0; i < DIMM_SOCKETS; i++) { /* Channel 0 */
637 switch (sysinfo->dimm[i]) {
638 case SYSINFO_DIMM_X16DS:
639 c0dramw |= (0x0000) << 4*(i % 2);
640 break;
641 case SYSINFO_DIMM_X8DS:
642 c0dramw |= (0x0001) << 4*(i % 2);
643 break;
644 case SYSINFO_DIMM_X16SS:
645 c0dramw |= (0x0000) << 4*(i % 2);
646 break;
647 case SYSINFO_DIMM_X8DDS:
648 c0dramw |= (0x0005) << 4*(i % 2);
649 break;
650 case SYSINFO_DIMM_NOT_POPULATED:
651 c0dramw |= (0x0000) << 4*(i % 2);
652 break;
653 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000654 }
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200655 for (i = DIMM_SOCKETS; i < idx * DIMM_SOCKETS; i++) { /* Channel 1 */
656 switch (sysinfo->dimm[i]) {
657 case SYSINFO_DIMM_X16DS:
658 c1dramw |= (0x0000) << 4*(i % 2);
659 break;
660 case SYSINFO_DIMM_X8DS:
Patrick Georgi68aed912018-11-16 18:00:12 +0100661 c1dramw |= (0x0010) << 4*(i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200662 break;
663 case SYSINFO_DIMM_X16SS:
664 c1dramw |= (0x0000) << 4*(i % 2);
665 break;
666 case SYSINFO_DIMM_X8DDS:
Patrick Georgi68aed912018-11-16 18:00:12 +0100667 c1dramw |= (0x0050) << 4*(i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200668 break;
669 case SYSINFO_DIMM_NOT_POPULATED:
670 c1dramw |= (0x0000) << 4*(i % 2);
671 break;
672 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000673 }
674
675 MCHBAR16(C0DRAMW) = c0dramw;
676 MCHBAR16(C1DRAMW) = c1dramw;
677}
678
679static void sdram_write_slew_rates(u32 offset, const u32 *slew_rate_table)
680{
681 int i;
682
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200683 for (i = 0; i < 16; i++)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000684 MCHBAR32(offset+(i*4)) = slew_rate_table[i];
685}
686
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000687static const u32 dq2030[] = {
688 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
689 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
690 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
691 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
692};
693
694static const u32 dq2330[] = {
695 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
696 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
697 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
698 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
699};
700
701static const u32 cmd2710[] = {
702 0x07060605, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
703 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
704 0x1110100f, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
705 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
706};
707
708static const u32 cmd3210[] = {
709 0x0f0d0b0a, 0x17151311, 0x1f1d1b19, 0x1f1f1f1f,
710 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
711 0x18171615, 0x1f1f1c1a, 0x1f1f1f1f, 0x1f1f1f1f,
712 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
713};
714
715static const u32 clk2030[] = {
716 0x0e0d0d0c, 0x100f0f0e, 0x100f0e0d, 0x15131211,
717 0x1d1b1917, 0x2523211f, 0x2a282927, 0x32302e2c,
718 0x17161514, 0x1b1a1918, 0x1f1e1d1c, 0x23222120,
719 0x27262524, 0x2d2b2928, 0x3533312f, 0x3d3b3937
720};
721
722static const u32 ctl3215[] = {
723 0x01010000, 0x03020101, 0x07060504, 0x0b0a0908,
724 0x100f0e0d, 0x14131211, 0x18171615, 0x1c1b1a19,
725 0x05040403, 0x07060605, 0x0a090807, 0x0f0d0c0b,
726 0x14131211, 0x18171615, 0x1c1b1a19, 0x201f1e1d
727};
728
729static const u32 ctl3220[] = {
730 0x05040403, 0x07060505, 0x0e0c0a08, 0x1a171411,
731 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e,
732 0x09080807, 0x0b0a0a09, 0x0f0d0c0b, 0x1b171311,
733 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e
734};
735
736static const u32 nc[] = {
737 0x00000000, 0x00000000, 0x00000000, 0x00000000,
738 0x00000000, 0x00000000, 0x00000000, 0x00000000,
739 0x00000000, 0x00000000, 0x00000000, 0x00000000,
740 0x00000000, 0x00000000, 0x00000000, 0x00000000
741};
742
743enum {
744 DQ2030,
745 DQ2330,
746 CMD2710,
747 CMD3210,
748 CLK2030,
749 CTL3215,
750 CTL3220,
751 NC,
752};
753
754static const u8 dual_channel_slew_group_lookup[] = {
755 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
756 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
757 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
758 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
759 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
760
761 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
762 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
763 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
764 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
765 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
766
767 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
768 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
769 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
770 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
771 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
772
773 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
774 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
775 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
776 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
777 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, NC, NC,
778
779 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
780 NC, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
781 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
782 NC, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD2710
783};
784
785static const u8 single_channel_slew_group_lookup[] = {
786 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
787 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
788 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
789 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
790 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
791
792 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
793 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
794 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
795 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
796 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
797
798 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
799 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
800 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
801 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
802 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
803
804 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
805 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
806 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
807 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
808 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
809
810 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
811 DQ2330, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
812 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
813 DQ2330, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD3210
814};
815
816static const u32 *slew_group_lookup(int dual_channel, int index)
817{
818 const u8 *slew_group;
819 /* Dual Channel needs different tables. */
820 if (dual_channel)
821 slew_group = dual_channel_slew_group_lookup;
822 else
823 slew_group = single_channel_slew_group_lookup;
824
825 switch (slew_group[index]) {
826 case DQ2030: return dq2030;
827 case DQ2330: return dq2330;
828 case CMD2710: return cmd2710;
829 case CMD3210: return cmd3210;
830 case CLK2030: return clk2030;
831 case CTL3215: return ctl3215;
832 case CTL3220: return ctl3220;
833 case NC: return nc;
834 }
835
836 return nc;
837}
838
Julius Wernercd49cce2019-03-05 16:53:33 -0800839#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000840/* Strength multiplier tables */
841static const u8 dual_channel_strength_multiplier[] = {
842 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
843 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
844 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
845 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
846 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
847 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
848 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
849 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
850 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
851 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
852 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
853 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
854 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
855 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
856 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
857 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
858 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
859 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
860 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
861 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
862 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
863 0x00, 0x00, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
864 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
865 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x44, 0x22
866};
867
868static const u8 single_channel_strength_multiplier[] = {
869 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
870 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
871 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
872 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
873 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
874 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
875 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
876 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
877 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
878 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
879 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
880 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
881 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
882 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
883 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
884 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
885 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
886 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
887 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
888 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
889 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
890 0x33, 0x00, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
891 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
892 0x33, 0x00, 0x11, 0x00, 0x44, 0x44, 0x33, 0x11
893};
Julius Wernercd49cce2019-03-05 16:53:33 -0800894#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000895static const u8 dual_channel_strength_multiplier[] = {
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, 0x22,
899 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
900 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
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, 0x22,
904 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
905 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
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, 0x22,
909 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
910 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
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, 0x22,
914 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
915 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
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, 0x22,
919 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33
920};
921
922static const u8 single_channel_strength_multiplier[] = {
923 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
924 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
925 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
926 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
927 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
928 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
929 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
930 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
931 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
932 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
933 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
934 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
935 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
936 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
937 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
938 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
939 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
940 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
941 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
942 0x44, 0x33, 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, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
946 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00
947};
948#endif
949
Stefan Reinauer278534d2008-10-29 04:51:07 +0000950static void sdram_rcomp_buffer_strength_and_slew(struct sys_info *sysinfo)
951{
Arthur Heymans70a8e342017-03-09 11:30:23 +0100952 const u8 *strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000953 int idx, dual_channel;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000954
955 /* Set Strength Multipliers */
956
957 /* Dual Channel needs different tables. */
958 if (sdram_capabilities_dual_channel()) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000959 printk(BIOS_DEBUG, "Programming Dual Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000960 strength_multiplier = dual_channel_strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000961 dual_channel = 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000962 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[2];
963 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000964 printk(BIOS_DEBUG, "Programming Single Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000965 strength_multiplier = single_channel_strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000966 dual_channel = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000967 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[1];
968 }
969
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000970 printk(BIOS_DEBUG, "Table Index: %d\n", idx);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000971
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000972 MCHBAR8(G1SC) = strength_multiplier[idx * 8 + 0];
973 MCHBAR8(G2SC) = strength_multiplier[idx * 8 + 1];
974 MCHBAR8(G3SC) = strength_multiplier[idx * 8 + 2];
975 MCHBAR8(G4SC) = strength_multiplier[idx * 8 + 3];
976 MCHBAR8(G5SC) = strength_multiplier[idx * 8 + 4];
977 MCHBAR8(G6SC) = strength_multiplier[idx * 8 + 5];
978 MCHBAR8(G7SC) = strength_multiplier[idx * 8 + 6];
979 MCHBAR8(G8SC) = strength_multiplier[idx * 8 + 7];
Stefan Reinauer278534d2008-10-29 04:51:07 +0000980
981 /* Channel 0 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000982 sdram_write_slew_rates(G1SRPUT, slew_group_lookup(dual_channel, idx * 8 + 0));
983 sdram_write_slew_rates(G2SRPUT, slew_group_lookup(dual_channel, idx * 8 + 1));
Arthur Heymans70a8e342017-03-09 11:30:23 +0100984 if ((slew_group_lookup(dual_channel, idx * 8 + 2) != nc) && (sysinfo->package == SYSINFO_PACKAGE_STACKED))
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000985
Stefan Reinauer278534d2008-10-29 04:51:07 +0000986 sdram_write_slew_rates(G3SRPUT, ctl3220);
Arthur Heymans70a8e342017-03-09 11:30:23 +0100987 else
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000988 sdram_write_slew_rates(G3SRPUT, slew_group_lookup(dual_channel, idx * 8 + 2));
Arthur Heymans70a8e342017-03-09 11:30:23 +0100989
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000990 sdram_write_slew_rates(G4SRPUT, slew_group_lookup(dual_channel, idx * 8 + 3));
991 sdram_write_slew_rates(G5SRPUT, slew_group_lookup(dual_channel, idx * 8 + 4));
992 sdram_write_slew_rates(G6SRPUT, slew_group_lookup(dual_channel, idx * 8 + 5));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000993
994 /* Channel 1 */
995 if (sysinfo->dual_channel) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000996 sdram_write_slew_rates(G7SRPUT, slew_group_lookup(dual_channel, idx * 8 + 6));
997 sdram_write_slew_rates(G8SRPUT, slew_group_lookup(dual_channel, idx * 8 + 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000998 } else {
999 sdram_write_slew_rates(G7SRPUT, nc);
1000 sdram_write_slew_rates(G8SRPUT, nc);
1001 }
1002}
1003
1004static void sdram_enable_rcomp(void)
1005{
1006 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001007 /* Enable Global Periodic RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001008 udelay(300);
1009 reg32 = MCHBAR32(GBRCOMPCTL);
1010 reg32 &= ~(1 << 23);
1011 MCHBAR32(GBRCOMPCTL) = reg32;
1012}
1013
1014static void sdram_program_dll_timings(struct sys_info *sysinfo)
1015{
Elyes HAOUAS44a30662017-02-23 13:14:44 +01001016 u32 channeldll = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001017 int i;
1018
Elyes HAOUAS38424982016-08-21 12:01:04 +02001019 printk(BIOS_DEBUG, "Programming DLL Timings...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001020
Arthur Heymans70a8e342017-03-09 11:30:23 +01001021 MCHBAR16(DQSMT) &= ~((3 << 12) | (1 << 10) | (0xf << 0));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001022 MCHBAR16(DQSMT) |= (1 << 13) | (0xc << 0);
1023
1024 /* We drive both channels with the same speed */
Julius Wernercd49cce2019-03-05 16:53:33 -08001025 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001026 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001027 case 400:
1028 channeldll = 0x26262626; break;
1029 case 533:
1030 channeldll = 0x22222222; break;
1031 case 667:
1032 channeldll = 0x11111111; break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001033 }
Julius Wernercd49cce2019-03-05 16:53:33 -08001034 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001035 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001036 case 400:
1037 channeldll = 0x33333333; break;
1038 case 533:
1039 channeldll = 0x24242424; break;
1040 case 667:
1041 channeldll = 0x25252525; break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001042 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001043 }
1044
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001045 for (i = 0; i < 4; i++) {
Elyes HAOUAS44a30662017-02-23 13:14:44 +01001046 MCHBAR32(C0R0B00DQST + (i * 0x10) + 0) = channeldll;
1047 MCHBAR32(C0R0B00DQST + (i * 0x10) + 4) = channeldll;
1048 MCHBAR32(C1R0B00DQST + (i * 0x10) + 0) = channeldll;
1049 MCHBAR32(C1R0B00DQST + (i * 0x10) + 4) = channeldll;
Julius Wernercd49cce2019-03-05 16:53:33 -08001050 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUAS44a30662017-02-23 13:14:44 +01001051 MCHBAR8(C0R0B00DQST + (i * 0x10) + 8) = channeldll & 0xff;
1052 MCHBAR8(C1R0B00DQST + (i * 0x10) + 8) = channeldll & 0xff;
Paul Menzelbce7e332017-02-22 18:46:27 +01001053 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001054 }
1055}
1056
1057static void sdram_force_rcomp(void)
1058{
1059 u32 reg32;
1060 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001061
Stefan Reinauer278534d2008-10-29 04:51:07 +00001062 reg32 = MCHBAR32(ODTC);
1063 reg32 |= (1 << 28);
1064 MCHBAR32(ODTC) = reg32;
1065
1066 reg32 = MCHBAR32(SMSRCTL);
1067 reg32 |= (1 << 0);
1068 MCHBAR32(SMSRCTL) = reg32;
1069
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001070 /* Start initial RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001071 reg32 = MCHBAR32(GBRCOMPCTL);
1072 reg32 |= (1 << 8);
1073 MCHBAR32(GBRCOMPCTL) = reg32;
1074
1075 reg8 = i945_silicon_revision();
1076 if ((reg8 == 0 && (MCHBAR32(DCC) & (3 << 0)) == 0) || (reg8 == 1)) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001077
Stefan Reinauer278534d2008-10-29 04:51:07 +00001078 reg32 = MCHBAR32(GBRCOMPCTL);
1079 reg32 |= (3 << 5);
1080 MCHBAR32(GBRCOMPCTL) = reg32;
1081 }
1082}
1083
1084static void sdram_initialize_system_memory_io(struct sys_info *sysinfo)
1085{
1086 u8 reg8;
1087 u32 reg32;
1088
Elyes HAOUAS38424982016-08-21 12:01:04 +02001089 printk(BIOS_DEBUG, "Initializing System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001090 /* Enable Data Half Clock Pushout */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001091 reg8 = MCHBAR8(C0HCTC);
1092 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001093 reg8 |= (1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001094 MCHBAR8(C0HCTC) = reg8;
1095
1096 reg8 = MCHBAR8(C1HCTC);
1097 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001098 reg8 |= (1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001099 MCHBAR8(C1HCTC) = reg8;
1100
Arthur Heymans70a8e342017-03-09 11:30:23 +01001101 MCHBAR16(WDLLBYPMODE) &= ~((1 << 9) | (1 << 6) | (1 << 4) | (1 << 3) | (1 << 1));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001102 MCHBAR16(WDLLBYPMODE) |= (1 << 8) | (1 << 7) | (1 << 5) | (1 << 2) | (1 << 0);
1103
1104 MCHBAR8(C0WDLLCMC) = 0;
1105 MCHBAR8(C1WDLLCMC) = 0;
1106
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001107 /* Program RCOMP Settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001108 sdram_program_dram_width(sysinfo);
1109
1110 sdram_rcomp_buffer_strength_and_slew(sysinfo);
1111
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001112 /* Indicate that RCOMP programming is done */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001113 reg32 = MCHBAR32(GBRCOMPCTL);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001114 reg32 &= ~((1 << 29) | (1 << 26) | (3 << 21) | (3 << 2));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001115 reg32 |= (3 << 27) | (3 << 0);
1116 MCHBAR32(GBRCOMPCTL) = reg32;
1117
1118 MCHBAR32(GBRCOMPCTL) |= (1 << 10);
1119
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001120 /* Program DLL Timings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001121 sdram_program_dll_timings(sysinfo);
1122
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001123 /* Force RCOMP cycle */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001124 sdram_force_rcomp();
1125}
1126
1127static void sdram_enable_system_memory_io(struct sys_info *sysinfo)
1128{
1129 u32 reg32;
1130
Elyes HAOUAS38424982016-08-21 12:01:04 +02001131 printk(BIOS_DEBUG, "Enabling System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001132
Stefan Reinauer278534d2008-10-29 04:51:07 +00001133 reg32 = MCHBAR32(RCVENMT);
1134 reg32 &= ~(0x3f << 6);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001135 MCHBAR32(RCVENMT) = reg32; /* [11:6] = 0 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001136
1137 reg32 |= (1 << 11) | (1 << 9);
1138 MCHBAR32(RCVENMT) = reg32;
1139
1140 reg32 = MCHBAR32(DRTST);
1141 reg32 |= (1 << 3) | (1 << 2);
1142 MCHBAR32(DRTST) = reg32;
1143
1144 reg32 = MCHBAR32(DRTST);
1145 reg32 |= (1 << 6) | (1 << 4);
1146 MCHBAR32(DRTST) = reg32;
1147
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001148 asm volatile ("nop; nop;" ::: "memory");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001149
1150 reg32 = MCHBAR32(DRTST);
1151
1152 /* Is channel 0 populated? */
1153 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
1154 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
1155 reg32 |= (1 << 7) | (1 << 5);
1156 else
1157 reg32 |= (1 << 31);
1158
1159 /* Is channel 1 populated? */
1160 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1161 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
1162 reg32 |= (1 << 9) | (1 << 8);
1163 else
1164 reg32 |= (1 << 30);
1165
1166 MCHBAR32(DRTST) = reg32;
1167
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001168 /* Activate DRAM Channel IO Buffers */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001169 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
1170 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) {
1171 reg32 = MCHBAR32(C0DRC1);
1172 reg32 |= (1 << 8);
1173 MCHBAR32(C0DRC1) = reg32;
1174 }
1175 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1176 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED) {
1177 reg32 = MCHBAR32(C1DRC1);
1178 reg32 |= (1 << 8);
1179 MCHBAR32(C1DRC1) = reg32;
1180 }
1181}
1182
Stefan Reinauer278534d2008-10-29 04:51:07 +00001183static int sdram_program_row_boundaries(struct sys_info *sysinfo)
1184{
1185 int i;
Arthur Heymans885c2892016-10-03 17:16:48 +02001186 int cum0, cum1, tolud, tom, pci_mmio_size;
1187 const struct device *dev;
1188 const struct northbridge_intel_i945_config *cfg = NULL;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001189
Paul Menzel84283bc2014-07-17 08:16:04 +02001190 printk(BIOS_DEBUG, "Setting RAM size...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001191
1192 cum0 = 0;
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001193 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001194 cum0 += sysinfo->banksize[i];
Stefan Reinauer278534d2008-10-29 04:51:07 +00001195 MCHBAR8(C0DRB0+i) = cum0;
1196 }
1197
1198 /* Assume we continue in Channel 1 where we stopped in Channel 0 */
1199 cum1 = cum0;
1200
1201 /* Exception: Interleaved starts from the beginning */
1202 if (sysinfo->interleaved)
1203 cum1 = 0;
1204
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001205 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001206 cum1 += sysinfo->banksize[i + 4];
Stefan Reinauer278534d2008-10-29 04:51:07 +00001207 MCHBAR8(C1DRB0+i) = cum1;
1208 }
1209
1210 /* Set TOLUD Top Of Low Usable DRAM */
1211 if (sysinfo->interleaved)
1212 tolud = (cum0 + cum1) << 1;
1213 else
1214 tolud = (cum1 ? cum1 : cum0) << 1;
Stefan Reinauer779b3e32008-11-10 15:43:37 +00001215
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001216 /* The TOM register has a different format */
1217 tom = tolud >> 3;
1218
1219 /* Limit the value of TOLUD to leave some space for PCI memory. */
Kyösti Mälkkic70eed12018-05-22 02:18:00 +03001220 dev = pcidev_on_root(0, 0);
Arthur Heymans885c2892016-10-03 17:16:48 +02001221 if (dev)
1222 cfg = dev->chip_info;
1223
1224 /* Don't use pci mmio sizes smaller than 768M */
1225 if (!cfg || cfg->pci_mmio_size <= DEFAULT_PCI_MMIO_SIZE)
1226 pci_mmio_size = DEFAULT_PCI_MMIO_SIZE;
1227 else
1228 pci_mmio_size = cfg->pci_mmio_size;
1229
1230 tolud = MIN(((4096 - pci_mmio_size) / 128) << 3, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001231
Arthur Heymans70a8e342017-03-09 11:30:23 +01001232 pci_write_config8(PCI_DEV(0, 0, 0), TOLUD, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001233
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001234 printk(BIOS_DEBUG, "C0DRB = 0x%08x\n", MCHBAR32(C0DRB0));
1235 printk(BIOS_DEBUG, "C1DRB = 0x%08x\n", MCHBAR32(C1DRB0));
Arthur Heymans70a8e342017-03-09 11:30:23 +01001236 printk(BIOS_DEBUG, "TOLUD = 0x%04x\n", pci_read_config8(PCI_DEV(0, 0, 0), TOLUD));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001237
Arthur Heymans70a8e342017-03-09 11:30:23 +01001238 pci_write_config16(PCI_DEV(0, 0, 0), TOM, tom);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001239
1240 return 0;
1241}
1242
Stefan Reinauer278534d2008-10-29 04:51:07 +00001243static int sdram_set_row_attributes(struct sys_info *sysinfo)
1244{
Arthur Heymans0ab49042017-02-06 22:40:14 +01001245 int i;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001246 u16 dra0 = 0, dra1 = 0, dra = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001247
Elyes HAOUAS38424982016-08-21 12:01:04 +02001248 printk(BIOS_DEBUG, "Setting row attributes...\n");
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001249 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001250 u8 columnsrows;
1251
Arthur Heymans70a8e342017-03-09 11:30:23 +01001252 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001253 continue;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001254
Arthur Heymans0ab49042017-02-06 22:40:14 +01001255 columnsrows = (sysinfo->rows[i] & 0x0f)
1256 | (sysinfo->cols[i] & 0xf) << 4;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001257
1258 switch (columnsrows) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001259 case 0x9d:
1260 dra = 2; break;
1261 case 0xad:
1262 dra = 3; break;
1263 case 0xbd:
1264 dra = 4; break;
1265 case 0xae:
1266 dra = 3; break;
1267 case 0xbe:
1268 dra = 4; break;
1269 default:
1270 die("Unsupported Rows/Columns. (DRA)");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001271 }
1272
1273 /* Double Sided DIMMs? */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001274 if (sysinfo->banksize[(2 * i) + 1] != 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001275 dra = (dra << 4) | dra;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001276
Stefan Reinauer278534d2008-10-29 04:51:07 +00001277 if (i < DIMM_SOCKETS)
1278 dra0 |= (dra << (i*8));
1279 else
1280 dra1 |= (dra << ((i - DIMM_SOCKETS)*8));
1281 }
1282
1283 MCHBAR16(C0DRA0) = dra0;
1284 MCHBAR16(C1DRA0) = dra1;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001285
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001286 printk(BIOS_DEBUG, "C0DRA = 0x%04x\n", dra0);
1287 printk(BIOS_DEBUG, "C1DRA = 0x%04x\n", dra1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001288
1289 return 0;
1290}
1291
1292static void sdram_set_bank_architecture(struct sys_info *sysinfo)
1293{
1294 u32 off32;
1295 int i;
1296
1297 MCHBAR16(C1BNKARC) &= 0xff00;
1298 MCHBAR16(C0BNKARC) &= 0xff00;
1299
1300 off32 = C0BNKARC;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001301 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001302 /* Switch to second channel */
1303 if (i == DIMM_SOCKETS)
1304 off32 = C1BNKARC;
1305
1306 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
1307 continue;
1308
1309 if (sysinfo->banks[i] != 8)
1310 continue;
1311
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001312 printk(BIOS_SPEW, "DIMM%d has 8 banks.\n", i);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001313
1314 if (i & 1)
1315 MCHBAR16(off32) |= 0x50;
1316 else
1317 MCHBAR16(off32) |= 0x05;
1318 }
1319}
1320
Stefan Reinauer278534d2008-10-29 04:51:07 +00001321static void sdram_program_refresh_rate(struct sys_info *sysinfo)
1322{
1323 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001324
Arthur Heymans70a8e342017-03-09 11:30:23 +01001325 if (sysinfo->refresh == REFRESH_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001326 reg32 = (2 << 8); /* Refresh enabled at 7.8us */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001327 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001328 reg32 = (1 << 8); /* Refresh enabled at 15.6us */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001329
1330 MCHBAR32(C0DRC0) &= ~(7 << 8);
1331 MCHBAR32(C0DRC0) |= reg32;
1332
1333 MCHBAR32(C1DRC0) &= ~(7 << 8);
1334 MCHBAR32(C1DRC0) |= reg32;
1335}
1336
1337static void sdram_program_cke_tristate(struct sys_info *sysinfo)
1338{
1339 u32 reg32;
1340 int i;
1341
1342 reg32 = MCHBAR32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001343
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001344 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001345 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001346 reg32 |= (1 << (16 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001347 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001348
Stefan Reinauer278534d2008-10-29 04:51:07 +00001349 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001350
Stefan Reinauer278534d2008-10-29 04:51:07 +00001351 reg32 |= (1 << 11);
1352 MCHBAR32(C0DRC1) = reg32;
1353
1354 /* Do we have to do this if we're in Single Channel Mode? */
1355 reg32 = MCHBAR32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001356
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001357 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001358 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001359 reg32 |= (1 << (12 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001360 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001361
Stefan Reinauer278534d2008-10-29 04:51:07 +00001362 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001363
Stefan Reinauer278534d2008-10-29 04:51:07 +00001364 reg32 |= (1 << 11);
1365 MCHBAR32(C1DRC1) = reg32;
1366}
1367
1368static void sdram_program_odt_tristate(struct sys_info *sysinfo)
1369{
1370 u32 reg32;
1371 int i;
1372
1373 reg32 = MCHBAR32(C0DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001374
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001375 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001376 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001377 reg32 |= (1 << (24 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001378 }
1379 MCHBAR32(C0DRC2) = reg32;
1380
1381 reg32 = MCHBAR32(C1DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001382
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001383 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001384 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001385 reg32 |= (1 << (20 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001386 }
1387 MCHBAR32(C1DRC2) = reg32;
1388}
1389
1390static void sdram_set_timing_and_control(struct sys_info *sysinfo)
1391{
Arthur Heymans25027232017-02-12 23:34:39 +01001392 u32 reg32, tRD_min;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001393 u32 tWTR;
1394 u32 temp_drt;
1395 int i, page_size;
1396
Edward O'Callaghan2f237c12014-05-25 06:24:39 +10001397 static const u8 cas_table[] = {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001398 2, 1, 0, 3
1399 };
1400
1401 reg32 = MCHBAR32(C0DRC0);
1402 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001403 reg32 &= ~((1 << 13) | (1 << 12));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001404 MCHBAR32(C0DRC0) = reg32;
1405
1406 reg32 = MCHBAR32(C1DRC0);
1407 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001408 reg32 &= ~((1 << 13) | (1 << 12));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001409 MCHBAR32(C1DRC0) = reg32;
1410
1411 if (!sysinfo->dual_channel && sysinfo->dimm[1] !=
1412 SYSINFO_DIMM_NOT_POPULATED) {
1413 reg32 = MCHBAR32(C0DRC0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001414 reg32 |= (1 << 15);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001415 MCHBAR32(C0DRC0) = reg32;
1416 }
1417
1418 sdram_program_refresh_rate(sysinfo);
1419
1420 sdram_program_cke_tristate(sysinfo);
1421
1422 sdram_program_odt_tristate(sysinfo);
1423
1424 /* Calculate DRT0 */
1425
1426 temp_drt = 0;
1427
1428 /* B2B Write Precharge (same bank) = CL-1 + BL/2 + tWR */
1429 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + sysinfo->twr;
1430 temp_drt |= (reg32 << 28);
1431
1432 /* Write Auto Precharge (same bank) = CL-1 + BL/2 + tWR + tRP */
1433 reg32 += sysinfo->trp;
1434 temp_drt |= (reg32 << 4);
1435
Arthur Heymans70a8e342017-03-09 11:30:23 +01001436 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001437 tWTR = 3; /* 667MHz */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001438 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001439 tWTR = 2; /* 400 and 533 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001440
1441 /* B2B Write to Read Command Spacing */
1442 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + tWTR;
1443 temp_drt |= (reg32 << 24);
1444
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001445 /* CxDRT0 [23:22], [21:20], [19:18] [16] have fixed values */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001446 temp_drt |= ((1 << 22) | (3 << 20) | (1 << 18) | (0 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001447
Arthur Heymans25027232017-02-12 23:34:39 +01001448 /*
1449 * tRD is the delay the memory controller is waiting on the FSB,
1450 * in mclk domain.
1451 * This parameter is important for stability and performance.
1452 * Those values might not be optimal but seem stable.
1453 */
1454 tRD_min = sysinfo->cas;
Arthur Heymanse1897612016-10-15 23:29:18 +02001455 switch (sysinfo->fsb_frequency) {
Arthur Heymans25027232017-02-12 23:34:39 +01001456 case 533: break;
1457 case 667: tRD_min += 1;
Arthur Heymanse1897612016-10-15 23:29:18 +02001458 break;
Arthur Heymans25027232017-02-12 23:34:39 +01001459 case 800: tRD_min += 2;
Arthur Heymanse1897612016-10-15 23:29:18 +02001460 break;
Arthur Heymans25027232017-02-12 23:34:39 +01001461 case 1066: tRD_min += 3;
Arthur Heymanse1897612016-10-15 23:29:18 +02001462 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001463 }
Arthur Heymanse1897612016-10-15 23:29:18 +02001464
Arthur Heymans25027232017-02-12 23:34:39 +01001465 temp_drt |= (tRD_min << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001466
1467 /* Read Auto Precharge to Activate */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001468
Stefan Reinauer278534d2008-10-29 04:51:07 +00001469 temp_drt |= (8 << 0);
1470
1471 MCHBAR32(C0DRT0) = temp_drt;
1472 MCHBAR32(C1DRT0) = temp_drt;
1473
1474 /* Calculate DRT1 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001475
Stefan Reinauer278534d2008-10-29 04:51:07 +00001476 temp_drt = MCHBAR32(C0DRT1) & 0x00020088;
1477
1478 /* DRAM RASB Precharge */
1479 temp_drt |= (sysinfo->trp - 2) << 0;
1480
1481 /* DRAM RASB to CASB Delay */
1482 temp_drt |= (sysinfo->trcd - 2) << 4;
1483
1484 /* CASB Latency */
1485 temp_drt |= (cas_table[sysinfo->cas - 3]) << 8;
1486
1487 /* Refresh Cycle Time */
1488 temp_drt |= (sysinfo->trfc) << 10;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001489
Stefan Reinauer278534d2008-10-29 04:51:07 +00001490 /* Pre-All to Activate Delay */
1491 temp_drt |= (0 << 16);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001492
Stefan Reinauer278534d2008-10-29 04:51:07 +00001493 /* Precharge to Precharge Delay stays at 1 clock */
1494 temp_drt |= (0 << 18);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001495
Stefan Reinauer278534d2008-10-29 04:51:07 +00001496 /* Activate to Precharge Delay */
1497 temp_drt |= (sysinfo->tras << 19);
1498
1499 /* Read to Precharge (tRTP) */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001500 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001501 temp_drt |= (1 << 28);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001502 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001503 temp_drt |= (0 << 28);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001504
1505 /* Determine page size */
1506 reg32 = 0;
1507 page_size = 1; /* Default: 1k pagesize */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001508 for (i = 0; i < 2*DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001509 if (sysinfo->dimm[i] == SYSINFO_DIMM_X16DS ||
1510 sysinfo->dimm[i] == SYSINFO_DIMM_X16SS)
1511 page_size = 2; /* 2k pagesize */
1512 }
1513
Arthur Heymans70a8e342017-03-09 11:30:23 +01001514 if (sysinfo->memory_frequency == 533 && page_size == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001515 reg32 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001516 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001517 reg32 = page_size;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001518
Stefan Reinauer278534d2008-10-29 04:51:07 +00001519 temp_drt |= (reg32 << 30);
1520
1521 MCHBAR32(C0DRT1) = temp_drt;
1522 MCHBAR32(C1DRT1) = temp_drt;
1523
1524 /* Program DRT2 */
1525 reg32 = MCHBAR32(C0DRT2);
1526 reg32 &= ~(1 << 8);
1527 MCHBAR32(C0DRT2) = reg32;
1528
1529 reg32 = MCHBAR32(C1DRT2);
1530 reg32 &= ~(1 << 8);
1531 MCHBAR32(C1DRT2) = reg32;
1532
1533 /* Calculate DRT3 */
1534 temp_drt = MCHBAR32(C0DRT3) & ~0x07ffffff;
1535
1536 /* Get old tRFC value */
1537 reg32 = MCHBAR32(C0DRT1) >> 10;
1538 reg32 &= 0x3f;
1539
1540 /* 788nS - tRFC */
1541 switch (sysinfo->memory_frequency) {
1542 case 400: /* 5nS */
1543 reg32 = ((78800 / 500) - reg32) & 0x1ff;
1544 reg32 |= (0x8c << 16) | (0x0c << 10); /* 1 us */
1545 break;
1546 case 533: /* 3.75nS */
1547 reg32 = ((78800 / 375) - reg32) & 0x1ff;
1548 reg32 |= (0xba << 16) | (0x10 << 10); /* 1 us */
1549 break;
1550 case 667: /* 3nS */
1551 reg32 = ((78800 / 300) - reg32) & 0x1ff;
1552 reg32 |= (0xe9 << 16) | (0x14 << 10); /* 1 us */
1553 break;
1554 }
1555
1556 temp_drt |= reg32;
1557
1558 MCHBAR32(C0DRT3) = temp_drt;
1559 MCHBAR32(C1DRT3) = temp_drt;
1560}
1561
1562static void sdram_set_channel_mode(struct sys_info *sysinfo)
1563{
1564 u32 reg32;
1565
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001566 printk(BIOS_DEBUG, "Setting mode of operation for memory channels...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001567
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001568 if (sdram_capabilities_interleave() &&
Arthur Heymans70a8e342017-03-09 11:30:23 +01001569 ((sysinfo->banksize[0] + sysinfo->banksize[1] +
1570 sysinfo->banksize[2] + sysinfo->banksize[3]) ==
1571 (sysinfo->banksize[4] + sysinfo->banksize[5] +
1572 sysinfo->banksize[6] + sysinfo->banksize[7]))) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001573 /* Both channels equipped with DIMMs of the same size */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001574 sysinfo->interleaved = 1;
1575 } else {
1576 sysinfo->interleaved = 0;
1577 }
1578
1579 reg32 = MCHBAR32(DCC);
1580 reg32 &= ~(7 << 0);
1581
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001582 if (sysinfo->interleaved) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001583 /* Dual Channel Interleaved */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001584 printk(BIOS_DEBUG, "Dual Channel Interleaved.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001585 reg32 |= (1 << 1);
1586 } else if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED &&
1587 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
1588 /* Channel 1 only */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001589 printk(BIOS_DEBUG, "Single Channel 1 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001590 reg32 |= (1 << 2);
Elyes HAOUAS75da1fb2017-02-16 18:59:13 +01001591 } else if (sdram_capabilities_dual_channel() &&
1592 (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1593 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) {
Martin Roth128c1042016-11-18 09:29:03 -07001594 /* Dual Channel Asymmetric */
1595 printk(BIOS_DEBUG, "Dual Channel Asymmetric.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001596 reg32 |= (1 << 0);
1597 } else {
1598 /* All bits 0 means Single Channel 0 operation */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001599 printk(BIOS_DEBUG, "Single Channel 0 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001600 }
1601
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001602 /* Now disable channel XORing */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001603 reg32 |= (1 << 10);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001604
1605 MCHBAR32(DCC) = reg32;
1606
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001607 PRINTK_DEBUG("DCC = 0x%08x\n", MCHBAR32(DCC));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001608}
1609
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001610static void sdram_program_pll_settings(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001611{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001612 MCHBAR32(PLLMON) = 0x80800000;
1613
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001614 sysinfo->fsb_frequency = fsbclk();
Peter Stuge76d91432010-10-01 10:02:33 +00001615 if (sysinfo->fsb_frequency == 0xffff)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001616 die("Unsupported FSB speed");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001617
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001618 /* Program CPCTL according to FSB speed */
1619 /* Only write the lower byte */
1620 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001621 case 400:
1622 MCHBAR8(CPCTL) = 0x90; break; /* FSB400 */
1623 case 533:
1624 MCHBAR8(CPCTL) = 0x95; break; /* FSB533 */
1625 case 667:
1626 MCHBAR8(CPCTL) = 0x8d; break; /* FSB667 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001627 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001628
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001629 MCHBAR16(CPCTL) &= ~(1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001630
Paul Menzel0ce5ebf2013-10-21 21:22:09 +02001631 MCHBAR16(CPCTL); /* Read back register to activate settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001632}
1633
1634static void sdram_program_graphics_frequency(struct sys_info *sysinfo)
1635{
1636 u8 reg8;
1637 u16 reg16;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001638 u8 freq, second_vco, voltage;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001639
1640#define CRCLK_166MHz 0x00
1641#define CRCLK_200MHz 0x01
1642#define CRCLK_250MHz 0x03
1643#define CRCLK_400MHz 0x05
1644
1645#define CDCLK_200MHz 0x00
1646#define CDCLK_320MHz 0x40
1647
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001648#define VOLTAGE_1_05 0x00
1649#define VOLTAGE_1_50 0x01
1650
Paul Menzeldaf9e502014-07-15 23:49:16 +02001651 printk(BIOS_DEBUG, "Setting Graphics Frequency...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001652
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001653 printk(BIOS_DEBUG, "FSB: %d MHz ", sysinfo->fsb_frequency);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001654
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001655 voltage = VOLTAGE_1_05;
1656 if (MCHBAR32(DFT_STRAP1) & (1 << 20))
1657 voltage = VOLTAGE_1_50;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001658 printk(BIOS_DEBUG, "Voltage: %s ", (voltage == VOLTAGE_1_05)?"1.05V":"1.5V");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001659
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001660 /* Gate graphics hardware for frequency change */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001661 reg8 = pci_read_config16(PCI_DEV(0, 2, 0), GCFC + 1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001662 reg8 = (1<<3) | (1<<1); /* disable crclk, gate cdclk */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001663 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001664
1665 /* Get graphics frequency capabilities */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001666 reg8 = sdram_capabilities_core_frequencies();
1667
Stefan Reinauer278534d2008-10-29 04:51:07 +00001668 freq = CRCLK_250MHz;
1669 switch (reg8) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001670 case GFX_FREQUENCY_CAP_ALL:
1671 if (voltage == VOLTAGE_1_05)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001672 freq = CRCLK_250MHz;
1673 else
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001674 freq = CRCLK_400MHz; /* 1.5V requires 400MHz */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001675 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001676 case GFX_FREQUENCY_CAP_250MHZ:
1677 freq = CRCLK_250MHz; break;
1678 case GFX_FREQUENCY_CAP_200MHZ:
1679 freq = CRCLK_200MHz; break;
1680 case GFX_FREQUENCY_CAP_166MHZ:
1681 freq = CRCLK_166MHz; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001682 }
1683
1684 if (freq != CRCLK_400MHz) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001685 /* What chipset are we? Force 166MHz for GMS */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001686 reg8 = (pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe7) & 0x70) >> 4;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001687 if (reg8 == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001688 freq = CRCLK_166MHz;
1689 }
1690
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001691 printk(BIOS_DEBUG, "Render: ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001692 switch (freq) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001693 case CRCLK_166MHz:
1694 printk(BIOS_DEBUG, "166MHz"); break;
1695 case CRCLK_200MHz:
1696 printk(BIOS_DEBUG, "200MHz"); break;
1697 case CRCLK_250MHz:
1698 printk(BIOS_DEBUG, "250MHz"); break;
1699 case CRCLK_400MHz:
1700 printk(BIOS_DEBUG, "400MHz"); break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001701 }
1702
Arthur Heymans70a8e342017-03-09 11:30:23 +01001703 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001704 sysinfo->mvco4x = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001705 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001706 sysinfo->mvco4x = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001707
Stefan Reinauer278534d2008-10-29 04:51:07 +00001708 second_vco = 0;
1709
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001710 if (voltage == VOLTAGE_1_50) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001711 second_vco = 1;
1712 } else if ((i945_silicon_revision() > 0) && (freq == CRCLK_250MHz)) {
1713 u16 mem = sysinfo->memory_frequency;
1714 u16 fsb = sysinfo->fsb_frequency;
1715
Arthur Heymans70a8e342017-03-09 11:30:23 +01001716 if ((fsb == 667 && mem == 533) ||
1717 (fsb == 533 && mem == 533) ||
1718 (fsb == 533 && mem == 400)) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001719 second_vco = 1;
1720 }
1721
1722 if (fsb == 667 && mem == 533)
1723 sysinfo->mvco4x = 1;
1724 }
1725
Arthur Heymans70a8e342017-03-09 11:30:23 +01001726 if (second_vco)
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001727 sysinfo->clkcfg_bit7 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001728 else
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001729 sysinfo->clkcfg_bit7 = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001730
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001731 /* Graphics Core Render Clock */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001732 reg16 = pci_read_config16(PCI_DEV(0, 2, 0), GCFC);
1733 reg16 &= ~((7 << 0) | (1 << 13));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001734 reg16 |= freq;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001735 pci_write_config16(PCI_DEV(0, 2, 0), GCFC, reg16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001736
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001737 /* Graphics Core Display Clock */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001738 reg8 = pci_read_config8(PCI_DEV(0, 2, 0), GCFC);
1739 reg8 &= ~((1<<7) | (7<<4));
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001740
1741 if (voltage == VOLTAGE_1_05) {
1742 reg8 |= CDCLK_200MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001743 printk(BIOS_DEBUG, " Display: 200MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001744 } else {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001745 reg8 |= CDCLK_320MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001746 printk(BIOS_DEBUG, " Display: 320MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001747 }
Arthur Heymans70a8e342017-03-09 11:30:23 +01001748 pci_write_config8(PCI_DEV(0, 2, 0), GCFC, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001749
Arthur Heymans70a8e342017-03-09 11:30:23 +01001750 reg8 = pci_read_config8(PCI_DEV(0, 2, 0), GCFC + 1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001751
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001752 reg8 |= (1<<3) | (1<<1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001753 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001754
1755 reg8 |= 0x0f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001756 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001757
1758 /* Ungate core render and display clocks */
1759 reg8 &= 0xf0;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001760 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001761}
1762
1763static void sdram_program_memory_frequency(struct sys_info *sysinfo)
1764{
1765 u32 clkcfg;
1766 u8 reg8;
Julius Wernercd49cce2019-03-05 16:53:33 -08001767 u8 offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001768
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001769 printk(BIOS_DEBUG, "Setting Memory Frequency... ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001770
Stefan Reinauer278534d2008-10-29 04:51:07 +00001771 clkcfg = MCHBAR32(CLKCFG);
1772
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001773 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001774
Arthur Heymans70a8e342017-03-09 11:30:23 +01001775 clkcfg &= ~((1 << 12) | (1 << 7) | (7 << 4));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001776
1777 if (sysinfo->mvco4x) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001778 printk(BIOS_DEBUG, "MVCO 4x, ");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001779 clkcfg &= ~(1 << 12);
1780 }
1781
1782 if (sysinfo->clkcfg_bit7) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001783 printk(BIOS_DEBUG, "second VCO, ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001784
Stefan Reinauer278534d2008-10-29 04:51:07 +00001785 clkcfg |= (1 << 7);
1786 }
1787
1788 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001789 case 400:
1790 clkcfg |= ((1 + offset) << 4); break;
1791 case 533:
1792 clkcfg |= ((2 + offset) << 4); break;
1793 case 667:
1794 clkcfg |= ((3 + offset) << 4); break;
1795 default:
1796 die("Target Memory Frequency Error");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001797 }
1798
1799 if (MCHBAR32(CLKCFG) == clkcfg) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001800 printk(BIOS_DEBUG, "ok (unchanged)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001801 return;
1802 }
1803
1804 MCHBAR32(CLKCFG) = clkcfg;
1805
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001806 /* Make sure the following code is in the
Stefan Reinauer278534d2008-10-29 04:51:07 +00001807 * cache before we execute it.
1808 */
1809 goto cache_code;
1810vco_update:
Arthur Heymans70a8e342017-03-09 11:30:23 +01001811 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001812 reg8 &= ~(1 << 7);
1813 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa2, reg8);
1814
Stefan Reinauer278534d2008-10-29 04:51:07 +00001815 clkcfg &= ~(1 << 10);
1816 MCHBAR32(CLKCFG) = clkcfg;
1817 clkcfg |= (1 << 10);
1818 MCHBAR32(CLKCFG) = clkcfg;
1819
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001820 asm volatile (
Stefan Reinauer278534d2008-10-29 04:51:07 +00001821 " movl $0x100, %%ecx\n"
1822 "delay_update:\n"
1823 " nop\n"
1824 " nop\n"
1825 " nop\n"
1826 " nop\n"
1827 " loop delay_update\n"
1828 : /* No outputs */
1829 : /* No inputs */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001830 : "%ecx", "memory"
Stefan Reinauer278534d2008-10-29 04:51:07 +00001831 );
1832
Stefan Reinauer278534d2008-10-29 04:51:07 +00001833 clkcfg &= ~(1 << 10);
1834 MCHBAR32(CLKCFG) = clkcfg;
1835
1836 goto out;
1837cache_code:
1838 goto vco_update;
1839out:
1840
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001841 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", MCHBAR32(CLKCFG));
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001842 printk(BIOS_DEBUG, "ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001843}
1844
1845static void sdram_program_clock_crossing(void)
1846{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001847 int idx = 0;
1848
1849 /**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001850 * We add the indices according to our clocks from CLKCFG.
Stefan Reinauer278534d2008-10-29 04:51:07 +00001851 */
Julius Wernercd49cce2019-03-05 16:53:33 -08001852#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001853 static const u32 data_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001854 0x00100401, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001855 0xffffffff, 0xffffffff, /* nonexistent */
1856 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001857
Stefan Reinauer278534d2008-10-29 04:51:07 +00001858 0x08040120, 0x00000000, /* DDR400 FSB533 */
1859 0x00100401, 0x00000000, /* DDR533 FSB533 */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001860 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001861
1862 0x04020120, 0x00000010, /* DDR400 FSB667 */
1863 0x10040280, 0x00000040, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001864 0x00100401, 0x00000000, /* DDR667 FSB667 */
1865
Martin Roth2ed0aa22016-01-05 20:58:58 -07001866 0xffffffff, 0xffffffff, /* nonexistent */
1867 0xffffffff, 0xffffffff, /* nonexistent */
1868 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001869
Martin Roth2ed0aa22016-01-05 20:58:58 -07001870 0xffffffff, 0xffffffff, /* nonexistent */
1871 0xffffffff, 0xffffffff, /* nonexistent */
1872 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001873 };
1874
1875 static const u32 command_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001876 0x04020208, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001877 0xffffffff, 0xffffffff, /* nonexistent */
1878 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001879
Stefan Reinauer278534d2008-10-29 04:51:07 +00001880 0x00060108, 0x00000000, /* DDR400 FSB533 */
1881 0x04020108, 0x00000000, /* DDR533 FSB533 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001882 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001883
1884 0x00040318, 0x00000000, /* DDR400 FSB667 */
1885 0x04020118, 0x00000000, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001886 0x02010804, 0x00000000, /* DDR667 FSB667 */
1887
Martin Roth2ed0aa22016-01-05 20:58:58 -07001888 0xffffffff, 0xffffffff, /* nonexistent */
1889 0xffffffff, 0xffffffff, /* nonexistent */
1890 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001891
Martin Roth2ed0aa22016-01-05 20:58:58 -07001892 0xffffffff, 0xffffffff, /* nonexistent */
1893 0xffffffff, 0xffffffff, /* nonexistent */
1894 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001895 };
1896
Julius Wernercd49cce2019-03-05 16:53:33 -08001897#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001898 /* i945 G/P */
1899 static const u32 data_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001900 0xffffffff, 0xffffffff, /* nonexistent */
1901 0xffffffff, 0xffffffff, /* nonexistent */
1902 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001903
1904 0x10080201, 0x00000000, /* DDR400 FSB533 */
1905 0x00100401, 0x00000000, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001906 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001907
Martin Roth2ed0aa22016-01-05 20:58:58 -07001908 0xffffffff, 0xffffffff, /* nonexistent */
1909 0xffffffff, 0xffffffff, /* nonexistent */
1910 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001911
1912 0x04020108, 0x00000000, /* DDR400 FSB800 */
1913 0x00020108, 0x00000000, /* DDR533 FSB800 */
1914 0x00080201, 0x00000000, /* DDR667 FSB800 */
1915
1916 0x00010402, 0x00000000, /* DDR400 FSB1066 */
1917 0x04020108, 0x00000000, /* DDR533 FSB1066 */
1918 0x08040110, 0x00000000, /* DDR667 FSB1066 */
1919 };
1920
1921 static const u32 command_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001922 0xffffffff, 0xffffffff, /* nonexistent */
1923 0xffffffff, 0xffffffff, /* nonexistent */
1924 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001925
1926 0x00010800, 0x00000402, /* DDR400 FSB533 */
1927 0x01000400, 0x00000200, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001928 0x00020904, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001929
Martin Roth2ed0aa22016-01-05 20:58:58 -07001930 0xffffffff, 0xffffffff, /* nonexistent */
1931 0xffffffff, 0xffffffff, /* nonexistent */
1932 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001933
1934 0x02010804, 0x00000000, /* DDR400 FSB800 */
1935 0x00010402, 0x00000000, /* DDR533 FSB800 */
Arthur Heymans8b6df622016-10-16 10:58:01 +02001936 0x04020130, 0x00000008, /* DDR667 FSB800 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001937
1938 0x00020904, 0x00000000, /* DDR400 FSB1066 */
1939 0x02010804, 0x00000000, /* DDR533 FSB1066 */
1940 0x180601c0, 0x00000020, /* DDR667 FSB1066 */
1941 };
1942#endif
1943
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001944 printk(BIOS_DEBUG, "Programming Clock Crossing...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001945
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001946 printk(BIOS_DEBUG, "MEM=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001947 switch (memclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001948 case 400:
1949 printk(BIOS_DEBUG, "400"); idx += 0; break;
1950 case 533:
1951 printk(BIOS_DEBUG, "533"); idx += 2; break;
1952 case 667:
1953 printk(BIOS_DEBUG, "667"); idx += 4; break;
1954 default:
1955 printk(BIOS_DEBUG, "RSVD %x", memclk()); return;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001956 }
1957
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001958 printk(BIOS_DEBUG, " FSB=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001959 switch (fsbclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001960 case 400:
1961 printk(BIOS_DEBUG, "400"); idx += 0; break;
1962 case 533:
1963 printk(BIOS_DEBUG, "533"); idx += 6; break;
1964 case 667:
1965 printk(BIOS_DEBUG, "667"); idx += 12; break;
1966 case 800:
1967 printk(BIOS_DEBUG, "800"); idx += 18; break;
1968 case 1066:
1969 printk(BIOS_DEBUG, "1066"); idx += 24; break;
1970 default:
1971 printk(BIOS_DEBUG, "RSVD %x\n", fsbclk()); return;
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001972 }
1973
Arthur Heymans70a8e342017-03-09 11:30:23 +01001974 if (command_clock_crossing[idx] == 0xffffffff)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001975 printk(BIOS_DEBUG, "Invalid MEM/FSB combination!\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001976
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001977 MCHBAR32(CCCFT + 0) = command_clock_crossing[idx];
1978 MCHBAR32(CCCFT + 4) = command_clock_crossing[idx + 1];
1979
Stefan Reinauer278534d2008-10-29 04:51:07 +00001980 MCHBAR32(C0DCCFT + 0) = data_clock_crossing[idx];
1981 MCHBAR32(C0DCCFT + 4) = data_clock_crossing[idx + 1];
1982 MCHBAR32(C1DCCFT + 0) = data_clock_crossing[idx];
1983 MCHBAR32(C1DCCFT + 4) = data_clock_crossing[idx + 1];
1984
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001985 printk(BIOS_DEBUG, "... ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001986}
1987
1988static void sdram_disable_fast_dispatch(void)
1989{
1990 u32 reg32;
1991
1992 reg32 = MCHBAR32(FSBPMC3);
1993 reg32 |= (1 << 1);
1994 MCHBAR32(FSBPMC3) = reg32;
1995
1996 reg32 = MCHBAR32(SBTEST);
1997 reg32 |= (3 << 1);
1998 MCHBAR32(SBTEST) = reg32;
1999}
2000
2001static void sdram_pre_jedec_initialization(void)
2002{
2003 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002004
Stefan Reinauer278534d2008-10-29 04:51:07 +00002005 reg32 = MCHBAR32(WCC);
2006 reg32 &= 0x113ff3ff;
2007 reg32 |= (4 << 29) | (3 << 25) | (1 << 10);
2008 MCHBAR32(WCC) = reg32;
2009
2010 MCHBAR32(SMVREFC) |= (1 << 6);
2011
2012 MCHBAR32(MMARB0) &= ~(3 << 17);
2013 MCHBAR32(MMARB0) |= (1 << 21) | (1 << 16);
2014
2015 MCHBAR32(MMARB1) &= ~(7 << 8);
2016 MCHBAR32(MMARB1) |= (3 << 8);
2017
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002018 /* Adaptive Idle Timer Control */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002019 MCHBAR32(C0AIT) = 0x000006c4;
2020 MCHBAR32(C0AIT+4) = 0x871a066d;
2021
2022 MCHBAR32(C1AIT) = 0x000006c4;
2023 MCHBAR32(C1AIT+4) = 0x871a066d;
2024}
2025
2026#define EA_DUALCHANNEL_XOR_BANK_RANK_MODE (0xd4 << 24)
2027#define EA_DUALCHANNEL_XOR_BANK_MODE (0xf4 << 24)
2028#define EA_DUALCHANNEL_BANK_RANK_MODE (0xc2 << 24)
2029#define EA_DUALCHANNEL_BANK_MODE (0xe2 << 24)
2030#define EA_SINGLECHANNEL_XOR_BANK_RANK_MODE (0x91 << 24)
2031#define EA_SINGLECHANNEL_XOR_BANK_MODE (0xb1 << 24)
2032#define EA_SINGLECHANNEL_BANK_RANK_MODE (0x80 << 24)
2033#define EA_SINGLECHANNEL_BANK_MODE (0xa0 << 24)
2034
2035static void sdram_enhanced_addressing_mode(struct sys_info *sysinfo)
2036{
2037 u32 chan0 = 0, chan1 = 0;
2038 int chan0_dualsided, chan1_dualsided, chan0_populated, chan1_populated;
2039
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002040 chan0_populated = (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Stefan Reinauer278534d2008-10-29 04:51:07 +00002041 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED);
Elyes HAOUAS308aeff2017-02-24 12:53:07 +01002042 chan1_populated = (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
2043 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002044 chan0_dualsided = (sysinfo->banksize[1] || sysinfo->banksize[3]);
2045 chan1_dualsided = (sysinfo->banksize[5] || sysinfo->banksize[7]);
2046
2047 if (sdram_capabilities_enhanced_addressing_xor()) {
2048 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002049 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002050 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002051 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002052 chan0 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002053 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002054 chan0 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002055 }
2056 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002057 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002058 chan1 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002059 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002060 chan1 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002061 }
2062 } else {
2063 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002064 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002065 chan0 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002066 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002067 chan0 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002068
Arthur Heymans70a8e342017-03-09 11:30:23 +01002069 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002070 chan1 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002071 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002072 chan1 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002073 }
2074 } else {
2075 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002076 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002077 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002078 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002079 chan0 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002080 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002081 chan0 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002082 }
2083 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002084 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002085 chan1 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002086 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002087 chan1 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002088 }
2089 } else {
2090 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002091 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002092 chan0 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002093 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002094 chan0 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002095
Arthur Heymans70a8e342017-03-09 11:30:23 +01002096 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002097 chan1 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002098 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002099 chan1 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002100 }
2101 }
2102
2103 MCHBAR32(C0DRC1) &= 0x00ffffff;
2104 MCHBAR32(C0DRC1) |= chan0;
2105 MCHBAR32(C1DRC1) &= 0x00ffffff;
2106 MCHBAR32(C1DRC1) |= chan1;
2107}
2108
2109static void sdram_post_jedec_initialization(struct sys_info *sysinfo)
2110{
2111 u32 reg32;
2112
2113 /* Enable Channel XORing for Dual Channel Interleave */
2114 if (sysinfo->interleaved) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002115
Stefan Reinauer278534d2008-10-29 04:51:07 +00002116 reg32 = MCHBAR32(DCC);
Julius Wernercd49cce2019-03-05 16:53:33 -08002117#if CONFIG(CHANNEL_XOR_RANDOMIZATION)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002118 reg32 &= ~(1 << 10);
Stefan Reinauer30140a52009-03-11 16:20:39 +00002119 reg32 |= (1 << 9);
2120#else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002121 reg32 &= ~(1 << 9);
Stefan Reinauer30140a52009-03-11 16:20:39 +00002122#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002123 MCHBAR32(DCC) = reg32;
2124 }
2125
2126 /* DRAM mode optimizations */
2127 sdram_enhanced_addressing_mode(sysinfo);
2128
2129 reg32 = MCHBAR32(FSBPMC3);
2130 reg32 &= ~(1 << 1);
2131 MCHBAR32(FSBPMC3) = reg32;
2132
2133 reg32 = MCHBAR32(SBTEST);
2134 reg32 &= ~(1 << 2);
2135 MCHBAR32(SBTEST) = reg32;
2136
2137 reg32 = MCHBAR32(SBOCC);
2138 reg32 &= 0xffbdb6ff;
2139 reg32 |= (0xbdb6 << 8) | (1 << 0);
2140 MCHBAR32(SBOCC) = reg32;
2141}
2142
2143static void sdram_power_management(struct sys_info *sysinfo)
2144{
2145 u8 reg8;
2146 u16 reg16;
2147 u32 reg32;
2148 int integrated_graphics = 1;
2149 int i;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002150
Stefan Reinauer278534d2008-10-29 04:51:07 +00002151 reg32 = MCHBAR32(C0DRT2);
2152 reg32 &= 0xffffff00;
2153 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002154 reg32 |= (1 << 5) | (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002155 MCHBAR32(C0DRT2) = reg32;
2156
2157 reg32 = MCHBAR32(C1DRT2);
2158 reg32 &= 0xffffff00;
2159 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002160 reg32 |= (1 << 5) | (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002161 MCHBAR32(C1DRT2) = reg32;
2162
2163 reg32 = MCHBAR32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002164
2165 reg32 |= (1 << 12) | (1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002166 MCHBAR32(C0DRC1) = reg32;
2167
2168 reg32 = MCHBAR32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002169
2170 reg32 |= (1 << 12) | (1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002171 MCHBAR32(C1DRC1) = reg32;
2172
Julius Wernercd49cce2019-03-05 16:53:33 -08002173 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002174 if (i945_silicon_revision() > 1) {
2175 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2176 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002177
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002178 MCHBAR16(UPMC1) = 0x1010 | peg_bits;
2179 } else {
2180 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2181 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002182
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002183 /* Rev 0 and 1 */
2184 MCHBAR16(UPMC1) = 0x0010 | peg_bits;
2185 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002186 }
2187
2188 reg16 = MCHBAR16(UPMC2);
2189 reg16 &= 0xfc00;
2190 reg16 |= 0x0100;
2191 MCHBAR16(UPMC2) = reg16;
2192
2193 MCHBAR32(UPMC3) = 0x000f06ff;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002194
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002195 for (i = 0; i < 5; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002196 MCHBAR32(UPMC3) &= ~(1 << 16);
2197 MCHBAR32(UPMC3) |= (1 << 16);
2198 }
2199
2200 MCHBAR32(GIPMC1) = 0x8000000c;
2201
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002202 reg16 = MCHBAR16(CPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002203 reg16 &= ~(7 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002204 if (i945_silicon_revision() > 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002205 reg16 |= (6 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002206 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002207 reg16 |= (4 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002208 MCHBAR16(CPCTL) = reg16;
2209
Stefan Reinauer30140a52009-03-11 16:20:39 +00002210#if 0
Stefan Reinauer278534d2008-10-29 04:51:07 +00002211 if ((MCHBAR32(ECO) & (1 << 16)) != 0) {
Stefan Reinauer30140a52009-03-11 16:20:39 +00002212#else
2213 if (i945_silicon_revision() != 0) {
2214#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002215 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002216 case 667:
2217 MCHBAR32(HGIPMC2) = 0x0d590d59; break;
2218 case 533:
2219 MCHBAR32(HGIPMC2) = 0x155b155b; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002220 }
2221 } else {
2222 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002223 case 667:
2224 MCHBAR32(HGIPMC2) = 0x09c409c4; break;
2225 case 533:
2226 MCHBAR32(HGIPMC2) = 0x0fa00fa0; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002227 }
2228 }
2229
2230 MCHBAR32(FSBPMC1) = 0x8000000c;
2231
2232 reg32 = MCHBAR32(C2C3TT);
2233 reg32 &= 0xffff0000;
2234 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002235 case 667:
2236 reg32 |= 0x0600; break;
2237 case 533:
2238 reg32 |= 0x0480; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002239 }
2240 MCHBAR32(C2C3TT) = reg32;
2241
2242 reg32 = MCHBAR32(C3C4TT);
2243 reg32 &= 0xffff0000;
2244 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002245 case 667:
2246 reg32 |= 0x0b80; break;
2247 case 533:
2248 reg32 |= 0x0980; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002249 }
2250 MCHBAR32(C3C4TT) = reg32;
2251
Arthur Heymans70a8e342017-03-09 11:30:23 +01002252 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002253 MCHBAR32(ECO) &= ~(1 << 16);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002254 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002255 MCHBAR32(ECO) |= (1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002256
2257#if 0
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002258
Arthur Heymans70a8e342017-03-09 11:30:23 +01002259 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002260 MCHBAR32(FSBPMC3) &= ~(1 << 29);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002261 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002262 MCHBAR32(FSBPMC3) |= (1 << 29);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002263#endif
2264 MCHBAR32(FSBPMC3) &= ~(1 << 29);
2265
2266 MCHBAR32(FSBPMC3) |= (1 << 21);
2267
2268 MCHBAR32(FSBPMC3) &= ~(1 << 19);
2269
2270 MCHBAR32(FSBPMC3) &= ~(1 << 13);
2271
2272 reg32 = MCHBAR32(FSBPMC4);
2273 reg32 &= ~(3 << 24);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002274 reg32 |= (2 << 24);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002275 MCHBAR32(FSBPMC4) = reg32;
2276
2277 MCHBAR32(FSBPMC4) |= (1 << 21);
2278
2279 MCHBAR32(FSBPMC4) |= (1 << 5);
2280
Arthur Heymans70a8e342017-03-09 11:30:23 +01002281 if ((i945_silicon_revision() < 2)) { /* || cpuid() = 0x6e8 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002282 /* stepping 0 and 1 or CPUID 6e8 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002283 MCHBAR32(FSBPMC4) &= ~(1 << 4);
2284 } else {
Stefan Reinauer30140a52009-03-11 16:20:39 +00002285 MCHBAR32(FSBPMC4) |= (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002286 }
2287
Arthur Heymans70a8e342017-03-09 11:30:23 +01002288 reg8 = pci_read_config8(PCI_DEV(0, 0x0, 0), 0xfc);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002289 reg8 |= (1 << 4);
2290 pci_write_config8(PCI_DEV(0, 0x0, 0), 0xfc, reg8);
2291
Arthur Heymans70a8e342017-03-09 11:30:23 +01002292 reg8 = pci_read_config8(PCI_DEV(0, 0x2, 0), 0xc1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002293 reg8 |= (1 << 2);
2294 pci_write_config8(PCI_DEV(0, 0x2, 0), 0xc1, reg8);
2295
Stefan Reinauerde3206a2010-02-22 06:09:43 +00002296#ifdef C2_SELF_REFRESH_DISABLE
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002297
Stefan Reinauer278534d2008-10-29 04:51:07 +00002298 if (integrated_graphics) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002299 printk(BIOS_DEBUG, "C2 self-refresh with IGD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002300 MCHBAR16(MIPMC4) = 0x0468;
2301 MCHBAR16(MIPMC5) = 0x046c;
2302 MCHBAR16(MIPMC6) = 0x046c;
2303 } else {
2304 MCHBAR16(MIPMC4) = 0x6468;
2305 MCHBAR16(MIPMC5) = 0x646c;
2306 MCHBAR16(MIPMC6) = 0x646c;
2307 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002308#else
2309 if (integrated_graphics) {
2310 MCHBAR16(MIPMC4) = 0x04f8;
2311 MCHBAR16(MIPMC5) = 0x04fc;
2312 MCHBAR16(MIPMC6) = 0x04fc;
2313 } else {
2314 MCHBAR16(MIPMC4) = 0x64f8;
2315 MCHBAR16(MIPMC5) = 0x64fc;
2316 MCHBAR16(MIPMC6) = 0x64fc;
2317 }
2318
2319#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002320
2321 reg32 = MCHBAR32(PMCFG);
2322 reg32 &= ~(3 << 17);
2323 reg32 |= (2 << 17);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002324 MCHBAR32(PMCFG) = reg32;
2325
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002326 MCHBAR32(PMCFG) |= (1 << 4);
2327
Stefan Reinauer278534d2008-10-29 04:51:07 +00002328 reg32 = MCHBAR32(0xc30);
2329 reg32 &= 0xffffff00;
2330 reg32 |= 0x01;
2331 MCHBAR32(0xc30) = reg32;
2332
2333 MCHBAR32(0xb18) &= ~(1 << 21);
2334}
2335
2336static void sdram_thermal_management(void)
2337{
Stefan Reinauer278534d2008-10-29 04:51:07 +00002338
Stefan Reinauer278534d2008-10-29 04:51:07 +00002339 MCHBAR8(TCO1) = 0x00;
2340 MCHBAR8(TCO0) = 0x00;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002341
2342 /* The Thermal Sensors for DIMMs at 0x50, 0x52 are at I2C addr
2343 * 0x30/0x32.
2344 */
2345
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002346 /* TODO This is not implemented yet. Volunteers? */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002347}
2348
2349static void sdram_save_receive_enable(void)
2350{
2351 int i;
2352 u32 reg32;
2353 u8 values[4];
2354
2355 /* The following values are stored to an unused CMOS
2356 * area and restored instead of recalculated in case
2357 * of an S3 resume.
2358 *
Arthur Heymans70a8e342017-03-09 11:30:23 +01002359 * C0WL0REOST [7:0] -> 8 bit
2360 * C1WL0REOST [7:0] -> 8 bit
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002361 * RCVENMT [11:8] [3:0] -> 8 bit
2362 * C0DRT1 [27:24] -> 4 bit
2363 * C1DRT1 [27:24] -> 4 bit
2364 */
2365
2366 values[0] = MCHBAR8(C0WL0REOST);
2367 values[1] = MCHBAR8(C1WL0REOST);
2368
2369 reg32 = MCHBAR32(RCVENMT);
2370 values[2] = (u8)((reg32 >> (8 - 4)) & 0xf0) | (reg32 & 0x0f);
2371
2372 reg32 = MCHBAR32(C0DRT1);
2373 values[3] = (reg32 >> 24) & 0x0f;
2374 reg32 = MCHBAR32(C1DRT1);
2375 values[3] |= (reg32 >> (24 - 4)) & 0xf0;
2376
2377 /* coreboot only uses bytes 0 - 127 for its CMOS values so far
Edwin Beasanteb50c7d2010-07-06 21:05:04 +00002378 * so we grab bytes 128 - 131 to save the receive enable values
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002379 */
2380
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002381 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002382 cmos_write(values[i], 128 + i);
2383}
2384
2385static void sdram_recover_receive_enable(void)
2386{
2387 int i;
2388 u32 reg32;
2389 u8 values[4];
2390
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002391 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002392 values[i] = cmos_read(128 + i);
2393
2394 MCHBAR8(C0WL0REOST) = values[0];
2395 MCHBAR8(C1WL0REOST) = values[1];
2396
2397 reg32 = MCHBAR32(RCVENMT);
2398 reg32 &= ~((0x0f << 8) | (0x0f << 0));
2399 reg32 |= ((u32)(values[2] & 0xf0) << (8 - 4)) | (values[2] & 0x0f);
2400 MCHBAR32(RCVENMT) = reg32;
2401
2402 reg32 = MCHBAR32(C0DRT1) & ~(0x0f << 24);
2403 reg32 |= (u32)(values[3] & 0x0f) << 24;
2404 MCHBAR32(C0DRT1) = reg32;
2405
2406 reg32 = MCHBAR32(C1DRT1) & ~(0x0f << 24);
2407 reg32 |= (u32)(values[3] & 0xf0) << (24 - 4);
2408 MCHBAR32(C1DRT1) = reg32;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002409}
2410
Stefan Reinauer278534d2008-10-29 04:51:07 +00002411static void sdram_program_receive_enable(struct sys_info *sysinfo)
2412{
2413 MCHBAR32(REPC) |= (1 << 0);
2414
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002415 /* Program Receive Enable Timings */
2416 if (sysinfo->boot_path == BOOT_PATH_RESUME) {
2417 sdram_recover_receive_enable();
2418 } else {
2419 receive_enable_adjust(sysinfo);
2420 sdram_save_receive_enable();
2421 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002422
2423 MCHBAR32(C0DRC1) |= (1 << 6);
2424 MCHBAR32(C1DRC1) |= (1 << 6);
2425 MCHBAR32(C0DRC1) &= ~(1 << 6);
2426 MCHBAR32(C1DRC1) &= ~(1 << 6);
2427
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002428 MCHBAR32(MIPMC3) |= (0x0f << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002429}
2430
2431/**
2432 * @brief Enable On-Die Termination for DDR2.
2433 *
2434 */
2435
2436static void sdram_on_die_termination(struct sys_info *sysinfo)
2437{
2438 static const u32 odt[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002439 0x00024911, 0xe0010000,
2440 0x00049211, 0xe0020000,
2441 0x0006db11, 0xe0030000,
Stefan Reinauer278534d2008-10-29 04:51:07 +00002442 };
2443
2444 u32 reg32;
2445 int cas;
2446
2447 reg32 = MCHBAR32(ODTC);
2448 reg32 &= ~(3 << 16);
2449 reg32 |= (1 << 14) | (1 << 6) | (2 << 16);
2450 MCHBAR32(ODTC) = reg32;
2451
Arthur Heymans70a8e342017-03-09 11:30:23 +01002452 if (!(sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED &&
2453 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)) {
Elyes HAOUAS38424982016-08-21 12:01:04 +02002454 printk(BIOS_DEBUG, "one dimm per channel config..\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002455
Stefan Reinauer278534d2008-10-29 04:51:07 +00002456 reg32 = MCHBAR32(C0ODT);
2457 reg32 &= ~(7 << 28);
2458 MCHBAR32(C0ODT) = reg32;
2459 reg32 = MCHBAR32(C1ODT);
2460 reg32 &= ~(7 << 28);
2461 MCHBAR32(C1ODT) = reg32;
2462 }
2463
2464 cas = sysinfo->cas;
2465
2466 reg32 = MCHBAR32(C0ODT) & 0xfff00000;
2467 reg32 |= odt[(cas-3) * 2];
2468 MCHBAR32(C0ODT) = reg32;
2469
2470 reg32 = MCHBAR32(C1ODT) & 0xfff00000;
2471 reg32 |= odt[(cas-3) * 2];
2472 MCHBAR32(C1ODT) = reg32;
2473
2474 reg32 = MCHBAR32(C0ODT + 4) & 0x1fc8ffff;
2475 reg32 |= odt[((cas-3) * 2) + 1];
2476 MCHBAR32(C0ODT + 4) = reg32;
2477
2478 reg32 = MCHBAR32(C1ODT + 4) & 0x1fc8ffff;
2479 reg32 |= odt[((cas-3) * 2) + 1];
2480 MCHBAR32(C1ODT + 4) = reg32;
2481}
2482
2483/**
2484 * @brief Enable clocks to populated sockets
2485 */
2486
2487static void sdram_enable_memory_clocks(struct sys_info *sysinfo)
2488{
2489 u8 clocks[2] = { 0, 0 };
2490
Julius Wernercd49cce2019-03-05 16:53:33 -08002491#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002492#define CLOCKS_WIDTH 2
Julius Wernercd49cce2019-03-05 16:53:33 -08002493#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002494#define CLOCKS_WIDTH 3
2495#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002496 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002497 clocks[0] |= (1 << CLOCKS_WIDTH)-1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002498
2499 if (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002500 clocks[0] |= ((1 << CLOCKS_WIDTH)-1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002501
2502 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002503 clocks[1] |= (1 << CLOCKS_WIDTH)-1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002504
2505 if (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002506 clocks[1] |= ((1 << CLOCKS_WIDTH)-1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002507
Julius Wernercd49cce2019-03-05 16:53:33 -08002508#if CONFIG(OVERRIDE_CLOCK_DISABLE)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002509 /* Usually system firmware turns off system memory clock signals
2510 * to unused SO-DIMM slots to reduce EMI and power consumption.
2511 * However, the Kontron 986LCD-M does not like unused clock
2512 * signals to be disabled.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002513 */
2514
2515 clocks[0] = 0xf; /* force all clock gate pairs to enable */
2516 clocks[1] = 0xf; /* force all clock gate pairs to enable */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002517#endif
2518
2519 MCHBAR8(C0DCLKDIS) = clocks[0];
2520 MCHBAR8(C1DCLKDIS) = clocks[1];
2521}
2522
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002523#define RTT_ODT_NONE 0
Arthur Heymans70a8e342017-03-09 11:30:23 +01002524#define RTT_ODT_50_OHM ((1 << 9) | (1 << 5))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002525#define RTT_ODT_75_OHM (1 << 5)
2526#define RTT_ODT_150_OHM (1 << 9)
2527
Arthur Heymans70a8e342017-03-09 11:30:23 +01002528#define EMRS_OCD_DEFAULT ((1 << 12) | (1 << 11) | (1 << 10))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002529
2530#define MRS_CAS_3 (3 << 7)
2531#define MRS_CAS_4 (4 << 7)
2532#define MRS_CAS_5 (5 << 7)
2533
2534#define MRS_TWR_3 (2 << 12)
2535#define MRS_TWR_4 (3 << 12)
2536#define MRS_TWR_5 (4 << 12)
2537
2538#define MRS_BT (1 << 6)
2539
2540#define MRS_BL4 (2 << 3)
2541#define MRS_BL8 (3 << 3)
2542
2543static void sdram_jedec_enable(struct sys_info *sysinfo)
2544{
2545 int i, nonzero;
2546 u32 bankaddr = 0, tmpaddr, mrsaddr = 0;
2547
2548 for (i = 0, nonzero = -1; i < 8; i++) {
Elyes HAOUAS01912202019-01-19 16:36:38 +01002549 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002550 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002551
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002552 printk(BIOS_DEBUG, "jedec enable sequence: bank %d\n", i);
Elyes HAOUAS01912202019-01-19 16:36:38 +01002553
2554 if (nonzero != -1) {
2555 if (sysinfo->interleaved && nonzero < 4 && i >= 4) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002556 bankaddr = 0x40;
Elyes HAOUAS01912202019-01-19 16:36:38 +01002557 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002558 printk(BIOS_DEBUG, "bankaddr from bank size of rank %d\n", nonzero);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002559 bankaddr += sysinfo->banksize[nonzero] <<
2560 (sysinfo->interleaved ? 26 : 25);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002561 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002562 }
2563
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002564 /* We have a bank with a non-zero size.. Remember it
Stefan Reinauer278534d2008-10-29 04:51:07 +00002565 * for the next offset we have to calculate
2566 */
2567 nonzero = i;
2568
2569 /* Get CAS latency set up */
2570 switch (sysinfo->cas) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002571 case 5:
2572 mrsaddr = MRS_CAS_5; break;
2573 case 4:
2574 mrsaddr = MRS_CAS_4; break;
2575 case 3:
2576 mrsaddr = MRS_CAS_3; break;
2577 default:
2578 die("Jedec Error (CAS).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002579 }
2580
2581 /* Get tWR set */
2582 switch (sysinfo->twr) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002583 case 5:
2584 mrsaddr |= MRS_TWR_5; break;
2585 case 4:
2586 mrsaddr |= MRS_TWR_4; break;
2587 case 3:
2588 mrsaddr |= MRS_TWR_3; break;
2589 default:
2590 die("Jedec Error (tWR).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002591 }
2592
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002593 /* Set "Burst Type" */
2594 mrsaddr |= MRS_BT;
2595
Stefan Reinauer278534d2008-10-29 04:51:07 +00002596 /* Interleaved */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002597 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002598 mrsaddr = mrsaddr << 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002599
2600 /* Only burst length 8 supported */
2601 mrsaddr |= MRS_BL8;
2602
2603 /* Apply NOP */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002604 PRINTK_DEBUG("Apply NOP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002605 do_ram_command(RAM_COMMAND_NOP);
2606 ram_read32(bankaddr);
2607
2608 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002609 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002610 do_ram_command(RAM_COMMAND_PRECHARGE);
2611 ram_read32(bankaddr);
2612
2613 /* Extended Mode Register Set (2) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002614 PRINTK_DEBUG("Extended Mode Register Set(2)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002615 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_2);
2616 ram_read32(bankaddr);
2617
2618 /* Extended Mode Register Set (3) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002619 PRINTK_DEBUG("Extended Mode Register Set(3)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002620 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_3);
2621 ram_read32(bankaddr);
2622
2623 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002624 PRINTK_DEBUG("Extended Mode Register Set\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002625 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2626 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002627 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002628 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002629 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002630 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002631 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002632 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002633 ram_read32(tmpaddr);
2634
2635 /* Mode Register Set: Reset DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002636 PRINTK_DEBUG("MRS: Reset DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002637 do_ram_command(RAM_COMMAND_MRS);
2638 tmpaddr = bankaddr;
2639 tmpaddr |= mrsaddr;
2640 /* Set DLL reset bit */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002641 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002642 tmpaddr |= (1 << 12);
2643 else
2644 tmpaddr |= (1 << 11);
2645 ram_read32(tmpaddr);
2646
2647 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002648 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002649 do_ram_command(RAM_COMMAND_PRECHARGE);
2650 ram_read32(bankaddr);
2651
2652 /* CAS before RAS Refresh */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002653 PRINTK_DEBUG("CAS before RAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002654 do_ram_command(RAM_COMMAND_CBR);
2655
2656 /* CBR wants two READs */
2657 ram_read32(bankaddr);
2658 ram_read32(bankaddr);
2659
2660 /* Mode Register Set: Enable DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002661 PRINTK_DEBUG("MRS: Enable DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002662 do_ram_command(RAM_COMMAND_MRS);
2663
2664 tmpaddr = bankaddr;
2665 tmpaddr |= mrsaddr;
2666 ram_read32(tmpaddr);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002667
Stefan Reinauer278534d2008-10-29 04:51:07 +00002668 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002669 PRINTK_DEBUG("Extended Mode Register Set: ODT/OCD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002670 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002671
Stefan Reinauer278534d2008-10-29 04:51:07 +00002672 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002673 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002674 tmpaddr |= RTT_ODT_75_OHM | EMRS_OCD_DEFAULT;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002675 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002676 tmpaddr |= ((RTT_ODT_150_OHM | EMRS_OCD_DEFAULT) << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002677 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002678 tmpaddr |= RTT_ODT_150_OHM | EMRS_OCD_DEFAULT;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002679 ram_read32(tmpaddr);
2680
2681 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002682 PRINTK_DEBUG("Extended Mode Register Set: OCD Exit\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002683 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2684
2685 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002686 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002687 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002688 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002689 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002690 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002691 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002692 ram_read32(tmpaddr);
2693 }
2694}
2695
2696static void sdram_init_complete(void)
2697{
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002698 PRINTK_DEBUG("Normal Operation\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002699 do_ram_command(RAM_COMMAND_NORMAL);
2700}
2701
2702static void sdram_setup_processor_side(void)
2703{
2704 if (i945_silicon_revision() == 0)
2705 MCHBAR32(FSBPMC3) |= (1 << 2);
2706
2707 MCHBAR8(0xb00) |= 1;
2708
2709 if (i945_silicon_revision() == 0)
2710 MCHBAR32(SLPCTL) |= (1 << 8);
2711}
2712
Stefan Reinauer278534d2008-10-29 04:51:07 +00002713/**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002714 * @param boot_path: 0 = normal, 1 = reset, 2 = resume from s3
Martin Rothf4cb4122015-01-06 10:27:39 -07002715 * @param spd_addresses pointer to a list of SPD addresses
Stefan Reinauer278534d2008-10-29 04:51:07 +00002716 */
Sven Schnelle541269b2011-02-21 09:39:17 +00002717void sdram_initialize(int boot_path, const u8 *spd_addresses)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002718{
2719 struct sys_info sysinfo;
Arthur Heymans0ab49042017-02-06 22:40:14 +01002720 u8 reg8;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002721
Patrick Georgi771328f2015-07-13 19:24:07 +02002722 timestamp_add_now(TS_BEFORE_INITRAM);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002723 printk(BIOS_DEBUG, "Setting up RAM controller.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002724
2725 memset(&sysinfo, 0, sizeof(sysinfo));
2726
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002727 sysinfo.boot_path = boot_path;
Sven Schnelle541269b2011-02-21 09:39:17 +00002728 sysinfo.spd_addresses = spd_addresses;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002729
Stefan Reinauer278534d2008-10-29 04:51:07 +00002730 /* Look at the type of DIMMs and verify all DIMMs are x8 or x16 width */
2731 sdram_get_dram_configuration(&sysinfo);
2732
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002733 /* If error, do cold boot */
2734 sdram_detect_errors(&sysinfo);
2735
Stefan Reinauer278534d2008-10-29 04:51:07 +00002736 /* Program PLL settings */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002737 sdram_program_pll_settings(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002738
Arthur Heymans18537812016-12-28 21:20:45 +01002739 /*
2740 * Program Graphics Frequency
2741 * Set core display and render clock on 945GC to the max
2742 */
Julius Wernercd49cce2019-03-05 16:53:33 -08002743 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM))
Arthur Heymans18537812016-12-28 21:20:45 +01002744 sdram_program_graphics_frequency(&sysinfo);
2745 else
2746 pci_write_config16(PCI_DEV(0, 2, 0), GCFC, 0x0534);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002747
2748 /* Program System Memory Frequency */
2749 sdram_program_memory_frequency(&sysinfo);
2750
2751 /* Determine Mode of Operation (Interleaved etc) */
2752 sdram_set_channel_mode(&sysinfo);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002753
Stefan Reinauer278534d2008-10-29 04:51:07 +00002754 /* Program Clock Crossing values */
2755 sdram_program_clock_crossing();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002756
Stefan Reinauer278534d2008-10-29 04:51:07 +00002757 /* Disable fast dispatch */
2758 sdram_disable_fast_dispatch();
2759
2760 /* Enable WIODLL Power Down in ACPI states */
2761 MCHBAR32(C0DMC) |= (1 << 24);
2762 MCHBAR32(C1DMC) |= (1 << 24);
2763
2764 /* Program DRAM Row Boundary/Attribute Registers */
2765
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002766 /* program row size DRB and set TOLUD */
2767 sdram_program_row_boundaries(&sysinfo);
2768
2769 /* program page size DRA */
2770 sdram_set_row_attributes(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002771
2772 /* Program CxBNKARC */
2773 sdram_set_bank_architecture(&sysinfo);
2774
2775 /* Program DRAM Timing and Control registers based on SPD */
2776 sdram_set_timing_and_control(&sysinfo);
2777
2778 /* On-Die Termination Adjustment */
2779 sdram_on_die_termination(&sysinfo);
2780
2781 /* Pre Jedec Initialization */
2782 sdram_pre_jedec_initialization();
2783
2784 /* Perform System Memory IO Initialization */
2785 sdram_initialize_system_memory_io(&sysinfo);
2786
2787 /* Perform System Memory IO Buffer Enable */
2788 sdram_enable_system_memory_io(&sysinfo);
2789
2790 /* Enable System Memory Clocks */
2791 sdram_enable_memory_clocks(&sysinfo);
2792
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002793 if (boot_path == BOOT_PATH_NORMAL) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002794 /* Jedec Initialization sequence */
2795 sdram_jedec_enable(&sysinfo);
2796 }
2797
2798 /* Program Power Management Registers */
2799 sdram_power_management(&sysinfo);
2800
2801 /* Post Jedec Init */
2802 sdram_post_jedec_initialization(&sysinfo);
2803
2804 /* Program DRAM Throttling */
2805 sdram_thermal_management();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002806
Stefan Reinauer278534d2008-10-29 04:51:07 +00002807 /* Normal Operations */
Stefan Reinaueraca6ec62009-10-26 17:12:21 +00002808 sdram_init_complete();
Stefan Reinauer278534d2008-10-29 04:51:07 +00002809
2810 /* Program Receive Enable Timings */
2811 sdram_program_receive_enable(&sysinfo);
2812
2813 /* Enable Periodic RCOMP */
2814 sdram_enable_rcomp();
2815
2816 /* Tell ICH7 that we're done */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002817 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002818 reg8 &= ~(1 << 7);
2819 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa2, reg8);
2820
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002821 printk(BIOS_DEBUG, "RAM initialization finished.\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002822
Stefan Reinauer278534d2008-10-29 04:51:07 +00002823 sdram_setup_processor_side();
Patrick Georgi771328f2015-07-13 19:24:07 +02002824 timestamp_add_now(TS_AFTER_INITRAM);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002825}