blob: 74407c14ffbcdd294855989fef1c49989ed82853 [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>
Stefan Reinauer278534d2008-10-29 04:51:07 +000029#include "raminit.h"
30#include "i945.h"
Arthur Heymans885c2892016-10-03 17:16:48 +020031#include "chip.h"
Arthur Heymans0ab49042017-02-06 22:40:14 +010032#include <device/dram/ddr2.h>
Patrick Georgi771328f2015-07-13 19:24:07 +020033#include <timestamp.h>
Rudolf Marekc4369532010-12-13 19:59:13 +000034
Stefan Reinauer278534d2008-10-29 04:51:07 +000035/* Debugging macros. */
Julius Wernercd49cce2019-03-05 16:53:33 -080036#if CONFIG(DEBUG_RAM_SETUP)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000037#define PRINTK_DEBUG(x...) printk(BIOS_DEBUG, x)
Stefan Reinauer278534d2008-10-29 04:51:07 +000038#else
39#define PRINTK_DEBUG(x...)
40#endif
41
Stefan Reinauer278534d2008-10-29 04:51:07 +000042#define RAM_INITIALIZATION_COMPLETE (1 << 19)
43
44#define RAM_COMMAND_SELF_REFRESH (0x0 << 16)
45#define RAM_COMMAND_NOP (0x1 << 16)
46#define RAM_COMMAND_PRECHARGE (0x2 << 16)
47#define RAM_COMMAND_MRS (0x3 << 16)
48#define RAM_COMMAND_EMRS (0x4 << 16)
49#define RAM_COMMAND_CBR (0x6 << 16)
50#define RAM_COMMAND_NORMAL (0x7 << 16)
51
52#define RAM_EMRS_1 (0x0 << 21)
53#define RAM_EMRS_2 (0x1 << 21)
54#define RAM_EMRS_3 (0x2 << 21)
55
Arthur Heymans885c2892016-10-03 17:16:48 +020056#define DEFAULT_PCI_MMIO_SIZE 768
Sven Schnelle541269b2011-02-21 09:39:17 +000057static int get_dimm_spd_address(struct sys_info *sysinfo, int device)
58{
59 if (sysinfo->spd_addresses)
60 return sysinfo->spd_addresses[device];
61 else
62 return DIMM0 + device;
63
64}
65
Arthur Heymans70a8e342017-03-09 11:30:23 +010066static inline int spd_read_byte(unsigned int device, unsigned int address)
Patrick Georgid0835952010-10-05 09:07:10 +000067{
68 return smbus_read_byte(device, address);
69}
70
Stefan Reinauerbc8613e2010-08-25 18:35:42 +000071static __attribute__((noinline)) void do_ram_command(u32 command)
Stefan Reinauer278534d2008-10-29 04:51:07 +000072{
73 u32 reg32;
74
75 reg32 = MCHBAR32(DCC);
Arthur Heymans70a8e342017-03-09 11:30:23 +010076 reg32 &= ~((3<<21) | (1<<20) | (1<<19) | (7 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +000077 reg32 |= command;
78
79 /* Also set Init Complete */
80 if (command == RAM_COMMAND_NORMAL)
81 reg32 |= RAM_INITIALIZATION_COMPLETE;
82
83 PRINTK_DEBUG(" Sending RAM command 0x%08x", reg32);
84
85 MCHBAR32(DCC) = reg32; /* This is the actual magic */
86
Stefan Reinauer779b3e32008-11-10 15:43:37 +000087 PRINTK_DEBUG("...done\n");
Stefan Reinauerd058ad12010-08-26 12:43:58 +000088
89 udelay(1);
Stefan Reinauer278534d2008-10-29 04:51:07 +000090}
91
Stefan Reinauer278534d2008-10-29 04:51:07 +000092static void ram_read32(u32 offset)
93{
Elyes HAOUAS15279a92016-07-28 21:05:26 +020094 PRINTK_DEBUG(" RAM read: %08x\n", offset);
Stefan Reinauer278534d2008-10-29 04:51:07 +000095
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080096 read32((void *)offset);
Stefan Reinauer278534d2008-10-29 04:51:07 +000097}
98
Stefan Reinauer3c0bfaf2010-12-27 11:34:57 +000099void sdram_dump_mchbar_registers(void)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000100{
101 int i;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000102 printk(BIOS_DEBUG, "Dumping MCHBAR Registers\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000103
Arthur Heymans70a8e342017-03-09 11:30:23 +0100104 for (i = 0; i < 0xfff; i += 4) {
Stefan Reinauer278534d2008-10-29 04:51:07 +0000105 if (MCHBAR32(i) == 0)
106 continue;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000107 printk(BIOS_DEBUG, "0x%04x: 0x%08x\n", i, MCHBAR32(i));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000108 }
109}
Stefan Reinauer278534d2008-10-29 04:51:07 +0000110
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000111static int memclk(void)
112{
Julius Wernercd49cce2019-03-05 16:53:33 -0800113 int offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200114
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000115 switch (((MCHBAR32(CLKCFG) >> 4) & 7) - offset) {
116 case 1: return 400;
117 case 2: return 533;
118 case 3: return 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100119 default:
120 printk(BIOS_DEBUG, "memclk: unknown register value %x\n",
121 ((MCHBAR32(CLKCFG) >> 4) & 7) - offset);
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000122 }
123 return -1;
124}
125
Peter Stuge76d91432010-10-01 10:02:33 +0000126static u16 fsbclk(void)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000127{
Julius Wernercd49cce2019-03-05 16:53:33 -0800128 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200129 switch (MCHBAR32(CLKCFG) & 7) {
130 case 0: return 400;
131 case 1: return 533;
132 case 3: return 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100133 default:
134 printk(BIOS_DEBUG, "fsbclk: unknown register value %x\n",
135 MCHBAR32(CLKCFG) & 7);
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200136 }
137 return 0xffff;
Julius Wernercd49cce2019-03-05 16:53:33 -0800138 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200139 switch (MCHBAR32(CLKCFG) & 7) {
140 case 0: return 1066;
141 case 1: return 533;
142 case 2: return 800;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100143 default:
144 printk(BIOS_DEBUG, "fsbclk: unknown register value %x\n",
145 MCHBAR32(CLKCFG) & 7);
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200146 }
147 return 0xffff;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000148 }
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000149}
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000150
Stefan Reinauer278534d2008-10-29 04:51:07 +0000151static int sdram_capabilities_max_supported_memory_frequency(void)
152{
153 u32 reg32;
154
Patrick Georgi77d66832010-10-01 08:02:45 +0000155#if CONFIG_MAXIMUM_SUPPORTED_FREQUENCY
156 return CONFIG_MAXIMUM_SUPPORTED_FREQUENCY;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000157#endif
158
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000159 reg32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000160 reg32 &= (7 << 0);
161
162 switch (reg32) {
163 case 4: return 400;
164 case 3: return 533;
165 case 2: return 667;
166 }
167 /* Newer revisions of this chipset rather support faster memory clocks,
168 * so if it's a reserved value, return the fastest memory clock that we
169 * know of and can handle
170 */
171 return 667;
172}
173
174/**
175 * @brief determine whether chipset is capable of dual channel interleaved mode
176 *
177 * @return 1 if interleaving is supported, 0 otherwise
178 */
179static int sdram_capabilities_interleave(void)
180{
181 u32 reg32;
182
Arthur Heymans70a8e342017-03-09 11:30:23 +0100183 reg32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000184 reg32 >>= 25;
185 reg32 &= 1;
186
187 return (!reg32);
188}
189
190/**
191 * @brief determine whether chipset is capable of two memory channels
192 *
193 * @return 1 if dual channel operation is supported, 0 otherwise
194 */
195static int sdram_capabilities_dual_channel(void)
196{
197 u32 reg32;
198
Arthur Heymans70a8e342017-03-09 11:30:23 +0100199 reg32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000200 reg32 >>= 24;
201 reg32 &= 1;
202
203 return (!reg32);
204}
205
206static int sdram_capabilities_enhanced_addressing_xor(void)
207{
208 u8 reg8;
209
210 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
211 reg8 &= (1 << 7);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000212
Stefan Reinauer278534d2008-10-29 04:51:07 +0000213 return (!reg8);
214}
215
Stefan Reinauer14e22772010-04-27 06:56:47 +0000216// TODO check if we ever need this function
Stefan Reinauer53b0ea42010-03-22 11:50:52 +0000217#if 0
Stefan Reinauer278534d2008-10-29 04:51:07 +0000218static int sdram_capabilities_MEM4G_disable(void)
219{
220 u8 reg8;
221
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000222 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000223 reg8 &= (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000224
Stefan Reinauer278534d2008-10-29 04:51:07 +0000225 return (reg8 != 0);
226}
Stefan Reinauer53b0ea42010-03-22 11:50:52 +0000227#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +0000228
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000229#define GFX_FREQUENCY_CAP_166MHZ 0x04
230#define GFX_FREQUENCY_CAP_200MHZ 0x03
231#define GFX_FREQUENCY_CAP_250MHZ 0x02
232#define GFX_FREQUENCY_CAP_ALL 0x00
233
234static int sdram_capabilities_core_frequencies(void)
235{
236 u8 reg8;
237
238 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
239 reg8 &= (1 << 3) | (1 << 2) | (1 << 1);
240 reg8 >>= 1;
241
Arthur Heymans70a8e342017-03-09 11:30:23 +0100242 return reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000243}
244
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000245static void sdram_detect_errors(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000246{
247 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000248 u8 do_reset = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000249
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100250 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000251
Stefan Reinauer278534d2008-10-29 04:51:07 +0000252 if (reg8 & ((1<<7)|(1<<2))) {
253 if (reg8 & (1<<2)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000254 printk(BIOS_DEBUG, "SLP S4# Assertion Width Violation.\n");
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000255 /* Write back clears bit 2 */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100256 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000257 do_reset = 1;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000258
Stefan Reinauer278534d2008-10-29 04:51:07 +0000259 }
260
261 if (reg8 & (1<<7)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000262 printk(BIOS_DEBUG, "DRAM initialization was interrupted.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000263 reg8 &= ~(1<<7);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100264 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000265 do_reset = 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000266 }
267
268 /* Set SLP_S3# Assertion Stretch Enable */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100269 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000270 reg8 |= (1 << 3);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100271 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000272
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000273 if (do_reset) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000274 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200275 full_reset();
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000276 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000277 }
278
279 /* Set DRAM initialization bit in ICH7 */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100280 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000281 reg8 |= (1<<7);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100282 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000283
Peter Stuge751508a2012-01-27 22:17:09 +0100284 /* clear self refresh status if check is disabled or not a resume */
Julius Werner5d1f9a02019-03-07 17:07:26 -0800285 if (!CONFIG(CHECK_SLFRCS_ON_RESUME)
Arthur Heymans0ab49042017-02-06 22:40:14 +0100286 || sysinfo->boot_path != BOOT_PATH_RESUME) {
Patrick Georgi86a11102013-03-15 14:11:37 +0100287 MCHBAR8(SLFRCS) |= 3;
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000288 } else {
289 /* Validate self refresh config */
290 if (((sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED) ||
291 (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)) &&
Patrick Georgi86a11102013-03-15 14:11:37 +0100292 !(MCHBAR8(SLFRCS) & (1<<0))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000293 do_reset = 1;
294 }
295 if (((sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED) ||
296 (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) &&
Patrick Georgi86a11102013-03-15 14:11:37 +0100297 !(MCHBAR8(SLFRCS) & (1<<1))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000298 do_reset = 1;
299 }
300 }
301
302 if (do_reset) {
303 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200304 full_reset();
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000305 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000306}
Stefan Reinauer278534d2008-10-29 04:51:07 +0000307
Arthur Heymans0ab49042017-02-06 22:40:14 +0100308struct timings {
309 u32 min_tCLK_cas[8];
310 u32 min_tRAS;
311 u32 min_tRP;
312 u32 min_tRCD;
313 u32 min_tWR;
314 u32 min_tRFC;
315 u32 max_tRR;
316 u8 cas_mask;
317};
Stefan Reinauer278534d2008-10-29 04:51:07 +0000318
Arthur Heymans0ab49042017-02-06 22:40:14 +0100319/**
320 * @brief loop over dimms and save maximal timings
321 */
322static void gather_common_timing(struct sys_info *sysinfo,
323 struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000324{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100325
326 int i, j;
327 u8 raw_spd[SPD_SIZE_MAX_DDR2];
328 u8 dimm_mask = 0;
329
330 memset(saved_timings, 0, sizeof(*saved_timings));
331 saved_timings->max_tRR = UINT32_MAX;
332 saved_timings->cas_mask = SPD_CAS_LATENCY_DDR2_3
333 | SPD_CAS_LATENCY_DDR2_4 | SPD_CAS_LATENCY_DDR2_5;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000334
335 /**
336 * i945 supports two DIMMs, in two configurations:
337 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000338 * - single channel with two DIMMs
339 * - dual channel with one DIMM per channel
Stefan Reinauer278534d2008-10-29 04:51:07 +0000340 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000341 * In practice dual channel mainboards have their SPD at 0x50/0x52
342 * whereas single channel configurations have their SPD at 0x50/0x51.
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000343 *
Stefan Reinauer278534d2008-10-29 04:51:07 +0000344 * The capability register knows a lot about the channel configuration
Uwe Hermannd773fd32010-11-20 20:23:08 +0000345 * but for now we stick with the information we gather via SPD.
Stefan Reinauer278534d2008-10-29 04:51:07 +0000346 */
347
Arthur Heymans0ab49042017-02-06 22:40:14 +0100348 printk(BIOS_DEBUG, "This mainboard supports ");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000349 if (sdram_capabilities_dual_channel()) {
350 sysinfo->dual_channel = 1;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100351 printk(BIOS_DEBUG, "Dual Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000352 } else {
353 sysinfo->dual_channel = 0;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100354 printk(BIOS_DEBUG, "only Single Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000355 }
356
Stefan Reinauer278534d2008-10-29 04:51:07 +0000357
Arthur Heymans70a8e342017-03-09 11:30:23 +0100358 for (i = 0; i < (2 * DIMM_SOCKETS); i++) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100359 int device = get_dimm_spd_address(sysinfo, i), bytes_read;
Arthur Heymansfc31e442018-02-12 15:12:34 +0100360 struct dimm_attr_ddr2_st dimm_info;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000361
362 /* Initialize the socket information with a sane value */
363 sysinfo->dimm[i] = SYSINFO_DIMM_NOT_POPULATED;
364
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000365 /* Dual Channel not supported, but Channel 1? Bail out */
366 if (!sdram_capabilities_dual_channel() && (i >> 1))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000367 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000368
Arthur Heymans0ab49042017-02-06 22:40:14 +0100369 if (spd_read_byte(device, SPD_MEMORY_TYPE) !=
370 SPD_MEMORY_TYPE_SDRAM_DDR2) {
371 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: N/A\n",
372 (i >> 1), (i & 1));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000373 continue;
374 }
375
Arthur Heymans0ab49042017-02-06 22:40:14 +0100376 /*
377 * spd_decode_ddr2() needs a 128-byte sized array but
378 * only the first 64 bytes contain data needed for raminit.
379 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000380
Kyösti Mälkkic01a5052019-01-30 09:39:23 +0200381 bytes_read = i2c_eeprom_read(device, 0, 64, raw_spd);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100382 printk(BIOS_DEBUG, "Reading SPD using i2c block operation.\n");
Julius Wernercd49cce2019-03-05 16:53:33 -0800383 if (CONFIG(DEBUG_RAM_SETUP) && bytes_read > 0)
Arthur Heymans0ab49042017-02-06 22:40:14 +0100384 hexdump(raw_spd, bytes_read);
Arthur Heymans56619452017-09-21 09:12:42 +0200385 if (bytes_read != 64) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100386 /* Try again with SMBUS byte read */
387 printk(BIOS_DEBUG, "i2c block operation failed,"
Paul Menzel105e3682017-09-21 08:11:05 +0200388 " trying smbus byte operation.\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100389 for (j = 0; j < 64; j++)
390 raw_spd[j] = spd_read_byte(device, j);
Julius Wernercd49cce2019-03-05 16:53:33 -0800391 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100392 hexdump(raw_spd, 64);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100393 }
Arthur Heymans56619452017-09-21 09:12:42 +0200394
395 if (spd_decode_ddr2(&dimm_info, raw_spd) != SPD_STATUS_OK) {
396 printk(BIOS_WARNING, "Encountered problems with SPD, "
397 "skipping this DIMM.\n");
398 continue;
399 }
400
Julius Wernercd49cce2019-03-05 16:53:33 -0800401 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100402 dram_print_spd_ddr2(&dimm_info);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000403
Arthur Heymans0ab49042017-02-06 22:40:14 +0100404 if (dimm_info.flags.is_ecc)
405 die("\nError: ECC memory not supported by this chipset\n");
406
407 if (spd_dimm_is_registered_ddr2(dimm_info.dimm_type))
408 die("\nError: Registered memory not supported by this chipset\n");
409
410 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: ", (i >> 1),
411 (i & 1));
412 /**
413 * There are 5 different possible populations for a DIMM socket:
414 * 0. x16 double ranked (X16DS)
415 * 1. x8 double ranked (X8DS)
416 * 2. x16 single ranked (X16SS)
417 * 3. x8 double stacked (X8DDS)
418 * 4. Unpopulated
419 */
420 switch (dimm_info.width) {
421 case 8:
422 switch (dimm_info.ranks) {
423 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000424 printk(BIOS_DEBUG, "x8DDS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000425 sysinfo->dimm[i] = SYSINFO_DIMM_X8DDS;
426 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100427 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000428 printk(BIOS_DEBUG, "x8DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000429 sysinfo->dimm[i] = SYSINFO_DIMM_X8DS;
430 break;
431 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000432 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000433 }
434 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100435 case 16:
436 switch (dimm_info.ranks) {
437 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000438 printk(BIOS_DEBUG, "x16DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000439 sysinfo->dimm[i] = SYSINFO_DIMM_X16DS;
440 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100441 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000442 printk(BIOS_DEBUG, "x16SS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000443 sysinfo->dimm[i] = SYSINFO_DIMM_X16SS;
444 break;
445 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000446 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000447 }
448 break;
449 default:
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000450 die("Unsupported DDR-II memory width.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000451 }
452
Arthur Heymans0ab49042017-02-06 22:40:14 +0100453 /* Is the current DIMM a stacked DIMM? */
454 if (dimm_info.flags.stacked)
455 sysinfo->package = SYSINFO_PACKAGE_STACKED;
456
457 if (!dimm_info.flags.bl8)
458 die("Only DDR-II RAM with burst length 8 is supported by this chipset.\n");
459
460 if (dimm_info.ranksize_mb < 128)
461 die("DDR-II rank size smaller than 128MB is not supported.\n");
462
463 sysinfo->banksize[i * 2] = dimm_info.ranksize_mb / 32;
464 printk(BIOS_DEBUG, "DIMM %d side 0 = %d MB\n", i,
465 sysinfo->banksize[i * 2] * 32);
466 if (dimm_info.ranks == 2) {
467 sysinfo->banksize[(i * 2) + 1] =
468 dimm_info.ranksize_mb / 32;
469 printk(BIOS_DEBUG, "DIMM %d side 1 = %d MB\n",
470 i, sysinfo->banksize[(i * 2) + 1] * 32);
471 }
472
473
474 sysinfo->rows[i] = dimm_info.row_bits;
475 sysinfo->cols[i] = dimm_info.col_bits;
476 sysinfo->banks[i] = dimm_info.banks;
477
478 /* int min_tRAS, min_tRP, min_tRCD, min_tWR, min_tRFC; */
479 saved_timings->min_tRAS = MAX(saved_timings->min_tRAS,
480 dimm_info.tRAS);
481 saved_timings->min_tRP = MAX(saved_timings->min_tRP,
482 dimm_info.tRP);
483 saved_timings->min_tRCD = MAX(saved_timings->min_tRCD,
484 dimm_info.tRCD);
485 saved_timings->min_tWR = MAX(saved_timings->min_tWR,
486 dimm_info.tWR);
487 saved_timings->min_tRFC = MAX(saved_timings->min_tRFC,
488 dimm_info.tRFC);
489 saved_timings->max_tRR = MIN(saved_timings->max_tRR,
490 dimm_info.tRR);
491 saved_timings->cas_mask &= dimm_info.cas_supported;
492 for (j = 0; j < 8; j++) {
493 if (!(saved_timings->cas_mask & (1 << j)))
494 saved_timings->min_tCLK_cas[j] = 0;
495 else
496 saved_timings->min_tCLK_cas[j] =
497 MAX(dimm_info.cycle_time[j],
498 saved_timings->min_tCLK_cas[j]);
499 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000500 dimm_mask |= (1 << i);
501 }
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200502 if (!dimm_mask)
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000503 die("No memory installed.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000504
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200505 if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1)))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100506 /* Possibly does not boot in this case */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000507 printk(BIOS_INFO, "Channel 0 has no memory populated.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000508}
509
Arthur Heymans0ab49042017-02-06 22:40:14 +0100510static void choose_tclk(struct sys_info *sysinfo,
511 struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000512{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100513 u32 ctrl_min_tclk;
514 int try_cas;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000515
Arthur Heymans0ab49042017-02-06 22:40:14 +0100516 ctrl_min_tclk = 2 * 256 * 1000
517 / sdram_capabilities_max_supported_memory_frequency();
518 normalize_tck(&ctrl_min_tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000519
Arthur Heymans0ab49042017-02-06 22:40:14 +0100520 try_cas = spd_get_msbs(saved_timings->cas_mask);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000521
Arthur Heymans0ab49042017-02-06 22:40:14 +0100522 while (saved_timings->cas_mask & (1 << try_cas) && try_cas > 0) {
523 sysinfo->cas = try_cas;
524 sysinfo->tclk = saved_timings->min_tCLK_cas[try_cas];
525 if (sysinfo->tclk >= ctrl_min_tclk &&
526 saved_timings->min_tCLK_cas[try_cas] !=
527 saved_timings->min_tCLK_cas[try_cas - 1])
Stefan Reinauer278534d2008-10-29 04:51:07 +0000528 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100529 try_cas--;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000530 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000531
Arthur Heymans0ab49042017-02-06 22:40:14 +0100532 normalize_tck(&sysinfo->tclk);
533
534 if ((sysinfo->cas < 3) || (sysinfo->tclk == 0))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000535 die("Could not find common memory frequency and CAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000536
Arthur Heymans0ab49042017-02-06 22:40:14 +0100537 /*
538 * The loop can still results in a timing too fast for the
539 * memory controller.
540 */
541 if (sysinfo->tclk < ctrl_min_tclk)
542 sysinfo->tclk = ctrl_min_tclk;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000543
Arthur Heymans0ab49042017-02-06 22:40:14 +0100544 switch (sysinfo->tclk) {
545 case TCK_200MHZ:
546 sysinfo->memory_frequency = 400;
547 break;
548 case TCK_266MHZ:
549 sysinfo->memory_frequency = 533;
550 break;
551 case TCK_333MHZ:
552 sysinfo->memory_frequency = 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100553 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000554 }
555
Arthur Heymans0ab49042017-02-06 22:40:14 +0100556 printk(BIOS_DEBUG,
557 "Memory will be driven at %dMT with CAS=%d clocks\n",
558 sysinfo->memory_frequency, sysinfo->cas);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000559}
560
Arthur Heymans0ab49042017-02-06 22:40:14 +0100561static void derive_timings(struct sys_info *sysinfo,
562 struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000563{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100564 sysinfo->tras = DIV_ROUND_UP(saved_timings->min_tRAS, sysinfo->tclk);
565 if (sysinfo->tras > 0x18)
566 die("DDR-II Module does not support this frequency (tRAS error)\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000567
Arthur Heymans0ab49042017-02-06 22:40:14 +0100568 sysinfo->trp = DIV_ROUND_UP(saved_timings->min_tRP, sysinfo->tclk);
569 if (sysinfo->trp > 6)
570 die("DDR-II Module does not support this frequency (tRP error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000571
Arthur Heymans0ab49042017-02-06 22:40:14 +0100572 sysinfo->trcd = DIV_ROUND_UP(saved_timings->min_tRCD, sysinfo->tclk);
573 if (sysinfo->trcd > 6)
574 die("DDR-II Module does not support this frequency (tRCD error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000575
Arthur Heymans0ab49042017-02-06 22:40:14 +0100576 sysinfo->twr = DIV_ROUND_UP(saved_timings->min_tWR, sysinfo->tclk);
577 if (sysinfo->twr > 5)
578 die("DDR-II Module does not support this frequency (tWR error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000579
Arthur Heymans0ab49042017-02-06 22:40:14 +0100580 sysinfo->trfc = DIV_ROUND_UP(saved_timings->min_tRFC, sysinfo->tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000581
Arthur Heymans0ab49042017-02-06 22:40:14 +0100582 printk(BIOS_DEBUG, "tRAS = %d cycles\n", sysinfo->tras);
583 printk(BIOS_DEBUG, "tRP = %d cycles\n", sysinfo->trp);
584 printk(BIOS_DEBUG, "tRCD = %d cycles\n", sysinfo->trcd);
585 printk(BIOS_DEBUG, "tWR = %d cycles\n", sysinfo->twr);
586 printk(BIOS_DEBUG, "tRFC = %d cycles\n", sysinfo->trfc);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000587
Arthur Heymans0ab49042017-02-06 22:40:14 +0100588 /* Refresh is slower than 15.6us, use 15.6us */
589 /* tRR is decoded in units of 1/256us */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000590
Arthur Heymans0ab49042017-02-06 22:40:14 +0100591#define T_RR_7_8US 2000000
592#define T_RR_15_6US 4000000
593#define REFRESH_7_8US 1
594#define REFRESH_15_6US 0
Stefan Reinauer278534d2008-10-29 04:51:07 +0000595
Arthur Heymans0ab49042017-02-06 22:40:14 +0100596 if (saved_timings->max_tRR < T_RR_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000597 die("DDR-II module has unsupported refresh value\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100598 else if (saved_timings->max_tRR < T_RR_15_6US)
599 sysinfo->refresh = REFRESH_7_8US;
600 else
601 sysinfo->refresh = REFRESH_15_6US;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000602 printk(BIOS_DEBUG, "Refresh: %s\n", sysinfo->refresh?"7.8us":"15.6us");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000603}
604
Arthur Heymans0ab49042017-02-06 22:40:14 +0100605/**
606 * @brief Get generic DIMM parameters.
607 * @param sysinfo Central memory controller information structure
608 *
609 * This function gathers several pieces of information for each system DIMM:
610 * o DIMM width (x8 / x16)
611 * o DIMM rank (single ranked / dual ranked)
612 *
613 * Also, some non-supported scenarios are detected.
614 */
615
616static void sdram_get_dram_configuration(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000617{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100618 struct timings saved_timings;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000619
Arthur Heymans0ab49042017-02-06 22:40:14 +0100620 gather_common_timing(sysinfo, &saved_timings);
621 choose_tclk(sysinfo, &saved_timings);
622 derive_timings(sysinfo, &saved_timings);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000623}
624
Arthur Heymans70a8e342017-03-09 11:30:23 +0100625static void sdram_program_dram_width(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000626{
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200627 u16 c0dramw = 0, c1dramw = 0;
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200628 int i, idx;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000629
630 if (sysinfo->dual_channel)
631 idx = 2;
632 else
633 idx = 1;
634
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200635 for (i = 0; i < DIMM_SOCKETS; i++) { /* Channel 0 */
636 switch (sysinfo->dimm[i]) {
637 case SYSINFO_DIMM_X16DS:
638 c0dramw |= (0x0000) << 4*(i % 2);
639 break;
640 case SYSINFO_DIMM_X8DS:
641 c0dramw |= (0x0001) << 4*(i % 2);
642 break;
643 case SYSINFO_DIMM_X16SS:
644 c0dramw |= (0x0000) << 4*(i % 2);
645 break;
646 case SYSINFO_DIMM_X8DDS:
647 c0dramw |= (0x0005) << 4*(i % 2);
648 break;
649 case SYSINFO_DIMM_NOT_POPULATED:
650 c0dramw |= (0x0000) << 4*(i % 2);
651 break;
652 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000653 }
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200654 for (i = DIMM_SOCKETS; i < idx * DIMM_SOCKETS; i++) { /* Channel 1 */
655 switch (sysinfo->dimm[i]) {
656 case SYSINFO_DIMM_X16DS:
657 c1dramw |= (0x0000) << 4*(i % 2);
658 break;
659 case SYSINFO_DIMM_X8DS:
Patrick Georgi68aed912018-11-16 18:00:12 +0100660 c1dramw |= (0x0010) << 4*(i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200661 break;
662 case SYSINFO_DIMM_X16SS:
663 c1dramw |= (0x0000) << 4*(i % 2);
664 break;
665 case SYSINFO_DIMM_X8DDS:
Patrick Georgi68aed912018-11-16 18:00:12 +0100666 c1dramw |= (0x0050) << 4*(i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200667 break;
668 case SYSINFO_DIMM_NOT_POPULATED:
669 c1dramw |= (0x0000) << 4*(i % 2);
670 break;
671 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000672 }
673
674 MCHBAR16(C0DRAMW) = c0dramw;
675 MCHBAR16(C1DRAMW) = c1dramw;
676}
677
678static void sdram_write_slew_rates(u32 offset, const u32 *slew_rate_table)
679{
680 int i;
681
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200682 for (i = 0; i < 16; i++)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000683 MCHBAR32(offset+(i*4)) = slew_rate_table[i];
684}
685
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000686static const u32 dq2030[] = {
687 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
688 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
689 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
690 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
691};
692
693static const u32 dq2330[] = {
694 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
695 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
696 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
697 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
698};
699
700static const u32 cmd2710[] = {
701 0x07060605, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
702 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
703 0x1110100f, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
704 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
705};
706
707static const u32 cmd3210[] = {
708 0x0f0d0b0a, 0x17151311, 0x1f1d1b19, 0x1f1f1f1f,
709 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
710 0x18171615, 0x1f1f1c1a, 0x1f1f1f1f, 0x1f1f1f1f,
711 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
712};
713
714static const u32 clk2030[] = {
715 0x0e0d0d0c, 0x100f0f0e, 0x100f0e0d, 0x15131211,
716 0x1d1b1917, 0x2523211f, 0x2a282927, 0x32302e2c,
717 0x17161514, 0x1b1a1918, 0x1f1e1d1c, 0x23222120,
718 0x27262524, 0x2d2b2928, 0x3533312f, 0x3d3b3937
719};
720
721static const u32 ctl3215[] = {
722 0x01010000, 0x03020101, 0x07060504, 0x0b0a0908,
723 0x100f0e0d, 0x14131211, 0x18171615, 0x1c1b1a19,
724 0x05040403, 0x07060605, 0x0a090807, 0x0f0d0c0b,
725 0x14131211, 0x18171615, 0x1c1b1a19, 0x201f1e1d
726};
727
728static const u32 ctl3220[] = {
729 0x05040403, 0x07060505, 0x0e0c0a08, 0x1a171411,
730 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e,
731 0x09080807, 0x0b0a0a09, 0x0f0d0c0b, 0x1b171311,
732 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e
733};
734
735static const u32 nc[] = {
736 0x00000000, 0x00000000, 0x00000000, 0x00000000,
737 0x00000000, 0x00000000, 0x00000000, 0x00000000,
738 0x00000000, 0x00000000, 0x00000000, 0x00000000,
739 0x00000000, 0x00000000, 0x00000000, 0x00000000
740};
741
742enum {
743 DQ2030,
744 DQ2330,
745 CMD2710,
746 CMD3210,
747 CLK2030,
748 CTL3215,
749 CTL3220,
750 NC,
751};
752
753static const u8 dual_channel_slew_group_lookup[] = {
754 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
755 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
756 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
757 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
758 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
759
760 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
761 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
762 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
763 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
764 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
765
766 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
767 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
768 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
769 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
770 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
771
772 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
773 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
774 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
775 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
776 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, NC, NC,
777
778 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
779 NC, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
780 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
781 NC, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD2710
782};
783
784static const u8 single_channel_slew_group_lookup[] = {
785 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
786 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
787 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
788 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
789 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
790
791 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
792 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
793 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
794 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
795 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
796
797 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
798 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
799 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
800 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
801 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
802
803 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
804 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
805 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
806 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
807 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
808
809 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
810 DQ2330, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
811 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
812 DQ2330, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD3210
813};
814
815static const u32 *slew_group_lookup(int dual_channel, int index)
816{
817 const u8 *slew_group;
818 /* Dual Channel needs different tables. */
819 if (dual_channel)
820 slew_group = dual_channel_slew_group_lookup;
821 else
822 slew_group = single_channel_slew_group_lookup;
823
824 switch (slew_group[index]) {
825 case DQ2030: return dq2030;
826 case DQ2330: return dq2330;
827 case CMD2710: return cmd2710;
828 case CMD3210: return cmd3210;
829 case CLK2030: return clk2030;
830 case CTL3215: return ctl3215;
831 case CTL3220: return ctl3220;
832 case NC: return nc;
833 }
834
835 return nc;
836}
837
Julius Wernercd49cce2019-03-05 16:53:33 -0800838#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000839/* Strength multiplier tables */
840static const u8 dual_channel_strength_multiplier[] = {
841 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
842 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
843 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
844 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
845 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
846 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
847 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
848 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
849 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
850 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
851 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
852 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
853 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
854 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
855 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
856 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
857 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
858 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
859 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
860 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
861 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
862 0x00, 0x00, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
863 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
864 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x44, 0x22
865};
866
867static const u8 single_channel_strength_multiplier[] = {
868 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
869 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
870 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
871 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
872 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
873 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
874 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
875 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
876 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
877 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
878 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
879 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
880 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
881 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
882 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
883 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
884 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
885 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
886 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
887 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
888 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
889 0x33, 0x00, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
890 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
891 0x33, 0x00, 0x11, 0x00, 0x44, 0x44, 0x33, 0x11
892};
Julius Wernercd49cce2019-03-05 16:53:33 -0800893#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000894static const u8 dual_channel_strength_multiplier[] = {
895 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
896 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
897 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
898 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
899 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
900 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
901 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
902 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
903 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
904 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
905 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
906 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
907 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
908 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
909 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
910 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
911 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
912 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
913 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
914 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
915 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
916 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
917 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
918 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33
919};
920
921static const u8 single_channel_strength_multiplier[] = {
922 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
923 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
924 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
925 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
926 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
927 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
928 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
929 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
930 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
931 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
932 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
933 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
934 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
935 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
936 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
937 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
938 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
939 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
940 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
941 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
942 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
943 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
944 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
945 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00
946};
947#endif
948
Stefan Reinauer278534d2008-10-29 04:51:07 +0000949static void sdram_rcomp_buffer_strength_and_slew(struct sys_info *sysinfo)
950{
Arthur Heymans70a8e342017-03-09 11:30:23 +0100951 const u8 *strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000952 int idx, dual_channel;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000953
954 /* Set Strength Multipliers */
955
956 /* Dual Channel needs different tables. */
957 if (sdram_capabilities_dual_channel()) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000958 printk(BIOS_DEBUG, "Programming Dual Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000959 strength_multiplier = dual_channel_strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000960 dual_channel = 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000961 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[2];
962 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000963 printk(BIOS_DEBUG, "Programming Single Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000964 strength_multiplier = single_channel_strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000965 dual_channel = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000966 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[1];
967 }
968
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000969 printk(BIOS_DEBUG, "Table Index: %d\n", idx);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000970
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000971 MCHBAR8(G1SC) = strength_multiplier[idx * 8 + 0];
972 MCHBAR8(G2SC) = strength_multiplier[idx * 8 + 1];
973 MCHBAR8(G3SC) = strength_multiplier[idx * 8 + 2];
974 MCHBAR8(G4SC) = strength_multiplier[idx * 8 + 3];
975 MCHBAR8(G5SC) = strength_multiplier[idx * 8 + 4];
976 MCHBAR8(G6SC) = strength_multiplier[idx * 8 + 5];
977 MCHBAR8(G7SC) = strength_multiplier[idx * 8 + 6];
978 MCHBAR8(G8SC) = strength_multiplier[idx * 8 + 7];
Stefan Reinauer278534d2008-10-29 04:51:07 +0000979
980 /* Channel 0 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000981 sdram_write_slew_rates(G1SRPUT, slew_group_lookup(dual_channel, idx * 8 + 0));
982 sdram_write_slew_rates(G2SRPUT, slew_group_lookup(dual_channel, idx * 8 + 1));
Arthur Heymans70a8e342017-03-09 11:30:23 +0100983 if ((slew_group_lookup(dual_channel, idx * 8 + 2) != nc) && (sysinfo->package == SYSINFO_PACKAGE_STACKED))
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000984
Stefan Reinauer278534d2008-10-29 04:51:07 +0000985 sdram_write_slew_rates(G3SRPUT, ctl3220);
Arthur Heymans70a8e342017-03-09 11:30:23 +0100986 else
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000987 sdram_write_slew_rates(G3SRPUT, slew_group_lookup(dual_channel, idx * 8 + 2));
Arthur Heymans70a8e342017-03-09 11:30:23 +0100988
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000989 sdram_write_slew_rates(G4SRPUT, slew_group_lookup(dual_channel, idx * 8 + 3));
990 sdram_write_slew_rates(G5SRPUT, slew_group_lookup(dual_channel, idx * 8 + 4));
991 sdram_write_slew_rates(G6SRPUT, slew_group_lookup(dual_channel, idx * 8 + 5));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000992
993 /* Channel 1 */
994 if (sysinfo->dual_channel) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000995 sdram_write_slew_rates(G7SRPUT, slew_group_lookup(dual_channel, idx * 8 + 6));
996 sdram_write_slew_rates(G8SRPUT, slew_group_lookup(dual_channel, idx * 8 + 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000997 } else {
998 sdram_write_slew_rates(G7SRPUT, nc);
999 sdram_write_slew_rates(G8SRPUT, nc);
1000 }
1001}
1002
1003static void sdram_enable_rcomp(void)
1004{
1005 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001006 /* Enable Global Periodic RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001007 udelay(300);
1008 reg32 = MCHBAR32(GBRCOMPCTL);
1009 reg32 &= ~(1 << 23);
1010 MCHBAR32(GBRCOMPCTL) = reg32;
1011}
1012
1013static void sdram_program_dll_timings(struct sys_info *sysinfo)
1014{
Elyes HAOUAS44a30662017-02-23 13:14:44 +01001015 u32 channeldll = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001016 int i;
1017
Elyes HAOUAS38424982016-08-21 12:01:04 +02001018 printk(BIOS_DEBUG, "Programming DLL Timings...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001019
Arthur Heymans70a8e342017-03-09 11:30:23 +01001020 MCHBAR16(DQSMT) &= ~((3 << 12) | (1 << 10) | (0xf << 0));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001021 MCHBAR16(DQSMT) |= (1 << 13) | (0xc << 0);
1022
1023 /* We drive both channels with the same speed */
Julius Wernercd49cce2019-03-05 16:53:33 -08001024 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001025 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001026 case 400:
1027 channeldll = 0x26262626; break;
1028 case 533:
1029 channeldll = 0x22222222; break;
1030 case 667:
1031 channeldll = 0x11111111; break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001032 }
Julius Wernercd49cce2019-03-05 16:53:33 -08001033 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001034 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001035 case 400:
1036 channeldll = 0x33333333; break;
1037 case 533:
1038 channeldll = 0x24242424; break;
1039 case 667:
1040 channeldll = 0x25252525; break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001041 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001042 }
1043
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001044 for (i = 0; i < 4; i++) {
Elyes HAOUAS44a30662017-02-23 13:14:44 +01001045 MCHBAR32(C0R0B00DQST + (i * 0x10) + 0) = channeldll;
1046 MCHBAR32(C0R0B00DQST + (i * 0x10) + 4) = channeldll;
1047 MCHBAR32(C1R0B00DQST + (i * 0x10) + 0) = channeldll;
1048 MCHBAR32(C1R0B00DQST + (i * 0x10) + 4) = channeldll;
Julius Wernercd49cce2019-03-05 16:53:33 -08001049 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUAS44a30662017-02-23 13:14:44 +01001050 MCHBAR8(C0R0B00DQST + (i * 0x10) + 8) = channeldll & 0xff;
1051 MCHBAR8(C1R0B00DQST + (i * 0x10) + 8) = channeldll & 0xff;
Paul Menzelbce7e332017-02-22 18:46:27 +01001052 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001053 }
1054}
1055
1056static void sdram_force_rcomp(void)
1057{
1058 u32 reg32;
1059 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001060
Stefan Reinauer278534d2008-10-29 04:51:07 +00001061 reg32 = MCHBAR32(ODTC);
1062 reg32 |= (1 << 28);
1063 MCHBAR32(ODTC) = reg32;
1064
1065 reg32 = MCHBAR32(SMSRCTL);
1066 reg32 |= (1 << 0);
1067 MCHBAR32(SMSRCTL) = reg32;
1068
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001069 /* Start initial RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001070 reg32 = MCHBAR32(GBRCOMPCTL);
1071 reg32 |= (1 << 8);
1072 MCHBAR32(GBRCOMPCTL) = reg32;
1073
1074 reg8 = i945_silicon_revision();
1075 if ((reg8 == 0 && (MCHBAR32(DCC) & (3 << 0)) == 0) || (reg8 == 1)) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001076
Stefan Reinauer278534d2008-10-29 04:51:07 +00001077 reg32 = MCHBAR32(GBRCOMPCTL);
1078 reg32 |= (3 << 5);
1079 MCHBAR32(GBRCOMPCTL) = reg32;
1080 }
1081}
1082
1083static void sdram_initialize_system_memory_io(struct sys_info *sysinfo)
1084{
1085 u8 reg8;
1086 u32 reg32;
1087
Elyes HAOUAS38424982016-08-21 12:01:04 +02001088 printk(BIOS_DEBUG, "Initializing System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001089 /* Enable Data Half Clock Pushout */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001090 reg8 = MCHBAR8(C0HCTC);
1091 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001092 reg8 |= (1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001093 MCHBAR8(C0HCTC) = reg8;
1094
1095 reg8 = MCHBAR8(C1HCTC);
1096 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001097 reg8 |= (1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001098 MCHBAR8(C1HCTC) = reg8;
1099
Arthur Heymans70a8e342017-03-09 11:30:23 +01001100 MCHBAR16(WDLLBYPMODE) &= ~((1 << 9) | (1 << 6) | (1 << 4) | (1 << 3) | (1 << 1));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001101 MCHBAR16(WDLLBYPMODE) |= (1 << 8) | (1 << 7) | (1 << 5) | (1 << 2) | (1 << 0);
1102
1103 MCHBAR8(C0WDLLCMC) = 0;
1104 MCHBAR8(C1WDLLCMC) = 0;
1105
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001106 /* Program RCOMP Settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001107 sdram_program_dram_width(sysinfo);
1108
1109 sdram_rcomp_buffer_strength_and_slew(sysinfo);
1110
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001111 /* Indicate that RCOMP programming is done */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001112 reg32 = MCHBAR32(GBRCOMPCTL);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001113 reg32 &= ~((1 << 29) | (1 << 26) | (3 << 21) | (3 << 2));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001114 reg32 |= (3 << 27) | (3 << 0);
1115 MCHBAR32(GBRCOMPCTL) = reg32;
1116
1117 MCHBAR32(GBRCOMPCTL) |= (1 << 10);
1118
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001119 /* Program DLL Timings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001120 sdram_program_dll_timings(sysinfo);
1121
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001122 /* Force RCOMP cycle */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001123 sdram_force_rcomp();
1124}
1125
1126static void sdram_enable_system_memory_io(struct sys_info *sysinfo)
1127{
1128 u32 reg32;
1129
Elyes HAOUAS38424982016-08-21 12:01:04 +02001130 printk(BIOS_DEBUG, "Enabling System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001131
Stefan Reinauer278534d2008-10-29 04:51:07 +00001132 reg32 = MCHBAR32(RCVENMT);
1133 reg32 &= ~(0x3f << 6);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001134 MCHBAR32(RCVENMT) = reg32; /* [11:6] = 0 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001135
1136 reg32 |= (1 << 11) | (1 << 9);
1137 MCHBAR32(RCVENMT) = reg32;
1138
1139 reg32 = MCHBAR32(DRTST);
1140 reg32 |= (1 << 3) | (1 << 2);
1141 MCHBAR32(DRTST) = reg32;
1142
1143 reg32 = MCHBAR32(DRTST);
1144 reg32 |= (1 << 6) | (1 << 4);
1145 MCHBAR32(DRTST) = reg32;
1146
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001147 asm volatile ("nop; nop;" ::: "memory");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001148
1149 reg32 = MCHBAR32(DRTST);
1150
1151 /* Is channel 0 populated? */
1152 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
1153 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
1154 reg32 |= (1 << 7) | (1 << 5);
1155 else
1156 reg32 |= (1 << 31);
1157
1158 /* Is channel 1 populated? */
1159 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1160 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
1161 reg32 |= (1 << 9) | (1 << 8);
1162 else
1163 reg32 |= (1 << 30);
1164
1165 MCHBAR32(DRTST) = reg32;
1166
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001167 /* Activate DRAM Channel IO Buffers */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001168 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
1169 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) {
1170 reg32 = MCHBAR32(C0DRC1);
1171 reg32 |= (1 << 8);
1172 MCHBAR32(C0DRC1) = reg32;
1173 }
1174 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1175 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED) {
1176 reg32 = MCHBAR32(C1DRC1);
1177 reg32 |= (1 << 8);
1178 MCHBAR32(C1DRC1) = reg32;
1179 }
1180}
1181
Stefan Reinauer278534d2008-10-29 04:51:07 +00001182static int sdram_program_row_boundaries(struct sys_info *sysinfo)
1183{
1184 int i;
Arthur Heymans885c2892016-10-03 17:16:48 +02001185 int cum0, cum1, tolud, tom, pci_mmio_size;
1186 const struct device *dev;
1187 const struct northbridge_intel_i945_config *cfg = NULL;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001188
Paul Menzel84283bc2014-07-17 08:16:04 +02001189 printk(BIOS_DEBUG, "Setting RAM size...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001190
1191 cum0 = 0;
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001192 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001193 cum0 += sysinfo->banksize[i];
Stefan Reinauer278534d2008-10-29 04:51:07 +00001194 MCHBAR8(C0DRB0+i) = cum0;
1195 }
1196
1197 /* Assume we continue in Channel 1 where we stopped in Channel 0 */
1198 cum1 = cum0;
1199
1200 /* Exception: Interleaved starts from the beginning */
1201 if (sysinfo->interleaved)
1202 cum1 = 0;
1203
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001204 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001205 cum1 += sysinfo->banksize[i + 4];
Stefan Reinauer278534d2008-10-29 04:51:07 +00001206 MCHBAR8(C1DRB0+i) = cum1;
1207 }
1208
1209 /* Set TOLUD Top Of Low Usable DRAM */
1210 if (sysinfo->interleaved)
1211 tolud = (cum0 + cum1) << 1;
1212 else
1213 tolud = (cum1 ? cum1 : cum0) << 1;
Stefan Reinauer779b3e32008-11-10 15:43:37 +00001214
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001215 /* The TOM register has a different format */
1216 tom = tolud >> 3;
1217
1218 /* Limit the value of TOLUD to leave some space for PCI memory. */
Kyösti Mälkkic70eed12018-05-22 02:18:00 +03001219 dev = pcidev_on_root(0, 0);
Arthur Heymans885c2892016-10-03 17:16:48 +02001220 if (dev)
1221 cfg = dev->chip_info;
1222
1223 /* Don't use pci mmio sizes smaller than 768M */
1224 if (!cfg || cfg->pci_mmio_size <= DEFAULT_PCI_MMIO_SIZE)
1225 pci_mmio_size = DEFAULT_PCI_MMIO_SIZE;
1226 else
1227 pci_mmio_size = cfg->pci_mmio_size;
1228
1229 tolud = MIN(((4096 - pci_mmio_size) / 128) << 3, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001230
Arthur Heymans70a8e342017-03-09 11:30:23 +01001231 pci_write_config8(PCI_DEV(0, 0, 0), TOLUD, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001232
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001233 printk(BIOS_DEBUG, "C0DRB = 0x%08x\n", MCHBAR32(C0DRB0));
1234 printk(BIOS_DEBUG, "C1DRB = 0x%08x\n", MCHBAR32(C1DRB0));
Arthur Heymans70a8e342017-03-09 11:30:23 +01001235 printk(BIOS_DEBUG, "TOLUD = 0x%04x\n", pci_read_config8(PCI_DEV(0, 0, 0), TOLUD));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001236
Arthur Heymans70a8e342017-03-09 11:30:23 +01001237 pci_write_config16(PCI_DEV(0, 0, 0), TOM, tom);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001238
1239 return 0;
1240}
1241
Stefan Reinauer278534d2008-10-29 04:51:07 +00001242static int sdram_set_row_attributes(struct sys_info *sysinfo)
1243{
Arthur Heymans0ab49042017-02-06 22:40:14 +01001244 int i;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001245 u16 dra0 = 0, dra1 = 0, dra = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001246
Elyes HAOUAS38424982016-08-21 12:01:04 +02001247 printk(BIOS_DEBUG, "Setting row attributes...\n");
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001248 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001249 u8 columnsrows;
1250
Arthur Heymans70a8e342017-03-09 11:30:23 +01001251 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001252 continue;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001253
Arthur Heymans0ab49042017-02-06 22:40:14 +01001254 columnsrows = (sysinfo->rows[i] & 0x0f)
1255 | (sysinfo->cols[i] & 0xf) << 4;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001256
1257 switch (columnsrows) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001258 case 0x9d:
1259 dra = 2; break;
1260 case 0xad:
1261 dra = 3; break;
1262 case 0xbd:
1263 dra = 4; break;
1264 case 0xae:
1265 dra = 3; break;
1266 case 0xbe:
1267 dra = 4; break;
1268 default:
1269 die("Unsupported Rows/Columns. (DRA)");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001270 }
1271
1272 /* Double Sided DIMMs? */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001273 if (sysinfo->banksize[(2 * i) + 1] != 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001274 dra = (dra << 4) | dra;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001275
Stefan Reinauer278534d2008-10-29 04:51:07 +00001276 if (i < DIMM_SOCKETS)
1277 dra0 |= (dra << (i*8));
1278 else
1279 dra1 |= (dra << ((i - DIMM_SOCKETS)*8));
1280 }
1281
1282 MCHBAR16(C0DRA0) = dra0;
1283 MCHBAR16(C1DRA0) = dra1;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001284
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001285 printk(BIOS_DEBUG, "C0DRA = 0x%04x\n", dra0);
1286 printk(BIOS_DEBUG, "C1DRA = 0x%04x\n", dra1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001287
1288 return 0;
1289}
1290
1291static void sdram_set_bank_architecture(struct sys_info *sysinfo)
1292{
1293 u32 off32;
1294 int i;
1295
1296 MCHBAR16(C1BNKARC) &= 0xff00;
1297 MCHBAR16(C0BNKARC) &= 0xff00;
1298
1299 off32 = C0BNKARC;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001300 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001301 /* Switch to second channel */
1302 if (i == DIMM_SOCKETS)
1303 off32 = C1BNKARC;
1304
1305 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
1306 continue;
1307
1308 if (sysinfo->banks[i] != 8)
1309 continue;
1310
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001311 printk(BIOS_SPEW, "DIMM%d has 8 banks.\n", i);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001312
1313 if (i & 1)
1314 MCHBAR16(off32) |= 0x50;
1315 else
1316 MCHBAR16(off32) |= 0x05;
1317 }
1318}
1319
Stefan Reinauer278534d2008-10-29 04:51:07 +00001320static void sdram_program_refresh_rate(struct sys_info *sysinfo)
1321{
1322 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001323
Arthur Heymans70a8e342017-03-09 11:30:23 +01001324 if (sysinfo->refresh == REFRESH_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001325 reg32 = (2 << 8); /* Refresh enabled at 7.8us */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001326 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001327 reg32 = (1 << 8); /* Refresh enabled at 15.6us */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001328
1329 MCHBAR32(C0DRC0) &= ~(7 << 8);
1330 MCHBAR32(C0DRC0) |= reg32;
1331
1332 MCHBAR32(C1DRC0) &= ~(7 << 8);
1333 MCHBAR32(C1DRC0) |= reg32;
1334}
1335
1336static void sdram_program_cke_tristate(struct sys_info *sysinfo)
1337{
1338 u32 reg32;
1339 int i;
1340
1341 reg32 = MCHBAR32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001342
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001343 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001344 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001345 reg32 |= (1 << (16 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001346 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001347
Stefan Reinauer278534d2008-10-29 04:51:07 +00001348 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001349
Stefan Reinauer278534d2008-10-29 04:51:07 +00001350 reg32 |= (1 << 11);
1351 MCHBAR32(C0DRC1) = reg32;
1352
1353 /* Do we have to do this if we're in Single Channel Mode? */
1354 reg32 = MCHBAR32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001355
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001356 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001357 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001358 reg32 |= (1 << (12 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001359 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001360
Stefan Reinauer278534d2008-10-29 04:51:07 +00001361 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001362
Stefan Reinauer278534d2008-10-29 04:51:07 +00001363 reg32 |= (1 << 11);
1364 MCHBAR32(C1DRC1) = reg32;
1365}
1366
1367static void sdram_program_odt_tristate(struct sys_info *sysinfo)
1368{
1369 u32 reg32;
1370 int i;
1371
1372 reg32 = MCHBAR32(C0DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001373
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001374 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001375 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001376 reg32 |= (1 << (24 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001377 }
1378 MCHBAR32(C0DRC2) = reg32;
1379
1380 reg32 = MCHBAR32(C1DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001381
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001382 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001383 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001384 reg32 |= (1 << (20 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001385 }
1386 MCHBAR32(C1DRC2) = reg32;
1387}
1388
1389static void sdram_set_timing_and_control(struct sys_info *sysinfo)
1390{
Arthur Heymans25027232017-02-12 23:34:39 +01001391 u32 reg32, tRD_min;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001392 u32 tWTR;
1393 u32 temp_drt;
1394 int i, page_size;
1395
Edward O'Callaghan2f237c12014-05-25 06:24:39 +10001396 static const u8 cas_table[] = {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001397 2, 1, 0, 3
1398 };
1399
1400 reg32 = MCHBAR32(C0DRC0);
1401 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001402 reg32 &= ~((1 << 13) | (1 << 12));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001403 MCHBAR32(C0DRC0) = reg32;
1404
1405 reg32 = MCHBAR32(C1DRC0);
1406 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001407 reg32 &= ~((1 << 13) | (1 << 12));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001408 MCHBAR32(C1DRC0) = reg32;
1409
1410 if (!sysinfo->dual_channel && sysinfo->dimm[1] !=
1411 SYSINFO_DIMM_NOT_POPULATED) {
1412 reg32 = MCHBAR32(C0DRC0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001413 reg32 |= (1 << 15);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001414 MCHBAR32(C0DRC0) = reg32;
1415 }
1416
1417 sdram_program_refresh_rate(sysinfo);
1418
1419 sdram_program_cke_tristate(sysinfo);
1420
1421 sdram_program_odt_tristate(sysinfo);
1422
1423 /* Calculate DRT0 */
1424
1425 temp_drt = 0;
1426
1427 /* B2B Write Precharge (same bank) = CL-1 + BL/2 + tWR */
1428 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + sysinfo->twr;
1429 temp_drt |= (reg32 << 28);
1430
1431 /* Write Auto Precharge (same bank) = CL-1 + BL/2 + tWR + tRP */
1432 reg32 += sysinfo->trp;
1433 temp_drt |= (reg32 << 4);
1434
Arthur Heymans70a8e342017-03-09 11:30:23 +01001435 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001436 tWTR = 3; /* 667MHz */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001437 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001438 tWTR = 2; /* 400 and 533 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001439
1440 /* B2B Write to Read Command Spacing */
1441 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + tWTR;
1442 temp_drt |= (reg32 << 24);
1443
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001444 /* CxDRT0 [23:22], [21:20], [19:18] [16] have fixed values */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001445 temp_drt |= ((1 << 22) | (3 << 20) | (1 << 18) | (0 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001446
Arthur Heymans25027232017-02-12 23:34:39 +01001447 /*
1448 * tRD is the delay the memory controller is waiting on the FSB,
1449 * in mclk domain.
1450 * This parameter is important for stability and performance.
1451 * Those values might not be optimal but seem stable.
1452 */
1453 tRD_min = sysinfo->cas;
Arthur Heymanse1897612016-10-15 23:29:18 +02001454 switch (sysinfo->fsb_frequency) {
Arthur Heymans25027232017-02-12 23:34:39 +01001455 case 533: break;
1456 case 667: tRD_min += 1;
Arthur Heymanse1897612016-10-15 23:29:18 +02001457 break;
Arthur Heymans25027232017-02-12 23:34:39 +01001458 case 800: tRD_min += 2;
Arthur Heymanse1897612016-10-15 23:29:18 +02001459 break;
Arthur Heymans25027232017-02-12 23:34:39 +01001460 case 1066: tRD_min += 3;
Arthur Heymanse1897612016-10-15 23:29:18 +02001461 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001462 }
Arthur Heymanse1897612016-10-15 23:29:18 +02001463
Arthur Heymans25027232017-02-12 23:34:39 +01001464 temp_drt |= (tRD_min << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001465
1466 /* Read Auto Precharge to Activate */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001467
Stefan Reinauer278534d2008-10-29 04:51:07 +00001468 temp_drt |= (8 << 0);
1469
1470 MCHBAR32(C0DRT0) = temp_drt;
1471 MCHBAR32(C1DRT0) = temp_drt;
1472
1473 /* Calculate DRT1 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001474
Stefan Reinauer278534d2008-10-29 04:51:07 +00001475 temp_drt = MCHBAR32(C0DRT1) & 0x00020088;
1476
1477 /* DRAM RASB Precharge */
1478 temp_drt |= (sysinfo->trp - 2) << 0;
1479
1480 /* DRAM RASB to CASB Delay */
1481 temp_drt |= (sysinfo->trcd - 2) << 4;
1482
1483 /* CASB Latency */
1484 temp_drt |= (cas_table[sysinfo->cas - 3]) << 8;
1485
1486 /* Refresh Cycle Time */
1487 temp_drt |= (sysinfo->trfc) << 10;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001488
Stefan Reinauer278534d2008-10-29 04:51:07 +00001489 /* Pre-All to Activate Delay */
1490 temp_drt |= (0 << 16);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001491
Stefan Reinauer278534d2008-10-29 04:51:07 +00001492 /* Precharge to Precharge Delay stays at 1 clock */
1493 temp_drt |= (0 << 18);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001494
Stefan Reinauer278534d2008-10-29 04:51:07 +00001495 /* Activate to Precharge Delay */
1496 temp_drt |= (sysinfo->tras << 19);
1497
1498 /* Read to Precharge (tRTP) */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001499 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001500 temp_drt |= (1 << 28);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001501 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001502 temp_drt |= (0 << 28);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001503
1504 /* Determine page size */
1505 reg32 = 0;
1506 page_size = 1; /* Default: 1k pagesize */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001507 for (i = 0; i < 2*DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001508 if (sysinfo->dimm[i] == SYSINFO_DIMM_X16DS ||
1509 sysinfo->dimm[i] == SYSINFO_DIMM_X16SS)
1510 page_size = 2; /* 2k pagesize */
1511 }
1512
Arthur Heymans70a8e342017-03-09 11:30:23 +01001513 if (sysinfo->memory_frequency == 533 && page_size == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001514 reg32 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001515 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001516 reg32 = page_size;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001517
Stefan Reinauer278534d2008-10-29 04:51:07 +00001518 temp_drt |= (reg32 << 30);
1519
1520 MCHBAR32(C0DRT1) = temp_drt;
1521 MCHBAR32(C1DRT1) = temp_drt;
1522
1523 /* Program DRT2 */
1524 reg32 = MCHBAR32(C0DRT2);
1525 reg32 &= ~(1 << 8);
1526 MCHBAR32(C0DRT2) = reg32;
1527
1528 reg32 = MCHBAR32(C1DRT2);
1529 reg32 &= ~(1 << 8);
1530 MCHBAR32(C1DRT2) = reg32;
1531
1532 /* Calculate DRT3 */
1533 temp_drt = MCHBAR32(C0DRT3) & ~0x07ffffff;
1534
1535 /* Get old tRFC value */
1536 reg32 = MCHBAR32(C0DRT1) >> 10;
1537 reg32 &= 0x3f;
1538
1539 /* 788nS - tRFC */
1540 switch (sysinfo->memory_frequency) {
1541 case 400: /* 5nS */
1542 reg32 = ((78800 / 500) - reg32) & 0x1ff;
1543 reg32 |= (0x8c << 16) | (0x0c << 10); /* 1 us */
1544 break;
1545 case 533: /* 3.75nS */
1546 reg32 = ((78800 / 375) - reg32) & 0x1ff;
1547 reg32 |= (0xba << 16) | (0x10 << 10); /* 1 us */
1548 break;
1549 case 667: /* 3nS */
1550 reg32 = ((78800 / 300) - reg32) & 0x1ff;
1551 reg32 |= (0xe9 << 16) | (0x14 << 10); /* 1 us */
1552 break;
1553 }
1554
1555 temp_drt |= reg32;
1556
1557 MCHBAR32(C0DRT3) = temp_drt;
1558 MCHBAR32(C1DRT3) = temp_drt;
1559}
1560
1561static void sdram_set_channel_mode(struct sys_info *sysinfo)
1562{
1563 u32 reg32;
1564
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001565 printk(BIOS_DEBUG, "Setting mode of operation for memory channels...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001566
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001567 if (sdram_capabilities_interleave() &&
Arthur Heymans70a8e342017-03-09 11:30:23 +01001568 ((sysinfo->banksize[0] + sysinfo->banksize[1] +
1569 sysinfo->banksize[2] + sysinfo->banksize[3]) ==
1570 (sysinfo->banksize[4] + sysinfo->banksize[5] +
1571 sysinfo->banksize[6] + sysinfo->banksize[7]))) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001572 /* Both channels equipped with DIMMs of the same size */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001573 sysinfo->interleaved = 1;
1574 } else {
1575 sysinfo->interleaved = 0;
1576 }
1577
1578 reg32 = MCHBAR32(DCC);
1579 reg32 &= ~(7 << 0);
1580
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001581 if (sysinfo->interleaved) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001582 /* Dual Channel Interleaved */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001583 printk(BIOS_DEBUG, "Dual Channel Interleaved.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001584 reg32 |= (1 << 1);
1585 } else if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED &&
1586 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
1587 /* Channel 1 only */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001588 printk(BIOS_DEBUG, "Single Channel 1 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001589 reg32 |= (1 << 2);
Elyes HAOUAS75da1fb2017-02-16 18:59:13 +01001590 } else if (sdram_capabilities_dual_channel() &&
1591 (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1592 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) {
Martin Roth128c1042016-11-18 09:29:03 -07001593 /* Dual Channel Asymmetric */
1594 printk(BIOS_DEBUG, "Dual Channel Asymmetric.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001595 reg32 |= (1 << 0);
1596 } else {
1597 /* All bits 0 means Single Channel 0 operation */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001598 printk(BIOS_DEBUG, "Single Channel 0 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001599 }
1600
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001601 /* Now disable channel XORing */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001602 reg32 |= (1 << 10);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001603
1604 MCHBAR32(DCC) = reg32;
1605
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001606 PRINTK_DEBUG("DCC = 0x%08x\n", MCHBAR32(DCC));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001607}
1608
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001609static void sdram_program_pll_settings(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001610{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001611 MCHBAR32(PLLMON) = 0x80800000;
1612
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001613 sysinfo->fsb_frequency = fsbclk();
Peter Stuge76d91432010-10-01 10:02:33 +00001614 if (sysinfo->fsb_frequency == 0xffff)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001615 die("Unsupported FSB speed");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001616
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001617 /* Program CPCTL according to FSB speed */
1618 /* Only write the lower byte */
1619 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001620 case 400:
1621 MCHBAR8(CPCTL) = 0x90; break; /* FSB400 */
1622 case 533:
1623 MCHBAR8(CPCTL) = 0x95; break; /* FSB533 */
1624 case 667:
1625 MCHBAR8(CPCTL) = 0x8d; break; /* FSB667 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001626 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001627
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001628 MCHBAR16(CPCTL) &= ~(1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001629
Paul Menzel0ce5ebf2013-10-21 21:22:09 +02001630 MCHBAR16(CPCTL); /* Read back register to activate settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001631}
1632
1633static void sdram_program_graphics_frequency(struct sys_info *sysinfo)
1634{
1635 u8 reg8;
1636 u16 reg16;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001637 u8 freq, second_vco, voltage;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001638
1639#define CRCLK_166MHz 0x00
1640#define CRCLK_200MHz 0x01
1641#define CRCLK_250MHz 0x03
1642#define CRCLK_400MHz 0x05
1643
1644#define CDCLK_200MHz 0x00
1645#define CDCLK_320MHz 0x40
1646
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001647#define VOLTAGE_1_05 0x00
1648#define VOLTAGE_1_50 0x01
1649
Paul Menzeldaf9e502014-07-15 23:49:16 +02001650 printk(BIOS_DEBUG, "Setting Graphics Frequency...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001651
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001652 printk(BIOS_DEBUG, "FSB: %d MHz ", sysinfo->fsb_frequency);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001653
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001654 voltage = VOLTAGE_1_05;
1655 if (MCHBAR32(DFT_STRAP1) & (1 << 20))
1656 voltage = VOLTAGE_1_50;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001657 printk(BIOS_DEBUG, "Voltage: %s ", (voltage == VOLTAGE_1_05)?"1.05V":"1.5V");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001658
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001659 /* Gate graphics hardware for frequency change */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001660 reg8 = pci_read_config16(PCI_DEV(0, 2, 0), GCFC + 1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001661 reg8 = (1<<3) | (1<<1); /* disable crclk, gate cdclk */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001662 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001663
1664 /* Get graphics frequency capabilities */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001665 reg8 = sdram_capabilities_core_frequencies();
1666
Stefan Reinauer278534d2008-10-29 04:51:07 +00001667 freq = CRCLK_250MHz;
1668 switch (reg8) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001669 case GFX_FREQUENCY_CAP_ALL:
1670 if (voltage == VOLTAGE_1_05)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001671 freq = CRCLK_250MHz;
1672 else
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001673 freq = CRCLK_400MHz; /* 1.5V requires 400MHz */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001674 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001675 case GFX_FREQUENCY_CAP_250MHZ:
1676 freq = CRCLK_250MHz; break;
1677 case GFX_FREQUENCY_CAP_200MHZ:
1678 freq = CRCLK_200MHz; break;
1679 case GFX_FREQUENCY_CAP_166MHZ:
1680 freq = CRCLK_166MHz; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001681 }
1682
1683 if (freq != CRCLK_400MHz) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001684 /* What chipset are we? Force 166MHz for GMS */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001685 reg8 = (pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe7) & 0x70) >> 4;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001686 if (reg8 == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001687 freq = CRCLK_166MHz;
1688 }
1689
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001690 printk(BIOS_DEBUG, "Render: ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001691 switch (freq) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001692 case CRCLK_166MHz:
1693 printk(BIOS_DEBUG, "166MHz"); break;
1694 case CRCLK_200MHz:
1695 printk(BIOS_DEBUG, "200MHz"); break;
1696 case CRCLK_250MHz:
1697 printk(BIOS_DEBUG, "250MHz"); break;
1698 case CRCLK_400MHz:
1699 printk(BIOS_DEBUG, "400MHz"); break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001700 }
1701
Arthur Heymans70a8e342017-03-09 11:30:23 +01001702 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001703 sysinfo->mvco4x = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001704 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001705 sysinfo->mvco4x = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001706
Stefan Reinauer278534d2008-10-29 04:51:07 +00001707 second_vco = 0;
1708
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001709 if (voltage == VOLTAGE_1_50) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001710 second_vco = 1;
1711 } else if ((i945_silicon_revision() > 0) && (freq == CRCLK_250MHz)) {
1712 u16 mem = sysinfo->memory_frequency;
1713 u16 fsb = sysinfo->fsb_frequency;
1714
Arthur Heymans70a8e342017-03-09 11:30:23 +01001715 if ((fsb == 667 && mem == 533) ||
1716 (fsb == 533 && mem == 533) ||
1717 (fsb == 533 && mem == 400)) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001718 second_vco = 1;
1719 }
1720
1721 if (fsb == 667 && mem == 533)
1722 sysinfo->mvco4x = 1;
1723 }
1724
Arthur Heymans70a8e342017-03-09 11:30:23 +01001725 if (second_vco)
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001726 sysinfo->clkcfg_bit7 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001727 else
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001728 sysinfo->clkcfg_bit7 = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001729
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001730 /* Graphics Core Render Clock */
Arthur Heymans70a8e342017-03-09 11:30:23 +0100