blob: 281e7b267992bede9ec2c87c7b8d7520165261a5 [file] [log] [blame]
Stefan Reinauer278534d2008-10-29 04:51:07 +00001/*
2 * This file is part of the coreboot project.
3 *
Stefan Reinauer71a3d962009-07-21 21:44:24 +00004 * Copyright (C) 2007-2009 coresystems GmbH
Arthur Heymans0ab49042017-02-06 22:40:14 +01005 * Copyright (C) 2017 Arthur Heymans <arthur@aheymans.xyz>
Stefan Reinauer278534d2008-10-29 04:51:07 +00006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Stefan Reinauer278534d2008-10-29 04:51:07 +000015 */
16
Patrick Georgid0835952010-10-05 09:07:10 +000017#include <console/console.h>
Stefan Reinauer278534d2008-10-29 04:51:07 +000018#include <cpu/x86/cache.h>
Arthur Heymans885c2892016-10-03 17:16:48 +020019#include <device/pci_def.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020020#include <device/pci_ops.h>
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 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001659 reg8 = pci_read_config16(PCI_DEV(0, 2, 0), GCFC + 1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001660 reg8 = (1<<3) | (1<<1); /* disable crclk, gate cdclk */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001661 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001662
1663 /* Get graphics frequency capabilities */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001664 reg8 = sdram_capabilities_core_frequencies();
1665
Stefan Reinauer278534d2008-10-29 04:51:07 +00001666 freq = CRCLK_250MHz;
1667 switch (reg8) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001668 case GFX_FREQUENCY_CAP_ALL:
1669 if (voltage == VOLTAGE_1_05)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001670 freq = CRCLK_250MHz;
1671 else
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001672 freq = CRCLK_400MHz; /* 1.5V requires 400MHz */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001673 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001674 case GFX_FREQUENCY_CAP_250MHZ:
1675 freq = CRCLK_250MHz; break;
1676 case GFX_FREQUENCY_CAP_200MHZ:
1677 freq = CRCLK_200MHz; break;
1678 case GFX_FREQUENCY_CAP_166MHZ:
1679 freq = CRCLK_166MHz; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001680 }
1681
1682 if (freq != CRCLK_400MHz) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001683 /* What chipset are we? Force 166MHz for GMS */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001684 reg8 = (pci_read_config8(PCI_DEV(0, 0x00, 0), 0xe7) & 0x70) >> 4;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001685 if (reg8 == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001686 freq = CRCLK_166MHz;
1687 }
1688
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001689 printk(BIOS_DEBUG, "Render: ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001690 switch (freq) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001691 case CRCLK_166MHz:
1692 printk(BIOS_DEBUG, "166MHz"); break;
1693 case CRCLK_200MHz:
1694 printk(BIOS_DEBUG, "200MHz"); break;
1695 case CRCLK_250MHz:
1696 printk(BIOS_DEBUG, "250MHz"); break;
1697 case CRCLK_400MHz:
1698 printk(BIOS_DEBUG, "400MHz"); break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001699 }
1700
Arthur Heymans70a8e342017-03-09 11:30:23 +01001701 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001702 sysinfo->mvco4x = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001703 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001704 sysinfo->mvco4x = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001705
Stefan Reinauer278534d2008-10-29 04:51:07 +00001706 second_vco = 0;
1707
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001708 if (voltage == VOLTAGE_1_50) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001709 second_vco = 1;
1710 } else if ((i945_silicon_revision() > 0) && (freq == CRCLK_250MHz)) {
1711 u16 mem = sysinfo->memory_frequency;
1712 u16 fsb = sysinfo->fsb_frequency;
1713
Arthur Heymans70a8e342017-03-09 11:30:23 +01001714 if ((fsb == 667 && mem == 533) ||
1715 (fsb == 533 && mem == 533) ||
1716 (fsb == 533 && mem == 400)) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001717 second_vco = 1;
1718 }
1719
1720 if (fsb == 667 && mem == 533)
1721 sysinfo->mvco4x = 1;
1722 }
1723
Arthur Heymans70a8e342017-03-09 11:30:23 +01001724 if (second_vco)
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001725 sysinfo->clkcfg_bit7 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001726 else
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001727 sysinfo->clkcfg_bit7 = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001728
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001729 /* Graphics Core Render Clock */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001730 reg16 = pci_read_config16(PCI_DEV(0, 2, 0), GCFC);
1731 reg16 &= ~((7 << 0) | (1 << 13));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001732 reg16 |= freq;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001733 pci_write_config16(PCI_DEV(0, 2, 0), GCFC, reg16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001734
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001735 /* Graphics Core Display Clock */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001736 reg8 = pci_read_config8(PCI_DEV(0, 2, 0), GCFC);
1737 reg8 &= ~((1<<7) | (7<<4));
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001738
1739 if (voltage == VOLTAGE_1_05) {
1740 reg8 |= CDCLK_200MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001741 printk(BIOS_DEBUG, " Display: 200MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001742 } else {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001743 reg8 |= CDCLK_320MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001744 printk(BIOS_DEBUG, " Display: 320MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001745 }
Arthur Heymans70a8e342017-03-09 11:30:23 +01001746 pci_write_config8(PCI_DEV(0, 2, 0), GCFC, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001747
Arthur Heymans70a8e342017-03-09 11:30:23 +01001748 reg8 = pci_read_config8(PCI_DEV(0, 2, 0), GCFC + 1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001749
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001750 reg8 |= (1<<3) | (1<<1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001751 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001752
1753 reg8 |= 0x0f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001754 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001755
1756 /* Ungate core render and display clocks */
1757 reg8 &= 0xf0;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001758 pci_write_config8(PCI_DEV(0, 2, 0), GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001759}
1760
1761static void sdram_program_memory_frequency(struct sys_info *sysinfo)
1762{
1763 u32 clkcfg;
1764 u8 reg8;
Julius Wernercd49cce2019-03-05 16:53:33 -08001765 u8 offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001766
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001767 printk(BIOS_DEBUG, "Setting Memory Frequency... ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001768
Stefan Reinauer278534d2008-10-29 04:51:07 +00001769 clkcfg = MCHBAR32(CLKCFG);
1770
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001771 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001772
Arthur Heymans70a8e342017-03-09 11:30:23 +01001773 clkcfg &= ~((1 << 12) | (1 << 7) | (7 << 4));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001774
1775 if (sysinfo->mvco4x) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001776 printk(BIOS_DEBUG, "MVCO 4x, ");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001777 clkcfg &= ~(1 << 12);
1778 }
1779
1780 if (sysinfo->clkcfg_bit7) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001781 printk(BIOS_DEBUG, "second VCO, ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001782
Stefan Reinauer278534d2008-10-29 04:51:07 +00001783 clkcfg |= (1 << 7);
1784 }
1785
1786 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001787 case 400:
1788 clkcfg |= ((1 + offset) << 4); break;
1789 case 533:
1790 clkcfg |= ((2 + offset) << 4); break;
1791 case 667:
1792 clkcfg |= ((3 + offset) << 4); break;
1793 default:
1794 die("Target Memory Frequency Error");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001795 }
1796
1797 if (MCHBAR32(CLKCFG) == clkcfg) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001798 printk(BIOS_DEBUG, "ok (unchanged)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001799 return;
1800 }
1801
1802 MCHBAR32(CLKCFG) = clkcfg;
1803
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001804 /* Make sure the following code is in the
Stefan Reinauer278534d2008-10-29 04:51:07 +00001805 * cache before we execute it.
1806 */
1807 goto cache_code;
1808vco_update:
Elyes HAOUAS32b9a992019-01-21 14:54:31 +01001809 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001810 reg8 &= ~(1 << 7);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +01001811 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001812
Stefan Reinauer278534d2008-10-29 04:51:07 +00001813 clkcfg &= ~(1 << 10);
1814 MCHBAR32(CLKCFG) = clkcfg;
1815 clkcfg |= (1 << 10);
1816 MCHBAR32(CLKCFG) = clkcfg;
1817
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001818 asm volatile (
Stefan Reinauer278534d2008-10-29 04:51:07 +00001819 " movl $0x100, %%ecx\n"
1820 "delay_update:\n"
1821 " nop\n"
1822 " nop\n"
1823 " nop\n"
1824 " nop\n"
1825 " loop delay_update\n"
1826 : /* No outputs */
1827 : /* No inputs */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001828 : "%ecx", "memory"
Stefan Reinauer278534d2008-10-29 04:51:07 +00001829 );
1830
Stefan Reinauer278534d2008-10-29 04:51:07 +00001831 clkcfg &= ~(1 << 10);
1832 MCHBAR32(CLKCFG) = clkcfg;
1833
1834 goto out;
1835cache_code:
1836 goto vco_update;
1837out:
1838
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001839 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", MCHBAR32(CLKCFG));
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001840 printk(BIOS_DEBUG, "ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001841}
1842
1843static void sdram_program_clock_crossing(void)
1844{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001845 int idx = 0;
1846
1847 /**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001848 * We add the indices according to our clocks from CLKCFG.
Stefan Reinauer278534d2008-10-29 04:51:07 +00001849 */
Julius Wernercd49cce2019-03-05 16:53:33 -08001850#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001851 static const u32 data_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001852 0x00100401, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001853 0xffffffff, 0xffffffff, /* nonexistent */
1854 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001855
Stefan Reinauer278534d2008-10-29 04:51:07 +00001856 0x08040120, 0x00000000, /* DDR400 FSB533 */
1857 0x00100401, 0x00000000, /* DDR533 FSB533 */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001858 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001859
1860 0x04020120, 0x00000010, /* DDR400 FSB667 */
1861 0x10040280, 0x00000040, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001862 0x00100401, 0x00000000, /* DDR667 FSB667 */
1863
Martin Roth2ed0aa22016-01-05 20:58:58 -07001864 0xffffffff, 0xffffffff, /* nonexistent */
1865 0xffffffff, 0xffffffff, /* nonexistent */
1866 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001867
Martin Roth2ed0aa22016-01-05 20:58:58 -07001868 0xffffffff, 0xffffffff, /* nonexistent */
1869 0xffffffff, 0xffffffff, /* nonexistent */
1870 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001871 };
1872
1873 static const u32 command_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001874 0x04020208, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001875 0xffffffff, 0xffffffff, /* nonexistent */
1876 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001877
Stefan Reinauer278534d2008-10-29 04:51:07 +00001878 0x00060108, 0x00000000, /* DDR400 FSB533 */
1879 0x04020108, 0x00000000, /* DDR533 FSB533 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001880 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001881
1882 0x00040318, 0x00000000, /* DDR400 FSB667 */
1883 0x04020118, 0x00000000, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001884 0x02010804, 0x00000000, /* DDR667 FSB667 */
1885
Martin Roth2ed0aa22016-01-05 20:58:58 -07001886 0xffffffff, 0xffffffff, /* nonexistent */
1887 0xffffffff, 0xffffffff, /* nonexistent */
1888 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001889
Martin Roth2ed0aa22016-01-05 20:58:58 -07001890 0xffffffff, 0xffffffff, /* nonexistent */
1891 0xffffffff, 0xffffffff, /* nonexistent */
1892 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001893 };
1894
Julius Wernercd49cce2019-03-05 16:53:33 -08001895#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001896 /* i945 G/P */
1897 static const u32 data_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001898 0xffffffff, 0xffffffff, /* nonexistent */
1899 0xffffffff, 0xffffffff, /* nonexistent */
1900 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001901
1902 0x10080201, 0x00000000, /* DDR400 FSB533 */
1903 0x00100401, 0x00000000, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001904 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001905
Martin Roth2ed0aa22016-01-05 20:58:58 -07001906 0xffffffff, 0xffffffff, /* nonexistent */
1907 0xffffffff, 0xffffffff, /* nonexistent */
1908 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001909
1910 0x04020108, 0x00000000, /* DDR400 FSB800 */
1911 0x00020108, 0x00000000, /* DDR533 FSB800 */
1912 0x00080201, 0x00000000, /* DDR667 FSB800 */
1913
1914 0x00010402, 0x00000000, /* DDR400 FSB1066 */
1915 0x04020108, 0x00000000, /* DDR533 FSB1066 */
1916 0x08040110, 0x00000000, /* DDR667 FSB1066 */
1917 };
1918
1919 static const u32 command_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001920 0xffffffff, 0xffffffff, /* nonexistent */
1921 0xffffffff, 0xffffffff, /* nonexistent */
1922 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001923
1924 0x00010800, 0x00000402, /* DDR400 FSB533 */
1925 0x01000400, 0x00000200, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001926 0x00020904, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001927
Martin Roth2ed0aa22016-01-05 20:58:58 -07001928 0xffffffff, 0xffffffff, /* nonexistent */
1929 0xffffffff, 0xffffffff, /* nonexistent */
1930 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001931
1932 0x02010804, 0x00000000, /* DDR400 FSB800 */
1933 0x00010402, 0x00000000, /* DDR533 FSB800 */
Arthur Heymans8b6df622016-10-16 10:58:01 +02001934 0x04020130, 0x00000008, /* DDR667 FSB800 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001935
1936 0x00020904, 0x00000000, /* DDR400 FSB1066 */
1937 0x02010804, 0x00000000, /* DDR533 FSB1066 */
1938 0x180601c0, 0x00000020, /* DDR667 FSB1066 */
1939 };
1940#endif
1941
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001942 printk(BIOS_DEBUG, "Programming Clock Crossing...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001943
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001944 printk(BIOS_DEBUG, "MEM=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001945 switch (memclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001946 case 400:
1947 printk(BIOS_DEBUG, "400"); idx += 0; break;
1948 case 533:
1949 printk(BIOS_DEBUG, "533"); idx += 2; break;
1950 case 667:
1951 printk(BIOS_DEBUG, "667"); idx += 4; break;
1952 default:
1953 printk(BIOS_DEBUG, "RSVD %x", memclk()); return;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001954 }
1955
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001956 printk(BIOS_DEBUG, " FSB=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001957 switch (fsbclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001958 case 400:
1959 printk(BIOS_DEBUG, "400"); idx += 0; break;
1960 case 533:
1961 printk(BIOS_DEBUG, "533"); idx += 6; break;
1962 case 667:
1963 printk(BIOS_DEBUG, "667"); idx += 12; break;
1964 case 800:
1965 printk(BIOS_DEBUG, "800"); idx += 18; break;
1966 case 1066:
1967 printk(BIOS_DEBUG, "1066"); idx += 24; break;
1968 default:
1969 printk(BIOS_DEBUG, "RSVD %x\n", fsbclk()); return;
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001970 }
1971
Arthur Heymans70a8e342017-03-09 11:30:23 +01001972 if (command_clock_crossing[idx] == 0xffffffff)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001973 printk(BIOS_DEBUG, "Invalid MEM/FSB combination!\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001974
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001975 MCHBAR32(CCCFT + 0) = command_clock_crossing[idx];
1976 MCHBAR32(CCCFT + 4) = command_clock_crossing[idx + 1];
1977
Stefan Reinauer278534d2008-10-29 04:51:07 +00001978 MCHBAR32(C0DCCFT + 0) = data_clock_crossing[idx];
1979 MCHBAR32(C0DCCFT + 4) = data_clock_crossing[idx + 1];
1980 MCHBAR32(C1DCCFT + 0) = data_clock_crossing[idx];
1981 MCHBAR32(C1DCCFT + 4) = data_clock_crossing[idx + 1];
1982
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001983 printk(BIOS_DEBUG, "... ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001984}
1985
1986static void sdram_disable_fast_dispatch(void)
1987{
1988 u32 reg32;
1989
1990 reg32 = MCHBAR32(FSBPMC3);
1991 reg32 |= (1 << 1);
1992 MCHBAR32(FSBPMC3) = reg32;
1993
1994 reg32 = MCHBAR32(SBTEST);
1995 reg32 |= (3 << 1);
1996 MCHBAR32(SBTEST) = reg32;
1997}
1998
1999static void sdram_pre_jedec_initialization(void)
2000{
2001 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002002
Stefan Reinauer278534d2008-10-29 04:51:07 +00002003 reg32 = MCHBAR32(WCC);
2004 reg32 &= 0x113ff3ff;
2005 reg32 |= (4 << 29) | (3 << 25) | (1 << 10);
2006 MCHBAR32(WCC) = reg32;
2007
2008 MCHBAR32(SMVREFC) |= (1 << 6);
2009
2010 MCHBAR32(MMARB0) &= ~(3 << 17);
2011 MCHBAR32(MMARB0) |= (1 << 21) | (1 << 16);
2012
2013 MCHBAR32(MMARB1) &= ~(7 << 8);
2014 MCHBAR32(MMARB1) |= (3 << 8);
2015
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002016 /* Adaptive Idle Timer Control */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002017 MCHBAR32(C0AIT) = 0x000006c4;
2018 MCHBAR32(C0AIT+4) = 0x871a066d;
2019
2020 MCHBAR32(C1AIT) = 0x000006c4;
2021 MCHBAR32(C1AIT+4) = 0x871a066d;
2022}
2023
2024#define EA_DUALCHANNEL_XOR_BANK_RANK_MODE (0xd4 << 24)
2025#define EA_DUALCHANNEL_XOR_BANK_MODE (0xf4 << 24)
2026#define EA_DUALCHANNEL_BANK_RANK_MODE (0xc2 << 24)
2027#define EA_DUALCHANNEL_BANK_MODE (0xe2 << 24)
2028#define EA_SINGLECHANNEL_XOR_BANK_RANK_MODE (0x91 << 24)
2029#define EA_SINGLECHANNEL_XOR_BANK_MODE (0xb1 << 24)
2030#define EA_SINGLECHANNEL_BANK_RANK_MODE (0x80 << 24)
2031#define EA_SINGLECHANNEL_BANK_MODE (0xa0 << 24)
2032
2033static void sdram_enhanced_addressing_mode(struct sys_info *sysinfo)
2034{
2035 u32 chan0 = 0, chan1 = 0;
2036 int chan0_dualsided, chan1_dualsided, chan0_populated, chan1_populated;
2037
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002038 chan0_populated = (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Stefan Reinauer278534d2008-10-29 04:51:07 +00002039 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED);
Elyes HAOUAS308aeff2017-02-24 12:53:07 +01002040 chan1_populated = (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
2041 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002042 chan0_dualsided = (sysinfo->banksize[1] || sysinfo->banksize[3]);
2043 chan1_dualsided = (sysinfo->banksize[5] || sysinfo->banksize[7]);
2044
2045 if (sdram_capabilities_enhanced_addressing_xor()) {
2046 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002047 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002048 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002049 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002050 chan0 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002051 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002052 chan0 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002053 }
2054 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002055 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002056 chan1 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002057 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002058 chan1 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002059 }
2060 } else {
2061 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002062 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002063 chan0 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002064 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002065 chan0 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002066
Arthur Heymans70a8e342017-03-09 11:30:23 +01002067 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002068 chan1 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002069 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002070 chan1 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002071 }
2072 } else {
2073 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002074 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002075 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002076 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002077 chan0 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002078 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002079 chan0 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002080 }
2081 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002082 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002083 chan1 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002084 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002085 chan1 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002086 }
2087 } else {
2088 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002089 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002090 chan0 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002091 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002092 chan0 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002093
Arthur Heymans70a8e342017-03-09 11:30:23 +01002094 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002095 chan1 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002096 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002097 chan1 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002098 }
2099 }
2100
2101 MCHBAR32(C0DRC1) &= 0x00ffffff;
2102 MCHBAR32(C0DRC1) |= chan0;
2103 MCHBAR32(C1DRC1) &= 0x00ffffff;
2104 MCHBAR32(C1DRC1) |= chan1;
2105}
2106
2107static void sdram_post_jedec_initialization(struct sys_info *sysinfo)
2108{
2109 u32 reg32;
2110
2111 /* Enable Channel XORing for Dual Channel Interleave */
2112 if (sysinfo->interleaved) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002113
Stefan Reinauer278534d2008-10-29 04:51:07 +00002114 reg32 = MCHBAR32(DCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002115 reg32 &= ~(1 << 10);
Stefan Reinauer30140a52009-03-11 16:20:39 +00002116 reg32 |= (1 << 9);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002117 MCHBAR32(DCC) = reg32;
2118 }
2119
2120 /* DRAM mode optimizations */
2121 sdram_enhanced_addressing_mode(sysinfo);
2122
2123 reg32 = MCHBAR32(FSBPMC3);
2124 reg32 &= ~(1 << 1);
2125 MCHBAR32(FSBPMC3) = reg32;
2126
2127 reg32 = MCHBAR32(SBTEST);
2128 reg32 &= ~(1 << 2);
2129 MCHBAR32(SBTEST) = reg32;
2130
2131 reg32 = MCHBAR32(SBOCC);
2132 reg32 &= 0xffbdb6ff;
2133 reg32 |= (0xbdb6 << 8) | (1 << 0);
2134 MCHBAR32(SBOCC) = reg32;
2135}
2136
2137static void sdram_power_management(struct sys_info *sysinfo)
2138{
2139 u8 reg8;
2140 u16 reg16;
2141 u32 reg32;
2142 int integrated_graphics = 1;
2143 int i;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002144
Stefan Reinauer278534d2008-10-29 04:51:07 +00002145 reg32 = MCHBAR32(C0DRT2);
2146 reg32 &= 0xffffff00;
2147 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002148 reg32 |= (1 << 5) | (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002149 MCHBAR32(C0DRT2) = reg32;
2150
2151 reg32 = MCHBAR32(C1DRT2);
2152 reg32 &= 0xffffff00;
2153 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002154 reg32 |= (1 << 5) | (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002155 MCHBAR32(C1DRT2) = reg32;
2156
2157 reg32 = MCHBAR32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002158
2159 reg32 |= (1 << 12) | (1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002160 MCHBAR32(C0DRC1) = reg32;
2161
2162 reg32 = MCHBAR32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002163
2164 reg32 |= (1 << 12) | (1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002165 MCHBAR32(C1DRC1) = reg32;
2166
Julius Wernercd49cce2019-03-05 16:53:33 -08002167 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002168 if (i945_silicon_revision() > 1) {
2169 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2170 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002171
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002172 MCHBAR16(UPMC1) = 0x1010 | peg_bits;
2173 } else {
2174 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2175 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002176
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002177 /* Rev 0 and 1 */
2178 MCHBAR16(UPMC1) = 0x0010 | peg_bits;
2179 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002180 }
2181
2182 reg16 = MCHBAR16(UPMC2);
2183 reg16 &= 0xfc00;
2184 reg16 |= 0x0100;
2185 MCHBAR16(UPMC2) = reg16;
2186
2187 MCHBAR32(UPMC3) = 0x000f06ff;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002188
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002189 for (i = 0; i < 5; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002190 MCHBAR32(UPMC3) &= ~(1 << 16);
2191 MCHBAR32(UPMC3) |= (1 << 16);
2192 }
2193
2194 MCHBAR32(GIPMC1) = 0x8000000c;
2195
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002196 reg16 = MCHBAR16(CPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002197 reg16 &= ~(7 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002198 if (i945_silicon_revision() > 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002199 reg16 |= (6 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002200 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002201 reg16 |= (4 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002202 MCHBAR16(CPCTL) = reg16;
2203
Stefan Reinauer30140a52009-03-11 16:20:39 +00002204#if 0
Stefan Reinauer278534d2008-10-29 04:51:07 +00002205 if ((MCHBAR32(ECO) & (1 << 16)) != 0) {
Stefan Reinauer30140a52009-03-11 16:20:39 +00002206#else
2207 if (i945_silicon_revision() != 0) {
2208#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002209 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002210 case 667:
2211 MCHBAR32(HGIPMC2) = 0x0d590d59; break;
2212 case 533:
2213 MCHBAR32(HGIPMC2) = 0x155b155b; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002214 }
2215 } else {
2216 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002217 case 667:
2218 MCHBAR32(HGIPMC2) = 0x09c409c4; break;
2219 case 533:
2220 MCHBAR32(HGIPMC2) = 0x0fa00fa0; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002221 }
2222 }
2223
2224 MCHBAR32(FSBPMC1) = 0x8000000c;
2225
2226 reg32 = MCHBAR32(C2C3TT);
2227 reg32 &= 0xffff0000;
2228 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002229 case 667:
2230 reg32 |= 0x0600; break;
2231 case 533:
2232 reg32 |= 0x0480; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002233 }
2234 MCHBAR32(C2C3TT) = reg32;
2235
2236 reg32 = MCHBAR32(C3C4TT);
2237 reg32 &= 0xffff0000;
2238 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002239 case 667:
2240 reg32 |= 0x0b80; break;
2241 case 533:
2242 reg32 |= 0x0980; break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002243 }
2244 MCHBAR32(C3C4TT) = reg32;
2245
Arthur Heymans70a8e342017-03-09 11:30:23 +01002246 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002247 MCHBAR32(ECO) &= ~(1 << 16);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002248 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002249 MCHBAR32(ECO) |= (1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002250
2251#if 0
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002252
Arthur Heymans70a8e342017-03-09 11:30:23 +01002253 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002254 MCHBAR32(FSBPMC3) &= ~(1 << 29);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002255 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002256 MCHBAR32(FSBPMC3) |= (1 << 29);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002257#endif
2258 MCHBAR32(FSBPMC3) &= ~(1 << 29);
2259
2260 MCHBAR32(FSBPMC3) |= (1 << 21);
2261
2262 MCHBAR32(FSBPMC3) &= ~(1 << 19);
2263
2264 MCHBAR32(FSBPMC3) &= ~(1 << 13);
2265
2266 reg32 = MCHBAR32(FSBPMC4);
2267 reg32 &= ~(3 << 24);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002268 reg32 |= (2 << 24);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002269 MCHBAR32(FSBPMC4) = reg32;
2270
2271 MCHBAR32(FSBPMC4) |= (1 << 21);
2272
2273 MCHBAR32(FSBPMC4) |= (1 << 5);
2274
Arthur Heymans70a8e342017-03-09 11:30:23 +01002275 if ((i945_silicon_revision() < 2)) { /* || cpuid() = 0x6e8 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002276 /* stepping 0 and 1 or CPUID 6e8 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002277 MCHBAR32(FSBPMC4) &= ~(1 << 4);
2278 } else {
Stefan Reinauer30140a52009-03-11 16:20:39 +00002279 MCHBAR32(FSBPMC4) |= (1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002280 }
2281
Arthur Heymans70a8e342017-03-09 11:30:23 +01002282 reg8 = pci_read_config8(PCI_DEV(0, 0x0, 0), 0xfc);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002283 reg8 |= (1 << 4);
2284 pci_write_config8(PCI_DEV(0, 0x0, 0), 0xfc, reg8);
2285
Arthur Heymans70a8e342017-03-09 11:30:23 +01002286 reg8 = pci_read_config8(PCI_DEV(0, 0x2, 0), 0xc1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002287 reg8 |= (1 << 2);
2288 pci_write_config8(PCI_DEV(0, 0x2, 0), 0xc1, reg8);
2289
Stefan Reinauerde3206a2010-02-22 06:09:43 +00002290#ifdef C2_SELF_REFRESH_DISABLE
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002291
Stefan Reinauer278534d2008-10-29 04:51:07 +00002292 if (integrated_graphics) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002293 printk(BIOS_DEBUG, "C2 self-refresh with IGD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002294 MCHBAR16(MIPMC4) = 0x0468;
2295 MCHBAR16(MIPMC5) = 0x046c;
2296 MCHBAR16(MIPMC6) = 0x046c;
2297 } else {
2298 MCHBAR16(MIPMC4) = 0x6468;
2299 MCHBAR16(MIPMC5) = 0x646c;
2300 MCHBAR16(MIPMC6) = 0x646c;
2301 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002302#else
2303 if (integrated_graphics) {
2304 MCHBAR16(MIPMC4) = 0x04f8;
2305 MCHBAR16(MIPMC5) = 0x04fc;
2306 MCHBAR16(MIPMC6) = 0x04fc;
2307 } else {
2308 MCHBAR16(MIPMC4) = 0x64f8;
2309 MCHBAR16(MIPMC5) = 0x64fc;
2310 MCHBAR16(MIPMC6) = 0x64fc;
2311 }
2312
2313#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002314
2315 reg32 = MCHBAR32(PMCFG);
2316 reg32 &= ~(3 << 17);
2317 reg32 |= (2 << 17);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002318 MCHBAR32(PMCFG) = reg32;
2319
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002320 MCHBAR32(PMCFG) |= (1 << 4);
2321
Stefan Reinauer278534d2008-10-29 04:51:07 +00002322 reg32 = MCHBAR32(0xc30);
2323 reg32 &= 0xffffff00;
2324 reg32 |= 0x01;
2325 MCHBAR32(0xc30) = reg32;
2326
2327 MCHBAR32(0xb18) &= ~(1 << 21);
2328}
2329
2330static void sdram_thermal_management(void)
2331{
Stefan Reinauer278534d2008-10-29 04:51:07 +00002332
Stefan Reinauer278534d2008-10-29 04:51:07 +00002333 MCHBAR8(TCO1) = 0x00;
2334 MCHBAR8(TCO0) = 0x00;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002335
2336 /* The Thermal Sensors for DIMMs at 0x50, 0x52 are at I2C addr
2337 * 0x30/0x32.
2338 */
2339
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002340 /* TODO This is not implemented yet. Volunteers? */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002341}
2342
2343static void sdram_save_receive_enable(void)
2344{
2345 int i;
2346 u32 reg32;
2347 u8 values[4];
2348
2349 /* The following values are stored to an unused CMOS
2350 * area and restored instead of recalculated in case
2351 * of an S3 resume.
2352 *
Arthur Heymans70a8e342017-03-09 11:30:23 +01002353 * C0WL0REOST [7:0] -> 8 bit
2354 * C1WL0REOST [7:0] -> 8 bit
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002355 * RCVENMT [11:8] [3:0] -> 8 bit
2356 * C0DRT1 [27:24] -> 4 bit
2357 * C1DRT1 [27:24] -> 4 bit
2358 */
2359
2360 values[0] = MCHBAR8(C0WL0REOST);
2361 values[1] = MCHBAR8(C1WL0REOST);
2362
2363 reg32 = MCHBAR32(RCVENMT);
2364 values[2] = (u8)((reg32 >> (8 - 4)) & 0xf0) | (reg32 & 0x0f);
2365
2366 reg32 = MCHBAR32(C0DRT1);
2367 values[3] = (reg32 >> 24) & 0x0f;
2368 reg32 = MCHBAR32(C1DRT1);
2369 values[3] |= (reg32 >> (24 - 4)) & 0xf0;
2370
2371 /* coreboot only uses bytes 0 - 127 for its CMOS values so far
Edwin Beasanteb50c7d2010-07-06 21:05:04 +00002372 * so we grab bytes 128 - 131 to save the receive enable values
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002373 */
2374
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002375 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002376 cmos_write(values[i], 128 + i);
2377}
2378
2379static void sdram_recover_receive_enable(void)
2380{
2381 int i;
2382 u32 reg32;
2383 u8 values[4];
2384
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002385 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002386 values[i] = cmos_read(128 + i);
2387
2388 MCHBAR8(C0WL0REOST) = values[0];
2389 MCHBAR8(C1WL0REOST) = values[1];
2390
2391 reg32 = MCHBAR32(RCVENMT);
2392 reg32 &= ~((0x0f << 8) | (0x0f << 0));
2393 reg32 |= ((u32)(values[2] & 0xf0) << (8 - 4)) | (values[2] & 0x0f);
2394 MCHBAR32(RCVENMT) = reg32;
2395
2396 reg32 = MCHBAR32(C0DRT1) & ~(0x0f << 24);
2397 reg32 |= (u32)(values[3] & 0x0f) << 24;
2398 MCHBAR32(C0DRT1) = reg32;
2399
2400 reg32 = MCHBAR32(C1DRT1) & ~(0x0f << 24);
2401 reg32 |= (u32)(values[3] & 0xf0) << (24 - 4);
2402 MCHBAR32(C1DRT1) = reg32;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002403}
2404
Stefan Reinauer278534d2008-10-29 04:51:07 +00002405static void sdram_program_receive_enable(struct sys_info *sysinfo)
2406{
2407 MCHBAR32(REPC) |= (1 << 0);
2408
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002409 /* Program Receive Enable Timings */
2410 if (sysinfo->boot_path == BOOT_PATH_RESUME) {
2411 sdram_recover_receive_enable();
2412 } else {
2413 receive_enable_adjust(sysinfo);
2414 sdram_save_receive_enable();
2415 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002416
2417 MCHBAR32(C0DRC1) |= (1 << 6);
2418 MCHBAR32(C1DRC1) |= (1 << 6);
2419 MCHBAR32(C0DRC1) &= ~(1 << 6);
2420 MCHBAR32(C1DRC1) &= ~(1 << 6);
2421
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002422 MCHBAR32(MIPMC3) |= (0x0f << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002423}
2424
2425/**
2426 * @brief Enable On-Die Termination for DDR2.
2427 *
2428 */
2429
2430static void sdram_on_die_termination(struct sys_info *sysinfo)
2431{
2432 static const u32 odt[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002433 0x00024911, 0xe0010000,
2434 0x00049211, 0xe0020000,
2435 0x0006db11, 0xe0030000,
Stefan Reinauer278534d2008-10-29 04:51:07 +00002436 };
2437
2438 u32 reg32;
2439 int cas;
2440
2441 reg32 = MCHBAR32(ODTC);
2442 reg32 &= ~(3 << 16);
2443 reg32 |= (1 << 14) | (1 << 6) | (2 << 16);
2444 MCHBAR32(ODTC) = reg32;
2445
Arthur Heymans70a8e342017-03-09 11:30:23 +01002446 if (!(sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED &&
2447 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)) {
Elyes HAOUAS38424982016-08-21 12:01:04 +02002448 printk(BIOS_DEBUG, "one dimm per channel config..\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002449
Stefan Reinauer278534d2008-10-29 04:51:07 +00002450 reg32 = MCHBAR32(C0ODT);
2451 reg32 &= ~(7 << 28);
2452 MCHBAR32(C0ODT) = reg32;
2453 reg32 = MCHBAR32(C1ODT);
2454 reg32 &= ~(7 << 28);
2455 MCHBAR32(C1ODT) = reg32;
2456 }
2457
2458 cas = sysinfo->cas;
2459
2460 reg32 = MCHBAR32(C0ODT) & 0xfff00000;
2461 reg32 |= odt[(cas-3) * 2];
2462 MCHBAR32(C0ODT) = reg32;
2463
2464 reg32 = MCHBAR32(C1ODT) & 0xfff00000;
2465 reg32 |= odt[(cas-3) * 2];
2466 MCHBAR32(C1ODT) = reg32;
2467
2468 reg32 = MCHBAR32(C0ODT + 4) & 0x1fc8ffff;
2469 reg32 |= odt[((cas-3) * 2) + 1];
2470 MCHBAR32(C0ODT + 4) = reg32;
2471
2472 reg32 = MCHBAR32(C1ODT + 4) & 0x1fc8ffff;
2473 reg32 |= odt[((cas-3) * 2) + 1];
2474 MCHBAR32(C1ODT + 4) = reg32;
2475}
2476
2477/**
2478 * @brief Enable clocks to populated sockets
2479 */
2480
2481static void sdram_enable_memory_clocks(struct sys_info *sysinfo)
2482{
2483 u8 clocks[2] = { 0, 0 };
2484
Julius Wernercd49cce2019-03-05 16:53:33 -08002485#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002486#define CLOCKS_WIDTH 2
Julius Wernercd49cce2019-03-05 16:53:33 -08002487#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002488#define CLOCKS_WIDTH 3
2489#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002490 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002491 clocks[0] |= (1 << CLOCKS_WIDTH)-1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002492
2493 if (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002494 clocks[0] |= ((1 << CLOCKS_WIDTH)-1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002495
2496 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002497 clocks[1] |= (1 << CLOCKS_WIDTH)-1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002498
2499 if (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002500 clocks[1] |= ((1 << CLOCKS_WIDTH)-1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002501
Julius Wernercd49cce2019-03-05 16:53:33 -08002502#if CONFIG(OVERRIDE_CLOCK_DISABLE)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002503 /* Usually system firmware turns off system memory clock signals
2504 * to unused SO-DIMM slots to reduce EMI and power consumption.
2505 * However, the Kontron 986LCD-M does not like unused clock
2506 * signals to be disabled.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002507 */
2508
2509 clocks[0] = 0xf; /* force all clock gate pairs to enable */
2510 clocks[1] = 0xf; /* force all clock gate pairs to enable */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002511#endif
2512
2513 MCHBAR8(C0DCLKDIS) = clocks[0];
2514 MCHBAR8(C1DCLKDIS) = clocks[1];
2515}
2516
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002517#define RTT_ODT_NONE 0
Arthur Heymans70a8e342017-03-09 11:30:23 +01002518#define RTT_ODT_50_OHM ((1 << 9) | (1 << 5))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002519#define RTT_ODT_75_OHM (1 << 5)
2520#define RTT_ODT_150_OHM (1 << 9)
2521
Arthur Heymans70a8e342017-03-09 11:30:23 +01002522#define EMRS_OCD_DEFAULT ((1 << 12) | (1 << 11) | (1 << 10))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002523
2524#define MRS_CAS_3 (3 << 7)
2525#define MRS_CAS_4 (4 << 7)
2526#define MRS_CAS_5 (5 << 7)
2527
2528#define MRS_TWR_3 (2 << 12)
2529#define MRS_TWR_4 (3 << 12)
2530#define MRS_TWR_5 (4 << 12)
2531
2532#define MRS_BT (1 << 6)
2533
2534#define MRS_BL4 (2 << 3)
2535#define MRS_BL8 (3 << 3)
2536
2537static void sdram_jedec_enable(struct sys_info *sysinfo)
2538{
2539 int i, nonzero;
2540 u32 bankaddr = 0, tmpaddr, mrsaddr = 0;
2541
2542 for (i = 0, nonzero = -1; i < 8; i++) {
Elyes HAOUAS01912202019-01-19 16:36:38 +01002543 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002544 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002545
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002546 printk(BIOS_DEBUG, "jedec enable sequence: bank %d\n", i);
Elyes HAOUAS01912202019-01-19 16:36:38 +01002547
2548 if (nonzero != -1) {
2549 if (sysinfo->interleaved && nonzero < 4 && i >= 4) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002550 bankaddr = 0x40;
Elyes HAOUAS01912202019-01-19 16:36:38 +01002551 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002552 printk(BIOS_DEBUG, "bankaddr from bank size of rank %d\n", nonzero);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002553 bankaddr += sysinfo->banksize[nonzero] <<
2554 (sysinfo->interleaved ? 26 : 25);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002555 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002556 }
2557
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002558 /* We have a bank with a non-zero size.. Remember it
Stefan Reinauer278534d2008-10-29 04:51:07 +00002559 * for the next offset we have to calculate
2560 */
2561 nonzero = i;
2562
2563 /* Get CAS latency set up */
2564 switch (sysinfo->cas) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002565 case 5:
2566 mrsaddr = MRS_CAS_5; break;
2567 case 4:
2568 mrsaddr = MRS_CAS_4; break;
2569 case 3:
2570 mrsaddr = MRS_CAS_3; break;
2571 default:
2572 die("Jedec Error (CAS).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002573 }
2574
2575 /* Get tWR set */
2576 switch (sysinfo->twr) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002577 case 5:
2578 mrsaddr |= MRS_TWR_5; break;
2579 case 4:
2580 mrsaddr |= MRS_TWR_4; break;
2581 case 3:
2582 mrsaddr |= MRS_TWR_3; break;
2583 default:
2584 die("Jedec Error (tWR).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002585 }
2586
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002587 /* Set "Burst Type" */
2588 mrsaddr |= MRS_BT;
2589
Stefan Reinauer278534d2008-10-29 04:51:07 +00002590 /* Interleaved */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002591 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002592 mrsaddr = mrsaddr << 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002593
2594 /* Only burst length 8 supported */
2595 mrsaddr |= MRS_BL8;
2596
2597 /* Apply NOP */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002598 PRINTK_DEBUG("Apply NOP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002599 do_ram_command(RAM_COMMAND_NOP);
2600 ram_read32(bankaddr);
2601
2602 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002603 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002604 do_ram_command(RAM_COMMAND_PRECHARGE);
2605 ram_read32(bankaddr);
2606
2607 /* Extended Mode Register Set (2) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002608 PRINTK_DEBUG("Extended Mode Register Set(2)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002609 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_2);
2610 ram_read32(bankaddr);
2611
2612 /* Extended Mode Register Set (3) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002613 PRINTK_DEBUG("Extended Mode Register Set(3)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002614 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_3);
2615 ram_read32(bankaddr);
2616
2617 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002618 PRINTK_DEBUG("Extended Mode Register Set\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002619 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2620 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002621 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002622 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002623 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002624 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002625 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002626 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002627 ram_read32(tmpaddr);
2628
2629 /* Mode Register Set: Reset DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002630 PRINTK_DEBUG("MRS: Reset DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002631 do_ram_command(RAM_COMMAND_MRS);
2632 tmpaddr = bankaddr;
2633 tmpaddr |= mrsaddr;
2634 /* Set DLL reset bit */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002635 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002636 tmpaddr |= (1 << 12);
2637 else
2638 tmpaddr |= (1 << 11);
2639 ram_read32(tmpaddr);
2640
2641 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002642 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002643 do_ram_command(RAM_COMMAND_PRECHARGE);
2644 ram_read32(bankaddr);
2645
2646 /* CAS before RAS Refresh */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002647 PRINTK_DEBUG("CAS before RAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002648 do_ram_command(RAM_COMMAND_CBR);
2649
2650 /* CBR wants two READs */
2651 ram_read32(bankaddr);
2652 ram_read32(bankaddr);
2653
2654 /* Mode Register Set: Enable DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002655 PRINTK_DEBUG("MRS: Enable DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002656 do_ram_command(RAM_COMMAND_MRS);
2657
2658 tmpaddr = bankaddr;
2659 tmpaddr |= mrsaddr;
2660 ram_read32(tmpaddr);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002661
Stefan Reinauer278534d2008-10-29 04:51:07 +00002662 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002663 PRINTK_DEBUG("Extended Mode Register Set: ODT/OCD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002664 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002665
Stefan Reinauer278534d2008-10-29 04:51:07 +00002666 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002667 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002668 tmpaddr |= RTT_ODT_75_OHM | EMRS_OCD_DEFAULT;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002669 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002670 tmpaddr |= ((RTT_ODT_150_OHM | EMRS_OCD_DEFAULT) << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002671 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002672 tmpaddr |= RTT_ODT_150_OHM | EMRS_OCD_DEFAULT;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002673 ram_read32(tmpaddr);
2674
2675 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002676 PRINTK_DEBUG("Extended Mode Register Set: OCD Exit\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002677 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2678
2679 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002680 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002681 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002682 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002683 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002684 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002685 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002686 ram_read32(tmpaddr);
2687 }
2688}
2689
2690static void sdram_init_complete(void)
2691{
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002692 PRINTK_DEBUG("Normal Operation\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002693 do_ram_command(RAM_COMMAND_NORMAL);
2694}
2695
2696static void sdram_setup_processor_side(void)
2697{
2698 if (i945_silicon_revision() == 0)
2699 MCHBAR32(FSBPMC3) |= (1 << 2);
2700
2701 MCHBAR8(0xb00) |= 1;
2702
2703 if (i945_silicon_revision() == 0)
2704 MCHBAR32(SLPCTL) |= (1 << 8);
2705}
2706
Stefan Reinauer278534d2008-10-29 04:51:07 +00002707/**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002708 * @param boot_path: 0 = normal, 1 = reset, 2 = resume from s3
Martin Rothf4cb4122015-01-06 10:27:39 -07002709 * @param spd_addresses pointer to a list of SPD addresses
Stefan Reinauer278534d2008-10-29 04:51:07 +00002710 */
Sven Schnelle541269b2011-02-21 09:39:17 +00002711void sdram_initialize(int boot_path, const u8 *spd_addresses)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002712{
2713 struct sys_info sysinfo;
Arthur Heymans0ab49042017-02-06 22:40:14 +01002714 u8 reg8;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002715
Patrick Georgi771328f2015-07-13 19:24:07 +02002716 timestamp_add_now(TS_BEFORE_INITRAM);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002717 printk(BIOS_DEBUG, "Setting up RAM controller.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002718
2719 memset(&sysinfo, 0, sizeof(sysinfo));
2720
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002721 sysinfo.boot_path = boot_path;
Sven Schnelle541269b2011-02-21 09:39:17 +00002722 sysinfo.spd_addresses = spd_addresses;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002723
Stefan Reinauer278534d2008-10-29 04:51:07 +00002724 /* Look at the type of DIMMs and verify all DIMMs are x8 or x16 width */
2725 sdram_get_dram_configuration(&sysinfo);
2726
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002727 /* If error, do cold boot */
2728 sdram_detect_errors(&sysinfo);
2729
Stefan Reinauer278534d2008-10-29 04:51:07 +00002730 /* Program PLL settings */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002731 sdram_program_pll_settings(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002732
Arthur Heymans18537812016-12-28 21:20:45 +01002733 /*
2734 * Program Graphics Frequency
2735 * Set core display and render clock on 945GC to the max
2736 */
Julius Wernercd49cce2019-03-05 16:53:33 -08002737 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM))
Arthur Heymans18537812016-12-28 21:20:45 +01002738 sdram_program_graphics_frequency(&sysinfo);
2739 else
2740 pci_write_config16(PCI_DEV(0, 2, 0), GCFC, 0x0534);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002741
2742 /* Program System Memory Frequency */
2743 sdram_program_memory_frequency(&sysinfo);
2744
2745 /* Determine Mode of Operation (Interleaved etc) */
2746 sdram_set_channel_mode(&sysinfo);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002747
Stefan Reinauer278534d2008-10-29 04:51:07 +00002748 /* Program Clock Crossing values */
2749 sdram_program_clock_crossing();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002750
Stefan Reinauer278534d2008-10-29 04:51:07 +00002751 /* Disable fast dispatch */
2752 sdram_disable_fast_dispatch();
2753
2754 /* Enable WIODLL Power Down in ACPI states */
2755 MCHBAR32(C0DMC) |= (1 << 24);
2756 MCHBAR32(C1DMC) |= (1 << 24);
2757
2758 /* Program DRAM Row Boundary/Attribute Registers */
2759
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002760 /* program row size DRB and set TOLUD */
2761 sdram_program_row_boundaries(&sysinfo);
2762
2763 /* program page size DRA */
2764 sdram_set_row_attributes(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002765
2766 /* Program CxBNKARC */
2767 sdram_set_bank_architecture(&sysinfo);
2768
2769 /* Program DRAM Timing and Control registers based on SPD */
2770 sdram_set_timing_and_control(&sysinfo);
2771
2772 /* On-Die Termination Adjustment */
2773 sdram_on_die_termination(&sysinfo);
2774
2775 /* Pre Jedec Initialization */
2776 sdram_pre_jedec_initialization();
2777
2778 /* Perform System Memory IO Initialization */
2779 sdram_initialize_system_memory_io(&sysinfo);
2780
2781 /* Perform System Memory IO Buffer Enable */
2782 sdram_enable_system_memory_io(&sysinfo);
2783
2784 /* Enable System Memory Clocks */
2785 sdram_enable_memory_clocks(&sysinfo);
2786
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002787 if (boot_path == BOOT_PATH_NORMAL) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002788 /* Jedec Initialization sequence */
2789 sdram_jedec_enable(&sysinfo);
2790 }
2791
2792 /* Program Power Management Registers */
2793 sdram_power_management(&sysinfo);
2794
2795 /* Post Jedec Init */
2796 sdram_post_jedec_initialization(&sysinfo);
2797
2798 /* Program DRAM Throttling */
2799 sdram_thermal_management();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002800
Stefan Reinauer278534d2008-10-29 04:51:07 +00002801 /* Normal Operations */
Stefan Reinaueraca6ec62009-10-26 17:12:21 +00002802 sdram_init_complete();
Stefan Reinauer278534d2008-10-29 04:51:07 +00002803
2804 /* Program Receive Enable Timings */
2805 sdram_program_receive_enable(&sysinfo);
2806
2807 /* Enable Periodic RCOMP */
2808 sdram_enable_rcomp();
2809
2810 /* Tell ICH7 that we're done */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +01002811 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002812 reg8 &= ~(1 << 7);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +01002813 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002814
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002815 printk(BIOS_DEBUG, "RAM initialization finished.\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002816
Stefan Reinauer278534d2008-10-29 04:51:07 +00002817 sdram_setup_processor_side();
Patrick Georgi771328f2015-07-13 19:24:07 +02002818 timestamp_add_now(TS_AFTER_INITRAM);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002819}