blob: 35875be372962ec915ca35cc480989ce807031e2 [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
Elyes Haouas4114fdc2022-10-02 13:48:07 +02003#include <cf9_reset.h>
Patrick Georgid0835952010-10-05 09:07:10 +00004#include <console/console.h>
Kyösti Mälkki7fbed222019-07-11 08:14:07 +03005#include <delay.h>
Arthur Heymans885c2892016-10-03 17:16:48 +02006#include <device/device.h>
Elyes Haouas4114fdc2022-10-02 13:48:07 +02007#include <device/dram/ddr2.h>
8#include <device/mmio.h>
9#include <device/pci_ops.h>
10#include <device/pci_type.h>
11#include <device/smbus_host.h>
Julius Werner7a8a4ab2015-05-22 16:26:40 -070012#include <lib.h>
Edwin Beasanteb50c7d2010-07-06 21:05:04 +000013#include <pc80/mc146818rtc.h>
Stefan Reinauer278534d2008-10-29 04:51:07 +000014#include <spd.h>
Patrick Georgid0835952010-10-05 09:07:10 +000015#include <string.h>
Elyes Haouas4114fdc2022-10-02 13:48:07 +020016#include <timestamp.h>
17#include <types.h>
18
Stefan Reinauer278534d2008-10-29 04:51:07 +000019#include "raminit.h"
20#include "i945.h"
Arthur Heymans885c2892016-10-03 17:16:48 +020021#include "chip.h"
Rudolf Marekc4369532010-12-13 19:59:13 +000022
Stefan Reinauer278534d2008-10-29 04:51:07 +000023/* Debugging macros. */
Julius Wernercd49cce2019-03-05 16:53:33 -080024#if CONFIG(DEBUG_RAM_SETUP)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000025#define PRINTK_DEBUG(x...) printk(BIOS_DEBUG, x)
Stefan Reinauer278534d2008-10-29 04:51:07 +000026#else
27#define PRINTK_DEBUG(x...)
28#endif
29
Stefan Reinauer278534d2008-10-29 04:51:07 +000030#define RAM_INITIALIZATION_COMPLETE (1 << 19)
31
32#define RAM_COMMAND_SELF_REFRESH (0x0 << 16)
33#define RAM_COMMAND_NOP (0x1 << 16)
34#define RAM_COMMAND_PRECHARGE (0x2 << 16)
35#define RAM_COMMAND_MRS (0x3 << 16)
36#define RAM_COMMAND_EMRS (0x4 << 16)
37#define RAM_COMMAND_CBR (0x6 << 16)
38#define RAM_COMMAND_NORMAL (0x7 << 16)
39
40#define RAM_EMRS_1 (0x0 << 21)
41#define RAM_EMRS_2 (0x1 << 21)
42#define RAM_EMRS_3 (0x2 << 21)
43
Arthur Heymans885c2892016-10-03 17:16:48 +020044#define DEFAULT_PCI_MMIO_SIZE 768
Sven Schnelle541269b2011-02-21 09:39:17 +000045static int get_dimm_spd_address(struct sys_info *sysinfo, int device)
46{
47 if (sysinfo->spd_addresses)
48 return sysinfo->spd_addresses[device];
49 else
Angel Ponse97a66d2021-04-03 00:15:16 +020050 return 0x50 + device;
Sven Schnelle541269b2011-02-21 09:39:17 +000051
52}
53
Stefan Reinauerbc8613e2010-08-25 18:35:42 +000054static __attribute__((noinline)) void do_ram_command(u32 command)
Stefan Reinauer278534d2008-10-29 04:51:07 +000055{
56 u32 reg32;
57
Angel Pons1d4044a2021-03-27 19:11:51 +010058 reg32 = mchbar_read32(DCC);
Angel Pons30492572020-06-11 13:24:54 +020059 reg32 &= ~((3 << 21) | (1 << 20) | (1 << 19) | (7 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +000060 reg32 |= command;
61
62 /* Also set Init Complete */
63 if (command == RAM_COMMAND_NORMAL)
64 reg32 |= RAM_INITIALIZATION_COMPLETE;
65
66 PRINTK_DEBUG(" Sending RAM command 0x%08x", reg32);
67
Angel Pons1d4044a2021-03-27 19:11:51 +010068 mchbar_write32(DCC, reg32); /* This is the actual magic */
Stefan Reinauer278534d2008-10-29 04:51:07 +000069
Stefan Reinauer779b3e32008-11-10 15:43:37 +000070 PRINTK_DEBUG("...done\n");
Stefan Reinauerd058ad12010-08-26 12:43:58 +000071
72 udelay(1);
Stefan Reinauer278534d2008-10-29 04:51:07 +000073}
74
Elyes HAOUAS964055d2022-01-14 18:56:49 +010075static void ram_read32(uintptr_t offset)
Stefan Reinauer278534d2008-10-29 04:51:07 +000076{
Elyes Haouase8bb6d22022-10-04 14:16:09 +020077 PRINTK_DEBUG(" RAM read: %" PRIxPTR "\n", offset);
Stefan Reinauer278534d2008-10-29 04:51:07 +000078
Elyes Haouas712c70b2022-02-25 10:05:22 +010079 read32p(offset);
Stefan Reinauer278534d2008-10-29 04:51:07 +000080}
81
Stefan Reinauer3c0bfaf2010-12-27 11:34:57 +000082void sdram_dump_mchbar_registers(void)
Stefan Reinauer278534d2008-10-29 04:51:07 +000083{
84 int i;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000085 printk(BIOS_DEBUG, "Dumping MCHBAR Registers\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +000086
Arthur Heymans70a8e342017-03-09 11:30:23 +010087 for (i = 0; i < 0xfff; i += 4) {
Angel Pons1d4044a2021-03-27 19:11:51 +010088 if (mchbar_read32(i) == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +000089 continue;
Angel Pons1d4044a2021-03-27 19:11:51 +010090 printk(BIOS_DEBUG, "0x%04x: 0x%08x\n", i, mchbar_read32(i));
Stefan Reinauer278534d2008-10-29 04:51:07 +000091 }
92}
Stefan Reinauer278534d2008-10-29 04:51:07 +000093
Stefan Reinauer24b4df52010-01-17 13:47:35 +000094static int memclk(void)
95{
Julius Wernercd49cce2019-03-05 16:53:33 -080096 int offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Elyes HAOUASc9848a82016-10-09 20:24:20 +020097
Angel Pons1d4044a2021-03-27 19:11:51 +010098 switch (((mchbar_read32(CLKCFG) >> 4) & 7) - offset) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +000099 case 1: return 400;
100 case 2: return 533;
101 case 3: return 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100102 default:
Elyes HAOUAS3cd43272020-03-05 22:01:17 +0100103 printk(BIOS_DEBUG, "%s: unknown register value %x\n", __func__,
Angel Pons1d4044a2021-03-27 19:11:51 +0100104 ((mchbar_read32(CLKCFG) >> 4) & 7) - offset);
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000105 }
106 return -1;
107}
108
Peter Stuge76d91432010-10-01 10:02:33 +0000109static u16 fsbclk(void)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000110{
Julius Wernercd49cce2019-03-05 16:53:33 -0800111 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Angel Pons1d4044a2021-03-27 19:11:51 +0100112 switch (mchbar_read32(CLKCFG) & 7) {
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200113 case 0: return 400;
114 case 1: return 533;
115 case 3: return 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100116 default:
Elyes HAOUAS3cd43272020-03-05 22:01:17 +0100117 printk(BIOS_DEBUG, "%s: unknown register value %x\n", __func__,
Angel Pons1d4044a2021-03-27 19:11:51 +0100118 mchbar_read32(CLKCFG) & 7);
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200119 }
120 return 0xffff;
Julius Wernercd49cce2019-03-05 16:53:33 -0800121 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Angel Pons1d4044a2021-03-27 19:11:51 +0100122 switch (mchbar_read32(CLKCFG) & 7) {
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200123 case 0: return 1066;
124 case 1: return 533;
125 case 2: return 800;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100126 default:
Elyes HAOUAS3cd43272020-03-05 22:01:17 +0100127 printk(BIOS_DEBUG, "%s: unknown register value %x\n", __func__,
Angel Pons1d4044a2021-03-27 19:11:51 +0100128 mchbar_read32(CLKCFG) & 7);
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200129 }
130 return 0xffff;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000131 }
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000132}
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000133
Stefan Reinauer278534d2008-10-29 04:51:07 +0000134static int sdram_capabilities_max_supported_memory_frequency(void)
135{
136 u32 reg32;
137
Patrick Georgi77d66832010-10-01 08:02:45 +0000138#if CONFIG_MAXIMUM_SUPPORTED_FREQUENCY
139 return CONFIG_MAXIMUM_SUPPORTED_FREQUENCY;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000140#endif
141
Angel Pons3580d812020-06-11 14:13:33 +0200142 reg32 = pci_read_config32(HOST_BRIDGE, 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000143 reg32 &= (7 << 0);
144
145 switch (reg32) {
146 case 4: return 400;
147 case 3: return 533;
148 case 2: return 667;
149 }
150 /* Newer revisions of this chipset rather support faster memory clocks,
151 * so if it's a reserved value, return the fastest memory clock that we
152 * know of and can handle
153 */
154 return 667;
155}
156
157/**
158 * @brief determine whether chipset is capable of dual channel interleaved mode
159 *
160 * @return 1 if interleaving is supported, 0 otherwise
161 */
162static int sdram_capabilities_interleave(void)
163{
164 u32 reg32;
165
Angel Pons3580d812020-06-11 14:13:33 +0200166 reg32 = pci_read_config32(HOST_BRIDGE, 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000167 reg32 >>= 25;
168 reg32 &= 1;
169
170 return (!reg32);
171}
172
173/**
174 * @brief determine whether chipset is capable of two memory channels
175 *
176 * @return 1 if dual channel operation is supported, 0 otherwise
177 */
178static int sdram_capabilities_dual_channel(void)
179{
180 u32 reg32;
181
Angel Pons3580d812020-06-11 14:13:33 +0200182 reg32 = pci_read_config32(HOST_BRIDGE, 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000183 reg32 >>= 24;
184 reg32 &= 1;
185
186 return (!reg32);
187}
188
189static int sdram_capabilities_enhanced_addressing_xor(void)
190{
191 u8 reg8;
192
Angel Pons3580d812020-06-11 14:13:33 +0200193 reg8 = pci_read_config8(HOST_BRIDGE, 0xe5); /* CAPID0 + 5 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000194 reg8 &= (1 << 7);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000195
Stefan Reinauer278534d2008-10-29 04:51:07 +0000196 return (!reg8);
197}
198
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000199#define GFX_FREQUENCY_CAP_166MHZ 0x04
200#define GFX_FREQUENCY_CAP_200MHZ 0x03
201#define GFX_FREQUENCY_CAP_250MHZ 0x02
202#define GFX_FREQUENCY_CAP_ALL 0x00
203
204static int sdram_capabilities_core_frequencies(void)
205{
206 u8 reg8;
207
Angel Pons3580d812020-06-11 14:13:33 +0200208 reg8 = pci_read_config8(HOST_BRIDGE, 0xe5); /* CAPID0 + 5 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000209 reg8 &= (1 << 3) | (1 << 2) | (1 << 1);
210 reg8 >>= 1;
211
Arthur Heymans70a8e342017-03-09 11:30:23 +0100212 return reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000213}
214
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000215static void sdram_detect_errors(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000216{
217 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000218 u8 do_reset = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000219
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100220 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000221
Angel Pons30492572020-06-11 13:24:54 +0200222 if (reg8 & ((1 << 7) | (1 << 2))) {
223 if (reg8 & (1 << 2)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000224 printk(BIOS_DEBUG, "SLP S4# Assertion Width Violation.\n");
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000225 /* Write back clears bit 2 */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100226 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000227 do_reset = 1;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000228
Stefan Reinauer278534d2008-10-29 04:51:07 +0000229 }
230
Angel Pons30492572020-06-11 13:24:54 +0200231 if (reg8 & (1 << 7)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000232 printk(BIOS_DEBUG, "DRAM initialization was interrupted.\n");
Angel Pons30492572020-06-11 13:24:54 +0200233 reg8 &= ~(1 << 7);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100234 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000235 do_reset = 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000236 }
237
238 /* Set SLP_S3# Assertion Stretch Enable */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100239 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000240 reg8 |= (1 << 3);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100241 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000242
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000243 if (do_reset) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000244 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200245 full_reset();
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000246 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000247 }
248
249 /* Set DRAM initialization bit in ICH7 */
Angel Ponse3c68d22020-06-08 12:09:03 +0200250 pci_or_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, 1 << 7);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000251
Peter Stuge751508a2012-01-27 22:17:09 +0100252 /* clear self refresh status if check is disabled or not a resume */
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200253 if (!CONFIG(CHECK_SLFRCS_ON_RESUME) || sysinfo->boot_path != BOOT_PATH_RESUME) {
Angel Pons1d4044a2021-03-27 19:11:51 +0100254 mchbar_setbits8(SLFRCS, 3);
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000255 } else {
256 /* Validate self refresh config */
257 if (((sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED) ||
258 (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)) &&
Angel Pons1d4044a2021-03-27 19:11:51 +0100259 !(mchbar_read8(SLFRCS) & (1 << 0))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000260 do_reset = 1;
261 }
262 if (((sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED) ||
263 (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) &&
Angel Pons1d4044a2021-03-27 19:11:51 +0100264 !(mchbar_read8(SLFRCS) & (1 << 1))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000265 do_reset = 1;
266 }
267 }
268
269 if (do_reset) {
270 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200271 full_reset();
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000272 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000273}
Stefan Reinauer278534d2008-10-29 04:51:07 +0000274
Arthur Heymans0ab49042017-02-06 22:40:14 +0100275struct timings {
276 u32 min_tCLK_cas[8];
277 u32 min_tRAS;
278 u32 min_tRP;
279 u32 min_tRCD;
280 u32 min_tWR;
281 u32 min_tRFC;
282 u32 max_tRR;
283 u8 cas_mask;
284};
Stefan Reinauer278534d2008-10-29 04:51:07 +0000285
Arthur Heymans0ab49042017-02-06 22:40:14 +0100286/**
287 * @brief loop over dimms and save maximal timings
288 */
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200289static void gather_common_timing(struct sys_info *sysinfo, struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000290{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100291
292 int i, j;
293 u8 raw_spd[SPD_SIZE_MAX_DDR2];
294 u8 dimm_mask = 0;
295
296 memset(saved_timings, 0, sizeof(*saved_timings));
297 saved_timings->max_tRR = UINT32_MAX;
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200298 saved_timings->cas_mask = SPD_CAS_LATENCY_DDR2_3 | SPD_CAS_LATENCY_DDR2_4
299 | SPD_CAS_LATENCY_DDR2_5;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000300
301 /**
302 * i945 supports two DIMMs, in two configurations:
303 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000304 * - single channel with two DIMMs
305 * - dual channel with one DIMM per channel
Stefan Reinauer278534d2008-10-29 04:51:07 +0000306 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000307 * In practice dual channel mainboards have their SPD at 0x50/0x52
308 * whereas single channel configurations have their SPD at 0x50/0x51.
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000309 *
Stefan Reinauer278534d2008-10-29 04:51:07 +0000310 * The capability register knows a lot about the channel configuration
Uwe Hermannd773fd32010-11-20 20:23:08 +0000311 * but for now we stick with the information we gather via SPD.
Stefan Reinauer278534d2008-10-29 04:51:07 +0000312 */
313
Arthur Heymans0ab49042017-02-06 22:40:14 +0100314 printk(BIOS_DEBUG, "This mainboard supports ");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000315 if (sdram_capabilities_dual_channel()) {
316 sysinfo->dual_channel = 1;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100317 printk(BIOS_DEBUG, "Dual Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000318 } else {
319 sysinfo->dual_channel = 0;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100320 printk(BIOS_DEBUG, "only Single Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000321 }
322
Arthur Heymans70a8e342017-03-09 11:30:23 +0100323 for (i = 0; i < (2 * DIMM_SOCKETS); i++) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100324 int device = get_dimm_spd_address(sysinfo, i), bytes_read;
Arthur Heymansfc31e442018-02-12 15:12:34 +0100325 struct dimm_attr_ddr2_st dimm_info;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000326
327 /* Initialize the socket information with a sane value */
328 sysinfo->dimm[i] = SYSINFO_DIMM_NOT_POPULATED;
329
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000330 /* Dual Channel not supported, but Channel 1? Bail out */
331 if (!sdram_capabilities_dual_channel() && (i >> 1))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000332 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000333
Kyösti Mälkkibd659852020-01-05 20:00:18 +0200334 if (smbus_read_byte(device, SPD_MEMORY_TYPE) !=
Arthur Heymans0ab49042017-02-06 22:40:14 +0100335 SPD_MEMORY_TYPE_SDRAM_DDR2) {
336 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: N/A\n",
337 (i >> 1), (i & 1));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000338 continue;
339 }
340
Arthur Heymans0ab49042017-02-06 22:40:14 +0100341 /*
342 * spd_decode_ddr2() needs a 128-byte sized array but
343 * only the first 64 bytes contain data needed for raminit.
344 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000345
Kyösti Mälkkic01a5052019-01-30 09:39:23 +0200346 bytes_read = i2c_eeprom_read(device, 0, 64, raw_spd);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100347 printk(BIOS_DEBUG, "Reading SPD using i2c block operation.\n");
Julius Wernercd49cce2019-03-05 16:53:33 -0800348 if (CONFIG(DEBUG_RAM_SETUP) && bytes_read > 0)
Arthur Heymans0ab49042017-02-06 22:40:14 +0100349 hexdump(raw_spd, bytes_read);
Arthur Heymans56619452017-09-21 09:12:42 +0200350 if (bytes_read != 64) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100351 /* Try again with SMBUS byte read */
352 printk(BIOS_DEBUG, "i2c block operation failed,"
Paul Menzel105e3682017-09-21 08:11:05 +0200353 " trying smbus byte operation.\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100354 for (j = 0; j < 64; j++)
Kyösti Mälkkibd659852020-01-05 20:00:18 +0200355 raw_spd[j] = smbus_read_byte(device, j);
Julius Wernercd49cce2019-03-05 16:53:33 -0800356 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100357 hexdump(raw_spd, 64);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100358 }
Arthur Heymans56619452017-09-21 09:12:42 +0200359
360 if (spd_decode_ddr2(&dimm_info, raw_spd) != SPD_STATUS_OK) {
361 printk(BIOS_WARNING, "Encountered problems with SPD, "
362 "skipping this DIMM.\n");
363 continue;
364 }
365
Julius Wernercd49cce2019-03-05 16:53:33 -0800366 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100367 dram_print_spd_ddr2(&dimm_info);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000368
Arthur Heymans0ab49042017-02-06 22:40:14 +0100369 if (dimm_info.flags.is_ecc)
370 die("\nError: ECC memory not supported by this chipset\n");
371
372 if (spd_dimm_is_registered_ddr2(dimm_info.dimm_type))
373 die("\nError: Registered memory not supported by this chipset\n");
374
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200375 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: ", (i >> 1), (i & 1));
Arthur Heymans0ab49042017-02-06 22:40:14 +0100376 /**
377 * There are 5 different possible populations for a DIMM socket:
378 * 0. x16 double ranked (X16DS)
379 * 1. x8 double ranked (X8DS)
380 * 2. x16 single ranked (X16SS)
381 * 3. x8 double stacked (X8DDS)
382 * 4. Unpopulated
383 */
384 switch (dimm_info.width) {
385 case 8:
386 switch (dimm_info.ranks) {
387 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000388 printk(BIOS_DEBUG, "x8DDS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000389 sysinfo->dimm[i] = SYSINFO_DIMM_X8DDS;
390 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100391 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000392 printk(BIOS_DEBUG, "x8DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000393 sysinfo->dimm[i] = SYSINFO_DIMM_X8DS;
394 break;
395 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000396 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000397 }
398 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100399 case 16:
400 switch (dimm_info.ranks) {
401 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000402 printk(BIOS_DEBUG, "x16DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000403 sysinfo->dimm[i] = SYSINFO_DIMM_X16DS;
404 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100405 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000406 printk(BIOS_DEBUG, "x16SS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000407 sysinfo->dimm[i] = SYSINFO_DIMM_X16SS;
408 break;
409 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000410 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000411 }
412 break;
413 default:
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000414 die("Unsupported DDR-II memory width.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000415 }
416
Arthur Heymans0ab49042017-02-06 22:40:14 +0100417 /* Is the current DIMM a stacked DIMM? */
418 if (dimm_info.flags.stacked)
419 sysinfo->package = SYSINFO_PACKAGE_STACKED;
420
421 if (!dimm_info.flags.bl8)
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100422 die("Only DDR-II RAM with burst length 8 is supported.\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100423
424 if (dimm_info.ranksize_mb < 128)
425 die("DDR-II rank size smaller than 128MB is not supported.\n");
426
427 sysinfo->banksize[i * 2] = dimm_info.ranksize_mb / 32;
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200428 printk(BIOS_DEBUG, "DIMM %d side 0 = %d MB\n", i, sysinfo->banksize[i * 2] * 32);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100429 if (dimm_info.ranks == 2) {
430 sysinfo->banksize[(i * 2) + 1] =
431 dimm_info.ranksize_mb / 32;
432 printk(BIOS_DEBUG, "DIMM %d side 1 = %d MB\n",
433 i, sysinfo->banksize[(i * 2) + 1] * 32);
434 }
435
Arthur Heymans0ab49042017-02-06 22:40:14 +0100436 sysinfo->rows[i] = dimm_info.row_bits;
437 sysinfo->cols[i] = dimm_info.col_bits;
438 sysinfo->banks[i] = dimm_info.banks;
439
440 /* int min_tRAS, min_tRP, min_tRCD, min_tWR, min_tRFC; */
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200441 saved_timings->min_tRAS = MAX(saved_timings->min_tRAS, dimm_info.tRAS);
442 saved_timings->min_tRP = MAX(saved_timings->min_tRP, dimm_info.tRP);
443 saved_timings->min_tRCD = MAX(saved_timings->min_tRCD, dimm_info.tRCD);
444 saved_timings->min_tWR = MAX(saved_timings->min_tWR, dimm_info.tWR);
445 saved_timings->min_tRFC = MAX(saved_timings->min_tRFC, dimm_info.tRFC);
446 saved_timings->max_tRR = MIN(saved_timings->max_tRR, dimm_info.tRR);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100447 saved_timings->cas_mask &= dimm_info.cas_supported;
448 for (j = 0; j < 8; j++) {
449 if (!(saved_timings->cas_mask & (1 << j)))
450 saved_timings->min_tCLK_cas[j] = 0;
451 else
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200452 saved_timings->min_tCLK_cas[j] = MAX(dimm_info.cycle_time[j],
Arthur Heymans0ab49042017-02-06 22:40:14 +0100453 saved_timings->min_tCLK_cas[j]);
454 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000455 dimm_mask |= (1 << i);
456 }
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200457 if (!dimm_mask)
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000458 die("No memory installed.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000459
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200460 if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1)))
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100461 /* FIXME: Possibly does not boot in this case */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000462 printk(BIOS_INFO, "Channel 0 has no memory populated.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000463}
464
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200465static void choose_tclk(struct sys_info *sysinfo, struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000466{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100467 u32 ctrl_min_tclk;
468 int try_cas;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000469
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200470 ctrl_min_tclk = 2 * 256 * 1000 / sdram_capabilities_max_supported_memory_frequency();
Arthur Heymans0ab49042017-02-06 22:40:14 +0100471 normalize_tck(&ctrl_min_tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000472
Arthur Heymans0ab49042017-02-06 22:40:14 +0100473 try_cas = spd_get_msbs(saved_timings->cas_mask);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000474
Arthur Heymans0ab49042017-02-06 22:40:14 +0100475 while (saved_timings->cas_mask & (1 << try_cas) && try_cas > 0) {
476 sysinfo->cas = try_cas;
477 sysinfo->tclk = saved_timings->min_tCLK_cas[try_cas];
478 if (sysinfo->tclk >= ctrl_min_tclk &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200479 saved_timings->min_tCLK_cas[try_cas] !=
480 saved_timings->min_tCLK_cas[try_cas - 1])
Stefan Reinauer278534d2008-10-29 04:51:07 +0000481 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100482 try_cas--;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000483 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000484
Arthur Heymans0ab49042017-02-06 22:40:14 +0100485 normalize_tck(&sysinfo->tclk);
486
487 if ((sysinfo->cas < 3) || (sysinfo->tclk == 0))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000488 die("Could not find common memory frequency and CAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000489
Arthur Heymans0ab49042017-02-06 22:40:14 +0100490 /*
491 * The loop can still results in a timing too fast for the
492 * memory controller.
493 */
494 if (sysinfo->tclk < ctrl_min_tclk)
495 sysinfo->tclk = ctrl_min_tclk;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000496
Arthur Heymans0ab49042017-02-06 22:40:14 +0100497 switch (sysinfo->tclk) {
498 case TCK_200MHZ:
499 sysinfo->memory_frequency = 400;
500 break;
501 case TCK_266MHZ:
502 sysinfo->memory_frequency = 533;
503 break;
504 case TCK_333MHZ:
505 sysinfo->memory_frequency = 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100506 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000507 }
508
Arthur Heymans0ab49042017-02-06 22:40:14 +0100509 printk(BIOS_DEBUG,
510 "Memory will be driven at %dMT with CAS=%d clocks\n",
511 sysinfo->memory_frequency, sysinfo->cas);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000512}
513
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200514static void derive_timings(struct sys_info *sysinfo, struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000515{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100516 sysinfo->tras = DIV_ROUND_UP(saved_timings->min_tRAS, sysinfo->tclk);
517 if (sysinfo->tras > 0x18)
518 die("DDR-II Module does not support this frequency (tRAS error)\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000519
Arthur Heymans0ab49042017-02-06 22:40:14 +0100520 sysinfo->trp = DIV_ROUND_UP(saved_timings->min_tRP, sysinfo->tclk);
521 if (sysinfo->trp > 6)
522 die("DDR-II Module does not support this frequency (tRP error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000523
Arthur Heymans0ab49042017-02-06 22:40:14 +0100524 sysinfo->trcd = DIV_ROUND_UP(saved_timings->min_tRCD, sysinfo->tclk);
525 if (sysinfo->trcd > 6)
526 die("DDR-II Module does not support this frequency (tRCD error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000527
Arthur Heymans0ab49042017-02-06 22:40:14 +0100528 sysinfo->twr = DIV_ROUND_UP(saved_timings->min_tWR, sysinfo->tclk);
529 if (sysinfo->twr > 5)
530 die("DDR-II Module does not support this frequency (tWR error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000531
Arthur Heymans0ab49042017-02-06 22:40:14 +0100532 sysinfo->trfc = DIV_ROUND_UP(saved_timings->min_tRFC, sysinfo->tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000533
Arthur Heymans0ab49042017-02-06 22:40:14 +0100534 printk(BIOS_DEBUG, "tRAS = %d cycles\n", sysinfo->tras);
535 printk(BIOS_DEBUG, "tRP = %d cycles\n", sysinfo->trp);
536 printk(BIOS_DEBUG, "tRCD = %d cycles\n", sysinfo->trcd);
537 printk(BIOS_DEBUG, "tWR = %d cycles\n", sysinfo->twr);
538 printk(BIOS_DEBUG, "tRFC = %d cycles\n", sysinfo->trfc);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000539
Arthur Heymans0ab49042017-02-06 22:40:14 +0100540 /* Refresh is slower than 15.6us, use 15.6us */
541 /* tRR is decoded in units of 1/256us */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000542
Arthur Heymans0ab49042017-02-06 22:40:14 +0100543#define T_RR_7_8US 2000000
544#define T_RR_15_6US 4000000
545#define REFRESH_7_8US 1
546#define REFRESH_15_6US 0
Stefan Reinauer278534d2008-10-29 04:51:07 +0000547
Arthur Heymans0ab49042017-02-06 22:40:14 +0100548 if (saved_timings->max_tRR < T_RR_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000549 die("DDR-II module has unsupported refresh value\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100550 else if (saved_timings->max_tRR < T_RR_15_6US)
551 sysinfo->refresh = REFRESH_7_8US;
552 else
553 sysinfo->refresh = REFRESH_15_6US;
Angel Pons30492572020-06-11 13:24:54 +0200554 printk(BIOS_DEBUG, "Refresh: %s\n", sysinfo->refresh ? "7.8us" : "15.6us");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000555}
556
Arthur Heymans0ab49042017-02-06 22:40:14 +0100557/**
558 * @brief Get generic DIMM parameters.
559 * @param sysinfo Central memory controller information structure
560 *
561 * This function gathers several pieces of information for each system DIMM:
562 * o DIMM width (x8 / x16)
563 * o DIMM rank (single ranked / dual ranked)
564 *
565 * Also, some non-supported scenarios are detected.
566 */
567
568static void sdram_get_dram_configuration(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000569{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100570 struct timings saved_timings;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000571
Arthur Heymans0ab49042017-02-06 22:40:14 +0100572 gather_common_timing(sysinfo, &saved_timings);
573 choose_tclk(sysinfo, &saved_timings);
574 derive_timings(sysinfo, &saved_timings);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000575}
576
Arthur Heymans70a8e342017-03-09 11:30:23 +0100577static void sdram_program_dram_width(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000578{
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200579 u16 c0dramw = 0, c1dramw = 0;
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200580 int i, idx;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000581
582 if (sysinfo->dual_channel)
583 idx = 2;
584 else
585 idx = 1;
586
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200587 for (i = 0; i < DIMM_SOCKETS; i++) { /* Channel 0 */
588 switch (sysinfo->dimm[i]) {
589 case SYSINFO_DIMM_X16DS:
Angel Pons30492572020-06-11 13:24:54 +0200590 c0dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200591 break;
592 case SYSINFO_DIMM_X8DS:
Angel Pons30492572020-06-11 13:24:54 +0200593 c0dramw |= (0x0001) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200594 break;
595 case SYSINFO_DIMM_X16SS:
Angel Pons30492572020-06-11 13:24:54 +0200596 c0dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200597 break;
598 case SYSINFO_DIMM_X8DDS:
Angel Pons30492572020-06-11 13:24:54 +0200599 c0dramw |= (0x0005) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200600 break;
601 case SYSINFO_DIMM_NOT_POPULATED:
Angel Pons30492572020-06-11 13:24:54 +0200602 c0dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200603 break;
604 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000605 }
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200606 for (i = DIMM_SOCKETS; i < idx * DIMM_SOCKETS; i++) { /* Channel 1 */
607 switch (sysinfo->dimm[i]) {
608 case SYSINFO_DIMM_X16DS:
Angel Pons30492572020-06-11 13:24:54 +0200609 c1dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200610 break;
611 case SYSINFO_DIMM_X8DS:
Angel Pons30492572020-06-11 13:24:54 +0200612 c1dramw |= (0x0010) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200613 break;
614 case SYSINFO_DIMM_X16SS:
Angel Pons30492572020-06-11 13:24:54 +0200615 c1dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200616 break;
617 case SYSINFO_DIMM_X8DDS:
Angel Pons30492572020-06-11 13:24:54 +0200618 c1dramw |= (0x0050) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200619 break;
620 case SYSINFO_DIMM_NOT_POPULATED:
Angel Pons30492572020-06-11 13:24:54 +0200621 c1dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200622 break;
623 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000624 }
625
Angel Pons1d4044a2021-03-27 19:11:51 +0100626 mchbar_write16(C0DRAMW, c0dramw);
627 mchbar_write16(C1DRAMW, c1dramw);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000628}
629
630static void sdram_write_slew_rates(u32 offset, const u32 *slew_rate_table)
631{
632 int i;
633
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200634 for (i = 0; i < 16; i++)
Angel Pons1d4044a2021-03-27 19:11:51 +0100635 mchbar_write32(offset + (i * 4), slew_rate_table[i]);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000636}
637
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000638static const u32 dq2030[] = {
639 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
640 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
641 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
642 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
643};
644
645static const u32 dq2330[] = {
646 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
647 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
648 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
649 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
650};
651
652static const u32 cmd2710[] = {
653 0x07060605, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
654 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
655 0x1110100f, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
656 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
657};
658
659static const u32 cmd3210[] = {
660 0x0f0d0b0a, 0x17151311, 0x1f1d1b19, 0x1f1f1f1f,
661 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
662 0x18171615, 0x1f1f1c1a, 0x1f1f1f1f, 0x1f1f1f1f,
663 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
664};
665
666static const u32 clk2030[] = {
667 0x0e0d0d0c, 0x100f0f0e, 0x100f0e0d, 0x15131211,
668 0x1d1b1917, 0x2523211f, 0x2a282927, 0x32302e2c,
669 0x17161514, 0x1b1a1918, 0x1f1e1d1c, 0x23222120,
670 0x27262524, 0x2d2b2928, 0x3533312f, 0x3d3b3937
671};
672
673static const u32 ctl3215[] = {
674 0x01010000, 0x03020101, 0x07060504, 0x0b0a0908,
675 0x100f0e0d, 0x14131211, 0x18171615, 0x1c1b1a19,
676 0x05040403, 0x07060605, 0x0a090807, 0x0f0d0c0b,
677 0x14131211, 0x18171615, 0x1c1b1a19, 0x201f1e1d
678};
679
680static const u32 ctl3220[] = {
681 0x05040403, 0x07060505, 0x0e0c0a08, 0x1a171411,
682 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e,
683 0x09080807, 0x0b0a0a09, 0x0f0d0c0b, 0x1b171311,
684 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e
685};
686
687static const u32 nc[] = {
688 0x00000000, 0x00000000, 0x00000000, 0x00000000,
689 0x00000000, 0x00000000, 0x00000000, 0x00000000,
690 0x00000000, 0x00000000, 0x00000000, 0x00000000,
691 0x00000000, 0x00000000, 0x00000000, 0x00000000
692};
693
694enum {
695 DQ2030,
696 DQ2330,
697 CMD2710,
698 CMD3210,
699 CLK2030,
700 CTL3215,
701 CTL3220,
702 NC,
703};
704
705static const u8 dual_channel_slew_group_lookup[] = {
706 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
707 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
708 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
709 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
710 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
711
712 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
713 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
714 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
715 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
716 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
717
718 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
719 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
720 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
721 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
722 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
723
724 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
725 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
726 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
727 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
728 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, NC, NC,
729
730 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
731 NC, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
732 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
733 NC, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD2710
734};
735
736static const u8 single_channel_slew_group_lookup[] = {
737 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
738 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
739 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
740 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
741 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
742
743 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
744 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
745 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
746 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
747 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
748
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, DQ2330, CMD3210,
752 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
753 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
754
755 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
756 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
757 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
758 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
759 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
760
761 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
762 DQ2330, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
763 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
764 DQ2330, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD3210
765};
766
767static const u32 *slew_group_lookup(int dual_channel, int index)
768{
769 const u8 *slew_group;
770 /* Dual Channel needs different tables. */
771 if (dual_channel)
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100772 slew_group = dual_channel_slew_group_lookup;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000773 else
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100774 slew_group = single_channel_slew_group_lookup;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000775
776 switch (slew_group[index]) {
777 case DQ2030: return dq2030;
778 case DQ2330: return dq2330;
779 case CMD2710: return cmd2710;
780 case CMD3210: return cmd3210;
781 case CLK2030: return clk2030;
782 case CTL3215: return ctl3215;
783 case CTL3220: return ctl3220;
784 case NC: return nc;
785 }
786
787 return nc;
788}
789
Julius Wernercd49cce2019-03-05 16:53:33 -0800790#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000791/* Strength multiplier tables */
792static const u8 dual_channel_strength_multiplier[] = {
793 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
794 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
795 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
796 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
797 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
798 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
799 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
800 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
801 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
802 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
803 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
804 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
805 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
806 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
807 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
808 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
809 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
810 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
811 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
812 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
813 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
814 0x00, 0x00, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
815 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
816 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x44, 0x22
817};
818
819static const u8 single_channel_strength_multiplier[] = {
820 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
821 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
822 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
823 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
824 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
825 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
826 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
827 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
828 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
829 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
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, 0x33, 0x11,
833 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
834 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
835 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
836 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
837 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
838 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
839 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
840 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
841 0x33, 0x00, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
842 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
843 0x33, 0x00, 0x11, 0x00, 0x44, 0x44, 0x33, 0x11
844};
Julius Wernercd49cce2019-03-05 16:53:33 -0800845#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000846static const u8 dual_channel_strength_multiplier[] = {
847 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
848 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
849 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
850 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
851 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
852 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
853 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
854 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
855 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
856 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
857 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
858 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
859 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
860 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
861 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
862 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
863 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
864 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
865 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
866 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
867 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
868 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
869 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
870 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33
871};
872
873static const u8 single_channel_strength_multiplier[] = {
874 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
875 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
876 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
877 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
878 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
879 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
880 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
881 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
882 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
883 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
884 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
885 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
886 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
887 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
888 0x44, 0x22, 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, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
892 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
893 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
894 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
895 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
896 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
897 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00
898};
899#endif
900
Stefan Reinauer278534d2008-10-29 04:51:07 +0000901static void sdram_rcomp_buffer_strength_and_slew(struct sys_info *sysinfo)
902{
Arthur Heymans70a8e342017-03-09 11:30:23 +0100903 const u8 *strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000904 int idx, dual_channel;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000905
906 /* Set Strength Multipliers */
907
908 /* Dual Channel needs different tables. */
909 if (sdram_capabilities_dual_channel()) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000910 printk(BIOS_DEBUG, "Programming Dual Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000911 strength_multiplier = dual_channel_strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000912 dual_channel = 1;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100913 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[2];
Stefan Reinauer278534d2008-10-29 04:51:07 +0000914 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000915 printk(BIOS_DEBUG, "Programming Single Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000916 strength_multiplier = single_channel_strength_multiplier;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000917 dual_channel = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000918 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[1];
919 }
920
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000921 printk(BIOS_DEBUG, "Table Index: %d\n", idx);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000922
Angel Pons1d4044a2021-03-27 19:11:51 +0100923 mchbar_write8(G1SC, strength_multiplier[idx * 8 + 0]);
924 mchbar_write8(G2SC, strength_multiplier[idx * 8 + 1]);
925 mchbar_write8(G3SC, strength_multiplier[idx * 8 + 2]);
926 mchbar_write8(G4SC, strength_multiplier[idx * 8 + 3]);
927 mchbar_write8(G5SC, strength_multiplier[idx * 8 + 4]);
928 mchbar_write8(G6SC, strength_multiplier[idx * 8 + 5]);
929 mchbar_write8(G7SC, strength_multiplier[idx * 8 + 6]);
930 mchbar_write8(G8SC, strength_multiplier[idx * 8 + 7]);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000931
932 /* Channel 0 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000933 sdram_write_slew_rates(G1SRPUT, slew_group_lookup(dual_channel, idx * 8 + 0));
934 sdram_write_slew_rates(G2SRPUT, slew_group_lookup(dual_channel, idx * 8 + 1));
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200935 if ((slew_group_lookup(dual_channel, idx * 8 + 2) != nc) &&
936 (sysinfo->package == SYSINFO_PACKAGE_STACKED))
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000937
Stefan Reinauer278534d2008-10-29 04:51:07 +0000938 sdram_write_slew_rates(G3SRPUT, ctl3220);
Arthur Heymans70a8e342017-03-09 11:30:23 +0100939 else
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000940 sdram_write_slew_rates(G3SRPUT, slew_group_lookup(dual_channel, idx * 8 + 2));
Arthur Heymans70a8e342017-03-09 11:30:23 +0100941
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000942 sdram_write_slew_rates(G4SRPUT, slew_group_lookup(dual_channel, idx * 8 + 3));
943 sdram_write_slew_rates(G5SRPUT, slew_group_lookup(dual_channel, idx * 8 + 4));
944 sdram_write_slew_rates(G6SRPUT, slew_group_lookup(dual_channel, idx * 8 + 5));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000945
946 /* Channel 1 */
947 if (sysinfo->dual_channel) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000948 sdram_write_slew_rates(G7SRPUT, slew_group_lookup(dual_channel, idx * 8 + 6));
949 sdram_write_slew_rates(G8SRPUT, slew_group_lookup(dual_channel, idx * 8 + 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000950 } else {
951 sdram_write_slew_rates(G7SRPUT, nc);
952 sdram_write_slew_rates(G8SRPUT, nc);
953 }
954}
955
956static void sdram_enable_rcomp(void)
957{
958 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000959 /* Enable Global Periodic RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000960 udelay(300);
Angel Pons1d4044a2021-03-27 19:11:51 +0100961 reg32 = mchbar_read32(GBRCOMPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000962 reg32 &= ~(1 << 23);
Angel Pons1d4044a2021-03-27 19:11:51 +0100963 mchbar_write32(GBRCOMPCTL, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000964}
965
966static void sdram_program_dll_timings(struct sys_info *sysinfo)
967{
Elyes HAOUAS44a30662017-02-23 13:14:44 +0100968 u32 channeldll = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000969 int i;
970
Elyes HAOUAS38424982016-08-21 12:01:04 +0200971 printk(BIOS_DEBUG, "Programming DLL Timings...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000972
Angel Pons1d4044a2021-03-27 19:11:51 +0100973 mchbar_clrbits16(DQSMT, 3 << 12 | 1 << 10 | 0xf << 0);
974 mchbar_setbits16(DQSMT, 1 << 13 | 0xc << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000975
976 /* We drive both channels with the same speed */
Julius Wernercd49cce2019-03-05 16:53:33 -0800977 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +0100978 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +0100979 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200980 channeldll = 0x26262626;
981 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100982 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200983 channeldll = 0x22222222;
984 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100985 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200986 channeldll = 0x11111111;
987 break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +0100988 }
Julius Wernercd49cce2019-03-05 16:53:33 -0800989 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +0100990 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +0100991 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200992 channeldll = 0x33333333;
993 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100994 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200995 channeldll = 0x24242424;
996 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100997 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200998 channeldll = 0x25252525;
999 break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001000 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001001 }
1002
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001003 for (i = 0; i < 4; i++) {
Angel Pons1d4044a2021-03-27 19:11:51 +01001004 mchbar_write32(C0R0B00DQST + (i * 0x10) + 0, channeldll);
1005 mchbar_write32(C0R0B00DQST + (i * 0x10) + 4, channeldll);
1006 mchbar_write32(C1R0B00DQST + (i * 0x10) + 0, channeldll);
1007 mchbar_write32(C1R0B00DQST + (i * 0x10) + 4, channeldll);
Julius Wernercd49cce2019-03-05 16:53:33 -08001008 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Angel Pons1d4044a2021-03-27 19:11:51 +01001009 mchbar_write8(C0R0B00DQST + (i * 0x10) + 8, channeldll & 0xff);
1010 mchbar_write8(C1R0B00DQST + (i * 0x10) + 8, channeldll & 0xff);
Paul Menzelbce7e332017-02-22 18:46:27 +01001011 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001012 }
1013}
1014
1015static void sdram_force_rcomp(void)
1016{
1017 u32 reg32;
1018 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001019
Angel Pons1d4044a2021-03-27 19:11:51 +01001020 reg32 = mchbar_read32(ODTC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001021 reg32 |= (1 << 28);
Angel Pons1d4044a2021-03-27 19:11:51 +01001022 mchbar_write32(ODTC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001023
Angel Pons1d4044a2021-03-27 19:11:51 +01001024 reg32 = mchbar_read32(SMSRCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001025 reg32 |= (1 << 0);
Angel Pons1d4044a2021-03-27 19:11:51 +01001026 mchbar_write32(SMSRCTL, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001027
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001028 /* Start initial RCOMP */
Angel Pons1d4044a2021-03-27 19:11:51 +01001029 reg32 = mchbar_read32(GBRCOMPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001030 reg32 |= (1 << 8);
Angel Pons1d4044a2021-03-27 19:11:51 +01001031 mchbar_write32(GBRCOMPCTL, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001032
1033 reg8 = i945_silicon_revision();
Angel Pons1d4044a2021-03-27 19:11:51 +01001034 if ((reg8 == 0 && (mchbar_read32(DCC) & (3 << 0)) == 0) || (reg8 == 1)) {
1035 reg32 = mchbar_read32(GBRCOMPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001036 reg32 |= (3 << 5);
Angel Pons1d4044a2021-03-27 19:11:51 +01001037 mchbar_write32(GBRCOMPCTL, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001038 }
1039}
1040
1041static void sdram_initialize_system_memory_io(struct sys_info *sysinfo)
1042{
1043 u8 reg8;
1044 u32 reg32;
1045
Elyes HAOUAS38424982016-08-21 12:01:04 +02001046 printk(BIOS_DEBUG, "Initializing System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001047 /* Enable Data Half Clock Pushout */
Angel Pons1d4044a2021-03-27 19:11:51 +01001048 reg8 = mchbar_read8(C0HCTC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001049 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001050 reg8 |= (1 << 0);
Angel Pons1d4044a2021-03-27 19:11:51 +01001051 mchbar_write8(C0HCTC, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001052
Angel Pons1d4044a2021-03-27 19:11:51 +01001053 reg8 = mchbar_read8(C1HCTC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001054 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001055 reg8 |= (1 << 0);
Angel Pons1d4044a2021-03-27 19:11:51 +01001056 mchbar_write8(C1HCTC, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001057
Angel Pons1d4044a2021-03-27 19:11:51 +01001058 mchbar_clrbits16(WDLLBYPMODE, 1 << 9 | 1 << 6 | 1 << 4 | 1 << 3 | 1 << 1);
1059 mchbar_setbits16(WDLLBYPMODE, 1 << 8 | 1 << 7 | 1 << 5 | 1 << 2 | 1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001060
Angel Pons1d4044a2021-03-27 19:11:51 +01001061 mchbar_write8(C0WDLLCMC, 0);
1062 mchbar_write8(C1WDLLCMC, 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001063
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001064 /* Program RCOMP Settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001065 sdram_program_dram_width(sysinfo);
1066
1067 sdram_rcomp_buffer_strength_and_slew(sysinfo);
1068
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001069 /* Indicate that RCOMP programming is done */
Angel Pons1d4044a2021-03-27 19:11:51 +01001070 reg32 = mchbar_read32(GBRCOMPCTL);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001071 reg32 &= ~((1 << 29) | (1 << 26) | (3 << 21) | (3 << 2));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001072 reg32 |= (3 << 27) | (3 << 0);
Angel Pons1d4044a2021-03-27 19:11:51 +01001073 mchbar_write32(GBRCOMPCTL, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001074
Angel Pons1d4044a2021-03-27 19:11:51 +01001075 mchbar_setbits32(GBRCOMPCTL, 1 << 10);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001076
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001077 /* Program DLL Timings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001078 sdram_program_dll_timings(sysinfo);
1079
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001080 /* Force RCOMP cycle */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001081 sdram_force_rcomp();
1082}
1083
1084static void sdram_enable_system_memory_io(struct sys_info *sysinfo)
1085{
1086 u32 reg32;
1087
Elyes HAOUAS38424982016-08-21 12:01:04 +02001088 printk(BIOS_DEBUG, "Enabling System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001089
Angel Pons1d4044a2021-03-27 19:11:51 +01001090 reg32 = mchbar_read32(RCVENMT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001091 reg32 &= ~(0x3f << 6);
Angel Pons1d4044a2021-03-27 19:11:51 +01001092 mchbar_write32(RCVENMT, reg32); /* [11:6] = 0 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001093
1094 reg32 |= (1 << 11) | (1 << 9);
Angel Pons1d4044a2021-03-27 19:11:51 +01001095 mchbar_write32(RCVENMT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001096
Angel Pons1d4044a2021-03-27 19:11:51 +01001097 reg32 = mchbar_read32(DRTST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001098 reg32 |= (1 << 3) | (1 << 2);
Angel Pons1d4044a2021-03-27 19:11:51 +01001099 mchbar_write32(DRTST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001100
Angel Pons1d4044a2021-03-27 19:11:51 +01001101 reg32 = mchbar_read32(DRTST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001102 reg32 |= (1 << 6) | (1 << 4);
Angel Pons1d4044a2021-03-27 19:11:51 +01001103 mchbar_write32(DRTST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001104
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001105 asm volatile ("nop; nop;" ::: "memory");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001106
Angel Pons1d4044a2021-03-27 19:11:51 +01001107 reg32 = mchbar_read32(DRTST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001108
1109 /* Is channel 0 populated? */
1110 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001111 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001112 reg32 |= (1 << 7) | (1 << 5);
1113 else
1114 reg32 |= (1 << 31);
1115
1116 /* Is channel 1 populated? */
1117 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001118 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001119 reg32 |= (1 << 9) | (1 << 8);
1120 else
1121 reg32 |= (1 << 30);
1122
Angel Pons1d4044a2021-03-27 19:11:51 +01001123 mchbar_write32(DRTST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001124
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001125 /* Activate DRAM Channel IO Buffers */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001126 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001127 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) {
Angel Pons1d4044a2021-03-27 19:11:51 +01001128 reg32 = mchbar_read32(C0DRC1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001129 reg32 |= (1 << 8);
Angel Pons1d4044a2021-03-27 19:11:51 +01001130 mchbar_write32(C0DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001131 }
1132 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001133 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED) {
Angel Pons1d4044a2021-03-27 19:11:51 +01001134 reg32 = mchbar_read32(C1DRC1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001135 reg32 |= (1 << 8);
Angel Pons1d4044a2021-03-27 19:11:51 +01001136 mchbar_write32(C1DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001137 }
1138}
1139
Stefan Reinauer278534d2008-10-29 04:51:07 +00001140static int sdram_program_row_boundaries(struct sys_info *sysinfo)
1141{
1142 int i;
Arthur Heymans885c2892016-10-03 17:16:48 +02001143 int cum0, cum1, tolud, tom, pci_mmio_size;
1144 const struct device *dev;
1145 const struct northbridge_intel_i945_config *cfg = NULL;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001146
Paul Menzel84283bc2014-07-17 08:16:04 +02001147 printk(BIOS_DEBUG, "Setting RAM size...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001148
1149 cum0 = 0;
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001150 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001151 cum0 += sysinfo->banksize[i];
Angel Pons1d4044a2021-03-27 19:11:51 +01001152 mchbar_write8(C0DRB0 + i, cum0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001153 }
1154
1155 /* Assume we continue in Channel 1 where we stopped in Channel 0 */
1156 cum1 = cum0;
1157
1158 /* Exception: Interleaved starts from the beginning */
1159 if (sysinfo->interleaved)
1160 cum1 = 0;
1161
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001162 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001163 cum1 += sysinfo->banksize[i + 4];
Angel Pons1d4044a2021-03-27 19:11:51 +01001164 mchbar_write8(C1DRB0 + i, cum1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001165 }
1166
1167 /* Set TOLUD Top Of Low Usable DRAM */
1168 if (sysinfo->interleaved)
1169 tolud = (cum0 + cum1) << 1;
1170 else
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001171 tolud = (cum1 ? cum1 : cum0) << 1;
Stefan Reinauer779b3e32008-11-10 15:43:37 +00001172
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001173 /* The TOM register has a different format */
1174 tom = tolud >> 3;
1175
1176 /* Limit the value of TOLUD to leave some space for PCI memory. */
Kyösti Mälkkic70eed12018-05-22 02:18:00 +03001177 dev = pcidev_on_root(0, 0);
Arthur Heymans885c2892016-10-03 17:16:48 +02001178 if (dev)
1179 cfg = dev->chip_info;
1180
1181 /* Don't use pci mmio sizes smaller than 768M */
1182 if (!cfg || cfg->pci_mmio_size <= DEFAULT_PCI_MMIO_SIZE)
1183 pci_mmio_size = DEFAULT_PCI_MMIO_SIZE;
1184 else
1185 pci_mmio_size = cfg->pci_mmio_size;
1186
1187 tolud = MIN(((4096 - pci_mmio_size) / 128) << 3, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001188
Angel Pons3580d812020-06-11 14:13:33 +02001189 pci_write_config8(HOST_BRIDGE, TOLUD, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001190
Angel Pons1d4044a2021-03-27 19:11:51 +01001191 printk(BIOS_DEBUG, "C0DRB = 0x%08x\n", mchbar_read32(C0DRB0));
1192 printk(BIOS_DEBUG, "C1DRB = 0x%08x\n", mchbar_read32(C1DRB0));
Angel Pons3580d812020-06-11 14:13:33 +02001193 printk(BIOS_DEBUG, "TOLUD = 0x%04x\n", pci_read_config8(HOST_BRIDGE, TOLUD));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001194
Angel Pons3580d812020-06-11 14:13:33 +02001195 pci_write_config16(HOST_BRIDGE, TOM, tom);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001196
1197 return 0;
1198}
1199
Stefan Reinauer278534d2008-10-29 04:51:07 +00001200static int sdram_set_row_attributes(struct sys_info *sysinfo)
1201{
Arthur Heymans0ab49042017-02-06 22:40:14 +01001202 int i;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001203 u16 dra0 = 0, dra1 = 0, dra = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001204
Elyes HAOUAS38424982016-08-21 12:01:04 +02001205 printk(BIOS_DEBUG, "Setting row attributes...\n");
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001206 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001207 u8 columnsrows;
1208
Arthur Heymans70a8e342017-03-09 11:30:23 +01001209 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001210 continue;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001211
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001212 columnsrows = (sysinfo->rows[i] & 0x0f) | (sysinfo->cols[i] & 0xf) << 4;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001213
1214 switch (columnsrows) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001215 case 0x9d:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001216 dra = 2;
1217 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001218 case 0xad:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001219 dra = 3;
1220 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001221 case 0xbd:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001222 dra = 4;
1223 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001224 case 0xae:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001225 dra = 3;
1226 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001227 case 0xbe:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001228 dra = 4;
1229 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001230 default:
1231 die("Unsupported Rows/Columns. (DRA)");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001232 }
1233
1234 /* Double Sided DIMMs? */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001235 if (sysinfo->banksize[(2 * i) + 1] != 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001236 dra = (dra << 4) | dra;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001237
Stefan Reinauer278534d2008-10-29 04:51:07 +00001238 if (i < DIMM_SOCKETS)
Angel Pons30492572020-06-11 13:24:54 +02001239 dra0 |= (dra << (i * 8));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001240 else
Angel Pons30492572020-06-11 13:24:54 +02001241 dra1 |= (dra << ((i - DIMM_SOCKETS) * 8));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001242 }
1243
Angel Pons1d4044a2021-03-27 19:11:51 +01001244 mchbar_write16(C0DRA0, dra0);
1245 mchbar_write16(C1DRA0, dra1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001246
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001247 printk(BIOS_DEBUG, "C0DRA = 0x%04x\n", dra0);
1248 printk(BIOS_DEBUG, "C1DRA = 0x%04x\n", dra1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001249
1250 return 0;
1251}
1252
1253static void sdram_set_bank_architecture(struct sys_info *sysinfo)
1254{
1255 u32 off32;
1256 int i;
1257
Angel Pons1d4044a2021-03-27 19:11:51 +01001258 mchbar_clrbits16(C1BNKARC, 0xff);
1259 mchbar_clrbits16(C0BNKARC, 0xff);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001260
1261 off32 = C0BNKARC;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001262 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001263 /* Switch to second channel */
1264 if (i == DIMM_SOCKETS)
1265 off32 = C1BNKARC;
1266
1267 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
1268 continue;
1269
1270 if (sysinfo->banks[i] != 8)
1271 continue;
1272
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001273 printk(BIOS_SPEW, "DIMM%d has 8 banks.\n", i);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001274
1275 if (i & 1)
Angel Pons1d4044a2021-03-27 19:11:51 +01001276 mchbar_setbits16(off32, 5 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001277 else
Angel Pons1d4044a2021-03-27 19:11:51 +01001278 mchbar_setbits16(off32, 5 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001279 }
1280}
1281
Stefan Reinauer278534d2008-10-29 04:51:07 +00001282static void sdram_program_refresh_rate(struct sys_info *sysinfo)
1283{
1284 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001285
Arthur Heymans70a8e342017-03-09 11:30:23 +01001286 if (sysinfo->refresh == REFRESH_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001287 reg32 = (2 << 8); /* Refresh enabled at 7.8us */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001288 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001289 reg32 = (1 << 8); /* Refresh enabled at 15.6us */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001290
Angel Pons1d4044a2021-03-27 19:11:51 +01001291 mchbar_clrbits32(C0DRC0, 7 << 8);
1292 mchbar_setbits32(C0DRC0, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001293
Angel Pons1d4044a2021-03-27 19:11:51 +01001294 mchbar_clrbits32(C1DRC0, 7 << 8);
1295 mchbar_setbits32(C1DRC0, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001296}
1297
1298static void sdram_program_cke_tristate(struct sys_info *sysinfo)
1299{
1300 u32 reg32;
1301 int i;
1302
Angel Pons1d4044a2021-03-27 19:11:51 +01001303 reg32 = mchbar_read32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001304
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001305 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001306 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001307 reg32 |= (1 << (16 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001308 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001309
Stefan Reinauer278534d2008-10-29 04:51:07 +00001310 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001311
Stefan Reinauer278534d2008-10-29 04:51:07 +00001312 reg32 |= (1 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01001313 mchbar_write32(C0DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001314
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001315 /* Do we have to do this if we're in Single Channel Mode? */
Angel Pons1d4044a2021-03-27 19:11:51 +01001316 reg32 = mchbar_read32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001317
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001318 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001319 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001320 reg32 |= (1 << (12 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001321 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001322
Stefan Reinauer278534d2008-10-29 04:51:07 +00001323 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001324
Stefan Reinauer278534d2008-10-29 04:51:07 +00001325 reg32 |= (1 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01001326 mchbar_write32(C1DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001327}
1328
1329static void sdram_program_odt_tristate(struct sys_info *sysinfo)
1330{
1331 u32 reg32;
1332 int i;
1333
Angel Pons1d4044a2021-03-27 19:11:51 +01001334 reg32 = mchbar_read32(C0DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001335
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001336 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001337 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001338 reg32 |= (1 << (24 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001339 }
Angel Pons1d4044a2021-03-27 19:11:51 +01001340 mchbar_write32(C0DRC2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001341
Angel Pons1d4044a2021-03-27 19:11:51 +01001342 reg32 = mchbar_read32(C1DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001343
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001344 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001345 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001346 reg32 |= (1 << (20 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001347 }
Angel Pons1d4044a2021-03-27 19:11:51 +01001348 mchbar_write32(C1DRC2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001349}
1350
1351static void sdram_set_timing_and_control(struct sys_info *sysinfo)
1352{
Arthur Heymans25027232017-02-12 23:34:39 +01001353 u32 reg32, tRD_min;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001354 u32 tWTR;
1355 u32 temp_drt;
1356 int i, page_size;
1357
Edward O'Callaghan2f237c12014-05-25 06:24:39 +10001358 static const u8 cas_table[] = {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001359 2, 1, 0, 3
1360 };
1361
Angel Pons1d4044a2021-03-27 19:11:51 +01001362 reg32 = mchbar_read32(C0DRC0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001363 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001364 reg32 &= ~((1 << 13) | (1 << 12));
Angel Pons1d4044a2021-03-27 19:11:51 +01001365 mchbar_write32(C0DRC0, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001366
Angel Pons1d4044a2021-03-27 19:11:51 +01001367 reg32 = mchbar_read32(C1DRC0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001368 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001369 reg32 &= ~((1 << 13) | (1 << 12));
Angel Pons1d4044a2021-03-27 19:11:51 +01001370 mchbar_write32(C1DRC0, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001371
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001372 if (!sysinfo->dual_channel && sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) {
Angel Pons1d4044a2021-03-27 19:11:51 +01001373 reg32 = mchbar_read32(C0DRC0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001374 reg32 |= (1 << 15);
Angel Pons1d4044a2021-03-27 19:11:51 +01001375 mchbar_write32(C0DRC0, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001376 }
1377
1378 sdram_program_refresh_rate(sysinfo);
1379
1380 sdram_program_cke_tristate(sysinfo);
1381
1382 sdram_program_odt_tristate(sysinfo);
1383
1384 /* Calculate DRT0 */
1385
1386 temp_drt = 0;
1387
1388 /* B2B Write Precharge (same bank) = CL-1 + BL/2 + tWR */
1389 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + sysinfo->twr;
1390 temp_drt |= (reg32 << 28);
1391
1392 /* Write Auto Precharge (same bank) = CL-1 + BL/2 + tWR + tRP */
1393 reg32 += sysinfo->trp;
1394 temp_drt |= (reg32 << 4);
1395
Arthur Heymans70a8e342017-03-09 11:30:23 +01001396 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001397 tWTR = 3; /* 667MHz */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001398 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001399 tWTR = 2; /* 400 and 533 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001400
1401 /* B2B Write to Read Command Spacing */
1402 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + tWTR;
1403 temp_drt |= (reg32 << 24);
1404
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001405 /* CxDRT0 [23:22], [21:20], [19:18] [16] have fixed values */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001406 temp_drt |= ((1 << 22) | (3 << 20) | (1 << 18) | (0 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001407
Arthur Heymans25027232017-02-12 23:34:39 +01001408 /*
1409 * tRD is the delay the memory controller is waiting on the FSB,
1410 * in mclk domain.
1411 * This parameter is important for stability and performance.
1412 * Those values might not be optimal but seem stable.
1413 */
1414 tRD_min = sysinfo->cas;
Arthur Heymanse1897612016-10-15 23:29:18 +02001415 switch (sysinfo->fsb_frequency) {
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001416 case 533:
Arthur Heymanse1897612016-10-15 23:29:18 +02001417 break;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001418 case 667:
1419 tRD_min += 1;
Arthur Heymanse1897612016-10-15 23:29:18 +02001420 break;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001421 case 800:
1422 tRD_min += 2;
1423 break;
1424 case 1066:
1425 tRD_min += 3;
Arthur Heymanse1897612016-10-15 23:29:18 +02001426 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001427 }
Arthur Heymanse1897612016-10-15 23:29:18 +02001428
Arthur Heymans25027232017-02-12 23:34:39 +01001429 temp_drt |= (tRD_min << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001430
1431 /* Read Auto Precharge to Activate */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001432
Stefan Reinauer278534d2008-10-29 04:51:07 +00001433 temp_drt |= (8 << 0);
1434
Angel Pons1d4044a2021-03-27 19:11:51 +01001435 mchbar_write32(C0DRT0, temp_drt);
1436 mchbar_write32(C1DRT0, temp_drt);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001437
1438 /* Calculate DRT1 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001439
Angel Pons1d4044a2021-03-27 19:11:51 +01001440 temp_drt = mchbar_read32(C0DRT1) & 0x00020088;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001441
1442 /* DRAM RASB Precharge */
1443 temp_drt |= (sysinfo->trp - 2) << 0;
1444
1445 /* DRAM RASB to CASB Delay */
1446 temp_drt |= (sysinfo->trcd - 2) << 4;
1447
1448 /* CASB Latency */
1449 temp_drt |= (cas_table[sysinfo->cas - 3]) << 8;
1450
1451 /* Refresh Cycle Time */
1452 temp_drt |= (sysinfo->trfc) << 10;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001453
Stefan Reinauer278534d2008-10-29 04:51:07 +00001454 /* Pre-All to Activate Delay */
1455 temp_drt |= (0 << 16);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001456
Stefan Reinauer278534d2008-10-29 04:51:07 +00001457 /* Precharge to Precharge Delay stays at 1 clock */
1458 temp_drt |= (0 << 18);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001459
Stefan Reinauer278534d2008-10-29 04:51:07 +00001460 /* Activate to Precharge Delay */
1461 temp_drt |= (sysinfo->tras << 19);
1462
1463 /* Read to Precharge (tRTP) */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001464 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001465 temp_drt |= (1 << 28);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001466 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001467 temp_drt |= (0 << 28);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001468
1469 /* Determine page size */
1470 reg32 = 0;
1471 page_size = 1; /* Default: 1k pagesize */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001472 for (i = 0; i < 2*DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001473 if (sysinfo->dimm[i] == SYSINFO_DIMM_X16DS ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001474 sysinfo->dimm[i] == SYSINFO_DIMM_X16SS)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001475 page_size = 2; /* 2k pagesize */
1476 }
1477
Arthur Heymans70a8e342017-03-09 11:30:23 +01001478 if (sysinfo->memory_frequency == 533 && page_size == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001479 reg32 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001480 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001481 reg32 = page_size;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001482
Stefan Reinauer278534d2008-10-29 04:51:07 +00001483 temp_drt |= (reg32 << 30);
1484
Angel Pons1d4044a2021-03-27 19:11:51 +01001485 mchbar_write32(C0DRT1, temp_drt);
1486 mchbar_write32(C1DRT1, temp_drt);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001487
1488 /* Program DRT2 */
Angel Pons1d4044a2021-03-27 19:11:51 +01001489 reg32 = mchbar_read32(C0DRT2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001490 reg32 &= ~(1 << 8);
Angel Pons1d4044a2021-03-27 19:11:51 +01001491 mchbar_write32(C0DRT2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001492
Angel Pons1d4044a2021-03-27 19:11:51 +01001493 reg32 = mchbar_read32(C1DRT2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001494 reg32 &= ~(1 << 8);
Angel Pons1d4044a2021-03-27 19:11:51 +01001495 mchbar_write32(C1DRT2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001496
1497 /* Calculate DRT3 */
Angel Pons1d4044a2021-03-27 19:11:51 +01001498 temp_drt = mchbar_read32(C0DRT3) & ~0x07ffffff;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001499
1500 /* Get old tRFC value */
Angel Pons1d4044a2021-03-27 19:11:51 +01001501 reg32 = mchbar_read32(C0DRT1) >> 10;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001502 reg32 &= 0x3f;
1503
1504 /* 788nS - tRFC */
1505 switch (sysinfo->memory_frequency) {
1506 case 400: /* 5nS */
1507 reg32 = ((78800 / 500) - reg32) & 0x1ff;
1508 reg32 |= (0x8c << 16) | (0x0c << 10); /* 1 us */
1509 break;
1510 case 533: /* 3.75nS */
1511 reg32 = ((78800 / 375) - reg32) & 0x1ff;
1512 reg32 |= (0xba << 16) | (0x10 << 10); /* 1 us */
1513 break;
1514 case 667: /* 3nS */
1515 reg32 = ((78800 / 300) - reg32) & 0x1ff;
1516 reg32 |= (0xe9 << 16) | (0x14 << 10); /* 1 us */
1517 break;
1518 }
1519
1520 temp_drt |= reg32;
1521
Angel Pons1d4044a2021-03-27 19:11:51 +01001522 mchbar_write32(C0DRT3, temp_drt);
1523 mchbar_write32(C1DRT3, temp_drt);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001524}
1525
1526static void sdram_set_channel_mode(struct sys_info *sysinfo)
1527{
1528 u32 reg32;
1529
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001530 printk(BIOS_DEBUG, "Setting mode of operation for memory channels...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001531
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001532 if (sdram_capabilities_interleave() &&
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001533 ((sysinfo->banksize[0] + sysinfo->banksize[1] +
1534 sysinfo->banksize[2] + sysinfo->banksize[3]) ==
1535 (sysinfo->banksize[4] + sysinfo->banksize[5] +
1536 sysinfo->banksize[6] + sysinfo->banksize[7]))) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001537 /* Both channels equipped with DIMMs of the same size */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001538 sysinfo->interleaved = 1;
1539 } else {
1540 sysinfo->interleaved = 0;
1541 }
1542
Angel Pons1d4044a2021-03-27 19:11:51 +01001543 reg32 = mchbar_read32(DCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001544 reg32 &= ~(7 << 0);
1545
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001546 if (sysinfo->interleaved) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001547 /* Dual Channel Interleaved */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001548 printk(BIOS_DEBUG, "Dual Channel Interleaved.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001549 reg32 |= (1 << 1);
1550 } else if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001551 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001552 /* Channel 1 only */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001553 printk(BIOS_DEBUG, "Single Channel 1 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001554 reg32 |= (1 << 2);
Elyes HAOUAS75da1fb2017-02-16 18:59:13 +01001555 } else if (sdram_capabilities_dual_channel() &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001556 (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1557 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) {
Martin Roth128c1042016-11-18 09:29:03 -07001558 /* Dual Channel Asymmetric */
1559 printk(BIOS_DEBUG, "Dual Channel Asymmetric.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001560 reg32 |= (1 << 0);
1561 } else {
1562 /* All bits 0 means Single Channel 0 operation */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001563 printk(BIOS_DEBUG, "Single Channel 0 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001564 }
1565
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001566 /* Now disable channel XORing */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001567 reg32 |= (1 << 10);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001568
Angel Pons1d4044a2021-03-27 19:11:51 +01001569 mchbar_write32(DCC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001570
Angel Pons1d4044a2021-03-27 19:11:51 +01001571 PRINTK_DEBUG("DCC = 0x%08x\n", mchbar_read32(DCC));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001572}
1573
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001574static void sdram_program_pll_settings(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001575{
Angel Pons1d4044a2021-03-27 19:11:51 +01001576 mchbar_write32(PLLMON, 0x80800000);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001577
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001578 sysinfo->fsb_frequency = fsbclk();
Peter Stuge76d91432010-10-01 10:02:33 +00001579 if (sysinfo->fsb_frequency == 0xffff)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001580 die("Unsupported FSB speed");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001581
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001582 /* Program CPCTL according to FSB speed */
1583 /* Only write the lower byte */
1584 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001585 case 400:
Angel Pons1d4044a2021-03-27 19:11:51 +01001586 mchbar_write8(CPCTL, 0x90);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001587 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001588 case 533:
Angel Pons1d4044a2021-03-27 19:11:51 +01001589 mchbar_write8(CPCTL, 0x95);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001590 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001591 case 667:
Angel Pons1d4044a2021-03-27 19:11:51 +01001592 mchbar_write8(CPCTL, 0x8d);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001593 break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001594 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001595
Angel Pons1d4044a2021-03-27 19:11:51 +01001596 mchbar_clrbits16(CPCTL, 1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001597
Angel Pons1d4044a2021-03-27 19:11:51 +01001598 mchbar_read16(CPCTL); /* Read back register to activate settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001599}
1600
1601static void sdram_program_graphics_frequency(struct sys_info *sysinfo)
1602{
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001603 u8 reg8;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001604 u8 freq, second_vco, voltage;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001605
1606#define CRCLK_166MHz 0x00
1607#define CRCLK_200MHz 0x01
1608#define CRCLK_250MHz 0x03
1609#define CRCLK_400MHz 0x05
1610
1611#define CDCLK_200MHz 0x00
1612#define CDCLK_320MHz 0x40
1613
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001614#define VOLTAGE_1_05 0x00
1615#define VOLTAGE_1_50 0x01
1616
Paul Menzeldaf9e502014-07-15 23:49:16 +02001617 printk(BIOS_DEBUG, "Setting Graphics Frequency...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001618
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001619 printk(BIOS_DEBUG, "FSB: %d MHz ", sysinfo->fsb_frequency);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001620
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001621 voltage = VOLTAGE_1_05;
Angel Pons1d4044a2021-03-27 19:11:51 +01001622 if (mchbar_read32(DFT_STRAP1) & (1 << 20))
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001623 voltage = VOLTAGE_1_50;
Angel Pons30492572020-06-11 13:24:54 +02001624 printk(BIOS_DEBUG, "Voltage: %s ", (voltage == VOLTAGE_1_05) ? "1.05V" : "1.5V");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001625
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001626 /* Gate graphics hardware for frequency change */
Angel Pons30492572020-06-11 13:24:54 +02001627 reg8 = (1 << 3) | (1 << 1); /* disable crclk, gate cdclk */
Angel Pons3580d812020-06-11 14:13:33 +02001628 pci_write_config8(IGD_DEV, GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001629
1630 /* Get graphics frequency capabilities */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001631 reg8 = sdram_capabilities_core_frequencies();
1632
Stefan Reinauer278534d2008-10-29 04:51:07 +00001633 freq = CRCLK_250MHz;
1634 switch (reg8) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001635 case GFX_FREQUENCY_CAP_ALL:
1636 if (voltage == VOLTAGE_1_05)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001637 freq = CRCLK_250MHz;
1638 else
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001639 freq = CRCLK_400MHz; /* 1.5V requires 400MHz */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001640 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001641 case GFX_FREQUENCY_CAP_250MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001642 freq = CRCLK_250MHz;
1643 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001644 case GFX_FREQUENCY_CAP_200MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001645 freq = CRCLK_200MHz;
1646 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001647 case GFX_FREQUENCY_CAP_166MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001648 freq = CRCLK_166MHz;
1649 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001650 }
1651
1652 if (freq != CRCLK_400MHz) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001653 /* What chipset are we? Force 166MHz for GMS */
Angel Pons3580d812020-06-11 14:13:33 +02001654 reg8 = (pci_read_config8(HOST_BRIDGE, 0xe7) & 0x70) >> 4;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001655 if (reg8 == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001656 freq = CRCLK_166MHz;
1657 }
1658
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001659 printk(BIOS_DEBUG, "Render: ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001660 switch (freq) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001661 case CRCLK_166MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001662 printk(BIOS_DEBUG, "166MHz");
1663 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001664 case CRCLK_200MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001665 printk(BIOS_DEBUG, "200MHz");
1666 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001667 case CRCLK_250MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001668 printk(BIOS_DEBUG, "250MHz");
1669 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001670 case CRCLK_400MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001671 printk(BIOS_DEBUG, "400MHz");
1672 break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001673 }
1674
Arthur Heymans70a8e342017-03-09 11:30:23 +01001675 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001676 sysinfo->mvco4x = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001677 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001678 sysinfo->mvco4x = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001679
Stefan Reinauer278534d2008-10-29 04:51:07 +00001680 second_vco = 0;
1681
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001682 if (voltage == VOLTAGE_1_50) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001683 second_vco = 1;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001684 } else if ((i945_silicon_revision() > 0) && (freq == CRCLK_250MHz)) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001685 u16 mem = sysinfo->memory_frequency;
1686 u16 fsb = sysinfo->fsb_frequency;
1687
Arthur Heymans70a8e342017-03-09 11:30:23 +01001688 if ((fsb == 667 && mem == 533) ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001689 (fsb == 533 && mem == 533) ||
1690 (fsb == 533 && mem == 400)) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001691 second_vco = 1;
1692 }
1693
1694 if (fsb == 667 && mem == 533)
1695 sysinfo->mvco4x = 1;
1696 }
1697
Arthur Heymans70a8e342017-03-09 11:30:23 +01001698 if (second_vco)
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001699 sysinfo->clkcfg_bit7 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001700 else
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001701 sysinfo->clkcfg_bit7 = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001702
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001703 /* Graphics Core Render Clock */
Angel Pons3580d812020-06-11 14:13:33 +02001704 pci_update_config16(IGD_DEV, GCFC, ~((7 << 0) | (1 << 13)), freq);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001705
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001706 /* Graphics Core Display Clock */
Angel Pons3580d812020-06-11 14:13:33 +02001707 reg8 = pci_read_config8(IGD_DEV, GCFC);
Angel Ponse3c68d22020-06-08 12:09:03 +02001708 reg8 &= ~((1 << 7) | (7 << 4));
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001709
1710 if (voltage == VOLTAGE_1_05) {
1711 reg8 |= CDCLK_200MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001712 printk(BIOS_DEBUG, " Display: 200MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001713 } else {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001714 reg8 |= CDCLK_320MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001715 printk(BIOS_DEBUG, " Display: 320MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001716 }
Angel Pons3580d812020-06-11 14:13:33 +02001717 pci_write_config8(IGD_DEV, GCFC, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001718
Angel Pons3580d812020-06-11 14:13:33 +02001719 reg8 = pci_read_config8(IGD_DEV, GCFC + 1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001720
Angel Ponse3c68d22020-06-08 12:09:03 +02001721 reg8 |= (1 << 3) | (1 << 1);
Angel Pons3580d812020-06-11 14:13:33 +02001722 pci_write_config8(IGD_DEV, GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001723
1724 reg8 |= 0x0f;
Angel Pons3580d812020-06-11 14:13:33 +02001725 pci_write_config8(IGD_DEV, GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001726
1727 /* Ungate core render and display clocks */
1728 reg8 &= 0xf0;
Angel Pons3580d812020-06-11 14:13:33 +02001729 pci_write_config8(IGD_DEV, GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001730}
1731
1732static void sdram_program_memory_frequency(struct sys_info *sysinfo)
1733{
1734 u32 clkcfg;
Julius Wernercd49cce2019-03-05 16:53:33 -08001735 u8 offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001736
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001737 printk(BIOS_DEBUG, "Setting Memory Frequency... ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001738
Angel Pons1d4044a2021-03-27 19:11:51 +01001739 clkcfg = mchbar_read32(CLKCFG);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001740
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001741 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001742
Arthur Heymans70a8e342017-03-09 11:30:23 +01001743 clkcfg &= ~((1 << 12) | (1 << 7) | (7 << 4));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001744
1745 if (sysinfo->mvco4x) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001746 printk(BIOS_DEBUG, "MVCO 4x, ");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001747 clkcfg &= ~(1 << 12);
1748 }
1749
1750 if (sysinfo->clkcfg_bit7) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001751 printk(BIOS_DEBUG, "second VCO, ");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001752 clkcfg |= (1 << 7);
1753 }
1754
1755 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001756 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001757 clkcfg |= ((1 + offset) << 4);
1758 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001759 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001760 clkcfg |= ((2 + offset) << 4);
1761 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001762 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001763 clkcfg |= ((3 + offset) << 4);
1764 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001765 default:
1766 die("Target Memory Frequency Error");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001767 }
1768
Angel Pons1d4044a2021-03-27 19:11:51 +01001769 if (mchbar_read32(CLKCFG) == clkcfg) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001770 printk(BIOS_DEBUG, "ok (unchanged)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001771 return;
1772 }
1773
Angel Pons1d4044a2021-03-27 19:11:51 +01001774 mchbar_write32(CLKCFG, clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001775
Petr Cveke75bb012022-06-16 17:13:22 +02001776 /*
1777 * Make sure the following code is in the cache before we execute it.
1778 * TODO: Experiments (i945GM) without any cache_code/delay_update
1779 * _seem_ to work even when XIP is disabled. Also on Pentium 4
1780 * the code is not cached at all by default.
1781 */
1782 asm volatile (
1783 " jmp cache_code\n"
1784 "vco_update:\n"
1785 : /* No outputs */
1786 : /* No inputs */
1787 : "memory"
1788 );
1789
Angel Ponse3c68d22020-06-08 12:09:03 +02001790 pci_and_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, (u8)~(1 << 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001791
Stefan Reinauer278534d2008-10-29 04:51:07 +00001792 clkcfg &= ~(1 << 10);
Angel Pons1d4044a2021-03-27 19:11:51 +01001793 mchbar_write32(CLKCFG, clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001794 clkcfg |= (1 << 10);
Angel Pons1d4044a2021-03-27 19:11:51 +01001795 mchbar_write32(CLKCFG, clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001796
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001797 asm volatile (
Stefan Reinauer278534d2008-10-29 04:51:07 +00001798 " movl $0x100, %%ecx\n"
1799 "delay_update:\n"
1800 " nop\n"
1801 " nop\n"
1802 " nop\n"
1803 " nop\n"
1804 " loop delay_update\n"
1805 : /* No outputs */
1806 : /* No inputs */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001807 : "%ecx", "memory"
Stefan Reinauer278534d2008-10-29 04:51:07 +00001808 );
1809
Stefan Reinauer278534d2008-10-29 04:51:07 +00001810 clkcfg &= ~(1 << 10);
Angel Pons1d4044a2021-03-27 19:11:51 +01001811 mchbar_write32(CLKCFG, clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001812
Petr Cveke75bb012022-06-16 17:13:22 +02001813 asm volatile (
1814 " jmp out\n"
1815 "cache_code:\n"
1816 " jmp vco_update\n"
1817 "out:\n"
1818 : /* No outputs */
1819 : /* No inputs */
1820 : "memory"
1821 );
Stefan Reinauer278534d2008-10-29 04:51:07 +00001822
Angel Pons1d4044a2021-03-27 19:11:51 +01001823 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", mchbar_read32(CLKCFG));
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001824 printk(BIOS_DEBUG, "ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001825}
1826
1827static void sdram_program_clock_crossing(void)
1828{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001829 int idx = 0;
1830
1831 /**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001832 * We add the indices according to our clocks from CLKCFG.
Stefan Reinauer278534d2008-10-29 04:51:07 +00001833 */
Julius Wernercd49cce2019-03-05 16:53:33 -08001834#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001835 static const u32 data_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001836 0x00100401, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001837 0xffffffff, 0xffffffff, /* nonexistent */
1838 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001839
Stefan Reinauer278534d2008-10-29 04:51:07 +00001840 0x08040120, 0x00000000, /* DDR400 FSB533 */
1841 0x00100401, 0x00000000, /* DDR533 FSB533 */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001842 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001843
1844 0x04020120, 0x00000010, /* DDR400 FSB667 */
1845 0x10040280, 0x00000040, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001846 0x00100401, 0x00000000, /* DDR667 FSB667 */
1847
Martin Roth2ed0aa22016-01-05 20:58:58 -07001848 0xffffffff, 0xffffffff, /* nonexistent */
1849 0xffffffff, 0xffffffff, /* nonexistent */
1850 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001851
Martin Roth2ed0aa22016-01-05 20:58:58 -07001852 0xffffffff, 0xffffffff, /* nonexistent */
1853 0xffffffff, 0xffffffff, /* nonexistent */
1854 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001855 };
1856
1857 static const u32 command_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001858 0x04020208, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001859 0xffffffff, 0xffffffff, /* nonexistent */
1860 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001861
Stefan Reinauer278534d2008-10-29 04:51:07 +00001862 0x00060108, 0x00000000, /* DDR400 FSB533 */
1863 0x04020108, 0x00000000, /* DDR533 FSB533 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001864 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001865
1866 0x00040318, 0x00000000, /* DDR400 FSB667 */
1867 0x04020118, 0x00000000, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001868 0x02010804, 0x00000000, /* DDR667 FSB667 */
1869
Martin Roth2ed0aa22016-01-05 20:58:58 -07001870 0xffffffff, 0xffffffff, /* nonexistent */
1871 0xffffffff, 0xffffffff, /* nonexistent */
1872 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001873
Martin Roth2ed0aa22016-01-05 20:58:58 -07001874 0xffffffff, 0xffffffff, /* nonexistent */
1875 0xffffffff, 0xffffffff, /* nonexistent */
1876 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001877 };
1878
Julius Wernercd49cce2019-03-05 16:53:33 -08001879#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001880 /* i945 G/P */
1881 static const u32 data_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001882 0xffffffff, 0xffffffff, /* nonexistent */
1883 0xffffffff, 0xffffffff, /* nonexistent */
1884 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001885
1886 0x10080201, 0x00000000, /* DDR400 FSB533 */
1887 0x00100401, 0x00000000, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001888 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001889
Martin Roth2ed0aa22016-01-05 20:58:58 -07001890 0xffffffff, 0xffffffff, /* nonexistent */
1891 0xffffffff, 0xffffffff, /* nonexistent */
1892 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001893
1894 0x04020108, 0x00000000, /* DDR400 FSB800 */
1895 0x00020108, 0x00000000, /* DDR533 FSB800 */
1896 0x00080201, 0x00000000, /* DDR667 FSB800 */
1897
1898 0x00010402, 0x00000000, /* DDR400 FSB1066 */
1899 0x04020108, 0x00000000, /* DDR533 FSB1066 */
1900 0x08040110, 0x00000000, /* DDR667 FSB1066 */
1901 };
1902
1903 static const u32 command_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001904 0xffffffff, 0xffffffff, /* nonexistent */
1905 0xffffffff, 0xffffffff, /* nonexistent */
1906 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001907
1908 0x00010800, 0x00000402, /* DDR400 FSB533 */
1909 0x01000400, 0x00000200, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001910 0x00020904, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001911
Martin Roth2ed0aa22016-01-05 20:58:58 -07001912 0xffffffff, 0xffffffff, /* nonexistent */
1913 0xffffffff, 0xffffffff, /* nonexistent */
1914 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001915
1916 0x02010804, 0x00000000, /* DDR400 FSB800 */
1917 0x00010402, 0x00000000, /* DDR533 FSB800 */
Arthur Heymans8b6df622016-10-16 10:58:01 +02001918 0x04020130, 0x00000008, /* DDR667 FSB800 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001919
1920 0x00020904, 0x00000000, /* DDR400 FSB1066 */
1921 0x02010804, 0x00000000, /* DDR533 FSB1066 */
1922 0x180601c0, 0x00000020, /* DDR667 FSB1066 */
1923 };
1924#endif
1925
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001926 printk(BIOS_DEBUG, "Programming Clock Crossing...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001927
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001928 printk(BIOS_DEBUG, "MEM=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001929 switch (memclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001930 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001931 printk(BIOS_DEBUG, "400");
1932 idx += 0;
1933 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001934 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001935 printk(BIOS_DEBUG, "533");
1936 idx += 2;
1937 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001938 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001939 printk(BIOS_DEBUG, "667");
1940 idx += 4;
1941 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001942 default:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001943 printk(BIOS_DEBUG, "RSVD %x", memclk());
1944 return;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001945 }
1946
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001947 printk(BIOS_DEBUG, " FSB=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001948 switch (fsbclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001949 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001950 printk(BIOS_DEBUG, "400");
1951 idx += 0;
1952 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001953 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001954 printk(BIOS_DEBUG, "533");
1955 idx += 6;
1956 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001957 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001958 printk(BIOS_DEBUG, "667");
1959 idx += 12;
1960 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001961 case 800:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001962 printk(BIOS_DEBUG, "800");
1963 idx += 18;
1964 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001965 case 1066:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001966 printk(BIOS_DEBUG, "1066");
1967 idx += 24;
1968 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001969 default:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001970 printk(BIOS_DEBUG, "RSVD %x\n", fsbclk());
1971 return;
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001972 }
1973
Arthur Heymans70a8e342017-03-09 11:30:23 +01001974 if (command_clock_crossing[idx] == 0xffffffff)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001975 printk(BIOS_DEBUG, "Invalid MEM/FSB combination!\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001976
Angel Pons1d4044a2021-03-27 19:11:51 +01001977 mchbar_write32(CCCFT + 0, command_clock_crossing[idx]);
1978 mchbar_write32(CCCFT + 4, command_clock_crossing[idx + 1]);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001979
Angel Pons1d4044a2021-03-27 19:11:51 +01001980 mchbar_write32(C0DCCFT + 0, data_clock_crossing[idx]);
1981 mchbar_write32(C0DCCFT + 4, data_clock_crossing[idx + 1]);
1982 mchbar_write32(C1DCCFT + 0, data_clock_crossing[idx]);
1983 mchbar_write32(C1DCCFT + 4, data_clock_crossing[idx + 1]);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001984
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001985 printk(BIOS_DEBUG, "... ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001986}
1987
1988static void sdram_disable_fast_dispatch(void)
1989{
1990 u32 reg32;
1991
Angel Pons1d4044a2021-03-27 19:11:51 +01001992 reg32 = mchbar_read32(FSBPMC3);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001993 reg32 |= (1 << 1);
Angel Pons1d4044a2021-03-27 19:11:51 +01001994 mchbar_write32(FSBPMC3, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001995
Angel Pons1d4044a2021-03-27 19:11:51 +01001996 reg32 = mchbar_read32(SBTEST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001997 reg32 |= (3 << 1);
Angel Pons1d4044a2021-03-27 19:11:51 +01001998 mchbar_write32(SBTEST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001999}
2000
2001static void sdram_pre_jedec_initialization(void)
2002{
2003 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002004
Angel Pons1d4044a2021-03-27 19:11:51 +01002005 reg32 = mchbar_read32(WCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002006 reg32 &= 0x113ff3ff;
2007 reg32 |= (4 << 29) | (3 << 25) | (1 << 10);
Angel Pons1d4044a2021-03-27 19:11:51 +01002008 mchbar_write32(WCC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002009
Angel Pons1d4044a2021-03-27 19:11:51 +01002010 mchbar_setbits32(SMVREFC, 1 << 6);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002011
Angel Pons1d4044a2021-03-27 19:11:51 +01002012 mchbar_clrbits32(MMARB0, 3 << 17);
2013 mchbar_setbits32(MMARB0, 1 << 21 | 1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002014
Angel Pons1d4044a2021-03-27 19:11:51 +01002015 mchbar_clrbits32(MMARB1, 7 << 8);
2016 mchbar_setbits32(MMARB1, 3 << 8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002017
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002018 /* Adaptive Idle Timer Control */
Angel Pons1d4044a2021-03-27 19:11:51 +01002019 mchbar_write32(C0AIT + 0, 0x000006c4);
2020 mchbar_write32(C0AIT + 4, 0x871a066d);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002021
Angel Pons1d4044a2021-03-27 19:11:51 +01002022 mchbar_write32(C1AIT + 0, 0x000006c4);
2023 mchbar_write32(C1AIT + 4, 0x871a066d);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002024}
2025
2026#define EA_DUALCHANNEL_XOR_BANK_RANK_MODE (0xd4 << 24)
2027#define EA_DUALCHANNEL_XOR_BANK_MODE (0xf4 << 24)
2028#define EA_DUALCHANNEL_BANK_RANK_MODE (0xc2 << 24)
2029#define EA_DUALCHANNEL_BANK_MODE (0xe2 << 24)
2030#define EA_SINGLECHANNEL_XOR_BANK_RANK_MODE (0x91 << 24)
2031#define EA_SINGLECHANNEL_XOR_BANK_MODE (0xb1 << 24)
2032#define EA_SINGLECHANNEL_BANK_RANK_MODE (0x80 << 24)
2033#define EA_SINGLECHANNEL_BANK_MODE (0xa0 << 24)
2034
2035static void sdram_enhanced_addressing_mode(struct sys_info *sysinfo)
2036{
2037 u32 chan0 = 0, chan1 = 0;
Paul Menzeld789b6582020-03-14 11:50:34 +01002038 bool chan0_dualsided, chan1_dualsided, chan0_populated, chan1_populated;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002039
Paul Menzel842dd332020-03-14 10:37:40 +01002040 chan0_populated = (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002041 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED);
Elyes HAOUAS308aeff2017-02-24 12:53:07 +01002042 chan1_populated = (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002043 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002044 chan0_dualsided = (sysinfo->banksize[1] || sysinfo->banksize[3]);
2045 chan1_dualsided = (sysinfo->banksize[5] || sysinfo->banksize[7]);
2046
2047 if (sdram_capabilities_enhanced_addressing_xor()) {
2048 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002049 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002050 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002051 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002052 chan0 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002053 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002054 chan0 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002055 }
2056 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002057 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002058 chan1 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002059 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002060 chan1 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002061 }
2062 } else {
2063 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002064 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002065 chan0 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002066 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002067 chan0 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002068
Arthur Heymans70a8e342017-03-09 11:30:23 +01002069 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002070 chan1 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002071 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002072 chan1 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002073 }
2074 } else {
2075 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002076 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002077 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002078 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002079 chan0 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002080 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002081 chan0 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002082 }
2083 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002084 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002085 chan1 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002086 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002087 chan1 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002088 }
2089 } else {
2090 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002091 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002092 chan0 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002093 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002094 chan0 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002095
Arthur Heymans70a8e342017-03-09 11:30:23 +01002096 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002097 chan1 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002098 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002099 chan1 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002100 }
2101 }
2102
Angel Pons1d4044a2021-03-27 19:11:51 +01002103 mchbar_clrbits32(C0DRC1, 0xff << 24);
2104 mchbar_setbits32(C0DRC1, chan0);
2105 mchbar_clrbits32(C1DRC1, 0xff << 24);
2106 mchbar_setbits32(C1DRC1, chan1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002107}
2108
2109static void sdram_post_jedec_initialization(struct sys_info *sysinfo)
2110{
2111 u32 reg32;
2112
2113 /* Enable Channel XORing for Dual Channel Interleave */
2114 if (sysinfo->interleaved) {
Angel Pons1d4044a2021-03-27 19:11:51 +01002115 reg32 = mchbar_read32(DCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002116 reg32 &= ~(1 << 10);
Stefan Reinauer30140a52009-03-11 16:20:39 +00002117 reg32 |= (1 << 9);
Angel Pons1d4044a2021-03-27 19:11:51 +01002118 mchbar_write32(DCC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002119 }
2120
2121 /* DRAM mode optimizations */
2122 sdram_enhanced_addressing_mode(sysinfo);
2123
Angel Pons1d4044a2021-03-27 19:11:51 +01002124 reg32 = mchbar_read32(FSBPMC3);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002125 reg32 &= ~(1 << 1);
Angel Pons1d4044a2021-03-27 19:11:51 +01002126 mchbar_write32(FSBPMC3, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002127
Angel Pons1d4044a2021-03-27 19:11:51 +01002128 reg32 = mchbar_read32(SBTEST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002129 reg32 &= ~(1 << 2);
Angel Pons1d4044a2021-03-27 19:11:51 +01002130 mchbar_write32(SBTEST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002131
Angel Pons1d4044a2021-03-27 19:11:51 +01002132 reg32 = mchbar_read32(SBOCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002133 reg32 &= 0xffbdb6ff;
2134 reg32 |= (0xbdb6 << 8) | (1 << 0);
Angel Pons1d4044a2021-03-27 19:11:51 +01002135 mchbar_write32(SBOCC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002136}
2137
2138static void sdram_power_management(struct sys_info *sysinfo)
2139{
Stefan Reinauer278534d2008-10-29 04:51:07 +00002140 u16 reg16;
2141 u32 reg32;
Elyes HAOUAS187bec72021-12-12 07:00:50 +01002142 bool integrated_graphics = true;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002143 int i;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002144
Elyes HAOUAS8f20b122021-02-14 13:22:10 +01002145 if (!(pci_read_config8(HOST_BRIDGE, DEVEN) & (DEVEN_D2F0 | DEVEN_D2F1)))
2146 integrated_graphics = false;
2147
Angel Pons1d4044a2021-03-27 19:11:51 +01002148 reg32 = mchbar_read32(C0DRT2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002149 reg32 &= 0xffffff00;
2150 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002151 reg32 |= (1 << 5) | (1 << 4);
Angel Pons1d4044a2021-03-27 19:11:51 +01002152 mchbar_write32(C0DRT2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002153
Angel Pons1d4044a2021-03-27 19:11:51 +01002154 reg32 = mchbar_read32(C1DRT2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002155 reg32 &= 0xffffff00;
2156 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002157 reg32 |= (1 << 5) | (1 << 4);
Angel Pons1d4044a2021-03-27 19:11:51 +01002158 mchbar_write32(C1DRT2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002159
Angel Pons1d4044a2021-03-27 19:11:51 +01002160 reg32 = mchbar_read32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002161
2162 reg32 |= (1 << 12) | (1 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01002163 mchbar_write32(C0DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002164
Angel Pons1d4044a2021-03-27 19:11:51 +01002165 reg32 = mchbar_read32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002166
2167 reg32 |= (1 << 12) | (1 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01002168 mchbar_write32(C1DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002169
Julius Wernercd49cce2019-03-05 16:53:33 -08002170 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002171 if (i945_silicon_revision() > 1) {
2172 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2173 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002174
Angel Pons1d4044a2021-03-27 19:11:51 +01002175 mchbar_write16(UPMC1, 0x1010 | peg_bits);
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002176 } else {
2177 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2178 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002179
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002180 /* Rev 0 and 1 */
Angel Pons1d4044a2021-03-27 19:11:51 +01002181 mchbar_write16(UPMC1, 0x0010 | peg_bits);
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002182 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002183 }
2184
Angel Pons1d4044a2021-03-27 19:11:51 +01002185 reg16 = mchbar_read16(UPMC2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002186 reg16 &= 0xfc00;
2187 reg16 |= 0x0100;
Angel Pons1d4044a2021-03-27 19:11:51 +01002188 mchbar_write16(UPMC2, reg16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002189
Angel Pons1d4044a2021-03-27 19:11:51 +01002190 mchbar_write32(UPMC3, 0x000f06ff);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002191
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002192 for (i = 0; i < 5; i++) {
Angel Pons1d4044a2021-03-27 19:11:51 +01002193 mchbar_clrbits32(UPMC3, 1 << 16);
2194 mchbar_setbits32(UPMC3, 1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002195 }
2196
Angel Pons1d4044a2021-03-27 19:11:51 +01002197 mchbar_write32(GIPMC1, 0x8000000c);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002198
Angel Pons1d4044a2021-03-27 19:11:51 +01002199 reg16 = mchbar_read16(CPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002200 reg16 &= ~(7 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002201 if (i945_silicon_revision() > 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002202 reg16 |= (6 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002203 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002204 reg16 |= (4 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01002205 mchbar_write16(CPCTL, reg16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002206
Angel Pons3580d812020-06-11 14:13:33 +02002207#if 0
Angel Pons1d4044a2021-03-27 19:11:51 +01002208 if ((mchbar_read32(ECO) & (1 << 16)) != 0) {
Angel Pons3580d812020-06-11 14:13:33 +02002209#else
Stefan Reinauer30140a52009-03-11 16:20:39 +00002210 if (i945_silicon_revision() != 0) {
Angel Pons3580d812020-06-11 14:13:33 +02002211#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002212 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002213 case 667:
Angel Pons1d4044a2021-03-27 19:11:51 +01002214 mchbar_write32(HGIPMC2, 0x0d590d59);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002215 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002216 case 533:
Angel Pons1d4044a2021-03-27 19:11:51 +01002217 mchbar_write32(HGIPMC2, 0x155b155b);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002218 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002219 }
2220 } else {
2221 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002222 case 667:
Angel Pons1d4044a2021-03-27 19:11:51 +01002223 mchbar_write32(HGIPMC2, 0x09c409c4);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002224 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002225 case 533:
Angel Pons1d4044a2021-03-27 19:11:51 +01002226 mchbar_write32(HGIPMC2, 0x0fa00fa0);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002227 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002228 }
2229 }
2230
Angel Pons1d4044a2021-03-27 19:11:51 +01002231 mchbar_write32(FSBPMC1, 0x8000000c);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002232
Angel Pons1d4044a2021-03-27 19:11:51 +01002233 reg32 = mchbar_read32(C2C3TT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002234 reg32 &= 0xffff0000;
2235 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002236 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002237 reg32 |= 0x0600;
2238 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002239 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002240 reg32 |= 0x0480;
2241 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002242 }
Angel Pons1d4044a2021-03-27 19:11:51 +01002243 mchbar_write32(C2C3TT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002244
Angel Pons1d4044a2021-03-27 19:11:51 +01002245 reg32 = mchbar_read32(C3C4TT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002246 reg32 &= 0xffff0000;
2247 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002248 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002249 reg32 |= 0x0b80;
2250 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002251 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002252 reg32 |= 0x0980;
2253 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002254 }
Angel Pons1d4044a2021-03-27 19:11:51 +01002255 mchbar_write32(C3C4TT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002256
Arthur Heymans70a8e342017-03-09 11:30:23 +01002257 if (i945_silicon_revision() == 0)
Angel Pons1d4044a2021-03-27 19:11:51 +01002258 mchbar_clrbits32(ECO, 1 << 16);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002259 else
Angel Pons1d4044a2021-03-27 19:11:51 +01002260 mchbar_setbits32(ECO, 1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002261
Angel Pons1d4044a2021-03-27 19:11:51 +01002262 mchbar_clrbits32(FSBPMC3, 1 << 29);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002263
Angel Pons1d4044a2021-03-27 19:11:51 +01002264 mchbar_setbits32(FSBPMC3, 1 << 21);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002265
Angel Pons1d4044a2021-03-27 19:11:51 +01002266 mchbar_clrbits32(FSBPMC3, 1 << 19);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002267
Angel Pons1d4044a2021-03-27 19:11:51 +01002268 mchbar_clrbits32(FSBPMC3, 1 << 13);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002269
Angel Pons1d4044a2021-03-27 19:11:51 +01002270 reg32 = mchbar_read32(FSBPMC4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002271 reg32 &= ~(3 << 24);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002272 reg32 |= (2 << 24);
Angel Pons1d4044a2021-03-27 19:11:51 +01002273 mchbar_write32(FSBPMC4, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002274
Angel Pons1d4044a2021-03-27 19:11:51 +01002275 mchbar_setbits32(FSBPMC4, 1 << 21);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002276
Angel Pons1d4044a2021-03-27 19:11:51 +01002277 mchbar_setbits32(FSBPMC4, 1 << 5);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002278
Arthur Heymans70a8e342017-03-09 11:30:23 +01002279 if ((i945_silicon_revision() < 2)) { /* || cpuid() = 0x6e8 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002280 /* stepping 0 and 1 or CPUID 6e8 */
Angel Pons1d4044a2021-03-27 19:11:51 +01002281 mchbar_clrbits32(FSBPMC4, 1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002282 } else {
Angel Pons1d4044a2021-03-27 19:11:51 +01002283 mchbar_setbits32(FSBPMC4, 1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002284 }
2285
Angel Pons3580d812020-06-11 14:13:33 +02002286 pci_or_config8(HOST_BRIDGE, 0xfc, 1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002287
Angel Pons3580d812020-06-11 14:13:33 +02002288 pci_or_config8(IGD_DEV, 0xc1, 1 << 2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002289
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002290 if (integrated_graphics) {
Angel Pons1d4044a2021-03-27 19:11:51 +01002291 mchbar_write16(MIPMC4, 0x04f8);
2292 mchbar_write16(MIPMC5, 0x04fc);
2293 mchbar_write16(MIPMC6, 0x04fc);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002294 } else {
Angel Pons1d4044a2021-03-27 19:11:51 +01002295 mchbar_write16(MIPMC4, 0x64f8);
2296 mchbar_write16(MIPMC5, 0x64fc);
2297 mchbar_write16(MIPMC6, 0x64fc);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002298 }
2299
Angel Pons1d4044a2021-03-27 19:11:51 +01002300 reg32 = mchbar_read32(PMCFG);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002301 reg32 &= ~(3 << 17);
2302 reg32 |= (2 << 17);
Angel Pons1d4044a2021-03-27 19:11:51 +01002303 mchbar_write32(PMCFG, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002304
Angel Pons1d4044a2021-03-27 19:11:51 +01002305 mchbar_setbits32(PMCFG, 1 << 4);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002306
Angel Pons1d4044a2021-03-27 19:11:51 +01002307 reg32 = mchbar_read32(UPMC4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002308 reg32 &= 0xffffff00;
2309 reg32 |= 0x01;
Angel Pons1d4044a2021-03-27 19:11:51 +01002310 mchbar_write32(UPMC4, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002311
Angel Pons1d4044a2021-03-27 19:11:51 +01002312 mchbar_clrbits32(0xb18, 1 << 21);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002313}
2314
2315static void sdram_thermal_management(void)
2316{
Stefan Reinauer278534d2008-10-29 04:51:07 +00002317
Angel Pons1d4044a2021-03-27 19:11:51 +01002318 mchbar_write8(TCO1, 0);
2319 mchbar_write8(TCO0, 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002320
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002321 /* The Thermal Sensors for DIMMs at 0x50, 0x52 are at I2C addr 0x30/0x32. */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002322
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002323 /* TODO This is not implemented yet. Volunteers? */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002324}
2325
2326static void sdram_save_receive_enable(void)
2327{
2328 int i;
2329 u32 reg32;
2330 u8 values[4];
2331
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002332 /* The following values are stored to an unused CMOS area and restored instead of
2333 * recalculated in case of an S3 resume.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002334 *
Arthur Heymans70a8e342017-03-09 11:30:23 +01002335 * C0WL0REOST [7:0] -> 8 bit
2336 * C1WL0REOST [7:0] -> 8 bit
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002337 * RCVENMT [11:8] [3:0] -> 8 bit
2338 * C0DRT1 [27:24] -> 4 bit
2339 * C1DRT1 [27:24] -> 4 bit
2340 */
2341
Angel Pons1d4044a2021-03-27 19:11:51 +01002342 values[0] = mchbar_read8(C0WL0REOST);
2343 values[1] = mchbar_read8(C1WL0REOST);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002344
Angel Pons1d4044a2021-03-27 19:11:51 +01002345 reg32 = mchbar_read32(RCVENMT);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002346 values[2] = (u8)((reg32 >> (8 - 4)) & 0xf0) | (reg32 & 0x0f);
2347
Angel Pons1d4044a2021-03-27 19:11:51 +01002348 reg32 = mchbar_read32(C0DRT1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002349 values[3] = (reg32 >> 24) & 0x0f;
Angel Pons1d4044a2021-03-27 19:11:51 +01002350 reg32 = mchbar_read32(C1DRT1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002351 values[3] |= (reg32 >> (24 - 4)) & 0xf0;
2352
2353 /* coreboot only uses bytes 0 - 127 for its CMOS values so far
Edwin Beasanteb50c7d2010-07-06 21:05:04 +00002354 * so we grab bytes 128 - 131 to save the receive enable values
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002355 */
2356
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002357 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002358 cmos_write(values[i], 128 + i);
2359}
2360
2361static void sdram_recover_receive_enable(void)
2362{
2363 int i;
2364 u32 reg32;
2365 u8 values[4];
2366
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002367 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002368 values[i] = cmos_read(128 + i);
2369
Angel Pons1d4044a2021-03-27 19:11:51 +01002370 mchbar_write8(C0WL0REOST, values[0]);
2371 mchbar_write8(C1WL0REOST, values[1]);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002372
Angel Pons1d4044a2021-03-27 19:11:51 +01002373 reg32 = mchbar_read32(RCVENMT);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002374 reg32 &= ~((0x0f << 8) | (0x0f << 0));
2375 reg32 |= ((u32)(values[2] & 0xf0) << (8 - 4)) | (values[2] & 0x0f);
Angel Pons1d4044a2021-03-27 19:11:51 +01002376 mchbar_write32(RCVENMT, reg32);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002377
Angel Pons1d4044a2021-03-27 19:11:51 +01002378 reg32 = mchbar_read32(C0DRT1) & ~(0x0f << 24);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002379 reg32 |= (u32)(values[3] & 0x0f) << 24;
Angel Pons1d4044a2021-03-27 19:11:51 +01002380 mchbar_write32(C0DRT1, reg32);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002381
Angel Pons1d4044a2021-03-27 19:11:51 +01002382 reg32 = mchbar_read32(C1DRT1) & ~(0x0f << 24);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002383 reg32 |= (u32)(values[3] & 0xf0) << (24 - 4);
Angel Pons1d4044a2021-03-27 19:11:51 +01002384 mchbar_write32(C1DRT1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002385}
2386
Stefan Reinauer278534d2008-10-29 04:51:07 +00002387static void sdram_program_receive_enable(struct sys_info *sysinfo)
2388{
Angel Pons1d4044a2021-03-27 19:11:51 +01002389 mchbar_setbits32(REPC, 1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002390
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002391 /* Program Receive Enable Timings */
2392 if (sysinfo->boot_path == BOOT_PATH_RESUME) {
2393 sdram_recover_receive_enable();
2394 } else {
2395 receive_enable_adjust(sysinfo);
2396 sdram_save_receive_enable();
2397 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002398
Angel Pons1d4044a2021-03-27 19:11:51 +01002399 mchbar_setbits32(C0DRC1, 1 << 6);
2400 mchbar_setbits32(C1DRC1, 1 << 6);
2401 mchbar_clrbits32(C0DRC1, 1 << 6);
2402 mchbar_clrbits32(C1DRC1, 1 << 6);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002403
Angel Pons1d4044a2021-03-27 19:11:51 +01002404 mchbar_setbits32(MIPMC3, 0x0f << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002405}
2406
2407/**
2408 * @brief Enable On-Die Termination for DDR2.
2409 *
2410 */
2411
2412static void sdram_on_die_termination(struct sys_info *sysinfo)
2413{
2414 static const u32 odt[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002415 0x00024911, 0xe0010000,
2416 0x00049211, 0xe0020000,
2417 0x0006db11, 0xe0030000,
Stefan Reinauer278534d2008-10-29 04:51:07 +00002418 };
2419
2420 u32 reg32;
2421 int cas;
2422
Angel Pons1d4044a2021-03-27 19:11:51 +01002423 reg32 = mchbar_read32(ODTC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002424 reg32 &= ~(3 << 16);
2425 reg32 |= (1 << 14) | (1 << 6) | (2 << 16);
Angel Pons1d4044a2021-03-27 19:11:51 +01002426 mchbar_write32(ODTC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002427
Paul Menzelb4d9f222020-03-14 10:34:29 +01002428 if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002429 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
Elyes HAOUAS38424982016-08-21 12:01:04 +02002430 printk(BIOS_DEBUG, "one dimm per channel config..\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002431
Angel Pons1d4044a2021-03-27 19:11:51 +01002432 reg32 = mchbar_read32(C0ODT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002433 reg32 &= ~(7 << 28);
Angel Pons1d4044a2021-03-27 19:11:51 +01002434 mchbar_write32(C0ODT, reg32);
2435 reg32 = mchbar_read32(C1ODT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002436 reg32 &= ~(7 << 28);
Angel Pons1d4044a2021-03-27 19:11:51 +01002437 mchbar_write32(C1ODT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002438 }
2439
2440 cas = sysinfo->cas;
2441
Angel Pons1d4044a2021-03-27 19:11:51 +01002442 reg32 = mchbar_read32(C0ODT) & 0xfff00000;
Angel Pons30492572020-06-11 13:24:54 +02002443 reg32 |= odt[(cas - 3) * 2];
Angel Pons1d4044a2021-03-27 19:11:51 +01002444 mchbar_write32(C0ODT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002445
Angel Pons1d4044a2021-03-27 19:11:51 +01002446 reg32 = mchbar_read32(C1ODT) & 0xfff00000;
Angel Pons30492572020-06-11 13:24:54 +02002447 reg32 |= odt[(cas - 3) * 2];
Angel Pons1d4044a2021-03-27 19:11:51 +01002448 mchbar_write32(C1ODT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002449
Angel Pons1d4044a2021-03-27 19:11:51 +01002450 reg32 = mchbar_read32(C0ODT + 4) & 0x1fc8ffff;
Angel Pons30492572020-06-11 13:24:54 +02002451 reg32 |= odt[((cas - 3) * 2) + 1];
Angel Pons1d4044a2021-03-27 19:11:51 +01002452 mchbar_write32(C0ODT + 4, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002453
Angel Pons1d4044a2021-03-27 19:11:51 +01002454 reg32 = mchbar_read32(C1ODT + 4) & 0x1fc8ffff;
Angel Pons30492572020-06-11 13:24:54 +02002455 reg32 |= odt[((cas - 3) * 2) + 1];
Angel Pons1d4044a2021-03-27 19:11:51 +01002456 mchbar_write32(C1ODT + 4, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002457}
2458
2459/**
2460 * @brief Enable clocks to populated sockets
2461 */
2462
2463static void sdram_enable_memory_clocks(struct sys_info *sysinfo)
2464{
2465 u8 clocks[2] = { 0, 0 };
2466
Julius Wernercd49cce2019-03-05 16:53:33 -08002467#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002468#define CLOCKS_WIDTH 2
Julius Wernercd49cce2019-03-05 16:53:33 -08002469#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002470#define CLOCKS_WIDTH 3
2471#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002472 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002473 clocks[0] |= (1 << CLOCKS_WIDTH) - 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002474
2475 if (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002476 clocks[0] |= ((1 << CLOCKS_WIDTH) - 1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002477
2478 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002479 clocks[1] |= (1 << CLOCKS_WIDTH) - 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002480
2481 if (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002482 clocks[1] |= ((1 << CLOCKS_WIDTH) - 1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002483
Julius Wernercd49cce2019-03-05 16:53:33 -08002484#if CONFIG(OVERRIDE_CLOCK_DISABLE)
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002485 /* Usually system firmware turns off system memory clock signals to unused SO-DIMM slots
2486 * to reduce EMI and power consumption.
2487 * However, the Kontron 986LCD-M does not like unused clock signals to be disabled.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002488 */
2489
2490 clocks[0] = 0xf; /* force all clock gate pairs to enable */
2491 clocks[1] = 0xf; /* force all clock gate pairs to enable */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002492#endif
2493
Angel Pons1d4044a2021-03-27 19:11:51 +01002494 mchbar_write8(C0DCLKDIS, clocks[0]);
2495 mchbar_write8(C1DCLKDIS, clocks[1]);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002496}
2497
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002498#define RTT_ODT_NONE 0
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002499#define RTT_ODT_50_OHM ((1 << 9) | (1 << 5))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002500#define RTT_ODT_75_OHM (1 << 5)
2501#define RTT_ODT_150_OHM (1 << 9)
2502
Arthur Heymans70a8e342017-03-09 11:30:23 +01002503#define EMRS_OCD_DEFAULT ((1 << 12) | (1 << 11) | (1 << 10))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002504
2505#define MRS_CAS_3 (3 << 7)
2506#define MRS_CAS_4 (4 << 7)
2507#define MRS_CAS_5 (5 << 7)
2508
2509#define MRS_TWR_3 (2 << 12)
2510#define MRS_TWR_4 (3 << 12)
2511#define MRS_TWR_5 (4 << 12)
2512
2513#define MRS_BT (1 << 6)
2514
2515#define MRS_BL4 (2 << 3)
2516#define MRS_BL8 (3 << 3)
2517
2518static void sdram_jedec_enable(struct sys_info *sysinfo)
2519{
2520 int i, nonzero;
2521 u32 bankaddr = 0, tmpaddr, mrsaddr = 0;
2522
2523 for (i = 0, nonzero = -1; i < 8; i++) {
Elyes HAOUAS01912202019-01-19 16:36:38 +01002524 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002525 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002526
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002527 printk(BIOS_DEBUG, "jedec enable sequence: bank %d\n", i);
Elyes HAOUAS01912202019-01-19 16:36:38 +01002528
2529 if (nonzero != -1) {
2530 if (sysinfo->interleaved && nonzero < 4 && i >= 4) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002531 bankaddr = 0x40;
Elyes HAOUAS01912202019-01-19 16:36:38 +01002532 } else {
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002533 printk(BIOS_DEBUG, "bankaddr from bank size of rank %d\n",
2534 nonzero);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002535 bankaddr += sysinfo->banksize[nonzero] <<
2536 (sysinfo->interleaved ? 26 : 25);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002537 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002538 }
2539
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002540 /*
2541 * We have a bank with a non-zero size... Remember it
Stefan Reinauer278534d2008-10-29 04:51:07 +00002542 * for the next offset we have to calculate
2543 */
2544 nonzero = i;
2545
2546 /* Get CAS latency set up */
2547 switch (sysinfo->cas) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002548 case 5:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002549 mrsaddr = MRS_CAS_5;
2550 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002551 case 4:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002552 mrsaddr = MRS_CAS_4;
2553 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002554 case 3:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002555 mrsaddr = MRS_CAS_3;
2556 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002557 default:
2558 die("Jedec Error (CAS).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002559 }
2560
2561 /* Get tWR set */
2562 switch (sysinfo->twr) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002563 case 5:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002564 mrsaddr |= MRS_TWR_5;
2565 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002566 case 4:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002567 mrsaddr |= MRS_TWR_4;
2568 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002569 case 3:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002570 mrsaddr |= MRS_TWR_3;
2571 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002572 default:
2573 die("Jedec Error (tWR).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002574 }
2575
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002576 /* Set "Burst Type" */
2577 mrsaddr |= MRS_BT;
2578
Stefan Reinauer278534d2008-10-29 04:51:07 +00002579 /* Interleaved */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002580 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002581 mrsaddr = mrsaddr << 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002582
2583 /* Only burst length 8 supported */
2584 mrsaddr |= MRS_BL8;
2585
2586 /* Apply NOP */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002587 PRINTK_DEBUG("Apply NOP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002588 do_ram_command(RAM_COMMAND_NOP);
2589 ram_read32(bankaddr);
2590
2591 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002592 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002593 do_ram_command(RAM_COMMAND_PRECHARGE);
2594 ram_read32(bankaddr);
2595
2596 /* Extended Mode Register Set (2) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002597 PRINTK_DEBUG("Extended Mode Register Set(2)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002598 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_2);
2599 ram_read32(bankaddr);
2600
2601 /* Extended Mode Register Set (3) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002602 PRINTK_DEBUG("Extended Mode Register Set(3)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002603 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_3);
2604 ram_read32(bankaddr);
2605
2606 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002607 PRINTK_DEBUG("Extended Mode Register Set\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002608 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2609 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002610 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002611 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002612 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002613 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002614 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002615 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002616 ram_read32(tmpaddr);
2617
2618 /* Mode Register Set: Reset DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002619 PRINTK_DEBUG("MRS: Reset DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002620 do_ram_command(RAM_COMMAND_MRS);
2621 tmpaddr = bankaddr;
2622 tmpaddr |= mrsaddr;
2623 /* Set DLL reset bit */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002624 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002625 tmpaddr |= (1 << 12);
2626 else
2627 tmpaddr |= (1 << 11);
2628 ram_read32(tmpaddr);
2629
2630 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002631 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002632 do_ram_command(RAM_COMMAND_PRECHARGE);
2633 ram_read32(bankaddr);
2634
2635 /* CAS before RAS Refresh */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002636 PRINTK_DEBUG("CAS before RAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002637 do_ram_command(RAM_COMMAND_CBR);
2638
2639 /* CBR wants two READs */
2640 ram_read32(bankaddr);
2641 ram_read32(bankaddr);
2642
2643 /* Mode Register Set: Enable DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002644 PRINTK_DEBUG("MRS: Enable DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002645 do_ram_command(RAM_COMMAND_MRS);
2646
2647 tmpaddr = bankaddr;
2648 tmpaddr |= mrsaddr;
2649 ram_read32(tmpaddr);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002650
Stefan Reinauer278534d2008-10-29 04:51:07 +00002651 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002652 PRINTK_DEBUG("Extended Mode Register Set: ODT/OCD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002653 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002654
Stefan Reinauer278534d2008-10-29 04:51:07 +00002655 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002656 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002657 tmpaddr |= RTT_ODT_75_OHM | EMRS_OCD_DEFAULT;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002658 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002659 tmpaddr |= ((RTT_ODT_150_OHM | EMRS_OCD_DEFAULT) << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002660 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002661 tmpaddr |= RTT_ODT_150_OHM | EMRS_OCD_DEFAULT;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002662 ram_read32(tmpaddr);
2663
2664 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002665 PRINTK_DEBUG("Extended Mode Register Set: OCD Exit\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002666 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2667
2668 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002669 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002670 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002671 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002672 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002673 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002674 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002675 ram_read32(tmpaddr);
2676 }
2677}
2678
2679static void sdram_init_complete(void)
2680{
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002681 PRINTK_DEBUG("Normal Operation\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002682 do_ram_command(RAM_COMMAND_NORMAL);
2683}
2684
2685static void sdram_setup_processor_side(void)
2686{
2687 if (i945_silicon_revision() == 0)
Angel Pons1d4044a2021-03-27 19:11:51 +01002688 mchbar_setbits32(FSBPMC3, 1 << 2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002689
Angel Pons1d4044a2021-03-27 19:11:51 +01002690 mchbar_setbits8(0xb00, 1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002691
2692 if (i945_silicon_revision() == 0)
Angel Pons1d4044a2021-03-27 19:11:51 +01002693 mchbar_setbits32(SLPCTL, 1 << 8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002694}
2695
Stefan Reinauer278534d2008-10-29 04:51:07 +00002696/**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002697 * @param boot_path: 0 = normal, 1 = reset, 2 = resume from s3
Martin Rothf4cb4122015-01-06 10:27:39 -07002698 * @param spd_addresses pointer to a list of SPD addresses
Stefan Reinauer278534d2008-10-29 04:51:07 +00002699 */
Sven Schnelle541269b2011-02-21 09:39:17 +00002700void sdram_initialize(int boot_path, const u8 *spd_addresses)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002701{
2702 struct sys_info sysinfo;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002703
Jakub Czapigaad6157e2022-02-15 11:50:31 +01002704 timestamp_add_now(TS_INITRAM_START);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002705 printk(BIOS_DEBUG, "Setting up RAM controller.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002706
2707 memset(&sysinfo, 0, sizeof(sysinfo));
2708
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002709 sysinfo.boot_path = boot_path;
Sven Schnelle541269b2011-02-21 09:39:17 +00002710 sysinfo.spd_addresses = spd_addresses;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002711
Stefan Reinauer278534d2008-10-29 04:51:07 +00002712 /* Look at the type of DIMMs and verify all DIMMs are x8 or x16 width */
2713 sdram_get_dram_configuration(&sysinfo);
2714
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002715 /* If error, do cold boot */
2716 sdram_detect_errors(&sysinfo);
2717
Stefan Reinauer278534d2008-10-29 04:51:07 +00002718 /* Program PLL settings */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002719 sdram_program_pll_settings(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002720
Arthur Heymans18537812016-12-28 21:20:45 +01002721 /*
2722 * Program Graphics Frequency
2723 * Set core display and render clock on 945GC to the max
2724 */
Julius Wernercd49cce2019-03-05 16:53:33 -08002725 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM))
Arthur Heymans18537812016-12-28 21:20:45 +01002726 sdram_program_graphics_frequency(&sysinfo);
2727 else
Angel Pons3580d812020-06-11 14:13:33 +02002728 pci_write_config16(IGD_DEV, GCFC, 0x0534);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002729
2730 /* Program System Memory Frequency */
2731 sdram_program_memory_frequency(&sysinfo);
2732
2733 /* Determine Mode of Operation (Interleaved etc) */
2734 sdram_set_channel_mode(&sysinfo);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002735
Stefan Reinauer278534d2008-10-29 04:51:07 +00002736 /* Program Clock Crossing values */
2737 sdram_program_clock_crossing();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002738
Stefan Reinauer278534d2008-10-29 04:51:07 +00002739 /* Disable fast dispatch */
2740 sdram_disable_fast_dispatch();
2741
2742 /* Enable WIODLL Power Down in ACPI states */
Angel Pons1d4044a2021-03-27 19:11:51 +01002743 mchbar_setbits32(C0DMC, 1 << 24);
2744 mchbar_setbits32(C1DMC, 1 << 24);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002745
2746 /* Program DRAM Row Boundary/Attribute Registers */
2747
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002748 /* program row size DRB and set TOLUD */
2749 sdram_program_row_boundaries(&sysinfo);
2750
2751 /* program page size DRA */
2752 sdram_set_row_attributes(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002753
2754 /* Program CxBNKARC */
2755 sdram_set_bank_architecture(&sysinfo);
2756
2757 /* Program DRAM Timing and Control registers based on SPD */
2758 sdram_set_timing_and_control(&sysinfo);
2759
2760 /* On-Die Termination Adjustment */
2761 sdram_on_die_termination(&sysinfo);
2762
2763 /* Pre Jedec Initialization */
2764 sdram_pre_jedec_initialization();
2765
2766 /* Perform System Memory IO Initialization */
2767 sdram_initialize_system_memory_io(&sysinfo);
2768
2769 /* Perform System Memory IO Buffer Enable */
2770 sdram_enable_system_memory_io(&sysinfo);
2771
2772 /* Enable System Memory Clocks */
2773 sdram_enable_memory_clocks(&sysinfo);
2774
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002775 if (boot_path == BOOT_PATH_NORMAL) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002776 /* Jedec Initialization sequence */
2777 sdram_jedec_enable(&sysinfo);
2778 }
2779
2780 /* Program Power Management Registers */
2781 sdram_power_management(&sysinfo);
2782
2783 /* Post Jedec Init */
2784 sdram_post_jedec_initialization(&sysinfo);
2785
2786 /* Program DRAM Throttling */
2787 sdram_thermal_management();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002788
Stefan Reinauer278534d2008-10-29 04:51:07 +00002789 /* Normal Operations */
Stefan Reinaueraca6ec62009-10-26 17:12:21 +00002790 sdram_init_complete();
Stefan Reinauer278534d2008-10-29 04:51:07 +00002791
2792 /* Program Receive Enable Timings */
2793 sdram_program_receive_enable(&sysinfo);
2794
2795 /* Enable Periodic RCOMP */
2796 sdram_enable_rcomp();
2797
2798 /* Tell ICH7 that we're done */
Angel Ponse3c68d22020-06-08 12:09:03 +02002799 pci_and_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, (u8)~(1 << 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +00002800
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002801 printk(BIOS_DEBUG, "RAM initialization finished.\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002802
Stefan Reinauer278534d2008-10-29 04:51:07 +00002803 sdram_setup_processor_side();
Jakub Czapigaad6157e2022-02-15 11:50:31 +01002804 timestamp_add_now(TS_INITRAM_END);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002805}