blob: b100c8f114f70f09892284c2fafaef5e4284b0f3 [file] [log] [blame]
Angel Pons4b429832020-04-02 23:48:50 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002
Patrick Georgid0835952010-10-05 09:07:10 +00003#include <console/console.h>
Kyösti Mälkki7fbed222019-07-11 08:14:07 +03004#include <delay.h>
Arthur Heymans885c2892016-10-03 17:16:48 +02005#include <device/pci_def.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +02006#include <device/pci_ops.h>
Kyösti Mälkki1a1b04e2020-01-07 22:34:33 +02007#include <device/smbus_host.h>
Elyes HAOUAS420d7e02019-04-21 18:39:34 +02008#include <cf9_reset.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02009#include <device/mmio.h>
Arthur Heymans885c2892016-10-03 17:16:48 +020010#include <device/device.h>
Julius Werner7a8a4ab2015-05-22 16:26:40 -070011#include <lib.h>
Edwin Beasanteb50c7d2010-07-06 21:05:04 +000012#include <pc80/mc146818rtc.h>
Stefan Reinauer278534d2008-10-29 04:51:07 +000013#include <spd.h>
Patrick Georgid0835952010-10-05 09:07:10 +000014#include <string.h>
Stefan Reinauer278534d2008-10-29 04:51:07 +000015#include "raminit.h"
16#include "i945.h"
Arthur Heymans885c2892016-10-03 17:16:48 +020017#include "chip.h"
Arthur Heymans0ab49042017-02-06 22:40:14 +010018#include <device/dram/ddr2.h>
Patrick Georgi771328f2015-07-13 19:24:07 +020019#include <timestamp.h>
Rudolf Marekc4369532010-12-13 19:59:13 +000020
Stefan Reinauer278534d2008-10-29 04:51:07 +000021/* Debugging macros. */
Julius Wernercd49cce2019-03-05 16:53:33 -080022#if CONFIG(DEBUG_RAM_SETUP)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000023#define PRINTK_DEBUG(x...) printk(BIOS_DEBUG, x)
Stefan Reinauer278534d2008-10-29 04:51:07 +000024#else
25#define PRINTK_DEBUG(x...)
26#endif
27
Stefan Reinauer278534d2008-10-29 04:51:07 +000028#define RAM_INITIALIZATION_COMPLETE (1 << 19)
29
30#define RAM_COMMAND_SELF_REFRESH (0x0 << 16)
31#define RAM_COMMAND_NOP (0x1 << 16)
32#define RAM_COMMAND_PRECHARGE (0x2 << 16)
33#define RAM_COMMAND_MRS (0x3 << 16)
34#define RAM_COMMAND_EMRS (0x4 << 16)
35#define RAM_COMMAND_CBR (0x6 << 16)
36#define RAM_COMMAND_NORMAL (0x7 << 16)
37
38#define RAM_EMRS_1 (0x0 << 21)
39#define RAM_EMRS_2 (0x1 << 21)
40#define RAM_EMRS_3 (0x2 << 21)
41
Arthur Heymans885c2892016-10-03 17:16:48 +020042#define DEFAULT_PCI_MMIO_SIZE 768
Sven Schnelle541269b2011-02-21 09:39:17 +000043static int get_dimm_spd_address(struct sys_info *sysinfo, int device)
44{
45 if (sysinfo->spd_addresses)
46 return sysinfo->spd_addresses[device];
47 else
Angel Ponse97a66d2021-04-03 00:15:16 +020048 return 0x50 + device;
Sven Schnelle541269b2011-02-21 09:39:17 +000049
50}
51
Stefan Reinauerbc8613e2010-08-25 18:35:42 +000052static __attribute__((noinline)) void do_ram_command(u32 command)
Stefan Reinauer278534d2008-10-29 04:51:07 +000053{
54 u32 reg32;
55
Angel Pons1d4044a2021-03-27 19:11:51 +010056 reg32 = mchbar_read32(DCC);
Angel Pons30492572020-06-11 13:24:54 +020057 reg32 &= ~((3 << 21) | (1 << 20) | (1 << 19) | (7 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +000058 reg32 |= command;
59
60 /* Also set Init Complete */
61 if (command == RAM_COMMAND_NORMAL)
62 reg32 |= RAM_INITIALIZATION_COMPLETE;
63
64 PRINTK_DEBUG(" Sending RAM command 0x%08x", reg32);
65
Angel Pons1d4044a2021-03-27 19:11:51 +010066 mchbar_write32(DCC, reg32); /* This is the actual magic */
Stefan Reinauer278534d2008-10-29 04:51:07 +000067
Stefan Reinauer779b3e32008-11-10 15:43:37 +000068 PRINTK_DEBUG("...done\n");
Stefan Reinauerd058ad12010-08-26 12:43:58 +000069
70 udelay(1);
Stefan Reinauer278534d2008-10-29 04:51:07 +000071}
72
Elyes HAOUAS964055d2022-01-14 18:56:49 +010073static void ram_read32(uintptr_t offset)
Stefan Reinauer278534d2008-10-29 04:51:07 +000074{
Elyes HAOUAS15279a92016-07-28 21:05:26 +020075 PRINTK_DEBUG(" RAM read: %08x\n", offset);
Stefan Reinauer278534d2008-10-29 04:51:07 +000076
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080077 read32((void *)offset);
Stefan Reinauer278534d2008-10-29 04:51:07 +000078}
79
Stefan Reinauer3c0bfaf2010-12-27 11:34:57 +000080void sdram_dump_mchbar_registers(void)
Stefan Reinauer278534d2008-10-29 04:51:07 +000081{
82 int i;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000083 printk(BIOS_DEBUG, "Dumping MCHBAR Registers\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +000084
Arthur Heymans70a8e342017-03-09 11:30:23 +010085 for (i = 0; i < 0xfff; i += 4) {
Angel Pons1d4044a2021-03-27 19:11:51 +010086 if (mchbar_read32(i) == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +000087 continue;
Angel Pons1d4044a2021-03-27 19:11:51 +010088 printk(BIOS_DEBUG, "0x%04x: 0x%08x\n", i, mchbar_read32(i));
Stefan Reinauer278534d2008-10-29 04:51:07 +000089 }
90}
Stefan Reinauer278534d2008-10-29 04:51:07 +000091
Stefan Reinauer24b4df52010-01-17 13:47:35 +000092static int memclk(void)
93{
Julius Wernercd49cce2019-03-05 16:53:33 -080094 int offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Elyes HAOUASc9848a82016-10-09 20:24:20 +020095
Angel Pons1d4044a2021-03-27 19:11:51 +010096 switch (((mchbar_read32(CLKCFG) >> 4) & 7) - offset) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +000097 case 1: return 400;
98 case 2: return 533;
99 case 3: return 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100100 default:
Elyes HAOUAS3cd43272020-03-05 22:01:17 +0100101 printk(BIOS_DEBUG, "%s: unknown register value %x\n", __func__,
Angel Pons1d4044a2021-03-27 19:11:51 +0100102 ((mchbar_read32(CLKCFG) >> 4) & 7) - offset);
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000103 }
104 return -1;
105}
106
Peter Stuge76d91432010-10-01 10:02:33 +0000107static u16 fsbclk(void)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000108{
Julius Wernercd49cce2019-03-05 16:53:33 -0800109 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Angel Pons1d4044a2021-03-27 19:11:51 +0100110 switch (mchbar_read32(CLKCFG) & 7) {
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200111 case 0: return 400;
112 case 1: return 533;
113 case 3: return 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100114 default:
Elyes HAOUAS3cd43272020-03-05 22:01:17 +0100115 printk(BIOS_DEBUG, "%s: unknown register value %x\n", __func__,
Angel Pons1d4044a2021-03-27 19:11:51 +0100116 mchbar_read32(CLKCFG) & 7);
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200117 }
118 return 0xffff;
Julius Wernercd49cce2019-03-05 16:53:33 -0800119 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Angel Pons1d4044a2021-03-27 19:11:51 +0100120 switch (mchbar_read32(CLKCFG) & 7) {
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200121 case 0: return 1066;
122 case 1: return 533;
123 case 2: return 800;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100124 default:
Elyes HAOUAS3cd43272020-03-05 22:01:17 +0100125 printk(BIOS_DEBUG, "%s: unknown register value %x\n", __func__,
Angel Pons1d4044a2021-03-27 19:11:51 +0100126 mchbar_read32(CLKCFG) & 7);
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200127 }
128 return 0xffff;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000129 }
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000130}
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000131
Stefan Reinauer278534d2008-10-29 04:51:07 +0000132static int sdram_capabilities_max_supported_memory_frequency(void)
133{
134 u32 reg32;
135
Patrick Georgi77d66832010-10-01 08:02:45 +0000136#if CONFIG_MAXIMUM_SUPPORTED_FREQUENCY
137 return CONFIG_MAXIMUM_SUPPORTED_FREQUENCY;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000138#endif
139
Angel Pons3580d812020-06-11 14:13:33 +0200140 reg32 = pci_read_config32(HOST_BRIDGE, 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000141 reg32 &= (7 << 0);
142
143 switch (reg32) {
144 case 4: return 400;
145 case 3: return 533;
146 case 2: return 667;
147 }
148 /* Newer revisions of this chipset rather support faster memory clocks,
149 * so if it's a reserved value, return the fastest memory clock that we
150 * know of and can handle
151 */
152 return 667;
153}
154
155/**
156 * @brief determine whether chipset is capable of dual channel interleaved mode
157 *
158 * @return 1 if interleaving is supported, 0 otherwise
159 */
160static int sdram_capabilities_interleave(void)
161{
162 u32 reg32;
163
Angel Pons3580d812020-06-11 14:13:33 +0200164 reg32 = pci_read_config32(HOST_BRIDGE, 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000165 reg32 >>= 25;
166 reg32 &= 1;
167
168 return (!reg32);
169}
170
171/**
172 * @brief determine whether chipset is capable of two memory channels
173 *
174 * @return 1 if dual channel operation is supported, 0 otherwise
175 */
176static int sdram_capabilities_dual_channel(void)
177{
178 u32 reg32;
179
Angel Pons3580d812020-06-11 14:13:33 +0200180 reg32 = pci_read_config32(HOST_BRIDGE, 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000181 reg32 >>= 24;
182 reg32 &= 1;
183
184 return (!reg32);
185}
186
187static int sdram_capabilities_enhanced_addressing_xor(void)
188{
189 u8 reg8;
190
Angel Pons3580d812020-06-11 14:13:33 +0200191 reg8 = pci_read_config8(HOST_BRIDGE, 0xe5); /* CAPID0 + 5 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000192 reg8 &= (1 << 7);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000193
Stefan Reinauer278534d2008-10-29 04:51:07 +0000194 return (!reg8);
195}
196
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000197#define GFX_FREQUENCY_CAP_166MHZ 0x04
198#define GFX_FREQUENCY_CAP_200MHZ 0x03
199#define GFX_FREQUENCY_CAP_250MHZ 0x02
200#define GFX_FREQUENCY_CAP_ALL 0x00
201
202static int sdram_capabilities_core_frequencies(void)
203{
204 u8 reg8;
205
Angel Pons3580d812020-06-11 14:13:33 +0200206 reg8 = pci_read_config8(HOST_BRIDGE, 0xe5); /* CAPID0 + 5 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000207 reg8 &= (1 << 3) | (1 << 2) | (1 << 1);
208 reg8 >>= 1;
209
Arthur Heymans70a8e342017-03-09 11:30:23 +0100210 return reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000211}
212
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000213static void sdram_detect_errors(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000214{
215 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000216 u8 do_reset = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000217
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100218 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000219
Angel Pons30492572020-06-11 13:24:54 +0200220 if (reg8 & ((1 << 7) | (1 << 2))) {
221 if (reg8 & (1 << 2)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000222 printk(BIOS_DEBUG, "SLP S4# Assertion Width Violation.\n");
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000223 /* Write back clears bit 2 */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100224 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000225 do_reset = 1;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000226
Stefan Reinauer278534d2008-10-29 04:51:07 +0000227 }
228
Angel Pons30492572020-06-11 13:24:54 +0200229 if (reg8 & (1 << 7)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000230 printk(BIOS_DEBUG, "DRAM initialization was interrupted.\n");
Angel Pons30492572020-06-11 13:24:54 +0200231 reg8 &= ~(1 << 7);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100232 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000233 do_reset = 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000234 }
235
236 /* Set SLP_S3# Assertion Stretch Enable */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100237 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000238 reg8 |= (1 << 3);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100239 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000240
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000241 if (do_reset) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000242 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200243 full_reset();
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000244 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000245 }
246
247 /* Set DRAM initialization bit in ICH7 */
Angel Ponse3c68d22020-06-08 12:09:03 +0200248 pci_or_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, 1 << 7);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000249
Peter Stuge751508a2012-01-27 22:17:09 +0100250 /* clear self refresh status if check is disabled or not a resume */
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200251 if (!CONFIG(CHECK_SLFRCS_ON_RESUME) || sysinfo->boot_path != BOOT_PATH_RESUME) {
Angel Pons1d4044a2021-03-27 19:11:51 +0100252 mchbar_setbits8(SLFRCS, 3);
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000253 } else {
254 /* Validate self refresh config */
255 if (((sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED) ||
256 (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)) &&
Angel Pons1d4044a2021-03-27 19:11:51 +0100257 !(mchbar_read8(SLFRCS) & (1 << 0))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000258 do_reset = 1;
259 }
260 if (((sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED) ||
261 (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) &&
Angel Pons1d4044a2021-03-27 19:11:51 +0100262 !(mchbar_read8(SLFRCS) & (1 << 1))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000263 do_reset = 1;
264 }
265 }
266
267 if (do_reset) {
268 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200269 full_reset();
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000270 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000271}
Stefan Reinauer278534d2008-10-29 04:51:07 +0000272
Arthur Heymans0ab49042017-02-06 22:40:14 +0100273struct timings {
274 u32 min_tCLK_cas[8];
275 u32 min_tRAS;
276 u32 min_tRP;
277 u32 min_tRCD;
278 u32 min_tWR;
279 u32 min_tRFC;
280 u32 max_tRR;
281 u8 cas_mask;
282};
Stefan Reinauer278534d2008-10-29 04:51:07 +0000283
Arthur Heymans0ab49042017-02-06 22:40:14 +0100284/**
285 * @brief loop over dimms and save maximal timings
286 */
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200287static void gather_common_timing(struct sys_info *sysinfo, struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000288{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100289
290 int i, j;
291 u8 raw_spd[SPD_SIZE_MAX_DDR2];
292 u8 dimm_mask = 0;
293
294 memset(saved_timings, 0, sizeof(*saved_timings));
295 saved_timings->max_tRR = UINT32_MAX;
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200296 saved_timings->cas_mask = SPD_CAS_LATENCY_DDR2_3 | SPD_CAS_LATENCY_DDR2_4
297 | SPD_CAS_LATENCY_DDR2_5;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000298
299 /**
300 * i945 supports two DIMMs, in two configurations:
301 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000302 * - single channel with two DIMMs
303 * - dual channel with one DIMM per channel
Stefan Reinauer278534d2008-10-29 04:51:07 +0000304 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000305 * In practice dual channel mainboards have their SPD at 0x50/0x52
306 * whereas single channel configurations have their SPD at 0x50/0x51.
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000307 *
Stefan Reinauer278534d2008-10-29 04:51:07 +0000308 * The capability register knows a lot about the channel configuration
Uwe Hermannd773fd32010-11-20 20:23:08 +0000309 * but for now we stick with the information we gather via SPD.
Stefan Reinauer278534d2008-10-29 04:51:07 +0000310 */
311
Arthur Heymans0ab49042017-02-06 22:40:14 +0100312 printk(BIOS_DEBUG, "This mainboard supports ");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000313 if (sdram_capabilities_dual_channel()) {
314 sysinfo->dual_channel = 1;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100315 printk(BIOS_DEBUG, "Dual Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000316 } else {
317 sysinfo->dual_channel = 0;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100318 printk(BIOS_DEBUG, "only Single Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000319 }
320
Arthur Heymans70a8e342017-03-09 11:30:23 +0100321 for (i = 0; i < (2 * DIMM_SOCKETS); i++) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100322 int device = get_dimm_spd_address(sysinfo, i), bytes_read;
Arthur Heymansfc31e442018-02-12 15:12:34 +0100323 struct dimm_attr_ddr2_st dimm_info;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000324
325 /* Initialize the socket information with a sane value */
326 sysinfo->dimm[i] = SYSINFO_DIMM_NOT_POPULATED;
327
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000328 /* Dual Channel not supported, but Channel 1? Bail out */
329 if (!sdram_capabilities_dual_channel() && (i >> 1))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000330 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000331
Kyösti Mälkkibd659852020-01-05 20:00:18 +0200332 if (smbus_read_byte(device, SPD_MEMORY_TYPE) !=
Arthur Heymans0ab49042017-02-06 22:40:14 +0100333 SPD_MEMORY_TYPE_SDRAM_DDR2) {
334 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: N/A\n",
335 (i >> 1), (i & 1));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000336 continue;
337 }
338
Arthur Heymans0ab49042017-02-06 22:40:14 +0100339 /*
340 * spd_decode_ddr2() needs a 128-byte sized array but
341 * only the first 64 bytes contain data needed for raminit.
342 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000343
Kyösti Mälkkic01a5052019-01-30 09:39:23 +0200344 bytes_read = i2c_eeprom_read(device, 0, 64, raw_spd);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100345 printk(BIOS_DEBUG, "Reading SPD using i2c block operation.\n");
Julius Wernercd49cce2019-03-05 16:53:33 -0800346 if (CONFIG(DEBUG_RAM_SETUP) && bytes_read > 0)
Arthur Heymans0ab49042017-02-06 22:40:14 +0100347 hexdump(raw_spd, bytes_read);
Arthur Heymans56619452017-09-21 09:12:42 +0200348 if (bytes_read != 64) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100349 /* Try again with SMBUS byte read */
350 printk(BIOS_DEBUG, "i2c block operation failed,"
Paul Menzel105e3682017-09-21 08:11:05 +0200351 " trying smbus byte operation.\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100352 for (j = 0; j < 64; j++)
Kyösti Mälkkibd659852020-01-05 20:00:18 +0200353 raw_spd[j] = smbus_read_byte(device, j);
Julius Wernercd49cce2019-03-05 16:53:33 -0800354 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100355 hexdump(raw_spd, 64);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100356 }
Arthur Heymans56619452017-09-21 09:12:42 +0200357
358 if (spd_decode_ddr2(&dimm_info, raw_spd) != SPD_STATUS_OK) {
359 printk(BIOS_WARNING, "Encountered problems with SPD, "
360 "skipping this DIMM.\n");
361 continue;
362 }
363
Julius Wernercd49cce2019-03-05 16:53:33 -0800364 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100365 dram_print_spd_ddr2(&dimm_info);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000366
Arthur Heymans0ab49042017-02-06 22:40:14 +0100367 if (dimm_info.flags.is_ecc)
368 die("\nError: ECC memory not supported by this chipset\n");
369
370 if (spd_dimm_is_registered_ddr2(dimm_info.dimm_type))
371 die("\nError: Registered memory not supported by this chipset\n");
372
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200373 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: ", (i >> 1), (i & 1));
Arthur Heymans0ab49042017-02-06 22:40:14 +0100374 /**
375 * There are 5 different possible populations for a DIMM socket:
376 * 0. x16 double ranked (X16DS)
377 * 1. x8 double ranked (X8DS)
378 * 2. x16 single ranked (X16SS)
379 * 3. x8 double stacked (X8DDS)
380 * 4. Unpopulated
381 */
382 switch (dimm_info.width) {
383 case 8:
384 switch (dimm_info.ranks) {
385 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000386 printk(BIOS_DEBUG, "x8DDS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000387 sysinfo->dimm[i] = SYSINFO_DIMM_X8DDS;
388 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100389 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000390 printk(BIOS_DEBUG, "x8DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000391 sysinfo->dimm[i] = SYSINFO_DIMM_X8DS;
392 break;
393 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000394 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000395 }
396 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100397 case 16:
398 switch (dimm_info.ranks) {
399 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000400 printk(BIOS_DEBUG, "x16DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000401 sysinfo->dimm[i] = SYSINFO_DIMM_X16DS;
402 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100403 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000404 printk(BIOS_DEBUG, "x16SS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000405 sysinfo->dimm[i] = SYSINFO_DIMM_X16SS;
406 break;
407 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000408 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000409 }
410 break;
411 default:
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000412 die("Unsupported DDR-II memory width.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000413 }
414
Arthur Heymans0ab49042017-02-06 22:40:14 +0100415 /* Is the current DIMM a stacked DIMM? */
416 if (dimm_info.flags.stacked)
417 sysinfo->package = SYSINFO_PACKAGE_STACKED;
418
419 if (!dimm_info.flags.bl8)
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100420 die("Only DDR-II RAM with burst length 8 is supported.\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100421
422 if (dimm_info.ranksize_mb < 128)
423 die("DDR-II rank size smaller than 128MB is not supported.\n");
424
425 sysinfo->banksize[i * 2] = dimm_info.ranksize_mb / 32;
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200426 printk(BIOS_DEBUG, "DIMM %d side 0 = %d MB\n", i, sysinfo->banksize[i * 2] * 32);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100427 if (dimm_info.ranks == 2) {
428 sysinfo->banksize[(i * 2) + 1] =
429 dimm_info.ranksize_mb / 32;
430 printk(BIOS_DEBUG, "DIMM %d side 1 = %d MB\n",
431 i, sysinfo->banksize[(i * 2) + 1] * 32);
432 }
433
Arthur Heymans0ab49042017-02-06 22:40:14 +0100434 sysinfo->rows[i] = dimm_info.row_bits;
435 sysinfo->cols[i] = dimm_info.col_bits;
436 sysinfo->banks[i] = dimm_info.banks;
437
438 /* int min_tRAS, min_tRP, min_tRCD, min_tWR, min_tRFC; */
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200439 saved_timings->min_tRAS = MAX(saved_timings->min_tRAS, dimm_info.tRAS);
440 saved_timings->min_tRP = MAX(saved_timings->min_tRP, dimm_info.tRP);
441 saved_timings->min_tRCD = MAX(saved_timings->min_tRCD, dimm_info.tRCD);
442 saved_timings->min_tWR = MAX(saved_timings->min_tWR, dimm_info.tWR);
443 saved_timings->min_tRFC = MAX(saved_timings->min_tRFC, dimm_info.tRFC);
444 saved_timings->max_tRR = MIN(saved_timings->max_tRR, dimm_info.tRR);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100445 saved_timings->cas_mask &= dimm_info.cas_supported;
446 for (j = 0; j < 8; j++) {
447 if (!(saved_timings->cas_mask & (1 << j)))
448 saved_timings->min_tCLK_cas[j] = 0;
449 else
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200450 saved_timings->min_tCLK_cas[j] = MAX(dimm_info.cycle_time[j],
Arthur Heymans0ab49042017-02-06 22:40:14 +0100451 saved_timings->min_tCLK_cas[j]);
452 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000453 dimm_mask |= (1 << i);
454 }
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200455 if (!dimm_mask)
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000456 die("No memory installed.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000457
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200458 if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1)))
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100459 /* FIXME: Possibly does not boot in this case */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000460 printk(BIOS_INFO, "Channel 0 has no memory populated.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000461}
462
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200463static void choose_tclk(struct sys_info *sysinfo, struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000464{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100465 u32 ctrl_min_tclk;
466 int try_cas;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000467
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200468 ctrl_min_tclk = 2 * 256 * 1000 / sdram_capabilities_max_supported_memory_frequency();
Arthur Heymans0ab49042017-02-06 22:40:14 +0100469 normalize_tck(&ctrl_min_tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000470
Arthur Heymans0ab49042017-02-06 22:40:14 +0100471 try_cas = spd_get_msbs(saved_timings->cas_mask);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000472
Arthur Heymans0ab49042017-02-06 22:40:14 +0100473 while (saved_timings->cas_mask & (1 << try_cas) && try_cas > 0) {
474 sysinfo->cas = try_cas;
475 sysinfo->tclk = saved_timings->min_tCLK_cas[try_cas];
476 if (sysinfo->tclk >= ctrl_min_tclk &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200477 saved_timings->min_tCLK_cas[try_cas] !=
478 saved_timings->min_tCLK_cas[try_cas - 1])
Stefan Reinauer278534d2008-10-29 04:51:07 +0000479 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100480 try_cas--;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000481 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000482
Arthur Heymans0ab49042017-02-06 22:40:14 +0100483 normalize_tck(&sysinfo->tclk);
484
485 if ((sysinfo->cas < 3) || (sysinfo->tclk == 0))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000486 die("Could not find common memory frequency and CAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000487
Arthur Heymans0ab49042017-02-06 22:40:14 +0100488 /*
489 * The loop can still results in a timing too fast for the
490 * memory controller.
491 */
492 if (sysinfo->tclk < ctrl_min_tclk)
493 sysinfo->tclk = ctrl_min_tclk;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000494
Arthur Heymans0ab49042017-02-06 22:40:14 +0100495 switch (sysinfo->tclk) {
496 case TCK_200MHZ:
497 sysinfo->memory_frequency = 400;
498 break;
499 case TCK_266MHZ:
500 sysinfo->memory_frequency = 533;
501 break;
502 case TCK_333MHZ:
503 sysinfo->memory_frequency = 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100504 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000505 }
506
Arthur Heymans0ab49042017-02-06 22:40:14 +0100507 printk(BIOS_DEBUG,
508 "Memory will be driven at %dMT with CAS=%d clocks\n",
509 sysinfo->memory_frequency, sysinfo->cas);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000510}
511
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200512static void derive_timings(struct sys_info *sysinfo, struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000513{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100514 sysinfo->tras = DIV_ROUND_UP(saved_timings->min_tRAS, sysinfo->tclk);
515 if (sysinfo->tras > 0x18)
516 die("DDR-II Module does not support this frequency (tRAS error)\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000517
Arthur Heymans0ab49042017-02-06 22:40:14 +0100518 sysinfo->trp = DIV_ROUND_UP(saved_timings->min_tRP, sysinfo->tclk);
519 if (sysinfo->trp > 6)
520 die("DDR-II Module does not support this frequency (tRP error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000521
Arthur Heymans0ab49042017-02-06 22:40:14 +0100522 sysinfo->trcd = DIV_ROUND_UP(saved_timings->min_tRCD, sysinfo->tclk);
523 if (sysinfo->trcd > 6)
524 die("DDR-II Module does not support this frequency (tRCD error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000525
Arthur Heymans0ab49042017-02-06 22:40:14 +0100526 sysinfo->twr = DIV_ROUND_UP(saved_timings->min_tWR, sysinfo->tclk);
527 if (sysinfo->twr > 5)
528 die("DDR-II Module does not support this frequency (tWR error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000529
Arthur Heymans0ab49042017-02-06 22:40:14 +0100530 sysinfo->trfc = DIV_ROUND_UP(saved_timings->min_tRFC, sysinfo->tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000531
Arthur Heymans0ab49042017-02-06 22:40:14 +0100532 printk(BIOS_DEBUG, "tRAS = %d cycles\n", sysinfo->tras);
533 printk(BIOS_DEBUG, "tRP = %d cycles\n", sysinfo->trp);
534 printk(BIOS_DEBUG, "tRCD = %d cycles\n", sysinfo->trcd);
535 printk(BIOS_DEBUG, "tWR = %d cycles\n", sysinfo->twr);
536 printk(BIOS_DEBUG, "tRFC = %d cycles\n", sysinfo->trfc);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000537
Arthur Heymans0ab49042017-02-06 22:40:14 +0100538 /* Refresh is slower than 15.6us, use 15.6us */
539 /* tRR is decoded in units of 1/256us */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000540
Arthur Heymans0ab49042017-02-06 22:40:14 +0100541#define T_RR_7_8US 2000000
542#define T_RR_15_6US 4000000
543#define REFRESH_7_8US 1
544#define REFRESH_15_6US 0
Stefan Reinauer278534d2008-10-29 04:51:07 +0000545
Arthur Heymans0ab49042017-02-06 22:40:14 +0100546 if (saved_timings->max_tRR < T_RR_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000547 die("DDR-II module has unsupported refresh value\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100548 else if (saved_timings->max_tRR < T_RR_15_6US)
549 sysinfo->refresh = REFRESH_7_8US;
550 else
551 sysinfo->refresh = REFRESH_15_6US;
Angel Pons30492572020-06-11 13:24:54 +0200552 printk(BIOS_DEBUG, "Refresh: %s\n", sysinfo->refresh ? "7.8us" : "15.6us");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000553}
554
Arthur Heymans0ab49042017-02-06 22:40:14 +0100555/**
556 * @brief Get generic DIMM parameters.
557 * @param sysinfo Central memory controller information structure
558 *
559 * This function gathers several pieces of information for each system DIMM:
560 * o DIMM width (x8 / x16)
561 * o DIMM rank (single ranked / dual ranked)
562 *
563 * Also, some non-supported scenarios are detected.
564 */
565
566static void sdram_get_dram_configuration(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000567{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100568 struct timings saved_timings;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000569
Arthur Heymans0ab49042017-02-06 22:40:14 +0100570 gather_common_timing(sysinfo, &saved_timings);
571 choose_tclk(sysinfo, &saved_timings);
572 derive_timings(sysinfo, &saved_timings);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000573}
574
Arthur Heymans70a8e342017-03-09 11:30:23 +0100575static void sdram_program_dram_width(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000576{
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200577 u16 c0dramw = 0, c1dramw = 0;
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200578 int i, idx;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000579
580 if (sysinfo->dual_channel)
581 idx = 2;
582 else
583 idx = 1;
584
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200585 for (i = 0; i < DIMM_SOCKETS; i++) { /* Channel 0 */
586 switch (sysinfo->dimm[i]) {
587 case SYSINFO_DIMM_X16DS:
Angel Pons30492572020-06-11 13:24:54 +0200588 c0dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200589 break;
590 case SYSINFO_DIMM_X8DS:
Angel Pons30492572020-06-11 13:24:54 +0200591 c0dramw |= (0x0001) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200592 break;
593 case SYSINFO_DIMM_X16SS:
Angel Pons30492572020-06-11 13:24:54 +0200594 c0dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200595 break;
596 case SYSINFO_DIMM_X8DDS:
Angel Pons30492572020-06-11 13:24:54 +0200597 c0dramw |= (0x0005) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200598 break;
599 case SYSINFO_DIMM_NOT_POPULATED:
Angel Pons30492572020-06-11 13:24:54 +0200600 c0dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200601 break;
602 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000603 }
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200604 for (i = DIMM_SOCKETS; i < idx * DIMM_SOCKETS; i++) { /* Channel 1 */
605 switch (sysinfo->dimm[i]) {
606 case SYSINFO_DIMM_X16DS:
Angel Pons30492572020-06-11 13:24:54 +0200607 c1dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200608 break;
609 case SYSINFO_DIMM_X8DS:
Angel Pons30492572020-06-11 13:24:54 +0200610 c1dramw |= (0x0010) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200611 break;
612 case SYSINFO_DIMM_X16SS:
Angel Pons30492572020-06-11 13:24:54 +0200613 c1dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200614 break;
615 case SYSINFO_DIMM_X8DDS:
Angel Pons30492572020-06-11 13:24:54 +0200616 c1dramw |= (0x0050) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200617 break;
618 case SYSINFO_DIMM_NOT_POPULATED:
Angel Pons30492572020-06-11 13:24:54 +0200619 c1dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200620 break;
621 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000622 }
623
Angel Pons1d4044a2021-03-27 19:11:51 +0100624 mchbar_write16(C0DRAMW, c0dramw);
625 mchbar_write16(C1DRAMW, c1dramw);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000626}
627
628static void sdram_write_slew_rates(u32 offset, const u32 *slew_rate_table)
629{
630 int i;
631
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200632 for (i = 0; i < 16; i++)
Angel Pons1d4044a2021-03-27 19:11:51 +0100633 mchbar_write32(offset + (i * 4), slew_rate_table[i]);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000634}
635
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000636static const u32 dq2030[] = {
637 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
638 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
639 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
640 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
641};
642
643static const u32 dq2330[] = {
644 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
645 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
646 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
647 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
648};
649
650static const u32 cmd2710[] = {
651 0x07060605, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
652 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
653 0x1110100f, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
654 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
655};
656
657static const u32 cmd3210[] = {
658 0x0f0d0b0a, 0x17151311, 0x1f1d1b19, 0x1f1f1f1f,
659 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
660 0x18171615, 0x1f1f1c1a, 0x1f1f1f1f, 0x1f1f1f1f,
661 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
662};
663
664static const u32 clk2030[] = {
665 0x0e0d0d0c, 0x100f0f0e, 0x100f0e0d, 0x15131211,
666 0x1d1b1917, 0x2523211f, 0x2a282927, 0x32302e2c,
667 0x17161514, 0x1b1a1918, 0x1f1e1d1c, 0x23222120,
668 0x27262524, 0x2d2b2928, 0x3533312f, 0x3d3b3937
669};
670
671static const u32 ctl3215[] = {
672 0x01010000, 0x03020101, 0x07060504, 0x0b0a0908,
673 0x100f0e0d, 0x14131211, 0x18171615, 0x1c1b1a19,
674 0x05040403, 0x07060605, 0x0a090807, 0x0f0d0c0b,
675 0x14131211, 0x18171615, 0x1c1b1a19, 0x201f1e1d
676};
677
678static const u32 ctl3220[] = {
679 0x05040403, 0x07060505, 0x0e0c0a08, 0x1a171411,
680 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e,
681 0x09080807, 0x0b0a0a09, 0x0f0d0c0b, 0x1b171311,
682 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e
683};
684
685static const u32 nc[] = {
686 0x00000000, 0x00000000, 0x00000000, 0x00000000,
687 0x00000000, 0x00000000, 0x00000000, 0x00000000,
688 0x00000000, 0x00000000, 0x00000000, 0x00000000,
689 0x00000000, 0x00000000, 0x00000000, 0x00000000
690};
691
692enum {
693 DQ2030,
694 DQ2330,
695 CMD2710,
696 CMD3210,
697 CLK2030,
698 CTL3215,
699 CTL3220,
700 NC,
701};
702
703static const u8 dual_channel_slew_group_lookup[] = {
704 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
705 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
706 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
707 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
708 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
709
710 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
711 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
712 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
713 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
714 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
715
716 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
717 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
718 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
719 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
720 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
721
722 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
723 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
724 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
725 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
726 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, NC, NC,
727
728 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
729 NC, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
730 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
731 NC, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD2710
732};
733
734static const u8 single_channel_slew_group_lookup[] = {
735 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
736 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
737 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
738 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
739 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
740
741 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
742 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
743 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
744 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
745 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
746
747 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
748 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
749 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
750 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
751 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
752
753 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
754 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
755 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
756 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
757 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
758
759 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
760 DQ2330, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
761 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
762 DQ2330, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD3210
763};
764
765static const u32 *slew_group_lookup(int dual_channel, int index)
766{
767 const u8 *slew_group;
768 /* Dual Channel needs different tables. */
769 if (dual_channel)
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100770 slew_group = dual_channel_slew_group_lookup;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000771 else
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100772 slew_group = single_channel_slew_group_lookup;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000773
774 switch (slew_group[index]) {
775 case DQ2030: return dq2030;
776 case DQ2330: return dq2330;
777 case CMD2710: return cmd2710;
778 case CMD3210: return cmd3210;
779 case CLK2030: return clk2030;
780 case CTL3215: return ctl3215;
781 case CTL3220: return ctl3220;
782 case NC: return nc;
783 }
784
785 return nc;
786}
787
Julius Wernercd49cce2019-03-05 16:53:33 -0800788#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000789/* Strength multiplier tables */
790static const u8 dual_channel_strength_multiplier[] = {
791 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
792 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
793 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
794 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
795 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
796 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
797 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
798 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
799 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
800 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
801 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
802 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
803 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
804 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
805 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
806 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
807 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
808 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
809 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
810 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
811 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
812 0x00, 0x00, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
813 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
814 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x44, 0x22
815};
816
817static const u8 single_channel_strength_multiplier[] = {
818 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
819 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
820 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
821 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
822 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
823 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
824 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
825 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
826 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
827 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
828 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
829 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
830 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
831 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
832 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
833 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
834 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
835 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
836 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
837 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
838 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
839 0x33, 0x00, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
840 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
841 0x33, 0x00, 0x11, 0x00, 0x44, 0x44, 0x33, 0x11
842};
Julius Wernercd49cce2019-03-05 16:53:33 -0800843#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000844static const u8 dual_channel_strength_multiplier[] = {
845 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
846 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
847 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
848 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
849 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
850 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
851 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
852 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
853 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
854 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
855 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
856 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
857 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
858 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
859 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
860 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
861 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
862 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
863 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
864 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
865 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
866 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
867 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
868 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33
869};
870
871static const u8 single_channel_strength_multiplier[] = {
872 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
873 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
874 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
875 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
876 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
877 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
878 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
879 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
880 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
881 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
882 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
883 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
884 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
885 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
886 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
887 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
888 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
889 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
890 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
891 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
892 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
893 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
894 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
895 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00
896};
897#endif
898
Stefan Reinauer278534d2008-10-29 04:51:07 +0000899static void sdram_rcomp_buffer_strength_and_slew(struct sys_info *sysinfo)
900{
Arthur Heymans70a8e342017-03-09 11:30:23 +0100901 const u8 *strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000902 int idx, dual_channel;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000903
904 /* Set Strength Multipliers */
905
906 /* Dual Channel needs different tables. */
907 if (sdram_capabilities_dual_channel()) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000908 printk(BIOS_DEBUG, "Programming Dual Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000909 strength_multiplier = dual_channel_strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000910 dual_channel = 1;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100911 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[2];
Stefan Reinauer278534d2008-10-29 04:51:07 +0000912 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000913 printk(BIOS_DEBUG, "Programming Single Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000914 strength_multiplier = single_channel_strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000915 dual_channel = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000916 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[1];
917 }
918
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000919 printk(BIOS_DEBUG, "Table Index: %d\n", idx);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000920
Angel Pons1d4044a2021-03-27 19:11:51 +0100921 mchbar_write8(G1SC, strength_multiplier[idx * 8 + 0]);
922 mchbar_write8(G2SC, strength_multiplier[idx * 8 + 1]);
923 mchbar_write8(G3SC, strength_multiplier[idx * 8 + 2]);
924 mchbar_write8(G4SC, strength_multiplier[idx * 8 + 3]);
925 mchbar_write8(G5SC, strength_multiplier[idx * 8 + 4]);
926 mchbar_write8(G6SC, strength_multiplier[idx * 8 + 5]);
927 mchbar_write8(G7SC, strength_multiplier[idx * 8 + 6]);
928 mchbar_write8(G8SC, strength_multiplier[idx * 8 + 7]);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000929
930 /* Channel 0 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000931 sdram_write_slew_rates(G1SRPUT, slew_group_lookup(dual_channel, idx * 8 + 0));
932 sdram_write_slew_rates(G2SRPUT, slew_group_lookup(dual_channel, idx * 8 + 1));
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200933 if ((slew_group_lookup(dual_channel, idx * 8 + 2) != nc) &&
934 (sysinfo->package == SYSINFO_PACKAGE_STACKED))
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000935
Stefan Reinauer278534d2008-10-29 04:51:07 +0000936 sdram_write_slew_rates(G3SRPUT, ctl3220);
Arthur Heymans70a8e342017-03-09 11:30:23 +0100937 else
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000938 sdram_write_slew_rates(G3SRPUT, slew_group_lookup(dual_channel, idx * 8 + 2));
Arthur Heymans70a8e342017-03-09 11:30:23 +0100939
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000940 sdram_write_slew_rates(G4SRPUT, slew_group_lookup(dual_channel, idx * 8 + 3));
941 sdram_write_slew_rates(G5SRPUT, slew_group_lookup(dual_channel, idx * 8 + 4));
942 sdram_write_slew_rates(G6SRPUT, slew_group_lookup(dual_channel, idx * 8 + 5));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000943
944 /* Channel 1 */
945 if (sysinfo->dual_channel) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000946 sdram_write_slew_rates(G7SRPUT, slew_group_lookup(dual_channel, idx * 8 + 6));
947 sdram_write_slew_rates(G8SRPUT, slew_group_lookup(dual_channel, idx * 8 + 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000948 } else {
949 sdram_write_slew_rates(G7SRPUT, nc);
950 sdram_write_slew_rates(G8SRPUT, nc);
951 }
952}
953
954static void sdram_enable_rcomp(void)
955{
956 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000957 /* Enable Global Periodic RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000958 udelay(300);
Angel Pons1d4044a2021-03-27 19:11:51 +0100959 reg32 = mchbar_read32(GBRCOMPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000960 reg32 &= ~(1 << 23);
Angel Pons1d4044a2021-03-27 19:11:51 +0100961 mchbar_write32(GBRCOMPCTL, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000962}
963
964static void sdram_program_dll_timings(struct sys_info *sysinfo)
965{
Elyes HAOUAS44a30662017-02-23 13:14:44 +0100966 u32 channeldll = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000967 int i;
968
Elyes HAOUAS38424982016-08-21 12:01:04 +0200969 printk(BIOS_DEBUG, "Programming DLL Timings...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000970
Angel Pons1d4044a2021-03-27 19:11:51 +0100971 mchbar_clrbits16(DQSMT, 3 << 12 | 1 << 10 | 0xf << 0);
972 mchbar_setbits16(DQSMT, 1 << 13 | 0xc << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000973
974 /* We drive both channels with the same speed */
Julius Wernercd49cce2019-03-05 16:53:33 -0800975 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +0100976 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +0100977 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200978 channeldll = 0x26262626;
979 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100980 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200981 channeldll = 0x22222222;
982 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100983 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200984 channeldll = 0x11111111;
985 break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +0100986 }
Julius Wernercd49cce2019-03-05 16:53:33 -0800987 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +0100988 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +0100989 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200990 channeldll = 0x33333333;
991 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100992 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200993 channeldll = 0x24242424;
994 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100995 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200996 channeldll = 0x25252525;
997 break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +0100998 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000999 }
1000
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001001 for (i = 0; i < 4; i++) {
Angel Pons1d4044a2021-03-27 19:11:51 +01001002 mchbar_write32(C0R0B00DQST + (i * 0x10) + 0, channeldll);
1003 mchbar_write32(C0R0B00DQST + (i * 0x10) + 4, channeldll);
1004 mchbar_write32(C1R0B00DQST + (i * 0x10) + 0, channeldll);
1005 mchbar_write32(C1R0B00DQST + (i * 0x10) + 4, channeldll);
Julius Wernercd49cce2019-03-05 16:53:33 -08001006 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Angel Pons1d4044a2021-03-27 19:11:51 +01001007 mchbar_write8(C0R0B00DQST + (i * 0x10) + 8, channeldll & 0xff);
1008 mchbar_write8(C1R0B00DQST + (i * 0x10) + 8, channeldll & 0xff);
Paul Menzelbce7e332017-02-22 18:46:27 +01001009 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001010 }
1011}
1012
1013static void sdram_force_rcomp(void)
1014{
1015 u32 reg32;
1016 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001017
Angel Pons1d4044a2021-03-27 19:11:51 +01001018 reg32 = mchbar_read32(ODTC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001019 reg32 |= (1 << 28);
Angel Pons1d4044a2021-03-27 19:11:51 +01001020 mchbar_write32(ODTC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001021
Angel Pons1d4044a2021-03-27 19:11:51 +01001022 reg32 = mchbar_read32(SMSRCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001023 reg32 |= (1 << 0);
Angel Pons1d4044a2021-03-27 19:11:51 +01001024 mchbar_write32(SMSRCTL, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001025
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001026 /* Start initial RCOMP */
Angel Pons1d4044a2021-03-27 19:11:51 +01001027 reg32 = mchbar_read32(GBRCOMPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001028 reg32 |= (1 << 8);
Angel Pons1d4044a2021-03-27 19:11:51 +01001029 mchbar_write32(GBRCOMPCTL, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001030
1031 reg8 = i945_silicon_revision();
Angel Pons1d4044a2021-03-27 19:11:51 +01001032 if ((reg8 == 0 && (mchbar_read32(DCC) & (3 << 0)) == 0) || (reg8 == 1)) {
1033 reg32 = mchbar_read32(GBRCOMPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001034 reg32 |= (3 << 5);
Angel Pons1d4044a2021-03-27 19:11:51 +01001035 mchbar_write32(GBRCOMPCTL, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001036 }
1037}
1038
1039static void sdram_initialize_system_memory_io(struct sys_info *sysinfo)
1040{
1041 u8 reg8;
1042 u32 reg32;
1043
Elyes HAOUAS38424982016-08-21 12:01:04 +02001044 printk(BIOS_DEBUG, "Initializing System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001045 /* Enable Data Half Clock Pushout */
Angel Pons1d4044a2021-03-27 19:11:51 +01001046 reg8 = mchbar_read8(C0HCTC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001047 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001048 reg8 |= (1 << 0);
Angel Pons1d4044a2021-03-27 19:11:51 +01001049 mchbar_write8(C0HCTC, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001050
Angel Pons1d4044a2021-03-27 19:11:51 +01001051 reg8 = mchbar_read8(C1HCTC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001052 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001053 reg8 |= (1 << 0);
Angel Pons1d4044a2021-03-27 19:11:51 +01001054 mchbar_write8(C1HCTC, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001055
Angel Pons1d4044a2021-03-27 19:11:51 +01001056 mchbar_clrbits16(WDLLBYPMODE, 1 << 9 | 1 << 6 | 1 << 4 | 1 << 3 | 1 << 1);
1057 mchbar_setbits16(WDLLBYPMODE, 1 << 8 | 1 << 7 | 1 << 5 | 1 << 2 | 1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001058
Angel Pons1d4044a2021-03-27 19:11:51 +01001059 mchbar_write8(C0WDLLCMC, 0);
1060 mchbar_write8(C1WDLLCMC, 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001061
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001062 /* Program RCOMP Settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001063 sdram_program_dram_width(sysinfo);
1064
1065 sdram_rcomp_buffer_strength_and_slew(sysinfo);
1066
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001067 /* Indicate that RCOMP programming is done */
Angel Pons1d4044a2021-03-27 19:11:51 +01001068 reg32 = mchbar_read32(GBRCOMPCTL);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001069 reg32 &= ~((1 << 29) | (1 << 26) | (3 << 21) | (3 << 2));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001070 reg32 |= (3 << 27) | (3 << 0);
Angel Pons1d4044a2021-03-27 19:11:51 +01001071 mchbar_write32(GBRCOMPCTL, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001072
Angel Pons1d4044a2021-03-27 19:11:51 +01001073 mchbar_setbits32(GBRCOMPCTL, 1 << 10);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001074
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001075 /* Program DLL Timings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001076 sdram_program_dll_timings(sysinfo);
1077
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001078 /* Force RCOMP cycle */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001079 sdram_force_rcomp();
1080}
1081
1082static void sdram_enable_system_memory_io(struct sys_info *sysinfo)
1083{
1084 u32 reg32;
1085
Elyes HAOUAS38424982016-08-21 12:01:04 +02001086 printk(BIOS_DEBUG, "Enabling System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001087
Angel Pons1d4044a2021-03-27 19:11:51 +01001088 reg32 = mchbar_read32(RCVENMT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001089 reg32 &= ~(0x3f << 6);
Angel Pons1d4044a2021-03-27 19:11:51 +01001090 mchbar_write32(RCVENMT, reg32); /* [11:6] = 0 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001091
1092 reg32 |= (1 << 11) | (1 << 9);
Angel Pons1d4044a2021-03-27 19:11:51 +01001093 mchbar_write32(RCVENMT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001094
Angel Pons1d4044a2021-03-27 19:11:51 +01001095 reg32 = mchbar_read32(DRTST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001096 reg32 |= (1 << 3) | (1 << 2);
Angel Pons1d4044a2021-03-27 19:11:51 +01001097 mchbar_write32(DRTST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001098
Angel Pons1d4044a2021-03-27 19:11:51 +01001099 reg32 = mchbar_read32(DRTST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001100 reg32 |= (1 << 6) | (1 << 4);
Angel Pons1d4044a2021-03-27 19:11:51 +01001101 mchbar_write32(DRTST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001102
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001103 asm volatile ("nop; nop;" ::: "memory");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001104
Angel Pons1d4044a2021-03-27 19:11:51 +01001105 reg32 = mchbar_read32(DRTST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001106
1107 /* Is channel 0 populated? */
1108 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001109 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001110 reg32 |= (1 << 7) | (1 << 5);
1111 else
1112 reg32 |= (1 << 31);
1113
1114 /* Is channel 1 populated? */
1115 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001116 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001117 reg32 |= (1 << 9) | (1 << 8);
1118 else
1119 reg32 |= (1 << 30);
1120
Angel Pons1d4044a2021-03-27 19:11:51 +01001121 mchbar_write32(DRTST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001122
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001123 /* Activate DRAM Channel IO Buffers */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001124 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001125 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) {
Angel Pons1d4044a2021-03-27 19:11:51 +01001126 reg32 = mchbar_read32(C0DRC1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001127 reg32 |= (1 << 8);
Angel Pons1d4044a2021-03-27 19:11:51 +01001128 mchbar_write32(C0DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001129 }
1130 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001131 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED) {
Angel Pons1d4044a2021-03-27 19:11:51 +01001132 reg32 = mchbar_read32(C1DRC1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001133 reg32 |= (1 << 8);
Angel Pons1d4044a2021-03-27 19:11:51 +01001134 mchbar_write32(C1DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001135 }
1136}
1137
Stefan Reinauer278534d2008-10-29 04:51:07 +00001138static int sdram_program_row_boundaries(struct sys_info *sysinfo)
1139{
1140 int i;
Arthur Heymans885c2892016-10-03 17:16:48 +02001141 int cum0, cum1, tolud, tom, pci_mmio_size;
1142 const struct device *dev;
1143 const struct northbridge_intel_i945_config *cfg = NULL;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001144
Paul Menzel84283bc2014-07-17 08:16:04 +02001145 printk(BIOS_DEBUG, "Setting RAM size...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001146
1147 cum0 = 0;
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001148 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001149 cum0 += sysinfo->banksize[i];
Angel Pons1d4044a2021-03-27 19:11:51 +01001150 mchbar_write8(C0DRB0 + i, cum0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001151 }
1152
1153 /* Assume we continue in Channel 1 where we stopped in Channel 0 */
1154 cum1 = cum0;
1155
1156 /* Exception: Interleaved starts from the beginning */
1157 if (sysinfo->interleaved)
1158 cum1 = 0;
1159
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001160 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001161 cum1 += sysinfo->banksize[i + 4];
Angel Pons1d4044a2021-03-27 19:11:51 +01001162 mchbar_write8(C1DRB0 + i, cum1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001163 }
1164
1165 /* Set TOLUD Top Of Low Usable DRAM */
1166 if (sysinfo->interleaved)
1167 tolud = (cum0 + cum1) << 1;
1168 else
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001169 tolud = (cum1 ? cum1 : cum0) << 1;
Stefan Reinauer779b3e32008-11-10 15:43:37 +00001170
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001171 /* The TOM register has a different format */
1172 tom = tolud >> 3;
1173
1174 /* Limit the value of TOLUD to leave some space for PCI memory. */
Kyösti Mälkkic70eed12018-05-22 02:18:00 +03001175 dev = pcidev_on_root(0, 0);
Arthur Heymans885c2892016-10-03 17:16:48 +02001176 if (dev)
1177 cfg = dev->chip_info;
1178
1179 /* Don't use pci mmio sizes smaller than 768M */
1180 if (!cfg || cfg->pci_mmio_size <= DEFAULT_PCI_MMIO_SIZE)
1181 pci_mmio_size = DEFAULT_PCI_MMIO_SIZE;
1182 else
1183 pci_mmio_size = cfg->pci_mmio_size;
1184
1185 tolud = MIN(((4096 - pci_mmio_size) / 128) << 3, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001186
Angel Pons3580d812020-06-11 14:13:33 +02001187 pci_write_config8(HOST_BRIDGE, TOLUD, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001188
Angel Pons1d4044a2021-03-27 19:11:51 +01001189 printk(BIOS_DEBUG, "C0DRB = 0x%08x\n", mchbar_read32(C0DRB0));
1190 printk(BIOS_DEBUG, "C1DRB = 0x%08x\n", mchbar_read32(C1DRB0));
Angel Pons3580d812020-06-11 14:13:33 +02001191 printk(BIOS_DEBUG, "TOLUD = 0x%04x\n", pci_read_config8(HOST_BRIDGE, TOLUD));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001192
Angel Pons3580d812020-06-11 14:13:33 +02001193 pci_write_config16(HOST_BRIDGE, TOM, tom);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001194
1195 return 0;
1196}
1197
Stefan Reinauer278534d2008-10-29 04:51:07 +00001198static int sdram_set_row_attributes(struct sys_info *sysinfo)
1199{
Arthur Heymans0ab49042017-02-06 22:40:14 +01001200 int i;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001201 u16 dra0 = 0, dra1 = 0, dra = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001202
Elyes HAOUAS38424982016-08-21 12:01:04 +02001203 printk(BIOS_DEBUG, "Setting row attributes...\n");
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001204 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001205 u8 columnsrows;
1206
Arthur Heymans70a8e342017-03-09 11:30:23 +01001207 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001208 continue;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001209
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001210 columnsrows = (sysinfo->rows[i] & 0x0f) | (sysinfo->cols[i] & 0xf) << 4;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001211
1212 switch (columnsrows) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001213 case 0x9d:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001214 dra = 2;
1215 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001216 case 0xad:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001217 dra = 3;
1218 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001219 case 0xbd:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001220 dra = 4;
1221 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001222 case 0xae:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001223 dra = 3;
1224 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001225 case 0xbe:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001226 dra = 4;
1227 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001228 default:
1229 die("Unsupported Rows/Columns. (DRA)");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001230 }
1231
1232 /* Double Sided DIMMs? */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001233 if (sysinfo->banksize[(2 * i) + 1] != 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001234 dra = (dra << 4) | dra;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001235
Stefan Reinauer278534d2008-10-29 04:51:07 +00001236 if (i < DIMM_SOCKETS)
Angel Pons30492572020-06-11 13:24:54 +02001237 dra0 |= (dra << (i * 8));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001238 else
Angel Pons30492572020-06-11 13:24:54 +02001239 dra1 |= (dra << ((i - DIMM_SOCKETS) * 8));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001240 }
1241
Angel Pons1d4044a2021-03-27 19:11:51 +01001242 mchbar_write16(C0DRA0, dra0);
1243 mchbar_write16(C1DRA0, dra1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001244
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001245 printk(BIOS_DEBUG, "C0DRA = 0x%04x\n", dra0);
1246 printk(BIOS_DEBUG, "C1DRA = 0x%04x\n", dra1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001247
1248 return 0;
1249}
1250
1251static void sdram_set_bank_architecture(struct sys_info *sysinfo)
1252{
1253 u32 off32;
1254 int i;
1255
Angel Pons1d4044a2021-03-27 19:11:51 +01001256 mchbar_clrbits16(C1BNKARC, 0xff);
1257 mchbar_clrbits16(C0BNKARC, 0xff);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001258
1259 off32 = C0BNKARC;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001260 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001261 /* Switch to second channel */
1262 if (i == DIMM_SOCKETS)
1263 off32 = C1BNKARC;
1264
1265 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
1266 continue;
1267
1268 if (sysinfo->banks[i] != 8)
1269 continue;
1270
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001271 printk(BIOS_SPEW, "DIMM%d has 8 banks.\n", i);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001272
1273 if (i & 1)
Angel Pons1d4044a2021-03-27 19:11:51 +01001274 mchbar_setbits16(off32, 5 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001275 else
Angel Pons1d4044a2021-03-27 19:11:51 +01001276 mchbar_setbits16(off32, 5 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001277 }
1278}
1279
Stefan Reinauer278534d2008-10-29 04:51:07 +00001280static void sdram_program_refresh_rate(struct sys_info *sysinfo)
1281{
1282 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001283
Arthur Heymans70a8e342017-03-09 11:30:23 +01001284 if (sysinfo->refresh == REFRESH_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001285 reg32 = (2 << 8); /* Refresh enabled at 7.8us */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001286 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001287 reg32 = (1 << 8); /* Refresh enabled at 15.6us */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001288
Angel Pons1d4044a2021-03-27 19:11:51 +01001289 mchbar_clrbits32(C0DRC0, 7 << 8);
1290 mchbar_setbits32(C0DRC0, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001291
Angel Pons1d4044a2021-03-27 19:11:51 +01001292 mchbar_clrbits32(C1DRC0, 7 << 8);
1293 mchbar_setbits32(C1DRC0, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001294}
1295
1296static void sdram_program_cke_tristate(struct sys_info *sysinfo)
1297{
1298 u32 reg32;
1299 int i;
1300
Angel Pons1d4044a2021-03-27 19:11:51 +01001301 reg32 = mchbar_read32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001302
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001303 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001304 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001305 reg32 |= (1 << (16 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001306 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001307
Stefan Reinauer278534d2008-10-29 04:51:07 +00001308 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001309
Stefan Reinauer278534d2008-10-29 04:51:07 +00001310 reg32 |= (1 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01001311 mchbar_write32(C0DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001312
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001313 /* Do we have to do this if we're in Single Channel Mode? */
Angel Pons1d4044a2021-03-27 19:11:51 +01001314 reg32 = mchbar_read32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001315
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001316 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001317 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001318 reg32 |= (1 << (12 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001319 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001320
Stefan Reinauer278534d2008-10-29 04:51:07 +00001321 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001322
Stefan Reinauer278534d2008-10-29 04:51:07 +00001323 reg32 |= (1 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01001324 mchbar_write32(C1DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001325}
1326
1327static void sdram_program_odt_tristate(struct sys_info *sysinfo)
1328{
1329 u32 reg32;
1330 int i;
1331
Angel Pons1d4044a2021-03-27 19:11:51 +01001332 reg32 = mchbar_read32(C0DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001333
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001334 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001335 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001336 reg32 |= (1 << (24 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001337 }
Angel Pons1d4044a2021-03-27 19:11:51 +01001338 mchbar_write32(C0DRC2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001339
Angel Pons1d4044a2021-03-27 19:11:51 +01001340 reg32 = mchbar_read32(C1DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001341
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001342 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001343 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001344 reg32 |= (1 << (20 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001345 }
Angel Pons1d4044a2021-03-27 19:11:51 +01001346 mchbar_write32(C1DRC2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001347}
1348
1349static void sdram_set_timing_and_control(struct sys_info *sysinfo)
1350{
Arthur Heymans25027232017-02-12 23:34:39 +01001351 u32 reg32, tRD_min;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001352 u32 tWTR;
1353 u32 temp_drt;
1354 int i, page_size;
1355
Edward O'Callaghan2f237c12014-05-25 06:24:39 +10001356 static const u8 cas_table[] = {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001357 2, 1, 0, 3
1358 };
1359
Angel Pons1d4044a2021-03-27 19:11:51 +01001360 reg32 = mchbar_read32(C0DRC0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001361 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001362 reg32 &= ~((1 << 13) | (1 << 12));
Angel Pons1d4044a2021-03-27 19:11:51 +01001363 mchbar_write32(C0DRC0, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001364
Angel Pons1d4044a2021-03-27 19:11:51 +01001365 reg32 = mchbar_read32(C1DRC0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001366 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001367 reg32 &= ~((1 << 13) | (1 << 12));
Angel Pons1d4044a2021-03-27 19:11:51 +01001368 mchbar_write32(C1DRC0, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001369
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001370 if (!sysinfo->dual_channel && sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) {
Angel Pons1d4044a2021-03-27 19:11:51 +01001371 reg32 = mchbar_read32(C0DRC0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001372 reg32 |= (1 << 15);
Angel Pons1d4044a2021-03-27 19:11:51 +01001373 mchbar_write32(C0DRC0, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001374 }
1375
1376 sdram_program_refresh_rate(sysinfo);
1377
1378 sdram_program_cke_tristate(sysinfo);
1379
1380 sdram_program_odt_tristate(sysinfo);
1381
1382 /* Calculate DRT0 */
1383
1384 temp_drt = 0;
1385
1386 /* B2B Write Precharge (same bank) = CL-1 + BL/2 + tWR */
1387 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + sysinfo->twr;
1388 temp_drt |= (reg32 << 28);
1389
1390 /* Write Auto Precharge (same bank) = CL-1 + BL/2 + tWR + tRP */
1391 reg32 += sysinfo->trp;
1392 temp_drt |= (reg32 << 4);
1393
Arthur Heymans70a8e342017-03-09 11:30:23 +01001394 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001395 tWTR = 3; /* 667MHz */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001396 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001397 tWTR = 2; /* 400 and 533 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001398
1399 /* B2B Write to Read Command Spacing */
1400 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + tWTR;
1401 temp_drt |= (reg32 << 24);
1402
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001403 /* CxDRT0 [23:22], [21:20], [19:18] [16] have fixed values */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001404 temp_drt |= ((1 << 22) | (3 << 20) | (1 << 18) | (0 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001405
Arthur Heymans25027232017-02-12 23:34:39 +01001406 /*
1407 * tRD is the delay the memory controller is waiting on the FSB,
1408 * in mclk domain.
1409 * This parameter is important for stability and performance.
1410 * Those values might not be optimal but seem stable.
1411 */
1412 tRD_min = sysinfo->cas;
Arthur Heymanse1897612016-10-15 23:29:18 +02001413 switch (sysinfo->fsb_frequency) {
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001414 case 533:
Arthur Heymanse1897612016-10-15 23:29:18 +02001415 break;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001416 case 667:
1417 tRD_min += 1;
Arthur Heymanse1897612016-10-15 23:29:18 +02001418 break;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001419 case 800:
1420 tRD_min += 2;
1421 break;
1422 case 1066:
1423 tRD_min += 3;
Arthur Heymanse1897612016-10-15 23:29:18 +02001424 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001425 }
Arthur Heymanse1897612016-10-15 23:29:18 +02001426
Arthur Heymans25027232017-02-12 23:34:39 +01001427 temp_drt |= (tRD_min << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001428
1429 /* Read Auto Precharge to Activate */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001430
Stefan Reinauer278534d2008-10-29 04:51:07 +00001431 temp_drt |= (8 << 0);
1432
Angel Pons1d4044a2021-03-27 19:11:51 +01001433 mchbar_write32(C0DRT0, temp_drt);
1434 mchbar_write32(C1DRT0, temp_drt);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001435
1436 /* Calculate DRT1 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001437
Angel Pons1d4044a2021-03-27 19:11:51 +01001438 temp_drt = mchbar_read32(C0DRT1) & 0x00020088;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001439
1440 /* DRAM RASB Precharge */
1441 temp_drt |= (sysinfo->trp - 2) << 0;
1442
1443 /* DRAM RASB to CASB Delay */
1444 temp_drt |= (sysinfo->trcd - 2) << 4;
1445
1446 /* CASB Latency */
1447 temp_drt |= (cas_table[sysinfo->cas - 3]) << 8;
1448
1449 /* Refresh Cycle Time */
1450 temp_drt |= (sysinfo->trfc) << 10;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001451
Stefan Reinauer278534d2008-10-29 04:51:07 +00001452 /* Pre-All to Activate Delay */
1453 temp_drt |= (0 << 16);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001454
Stefan Reinauer278534d2008-10-29 04:51:07 +00001455 /* Precharge to Precharge Delay stays at 1 clock */
1456 temp_drt |= (0 << 18);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001457
Stefan Reinauer278534d2008-10-29 04:51:07 +00001458 /* Activate to Precharge Delay */
1459 temp_drt |= (sysinfo->tras << 19);
1460
1461 /* Read to Precharge (tRTP) */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001462 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001463 temp_drt |= (1 << 28);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001464 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001465 temp_drt |= (0 << 28);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001466
1467 /* Determine page size */
1468 reg32 = 0;
1469 page_size = 1; /* Default: 1k pagesize */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001470 for (i = 0; i < 2*DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001471 if (sysinfo->dimm[i] == SYSINFO_DIMM_X16DS ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001472 sysinfo->dimm[i] == SYSINFO_DIMM_X16SS)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001473 page_size = 2; /* 2k pagesize */
1474 }
1475
Arthur Heymans70a8e342017-03-09 11:30:23 +01001476 if (sysinfo->memory_frequency == 533 && page_size == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001477 reg32 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001478 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001479 reg32 = page_size;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001480
Stefan Reinauer278534d2008-10-29 04:51:07 +00001481 temp_drt |= (reg32 << 30);
1482
Angel Pons1d4044a2021-03-27 19:11:51 +01001483 mchbar_write32(C0DRT1, temp_drt);
1484 mchbar_write32(C1DRT1, temp_drt);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001485
1486 /* Program DRT2 */
Angel Pons1d4044a2021-03-27 19:11:51 +01001487 reg32 = mchbar_read32(C0DRT2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001488 reg32 &= ~(1 << 8);
Angel Pons1d4044a2021-03-27 19:11:51 +01001489 mchbar_write32(C0DRT2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001490
Angel Pons1d4044a2021-03-27 19:11:51 +01001491 reg32 = mchbar_read32(C1DRT2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001492 reg32 &= ~(1 << 8);
Angel Pons1d4044a2021-03-27 19:11:51 +01001493 mchbar_write32(C1DRT2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001494
1495 /* Calculate DRT3 */
Angel Pons1d4044a2021-03-27 19:11:51 +01001496 temp_drt = mchbar_read32(C0DRT3) & ~0x07ffffff;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001497
1498 /* Get old tRFC value */
Angel Pons1d4044a2021-03-27 19:11:51 +01001499 reg32 = mchbar_read32(C0DRT1) >> 10;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001500 reg32 &= 0x3f;
1501
1502 /* 788nS - tRFC */
1503 switch (sysinfo->memory_frequency) {
1504 case 400: /* 5nS */
1505 reg32 = ((78800 / 500) - reg32) & 0x1ff;
1506 reg32 |= (0x8c << 16) | (0x0c << 10); /* 1 us */
1507 break;
1508 case 533: /* 3.75nS */
1509 reg32 = ((78800 / 375) - reg32) & 0x1ff;
1510 reg32 |= (0xba << 16) | (0x10 << 10); /* 1 us */
1511 break;
1512 case 667: /* 3nS */
1513 reg32 = ((78800 / 300) - reg32) & 0x1ff;
1514 reg32 |= (0xe9 << 16) | (0x14 << 10); /* 1 us */
1515 break;
1516 }
1517
1518 temp_drt |= reg32;
1519
Angel Pons1d4044a2021-03-27 19:11:51 +01001520 mchbar_write32(C0DRT3, temp_drt);
1521 mchbar_write32(C1DRT3, temp_drt);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001522}
1523
1524static void sdram_set_channel_mode(struct sys_info *sysinfo)
1525{
1526 u32 reg32;
1527
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001528 printk(BIOS_DEBUG, "Setting mode of operation for memory channels...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001529
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001530 if (sdram_capabilities_interleave() &&
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001531 ((sysinfo->banksize[0] + sysinfo->banksize[1] +
1532 sysinfo->banksize[2] + sysinfo->banksize[3]) ==
1533 (sysinfo->banksize[4] + sysinfo->banksize[5] +
1534 sysinfo->banksize[6] + sysinfo->banksize[7]))) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001535 /* Both channels equipped with DIMMs of the same size */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001536 sysinfo->interleaved = 1;
1537 } else {
1538 sysinfo->interleaved = 0;
1539 }
1540
Angel Pons1d4044a2021-03-27 19:11:51 +01001541 reg32 = mchbar_read32(DCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001542 reg32 &= ~(7 << 0);
1543
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001544 if (sysinfo->interleaved) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001545 /* Dual Channel Interleaved */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001546 printk(BIOS_DEBUG, "Dual Channel Interleaved.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001547 reg32 |= (1 << 1);
1548 } else if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001549 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001550 /* Channel 1 only */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001551 printk(BIOS_DEBUG, "Single Channel 1 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001552 reg32 |= (1 << 2);
Elyes HAOUAS75da1fb2017-02-16 18:59:13 +01001553 } else if (sdram_capabilities_dual_channel() &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001554 (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1555 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) {
Martin Roth128c1042016-11-18 09:29:03 -07001556 /* Dual Channel Asymmetric */
1557 printk(BIOS_DEBUG, "Dual Channel Asymmetric.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001558 reg32 |= (1 << 0);
1559 } else {
1560 /* All bits 0 means Single Channel 0 operation */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001561 printk(BIOS_DEBUG, "Single Channel 0 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001562 }
1563
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001564 /* Now disable channel XORing */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001565 reg32 |= (1 << 10);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001566
Angel Pons1d4044a2021-03-27 19:11:51 +01001567 mchbar_write32(DCC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001568
Angel Pons1d4044a2021-03-27 19:11:51 +01001569 PRINTK_DEBUG("DCC = 0x%08x\n", mchbar_read32(DCC));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001570}
1571
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001572static void sdram_program_pll_settings(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001573{
Angel Pons1d4044a2021-03-27 19:11:51 +01001574 mchbar_write32(PLLMON, 0x80800000);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001575
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001576 sysinfo->fsb_frequency = fsbclk();
Peter Stuge76d91432010-10-01 10:02:33 +00001577 if (sysinfo->fsb_frequency == 0xffff)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001578 die("Unsupported FSB speed");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001579
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001580 /* Program CPCTL according to FSB speed */
1581 /* Only write the lower byte */
1582 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001583 case 400:
Angel Pons1d4044a2021-03-27 19:11:51 +01001584 mchbar_write8(CPCTL, 0x90);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001585 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001586 case 533:
Angel Pons1d4044a2021-03-27 19:11:51 +01001587 mchbar_write8(CPCTL, 0x95);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001588 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001589 case 667:
Angel Pons1d4044a2021-03-27 19:11:51 +01001590 mchbar_write8(CPCTL, 0x8d);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001591 break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001592 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001593
Angel Pons1d4044a2021-03-27 19:11:51 +01001594 mchbar_clrbits16(CPCTL, 1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001595
Angel Pons1d4044a2021-03-27 19:11:51 +01001596 mchbar_read16(CPCTL); /* Read back register to activate settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001597}
1598
1599static void sdram_program_graphics_frequency(struct sys_info *sysinfo)
1600{
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001601 u8 reg8;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001602 u8 freq, second_vco, voltage;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001603
1604#define CRCLK_166MHz 0x00
1605#define CRCLK_200MHz 0x01
1606#define CRCLK_250MHz 0x03
1607#define CRCLK_400MHz 0x05
1608
1609#define CDCLK_200MHz 0x00
1610#define CDCLK_320MHz 0x40
1611
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001612#define VOLTAGE_1_05 0x00
1613#define VOLTAGE_1_50 0x01
1614
Paul Menzeldaf9e502014-07-15 23:49:16 +02001615 printk(BIOS_DEBUG, "Setting Graphics Frequency...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001616
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001617 printk(BIOS_DEBUG, "FSB: %d MHz ", sysinfo->fsb_frequency);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001618
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001619 voltage = VOLTAGE_1_05;
Angel Pons1d4044a2021-03-27 19:11:51 +01001620 if (mchbar_read32(DFT_STRAP1) & (1 << 20))
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001621 voltage = VOLTAGE_1_50;
Angel Pons30492572020-06-11 13:24:54 +02001622 printk(BIOS_DEBUG, "Voltage: %s ", (voltage == VOLTAGE_1_05) ? "1.05V" : "1.5V");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001623
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001624 /* Gate graphics hardware for frequency change */
Angel Pons30492572020-06-11 13:24:54 +02001625 reg8 = (1 << 3) | (1 << 1); /* disable crclk, gate cdclk */
Angel Pons3580d812020-06-11 14:13:33 +02001626 pci_write_config8(IGD_DEV, GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001627
1628 /* Get graphics frequency capabilities */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001629 reg8 = sdram_capabilities_core_frequencies();
1630
Stefan Reinauer278534d2008-10-29 04:51:07 +00001631 freq = CRCLK_250MHz;
1632 switch (reg8) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001633 case GFX_FREQUENCY_CAP_ALL:
1634 if (voltage == VOLTAGE_1_05)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001635 freq = CRCLK_250MHz;
1636 else
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001637 freq = CRCLK_400MHz; /* 1.5V requires 400MHz */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001638 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001639 case GFX_FREQUENCY_CAP_250MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001640 freq = CRCLK_250MHz;
1641 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001642 case GFX_FREQUENCY_CAP_200MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001643 freq = CRCLK_200MHz;
1644 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001645 case GFX_FREQUENCY_CAP_166MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001646 freq = CRCLK_166MHz;
1647 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001648 }
1649
1650 if (freq != CRCLK_400MHz) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001651 /* What chipset are we? Force 166MHz for GMS */
Angel Pons3580d812020-06-11 14:13:33 +02001652 reg8 = (pci_read_config8(HOST_BRIDGE, 0xe7) & 0x70) >> 4;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001653 if (reg8 == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001654 freq = CRCLK_166MHz;
1655 }
1656
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001657 printk(BIOS_DEBUG, "Render: ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001658 switch (freq) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001659 case CRCLK_166MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001660 printk(BIOS_DEBUG, "166MHz");
1661 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001662 case CRCLK_200MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001663 printk(BIOS_DEBUG, "200MHz");
1664 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001665 case CRCLK_250MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001666 printk(BIOS_DEBUG, "250MHz");
1667 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001668 case CRCLK_400MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001669 printk(BIOS_DEBUG, "400MHz");
1670 break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001671 }
1672
Arthur Heymans70a8e342017-03-09 11:30:23 +01001673 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001674 sysinfo->mvco4x = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001675 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001676 sysinfo->mvco4x = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001677
Stefan Reinauer278534d2008-10-29 04:51:07 +00001678 second_vco = 0;
1679
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001680 if (voltage == VOLTAGE_1_50) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001681 second_vco = 1;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001682 } else if ((i945_silicon_revision() > 0) && (freq == CRCLK_250MHz)) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001683 u16 mem = sysinfo->memory_frequency;
1684 u16 fsb = sysinfo->fsb_frequency;
1685
Arthur Heymans70a8e342017-03-09 11:30:23 +01001686 if ((fsb == 667 && mem == 533) ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001687 (fsb == 533 && mem == 533) ||
1688 (fsb == 533 && mem == 400)) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001689 second_vco = 1;
1690 }
1691
1692 if (fsb == 667 && mem == 533)
1693 sysinfo->mvco4x = 1;
1694 }
1695
Arthur Heymans70a8e342017-03-09 11:30:23 +01001696 if (second_vco)
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001697 sysinfo->clkcfg_bit7 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001698 else
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001699 sysinfo->clkcfg_bit7 = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001700
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001701 /* Graphics Core Render Clock */
Angel Pons3580d812020-06-11 14:13:33 +02001702 pci_update_config16(IGD_DEV, GCFC, ~((7 << 0) | (1 << 13)), freq);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001703
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001704 /* Graphics Core Display Clock */
Angel Pons3580d812020-06-11 14:13:33 +02001705 reg8 = pci_read_config8(IGD_DEV, GCFC);
Angel Ponse3c68d22020-06-08 12:09:03 +02001706 reg8 &= ~((1 << 7) | (7 << 4));
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001707
1708 if (voltage == VOLTAGE_1_05) {
1709 reg8 |= CDCLK_200MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001710 printk(BIOS_DEBUG, " Display: 200MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001711 } else {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001712 reg8 |= CDCLK_320MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001713 printk(BIOS_DEBUG, " Display: 320MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001714 }
Angel Pons3580d812020-06-11 14:13:33 +02001715 pci_write_config8(IGD_DEV, GCFC, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001716
Angel Pons3580d812020-06-11 14:13:33 +02001717 reg8 = pci_read_config8(IGD_DEV, GCFC + 1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001718
Angel Ponse3c68d22020-06-08 12:09:03 +02001719 reg8 |= (1 << 3) | (1 << 1);
Angel Pons3580d812020-06-11 14:13:33 +02001720 pci_write_config8(IGD_DEV, GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001721
1722 reg8 |= 0x0f;
Angel Pons3580d812020-06-11 14:13:33 +02001723 pci_write_config8(IGD_DEV, GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001724
1725 /* Ungate core render and display clocks */
1726 reg8 &= 0xf0;
Angel Pons3580d812020-06-11 14:13:33 +02001727 pci_write_config8(IGD_DEV, GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001728}
1729
1730static void sdram_program_memory_frequency(struct sys_info *sysinfo)
1731{
1732 u32 clkcfg;
Julius Wernercd49cce2019-03-05 16:53:33 -08001733 u8 offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001734
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001735 printk(BIOS_DEBUG, "Setting Memory Frequency... ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001736
Angel Pons1d4044a2021-03-27 19:11:51 +01001737 clkcfg = mchbar_read32(CLKCFG);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001738
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001739 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001740
Arthur Heymans70a8e342017-03-09 11:30:23 +01001741 clkcfg &= ~((1 << 12) | (1 << 7) | (7 << 4));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001742
1743 if (sysinfo->mvco4x) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001744 printk(BIOS_DEBUG, "MVCO 4x, ");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001745 clkcfg &= ~(1 << 12);
1746 }
1747
1748 if (sysinfo->clkcfg_bit7) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001749 printk(BIOS_DEBUG, "second VCO, ");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001750 clkcfg |= (1 << 7);
1751 }
1752
1753 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001754 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001755 clkcfg |= ((1 + offset) << 4);
1756 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001757 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001758 clkcfg |= ((2 + offset) << 4);
1759 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001760 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001761 clkcfg |= ((3 + offset) << 4);
1762 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001763 default:
1764 die("Target Memory Frequency Error");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001765 }
1766
Angel Pons1d4044a2021-03-27 19:11:51 +01001767 if (mchbar_read32(CLKCFG) == clkcfg) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001768 printk(BIOS_DEBUG, "ok (unchanged)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001769 return;
1770 }
1771
Angel Pons1d4044a2021-03-27 19:11:51 +01001772 mchbar_write32(CLKCFG, clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001773
Petr Cveke75bb012022-06-16 17:13:22 +02001774 /*
1775 * Make sure the following code is in the cache before we execute it.
1776 * TODO: Experiments (i945GM) without any cache_code/delay_update
1777 * _seem_ to work even when XIP is disabled. Also on Pentium 4
1778 * the code is not cached at all by default.
1779 */
1780 asm volatile (
1781 " jmp cache_code\n"
1782 "vco_update:\n"
1783 : /* No outputs */
1784 : /* No inputs */
1785 : "memory"
1786 );
1787
Angel Ponse3c68d22020-06-08 12:09:03 +02001788 pci_and_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, (u8)~(1 << 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001789
Stefan Reinauer278534d2008-10-29 04:51:07 +00001790 clkcfg &= ~(1 << 10);
Angel Pons1d4044a2021-03-27 19:11:51 +01001791 mchbar_write32(CLKCFG, clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001792 clkcfg |= (1 << 10);
Angel Pons1d4044a2021-03-27 19:11:51 +01001793 mchbar_write32(CLKCFG, clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001794
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001795 asm volatile (
Stefan Reinauer278534d2008-10-29 04:51:07 +00001796 " movl $0x100, %%ecx\n"
1797 "delay_update:\n"
1798 " nop\n"
1799 " nop\n"
1800 " nop\n"
1801 " nop\n"
1802 " loop delay_update\n"
1803 : /* No outputs */
1804 : /* No inputs */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001805 : "%ecx", "memory"
Stefan Reinauer278534d2008-10-29 04:51:07 +00001806 );
1807
Stefan Reinauer278534d2008-10-29 04:51:07 +00001808 clkcfg &= ~(1 << 10);
Angel Pons1d4044a2021-03-27 19:11:51 +01001809 mchbar_write32(CLKCFG, clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001810
Petr Cveke75bb012022-06-16 17:13:22 +02001811 asm volatile (
1812 " jmp out\n"
1813 "cache_code:\n"
1814 " jmp vco_update\n"
1815 "out:\n"
1816 : /* No outputs */
1817 : /* No inputs */
1818 : "memory"
1819 );
Stefan Reinauer278534d2008-10-29 04:51:07 +00001820
Angel Pons1d4044a2021-03-27 19:11:51 +01001821 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", mchbar_read32(CLKCFG));
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001822 printk(BIOS_DEBUG, "ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001823}
1824
1825static void sdram_program_clock_crossing(void)
1826{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001827 int idx = 0;
1828
1829 /**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001830 * We add the indices according to our clocks from CLKCFG.
Stefan Reinauer278534d2008-10-29 04:51:07 +00001831 */
Julius Wernercd49cce2019-03-05 16:53:33 -08001832#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001833 static const u32 data_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001834 0x00100401, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001835 0xffffffff, 0xffffffff, /* nonexistent */
1836 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001837
Stefan Reinauer278534d2008-10-29 04:51:07 +00001838 0x08040120, 0x00000000, /* DDR400 FSB533 */
1839 0x00100401, 0x00000000, /* DDR533 FSB533 */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001840 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001841
1842 0x04020120, 0x00000010, /* DDR400 FSB667 */
1843 0x10040280, 0x00000040, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001844 0x00100401, 0x00000000, /* DDR667 FSB667 */
1845
Martin Roth2ed0aa22016-01-05 20:58:58 -07001846 0xffffffff, 0xffffffff, /* nonexistent */
1847 0xffffffff, 0xffffffff, /* nonexistent */
1848 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001849
Martin Roth2ed0aa22016-01-05 20:58:58 -07001850 0xffffffff, 0xffffffff, /* nonexistent */
1851 0xffffffff, 0xffffffff, /* nonexistent */
1852 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001853 };
1854
1855 static const u32 command_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001856 0x04020208, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001857 0xffffffff, 0xffffffff, /* nonexistent */
1858 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001859
Stefan Reinauer278534d2008-10-29 04:51:07 +00001860 0x00060108, 0x00000000, /* DDR400 FSB533 */
1861 0x04020108, 0x00000000, /* DDR533 FSB533 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001862 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001863
1864 0x00040318, 0x00000000, /* DDR400 FSB667 */
1865 0x04020118, 0x00000000, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001866 0x02010804, 0x00000000, /* DDR667 FSB667 */
1867
Martin Roth2ed0aa22016-01-05 20:58:58 -07001868 0xffffffff, 0xffffffff, /* nonexistent */
1869 0xffffffff, 0xffffffff, /* nonexistent */
1870 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001871
Martin Roth2ed0aa22016-01-05 20:58:58 -07001872 0xffffffff, 0xffffffff, /* nonexistent */
1873 0xffffffff, 0xffffffff, /* nonexistent */
1874 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001875 };
1876
Julius Wernercd49cce2019-03-05 16:53:33 -08001877#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001878 /* i945 G/P */
1879 static const u32 data_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001880 0xffffffff, 0xffffffff, /* nonexistent */
1881 0xffffffff, 0xffffffff, /* nonexistent */
1882 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001883
1884 0x10080201, 0x00000000, /* DDR400 FSB533 */
1885 0x00100401, 0x00000000, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001886 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001887
Martin Roth2ed0aa22016-01-05 20:58:58 -07001888 0xffffffff, 0xffffffff, /* nonexistent */
1889 0xffffffff, 0xffffffff, /* nonexistent */
1890 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001891
1892 0x04020108, 0x00000000, /* DDR400 FSB800 */
1893 0x00020108, 0x00000000, /* DDR533 FSB800 */
1894 0x00080201, 0x00000000, /* DDR667 FSB800 */
1895
1896 0x00010402, 0x00000000, /* DDR400 FSB1066 */
1897 0x04020108, 0x00000000, /* DDR533 FSB1066 */
1898 0x08040110, 0x00000000, /* DDR667 FSB1066 */
1899 };
1900
1901 static const u32 command_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001902 0xffffffff, 0xffffffff, /* nonexistent */
1903 0xffffffff, 0xffffffff, /* nonexistent */
1904 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001905
1906 0x00010800, 0x00000402, /* DDR400 FSB533 */
1907 0x01000400, 0x00000200, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001908 0x00020904, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001909
Martin Roth2ed0aa22016-01-05 20:58:58 -07001910 0xffffffff, 0xffffffff, /* nonexistent */
1911 0xffffffff, 0xffffffff, /* nonexistent */
1912 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001913
1914 0x02010804, 0x00000000, /* DDR400 FSB800 */
1915 0x00010402, 0x00000000, /* DDR533 FSB800 */
Arthur Heymans8b6df622016-10-16 10:58:01 +02001916 0x04020130, 0x00000008, /* DDR667 FSB800 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001917
1918 0x00020904, 0x00000000, /* DDR400 FSB1066 */
1919 0x02010804, 0x00000000, /* DDR533 FSB1066 */
1920 0x180601c0, 0x00000020, /* DDR667 FSB1066 */
1921 };
1922#endif
1923
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001924 printk(BIOS_DEBUG, "Programming Clock Crossing...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001925
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001926 printk(BIOS_DEBUG, "MEM=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001927 switch (memclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001928 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001929 printk(BIOS_DEBUG, "400");
1930 idx += 0;
1931 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001932 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001933 printk(BIOS_DEBUG, "533");
1934 idx += 2;
1935 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001936 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001937 printk(BIOS_DEBUG, "667");
1938 idx += 4;
1939 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001940 default:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001941 printk(BIOS_DEBUG, "RSVD %x", memclk());
1942 return;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001943 }
1944
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001945 printk(BIOS_DEBUG, " FSB=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001946 switch (fsbclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001947 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001948 printk(BIOS_DEBUG, "400");
1949 idx += 0;
1950 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001951 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001952 printk(BIOS_DEBUG, "533");
1953 idx += 6;
1954 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001955 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001956 printk(BIOS_DEBUG, "667");
1957 idx += 12;
1958 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001959 case 800:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001960 printk(BIOS_DEBUG, "800");
1961 idx += 18;
1962 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001963 case 1066:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001964 printk(BIOS_DEBUG, "1066");
1965 idx += 24;
1966 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001967 default:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001968 printk(BIOS_DEBUG, "RSVD %x\n", fsbclk());
1969 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
Angel Pons1d4044a2021-03-27 19:11:51 +01001975 mchbar_write32(CCCFT + 0, command_clock_crossing[idx]);
1976 mchbar_write32(CCCFT + 4, command_clock_crossing[idx + 1]);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001977
Angel Pons1d4044a2021-03-27 19:11:51 +01001978 mchbar_write32(C0DCCFT + 0, data_clock_crossing[idx]);
1979 mchbar_write32(C0DCCFT + 4, data_clock_crossing[idx + 1]);
1980 mchbar_write32(C1DCCFT + 0, data_clock_crossing[idx]);
1981 mchbar_write32(C1DCCFT + 4, data_clock_crossing[idx + 1]);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001982
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
Angel Pons1d4044a2021-03-27 19:11:51 +01001990 reg32 = mchbar_read32(FSBPMC3);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001991 reg32 |= (1 << 1);
Angel Pons1d4044a2021-03-27 19:11:51 +01001992 mchbar_write32(FSBPMC3, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001993
Angel Pons1d4044a2021-03-27 19:11:51 +01001994 reg32 = mchbar_read32(SBTEST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001995 reg32 |= (3 << 1);
Angel Pons1d4044a2021-03-27 19:11:51 +01001996 mchbar_write32(SBTEST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001997}
1998
1999static void sdram_pre_jedec_initialization(void)
2000{
2001 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002002
Angel Pons1d4044a2021-03-27 19:11:51 +01002003 reg32 = mchbar_read32(WCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002004 reg32 &= 0x113ff3ff;
2005 reg32 |= (4 << 29) | (3 << 25) | (1 << 10);
Angel Pons1d4044a2021-03-27 19:11:51 +01002006 mchbar_write32(WCC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002007
Angel Pons1d4044a2021-03-27 19:11:51 +01002008 mchbar_setbits32(SMVREFC, 1 << 6);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002009
Angel Pons1d4044a2021-03-27 19:11:51 +01002010 mchbar_clrbits32(MMARB0, 3 << 17);
2011 mchbar_setbits32(MMARB0, 1 << 21 | 1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002012
Angel Pons1d4044a2021-03-27 19:11:51 +01002013 mchbar_clrbits32(MMARB1, 7 << 8);
2014 mchbar_setbits32(MMARB1, 3 << 8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002015
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002016 /* Adaptive Idle Timer Control */
Angel Pons1d4044a2021-03-27 19:11:51 +01002017 mchbar_write32(C0AIT + 0, 0x000006c4);
2018 mchbar_write32(C0AIT + 4, 0x871a066d);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002019
Angel Pons1d4044a2021-03-27 19:11:51 +01002020 mchbar_write32(C1AIT + 0, 0x000006c4);
2021 mchbar_write32(C1AIT + 4, 0x871a066d);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002022}
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;
Paul Menzeld789b6582020-03-14 11:50:34 +01002036 bool chan0_dualsided, chan1_dualsided, chan0_populated, chan1_populated;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002037
Paul Menzel842dd332020-03-14 10:37:40 +01002038 chan0_populated = (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002039 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED);
Elyes HAOUAS308aeff2017-02-24 12:53:07 +01002040 chan1_populated = (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002041 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
Angel Pons1d4044a2021-03-27 19:11:51 +01002101 mchbar_clrbits32(C0DRC1, 0xff << 24);
2102 mchbar_setbits32(C0DRC1, chan0);
2103 mchbar_clrbits32(C1DRC1, 0xff << 24);
2104 mchbar_setbits32(C1DRC1, chan1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002105}
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) {
Angel Pons1d4044a2021-03-27 19:11:51 +01002113 reg32 = mchbar_read32(DCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002114 reg32 &= ~(1 << 10);
Stefan Reinauer30140a52009-03-11 16:20:39 +00002115 reg32 |= (1 << 9);
Angel Pons1d4044a2021-03-27 19:11:51 +01002116 mchbar_write32(DCC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002117 }
2118
2119 /* DRAM mode optimizations */
2120 sdram_enhanced_addressing_mode(sysinfo);
2121
Angel Pons1d4044a2021-03-27 19:11:51 +01002122 reg32 = mchbar_read32(FSBPMC3);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002123 reg32 &= ~(1 << 1);
Angel Pons1d4044a2021-03-27 19:11:51 +01002124 mchbar_write32(FSBPMC3, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002125
Angel Pons1d4044a2021-03-27 19:11:51 +01002126 reg32 = mchbar_read32(SBTEST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002127 reg32 &= ~(1 << 2);
Angel Pons1d4044a2021-03-27 19:11:51 +01002128 mchbar_write32(SBTEST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002129
Angel Pons1d4044a2021-03-27 19:11:51 +01002130 reg32 = mchbar_read32(SBOCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002131 reg32 &= 0xffbdb6ff;
2132 reg32 |= (0xbdb6 << 8) | (1 << 0);
Angel Pons1d4044a2021-03-27 19:11:51 +01002133 mchbar_write32(SBOCC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002134}
2135
2136static void sdram_power_management(struct sys_info *sysinfo)
2137{
Stefan Reinauer278534d2008-10-29 04:51:07 +00002138 u16 reg16;
2139 u32 reg32;
Elyes HAOUAS187bec72021-12-12 07:00:50 +01002140 bool integrated_graphics = true;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002141 int i;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002142
Elyes HAOUAS8f20b122021-02-14 13:22:10 +01002143 if (!(pci_read_config8(HOST_BRIDGE, DEVEN) & (DEVEN_D2F0 | DEVEN_D2F1)))
2144 integrated_graphics = false;
2145
Angel Pons1d4044a2021-03-27 19:11:51 +01002146 reg32 = mchbar_read32(C0DRT2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002147 reg32 &= 0xffffff00;
2148 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002149 reg32 |= (1 << 5) | (1 << 4);
Angel Pons1d4044a2021-03-27 19:11:51 +01002150 mchbar_write32(C0DRT2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002151
Angel Pons1d4044a2021-03-27 19:11:51 +01002152 reg32 = mchbar_read32(C1DRT2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002153 reg32 &= 0xffffff00;
2154 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002155 reg32 |= (1 << 5) | (1 << 4);
Angel Pons1d4044a2021-03-27 19:11:51 +01002156 mchbar_write32(C1DRT2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002157
Angel Pons1d4044a2021-03-27 19:11:51 +01002158 reg32 = mchbar_read32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002159
2160 reg32 |= (1 << 12) | (1 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01002161 mchbar_write32(C0DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002162
Angel Pons1d4044a2021-03-27 19:11:51 +01002163 reg32 = mchbar_read32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002164
2165 reg32 |= (1 << 12) | (1 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01002166 mchbar_write32(C1DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002167
Julius Wernercd49cce2019-03-05 16:53:33 -08002168 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002169 if (i945_silicon_revision() > 1) {
2170 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2171 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002172
Angel Pons1d4044a2021-03-27 19:11:51 +01002173 mchbar_write16(UPMC1, 0x1010 | peg_bits);
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002174 } else {
2175 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2176 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002177
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002178 /* Rev 0 and 1 */
Angel Pons1d4044a2021-03-27 19:11:51 +01002179 mchbar_write16(UPMC1, 0x0010 | peg_bits);
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002180 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002181 }
2182
Angel Pons1d4044a2021-03-27 19:11:51 +01002183 reg16 = mchbar_read16(UPMC2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002184 reg16 &= 0xfc00;
2185 reg16 |= 0x0100;
Angel Pons1d4044a2021-03-27 19:11:51 +01002186 mchbar_write16(UPMC2, reg16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002187
Angel Pons1d4044a2021-03-27 19:11:51 +01002188 mchbar_write32(UPMC3, 0x000f06ff);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002189
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002190 for (i = 0; i < 5; i++) {
Angel Pons1d4044a2021-03-27 19:11:51 +01002191 mchbar_clrbits32(UPMC3, 1 << 16);
2192 mchbar_setbits32(UPMC3, 1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002193 }
2194
Angel Pons1d4044a2021-03-27 19:11:51 +01002195 mchbar_write32(GIPMC1, 0x8000000c);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002196
Angel Pons1d4044a2021-03-27 19:11:51 +01002197 reg16 = mchbar_read16(CPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002198 reg16 &= ~(7 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002199 if (i945_silicon_revision() > 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002200 reg16 |= (6 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002201 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002202 reg16 |= (4 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01002203 mchbar_write16(CPCTL, reg16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002204
Angel Pons3580d812020-06-11 14:13:33 +02002205#if 0
Angel Pons1d4044a2021-03-27 19:11:51 +01002206 if ((mchbar_read32(ECO) & (1 << 16)) != 0) {
Angel Pons3580d812020-06-11 14:13:33 +02002207#else
Stefan Reinauer30140a52009-03-11 16:20:39 +00002208 if (i945_silicon_revision() != 0) {
Angel Pons3580d812020-06-11 14:13:33 +02002209#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002210 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002211 case 667:
Angel Pons1d4044a2021-03-27 19:11:51 +01002212 mchbar_write32(HGIPMC2, 0x0d590d59);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002213 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002214 case 533:
Angel Pons1d4044a2021-03-27 19:11:51 +01002215 mchbar_write32(HGIPMC2, 0x155b155b);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002216 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002217 }
2218 } else {
2219 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002220 case 667:
Angel Pons1d4044a2021-03-27 19:11:51 +01002221 mchbar_write32(HGIPMC2, 0x09c409c4);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002222 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002223 case 533:
Angel Pons1d4044a2021-03-27 19:11:51 +01002224 mchbar_write32(HGIPMC2, 0x0fa00fa0);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002225 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002226 }
2227 }
2228
Angel Pons1d4044a2021-03-27 19:11:51 +01002229 mchbar_write32(FSBPMC1, 0x8000000c);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002230
Angel Pons1d4044a2021-03-27 19:11:51 +01002231 reg32 = mchbar_read32(C2C3TT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002232 reg32 &= 0xffff0000;
2233 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002234 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002235 reg32 |= 0x0600;
2236 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002237 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002238 reg32 |= 0x0480;
2239 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002240 }
Angel Pons1d4044a2021-03-27 19:11:51 +01002241 mchbar_write32(C2C3TT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002242
Angel Pons1d4044a2021-03-27 19:11:51 +01002243 reg32 = mchbar_read32(C3C4TT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002244 reg32 &= 0xffff0000;
2245 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002246 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002247 reg32 |= 0x0b80;
2248 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002249 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002250 reg32 |= 0x0980;
2251 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002252 }
Angel Pons1d4044a2021-03-27 19:11:51 +01002253 mchbar_write32(C3C4TT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002254
Arthur Heymans70a8e342017-03-09 11:30:23 +01002255 if (i945_silicon_revision() == 0)
Angel Pons1d4044a2021-03-27 19:11:51 +01002256 mchbar_clrbits32(ECO, 1 << 16);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002257 else
Angel Pons1d4044a2021-03-27 19:11:51 +01002258 mchbar_setbits32(ECO, 1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002259
Angel Pons1d4044a2021-03-27 19:11:51 +01002260 mchbar_clrbits32(FSBPMC3, 1 << 29);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002261
Angel Pons1d4044a2021-03-27 19:11:51 +01002262 mchbar_setbits32(FSBPMC3, 1 << 21);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002263
Angel Pons1d4044a2021-03-27 19:11:51 +01002264 mchbar_clrbits32(FSBPMC3, 1 << 19);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002265
Angel Pons1d4044a2021-03-27 19:11:51 +01002266 mchbar_clrbits32(FSBPMC3, 1 << 13);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002267
Angel Pons1d4044a2021-03-27 19:11:51 +01002268 reg32 = mchbar_read32(FSBPMC4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002269 reg32 &= ~(3 << 24);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002270 reg32 |= (2 << 24);
Angel Pons1d4044a2021-03-27 19:11:51 +01002271 mchbar_write32(FSBPMC4, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002272
Angel Pons1d4044a2021-03-27 19:11:51 +01002273 mchbar_setbits32(FSBPMC4, 1 << 21);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002274
Angel Pons1d4044a2021-03-27 19:11:51 +01002275 mchbar_setbits32(FSBPMC4, 1 << 5);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002276
Arthur Heymans70a8e342017-03-09 11:30:23 +01002277 if ((i945_silicon_revision() < 2)) { /* || cpuid() = 0x6e8 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002278 /* stepping 0 and 1 or CPUID 6e8 */
Angel Pons1d4044a2021-03-27 19:11:51 +01002279 mchbar_clrbits32(FSBPMC4, 1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002280 } else {
Angel Pons1d4044a2021-03-27 19:11:51 +01002281 mchbar_setbits32(FSBPMC4, 1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002282 }
2283
Angel Pons3580d812020-06-11 14:13:33 +02002284 pci_or_config8(HOST_BRIDGE, 0xfc, 1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002285
Angel Pons3580d812020-06-11 14:13:33 +02002286 pci_or_config8(IGD_DEV, 0xc1, 1 << 2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002287
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002288 if (integrated_graphics) {
Angel Pons1d4044a2021-03-27 19:11:51 +01002289 mchbar_write16(MIPMC4, 0x04f8);
2290 mchbar_write16(MIPMC5, 0x04fc);
2291 mchbar_write16(MIPMC6, 0x04fc);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002292 } else {
Angel Pons1d4044a2021-03-27 19:11:51 +01002293 mchbar_write16(MIPMC4, 0x64f8);
2294 mchbar_write16(MIPMC5, 0x64fc);
2295 mchbar_write16(MIPMC6, 0x64fc);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002296 }
2297
Angel Pons1d4044a2021-03-27 19:11:51 +01002298 reg32 = mchbar_read32(PMCFG);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002299 reg32 &= ~(3 << 17);
2300 reg32 |= (2 << 17);
Angel Pons1d4044a2021-03-27 19:11:51 +01002301 mchbar_write32(PMCFG, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002302
Angel Pons1d4044a2021-03-27 19:11:51 +01002303 mchbar_setbits32(PMCFG, 1 << 4);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002304
Angel Pons1d4044a2021-03-27 19:11:51 +01002305 reg32 = mchbar_read32(UPMC4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002306 reg32 &= 0xffffff00;
2307 reg32 |= 0x01;
Angel Pons1d4044a2021-03-27 19:11:51 +01002308 mchbar_write32(UPMC4, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002309
Angel Pons1d4044a2021-03-27 19:11:51 +01002310 mchbar_clrbits32(0xb18, 1 << 21);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002311}
2312
2313static void sdram_thermal_management(void)
2314{
Stefan Reinauer278534d2008-10-29 04:51:07 +00002315
Angel Pons1d4044a2021-03-27 19:11:51 +01002316 mchbar_write8(TCO1, 0);
2317 mchbar_write8(TCO0, 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002318
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002319 /* The Thermal Sensors for DIMMs at 0x50, 0x52 are at I2C addr 0x30/0x32. */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002320
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002321 /* TODO This is not implemented yet. Volunteers? */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002322}
2323
2324static void sdram_save_receive_enable(void)
2325{
2326 int i;
2327 u32 reg32;
2328 u8 values[4];
2329
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002330 /* The following values are stored to an unused CMOS area and restored instead of
2331 * recalculated in case of an S3 resume.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002332 *
Arthur Heymans70a8e342017-03-09 11:30:23 +01002333 * C0WL0REOST [7:0] -> 8 bit
2334 * C1WL0REOST [7:0] -> 8 bit
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002335 * RCVENMT [11:8] [3:0] -> 8 bit
2336 * C0DRT1 [27:24] -> 4 bit
2337 * C1DRT1 [27:24] -> 4 bit
2338 */
2339
Angel Pons1d4044a2021-03-27 19:11:51 +01002340 values[0] = mchbar_read8(C0WL0REOST);
2341 values[1] = mchbar_read8(C1WL0REOST);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002342
Angel Pons1d4044a2021-03-27 19:11:51 +01002343 reg32 = mchbar_read32(RCVENMT);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002344 values[2] = (u8)((reg32 >> (8 - 4)) & 0xf0) | (reg32 & 0x0f);
2345
Angel Pons1d4044a2021-03-27 19:11:51 +01002346 reg32 = mchbar_read32(C0DRT1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002347 values[3] = (reg32 >> 24) & 0x0f;
Angel Pons1d4044a2021-03-27 19:11:51 +01002348 reg32 = mchbar_read32(C1DRT1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002349 values[3] |= (reg32 >> (24 - 4)) & 0xf0;
2350
2351 /* coreboot only uses bytes 0 - 127 for its CMOS values so far
Edwin Beasanteb50c7d2010-07-06 21:05:04 +00002352 * so we grab bytes 128 - 131 to save the receive enable values
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002353 */
2354
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002355 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002356 cmos_write(values[i], 128 + i);
2357}
2358
2359static void sdram_recover_receive_enable(void)
2360{
2361 int i;
2362 u32 reg32;
2363 u8 values[4];
2364
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002365 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002366 values[i] = cmos_read(128 + i);
2367
Angel Pons1d4044a2021-03-27 19:11:51 +01002368 mchbar_write8(C0WL0REOST, values[0]);
2369 mchbar_write8(C1WL0REOST, values[1]);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002370
Angel Pons1d4044a2021-03-27 19:11:51 +01002371 reg32 = mchbar_read32(RCVENMT);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002372 reg32 &= ~((0x0f << 8) | (0x0f << 0));
2373 reg32 |= ((u32)(values[2] & 0xf0) << (8 - 4)) | (values[2] & 0x0f);
Angel Pons1d4044a2021-03-27 19:11:51 +01002374 mchbar_write32(RCVENMT, reg32);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002375
Angel Pons1d4044a2021-03-27 19:11:51 +01002376 reg32 = mchbar_read32(C0DRT1) & ~(0x0f << 24);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002377 reg32 |= (u32)(values[3] & 0x0f) << 24;
Angel Pons1d4044a2021-03-27 19:11:51 +01002378 mchbar_write32(C0DRT1, reg32);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002379
Angel Pons1d4044a2021-03-27 19:11:51 +01002380 reg32 = mchbar_read32(C1DRT1) & ~(0x0f << 24);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002381 reg32 |= (u32)(values[3] & 0xf0) << (24 - 4);
Angel Pons1d4044a2021-03-27 19:11:51 +01002382 mchbar_write32(C1DRT1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002383}
2384
Stefan Reinauer278534d2008-10-29 04:51:07 +00002385static void sdram_program_receive_enable(struct sys_info *sysinfo)
2386{
Angel Pons1d4044a2021-03-27 19:11:51 +01002387 mchbar_setbits32(REPC, 1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002388
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002389 /* Program Receive Enable Timings */
2390 if (sysinfo->boot_path == BOOT_PATH_RESUME) {
2391 sdram_recover_receive_enable();
2392 } else {
2393 receive_enable_adjust(sysinfo);
2394 sdram_save_receive_enable();
2395 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002396
Angel Pons1d4044a2021-03-27 19:11:51 +01002397 mchbar_setbits32(C0DRC1, 1 << 6);
2398 mchbar_setbits32(C1DRC1, 1 << 6);
2399 mchbar_clrbits32(C0DRC1, 1 << 6);
2400 mchbar_clrbits32(C1DRC1, 1 << 6);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002401
Angel Pons1d4044a2021-03-27 19:11:51 +01002402 mchbar_setbits32(MIPMC3, 0x0f << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002403}
2404
2405/**
2406 * @brief Enable On-Die Termination for DDR2.
2407 *
2408 */
2409
2410static void sdram_on_die_termination(struct sys_info *sysinfo)
2411{
2412 static const u32 odt[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002413 0x00024911, 0xe0010000,
2414 0x00049211, 0xe0020000,
2415 0x0006db11, 0xe0030000,
Stefan Reinauer278534d2008-10-29 04:51:07 +00002416 };
2417
2418 u32 reg32;
2419 int cas;
2420
Angel Pons1d4044a2021-03-27 19:11:51 +01002421 reg32 = mchbar_read32(ODTC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002422 reg32 &= ~(3 << 16);
2423 reg32 |= (1 << 14) | (1 << 6) | (2 << 16);
Angel Pons1d4044a2021-03-27 19:11:51 +01002424 mchbar_write32(ODTC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002425
Paul Menzelb4d9f222020-03-14 10:34:29 +01002426 if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002427 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
Elyes HAOUAS38424982016-08-21 12:01:04 +02002428 printk(BIOS_DEBUG, "one dimm per channel config..\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002429
Angel Pons1d4044a2021-03-27 19:11:51 +01002430 reg32 = mchbar_read32(C0ODT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002431 reg32 &= ~(7 << 28);
Angel Pons1d4044a2021-03-27 19:11:51 +01002432 mchbar_write32(C0ODT, reg32);
2433 reg32 = mchbar_read32(C1ODT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002434 reg32 &= ~(7 << 28);
Angel Pons1d4044a2021-03-27 19:11:51 +01002435 mchbar_write32(C1ODT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002436 }
2437
2438 cas = sysinfo->cas;
2439
Angel Pons1d4044a2021-03-27 19:11:51 +01002440 reg32 = mchbar_read32(C0ODT) & 0xfff00000;
Angel Pons30492572020-06-11 13:24:54 +02002441 reg32 |= odt[(cas - 3) * 2];
Angel Pons1d4044a2021-03-27 19:11:51 +01002442 mchbar_write32(C0ODT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002443
Angel Pons1d4044a2021-03-27 19:11:51 +01002444 reg32 = mchbar_read32(C1ODT) & 0xfff00000;
Angel Pons30492572020-06-11 13:24:54 +02002445 reg32 |= odt[(cas - 3) * 2];
Angel Pons1d4044a2021-03-27 19:11:51 +01002446 mchbar_write32(C1ODT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002447
Angel Pons1d4044a2021-03-27 19:11:51 +01002448 reg32 = mchbar_read32(C0ODT + 4) & 0x1fc8ffff;
Angel Pons30492572020-06-11 13:24:54 +02002449 reg32 |= odt[((cas - 3) * 2) + 1];
Angel Pons1d4044a2021-03-27 19:11:51 +01002450 mchbar_write32(C0ODT + 4, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002451
Angel Pons1d4044a2021-03-27 19:11:51 +01002452 reg32 = mchbar_read32(C1ODT + 4) & 0x1fc8ffff;
Angel Pons30492572020-06-11 13:24:54 +02002453 reg32 |= odt[((cas - 3) * 2) + 1];
Angel Pons1d4044a2021-03-27 19:11:51 +01002454 mchbar_write32(C1ODT + 4, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002455}
2456
2457/**
2458 * @brief Enable clocks to populated sockets
2459 */
2460
2461static void sdram_enable_memory_clocks(struct sys_info *sysinfo)
2462{
2463 u8 clocks[2] = { 0, 0 };
2464
Julius Wernercd49cce2019-03-05 16:53:33 -08002465#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002466#define CLOCKS_WIDTH 2
Julius Wernercd49cce2019-03-05 16:53:33 -08002467#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002468#define CLOCKS_WIDTH 3
2469#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002470 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002471 clocks[0] |= (1 << CLOCKS_WIDTH) - 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002472
2473 if (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002474 clocks[0] |= ((1 << CLOCKS_WIDTH) - 1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002475
2476 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002477 clocks[1] |= (1 << CLOCKS_WIDTH) - 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002478
2479 if (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002480 clocks[1] |= ((1 << CLOCKS_WIDTH) - 1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002481
Julius Wernercd49cce2019-03-05 16:53:33 -08002482#if CONFIG(OVERRIDE_CLOCK_DISABLE)
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002483 /* Usually system firmware turns off system memory clock signals to unused SO-DIMM slots
2484 * to reduce EMI and power consumption.
2485 * However, the Kontron 986LCD-M does not like unused clock signals to be disabled.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002486 */
2487
2488 clocks[0] = 0xf; /* force all clock gate pairs to enable */
2489 clocks[1] = 0xf; /* force all clock gate pairs to enable */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002490#endif
2491
Angel Pons1d4044a2021-03-27 19:11:51 +01002492 mchbar_write8(C0DCLKDIS, clocks[0]);
2493 mchbar_write8(C1DCLKDIS, clocks[1]);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002494}
2495
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002496#define RTT_ODT_NONE 0
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002497#define RTT_ODT_50_OHM ((1 << 9) | (1 << 5))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002498#define RTT_ODT_75_OHM (1 << 5)
2499#define RTT_ODT_150_OHM (1 << 9)
2500
Arthur Heymans70a8e342017-03-09 11:30:23 +01002501#define EMRS_OCD_DEFAULT ((1 << 12) | (1 << 11) | (1 << 10))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002502
2503#define MRS_CAS_3 (3 << 7)
2504#define MRS_CAS_4 (4 << 7)
2505#define MRS_CAS_5 (5 << 7)
2506
2507#define MRS_TWR_3 (2 << 12)
2508#define MRS_TWR_4 (3 << 12)
2509#define MRS_TWR_5 (4 << 12)
2510
2511#define MRS_BT (1 << 6)
2512
2513#define MRS_BL4 (2 << 3)
2514#define MRS_BL8 (3 << 3)
2515
2516static void sdram_jedec_enable(struct sys_info *sysinfo)
2517{
2518 int i, nonzero;
2519 u32 bankaddr = 0, tmpaddr, mrsaddr = 0;
2520
2521 for (i = 0, nonzero = -1; i < 8; i++) {
Elyes HAOUAS01912202019-01-19 16:36:38 +01002522 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002523 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002524
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002525 printk(BIOS_DEBUG, "jedec enable sequence: bank %d\n", i);
Elyes HAOUAS01912202019-01-19 16:36:38 +01002526
2527 if (nonzero != -1) {
2528 if (sysinfo->interleaved && nonzero < 4 && i >= 4) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002529 bankaddr = 0x40;
Elyes HAOUAS01912202019-01-19 16:36:38 +01002530 } else {
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002531 printk(BIOS_DEBUG, "bankaddr from bank size of rank %d\n",
2532 nonzero);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002533 bankaddr += sysinfo->banksize[nonzero] <<
2534 (sysinfo->interleaved ? 26 : 25);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002535 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002536 }
2537
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002538 /*
2539 * We have a bank with a non-zero size... Remember it
Stefan Reinauer278534d2008-10-29 04:51:07 +00002540 * for the next offset we have to calculate
2541 */
2542 nonzero = i;
2543
2544 /* Get CAS latency set up */
2545 switch (sysinfo->cas) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002546 case 5:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002547 mrsaddr = MRS_CAS_5;
2548 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002549 case 4:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002550 mrsaddr = MRS_CAS_4;
2551 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002552 case 3:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002553 mrsaddr = MRS_CAS_3;
2554 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002555 default:
2556 die("Jedec Error (CAS).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002557 }
2558
2559 /* Get tWR set */
2560 switch (sysinfo->twr) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002561 case 5:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002562 mrsaddr |= MRS_TWR_5;
2563 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002564 case 4:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002565 mrsaddr |= MRS_TWR_4;
2566 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002567 case 3:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002568 mrsaddr |= MRS_TWR_3;
2569 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002570 default:
2571 die("Jedec Error (tWR).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002572 }
2573
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002574 /* Set "Burst Type" */
2575 mrsaddr |= MRS_BT;
2576
Stefan Reinauer278534d2008-10-29 04:51:07 +00002577 /* Interleaved */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002578 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002579 mrsaddr = mrsaddr << 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002580
2581 /* Only burst length 8 supported */
2582 mrsaddr |= MRS_BL8;
2583
2584 /* Apply NOP */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002585 PRINTK_DEBUG("Apply NOP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002586 do_ram_command(RAM_COMMAND_NOP);
2587 ram_read32(bankaddr);
2588
2589 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002590 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002591 do_ram_command(RAM_COMMAND_PRECHARGE);
2592 ram_read32(bankaddr);
2593
2594 /* Extended Mode Register Set (2) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002595 PRINTK_DEBUG("Extended Mode Register Set(2)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002596 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_2);
2597 ram_read32(bankaddr);
2598
2599 /* Extended Mode Register Set (3) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002600 PRINTK_DEBUG("Extended Mode Register Set(3)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002601 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_3);
2602 ram_read32(bankaddr);
2603
2604 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002605 PRINTK_DEBUG("Extended Mode Register Set\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002606 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2607 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002608 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002609 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002610 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002611 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002612 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002613 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002614 ram_read32(tmpaddr);
2615
2616 /* Mode Register Set: Reset DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002617 PRINTK_DEBUG("MRS: Reset DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002618 do_ram_command(RAM_COMMAND_MRS);
2619 tmpaddr = bankaddr;
2620 tmpaddr |= mrsaddr;
2621 /* Set DLL reset bit */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002622 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002623 tmpaddr |= (1 << 12);
2624 else
2625 tmpaddr |= (1 << 11);
2626 ram_read32(tmpaddr);
2627
2628 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002629 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002630 do_ram_command(RAM_COMMAND_PRECHARGE);
2631 ram_read32(bankaddr);
2632
2633 /* CAS before RAS Refresh */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002634 PRINTK_DEBUG("CAS before RAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002635 do_ram_command(RAM_COMMAND_CBR);
2636
2637 /* CBR wants two READs */
2638 ram_read32(bankaddr);
2639 ram_read32(bankaddr);
2640
2641 /* Mode Register Set: Enable DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002642 PRINTK_DEBUG("MRS: Enable DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002643 do_ram_command(RAM_COMMAND_MRS);
2644
2645 tmpaddr = bankaddr;
2646 tmpaddr |= mrsaddr;
2647 ram_read32(tmpaddr);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002648
Stefan Reinauer278534d2008-10-29 04:51:07 +00002649 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002650 PRINTK_DEBUG("Extended Mode Register Set: ODT/OCD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002651 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002652
Stefan Reinauer278534d2008-10-29 04:51:07 +00002653 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002654 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002655 tmpaddr |= RTT_ODT_75_OHM | EMRS_OCD_DEFAULT;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002656 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002657 tmpaddr |= ((RTT_ODT_150_OHM | EMRS_OCD_DEFAULT) << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002658 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002659 tmpaddr |= RTT_ODT_150_OHM | EMRS_OCD_DEFAULT;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002660 ram_read32(tmpaddr);
2661
2662 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002663 PRINTK_DEBUG("Extended Mode Register Set: OCD Exit\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002664 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2665
2666 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;
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 << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002671 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002672 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002673 ram_read32(tmpaddr);
2674 }
2675}
2676
2677static void sdram_init_complete(void)
2678{
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002679 PRINTK_DEBUG("Normal Operation\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002680 do_ram_command(RAM_COMMAND_NORMAL);
2681}
2682
2683static void sdram_setup_processor_side(void)
2684{
2685 if (i945_silicon_revision() == 0)
Angel Pons1d4044a2021-03-27 19:11:51 +01002686 mchbar_setbits32(FSBPMC3, 1 << 2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002687
Angel Pons1d4044a2021-03-27 19:11:51 +01002688 mchbar_setbits8(0xb00, 1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002689
2690 if (i945_silicon_revision() == 0)
Angel Pons1d4044a2021-03-27 19:11:51 +01002691 mchbar_setbits32(SLPCTL, 1 << 8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002692}
2693
Stefan Reinauer278534d2008-10-29 04:51:07 +00002694/**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002695 * @param boot_path: 0 = normal, 1 = reset, 2 = resume from s3
Martin Rothf4cb4122015-01-06 10:27:39 -07002696 * @param spd_addresses pointer to a list of SPD addresses
Stefan Reinauer278534d2008-10-29 04:51:07 +00002697 */
Sven Schnelle541269b2011-02-21 09:39:17 +00002698void sdram_initialize(int boot_path, const u8 *spd_addresses)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002699{
2700 struct sys_info sysinfo;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002701
Jakub Czapigaad6157e2022-02-15 11:50:31 +01002702 timestamp_add_now(TS_INITRAM_START);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002703 printk(BIOS_DEBUG, "Setting up RAM controller.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002704
2705 memset(&sysinfo, 0, sizeof(sysinfo));
2706
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002707 sysinfo.boot_path = boot_path;
Sven Schnelle541269b2011-02-21 09:39:17 +00002708 sysinfo.spd_addresses = spd_addresses;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002709
Stefan Reinauer278534d2008-10-29 04:51:07 +00002710 /* Look at the type of DIMMs and verify all DIMMs are x8 or x16 width */
2711 sdram_get_dram_configuration(&sysinfo);
2712
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002713 /* If error, do cold boot */
2714 sdram_detect_errors(&sysinfo);
2715
Stefan Reinauer278534d2008-10-29 04:51:07 +00002716 /* Program PLL settings */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002717 sdram_program_pll_settings(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002718
Arthur Heymans18537812016-12-28 21:20:45 +01002719 /*
2720 * Program Graphics Frequency
2721 * Set core display and render clock on 945GC to the max
2722 */
Julius Wernercd49cce2019-03-05 16:53:33 -08002723 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM))
Arthur Heymans18537812016-12-28 21:20:45 +01002724 sdram_program_graphics_frequency(&sysinfo);
2725 else
Angel Pons3580d812020-06-11 14:13:33 +02002726 pci_write_config16(IGD_DEV, GCFC, 0x0534);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002727
2728 /* Program System Memory Frequency */
2729 sdram_program_memory_frequency(&sysinfo);
2730
2731 /* Determine Mode of Operation (Interleaved etc) */
2732 sdram_set_channel_mode(&sysinfo);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002733
Stefan Reinauer278534d2008-10-29 04:51:07 +00002734 /* Program Clock Crossing values */
2735 sdram_program_clock_crossing();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002736
Stefan Reinauer278534d2008-10-29 04:51:07 +00002737 /* Disable fast dispatch */
2738 sdram_disable_fast_dispatch();
2739
2740 /* Enable WIODLL Power Down in ACPI states */
Angel Pons1d4044a2021-03-27 19:11:51 +01002741 mchbar_setbits32(C0DMC, 1 << 24);
2742 mchbar_setbits32(C1DMC, 1 << 24);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002743
2744 /* Program DRAM Row Boundary/Attribute Registers */
2745
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002746 /* program row size DRB and set TOLUD */
2747 sdram_program_row_boundaries(&sysinfo);
2748
2749 /* program page size DRA */
2750 sdram_set_row_attributes(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002751
2752 /* Program CxBNKARC */
2753 sdram_set_bank_architecture(&sysinfo);
2754
2755 /* Program DRAM Timing and Control registers based on SPD */
2756 sdram_set_timing_and_control(&sysinfo);
2757
2758 /* On-Die Termination Adjustment */
2759 sdram_on_die_termination(&sysinfo);
2760
2761 /* Pre Jedec Initialization */
2762 sdram_pre_jedec_initialization();
2763
2764 /* Perform System Memory IO Initialization */
2765 sdram_initialize_system_memory_io(&sysinfo);
2766
2767 /* Perform System Memory IO Buffer Enable */
2768 sdram_enable_system_memory_io(&sysinfo);
2769
2770 /* Enable System Memory Clocks */
2771 sdram_enable_memory_clocks(&sysinfo);
2772
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002773 if (boot_path == BOOT_PATH_NORMAL) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002774 /* Jedec Initialization sequence */
2775 sdram_jedec_enable(&sysinfo);
2776 }
2777
2778 /* Program Power Management Registers */
2779 sdram_power_management(&sysinfo);
2780
2781 /* Post Jedec Init */
2782 sdram_post_jedec_initialization(&sysinfo);
2783
2784 /* Program DRAM Throttling */
2785 sdram_thermal_management();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002786
Stefan Reinauer278534d2008-10-29 04:51:07 +00002787 /* Normal Operations */
Stefan Reinaueraca6ec62009-10-26 17:12:21 +00002788 sdram_init_complete();
Stefan Reinauer278534d2008-10-29 04:51:07 +00002789
2790 /* Program Receive Enable Timings */
2791 sdram_program_receive_enable(&sysinfo);
2792
2793 /* Enable Periodic RCOMP */
2794 sdram_enable_rcomp();
2795
2796 /* Tell ICH7 that we're done */
Angel Ponse3c68d22020-06-08 12:09:03 +02002797 pci_and_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, (u8)~(1 << 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +00002798
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002799 printk(BIOS_DEBUG, "RAM initialization finished.\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002800
Stefan Reinauer278534d2008-10-29 04:51:07 +00002801 sdram_setup_processor_side();
Jakub Czapigaad6157e2022-02-15 11:50:31 +01002802 timestamp_add_now(TS_INITRAM_END);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002803}