blob: 2489aa7cab4a019f9e8243e9a6447d9e8c043976 [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>
Kyösti Mälkki7fbed222019-07-11 08:14:07 +030018#include <delay.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>
Elyes HAOUAS420d7e02019-04-21 18:39:34 +020021#include <cf9_reset.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020022#include <device/mmio.h>
Arthur Heymans885c2892016-10-03 17:16:48 +020023#include <device/device.h>
Julius Werner7a8a4ab2015-05-22 16:26:40 -070024#include <lib.h>
Edwin Beasanteb50c7d2010-07-06 21:05:04 +000025#include <pc80/mc146818rtc.h>
Stefan Reinauer278534d2008-10-29 04:51:07 +000026#include <spd.h>
Patrick Georgid0835952010-10-05 09:07:10 +000027#include <string.h>
Stefan Reinauer278534d2008-10-29 04:51:07 +000028#include "raminit.h"
29#include "i945.h"
Arthur Heymans885c2892016-10-03 17:16:48 +020030#include "chip.h"
Arthur Heymans0ab49042017-02-06 22:40:14 +010031#include <device/dram/ddr2.h>
Patrick Georgi771328f2015-07-13 19:24:07 +020032#include <timestamp.h>
Rudolf Marekc4369532010-12-13 19:59:13 +000033
Stefan Reinauer278534d2008-10-29 04:51:07 +000034/* Debugging macros. */
Julius Wernercd49cce2019-03-05 16:53:33 -080035#if CONFIG(DEBUG_RAM_SETUP)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000036#define PRINTK_DEBUG(x...) printk(BIOS_DEBUG, x)
Stefan Reinauer278534d2008-10-29 04:51:07 +000037#else
38#define PRINTK_DEBUG(x...)
39#endif
40
Stefan Reinauer278534d2008-10-29 04:51:07 +000041#define RAM_INITIALIZATION_COMPLETE (1 << 19)
42
43#define RAM_COMMAND_SELF_REFRESH (0x0 << 16)
44#define RAM_COMMAND_NOP (0x1 << 16)
45#define RAM_COMMAND_PRECHARGE (0x2 << 16)
46#define RAM_COMMAND_MRS (0x3 << 16)
47#define RAM_COMMAND_EMRS (0x4 << 16)
48#define RAM_COMMAND_CBR (0x6 << 16)
49#define RAM_COMMAND_NORMAL (0x7 << 16)
50
51#define RAM_EMRS_1 (0x0 << 21)
52#define RAM_EMRS_2 (0x1 << 21)
53#define RAM_EMRS_3 (0x2 << 21)
54
Arthur Heymans885c2892016-10-03 17:16:48 +020055#define DEFAULT_PCI_MMIO_SIZE 768
Sven Schnelle541269b2011-02-21 09:39:17 +000056static int get_dimm_spd_address(struct sys_info *sysinfo, int device)
57{
58 if (sysinfo->spd_addresses)
59 return sysinfo->spd_addresses[device];
60 else
61 return DIMM0 + device;
62
63}
64
Stefan Reinauerbc8613e2010-08-25 18:35:42 +000065static __attribute__((noinline)) void do_ram_command(u32 command)
Stefan Reinauer278534d2008-10-29 04:51:07 +000066{
67 u32 reg32;
68
69 reg32 = MCHBAR32(DCC);
Arthur Heymans70a8e342017-03-09 11:30:23 +010070 reg32 &= ~((3<<21) | (1<<20) | (1<<19) | (7 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +000071 reg32 |= command;
72
73 /* Also set Init Complete */
74 if (command == RAM_COMMAND_NORMAL)
75 reg32 |= RAM_INITIALIZATION_COMPLETE;
76
77 PRINTK_DEBUG(" Sending RAM command 0x%08x", reg32);
78
79 MCHBAR32(DCC) = reg32; /* This is the actual magic */
80
Stefan Reinauer779b3e32008-11-10 15:43:37 +000081 PRINTK_DEBUG("...done\n");
Stefan Reinauerd058ad12010-08-26 12:43:58 +000082
83 udelay(1);
Stefan Reinauer278534d2008-10-29 04:51:07 +000084}
85
Stefan Reinauer278534d2008-10-29 04:51:07 +000086static void ram_read32(u32 offset)
87{
Elyes HAOUAS15279a92016-07-28 21:05:26 +020088 PRINTK_DEBUG(" RAM read: %08x\n", offset);
Stefan Reinauer278534d2008-10-29 04:51:07 +000089
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080090 read32((void *)offset);
Stefan Reinauer278534d2008-10-29 04:51:07 +000091}
92
Stefan Reinauer3c0bfaf2010-12-27 11:34:57 +000093void sdram_dump_mchbar_registers(void)
Stefan Reinauer278534d2008-10-29 04:51:07 +000094{
95 int i;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000096 printk(BIOS_DEBUG, "Dumping MCHBAR Registers\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +000097
Arthur Heymans70a8e342017-03-09 11:30:23 +010098 for (i = 0; i < 0xfff; i += 4) {
Stefan Reinauer278534d2008-10-29 04:51:07 +000099 if (MCHBAR32(i) == 0)
100 continue;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000101 printk(BIOS_DEBUG, "0x%04x: 0x%08x\n", i, MCHBAR32(i));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000102 }
103}
Stefan Reinauer278534d2008-10-29 04:51:07 +0000104
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000105static int memclk(void)
106{
Julius Wernercd49cce2019-03-05 16:53:33 -0800107 int offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200108
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000109 switch (((MCHBAR32(CLKCFG) >> 4) & 7) - offset) {
110 case 1: return 400;
111 case 2: return 533;
112 case 3: return 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100113 default:
Elyes HAOUAS3cd43272020-03-05 22:01:17 +0100114 printk(BIOS_DEBUG, "%s: unknown register value %x\n", __func__,
Arthur Heymans70a8e342017-03-09 11:30:23 +0100115 ((MCHBAR32(CLKCFG) >> 4) & 7) - offset);
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000116 }
117 return -1;
118}
119
Peter Stuge76d91432010-10-01 10:02:33 +0000120static u16 fsbclk(void)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000121{
Julius Wernercd49cce2019-03-05 16:53:33 -0800122 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200123 switch (MCHBAR32(CLKCFG) & 7) {
124 case 0: return 400;
125 case 1: return 533;
126 case 3: return 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100127 default:
Elyes HAOUAS3cd43272020-03-05 22:01:17 +0100128 printk(BIOS_DEBUG, "%s: unknown register value %x\n", __func__,
Arthur Heymans70a8e342017-03-09 11:30:23 +0100129 MCHBAR32(CLKCFG) & 7);
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200130 }
131 return 0xffff;
Julius Wernercd49cce2019-03-05 16:53:33 -0800132 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200133 switch (MCHBAR32(CLKCFG) & 7) {
134 case 0: return 1066;
135 case 1: return 533;
136 case 2: return 800;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100137 default:
Elyes HAOUAS3cd43272020-03-05 22:01:17 +0100138 printk(BIOS_DEBUG, "%s: unknown register value %x\n", __func__,
Arthur Heymans70a8e342017-03-09 11:30:23 +0100139 MCHBAR32(CLKCFG) & 7);
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200140 }
141 return 0xffff;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000142 }
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000143}
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000144
Stefan Reinauer278534d2008-10-29 04:51:07 +0000145static int sdram_capabilities_max_supported_memory_frequency(void)
146{
147 u32 reg32;
148
Patrick Georgi77d66832010-10-01 08:02:45 +0000149#if CONFIG_MAXIMUM_SUPPORTED_FREQUENCY
150 return CONFIG_MAXIMUM_SUPPORTED_FREQUENCY;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000151#endif
152
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000153 reg32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000154 reg32 &= (7 << 0);
155
156 switch (reg32) {
157 case 4: return 400;
158 case 3: return 533;
159 case 2: return 667;
160 }
161 /* Newer revisions of this chipset rather support faster memory clocks,
162 * so if it's a reserved value, return the fastest memory clock that we
163 * know of and can handle
164 */
165 return 667;
166}
167
168/**
169 * @brief determine whether chipset is capable of dual channel interleaved mode
170 *
171 * @return 1 if interleaving is supported, 0 otherwise
172 */
173static int sdram_capabilities_interleave(void)
174{
175 u32 reg32;
176
Arthur Heymans70a8e342017-03-09 11:30:23 +0100177 reg32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000178 reg32 >>= 25;
179 reg32 &= 1;
180
181 return (!reg32);
182}
183
184/**
185 * @brief determine whether chipset is capable of two memory channels
186 *
187 * @return 1 if dual channel operation is supported, 0 otherwise
188 */
189static int sdram_capabilities_dual_channel(void)
190{
191 u32 reg32;
192
Arthur Heymans70a8e342017-03-09 11:30:23 +0100193 reg32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000194 reg32 >>= 24;
195 reg32 &= 1;
196
197 return (!reg32);
198}
199
200static int sdram_capabilities_enhanced_addressing_xor(void)
201{
202 u8 reg8;
203
204 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
205 reg8 &= (1 << 7);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000206
Stefan Reinauer278534d2008-10-29 04:51:07 +0000207 return (!reg8);
208}
209
Stefan Reinauer14e22772010-04-27 06:56:47 +0000210// TODO check if we ever need this function
Stefan Reinauer53b0ea42010-03-22 11:50:52 +0000211#if 0
Stefan Reinauer278534d2008-10-29 04:51:07 +0000212static int sdram_capabilities_MEM4G_disable(void)
213{
214 u8 reg8;
215
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000216 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000217 reg8 &= (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000218
Stefan Reinauer278534d2008-10-29 04:51:07 +0000219 return (reg8 != 0);
220}
Stefan Reinauer53b0ea42010-03-22 11:50:52 +0000221#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +0000222
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000223#define GFX_FREQUENCY_CAP_166MHZ 0x04
224#define GFX_FREQUENCY_CAP_200MHZ 0x03
225#define GFX_FREQUENCY_CAP_250MHZ 0x02
226#define GFX_FREQUENCY_CAP_ALL 0x00
227
228static int sdram_capabilities_core_frequencies(void)
229{
230 u8 reg8;
231
232 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
233 reg8 &= (1 << 3) | (1 << 2) | (1 << 1);
234 reg8 >>= 1;
235
Arthur Heymans70a8e342017-03-09 11:30:23 +0100236 return reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000237}
238
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000239static void sdram_detect_errors(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000240{
241 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000242 u8 do_reset = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000243
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100244 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000245
Stefan Reinauer278534d2008-10-29 04:51:07 +0000246 if (reg8 & ((1<<7)|(1<<2))) {
247 if (reg8 & (1<<2)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000248 printk(BIOS_DEBUG, "SLP S4# Assertion Width Violation.\n");
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000249 /* Write back clears bit 2 */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100250 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000251 do_reset = 1;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000252
Stefan Reinauer278534d2008-10-29 04:51:07 +0000253 }
254
255 if (reg8 & (1<<7)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000256 printk(BIOS_DEBUG, "DRAM initialization was interrupted.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000257 reg8 &= ~(1<<7);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100258 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000259 do_reset = 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000260 }
261
262 /* Set SLP_S3# Assertion Stretch Enable */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100263 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000264 reg8 |= (1 << 3);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100265 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000266
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000267 if (do_reset) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000268 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200269 full_reset();
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000270 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000271 }
272
273 /* Set DRAM initialization bit in ICH7 */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100274 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000275 reg8 |= (1<<7);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100276 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000277
Peter Stuge751508a2012-01-27 22:17:09 +0100278 /* clear self refresh status if check is disabled or not a resume */
Julius Werner5d1f9a02019-03-07 17:07:26 -0800279 if (!CONFIG(CHECK_SLFRCS_ON_RESUME)
Arthur Heymans0ab49042017-02-06 22:40:14 +0100280 || sysinfo->boot_path != BOOT_PATH_RESUME) {
Patrick Georgi86a11102013-03-15 14:11:37 +0100281 MCHBAR8(SLFRCS) |= 3;
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000282 } else {
283 /* Validate self refresh config */
284 if (((sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED) ||
285 (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)) &&
Patrick Georgi86a11102013-03-15 14:11:37 +0100286 !(MCHBAR8(SLFRCS) & (1<<0))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000287 do_reset = 1;
288 }
289 if (((sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED) ||
290 (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) &&
Patrick Georgi86a11102013-03-15 14:11:37 +0100291 !(MCHBAR8(SLFRCS) & (1<<1))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000292 do_reset = 1;
293 }
294 }
295
296 if (do_reset) {
297 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200298 full_reset();
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000299 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000300}
Stefan Reinauer278534d2008-10-29 04:51:07 +0000301
Arthur Heymans0ab49042017-02-06 22:40:14 +0100302struct timings {
303 u32 min_tCLK_cas[8];
304 u32 min_tRAS;
305 u32 min_tRP;
306 u32 min_tRCD;
307 u32 min_tWR;
308 u32 min_tRFC;
309 u32 max_tRR;
310 u8 cas_mask;
311};
Stefan Reinauer278534d2008-10-29 04:51:07 +0000312
Arthur Heymans0ab49042017-02-06 22:40:14 +0100313/**
314 * @brief loop over dimms and save maximal timings
315 */
316static void gather_common_timing(struct sys_info *sysinfo,
317 struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000318{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100319
320 int i, j;
321 u8 raw_spd[SPD_SIZE_MAX_DDR2];
322 u8 dimm_mask = 0;
323
324 memset(saved_timings, 0, sizeof(*saved_timings));
325 saved_timings->max_tRR = UINT32_MAX;
326 saved_timings->cas_mask = SPD_CAS_LATENCY_DDR2_3
327 | SPD_CAS_LATENCY_DDR2_4 | SPD_CAS_LATENCY_DDR2_5;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000328
329 /**
330 * i945 supports two DIMMs, in two configurations:
331 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000332 * - single channel with two DIMMs
333 * - dual channel with one DIMM per channel
Stefan Reinauer278534d2008-10-29 04:51:07 +0000334 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000335 * In practice dual channel mainboards have their SPD at 0x50/0x52
336 * whereas single channel configurations have their SPD at 0x50/0x51.
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000337 *
Stefan Reinauer278534d2008-10-29 04:51:07 +0000338 * The capability register knows a lot about the channel configuration
Uwe Hermannd773fd32010-11-20 20:23:08 +0000339 * but for now we stick with the information we gather via SPD.
Stefan Reinauer278534d2008-10-29 04:51:07 +0000340 */
341
Arthur Heymans0ab49042017-02-06 22:40:14 +0100342 printk(BIOS_DEBUG, "This mainboard supports ");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000343 if (sdram_capabilities_dual_channel()) {
344 sysinfo->dual_channel = 1;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100345 printk(BIOS_DEBUG, "Dual Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000346 } else {
347 sysinfo->dual_channel = 0;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100348 printk(BIOS_DEBUG, "only Single Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000349 }
350
Stefan Reinauer278534d2008-10-29 04:51:07 +0000351
Arthur Heymans70a8e342017-03-09 11:30:23 +0100352 for (i = 0; i < (2 * DIMM_SOCKETS); i++) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100353 int device = get_dimm_spd_address(sysinfo, i), bytes_read;
Arthur Heymansfc31e442018-02-12 15:12:34 +0100354 struct dimm_attr_ddr2_st dimm_info;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000355
356 /* Initialize the socket information with a sane value */
357 sysinfo->dimm[i] = SYSINFO_DIMM_NOT_POPULATED;
358
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000359 /* Dual Channel not supported, but Channel 1? Bail out */
360 if (!sdram_capabilities_dual_channel() && (i >> 1))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000361 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000362
Kyösti Mälkkibd659852020-01-05 20:00:18 +0200363 if (smbus_read_byte(device, SPD_MEMORY_TYPE) !=
Arthur Heymans0ab49042017-02-06 22:40:14 +0100364 SPD_MEMORY_TYPE_SDRAM_DDR2) {
365 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: N/A\n",
366 (i >> 1), (i & 1));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000367 continue;
368 }
369
Arthur Heymans0ab49042017-02-06 22:40:14 +0100370 /*
371 * spd_decode_ddr2() needs a 128-byte sized array but
372 * only the first 64 bytes contain data needed for raminit.
373 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000374
Kyösti Mälkkic01a5052019-01-30 09:39:23 +0200375 bytes_read = i2c_eeprom_read(device, 0, 64, raw_spd);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100376 printk(BIOS_DEBUG, "Reading SPD using i2c block operation.\n");
Julius Wernercd49cce2019-03-05 16:53:33 -0800377 if (CONFIG(DEBUG_RAM_SETUP) && bytes_read > 0)
Arthur Heymans0ab49042017-02-06 22:40:14 +0100378 hexdump(raw_spd, bytes_read);
Arthur Heymans56619452017-09-21 09:12:42 +0200379 if (bytes_read != 64) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100380 /* Try again with SMBUS byte read */
381 printk(BIOS_DEBUG, "i2c block operation failed,"
Paul Menzel105e3682017-09-21 08:11:05 +0200382 " trying smbus byte operation.\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100383 for (j = 0; j < 64; j++)
Kyösti Mälkkibd659852020-01-05 20:00:18 +0200384 raw_spd[j] = smbus_read_byte(device, j);
Julius Wernercd49cce2019-03-05 16:53:33 -0800385 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100386 hexdump(raw_spd, 64);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100387 }
Arthur Heymans56619452017-09-21 09:12:42 +0200388
389 if (spd_decode_ddr2(&dimm_info, raw_spd) != SPD_STATUS_OK) {
390 printk(BIOS_WARNING, "Encountered problems with SPD, "
391 "skipping this DIMM.\n");
392 continue;
393 }
394
Julius Wernercd49cce2019-03-05 16:53:33 -0800395 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100396 dram_print_spd_ddr2(&dimm_info);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000397
Arthur Heymans0ab49042017-02-06 22:40:14 +0100398 if (dimm_info.flags.is_ecc)
399 die("\nError: ECC memory not supported by this chipset\n");
400
401 if (spd_dimm_is_registered_ddr2(dimm_info.dimm_type))
402 die("\nError: Registered memory not supported by this chipset\n");
403
404 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: ", (i >> 1),
405 (i & 1));
406 /**
407 * There are 5 different possible populations for a DIMM socket:
408 * 0. x16 double ranked (X16DS)
409 * 1. x8 double ranked (X8DS)
410 * 2. x16 single ranked (X16SS)
411 * 3. x8 double stacked (X8DDS)
412 * 4. Unpopulated
413 */
414 switch (dimm_info.width) {
415 case 8:
416 switch (dimm_info.ranks) {
417 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000418 printk(BIOS_DEBUG, "x8DDS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000419 sysinfo->dimm[i] = SYSINFO_DIMM_X8DDS;
420 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100421 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000422 printk(BIOS_DEBUG, "x8DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000423 sysinfo->dimm[i] = SYSINFO_DIMM_X8DS;
424 break;
425 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000426 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000427 }
428 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100429 case 16:
430 switch (dimm_info.ranks) {
431 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000432 printk(BIOS_DEBUG, "x16DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000433 sysinfo->dimm[i] = SYSINFO_DIMM_X16DS;
434 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100435 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000436 printk(BIOS_DEBUG, "x16SS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000437 sysinfo->dimm[i] = SYSINFO_DIMM_X16SS;
438 break;
439 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000440 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000441 }
442 break;
443 default:
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000444 die("Unsupported DDR-II memory width.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000445 }
446
Arthur Heymans0ab49042017-02-06 22:40:14 +0100447 /* Is the current DIMM a stacked DIMM? */
448 if (dimm_info.flags.stacked)
449 sysinfo->package = SYSINFO_PACKAGE_STACKED;
450
451 if (!dimm_info.flags.bl8)
452 die("Only DDR-II RAM with burst length 8 is supported by this chipset.\n");
453
454 if (dimm_info.ranksize_mb < 128)
455 die("DDR-II rank size smaller than 128MB is not supported.\n");
456
457 sysinfo->banksize[i * 2] = dimm_info.ranksize_mb / 32;
458 printk(BIOS_DEBUG, "DIMM %d side 0 = %d MB\n", i,
459 sysinfo->banksize[i * 2] * 32);
460 if (dimm_info.ranks == 2) {
461 sysinfo->banksize[(i * 2) + 1] =
462 dimm_info.ranksize_mb / 32;
463 printk(BIOS_DEBUG, "DIMM %d side 1 = %d MB\n",
464 i, sysinfo->banksize[(i * 2) + 1] * 32);
465 }
466
467
468 sysinfo->rows[i] = dimm_info.row_bits;
469 sysinfo->cols[i] = dimm_info.col_bits;
470 sysinfo->banks[i] = dimm_info.banks;
471
472 /* int min_tRAS, min_tRP, min_tRCD, min_tWR, min_tRFC; */
473 saved_timings->min_tRAS = MAX(saved_timings->min_tRAS,
474 dimm_info.tRAS);
475 saved_timings->min_tRP = MAX(saved_timings->min_tRP,
476 dimm_info.tRP);
477 saved_timings->min_tRCD = MAX(saved_timings->min_tRCD,
478 dimm_info.tRCD);
479 saved_timings->min_tWR = MAX(saved_timings->min_tWR,
480 dimm_info.tWR);
481 saved_timings->min_tRFC = MAX(saved_timings->min_tRFC,
482 dimm_info.tRFC);
483 saved_timings->max_tRR = MIN(saved_timings->max_tRR,
484 dimm_info.tRR);
485 saved_timings->cas_mask &= dimm_info.cas_supported;
486 for (j = 0; j < 8; j++) {
487 if (!(saved_timings->cas_mask & (1 << j)))
488 saved_timings->min_tCLK_cas[j] = 0;
489 else
490 saved_timings->min_tCLK_cas[j] =
491 MAX(dimm_info.cycle_time[j],
492 saved_timings->min_tCLK_cas[j]);
493 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000494 dimm_mask |= (1 << i);
495 }
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200496 if (!dimm_mask)
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000497 die("No memory installed.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000498
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200499 if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1)))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100500 /* Possibly does not boot in this case */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000501 printk(BIOS_INFO, "Channel 0 has no memory populated.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000502}
503
Arthur Heymans0ab49042017-02-06 22:40:14 +0100504static void choose_tclk(struct sys_info *sysinfo,
505 struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000506{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100507 u32 ctrl_min_tclk;
508 int try_cas;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000509
Arthur Heymans0ab49042017-02-06 22:40:14 +0100510 ctrl_min_tclk = 2 * 256 * 1000
511 / sdram_capabilities_max_supported_memory_frequency();
512 normalize_tck(&ctrl_min_tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000513
Arthur Heymans0ab49042017-02-06 22:40:14 +0100514 try_cas = spd_get_msbs(saved_timings->cas_mask);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000515
Arthur Heymans0ab49042017-02-06 22:40:14 +0100516 while (saved_timings->cas_mask & (1 << try_cas) && try_cas > 0) {
517 sysinfo->cas = try_cas;
518 sysinfo->tclk = saved_timings->min_tCLK_cas[try_cas];
519 if (sysinfo->tclk >= ctrl_min_tclk &&
520 saved_timings->min_tCLK_cas[try_cas] !=
521 saved_timings->min_tCLK_cas[try_cas - 1])
Stefan Reinauer278534d2008-10-29 04:51:07 +0000522 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100523 try_cas--;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000524 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000525
Arthur Heymans0ab49042017-02-06 22:40:14 +0100526 normalize_tck(&sysinfo->tclk);
527
528 if ((sysinfo->cas < 3) || (sysinfo->tclk == 0))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000529 die("Could not find common memory frequency and CAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000530
Arthur Heymans0ab49042017-02-06 22:40:14 +0100531 /*
532 * The loop can still results in a timing too fast for the
533 * memory controller.
534 */
535 if (sysinfo->tclk < ctrl_min_tclk)
536 sysinfo->tclk = ctrl_min_tclk;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000537
Arthur Heymans0ab49042017-02-06 22:40:14 +0100538 switch (sysinfo->tclk) {
539 case TCK_200MHZ:
540 sysinfo->memory_frequency = 400;
541 break;
542 case TCK_266MHZ:
543 sysinfo->memory_frequency = 533;
544 break;
545 case TCK_333MHZ:
546 sysinfo->memory_frequency = 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100547 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000548 }
549
Arthur Heymans0ab49042017-02-06 22:40:14 +0100550 printk(BIOS_DEBUG,
551 "Memory will be driven at %dMT with CAS=%d clocks\n",
552 sysinfo->memory_frequency, sysinfo->cas);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000553}
554
Arthur Heymans0ab49042017-02-06 22:40:14 +0100555static void derive_timings(struct sys_info *sysinfo,
556 struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000557{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100558 sysinfo->tras = DIV_ROUND_UP(saved_timings->min_tRAS, sysinfo->tclk);
559 if (sysinfo->tras > 0x18)
560 die("DDR-II Module does not support this frequency (tRAS error)\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000561
Arthur Heymans0ab49042017-02-06 22:40:14 +0100562 sysinfo->trp = DIV_ROUND_UP(saved_timings->min_tRP, sysinfo->tclk);
563 if (sysinfo->trp > 6)
564 die("DDR-II Module does not support this frequency (tRP error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000565
Arthur Heymans0ab49042017-02-06 22:40:14 +0100566 sysinfo->trcd = DIV_ROUND_UP(saved_timings->min_tRCD, sysinfo->tclk);
567 if (sysinfo->trcd > 6)
568 die("DDR-II Module does not support this frequency (tRCD error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000569
Arthur Heymans0ab49042017-02-06 22:40:14 +0100570 sysinfo->twr = DIV_ROUND_UP(saved_timings->min_tWR, sysinfo->tclk);
571 if (sysinfo->twr > 5)
572 die("DDR-II Module does not support this frequency (tWR error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000573
Arthur Heymans0ab49042017-02-06 22:40:14 +0100574 sysinfo->trfc = DIV_ROUND_UP(saved_timings->min_tRFC, sysinfo->tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000575
Arthur Heymans0ab49042017-02-06 22:40:14 +0100576 printk(BIOS_DEBUG, "tRAS = %d cycles\n", sysinfo->tras);
577 printk(BIOS_DEBUG, "tRP = %d cycles\n", sysinfo->trp);
578 printk(BIOS_DEBUG, "tRCD = %d cycles\n", sysinfo->trcd);
579 printk(BIOS_DEBUG, "tWR = %d cycles\n", sysinfo->twr);
580 printk(BIOS_DEBUG, "tRFC = %d cycles\n", sysinfo->trfc);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000581
Arthur Heymans0ab49042017-02-06 22:40:14 +0100582 /* Refresh is slower than 15.6us, use 15.6us */
583 /* tRR is decoded in units of 1/256us */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000584
Arthur Heymans0ab49042017-02-06 22:40:14 +0100585#define T_RR_7_8US 2000000
586#define T_RR_15_6US 4000000
587#define REFRESH_7_8US 1
588#define REFRESH_15_6US 0
Stefan Reinauer278534d2008-10-29 04:51:07 +0000589
Arthur Heymans0ab49042017-02-06 22:40:14 +0100590 if (saved_timings->max_tRR < T_RR_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000591 die("DDR-II module has unsupported refresh value\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100592 else if (saved_timings->max_tRR < T_RR_15_6US)
593 sysinfo->refresh = REFRESH_7_8US;
594 else
595 sysinfo->refresh = REFRESH_15_6US;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000596 printk(BIOS_DEBUG, "Refresh: %s\n", sysinfo->refresh?"7.8us":"15.6us");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000597}
598
Arthur Heymans0ab49042017-02-06 22:40:14 +0100599/**
600 * @brief Get generic DIMM parameters.
601 * @param sysinfo Central memory controller information structure
602 *
603 * This function gathers several pieces of information for each system DIMM:
604 * o DIMM width (x8 / x16)
605 * o DIMM rank (single ranked / dual ranked)
606 *
607 * Also, some non-supported scenarios are detected.
608 */
609
610static void sdram_get_dram_configuration(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000611{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100612 struct timings saved_timings;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000613
Arthur Heymans0ab49042017-02-06 22:40:14 +0100614 gather_common_timing(sysinfo, &saved_timings);
615 choose_tclk(sysinfo, &saved_timings);
616 derive_timings(sysinfo, &saved_timings);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000617}
618
Arthur Heymans70a8e342017-03-09 11:30:23 +0100619static void sdram_program_dram_width(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000620{
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200621 u16 c0dramw = 0, c1dramw = 0;
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200622 int i, idx;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000623
624 if (sysinfo->dual_channel)
625 idx = 2;
626 else
627 idx = 1;
628
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200629 for (i = 0; i < DIMM_SOCKETS; i++) { /* Channel 0 */
630 switch (sysinfo->dimm[i]) {
631 case SYSINFO_DIMM_X16DS:
632 c0dramw |= (0x0000) << 4*(i % 2);
633 break;
634 case SYSINFO_DIMM_X8DS:
635 c0dramw |= (0x0001) << 4*(i % 2);
636 break;
637 case SYSINFO_DIMM_X16SS:
638 c0dramw |= (0x0000) << 4*(i % 2);
639 break;
640 case SYSINFO_DIMM_X8DDS:
641 c0dramw |= (0x0005) << 4*(i % 2);
642 break;
643 case SYSINFO_DIMM_NOT_POPULATED:
644 c0dramw |= (0x0000) << 4*(i % 2);
645 break;
646 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000647 }
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200648 for (i = DIMM_SOCKETS; i < idx * DIMM_SOCKETS; i++) { /* Channel 1 */
649 switch (sysinfo->dimm[i]) {
650 case SYSINFO_DIMM_X16DS:
651 c1dramw |= (0x0000) << 4*(i % 2);
652 break;
653 case SYSINFO_DIMM_X8DS:
Patrick Georgi68aed912018-11-16 18:00:12 +0100654 c1dramw |= (0x0010) << 4*(i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200655 break;
656 case SYSINFO_DIMM_X16SS:
657 c1dramw |= (0x0000) << 4*(i % 2);
658 break;
659 case SYSINFO_DIMM_X8DDS:
Patrick Georgi68aed912018-11-16 18:00:12 +0100660 c1dramw |= (0x0050) << 4*(i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200661 break;
662 case SYSINFO_DIMM_NOT_POPULATED:
663 c1dramw |= (0x0000) << 4*(i % 2);
664 break;
665 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000666 }
667
668 MCHBAR16(C0DRAMW) = c0dramw;
669 MCHBAR16(C1DRAMW) = c1dramw;
670}
671
672static void sdram_write_slew_rates(u32 offset, const u32 *slew_rate_table)
673{
674 int i;
675
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200676 for (i = 0; i < 16; i++)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000677 MCHBAR32(offset+(i*4)) = slew_rate_table[i];
678}
679
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000680static const u32 dq2030[] = {
681 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
682 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
683 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
684 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
685};
686
687static const u32 dq2330[] = {
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 cmd2710[] = {
695 0x07060605, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
696 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
697 0x1110100f, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
698 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
699};
700
701static const u32 cmd3210[] = {
702 0x0f0d0b0a, 0x17151311, 0x1f1d1b19, 0x1f1f1f1f,
703 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
704 0x18171615, 0x1f1f1c1a, 0x1f1f1f1f, 0x1f1f1f1f,
705 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
706};
707
708static const u32 clk2030[] = {
709 0x0e0d0d0c, 0x100f0f0e, 0x100f0e0d, 0x15131211,
710 0x1d1b1917, 0x2523211f, 0x2a282927, 0x32302e2c,
711 0x17161514, 0x1b1a1918, 0x1f1e1d1c, 0x23222120,
712 0x27262524, 0x2d2b2928, 0x3533312f, 0x3d3b3937
713};
714
715static const u32 ctl3215[] = {
716 0x01010000, 0x03020101, 0x07060504, 0x0b0a0908,
717 0x100f0e0d, 0x14131211, 0x18171615, 0x1c1b1a19,
718 0x05040403, 0x07060605, 0x0a090807, 0x0f0d0c0b,
719 0x14131211, 0x18171615, 0x1c1b1a19, 0x201f1e1d
720};
721
722static const u32 ctl3220[] = {
723 0x05040403, 0x07060505, 0x0e0c0a08, 0x1a171411,
724 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e,
725 0x09080807, 0x0b0a0a09, 0x0f0d0c0b, 0x1b171311,
726 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e
727};
728
729static const u32 nc[] = {
730 0x00000000, 0x00000000, 0x00000000, 0x00000000,
731 0x00000000, 0x00000000, 0x00000000, 0x00000000,
732 0x00000000, 0x00000000, 0x00000000, 0x00000000,
733 0x00000000, 0x00000000, 0x00000000, 0x00000000
734};
735
736enum {
737 DQ2030,
738 DQ2330,
739 CMD2710,
740 CMD3210,
741 CLK2030,
742 CTL3215,
743 CTL3220,
744 NC,
745};
746
747static const u8 dual_channel_slew_group_lookup[] = {
748 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
749 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
750 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
751 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
752 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
753
754 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
755 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
756 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
757 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
758 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
759
760 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
761 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
762 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
763 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
764 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
765
766 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
767 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
768 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
769 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
770 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, NC, NC,
771
772 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
773 NC, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
774 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
775 NC, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD2710
776};
777
778static const u8 single_channel_slew_group_lookup[] = {
779 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
780 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
781 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
782 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
783 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
784
785 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
786 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
787 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
788 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
789 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
790
791 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
792 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
793 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
794 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
795 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
796
797 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
798 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
799 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
800 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
801 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
802
803 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
804 DQ2330, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
805 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
806 DQ2330, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD3210
807};
808
809static const u32 *slew_group_lookup(int dual_channel, int index)
810{
811 const u8 *slew_group;
812 /* Dual Channel needs different tables. */
813 if (dual_channel)
814 slew_group = dual_channel_slew_group_lookup;
815 else
816 slew_group = single_channel_slew_group_lookup;
817
818 switch (slew_group[index]) {
819 case DQ2030: return dq2030;
820 case DQ2330: return dq2330;
821 case CMD2710: return cmd2710;
822 case CMD3210: return cmd3210;
823 case CLK2030: return clk2030;
824 case CTL3215: return ctl3215;
825 case CTL3220: return ctl3220;
826 case NC: return nc;
827 }
828
829 return nc;
830}
831
Julius Wernercd49cce2019-03-05 16:53:33 -0800832#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000833/* Strength multiplier tables */
834static const u8 dual_channel_strength_multiplier[] = {
835 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
836 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
837 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
838 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
839 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
840 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
841 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
842 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
843 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
844 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
845 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
846 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
847 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
848 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
849 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
850 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
851 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
852 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
853 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
854 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
855 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
856 0x00, 0x00, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
857 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
858 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x44, 0x22
859};
860
861static const u8 single_channel_strength_multiplier[] = {
862 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
863 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
864 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
865 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
866 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
867 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
868 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
869 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
870 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
871 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
872 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
873 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
874 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
875 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
876 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
877 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
878 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
879 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
880 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
881 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
882 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
883 0x33, 0x00, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
884 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
885 0x33, 0x00, 0x11, 0x00, 0x44, 0x44, 0x33, 0x11
886};
Julius Wernercd49cce2019-03-05 16:53:33 -0800887#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000888static const u8 dual_channel_strength_multiplier[] = {
889 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
890 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
891 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
892 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
893 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
894 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
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, 0x33,
898 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
899 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
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, 0x33,
903 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
904 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
905 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
906 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
907 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
908 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
909 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
910 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
911 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
912 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33
913};
914
915static const u8 single_channel_strength_multiplier[] = {
916 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
917 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
918 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
919 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
920 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
921 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
922 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
923 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
924 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
925 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
926 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
927 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
928 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
929 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
930 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
931 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
932 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
933 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
934 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
935 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
936 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
937 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
938 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
939 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00
940};
941#endif
942
Stefan Reinauer278534d2008-10-29 04:51:07 +0000943static void sdram_rcomp_buffer_strength_and_slew(struct sys_info *sysinfo)
944{
Arthur Heymans70a8e342017-03-09 11:30:23 +0100945 const u8 *strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000946 int idx, dual_channel;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000947
948 /* Set Strength Multipliers */
949
950 /* Dual Channel needs different tables. */
951 if (sdram_capabilities_dual_channel()) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000952 printk(BIOS_DEBUG, "Programming Dual Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000953 strength_multiplier = dual_channel_strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000954 dual_channel = 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000955 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[2];
956 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000957 printk(BIOS_DEBUG, "Programming Single Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000958 strength_multiplier = single_channel_strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000959 dual_channel = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000960 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[1];
961 }
962
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000963 printk(BIOS_DEBUG, "Table Index: %d\n", idx);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000964
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000965 MCHBAR8(G1SC) = strength_multiplier[idx * 8 + 0];
966 MCHBAR8(G2SC) = strength_multiplier[idx * 8 + 1];
967 MCHBAR8(G3SC) = strength_multiplier[idx * 8 + 2];
968 MCHBAR8(G4SC) = strength_multiplier[idx * 8 + 3];
969 MCHBAR8(G5SC) = strength_multiplier[idx * 8 + 4];
970 MCHBAR8(G6SC) = strength_multiplier[idx * 8 + 5];
971 MCHBAR8(G7SC) = strength_multiplier[idx * 8 + 6];
972 MCHBAR8(G8SC) = strength_multiplier[idx * 8 + 7];
Stefan Reinauer278534d2008-10-29 04:51:07 +0000973
974 /* Channel 0 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000975 sdram_write_slew_rates(G1SRPUT, slew_group_lookup(dual_channel, idx * 8 + 0));
976 sdram_write_slew_rates(G2SRPUT, slew_group_lookup(dual_channel, idx * 8 + 1));
Arthur Heymans70a8e342017-03-09 11:30:23 +0100977 if ((slew_group_lookup(dual_channel, idx * 8 + 2) != nc) && (sysinfo->package == SYSINFO_PACKAGE_STACKED))
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000978
Stefan Reinauer278534d2008-10-29 04:51:07 +0000979 sdram_write_slew_rates(G3SRPUT, ctl3220);
Arthur Heymans70a8e342017-03-09 11:30:23 +0100980 else
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000981 sdram_write_slew_rates(G3SRPUT, slew_group_lookup(dual_channel, idx * 8 + 2));
Arthur Heymans70a8e342017-03-09 11:30:23 +0100982
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000983 sdram_write_slew_rates(G4SRPUT, slew_group_lookup(dual_channel, idx * 8 + 3));
984 sdram_write_slew_rates(G5SRPUT, slew_group_lookup(dual_channel, idx * 8 + 4));
985 sdram_write_slew_rates(G6SRPUT, slew_group_lookup(dual_channel, idx * 8 + 5));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000986
987 /* Channel 1 */
988 if (sysinfo->dual_channel) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000989 sdram_write_slew_rates(G7SRPUT, slew_group_lookup(dual_channel, idx * 8 + 6));
990 sdram_write_slew_rates(G8SRPUT, slew_group_lookup(dual_channel, idx * 8 + 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000991 } else {
992 sdram_write_slew_rates(G7SRPUT, nc);
993 sdram_write_slew_rates(G8SRPUT, nc);
994 }
995}
996
997static void sdram_enable_rcomp(void)
998{
999 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001000 /* Enable Global Periodic RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001001 udelay(300);
1002 reg32 = MCHBAR32(GBRCOMPCTL);
1003 reg32 &= ~(1 << 23);
1004 MCHBAR32(GBRCOMPCTL) = reg32;
1005}
1006
1007static void sdram_program_dll_timings(struct sys_info *sysinfo)
1008{
Elyes HAOUAS44a30662017-02-23 13:14:44 +01001009 u32 channeldll = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001010 int i;
1011
Elyes HAOUAS38424982016-08-21 12:01:04 +02001012 printk(BIOS_DEBUG, "Programming DLL Timings...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001013
Arthur Heymans70a8e342017-03-09 11:30:23 +01001014 MCHBAR16(DQSMT) &= ~((3 << 12) | (1 << 10) | (0xf << 0));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001015 MCHBAR16(DQSMT) |= (1 << 13) | (0xc << 0);
1016
1017 /* We drive both channels with the same speed */
Julius Wernercd49cce2019-03-05 16:53:33 -08001018 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001019 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001020 case 400:
1021 channeldll = 0x26262626; break;
1022 case 533:
1023 channeldll = 0x22222222; break;
1024 case 667:
1025 channeldll = 0x11111111; break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001026 }
Julius Wernercd49cce2019-03-05 16:53:33 -08001027 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001028 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001029 case 400:
1030 channeldll = 0x33333333; break;
1031 case 533:
1032 channeldll = 0x24242424; break;
1033 case 667:
1034 channeldll = 0x25252525; break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001035 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001036 }
1037
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001038 for (i = 0; i < 4; i++) {
Elyes HAOUAS44a30662017-02-23 13:14:44 +01001039 MCHBAR32(C0R0B00DQST + (i * 0x10) + 0) = channeldll;
1040 MCHBAR32(C0R0B00DQST + (i * 0x10) + 4) = channeldll;
1041 MCHBAR32(C1R0B00DQST + (i * 0x10) + 0) = channeldll;
1042 MCHBAR32(C1R0B00DQST + (i * 0x10) + 4) = channeldll;
Julius Wernercd49cce2019-03-05 16:53:33 -08001043 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUAS44a30662017-02-23 13:14:44 +01001044 MCHBAR8(C0R0B00DQST + (i * 0x10) + 8) = channeldll & 0xff;
1045 MCHBAR8(C1R0B00DQST + (i * 0x10) + 8) = channeldll & 0xff;
Paul Menzelbce7e332017-02-22 18:46:27 +01001046 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001047 }
1048}
1049
1050static void sdram_force_rcomp(void)
1051{
1052 u32 reg32;
1053 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001054
Stefan Reinauer278534d2008-10-29 04:51:07 +00001055 reg32 = MCHBAR32(ODTC);
1056 reg32 |= (1 << 28);
1057 MCHBAR32(ODTC) = reg32;
1058
1059 reg32 = MCHBAR32(SMSRCTL);
1060 reg32 |= (1 << 0);
1061 MCHBAR32(SMSRCTL) = reg32;
1062
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001063 /* Start initial RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001064 reg32 = MCHBAR32(GBRCOMPCTL);
1065 reg32 |= (1 << 8);
1066 MCHBAR32(GBRCOMPCTL) = reg32;
1067
1068 reg8 = i945_silicon_revision();
1069 if ((reg8 == 0 && (MCHBAR32(DCC) & (3 << 0)) == 0) || (reg8 == 1)) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001070
Stefan Reinauer278534d2008-10-29 04:51:07 +00001071 reg32 = MCHBAR32(GBRCOMPCTL);
1072 reg32 |= (3 << 5);
1073 MCHBAR32(GBRCOMPCTL) = reg32;
1074 }
1075}
1076
1077static void sdram_initialize_system_memory_io(struct sys_info *sysinfo)
1078{
1079 u8 reg8;
1080 u32 reg32;
1081
Elyes HAOUAS38424982016-08-21 12:01:04 +02001082 printk(BIOS_DEBUG, "Initializing System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001083 /* Enable Data Half Clock Pushout */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001084 reg8 = MCHBAR8(C0HCTC);
1085 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001086 reg8 |= (1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001087 MCHBAR8(C0HCTC) = reg8;
1088
1089 reg8 = MCHBAR8(C1HCTC);
1090 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001091 reg8 |= (1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001092 MCHBAR8(C1HCTC) = reg8;
1093
Arthur Heymans70a8e342017-03-09 11:30:23 +01001094 MCHBAR16(WDLLBYPMODE) &= ~((1 << 9) | (1 << 6) | (1 << 4) | (1 << 3) | (1 << 1));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001095 MCHBAR16(WDLLBYPMODE) |= (1 << 8) | (1 << 7) | (1 << 5) | (1 << 2) | (1 << 0);
1096
1097 MCHBAR8(C0WDLLCMC) = 0;
1098 MCHBAR8(C1WDLLCMC) = 0;
1099
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001100 /* Program RCOMP Settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001101 sdram_program_dram_width(sysinfo);
1102
1103 sdram_rcomp_buffer_strength_and_slew(sysinfo);
1104
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001105 /* Indicate that RCOMP programming is done */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001106 reg32 = MCHBAR32(GBRCOMPCTL);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001107 reg32 &= ~((1 << 29) | (1 << 26) | (3 << 21) | (3 << 2));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001108 reg32 |= (3 << 27) | (3 << 0);
1109 MCHBAR32(GBRCOMPCTL) = reg32;
1110
1111 MCHBAR32(GBRCOMPCTL) |= (1 << 10);
1112
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001113 /* Program DLL Timings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001114 sdram_program_dll_timings(sysinfo);
1115
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001116 /* Force RCOMP cycle */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001117 sdram_force_rcomp();
1118}
1119
1120static void sdram_enable_system_memory_io(struct sys_info *sysinfo)
1121{
1122 u32 reg32;
1123
Elyes HAOUAS38424982016-08-21 12:01:04 +02001124 printk(BIOS_DEBUG, "Enabling System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001125
Stefan Reinauer278534d2008-10-29 04:51:07 +00001126 reg32 = MCHBAR32(RCVENMT);
1127 reg32 &= ~(0x3f << 6);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001128 MCHBAR32(RCVENMT) = reg32; /* [11:6] = 0 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001129
1130 reg32 |= (1 << 11) | (1 << 9);
1131 MCHBAR32(RCVENMT) = reg32;
1132
1133 reg32 = MCHBAR32(DRTST);
1134 reg32 |= (1 << 3) | (1 << 2);
1135 MCHBAR32(DRTST) = reg32;
1136
1137 reg32 = MCHBAR32(DRTST);
1138 reg32 |= (1 << 6) | (1 << 4);
1139 MCHBAR32(DRTST) = reg32;
1140
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001141 asm volatile ("nop; nop;" ::: "memory");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001142
1143 reg32 = MCHBAR32(DRTST);
1144
1145 /* Is channel 0 populated? */
1146 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
1147 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
1148 reg32 |= (1 << 7) | (1 << 5);
1149 else
1150 reg32 |= (1 << 31);
1151
1152 /* Is channel 1 populated? */
1153 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1154 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
1155 reg32 |= (1 << 9) | (1 << 8);
1156 else
1157 reg32 |= (1 << 30);
1158
1159 MCHBAR32(DRTST) = reg32;
1160
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001161 /* Activate DRAM Channel IO Buffers */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001162 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
1163 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) {
1164 reg32 = MCHBAR32(C0DRC1);
1165 reg32 |= (1 << 8);
1166 MCHBAR32(C0DRC1) = reg32;
1167 }
1168 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1169 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED) {
1170 reg32 = MCHBAR32(C1DRC1);
1171 reg32 |= (1 << 8);
1172 MCHBAR32(C1DRC1) = reg32;
1173 }
1174}
1175
Stefan Reinauer278534d2008-10-29 04:51:07 +00001176static int sdram_program_row_boundaries(struct sys_info *sysinfo)
1177{
1178 int i;
Arthur Heymans885c2892016-10-03 17:16:48 +02001179 int cum0, cum1, tolud, tom, pci_mmio_size;
1180 const struct device *dev;
1181 const struct northbridge_intel_i945_config *cfg = NULL;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001182
Paul Menzel84283bc2014-07-17 08:16:04 +02001183 printk(BIOS_DEBUG, "Setting RAM size...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001184
1185 cum0 = 0;
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001186 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001187 cum0 += sysinfo->banksize[i];
Stefan Reinauer278534d2008-10-29 04:51:07 +00001188 MCHBAR8(C0DRB0+i) = cum0;
1189 }
1190
1191 /* Assume we continue in Channel 1 where we stopped in Channel 0 */
1192 cum1 = cum0;
1193
1194 /* Exception: Interleaved starts from the beginning */
1195 if (sysinfo->interleaved)
1196 cum1 = 0;
1197
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001198 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001199 cum1 += sysinfo->banksize[i + 4];
Stefan Reinauer278534d2008-10-29 04:51:07 +00001200 MCHBAR8(C1DRB0+i) = cum1;
1201 }
1202
1203 /* Set TOLUD Top Of Low Usable DRAM */
1204 if (sysinfo->interleaved)
1205 tolud = (cum0 + cum1) << 1;
1206 else
1207 tolud = (cum1 ? cum1 : cum0) << 1;
Stefan Reinauer779b3e32008-11-10 15:43:37 +00001208
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001209 /* The TOM register has a different format */
1210 tom = tolud >> 3;
1211
1212 /* Limit the value of TOLUD to leave some space for PCI memory. */
Kyösti Mälkkic70eed12018-05-22 02:18:00 +03001213 dev = pcidev_on_root(0, 0);
Arthur Heymans885c2892016-10-03 17:16:48 +02001214 if (dev)
1215 cfg = dev->chip_info;
1216
1217 /* Don't use pci mmio sizes smaller than 768M */
1218 if (!cfg || cfg->pci_mmio_size <= DEFAULT_PCI_MMIO_SIZE)
1219 pci_mmio_size = DEFAULT_PCI_MMIO_SIZE;
1220 else
1221 pci_mmio_size = cfg->pci_mmio_size;
1222
1223 tolud = MIN(((4096 - pci_mmio_size) / 128) << 3, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001224
Arthur Heymans70a8e342017-03-09 11:30:23 +01001225 pci_write_config8(PCI_DEV(0, 0, 0), TOLUD, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001226
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001227 printk(BIOS_DEBUG, "C0DRB = 0x%08x\n", MCHBAR32(C0DRB0));
1228 printk(BIOS_DEBUG, "C1DRB = 0x%08x\n", MCHBAR32(C1DRB0));
Arthur Heymans70a8e342017-03-09 11:30:23 +01001229 printk(BIOS_DEBUG, "TOLUD = 0x%04x\n", pci_read_config8(PCI_DEV(0, 0, 0), TOLUD));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001230
Arthur Heymans70a8e342017-03-09 11:30:23 +01001231 pci_write_config16(PCI_DEV(0, 0, 0), TOM, tom);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001232
1233 return 0;
1234}
1235
Stefan Reinauer278534d2008-10-29 04:51:07 +00001236static int sdram_set_row_attributes(struct sys_info *sysinfo)
1237{
Arthur Heymans0ab49042017-02-06 22:40:14 +01001238 int i;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001239 u16 dra0 = 0, dra1 = 0, dra = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001240
Elyes HAOUAS38424982016-08-21 12:01:04 +02001241 printk(BIOS_DEBUG, "Setting row attributes...\n");
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001242 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001243 u8 columnsrows;
1244
Arthur Heymans70a8e342017-03-09 11:30:23 +01001245 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001246 continue;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001247
Arthur Heymans0ab49042017-02-06 22:40:14 +01001248 columnsrows = (sysinfo->rows[i] & 0x0f)
1249 | (sysinfo->cols[i] & 0xf) << 4;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001250
1251 switch (columnsrows) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001252 case 0x9d:
1253 dra = 2; break;
1254 case 0xad:
1255 dra = 3; break;
1256 case 0xbd:
1257 dra = 4; break;
1258 case 0xae:
1259 dra = 3; break;
1260 case 0xbe:
1261 dra = 4; break;
1262 default:
1263 die("Unsupported Rows/Columns. (DRA)");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001264 }
1265
1266 /* Double Sided DIMMs? */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001267 if (sysinfo->banksize[(2 * i) + 1] != 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001268 dra = (dra << 4) | dra;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001269
Stefan Reinauer278534d2008-10-29 04:51:07 +00001270 if (i < DIMM_SOCKETS)
1271 dra0 |= (dra << (i*8));
1272 else
1273 dra1 |= (dra << ((i - DIMM_SOCKETS)*8));
1274 }
1275
1276 MCHBAR16(C0DRA0) = dra0;
1277 MCHBAR16(C1DRA0) = dra1;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001278
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001279 printk(BIOS_DEBUG, "C0DRA = 0x%04x\n", dra0);
1280 printk(BIOS_DEBUG, "C1DRA = 0x%04x\n", dra1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001281
1282 return 0;
1283}
1284
1285static void sdram_set_bank_architecture(struct sys_info *sysinfo)
1286{
1287 u32 off32;
1288 int i;
1289
1290 MCHBAR16(C1BNKARC) &= 0xff00;
1291 MCHBAR16(C0BNKARC) &= 0xff00;
1292
1293 off32 = C0BNKARC;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001294 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001295 /* Switch to second channel */
1296 if (i == DIMM_SOCKETS)
1297 off32 = C1BNKARC;
1298
1299 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
1300 continue;
1301
1302 if (sysinfo->banks[i] != 8)
1303 continue;
1304
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001305 printk(BIOS_SPEW, "DIMM%d has 8 banks.\n", i);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001306
1307 if (i & 1)
1308 MCHBAR16(off32) |= 0x50;
1309 else
1310 MCHBAR16(off32) |= 0x05;
1311 }
1312}
1313
Stefan Reinauer278534d2008-10-29 04:51:07 +00001314static void sdram_program_refresh_rate(struct sys_info *sysinfo)
1315{
1316 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001317
Arthur Heymans70a8e342017-03-09 11:30:23 +01001318 if (sysinfo->refresh == REFRESH_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001319 reg32 = (2 << 8); /* Refresh enabled at 7.8us */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001320 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001321 reg32 = (1 << 8); /* Refresh enabled at 15.6us */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001322
1323 MCHBAR32(C0DRC0) &= ~(7 << 8);
1324 MCHBAR32(C0DRC0) |= reg32;
1325
1326 MCHBAR32(C1DRC0) &= ~(7 << 8);
1327 MCHBAR32(C1DRC0) |= reg32;
1328}
1329
1330static void sdram_program_cke_tristate(struct sys_info *sysinfo)
1331{
1332 u32 reg32;
1333 int i;
1334
1335 reg32 = MCHBAR32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001336
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001337 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001338 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001339 reg32 |= (1 << (16 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001340 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001341
Stefan Reinauer278534d2008-10-29 04:51:07 +00001342 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001343
Stefan Reinauer278534d2008-10-29 04:51:07 +00001344 reg32 |= (1 << 11);
1345 MCHBAR32(C0DRC1) = reg32;
1346
1347 /* Do we have to do this if we're in Single Channel Mode? */
1348 reg32 = MCHBAR32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001349
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001350 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001351 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001352 reg32 |= (1 << (12 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001353 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001354
Stefan Reinauer278534d2008-10-29 04:51:07 +00001355 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001356
Stefan Reinauer278534d2008-10-29 04:51:07 +00001357 reg32 |= (1 << 11);
1358 MCHBAR32(C1DRC1) = reg32;
1359}
1360
1361static void sdram_program_odt_tristate(struct sys_info *sysinfo)
1362{
1363 u32 reg32;
1364 int i;
1365
1366 reg32 = MCHBAR32(C0DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001367
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001368 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001369 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001370 reg32 |= (1 << (24 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001371 }
1372 MCHBAR32(C0DRC2) = reg32;
1373
1374 reg32 = MCHBAR32(C1DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001375
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001376 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001377 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001378 reg32 |= (1 << (20 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001379 }
1380 MCHBAR32(C1DRC2) = reg32;
1381}
1382
1383static void sdram_set_timing_and_control(struct sys_info *sysinfo)
1384{
Arthur Heymans25027232017-02-12 23:34:39 +01001385 u32 reg32, tRD_min;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001386 u32 tWTR;
1387 u32 temp_drt;
1388 int i, page_size;
1389
Edward O'Callaghan2f237c12014-05-25 06:24:39 +10001390 static const u8 cas_table[] = {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001391 2, 1, 0, 3
1392 };
1393
1394 reg32 = MCHBAR32(C0DRC0);
1395 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001396 reg32 &= ~((1 << 13) | (1 << 12));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001397 MCHBAR32(C0DRC0) = reg32;
1398
1399 reg32 = MCHBAR32(C1DRC0);
1400 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001401 reg32 &= ~((1 << 13) | (1 << 12));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001402 MCHBAR32(C1DRC0) = reg32;
1403
1404 if (!sysinfo->dual_channel && sysinfo->dimm[1] !=
1405 SYSINFO_DIMM_NOT_POPULATED) {
1406 reg32 = MCHBAR32(C0DRC0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001407 reg32 |= (1 << 15);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001408 MCHBAR32(C0DRC0) = reg32;
1409 }
1410
1411 sdram_program_refresh_rate(sysinfo);
1412
1413 sdram_program_cke_tristate(sysinfo);
1414
1415 sdram_program_odt_tristate(sysinfo);
1416
1417 /* Calculate DRT0 */
1418
1419 temp_drt = 0;
1420
1421 /* B2B Write Precharge (same bank) = CL-1 + BL/2 + tWR */
1422 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + sysinfo->twr;
1423 temp_drt |= (reg32 << 28);
1424
1425 /* Write Auto Precharge (same bank) = CL-1 + BL/2 + tWR + tRP */
1426 reg32 += sysinfo->trp;
1427 temp_drt |= (reg32 << 4);
1428
Arthur Heymans70a8e342017-03-09 11:30:23 +01001429 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001430 tWTR = 3; /* 667MHz */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001431 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001432 tWTR = 2; /* 400 and 533 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001433
1434 /* B2B Write to Read Command Spacing */
1435 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + tWTR;
1436 temp_drt |= (reg32 << 24);
1437
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001438 /* CxDRT0 [23:22], [21:20], [19:18] [16] have fixed values */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001439 temp_drt |= ((1 << 22) | (3 << 20) | (1 << 18) | (0 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001440
Arthur Heymans25027232017-02-12 23:34:39 +01001441 /*
1442 * tRD is the delay the memory controller is waiting on the FSB,
1443 * in mclk domain.
1444 * This parameter is important for stability and performance.
1445 * Those values might not be optimal but seem stable.
1446 */
1447 tRD_min = sysinfo->cas;
Arthur Heymanse1897612016-10-15 23:29:18 +02001448 switch (sysinfo->fsb_frequency) {
Arthur Heymans25027232017-02-12 23:34:39 +01001449 case 533: break;
1450 case 667: tRD_min += 1;
Arthur Heymanse1897612016-10-15 23:29:18 +02001451 break;
Arthur Heymans25027232017-02-12 23:34:39 +01001452 case 800: tRD_min += 2;
Arthur Heymanse1897612016-10-15 23:29:18 +02001453 break;
Arthur Heymans25027232017-02-12 23:34:39 +01001454 case 1066: tRD_min += 3;
Arthur Heymanse1897612016-10-15 23:29:18 +02001455 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001456 }
Arthur Heymanse1897612016-10-15 23:29:18 +02001457
Arthur Heymans25027232017-02-12 23:34:39 +01001458 temp_drt |= (tRD_min << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001459
1460 /* Read Auto Precharge to Activate */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001461
Stefan Reinauer278534d2008-10-29 04:51:07 +00001462 temp_drt |= (8 << 0);
1463
1464 MCHBAR32(C0DRT0) = temp_drt;
1465 MCHBAR32(C1DRT0) = temp_drt;
1466
1467 /* Calculate DRT1 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001468
Stefan Reinauer278534d2008-10-29 04:51:07 +00001469 temp_drt = MCHBAR32(C0DRT1) & 0x00020088;
1470
1471 /* DRAM RASB Precharge */
1472 temp_drt |= (sysinfo->trp - 2) << 0;
1473
1474 /* DRAM RASB to CASB Delay */
1475 temp_drt |= (sysinfo->trcd - 2) << 4;
1476
1477 /* CASB Latency */
1478 temp_drt |= (cas_table[sysinfo->cas - 3]) << 8;
1479
1480 /* Refresh Cycle Time */
1481 temp_drt |= (sysinfo->trfc) << 10;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001482
Stefan Reinauer278534d2008-10-29 04:51:07 +00001483 /* Pre-All to Activate Delay */
1484 temp_drt |= (0 << 16);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001485
Stefan Reinauer278534d2008-10-29 04:51:07 +00001486 /* Precharge to Precharge Delay stays at 1 clock */
1487 temp_drt |= (0 << 18);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001488
Stefan Reinauer278534d2008-10-29 04:51:07 +00001489 /* Activate to Precharge Delay */
1490 temp_drt |= (sysinfo->tras << 19);
1491
1492 /* Read to Precharge (tRTP) */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001493 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001494 temp_drt |= (1 << 28);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001495 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001496 temp_drt |= (0 << 28);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001497
1498 /* Determine page size */
1499 reg32 = 0;
1500 page_size = 1; /* Default: 1k pagesize */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001501 for (i = 0; i < 2*DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001502 if (sysinfo->dimm[i] == SYSINFO_DIMM_X16DS ||
1503 sysinfo->dimm[i] == SYSINFO_DIMM_X16SS)
1504 page_size = 2; /* 2k pagesize */
1505 }
1506
Arthur Heymans70a8e342017-03-09 11:30:23 +01001507 if (sysinfo->memory_frequency == 533 && page_size == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001508 reg32 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001509 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001510 reg32 = page_size;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001511
Stefan Reinauer278534d2008-10-29 04:51:07 +00001512 temp_drt |= (reg32 << 30);
1513
1514 MCHBAR32(C0DRT1) = temp_drt;
1515 MCHBAR32(C1DRT1) = temp_drt;
1516
1517 /* Program DRT2 */
1518 reg32 = MCHBAR32(C0DRT2);
1519 reg32 &= ~(1 << 8);
1520 MCHBAR32(C0DRT2) = reg32;
1521
1522 reg32 = MCHBAR32(C1DRT2);
1523 reg32 &= ~(1 << 8);
1524 MCHBAR32(C1DRT2) = reg32;
1525
1526 /* Calculate DRT3 */
1527 temp_drt = MCHBAR32(C0DRT3) & ~0x07ffffff;
1528
1529 /* Get old tRFC value */
1530 reg32 = MCHBAR32(C0DRT1) >> 10;
1531 reg32 &= 0x3f;
1532
1533 /* 788nS - tRFC */
1534 switch (sysinfo->memory_frequency) {
1535 case 400: /* 5nS */
1536 reg32 = ((78800 / 500) - reg32) & 0x1ff;
1537 reg32 |= (0x8c << 16) | (0x0c << 10); /* 1 us */
1538 break;
1539 case 533: /* 3.75nS */
1540 reg32 = ((78800 / 375) - reg32) & 0x1ff;
1541 reg32 |= (0xba << 16) | (0x10 << 10); /* 1 us */
1542 break;
1543 case 667: /* 3nS */
1544 reg32 = ((78800 / 300) - reg32) & 0x1ff;
1545 reg32 |= (0xe9 << 16) | (0x14 << 10); /* 1 us */
1546 break;
1547 }
1548
1549 temp_drt |= reg32;
1550
1551 MCHBAR32(C0DRT3) = temp_drt;
1552 MCHBAR32(C1DRT3) = temp_drt;
1553}
1554
1555static void sdram_set_channel_mode(struct sys_info *sysinfo)
1556{
1557 u32 reg32;
1558
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001559 printk(BIOS_DEBUG, "Setting mode of operation for memory channels...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001560
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001561 if (sdram_capabilities_interleave() &&
Arthur Heymans70a8e342017-03-09 11:30:23 +01001562 ((sysinfo->banksize[0] + sysinfo->banksize[1] +
1563 sysinfo->banksize[2] + sysinfo->banksize[3]) ==
1564 (sysinfo->banksize[4] + sysinfo->banksize[5] +
1565 sysinfo->banksize[6] + sysinfo->banksize[7]))) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001566 /* Both channels equipped with DIMMs of the same size */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001567 sysinfo->interleaved = 1;
1568 } else {
1569 sysinfo->interleaved = 0;
1570 }
1571
1572 reg32 = MCHBAR32(DCC);
1573 reg32 &= ~(7 << 0);
1574
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001575 if (sysinfo->interleaved) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001576 /* Dual Channel Interleaved */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001577 printk(BIOS_DEBUG, "Dual Channel Interleaved.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001578 reg32 |= (1 << 1);
1579 } else if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED &&
1580 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
1581 /* Channel 1 only */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001582 printk(BIOS_DEBUG, "Single Channel 1 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001583 reg32 |= (1 << 2);
Elyes HAOUAS75da1fb2017-02-16 18:59:13 +01001584 } else if (sdram_capabilities_dual_channel() &&
1585 (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1586 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) {
Martin Roth128c1042016-11-18 09:29:03 -07001587 /* Dual Channel Asymmetric */
1588 printk(BIOS_DEBUG, "Dual Channel Asymmetric.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001589 reg32 |= (1 << 0);
1590 } else {
1591 /* All bits 0 means Single Channel 0 operation */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001592 printk(BIOS_DEBUG, "Single Channel 0 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001593 }
1594
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001595 /* Now disable channel XORing */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001596 reg32 |= (1 << 10);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001597
1598 MCHBAR32(DCC) = reg32;
1599
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001600 PRINTK_DEBUG("DCC = 0x%08x\n", MCHBAR32(DCC));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001601}
1602
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001603static void sdram_program_pll_settings(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001604{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001605 MCHBAR32(PLLMON) = 0x80800000;
1606
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001607 sysinfo->fsb_frequency = fsbclk();
Peter Stuge76d91432010-10-01 10:02:33 +00001608 if (sysinfo->fsb_frequency == 0xffff)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001609 die("Unsupported FSB speed");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001610
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001611 /* Program CPCTL according to FSB speed */
1612 /* Only write the lower byte */
1613 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001614 case 400:
1615 MCHBAR8(CPCTL) = 0x90; break; /* FSB400 */
1616 case 533:
1617 MCHBAR8(CPCTL) = 0x95; break; /* FSB533 */
1618 case 667:
1619 MCHBAR8(CPCTL) = 0x8d; break; /* FSB667 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001620 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001621
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001622 MCHBAR16(CPCTL) &= ~(1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001623
Paul Menzel0ce5ebf2013-10-21 21:22:09 +02001624 MCHBAR16(CPCTL); /* Read back register to activate settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001625}
1626
1627static void sdram_program_graphics_frequency(struct sys_info *sysinfo)
1628{
1629 u8 reg8;
1630 u16 reg16;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001631 u8 freq, second_vco, voltage;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001632
1633#define CRCLK_166MHz 0x00
1634#define CRCLK_200MHz 0x01
1635#define CRCLK_250MHz 0x03
1636#define CRCLK_400MHz 0x05
1637
1638#define CDCLK_200MHz 0x00
1639#define CDCLK_320MHz 0x40
1640
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001641#define VOLTAGE_1_05 0x00
1642#define VOLTAGE_1_50 0x01
1643
Paul Menzeldaf9e502014-07-15 23:49:16 +02001644 printk(BIOS_DEBUG, "Setting Graphics Frequency...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001645
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001646 printk(BIOS_DEBUG, "FSB: %d MHz ", sysinfo->fsb_frequency);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001647
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001648 voltage = VOLTAGE_1_05;
1649 if (MCHBAR32(DFT_STRAP1) & (1 << 20))
1650 voltage = VOLTAGE_1_50;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001651 printk(BIOS_DEBUG, "Voltage: %s ", (voltage == VOLTAGE_1_05)?"1.05V":"1.5V");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001652
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001653 /* Gate graphics hardware for frequency change */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001654 reg8 = (1<<3) | (1<<1); /* disable crclk, gate cdclk */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001655 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001656
1657 /* Get graphics frequency capabilities */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001658 reg8 = sdram_capabilities_core_frequencies();
1659
Stefan Reinauer278534d2008-10-29 04:51:07 +00001660 freq = CRCLK_250MHz;
1661 switch (reg8) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001662 case GFX_FREQUENCY_CAP_ALL:
1663 if (voltage == VOLTAGE_1_05)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001664 freq = CRCLK_250MHz;
1665 else
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001666 freq = CRCLK_400MHz; /* 1.5V requires 400MHz */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001667 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001668 case GFX_FREQUENCY_CAP_250MHZ:
1669 freq = CRCLK_250MHz; break;
1670 case GFX_FREQUENCY_CAP_200MHZ:
1671 freq = CRCLK_200MHz; break;
1672 case GFX_FREQUENCY_CAP_166MHZ:
1673 freq = CRCLK_166MHz; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001674 }
1675
1676 if (freq != CRCLK_400MHz) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001677 /* What chipset are we? Force 166MHz for GMS */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001678 reg8 = (pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe7) & 0x70) >> 4;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001679 if (reg8 == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001680 freq = CRCLK_166MHz;
1681 }
1682
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001683 printk(BIOS_DEBUG, "Render: ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001684 switch (freq) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001685 case CRCLK_166MHz:
1686 printk(BIOS_DEBUG, "166MHz"); break;
1687 case CRCLK_200MHz:
1688 printk(BIOS_DEBUG, "200MHz"); break;
1689 case CRCLK_250MHz:
1690 printk(BIOS_DEBUG, "250MHz"); break;
1691 case CRCLK_400MHz:
1692 printk(BIOS_DEBUG, "400MHz"); break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001693 }
1694
Arthur Heymans70a8e342017-03-09 11:30:23 +01001695 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001696 sysinfo->mvco4x = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001697 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001698 sysinfo->mvco4x = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001699
Stefan Reinauer278534d2008-10-29 04:51:07 +00001700 second_vco = 0;
1701
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001702 if (voltage == VOLTAGE_1_50) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001703 second_vco = 1;
1704 } else if ((i945_silicon_revision() > 0) && (freq == CRCLK_250MHz)) {
1705 u16 mem = sysinfo->memory_frequency;
1706 u16 fsb = sysinfo->fsb_frequency;
1707
Arthur Heymans70a8e342017-03-09 11:30:23 +01001708 if ((fsb == 667 && mem == 533) ||
1709 (fsb == 533 && mem == 533) ||
1710 (fsb == 533 && mem == 400)) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001711 second_vco = 1;
1712 }
1713
1714 if (fsb == 667 && mem == 533)
1715 sysinfo->mvco4x = 1;
1716 }
1717
Arthur Heymans70a8e342017-03-09 11:30:23 +01001718 if (second_vco)
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001719 sysinfo->clkcfg_bit7 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001720 else
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001721 sysinfo->clkcfg_bit7 = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001722
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001723 /* Graphics Core Render Clock */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001724 reg16 = pci_read_config16(PCI_DEV(0, 2, 0), GCFC);
1725 reg16 &= ~((7 << 0) | (1 << 13));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001726 reg16 |= freq;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001727 pci_write_config16(PCI_DEV(0, 2, 0), GCFC, reg16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001728
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001729 /* Graphics Core Display Clock */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001730 reg8 = pci_read_config8(PCI_DEV(0, 2, 0), GCFC);
1731 reg8 &= ~((1<<7) | (7<<4));
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001732
1733 if (voltage == VOLTAGE_1_05) {
1734 reg8 |= CDCLK_200MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001735 printk(BIOS_DEBUG, " Display: 200MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001736 } else {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001737 reg8 |= CDCLK_320MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001738 printk(BIOS_DEBUG, " Display: 320MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001739 }
Arthur Heymans70a8e342017-03-09 11:30:23 +01001740 pci_write_config8(PCI_DEV(0, 2, 0), GCFC, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001741
Arthur Heymans70a8e342017-03-09 11:30:23 +01001742 reg8 = pci_read_config8(PCI_DEV(0, 2, 0), GCFC + 1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001743
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001744 reg8 |= (1<<3) | (1<<1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001745 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001746
1747 reg8 |= 0x0f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001748 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001749
1750 /* Ungate core render and display clocks */
1751 reg8 &= 0xf0;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001752 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001753}
1754
1755static void sdram_program_memory_frequency(struct sys_info *sysinfo)
1756{
1757 u32 clkcfg;
1758 u8 reg8;
Julius Wernercd49cce2019-03-05 16:53:33 -08001759 u8 offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001760
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001761 printk(BIOS_DEBUG, "Setting Memory Frequency... ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001762
Stefan Reinauer278534d2008-10-29 04:51:07 +00001763 clkcfg = MCHBAR32(CLKCFG);
1764
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001765 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001766
Arthur Heymans70a8e342017-03-09 11:30:23 +01001767 clkcfg &= ~((1 << 12) | (1 << 7) | (7 << 4));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001768
1769 if (sysinfo->mvco4x) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001770 printk(BIOS_DEBUG, "MVCO 4x, ");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001771 clkcfg &= ~(1 << 12);
1772 }
1773
1774 if (sysinfo->clkcfg_bit7) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001775 printk(BIOS_DEBUG, "second VCO, ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001776
Stefan Reinauer278534d2008-10-29 04:51:07 +00001777 clkcfg |= (1 << 7);
1778 }
1779
1780 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001781 case 400:
1782 clkcfg |= ((1 + offset) << 4); break;
1783 case 533:
1784 clkcfg |= ((2 + offset) << 4); break;
1785 case 667:
1786 clkcfg |= ((3 + offset) << 4); break;
1787 default:
1788 die("Target Memory Frequency Error");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001789 }
1790
1791 if (MCHBAR32(CLKCFG) == clkcfg) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001792 printk(BIOS_DEBUG, "ok (unchanged)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001793 return;
1794 }
1795
1796 MCHBAR32(CLKCFG) = clkcfg;
1797
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001798 /* Make sure the following code is in the
Stefan Reinauer278534d2008-10-29 04:51:07 +00001799 * cache before we execute it.
1800 */
1801 goto cache_code;
1802vco_update:
Elyes HAOUAS32b9a992019-01-21 14:54:31 +01001803 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001804 reg8 &= ~(1 << 7);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +01001805 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001806
Stefan Reinauer278534d2008-10-29 04:51:07 +00001807 clkcfg &= ~(1 << 10);
1808 MCHBAR32(CLKCFG) = clkcfg;
1809 clkcfg |= (1 << 10);
1810 MCHBAR32(CLKCFG) = clkcfg;
1811
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001812 asm volatile (
Stefan Reinauer278534d2008-10-29 04:51:07 +00001813 " movl $0x100, %%ecx\n"
1814 "delay_update:\n"
1815 " nop\n"
1816 " nop\n"
1817 " nop\n"
1818 " nop\n"
1819 " loop delay_update\n"
1820 : /* No outputs */
1821 : /* No inputs */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001822 : "%ecx", "memory"
Stefan Reinauer278534d2008-10-29 04:51:07 +00001823 );
1824
Stefan Reinauer278534d2008-10-29 04:51:07 +00001825 clkcfg &= ~(1 << 10);
1826 MCHBAR32(CLKCFG) = clkcfg;
1827
1828 goto out;
1829cache_code:
1830 goto vco_update;
1831out:
1832
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001833 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", MCHBAR32(CLKCFG));
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001834 printk(BIOS_DEBUG, "ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001835}
1836
1837static void sdram_program_clock_crossing(void)
1838{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001839 int idx = 0;
1840
1841 /**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001842 * We add the indices according to our clocks from CLKCFG.
Stefan Reinauer278534d2008-10-29 04:51:07 +00001843 */
Julius Wernercd49cce2019-03-05 16:53:33 -08001844#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001845 static const u32 data_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001846 0x00100401, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001847 0xffffffff, 0xffffffff, /* nonexistent */
1848 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001849
Stefan Reinauer278534d2008-10-29 04:51:07 +00001850 0x08040120, 0x00000000, /* DDR400 FSB533 */
1851 0x00100401, 0x00000000, /* DDR533 FSB533 */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001852 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001853
1854 0x04020120, 0x00000010, /* DDR400 FSB667 */
1855 0x10040280, 0x00000040, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001856 0x00100401, 0x00000000, /* DDR667 FSB667 */
1857
Martin Roth2ed0aa22016-01-05 20:58:58 -07001858 0xffffffff, 0xffffffff, /* nonexistent */
1859 0xffffffff, 0xffffffff, /* nonexistent */
1860 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001861
Martin Roth2ed0aa22016-01-05 20:58:58 -07001862 0xffffffff, 0xffffffff, /* nonexistent */
1863 0xffffffff, 0xffffffff, /* nonexistent */
1864 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001865 };
1866
1867 static const u32 command_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001868 0x04020208, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001869 0xffffffff, 0xffffffff, /* nonexistent */
1870 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001871
Stefan Reinauer278534d2008-10-29 04:51:07 +00001872 0x00060108, 0x00000000, /* DDR400 FSB533 */
1873 0x04020108, 0x00000000, /* DDR533 FSB533 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001874 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001875
1876 0x00040318, 0x00000000, /* DDR400 FSB667 */
1877 0x04020118, 0x00000000, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001878 0x02010804, 0x00000000, /* DDR667 FSB667 */
1879
Martin Roth2ed0aa22016-01-05 20:58:58 -07001880 0xffffffff, 0xffffffff, /* nonexistent */
1881 0xffffffff, 0xffffffff, /* nonexistent */
1882 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001883
Martin Roth2ed0aa22016-01-05 20:58:58 -07001884 0xffffffff, 0xffffffff, /* nonexistent */
1885 0xffffffff, 0xffffffff, /* nonexistent */
1886 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001887 };
1888
Julius Wernercd49cce2019-03-05 16:53:33 -08001889#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001890 /* i945 G/P */
1891 static const u32 data_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001892 0xffffffff, 0xffffffff, /* nonexistent */
1893 0xffffffff, 0xffffffff, /* nonexistent */
1894 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001895
1896 0x10080201, 0x00000000, /* DDR400 FSB533 */
1897 0x00100401, 0x00000000, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001898 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001899
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 0x04020108, 0x00000000, /* DDR400 FSB800 */
1905 0x00020108, 0x00000000, /* DDR533 FSB800 */
1906 0x00080201, 0x00000000, /* DDR667 FSB800 */
1907
1908 0x00010402, 0x00000000, /* DDR400 FSB1066 */
1909 0x04020108, 0x00000000, /* DDR533 FSB1066 */
1910 0x08040110, 0x00000000, /* DDR667 FSB1066 */
1911 };
1912
1913 static const u32 command_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001914 0xffffffff, 0xffffffff, /* nonexistent */
1915 0xffffffff, 0xffffffff, /* nonexistent */
1916 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001917
1918 0x00010800, 0x00000402, /* DDR400 FSB533 */
1919 0x01000400, 0x00000200, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001920 0x00020904, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001921
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 0x02010804, 0x00000000, /* DDR400 FSB800 */
1927 0x00010402, 0x00000000, /* DDR533 FSB800 */
Arthur Heymans8b6df622016-10-16 10:58:01 +02001928 0x04020130, 0x00000008, /* DDR667 FSB800 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001929
1930 0x00020904, 0x00000000, /* DDR400 FSB1066 */
1931 0x02010804, 0x00000000, /* DDR533 FSB1066 */
1932 0x180601c0, 0x00000020, /* DDR667 FSB1066 */
1933 };
1934#endif
1935
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001936 printk(BIOS_DEBUG, "Programming Clock Crossing...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001937
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001938 printk(BIOS_DEBUG, "MEM=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001939 switch (memclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001940 case 400:
1941 printk(BIOS_DEBUG, "400"); idx += 0; break;
1942 case 533:
1943 printk(BIOS_DEBUG, "533"); idx += 2; break;
1944 case 667:
1945 printk(BIOS_DEBUG, "667"); idx += 4; break;
1946 default:
1947 printk(BIOS_DEBUG, "RSVD %x", memclk()); return;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001948 }
1949
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001950 printk(BIOS_DEBUG, " FSB=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001951 switch (fsbclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001952 case 400:
1953 printk(BIOS_DEBUG, "400"); idx += 0; break;
1954 case 533:
1955 printk(BIOS_DEBUG, "533"); idx += 6; break;
1956 case 667:
1957 printk(BIOS_DEBUG, "667"); idx += 12; break;
1958 case 800:
1959 printk(BIOS_DEBUG, "800"); idx += 18; break;
1960 case 1066:
1961 printk(BIOS_DEBUG, "1066"); idx += 24; break;
1962 default:
1963 printk(BIOS_DEBUG, "RSVD %x\n", fsbclk()); return;
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001964 }
1965
Arthur Heymans70a8e342017-03-09 11:30:23 +01001966 if (command_clock_crossing[idx] == 0xffffffff)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001967 printk(BIOS_DEBUG, "Invalid MEM/FSB combination!\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001968
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001969 MCHBAR32(CCCFT + 0) = command_clock_crossing[idx];
1970 MCHBAR32(CCCFT + 4) = command_clock_crossing[idx + 1];
1971
Stefan Reinauer278534d2008-10-29 04:51:07 +00001972 MCHBAR32(C0DCCFT + 0) = data_clock_crossing[idx];
1973 MCHBAR32(C0DCCFT + 4) = data_clock_crossing[idx + 1];
1974 MCHBAR32(C1DCCFT + 0) = data_clock_crossing[idx];
1975 MCHBAR32(C1DCCFT + 4) = data_clock_crossing[idx + 1];
1976
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001977 printk(BIOS_DEBUG, "... ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001978}
1979
1980static void sdram_disable_fast_dispatch(void)
1981{
1982 u32 reg32;
1983
1984 reg32 = MCHBAR32(FSBPMC3);
1985 reg32 |= (1 << 1);
1986 MCHBAR32(FSBPMC3) = reg32;
1987
1988 reg32 = MCHBAR32(SBTEST);
1989 reg32 |= (3 << 1);
1990 MCHBAR32(SBTEST) = reg32;
1991}
1992
1993static void sdram_pre_jedec_initialization(void)
1994{
1995 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001996
Stefan Reinauer278534d2008-10-29 04:51:07 +00001997 reg32 = MCHBAR32(WCC);
1998 reg32 &= 0x113ff3ff;
1999 reg32 |= (4 << 29) | (3 << 25) | (1 << 10);
2000 MCHBAR32(WCC) = reg32;
2001
2002 MCHBAR32(SMVREFC) |= (1 << 6);
2003
2004 MCHBAR32(MMARB0) &= ~(3 << 17);
2005 MCHBAR32(MMARB0) |= (1 << 21) | (1 << 16);
2006
2007 MCHBAR32(MMARB1) &= ~(7 << 8);
2008 MCHBAR32(MMARB1) |= (3 << 8);
2009
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002010 /* Adaptive Idle Timer Control */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002011 MCHBAR32(C0AIT) = 0x000006c4;
2012 MCHBAR32(C0AIT+4) = 0x871a066d;
2013
2014 MCHBAR32(C1AIT) = 0x000006c4;
2015 MCHBAR32(C1AIT+4) = 0x871a066d;
2016}
2017
2018#define EA_DUALCHANNEL_XOR_BANK_RANK_MODE (0xd4 << 24)
2019#define EA_DUALCHANNEL_XOR_BANK_MODE (0xf4 << 24)
2020#define EA_DUALCHANNEL_BANK_RANK_MODE (0xc2 << 24)
2021#define EA_DUALCHANNEL_BANK_MODE (0xe2 << 24)
2022#define EA_SINGLECHANNEL_XOR_BANK_RANK_MODE (0x91 << 24)
2023#define EA_SINGLECHANNEL_XOR_BANK_MODE (0xb1 << 24)
2024#define EA_SINGLECHANNEL_BANK_RANK_MODE (0x80 << 24)
2025#define EA_SINGLECHANNEL_BANK_MODE (0xa0 << 24)
2026
2027static void sdram_enhanced_addressing_mode(struct sys_info *sysinfo)
2028{
2029 u32 chan0 = 0, chan1 = 0;
2030 int chan0_dualsided, chan1_dualsided, chan0_populated, chan1_populated;
2031
Paul Menzel842dd332020-03-14 10:37:40 +01002032 chan0_populated = (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Stefan Reinauer278534d2008-10-29 04:51:07 +00002033 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED);
Elyes HAOUAS308aeff2017-02-24 12:53:07 +01002034 chan1_populated = (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
2035 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002036 chan0_dualsided = (sysinfo->banksize[1] || sysinfo->banksize[3]);
2037 chan1_dualsided = (sysinfo->banksize[5] || sysinfo->banksize[7]);
2038
2039 if (sdram_capabilities_enhanced_addressing_xor()) {
2040 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002041 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002042 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002043 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002044 chan0 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002045 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002046 chan0 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002047 }
2048 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002049 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002050 chan1 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002051 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002052 chan1 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002053 }
2054 } else {
2055 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002056 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002057 chan0 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002058 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002059 chan0 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002060
Arthur Heymans70a8e342017-03-09 11:30:23 +01002061 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002062 chan1 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002063 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002064 chan1 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002065 }
2066 } else {
2067 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002068 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002069 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002070 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002071 chan0 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002072 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002073 chan0 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002074 }
2075 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002076 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002077 chan1 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002078 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002079 chan1 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002080 }
2081 } else {
2082 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002083 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002084 chan0 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002085 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002086 chan0 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002087
Arthur Heymans70a8e342017-03-09 11:30:23 +01002088 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002089 chan1 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002090 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002091 chan1 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002092 }
2093 }
2094
2095 MCHBAR32(C0DRC1) &= 0x00ffffff;
2096 MCHBAR32(C0DRC1) |= chan0;
2097 MCHBAR32(C1DRC1) &= 0x00ffffff;
2098 MCHBAR32(C1DRC1) |= chan1;
2099}
2100
2101static void sdram_post_jedec_initialization(struct sys_info *sysinfo)
2102{
2103 u32 reg32;
2104
2105 /* Enable Channel XORing for Dual Channel Interleave */
2106 if (sysinfo->interleaved) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002107
Stefan Reinauer278534d2008-10-29 04:51:07 +00002108 reg32 = MCHBAR32(DCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002109 reg32 &= ~(1 << 10);
Stefan Reinauer30140a52009-03-11 16:20:39 +00002110 reg32 |= (1 << 9);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002111 MCHBAR32(DCC) = reg32;
2112 }
2113
2114 /* DRAM mode optimizations */
2115 sdram_enhanced_addressing_mode(sysinfo);
2116
2117 reg32 = MCHBAR32(FSBPMC3);
2118 reg32 &= ~(1 << 1);
2119 MCHBAR32(FSBPMC3) = reg32;
2120
2121 reg32 = MCHBAR32(SBTEST);
2122 reg32 &= ~(1 << 2);
2123 MCHBAR32(SBTEST) = reg32;
2124
2125 reg32 = MCHBAR32(SBOCC);
2126 reg32 &= 0xffbdb6ff;
2127 reg32 |= (0xbdb6 << 8) | (1 << 0);
2128 MCHBAR32(SBOCC) = reg32;
2129}
2130
2131static void sdram_power_management(struct sys_info *sysinfo)
2132{
2133 u8 reg8;
2134 u16 reg16;
2135 u32 reg32;
2136 int integrated_graphics = 1;
2137 int i;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002138
Stefan Reinauer278534d2008-10-29 04:51:07 +00002139 reg32 = MCHBAR32(C0DRT2);
2140 reg32 &= 0xffffff00;
2141 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002142 reg32 |= (1 << 5) | (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002143 MCHBAR32(C0DRT2) = reg32;
2144
2145 reg32 = MCHBAR32(C1DRT2);
2146 reg32 &= 0xffffff00;
2147 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002148 reg32 |= (1 << 5) | (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002149 MCHBAR32(C1DRT2) = reg32;
2150
2151 reg32 = MCHBAR32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002152
2153 reg32 |= (1 << 12) | (1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002154 MCHBAR32(C0DRC1) = reg32;
2155
2156 reg32 = MCHBAR32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002157
2158 reg32 |= (1 << 12) | (1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002159 MCHBAR32(C1DRC1) = reg32;
2160
Julius Wernercd49cce2019-03-05 16:53:33 -08002161 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002162 if (i945_silicon_revision() > 1) {
2163 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2164 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002165
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002166 MCHBAR16(UPMC1) = 0x1010 | peg_bits;
2167 } else {
2168 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2169 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002170
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002171 /* Rev 0 and 1 */
2172 MCHBAR16(UPMC1) = 0x0010 | peg_bits;
2173 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002174 }
2175
2176 reg16 = MCHBAR16(UPMC2);
2177 reg16 &= 0xfc00;
2178 reg16 |= 0x0100;
2179 MCHBAR16(UPMC2) = reg16;
2180
2181 MCHBAR32(UPMC3) = 0x000f06ff;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002182
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002183 for (i = 0; i < 5; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002184 MCHBAR32(UPMC3) &= ~(1 << 16);
2185 MCHBAR32(UPMC3) |= (1 << 16);
2186 }
2187
2188 MCHBAR32(GIPMC1) = 0x8000000c;
2189
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002190 reg16 = MCHBAR16(CPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002191 reg16 &= ~(7 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002192 if (i945_silicon_revision() > 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002193 reg16 |= (6 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002194 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002195 reg16 |= (4 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002196 MCHBAR16(CPCTL) = reg16;
2197
Stefan Reinauer30140a52009-03-11 16:20:39 +00002198#if 0
Stefan Reinauer278534d2008-10-29 04:51:07 +00002199 if ((MCHBAR32(ECO) & (1 << 16)) != 0) {
Stefan Reinauer30140a52009-03-11 16:20:39 +00002200#else
2201 if (i945_silicon_revision() != 0) {
2202#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002203 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002204 case 667:
2205 MCHBAR32(HGIPMC2) = 0x0d590d59; break;
2206 case 533:
2207 MCHBAR32(HGIPMC2) = 0x155b155b; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002208 }
2209 } else {
2210 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002211 case 667:
2212 MCHBAR32(HGIPMC2) = 0x09c409c4; break;
2213 case 533:
2214 MCHBAR32(HGIPMC2) = 0x0fa00fa0; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002215 }
2216 }
2217
2218 MCHBAR32(FSBPMC1) = 0x8000000c;
2219
2220 reg32 = MCHBAR32(C2C3TT);
2221 reg32 &= 0xffff0000;
2222 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002223 case 667:
2224 reg32 |= 0x0600; break;
2225 case 533:
2226 reg32 |= 0x0480; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002227 }
2228 MCHBAR32(C2C3TT) = reg32;
2229
2230 reg32 = MCHBAR32(C3C4TT);
2231 reg32 &= 0xffff0000;
2232 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002233 case 667:
2234 reg32 |= 0x0b80; break;
2235 case 533:
2236 reg32 |= 0x0980; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002237 }
2238 MCHBAR32(C3C4TT) = reg32;
2239
Arthur Heymans70a8e342017-03-09 11:30:23 +01002240 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002241 MCHBAR32(ECO) &= ~(1 << 16);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002242 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002243 MCHBAR32(ECO) |= (1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002244
2245#if 0
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002246
Arthur Heymans70a8e342017-03-09 11:30:23 +01002247 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002248 MCHBAR32(FSBPMC3) &= ~(1 << 29);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002249 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002250 MCHBAR32(FSBPMC3) |= (1 << 29);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002251#endif
2252 MCHBAR32(FSBPMC3) &= ~(1 << 29);
2253
2254 MCHBAR32(FSBPMC3) |= (1 << 21);
2255
2256 MCHBAR32(FSBPMC3) &= ~(1 << 19);
2257
2258 MCHBAR32(FSBPMC3) &= ~(1 << 13);
2259
2260 reg32 = MCHBAR32(FSBPMC4);
2261 reg32 &= ~(3 << 24);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002262 reg32 |= (2 << 24);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002263 MCHBAR32(FSBPMC4) = reg32;
2264
2265 MCHBAR32(FSBPMC4) |= (1 << 21);
2266
2267 MCHBAR32(FSBPMC4) |= (1 << 5);
2268
Arthur Heymans70a8e342017-03-09 11:30:23 +01002269 if ((i945_silicon_revision() < 2)) { /* || cpuid() = 0x6e8 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002270 /* stepping 0 and 1 or CPUID 6e8 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002271 MCHBAR32(FSBPMC4) &= ~(1 << 4);
2272 } else {
Stefan Reinauer30140a52009-03-11 16:20:39 +00002273 MCHBAR32(FSBPMC4) |= (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002274 }
2275
Arthur Heymans70a8e342017-03-09 11:30:23 +01002276 reg8 = pci_read_config8(PCI_DEV(0, 0x0, 0), 0xfc);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002277 reg8 |= (1 << 4);
2278 pci_write_config8(PCI_DEV(0, 0x0, 0), 0xfc, reg8);
2279
Arthur Heymans70a8e342017-03-09 11:30:23 +01002280 reg8 = pci_read_config8(PCI_DEV(0, 0x2, 0), 0xc1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002281 reg8 |= (1 << 2);
2282 pci_write_config8(PCI_DEV(0, 0x2, 0), 0xc1, reg8);
2283
Stefan Reinauerde3206a2010-02-22 06:09:43 +00002284#ifdef C2_SELF_REFRESH_DISABLE
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002285
Stefan Reinauer278534d2008-10-29 04:51:07 +00002286 if (integrated_graphics) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002287 printk(BIOS_DEBUG, "C2 self-refresh with IGD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002288 MCHBAR16(MIPMC4) = 0x0468;
2289 MCHBAR16(MIPMC5) = 0x046c;
2290 MCHBAR16(MIPMC6) = 0x046c;
2291 } else {
2292 MCHBAR16(MIPMC4) = 0x6468;
2293 MCHBAR16(MIPMC5) = 0x646c;
2294 MCHBAR16(MIPMC6) = 0x646c;
2295 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002296#else
2297 if (integrated_graphics) {
2298 MCHBAR16(MIPMC4) = 0x04f8;
2299 MCHBAR16(MIPMC5) = 0x04fc;
2300 MCHBAR16(MIPMC6) = 0x04fc;
2301 } else {
2302 MCHBAR16(MIPMC4) = 0x64f8;
2303 MCHBAR16(MIPMC5) = 0x64fc;
2304 MCHBAR16(MIPMC6) = 0x64fc;
2305 }
2306
2307#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002308
2309 reg32 = MCHBAR32(PMCFG);
2310 reg32 &= ~(3 << 17);
2311 reg32 |= (2 << 17);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002312 MCHBAR32(PMCFG) = reg32;
2313
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002314 MCHBAR32(PMCFG) |= (1 << 4);
2315
Stefan Reinauer278534d2008-10-29 04:51:07 +00002316 reg32 = MCHBAR32(0xc30);
2317 reg32 &= 0xffffff00;
2318 reg32 |= 0x01;
2319 MCHBAR32(0xc30) = reg32;
2320
2321 MCHBAR32(0xb18) &= ~(1 << 21);
2322}
2323
2324static void sdram_thermal_management(void)
2325{
Stefan Reinauer278534d2008-10-29 04:51:07 +00002326
Stefan Reinauer278534d2008-10-29 04:51:07 +00002327 MCHBAR8(TCO1) = 0x00;
2328 MCHBAR8(TCO0) = 0x00;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002329
2330 /* The Thermal Sensors for DIMMs at 0x50, 0x52 are at I2C addr
2331 * 0x30/0x32.
2332 */
2333
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002334 /* TODO This is not implemented yet. Volunteers? */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002335}
2336
2337static void sdram_save_receive_enable(void)
2338{
2339 int i;
2340 u32 reg32;
2341 u8 values[4];
2342
2343 /* The following values are stored to an unused CMOS
2344 * area and restored instead of recalculated in case
2345 * of an S3 resume.
2346 *
Arthur Heymans70a8e342017-03-09 11:30:23 +01002347 * C0WL0REOST [7:0] -> 8 bit
2348 * C1WL0REOST [7:0] -> 8 bit
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002349 * RCVENMT [11:8] [3:0] -> 8 bit
2350 * C0DRT1 [27:24] -> 4 bit
2351 * C1DRT1 [27:24] -> 4 bit
2352 */
2353
2354 values[0] = MCHBAR8(C0WL0REOST);
2355 values[1] = MCHBAR8(C1WL0REOST);
2356
2357 reg32 = MCHBAR32(RCVENMT);
2358 values[2] = (u8)((reg32 >> (8 - 4)) & 0xf0) | (reg32 & 0x0f);
2359
2360 reg32 = MCHBAR32(C0DRT1);
2361 values[3] = (reg32 >> 24) & 0x0f;
2362 reg32 = MCHBAR32(C1DRT1);
2363 values[3] |= (reg32 >> (24 - 4)) & 0xf0;
2364
2365 /* coreboot only uses bytes 0 - 127 for its CMOS values so far
Edwin Beasanteb50c7d2010-07-06 21:05:04 +00002366 * so we grab bytes 128 - 131 to save the receive enable values
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002367 */
2368
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002369 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002370 cmos_write(values[i], 128 + i);
2371}
2372
2373static void sdram_recover_receive_enable(void)
2374{
2375 int i;
2376 u32 reg32;
2377 u8 values[4];
2378
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002379 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002380 values[i] = cmos_read(128 + i);
2381
2382 MCHBAR8(C0WL0REOST) = values[0];
2383 MCHBAR8(C1WL0REOST) = values[1];
2384
2385 reg32 = MCHBAR32(RCVENMT);
2386 reg32 &= ~((0x0f << 8) | (0x0f << 0));
2387 reg32 |= ((u32)(values[2] & 0xf0) << (8 - 4)) | (values[2] & 0x0f);
2388 MCHBAR32(RCVENMT) = reg32;
2389
2390 reg32 = MCHBAR32(C0DRT1) & ~(0x0f << 24);
2391 reg32 |= (u32)(values[3] & 0x0f) << 24;
2392 MCHBAR32(C0DRT1) = reg32;
2393
2394 reg32 = MCHBAR32(C1DRT1) & ~(0x0f << 24);
2395 reg32 |= (u32)(values[3] & 0xf0) << (24 - 4);
2396 MCHBAR32(C1DRT1) = reg32;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002397}
2398
Stefan Reinauer278534d2008-10-29 04:51:07 +00002399static void sdram_program_receive_enable(struct sys_info *sysinfo)
2400{
2401 MCHBAR32(REPC) |= (1 << 0);
2402
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002403 /* Program Receive Enable Timings */
2404 if (sysinfo->boot_path == BOOT_PATH_RESUME) {
2405 sdram_recover_receive_enable();
2406 } else {
2407 receive_enable_adjust(sysinfo);
2408 sdram_save_receive_enable();
2409 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002410
2411 MCHBAR32(C0DRC1) |= (1 << 6);
2412 MCHBAR32(C1DRC1) |= (1 << 6);
2413 MCHBAR32(C0DRC1) &= ~(1 << 6);
2414 MCHBAR32(C1DRC1) &= ~(1 << 6);
2415
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002416 MCHBAR32(MIPMC3) |= (0x0f << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002417}
2418
2419/**
2420 * @brief Enable On-Die Termination for DDR2.
2421 *
2422 */
2423
2424static void sdram_on_die_termination(struct sys_info *sysinfo)
2425{
2426 static const u32 odt[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002427 0x00024911, 0xe0010000,
2428 0x00049211, 0xe0020000,
2429 0x0006db11, 0xe0030000,
Stefan Reinauer278534d2008-10-29 04:51:07 +00002430 };
2431
2432 u32 reg32;
2433 int cas;
2434
2435 reg32 = MCHBAR32(ODTC);
2436 reg32 &= ~(3 << 16);
2437 reg32 |= (1 << 14) | (1 << 6) | (2 << 16);
2438 MCHBAR32(ODTC) = reg32;
2439
Arthur Heymans70a8e342017-03-09 11:30:23 +01002440 if (!(sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED &&
2441 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)) {
Elyes HAOUAS38424982016-08-21 12:01:04 +02002442 printk(BIOS_DEBUG, "one dimm per channel config..\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002443
Stefan Reinauer278534d2008-10-29 04:51:07 +00002444 reg32 = MCHBAR32(C0ODT);
2445 reg32 &= ~(7 << 28);
2446 MCHBAR32(C0ODT) = reg32;
2447 reg32 = MCHBAR32(C1ODT);
2448 reg32 &= ~(7 << 28);
2449 MCHBAR32(C1ODT) = reg32;
2450 }
2451
2452 cas = sysinfo->cas;
2453
2454 reg32 = MCHBAR32(C0ODT) & 0xfff00000;
2455 reg32 |= odt[(cas-3) * 2];
2456 MCHBAR32(C0ODT) = reg32;
2457
2458 reg32 = MCHBAR32(C1ODT) & 0xfff00000;
2459 reg32 |= odt[(cas-3) * 2];
2460 MCHBAR32(C1ODT) = reg32;
2461
2462 reg32 = MCHBAR32(C0ODT + 4) & 0x1fc8ffff;
2463 reg32 |= odt[((cas-3) * 2) + 1];
2464 MCHBAR32(C0ODT + 4) = reg32;
2465
2466 reg32 = MCHBAR32(C1ODT + 4) & 0x1fc8ffff;
2467 reg32 |= odt[((cas-3) * 2) + 1];
2468 MCHBAR32(C1ODT + 4) = reg32;
2469}
2470
2471/**
2472 * @brief Enable clocks to populated sockets
2473 */
2474
2475static void sdram_enable_memory_clocks(struct sys_info *sysinfo)
2476{
2477 u8 clocks[2] = { 0, 0 };
2478
Julius Wernercd49cce2019-03-05 16:53:33 -08002479#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002480#define CLOCKS_WIDTH 2
Julius Wernercd49cce2019-03-05 16:53:33 -08002481#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002482#define CLOCKS_WIDTH 3
2483#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002484 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002485 clocks[0] |= (1 << CLOCKS_WIDTH)-1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002486
2487 if (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002488 clocks[0] |= ((1 << CLOCKS_WIDTH)-1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002489
2490 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002491 clocks[1] |= (1 << CLOCKS_WIDTH)-1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002492
2493 if (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002494 clocks[1] |= ((1 << CLOCKS_WIDTH)-1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002495
Julius Wernercd49cce2019-03-05 16:53:33 -08002496#if CONFIG(OVERRIDE_CLOCK_DISABLE)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002497 /* Usually system firmware turns off system memory clock signals
2498 * to unused SO-DIMM slots to reduce EMI and power consumption.
2499 * However, the Kontron 986LCD-M does not like unused clock
2500 * signals to be disabled.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002501 */
2502
2503 clocks[0] = 0xf; /* force all clock gate pairs to enable */
2504 clocks[1] = 0xf; /* force all clock gate pairs to enable */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002505#endif
2506
2507 MCHBAR8(C0DCLKDIS) = clocks[0];
2508 MCHBAR8(C1DCLKDIS) = clocks[1];
2509}
2510
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002511#define RTT_ODT_NONE 0
Arthur Heymans70a8e342017-03-09 11:30:23 +01002512#define RTT_ODT_50_OHM ((1 << 9) | (1 << 5))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002513#define RTT_ODT_75_OHM (1 << 5)
2514#define RTT_ODT_150_OHM (1 << 9)
2515
Arthur Heymans70a8e342017-03-09 11:30:23 +01002516#define EMRS_OCD_DEFAULT ((1 << 12) | (1 << 11) | (1 << 10))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002517
2518#define MRS_CAS_3 (3 << 7)
2519#define MRS_CAS_4 (4 << 7)
2520#define MRS_CAS_5 (5 << 7)
2521
2522#define MRS_TWR_3 (2 << 12)
2523#define MRS_TWR_4 (3 << 12)
2524#define MRS_TWR_5 (4 << 12)
2525
2526#define MRS_BT (1 << 6)
2527
2528#define MRS_BL4 (2 << 3)
2529#define MRS_BL8 (3 << 3)
2530
2531static void sdram_jedec_enable(struct sys_info *sysinfo)
2532{
2533 int i, nonzero;
2534 u32 bankaddr = 0, tmpaddr, mrsaddr = 0;
2535
2536 for (i = 0, nonzero = -1; i < 8; i++) {
Elyes HAOUAS01912202019-01-19 16:36:38 +01002537 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002538 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002539
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002540 printk(BIOS_DEBUG, "jedec enable sequence: bank %d\n", i);
Elyes HAOUAS01912202019-01-19 16:36:38 +01002541
2542 if (nonzero != -1) {
2543 if (sysinfo->interleaved && nonzero < 4 && i >= 4) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002544 bankaddr = 0x40;
Elyes HAOUAS01912202019-01-19 16:36:38 +01002545 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002546 printk(BIOS_DEBUG, "bankaddr from bank size of rank %d\n", nonzero);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002547 bankaddr += sysinfo->banksize[nonzero] <<
2548 (sysinfo->interleaved ? 26 : 25);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002549 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002550 }
2551
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002552 /* We have a bank with a non-zero size.. Remember it
Stefan Reinauer278534d2008-10-29 04:51:07 +00002553 * for the next offset we have to calculate
2554 */
2555 nonzero = i;
2556
2557 /* Get CAS latency set up */
2558 switch (sysinfo->cas) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002559 case 5:
2560 mrsaddr = MRS_CAS_5; break;
2561 case 4:
2562 mrsaddr = MRS_CAS_4; break;
2563 case 3:
2564 mrsaddr = MRS_CAS_3; break;
2565 default:
2566 die("Jedec Error (CAS).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002567 }
2568
2569 /* Get tWR set */
2570 switch (sysinfo->twr) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002571 case 5:
2572 mrsaddr |= MRS_TWR_5; break;
2573 case 4:
2574 mrsaddr |= MRS_TWR_4; break;
2575 case 3:
2576 mrsaddr |= MRS_TWR_3; break;
2577 default:
2578 die("Jedec Error (tWR).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002579 }
2580
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002581 /* Set "Burst Type" */
2582 mrsaddr |= MRS_BT;
2583
Stefan Reinauer278534d2008-10-29 04:51:07 +00002584 /* Interleaved */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002585 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002586 mrsaddr = mrsaddr << 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002587
2588 /* Only burst length 8 supported */
2589 mrsaddr |= MRS_BL8;
2590
2591 /* Apply NOP */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002592 PRINTK_DEBUG("Apply NOP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002593 do_ram_command(RAM_COMMAND_NOP);
2594 ram_read32(bankaddr);
2595
2596 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002597 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002598 do_ram_command(RAM_COMMAND_PRECHARGE);
2599 ram_read32(bankaddr);
2600
2601 /* Extended Mode Register Set (2) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002602 PRINTK_DEBUG("Extended Mode Register Set(2)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002603 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_2);
2604 ram_read32(bankaddr);
2605
2606 /* Extended Mode Register Set (3) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002607 PRINTK_DEBUG("Extended Mode Register Set(3)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002608 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_3);
2609 ram_read32(bankaddr);
2610
2611 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002612 PRINTK_DEBUG("Extended Mode Register Set\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002613 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2614 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002615 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002616 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002617 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002618 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002619 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002620 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002621 ram_read32(tmpaddr);
2622
2623 /* Mode Register Set: Reset DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002624 PRINTK_DEBUG("MRS: Reset DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002625 do_ram_command(RAM_COMMAND_MRS);
2626 tmpaddr = bankaddr;
2627 tmpaddr |= mrsaddr;
2628 /* Set DLL reset bit */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002629 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002630 tmpaddr |= (1 << 12);
2631 else
2632 tmpaddr |= (1 << 11);
2633 ram_read32(tmpaddr);
2634
2635 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002636 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002637 do_ram_command(RAM_COMMAND_PRECHARGE);
2638 ram_read32(bankaddr);
2639
2640 /* CAS before RAS Refresh */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002641 PRINTK_DEBUG("CAS before RAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002642 do_ram_command(RAM_COMMAND_CBR);
2643
2644 /* CBR wants two READs */
2645 ram_read32(bankaddr);
2646 ram_read32(bankaddr);
2647
2648 /* Mode Register Set: Enable DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002649 PRINTK_DEBUG("MRS: Enable DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002650 do_ram_command(RAM_COMMAND_MRS);
2651
2652 tmpaddr = bankaddr;
2653 tmpaddr |= mrsaddr;
2654 ram_read32(tmpaddr);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002655
Stefan Reinauer278534d2008-10-29 04:51:07 +00002656 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002657 PRINTK_DEBUG("Extended Mode Register Set: ODT/OCD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002658 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002659
Stefan Reinauer278534d2008-10-29 04:51:07 +00002660 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002661 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002662 tmpaddr |= RTT_ODT_75_OHM | EMRS_OCD_DEFAULT;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002663 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002664 tmpaddr |= ((RTT_ODT_150_OHM | EMRS_OCD_DEFAULT) << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002665 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002666 tmpaddr |= RTT_ODT_150_OHM | EMRS_OCD_DEFAULT;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002667 ram_read32(tmpaddr);
2668
2669 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002670 PRINTK_DEBUG("Extended Mode Register Set: OCD Exit\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002671 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2672
2673 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002674 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002675 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002676 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002677 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002678 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002679 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002680 ram_read32(tmpaddr);
2681 }
2682}
2683
2684static void sdram_init_complete(void)
2685{
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002686 PRINTK_DEBUG("Normal Operation\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002687 do_ram_command(RAM_COMMAND_NORMAL);
2688}
2689
2690static void sdram_setup_processor_side(void)
2691{
2692 if (i945_silicon_revision() == 0)
2693 MCHBAR32(FSBPMC3) |= (1 << 2);
2694
2695 MCHBAR8(0xb00) |= 1;
2696
2697 if (i945_silicon_revision() == 0)
2698 MCHBAR32(SLPCTL) |= (1 << 8);
2699}
2700
Stefan Reinauer278534d2008-10-29 04:51:07 +00002701/**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002702 * @param boot_path: 0 = normal, 1 = reset, 2 = resume from s3
Martin Rothf4cb4122015-01-06 10:27:39 -07002703 * @param spd_addresses pointer to a list of SPD addresses
Stefan Reinauer278534d2008-10-29 04:51:07 +00002704 */
Sven Schnelle541269b2011-02-21 09:39:17 +00002705void sdram_initialize(int boot_path, const u8 *spd_addresses)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002706{
2707 struct sys_info sysinfo;
Arthur Heymans0ab49042017-02-06 22:40:14 +01002708 u8 reg8;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002709
Patrick Georgi771328f2015-07-13 19:24:07 +02002710 timestamp_add_now(TS_BEFORE_INITRAM);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002711 printk(BIOS_DEBUG, "Setting up RAM controller.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002712
2713 memset(&sysinfo, 0, sizeof(sysinfo));
2714
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002715 sysinfo.boot_path = boot_path;
Sven Schnelle541269b2011-02-21 09:39:17 +00002716 sysinfo.spd_addresses = spd_addresses;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002717
Stefan Reinauer278534d2008-10-29 04:51:07 +00002718 /* Look at the type of DIMMs and verify all DIMMs are x8 or x16 width */
2719 sdram_get_dram_configuration(&sysinfo);
2720
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002721 /* If error, do cold boot */
2722 sdram_detect_errors(&sysinfo);
2723
Stefan Reinauer278534d2008-10-29 04:51:07 +00002724 /* Program PLL settings */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002725 sdram_program_pll_settings(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002726
Arthur Heymans18537812016-12-28 21:20:45 +01002727 /*
2728 * Program Graphics Frequency
2729 * Set core display and render clock on 945GC to the max
2730 */
Julius Wernercd49cce2019-03-05 16:53:33 -08002731 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM))
Arthur Heymans18537812016-12-28 21:20:45 +01002732 sdram_program_graphics_frequency(&sysinfo);
2733 else
2734 pci_write_config16(PCI_DEV(0, 2, 0), GCFC, 0x0534);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002735
2736 /* Program System Memory Frequency */
2737 sdram_program_memory_frequency(&sysinfo);
2738
2739 /* Determine Mode of Operation (Interleaved etc) */
2740 sdram_set_channel_mode(&sysinfo);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002741
Stefan Reinauer278534d2008-10-29 04:51:07 +00002742 /* Program Clock Crossing values */
2743 sdram_program_clock_crossing();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002744
Stefan Reinauer278534d2008-10-29 04:51:07 +00002745 /* Disable fast dispatch */
2746 sdram_disable_fast_dispatch();
2747
2748 /* Enable WIODLL Power Down in ACPI states */
2749 MCHBAR32(C0DMC) |= (1 << 24);
2750 MCHBAR32(C1DMC) |= (1 << 24);
2751
2752 /* Program DRAM Row Boundary/Attribute Registers */
2753
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002754 /* program row size DRB and set TOLUD */
2755 sdram_program_row_boundaries(&sysinfo);
2756
2757 /* program page size DRA */
2758 sdram_set_row_attributes(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002759
2760 /* Program CxBNKARC */
2761 sdram_set_bank_architecture(&sysinfo);
2762
2763 /* Program DRAM Timing and Control registers based on SPD */
2764 sdram_set_timing_and_control(&sysinfo);
2765
2766 /* On-Die Termination Adjustment */
2767 sdram_on_die_termination(&sysinfo);
2768
2769 /* Pre Jedec Initialization */
2770 sdram_pre_jedec_initialization();
2771
2772 /* Perform System Memory IO Initialization */
2773 sdram_initialize_system_memory_io(&sysinfo);
2774
2775 /* Perform System Memory IO Buffer Enable */
2776 sdram_enable_system_memory_io(&sysinfo);
2777
2778 /* Enable System Memory Clocks */
2779 sdram_enable_memory_clocks(&sysinfo);
2780
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002781 if (boot_path == BOOT_PATH_NORMAL) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002782 /* Jedec Initialization sequence */
2783 sdram_jedec_enable(&sysinfo);
2784 }
2785
2786 /* Program Power Management Registers */
2787 sdram_power_management(&sysinfo);
2788
2789 /* Post Jedec Init */
2790 sdram_post_jedec_initialization(&sysinfo);
2791
2792 /* Program DRAM Throttling */
2793 sdram_thermal_management();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002794
Stefan Reinauer278534d2008-10-29 04:51:07 +00002795 /* Normal Operations */
Stefan Reinaueraca6ec62009-10-26 17:12:21 +00002796 sdram_init_complete();
Stefan Reinauer278534d2008-10-29 04:51:07 +00002797
2798 /* Program Receive Enable Timings */
2799 sdram_program_receive_enable(&sysinfo);
2800
2801 /* Enable Periodic RCOMP */
2802 sdram_enable_rcomp();
2803
2804 /* Tell ICH7 that we're done */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +01002805 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002806 reg8 &= ~(1 << 7);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +01002807 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002808
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002809 printk(BIOS_DEBUG, "RAM initialization finished.\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002810
Stefan Reinauer278534d2008-10-29 04:51:07 +00002811 sdram_setup_processor_side();
Patrick Georgi771328f2015-07-13 19:24:07 +02002812 timestamp_add_now(TS_AFTER_INITRAM);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002813}