blob: 51ee65d7dfbcbb0d094dcc963696f1a2a40da422 [file] [log] [blame]
Stefan Reinauer278534d2008-10-29 04:51:07 +00001/*
2 * This file is part of the coreboot project.
3 *
Stefan Reinauer278534d2008-10-29 04:51:07 +00004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 2 of the License.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
Stefan Reinauer278534d2008-10-29 04:51:07 +000013 */
14
Patrick Georgid0835952010-10-05 09:07:10 +000015#include <console/console.h>
Kyösti Mälkki7fbed222019-07-11 08:14:07 +030016#include <delay.h>
Arthur Heymans885c2892016-10-03 17:16:48 +020017#include <device/pci_def.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020018#include <device/pci_ops.h>
Elyes HAOUAS420d7e02019-04-21 18:39:34 +020019#include <cf9_reset.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020020#include <device/mmio.h>
Arthur Heymans885c2892016-10-03 17:16:48 +020021#include <device/device.h>
Julius Werner7a8a4ab2015-05-22 16:26:40 -070022#include <lib.h>
Edwin Beasanteb50c7d2010-07-06 21:05:04 +000023#include <pc80/mc146818rtc.h>
Stefan Reinauer278534d2008-10-29 04:51:07 +000024#include <spd.h>
Patrick Georgid0835952010-10-05 09:07:10 +000025#include <string.h>
Stefan Reinauer278534d2008-10-29 04:51:07 +000026#include "raminit.h"
27#include "i945.h"
Arthur Heymans885c2892016-10-03 17:16:48 +020028#include "chip.h"
Arthur Heymans0ab49042017-02-06 22:40:14 +010029#include <device/dram/ddr2.h>
Patrick Georgi771328f2015-07-13 19:24:07 +020030#include <timestamp.h>
Rudolf Marekc4369532010-12-13 19:59:13 +000031
Stefan Reinauer278534d2008-10-29 04:51:07 +000032/* Debugging macros. */
Julius Wernercd49cce2019-03-05 16:53:33 -080033#if CONFIG(DEBUG_RAM_SETUP)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000034#define PRINTK_DEBUG(x...) printk(BIOS_DEBUG, x)
Stefan Reinauer278534d2008-10-29 04:51:07 +000035#else
36#define PRINTK_DEBUG(x...)
37#endif
38
Stefan Reinauer278534d2008-10-29 04:51:07 +000039#define RAM_INITIALIZATION_COMPLETE (1 << 19)
40
41#define RAM_COMMAND_SELF_REFRESH (0x0 << 16)
42#define RAM_COMMAND_NOP (0x1 << 16)
43#define RAM_COMMAND_PRECHARGE (0x2 << 16)
44#define RAM_COMMAND_MRS (0x3 << 16)
45#define RAM_COMMAND_EMRS (0x4 << 16)
46#define RAM_COMMAND_CBR (0x6 << 16)
47#define RAM_COMMAND_NORMAL (0x7 << 16)
48
49#define RAM_EMRS_1 (0x0 << 21)
50#define RAM_EMRS_2 (0x1 << 21)
51#define RAM_EMRS_3 (0x2 << 21)
52
Arthur Heymans885c2892016-10-03 17:16:48 +020053#define DEFAULT_PCI_MMIO_SIZE 768
Sven Schnelle541269b2011-02-21 09:39:17 +000054static int get_dimm_spd_address(struct sys_info *sysinfo, int device)
55{
56 if (sysinfo->spd_addresses)
57 return sysinfo->spd_addresses[device];
58 else
59 return DIMM0 + device;
60
61}
62
Stefan Reinauerbc8613e2010-08-25 18:35:42 +000063static __attribute__((noinline)) void do_ram_command(u32 command)
Stefan Reinauer278534d2008-10-29 04:51:07 +000064{
65 u32 reg32;
66
67 reg32 = MCHBAR32(DCC);
Arthur Heymans70a8e342017-03-09 11:30:23 +010068 reg32 &= ~((3<<21) | (1<<20) | (1<<19) | (7 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +000069 reg32 |= command;
70
71 /* Also set Init Complete */
72 if (command == RAM_COMMAND_NORMAL)
73 reg32 |= RAM_INITIALIZATION_COMPLETE;
74
75 PRINTK_DEBUG(" Sending RAM command 0x%08x", reg32);
76
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +010077 MCHBAR32(DCC) = reg32; /* This is the actual magic */
Stefan Reinauer278534d2008-10-29 04:51:07 +000078
Stefan Reinauer779b3e32008-11-10 15:43:37 +000079 PRINTK_DEBUG("...done\n");
Stefan Reinauerd058ad12010-08-26 12:43:58 +000080
81 udelay(1);
Stefan Reinauer278534d2008-10-29 04:51:07 +000082}
83
Stefan Reinauer278534d2008-10-29 04:51:07 +000084static void ram_read32(u32 offset)
85{
Elyes HAOUAS15279a92016-07-28 21:05:26 +020086 PRINTK_DEBUG(" RAM read: %08x\n", offset);
Stefan Reinauer278534d2008-10-29 04:51:07 +000087
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080088 read32((void *)offset);
Stefan Reinauer278534d2008-10-29 04:51:07 +000089}
90
Stefan Reinauer3c0bfaf2010-12-27 11:34:57 +000091void sdram_dump_mchbar_registers(void)
Stefan Reinauer278534d2008-10-29 04:51:07 +000092{
93 int i;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000094 printk(BIOS_DEBUG, "Dumping MCHBAR Registers\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +000095
Arthur Heymans70a8e342017-03-09 11:30:23 +010096 for (i = 0; i < 0xfff; i += 4) {
Stefan Reinauer278534d2008-10-29 04:51:07 +000097 if (MCHBAR32(i) == 0)
98 continue;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000099 printk(BIOS_DEBUG, "0x%04x: 0x%08x\n", i, MCHBAR32(i));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000100 }
101}
Stefan Reinauer278534d2008-10-29 04:51:07 +0000102
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000103static int memclk(void)
104{
Julius Wernercd49cce2019-03-05 16:53:33 -0800105 int offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200106
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000107 switch (((MCHBAR32(CLKCFG) >> 4) & 7) - offset) {
108 case 1: return 400;
109 case 2: return 533;
110 case 3: return 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100111 default:
Elyes HAOUAS3cd43272020-03-05 22:01:17 +0100112 printk(BIOS_DEBUG, "%s: unknown register value %x\n", __func__,
Arthur Heymans70a8e342017-03-09 11:30:23 +0100113 ((MCHBAR32(CLKCFG) >> 4) & 7) - offset);
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000114 }
115 return -1;
116}
117
Peter Stuge76d91432010-10-01 10:02:33 +0000118static u16 fsbclk(void)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000119{
Julius Wernercd49cce2019-03-05 16:53:33 -0800120 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200121 switch (MCHBAR32(CLKCFG) & 7) {
122 case 0: return 400;
123 case 1: return 533;
124 case 3: return 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100125 default:
Elyes HAOUAS3cd43272020-03-05 22:01:17 +0100126 printk(BIOS_DEBUG, "%s: unknown register value %x\n", __func__,
Arthur Heymans70a8e342017-03-09 11:30:23 +0100127 MCHBAR32(CLKCFG) & 7);
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200128 }
129 return 0xffff;
Julius Wernercd49cce2019-03-05 16:53:33 -0800130 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200131 switch (MCHBAR32(CLKCFG) & 7) {
132 case 0: return 1066;
133 case 1: return 533;
134 case 2: return 800;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100135 default:
Elyes HAOUAS3cd43272020-03-05 22:01:17 +0100136 printk(BIOS_DEBUG, "%s: unknown register value %x\n", __func__,
Arthur Heymans70a8e342017-03-09 11:30:23 +0100137 MCHBAR32(CLKCFG) & 7);
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200138 }
139 return 0xffff;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000140 }
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000141}
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000142
Stefan Reinauer278534d2008-10-29 04:51:07 +0000143static int sdram_capabilities_max_supported_memory_frequency(void)
144{
145 u32 reg32;
146
Patrick Georgi77d66832010-10-01 08:02:45 +0000147#if CONFIG_MAXIMUM_SUPPORTED_FREQUENCY
148 return CONFIG_MAXIMUM_SUPPORTED_FREQUENCY;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000149#endif
150
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000151 reg32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000152 reg32 &= (7 << 0);
153
154 switch (reg32) {
155 case 4: return 400;
156 case 3: return 533;
157 case 2: return 667;
158 }
159 /* Newer revisions of this chipset rather support faster memory clocks,
160 * so if it's a reserved value, return the fastest memory clock that we
161 * know of and can handle
162 */
163 return 667;
164}
165
166/**
167 * @brief determine whether chipset is capable of dual channel interleaved mode
168 *
169 * @return 1 if interleaving is supported, 0 otherwise
170 */
171static int sdram_capabilities_interleave(void)
172{
173 u32 reg32;
174
Arthur Heymans70a8e342017-03-09 11:30:23 +0100175 reg32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000176 reg32 >>= 25;
177 reg32 &= 1;
178
179 return (!reg32);
180}
181
182/**
183 * @brief determine whether chipset is capable of two memory channels
184 *
185 * @return 1 if dual channel operation is supported, 0 otherwise
186 */
187static int sdram_capabilities_dual_channel(void)
188{
189 u32 reg32;
190
Arthur Heymans70a8e342017-03-09 11:30:23 +0100191 reg32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000192 reg32 >>= 24;
193 reg32 &= 1;
194
195 return (!reg32);
196}
197
198static int sdram_capabilities_enhanced_addressing_xor(void)
199{
200 u8 reg8;
201
202 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
203 reg8 &= (1 << 7);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000204
Stefan Reinauer278534d2008-10-29 04:51:07 +0000205 return (!reg8);
206}
207
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100208/* TODO check if we ever need this function */
Stefan Reinauer53b0ea42010-03-22 11:50:52 +0000209#if 0
Stefan Reinauer278534d2008-10-29 04:51:07 +0000210static int sdram_capabilities_MEM4G_disable(void)
211{
212 u8 reg8;
213
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000214 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000215 reg8 &= (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000216
Stefan Reinauer278534d2008-10-29 04:51:07 +0000217 return (reg8 != 0);
218}
Stefan Reinauer53b0ea42010-03-22 11:50:52 +0000219#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +0000220
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000221#define GFX_FREQUENCY_CAP_166MHZ 0x04
222#define GFX_FREQUENCY_CAP_200MHZ 0x03
223#define GFX_FREQUENCY_CAP_250MHZ 0x02
224#define GFX_FREQUENCY_CAP_ALL 0x00
225
226static int sdram_capabilities_core_frequencies(void)
227{
228 u8 reg8;
229
230 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
231 reg8 &= (1 << 3) | (1 << 2) | (1 << 1);
232 reg8 >>= 1;
233
Arthur Heymans70a8e342017-03-09 11:30:23 +0100234 return reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000235}
236
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000237static void sdram_detect_errors(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000238{
239 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000240 u8 do_reset = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000241
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100242 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000243
Stefan Reinauer278534d2008-10-29 04:51:07 +0000244 if (reg8 & ((1<<7)|(1<<2))) {
245 if (reg8 & (1<<2)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000246 printk(BIOS_DEBUG, "SLP S4# Assertion Width Violation.\n");
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000247 /* Write back clears bit 2 */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100248 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000249 do_reset = 1;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000250
Stefan Reinauer278534d2008-10-29 04:51:07 +0000251 }
252
253 if (reg8 & (1<<7)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000254 printk(BIOS_DEBUG, "DRAM initialization was interrupted.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000255 reg8 &= ~(1<<7);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100256 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000257 do_reset = 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000258 }
259
260 /* Set SLP_S3# Assertion Stretch Enable */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100261 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000262 reg8 |= (1 << 3);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100263 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000264
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000265 if (do_reset) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000266 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200267 full_reset();
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000268 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000269 }
270
271 /* Set DRAM initialization bit in ICH7 */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100272 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000273 reg8 |= (1<<7);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100274 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000275
Peter Stuge751508a2012-01-27 22:17:09 +0100276 /* clear self refresh status if check is disabled or not a resume */
Julius Werner5d1f9a02019-03-07 17:07:26 -0800277 if (!CONFIG(CHECK_SLFRCS_ON_RESUME)
Arthur Heymans0ab49042017-02-06 22:40:14 +0100278 || sysinfo->boot_path != BOOT_PATH_RESUME) {
Patrick Georgi86a11102013-03-15 14:11:37 +0100279 MCHBAR8(SLFRCS) |= 3;
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000280 } else {
281 /* Validate self refresh config */
282 if (((sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED) ||
283 (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)) &&
Patrick Georgi86a11102013-03-15 14:11:37 +0100284 !(MCHBAR8(SLFRCS) & (1<<0))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000285 do_reset = 1;
286 }
287 if (((sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED) ||
288 (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) &&
Patrick Georgi86a11102013-03-15 14:11:37 +0100289 !(MCHBAR8(SLFRCS) & (1<<1))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000290 do_reset = 1;
291 }
292 }
293
294 if (do_reset) {
295 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200296 full_reset();
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000297 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000298}
Stefan Reinauer278534d2008-10-29 04:51:07 +0000299
Arthur Heymans0ab49042017-02-06 22:40:14 +0100300struct timings {
301 u32 min_tCLK_cas[8];
302 u32 min_tRAS;
303 u32 min_tRP;
304 u32 min_tRCD;
305 u32 min_tWR;
306 u32 min_tRFC;
307 u32 max_tRR;
308 u8 cas_mask;
309};
Stefan Reinauer278534d2008-10-29 04:51:07 +0000310
Arthur Heymans0ab49042017-02-06 22:40:14 +0100311/**
312 * @brief loop over dimms and save maximal timings
313 */
314static void gather_common_timing(struct sys_info *sysinfo,
315 struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000316{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100317
318 int i, j;
319 u8 raw_spd[SPD_SIZE_MAX_DDR2];
320 u8 dimm_mask = 0;
321
322 memset(saved_timings, 0, sizeof(*saved_timings));
323 saved_timings->max_tRR = UINT32_MAX;
324 saved_timings->cas_mask = SPD_CAS_LATENCY_DDR2_3
325 | SPD_CAS_LATENCY_DDR2_4 | SPD_CAS_LATENCY_DDR2_5;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000326
327 /**
328 * i945 supports two DIMMs, in two configurations:
329 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000330 * - single channel with two DIMMs
331 * - dual channel with one DIMM per channel
Stefan Reinauer278534d2008-10-29 04:51:07 +0000332 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000333 * In practice dual channel mainboards have their SPD at 0x50/0x52
334 * whereas single channel configurations have their SPD at 0x50/0x51.
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000335 *
Stefan Reinauer278534d2008-10-29 04:51:07 +0000336 * The capability register knows a lot about the channel configuration
Uwe Hermannd773fd32010-11-20 20:23:08 +0000337 * but for now we stick with the information we gather via SPD.
Stefan Reinauer278534d2008-10-29 04:51:07 +0000338 */
339
Arthur Heymans0ab49042017-02-06 22:40:14 +0100340 printk(BIOS_DEBUG, "This mainboard supports ");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000341 if (sdram_capabilities_dual_channel()) {
342 sysinfo->dual_channel = 1;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100343 printk(BIOS_DEBUG, "Dual Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000344 } else {
345 sysinfo->dual_channel = 0;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100346 printk(BIOS_DEBUG, "only Single Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000347 }
348
Stefan Reinauer278534d2008-10-29 04:51:07 +0000349
Arthur Heymans70a8e342017-03-09 11:30:23 +0100350 for (i = 0; i < (2 * DIMM_SOCKETS); i++) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100351 int device = get_dimm_spd_address(sysinfo, i), bytes_read;
Arthur Heymansfc31e442018-02-12 15:12:34 +0100352 struct dimm_attr_ddr2_st dimm_info;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000353
354 /* Initialize the socket information with a sane value */
355 sysinfo->dimm[i] = SYSINFO_DIMM_NOT_POPULATED;
356
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000357 /* Dual Channel not supported, but Channel 1? Bail out */
358 if (!sdram_capabilities_dual_channel() && (i >> 1))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000359 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000360
Kyösti Mälkkibd659852020-01-05 20:00:18 +0200361 if (smbus_read_byte(device, SPD_MEMORY_TYPE) !=
Arthur Heymans0ab49042017-02-06 22:40:14 +0100362 SPD_MEMORY_TYPE_SDRAM_DDR2) {
363 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: N/A\n",
364 (i >> 1), (i & 1));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000365 continue;
366 }
367
Arthur Heymans0ab49042017-02-06 22:40:14 +0100368 /*
369 * spd_decode_ddr2() needs a 128-byte sized array but
370 * only the first 64 bytes contain data needed for raminit.
371 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000372
Kyösti Mälkkic01a5052019-01-30 09:39:23 +0200373 bytes_read = i2c_eeprom_read(device, 0, 64, raw_spd);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100374 printk(BIOS_DEBUG, "Reading SPD using i2c block operation.\n");
Julius Wernercd49cce2019-03-05 16:53:33 -0800375 if (CONFIG(DEBUG_RAM_SETUP) && bytes_read > 0)
Arthur Heymans0ab49042017-02-06 22:40:14 +0100376 hexdump(raw_spd, bytes_read);
Arthur Heymans56619452017-09-21 09:12:42 +0200377 if (bytes_read != 64) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100378 /* Try again with SMBUS byte read */
379 printk(BIOS_DEBUG, "i2c block operation failed,"
Paul Menzel105e3682017-09-21 08:11:05 +0200380 " trying smbus byte operation.\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100381 for (j = 0; j < 64; j++)
Kyösti Mälkkibd659852020-01-05 20:00:18 +0200382 raw_spd[j] = smbus_read_byte(device, j);
Julius Wernercd49cce2019-03-05 16:53:33 -0800383 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100384 hexdump(raw_spd, 64);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100385 }
Arthur Heymans56619452017-09-21 09:12:42 +0200386
387 if (spd_decode_ddr2(&dimm_info, raw_spd) != SPD_STATUS_OK) {
388 printk(BIOS_WARNING, "Encountered problems with SPD, "
389 "skipping this DIMM.\n");
390 continue;
391 }
392
Julius Wernercd49cce2019-03-05 16:53:33 -0800393 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100394 dram_print_spd_ddr2(&dimm_info);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000395
Arthur Heymans0ab49042017-02-06 22:40:14 +0100396 if (dimm_info.flags.is_ecc)
397 die("\nError: ECC memory not supported by this chipset\n");
398
399 if (spd_dimm_is_registered_ddr2(dimm_info.dimm_type))
400 die("\nError: Registered memory not supported by this chipset\n");
401
402 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: ", (i >> 1),
403 (i & 1));
404 /**
405 * There are 5 different possible populations for a DIMM socket:
406 * 0. x16 double ranked (X16DS)
407 * 1. x8 double ranked (X8DS)
408 * 2. x16 single ranked (X16SS)
409 * 3. x8 double stacked (X8DDS)
410 * 4. Unpopulated
411 */
412 switch (dimm_info.width) {
413 case 8:
414 switch (dimm_info.ranks) {
415 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000416 printk(BIOS_DEBUG, "x8DDS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000417 sysinfo->dimm[i] = SYSINFO_DIMM_X8DDS;
418 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100419 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000420 printk(BIOS_DEBUG, "x8DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000421 sysinfo->dimm[i] = SYSINFO_DIMM_X8DS;
422 break;
423 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000424 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000425 }
426 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100427 case 16:
428 switch (dimm_info.ranks) {
429 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000430 printk(BIOS_DEBUG, "x16DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000431 sysinfo->dimm[i] = SYSINFO_DIMM_X16DS;
432 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100433 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000434 printk(BIOS_DEBUG, "x16SS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000435 sysinfo->dimm[i] = SYSINFO_DIMM_X16SS;
436 break;
437 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000438 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000439 }
440 break;
441 default:
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000442 die("Unsupported DDR-II memory width.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000443 }
444
Arthur Heymans0ab49042017-02-06 22:40:14 +0100445 /* Is the current DIMM a stacked DIMM? */
446 if (dimm_info.flags.stacked)
447 sysinfo->package = SYSINFO_PACKAGE_STACKED;
448
449 if (!dimm_info.flags.bl8)
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100450 die("Only DDR-II RAM with burst length 8 is supported.\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100451
452 if (dimm_info.ranksize_mb < 128)
453 die("DDR-II rank size smaller than 128MB is not supported.\n");
454
455 sysinfo->banksize[i * 2] = dimm_info.ranksize_mb / 32;
456 printk(BIOS_DEBUG, "DIMM %d side 0 = %d MB\n", i,
457 sysinfo->banksize[i * 2] * 32);
458 if (dimm_info.ranks == 2) {
459 sysinfo->banksize[(i * 2) + 1] =
460 dimm_info.ranksize_mb / 32;
461 printk(BIOS_DEBUG, "DIMM %d side 1 = %d MB\n",
462 i, sysinfo->banksize[(i * 2) + 1] * 32);
463 }
464
465
466 sysinfo->rows[i] = dimm_info.row_bits;
467 sysinfo->cols[i] = dimm_info.col_bits;
468 sysinfo->banks[i] = dimm_info.banks;
469
470 /* int min_tRAS, min_tRP, min_tRCD, min_tWR, min_tRFC; */
471 saved_timings->min_tRAS = MAX(saved_timings->min_tRAS,
472 dimm_info.tRAS);
473 saved_timings->min_tRP = MAX(saved_timings->min_tRP,
474 dimm_info.tRP);
475 saved_timings->min_tRCD = MAX(saved_timings->min_tRCD,
476 dimm_info.tRCD);
477 saved_timings->min_tWR = MAX(saved_timings->min_tWR,
478 dimm_info.tWR);
479 saved_timings->min_tRFC = MAX(saved_timings->min_tRFC,
480 dimm_info.tRFC);
481 saved_timings->max_tRR = MIN(saved_timings->max_tRR,
482 dimm_info.tRR);
483 saved_timings->cas_mask &= dimm_info.cas_supported;
484 for (j = 0; j < 8; j++) {
485 if (!(saved_timings->cas_mask & (1 << j)))
486 saved_timings->min_tCLK_cas[j] = 0;
487 else
488 saved_timings->min_tCLK_cas[j] =
489 MAX(dimm_info.cycle_time[j],
490 saved_timings->min_tCLK_cas[j]);
491 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000492 dimm_mask |= (1 << i);
493 }
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200494 if (!dimm_mask)
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000495 die("No memory installed.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000496
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200497 if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1)))
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100498 /* FIXME: Possibly does not boot in this case */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000499 printk(BIOS_INFO, "Channel 0 has no memory populated.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000500}
501
Arthur Heymans0ab49042017-02-06 22:40:14 +0100502static void choose_tclk(struct sys_info *sysinfo,
503 struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000504{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100505 u32 ctrl_min_tclk;
506 int try_cas;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000507
Arthur Heymans0ab49042017-02-06 22:40:14 +0100508 ctrl_min_tclk = 2 * 256 * 1000
509 / sdram_capabilities_max_supported_memory_frequency();
510 normalize_tck(&ctrl_min_tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000511
Arthur Heymans0ab49042017-02-06 22:40:14 +0100512 try_cas = spd_get_msbs(saved_timings->cas_mask);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000513
Arthur Heymans0ab49042017-02-06 22:40:14 +0100514 while (saved_timings->cas_mask & (1 << try_cas) && try_cas > 0) {
515 sysinfo->cas = try_cas;
516 sysinfo->tclk = saved_timings->min_tCLK_cas[try_cas];
517 if (sysinfo->tclk >= ctrl_min_tclk &&
518 saved_timings->min_tCLK_cas[try_cas] !=
519 saved_timings->min_tCLK_cas[try_cas - 1])
Stefan Reinauer278534d2008-10-29 04:51:07 +0000520 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100521 try_cas--;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000522 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000523
Arthur Heymans0ab49042017-02-06 22:40:14 +0100524 normalize_tck(&sysinfo->tclk);
525
526 if ((sysinfo->cas < 3) || (sysinfo->tclk == 0))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000527 die("Could not find common memory frequency and CAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000528
Arthur Heymans0ab49042017-02-06 22:40:14 +0100529 /*
530 * The loop can still results in a timing too fast for the
531 * memory controller.
532 */
533 if (sysinfo->tclk < ctrl_min_tclk)
534 sysinfo->tclk = ctrl_min_tclk;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000535
Arthur Heymans0ab49042017-02-06 22:40:14 +0100536 switch (sysinfo->tclk) {
537 case TCK_200MHZ:
538 sysinfo->memory_frequency = 400;
539 break;
540 case TCK_266MHZ:
541 sysinfo->memory_frequency = 533;
542 break;
543 case TCK_333MHZ:
544 sysinfo->memory_frequency = 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100545 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000546 }
547
Arthur Heymans0ab49042017-02-06 22:40:14 +0100548 printk(BIOS_DEBUG,
549 "Memory will be driven at %dMT with CAS=%d clocks\n",
550 sysinfo->memory_frequency, sysinfo->cas);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000551}
552
Arthur Heymans0ab49042017-02-06 22:40:14 +0100553static void derive_timings(struct sys_info *sysinfo,
554 struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000555{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100556 sysinfo->tras = DIV_ROUND_UP(saved_timings->min_tRAS, sysinfo->tclk);
557 if (sysinfo->tras > 0x18)
558 die("DDR-II Module does not support this frequency (tRAS error)\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000559
Arthur Heymans0ab49042017-02-06 22:40:14 +0100560 sysinfo->trp = DIV_ROUND_UP(saved_timings->min_tRP, sysinfo->tclk);
561 if (sysinfo->trp > 6)
562 die("DDR-II Module does not support this frequency (tRP error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000563
Arthur Heymans0ab49042017-02-06 22:40:14 +0100564 sysinfo->trcd = DIV_ROUND_UP(saved_timings->min_tRCD, sysinfo->tclk);
565 if (sysinfo->trcd > 6)
566 die("DDR-II Module does not support this frequency (tRCD error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000567
Arthur Heymans0ab49042017-02-06 22:40:14 +0100568 sysinfo->twr = DIV_ROUND_UP(saved_timings->min_tWR, sysinfo->tclk);
569 if (sysinfo->twr > 5)
570 die("DDR-II Module does not support this frequency (tWR error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000571
Arthur Heymans0ab49042017-02-06 22:40:14 +0100572 sysinfo->trfc = DIV_ROUND_UP(saved_timings->min_tRFC, sysinfo->tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000573
Arthur Heymans0ab49042017-02-06 22:40:14 +0100574 printk(BIOS_DEBUG, "tRAS = %d cycles\n", sysinfo->tras);
575 printk(BIOS_DEBUG, "tRP = %d cycles\n", sysinfo->trp);
576 printk(BIOS_DEBUG, "tRCD = %d cycles\n", sysinfo->trcd);
577 printk(BIOS_DEBUG, "tWR = %d cycles\n", sysinfo->twr);
578 printk(BIOS_DEBUG, "tRFC = %d cycles\n", sysinfo->trfc);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000579
Arthur Heymans0ab49042017-02-06 22:40:14 +0100580 /* Refresh is slower than 15.6us, use 15.6us */
581 /* tRR is decoded in units of 1/256us */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000582
Arthur Heymans0ab49042017-02-06 22:40:14 +0100583#define T_RR_7_8US 2000000
584#define T_RR_15_6US 4000000
585#define REFRESH_7_8US 1
586#define REFRESH_15_6US 0
Stefan Reinauer278534d2008-10-29 04:51:07 +0000587
Arthur Heymans0ab49042017-02-06 22:40:14 +0100588 if (saved_timings->max_tRR < T_RR_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000589 die("DDR-II module has unsupported refresh value\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100590 else if (saved_timings->max_tRR < T_RR_15_6US)
591 sysinfo->refresh = REFRESH_7_8US;
592 else
593 sysinfo->refresh = REFRESH_15_6US;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000594 printk(BIOS_DEBUG, "Refresh: %s\n", sysinfo->refresh?"7.8us":"15.6us");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000595}
596
Arthur Heymans0ab49042017-02-06 22:40:14 +0100597/**
598 * @brief Get generic DIMM parameters.
599 * @param sysinfo Central memory controller information structure
600 *
601 * This function gathers several pieces of information for each system DIMM:
602 * o DIMM width (x8 / x16)
603 * o DIMM rank (single ranked / dual ranked)
604 *
605 * Also, some non-supported scenarios are detected.
606 */
607
608static void sdram_get_dram_configuration(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000609{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100610 struct timings saved_timings;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000611
Arthur Heymans0ab49042017-02-06 22:40:14 +0100612 gather_common_timing(sysinfo, &saved_timings);
613 choose_tclk(sysinfo, &saved_timings);
614 derive_timings(sysinfo, &saved_timings);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000615}
616
Arthur Heymans70a8e342017-03-09 11:30:23 +0100617static void sdram_program_dram_width(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000618{
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200619 u16 c0dramw = 0, c1dramw = 0;
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200620 int i, idx;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000621
622 if (sysinfo->dual_channel)
623 idx = 2;
624 else
625 idx = 1;
626
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200627 for (i = 0; i < DIMM_SOCKETS; i++) { /* Channel 0 */
628 switch (sysinfo->dimm[i]) {
629 case SYSINFO_DIMM_X16DS:
630 c0dramw |= (0x0000) << 4*(i % 2);
631 break;
632 case SYSINFO_DIMM_X8DS:
633 c0dramw |= (0x0001) << 4*(i % 2);
634 break;
635 case SYSINFO_DIMM_X16SS:
636 c0dramw |= (0x0000) << 4*(i % 2);
637 break;
638 case SYSINFO_DIMM_X8DDS:
639 c0dramw |= (0x0005) << 4*(i % 2);
640 break;
641 case SYSINFO_DIMM_NOT_POPULATED:
642 c0dramw |= (0x0000) << 4*(i % 2);
643 break;
644 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000645 }
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200646 for (i = DIMM_SOCKETS; i < idx * DIMM_SOCKETS; i++) { /* Channel 1 */
647 switch (sysinfo->dimm[i]) {
648 case SYSINFO_DIMM_X16DS:
649 c1dramw |= (0x0000) << 4*(i % 2);
650 break;
651 case SYSINFO_DIMM_X8DS:
Patrick Georgi68aed912018-11-16 18:00:12 +0100652 c1dramw |= (0x0010) << 4*(i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200653 break;
654 case SYSINFO_DIMM_X16SS:
655 c1dramw |= (0x0000) << 4*(i % 2);
656 break;
657 case SYSINFO_DIMM_X8DDS:
Patrick Georgi68aed912018-11-16 18:00:12 +0100658 c1dramw |= (0x0050) << 4*(i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200659 break;
660 case SYSINFO_DIMM_NOT_POPULATED:
661 c1dramw |= (0x0000) << 4*(i % 2);
662 break;
663 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000664 }
665
666 MCHBAR16(C0DRAMW) = c0dramw;
667 MCHBAR16(C1DRAMW) = c1dramw;
668}
669
670static void sdram_write_slew_rates(u32 offset, const u32 *slew_rate_table)
671{
672 int i;
673
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200674 for (i = 0; i < 16; i++)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000675 MCHBAR32(offset+(i*4)) = slew_rate_table[i];
676}
677
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000678static const u32 dq2030[] = {
679 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
680 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
681 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
682 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
683};
684
685static const u32 dq2330[] = {
686 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
687 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
688 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
689 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
690};
691
692static const u32 cmd2710[] = {
693 0x07060605, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
694 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
695 0x1110100f, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
696 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
697};
698
699static const u32 cmd3210[] = {
700 0x0f0d0b0a, 0x17151311, 0x1f1d1b19, 0x1f1f1f1f,
701 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
702 0x18171615, 0x1f1f1c1a, 0x1f1f1f1f, 0x1f1f1f1f,
703 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
704};
705
706static const u32 clk2030[] = {
707 0x0e0d0d0c, 0x100f0f0e, 0x100f0e0d, 0x15131211,
708 0x1d1b1917, 0x2523211f, 0x2a282927, 0x32302e2c,
709 0x17161514, 0x1b1a1918, 0x1f1e1d1c, 0x23222120,
710 0x27262524, 0x2d2b2928, 0x3533312f, 0x3d3b3937
711};
712
713static const u32 ctl3215[] = {
714 0x01010000, 0x03020101, 0x07060504, 0x0b0a0908,
715 0x100f0e0d, 0x14131211, 0x18171615, 0x1c1b1a19,
716 0x05040403, 0x07060605, 0x0a090807, 0x0f0d0c0b,
717 0x14131211, 0x18171615, 0x1c1b1a19, 0x201f1e1d
718};
719
720static const u32 ctl3220[] = {
721 0x05040403, 0x07060505, 0x0e0c0a08, 0x1a171411,
722 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e,
723 0x09080807, 0x0b0a0a09, 0x0f0d0c0b, 0x1b171311,
724 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e
725};
726
727static const u32 nc[] = {
728 0x00000000, 0x00000000, 0x00000000, 0x00000000,
729 0x00000000, 0x00000000, 0x00000000, 0x00000000,
730 0x00000000, 0x00000000, 0x00000000, 0x00000000,
731 0x00000000, 0x00000000, 0x00000000, 0x00000000
732};
733
734enum {
735 DQ2030,
736 DQ2330,
737 CMD2710,
738 CMD3210,
739 CLK2030,
740 CTL3215,
741 CTL3220,
742 NC,
743};
744
745static const u8 dual_channel_slew_group_lookup[] = {
746 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
747 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
748 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
749 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
750 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
751
752 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
753 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
754 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
755 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
756 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
757
758 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
759 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
760 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
761 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
762 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
763
764 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
765 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
766 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
767 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
768 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, NC, NC,
769
770 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
771 NC, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
772 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
773 NC, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD2710
774};
775
776static const u8 single_channel_slew_group_lookup[] = {
777 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
778 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
779 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
780 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
781 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
782
783 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
784 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
785 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
786 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
787 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
788
789 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
790 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
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, NC, NC,
794
795 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
796 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
797 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
798 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
799 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
800
801 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
802 DQ2330, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
803 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
804 DQ2330, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD3210
805};
806
807static const u32 *slew_group_lookup(int dual_channel, int index)
808{
809 const u8 *slew_group;
810 /* Dual Channel needs different tables. */
811 if (dual_channel)
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100812 slew_group = dual_channel_slew_group_lookup;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000813 else
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100814 slew_group = single_channel_slew_group_lookup;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000815
816 switch (slew_group[index]) {
817 case DQ2030: return dq2030;
818 case DQ2330: return dq2330;
819 case CMD2710: return cmd2710;
820 case CMD3210: return cmd3210;
821 case CLK2030: return clk2030;
822 case CTL3215: return ctl3215;
823 case CTL3220: return ctl3220;
824 case NC: return nc;
825 }
826
827 return nc;
828}
829
Julius Wernercd49cce2019-03-05 16:53:33 -0800830#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000831/* Strength multiplier tables */
832static const u8 dual_channel_strength_multiplier[] = {
833 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
834 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
835 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
836 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
837 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
838 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
839 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
840 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
841 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
842 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
843 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
844 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
845 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
846 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
847 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
848 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
849 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
850 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
851 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
852 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
853 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
854 0x00, 0x00, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
855 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
856 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x44, 0x22
857};
858
859static const u8 single_channel_strength_multiplier[] = {
860 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
861 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
862 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
863 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
864 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
865 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
866 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
867 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
868 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
869 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
870 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
871 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
872 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
873 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
874 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
875 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
876 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
877 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
878 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
879 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
880 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
881 0x33, 0x00, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
882 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
883 0x33, 0x00, 0x11, 0x00, 0x44, 0x44, 0x33, 0x11
884};
Julius Wernercd49cce2019-03-05 16:53:33 -0800885#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000886static const u8 dual_channel_strength_multiplier[] = {
887 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
888 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
889 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
890 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
891 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
892 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
893 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
894 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
895 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
896 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
897 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
898 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
899 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
900 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
901 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
902 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
903 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
904 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
905 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
906 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
907 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
908 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
909 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
910 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33
911};
912
913static const u8 single_channel_strength_multiplier[] = {
914 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
915 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
916 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
917 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
918 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
919 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
920 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
921 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
922 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
923 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
924 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
925 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
926 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
927 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
928 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
929 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
930 0x44, 0x88, 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, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
934 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
935 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
936 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
937 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00
938};
939#endif
940
Stefan Reinauer278534d2008-10-29 04:51:07 +0000941static void sdram_rcomp_buffer_strength_and_slew(struct sys_info *sysinfo)
942{
Arthur Heymans70a8e342017-03-09 11:30:23 +0100943 const u8 *strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000944 int idx, dual_channel;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000945
946 /* Set Strength Multipliers */
947
948 /* Dual Channel needs different tables. */
949 if (sdram_capabilities_dual_channel()) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000950 printk(BIOS_DEBUG, "Programming Dual Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000951 strength_multiplier = dual_channel_strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000952 dual_channel = 1;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100953 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[2];
Stefan Reinauer278534d2008-10-29 04:51:07 +0000954 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000955 printk(BIOS_DEBUG, "Programming Single Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000956 strength_multiplier = single_channel_strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000957 dual_channel = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000958 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[1];
959 }
960
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000961 printk(BIOS_DEBUG, "Table Index: %d\n", idx);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000962
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000963 MCHBAR8(G1SC) = strength_multiplier[idx * 8 + 0];
964 MCHBAR8(G2SC) = strength_multiplier[idx * 8 + 1];
965 MCHBAR8(G3SC) = strength_multiplier[idx * 8 + 2];
966 MCHBAR8(G4SC) = strength_multiplier[idx * 8 + 3];
967 MCHBAR8(G5SC) = strength_multiplier[idx * 8 + 4];
968 MCHBAR8(G6SC) = strength_multiplier[idx * 8 + 5];
969 MCHBAR8(G7SC) = strength_multiplier[idx * 8 + 6];
970 MCHBAR8(G8SC) = strength_multiplier[idx * 8 + 7];
Stefan Reinauer278534d2008-10-29 04:51:07 +0000971
972 /* Channel 0 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000973 sdram_write_slew_rates(G1SRPUT, slew_group_lookup(dual_channel, idx * 8 + 0));
974 sdram_write_slew_rates(G2SRPUT, slew_group_lookup(dual_channel, idx * 8 + 1));
Arthur Heymans70a8e342017-03-09 11:30:23 +0100975 if ((slew_group_lookup(dual_channel, idx * 8 + 2) != nc) && (sysinfo->package == SYSINFO_PACKAGE_STACKED))
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000976
Stefan Reinauer278534d2008-10-29 04:51:07 +0000977 sdram_write_slew_rates(G3SRPUT, ctl3220);
Arthur Heymans70a8e342017-03-09 11:30:23 +0100978 else
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000979 sdram_write_slew_rates(G3SRPUT, slew_group_lookup(dual_channel, idx * 8 + 2));
Arthur Heymans70a8e342017-03-09 11:30:23 +0100980
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000981 sdram_write_slew_rates(G4SRPUT, slew_group_lookup(dual_channel, idx * 8 + 3));
982 sdram_write_slew_rates(G5SRPUT, slew_group_lookup(dual_channel, idx * 8 + 4));
983 sdram_write_slew_rates(G6SRPUT, slew_group_lookup(dual_channel, idx * 8 + 5));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000984
985 /* Channel 1 */
986 if (sysinfo->dual_channel) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000987 sdram_write_slew_rates(G7SRPUT, slew_group_lookup(dual_channel, idx * 8 + 6));
988 sdram_write_slew_rates(G8SRPUT, slew_group_lookup(dual_channel, idx * 8 + 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000989 } else {
990 sdram_write_slew_rates(G7SRPUT, nc);
991 sdram_write_slew_rates(G8SRPUT, nc);
992 }
993}
994
995static void sdram_enable_rcomp(void)
996{
997 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000998 /* Enable Global Periodic RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000999 udelay(300);
1000 reg32 = MCHBAR32(GBRCOMPCTL);
1001 reg32 &= ~(1 << 23);
1002 MCHBAR32(GBRCOMPCTL) = reg32;
1003}
1004
1005static void sdram_program_dll_timings(struct sys_info *sysinfo)
1006{
Elyes HAOUAS44a30662017-02-23 13:14:44 +01001007 u32 channeldll = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001008 int i;
1009
Elyes HAOUAS38424982016-08-21 12:01:04 +02001010 printk(BIOS_DEBUG, "Programming DLL Timings...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001011
Arthur Heymans70a8e342017-03-09 11:30:23 +01001012 MCHBAR16(DQSMT) &= ~((3 << 12) | (1 << 10) | (0xf << 0));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001013 MCHBAR16(DQSMT) |= (1 << 13) | (0xc << 0);
1014
1015 /* We drive both channels with the same speed */
Julius Wernercd49cce2019-03-05 16:53:33 -08001016 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001017 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001018 case 400:
1019 channeldll = 0x26262626; break;
1020 case 533:
1021 channeldll = 0x22222222; break;
1022 case 667:
1023 channeldll = 0x11111111; break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001024 }
Julius Wernercd49cce2019-03-05 16:53:33 -08001025 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001026 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001027 case 400:
1028 channeldll = 0x33333333; break;
1029 case 533:
1030 channeldll = 0x24242424; break;
1031 case 667:
1032 channeldll = 0x25252525; break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001033 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001034 }
1035
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001036 for (i = 0; i < 4; i++) {
Elyes HAOUAS44a30662017-02-23 13:14:44 +01001037 MCHBAR32(C0R0B00DQST + (i * 0x10) + 0) = channeldll;
1038 MCHBAR32(C0R0B00DQST + (i * 0x10) + 4) = channeldll;
1039 MCHBAR32(C1R0B00DQST + (i * 0x10) + 0) = channeldll;
1040 MCHBAR32(C1R0B00DQST + (i * 0x10) + 4) = channeldll;
Julius Wernercd49cce2019-03-05 16:53:33 -08001041 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUAS44a30662017-02-23 13:14:44 +01001042 MCHBAR8(C0R0B00DQST + (i * 0x10) + 8) = channeldll & 0xff;
1043 MCHBAR8(C1R0B00DQST + (i * 0x10) + 8) = channeldll & 0xff;
Paul Menzelbce7e332017-02-22 18:46:27 +01001044 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001045 }
1046}
1047
1048static void sdram_force_rcomp(void)
1049{
1050 u32 reg32;
1051 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001052
Stefan Reinauer278534d2008-10-29 04:51:07 +00001053 reg32 = MCHBAR32(ODTC);
1054 reg32 |= (1 << 28);
1055 MCHBAR32(ODTC) = reg32;
1056
1057 reg32 = MCHBAR32(SMSRCTL);
1058 reg32 |= (1 << 0);
1059 MCHBAR32(SMSRCTL) = reg32;
1060
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001061 /* Start initial RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001062 reg32 = MCHBAR32(GBRCOMPCTL);
1063 reg32 |= (1 << 8);
1064 MCHBAR32(GBRCOMPCTL) = reg32;
1065
1066 reg8 = i945_silicon_revision();
1067 if ((reg8 == 0 && (MCHBAR32(DCC) & (3 << 0)) == 0) || (reg8 == 1)) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001068
Stefan Reinauer278534d2008-10-29 04:51:07 +00001069 reg32 = MCHBAR32(GBRCOMPCTL);
1070 reg32 |= (3 << 5);
1071 MCHBAR32(GBRCOMPCTL) = reg32;
1072 }
1073}
1074
1075static void sdram_initialize_system_memory_io(struct sys_info *sysinfo)
1076{
1077 u8 reg8;
1078 u32 reg32;
1079
Elyes HAOUAS38424982016-08-21 12:01:04 +02001080 printk(BIOS_DEBUG, "Initializing System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001081 /* Enable Data Half Clock Pushout */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001082 reg8 = MCHBAR8(C0HCTC);
1083 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001084 reg8 |= (1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001085 MCHBAR8(C0HCTC) = reg8;
1086
1087 reg8 = MCHBAR8(C1HCTC);
1088 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001089 reg8 |= (1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001090 MCHBAR8(C1HCTC) = reg8;
1091
Arthur Heymans70a8e342017-03-09 11:30:23 +01001092 MCHBAR16(WDLLBYPMODE) &= ~((1 << 9) | (1 << 6) | (1 << 4) | (1 << 3) | (1 << 1));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001093 MCHBAR16(WDLLBYPMODE) |= (1 << 8) | (1 << 7) | (1 << 5) | (1 << 2) | (1 << 0);
1094
1095 MCHBAR8(C0WDLLCMC) = 0;
1096 MCHBAR8(C1WDLLCMC) = 0;
1097
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001098 /* Program RCOMP Settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001099 sdram_program_dram_width(sysinfo);
1100
1101 sdram_rcomp_buffer_strength_and_slew(sysinfo);
1102
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001103 /* Indicate that RCOMP programming is done */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001104 reg32 = MCHBAR32(GBRCOMPCTL);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001105 reg32 &= ~((1 << 29) | (1 << 26) | (3 << 21) | (3 << 2));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001106 reg32 |= (3 << 27) | (3 << 0);
1107 MCHBAR32(GBRCOMPCTL) = reg32;
1108
1109 MCHBAR32(GBRCOMPCTL) |= (1 << 10);
1110
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001111 /* Program DLL Timings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001112 sdram_program_dll_timings(sysinfo);
1113
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001114 /* Force RCOMP cycle */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001115 sdram_force_rcomp();
1116}
1117
1118static void sdram_enable_system_memory_io(struct sys_info *sysinfo)
1119{
1120 u32 reg32;
1121
Elyes HAOUAS38424982016-08-21 12:01:04 +02001122 printk(BIOS_DEBUG, "Enabling System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001123
Stefan Reinauer278534d2008-10-29 04:51:07 +00001124 reg32 = MCHBAR32(RCVENMT);
1125 reg32 &= ~(0x3f << 6);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001126 MCHBAR32(RCVENMT) = reg32; /* [11:6] = 0 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001127
1128 reg32 |= (1 << 11) | (1 << 9);
1129 MCHBAR32(RCVENMT) = reg32;
1130
1131 reg32 = MCHBAR32(DRTST);
1132 reg32 |= (1 << 3) | (1 << 2);
1133 MCHBAR32(DRTST) = reg32;
1134
1135 reg32 = MCHBAR32(DRTST);
1136 reg32 |= (1 << 6) | (1 << 4);
1137 MCHBAR32(DRTST) = reg32;
1138
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001139 asm volatile ("nop; nop;" ::: "memory");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001140
1141 reg32 = MCHBAR32(DRTST);
1142
1143 /* Is channel 0 populated? */
1144 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
1145 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
1146 reg32 |= (1 << 7) | (1 << 5);
1147 else
1148 reg32 |= (1 << 31);
1149
1150 /* Is channel 1 populated? */
1151 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1152 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
1153 reg32 |= (1 << 9) | (1 << 8);
1154 else
1155 reg32 |= (1 << 30);
1156
1157 MCHBAR32(DRTST) = reg32;
1158
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001159 /* Activate DRAM Channel IO Buffers */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001160 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
1161 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) {
1162 reg32 = MCHBAR32(C0DRC1);
1163 reg32 |= (1 << 8);
1164 MCHBAR32(C0DRC1) = reg32;
1165 }
1166 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1167 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED) {
1168 reg32 = MCHBAR32(C1DRC1);
1169 reg32 |= (1 << 8);
1170 MCHBAR32(C1DRC1) = reg32;
1171 }
1172}
1173
Stefan Reinauer278534d2008-10-29 04:51:07 +00001174static int sdram_program_row_boundaries(struct sys_info *sysinfo)
1175{
1176 int i;
Arthur Heymans885c2892016-10-03 17:16:48 +02001177 int cum0, cum1, tolud, tom, pci_mmio_size;
1178 const struct device *dev;
1179 const struct northbridge_intel_i945_config *cfg = NULL;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001180
Paul Menzel84283bc2014-07-17 08:16:04 +02001181 printk(BIOS_DEBUG, "Setting RAM size...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001182
1183 cum0 = 0;
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001184 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001185 cum0 += sysinfo->banksize[i];
Stefan Reinauer278534d2008-10-29 04:51:07 +00001186 MCHBAR8(C0DRB0+i) = cum0;
1187 }
1188
1189 /* Assume we continue in Channel 1 where we stopped in Channel 0 */
1190 cum1 = cum0;
1191
1192 /* Exception: Interleaved starts from the beginning */
1193 if (sysinfo->interleaved)
1194 cum1 = 0;
1195
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001196 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001197 cum1 += sysinfo->banksize[i + 4];
Stefan Reinauer278534d2008-10-29 04:51:07 +00001198 MCHBAR8(C1DRB0+i) = cum1;
1199 }
1200
1201 /* Set TOLUD Top Of Low Usable DRAM */
1202 if (sysinfo->interleaved)
1203 tolud = (cum0 + cum1) << 1;
1204 else
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001205 tolud = (cum1 ? cum1 : cum0) << 1;
Stefan Reinauer779b3e32008-11-10 15:43:37 +00001206
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001207 /* The TOM register has a different format */
1208 tom = tolud >> 3;
1209
1210 /* Limit the value of TOLUD to leave some space for PCI memory. */
Kyösti Mälkkic70eed12018-05-22 02:18:00 +03001211 dev = pcidev_on_root(0, 0);
Arthur Heymans885c2892016-10-03 17:16:48 +02001212 if (dev)
1213 cfg = dev->chip_info;
1214
1215 /* Don't use pci mmio sizes smaller than 768M */
1216 if (!cfg || cfg->pci_mmio_size <= DEFAULT_PCI_MMIO_SIZE)
1217 pci_mmio_size = DEFAULT_PCI_MMIO_SIZE;
1218 else
1219 pci_mmio_size = cfg->pci_mmio_size;
1220
1221 tolud = MIN(((4096 - pci_mmio_size) / 128) << 3, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001222
Arthur Heymans70a8e342017-03-09 11:30:23 +01001223 pci_write_config8(PCI_DEV(0, 0, 0), TOLUD, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001224
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001225 printk(BIOS_DEBUG, "C0DRB = 0x%08x\n", MCHBAR32(C0DRB0));
1226 printk(BIOS_DEBUG, "C1DRB = 0x%08x\n", MCHBAR32(C1DRB0));
Arthur Heymans70a8e342017-03-09 11:30:23 +01001227 printk(BIOS_DEBUG, "TOLUD = 0x%04x\n", pci_read_config8(PCI_DEV(0, 0, 0), TOLUD));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001228
Arthur Heymans70a8e342017-03-09 11:30:23 +01001229 pci_write_config16(PCI_DEV(0, 0, 0), TOM, tom);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001230
1231 return 0;
1232}
1233
Stefan Reinauer278534d2008-10-29 04:51:07 +00001234static int sdram_set_row_attributes(struct sys_info *sysinfo)
1235{
Arthur Heymans0ab49042017-02-06 22:40:14 +01001236 int i;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001237 u16 dra0 = 0, dra1 = 0, dra = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001238
Elyes HAOUAS38424982016-08-21 12:01:04 +02001239 printk(BIOS_DEBUG, "Setting row attributes...\n");
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001240 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001241 u8 columnsrows;
1242
Arthur Heymans70a8e342017-03-09 11:30:23 +01001243 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001244 continue;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001245
Arthur Heymans0ab49042017-02-06 22:40:14 +01001246 columnsrows = (sysinfo->rows[i] & 0x0f)
1247 | (sysinfo->cols[i] & 0xf) << 4;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001248
1249 switch (columnsrows) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001250 case 0x9d:
1251 dra = 2; break;
1252 case 0xad:
1253 dra = 3; break;
1254 case 0xbd:
1255 dra = 4; break;
1256 case 0xae:
1257 dra = 3; break;
1258 case 0xbe:
1259 dra = 4; break;
1260 default:
1261 die("Unsupported Rows/Columns. (DRA)");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001262 }
1263
1264 /* Double Sided DIMMs? */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001265 if (sysinfo->banksize[(2 * i) + 1] != 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001266 dra = (dra << 4) | dra;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001267
Stefan Reinauer278534d2008-10-29 04:51:07 +00001268 if (i < DIMM_SOCKETS)
1269 dra0 |= (dra << (i*8));
1270 else
1271 dra1 |= (dra << ((i - DIMM_SOCKETS)*8));
1272 }
1273
1274 MCHBAR16(C0DRA0) = dra0;
1275 MCHBAR16(C1DRA0) = dra1;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001276
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001277 printk(BIOS_DEBUG, "C0DRA = 0x%04x\n", dra0);
1278 printk(BIOS_DEBUG, "C1DRA = 0x%04x\n", dra1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001279
1280 return 0;
1281}
1282
1283static void sdram_set_bank_architecture(struct sys_info *sysinfo)
1284{
1285 u32 off32;
1286 int i;
1287
1288 MCHBAR16(C1BNKARC) &= 0xff00;
1289 MCHBAR16(C0BNKARC) &= 0xff00;
1290
1291 off32 = C0BNKARC;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001292 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001293 /* Switch to second channel */
1294 if (i == DIMM_SOCKETS)
1295 off32 = C1BNKARC;
1296
1297 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
1298 continue;
1299
1300 if (sysinfo->banks[i] != 8)
1301 continue;
1302
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001303 printk(BIOS_SPEW, "DIMM%d has 8 banks.\n", i);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001304
1305 if (i & 1)
1306 MCHBAR16(off32) |= 0x50;
1307 else
1308 MCHBAR16(off32) |= 0x05;
1309 }
1310}
1311
Stefan Reinauer278534d2008-10-29 04:51:07 +00001312static void sdram_program_refresh_rate(struct sys_info *sysinfo)
1313{
1314 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001315
Arthur Heymans70a8e342017-03-09 11:30:23 +01001316 if (sysinfo->refresh == REFRESH_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001317 reg32 = (2 << 8); /* Refresh enabled at 7.8us */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001318 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001319 reg32 = (1 << 8); /* Refresh enabled at 15.6us */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001320
1321 MCHBAR32(C0DRC0) &= ~(7 << 8);
1322 MCHBAR32(C0DRC0) |= reg32;
1323
1324 MCHBAR32(C1DRC0) &= ~(7 << 8);
1325 MCHBAR32(C1DRC0) |= reg32;
1326}
1327
1328static void sdram_program_cke_tristate(struct sys_info *sysinfo)
1329{
1330 u32 reg32;
1331 int i;
1332
1333 reg32 = MCHBAR32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001334
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001335 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001336 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001337 reg32 |= (1 << (16 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001338 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001339
Stefan Reinauer278534d2008-10-29 04:51:07 +00001340 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001341
Stefan Reinauer278534d2008-10-29 04:51:07 +00001342 reg32 |= (1 << 11);
1343 MCHBAR32(C0DRC1) = reg32;
1344
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001345 /* Do we have to do this if we're in Single Channel Mode? */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001346 reg32 = MCHBAR32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001347
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001348 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001349 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001350 reg32 |= (1 << (12 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001351 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001352
Stefan Reinauer278534d2008-10-29 04:51:07 +00001353 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001354
Stefan Reinauer278534d2008-10-29 04:51:07 +00001355 reg32 |= (1 << 11);
1356 MCHBAR32(C1DRC1) = reg32;
1357}
1358
1359static void sdram_program_odt_tristate(struct sys_info *sysinfo)
1360{
1361 u32 reg32;
1362 int i;
1363
1364 reg32 = MCHBAR32(C0DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001365
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001366 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001367 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001368 reg32 |= (1 << (24 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001369 }
1370 MCHBAR32(C0DRC2) = reg32;
1371
1372 reg32 = MCHBAR32(C1DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001373
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001374 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001375 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001376 reg32 |= (1 << (20 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001377 }
1378 MCHBAR32(C1DRC2) = reg32;
1379}
1380
1381static void sdram_set_timing_and_control(struct sys_info *sysinfo)
1382{
Arthur Heymans25027232017-02-12 23:34:39 +01001383 u32 reg32, tRD_min;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001384 u32 tWTR;
1385 u32 temp_drt;
1386 int i, page_size;
1387
Edward O'Callaghan2f237c12014-05-25 06:24:39 +10001388 static const u8 cas_table[] = {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001389 2, 1, 0, 3
1390 };
1391
1392 reg32 = MCHBAR32(C0DRC0);
1393 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001394 reg32 &= ~((1 << 13) | (1 << 12));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001395 MCHBAR32(C0DRC0) = reg32;
1396
1397 reg32 = MCHBAR32(C1DRC0);
1398 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001399 reg32 &= ~((1 << 13) | (1 << 12));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001400 MCHBAR32(C1DRC0) = reg32;
1401
1402 if (!sysinfo->dual_channel && sysinfo->dimm[1] !=
1403 SYSINFO_DIMM_NOT_POPULATED) {
1404 reg32 = MCHBAR32(C0DRC0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001405 reg32 |= (1 << 15);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001406 MCHBAR32(C0DRC0) = reg32;
1407 }
1408
1409 sdram_program_refresh_rate(sysinfo);
1410
1411 sdram_program_cke_tristate(sysinfo);
1412
1413 sdram_program_odt_tristate(sysinfo);
1414
1415 /* Calculate DRT0 */
1416
1417 temp_drt = 0;
1418
1419 /* B2B Write Precharge (same bank) = CL-1 + BL/2 + tWR */
1420 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + sysinfo->twr;
1421 temp_drt |= (reg32 << 28);
1422
1423 /* Write Auto Precharge (same bank) = CL-1 + BL/2 + tWR + tRP */
1424 reg32 += sysinfo->trp;
1425 temp_drt |= (reg32 << 4);
1426
Arthur Heymans70a8e342017-03-09 11:30:23 +01001427 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001428 tWTR = 3; /* 667MHz */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001429 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001430 tWTR = 2; /* 400 and 533 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001431
1432 /* B2B Write to Read Command Spacing */
1433 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + tWTR;
1434 temp_drt |= (reg32 << 24);
1435
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001436 /* CxDRT0 [23:22], [21:20], [19:18] [16] have fixed values */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001437 temp_drt |= ((1 << 22) | (3 << 20) | (1 << 18) | (0 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001438
Arthur Heymans25027232017-02-12 23:34:39 +01001439 /*
1440 * tRD is the delay the memory controller is waiting on the FSB,
1441 * in mclk domain.
1442 * This parameter is important for stability and performance.
1443 * Those values might not be optimal but seem stable.
1444 */
1445 tRD_min = sysinfo->cas;
Arthur Heymanse1897612016-10-15 23:29:18 +02001446 switch (sysinfo->fsb_frequency) {
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001447 case 533:
Arthur Heymanse1897612016-10-15 23:29:18 +02001448 break;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001449 case 667:
1450 tRD_min += 1;
Arthur Heymanse1897612016-10-15 23:29:18 +02001451 break;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001452 case 800:
1453 tRD_min += 2;
1454 break;
1455 case 1066:
1456 tRD_min += 3;
Arthur Heymanse1897612016-10-15 23:29:18 +02001457 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001458 }
Arthur Heymanse1897612016-10-15 23:29:18 +02001459
Arthur Heymans25027232017-02-12 23:34:39 +01001460 temp_drt |= (tRD_min << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001461
1462 /* Read Auto Precharge to Activate */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001463
Stefan Reinauer278534d2008-10-29 04:51:07 +00001464 temp_drt |= (8 << 0);
1465
1466 MCHBAR32(C0DRT0) = temp_drt;
1467 MCHBAR32(C1DRT0) = temp_drt;
1468
1469 /* Calculate DRT1 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001470
Stefan Reinauer278534d2008-10-29 04:51:07 +00001471 temp_drt = MCHBAR32(C0DRT1) & 0x00020088;
1472
1473 /* DRAM RASB Precharge */
1474 temp_drt |= (sysinfo->trp - 2) << 0;
1475
1476 /* DRAM RASB to CASB Delay */
1477 temp_drt |= (sysinfo->trcd - 2) << 4;
1478
1479 /* CASB Latency */
1480 temp_drt |= (cas_table[sysinfo->cas - 3]) << 8;
1481
1482 /* Refresh Cycle Time */
1483 temp_drt |= (sysinfo->trfc) << 10;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001484
Stefan Reinauer278534d2008-10-29 04:51:07 +00001485 /* Pre-All to Activate Delay */
1486 temp_drt |= (0 << 16);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001487
Stefan Reinauer278534d2008-10-29 04:51:07 +00001488 /* Precharge to Precharge Delay stays at 1 clock */
1489 temp_drt |= (0 << 18);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001490
Stefan Reinauer278534d2008-10-29 04:51:07 +00001491 /* Activate to Precharge Delay */
1492 temp_drt |= (sysinfo->tras << 19);
1493
1494 /* Read to Precharge (tRTP) */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001495 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001496 temp_drt |= (1 << 28);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001497 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001498 temp_drt |= (0 << 28);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001499
1500 /* Determine page size */
1501 reg32 = 0;
1502 page_size = 1; /* Default: 1k pagesize */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001503 for (i = 0; i < 2*DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001504 if (sysinfo->dimm[i] == SYSINFO_DIMM_X16DS ||
1505 sysinfo->dimm[i] == SYSINFO_DIMM_X16SS)
1506 page_size = 2; /* 2k pagesize */
1507 }
1508
Arthur Heymans70a8e342017-03-09 11:30:23 +01001509 if (sysinfo->memory_frequency == 533 && page_size == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001510 reg32 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001511 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001512 reg32 = page_size;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001513
Stefan Reinauer278534d2008-10-29 04:51:07 +00001514 temp_drt |= (reg32 << 30);
1515
1516 MCHBAR32(C0DRT1) = temp_drt;
1517 MCHBAR32(C1DRT1) = temp_drt;
1518
1519 /* Program DRT2 */
1520 reg32 = MCHBAR32(C0DRT2);
1521 reg32 &= ~(1 << 8);
1522 MCHBAR32(C0DRT2) = reg32;
1523
1524 reg32 = MCHBAR32(C1DRT2);
1525 reg32 &= ~(1 << 8);
1526 MCHBAR32(C1DRT2) = reg32;
1527
1528 /* Calculate DRT3 */
1529 temp_drt = MCHBAR32(C0DRT3) & ~0x07ffffff;
1530
1531 /* Get old tRFC value */
1532 reg32 = MCHBAR32(C0DRT1) >> 10;
1533 reg32 &= 0x3f;
1534
1535 /* 788nS - tRFC */
1536 switch (sysinfo->memory_frequency) {
1537 case 400: /* 5nS */
1538 reg32 = ((78800 / 500) - reg32) & 0x1ff;
1539 reg32 |= (0x8c << 16) | (0x0c << 10); /* 1 us */
1540 break;
1541 case 533: /* 3.75nS */
1542 reg32 = ((78800 / 375) - reg32) & 0x1ff;
1543 reg32 |= (0xba << 16) | (0x10 << 10); /* 1 us */
1544 break;
1545 case 667: /* 3nS */
1546 reg32 = ((78800 / 300) - reg32) & 0x1ff;
1547 reg32 |= (0xe9 << 16) | (0x14 << 10); /* 1 us */
1548 break;
1549 }
1550
1551 temp_drt |= reg32;
1552
1553 MCHBAR32(C0DRT3) = temp_drt;
1554 MCHBAR32(C1DRT3) = temp_drt;
1555}
1556
1557static void sdram_set_channel_mode(struct sys_info *sysinfo)
1558{
1559 u32 reg32;
1560
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001561 printk(BIOS_DEBUG, "Setting mode of operation for memory channels...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001562
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001563 if (sdram_capabilities_interleave() &&
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001564 ((sysinfo->banksize[0] + sysinfo->banksize[1] +
1565 sysinfo->banksize[2] + sysinfo->banksize[3]) ==
1566 (sysinfo->banksize[4] + sysinfo->banksize[5] +
1567 sysinfo->banksize[6] + sysinfo->banksize[7]))) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001568 /* Both channels equipped with DIMMs of the same size */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001569 sysinfo->interleaved = 1;
1570 } else {
1571 sysinfo->interleaved = 0;
1572 }
1573
1574 reg32 = MCHBAR32(DCC);
1575 reg32 &= ~(7 << 0);
1576
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001577 if (sysinfo->interleaved) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001578 /* Dual Channel Interleaved */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001579 printk(BIOS_DEBUG, "Dual Channel Interleaved.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001580 reg32 |= (1 << 1);
1581 } else if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED &&
1582 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
1583 /* Channel 1 only */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001584 printk(BIOS_DEBUG, "Single Channel 1 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001585 reg32 |= (1 << 2);
Elyes HAOUAS75da1fb2017-02-16 18:59:13 +01001586 } else if (sdram_capabilities_dual_channel() &&
1587 (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1588 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) {
Martin Roth128c1042016-11-18 09:29:03 -07001589 /* Dual Channel Asymmetric */
1590 printk(BIOS_DEBUG, "Dual Channel Asymmetric.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001591 reg32 |= (1 << 0);
1592 } else {
1593 /* All bits 0 means Single Channel 0 operation */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001594 printk(BIOS_DEBUG, "Single Channel 0 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001595 }
1596
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001597 /* Now disable channel XORing */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001598 reg32 |= (1 << 10);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001599
1600 MCHBAR32(DCC) = reg32;
1601
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001602 PRINTK_DEBUG("DCC = 0x%08x\n", MCHBAR32(DCC));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001603}
1604
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001605static void sdram_program_pll_settings(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001606{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001607 MCHBAR32(PLLMON) = 0x80800000;
1608
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001609 sysinfo->fsb_frequency = fsbclk();
Peter Stuge76d91432010-10-01 10:02:33 +00001610 if (sysinfo->fsb_frequency == 0xffff)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001611 die("Unsupported FSB speed");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001612
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001613 /* Program CPCTL according to FSB speed */
1614 /* Only write the lower byte */
1615 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001616 case 400:
1617 MCHBAR8(CPCTL) = 0x90; break; /* FSB400 */
1618 case 533:
1619 MCHBAR8(CPCTL) = 0x95; break; /* FSB533 */
1620 case 667:
1621 MCHBAR8(CPCTL) = 0x8d; break; /* FSB667 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001622 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001623
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001624 MCHBAR16(CPCTL) &= ~(1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001625
Paul Menzel0ce5ebf2013-10-21 21:22:09 +02001626 MCHBAR16(CPCTL); /* Read back register to activate settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001627}
1628
1629static void sdram_program_graphics_frequency(struct sys_info *sysinfo)
1630{
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001631 u8 reg8;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001632 u16 reg16;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001633 u8 freq, second_vco, voltage;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001634
1635#define CRCLK_166MHz 0x00
1636#define CRCLK_200MHz 0x01
1637#define CRCLK_250MHz 0x03
1638#define CRCLK_400MHz 0x05
1639
1640#define CDCLK_200MHz 0x00
1641#define CDCLK_320MHz 0x40
1642
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001643#define VOLTAGE_1_05 0x00
1644#define VOLTAGE_1_50 0x01
1645
Paul Menzeldaf9e502014-07-15 23:49:16 +02001646 printk(BIOS_DEBUG, "Setting Graphics Frequency...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001647
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001648 printk(BIOS_DEBUG, "FSB: %d MHz ", sysinfo->fsb_frequency);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001649
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001650 voltage = VOLTAGE_1_05;
1651 if (MCHBAR32(DFT_STRAP1) & (1 << 20))
1652 voltage = VOLTAGE_1_50;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001653 printk(BIOS_DEBUG, "Voltage: %s ", (voltage == VOLTAGE_1_05)?"1.05V":"1.5V");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001654
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001655 /* Gate graphics hardware for frequency change */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001656 reg8 = (1<<3) | (1<<1); /* disable crclk, gate cdclk */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001657 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001658
1659 /* Get graphics frequency capabilities */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001660 reg8 = sdram_capabilities_core_frequencies();
1661
Stefan Reinauer278534d2008-10-29 04:51:07 +00001662 freq = CRCLK_250MHz;
1663 switch (reg8) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001664 case GFX_FREQUENCY_CAP_ALL:
1665 if (voltage == VOLTAGE_1_05)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001666 freq = CRCLK_250MHz;
1667 else
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001668 freq = CRCLK_400MHz; /* 1.5V requires 400MHz */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001669 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001670 case GFX_FREQUENCY_CAP_250MHZ:
1671 freq = CRCLK_250MHz; break;
1672 case GFX_FREQUENCY_CAP_200MHZ:
1673 freq = CRCLK_200MHz; break;
1674 case GFX_FREQUENCY_CAP_166MHZ:
1675 freq = CRCLK_166MHz; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001676 }
1677
1678 if (freq != CRCLK_400MHz) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001679 /* What chipset are we? Force 166MHz for GMS */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001680 reg8 = (pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe7) & 0x70) >> 4;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001681 if (reg8 == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001682 freq = CRCLK_166MHz;
1683 }
1684
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001685 printk(BIOS_DEBUG, "Render: ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001686 switch (freq) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001687 case CRCLK_166MHz:
1688 printk(BIOS_DEBUG, "166MHz"); break;
1689 case CRCLK_200MHz:
1690 printk(BIOS_DEBUG, "200MHz"); break;
1691 case CRCLK_250MHz:
1692 printk(BIOS_DEBUG, "250MHz"); break;
1693 case CRCLK_400MHz:
1694 printk(BIOS_DEBUG, "400MHz"); break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001695 }
1696
Arthur Heymans70a8e342017-03-09 11:30:23 +01001697 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001698 sysinfo->mvco4x = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001699 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001700 sysinfo->mvco4x = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001701
Stefan Reinauer278534d2008-10-29 04:51:07 +00001702 second_vco = 0;
1703
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001704 if (voltage == VOLTAGE_1_50) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001705 second_vco = 1;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001706 } else if ((i945_silicon_revision() > 0) && (freq == CRCLK_250MHz)) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001707 u16 mem = sysinfo->memory_frequency;
1708 u16 fsb = sysinfo->fsb_frequency;
1709
Arthur Heymans70a8e342017-03-09 11:30:23 +01001710 if ((fsb == 667 && mem == 533) ||
1711 (fsb == 533 && mem == 533) ||
1712 (fsb == 533 && mem == 400)) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001713 second_vco = 1;
1714 }
1715
1716 if (fsb == 667 && mem == 533)
1717 sysinfo->mvco4x = 1;
1718 }
1719
Arthur Heymans70a8e342017-03-09 11:30:23 +01001720 if (second_vco)
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001721 sysinfo->clkcfg_bit7 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001722 else
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001723 sysinfo->clkcfg_bit7 = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001724
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001725 /* Graphics Core Render Clock */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001726 reg16 = pci_read_config16(PCI_DEV(0, 2, 0), GCFC);
1727 reg16 &= ~((7 << 0) | (1 << 13));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001728 reg16 |= freq;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001729 pci_write_config16(PCI_DEV(0, 2, 0), GCFC, reg16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001730
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001731 /* Graphics Core Display Clock */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001732 reg8 = pci_read_config8(PCI_DEV(0, 2, 0), GCFC);
1733 reg8 &= ~((1<<7) | (7<<4));
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001734
1735 if (voltage == VOLTAGE_1_05) {
1736 reg8 |= CDCLK_200MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001737 printk(BIOS_DEBUG, " Display: 200MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001738 } else {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001739 reg8 |= CDCLK_320MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001740 printk(BIOS_DEBUG, " Display: 320MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001741 }
Arthur Heymans70a8e342017-03-09 11:30:23 +01001742 pci_write_config8(PCI_DEV(0, 2, 0), GCFC, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001743
Arthur Heymans70a8e342017-03-09 11:30:23 +01001744 reg8 = pci_read_config8(PCI_DEV(0, 2, 0), GCFC + 1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001745
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001746 reg8 |= (1<<3) | (1<<1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001747 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001748
1749 reg8 |= 0x0f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001750 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001751
1752 /* Ungate core render and display clocks */
1753 reg8 &= 0xf0;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001754 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001755}
1756
1757static void sdram_program_memory_frequency(struct sys_info *sysinfo)
1758{
1759 u32 clkcfg;
1760 u8 reg8;
Julius Wernercd49cce2019-03-05 16:53:33 -08001761 u8 offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001762
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001763 printk(BIOS_DEBUG, "Setting Memory Frequency... ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001764
Stefan Reinauer278534d2008-10-29 04:51:07 +00001765 clkcfg = MCHBAR32(CLKCFG);
1766
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001767 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001768
Arthur Heymans70a8e342017-03-09 11:30:23 +01001769 clkcfg &= ~((1 << 12) | (1 << 7) | (7 << 4));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001770
1771 if (sysinfo->mvco4x) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001772 printk(BIOS_DEBUG, "MVCO 4x, ");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001773 clkcfg &= ~(1 << 12);
1774 }
1775
1776 if (sysinfo->clkcfg_bit7) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001777 printk(BIOS_DEBUG, "second VCO, ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001778
Stefan Reinauer278534d2008-10-29 04:51:07 +00001779 clkcfg |= (1 << 7);
1780 }
1781
1782 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001783 case 400:
1784 clkcfg |= ((1 + offset) << 4); break;
1785 case 533:
1786 clkcfg |= ((2 + offset) << 4); break;
1787 case 667:
1788 clkcfg |= ((3 + offset) << 4); break;
1789 default:
1790 die("Target Memory Frequency Error");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001791 }
1792
1793 if (MCHBAR32(CLKCFG) == clkcfg) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001794 printk(BIOS_DEBUG, "ok (unchanged)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001795 return;
1796 }
1797
1798 MCHBAR32(CLKCFG) = clkcfg;
1799
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001800 /* Make sure the following code is in the
Stefan Reinauer278534d2008-10-29 04:51:07 +00001801 * cache before we execute it.
1802 */
1803 goto cache_code;
1804vco_update:
Elyes HAOUAS32b9a992019-01-21 14:54:31 +01001805 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001806 reg8 &= ~(1 << 7);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +01001807 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001808
Stefan Reinauer278534d2008-10-29 04:51:07 +00001809 clkcfg &= ~(1 << 10);
1810 MCHBAR32(CLKCFG) = clkcfg;
1811 clkcfg |= (1 << 10);
1812 MCHBAR32(CLKCFG) = clkcfg;
1813
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001814 asm volatile (
Stefan Reinauer278534d2008-10-29 04:51:07 +00001815 " movl $0x100, %%ecx\n"
1816 "delay_update:\n"
1817 " nop\n"
1818 " nop\n"
1819 " nop\n"
1820 " nop\n"
1821 " loop delay_update\n"
1822 : /* No outputs */
1823 : /* No inputs */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001824 : "%ecx", "memory"
Stefan Reinauer278534d2008-10-29 04:51:07 +00001825 );
1826
Stefan Reinauer278534d2008-10-29 04:51:07 +00001827 clkcfg &= ~(1 << 10);
1828 MCHBAR32(CLKCFG) = clkcfg;
1829
1830 goto out;
1831cache_code:
1832 goto vco_update;
1833out:
1834
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001835 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", MCHBAR32(CLKCFG));
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001836 printk(BIOS_DEBUG, "ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001837}
1838
1839static void sdram_program_clock_crossing(void)
1840{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001841 int idx = 0;
1842
1843 /**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001844 * We add the indices according to our clocks from CLKCFG.
Stefan Reinauer278534d2008-10-29 04:51:07 +00001845 */
Julius Wernercd49cce2019-03-05 16:53:33 -08001846#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001847 static const u32 data_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001848 0x00100401, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001849 0xffffffff, 0xffffffff, /* nonexistent */
1850 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001851
Stefan Reinauer278534d2008-10-29 04:51:07 +00001852 0x08040120, 0x00000000, /* DDR400 FSB533 */
1853 0x00100401, 0x00000000, /* DDR533 FSB533 */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001854 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001855
1856 0x04020120, 0x00000010, /* DDR400 FSB667 */
1857 0x10040280, 0x00000040, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001858 0x00100401, 0x00000000, /* DDR667 FSB667 */
1859
Martin Roth2ed0aa22016-01-05 20:58:58 -07001860 0xffffffff, 0xffffffff, /* nonexistent */
1861 0xffffffff, 0xffffffff, /* nonexistent */
1862 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001863
Martin Roth2ed0aa22016-01-05 20:58:58 -07001864 0xffffffff, 0xffffffff, /* nonexistent */
1865 0xffffffff, 0xffffffff, /* nonexistent */
1866 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001867 };
1868
1869 static const u32 command_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001870 0x04020208, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001871 0xffffffff, 0xffffffff, /* nonexistent */
1872 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001873
Stefan Reinauer278534d2008-10-29 04:51:07 +00001874 0x00060108, 0x00000000, /* DDR400 FSB533 */
1875 0x04020108, 0x00000000, /* DDR533 FSB533 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001876 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001877
1878 0x00040318, 0x00000000, /* DDR400 FSB667 */
1879 0x04020118, 0x00000000, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001880 0x02010804, 0x00000000, /* DDR667 FSB667 */
1881
Martin Roth2ed0aa22016-01-05 20:58:58 -07001882 0xffffffff, 0xffffffff, /* nonexistent */
1883 0xffffffff, 0xffffffff, /* nonexistent */
1884 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001885
Martin Roth2ed0aa22016-01-05 20:58:58 -07001886 0xffffffff, 0xffffffff, /* nonexistent */
1887 0xffffffff, 0xffffffff, /* nonexistent */
1888 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001889 };
1890
Julius Wernercd49cce2019-03-05 16:53:33 -08001891#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001892 /* i945 G/P */
1893 static const u32 data_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001894 0xffffffff, 0xffffffff, /* nonexistent */
1895 0xffffffff, 0xffffffff, /* nonexistent */
1896 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001897
1898 0x10080201, 0x00000000, /* DDR400 FSB533 */
1899 0x00100401, 0x00000000, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001900 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001901
Martin Roth2ed0aa22016-01-05 20:58:58 -07001902 0xffffffff, 0xffffffff, /* nonexistent */
1903 0xffffffff, 0xffffffff, /* nonexistent */
1904 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001905
1906 0x04020108, 0x00000000, /* DDR400 FSB800 */
1907 0x00020108, 0x00000000, /* DDR533 FSB800 */
1908 0x00080201, 0x00000000, /* DDR667 FSB800 */
1909
1910 0x00010402, 0x00000000, /* DDR400 FSB1066 */
1911 0x04020108, 0x00000000, /* DDR533 FSB1066 */
1912 0x08040110, 0x00000000, /* DDR667 FSB1066 */
1913 };
1914
1915 static const u32 command_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001916 0xffffffff, 0xffffffff, /* nonexistent */
1917 0xffffffff, 0xffffffff, /* nonexistent */
1918 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001919
1920 0x00010800, 0x00000402, /* DDR400 FSB533 */
1921 0x01000400, 0x00000200, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001922 0x00020904, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001923
Martin Roth2ed0aa22016-01-05 20:58:58 -07001924 0xffffffff, 0xffffffff, /* nonexistent */
1925 0xffffffff, 0xffffffff, /* nonexistent */
1926 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001927
1928 0x02010804, 0x00000000, /* DDR400 FSB800 */
1929 0x00010402, 0x00000000, /* DDR533 FSB800 */
Arthur Heymans8b6df622016-10-16 10:58:01 +02001930 0x04020130, 0x00000008, /* DDR667 FSB800 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001931
1932 0x00020904, 0x00000000, /* DDR400 FSB1066 */
1933 0x02010804, 0x00000000, /* DDR533 FSB1066 */
1934 0x180601c0, 0x00000020, /* DDR667 FSB1066 */
1935 };
1936#endif
1937
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001938 printk(BIOS_DEBUG, "Programming Clock Crossing...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001939
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001940 printk(BIOS_DEBUG, "MEM=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001941 switch (memclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001942 case 400:
1943 printk(BIOS_DEBUG, "400"); idx += 0; break;
1944 case 533:
1945 printk(BIOS_DEBUG, "533"); idx += 2; break;
1946 case 667:
1947 printk(BIOS_DEBUG, "667"); idx += 4; break;
1948 default:
1949 printk(BIOS_DEBUG, "RSVD %x", memclk()); return;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001950 }
1951
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001952 printk(BIOS_DEBUG, " FSB=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001953 switch (fsbclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001954 case 400:
1955 printk(BIOS_DEBUG, "400"); idx += 0; break;
1956 case 533:
1957 printk(BIOS_DEBUG, "533"); idx += 6; break;
1958 case 667:
1959 printk(BIOS_DEBUG, "667"); idx += 12; break;
1960 case 800:
1961 printk(BIOS_DEBUG, "800"); idx += 18; break;
1962 case 1066:
1963 printk(BIOS_DEBUG, "1066"); idx += 24; break;
1964 default:
1965 printk(BIOS_DEBUG, "RSVD %x\n", fsbclk()); return;
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001966 }
1967
Arthur Heymans70a8e342017-03-09 11:30:23 +01001968 if (command_clock_crossing[idx] == 0xffffffff)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001969 printk(BIOS_DEBUG, "Invalid MEM/FSB combination!\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001970
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001971 MCHBAR32(CCCFT + 0) = command_clock_crossing[idx];
1972 MCHBAR32(CCCFT + 4) = command_clock_crossing[idx + 1];
1973
Stefan Reinauer278534d2008-10-29 04:51:07 +00001974 MCHBAR32(C0DCCFT + 0) = data_clock_crossing[idx];
1975 MCHBAR32(C0DCCFT + 4) = data_clock_crossing[idx + 1];
1976 MCHBAR32(C1DCCFT + 0) = data_clock_crossing[idx];
1977 MCHBAR32(C1DCCFT + 4) = data_clock_crossing[idx + 1];
1978
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001979 printk(BIOS_DEBUG, "... ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001980}
1981
1982static void sdram_disable_fast_dispatch(void)
1983{
1984 u32 reg32;
1985
1986 reg32 = MCHBAR32(FSBPMC3);
1987 reg32 |= (1 << 1);
1988 MCHBAR32(FSBPMC3) = reg32;
1989
1990 reg32 = MCHBAR32(SBTEST);
1991 reg32 |= (3 << 1);
1992 MCHBAR32(SBTEST) = reg32;
1993}
1994
1995static void sdram_pre_jedec_initialization(void)
1996{
1997 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001998
Stefan Reinauer278534d2008-10-29 04:51:07 +00001999 reg32 = MCHBAR32(WCC);
2000 reg32 &= 0x113ff3ff;
2001 reg32 |= (4 << 29) | (3 << 25) | (1 << 10);
2002 MCHBAR32(WCC) = reg32;
2003
2004 MCHBAR32(SMVREFC) |= (1 << 6);
2005
2006 MCHBAR32(MMARB0) &= ~(3 << 17);
2007 MCHBAR32(MMARB0) |= (1 << 21) | (1 << 16);
2008
2009 MCHBAR32(MMARB1) &= ~(7 << 8);
2010 MCHBAR32(MMARB1) |= (3 << 8);
2011
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002012 /* Adaptive Idle Timer Control */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002013 MCHBAR32(C0AIT) = 0x000006c4;
2014 MCHBAR32(C0AIT+4) = 0x871a066d;
2015
2016 MCHBAR32(C1AIT) = 0x000006c4;
2017 MCHBAR32(C1AIT+4) = 0x871a066d;
2018}
2019
2020#define EA_DUALCHANNEL_XOR_BANK_RANK_MODE (0xd4 << 24)
2021#define EA_DUALCHANNEL_XOR_BANK_MODE (0xf4 << 24)
2022#define EA_DUALCHANNEL_BANK_RANK_MODE (0xc2 << 24)
2023#define EA_DUALCHANNEL_BANK_MODE (0xe2 << 24)
2024#define EA_SINGLECHANNEL_XOR_BANK_RANK_MODE (0x91 << 24)
2025#define EA_SINGLECHANNEL_XOR_BANK_MODE (0xb1 << 24)
2026#define EA_SINGLECHANNEL_BANK_RANK_MODE (0x80 << 24)
2027#define EA_SINGLECHANNEL_BANK_MODE (0xa0 << 24)
2028
2029static void sdram_enhanced_addressing_mode(struct sys_info *sysinfo)
2030{
2031 u32 chan0 = 0, chan1 = 0;
Paul Menzeld789b6582020-03-14 11:50:34 +01002032 bool chan0_dualsided, chan1_dualsided, chan0_populated, chan1_populated;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002033
Paul Menzel842dd332020-03-14 10:37:40 +01002034 chan0_populated = (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Stefan Reinauer278534d2008-10-29 04:51:07 +00002035 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED);
Elyes HAOUAS308aeff2017-02-24 12:53:07 +01002036 chan1_populated = (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
2037 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002038 chan0_dualsided = (sysinfo->banksize[1] || sysinfo->banksize[3]);
2039 chan1_dualsided = (sysinfo->banksize[5] || sysinfo->banksize[7]);
2040
2041 if (sdram_capabilities_enhanced_addressing_xor()) {
2042 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002043 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002044 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002045 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002046 chan0 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002047 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002048 chan0 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002049 }
2050 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002051 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002052 chan1 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002053 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002054 chan1 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002055 }
2056 } else {
2057 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002058 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002059 chan0 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002060 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002061 chan0 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002062
Arthur Heymans70a8e342017-03-09 11:30:23 +01002063 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002064 chan1 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002065 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002066 chan1 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002067 }
2068 } else {
2069 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002070 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002071 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002072 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002073 chan0 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002074 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002075 chan0 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002076 }
2077 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002078 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002079 chan1 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002080 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002081 chan1 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002082 }
2083 } else {
2084 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002085 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002086 chan0 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002087 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002088 chan0 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002089
Arthur Heymans70a8e342017-03-09 11:30:23 +01002090 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002091 chan1 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002092 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002093 chan1 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002094 }
2095 }
2096
2097 MCHBAR32(C0DRC1) &= 0x00ffffff;
2098 MCHBAR32(C0DRC1) |= chan0;
2099 MCHBAR32(C1DRC1) &= 0x00ffffff;
2100 MCHBAR32(C1DRC1) |= chan1;
2101}
2102
2103static void sdram_post_jedec_initialization(struct sys_info *sysinfo)
2104{
2105 u32 reg32;
2106
2107 /* Enable Channel XORing for Dual Channel Interleave */
2108 if (sysinfo->interleaved) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002109
Stefan Reinauer278534d2008-10-29 04:51:07 +00002110 reg32 = MCHBAR32(DCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002111 reg32 &= ~(1 << 10);
Stefan Reinauer30140a52009-03-11 16:20:39 +00002112 reg32 |= (1 << 9);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002113 MCHBAR32(DCC) = reg32;
2114 }
2115
2116 /* DRAM mode optimizations */
2117 sdram_enhanced_addressing_mode(sysinfo);
2118
2119 reg32 = MCHBAR32(FSBPMC3);
2120 reg32 &= ~(1 << 1);
2121 MCHBAR32(FSBPMC3) = reg32;
2122
2123 reg32 = MCHBAR32(SBTEST);
2124 reg32 &= ~(1 << 2);
2125 MCHBAR32(SBTEST) = reg32;
2126
2127 reg32 = MCHBAR32(SBOCC);
2128 reg32 &= 0xffbdb6ff;
2129 reg32 |= (0xbdb6 << 8) | (1 << 0);
2130 MCHBAR32(SBOCC) = reg32;
2131}
2132
2133static void sdram_power_management(struct sys_info *sysinfo)
2134{
2135 u8 reg8;
2136 u16 reg16;
2137 u32 reg32;
2138 int integrated_graphics = 1;
2139 int i;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002140
Stefan Reinauer278534d2008-10-29 04:51:07 +00002141 reg32 = MCHBAR32(C0DRT2);
2142 reg32 &= 0xffffff00;
2143 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002144 reg32 |= (1 << 5) | (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002145 MCHBAR32(C0DRT2) = reg32;
2146
2147 reg32 = MCHBAR32(C1DRT2);
2148 reg32 &= 0xffffff00;
2149 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002150 reg32 |= (1 << 5) | (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002151 MCHBAR32(C1DRT2) = reg32;
2152
2153 reg32 = MCHBAR32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002154
2155 reg32 |= (1 << 12) | (1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002156 MCHBAR32(C0DRC1) = reg32;
2157
2158 reg32 = MCHBAR32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002159
2160 reg32 |= (1 << 12) | (1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002161 MCHBAR32(C1DRC1) = reg32;
2162
Julius Wernercd49cce2019-03-05 16:53:33 -08002163 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002164 if (i945_silicon_revision() > 1) {
2165 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2166 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002167
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002168 MCHBAR16(UPMC1) = 0x1010 | peg_bits;
2169 } else {
2170 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2171 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002172
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002173 /* Rev 0 and 1 */
2174 MCHBAR16(UPMC1) = 0x0010 | peg_bits;
2175 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002176 }
2177
2178 reg16 = MCHBAR16(UPMC2);
2179 reg16 &= 0xfc00;
2180 reg16 |= 0x0100;
2181 MCHBAR16(UPMC2) = reg16;
2182
2183 MCHBAR32(UPMC3) = 0x000f06ff;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002184
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002185 for (i = 0; i < 5; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002186 MCHBAR32(UPMC3) &= ~(1 << 16);
2187 MCHBAR32(UPMC3) |= (1 << 16);
2188 }
2189
2190 MCHBAR32(GIPMC1) = 0x8000000c;
2191
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002192 reg16 = MCHBAR16(CPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002193 reg16 &= ~(7 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002194 if (i945_silicon_revision() > 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002195 reg16 |= (6 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002196 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002197 reg16 |= (4 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002198 MCHBAR16(CPCTL) = reg16;
2199
Stefan Reinauer30140a52009-03-11 16:20:39 +00002200#if 0
Stefan Reinauer278534d2008-10-29 04:51:07 +00002201 if ((MCHBAR32(ECO) & (1 << 16)) != 0) {
Stefan Reinauer30140a52009-03-11 16:20:39 +00002202#else
2203 if (i945_silicon_revision() != 0) {
2204#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002205 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002206 case 667:
2207 MCHBAR32(HGIPMC2) = 0x0d590d59; break;
2208 case 533:
2209 MCHBAR32(HGIPMC2) = 0x155b155b; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002210 }
2211 } else {
2212 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002213 case 667:
2214 MCHBAR32(HGIPMC2) = 0x09c409c4; break;
2215 case 533:
2216 MCHBAR32(HGIPMC2) = 0x0fa00fa0; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002217 }
2218 }
2219
2220 MCHBAR32(FSBPMC1) = 0x8000000c;
2221
2222 reg32 = MCHBAR32(C2C3TT);
2223 reg32 &= 0xffff0000;
2224 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002225 case 667:
2226 reg32 |= 0x0600; break;
2227 case 533:
2228 reg32 |= 0x0480; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002229 }
2230 MCHBAR32(C2C3TT) = reg32;
2231
2232 reg32 = MCHBAR32(C3C4TT);
2233 reg32 &= 0xffff0000;
2234 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002235 case 667:
2236 reg32 |= 0x0b80; break;
2237 case 533:
2238 reg32 |= 0x0980; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002239 }
2240 MCHBAR32(C3C4TT) = reg32;
2241
Arthur Heymans70a8e342017-03-09 11:30:23 +01002242 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002243 MCHBAR32(ECO) &= ~(1 << 16);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002244 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002245 MCHBAR32(ECO) |= (1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002246
2247#if 0
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002248
Arthur Heymans70a8e342017-03-09 11:30:23 +01002249 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002250 MCHBAR32(FSBPMC3) &= ~(1 << 29);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002251 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002252 MCHBAR32(FSBPMC3) |= (1 << 29);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002253#endif
2254 MCHBAR32(FSBPMC3) &= ~(1 << 29);
2255
2256 MCHBAR32(FSBPMC3) |= (1 << 21);
2257
2258 MCHBAR32(FSBPMC3) &= ~(1 << 19);
2259
2260 MCHBAR32(FSBPMC3) &= ~(1 << 13);
2261
2262 reg32 = MCHBAR32(FSBPMC4);
2263 reg32 &= ~(3 << 24);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002264 reg32 |= (2 << 24);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002265 MCHBAR32(FSBPMC4) = reg32;
2266
2267 MCHBAR32(FSBPMC4) |= (1 << 21);
2268
2269 MCHBAR32(FSBPMC4) |= (1 << 5);
2270
Arthur Heymans70a8e342017-03-09 11:30:23 +01002271 if ((i945_silicon_revision() < 2)) { /* || cpuid() = 0x6e8 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002272 /* stepping 0 and 1 or CPUID 6e8 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002273 MCHBAR32(FSBPMC4) &= ~(1 << 4);
2274 } else {
Stefan Reinauer30140a52009-03-11 16:20:39 +00002275 MCHBAR32(FSBPMC4) |= (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002276 }
2277
Arthur Heymans70a8e342017-03-09 11:30:23 +01002278 reg8 = pci_read_config8(PCI_DEV(0, 0x0, 0), 0xfc);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002279 reg8 |= (1 << 4);
2280 pci_write_config8(PCI_DEV(0, 0x0, 0), 0xfc, reg8);
2281
Arthur Heymans70a8e342017-03-09 11:30:23 +01002282 reg8 = pci_read_config8(PCI_DEV(0, 0x2, 0), 0xc1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002283 reg8 |= (1 << 2);
2284 pci_write_config8(PCI_DEV(0, 0x2, 0), 0xc1, reg8);
2285
Stefan Reinauerde3206a2010-02-22 06:09:43 +00002286#ifdef C2_SELF_REFRESH_DISABLE
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002287
Stefan Reinauer278534d2008-10-29 04:51:07 +00002288 if (integrated_graphics) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002289 printk(BIOS_DEBUG, "C2 self-refresh with IGD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002290 MCHBAR16(MIPMC4) = 0x0468;
2291 MCHBAR16(MIPMC5) = 0x046c;
2292 MCHBAR16(MIPMC6) = 0x046c;
2293 } else {
2294 MCHBAR16(MIPMC4) = 0x6468;
2295 MCHBAR16(MIPMC5) = 0x646c;
2296 MCHBAR16(MIPMC6) = 0x646c;
2297 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002298#else
2299 if (integrated_graphics) {
2300 MCHBAR16(MIPMC4) = 0x04f8;
2301 MCHBAR16(MIPMC5) = 0x04fc;
2302 MCHBAR16(MIPMC6) = 0x04fc;
2303 } else {
2304 MCHBAR16(MIPMC4) = 0x64f8;
2305 MCHBAR16(MIPMC5) = 0x64fc;
2306 MCHBAR16(MIPMC6) = 0x64fc;
2307 }
2308
2309#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002310
2311 reg32 = MCHBAR32(PMCFG);
2312 reg32 &= ~(3 << 17);
2313 reg32 |= (2 << 17);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002314 MCHBAR32(PMCFG) = reg32;
2315
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002316 MCHBAR32(PMCFG) |= (1 << 4);
2317
Stefan Reinauer278534d2008-10-29 04:51:07 +00002318 reg32 = MCHBAR32(0xc30);
2319 reg32 &= 0xffffff00;
2320 reg32 |= 0x01;
2321 MCHBAR32(0xc30) = reg32;
2322
2323 MCHBAR32(0xb18) &= ~(1 << 21);
2324}
2325
2326static void sdram_thermal_management(void)
2327{
Stefan Reinauer278534d2008-10-29 04:51:07 +00002328
Stefan Reinauer278534d2008-10-29 04:51:07 +00002329 MCHBAR8(TCO1) = 0x00;
2330 MCHBAR8(TCO0) = 0x00;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002331
2332 /* The Thermal Sensors for DIMMs at 0x50, 0x52 are at I2C addr
2333 * 0x30/0x32.
2334 */
2335
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002336 /* TODO This is not implemented yet. Volunteers? */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002337}
2338
2339static void sdram_save_receive_enable(void)
2340{
2341 int i;
2342 u32 reg32;
2343 u8 values[4];
2344
2345 /* The following values are stored to an unused CMOS
2346 * area and restored instead of recalculated in case
2347 * of an S3 resume.
2348 *
Arthur Heymans70a8e342017-03-09 11:30:23 +01002349 * C0WL0REOST [7:0] -> 8 bit
2350 * C1WL0REOST [7:0] -> 8 bit
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002351 * RCVENMT [11:8] [3:0] -> 8 bit
2352 * C0DRT1 [27:24] -> 4 bit
2353 * C1DRT1 [27:24] -> 4 bit
2354 */
2355
2356 values[0] = MCHBAR8(C0WL0REOST);
2357 values[1] = MCHBAR8(C1WL0REOST);
2358
2359 reg32 = MCHBAR32(RCVENMT);
2360 values[2] = (u8)((reg32 >> (8 - 4)) & 0xf0) | (reg32 & 0x0f);
2361
2362 reg32 = MCHBAR32(C0DRT1);
2363 values[3] = (reg32 >> 24) & 0x0f;
2364 reg32 = MCHBAR32(C1DRT1);
2365 values[3] |= (reg32 >> (24 - 4)) & 0xf0;
2366
2367 /* coreboot only uses bytes 0 - 127 for its CMOS values so far
Edwin Beasanteb50c7d2010-07-06 21:05:04 +00002368 * so we grab bytes 128 - 131 to save the receive enable values
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002369 */
2370
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002371 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002372 cmos_write(values[i], 128 + i);
2373}
2374
2375static void sdram_recover_receive_enable(void)
2376{
2377 int i;
2378 u32 reg32;
2379 u8 values[4];
2380
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002381 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002382 values[i] = cmos_read(128 + i);
2383
2384 MCHBAR8(C0WL0REOST) = values[0];
2385 MCHBAR8(C1WL0REOST) = values[1];
2386
2387 reg32 = MCHBAR32(RCVENMT);
2388 reg32 &= ~((0x0f << 8) | (0x0f << 0));
2389 reg32 |= ((u32)(values[2] & 0xf0) << (8 - 4)) | (values[2] & 0x0f);
2390 MCHBAR32(RCVENMT) = reg32;
2391
2392 reg32 = MCHBAR32(C0DRT1) & ~(0x0f << 24);
2393 reg32 |= (u32)(values[3] & 0x0f) << 24;
2394 MCHBAR32(C0DRT1) = reg32;
2395
2396 reg32 = MCHBAR32(C1DRT1) & ~(0x0f << 24);
2397 reg32 |= (u32)(values[3] & 0xf0) << (24 - 4);
2398 MCHBAR32(C1DRT1) = reg32;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002399}
2400
Stefan Reinauer278534d2008-10-29 04:51:07 +00002401static void sdram_program_receive_enable(struct sys_info *sysinfo)
2402{
2403 MCHBAR32(REPC) |= (1 << 0);
2404
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002405 /* Program Receive Enable Timings */
2406 if (sysinfo->boot_path == BOOT_PATH_RESUME) {
2407 sdram_recover_receive_enable();
2408 } else {
2409 receive_enable_adjust(sysinfo);
2410 sdram_save_receive_enable();
2411 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002412
2413 MCHBAR32(C0DRC1) |= (1 << 6);
2414 MCHBAR32(C1DRC1) |= (1 << 6);
2415 MCHBAR32(C0DRC1) &= ~(1 << 6);
2416 MCHBAR32(C1DRC1) &= ~(1 << 6);
2417
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002418 MCHBAR32(MIPMC3) |= (0x0f << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002419}
2420
2421/**
2422 * @brief Enable On-Die Termination for DDR2.
2423 *
2424 */
2425
2426static void sdram_on_die_termination(struct sys_info *sysinfo)
2427{
2428 static const u32 odt[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002429 0x00024911, 0xe0010000,
2430 0x00049211, 0xe0020000,
2431 0x0006db11, 0xe0030000,
Stefan Reinauer278534d2008-10-29 04:51:07 +00002432 };
2433
2434 u32 reg32;
2435 int cas;
2436
2437 reg32 = MCHBAR32(ODTC);
2438 reg32 &= ~(3 << 16);
2439 reg32 |= (1 << 14) | (1 << 6) | (2 << 16);
2440 MCHBAR32(ODTC) = reg32;
2441
Paul Menzelb4d9f222020-03-14 10:34:29 +01002442 if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED ||
2443 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
Elyes HAOUAS38424982016-08-21 12:01:04 +02002444 printk(BIOS_DEBUG, "one dimm per channel config..\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002445
Stefan Reinauer278534d2008-10-29 04:51:07 +00002446 reg32 = MCHBAR32(C0ODT);
2447 reg32 &= ~(7 << 28);
2448 MCHBAR32(C0ODT) = reg32;
2449 reg32 = MCHBAR32(C1ODT);
2450 reg32 &= ~(7 << 28);
2451 MCHBAR32(C1ODT) = reg32;
2452 }
2453
2454 cas = sysinfo->cas;
2455
2456 reg32 = MCHBAR32(C0ODT) & 0xfff00000;
2457 reg32 |= odt[(cas-3) * 2];
2458 MCHBAR32(C0ODT) = reg32;
2459
2460 reg32 = MCHBAR32(C1ODT) & 0xfff00000;
2461 reg32 |= odt[(cas-3) * 2];
2462 MCHBAR32(C1ODT) = reg32;
2463
2464 reg32 = MCHBAR32(C0ODT + 4) & 0x1fc8ffff;
2465 reg32 |= odt[((cas-3) * 2) + 1];
2466 MCHBAR32(C0ODT + 4) = reg32;
2467
2468 reg32 = MCHBAR32(C1ODT + 4) & 0x1fc8ffff;
2469 reg32 |= odt[((cas-3) * 2) + 1];
2470 MCHBAR32(C1ODT + 4) = reg32;
2471}
2472
2473/**
2474 * @brief Enable clocks to populated sockets
2475 */
2476
2477static void sdram_enable_memory_clocks(struct sys_info *sysinfo)
2478{
2479 u8 clocks[2] = { 0, 0 };
2480
Julius Wernercd49cce2019-03-05 16:53:33 -08002481#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002482#define CLOCKS_WIDTH 2
Julius Wernercd49cce2019-03-05 16:53:33 -08002483#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002484#define CLOCKS_WIDTH 3
2485#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002486 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002487 clocks[0] |= (1 << CLOCKS_WIDTH)-1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002488
2489 if (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002490 clocks[0] |= ((1 << CLOCKS_WIDTH)-1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002491
2492 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002493 clocks[1] |= (1 << CLOCKS_WIDTH)-1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002494
2495 if (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002496 clocks[1] |= ((1 << CLOCKS_WIDTH)-1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002497
Julius Wernercd49cce2019-03-05 16:53:33 -08002498#if CONFIG(OVERRIDE_CLOCK_DISABLE)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002499 /* Usually system firmware turns off system memory clock signals
2500 * to unused SO-DIMM slots to reduce EMI and power consumption.
2501 * However, the Kontron 986LCD-M does not like unused clock
2502 * signals to be disabled.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002503 */
2504
2505 clocks[0] = 0xf; /* force all clock gate pairs to enable */
2506 clocks[1] = 0xf; /* force all clock gate pairs to enable */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002507#endif
2508
2509 MCHBAR8(C0DCLKDIS) = clocks[0];
2510 MCHBAR8(C1DCLKDIS) = clocks[1];
2511}
2512
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002513#define RTT_ODT_NONE 0
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002514#define RTT_ODT_50_OHM ((1 << 9) | (1 << 5))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002515#define RTT_ODT_75_OHM (1 << 5)
2516#define RTT_ODT_150_OHM (1 << 9)
2517
Arthur Heymans70a8e342017-03-09 11:30:23 +01002518#define EMRS_OCD_DEFAULT ((1 << 12) | (1 << 11) | (1 << 10))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002519
2520#define MRS_CAS_3 (3 << 7)
2521#define MRS_CAS_4 (4 << 7)
2522#define MRS_CAS_5 (5 << 7)
2523
2524#define MRS_TWR_3 (2 << 12)
2525#define MRS_TWR_4 (3 << 12)
2526#define MRS_TWR_5 (4 << 12)
2527
2528#define MRS_BT (1 << 6)
2529
2530#define MRS_BL4 (2 << 3)
2531#define MRS_BL8 (3 << 3)
2532
2533static void sdram_jedec_enable(struct sys_info *sysinfo)
2534{
2535 int i, nonzero;
2536 u32 bankaddr = 0, tmpaddr, mrsaddr = 0;
2537
2538 for (i = 0, nonzero = -1; i < 8; i++) {
Elyes HAOUAS01912202019-01-19 16:36:38 +01002539 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002540 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002541
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002542 printk(BIOS_DEBUG, "jedec enable sequence: bank %d\n", i);
Elyes HAOUAS01912202019-01-19 16:36:38 +01002543
2544 if (nonzero != -1) {
2545 if (sysinfo->interleaved && nonzero < 4 && i >= 4) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002546 bankaddr = 0x40;
Elyes HAOUAS01912202019-01-19 16:36:38 +01002547 } else {
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002548 printk(BIOS_DEBUG, "bankaddr from bank size of rank %d\n",
2549 nonzero);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002550 bankaddr += sysinfo->banksize[nonzero] <<
2551 (sysinfo->interleaved ? 26 : 25);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002552 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002553 }
2554
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002555 /*
2556 * We have a bank with a non-zero size... Remember it
Stefan Reinauer278534d2008-10-29 04:51:07 +00002557 * for the next offset we have to calculate
2558 */
2559 nonzero = i;
2560
2561 /* Get CAS latency set up */
2562 switch (sysinfo->cas) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002563 case 5:
2564 mrsaddr = MRS_CAS_5; break;
2565 case 4:
2566 mrsaddr = MRS_CAS_4; break;
2567 case 3:
2568 mrsaddr = MRS_CAS_3; break;
2569 default:
2570 die("Jedec Error (CAS).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002571 }
2572
2573 /* Get tWR set */
2574 switch (sysinfo->twr) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002575 case 5:
2576 mrsaddr |= MRS_TWR_5; break;
2577 case 4:
2578 mrsaddr |= MRS_TWR_4; break;
2579 case 3:
2580 mrsaddr |= MRS_TWR_3; break;
2581 default:
2582 die("Jedec Error (tWR).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002583 }
2584
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002585 /* Set "Burst Type" */
2586 mrsaddr |= MRS_BT;
2587
Stefan Reinauer278534d2008-10-29 04:51:07 +00002588 /* Interleaved */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002589 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002590 mrsaddr = mrsaddr << 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002591
2592 /* Only burst length 8 supported */
2593 mrsaddr |= MRS_BL8;
2594
2595 /* Apply NOP */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002596 PRINTK_DEBUG("Apply NOP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002597 do_ram_command(RAM_COMMAND_NOP);
2598 ram_read32(bankaddr);
2599
2600 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002601 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002602 do_ram_command(RAM_COMMAND_PRECHARGE);
2603 ram_read32(bankaddr);
2604
2605 /* Extended Mode Register Set (2) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002606 PRINTK_DEBUG("Extended Mode Register Set(2)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002607 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_2);
2608 ram_read32(bankaddr);
2609
2610 /* Extended Mode Register Set (3) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002611 PRINTK_DEBUG("Extended Mode Register Set(3)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002612 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_3);
2613 ram_read32(bankaddr);
2614
2615 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002616 PRINTK_DEBUG("Extended Mode Register Set\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002617 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2618 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002619 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002620 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002621 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002622 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002623 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002624 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002625 ram_read32(tmpaddr);
2626
2627 /* Mode Register Set: Reset DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002628 PRINTK_DEBUG("MRS: Reset DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002629 do_ram_command(RAM_COMMAND_MRS);
2630 tmpaddr = bankaddr;
2631 tmpaddr |= mrsaddr;
2632 /* Set DLL reset bit */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002633 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002634 tmpaddr |= (1 << 12);
2635 else
2636 tmpaddr |= (1 << 11);
2637 ram_read32(tmpaddr);
2638
2639 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002640 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002641 do_ram_command(RAM_COMMAND_PRECHARGE);
2642 ram_read32(bankaddr);
2643
2644 /* CAS before RAS Refresh */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002645 PRINTK_DEBUG("CAS before RAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002646 do_ram_command(RAM_COMMAND_CBR);
2647
2648 /* CBR wants two READs */
2649 ram_read32(bankaddr);
2650 ram_read32(bankaddr);
2651
2652 /* Mode Register Set: Enable DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002653 PRINTK_DEBUG("MRS: Enable DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002654 do_ram_command(RAM_COMMAND_MRS);
2655
2656 tmpaddr = bankaddr;
2657 tmpaddr |= mrsaddr;
2658 ram_read32(tmpaddr);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002659
Stefan Reinauer278534d2008-10-29 04:51:07 +00002660 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002661 PRINTK_DEBUG("Extended Mode Register Set: ODT/OCD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002662 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002663
Stefan Reinauer278534d2008-10-29 04:51:07 +00002664 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002665 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002666 tmpaddr |= RTT_ODT_75_OHM | EMRS_OCD_DEFAULT;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002667 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002668 tmpaddr |= ((RTT_ODT_150_OHM | EMRS_OCD_DEFAULT) << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002669 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002670 tmpaddr |= RTT_ODT_150_OHM | EMRS_OCD_DEFAULT;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002671 ram_read32(tmpaddr);
2672
2673 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002674 PRINTK_DEBUG("Extended Mode Register Set: OCD Exit\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002675 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2676
2677 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002678 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002679 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002680 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002681 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002682 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002683 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002684 ram_read32(tmpaddr);
2685 }
2686}
2687
2688static void sdram_init_complete(void)
2689{
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002690 PRINTK_DEBUG("Normal Operation\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002691 do_ram_command(RAM_COMMAND_NORMAL);
2692}
2693
2694static void sdram_setup_processor_side(void)
2695{
2696 if (i945_silicon_revision() == 0)
2697 MCHBAR32(FSBPMC3) |= (1 << 2);
2698
2699 MCHBAR8(0xb00) |= 1;
2700
2701 if (i945_silicon_revision() == 0)
2702 MCHBAR32(SLPCTL) |= (1 << 8);
2703}
2704
Stefan Reinauer278534d2008-10-29 04:51:07 +00002705/**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002706 * @param boot_path: 0 = normal, 1 = reset, 2 = resume from s3
Martin Rothf4cb4122015-01-06 10:27:39 -07002707 * @param spd_addresses pointer to a list of SPD addresses
Stefan Reinauer278534d2008-10-29 04:51:07 +00002708 */
Sven Schnelle541269b2011-02-21 09:39:17 +00002709void sdram_initialize(int boot_path, const u8 *spd_addresses)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002710{
2711 struct sys_info sysinfo;
Arthur Heymans0ab49042017-02-06 22:40:14 +01002712 u8 reg8;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002713
Patrick Georgi771328f2015-07-13 19:24:07 +02002714 timestamp_add_now(TS_BEFORE_INITRAM);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002715 printk(BIOS_DEBUG, "Setting up RAM controller.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002716
2717 memset(&sysinfo, 0, sizeof(sysinfo));
2718
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002719 sysinfo.boot_path = boot_path;
Sven Schnelle541269b2011-02-21 09:39:17 +00002720 sysinfo.spd_addresses = spd_addresses;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002721
Stefan Reinauer278534d2008-10-29 04:51:07 +00002722 /* Look at the type of DIMMs and verify all DIMMs are x8 or x16 width */
2723 sdram_get_dram_configuration(&sysinfo);
2724
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002725 /* If error, do cold boot */
2726 sdram_detect_errors(&sysinfo);
2727
Stefan Reinauer278534d2008-10-29 04:51:07 +00002728 /* Program PLL settings */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002729 sdram_program_pll_settings(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002730
Arthur Heymans18537812016-12-28 21:20:45 +01002731 /*
2732 * Program Graphics Frequency
2733 * Set core display and render clock on 945GC to the max
2734 */
Julius Wernercd49cce2019-03-05 16:53:33 -08002735 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM))
Arthur Heymans18537812016-12-28 21:20:45 +01002736 sdram_program_graphics_frequency(&sysinfo);
2737 else
2738 pci_write_config16(PCI_DEV(0, 2, 0), GCFC, 0x0534);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002739
2740 /* Program System Memory Frequency */
2741 sdram_program_memory_frequency(&sysinfo);
2742
2743 /* Determine Mode of Operation (Interleaved etc) */
2744 sdram_set_channel_mode(&sysinfo);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002745
Stefan Reinauer278534d2008-10-29 04:51:07 +00002746 /* Program Clock Crossing values */
2747 sdram_program_clock_crossing();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002748
Stefan Reinauer278534d2008-10-29 04:51:07 +00002749 /* Disable fast dispatch */
2750 sdram_disable_fast_dispatch();
2751
2752 /* Enable WIODLL Power Down in ACPI states */
2753 MCHBAR32(C0DMC) |= (1 << 24);
2754 MCHBAR32(C1DMC) |= (1 << 24);
2755
2756 /* Program DRAM Row Boundary/Attribute Registers */
2757
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002758 /* program row size DRB and set TOLUD */
2759 sdram_program_row_boundaries(&sysinfo);
2760
2761 /* program page size DRA */
2762 sdram_set_row_attributes(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002763
2764 /* Program CxBNKARC */
2765 sdram_set_bank_architecture(&sysinfo);
2766
2767 /* Program DRAM Timing and Control registers based on SPD */
2768 sdram_set_timing_and_control(&sysinfo);
2769
2770 /* On-Die Termination Adjustment */
2771 sdram_on_die_termination(&sysinfo);
2772
2773 /* Pre Jedec Initialization */
2774 sdram_pre_jedec_initialization();
2775
2776 /* Perform System Memory IO Initialization */
2777 sdram_initialize_system_memory_io(&sysinfo);
2778
2779 /* Perform System Memory IO Buffer Enable */
2780 sdram_enable_system_memory_io(&sysinfo);
2781
2782 /* Enable System Memory Clocks */
2783 sdram_enable_memory_clocks(&sysinfo);
2784
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002785 if (boot_path == BOOT_PATH_NORMAL) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002786 /* Jedec Initialization sequence */
2787 sdram_jedec_enable(&sysinfo);
2788 }
2789
2790 /* Program Power Management Registers */
2791 sdram_power_management(&sysinfo);
2792
2793 /* Post Jedec Init */
2794 sdram_post_jedec_initialization(&sysinfo);
2795
2796 /* Program DRAM Throttling */
2797 sdram_thermal_management();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002798
Stefan Reinauer278534d2008-10-29 04:51:07 +00002799 /* Normal Operations */
Stefan Reinaueraca6ec62009-10-26 17:12:21 +00002800 sdram_init_complete();
Stefan Reinauer278534d2008-10-29 04:51:07 +00002801
2802 /* Program Receive Enable Timings */
2803 sdram_program_receive_enable(&sysinfo);
2804
2805 /* Enable Periodic RCOMP */
2806 sdram_enable_rcomp();
2807
2808 /* Tell ICH7 that we're done */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +01002809 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002810 reg8 &= ~(1 << 7);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +01002811 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002812
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002813 printk(BIOS_DEBUG, "RAM initialization finished.\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002814
Stefan Reinauer278534d2008-10-29 04:51:07 +00002815 sdram_setup_processor_side();
Patrick Georgi771328f2015-07-13 19:24:07 +02002816 timestamp_add_now(TS_AFTER_INITRAM);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002817}