blob: e168f7ce9447c18912d382988ac67779b8b9e45b [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
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001774 /* Make sure the following code is in the cache before we execute it. */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001775 goto cache_code;
1776vco_update:
Angel Ponse3c68d22020-06-08 12:09:03 +02001777 pci_and_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, (u8)~(1 << 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001778
Stefan Reinauer278534d2008-10-29 04:51:07 +00001779 clkcfg &= ~(1 << 10);
Angel Pons1d4044a2021-03-27 19:11:51 +01001780 mchbar_write32(CLKCFG, clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001781 clkcfg |= (1 << 10);
Angel Pons1d4044a2021-03-27 19:11:51 +01001782 mchbar_write32(CLKCFG, clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001783
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001784 asm volatile (
Stefan Reinauer278534d2008-10-29 04:51:07 +00001785 " movl $0x100, %%ecx\n"
1786 "delay_update:\n"
1787 " nop\n"
1788 " nop\n"
1789 " nop\n"
1790 " nop\n"
1791 " loop delay_update\n"
1792 : /* No outputs */
1793 : /* No inputs */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001794 : "%ecx", "memory"
Stefan Reinauer278534d2008-10-29 04:51:07 +00001795 );
1796
Stefan Reinauer278534d2008-10-29 04:51:07 +00001797 clkcfg &= ~(1 << 10);
Angel Pons1d4044a2021-03-27 19:11:51 +01001798 mchbar_write32(CLKCFG, clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001799
1800 goto out;
1801cache_code:
1802 goto vco_update;
1803out:
1804
Angel Pons1d4044a2021-03-27 19:11:51 +01001805 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", mchbar_read32(CLKCFG));
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001806 printk(BIOS_DEBUG, "ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001807}
1808
1809static void sdram_program_clock_crossing(void)
1810{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001811 int idx = 0;
1812
1813 /**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001814 * We add the indices according to our clocks from CLKCFG.
Stefan Reinauer278534d2008-10-29 04:51:07 +00001815 */
Julius Wernercd49cce2019-03-05 16:53:33 -08001816#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001817 static const u32 data_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001818 0x00100401, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001819 0xffffffff, 0xffffffff, /* nonexistent */
1820 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001821
Stefan Reinauer278534d2008-10-29 04:51:07 +00001822 0x08040120, 0x00000000, /* DDR400 FSB533 */
1823 0x00100401, 0x00000000, /* DDR533 FSB533 */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001824 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001825
1826 0x04020120, 0x00000010, /* DDR400 FSB667 */
1827 0x10040280, 0x00000040, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001828 0x00100401, 0x00000000, /* DDR667 FSB667 */
1829
Martin Roth2ed0aa22016-01-05 20:58:58 -07001830 0xffffffff, 0xffffffff, /* nonexistent */
1831 0xffffffff, 0xffffffff, /* nonexistent */
1832 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001833
Martin Roth2ed0aa22016-01-05 20:58:58 -07001834 0xffffffff, 0xffffffff, /* nonexistent */
1835 0xffffffff, 0xffffffff, /* nonexistent */
1836 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001837 };
1838
1839 static const u32 command_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001840 0x04020208, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001841 0xffffffff, 0xffffffff, /* nonexistent */
1842 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001843
Stefan Reinauer278534d2008-10-29 04:51:07 +00001844 0x00060108, 0x00000000, /* DDR400 FSB533 */
1845 0x04020108, 0x00000000, /* DDR533 FSB533 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001846 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001847
1848 0x00040318, 0x00000000, /* DDR400 FSB667 */
1849 0x04020118, 0x00000000, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001850 0x02010804, 0x00000000, /* DDR667 FSB667 */
1851
Martin Roth2ed0aa22016-01-05 20:58:58 -07001852 0xffffffff, 0xffffffff, /* nonexistent */
1853 0xffffffff, 0xffffffff, /* nonexistent */
1854 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001855
Martin Roth2ed0aa22016-01-05 20:58:58 -07001856 0xffffffff, 0xffffffff, /* nonexistent */
1857 0xffffffff, 0xffffffff, /* nonexistent */
1858 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001859 };
1860
Julius Wernercd49cce2019-03-05 16:53:33 -08001861#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001862 /* i945 G/P */
1863 static const u32 data_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001864 0xffffffff, 0xffffffff, /* nonexistent */
1865 0xffffffff, 0xffffffff, /* nonexistent */
1866 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001867
1868 0x10080201, 0x00000000, /* DDR400 FSB533 */
1869 0x00100401, 0x00000000, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001870 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
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 Reinauer24b4df52010-01-17 13:47:35 +00001875
1876 0x04020108, 0x00000000, /* DDR400 FSB800 */
1877 0x00020108, 0x00000000, /* DDR533 FSB800 */
1878 0x00080201, 0x00000000, /* DDR667 FSB800 */
1879
1880 0x00010402, 0x00000000, /* DDR400 FSB1066 */
1881 0x04020108, 0x00000000, /* DDR533 FSB1066 */
1882 0x08040110, 0x00000000, /* DDR667 FSB1066 */
1883 };
1884
1885 static const u32 command_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001886 0xffffffff, 0xffffffff, /* nonexistent */
1887 0xffffffff, 0xffffffff, /* nonexistent */
1888 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001889
1890 0x00010800, 0x00000402, /* DDR400 FSB533 */
1891 0x01000400, 0x00000200, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001892 0x00020904, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001893
Martin Roth2ed0aa22016-01-05 20:58:58 -07001894 0xffffffff, 0xffffffff, /* nonexistent */
1895 0xffffffff, 0xffffffff, /* nonexistent */
1896 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001897
1898 0x02010804, 0x00000000, /* DDR400 FSB800 */
1899 0x00010402, 0x00000000, /* DDR533 FSB800 */
Arthur Heymans8b6df622016-10-16 10:58:01 +02001900 0x04020130, 0x00000008, /* DDR667 FSB800 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001901
1902 0x00020904, 0x00000000, /* DDR400 FSB1066 */
1903 0x02010804, 0x00000000, /* DDR533 FSB1066 */
1904 0x180601c0, 0x00000020, /* DDR667 FSB1066 */
1905 };
1906#endif
1907
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001908 printk(BIOS_DEBUG, "Programming Clock Crossing...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001909
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001910 printk(BIOS_DEBUG, "MEM=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001911 switch (memclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001912 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001913 printk(BIOS_DEBUG, "400");
1914 idx += 0;
1915 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001916 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001917 printk(BIOS_DEBUG, "533");
1918 idx += 2;
1919 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001920 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001921 printk(BIOS_DEBUG, "667");
1922 idx += 4;
1923 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001924 default:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001925 printk(BIOS_DEBUG, "RSVD %x", memclk());
1926 return;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001927 }
1928
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001929 printk(BIOS_DEBUG, " FSB=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001930 switch (fsbclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001931 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001932 printk(BIOS_DEBUG, "400");
1933 idx += 0;
1934 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001935 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001936 printk(BIOS_DEBUG, "533");
1937 idx += 6;
1938 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001939 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001940 printk(BIOS_DEBUG, "667");
1941 idx += 12;
1942 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001943 case 800:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001944 printk(BIOS_DEBUG, "800");
1945 idx += 18;
1946 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001947 case 1066:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001948 printk(BIOS_DEBUG, "1066");
1949 idx += 24;
1950 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001951 default:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001952 printk(BIOS_DEBUG, "RSVD %x\n", fsbclk());
1953 return;
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001954 }
1955
Arthur Heymans70a8e342017-03-09 11:30:23 +01001956 if (command_clock_crossing[idx] == 0xffffffff)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001957 printk(BIOS_DEBUG, "Invalid MEM/FSB combination!\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001958
Angel Pons1d4044a2021-03-27 19:11:51 +01001959 mchbar_write32(CCCFT + 0, command_clock_crossing[idx]);
1960 mchbar_write32(CCCFT + 4, command_clock_crossing[idx + 1]);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001961
Angel Pons1d4044a2021-03-27 19:11:51 +01001962 mchbar_write32(C0DCCFT + 0, data_clock_crossing[idx]);
1963 mchbar_write32(C0DCCFT + 4, data_clock_crossing[idx + 1]);
1964 mchbar_write32(C1DCCFT + 0, data_clock_crossing[idx]);
1965 mchbar_write32(C1DCCFT + 4, data_clock_crossing[idx + 1]);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001966
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001967 printk(BIOS_DEBUG, "... ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001968}
1969
1970static void sdram_disable_fast_dispatch(void)
1971{
1972 u32 reg32;
1973
Angel Pons1d4044a2021-03-27 19:11:51 +01001974 reg32 = mchbar_read32(FSBPMC3);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001975 reg32 |= (1 << 1);
Angel Pons1d4044a2021-03-27 19:11:51 +01001976 mchbar_write32(FSBPMC3, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001977
Angel Pons1d4044a2021-03-27 19:11:51 +01001978 reg32 = mchbar_read32(SBTEST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001979 reg32 |= (3 << 1);
Angel Pons1d4044a2021-03-27 19:11:51 +01001980 mchbar_write32(SBTEST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001981}
1982
1983static void sdram_pre_jedec_initialization(void)
1984{
1985 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001986
Angel Pons1d4044a2021-03-27 19:11:51 +01001987 reg32 = mchbar_read32(WCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001988 reg32 &= 0x113ff3ff;
1989 reg32 |= (4 << 29) | (3 << 25) | (1 << 10);
Angel Pons1d4044a2021-03-27 19:11:51 +01001990 mchbar_write32(WCC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001991
Angel Pons1d4044a2021-03-27 19:11:51 +01001992 mchbar_setbits32(SMVREFC, 1 << 6);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001993
Angel Pons1d4044a2021-03-27 19:11:51 +01001994 mchbar_clrbits32(MMARB0, 3 << 17);
1995 mchbar_setbits32(MMARB0, 1 << 21 | 1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001996
Angel Pons1d4044a2021-03-27 19:11:51 +01001997 mchbar_clrbits32(MMARB1, 7 << 8);
1998 mchbar_setbits32(MMARB1, 3 << 8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001999
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002000 /* Adaptive Idle Timer Control */
Angel Pons1d4044a2021-03-27 19:11:51 +01002001 mchbar_write32(C0AIT + 0, 0x000006c4);
2002 mchbar_write32(C0AIT + 4, 0x871a066d);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002003
Angel Pons1d4044a2021-03-27 19:11:51 +01002004 mchbar_write32(C1AIT + 0, 0x000006c4);
2005 mchbar_write32(C1AIT + 4, 0x871a066d);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002006}
2007
2008#define EA_DUALCHANNEL_XOR_BANK_RANK_MODE (0xd4 << 24)
2009#define EA_DUALCHANNEL_XOR_BANK_MODE (0xf4 << 24)
2010#define EA_DUALCHANNEL_BANK_RANK_MODE (0xc2 << 24)
2011#define EA_DUALCHANNEL_BANK_MODE (0xe2 << 24)
2012#define EA_SINGLECHANNEL_XOR_BANK_RANK_MODE (0x91 << 24)
2013#define EA_SINGLECHANNEL_XOR_BANK_MODE (0xb1 << 24)
2014#define EA_SINGLECHANNEL_BANK_RANK_MODE (0x80 << 24)
2015#define EA_SINGLECHANNEL_BANK_MODE (0xa0 << 24)
2016
2017static void sdram_enhanced_addressing_mode(struct sys_info *sysinfo)
2018{
2019 u32 chan0 = 0, chan1 = 0;
Paul Menzeld789b6582020-03-14 11:50:34 +01002020 bool chan0_dualsided, chan1_dualsided, chan0_populated, chan1_populated;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002021
Paul Menzel842dd332020-03-14 10:37:40 +01002022 chan0_populated = (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002023 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED);
Elyes HAOUAS308aeff2017-02-24 12:53:07 +01002024 chan1_populated = (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002025 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002026 chan0_dualsided = (sysinfo->banksize[1] || sysinfo->banksize[3]);
2027 chan1_dualsided = (sysinfo->banksize[5] || sysinfo->banksize[7]);
2028
2029 if (sdram_capabilities_enhanced_addressing_xor()) {
2030 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002031 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002032 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002033 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002034 chan0 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002035 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002036 chan0 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002037 }
2038 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002039 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002040 chan1 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002041 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002042 chan1 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002043 }
2044 } else {
2045 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002046 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002047 chan0 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002048 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002049 chan0 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002050
Arthur Heymans70a8e342017-03-09 11:30:23 +01002051 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002052 chan1 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002053 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002054 chan1 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002055 }
2056 } else {
2057 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002058 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002059 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002060 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002061 chan0 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002062 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002063 chan0 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002064 }
2065 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002066 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002067 chan1 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002068 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002069 chan1 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002070 }
2071 } else {
2072 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002073 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002074 chan0 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002075 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002076 chan0 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002077
Arthur Heymans70a8e342017-03-09 11:30:23 +01002078 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002079 chan1 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002080 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002081 chan1 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002082 }
2083 }
2084
Angel Pons1d4044a2021-03-27 19:11:51 +01002085 mchbar_clrbits32(C0DRC1, 0xff << 24);
2086 mchbar_setbits32(C0DRC1, chan0);
2087 mchbar_clrbits32(C1DRC1, 0xff << 24);
2088 mchbar_setbits32(C1DRC1, chan1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002089}
2090
2091static void sdram_post_jedec_initialization(struct sys_info *sysinfo)
2092{
2093 u32 reg32;
2094
2095 /* Enable Channel XORing for Dual Channel Interleave */
2096 if (sysinfo->interleaved) {
Angel Pons1d4044a2021-03-27 19:11:51 +01002097 reg32 = mchbar_read32(DCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002098 reg32 &= ~(1 << 10);
Stefan Reinauer30140a52009-03-11 16:20:39 +00002099 reg32 |= (1 << 9);
Angel Pons1d4044a2021-03-27 19:11:51 +01002100 mchbar_write32(DCC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002101 }
2102
2103 /* DRAM mode optimizations */
2104 sdram_enhanced_addressing_mode(sysinfo);
2105
Angel Pons1d4044a2021-03-27 19:11:51 +01002106 reg32 = mchbar_read32(FSBPMC3);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002107 reg32 &= ~(1 << 1);
Angel Pons1d4044a2021-03-27 19:11:51 +01002108 mchbar_write32(FSBPMC3, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002109
Angel Pons1d4044a2021-03-27 19:11:51 +01002110 reg32 = mchbar_read32(SBTEST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002111 reg32 &= ~(1 << 2);
Angel Pons1d4044a2021-03-27 19:11:51 +01002112 mchbar_write32(SBTEST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002113
Angel Pons1d4044a2021-03-27 19:11:51 +01002114 reg32 = mchbar_read32(SBOCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002115 reg32 &= 0xffbdb6ff;
2116 reg32 |= (0xbdb6 << 8) | (1 << 0);
Angel Pons1d4044a2021-03-27 19:11:51 +01002117 mchbar_write32(SBOCC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002118}
2119
2120static void sdram_power_management(struct sys_info *sysinfo)
2121{
Stefan Reinauer278534d2008-10-29 04:51:07 +00002122 u16 reg16;
2123 u32 reg32;
Elyes HAOUAS187bec72021-12-12 07:00:50 +01002124 bool integrated_graphics = true;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002125 int i;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002126
Elyes HAOUAS8f20b122021-02-14 13:22:10 +01002127 if (!(pci_read_config8(HOST_BRIDGE, DEVEN) & (DEVEN_D2F0 | DEVEN_D2F1)))
2128 integrated_graphics = false;
2129
Angel Pons1d4044a2021-03-27 19:11:51 +01002130 reg32 = mchbar_read32(C0DRT2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002131 reg32 &= 0xffffff00;
2132 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002133 reg32 |= (1 << 5) | (1 << 4);
Angel Pons1d4044a2021-03-27 19:11:51 +01002134 mchbar_write32(C0DRT2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002135
Angel Pons1d4044a2021-03-27 19:11:51 +01002136 reg32 = mchbar_read32(C1DRT2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002137 reg32 &= 0xffffff00;
2138 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002139 reg32 |= (1 << 5) | (1 << 4);
Angel Pons1d4044a2021-03-27 19:11:51 +01002140 mchbar_write32(C1DRT2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002141
Angel Pons1d4044a2021-03-27 19:11:51 +01002142 reg32 = mchbar_read32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002143
2144 reg32 |= (1 << 12) | (1 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01002145 mchbar_write32(C0DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002146
Angel Pons1d4044a2021-03-27 19:11:51 +01002147 reg32 = mchbar_read32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002148
2149 reg32 |= (1 << 12) | (1 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01002150 mchbar_write32(C1DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002151
Julius Wernercd49cce2019-03-05 16:53:33 -08002152 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002153 if (i945_silicon_revision() > 1) {
2154 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2155 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002156
Angel Pons1d4044a2021-03-27 19:11:51 +01002157 mchbar_write16(UPMC1, 0x1010 | peg_bits);
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002158 } else {
2159 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2160 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002161
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002162 /* Rev 0 and 1 */
Angel Pons1d4044a2021-03-27 19:11:51 +01002163 mchbar_write16(UPMC1, 0x0010 | peg_bits);
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002164 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002165 }
2166
Angel Pons1d4044a2021-03-27 19:11:51 +01002167 reg16 = mchbar_read16(UPMC2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002168 reg16 &= 0xfc00;
2169 reg16 |= 0x0100;
Angel Pons1d4044a2021-03-27 19:11:51 +01002170 mchbar_write16(UPMC2, reg16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002171
Angel Pons1d4044a2021-03-27 19:11:51 +01002172 mchbar_write32(UPMC3, 0x000f06ff);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002173
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002174 for (i = 0; i < 5; i++) {
Angel Pons1d4044a2021-03-27 19:11:51 +01002175 mchbar_clrbits32(UPMC3, 1 << 16);
2176 mchbar_setbits32(UPMC3, 1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002177 }
2178
Angel Pons1d4044a2021-03-27 19:11:51 +01002179 mchbar_write32(GIPMC1, 0x8000000c);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002180
Angel Pons1d4044a2021-03-27 19:11:51 +01002181 reg16 = mchbar_read16(CPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002182 reg16 &= ~(7 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002183 if (i945_silicon_revision() > 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002184 reg16 |= (6 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002185 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002186 reg16 |= (4 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01002187 mchbar_write16(CPCTL, reg16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002188
Angel Pons3580d812020-06-11 14:13:33 +02002189#if 0
Angel Pons1d4044a2021-03-27 19:11:51 +01002190 if ((mchbar_read32(ECO) & (1 << 16)) != 0) {
Angel Pons3580d812020-06-11 14:13:33 +02002191#else
Stefan Reinauer30140a52009-03-11 16:20:39 +00002192 if (i945_silicon_revision() != 0) {
Angel Pons3580d812020-06-11 14:13:33 +02002193#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002194 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002195 case 667:
Angel Pons1d4044a2021-03-27 19:11:51 +01002196 mchbar_write32(HGIPMC2, 0x0d590d59);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002197 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002198 case 533:
Angel Pons1d4044a2021-03-27 19:11:51 +01002199 mchbar_write32(HGIPMC2, 0x155b155b);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002200 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002201 }
2202 } else {
2203 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002204 case 667:
Angel Pons1d4044a2021-03-27 19:11:51 +01002205 mchbar_write32(HGIPMC2, 0x09c409c4);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002206 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002207 case 533:
Angel Pons1d4044a2021-03-27 19:11:51 +01002208 mchbar_write32(HGIPMC2, 0x0fa00fa0);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002209 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002210 }
2211 }
2212
Angel Pons1d4044a2021-03-27 19:11:51 +01002213 mchbar_write32(FSBPMC1, 0x8000000c);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002214
Angel Pons1d4044a2021-03-27 19:11:51 +01002215 reg32 = mchbar_read32(C2C3TT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002216 reg32 &= 0xffff0000;
2217 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002218 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002219 reg32 |= 0x0600;
2220 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002221 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002222 reg32 |= 0x0480;
2223 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002224 }
Angel Pons1d4044a2021-03-27 19:11:51 +01002225 mchbar_write32(C2C3TT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002226
Angel Pons1d4044a2021-03-27 19:11:51 +01002227 reg32 = mchbar_read32(C3C4TT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002228 reg32 &= 0xffff0000;
2229 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002230 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002231 reg32 |= 0x0b80;
2232 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002233 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002234 reg32 |= 0x0980;
2235 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002236 }
Angel Pons1d4044a2021-03-27 19:11:51 +01002237 mchbar_write32(C3C4TT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002238
Arthur Heymans70a8e342017-03-09 11:30:23 +01002239 if (i945_silicon_revision() == 0)
Angel Pons1d4044a2021-03-27 19:11:51 +01002240 mchbar_clrbits32(ECO, 1 << 16);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002241 else
Angel Pons1d4044a2021-03-27 19:11:51 +01002242 mchbar_setbits32(ECO, 1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002243
Angel Pons1d4044a2021-03-27 19:11:51 +01002244 mchbar_clrbits32(FSBPMC3, 1 << 29);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002245
Angel Pons1d4044a2021-03-27 19:11:51 +01002246 mchbar_setbits32(FSBPMC3, 1 << 21);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002247
Angel Pons1d4044a2021-03-27 19:11:51 +01002248 mchbar_clrbits32(FSBPMC3, 1 << 19);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002249
Angel Pons1d4044a2021-03-27 19:11:51 +01002250 mchbar_clrbits32(FSBPMC3, 1 << 13);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002251
Angel Pons1d4044a2021-03-27 19:11:51 +01002252 reg32 = mchbar_read32(FSBPMC4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002253 reg32 &= ~(3 << 24);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002254 reg32 |= (2 << 24);
Angel Pons1d4044a2021-03-27 19:11:51 +01002255 mchbar_write32(FSBPMC4, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002256
Angel Pons1d4044a2021-03-27 19:11:51 +01002257 mchbar_setbits32(FSBPMC4, 1 << 21);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002258
Angel Pons1d4044a2021-03-27 19:11:51 +01002259 mchbar_setbits32(FSBPMC4, 1 << 5);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002260
Arthur Heymans70a8e342017-03-09 11:30:23 +01002261 if ((i945_silicon_revision() < 2)) { /* || cpuid() = 0x6e8 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002262 /* stepping 0 and 1 or CPUID 6e8 */
Angel Pons1d4044a2021-03-27 19:11:51 +01002263 mchbar_clrbits32(FSBPMC4, 1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002264 } else {
Angel Pons1d4044a2021-03-27 19:11:51 +01002265 mchbar_setbits32(FSBPMC4, 1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002266 }
2267
Angel Pons3580d812020-06-11 14:13:33 +02002268 pci_or_config8(HOST_BRIDGE, 0xfc, 1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002269
Angel Pons3580d812020-06-11 14:13:33 +02002270 pci_or_config8(IGD_DEV, 0xc1, 1 << 2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002271
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002272 if (integrated_graphics) {
Angel Pons1d4044a2021-03-27 19:11:51 +01002273 mchbar_write16(MIPMC4, 0x04f8);
2274 mchbar_write16(MIPMC5, 0x04fc);
2275 mchbar_write16(MIPMC6, 0x04fc);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002276 } else {
Angel Pons1d4044a2021-03-27 19:11:51 +01002277 mchbar_write16(MIPMC4, 0x64f8);
2278 mchbar_write16(MIPMC5, 0x64fc);
2279 mchbar_write16(MIPMC6, 0x64fc);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002280 }
2281
Angel Pons1d4044a2021-03-27 19:11:51 +01002282 reg32 = mchbar_read32(PMCFG);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002283 reg32 &= ~(3 << 17);
2284 reg32 |= (2 << 17);
Angel Pons1d4044a2021-03-27 19:11:51 +01002285 mchbar_write32(PMCFG, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002286
Angel Pons1d4044a2021-03-27 19:11:51 +01002287 mchbar_setbits32(PMCFG, 1 << 4);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002288
Angel Pons1d4044a2021-03-27 19:11:51 +01002289 reg32 = mchbar_read32(UPMC4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002290 reg32 &= 0xffffff00;
2291 reg32 |= 0x01;
Angel Pons1d4044a2021-03-27 19:11:51 +01002292 mchbar_write32(UPMC4, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002293
Angel Pons1d4044a2021-03-27 19:11:51 +01002294 mchbar_clrbits32(0xb18, 1 << 21);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002295}
2296
2297static void sdram_thermal_management(void)
2298{
Stefan Reinauer278534d2008-10-29 04:51:07 +00002299
Angel Pons1d4044a2021-03-27 19:11:51 +01002300 mchbar_write8(TCO1, 0);
2301 mchbar_write8(TCO0, 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002302
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002303 /* The Thermal Sensors for DIMMs at 0x50, 0x52 are at I2C addr 0x30/0x32. */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002304
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002305 /* TODO This is not implemented yet. Volunteers? */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002306}
2307
2308static void sdram_save_receive_enable(void)
2309{
2310 int i;
2311 u32 reg32;
2312 u8 values[4];
2313
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002314 /* The following values are stored to an unused CMOS area and restored instead of
2315 * recalculated in case of an S3 resume.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002316 *
Arthur Heymans70a8e342017-03-09 11:30:23 +01002317 * C0WL0REOST [7:0] -> 8 bit
2318 * C1WL0REOST [7:0] -> 8 bit
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002319 * RCVENMT [11:8] [3:0] -> 8 bit
2320 * C0DRT1 [27:24] -> 4 bit
2321 * C1DRT1 [27:24] -> 4 bit
2322 */
2323
Angel Pons1d4044a2021-03-27 19:11:51 +01002324 values[0] = mchbar_read8(C0WL0REOST);
2325 values[1] = mchbar_read8(C1WL0REOST);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002326
Angel Pons1d4044a2021-03-27 19:11:51 +01002327 reg32 = mchbar_read32(RCVENMT);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002328 values[2] = (u8)((reg32 >> (8 - 4)) & 0xf0) | (reg32 & 0x0f);
2329
Angel Pons1d4044a2021-03-27 19:11:51 +01002330 reg32 = mchbar_read32(C0DRT1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002331 values[3] = (reg32 >> 24) & 0x0f;
Angel Pons1d4044a2021-03-27 19:11:51 +01002332 reg32 = mchbar_read32(C1DRT1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002333 values[3] |= (reg32 >> (24 - 4)) & 0xf0;
2334
2335 /* coreboot only uses bytes 0 - 127 for its CMOS values so far
Edwin Beasanteb50c7d2010-07-06 21:05:04 +00002336 * so we grab bytes 128 - 131 to save the receive enable values
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002337 */
2338
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002339 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002340 cmos_write(values[i], 128 + i);
2341}
2342
2343static void sdram_recover_receive_enable(void)
2344{
2345 int i;
2346 u32 reg32;
2347 u8 values[4];
2348
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002349 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002350 values[i] = cmos_read(128 + i);
2351
Angel Pons1d4044a2021-03-27 19:11:51 +01002352 mchbar_write8(C0WL0REOST, values[0]);
2353 mchbar_write8(C1WL0REOST, values[1]);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002354
Angel Pons1d4044a2021-03-27 19:11:51 +01002355 reg32 = mchbar_read32(RCVENMT);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002356 reg32 &= ~((0x0f << 8) | (0x0f << 0));
2357 reg32 |= ((u32)(values[2] & 0xf0) << (8 - 4)) | (values[2] & 0x0f);
Angel Pons1d4044a2021-03-27 19:11:51 +01002358 mchbar_write32(RCVENMT, reg32);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002359
Angel Pons1d4044a2021-03-27 19:11:51 +01002360 reg32 = mchbar_read32(C0DRT1) & ~(0x0f << 24);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002361 reg32 |= (u32)(values[3] & 0x0f) << 24;
Angel Pons1d4044a2021-03-27 19:11:51 +01002362 mchbar_write32(C0DRT1, reg32);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002363
Angel Pons1d4044a2021-03-27 19:11:51 +01002364 reg32 = mchbar_read32(C1DRT1) & ~(0x0f << 24);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002365 reg32 |= (u32)(values[3] & 0xf0) << (24 - 4);
Angel Pons1d4044a2021-03-27 19:11:51 +01002366 mchbar_write32(C1DRT1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002367}
2368
Stefan Reinauer278534d2008-10-29 04:51:07 +00002369static void sdram_program_receive_enable(struct sys_info *sysinfo)
2370{
Angel Pons1d4044a2021-03-27 19:11:51 +01002371 mchbar_setbits32(REPC, 1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002372
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002373 /* Program Receive Enable Timings */
2374 if (sysinfo->boot_path == BOOT_PATH_RESUME) {
2375 sdram_recover_receive_enable();
2376 } else {
2377 receive_enable_adjust(sysinfo);
2378 sdram_save_receive_enable();
2379 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002380
Angel Pons1d4044a2021-03-27 19:11:51 +01002381 mchbar_setbits32(C0DRC1, 1 << 6);
2382 mchbar_setbits32(C1DRC1, 1 << 6);
2383 mchbar_clrbits32(C0DRC1, 1 << 6);
2384 mchbar_clrbits32(C1DRC1, 1 << 6);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002385
Angel Pons1d4044a2021-03-27 19:11:51 +01002386 mchbar_setbits32(MIPMC3, 0x0f << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002387}
2388
2389/**
2390 * @brief Enable On-Die Termination for DDR2.
2391 *
2392 */
2393
2394static void sdram_on_die_termination(struct sys_info *sysinfo)
2395{
2396 static const u32 odt[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002397 0x00024911, 0xe0010000,
2398 0x00049211, 0xe0020000,
2399 0x0006db11, 0xe0030000,
Stefan Reinauer278534d2008-10-29 04:51:07 +00002400 };
2401
2402 u32 reg32;
2403 int cas;
2404
Angel Pons1d4044a2021-03-27 19:11:51 +01002405 reg32 = mchbar_read32(ODTC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002406 reg32 &= ~(3 << 16);
2407 reg32 |= (1 << 14) | (1 << 6) | (2 << 16);
Angel Pons1d4044a2021-03-27 19:11:51 +01002408 mchbar_write32(ODTC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002409
Paul Menzelb4d9f222020-03-14 10:34:29 +01002410 if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002411 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
Elyes HAOUAS38424982016-08-21 12:01:04 +02002412 printk(BIOS_DEBUG, "one dimm per channel config..\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002413
Angel Pons1d4044a2021-03-27 19:11:51 +01002414 reg32 = mchbar_read32(C0ODT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002415 reg32 &= ~(7 << 28);
Angel Pons1d4044a2021-03-27 19:11:51 +01002416 mchbar_write32(C0ODT, reg32);
2417 reg32 = mchbar_read32(C1ODT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002418 reg32 &= ~(7 << 28);
Angel Pons1d4044a2021-03-27 19:11:51 +01002419 mchbar_write32(C1ODT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002420 }
2421
2422 cas = sysinfo->cas;
2423
Angel Pons1d4044a2021-03-27 19:11:51 +01002424 reg32 = mchbar_read32(C0ODT) & 0xfff00000;
Angel Pons30492572020-06-11 13:24:54 +02002425 reg32 |= odt[(cas - 3) * 2];
Angel Pons1d4044a2021-03-27 19:11:51 +01002426 mchbar_write32(C0ODT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002427
Angel Pons1d4044a2021-03-27 19:11:51 +01002428 reg32 = mchbar_read32(C1ODT) & 0xfff00000;
Angel Pons30492572020-06-11 13:24:54 +02002429 reg32 |= odt[(cas - 3) * 2];
Angel Pons1d4044a2021-03-27 19:11:51 +01002430 mchbar_write32(C1ODT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002431
Angel Pons1d4044a2021-03-27 19:11:51 +01002432 reg32 = mchbar_read32(C0ODT + 4) & 0x1fc8ffff;
Angel Pons30492572020-06-11 13:24:54 +02002433 reg32 |= odt[((cas - 3) * 2) + 1];
Angel Pons1d4044a2021-03-27 19:11:51 +01002434 mchbar_write32(C0ODT + 4, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002435
Angel Pons1d4044a2021-03-27 19:11:51 +01002436 reg32 = mchbar_read32(C1ODT + 4) & 0x1fc8ffff;
Angel Pons30492572020-06-11 13:24:54 +02002437 reg32 |= odt[((cas - 3) * 2) + 1];
Angel Pons1d4044a2021-03-27 19:11:51 +01002438 mchbar_write32(C1ODT + 4, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002439}
2440
2441/**
2442 * @brief Enable clocks to populated sockets
2443 */
2444
2445static void sdram_enable_memory_clocks(struct sys_info *sysinfo)
2446{
2447 u8 clocks[2] = { 0, 0 };
2448
Julius Wernercd49cce2019-03-05 16:53:33 -08002449#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002450#define CLOCKS_WIDTH 2
Julius Wernercd49cce2019-03-05 16:53:33 -08002451#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002452#define CLOCKS_WIDTH 3
2453#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002454 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002455 clocks[0] |= (1 << CLOCKS_WIDTH) - 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002456
2457 if (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002458 clocks[0] |= ((1 << CLOCKS_WIDTH) - 1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002459
2460 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002461 clocks[1] |= (1 << CLOCKS_WIDTH) - 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002462
2463 if (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002464 clocks[1] |= ((1 << CLOCKS_WIDTH) - 1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002465
Julius Wernercd49cce2019-03-05 16:53:33 -08002466#if CONFIG(OVERRIDE_CLOCK_DISABLE)
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002467 /* Usually system firmware turns off system memory clock signals to unused SO-DIMM slots
2468 * to reduce EMI and power consumption.
2469 * However, the Kontron 986LCD-M does not like unused clock signals to be disabled.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002470 */
2471
2472 clocks[0] = 0xf; /* force all clock gate pairs to enable */
2473 clocks[1] = 0xf; /* force all clock gate pairs to enable */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002474#endif
2475
Angel Pons1d4044a2021-03-27 19:11:51 +01002476 mchbar_write8(C0DCLKDIS, clocks[0]);
2477 mchbar_write8(C1DCLKDIS, clocks[1]);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002478}
2479
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002480#define RTT_ODT_NONE 0
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002481#define RTT_ODT_50_OHM ((1 << 9) | (1 << 5))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002482#define RTT_ODT_75_OHM (1 << 5)
2483#define RTT_ODT_150_OHM (1 << 9)
2484
Arthur Heymans70a8e342017-03-09 11:30:23 +01002485#define EMRS_OCD_DEFAULT ((1 << 12) | (1 << 11) | (1 << 10))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002486
2487#define MRS_CAS_3 (3 << 7)
2488#define MRS_CAS_4 (4 << 7)
2489#define MRS_CAS_5 (5 << 7)
2490
2491#define MRS_TWR_3 (2 << 12)
2492#define MRS_TWR_4 (3 << 12)
2493#define MRS_TWR_5 (4 << 12)
2494
2495#define MRS_BT (1 << 6)
2496
2497#define MRS_BL4 (2 << 3)
2498#define MRS_BL8 (3 << 3)
2499
2500static void sdram_jedec_enable(struct sys_info *sysinfo)
2501{
2502 int i, nonzero;
2503 u32 bankaddr = 0, tmpaddr, mrsaddr = 0;
2504
2505 for (i = 0, nonzero = -1; i < 8; i++) {
Elyes HAOUAS01912202019-01-19 16:36:38 +01002506 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002507 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002508
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002509 printk(BIOS_DEBUG, "jedec enable sequence: bank %d\n", i);
Elyes HAOUAS01912202019-01-19 16:36:38 +01002510
2511 if (nonzero != -1) {
2512 if (sysinfo->interleaved && nonzero < 4 && i >= 4) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002513 bankaddr = 0x40;
Elyes HAOUAS01912202019-01-19 16:36:38 +01002514 } else {
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002515 printk(BIOS_DEBUG, "bankaddr from bank size of rank %d\n",
2516 nonzero);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002517 bankaddr += sysinfo->banksize[nonzero] <<
2518 (sysinfo->interleaved ? 26 : 25);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002519 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002520 }
2521
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002522 /*
2523 * We have a bank with a non-zero size... Remember it
Stefan Reinauer278534d2008-10-29 04:51:07 +00002524 * for the next offset we have to calculate
2525 */
2526 nonzero = i;
2527
2528 /* Get CAS latency set up */
2529 switch (sysinfo->cas) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002530 case 5:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002531 mrsaddr = MRS_CAS_5;
2532 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002533 case 4:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002534 mrsaddr = MRS_CAS_4;
2535 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002536 case 3:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002537 mrsaddr = MRS_CAS_3;
2538 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002539 default:
2540 die("Jedec Error (CAS).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002541 }
2542
2543 /* Get tWR set */
2544 switch (sysinfo->twr) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002545 case 5:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002546 mrsaddr |= MRS_TWR_5;
2547 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002548 case 4:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002549 mrsaddr |= MRS_TWR_4;
2550 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002551 case 3:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002552 mrsaddr |= MRS_TWR_3;
2553 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002554 default:
2555 die("Jedec Error (tWR).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002556 }
2557
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002558 /* Set "Burst Type" */
2559 mrsaddr |= MRS_BT;
2560
Stefan Reinauer278534d2008-10-29 04:51:07 +00002561 /* Interleaved */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002562 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002563 mrsaddr = mrsaddr << 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002564
2565 /* Only burst length 8 supported */
2566 mrsaddr |= MRS_BL8;
2567
2568 /* Apply NOP */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002569 PRINTK_DEBUG("Apply NOP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002570 do_ram_command(RAM_COMMAND_NOP);
2571 ram_read32(bankaddr);
2572
2573 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002574 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002575 do_ram_command(RAM_COMMAND_PRECHARGE);
2576 ram_read32(bankaddr);
2577
2578 /* Extended Mode Register Set (2) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002579 PRINTK_DEBUG("Extended Mode Register Set(2)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002580 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_2);
2581 ram_read32(bankaddr);
2582
2583 /* Extended Mode Register Set (3) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002584 PRINTK_DEBUG("Extended Mode Register Set(3)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002585 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_3);
2586 ram_read32(bankaddr);
2587
2588 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002589 PRINTK_DEBUG("Extended Mode Register Set\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002590 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2591 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002592 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002593 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002594 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002595 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002596 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002597 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002598 ram_read32(tmpaddr);
2599
2600 /* Mode Register Set: Reset DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002601 PRINTK_DEBUG("MRS: Reset DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002602 do_ram_command(RAM_COMMAND_MRS);
2603 tmpaddr = bankaddr;
2604 tmpaddr |= mrsaddr;
2605 /* Set DLL reset bit */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002606 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002607 tmpaddr |= (1 << 12);
2608 else
2609 tmpaddr |= (1 << 11);
2610 ram_read32(tmpaddr);
2611
2612 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002613 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002614 do_ram_command(RAM_COMMAND_PRECHARGE);
2615 ram_read32(bankaddr);
2616
2617 /* CAS before RAS Refresh */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002618 PRINTK_DEBUG("CAS before RAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002619 do_ram_command(RAM_COMMAND_CBR);
2620
2621 /* CBR wants two READs */
2622 ram_read32(bankaddr);
2623 ram_read32(bankaddr);
2624
2625 /* Mode Register Set: Enable DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002626 PRINTK_DEBUG("MRS: Enable DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002627 do_ram_command(RAM_COMMAND_MRS);
2628
2629 tmpaddr = bankaddr;
2630 tmpaddr |= mrsaddr;
2631 ram_read32(tmpaddr);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002632
Stefan Reinauer278534d2008-10-29 04:51:07 +00002633 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002634 PRINTK_DEBUG("Extended Mode Register Set: ODT/OCD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002635 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002636
Stefan Reinauer278534d2008-10-29 04:51:07 +00002637 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002638 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002639 tmpaddr |= RTT_ODT_75_OHM | EMRS_OCD_DEFAULT;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002640 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002641 tmpaddr |= ((RTT_ODT_150_OHM | EMRS_OCD_DEFAULT) << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002642 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002643 tmpaddr |= RTT_ODT_150_OHM | EMRS_OCD_DEFAULT;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002644 ram_read32(tmpaddr);
2645
2646 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002647 PRINTK_DEBUG("Extended Mode Register Set: OCD Exit\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002648 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2649
2650 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002651 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002652 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002653 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002654 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002655 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002656 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002657 ram_read32(tmpaddr);
2658 }
2659}
2660
2661static void sdram_init_complete(void)
2662{
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002663 PRINTK_DEBUG("Normal Operation\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002664 do_ram_command(RAM_COMMAND_NORMAL);
2665}
2666
2667static void sdram_setup_processor_side(void)
2668{
2669 if (i945_silicon_revision() == 0)
Angel Pons1d4044a2021-03-27 19:11:51 +01002670 mchbar_setbits32(FSBPMC3, 1 << 2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002671
Angel Pons1d4044a2021-03-27 19:11:51 +01002672 mchbar_setbits8(0xb00, 1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002673
2674 if (i945_silicon_revision() == 0)
Angel Pons1d4044a2021-03-27 19:11:51 +01002675 mchbar_setbits32(SLPCTL, 1 << 8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002676}
2677
Stefan Reinauer278534d2008-10-29 04:51:07 +00002678/**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002679 * @param boot_path: 0 = normal, 1 = reset, 2 = resume from s3
Martin Rothf4cb4122015-01-06 10:27:39 -07002680 * @param spd_addresses pointer to a list of SPD addresses
Stefan Reinauer278534d2008-10-29 04:51:07 +00002681 */
Sven Schnelle541269b2011-02-21 09:39:17 +00002682void sdram_initialize(int boot_path, const u8 *spd_addresses)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002683{
2684 struct sys_info sysinfo;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002685
Patrick Georgi771328f2015-07-13 19:24:07 +02002686 timestamp_add_now(TS_BEFORE_INITRAM);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002687 printk(BIOS_DEBUG, "Setting up RAM controller.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002688
2689 memset(&sysinfo, 0, sizeof(sysinfo));
2690
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002691 sysinfo.boot_path = boot_path;
Sven Schnelle541269b2011-02-21 09:39:17 +00002692 sysinfo.spd_addresses = spd_addresses;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002693
Stefan Reinauer278534d2008-10-29 04:51:07 +00002694 /* Look at the type of DIMMs and verify all DIMMs are x8 or x16 width */
2695 sdram_get_dram_configuration(&sysinfo);
2696
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002697 /* If error, do cold boot */
2698 sdram_detect_errors(&sysinfo);
2699
Stefan Reinauer278534d2008-10-29 04:51:07 +00002700 /* Program PLL settings */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002701 sdram_program_pll_settings(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002702
Arthur Heymans18537812016-12-28 21:20:45 +01002703 /*
2704 * Program Graphics Frequency
2705 * Set core display and render clock on 945GC to the max
2706 */
Julius Wernercd49cce2019-03-05 16:53:33 -08002707 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM))
Arthur Heymans18537812016-12-28 21:20:45 +01002708 sdram_program_graphics_frequency(&sysinfo);
2709 else
Angel Pons3580d812020-06-11 14:13:33 +02002710 pci_write_config16(IGD_DEV, GCFC, 0x0534);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002711
2712 /* Program System Memory Frequency */
2713 sdram_program_memory_frequency(&sysinfo);
2714
2715 /* Determine Mode of Operation (Interleaved etc) */
2716 sdram_set_channel_mode(&sysinfo);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002717
Stefan Reinauer278534d2008-10-29 04:51:07 +00002718 /* Program Clock Crossing values */
2719 sdram_program_clock_crossing();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002720
Stefan Reinauer278534d2008-10-29 04:51:07 +00002721 /* Disable fast dispatch */
2722 sdram_disable_fast_dispatch();
2723
2724 /* Enable WIODLL Power Down in ACPI states */
Angel Pons1d4044a2021-03-27 19:11:51 +01002725 mchbar_setbits32(C0DMC, 1 << 24);
2726 mchbar_setbits32(C1DMC, 1 << 24);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002727
2728 /* Program DRAM Row Boundary/Attribute Registers */
2729
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002730 /* program row size DRB and set TOLUD */
2731 sdram_program_row_boundaries(&sysinfo);
2732
2733 /* program page size DRA */
2734 sdram_set_row_attributes(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002735
2736 /* Program CxBNKARC */
2737 sdram_set_bank_architecture(&sysinfo);
2738
2739 /* Program DRAM Timing and Control registers based on SPD */
2740 sdram_set_timing_and_control(&sysinfo);
2741
2742 /* On-Die Termination Adjustment */
2743 sdram_on_die_termination(&sysinfo);
2744
2745 /* Pre Jedec Initialization */
2746 sdram_pre_jedec_initialization();
2747
2748 /* Perform System Memory IO Initialization */
2749 sdram_initialize_system_memory_io(&sysinfo);
2750
2751 /* Perform System Memory IO Buffer Enable */
2752 sdram_enable_system_memory_io(&sysinfo);
2753
2754 /* Enable System Memory Clocks */
2755 sdram_enable_memory_clocks(&sysinfo);
2756
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002757 if (boot_path == BOOT_PATH_NORMAL) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002758 /* Jedec Initialization sequence */
2759 sdram_jedec_enable(&sysinfo);
2760 }
2761
2762 /* Program Power Management Registers */
2763 sdram_power_management(&sysinfo);
2764
2765 /* Post Jedec Init */
2766 sdram_post_jedec_initialization(&sysinfo);
2767
2768 /* Program DRAM Throttling */
2769 sdram_thermal_management();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002770
Stefan Reinauer278534d2008-10-29 04:51:07 +00002771 /* Normal Operations */
Stefan Reinaueraca6ec62009-10-26 17:12:21 +00002772 sdram_init_complete();
Stefan Reinauer278534d2008-10-29 04:51:07 +00002773
2774 /* Program Receive Enable Timings */
2775 sdram_program_receive_enable(&sysinfo);
2776
2777 /* Enable Periodic RCOMP */
2778 sdram_enable_rcomp();
2779
2780 /* Tell ICH7 that we're done */
Angel Ponse3c68d22020-06-08 12:09:03 +02002781 pci_and_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, (u8)~(1 << 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +00002782
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002783 printk(BIOS_DEBUG, "RAM initialization finished.\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002784
Stefan Reinauer278534d2008-10-29 04:51:07 +00002785 sdram_setup_processor_side();
Patrick Georgi771328f2015-07-13 19:24:07 +02002786 timestamp_add_now(TS_AFTER_INITRAM);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002787}