blob: 709677469f0b735372752f080e03ca5d1b061a86 [file] [log] [blame]
Stefan Reinauer278534d2008-10-29 04:51:07 +00001/*
2 * This file is part of the coreboot project.
3 *
Stefan Reinauer71a3d962009-07-21 21:44:24 +00004 * Copyright (C) 2007-2009 coresystems GmbH
Arthur Heymans0ab49042017-02-06 22:40:14 +01005 * Copyright (C) 2017 Arthur Heymans <arthur@aheymans.xyz>
Stefan Reinauer278534d2008-10-29 04:51:07 +00006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Stefan Reinauer278534d2008-10-29 04:51:07 +000015 */
16
Patrick Georgid0835952010-10-05 09:07:10 +000017#include <console/console.h>
Kyösti Mälkki7fbed222019-07-11 08:14:07 +030018#include <delay.h>
Arthur Heymans885c2892016-10-03 17:16:48 +020019#include <device/pci_def.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020020#include <device/pci_ops.h>
Elyes HAOUAS420d7e02019-04-21 18:39:34 +020021#include <cf9_reset.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020022#include <device/mmio.h>
Arthur Heymans885c2892016-10-03 17:16:48 +020023#include <device/device.h>
Julius Werner7a8a4ab2015-05-22 16:26:40 -070024#include <lib.h>
Edwin Beasanteb50c7d2010-07-06 21:05:04 +000025#include <pc80/mc146818rtc.h>
Stefan Reinauer278534d2008-10-29 04:51:07 +000026#include <spd.h>
Patrick Georgid0835952010-10-05 09:07:10 +000027#include <string.h>
Stefan Reinauer278534d2008-10-29 04:51:07 +000028#include "raminit.h"
29#include "i945.h"
Arthur Heymans885c2892016-10-03 17:16:48 +020030#include "chip.h"
Arthur Heymans0ab49042017-02-06 22:40:14 +010031#include <device/dram/ddr2.h>
Patrick Georgi771328f2015-07-13 19:24:07 +020032#include <timestamp.h>
Rudolf Marekc4369532010-12-13 19:59:13 +000033
Stefan Reinauer278534d2008-10-29 04:51:07 +000034/* Debugging macros. */
Julius Wernercd49cce2019-03-05 16:53:33 -080035#if CONFIG(DEBUG_RAM_SETUP)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000036#define PRINTK_DEBUG(x...) printk(BIOS_DEBUG, x)
Stefan Reinauer278534d2008-10-29 04:51:07 +000037#else
38#define PRINTK_DEBUG(x...)
39#endif
40
Stefan Reinauer278534d2008-10-29 04:51:07 +000041#define RAM_INITIALIZATION_COMPLETE (1 << 19)
42
43#define RAM_COMMAND_SELF_REFRESH (0x0 << 16)
44#define RAM_COMMAND_NOP (0x1 << 16)
45#define RAM_COMMAND_PRECHARGE (0x2 << 16)
46#define RAM_COMMAND_MRS (0x3 << 16)
47#define RAM_COMMAND_EMRS (0x4 << 16)
48#define RAM_COMMAND_CBR (0x6 << 16)
49#define RAM_COMMAND_NORMAL (0x7 << 16)
50
51#define RAM_EMRS_1 (0x0 << 21)
52#define RAM_EMRS_2 (0x1 << 21)
53#define RAM_EMRS_3 (0x2 << 21)
54
Arthur Heymans885c2892016-10-03 17:16:48 +020055#define DEFAULT_PCI_MMIO_SIZE 768
Sven Schnelle541269b2011-02-21 09:39:17 +000056static int get_dimm_spd_address(struct sys_info *sysinfo, int device)
57{
58 if (sysinfo->spd_addresses)
59 return sysinfo->spd_addresses[device];
60 else
61 return DIMM0 + device;
62
63}
64
Arthur Heymans70a8e342017-03-09 11:30:23 +010065static inline int spd_read_byte(unsigned int device, unsigned int address)
Patrick Georgid0835952010-10-05 09:07:10 +000066{
67 return smbus_read_byte(device, address);
68}
69
Stefan Reinauerbc8613e2010-08-25 18:35:42 +000070static __attribute__((noinline)) void do_ram_command(u32 command)
Stefan Reinauer278534d2008-10-29 04:51:07 +000071{
72 u32 reg32;
73
74 reg32 = MCHBAR32(DCC);
Arthur Heymans70a8e342017-03-09 11:30:23 +010075 reg32 &= ~((3<<21) | (1<<20) | (1<<19) | (7 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +000076 reg32 |= command;
77
78 /* Also set Init Complete */
79 if (command == RAM_COMMAND_NORMAL)
80 reg32 |= RAM_INITIALIZATION_COMPLETE;
81
82 PRINTK_DEBUG(" Sending RAM command 0x%08x", reg32);
83
84 MCHBAR32(DCC) = reg32; /* This is the actual magic */
85
Stefan Reinauer779b3e32008-11-10 15:43:37 +000086 PRINTK_DEBUG("...done\n");
Stefan Reinauerd058ad12010-08-26 12:43:58 +000087
88 udelay(1);
Stefan Reinauer278534d2008-10-29 04:51:07 +000089}
90
Stefan Reinauer278534d2008-10-29 04:51:07 +000091static void ram_read32(u32 offset)
92{
Elyes HAOUAS15279a92016-07-28 21:05:26 +020093 PRINTK_DEBUG(" RAM read: %08x\n", offset);
Stefan Reinauer278534d2008-10-29 04:51:07 +000094
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080095 read32((void *)offset);
Stefan Reinauer278534d2008-10-29 04:51:07 +000096}
97
Stefan Reinauer3c0bfaf2010-12-27 11:34:57 +000098void sdram_dump_mchbar_registers(void)
Stefan Reinauer278534d2008-10-29 04:51:07 +000099{
100 int i;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000101 printk(BIOS_DEBUG, "Dumping MCHBAR Registers\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000102
Arthur Heymans70a8e342017-03-09 11:30:23 +0100103 for (i = 0; i < 0xfff; i += 4) {
Stefan Reinauer278534d2008-10-29 04:51:07 +0000104 if (MCHBAR32(i) == 0)
105 continue;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000106 printk(BIOS_DEBUG, "0x%04x: 0x%08x\n", i, MCHBAR32(i));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000107 }
108}
Stefan Reinauer278534d2008-10-29 04:51:07 +0000109
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000110static int memclk(void)
111{
Julius Wernercd49cce2019-03-05 16:53:33 -0800112 int offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200113
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000114 switch (((MCHBAR32(CLKCFG) >> 4) & 7) - offset) {
115 case 1: return 400;
116 case 2: return 533;
117 case 3: return 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100118 default:
119 printk(BIOS_DEBUG, "memclk: unknown register value %x\n",
120 ((MCHBAR32(CLKCFG) >> 4) & 7) - offset);
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000121 }
122 return -1;
123}
124
Peter Stuge76d91432010-10-01 10:02:33 +0000125static u16 fsbclk(void)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000126{
Julius Wernercd49cce2019-03-05 16:53:33 -0800127 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200128 switch (MCHBAR32(CLKCFG) & 7) {
129 case 0: return 400;
130 case 1: return 533;
131 case 3: return 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100132 default:
133 printk(BIOS_DEBUG, "fsbclk: unknown register value %x\n",
134 MCHBAR32(CLKCFG) & 7);
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200135 }
136 return 0xffff;
Julius Wernercd49cce2019-03-05 16:53:33 -0800137 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200138 switch (MCHBAR32(CLKCFG) & 7) {
139 case 0: return 1066;
140 case 1: return 533;
141 case 2: return 800;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100142 default:
143 printk(BIOS_DEBUG, "fsbclk: unknown register value %x\n",
144 MCHBAR32(CLKCFG) & 7);
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200145 }
146 return 0xffff;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000147 }
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000148}
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000149
Stefan Reinauer278534d2008-10-29 04:51:07 +0000150static int sdram_capabilities_max_supported_memory_frequency(void)
151{
152 u32 reg32;
153
Patrick Georgi77d66832010-10-01 08:02:45 +0000154#if CONFIG_MAXIMUM_SUPPORTED_FREQUENCY
155 return CONFIG_MAXIMUM_SUPPORTED_FREQUENCY;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000156#endif
157
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000158 reg32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000159 reg32 &= (7 << 0);
160
161 switch (reg32) {
162 case 4: return 400;
163 case 3: return 533;
164 case 2: return 667;
165 }
166 /* Newer revisions of this chipset rather support faster memory clocks,
167 * so if it's a reserved value, return the fastest memory clock that we
168 * know of and can handle
169 */
170 return 667;
171}
172
173/**
174 * @brief determine whether chipset is capable of dual channel interleaved mode
175 *
176 * @return 1 if interleaving is supported, 0 otherwise
177 */
178static int sdram_capabilities_interleave(void)
179{
180 u32 reg32;
181
Arthur Heymans70a8e342017-03-09 11:30:23 +0100182 reg32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000183 reg32 >>= 25;
184 reg32 &= 1;
185
186 return (!reg32);
187}
188
189/**
190 * @brief determine whether chipset is capable of two memory channels
191 *
192 * @return 1 if dual channel operation is supported, 0 otherwise
193 */
194static int sdram_capabilities_dual_channel(void)
195{
196 u32 reg32;
197
Arthur Heymans70a8e342017-03-09 11:30:23 +0100198 reg32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000199 reg32 >>= 24;
200 reg32 &= 1;
201
202 return (!reg32);
203}
204
205static int sdram_capabilities_enhanced_addressing_xor(void)
206{
207 u8 reg8;
208
209 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
210 reg8 &= (1 << 7);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000211
Stefan Reinauer278534d2008-10-29 04:51:07 +0000212 return (!reg8);
213}
214
Stefan Reinauer14e22772010-04-27 06:56:47 +0000215// TODO check if we ever need this function
Stefan Reinauer53b0ea42010-03-22 11:50:52 +0000216#if 0
Stefan Reinauer278534d2008-10-29 04:51:07 +0000217static int sdram_capabilities_MEM4G_disable(void)
218{
219 u8 reg8;
220
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000221 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000222 reg8 &= (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000223
Stefan Reinauer278534d2008-10-29 04:51:07 +0000224 return (reg8 != 0);
225}
Stefan Reinauer53b0ea42010-03-22 11:50:52 +0000226#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +0000227
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000228#define GFX_FREQUENCY_CAP_166MHZ 0x04
229#define GFX_FREQUENCY_CAP_200MHZ 0x03
230#define GFX_FREQUENCY_CAP_250MHZ 0x02
231#define GFX_FREQUENCY_CAP_ALL 0x00
232
233static int sdram_capabilities_core_frequencies(void)
234{
235 u8 reg8;
236
237 reg8 = pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe5); /* CAPID0 + 5 */
238 reg8 &= (1 << 3) | (1 << 2) | (1 << 1);
239 reg8 >>= 1;
240
Arthur Heymans70a8e342017-03-09 11:30:23 +0100241 return reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000242}
243
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000244static void sdram_detect_errors(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000245{
246 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000247 u8 do_reset = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000248
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100249 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000250
Stefan Reinauer278534d2008-10-29 04:51:07 +0000251 if (reg8 & ((1<<7)|(1<<2))) {
252 if (reg8 & (1<<2)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000253 printk(BIOS_DEBUG, "SLP S4# Assertion Width Violation.\n");
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000254 /* Write back clears bit 2 */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100255 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000256 do_reset = 1;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000257
Stefan Reinauer278534d2008-10-29 04:51:07 +0000258 }
259
260 if (reg8 & (1<<7)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000261 printk(BIOS_DEBUG, "DRAM initialization was interrupted.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000262 reg8 &= ~(1<<7);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100263 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000264 do_reset = 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000265 }
266
267 /* Set SLP_S3# Assertion Stretch Enable */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100268 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000269 reg8 |= (1 << 3);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100270 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000271
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000272 if (do_reset) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000273 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200274 full_reset();
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000275 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000276 }
277
278 /* Set DRAM initialization bit in ICH7 */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100279 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000280 reg8 |= (1<<7);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100281 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000282
Peter Stuge751508a2012-01-27 22:17:09 +0100283 /* clear self refresh status if check is disabled or not a resume */
Julius Werner5d1f9a02019-03-07 17:07:26 -0800284 if (!CONFIG(CHECK_SLFRCS_ON_RESUME)
Arthur Heymans0ab49042017-02-06 22:40:14 +0100285 || sysinfo->boot_path != BOOT_PATH_RESUME) {
Patrick Georgi86a11102013-03-15 14:11:37 +0100286 MCHBAR8(SLFRCS) |= 3;
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000287 } else {
288 /* Validate self refresh config */
289 if (((sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED) ||
290 (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)) &&
Patrick Georgi86a11102013-03-15 14:11:37 +0100291 !(MCHBAR8(SLFRCS) & (1<<0))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000292 do_reset = 1;
293 }
294 if (((sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED) ||
295 (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) &&
Patrick Georgi86a11102013-03-15 14:11:37 +0100296 !(MCHBAR8(SLFRCS) & (1<<1))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000297 do_reset = 1;
298 }
299 }
300
301 if (do_reset) {
302 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200303 full_reset();
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000304 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000305}
Stefan Reinauer278534d2008-10-29 04:51:07 +0000306
Arthur Heymans0ab49042017-02-06 22:40:14 +0100307struct timings {
308 u32 min_tCLK_cas[8];
309 u32 min_tRAS;
310 u32 min_tRP;
311 u32 min_tRCD;
312 u32 min_tWR;
313 u32 min_tRFC;
314 u32 max_tRR;
315 u8 cas_mask;
316};
Stefan Reinauer278534d2008-10-29 04:51:07 +0000317
Arthur Heymans0ab49042017-02-06 22:40:14 +0100318/**
319 * @brief loop over dimms and save maximal timings
320 */
321static void gather_common_timing(struct sys_info *sysinfo,
322 struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000323{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100324
325 int i, j;
326 u8 raw_spd[SPD_SIZE_MAX_DDR2];
327 u8 dimm_mask = 0;
328
329 memset(saved_timings, 0, sizeof(*saved_timings));
330 saved_timings->max_tRR = UINT32_MAX;
331 saved_timings->cas_mask = SPD_CAS_LATENCY_DDR2_3
332 | SPD_CAS_LATENCY_DDR2_4 | SPD_CAS_LATENCY_DDR2_5;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000333
334 /**
335 * i945 supports two DIMMs, in two configurations:
336 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000337 * - single channel with two DIMMs
338 * - dual channel with one DIMM per channel
Stefan Reinauer278534d2008-10-29 04:51:07 +0000339 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000340 * In practice dual channel mainboards have their SPD at 0x50/0x52
341 * whereas single channel configurations have their SPD at 0x50/0x51.
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000342 *
Stefan Reinauer278534d2008-10-29 04:51:07 +0000343 * The capability register knows a lot about the channel configuration
Uwe Hermannd773fd32010-11-20 20:23:08 +0000344 * but for now we stick with the information we gather via SPD.
Stefan Reinauer278534d2008-10-29 04:51:07 +0000345 */
346
Arthur Heymans0ab49042017-02-06 22:40:14 +0100347 printk(BIOS_DEBUG, "This mainboard supports ");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000348 if (sdram_capabilities_dual_channel()) {
349 sysinfo->dual_channel = 1;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100350 printk(BIOS_DEBUG, "Dual Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000351 } else {
352 sysinfo->dual_channel = 0;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100353 printk(BIOS_DEBUG, "only Single Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000354 }
355
Stefan Reinauer278534d2008-10-29 04:51:07 +0000356
Arthur Heymans70a8e342017-03-09 11:30:23 +0100357 for (i = 0; i < (2 * DIMM_SOCKETS); i++) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100358 int device = get_dimm_spd_address(sysinfo, i), bytes_read;
Arthur Heymansfc31e442018-02-12 15:12:34 +0100359 struct dimm_attr_ddr2_st dimm_info;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000360
361 /* Initialize the socket information with a sane value */
362 sysinfo->dimm[i] = SYSINFO_DIMM_NOT_POPULATED;
363
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000364 /* Dual Channel not supported, but Channel 1? Bail out */
365 if (!sdram_capabilities_dual_channel() && (i >> 1))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000366 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000367
Arthur Heymans0ab49042017-02-06 22:40:14 +0100368 if (spd_read_byte(device, SPD_MEMORY_TYPE) !=
369 SPD_MEMORY_TYPE_SDRAM_DDR2) {
370 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: N/A\n",
371 (i >> 1), (i & 1));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000372 continue;
373 }
374
Arthur Heymans0ab49042017-02-06 22:40:14 +0100375 /*
376 * spd_decode_ddr2() needs a 128-byte sized array but
377 * only the first 64 bytes contain data needed for raminit.
378 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000379
Kyösti Mälkkic01a5052019-01-30 09:39:23 +0200380 bytes_read = i2c_eeprom_read(device, 0, 64, raw_spd);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100381 printk(BIOS_DEBUG, "Reading SPD using i2c block operation.\n");
Julius Wernercd49cce2019-03-05 16:53:33 -0800382 if (CONFIG(DEBUG_RAM_SETUP) && bytes_read > 0)
Arthur Heymans0ab49042017-02-06 22:40:14 +0100383 hexdump(raw_spd, bytes_read);
Arthur Heymans56619452017-09-21 09:12:42 +0200384 if (bytes_read != 64) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100385 /* Try again with SMBUS byte read */
386 printk(BIOS_DEBUG, "i2c block operation failed,"
Paul Menzel105e3682017-09-21 08:11:05 +0200387 " trying smbus byte operation.\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100388 for (j = 0; j < 64; j++)
389 raw_spd[j] = spd_read_byte(device, j);
Julius Wernercd49cce2019-03-05 16:53:33 -0800390 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100391 hexdump(raw_spd, 64);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100392 }
Arthur Heymans56619452017-09-21 09:12:42 +0200393
394 if (spd_decode_ddr2(&dimm_info, raw_spd) != SPD_STATUS_OK) {
395 printk(BIOS_WARNING, "Encountered problems with SPD, "
396 "skipping this DIMM.\n");
397 continue;
398 }
399
Julius Wernercd49cce2019-03-05 16:53:33 -0800400 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100401 dram_print_spd_ddr2(&dimm_info);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000402
Arthur Heymans0ab49042017-02-06 22:40:14 +0100403 if (dimm_info.flags.is_ecc)
404 die("\nError: ECC memory not supported by this chipset\n");
405
406 if (spd_dimm_is_registered_ddr2(dimm_info.dimm_type))
407 die("\nError: Registered memory not supported by this chipset\n");
408
409 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: ", (i >> 1),
410 (i & 1));
411 /**
412 * There are 5 different possible populations for a DIMM socket:
413 * 0. x16 double ranked (X16DS)
414 * 1. x8 double ranked (X8DS)
415 * 2. x16 single ranked (X16SS)
416 * 3. x8 double stacked (X8DDS)
417 * 4. Unpopulated
418 */
419 switch (dimm_info.width) {
420 case 8:
421 switch (dimm_info.ranks) {
422 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000423 printk(BIOS_DEBUG, "x8DDS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000424 sysinfo->dimm[i] = SYSINFO_DIMM_X8DDS;
425 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100426 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000427 printk(BIOS_DEBUG, "x8DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000428 sysinfo->dimm[i] = SYSINFO_DIMM_X8DS;
429 break;
430 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000431 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000432 }
433 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100434 case 16:
435 switch (dimm_info.ranks) {
436 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000437 printk(BIOS_DEBUG, "x16DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000438 sysinfo->dimm[i] = SYSINFO_DIMM_X16DS;
439 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100440 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000441 printk(BIOS_DEBUG, "x16SS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000442 sysinfo->dimm[i] = SYSINFO_DIMM_X16SS;
443 break;
444 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000445 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000446 }
447 break;
448 default:
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000449 die("Unsupported DDR-II memory width.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000450 }
451
Arthur Heymans0ab49042017-02-06 22:40:14 +0100452 /* Is the current DIMM a stacked DIMM? */
453 if (dimm_info.flags.stacked)
454 sysinfo->package = SYSINFO_PACKAGE_STACKED;
455
456 if (!dimm_info.flags.bl8)
457 die("Only DDR-II RAM with burst length 8 is supported by this chipset.\n");
458
459 if (dimm_info.ranksize_mb < 128)
460 die("DDR-II rank size smaller than 128MB is not supported.\n");
461
462 sysinfo->banksize[i * 2] = dimm_info.ranksize_mb / 32;
463 printk(BIOS_DEBUG, "DIMM %d side 0 = %d MB\n", i,
464 sysinfo->banksize[i * 2] * 32);
465 if (dimm_info.ranks == 2) {
466 sysinfo->banksize[(i * 2) + 1] =
467 dimm_info.ranksize_mb / 32;
468 printk(BIOS_DEBUG, "DIMM %d side 1 = %d MB\n",
469 i, sysinfo->banksize[(i * 2) + 1] * 32);
470 }
471
472
473 sysinfo->rows[i] = dimm_info.row_bits;
474 sysinfo->cols[i] = dimm_info.col_bits;
475 sysinfo->banks[i] = dimm_info.banks;
476
477 /* int min_tRAS, min_tRP, min_tRCD, min_tWR, min_tRFC; */
478 saved_timings->min_tRAS = MAX(saved_timings->min_tRAS,
479 dimm_info.tRAS);
480 saved_timings->min_tRP = MAX(saved_timings->min_tRP,
481 dimm_info.tRP);
482 saved_timings->min_tRCD = MAX(saved_timings->min_tRCD,
483 dimm_info.tRCD);
484 saved_timings->min_tWR = MAX(saved_timings->min_tWR,
485 dimm_info.tWR);
486 saved_timings->min_tRFC = MAX(saved_timings->min_tRFC,
487 dimm_info.tRFC);
488 saved_timings->max_tRR = MIN(saved_timings->max_tRR,
489 dimm_info.tRR);
490 saved_timings->cas_mask &= dimm_info.cas_supported;
491 for (j = 0; j < 8; j++) {
492 if (!(saved_timings->cas_mask & (1 << j)))
493 saved_timings->min_tCLK_cas[j] = 0;
494 else
495 saved_timings->min_tCLK_cas[j] =
496 MAX(dimm_info.cycle_time[j],
497 saved_timings->min_tCLK_cas[j]);
498 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000499 dimm_mask |= (1 << i);
500 }
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200501 if (!dimm_mask)
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000502 die("No memory installed.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000503
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200504 if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1)))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100505 /* Possibly does not boot in this case */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000506 printk(BIOS_INFO, "Channel 0 has no memory populated.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000507}
508
Arthur Heymans0ab49042017-02-06 22:40:14 +0100509static void choose_tclk(struct sys_info *sysinfo,
510 struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000511{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100512 u32 ctrl_min_tclk;
513 int try_cas;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000514
Arthur Heymans0ab49042017-02-06 22:40:14 +0100515 ctrl_min_tclk = 2 * 256 * 1000
516 / sdram_capabilities_max_supported_memory_frequency();
517 normalize_tck(&ctrl_min_tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000518
Arthur Heymans0ab49042017-02-06 22:40:14 +0100519 try_cas = spd_get_msbs(saved_timings->cas_mask);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000520
Arthur Heymans0ab49042017-02-06 22:40:14 +0100521 while (saved_timings->cas_mask & (1 << try_cas) && try_cas > 0) {
522 sysinfo->cas = try_cas;
523 sysinfo->tclk = saved_timings->min_tCLK_cas[try_cas];
524 if (sysinfo->tclk >= ctrl_min_tclk &&
525 saved_timings->min_tCLK_cas[try_cas] !=
526 saved_timings->min_tCLK_cas[try_cas - 1])
Stefan Reinauer278534d2008-10-29 04:51:07 +0000527 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100528 try_cas--;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000529 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000530
Arthur Heymans0ab49042017-02-06 22:40:14 +0100531 normalize_tck(&sysinfo->tclk);
532
533 if ((sysinfo->cas < 3) || (sysinfo->tclk == 0))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000534 die("Could not find common memory frequency and CAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000535
Arthur Heymans0ab49042017-02-06 22:40:14 +0100536 /*
537 * The loop can still results in a timing too fast for the
538 * memory controller.
539 */
540 if (sysinfo->tclk < ctrl_min_tclk)
541 sysinfo->tclk = ctrl_min_tclk;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000542
Arthur Heymans0ab49042017-02-06 22:40:14 +0100543 switch (sysinfo->tclk) {
544 case TCK_200MHZ:
545 sysinfo->memory_frequency = 400;
546 break;
547 case TCK_266MHZ:
548 sysinfo->memory_frequency = 533;
549 break;
550 case TCK_333MHZ:
551 sysinfo->memory_frequency = 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100552 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000553 }
554
Arthur Heymans0ab49042017-02-06 22:40:14 +0100555 printk(BIOS_DEBUG,
556 "Memory will be driven at %dMT with CAS=%d clocks\n",
557 sysinfo->memory_frequency, sysinfo->cas);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000558}
559
Arthur Heymans0ab49042017-02-06 22:40:14 +0100560static void derive_timings(struct sys_info *sysinfo,
561 struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000562{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100563 sysinfo->tras = DIV_ROUND_UP(saved_timings->min_tRAS, sysinfo->tclk);
564 if (sysinfo->tras > 0x18)
565 die("DDR-II Module does not support this frequency (tRAS error)\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000566
Arthur Heymans0ab49042017-02-06 22:40:14 +0100567 sysinfo->trp = DIV_ROUND_UP(saved_timings->min_tRP, sysinfo->tclk);
568 if (sysinfo->trp > 6)
569 die("DDR-II Module does not support this frequency (tRP error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000570
Arthur Heymans0ab49042017-02-06 22:40:14 +0100571 sysinfo->trcd = DIV_ROUND_UP(saved_timings->min_tRCD, sysinfo->tclk);
572 if (sysinfo->trcd > 6)
573 die("DDR-II Module does not support this frequency (tRCD error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000574
Arthur Heymans0ab49042017-02-06 22:40:14 +0100575 sysinfo->twr = DIV_ROUND_UP(saved_timings->min_tWR, sysinfo->tclk);
576 if (sysinfo->twr > 5)
577 die("DDR-II Module does not support this frequency (tWR error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000578
Arthur Heymans0ab49042017-02-06 22:40:14 +0100579 sysinfo->trfc = DIV_ROUND_UP(saved_timings->min_tRFC, sysinfo->tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000580
Arthur Heymans0ab49042017-02-06 22:40:14 +0100581 printk(BIOS_DEBUG, "tRAS = %d cycles\n", sysinfo->tras);
582 printk(BIOS_DEBUG, "tRP = %d cycles\n", sysinfo->trp);
583 printk(BIOS_DEBUG, "tRCD = %d cycles\n", sysinfo->trcd);
584 printk(BIOS_DEBUG, "tWR = %d cycles\n", sysinfo->twr);
585 printk(BIOS_DEBUG, "tRFC = %d cycles\n", sysinfo->trfc);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000586
Arthur Heymans0ab49042017-02-06 22:40:14 +0100587 /* Refresh is slower than 15.6us, use 15.6us */
588 /* tRR is decoded in units of 1/256us */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000589
Arthur Heymans0ab49042017-02-06 22:40:14 +0100590#define T_RR_7_8US 2000000
591#define T_RR_15_6US 4000000
592#define REFRESH_7_8US 1
593#define REFRESH_15_6US 0
Stefan Reinauer278534d2008-10-29 04:51:07 +0000594
Arthur Heymans0ab49042017-02-06 22:40:14 +0100595 if (saved_timings->max_tRR < T_RR_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000596 die("DDR-II module has unsupported refresh value\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100597 else if (saved_timings->max_tRR < T_RR_15_6US)
598 sysinfo->refresh = REFRESH_7_8US;
599 else
600 sysinfo->refresh = REFRESH_15_6US;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000601 printk(BIOS_DEBUG, "Refresh: %s\n", sysinfo->refresh?"7.8us":"15.6us");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000602}
603
Arthur Heymans0ab49042017-02-06 22:40:14 +0100604/**
605 * @brief Get generic DIMM parameters.
606 * @param sysinfo Central memory controller information structure
607 *
608 * This function gathers several pieces of information for each system DIMM:
609 * o DIMM width (x8 / x16)
610 * o DIMM rank (single ranked / dual ranked)
611 *
612 * Also, some non-supported scenarios are detected.
613 */
614
615static void sdram_get_dram_configuration(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000616{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100617 struct timings saved_timings;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000618
Arthur Heymans0ab49042017-02-06 22:40:14 +0100619 gather_common_timing(sysinfo, &saved_timings);
620 choose_tclk(sysinfo, &saved_timings);
621 derive_timings(sysinfo, &saved_timings);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000622}
623
Arthur Heymans70a8e342017-03-09 11:30:23 +0100624static void sdram_program_dram_width(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000625{
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200626 u16 c0dramw = 0, c1dramw = 0;
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200627 int i, idx;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000628
629 if (sysinfo->dual_channel)
630 idx = 2;
631 else
632 idx = 1;
633
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200634 for (i = 0; i < DIMM_SOCKETS; i++) { /* Channel 0 */
635 switch (sysinfo->dimm[i]) {
636 case SYSINFO_DIMM_X16DS:
637 c0dramw |= (0x0000) << 4*(i % 2);
638 break;
639 case SYSINFO_DIMM_X8DS:
640 c0dramw |= (0x0001) << 4*(i % 2);
641 break;
642 case SYSINFO_DIMM_X16SS:
643 c0dramw |= (0x0000) << 4*(i % 2);
644 break;
645 case SYSINFO_DIMM_X8DDS:
646 c0dramw |= (0x0005) << 4*(i % 2);
647 break;
648 case SYSINFO_DIMM_NOT_POPULATED:
649 c0dramw |= (0x0000) << 4*(i % 2);
650 break;
651 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000652 }
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200653 for (i = DIMM_SOCKETS; i < idx * DIMM_SOCKETS; i++) { /* Channel 1 */
654 switch (sysinfo->dimm[i]) {
655 case SYSINFO_DIMM_X16DS:
656 c1dramw |= (0x0000) << 4*(i % 2);
657 break;
658 case SYSINFO_DIMM_X8DS:
Patrick Georgi68aed912018-11-16 18:00:12 +0100659 c1dramw |= (0x0010) << 4*(i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200660 break;
661 case SYSINFO_DIMM_X16SS:
662 c1dramw |= (0x0000) << 4*(i % 2);
663 break;
664 case SYSINFO_DIMM_X8DDS:
Patrick Georgi68aed912018-11-16 18:00:12 +0100665 c1dramw |= (0x0050) << 4*(i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200666 break;
667 case SYSINFO_DIMM_NOT_POPULATED:
668 c1dramw |= (0x0000) << 4*(i % 2);
669 break;
670 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000671 }
672
673 MCHBAR16(C0DRAMW) = c0dramw;
674 MCHBAR16(C1DRAMW) = c1dramw;
675}
676
677static void sdram_write_slew_rates(u32 offset, const u32 *slew_rate_table)
678{
679 int i;
680
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200681 for (i = 0; i < 16; i++)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000682 MCHBAR32(offset+(i*4)) = slew_rate_table[i];
683}
684
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000685static const u32 dq2030[] = {
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 dq2330[] = {
693 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
694 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
695 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
696 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
697};
698
699static const u32 cmd2710[] = {
700 0x07060605, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
701 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
702 0x1110100f, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
703 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
704};
705
706static const u32 cmd3210[] = {
707 0x0f0d0b0a, 0x17151311, 0x1f1d1b19, 0x1f1f1f1f,
708 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
709 0x18171615, 0x1f1f1c1a, 0x1f1f1f1f, 0x1f1f1f1f,
710 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
711};
712
713static const u32 clk2030[] = {
714 0x0e0d0d0c, 0x100f0f0e, 0x100f0e0d, 0x15131211,
715 0x1d1b1917, 0x2523211f, 0x2a282927, 0x32302e2c,
716 0x17161514, 0x1b1a1918, 0x1f1e1d1c, 0x23222120,
717 0x27262524, 0x2d2b2928, 0x3533312f, 0x3d3b3937
718};
719
720static const u32 ctl3215[] = {
721 0x01010000, 0x03020101, 0x07060504, 0x0b0a0908,
722 0x100f0e0d, 0x14131211, 0x18171615, 0x1c1b1a19,
723 0x05040403, 0x07060605, 0x0a090807, 0x0f0d0c0b,
724 0x14131211, 0x18171615, 0x1c1b1a19, 0x201f1e1d
725};
726
727static const u32 ctl3220[] = {
728 0x05040403, 0x07060505, 0x0e0c0a08, 0x1a171411,
729 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e,
730 0x09080807, 0x0b0a0a09, 0x0f0d0c0b, 0x1b171311,
731 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e
732};
733
734static const u32 nc[] = {
735 0x00000000, 0x00000000, 0x00000000, 0x00000000,
736 0x00000000, 0x00000000, 0x00000000, 0x00000000,
737 0x00000000, 0x00000000, 0x00000000, 0x00000000,
738 0x00000000, 0x00000000, 0x00000000, 0x00000000
739};
740
741enum {
742 DQ2030,
743 DQ2330,
744 CMD2710,
745 CMD3210,
746 CLK2030,
747 CTL3215,
748 CTL3220,
749 NC,
750};
751
752static const u8 dual_channel_slew_group_lookup[] = {
753 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
754 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
755 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
756 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
757 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
758
759 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
760 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
761 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
762 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
763 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
764
765 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
766 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
767 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
768 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
769 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
770
771 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
772 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
773 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
774 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
775 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, NC, NC,
776
777 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
778 NC, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
779 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
780 NC, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD2710
781};
782
783static const u8 single_channel_slew_group_lookup[] = {
784 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
785 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
786 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
787 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
788 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
789
790 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
791 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
792 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
793 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
794 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
795
796 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
797 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
798 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
799 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
800 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
801
802 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
803 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
804 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
805 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
806 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
807
808 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
809 DQ2330, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
810 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
811 DQ2330, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD3210
812};
813
814static const u32 *slew_group_lookup(int dual_channel, int index)
815{
816 const u8 *slew_group;
817 /* Dual Channel needs different tables. */
818 if (dual_channel)
819 slew_group = dual_channel_slew_group_lookup;
820 else
821 slew_group = single_channel_slew_group_lookup;
822
823 switch (slew_group[index]) {
824 case DQ2030: return dq2030;
825 case DQ2330: return dq2330;
826 case CMD2710: return cmd2710;
827 case CMD3210: return cmd3210;
828 case CLK2030: return clk2030;
829 case CTL3215: return ctl3215;
830 case CTL3220: return ctl3220;
831 case NC: return nc;
832 }
833
834 return nc;
835}
836
Julius Wernercd49cce2019-03-05 16:53:33 -0800837#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000838/* Strength multiplier tables */
839static const u8 dual_channel_strength_multiplier[] = {
840 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
841 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
842 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
843 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
844 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
845 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
846 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
847 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
848 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
849 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
850 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
851 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
852 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
853 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
854 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
855 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
856 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
857 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
858 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
859 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
860 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
861 0x00, 0x00, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
862 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
863 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x44, 0x22
864};
865
866static const u8 single_channel_strength_multiplier[] = {
867 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
868 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
869 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
870 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
871 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
872 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
873 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
874 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
875 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
876 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
877 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
878 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
879 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
880 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
881 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
882 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
883 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
884 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
885 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
886 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
887 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
888 0x33, 0x00, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
889 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
890 0x33, 0x00, 0x11, 0x00, 0x44, 0x44, 0x33, 0x11
891};
Julius Wernercd49cce2019-03-05 16:53:33 -0800892#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000893static const u8 dual_channel_strength_multiplier[] = {
894 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
895 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
896 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
897 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
898 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
899 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
900 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
901 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
902 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
903 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
904 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
905 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
906 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
907 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
908 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
909 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
910 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
911 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
912 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
913 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
914 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
915 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
916 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
917 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33
918};
919
920static const u8 single_channel_strength_multiplier[] = {
921 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
922 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
923 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
924 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
925 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
926 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
927 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
928 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
929 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
930 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
931 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
932 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
933 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
934 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
935 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
936 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
937 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
938 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
939 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
940 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
941 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
942 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
943 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
944 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00
945};
946#endif
947
Stefan Reinauer278534d2008-10-29 04:51:07 +0000948static void sdram_rcomp_buffer_strength_and_slew(struct sys_info *sysinfo)
949{
Arthur Heymans70a8e342017-03-09 11:30:23 +0100950 const u8 *strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000951 int idx, dual_channel;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000952
953 /* Set Strength Multipliers */
954
955 /* Dual Channel needs different tables. */
956 if (sdram_capabilities_dual_channel()) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000957 printk(BIOS_DEBUG, "Programming Dual Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000958 strength_multiplier = dual_channel_strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000959 dual_channel = 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000960 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[2];
961 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000962 printk(BIOS_DEBUG, "Programming Single Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000963 strength_multiplier = single_channel_strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000964 dual_channel = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000965 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[1];
966 }
967
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000968 printk(BIOS_DEBUG, "Table Index: %d\n", idx);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000969
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000970 MCHBAR8(G1SC) = strength_multiplier[idx * 8 + 0];
971 MCHBAR8(G2SC) = strength_multiplier[idx * 8 + 1];
972 MCHBAR8(G3SC) = strength_multiplier[idx * 8 + 2];
973 MCHBAR8(G4SC) = strength_multiplier[idx * 8 + 3];
974 MCHBAR8(G5SC) = strength_multiplier[idx * 8 + 4];
975 MCHBAR8(G6SC) = strength_multiplier[idx * 8 + 5];
976 MCHBAR8(G7SC) = strength_multiplier[idx * 8 + 6];
977 MCHBAR8(G8SC) = strength_multiplier[idx * 8 + 7];
Stefan Reinauer278534d2008-10-29 04:51:07 +0000978
979 /* Channel 0 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000980 sdram_write_slew_rates(G1SRPUT, slew_group_lookup(dual_channel, idx * 8 + 0));
981 sdram_write_slew_rates(G2SRPUT, slew_group_lookup(dual_channel, idx * 8 + 1));
Arthur Heymans70a8e342017-03-09 11:30:23 +0100982 if ((slew_group_lookup(dual_channel, idx * 8 + 2) != nc) && (sysinfo->package == SYSINFO_PACKAGE_STACKED))
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000983
Stefan Reinauer278534d2008-10-29 04:51:07 +0000984 sdram_write_slew_rates(G3SRPUT, ctl3220);
Arthur Heymans70a8e342017-03-09 11:30:23 +0100985 else
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000986 sdram_write_slew_rates(G3SRPUT, slew_group_lookup(dual_channel, idx * 8 + 2));
Arthur Heymans70a8e342017-03-09 11:30:23 +0100987
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000988 sdram_write_slew_rates(G4SRPUT, slew_group_lookup(dual_channel, idx * 8 + 3));
989 sdram_write_slew_rates(G5SRPUT, slew_group_lookup(dual_channel, idx * 8 + 4));
990 sdram_write_slew_rates(G6SRPUT, slew_group_lookup(dual_channel, idx * 8 + 5));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000991
992 /* Channel 1 */
993 if (sysinfo->dual_channel) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000994 sdram_write_slew_rates(G7SRPUT, slew_group_lookup(dual_channel, idx * 8 + 6));
995 sdram_write_slew_rates(G8SRPUT, slew_group_lookup(dual_channel, idx * 8 + 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000996 } else {
997 sdram_write_slew_rates(G7SRPUT, nc);
998 sdram_write_slew_rates(G8SRPUT, nc);
999 }
1000}
1001
1002static void sdram_enable_rcomp(void)
1003{
1004 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001005 /* Enable Global Periodic RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001006 udelay(300);
1007 reg32 = MCHBAR32(GBRCOMPCTL);
1008 reg32 &= ~(1 << 23);
1009 MCHBAR32(GBRCOMPCTL) = reg32;
1010}
1011
1012static void sdram_program_dll_timings(struct sys_info *sysinfo)
1013{
Elyes HAOUAS44a30662017-02-23 13:14:44 +01001014 u32 channeldll = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001015 int i;
1016
Elyes HAOUAS38424982016-08-21 12:01:04 +02001017 printk(BIOS_DEBUG, "Programming DLL Timings...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001018
Arthur Heymans70a8e342017-03-09 11:30:23 +01001019 MCHBAR16(DQSMT) &= ~((3 << 12) | (1 << 10) | (0xf << 0));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001020 MCHBAR16(DQSMT) |= (1 << 13) | (0xc << 0);
1021
1022 /* We drive both channels with the same speed */
Julius Wernercd49cce2019-03-05 16:53:33 -08001023 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001024 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001025 case 400:
1026 channeldll = 0x26262626; break;
1027 case 533:
1028 channeldll = 0x22222222; break;
1029 case 667:
1030 channeldll = 0x11111111; break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001031 }
Julius Wernercd49cce2019-03-05 16:53:33 -08001032 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001033 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001034 case 400:
1035 channeldll = 0x33333333; break;
1036 case 533:
1037 channeldll = 0x24242424; break;
1038 case 667:
1039 channeldll = 0x25252525; break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001040 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001041 }
1042
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001043 for (i = 0; i < 4; i++) {
Elyes HAOUAS44a30662017-02-23 13:14:44 +01001044 MCHBAR32(C0R0B00DQST + (i * 0x10) + 0) = channeldll;
1045 MCHBAR32(C0R0B00DQST + (i * 0x10) + 4) = channeldll;
1046 MCHBAR32(C1R0B00DQST + (i * 0x10) + 0) = channeldll;
1047 MCHBAR32(C1R0B00DQST + (i * 0x10) + 4) = channeldll;
Julius Wernercd49cce2019-03-05 16:53:33 -08001048 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUAS44a30662017-02-23 13:14:44 +01001049 MCHBAR8(C0R0B00DQST + (i * 0x10) + 8) = channeldll & 0xff;
1050 MCHBAR8(C1R0B00DQST + (i * 0x10) + 8) = channeldll & 0xff;
Paul Menzelbce7e332017-02-22 18:46:27 +01001051 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001052 }
1053}
1054
1055static void sdram_force_rcomp(void)
1056{
1057 u32 reg32;
1058 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001059
Stefan Reinauer278534d2008-10-29 04:51:07 +00001060 reg32 = MCHBAR32(ODTC);
1061 reg32 |= (1 << 28);
1062 MCHBAR32(ODTC) = reg32;
1063
1064 reg32 = MCHBAR32(SMSRCTL);
1065 reg32 |= (1 << 0);
1066 MCHBAR32(SMSRCTL) = reg32;
1067
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001068 /* Start initial RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001069 reg32 = MCHBAR32(GBRCOMPCTL);
1070 reg32 |= (1 << 8);
1071 MCHBAR32(GBRCOMPCTL) = reg32;
1072
1073 reg8 = i945_silicon_revision();
1074 if ((reg8 == 0 && (MCHBAR32(DCC) & (3 << 0)) == 0) || (reg8 == 1)) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001075
Stefan Reinauer278534d2008-10-29 04:51:07 +00001076 reg32 = MCHBAR32(GBRCOMPCTL);
1077 reg32 |= (3 << 5);
1078 MCHBAR32(GBRCOMPCTL) = reg32;
1079 }
1080}
1081
1082static void sdram_initialize_system_memory_io(struct sys_info *sysinfo)
1083{
1084 u8 reg8;
1085 u32 reg32;
1086
Elyes HAOUAS38424982016-08-21 12:01:04 +02001087 printk(BIOS_DEBUG, "Initializing System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001088 /* Enable Data Half Clock Pushout */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001089 reg8 = MCHBAR8(C0HCTC);
1090 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001091 reg8 |= (1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001092 MCHBAR8(C0HCTC) = reg8;
1093
1094 reg8 = MCHBAR8(C1HCTC);
1095 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001096 reg8 |= (1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001097 MCHBAR8(C1HCTC) = reg8;
1098
Arthur Heymans70a8e342017-03-09 11:30:23 +01001099 MCHBAR16(WDLLBYPMODE) &= ~((1 << 9) | (1 << 6) | (1 << 4) | (1 << 3) | (1 << 1));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001100 MCHBAR16(WDLLBYPMODE) |= (1 << 8) | (1 << 7) | (1 << 5) | (1 << 2) | (1 << 0);
1101
1102 MCHBAR8(C0WDLLCMC) = 0;
1103 MCHBAR8(C1WDLLCMC) = 0;
1104
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001105 /* Program RCOMP Settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001106 sdram_program_dram_width(sysinfo);
1107
1108 sdram_rcomp_buffer_strength_and_slew(sysinfo);
1109
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001110 /* Indicate that RCOMP programming is done */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001111 reg32 = MCHBAR32(GBRCOMPCTL);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001112 reg32 &= ~((1 << 29) | (1 << 26) | (3 << 21) | (3 << 2));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001113 reg32 |= (3 << 27) | (3 << 0);
1114 MCHBAR32(GBRCOMPCTL) = reg32;
1115
1116 MCHBAR32(GBRCOMPCTL) |= (1 << 10);
1117
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001118 /* Program DLL Timings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001119 sdram_program_dll_timings(sysinfo);
1120
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001121 /* Force RCOMP cycle */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001122 sdram_force_rcomp();
1123}
1124
1125static void sdram_enable_system_memory_io(struct sys_info *sysinfo)
1126{
1127 u32 reg32;
1128
Elyes HAOUAS38424982016-08-21 12:01:04 +02001129 printk(BIOS_DEBUG, "Enabling System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001130
Stefan Reinauer278534d2008-10-29 04:51:07 +00001131 reg32 = MCHBAR32(RCVENMT);
1132 reg32 &= ~(0x3f << 6);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001133 MCHBAR32(RCVENMT) = reg32; /* [11:6] = 0 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001134
1135 reg32 |= (1 << 11) | (1 << 9);
1136 MCHBAR32(RCVENMT) = reg32;
1137
1138 reg32 = MCHBAR32(DRTST);
1139 reg32 |= (1 << 3) | (1 << 2);
1140 MCHBAR32(DRTST) = reg32;
1141
1142 reg32 = MCHBAR32(DRTST);
1143 reg32 |= (1 << 6) | (1 << 4);
1144 MCHBAR32(DRTST) = reg32;
1145
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001146 asm volatile ("nop; nop;" ::: "memory");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001147
1148 reg32 = MCHBAR32(DRTST);
1149
1150 /* Is channel 0 populated? */
1151 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
1152 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
1153 reg32 |= (1 << 7) | (1 << 5);
1154 else
1155 reg32 |= (1 << 31);
1156
1157 /* Is channel 1 populated? */
1158 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1159 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
1160 reg32 |= (1 << 9) | (1 << 8);
1161 else
1162 reg32 |= (1 << 30);
1163
1164 MCHBAR32(DRTST) = reg32;
1165
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001166 /* Activate DRAM Channel IO Buffers */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001167 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
1168 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) {
1169 reg32 = MCHBAR32(C0DRC1);
1170 reg32 |= (1 << 8);
1171 MCHBAR32(C0DRC1) = reg32;
1172 }
1173 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1174 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED) {
1175 reg32 = MCHBAR32(C1DRC1);
1176 reg32 |= (1 << 8);
1177 MCHBAR32(C1DRC1) = reg32;
1178 }
1179}
1180
Stefan Reinauer278534d2008-10-29 04:51:07 +00001181static int sdram_program_row_boundaries(struct sys_info *sysinfo)
1182{
1183 int i;
Arthur Heymans885c2892016-10-03 17:16:48 +02001184 int cum0, cum1, tolud, tom, pci_mmio_size;
1185 const struct device *dev;
1186 const struct northbridge_intel_i945_config *cfg = NULL;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001187
Paul Menzel84283bc2014-07-17 08:16:04 +02001188 printk(BIOS_DEBUG, "Setting RAM size...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001189
1190 cum0 = 0;
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001191 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001192 cum0 += sysinfo->banksize[i];
Stefan Reinauer278534d2008-10-29 04:51:07 +00001193 MCHBAR8(C0DRB0+i) = cum0;
1194 }
1195
1196 /* Assume we continue in Channel 1 where we stopped in Channel 0 */
1197 cum1 = cum0;
1198
1199 /* Exception: Interleaved starts from the beginning */
1200 if (sysinfo->interleaved)
1201 cum1 = 0;
1202
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001203 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001204 cum1 += sysinfo->banksize[i + 4];
Stefan Reinauer278534d2008-10-29 04:51:07 +00001205 MCHBAR8(C1DRB0+i) = cum1;
1206 }
1207
1208 /* Set TOLUD Top Of Low Usable DRAM */
1209 if (sysinfo->interleaved)
1210 tolud = (cum0 + cum1) << 1;
1211 else
1212 tolud = (cum1 ? cum1 : cum0) << 1;
Stefan Reinauer779b3e32008-11-10 15:43:37 +00001213
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001214 /* The TOM register has a different format */
1215 tom = tolud >> 3;
1216
1217 /* Limit the value of TOLUD to leave some space for PCI memory. */
Kyösti Mälkkic70eed12018-05-22 02:18:00 +03001218 dev = pcidev_on_root(0, 0);
Arthur Heymans885c2892016-10-03 17:16:48 +02001219 if (dev)
1220 cfg = dev->chip_info;
1221
1222 /* Don't use pci mmio sizes smaller than 768M */
1223 if (!cfg || cfg->pci_mmio_size <= DEFAULT_PCI_MMIO_SIZE)
1224 pci_mmio_size = DEFAULT_PCI_MMIO_SIZE;
1225 else
1226 pci_mmio_size = cfg->pci_mmio_size;
1227
1228 tolud = MIN(((4096 - pci_mmio_size) / 128) << 3, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001229
Arthur Heymans70a8e342017-03-09 11:30:23 +01001230 pci_write_config8(PCI_DEV(0, 0, 0), TOLUD, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001231
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001232 printk(BIOS_DEBUG, "C0DRB = 0x%08x\n", MCHBAR32(C0DRB0));
1233 printk(BIOS_DEBUG, "C1DRB = 0x%08x\n", MCHBAR32(C1DRB0));
Arthur Heymans70a8e342017-03-09 11:30:23 +01001234 printk(BIOS_DEBUG, "TOLUD = 0x%04x\n", pci_read_config8(PCI_DEV(0, 0, 0), TOLUD));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001235
Arthur Heymans70a8e342017-03-09 11:30:23 +01001236 pci_write_config16(PCI_DEV(0, 0, 0), TOM, tom);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001237
1238 return 0;
1239}
1240
Stefan Reinauer278534d2008-10-29 04:51:07 +00001241static int sdram_set_row_attributes(struct sys_info *sysinfo)
1242{
Arthur Heymans0ab49042017-02-06 22:40:14 +01001243 int i;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001244 u16 dra0 = 0, dra1 = 0, dra = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001245
Elyes HAOUAS38424982016-08-21 12:01:04 +02001246 printk(BIOS_DEBUG, "Setting row attributes...\n");
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001247 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001248 u8 columnsrows;
1249
Arthur Heymans70a8e342017-03-09 11:30:23 +01001250 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001251 continue;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001252
Arthur Heymans0ab49042017-02-06 22:40:14 +01001253 columnsrows = (sysinfo->rows[i] & 0x0f)
1254 | (sysinfo->cols[i] & 0xf) << 4;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001255
1256 switch (columnsrows) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001257 case 0x9d:
1258 dra = 2; break;
1259 case 0xad:
1260 dra = 3; break;
1261 case 0xbd:
1262 dra = 4; break;
1263 case 0xae:
1264 dra = 3; break;
1265 case 0xbe:
1266 dra = 4; break;
1267 default:
1268 die("Unsupported Rows/Columns. (DRA)");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001269 }
1270
1271 /* Double Sided DIMMs? */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001272 if (sysinfo->banksize[(2 * i) + 1] != 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001273 dra = (dra << 4) | dra;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001274
Stefan Reinauer278534d2008-10-29 04:51:07 +00001275 if (i < DIMM_SOCKETS)
1276 dra0 |= (dra << (i*8));
1277 else
1278 dra1 |= (dra << ((i - DIMM_SOCKETS)*8));
1279 }
1280
1281 MCHBAR16(C0DRA0) = dra0;
1282 MCHBAR16(C1DRA0) = dra1;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001283
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001284 printk(BIOS_DEBUG, "C0DRA = 0x%04x\n", dra0);
1285 printk(BIOS_DEBUG, "C1DRA = 0x%04x\n", dra1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001286
1287 return 0;
1288}
1289
1290static void sdram_set_bank_architecture(struct sys_info *sysinfo)
1291{
1292 u32 off32;
1293 int i;
1294
1295 MCHBAR16(C1BNKARC) &= 0xff00;
1296 MCHBAR16(C0BNKARC) &= 0xff00;
1297
1298 off32 = C0BNKARC;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001299 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001300 /* Switch to second channel */
1301 if (i == DIMM_SOCKETS)
1302 off32 = C1BNKARC;
1303
1304 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
1305 continue;
1306
1307 if (sysinfo->banks[i] != 8)
1308 continue;
1309
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001310 printk(BIOS_SPEW, "DIMM%d has 8 banks.\n", i);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001311
1312 if (i & 1)
1313 MCHBAR16(off32) |= 0x50;
1314 else
1315 MCHBAR16(off32) |= 0x05;
1316 }
1317}
1318
Stefan Reinauer278534d2008-10-29 04:51:07 +00001319static void sdram_program_refresh_rate(struct sys_info *sysinfo)
1320{
1321 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001322
Arthur Heymans70a8e342017-03-09 11:30:23 +01001323 if (sysinfo->refresh == REFRESH_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001324 reg32 = (2 << 8); /* Refresh enabled at 7.8us */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001325 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001326 reg32 = (1 << 8); /* Refresh enabled at 15.6us */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001327
1328 MCHBAR32(C0DRC0) &= ~(7 << 8);
1329 MCHBAR32(C0DRC0) |= reg32;
1330
1331 MCHBAR32(C1DRC0) &= ~(7 << 8);
1332 MCHBAR32(C1DRC0) |= reg32;
1333}
1334
1335static void sdram_program_cke_tristate(struct sys_info *sysinfo)
1336{
1337 u32 reg32;
1338 int i;
1339
1340 reg32 = MCHBAR32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001341
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001342 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001343 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001344 reg32 |= (1 << (16 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001345 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001346
Stefan Reinauer278534d2008-10-29 04:51:07 +00001347 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001348
Stefan Reinauer278534d2008-10-29 04:51:07 +00001349 reg32 |= (1 << 11);
1350 MCHBAR32(C0DRC1) = reg32;
1351
1352 /* Do we have to do this if we're in Single Channel Mode? */
1353 reg32 = MCHBAR32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001354
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001355 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001356 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001357 reg32 |= (1 << (12 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001358 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001359
Stefan Reinauer278534d2008-10-29 04:51:07 +00001360 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001361
Stefan Reinauer278534d2008-10-29 04:51:07 +00001362 reg32 |= (1 << 11);
1363 MCHBAR32(C1DRC1) = reg32;
1364}
1365
1366static void sdram_program_odt_tristate(struct sys_info *sysinfo)
1367{
1368 u32 reg32;
1369 int i;
1370
1371 reg32 = MCHBAR32(C0DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001372
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001373 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001374 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001375 reg32 |= (1 << (24 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001376 }
1377 MCHBAR32(C0DRC2) = reg32;
1378
1379 reg32 = MCHBAR32(C1DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001380
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001381 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001382 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001383 reg32 |= (1 << (20 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001384 }
1385 MCHBAR32(C1DRC2) = reg32;
1386}
1387
1388static void sdram_set_timing_and_control(struct sys_info *sysinfo)
1389{
Arthur Heymans25027232017-02-12 23:34:39 +01001390 u32 reg32, tRD_min;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001391 u32 tWTR;
1392 u32 temp_drt;
1393 int i, page_size;
1394
Edward O'Callaghan2f237c12014-05-25 06:24:39 +10001395 static const u8 cas_table[] = {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001396 2, 1, 0, 3
1397 };
1398
1399 reg32 = MCHBAR32(C0DRC0);
1400 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001401 reg32 &= ~((1 << 13) | (1 << 12));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001402 MCHBAR32(C0DRC0) = reg32;
1403
1404 reg32 = MCHBAR32(C1DRC0);
1405 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001406 reg32 &= ~((1 << 13) | (1 << 12));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001407 MCHBAR32(C1DRC0) = reg32;
1408
1409 if (!sysinfo->dual_channel && sysinfo->dimm[1] !=
1410 SYSINFO_DIMM_NOT_POPULATED) {
1411 reg32 = MCHBAR32(C0DRC0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001412 reg32 |= (1 << 15);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001413 MCHBAR32(C0DRC0) = reg32;
1414 }
1415
1416 sdram_program_refresh_rate(sysinfo);
1417
1418 sdram_program_cke_tristate(sysinfo);
1419
1420 sdram_program_odt_tristate(sysinfo);
1421
1422 /* Calculate DRT0 */
1423
1424 temp_drt = 0;
1425
1426 /* B2B Write Precharge (same bank) = CL-1 + BL/2 + tWR */
1427 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + sysinfo->twr;
1428 temp_drt |= (reg32 << 28);
1429
1430 /* Write Auto Precharge (same bank) = CL-1 + BL/2 + tWR + tRP */
1431 reg32 += sysinfo->trp;
1432 temp_drt |= (reg32 << 4);
1433
Arthur Heymans70a8e342017-03-09 11:30:23 +01001434 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001435 tWTR = 3; /* 667MHz */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001436 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001437 tWTR = 2; /* 400 and 533 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001438
1439 /* B2B Write to Read Command Spacing */
1440 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + tWTR;
1441 temp_drt |= (reg32 << 24);
1442
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001443 /* CxDRT0 [23:22], [21:20], [19:18] [16] have fixed values */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001444 temp_drt |= ((1 << 22) | (3 << 20) | (1 << 18) | (0 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001445
Arthur Heymans25027232017-02-12 23:34:39 +01001446 /*
1447 * tRD is the delay the memory controller is waiting on the FSB,
1448 * in mclk domain.
1449 * This parameter is important for stability and performance.
1450 * Those values might not be optimal but seem stable.
1451 */
1452 tRD_min = sysinfo->cas;
Arthur Heymanse1897612016-10-15 23:29:18 +02001453 switch (sysinfo->fsb_frequency) {
Arthur Heymans25027232017-02-12 23:34:39 +01001454 case 533: break;
1455 case 667: tRD_min += 1;
Arthur Heymanse1897612016-10-15 23:29:18 +02001456 break;
Arthur Heymans25027232017-02-12 23:34:39 +01001457 case 800: tRD_min += 2;
Arthur Heymanse1897612016-10-15 23:29:18 +02001458 break;
Arthur Heymans25027232017-02-12 23:34:39 +01001459 case 1066: tRD_min += 3;
Arthur Heymanse1897612016-10-15 23:29:18 +02001460 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001461 }
Arthur Heymanse1897612016-10-15 23:29:18 +02001462
Arthur Heymans25027232017-02-12 23:34:39 +01001463 temp_drt |= (tRD_min << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001464
1465 /* Read Auto Precharge to Activate */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001466
Stefan Reinauer278534d2008-10-29 04:51:07 +00001467 temp_drt |= (8 << 0);
1468
1469 MCHBAR32(C0DRT0) = temp_drt;
1470 MCHBAR32(C1DRT0) = temp_drt;
1471
1472 /* Calculate DRT1 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001473
Stefan Reinauer278534d2008-10-29 04:51:07 +00001474 temp_drt = MCHBAR32(C0DRT1) & 0x00020088;
1475
1476 /* DRAM RASB Precharge */
1477 temp_drt |= (sysinfo->trp - 2) << 0;
1478
1479 /* DRAM RASB to CASB Delay */
1480 temp_drt |= (sysinfo->trcd - 2) << 4;
1481
1482 /* CASB Latency */
1483 temp_drt |= (cas_table[sysinfo->cas - 3]) << 8;
1484
1485 /* Refresh Cycle Time */
1486 temp_drt |= (sysinfo->trfc) << 10;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001487
Stefan Reinauer278534d2008-10-29 04:51:07 +00001488 /* Pre-All to Activate Delay */
1489 temp_drt |= (0 << 16);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001490
Stefan Reinauer278534d2008-10-29 04:51:07 +00001491 /* Precharge to Precharge Delay stays at 1 clock */
1492 temp_drt |= (0 << 18);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001493
Stefan Reinauer278534d2008-10-29 04:51:07 +00001494 /* Activate to Precharge Delay */
1495 temp_drt |= (sysinfo->tras << 19);
1496
1497 /* Read to Precharge (tRTP) */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001498 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001499 temp_drt |= (1 << 28);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001500 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001501 temp_drt |= (0 << 28);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001502
1503 /* Determine page size */
1504 reg32 = 0;
1505 page_size = 1; /* Default: 1k pagesize */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001506 for (i = 0; i < 2*DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001507 if (sysinfo->dimm[i] == SYSINFO_DIMM_X16DS ||
1508 sysinfo->dimm[i] == SYSINFO_DIMM_X16SS)
1509 page_size = 2; /* 2k pagesize */
1510 }
1511
Arthur Heymans70a8e342017-03-09 11:30:23 +01001512 if (sysinfo->memory_frequency == 533 && page_size == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001513 reg32 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001514 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001515 reg32 = page_size;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001516
Stefan Reinauer278534d2008-10-29 04:51:07 +00001517 temp_drt |= (reg32 << 30);
1518
1519 MCHBAR32(C0DRT1) = temp_drt;
1520 MCHBAR32(C1DRT1) = temp_drt;
1521
1522 /* Program DRT2 */
1523 reg32 = MCHBAR32(C0DRT2);
1524 reg32 &= ~(1 << 8);
1525 MCHBAR32(C0DRT2) = reg32;
1526
1527 reg32 = MCHBAR32(C1DRT2);
1528 reg32 &= ~(1 << 8);
1529 MCHBAR32(C1DRT2) = reg32;
1530
1531 /* Calculate DRT3 */
1532 temp_drt = MCHBAR32(C0DRT3) & ~0x07ffffff;
1533
1534 /* Get old tRFC value */
1535 reg32 = MCHBAR32(C0DRT1) >> 10;
1536 reg32 &= 0x3f;
1537
1538 /* 788nS - tRFC */
1539 switch (sysinfo->memory_frequency) {
1540 case 400: /* 5nS */
1541 reg32 = ((78800 / 500) - reg32) & 0x1ff;
1542 reg32 |= (0x8c << 16) | (0x0c << 10); /* 1 us */
1543 break;
1544 case 533: /* 3.75nS */
1545 reg32 = ((78800 / 375) - reg32) & 0x1ff;
1546 reg32 |= (0xba << 16) | (0x10 << 10); /* 1 us */
1547 break;
1548 case 667: /* 3nS */
1549 reg32 = ((78800 / 300) - reg32) & 0x1ff;
1550 reg32 |= (0xe9 << 16) | (0x14 << 10); /* 1 us */
1551 break;
1552 }
1553
1554 temp_drt |= reg32;
1555
1556 MCHBAR32(C0DRT3) = temp_drt;
1557 MCHBAR32(C1DRT3) = temp_drt;
1558}
1559
1560static void sdram_set_channel_mode(struct sys_info *sysinfo)
1561{
1562 u32 reg32;
1563
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001564 printk(BIOS_DEBUG, "Setting mode of operation for memory channels...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001565
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001566 if (sdram_capabilities_interleave() &&
Arthur Heymans70a8e342017-03-09 11:30:23 +01001567 ((sysinfo->banksize[0] + sysinfo->banksize[1] +
1568 sysinfo->banksize[2] + sysinfo->banksize[3]) ==
1569 (sysinfo->banksize[4] + sysinfo->banksize[5] +
1570 sysinfo->banksize[6] + sysinfo->banksize[7]))) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001571 /* Both channels equipped with DIMMs of the same size */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001572 sysinfo->interleaved = 1;
1573 } else {
1574 sysinfo->interleaved = 0;
1575 }
1576
1577 reg32 = MCHBAR32(DCC);
1578 reg32 &= ~(7 << 0);
1579
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001580 if (sysinfo->interleaved) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001581 /* Dual Channel Interleaved */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001582 printk(BIOS_DEBUG, "Dual Channel Interleaved.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001583 reg32 |= (1 << 1);
1584 } else if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED &&
1585 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
1586 /* Channel 1 only */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001587 printk(BIOS_DEBUG, "Single Channel 1 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001588 reg32 |= (1 << 2);
Elyes HAOUAS75da1fb2017-02-16 18:59:13 +01001589 } else if (sdram_capabilities_dual_channel() &&
1590 (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1591 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) {
Martin Roth128c1042016-11-18 09:29:03 -07001592 /* Dual Channel Asymmetric */
1593 printk(BIOS_DEBUG, "Dual Channel Asymmetric.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001594 reg32 |= (1 << 0);
1595 } else {
1596 /* All bits 0 means Single Channel 0 operation */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001597 printk(BIOS_DEBUG, "Single Channel 0 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001598 }
1599
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001600 /* Now disable channel XORing */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001601 reg32 |= (1 << 10);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001602
1603 MCHBAR32(DCC) = reg32;
1604
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001605 PRINTK_DEBUG("DCC = 0x%08x\n", MCHBAR32(DCC));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001606}
1607
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001608static void sdram_program_pll_settings(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001609{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001610 MCHBAR32(PLLMON) = 0x80800000;
1611
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001612 sysinfo->fsb_frequency = fsbclk();
Peter Stuge76d91432010-10-01 10:02:33 +00001613 if (sysinfo->fsb_frequency == 0xffff)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001614 die("Unsupported FSB speed");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001615
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001616 /* Program CPCTL according to FSB speed */
1617 /* Only write the lower byte */
1618 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001619 case 400:
1620 MCHBAR8(CPCTL) = 0x90; break; /* FSB400 */
1621 case 533:
1622 MCHBAR8(CPCTL) = 0x95; break; /* FSB533 */
1623 case 667:
1624 MCHBAR8(CPCTL) = 0x8d; break; /* FSB667 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001625 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001626
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001627 MCHBAR16(CPCTL) &= ~(1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001628
Paul Menzel0ce5ebf2013-10-21 21:22:09 +02001629 MCHBAR16(CPCTL); /* Read back register to activate settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001630}
1631
1632static void sdram_program_graphics_frequency(struct sys_info *sysinfo)
1633{
1634 u8 reg8;
1635 u16 reg16;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001636 u8 freq, second_vco, voltage;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001637
1638#define CRCLK_166MHz 0x00
1639#define CRCLK_200MHz 0x01
1640#define CRCLK_250MHz 0x03
1641#define CRCLK_400MHz 0x05
1642
1643#define CDCLK_200MHz 0x00
1644#define CDCLK_320MHz 0x40
1645
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001646#define VOLTAGE_1_05 0x00
1647#define VOLTAGE_1_50 0x01
1648
Paul Menzeldaf9e502014-07-15 23:49:16 +02001649 printk(BIOS_DEBUG, "Setting Graphics Frequency...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001650
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001651 printk(BIOS_DEBUG, "FSB: %d MHz ", sysinfo->fsb_frequency);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001652
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001653 voltage = VOLTAGE_1_05;
1654 if (MCHBAR32(DFT_STRAP1) & (1 << 20))
1655 voltage = VOLTAGE_1_50;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001656 printk(BIOS_DEBUG, "Voltage: %s ", (voltage == VOLTAGE_1_05)?"1.05V":"1.5V");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001657
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001658 /* Gate graphics hardware for frequency change */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001659 reg8 = (1<<3) | (1<<1); /* disable crclk, gate cdclk */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001660 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001661
1662 /* Get graphics frequency capabilities */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001663 reg8 = sdram_capabilities_core_frequencies();
1664
Stefan Reinauer278534d2008-10-29 04:51:07 +00001665 freq = CRCLK_250MHz;
1666 switch (reg8) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001667 case GFX_FREQUENCY_CAP_ALL:
1668 if (voltage == VOLTAGE_1_05)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001669 freq = CRCLK_250MHz;
1670 else
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001671 freq = CRCLK_400MHz; /* 1.5V requires 400MHz */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001672 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001673 case GFX_FREQUENCY_CAP_250MHZ:
1674 freq = CRCLK_250MHz; break;
1675 case GFX_FREQUENCY_CAP_200MHZ:
1676 freq = CRCLK_200MHz; break;
1677 case GFX_FREQUENCY_CAP_166MHZ:
1678 freq = CRCLK_166MHz; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001679 }
1680
1681 if (freq != CRCLK_400MHz) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001682 /* What chipset are we? Force 166MHz for GMS */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001683 reg8 = (pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe7) & 0x70) >> 4;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001684 if (reg8 == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001685 freq = CRCLK_166MHz;
1686 }
1687
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001688 printk(BIOS_DEBUG, "Render: ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001689 switch (freq) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001690 case CRCLK_166MHz:
1691 printk(BIOS_DEBUG, "166MHz"); break;
1692 case CRCLK_200MHz:
1693 printk(BIOS_DEBUG, "200MHz"); break;
1694 case CRCLK_250MHz:
1695 printk(BIOS_DEBUG, "250MHz"); break;
1696 case CRCLK_400MHz:
1697 printk(BIOS_DEBUG, "400MHz"); break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001698 }
1699
Arthur Heymans70a8e342017-03-09 11:30:23 +01001700 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001701 sysinfo->mvco4x = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001702 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001703 sysinfo->mvco4x = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001704
Stefan Reinauer278534d2008-10-29 04:51:07 +00001705 second_vco = 0;
1706
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001707 if (voltage == VOLTAGE_1_50) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001708 second_vco = 1;
1709 } else if ((i945_silicon_revision() > 0) && (freq == CRCLK_250MHz)) {
1710 u16 mem = sysinfo->memory_frequency;
1711 u16 fsb = sysinfo->fsb_frequency;
1712
Arthur Heymans70a8e342017-03-09 11:30:23 +01001713 if ((fsb == 667 && mem == 533) ||
1714 (fsb == 533 && mem == 533) ||
1715 (fsb == 533 && mem == 400)) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001716 second_vco = 1;
1717 }
1718
1719 if (fsb == 667 && mem == 533)
1720 sysinfo->mvco4x = 1;
1721 }
1722
Arthur Heymans70a8e342017-03-09 11:30:23 +01001723 if (second_vco)
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001724 sysinfo->clkcfg_bit7 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001725 else
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001726 sysinfo->clkcfg_bit7 = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001727
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001728 /* Graphics Core Render Clock */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001729 reg16 = pci_read_config16(PCI_DEV(0, 2, 0), GCFC);
1730 reg16 &= ~((7 << 0) | (1 << 13));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001731 reg16 |= freq;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001732 pci_write_config16(PCI_DEV(0, 2, 0), GCFC, reg16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001733
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001734 /* Graphics Core Display Clock */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001735 reg8 = pci_read_config8(PCI_DEV(0, 2, 0), GCFC);
1736 reg8 &= ~((1<<7) | (7<<4));
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001737
1738 if (voltage == VOLTAGE_1_05) {
1739 reg8 |= CDCLK_200MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001740 printk(BIOS_DEBUG, " Display: 200MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001741 } else {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001742 reg8 |= CDCLK_320MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001743 printk(BIOS_DEBUG, " Display: 320MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001744 }
Arthur Heymans70a8e342017-03-09 11:30:23 +01001745 pci_write_config8(PCI_DEV(0, 2, 0), GCFC, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001746
Arthur Heymans70a8e342017-03-09 11:30:23 +01001747 reg8 = pci_read_config8(PCI_DEV(0, 2, 0), GCFC + 1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001748
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001749 reg8 |= (1<<3) | (1<<1);
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 reg8 |= 0x0f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001753 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001754
1755 /* Ungate core render and display clocks */
1756 reg8 &= 0xf0;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001757 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001758}
1759
1760static void sdram_program_memory_frequency(struct sys_info *sysinfo)
1761{
1762 u32 clkcfg;
1763 u8 reg8;
Julius Wernercd49cce2019-03-05 16:53:33 -08001764 u8 offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001765
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001766 printk(BIOS_DEBUG, "Setting Memory Frequency... ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001767
Stefan Reinauer278534d2008-10-29 04:51:07 +00001768 clkcfg = MCHBAR32(CLKCFG);
1769
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001770 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001771
Arthur Heymans70a8e342017-03-09 11:30:23 +01001772 clkcfg &= ~((1 << 12) | (1 << 7) | (7 << 4));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001773
1774 if (sysinfo->mvco4x) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001775 printk(BIOS_DEBUG, "MVCO 4x, ");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001776 clkcfg &= ~(1 << 12);
1777 }
1778
1779 if (sysinfo->clkcfg_bit7) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001780 printk(BIOS_DEBUG, "second VCO, ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001781
Stefan Reinauer278534d2008-10-29 04:51:07 +00001782 clkcfg |= (1 << 7);
1783 }
1784
1785 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001786 case 400:
1787 clkcfg |= ((1 + offset) << 4); break;
1788 case 533:
1789 clkcfg |= ((2 + offset) << 4); break;
1790 case 667:
1791 clkcfg |= ((3 + offset) << 4); break;
1792 default:
1793 die("Target Memory Frequency Error");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001794 }
1795
1796 if (MCHBAR32(CLKCFG) == clkcfg) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001797 printk(BIOS_DEBUG, "ok (unchanged)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001798 return;
1799 }
1800
1801 MCHBAR32(CLKCFG) = clkcfg;
1802
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001803 /* Make sure the following code is in the
Stefan Reinauer278534d2008-10-29 04:51:07 +00001804 * cache before we execute it.
1805 */
1806 goto cache_code;
1807vco_update:
Elyes HAOUAS32b9a992019-01-21 14:54:31 +01001808 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001809 reg8 &= ~(1 << 7);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +01001810 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001811
Stefan Reinauer278534d2008-10-29 04:51:07 +00001812 clkcfg &= ~(1 << 10);
1813 MCHBAR32(CLKCFG) = clkcfg;
1814 clkcfg |= (1 << 10);
1815 MCHBAR32(CLKCFG) = clkcfg;
1816
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001817 asm volatile (
Stefan Reinauer278534d2008-10-29 04:51:07 +00001818 " movl $0x100, %%ecx\n"
1819 "delay_update:\n"
1820 " nop\n"
1821 " nop\n"
1822 " nop\n"
1823 " nop\n"
1824 " loop delay_update\n"
1825 : /* No outputs */
1826 : /* No inputs */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001827 : "%ecx", "memory"
Stefan Reinauer278534d2008-10-29 04:51:07 +00001828 );
1829
Stefan Reinauer278534d2008-10-29 04:51:07 +00001830 clkcfg &= ~(1 << 10);
1831 MCHBAR32(CLKCFG) = clkcfg;
1832
1833 goto out;
1834cache_code:
1835 goto vco_update;
1836out:
1837
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001838 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", MCHBAR32(CLKCFG));
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001839 printk(BIOS_DEBUG, "ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001840}
1841
1842static void sdram_program_clock_crossing(void)
1843{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001844 int idx = 0;
1845
1846 /**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001847 * We add the indices according to our clocks from CLKCFG.
Stefan Reinauer278534d2008-10-29 04:51:07 +00001848 */
Julius Wernercd49cce2019-03-05 16:53:33 -08001849#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001850 static const u32 data_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001851 0x00100401, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001852 0xffffffff, 0xffffffff, /* nonexistent */
1853 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001854
Stefan Reinauer278534d2008-10-29 04:51:07 +00001855 0x08040120, 0x00000000, /* DDR400 FSB533 */
1856 0x00100401, 0x00000000, /* DDR533 FSB533 */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001857 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001858
1859 0x04020120, 0x00000010, /* DDR400 FSB667 */
1860 0x10040280, 0x00000040, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001861 0x00100401, 0x00000000, /* DDR667 FSB667 */
1862
Martin Roth2ed0aa22016-01-05 20:58:58 -07001863 0xffffffff, 0xffffffff, /* nonexistent */
1864 0xffffffff, 0xffffffff, /* nonexistent */
1865 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001866
Martin Roth2ed0aa22016-01-05 20:58:58 -07001867 0xffffffff, 0xffffffff, /* nonexistent */
1868 0xffffffff, 0xffffffff, /* nonexistent */
1869 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001870 };
1871
1872 static const u32 command_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001873 0x04020208, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001874 0xffffffff, 0xffffffff, /* nonexistent */
1875 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001876
Stefan Reinauer278534d2008-10-29 04:51:07 +00001877 0x00060108, 0x00000000, /* DDR400 FSB533 */
1878 0x04020108, 0x00000000, /* DDR533 FSB533 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001879 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001880
1881 0x00040318, 0x00000000, /* DDR400 FSB667 */
1882 0x04020118, 0x00000000, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001883 0x02010804, 0x00000000, /* DDR667 FSB667 */
1884
Martin Roth2ed0aa22016-01-05 20:58:58 -07001885 0xffffffff, 0xffffffff, /* nonexistent */
1886 0xffffffff, 0xffffffff, /* nonexistent */
1887 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001888
Martin Roth2ed0aa22016-01-05 20:58:58 -07001889 0xffffffff, 0xffffffff, /* nonexistent */
1890 0xffffffff, 0xffffffff, /* nonexistent */
1891 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001892 };
1893
Julius Wernercd49cce2019-03-05 16:53:33 -08001894#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001895 /* i945 G/P */
1896 static const u32 data_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001897 0xffffffff, 0xffffffff, /* nonexistent */
1898 0xffffffff, 0xffffffff, /* nonexistent */
1899 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001900
1901 0x10080201, 0x00000000, /* DDR400 FSB533 */
1902 0x00100401, 0x00000000, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001903 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001904
Martin Roth2ed0aa22016-01-05 20:58:58 -07001905 0xffffffff, 0xffffffff, /* nonexistent */
1906 0xffffffff, 0xffffffff, /* nonexistent */
1907 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001908
1909 0x04020108, 0x00000000, /* DDR400 FSB800 */
1910 0x00020108, 0x00000000, /* DDR533 FSB800 */
1911 0x00080201, 0x00000000, /* DDR667 FSB800 */
1912
1913 0x00010402, 0x00000000, /* DDR400 FSB1066 */
1914 0x04020108, 0x00000000, /* DDR533 FSB1066 */
1915 0x08040110, 0x00000000, /* DDR667 FSB1066 */
1916 };
1917
1918 static const u32 command_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001919 0xffffffff, 0xffffffff, /* nonexistent */
1920 0xffffffff, 0xffffffff, /* nonexistent */
1921 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001922
1923 0x00010800, 0x00000402, /* DDR400 FSB533 */
1924 0x01000400, 0x00000200, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001925 0x00020904, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001926
Martin Roth2ed0aa22016-01-05 20:58:58 -07001927 0xffffffff, 0xffffffff, /* nonexistent */
1928 0xffffffff, 0xffffffff, /* nonexistent */
1929 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001930
1931 0x02010804, 0x00000000, /* DDR400 FSB800 */
1932 0x00010402, 0x00000000, /* DDR533 FSB800 */
Arthur Heymans8b6df622016-10-16 10:58:01 +02001933 0x04020130, 0x00000008, /* DDR667 FSB800 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001934
1935 0x00020904, 0x00000000, /* DDR400 FSB1066 */
1936 0x02010804, 0x00000000, /* DDR533 FSB1066 */
1937 0x180601c0, 0x00000020, /* DDR667 FSB1066 */
1938 };
1939#endif
1940
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001941 printk(BIOS_DEBUG, "Programming Clock Crossing...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001942
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001943 printk(BIOS_DEBUG, "MEM=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001944 switch (memclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001945 case 400:
1946 printk(BIOS_DEBUG, "400"); idx += 0; break;
1947 case 533:
1948 printk(BIOS_DEBUG, "533"); idx += 2; break;
1949 case 667:
1950 printk(BIOS_DEBUG, "667"); idx += 4; break;
1951 default:
1952 printk(BIOS_DEBUG, "RSVD %x", memclk()); return;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001953 }
1954
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001955 printk(BIOS_DEBUG, " FSB=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001956 switch (fsbclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001957 case 400:
1958 printk(BIOS_DEBUG, "400"); idx += 0; break;
1959 case 533:
1960 printk(BIOS_DEBUG, "533"); idx += 6; break;
1961 case 667:
1962 printk(BIOS_DEBUG, "667"); idx += 12; break;
1963 case 800:
1964 printk(BIOS_DEBUG, "800"); idx += 18; break;
1965 case 1066:
1966 printk(BIOS_DEBUG, "1066"); idx += 24; break;
1967 default:
1968 printk(BIOS_DEBUG, "RSVD %x\n", fsbclk()); return;
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001969 }
1970
Arthur Heymans70a8e342017-03-09 11:30:23 +01001971 if (command_clock_crossing[idx] == 0xffffffff)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001972 printk(BIOS_DEBUG, "Invalid MEM/FSB combination!\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001973
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001974 MCHBAR32(CCCFT + 0) = command_clock_crossing[idx];
1975 MCHBAR32(CCCFT + 4) = command_clock_crossing[idx + 1];
1976
Stefan Reinauer278534d2008-10-29 04:51:07 +00001977 MCHBAR32(C0DCCFT + 0) = data_clock_crossing[idx];
1978 MCHBAR32(C0DCCFT + 4) = data_clock_crossing[idx + 1];
1979 MCHBAR32(C1DCCFT + 0) = data_clock_crossing[idx];
1980 MCHBAR32(C1DCCFT + 4) = data_clock_crossing[idx + 1];
1981
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001982 printk(BIOS_DEBUG, "... ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001983}
1984
1985static void sdram_disable_fast_dispatch(void)
1986{
1987 u32 reg32;
1988
1989 reg32 = MCHBAR32(FSBPMC3);
1990 reg32 |= (1 << 1);
1991 MCHBAR32(FSBPMC3) = reg32;
1992
1993 reg32 = MCHBAR32(SBTEST);
1994 reg32 |= (3 << 1);
1995 MCHBAR32(SBTEST) = reg32;
1996}
1997
1998static void sdram_pre_jedec_initialization(void)
1999{
2000 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002001
Stefan Reinauer278534d2008-10-29 04:51:07 +00002002 reg32 = MCHBAR32(WCC);
2003 reg32 &= 0x113ff3ff;
2004 reg32 |= (4 << 29) | (3 << 25) | (1 << 10);
2005 MCHBAR32(WCC) = reg32;
2006
2007 MCHBAR32(SMVREFC) |= (1 << 6);
2008
2009 MCHBAR32(MMARB0) &= ~(3 << 17);
2010 MCHBAR32(MMARB0) |= (1 << 21) | (1 << 16);
2011
2012 MCHBAR32(MMARB1) &= ~(7 << 8);
2013 MCHBAR32(MMARB1) |= (3 << 8);
2014
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002015 /* Adaptive Idle Timer Control */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002016 MCHBAR32(C0AIT) = 0x000006c4;
2017 MCHBAR32(C0AIT+4) = 0x871a066d;
2018
2019 MCHBAR32(C1AIT) = 0x000006c4;
2020 MCHBAR32(C1AIT+4) = 0x871a066d;
2021}
2022
2023#define EA_DUALCHANNEL_XOR_BANK_RANK_MODE (0xd4 << 24)
2024#define EA_DUALCHANNEL_XOR_BANK_MODE (0xf4 << 24)
2025#define EA_DUALCHANNEL_BANK_RANK_MODE (0xc2 << 24)
2026#define EA_DUALCHANNEL_BANK_MODE (0xe2 << 24)
2027#define EA_SINGLECHANNEL_XOR_BANK_RANK_MODE (0x91 << 24)
2028#define EA_SINGLECHANNEL_XOR_BANK_MODE (0xb1 << 24)
2029#define EA_SINGLECHANNEL_BANK_RANK_MODE (0x80 << 24)
2030#define EA_SINGLECHANNEL_BANK_MODE (0xa0 << 24)
2031
2032static void sdram_enhanced_addressing_mode(struct sys_info *sysinfo)
2033{
2034 u32 chan0 = 0, chan1 = 0;
2035 int chan0_dualsided, chan1_dualsided, chan0_populated, chan1_populated;
2036
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002037 chan0_populated = (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Stefan Reinauer278534d2008-10-29 04:51:07 +00002038 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED);
Elyes HAOUAS308aeff2017-02-24 12:53:07 +01002039 chan1_populated = (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
2040 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002041 chan0_dualsided = (sysinfo->banksize[1] || sysinfo->banksize[3]);
2042 chan1_dualsided = (sysinfo->banksize[5] || sysinfo->banksize[7]);
2043
2044 if (sdram_capabilities_enhanced_addressing_xor()) {
2045 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002046 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002047 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002048 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002049 chan0 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002050 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002051 chan0 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002052 }
2053 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002054 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002055 chan1 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002056 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002057 chan1 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002058 }
2059 } else {
2060 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002061 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002062 chan0 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002063 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002064 chan0 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002065
Arthur Heymans70a8e342017-03-09 11:30:23 +01002066 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002067 chan1 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002068 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002069 chan1 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002070 }
2071 } else {
2072 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002073 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002074 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002075 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002076 chan0 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002077 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002078 chan0 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002079 }
2080 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002081 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002082 chan1 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002083 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002084 chan1 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002085 }
2086 } else {
2087 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002088 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002089 chan0 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002090 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002091 chan0 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002092
Arthur Heymans70a8e342017-03-09 11:30:23 +01002093 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002094 chan1 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002095 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002096 chan1 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002097 }
2098 }
2099
2100 MCHBAR32(C0DRC1) &= 0x00ffffff;
2101 MCHBAR32(C0DRC1) |= chan0;
2102 MCHBAR32(C1DRC1) &= 0x00ffffff;
2103 MCHBAR32(C1DRC1) |= chan1;
2104}
2105
2106static void sdram_post_jedec_initialization(struct sys_info *sysinfo)
2107{
2108 u32 reg32;
2109
2110 /* Enable Channel XORing for Dual Channel Interleave */
2111 if (sysinfo->interleaved) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002112
Stefan Reinauer278534d2008-10-29 04:51:07 +00002113 reg32 = MCHBAR32(DCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002114 reg32 &= ~(1 << 10);
Stefan Reinauer30140a52009-03-11 16:20:39 +00002115 reg32 |= (1 << 9);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002116 MCHBAR32(DCC) = reg32;
2117 }
2118
2119 /* DRAM mode optimizations */
2120 sdram_enhanced_addressing_mode(sysinfo);
2121
2122 reg32 = MCHBAR32(FSBPMC3);
2123 reg32 &= ~(1 << 1);
2124 MCHBAR32(FSBPMC3) = reg32;
2125
2126 reg32 = MCHBAR32(SBTEST);
2127 reg32 &= ~(1 << 2);
2128 MCHBAR32(SBTEST) = reg32;
2129
2130 reg32 = MCHBAR32(SBOCC);
2131 reg32 &= 0xffbdb6ff;
2132 reg32 |= (0xbdb6 << 8) | (1 << 0);
2133 MCHBAR32(SBOCC) = reg32;
2134}
2135
2136static void sdram_power_management(struct sys_info *sysinfo)
2137{
2138 u8 reg8;
2139 u16 reg16;
2140 u32 reg32;
2141 int integrated_graphics = 1;
2142 int i;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002143
Stefan Reinauer278534d2008-10-29 04:51:07 +00002144 reg32 = MCHBAR32(C0DRT2);
2145 reg32 &= 0xffffff00;
2146 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002147 reg32 |= (1 << 5) | (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002148 MCHBAR32(C0DRT2) = reg32;
2149
2150 reg32 = MCHBAR32(C1DRT2);
2151 reg32 &= 0xffffff00;
2152 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002153 reg32 |= (1 << 5) | (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002154 MCHBAR32(C1DRT2) = reg32;
2155
2156 reg32 = MCHBAR32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002157
2158 reg32 |= (1 << 12) | (1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002159 MCHBAR32(C0DRC1) = reg32;
2160
2161 reg32 = MCHBAR32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002162
2163 reg32 |= (1 << 12) | (1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002164 MCHBAR32(C1DRC1) = reg32;
2165
Julius Wernercd49cce2019-03-05 16:53:33 -08002166 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002167 if (i945_silicon_revision() > 1) {
2168 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2169 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002170
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002171 MCHBAR16(UPMC1) = 0x1010 | peg_bits;
2172 } else {
2173 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2174 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002175
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002176 /* Rev 0 and 1 */
2177 MCHBAR16(UPMC1) = 0x0010 | peg_bits;
2178 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002179 }
2180
2181 reg16 = MCHBAR16(UPMC2);
2182 reg16 &= 0xfc00;
2183 reg16 |= 0x0100;
2184 MCHBAR16(UPMC2) = reg16;
2185
2186 MCHBAR32(UPMC3) = 0x000f06ff;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002187
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002188 for (i = 0; i < 5; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002189 MCHBAR32(UPMC3) &= ~(1 << 16);
2190 MCHBAR32(UPMC3) |= (1 << 16);
2191 }
2192
2193 MCHBAR32(GIPMC1) = 0x8000000c;
2194
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002195 reg16 = MCHBAR16(CPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002196 reg16 &= ~(7 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002197 if (i945_silicon_revision() > 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002198 reg16 |= (6 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002199 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002200 reg16 |= (4 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002201 MCHBAR16(CPCTL) = reg16;
2202
Stefan Reinauer30140a52009-03-11 16:20:39 +00002203#if 0
Stefan Reinauer278534d2008-10-29 04:51:07 +00002204 if ((MCHBAR32(ECO) & (1 << 16)) != 0) {
Stefan Reinauer30140a52009-03-11 16:20:39 +00002205#else
2206 if (i945_silicon_revision() != 0) {
2207#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002208 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002209 case 667:
2210 MCHBAR32(HGIPMC2) = 0x0d590d59; break;
2211 case 533:
2212 MCHBAR32(HGIPMC2) = 0x155b155b; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002213 }
2214 } else {
2215 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002216 case 667:
2217 MCHBAR32(HGIPMC2) = 0x09c409c4; break;
2218 case 533:
2219 MCHBAR32(HGIPMC2) = 0x0fa00fa0; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002220 }
2221 }
2222
2223 MCHBAR32(FSBPMC1) = 0x8000000c;
2224
2225 reg32 = MCHBAR32(C2C3TT);
2226 reg32 &= 0xffff0000;
2227 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002228 case 667:
2229 reg32 |= 0x0600; break;
2230 case 533:
2231 reg32 |= 0x0480; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002232 }
2233 MCHBAR32(C2C3TT) = reg32;
2234
2235 reg32 = MCHBAR32(C3C4TT);
2236 reg32 &= 0xffff0000;
2237 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002238 case 667:
2239 reg32 |= 0x0b80; break;
2240 case 533:
2241 reg32 |= 0x0980; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002242 }
2243 MCHBAR32(C3C4TT) = reg32;
2244
Arthur Heymans70a8e342017-03-09 11:30:23 +01002245 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002246 MCHBAR32(ECO) &= ~(1 << 16);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002247 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002248 MCHBAR32(ECO) |= (1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002249
2250#if 0
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002251
Arthur Heymans70a8e342017-03-09 11:30:23 +01002252 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002253 MCHBAR32(FSBPMC3) &= ~(1 << 29);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002254 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002255 MCHBAR32(FSBPMC3) |= (1 << 29);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002256#endif
2257 MCHBAR32(FSBPMC3) &= ~(1 << 29);
2258
2259 MCHBAR32(FSBPMC3) |= (1 << 21);
2260
2261 MCHBAR32(FSBPMC3) &= ~(1 << 19);
2262
2263 MCHBAR32(FSBPMC3) &= ~(1 << 13);
2264
2265 reg32 = MCHBAR32(FSBPMC4);
2266 reg32 &= ~(3 << 24);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002267 reg32 |= (2 << 24);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002268 MCHBAR32(FSBPMC4) = reg32;
2269
2270 MCHBAR32(FSBPMC4) |= (1 << 21);
2271
2272 MCHBAR32(FSBPMC4) |= (1 << 5);
2273
Arthur Heymans70a8e342017-03-09 11:30:23 +01002274 if ((i945_silicon_revision() < 2)) { /* || cpuid() = 0x6e8 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002275 /* stepping 0 and 1 or CPUID 6e8 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002276 MCHBAR32(FSBPMC4) &= ~(1 << 4);
2277 } else {
Stefan Reinauer30140a52009-03-11 16:20:39 +00002278 MCHBAR32(FSBPMC4) |= (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002279 }
2280
Arthur Heymans70a8e342017-03-09 11:30:23 +01002281 reg8 = pci_read_config8(PCI_DEV(0, 0x0, 0), 0xfc);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002282 reg8 |= (1 << 4);
2283 pci_write_config8(PCI_DEV(0, 0x0, 0), 0xfc, reg8);
2284
Arthur Heymans70a8e342017-03-09 11:30:23 +01002285 reg8 = pci_read_config8(PCI_DEV(0, 0x2, 0), 0xc1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002286 reg8 |= (1 << 2);
2287 pci_write_config8(PCI_DEV(0, 0x2, 0), 0xc1, reg8);
2288
Stefan Reinauerde3206a2010-02-22 06:09:43 +00002289#ifdef C2_SELF_REFRESH_DISABLE
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002290
Stefan Reinauer278534d2008-10-29 04:51:07 +00002291 if (integrated_graphics) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002292 printk(BIOS_DEBUG, "C2 self-refresh with IGD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002293 MCHBAR16(MIPMC4) = 0x0468;
2294 MCHBAR16(MIPMC5) = 0x046c;
2295 MCHBAR16(MIPMC6) = 0x046c;
2296 } else {
2297 MCHBAR16(MIPMC4) = 0x6468;
2298 MCHBAR16(MIPMC5) = 0x646c;
2299 MCHBAR16(MIPMC6) = 0x646c;
2300 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002301#else
2302 if (integrated_graphics) {
2303 MCHBAR16(MIPMC4) = 0x04f8;
2304 MCHBAR16(MIPMC5) = 0x04fc;
2305 MCHBAR16(MIPMC6) = 0x04fc;
2306 } else {
2307 MCHBAR16(MIPMC4) = 0x64f8;
2308 MCHBAR16(MIPMC5) = 0x64fc;
2309 MCHBAR16(MIPMC6) = 0x64fc;
2310 }
2311
2312#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002313
2314 reg32 = MCHBAR32(PMCFG);
2315 reg32 &= ~(3 << 17);
2316 reg32 |= (2 << 17);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002317 MCHBAR32(PMCFG) = reg32;
2318
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002319 MCHBAR32(PMCFG) |= (1 << 4);
2320
Stefan Reinauer278534d2008-10-29 04:51:07 +00002321 reg32 = MCHBAR32(0xc30);
2322 reg32 &= 0xffffff00;
2323 reg32 |= 0x01;
2324 MCHBAR32(0xc30) = reg32;
2325
2326 MCHBAR32(0xb18) &= ~(1 << 21);
2327}
2328
2329static void sdram_thermal_management(void)
2330{
Stefan Reinauer278534d2008-10-29 04:51:07 +00002331
Stefan Reinauer278534d2008-10-29 04:51:07 +00002332 MCHBAR8(TCO1) = 0x00;
2333 MCHBAR8(TCO0) = 0x00;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002334
2335 /* The Thermal Sensors for DIMMs at 0x50, 0x52 are at I2C addr
2336 * 0x30/0x32.
2337 */
2338
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002339 /* TODO This is not implemented yet. Volunteers? */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002340}
2341
2342static void sdram_save_receive_enable(void)
2343{
2344 int i;
2345 u32 reg32;
2346 u8 values[4];
2347
2348 /* The following values are stored to an unused CMOS
2349 * area and restored instead of recalculated in case
2350 * of an S3 resume.
2351 *
Arthur Heymans70a8e342017-03-09 11:30:23 +01002352 * C0WL0REOST [7:0] -> 8 bit
2353 * C1WL0REOST [7:0] -> 8 bit
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002354 * RCVENMT [11:8] [3:0] -> 8 bit
2355 * C0DRT1 [27:24] -> 4 bit
2356 * C1DRT1 [27:24] -> 4 bit
2357 */
2358
2359 values[0] = MCHBAR8(C0WL0REOST);
2360 values[1] = MCHBAR8(C1WL0REOST);
2361
2362 reg32 = MCHBAR32(RCVENMT);
2363 values[2] = (u8)((reg32 >> (8 - 4)) & 0xf0) | (reg32 & 0x0f);
2364
2365 reg32 = MCHBAR32(C0DRT1);
2366 values[3] = (reg32 >> 24) & 0x0f;
2367 reg32 = MCHBAR32(C1DRT1);
2368 values[3] |= (reg32 >> (24 - 4)) & 0xf0;
2369
2370 /* coreboot only uses bytes 0 - 127 for its CMOS values so far
Edwin Beasanteb50c7d2010-07-06 21:05:04 +00002371 * so we grab bytes 128 - 131 to save the receive enable values
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002372 */
2373
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002374 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002375 cmos_write(values[i], 128 + i);
2376}
2377
2378static void sdram_recover_receive_enable(void)
2379{
2380 int i;
2381 u32 reg32;
2382 u8 values[4];
2383
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002384 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002385 values[i] = cmos_read(128 + i);
2386
2387 MCHBAR8(C0WL0REOST) = values[0];
2388 MCHBAR8(C1WL0REOST) = values[1];
2389
2390 reg32 = MCHBAR32(RCVENMT);
2391 reg32 &= ~((0x0f << 8) | (0x0f << 0));
2392 reg32 |= ((u32)(values[2] & 0xf0) << (8 - 4)) | (values[2] & 0x0f);
2393 MCHBAR32(RCVENMT) = reg32;
2394
2395 reg32 = MCHBAR32(C0DRT1) & ~(0x0f << 24);
2396 reg32 |= (u32)(values[3] & 0x0f) << 24;
2397 MCHBAR32(C0DRT1) = reg32;
2398
2399 reg32 = MCHBAR32(C1DRT1) & ~(0x0f << 24);
2400 reg32 |= (u32)(values[3] & 0xf0) << (24 - 4);
2401 MCHBAR32(C1DRT1) = reg32;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002402}
2403
Stefan Reinauer278534d2008-10-29 04:51:07 +00002404static void sdram_program_receive_enable(struct sys_info *sysinfo)
2405{
2406 MCHBAR32(REPC) |= (1 << 0);
2407
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002408 /* Program Receive Enable Timings */
2409 if (sysinfo->boot_path == BOOT_PATH_RESUME) {
2410 sdram_recover_receive_enable();
2411 } else {
2412 receive_enable_adjust(sysinfo);
2413 sdram_save_receive_enable();
2414 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002415
2416 MCHBAR32(C0DRC1) |= (1 << 6);
2417 MCHBAR32(C1DRC1) |= (1 << 6);
2418 MCHBAR32(C0DRC1) &= ~(1 << 6);
2419 MCHBAR32(C1DRC1) &= ~(1 << 6);
2420
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002421 MCHBAR32(MIPMC3) |= (0x0f << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002422}
2423
2424/**
2425 * @brief Enable On-Die Termination for DDR2.
2426 *
2427 */
2428
2429static void sdram_on_die_termination(struct sys_info *sysinfo)
2430{
2431 static const u32 odt[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002432 0x00024911, 0xe0010000,
2433 0x00049211, 0xe0020000,
2434 0x0006db11, 0xe0030000,
Stefan Reinauer278534d2008-10-29 04:51:07 +00002435 };
2436
2437 u32 reg32;
2438 int cas;
2439
2440 reg32 = MCHBAR32(ODTC);
2441 reg32 &= ~(3 << 16);
2442 reg32 |= (1 << 14) | (1 << 6) | (2 << 16);
2443 MCHBAR32(ODTC) = reg32;
2444
Arthur Heymans70a8e342017-03-09 11:30:23 +01002445 if (!(sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED &&
2446 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)) {
Elyes HAOUAS38424982016-08-21 12:01:04 +02002447 printk(BIOS_DEBUG, "one dimm per channel config..\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002448
Stefan Reinauer278534d2008-10-29 04:51:07 +00002449 reg32 = MCHBAR32(C0ODT);
2450 reg32 &= ~(7 << 28);
2451 MCHBAR32(C0ODT) = reg32;
2452 reg32 = MCHBAR32(C1ODT);
2453 reg32 &= ~(7 << 28);
2454 MCHBAR32(C1ODT) = reg32;
2455 }
2456
2457 cas = sysinfo->cas;
2458
2459 reg32 = MCHBAR32(C0ODT) & 0xfff00000;
2460 reg32 |= odt[(cas-3) * 2];
2461 MCHBAR32(C0ODT) = reg32;
2462
2463 reg32 = MCHBAR32(C1ODT) & 0xfff00000;
2464 reg32 |= odt[(cas-3) * 2];
2465 MCHBAR32(C1ODT) = reg32;
2466
2467 reg32 = MCHBAR32(C0ODT + 4) & 0x1fc8ffff;
2468 reg32 |= odt[((cas-3) * 2) + 1];
2469 MCHBAR32(C0ODT + 4) = reg32;
2470
2471 reg32 = MCHBAR32(C1ODT + 4) & 0x1fc8ffff;
2472 reg32 |= odt[((cas-3) * 2) + 1];
2473 MCHBAR32(C1ODT + 4) = reg32;
2474}
2475
2476/**
2477 * @brief Enable clocks to populated sockets
2478 */
2479
2480static void sdram_enable_memory_clocks(struct sys_info *sysinfo)
2481{
2482 u8 clocks[2] = { 0, 0 };
2483
Julius Wernercd49cce2019-03-05 16:53:33 -08002484#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002485#define CLOCKS_WIDTH 2
Julius Wernercd49cce2019-03-05 16:53:33 -08002486#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002487#define CLOCKS_WIDTH 3
2488#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002489 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002490 clocks[0] |= (1 << CLOCKS_WIDTH)-1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002491
2492 if (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002493 clocks[0] |= ((1 << CLOCKS_WIDTH)-1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002494
2495 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002496 clocks[1] |= (1 << CLOCKS_WIDTH)-1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002497
2498 if (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002499 clocks[1] |= ((1 << CLOCKS_WIDTH)-1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002500
Julius Wernercd49cce2019-03-05 16:53:33 -08002501#if CONFIG(OVERRIDE_CLOCK_DISABLE)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002502 /* Usually system firmware turns off system memory clock signals
2503 * to unused SO-DIMM slots to reduce EMI and power consumption.
2504 * However, the Kontron 986LCD-M does not like unused clock
2505 * signals to be disabled.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002506 */
2507
2508 clocks[0] = 0xf; /* force all clock gate pairs to enable */
2509 clocks[1] = 0xf; /* force all clock gate pairs to enable */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002510#endif
2511
2512 MCHBAR8(C0DCLKDIS) = clocks[0];
2513 MCHBAR8(C1DCLKDIS) = clocks[1];
2514}
2515
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002516#define RTT_ODT_NONE 0
Arthur Heymans70a8e342017-03-09 11:30:23 +01002517#define RTT_ODT_50_OHM ((1 << 9) | (1 << 5))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002518#define RTT_ODT_75_OHM (1 << 5)
2519#define RTT_ODT_150_OHM (1 << 9)
2520
Arthur Heymans70a8e342017-03-09 11:30:23 +01002521#define EMRS_OCD_DEFAULT ((1 << 12) | (1 << 11) | (1 << 10))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002522
2523#define MRS_CAS_3 (3 << 7)
2524#define MRS_CAS_4 (4 << 7)
2525#define MRS_CAS_5 (5 << 7)
2526
2527#define MRS_TWR_3 (2 << 12)
2528#define MRS_TWR_4 (3 << 12)
2529#define MRS_TWR_5 (4 << 12)
2530
2531#define MRS_BT (1 << 6)
2532
2533#define MRS_BL4 (2 << 3)
2534#define MRS_BL8 (3 << 3)
2535
2536static void sdram_jedec_enable(struct sys_info *sysinfo)
2537{
2538 int i, nonzero;
2539 u32 bankaddr = 0, tmpaddr, mrsaddr = 0;
2540
2541 for (i = 0, nonzero = -1; i < 8; i++) {
Elyes HAOUAS01912202019-01-19 16:36:38 +01002542 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002543 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002544
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002545 printk(BIOS_DEBUG, "jedec enable sequence: bank %d\n", i);
Elyes HAOUAS01912202019-01-19 16:36:38 +01002546
2547 if (nonzero != -1) {
2548 if (sysinfo->interleaved && nonzero < 4 && i >= 4) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002549 bankaddr = 0x40;
Elyes HAOUAS01912202019-01-19 16:36:38 +01002550 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002551 printk(BIOS_DEBUG, "bankaddr from bank size of rank %d\n", nonzero);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002552 bankaddr += sysinfo->banksize[nonzero] <<
2553 (sysinfo->interleaved ? 26 : 25);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002554 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002555 }
2556
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002557 /* We have a bank with a non-zero size.. Remember it
Stefan Reinauer278534d2008-10-29 04:51:07 +00002558 * for the next offset we have to calculate
2559 */
2560 nonzero = i;
2561
2562 /* Get CAS latency set up */
2563 switch (sysinfo->cas) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002564 case 5:
2565 mrsaddr = MRS_CAS_5; break;
2566 case 4:
2567 mrsaddr = MRS_CAS_4; break;
2568 case 3:
2569 mrsaddr = MRS_CAS_3; break;
2570 default:
2571 die("Jedec Error (CAS).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002572 }
2573
2574 /* Get tWR set */
2575 switch (sysinfo->twr) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002576 case 5:
2577 mrsaddr |= MRS_TWR_5; break;
2578 case 4:
2579 mrsaddr |= MRS_TWR_4; break;
2580 case 3:
2581 mrsaddr |= MRS_TWR_3; break;
2582 default:
2583 die("Jedec Error (tWR).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002584 }
2585
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002586 /* Set "Burst Type" */
2587 mrsaddr |= MRS_BT;
2588
Stefan Reinauer278534d2008-10-29 04:51:07 +00002589 /* Interleaved */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002590 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002591 mrsaddr = mrsaddr << 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002592
2593 /* Only burst length 8 supported */
2594 mrsaddr |= MRS_BL8;
2595
2596 /* Apply NOP */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002597 PRINTK_DEBUG("Apply NOP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002598 do_ram_command(RAM_COMMAND_NOP);
2599 ram_read32(bankaddr);
2600
2601 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002602 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002603 do_ram_command(RAM_COMMAND_PRECHARGE);
2604 ram_read32(bankaddr);
2605
2606 /* Extended Mode Register Set (2) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002607 PRINTK_DEBUG("Extended Mode Register Set(2)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002608 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_2);
2609 ram_read32(bankaddr);
2610
2611 /* Extended Mode Register Set (3) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002612 PRINTK_DEBUG("Extended Mode Register Set(3)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002613 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_3);
2614 ram_read32(bankaddr);
2615
2616 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002617 PRINTK_DEBUG("Extended Mode Register Set\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002618 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2619 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002620 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002621 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002622 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002623 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002624 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002625 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002626 ram_read32(tmpaddr);
2627
2628 /* Mode Register Set: Reset DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002629 PRINTK_DEBUG("MRS: Reset DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002630 do_ram_command(RAM_COMMAND_MRS);
2631 tmpaddr = bankaddr;
2632 tmpaddr |= mrsaddr;
2633 /* Set DLL reset bit */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002634 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002635 tmpaddr |= (1 << 12);
2636 else
2637 tmpaddr |= (1 << 11);
2638 ram_read32(tmpaddr);
2639
2640 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002641 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002642 do_ram_command(RAM_COMMAND_PRECHARGE);
2643 ram_read32(bankaddr);
2644
2645 /* CAS before RAS Refresh */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002646 PRINTK_DEBUG("CAS before RAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002647 do_ram_command(RAM_COMMAND_CBR);
2648
2649 /* CBR wants two READs */
2650 ram_read32(bankaddr);
2651 ram_read32(bankaddr);
2652
2653 /* Mode Register Set: Enable DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002654 PRINTK_DEBUG("MRS: Enable DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002655 do_ram_command(RAM_COMMAND_MRS);
2656
2657 tmpaddr = bankaddr;
2658 tmpaddr |= mrsaddr;
2659 ram_read32(tmpaddr);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002660
Stefan Reinauer278534d2008-10-29 04:51:07 +00002661 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002662 PRINTK_DEBUG("Extended Mode Register Set: ODT/OCD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002663 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002664
Stefan Reinauer278534d2008-10-29 04:51:07 +00002665 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002666 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002667 tmpaddr |= RTT_ODT_75_OHM | EMRS_OCD_DEFAULT;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002668 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002669 tmpaddr |= ((RTT_ODT_150_OHM | EMRS_OCD_DEFAULT) << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002670 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002671 tmpaddr |= RTT_ODT_150_OHM | EMRS_OCD_DEFAULT;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002672 ram_read32(tmpaddr);
2673
2674 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002675 PRINTK_DEBUG("Extended Mode Register Set: OCD Exit\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002676 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2677
2678 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002679 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002680 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002681 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002682 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002683 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002684 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002685 ram_read32(tmpaddr);
2686 }
2687}
2688
2689static void sdram_init_complete(void)
2690{
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002691 PRINTK_DEBUG("Normal Operation\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002692 do_ram_command(RAM_COMMAND_NORMAL);
2693}
2694
2695static void sdram_setup_processor_side(void)
2696{
2697 if (i945_silicon_revision() == 0)
2698 MCHBAR32(FSBPMC3) |= (1 << 2);
2699
2700 MCHBAR8(0xb00) |= 1;
2701
2702 if (i945_silicon_revision() == 0)
2703 MCHBAR32(SLPCTL) |= (1 << 8);
2704}
2705
Stefan Reinauer278534d2008-10-29 04:51:07 +00002706/**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002707 * @param boot_path: 0 = normal, 1 = reset, 2 = resume from s3
Martin Rothf4cb4122015-01-06 10:27:39 -07002708 * @param spd_addresses pointer to a list of SPD addresses
Stefan Reinauer278534d2008-10-29 04:51:07 +00002709 */
Sven Schnelle541269b2011-02-21 09:39:17 +00002710void sdram_initialize(int boot_path, const u8 *spd_addresses)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002711{
2712 struct sys_info sysinfo;
Arthur Heymans0ab49042017-02-06 22:40:14 +01002713 u8 reg8;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002714
Patrick Georgi771328f2015-07-13 19:24:07 +02002715 timestamp_add_now(TS_BEFORE_INITRAM);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002716 printk(BIOS_DEBUG, "Setting up RAM controller.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002717
2718 memset(&sysinfo, 0, sizeof(sysinfo));
2719
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002720 sysinfo.boot_path = boot_path;
Sven Schnelle541269b2011-02-21 09:39:17 +00002721 sysinfo.spd_addresses = spd_addresses;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002722
Stefan Reinauer278534d2008-10-29 04:51:07 +00002723 /* Look at the type of DIMMs and verify all DIMMs are x8 or x16 width */
2724 sdram_get_dram_configuration(&sysinfo);
2725
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002726 /* If error, do cold boot */
2727 sdram_detect_errors(&sysinfo);
2728
Stefan Reinauer278534d2008-10-29 04:51:07 +00002729 /* Program PLL settings */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002730 sdram_program_pll_settings(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002731
Arthur Heymans18537812016-12-28 21:20:45 +01002732 /*
2733 * Program Graphics Frequency
2734 * Set core display and render clock on 945GC to the max
2735 */
Julius Wernercd49cce2019-03-05 16:53:33 -08002736 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM))
Arthur Heymans18537812016-12-28 21:20:45 +01002737 sdram_program_graphics_frequency(&sysinfo);
2738 else
2739 pci_write_config16(PCI_DEV(0, 2, 0), GCFC, 0x0534);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002740
2741 /* Program System Memory Frequency */
2742 sdram_program_memory_frequency(&sysinfo);
2743
2744 /* Determine Mode of Operation (Interleaved etc) */
2745 sdram_set_channel_mode(&sysinfo);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002746
Stefan Reinauer278534d2008-10-29 04:51:07 +00002747 /* Program Clock Crossing values */
2748 sdram_program_clock_crossing();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002749
Stefan Reinauer278534d2008-10-29 04:51:07 +00002750 /* Disable fast dispatch */
2751 sdram_disable_fast_dispatch();
2752
2753 /* Enable WIODLL Power Down in ACPI states */
2754 MCHBAR32(C0DMC) |= (1 << 24);
2755 MCHBAR32(C1DMC) |= (1 << 24);
2756
2757 /* Program DRAM Row Boundary/Attribute Registers */
2758
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002759 /* program row size DRB and set TOLUD */
2760 sdram_program_row_boundaries(&sysinfo);
2761
2762 /* program page size DRA */
2763 sdram_set_row_attributes(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002764
2765 /* Program CxBNKARC */
2766 sdram_set_bank_architecture(&sysinfo);
2767
2768 /* Program DRAM Timing and Control registers based on SPD */
2769 sdram_set_timing_and_control(&sysinfo);
2770
2771 /* On-Die Termination Adjustment */
2772 sdram_on_die_termination(&sysinfo);
2773
2774 /* Pre Jedec Initialization */
2775 sdram_pre_jedec_initialization();
2776
2777 /* Perform System Memory IO Initialization */
2778 sdram_initialize_system_memory_io(&sysinfo);
2779
2780 /* Perform System Memory IO Buffer Enable */
2781 sdram_enable_system_memory_io(&sysinfo);
2782
2783 /* Enable System Memory Clocks */
2784 sdram_enable_memory_clocks(&sysinfo);
2785
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002786 if (boot_path == BOOT_PATH_NORMAL) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002787 /* Jedec Initialization sequence */
2788 sdram_jedec_enable(&sysinfo);
2789 }
2790
2791 /* Program Power Management Registers */
2792 sdram_power_management(&sysinfo);
2793
2794 /* Post Jedec Init */
2795 sdram_post_jedec_initialization(&sysinfo);
2796
2797 /* Program DRAM Throttling */
2798 sdram_thermal_management();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002799
Stefan Reinauer278534d2008-10-29 04:51:07 +00002800 /* Normal Operations */
Stefan Reinaueraca6ec62009-10-26 17:12:21 +00002801 sdram_init_complete();
Stefan Reinauer278534d2008-10-29 04:51:07 +00002802
2803 /* Program Receive Enable Timings */
2804 sdram_program_receive_enable(&sysinfo);
2805
2806 /* Enable Periodic RCOMP */
2807 sdram_enable_rcomp();
2808
2809 /* Tell ICH7 that we're done */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +01002810 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002811 reg8 &= ~(1 << 7);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +01002812 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002813
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002814 printk(BIOS_DEBUG, "RAM initialization finished.\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002815
Stefan Reinauer278534d2008-10-29 04:51:07 +00002816 sdram_setup_processor_side();
Patrick Georgi771328f2015-07-13 19:24:07 +02002817 timestamp_add_now(TS_AFTER_INITRAM);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002818}