blob: c9b08378ae8f90572bb1e39c90f02f181e89d2e1 [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>
Paul Menzel8917ab42022-10-11 08:09:14 +020012#include <inttypes.h>
Julius Werner7a8a4ab2015-05-22 16:26:40 -070013#include <lib.h>
Edwin Beasanteb50c7d2010-07-06 21:05:04 +000014#include <pc80/mc146818rtc.h>
Stefan Reinauer278534d2008-10-29 04:51:07 +000015#include <spd.h>
Patrick Georgid0835952010-10-05 09:07:10 +000016#include <string.h>
Elyes Haouas4114fdc2022-10-02 13:48:07 +020017#include <timestamp.h>
18#include <types.h>
19
Stefan Reinauer278534d2008-10-29 04:51:07 +000020#include "raminit.h"
21#include "i945.h"
Arthur Heymans885c2892016-10-03 17:16:48 +020022#include "chip.h"
Rudolf Marekc4369532010-12-13 19:59:13 +000023
Stefan Reinauer278534d2008-10-29 04:51:07 +000024/* Debugging macros. */
Julius Wernercd49cce2019-03-05 16:53:33 -080025#if CONFIG(DEBUG_RAM_SETUP)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000026#define PRINTK_DEBUG(x...) printk(BIOS_DEBUG, x)
Stefan Reinauer278534d2008-10-29 04:51:07 +000027#else
28#define PRINTK_DEBUG(x...)
29#endif
30
Stefan Reinauer278534d2008-10-29 04:51:07 +000031#define RAM_INITIALIZATION_COMPLETE (1 << 19)
32
33#define RAM_COMMAND_SELF_REFRESH (0x0 << 16)
34#define RAM_COMMAND_NOP (0x1 << 16)
35#define RAM_COMMAND_PRECHARGE (0x2 << 16)
36#define RAM_COMMAND_MRS (0x3 << 16)
37#define RAM_COMMAND_EMRS (0x4 << 16)
38#define RAM_COMMAND_CBR (0x6 << 16)
39#define RAM_COMMAND_NORMAL (0x7 << 16)
40
41#define RAM_EMRS_1 (0x0 << 21)
42#define RAM_EMRS_2 (0x1 << 21)
43#define RAM_EMRS_3 (0x2 << 21)
44
Arthur Heymans885c2892016-10-03 17:16:48 +020045#define DEFAULT_PCI_MMIO_SIZE 768
Sven Schnelle541269b2011-02-21 09:39:17 +000046static int get_dimm_spd_address(struct sys_info *sysinfo, int device)
47{
48 if (sysinfo->spd_addresses)
49 return sysinfo->spd_addresses[device];
50 else
Angel Ponse97a66d2021-04-03 00:15:16 +020051 return 0x50 + device;
Sven Schnelle541269b2011-02-21 09:39:17 +000052
53}
54
Stefan Reinauerbc8613e2010-08-25 18:35:42 +000055static __attribute__((noinline)) void do_ram_command(u32 command)
Stefan Reinauer278534d2008-10-29 04:51:07 +000056{
57 u32 reg32;
58
Angel Pons1d4044a2021-03-27 19:11:51 +010059 reg32 = mchbar_read32(DCC);
Angel Pons30492572020-06-11 13:24:54 +020060 reg32 &= ~((3 << 21) | (1 << 20) | (1 << 19) | (7 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +000061 reg32 |= command;
62
63 /* Also set Init Complete */
64 if (command == RAM_COMMAND_NORMAL)
65 reg32 |= RAM_INITIALIZATION_COMPLETE;
66
67 PRINTK_DEBUG(" Sending RAM command 0x%08x", reg32);
68
Angel Pons1d4044a2021-03-27 19:11:51 +010069 mchbar_write32(DCC, reg32); /* This is the actual magic */
Stefan Reinauer278534d2008-10-29 04:51:07 +000070
Stefan Reinauer779b3e32008-11-10 15:43:37 +000071 PRINTK_DEBUG("...done\n");
Stefan Reinauerd058ad12010-08-26 12:43:58 +000072
73 udelay(1);
Stefan Reinauer278534d2008-10-29 04:51:07 +000074}
75
Elyes HAOUAS964055d2022-01-14 18:56:49 +010076static void ram_read32(uintptr_t offset)
Stefan Reinauer278534d2008-10-29 04:51:07 +000077{
Elyes Haouase8bb6d22022-10-04 14:16:09 +020078 PRINTK_DEBUG(" RAM read: %" PRIxPTR "\n", offset);
Stefan Reinauer278534d2008-10-29 04:51:07 +000079
Elyes Haouas712c70b2022-02-25 10:05:22 +010080 read32p(offset);
Stefan Reinauer278534d2008-10-29 04:51:07 +000081}
82
Stefan Reinauer3c0bfaf2010-12-27 11:34:57 +000083void sdram_dump_mchbar_registers(void)
Stefan Reinauer278534d2008-10-29 04:51:07 +000084{
85 int i;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000086 printk(BIOS_DEBUG, "Dumping MCHBAR Registers\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +000087
Arthur Heymans70a8e342017-03-09 11:30:23 +010088 for (i = 0; i < 0xfff; i += 4) {
Angel Pons1d4044a2021-03-27 19:11:51 +010089 if (mchbar_read32(i) == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +000090 continue;
Angel Pons1d4044a2021-03-27 19:11:51 +010091 printk(BIOS_DEBUG, "0x%04x: 0x%08x\n", i, mchbar_read32(i));
Stefan Reinauer278534d2008-10-29 04:51:07 +000092 }
93}
Stefan Reinauer278534d2008-10-29 04:51:07 +000094
Stefan Reinauer24b4df52010-01-17 13:47:35 +000095static int memclk(void)
96{
Julius Wernercd49cce2019-03-05 16:53:33 -080097 int offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Elyes HAOUASc9848a82016-10-09 20:24:20 +020098
Angel Pons1d4044a2021-03-27 19:11:51 +010099 switch (((mchbar_read32(CLKCFG) >> 4) & 7) - offset) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000100 case 1: return 400;
101 case 2: return 533;
102 case 3: return 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100103 default:
Elyes HAOUAS3cd43272020-03-05 22:01:17 +0100104 printk(BIOS_DEBUG, "%s: unknown register value %x\n", __func__,
Angel Pons1d4044a2021-03-27 19:11:51 +0100105 ((mchbar_read32(CLKCFG) >> 4) & 7) - offset);
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000106 }
107 return -1;
108}
109
Peter Stuge76d91432010-10-01 10:02:33 +0000110static u16 fsbclk(void)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000111{
Julius Wernercd49cce2019-03-05 16:53:33 -0800112 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Angel Pons1d4044a2021-03-27 19:11:51 +0100113 switch (mchbar_read32(CLKCFG) & 7) {
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200114 case 0: return 400;
115 case 1: return 533;
116 case 3: return 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100117 default:
Elyes HAOUAS3cd43272020-03-05 22:01:17 +0100118 printk(BIOS_DEBUG, "%s: unknown register value %x\n", __func__,
Angel Pons1d4044a2021-03-27 19:11:51 +0100119 mchbar_read32(CLKCFG) & 7);
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200120 }
121 return 0xffff;
Julius Wernercd49cce2019-03-05 16:53:33 -0800122 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Angel Pons1d4044a2021-03-27 19:11:51 +0100123 switch (mchbar_read32(CLKCFG) & 7) {
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200124 case 0: return 1066;
125 case 1: return 533;
126 case 2: return 800;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100127 default:
Elyes HAOUAS3cd43272020-03-05 22:01:17 +0100128 printk(BIOS_DEBUG, "%s: unknown register value %x\n", __func__,
Angel Pons1d4044a2021-03-27 19:11:51 +0100129 mchbar_read32(CLKCFG) & 7);
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200130 }
131 return 0xffff;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000132 }
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000133}
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000134
Stefan Reinauer278534d2008-10-29 04:51:07 +0000135static int sdram_capabilities_max_supported_memory_frequency(void)
136{
137 u32 reg32;
138
Patrick Georgi77d66832010-10-01 08:02:45 +0000139#if CONFIG_MAXIMUM_SUPPORTED_FREQUENCY
140 return CONFIG_MAXIMUM_SUPPORTED_FREQUENCY;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000141#endif
142
Angel Pons3580d812020-06-11 14:13:33 +0200143 reg32 = pci_read_config32(HOST_BRIDGE, 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000144 reg32 &= (7 << 0);
145
146 switch (reg32) {
147 case 4: return 400;
148 case 3: return 533;
149 case 2: return 667;
150 }
151 /* Newer revisions of this chipset rather support faster memory clocks,
152 * so if it's a reserved value, return the fastest memory clock that we
153 * know of and can handle
154 */
155 return 667;
156}
157
158/**
159 * @brief determine whether chipset is capable of dual channel interleaved mode
160 *
161 * @return 1 if interleaving is supported, 0 otherwise
162 */
163static int sdram_capabilities_interleave(void)
164{
165 u32 reg32;
166
Angel Pons3580d812020-06-11 14:13:33 +0200167 reg32 = pci_read_config32(HOST_BRIDGE, 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000168 reg32 >>= 25;
169 reg32 &= 1;
170
171 return (!reg32);
172}
173
174/**
175 * @brief determine whether chipset is capable of two memory channels
176 *
177 * @return 1 if dual channel operation is supported, 0 otherwise
178 */
179static int sdram_capabilities_dual_channel(void)
180{
181 u32 reg32;
182
Angel Pons3580d812020-06-11 14:13:33 +0200183 reg32 = pci_read_config32(HOST_BRIDGE, 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000184 reg32 >>= 24;
185 reg32 &= 1;
186
187 return (!reg32);
188}
189
190static int sdram_capabilities_enhanced_addressing_xor(void)
191{
192 u8 reg8;
193
Angel Pons3580d812020-06-11 14:13:33 +0200194 reg8 = pci_read_config8(HOST_BRIDGE, 0xe5); /* CAPID0 + 5 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000195 reg8 &= (1 << 7);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000196
Stefan Reinauer278534d2008-10-29 04:51:07 +0000197 return (!reg8);
198}
199
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000200#define GFX_FREQUENCY_CAP_166MHZ 0x04
201#define GFX_FREQUENCY_CAP_200MHZ 0x03
202#define GFX_FREQUENCY_CAP_250MHZ 0x02
203#define GFX_FREQUENCY_CAP_ALL 0x00
204
205static int sdram_capabilities_core_frequencies(void)
206{
207 u8 reg8;
208
Angel Pons3580d812020-06-11 14:13:33 +0200209 reg8 = pci_read_config8(HOST_BRIDGE, 0xe5); /* CAPID0 + 5 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000210 reg8 &= (1 << 3) | (1 << 2) | (1 << 1);
211 reg8 >>= 1;
212
Arthur Heymans70a8e342017-03-09 11:30:23 +0100213 return reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000214}
215
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000216static void sdram_detect_errors(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000217{
218 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000219 u8 do_reset = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000220
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100221 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000222
Angel Pons30492572020-06-11 13:24:54 +0200223 if (reg8 & ((1 << 7) | (1 << 2))) {
224 if (reg8 & (1 << 2)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000225 printk(BIOS_DEBUG, "SLP S4# Assertion Width Violation.\n");
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000226 /* Write back clears bit 2 */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100227 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000228 do_reset = 1;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000229
Stefan Reinauer278534d2008-10-29 04:51:07 +0000230 }
231
Angel Pons30492572020-06-11 13:24:54 +0200232 if (reg8 & (1 << 7)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000233 printk(BIOS_DEBUG, "DRAM initialization was interrupted.\n");
Angel Pons30492572020-06-11 13:24:54 +0200234 reg8 &= ~(1 << 7);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100235 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000236 do_reset = 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000237 }
238
239 /* Set SLP_S3# Assertion Stretch Enable */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100240 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000241 reg8 |= (1 << 3);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100242 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000243
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000244 if (do_reset) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000245 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200246 full_reset();
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000247 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000248 }
249
250 /* Set DRAM initialization bit in ICH7 */
Angel Ponse3c68d22020-06-08 12:09:03 +0200251 pci_or_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, 1 << 7);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000252
Peter Stuge751508a2012-01-27 22:17:09 +0100253 /* clear self refresh status if check is disabled or not a resume */
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200254 if (!CONFIG(CHECK_SLFRCS_ON_RESUME) || sysinfo->boot_path != BOOT_PATH_RESUME) {
Angel Pons1d4044a2021-03-27 19:11:51 +0100255 mchbar_setbits8(SLFRCS, 3);
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000256 } else {
257 /* Validate self refresh config */
258 if (((sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED) ||
259 (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)) &&
Angel Pons1d4044a2021-03-27 19:11:51 +0100260 !(mchbar_read8(SLFRCS) & (1 << 0))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000261 do_reset = 1;
262 }
263 if (((sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED) ||
264 (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) &&
Angel Pons1d4044a2021-03-27 19:11:51 +0100265 !(mchbar_read8(SLFRCS) & (1 << 1))) {
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000266 do_reset = 1;
267 }
268 }
269
270 if (do_reset) {
271 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200272 full_reset();
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000273 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000274}
Stefan Reinauer278534d2008-10-29 04:51:07 +0000275
Arthur Heymans0ab49042017-02-06 22:40:14 +0100276struct timings {
277 u32 min_tCLK_cas[8];
278 u32 min_tRAS;
279 u32 min_tRP;
280 u32 min_tRCD;
281 u32 min_tWR;
282 u32 min_tRFC;
283 u32 max_tRR;
284 u8 cas_mask;
285};
Stefan Reinauer278534d2008-10-29 04:51:07 +0000286
Arthur Heymans0ab49042017-02-06 22:40:14 +0100287/**
288 * @brief loop over dimms and save maximal timings
289 */
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200290static void gather_common_timing(struct sys_info *sysinfo, struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000291{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100292
293 int i, j;
294 u8 raw_spd[SPD_SIZE_MAX_DDR2];
295 u8 dimm_mask = 0;
296
297 memset(saved_timings, 0, sizeof(*saved_timings));
298 saved_timings->max_tRR = UINT32_MAX;
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200299 saved_timings->cas_mask = SPD_CAS_LATENCY_DDR2_3 | SPD_CAS_LATENCY_DDR2_4
300 | SPD_CAS_LATENCY_DDR2_5;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000301
302 /**
303 * i945 supports two DIMMs, in two configurations:
304 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000305 * - single channel with two DIMMs
306 * - dual channel with one DIMM per channel
Stefan Reinauer278534d2008-10-29 04:51:07 +0000307 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000308 * In practice dual channel mainboards have their SPD at 0x50/0x52
309 * whereas single channel configurations have their SPD at 0x50/0x51.
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000310 *
Stefan Reinauer278534d2008-10-29 04:51:07 +0000311 * The capability register knows a lot about the channel configuration
Uwe Hermannd773fd32010-11-20 20:23:08 +0000312 * but for now we stick with the information we gather via SPD.
Stefan Reinauer278534d2008-10-29 04:51:07 +0000313 */
314
Arthur Heymans0ab49042017-02-06 22:40:14 +0100315 printk(BIOS_DEBUG, "This mainboard supports ");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000316 if (sdram_capabilities_dual_channel()) {
Elyes Haouas49446092022-09-28 14:14:05 +0200317 sysinfo->dual_channel = true;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100318 printk(BIOS_DEBUG, "Dual Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000319 } else {
Elyes Haouas49446092022-09-28 14:14:05 +0200320 sysinfo->dual_channel = false;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100321 printk(BIOS_DEBUG, "only Single Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000322 }
323
Arthur Heymans70a8e342017-03-09 11:30:23 +0100324 for (i = 0; i < (2 * DIMM_SOCKETS); i++) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100325 int device = get_dimm_spd_address(sysinfo, i), bytes_read;
Arthur Heymansfc31e442018-02-12 15:12:34 +0100326 struct dimm_attr_ddr2_st dimm_info;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000327
328 /* Initialize the socket information with a sane value */
329 sysinfo->dimm[i] = SYSINFO_DIMM_NOT_POPULATED;
330
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000331 /* Dual Channel not supported, but Channel 1? Bail out */
332 if (!sdram_capabilities_dual_channel() && (i >> 1))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000333 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000334
Kyösti Mälkkibd659852020-01-05 20:00:18 +0200335 if (smbus_read_byte(device, SPD_MEMORY_TYPE) !=
Arthur Heymans0ab49042017-02-06 22:40:14 +0100336 SPD_MEMORY_TYPE_SDRAM_DDR2) {
337 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: N/A\n",
338 (i >> 1), (i & 1));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000339 continue;
340 }
341
Arthur Heymans0ab49042017-02-06 22:40:14 +0100342 /*
343 * spd_decode_ddr2() needs a 128-byte sized array but
344 * only the first 64 bytes contain data needed for raminit.
345 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000346
Kyösti Mälkkic01a5052019-01-30 09:39:23 +0200347 bytes_read = i2c_eeprom_read(device, 0, 64, raw_spd);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100348 printk(BIOS_DEBUG, "Reading SPD using i2c block operation.\n");
Julius Wernercd49cce2019-03-05 16:53:33 -0800349 if (CONFIG(DEBUG_RAM_SETUP) && bytes_read > 0)
Arthur Heymans0ab49042017-02-06 22:40:14 +0100350 hexdump(raw_spd, bytes_read);
Arthur Heymans56619452017-09-21 09:12:42 +0200351 if (bytes_read != 64) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100352 /* Try again with SMBUS byte read */
353 printk(BIOS_DEBUG, "i2c block operation failed,"
Paul Menzel105e3682017-09-21 08:11:05 +0200354 " trying smbus byte operation.\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100355 for (j = 0; j < 64; j++)
Kyösti Mälkkibd659852020-01-05 20:00:18 +0200356 raw_spd[j] = smbus_read_byte(device, j);
Julius Wernercd49cce2019-03-05 16:53:33 -0800357 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100358 hexdump(raw_spd, 64);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100359 }
Arthur Heymans56619452017-09-21 09:12:42 +0200360
361 if (spd_decode_ddr2(&dimm_info, raw_spd) != SPD_STATUS_OK) {
362 printk(BIOS_WARNING, "Encountered problems with SPD, "
363 "skipping this DIMM.\n");
364 continue;
365 }
366
Julius Wernercd49cce2019-03-05 16:53:33 -0800367 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100368 dram_print_spd_ddr2(&dimm_info);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000369
Arthur Heymans0ab49042017-02-06 22:40:14 +0100370 if (dimm_info.flags.is_ecc)
371 die("\nError: ECC memory not supported by this chipset\n");
372
373 if (spd_dimm_is_registered_ddr2(dimm_info.dimm_type))
374 die("\nError: Registered memory not supported by this chipset\n");
375
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200376 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: ", (i >> 1), (i & 1));
Arthur Heymans0ab49042017-02-06 22:40:14 +0100377 /**
378 * There are 5 different possible populations for a DIMM socket:
379 * 0. x16 double ranked (X16DS)
380 * 1. x8 double ranked (X8DS)
381 * 2. x16 single ranked (X16SS)
382 * 3. x8 double stacked (X8DDS)
383 * 4. Unpopulated
384 */
385 switch (dimm_info.width) {
386 case 8:
387 switch (dimm_info.ranks) {
388 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000389 printk(BIOS_DEBUG, "x8DDS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000390 sysinfo->dimm[i] = SYSINFO_DIMM_X8DDS;
391 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100392 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000393 printk(BIOS_DEBUG, "x8DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000394 sysinfo->dimm[i] = SYSINFO_DIMM_X8DS;
395 break;
396 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000397 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000398 }
399 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100400 case 16:
401 switch (dimm_info.ranks) {
402 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000403 printk(BIOS_DEBUG, "x16DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000404 sysinfo->dimm[i] = SYSINFO_DIMM_X16DS;
405 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100406 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000407 printk(BIOS_DEBUG, "x16SS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000408 sysinfo->dimm[i] = SYSINFO_DIMM_X16SS;
409 break;
410 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000411 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000412 }
413 break;
414 default:
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000415 die("Unsupported DDR-II memory width.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000416 }
417
Arthur Heymans0ab49042017-02-06 22:40:14 +0100418 /* Is the current DIMM a stacked DIMM? */
419 if (dimm_info.flags.stacked)
420 sysinfo->package = SYSINFO_PACKAGE_STACKED;
421
422 if (!dimm_info.flags.bl8)
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100423 die("Only DDR-II RAM with burst length 8 is supported.\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100424
425 if (dimm_info.ranksize_mb < 128)
426 die("DDR-II rank size smaller than 128MB is not supported.\n");
427
428 sysinfo->banksize[i * 2] = dimm_info.ranksize_mb / 32;
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200429 printk(BIOS_DEBUG, "DIMM %d side 0 = %d MB\n", i, sysinfo->banksize[i * 2] * 32);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100430 if (dimm_info.ranks == 2) {
431 sysinfo->banksize[(i * 2) + 1] =
432 dimm_info.ranksize_mb / 32;
433 printk(BIOS_DEBUG, "DIMM %d side 1 = %d MB\n",
434 i, sysinfo->banksize[(i * 2) + 1] * 32);
435 }
436
Arthur Heymans0ab49042017-02-06 22:40:14 +0100437 sysinfo->rows[i] = dimm_info.row_bits;
438 sysinfo->cols[i] = dimm_info.col_bits;
439 sysinfo->banks[i] = dimm_info.banks;
440
441 /* int min_tRAS, min_tRP, min_tRCD, min_tWR, min_tRFC; */
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200442 saved_timings->min_tRAS = MAX(saved_timings->min_tRAS, dimm_info.tRAS);
443 saved_timings->min_tRP = MAX(saved_timings->min_tRP, dimm_info.tRP);
444 saved_timings->min_tRCD = MAX(saved_timings->min_tRCD, dimm_info.tRCD);
445 saved_timings->min_tWR = MAX(saved_timings->min_tWR, dimm_info.tWR);
446 saved_timings->min_tRFC = MAX(saved_timings->min_tRFC, dimm_info.tRFC);
447 saved_timings->max_tRR = MIN(saved_timings->max_tRR, dimm_info.tRR);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100448 saved_timings->cas_mask &= dimm_info.cas_supported;
449 for (j = 0; j < 8; j++) {
450 if (!(saved_timings->cas_mask & (1 << j)))
451 saved_timings->min_tCLK_cas[j] = 0;
452 else
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200453 saved_timings->min_tCLK_cas[j] = MAX(dimm_info.cycle_time[j],
Arthur Heymans0ab49042017-02-06 22:40:14 +0100454 saved_timings->min_tCLK_cas[j]);
455 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000456 dimm_mask |= (1 << i);
457 }
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200458 if (!dimm_mask)
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000459 die("No memory installed.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000460
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200461 if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1)))
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100462 /* FIXME: Possibly does not boot in this case */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000463 printk(BIOS_INFO, "Channel 0 has no memory populated.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000464}
465
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200466static void choose_tclk(struct sys_info *sysinfo, struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000467{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100468 u32 ctrl_min_tclk;
469 int try_cas;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000470
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200471 ctrl_min_tclk = 2 * 256 * 1000 / sdram_capabilities_max_supported_memory_frequency();
Arthur Heymans0ab49042017-02-06 22:40:14 +0100472 normalize_tck(&ctrl_min_tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000473
Arthur Heymans0ab49042017-02-06 22:40:14 +0100474 try_cas = spd_get_msbs(saved_timings->cas_mask);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000475
Arthur Heymans0ab49042017-02-06 22:40:14 +0100476 while (saved_timings->cas_mask & (1 << try_cas) && try_cas > 0) {
477 sysinfo->cas = try_cas;
478 sysinfo->tclk = saved_timings->min_tCLK_cas[try_cas];
479 if (sysinfo->tclk >= ctrl_min_tclk &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200480 saved_timings->min_tCLK_cas[try_cas] !=
481 saved_timings->min_tCLK_cas[try_cas - 1])
Stefan Reinauer278534d2008-10-29 04:51:07 +0000482 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100483 try_cas--;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000484 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000485
Arthur Heymans0ab49042017-02-06 22:40:14 +0100486 normalize_tck(&sysinfo->tclk);
487
488 if ((sysinfo->cas < 3) || (sysinfo->tclk == 0))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000489 die("Could not find common memory frequency and CAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000490
Arthur Heymans0ab49042017-02-06 22:40:14 +0100491 /*
492 * The loop can still results in a timing too fast for the
493 * memory controller.
494 */
495 if (sysinfo->tclk < ctrl_min_tclk)
496 sysinfo->tclk = ctrl_min_tclk;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000497
Arthur Heymans0ab49042017-02-06 22:40:14 +0100498 switch (sysinfo->tclk) {
499 case TCK_200MHZ:
500 sysinfo->memory_frequency = 400;
501 break;
502 case TCK_266MHZ:
503 sysinfo->memory_frequency = 533;
504 break;
505 case TCK_333MHZ:
506 sysinfo->memory_frequency = 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100507 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000508 }
509
Arthur Heymans0ab49042017-02-06 22:40:14 +0100510 printk(BIOS_DEBUG,
511 "Memory will be driven at %dMT with CAS=%d clocks\n",
512 sysinfo->memory_frequency, sysinfo->cas);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000513}
514
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200515static void derive_timings(struct sys_info *sysinfo, struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000516{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100517 sysinfo->tras = DIV_ROUND_UP(saved_timings->min_tRAS, sysinfo->tclk);
518 if (sysinfo->tras > 0x18)
519 die("DDR-II Module does not support this frequency (tRAS error)\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000520
Arthur Heymans0ab49042017-02-06 22:40:14 +0100521 sysinfo->trp = DIV_ROUND_UP(saved_timings->min_tRP, sysinfo->tclk);
522 if (sysinfo->trp > 6)
523 die("DDR-II Module does not support this frequency (tRP error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000524
Arthur Heymans0ab49042017-02-06 22:40:14 +0100525 sysinfo->trcd = DIV_ROUND_UP(saved_timings->min_tRCD, sysinfo->tclk);
526 if (sysinfo->trcd > 6)
527 die("DDR-II Module does not support this frequency (tRCD error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000528
Arthur Heymans0ab49042017-02-06 22:40:14 +0100529 sysinfo->twr = DIV_ROUND_UP(saved_timings->min_tWR, sysinfo->tclk);
530 if (sysinfo->twr > 5)
531 die("DDR-II Module does not support this frequency (tWR error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000532
Arthur Heymans0ab49042017-02-06 22:40:14 +0100533 sysinfo->trfc = DIV_ROUND_UP(saved_timings->min_tRFC, sysinfo->tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000534
Arthur Heymans0ab49042017-02-06 22:40:14 +0100535 printk(BIOS_DEBUG, "tRAS = %d cycles\n", sysinfo->tras);
536 printk(BIOS_DEBUG, "tRP = %d cycles\n", sysinfo->trp);
537 printk(BIOS_DEBUG, "tRCD = %d cycles\n", sysinfo->trcd);
538 printk(BIOS_DEBUG, "tWR = %d cycles\n", sysinfo->twr);
539 printk(BIOS_DEBUG, "tRFC = %d cycles\n", sysinfo->trfc);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000540
Arthur Heymans0ab49042017-02-06 22:40:14 +0100541 /* Refresh is slower than 15.6us, use 15.6us */
542 /* tRR is decoded in units of 1/256us */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000543
Arthur Heymans0ab49042017-02-06 22:40:14 +0100544#define T_RR_7_8US 2000000
545#define T_RR_15_6US 4000000
546#define REFRESH_7_8US 1
547#define REFRESH_15_6US 0
Stefan Reinauer278534d2008-10-29 04:51:07 +0000548
Arthur Heymans0ab49042017-02-06 22:40:14 +0100549 if (saved_timings->max_tRR < T_RR_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000550 die("DDR-II module has unsupported refresh value\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100551 else if (saved_timings->max_tRR < T_RR_15_6US)
552 sysinfo->refresh = REFRESH_7_8US;
553 else
554 sysinfo->refresh = REFRESH_15_6US;
Angel Pons30492572020-06-11 13:24:54 +0200555 printk(BIOS_DEBUG, "Refresh: %s\n", sysinfo->refresh ? "7.8us" : "15.6us");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000556}
557
Arthur Heymans0ab49042017-02-06 22:40:14 +0100558/**
559 * @brief Get generic DIMM parameters.
560 * @param sysinfo Central memory controller information structure
561 *
562 * This function gathers several pieces of information for each system DIMM:
563 * o DIMM width (x8 / x16)
564 * o DIMM rank (single ranked / dual ranked)
565 *
566 * Also, some non-supported scenarios are detected.
567 */
568
569static void sdram_get_dram_configuration(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000570{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100571 struct timings saved_timings;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000572
Arthur Heymans0ab49042017-02-06 22:40:14 +0100573 gather_common_timing(sysinfo, &saved_timings);
574 choose_tclk(sysinfo, &saved_timings);
575 derive_timings(sysinfo, &saved_timings);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000576}
577
Arthur Heymans70a8e342017-03-09 11:30:23 +0100578static void sdram_program_dram_width(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000579{
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200580 u16 c0dramw = 0, c1dramw = 0;
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200581 int i, idx;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000582
583 if (sysinfo->dual_channel)
584 idx = 2;
585 else
586 idx = 1;
587
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200588 for (i = 0; i < DIMM_SOCKETS; i++) { /* Channel 0 */
589 switch (sysinfo->dimm[i]) {
590 case SYSINFO_DIMM_X16DS:
Angel Pons30492572020-06-11 13:24:54 +0200591 c0dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200592 break;
593 case SYSINFO_DIMM_X8DS:
Angel Pons30492572020-06-11 13:24:54 +0200594 c0dramw |= (0x0001) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200595 break;
596 case SYSINFO_DIMM_X16SS:
Angel Pons30492572020-06-11 13:24:54 +0200597 c0dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200598 break;
599 case SYSINFO_DIMM_X8DDS:
Angel Pons30492572020-06-11 13:24:54 +0200600 c0dramw |= (0x0005) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200601 break;
602 case SYSINFO_DIMM_NOT_POPULATED:
Angel Pons30492572020-06-11 13:24:54 +0200603 c0dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200604 break;
605 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000606 }
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200607 for (i = DIMM_SOCKETS; i < idx * DIMM_SOCKETS; i++) { /* Channel 1 */
608 switch (sysinfo->dimm[i]) {
609 case SYSINFO_DIMM_X16DS:
Angel Pons30492572020-06-11 13:24:54 +0200610 c1dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200611 break;
612 case SYSINFO_DIMM_X8DS:
Angel Pons30492572020-06-11 13:24:54 +0200613 c1dramw |= (0x0010) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200614 break;
615 case SYSINFO_DIMM_X16SS:
Angel Pons30492572020-06-11 13:24:54 +0200616 c1dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200617 break;
618 case SYSINFO_DIMM_X8DDS:
Angel Pons30492572020-06-11 13:24:54 +0200619 c1dramw |= (0x0050) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200620 break;
621 case SYSINFO_DIMM_NOT_POPULATED:
Angel Pons30492572020-06-11 13:24:54 +0200622 c1dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200623 break;
624 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000625 }
626
Angel Pons1d4044a2021-03-27 19:11:51 +0100627 mchbar_write16(C0DRAMW, c0dramw);
628 mchbar_write16(C1DRAMW, c1dramw);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000629}
630
631static void sdram_write_slew_rates(u32 offset, const u32 *slew_rate_table)
632{
633 int i;
634
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200635 for (i = 0; i < 16; i++)
Angel Pons1d4044a2021-03-27 19:11:51 +0100636 mchbar_write32(offset + (i * 4), slew_rate_table[i]);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000637}
638
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000639static const u32 dq2030[] = {
640 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
641 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
642 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
643 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
644};
645
646static const u32 dq2330[] = {
647 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
648 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
649 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
650 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
651};
652
653static const u32 cmd2710[] = {
654 0x07060605, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
655 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
656 0x1110100f, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
657 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
658};
659
660static const u32 cmd3210[] = {
661 0x0f0d0b0a, 0x17151311, 0x1f1d1b19, 0x1f1f1f1f,
662 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
663 0x18171615, 0x1f1f1c1a, 0x1f1f1f1f, 0x1f1f1f1f,
664 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
665};
666
667static const u32 clk2030[] = {
668 0x0e0d0d0c, 0x100f0f0e, 0x100f0e0d, 0x15131211,
669 0x1d1b1917, 0x2523211f, 0x2a282927, 0x32302e2c,
670 0x17161514, 0x1b1a1918, 0x1f1e1d1c, 0x23222120,
671 0x27262524, 0x2d2b2928, 0x3533312f, 0x3d3b3937
672};
673
674static const u32 ctl3215[] = {
675 0x01010000, 0x03020101, 0x07060504, 0x0b0a0908,
676 0x100f0e0d, 0x14131211, 0x18171615, 0x1c1b1a19,
677 0x05040403, 0x07060605, 0x0a090807, 0x0f0d0c0b,
678 0x14131211, 0x18171615, 0x1c1b1a19, 0x201f1e1d
679};
680
681static const u32 ctl3220[] = {
682 0x05040403, 0x07060505, 0x0e0c0a08, 0x1a171411,
683 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e,
684 0x09080807, 0x0b0a0a09, 0x0f0d0c0b, 0x1b171311,
685 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e
686};
687
688static const u32 nc[] = {
689 0x00000000, 0x00000000, 0x00000000, 0x00000000,
690 0x00000000, 0x00000000, 0x00000000, 0x00000000,
691 0x00000000, 0x00000000, 0x00000000, 0x00000000,
692 0x00000000, 0x00000000, 0x00000000, 0x00000000
693};
694
695enum {
696 DQ2030,
697 DQ2330,
698 CMD2710,
699 CMD3210,
700 CLK2030,
701 CTL3215,
702 CTL3220,
703 NC,
704};
705
706static const u8 dual_channel_slew_group_lookup[] = {
707 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
708 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
709 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
710 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
711 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
712
713 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
714 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
715 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
716 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
717 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
718
719 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
720 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
721 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
722 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
723 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
724
725 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
726 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
727 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
728 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
729 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, NC, NC,
730
731 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
732 NC, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
733 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
734 NC, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD2710
735};
736
737static const u8 single_channel_slew_group_lookup[] = {
738 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
739 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
740 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
741 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
742 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
743
744 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
745 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
746 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
747 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
748 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
749
750 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
751 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
752 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
753 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
754 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
755
756 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
757 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
758 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
759 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
760 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
761
762 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
763 DQ2330, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
764 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
765 DQ2330, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD3210
766};
767
Elyes Haouas49446092022-09-28 14:14:05 +0200768static const u32 *slew_group_lookup(bool dual_channel, int index)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000769{
770 const u8 *slew_group;
771 /* Dual Channel needs different tables. */
772 if (dual_channel)
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100773 slew_group = dual_channel_slew_group_lookup;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000774 else
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100775 slew_group = single_channel_slew_group_lookup;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000776
777 switch (slew_group[index]) {
778 case DQ2030: return dq2030;
779 case DQ2330: return dq2330;
780 case CMD2710: return cmd2710;
781 case CMD3210: return cmd3210;
782 case CLK2030: return clk2030;
783 case CTL3215: return ctl3215;
784 case CTL3220: return ctl3220;
785 case NC: return nc;
786 }
787
788 return nc;
789}
790
Julius Wernercd49cce2019-03-05 16:53:33 -0800791#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000792/* Strength multiplier tables */
793static const u8 dual_channel_strength_multiplier[] = {
794 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
795 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
796 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
797 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
798 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
799 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
800 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
801 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
802 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
803 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
804 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
805 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
806 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
807 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
808 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
809 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
810 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
811 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
812 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
813 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
814 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
815 0x00, 0x00, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
816 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
817 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x44, 0x22
818};
819
820static const u8 single_channel_strength_multiplier[] = {
821 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
822 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
823 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
824 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
825 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
826 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
827 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
828 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
829 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
830 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
831 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
832 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
833 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
834 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
835 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
836 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
837 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
838 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
839 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
840 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
841 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
842 0x33, 0x00, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
843 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
844 0x33, 0x00, 0x11, 0x00, 0x44, 0x44, 0x33, 0x11
845};
Julius Wernercd49cce2019-03-05 16:53:33 -0800846#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000847static const u8 dual_channel_strength_multiplier[] = {
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, 0x22,
851 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
852 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
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, 0x22,
856 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
857 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
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, 0x22,
861 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
862 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
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, 0x22,
866 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
867 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
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, 0x22,
871 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33
872};
873
874static const u8 single_channel_strength_multiplier[] = {
875 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
876 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
877 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
878 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
879 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
880 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
881 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
882 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
883 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
884 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
885 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
886 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
887 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
888 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
889 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
890 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
891 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
892 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
893 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
894 0x44, 0x33, 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, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
898 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00
899};
900#endif
901
Stefan Reinauer278534d2008-10-29 04:51:07 +0000902static void sdram_rcomp_buffer_strength_and_slew(struct sys_info *sysinfo)
903{
Arthur Heymans70a8e342017-03-09 11:30:23 +0100904 const u8 *strength_multiplier;
Elyes Haouas49446092022-09-28 14:14:05 +0200905 int idx;
906 bool dual_channel;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000907
908 /* Set Strength Multipliers */
909
910 /* Dual Channel needs different tables. */
911 if (sdram_capabilities_dual_channel()) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000912 printk(BIOS_DEBUG, "Programming Dual Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000913 strength_multiplier = dual_channel_strength_multiplier;
Elyes Haouas49446092022-09-28 14:14:05 +0200914 dual_channel = true;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100915 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[2];
Stefan Reinauer278534d2008-10-29 04:51:07 +0000916 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000917 printk(BIOS_DEBUG, "Programming Single Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000918 strength_multiplier = single_channel_strength_multiplier;
Elyes Haouas49446092022-09-28 14:14:05 +0200919 dual_channel = false;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000920 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[1];
921 }
922
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000923 printk(BIOS_DEBUG, "Table Index: %d\n", idx);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000924
Angel Pons1d4044a2021-03-27 19:11:51 +0100925 mchbar_write8(G1SC, strength_multiplier[idx * 8 + 0]);
926 mchbar_write8(G2SC, strength_multiplier[idx * 8 + 1]);
927 mchbar_write8(G3SC, strength_multiplier[idx * 8 + 2]);
928 mchbar_write8(G4SC, strength_multiplier[idx * 8 + 3]);
929 mchbar_write8(G5SC, strength_multiplier[idx * 8 + 4]);
930 mchbar_write8(G6SC, strength_multiplier[idx * 8 + 5]);
931 mchbar_write8(G7SC, strength_multiplier[idx * 8 + 6]);
932 mchbar_write8(G8SC, strength_multiplier[idx * 8 + 7]);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000933
934 /* Channel 0 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000935 sdram_write_slew_rates(G1SRPUT, slew_group_lookup(dual_channel, idx * 8 + 0));
936 sdram_write_slew_rates(G2SRPUT, slew_group_lookup(dual_channel, idx * 8 + 1));
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200937 if ((slew_group_lookup(dual_channel, idx * 8 + 2) != nc) &&
938 (sysinfo->package == SYSINFO_PACKAGE_STACKED))
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000939
Stefan Reinauer278534d2008-10-29 04:51:07 +0000940 sdram_write_slew_rates(G3SRPUT, ctl3220);
Arthur Heymans70a8e342017-03-09 11:30:23 +0100941 else
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000942 sdram_write_slew_rates(G3SRPUT, slew_group_lookup(dual_channel, idx * 8 + 2));
Arthur Heymans70a8e342017-03-09 11:30:23 +0100943
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000944 sdram_write_slew_rates(G4SRPUT, slew_group_lookup(dual_channel, idx * 8 + 3));
945 sdram_write_slew_rates(G5SRPUT, slew_group_lookup(dual_channel, idx * 8 + 4));
946 sdram_write_slew_rates(G6SRPUT, slew_group_lookup(dual_channel, idx * 8 + 5));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000947
948 /* Channel 1 */
949 if (sysinfo->dual_channel) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000950 sdram_write_slew_rates(G7SRPUT, slew_group_lookup(dual_channel, idx * 8 + 6));
951 sdram_write_slew_rates(G8SRPUT, slew_group_lookup(dual_channel, idx * 8 + 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000952 } else {
953 sdram_write_slew_rates(G7SRPUT, nc);
954 sdram_write_slew_rates(G8SRPUT, nc);
955 }
956}
957
958static void sdram_enable_rcomp(void)
959{
960 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000961 /* Enable Global Periodic RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000962 udelay(300);
Angel Pons1d4044a2021-03-27 19:11:51 +0100963 reg32 = mchbar_read32(GBRCOMPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000964 reg32 &= ~(1 << 23);
Angel Pons1d4044a2021-03-27 19:11:51 +0100965 mchbar_write32(GBRCOMPCTL, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000966}
967
968static void sdram_program_dll_timings(struct sys_info *sysinfo)
969{
Elyes HAOUAS44a30662017-02-23 13:14:44 +0100970 u32 channeldll = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000971 int i;
972
Elyes HAOUAS38424982016-08-21 12:01:04 +0200973 printk(BIOS_DEBUG, "Programming DLL Timings...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000974
Angel Pons1d4044a2021-03-27 19:11:51 +0100975 mchbar_clrbits16(DQSMT, 3 << 12 | 1 << 10 | 0xf << 0);
976 mchbar_setbits16(DQSMT, 1 << 13 | 0xc << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000977
978 /* We drive both channels with the same speed */
Julius Wernercd49cce2019-03-05 16:53:33 -0800979 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +0100980 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +0100981 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200982 channeldll = 0x26262626;
983 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100984 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200985 channeldll = 0x22222222;
986 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100987 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200988 channeldll = 0x11111111;
989 break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +0100990 }
Julius Wernercd49cce2019-03-05 16:53:33 -0800991 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +0100992 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +0100993 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200994 channeldll = 0x33333333;
995 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100996 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200997 channeldll = 0x24242424;
998 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100999 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001000 channeldll = 0x25252525;
1001 break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001002 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001003 }
1004
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001005 for (i = 0; i < 4; i++) {
Angel Pons1d4044a2021-03-27 19:11:51 +01001006 mchbar_write32(C0R0B00DQST + (i * 0x10) + 0, channeldll);
1007 mchbar_write32(C0R0B00DQST + (i * 0x10) + 4, channeldll);
1008 mchbar_write32(C1R0B00DQST + (i * 0x10) + 0, channeldll);
1009 mchbar_write32(C1R0B00DQST + (i * 0x10) + 4, channeldll);
Julius Wernercd49cce2019-03-05 16:53:33 -08001010 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Angel Pons1d4044a2021-03-27 19:11:51 +01001011 mchbar_write8(C0R0B00DQST + (i * 0x10) + 8, channeldll & 0xff);
1012 mchbar_write8(C1R0B00DQST + (i * 0x10) + 8, channeldll & 0xff);
Paul Menzelbce7e332017-02-22 18:46:27 +01001013 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001014 }
1015}
1016
1017static void sdram_force_rcomp(void)
1018{
1019 u32 reg32;
1020 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001021
Angel Pons1d4044a2021-03-27 19:11:51 +01001022 reg32 = mchbar_read32(ODTC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001023 reg32 |= (1 << 28);
Angel Pons1d4044a2021-03-27 19:11:51 +01001024 mchbar_write32(ODTC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001025
Angel Pons1d4044a2021-03-27 19:11:51 +01001026 reg32 = mchbar_read32(SMSRCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001027 reg32 |= (1 << 0);
Angel Pons1d4044a2021-03-27 19:11:51 +01001028 mchbar_write32(SMSRCTL, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001029
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001030 /* Start initial RCOMP */
Angel Pons1d4044a2021-03-27 19:11:51 +01001031 reg32 = mchbar_read32(GBRCOMPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001032 reg32 |= (1 << 8);
Angel Pons1d4044a2021-03-27 19:11:51 +01001033 mchbar_write32(GBRCOMPCTL, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001034
1035 reg8 = i945_silicon_revision();
Angel Pons1d4044a2021-03-27 19:11:51 +01001036 if ((reg8 == 0 && (mchbar_read32(DCC) & (3 << 0)) == 0) || (reg8 == 1)) {
1037 reg32 = mchbar_read32(GBRCOMPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001038 reg32 |= (3 << 5);
Angel Pons1d4044a2021-03-27 19:11:51 +01001039 mchbar_write32(GBRCOMPCTL, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001040 }
1041}
1042
1043static void sdram_initialize_system_memory_io(struct sys_info *sysinfo)
1044{
1045 u8 reg8;
1046 u32 reg32;
1047
Elyes HAOUAS38424982016-08-21 12:01:04 +02001048 printk(BIOS_DEBUG, "Initializing System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001049 /* Enable Data Half Clock Pushout */
Angel Pons1d4044a2021-03-27 19:11:51 +01001050 reg8 = mchbar_read8(C0HCTC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001051 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001052 reg8 |= (1 << 0);
Angel Pons1d4044a2021-03-27 19:11:51 +01001053 mchbar_write8(C0HCTC, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001054
Angel Pons1d4044a2021-03-27 19:11:51 +01001055 reg8 = mchbar_read8(C1HCTC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001056 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001057 reg8 |= (1 << 0);
Angel Pons1d4044a2021-03-27 19:11:51 +01001058 mchbar_write8(C1HCTC, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001059
Angel Pons1d4044a2021-03-27 19:11:51 +01001060 mchbar_clrbits16(WDLLBYPMODE, 1 << 9 | 1 << 6 | 1 << 4 | 1 << 3 | 1 << 1);
1061 mchbar_setbits16(WDLLBYPMODE, 1 << 8 | 1 << 7 | 1 << 5 | 1 << 2 | 1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001062
Angel Pons1d4044a2021-03-27 19:11:51 +01001063 mchbar_write8(C0WDLLCMC, 0);
1064 mchbar_write8(C1WDLLCMC, 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001065
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001066 /* Program RCOMP Settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001067 sdram_program_dram_width(sysinfo);
1068
1069 sdram_rcomp_buffer_strength_and_slew(sysinfo);
1070
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001071 /* Indicate that RCOMP programming is done */
Angel Pons1d4044a2021-03-27 19:11:51 +01001072 reg32 = mchbar_read32(GBRCOMPCTL);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001073 reg32 &= ~((1 << 29) | (1 << 26) | (3 << 21) | (3 << 2));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001074 reg32 |= (3 << 27) | (3 << 0);
Angel Pons1d4044a2021-03-27 19:11:51 +01001075 mchbar_write32(GBRCOMPCTL, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001076
Angel Pons1d4044a2021-03-27 19:11:51 +01001077 mchbar_setbits32(GBRCOMPCTL, 1 << 10);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001078
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001079 /* Program DLL Timings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001080 sdram_program_dll_timings(sysinfo);
1081
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001082 /* Force RCOMP cycle */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001083 sdram_force_rcomp();
1084}
1085
1086static void sdram_enable_system_memory_io(struct sys_info *sysinfo)
1087{
1088 u32 reg32;
1089
Elyes HAOUAS38424982016-08-21 12:01:04 +02001090 printk(BIOS_DEBUG, "Enabling System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001091
Angel Pons1d4044a2021-03-27 19:11:51 +01001092 reg32 = mchbar_read32(RCVENMT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001093 reg32 &= ~(0x3f << 6);
Angel Pons1d4044a2021-03-27 19:11:51 +01001094 mchbar_write32(RCVENMT, reg32); /* [11:6] = 0 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001095
1096 reg32 |= (1 << 11) | (1 << 9);
Angel Pons1d4044a2021-03-27 19:11:51 +01001097 mchbar_write32(RCVENMT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001098
Angel Pons1d4044a2021-03-27 19:11:51 +01001099 reg32 = mchbar_read32(DRTST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001100 reg32 |= (1 << 3) | (1 << 2);
Angel Pons1d4044a2021-03-27 19:11:51 +01001101 mchbar_write32(DRTST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001102
Angel Pons1d4044a2021-03-27 19:11:51 +01001103 reg32 = mchbar_read32(DRTST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001104 reg32 |= (1 << 6) | (1 << 4);
Angel Pons1d4044a2021-03-27 19:11:51 +01001105 mchbar_write32(DRTST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001106
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001107 asm volatile ("nop; nop;" ::: "memory");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001108
Angel Pons1d4044a2021-03-27 19:11:51 +01001109 reg32 = mchbar_read32(DRTST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001110
1111 /* Is channel 0 populated? */
1112 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001113 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001114 reg32 |= (1 << 7) | (1 << 5);
1115 else
1116 reg32 |= (1 << 31);
1117
1118 /* Is channel 1 populated? */
1119 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001120 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001121 reg32 |= (1 << 9) | (1 << 8);
1122 else
1123 reg32 |= (1 << 30);
1124
Angel Pons1d4044a2021-03-27 19:11:51 +01001125 mchbar_write32(DRTST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001126
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001127 /* Activate DRAM Channel IO Buffers */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001128 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001129 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) {
Angel Pons1d4044a2021-03-27 19:11:51 +01001130 reg32 = mchbar_read32(C0DRC1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001131 reg32 |= (1 << 8);
Angel Pons1d4044a2021-03-27 19:11:51 +01001132 mchbar_write32(C0DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001133 }
1134 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001135 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED) {
Angel Pons1d4044a2021-03-27 19:11:51 +01001136 reg32 = mchbar_read32(C1DRC1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001137 reg32 |= (1 << 8);
Angel Pons1d4044a2021-03-27 19:11:51 +01001138 mchbar_write32(C1DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001139 }
1140}
1141
Stefan Reinauer278534d2008-10-29 04:51:07 +00001142static int sdram_program_row_boundaries(struct sys_info *sysinfo)
1143{
1144 int i;
Arthur Heymans885c2892016-10-03 17:16:48 +02001145 int cum0, cum1, tolud, tom, pci_mmio_size;
1146 const struct device *dev;
1147 const struct northbridge_intel_i945_config *cfg = NULL;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001148
Paul Menzel84283bc2014-07-17 08:16:04 +02001149 printk(BIOS_DEBUG, "Setting RAM size...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001150
1151 cum0 = 0;
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001152 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001153 cum0 += sysinfo->banksize[i];
Angel Pons1d4044a2021-03-27 19:11:51 +01001154 mchbar_write8(C0DRB0 + i, cum0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001155 }
1156
1157 /* Assume we continue in Channel 1 where we stopped in Channel 0 */
1158 cum1 = cum0;
1159
1160 /* Exception: Interleaved starts from the beginning */
1161 if (sysinfo->interleaved)
1162 cum1 = 0;
1163
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001164 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001165 cum1 += sysinfo->banksize[i + 4];
Angel Pons1d4044a2021-03-27 19:11:51 +01001166 mchbar_write8(C1DRB0 + i, cum1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001167 }
1168
1169 /* Set TOLUD Top Of Low Usable DRAM */
1170 if (sysinfo->interleaved)
1171 tolud = (cum0 + cum1) << 1;
1172 else
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001173 tolud = (cum1 ? cum1 : cum0) << 1;
Stefan Reinauer779b3e32008-11-10 15:43:37 +00001174
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001175 /* The TOM register has a different format */
1176 tom = tolud >> 3;
1177
1178 /* Limit the value of TOLUD to leave some space for PCI memory. */
Kyösti Mälkkic70eed12018-05-22 02:18:00 +03001179 dev = pcidev_on_root(0, 0);
Arthur Heymans885c2892016-10-03 17:16:48 +02001180 if (dev)
1181 cfg = dev->chip_info;
1182
1183 /* Don't use pci mmio sizes smaller than 768M */
1184 if (!cfg || cfg->pci_mmio_size <= DEFAULT_PCI_MMIO_SIZE)
1185 pci_mmio_size = DEFAULT_PCI_MMIO_SIZE;
1186 else
1187 pci_mmio_size = cfg->pci_mmio_size;
1188
1189 tolud = MIN(((4096 - pci_mmio_size) / 128) << 3, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001190
Angel Pons3580d812020-06-11 14:13:33 +02001191 pci_write_config8(HOST_BRIDGE, TOLUD, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001192
Angel Pons1d4044a2021-03-27 19:11:51 +01001193 printk(BIOS_DEBUG, "C0DRB = 0x%08x\n", mchbar_read32(C0DRB0));
1194 printk(BIOS_DEBUG, "C1DRB = 0x%08x\n", mchbar_read32(C1DRB0));
Angel Pons3580d812020-06-11 14:13:33 +02001195 printk(BIOS_DEBUG, "TOLUD = 0x%04x\n", pci_read_config8(HOST_BRIDGE, TOLUD));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001196
Angel Pons3580d812020-06-11 14:13:33 +02001197 pci_write_config16(HOST_BRIDGE, TOM, tom);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001198
1199 return 0;
1200}
1201
Stefan Reinauer278534d2008-10-29 04:51:07 +00001202static int sdram_set_row_attributes(struct sys_info *sysinfo)
1203{
Arthur Heymans0ab49042017-02-06 22:40:14 +01001204 int i;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001205 u16 dra0 = 0, dra1 = 0, dra = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001206
Elyes HAOUAS38424982016-08-21 12:01:04 +02001207 printk(BIOS_DEBUG, "Setting row attributes...\n");
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001208 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001209 u8 columnsrows;
1210
Arthur Heymans70a8e342017-03-09 11:30:23 +01001211 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001212 continue;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001213
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001214 columnsrows = (sysinfo->rows[i] & 0x0f) | (sysinfo->cols[i] & 0xf) << 4;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001215
1216 switch (columnsrows) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001217 case 0x9d:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001218 dra = 2;
1219 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001220 case 0xad:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001221 dra = 3;
1222 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001223 case 0xbd:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001224 dra = 4;
1225 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001226 case 0xae:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001227 dra = 3;
1228 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001229 case 0xbe:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001230 dra = 4;
1231 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001232 default:
1233 die("Unsupported Rows/Columns. (DRA)");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001234 }
1235
1236 /* Double Sided DIMMs? */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001237 if (sysinfo->banksize[(2 * i) + 1] != 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001238 dra = (dra << 4) | dra;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001239
Stefan Reinauer278534d2008-10-29 04:51:07 +00001240 if (i < DIMM_SOCKETS)
Angel Pons30492572020-06-11 13:24:54 +02001241 dra0 |= (dra << (i * 8));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001242 else
Angel Pons30492572020-06-11 13:24:54 +02001243 dra1 |= (dra << ((i - DIMM_SOCKETS) * 8));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001244 }
1245
Angel Pons1d4044a2021-03-27 19:11:51 +01001246 mchbar_write16(C0DRA0, dra0);
1247 mchbar_write16(C1DRA0, dra1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001248
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001249 printk(BIOS_DEBUG, "C0DRA = 0x%04x\n", dra0);
1250 printk(BIOS_DEBUG, "C1DRA = 0x%04x\n", dra1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001251
1252 return 0;
1253}
1254
1255static void sdram_set_bank_architecture(struct sys_info *sysinfo)
1256{
1257 u32 off32;
1258 int i;
1259
Angel Pons1d4044a2021-03-27 19:11:51 +01001260 mchbar_clrbits16(C1BNKARC, 0xff);
1261 mchbar_clrbits16(C0BNKARC, 0xff);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001262
1263 off32 = C0BNKARC;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001264 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001265 /* Switch to second channel */
1266 if (i == DIMM_SOCKETS)
1267 off32 = C1BNKARC;
1268
1269 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
1270 continue;
1271
1272 if (sysinfo->banks[i] != 8)
1273 continue;
1274
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001275 printk(BIOS_SPEW, "DIMM%d has 8 banks.\n", i);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001276
1277 if (i & 1)
Angel Pons1d4044a2021-03-27 19:11:51 +01001278 mchbar_setbits16(off32, 5 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001279 else
Angel Pons1d4044a2021-03-27 19:11:51 +01001280 mchbar_setbits16(off32, 5 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001281 }
1282}
1283
Stefan Reinauer278534d2008-10-29 04:51:07 +00001284static void sdram_program_refresh_rate(struct sys_info *sysinfo)
1285{
1286 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001287
Arthur Heymans70a8e342017-03-09 11:30:23 +01001288 if (sysinfo->refresh == REFRESH_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001289 reg32 = (2 << 8); /* Refresh enabled at 7.8us */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001290 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001291 reg32 = (1 << 8); /* Refresh enabled at 15.6us */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001292
Angel Pons1d4044a2021-03-27 19:11:51 +01001293 mchbar_clrbits32(C0DRC0, 7 << 8);
1294 mchbar_setbits32(C0DRC0, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001295
Angel Pons1d4044a2021-03-27 19:11:51 +01001296 mchbar_clrbits32(C1DRC0, 7 << 8);
1297 mchbar_setbits32(C1DRC0, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001298}
1299
1300static void sdram_program_cke_tristate(struct sys_info *sysinfo)
1301{
1302 u32 reg32;
1303 int i;
1304
Angel Pons1d4044a2021-03-27 19:11:51 +01001305 reg32 = mchbar_read32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001306
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001307 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001308 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001309 reg32 |= (1 << (16 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001310 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001311
Stefan Reinauer278534d2008-10-29 04:51:07 +00001312 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001313
Stefan Reinauer278534d2008-10-29 04:51:07 +00001314 reg32 |= (1 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01001315 mchbar_write32(C0DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001316
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001317 /* Do we have to do this if we're in Single Channel Mode? */
Angel Pons1d4044a2021-03-27 19:11:51 +01001318 reg32 = mchbar_read32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001319
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001320 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001321 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001322 reg32 |= (1 << (12 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001323 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001324
Stefan Reinauer278534d2008-10-29 04:51:07 +00001325 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001326
Stefan Reinauer278534d2008-10-29 04:51:07 +00001327 reg32 |= (1 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01001328 mchbar_write32(C1DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001329}
1330
1331static void sdram_program_odt_tristate(struct sys_info *sysinfo)
1332{
1333 u32 reg32;
1334 int i;
1335
Angel Pons1d4044a2021-03-27 19:11:51 +01001336 reg32 = mchbar_read32(C0DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001337
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001338 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001339 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001340 reg32 |= (1 << (24 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001341 }
Angel Pons1d4044a2021-03-27 19:11:51 +01001342 mchbar_write32(C0DRC2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001343
Angel Pons1d4044a2021-03-27 19:11:51 +01001344 reg32 = mchbar_read32(C1DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001345
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001346 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001347 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001348 reg32 |= (1 << (20 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001349 }
Angel Pons1d4044a2021-03-27 19:11:51 +01001350 mchbar_write32(C1DRC2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001351}
1352
1353static void sdram_set_timing_and_control(struct sys_info *sysinfo)
1354{
Arthur Heymans25027232017-02-12 23:34:39 +01001355 u32 reg32, tRD_min;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001356 u32 tWTR;
1357 u32 temp_drt;
1358 int i, page_size;
1359
Edward O'Callaghan2f237c12014-05-25 06:24:39 +10001360 static const u8 cas_table[] = {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001361 2, 1, 0, 3
1362 };
1363
Angel Pons1d4044a2021-03-27 19:11:51 +01001364 reg32 = mchbar_read32(C0DRC0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001365 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001366 reg32 &= ~((1 << 13) | (1 << 12));
Angel Pons1d4044a2021-03-27 19:11:51 +01001367 mchbar_write32(C0DRC0, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001368
Angel Pons1d4044a2021-03-27 19:11:51 +01001369 reg32 = mchbar_read32(C1DRC0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001370 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001371 reg32 &= ~((1 << 13) | (1 << 12));
Angel Pons1d4044a2021-03-27 19:11:51 +01001372 mchbar_write32(C1DRC0, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001373
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001374 if (!sysinfo->dual_channel && sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) {
Angel Pons1d4044a2021-03-27 19:11:51 +01001375 reg32 = mchbar_read32(C0DRC0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001376 reg32 |= (1 << 15);
Angel Pons1d4044a2021-03-27 19:11:51 +01001377 mchbar_write32(C0DRC0, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001378 }
1379
1380 sdram_program_refresh_rate(sysinfo);
1381
1382 sdram_program_cke_tristate(sysinfo);
1383
1384 sdram_program_odt_tristate(sysinfo);
1385
1386 /* Calculate DRT0 */
1387
1388 temp_drt = 0;
1389
1390 /* B2B Write Precharge (same bank) = CL-1 + BL/2 + tWR */
1391 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + sysinfo->twr;
1392 temp_drt |= (reg32 << 28);
1393
1394 /* Write Auto Precharge (same bank) = CL-1 + BL/2 + tWR + tRP */
1395 reg32 += sysinfo->trp;
1396 temp_drt |= (reg32 << 4);
1397
Arthur Heymans70a8e342017-03-09 11:30:23 +01001398 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001399 tWTR = 3; /* 667MHz */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001400 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001401 tWTR = 2; /* 400 and 533 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001402
1403 /* B2B Write to Read Command Spacing */
1404 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + tWTR;
1405 temp_drt |= (reg32 << 24);
1406
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001407 /* CxDRT0 [23:22], [21:20], [19:18] [16] have fixed values */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001408 temp_drt |= ((1 << 22) | (3 << 20) | (1 << 18) | (0 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001409
Arthur Heymans25027232017-02-12 23:34:39 +01001410 /*
1411 * tRD is the delay the memory controller is waiting on the FSB,
1412 * in mclk domain.
1413 * This parameter is important for stability and performance.
1414 * Those values might not be optimal but seem stable.
1415 */
1416 tRD_min = sysinfo->cas;
Arthur Heymanse1897612016-10-15 23:29:18 +02001417 switch (sysinfo->fsb_frequency) {
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001418 case 533:
Arthur Heymanse1897612016-10-15 23:29:18 +02001419 break;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001420 case 667:
1421 tRD_min += 1;
Arthur Heymanse1897612016-10-15 23:29:18 +02001422 break;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001423 case 800:
1424 tRD_min += 2;
1425 break;
1426 case 1066:
1427 tRD_min += 3;
Arthur Heymanse1897612016-10-15 23:29:18 +02001428 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001429 }
Arthur Heymanse1897612016-10-15 23:29:18 +02001430
Arthur Heymans25027232017-02-12 23:34:39 +01001431 temp_drt |= (tRD_min << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001432
1433 /* Read Auto Precharge to Activate */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001434
Stefan Reinauer278534d2008-10-29 04:51:07 +00001435 temp_drt |= (8 << 0);
1436
Angel Pons1d4044a2021-03-27 19:11:51 +01001437 mchbar_write32(C0DRT0, temp_drt);
1438 mchbar_write32(C1DRT0, temp_drt);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001439
1440 /* Calculate DRT1 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001441
Angel Pons1d4044a2021-03-27 19:11:51 +01001442 temp_drt = mchbar_read32(C0DRT1) & 0x00020088;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001443
1444 /* DRAM RASB Precharge */
1445 temp_drt |= (sysinfo->trp - 2) << 0;
1446
1447 /* DRAM RASB to CASB Delay */
1448 temp_drt |= (sysinfo->trcd - 2) << 4;
1449
1450 /* CASB Latency */
1451 temp_drt |= (cas_table[sysinfo->cas - 3]) << 8;
1452
1453 /* Refresh Cycle Time */
1454 temp_drt |= (sysinfo->trfc) << 10;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001455
Stefan Reinauer278534d2008-10-29 04:51:07 +00001456 /* Pre-All to Activate Delay */
1457 temp_drt |= (0 << 16);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001458
Stefan Reinauer278534d2008-10-29 04:51:07 +00001459 /* Precharge to Precharge Delay stays at 1 clock */
1460 temp_drt |= (0 << 18);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001461
Stefan Reinauer278534d2008-10-29 04:51:07 +00001462 /* Activate to Precharge Delay */
1463 temp_drt |= (sysinfo->tras << 19);
1464
1465 /* Read to Precharge (tRTP) */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001466 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001467 temp_drt |= (1 << 28);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001468 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001469 temp_drt |= (0 << 28);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001470
1471 /* Determine page size */
1472 reg32 = 0;
1473 page_size = 1; /* Default: 1k pagesize */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001474 for (i = 0; i < 2*DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001475 if (sysinfo->dimm[i] == SYSINFO_DIMM_X16DS ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001476 sysinfo->dimm[i] == SYSINFO_DIMM_X16SS)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001477 page_size = 2; /* 2k pagesize */
1478 }
1479
Arthur Heymans70a8e342017-03-09 11:30:23 +01001480 if (sysinfo->memory_frequency == 533 && page_size == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001481 reg32 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001482 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001483 reg32 = page_size;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001484
Stefan Reinauer278534d2008-10-29 04:51:07 +00001485 temp_drt |= (reg32 << 30);
1486
Angel Pons1d4044a2021-03-27 19:11:51 +01001487 mchbar_write32(C0DRT1, temp_drt);
1488 mchbar_write32(C1DRT1, temp_drt);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001489
1490 /* Program DRT2 */
Angel Pons1d4044a2021-03-27 19:11:51 +01001491 reg32 = mchbar_read32(C0DRT2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001492 reg32 &= ~(1 << 8);
Angel Pons1d4044a2021-03-27 19:11:51 +01001493 mchbar_write32(C0DRT2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001494
Angel Pons1d4044a2021-03-27 19:11:51 +01001495 reg32 = mchbar_read32(C1DRT2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001496 reg32 &= ~(1 << 8);
Angel Pons1d4044a2021-03-27 19:11:51 +01001497 mchbar_write32(C1DRT2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001498
1499 /* Calculate DRT3 */
Angel Pons1d4044a2021-03-27 19:11:51 +01001500 temp_drt = mchbar_read32(C0DRT3) & ~0x07ffffff;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001501
1502 /* Get old tRFC value */
Angel Pons1d4044a2021-03-27 19:11:51 +01001503 reg32 = mchbar_read32(C0DRT1) >> 10;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001504 reg32 &= 0x3f;
1505
1506 /* 788nS - tRFC */
1507 switch (sysinfo->memory_frequency) {
1508 case 400: /* 5nS */
1509 reg32 = ((78800 / 500) - reg32) & 0x1ff;
1510 reg32 |= (0x8c << 16) | (0x0c << 10); /* 1 us */
1511 break;
1512 case 533: /* 3.75nS */
1513 reg32 = ((78800 / 375) - reg32) & 0x1ff;
1514 reg32 |= (0xba << 16) | (0x10 << 10); /* 1 us */
1515 break;
1516 case 667: /* 3nS */
1517 reg32 = ((78800 / 300) - reg32) & 0x1ff;
1518 reg32 |= (0xe9 << 16) | (0x14 << 10); /* 1 us */
1519 break;
1520 }
1521
1522 temp_drt |= reg32;
1523
Angel Pons1d4044a2021-03-27 19:11:51 +01001524 mchbar_write32(C0DRT3, temp_drt);
1525 mchbar_write32(C1DRT3, temp_drt);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001526}
1527
1528static void sdram_set_channel_mode(struct sys_info *sysinfo)
1529{
1530 u32 reg32;
1531
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001532 printk(BIOS_DEBUG, "Setting mode of operation for memory channels...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001533
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001534 if (sdram_capabilities_interleave() &&
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001535 ((sysinfo->banksize[0] + sysinfo->banksize[1] +
1536 sysinfo->banksize[2] + sysinfo->banksize[3]) ==
1537 (sysinfo->banksize[4] + sysinfo->banksize[5] +
1538 sysinfo->banksize[6] + sysinfo->banksize[7]))) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001539 /* Both channels equipped with DIMMs of the same size */
Elyes Haouas49446092022-09-28 14:14:05 +02001540 sysinfo->interleaved = true;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001541 } else {
Elyes Haouas49446092022-09-28 14:14:05 +02001542 sysinfo->interleaved = false;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001543 }
1544
Angel Pons1d4044a2021-03-27 19:11:51 +01001545 reg32 = mchbar_read32(DCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001546 reg32 &= ~(7 << 0);
1547
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001548 if (sysinfo->interleaved) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001549 /* Dual Channel Interleaved */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001550 printk(BIOS_DEBUG, "Dual Channel Interleaved.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001551 reg32 |= (1 << 1);
1552 } else if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001553 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001554 /* Channel 1 only */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001555 printk(BIOS_DEBUG, "Single Channel 1 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001556 reg32 |= (1 << 2);
Elyes HAOUAS75da1fb2017-02-16 18:59:13 +01001557 } else if (sdram_capabilities_dual_channel() &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001558 (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1559 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) {
Martin Roth128c1042016-11-18 09:29:03 -07001560 /* Dual Channel Asymmetric */
1561 printk(BIOS_DEBUG, "Dual Channel Asymmetric.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001562 reg32 |= (1 << 0);
1563 } else {
1564 /* All bits 0 means Single Channel 0 operation */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001565 printk(BIOS_DEBUG, "Single Channel 0 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001566 }
1567
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001568 /* Now disable channel XORing */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001569 reg32 |= (1 << 10);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001570
Angel Pons1d4044a2021-03-27 19:11:51 +01001571 mchbar_write32(DCC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001572
Angel Pons1d4044a2021-03-27 19:11:51 +01001573 PRINTK_DEBUG("DCC = 0x%08x\n", mchbar_read32(DCC));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001574}
1575
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001576static void sdram_program_pll_settings(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001577{
Angel Pons1d4044a2021-03-27 19:11:51 +01001578 mchbar_write32(PLLMON, 0x80800000);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001579
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001580 sysinfo->fsb_frequency = fsbclk();
Peter Stuge76d91432010-10-01 10:02:33 +00001581 if (sysinfo->fsb_frequency == 0xffff)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001582 die("Unsupported FSB speed");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001583
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001584 /* Program CPCTL according to FSB speed */
1585 /* Only write the lower byte */
1586 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001587 case 400:
Angel Pons1d4044a2021-03-27 19:11:51 +01001588 mchbar_write8(CPCTL, 0x90);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001589 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001590 case 533:
Angel Pons1d4044a2021-03-27 19:11:51 +01001591 mchbar_write8(CPCTL, 0x95);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001592 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001593 case 667:
Angel Pons1d4044a2021-03-27 19:11:51 +01001594 mchbar_write8(CPCTL, 0x8d);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001595 break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001596 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001597
Angel Pons1d4044a2021-03-27 19:11:51 +01001598 mchbar_clrbits16(CPCTL, 1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001599
Angel Pons1d4044a2021-03-27 19:11:51 +01001600 mchbar_read16(CPCTL); /* Read back register to activate settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001601}
1602
1603static void sdram_program_graphics_frequency(struct sys_info *sysinfo)
1604{
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001605 u8 reg8;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001606 u8 freq, second_vco, voltage;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001607
1608#define CRCLK_166MHz 0x00
1609#define CRCLK_200MHz 0x01
1610#define CRCLK_250MHz 0x03
1611#define CRCLK_400MHz 0x05
1612
1613#define CDCLK_200MHz 0x00
1614#define CDCLK_320MHz 0x40
1615
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001616#define VOLTAGE_1_05 0x00
1617#define VOLTAGE_1_50 0x01
1618
Paul Menzeldaf9e502014-07-15 23:49:16 +02001619 printk(BIOS_DEBUG, "Setting Graphics Frequency...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001620
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001621 printk(BIOS_DEBUG, "FSB: %d MHz ", sysinfo->fsb_frequency);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001622
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001623 voltage = VOLTAGE_1_05;
Angel Pons1d4044a2021-03-27 19:11:51 +01001624 if (mchbar_read32(DFT_STRAP1) & (1 << 20))
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001625 voltage = VOLTAGE_1_50;
Angel Pons30492572020-06-11 13:24:54 +02001626 printk(BIOS_DEBUG, "Voltage: %s ", (voltage == VOLTAGE_1_05) ? "1.05V" : "1.5V");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001627
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001628 /* Gate graphics hardware for frequency change */
Angel Pons30492572020-06-11 13:24:54 +02001629 reg8 = (1 << 3) | (1 << 1); /* disable crclk, gate cdclk */
Angel Pons3580d812020-06-11 14:13:33 +02001630 pci_write_config8(IGD_DEV, GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001631
1632 /* Get graphics frequency capabilities */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001633 reg8 = sdram_capabilities_core_frequencies();
1634
Stefan Reinauer278534d2008-10-29 04:51:07 +00001635 freq = CRCLK_250MHz;
1636 switch (reg8) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001637 case GFX_FREQUENCY_CAP_ALL:
1638 if (voltage == VOLTAGE_1_05)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001639 freq = CRCLK_250MHz;
1640 else
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001641 freq = CRCLK_400MHz; /* 1.5V requires 400MHz */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001642 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001643 case GFX_FREQUENCY_CAP_250MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001644 freq = CRCLK_250MHz;
1645 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001646 case GFX_FREQUENCY_CAP_200MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001647 freq = CRCLK_200MHz;
1648 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001649 case GFX_FREQUENCY_CAP_166MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001650 freq = CRCLK_166MHz;
1651 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001652 }
1653
1654 if (freq != CRCLK_400MHz) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001655 /* What chipset are we? Force 166MHz for GMS */
Angel Pons3580d812020-06-11 14:13:33 +02001656 reg8 = (pci_read_config8(HOST_BRIDGE, 0xe7) & 0x70) >> 4;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001657 if (reg8 == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001658 freq = CRCLK_166MHz;
1659 }
1660
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001661 printk(BIOS_DEBUG, "Render: ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001662 switch (freq) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001663 case CRCLK_166MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001664 printk(BIOS_DEBUG, "166MHz");
1665 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001666 case CRCLK_200MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001667 printk(BIOS_DEBUG, "200MHz");
1668 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001669 case CRCLK_250MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001670 printk(BIOS_DEBUG, "250MHz");
1671 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001672 case CRCLK_400MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001673 printk(BIOS_DEBUG, "400MHz");
1674 break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001675 }
1676
Arthur Heymans70a8e342017-03-09 11:30:23 +01001677 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001678 sysinfo->mvco4x = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001679 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001680 sysinfo->mvco4x = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001681
Stefan Reinauer278534d2008-10-29 04:51:07 +00001682 second_vco = 0;
1683
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001684 if (voltage == VOLTAGE_1_50) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001685 second_vco = 1;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001686 } else if ((i945_silicon_revision() > 0) && (freq == CRCLK_250MHz)) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001687 u16 mem = sysinfo->memory_frequency;
1688 u16 fsb = sysinfo->fsb_frequency;
1689
Arthur Heymans70a8e342017-03-09 11:30:23 +01001690 if ((fsb == 667 && mem == 533) ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001691 (fsb == 533 && mem == 533) ||
1692 (fsb == 533 && mem == 400)) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001693 second_vco = 1;
1694 }
1695
1696 if (fsb == 667 && mem == 533)
1697 sysinfo->mvco4x = 1;
1698 }
1699
Arthur Heymans70a8e342017-03-09 11:30:23 +01001700 if (second_vco)
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001701 sysinfo->clkcfg_bit7 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001702 else
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001703 sysinfo->clkcfg_bit7 = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001704
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001705 /* Graphics Core Render Clock */
Angel Pons3580d812020-06-11 14:13:33 +02001706 pci_update_config16(IGD_DEV, GCFC, ~((7 << 0) | (1 << 13)), freq);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001707
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001708 /* Graphics Core Display Clock */
Angel Pons3580d812020-06-11 14:13:33 +02001709 reg8 = pci_read_config8(IGD_DEV, GCFC);
Angel Ponse3c68d22020-06-08 12:09:03 +02001710 reg8 &= ~((1 << 7) | (7 << 4));
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001711
1712 if (voltage == VOLTAGE_1_05) {
1713 reg8 |= CDCLK_200MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001714 printk(BIOS_DEBUG, " Display: 200MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001715 } else {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001716 reg8 |= CDCLK_320MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001717 printk(BIOS_DEBUG, " Display: 320MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001718 }
Angel Pons3580d812020-06-11 14:13:33 +02001719 pci_write_config8(IGD_DEV, GCFC, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001720
Angel Pons3580d812020-06-11 14:13:33 +02001721 reg8 = pci_read_config8(IGD_DEV, GCFC + 1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001722
Angel Ponse3c68d22020-06-08 12:09:03 +02001723 reg8 |= (1 << 3) | (1 << 1);
Angel Pons3580d812020-06-11 14:13:33 +02001724 pci_write_config8(IGD_DEV, GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001725
1726 reg8 |= 0x0f;
Angel Pons3580d812020-06-11 14:13:33 +02001727 pci_write_config8(IGD_DEV, GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001728
1729 /* Ungate core render and display clocks */
1730 reg8 &= 0xf0;
Angel Pons3580d812020-06-11 14:13:33 +02001731 pci_write_config8(IGD_DEV, GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001732}
1733
1734static void sdram_program_memory_frequency(struct sys_info *sysinfo)
1735{
1736 u32 clkcfg;
Julius Wernercd49cce2019-03-05 16:53:33 -08001737 u8 offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001738
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001739 printk(BIOS_DEBUG, "Setting Memory Frequency... ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001740
Angel Pons1d4044a2021-03-27 19:11:51 +01001741 clkcfg = mchbar_read32(CLKCFG);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001742
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001743 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001744
Arthur Heymans70a8e342017-03-09 11:30:23 +01001745 clkcfg &= ~((1 << 12) | (1 << 7) | (7 << 4));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001746
1747 if (sysinfo->mvco4x) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001748 printk(BIOS_DEBUG, "MVCO 4x, ");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001749 clkcfg &= ~(1 << 12);
1750 }
1751
1752 if (sysinfo->clkcfg_bit7) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001753 printk(BIOS_DEBUG, "second VCO, ");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001754 clkcfg |= (1 << 7);
1755 }
1756
1757 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001758 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001759 clkcfg |= ((1 + offset) << 4);
1760 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001761 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001762 clkcfg |= ((2 + offset) << 4);
1763 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001764 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001765 clkcfg |= ((3 + offset) << 4);
1766 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001767 default:
1768 die("Target Memory Frequency Error");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001769 }
1770
Angel Pons1d4044a2021-03-27 19:11:51 +01001771 if (mchbar_read32(CLKCFG) == clkcfg) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001772 printk(BIOS_DEBUG, "ok (unchanged)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001773 return;
1774 }
1775
Angel Pons1d4044a2021-03-27 19:11:51 +01001776 mchbar_write32(CLKCFG, clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001777
Petr Cveke75bb012022-06-16 17:13:22 +02001778 /*
1779 * Make sure the following code is in the cache before we execute it.
1780 * TODO: Experiments (i945GM) without any cache_code/delay_update
1781 * _seem_ to work even when XIP is disabled. Also on Pentium 4
1782 * the code is not cached at all by default.
1783 */
1784 asm volatile (
1785 " jmp cache_code\n"
1786 "vco_update:\n"
1787 : /* No outputs */
1788 : /* No inputs */
1789 : "memory"
1790 );
1791
Angel Ponse3c68d22020-06-08 12:09:03 +02001792 pci_and_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, (u8)~(1 << 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001793
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 clkcfg |= (1 << 10);
Angel Pons1d4044a2021-03-27 19:11:51 +01001797 mchbar_write32(CLKCFG, clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001798
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001799 asm volatile (
Stefan Reinauer278534d2008-10-29 04:51:07 +00001800 " movl $0x100, %%ecx\n"
1801 "delay_update:\n"
1802 " nop\n"
1803 " nop\n"
1804 " nop\n"
1805 " nop\n"
1806 " loop delay_update\n"
1807 : /* No outputs */
1808 : /* No inputs */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001809 : "%ecx", "memory"
Stefan Reinauer278534d2008-10-29 04:51:07 +00001810 );
1811
Stefan Reinauer278534d2008-10-29 04:51:07 +00001812 clkcfg &= ~(1 << 10);
Angel Pons1d4044a2021-03-27 19:11:51 +01001813 mchbar_write32(CLKCFG, clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001814
Petr Cveke75bb012022-06-16 17:13:22 +02001815 asm volatile (
1816 " jmp out\n"
1817 "cache_code:\n"
1818 " jmp vco_update\n"
1819 "out:\n"
1820 : /* No outputs */
1821 : /* No inputs */
1822 : "memory"
1823 );
Stefan Reinauer278534d2008-10-29 04:51:07 +00001824
Angel Pons1d4044a2021-03-27 19:11:51 +01001825 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", mchbar_read32(CLKCFG));
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001826 printk(BIOS_DEBUG, "ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001827}
1828
1829static void sdram_program_clock_crossing(void)
1830{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001831 int idx = 0;
1832
1833 /**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001834 * We add the indices according to our clocks from CLKCFG.
Stefan Reinauer278534d2008-10-29 04:51:07 +00001835 */
Julius Wernercd49cce2019-03-05 16:53:33 -08001836#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001837 static const u32 data_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001838 0x00100401, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001839 0xffffffff, 0xffffffff, /* nonexistent */
1840 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001841
Stefan Reinauer278534d2008-10-29 04:51:07 +00001842 0x08040120, 0x00000000, /* DDR400 FSB533 */
1843 0x00100401, 0x00000000, /* DDR533 FSB533 */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001844 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001845
1846 0x04020120, 0x00000010, /* DDR400 FSB667 */
1847 0x10040280, 0x00000040, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001848 0x00100401, 0x00000000, /* DDR667 FSB667 */
1849
Martin Roth2ed0aa22016-01-05 20:58:58 -07001850 0xffffffff, 0xffffffff, /* nonexistent */
1851 0xffffffff, 0xffffffff, /* nonexistent */
1852 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001853
Martin Roth2ed0aa22016-01-05 20:58:58 -07001854 0xffffffff, 0xffffffff, /* nonexistent */
1855 0xffffffff, 0xffffffff, /* nonexistent */
1856 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001857 };
1858
1859 static const u32 command_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001860 0x04020208, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001861 0xffffffff, 0xffffffff, /* nonexistent */
1862 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001863
Stefan Reinauer278534d2008-10-29 04:51:07 +00001864 0x00060108, 0x00000000, /* DDR400 FSB533 */
1865 0x04020108, 0x00000000, /* DDR533 FSB533 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001866 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001867
1868 0x00040318, 0x00000000, /* DDR400 FSB667 */
1869 0x04020118, 0x00000000, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001870 0x02010804, 0x00000000, /* DDR667 FSB667 */
1871
Martin Roth2ed0aa22016-01-05 20:58:58 -07001872 0xffffffff, 0xffffffff, /* nonexistent */
1873 0xffffffff, 0xffffffff, /* nonexistent */
1874 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001875
Martin Roth2ed0aa22016-01-05 20:58:58 -07001876 0xffffffff, 0xffffffff, /* nonexistent */
1877 0xffffffff, 0xffffffff, /* nonexistent */
1878 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001879 };
1880
Julius Wernercd49cce2019-03-05 16:53:33 -08001881#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001882 /* i945 G/P */
1883 static const u32 data_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001884 0xffffffff, 0xffffffff, /* nonexistent */
1885 0xffffffff, 0xffffffff, /* nonexistent */
1886 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001887
1888 0x10080201, 0x00000000, /* DDR400 FSB533 */
1889 0x00100401, 0x00000000, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001890 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001891
Martin Roth2ed0aa22016-01-05 20:58:58 -07001892 0xffffffff, 0xffffffff, /* nonexistent */
1893 0xffffffff, 0xffffffff, /* nonexistent */
1894 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001895
1896 0x04020108, 0x00000000, /* DDR400 FSB800 */
1897 0x00020108, 0x00000000, /* DDR533 FSB800 */
1898 0x00080201, 0x00000000, /* DDR667 FSB800 */
1899
1900 0x00010402, 0x00000000, /* DDR400 FSB1066 */
1901 0x04020108, 0x00000000, /* DDR533 FSB1066 */
1902 0x08040110, 0x00000000, /* DDR667 FSB1066 */
1903 };
1904
1905 static const u32 command_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001906 0xffffffff, 0xffffffff, /* nonexistent */
1907 0xffffffff, 0xffffffff, /* nonexistent */
1908 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001909
1910 0x00010800, 0x00000402, /* DDR400 FSB533 */
1911 0x01000400, 0x00000200, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001912 0x00020904, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001913
Martin Roth2ed0aa22016-01-05 20:58:58 -07001914 0xffffffff, 0xffffffff, /* nonexistent */
1915 0xffffffff, 0xffffffff, /* nonexistent */
1916 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001917
1918 0x02010804, 0x00000000, /* DDR400 FSB800 */
1919 0x00010402, 0x00000000, /* DDR533 FSB800 */
Arthur Heymans8b6df622016-10-16 10:58:01 +02001920 0x04020130, 0x00000008, /* DDR667 FSB800 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001921
1922 0x00020904, 0x00000000, /* DDR400 FSB1066 */
1923 0x02010804, 0x00000000, /* DDR533 FSB1066 */
1924 0x180601c0, 0x00000020, /* DDR667 FSB1066 */
1925 };
1926#endif
1927
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001928 printk(BIOS_DEBUG, "Programming Clock Crossing...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001929
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001930 printk(BIOS_DEBUG, "MEM=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001931 switch (memclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001932 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001933 printk(BIOS_DEBUG, "400");
1934 idx += 0;
1935 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001936 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001937 printk(BIOS_DEBUG, "533");
1938 idx += 2;
1939 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001940 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001941 printk(BIOS_DEBUG, "667");
1942 idx += 4;
1943 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001944 default:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001945 printk(BIOS_DEBUG, "RSVD %x", memclk());
1946 return;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001947 }
1948
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001949 printk(BIOS_DEBUG, " FSB=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001950 switch (fsbclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001951 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001952 printk(BIOS_DEBUG, "400");
1953 idx += 0;
1954 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001955 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001956 printk(BIOS_DEBUG, "533");
1957 idx += 6;
1958 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001959 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001960 printk(BIOS_DEBUG, "667");
1961 idx += 12;
1962 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001963 case 800:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001964 printk(BIOS_DEBUG, "800");
1965 idx += 18;
1966 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001967 case 1066:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001968 printk(BIOS_DEBUG, "1066");
1969 idx += 24;
1970 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001971 default:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001972 printk(BIOS_DEBUG, "RSVD %x\n", fsbclk());
1973 return;
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001974 }
1975
Arthur Heymans70a8e342017-03-09 11:30:23 +01001976 if (command_clock_crossing[idx] == 0xffffffff)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001977 printk(BIOS_DEBUG, "Invalid MEM/FSB combination!\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001978
Angel Pons1d4044a2021-03-27 19:11:51 +01001979 mchbar_write32(CCCFT + 0, command_clock_crossing[idx]);
1980 mchbar_write32(CCCFT + 4, command_clock_crossing[idx + 1]);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001981
Angel Pons1d4044a2021-03-27 19:11:51 +01001982 mchbar_write32(C0DCCFT + 0, data_clock_crossing[idx]);
1983 mchbar_write32(C0DCCFT + 4, data_clock_crossing[idx + 1]);
1984 mchbar_write32(C1DCCFT + 0, data_clock_crossing[idx]);
1985 mchbar_write32(C1DCCFT + 4, data_clock_crossing[idx + 1]);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001986
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001987 printk(BIOS_DEBUG, "... ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001988}
1989
1990static void sdram_disable_fast_dispatch(void)
1991{
1992 u32 reg32;
1993
Angel Pons1d4044a2021-03-27 19:11:51 +01001994 reg32 = mchbar_read32(FSBPMC3);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001995 reg32 |= (1 << 1);
Angel Pons1d4044a2021-03-27 19:11:51 +01001996 mchbar_write32(FSBPMC3, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001997
Angel Pons1d4044a2021-03-27 19:11:51 +01001998 reg32 = mchbar_read32(SBTEST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001999 reg32 |= (3 << 1);
Angel Pons1d4044a2021-03-27 19:11:51 +01002000 mchbar_write32(SBTEST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002001}
2002
2003static void sdram_pre_jedec_initialization(void)
2004{
2005 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002006
Angel Pons1d4044a2021-03-27 19:11:51 +01002007 reg32 = mchbar_read32(WCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002008 reg32 &= 0x113ff3ff;
2009 reg32 |= (4 << 29) | (3 << 25) | (1 << 10);
Angel Pons1d4044a2021-03-27 19:11:51 +01002010 mchbar_write32(WCC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002011
Angel Pons1d4044a2021-03-27 19:11:51 +01002012 mchbar_setbits32(SMVREFC, 1 << 6);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002013
Angel Pons1d4044a2021-03-27 19:11:51 +01002014 mchbar_clrbits32(MMARB0, 3 << 17);
2015 mchbar_setbits32(MMARB0, 1 << 21 | 1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002016
Angel Pons1d4044a2021-03-27 19:11:51 +01002017 mchbar_clrbits32(MMARB1, 7 << 8);
2018 mchbar_setbits32(MMARB1, 3 << 8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002019
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002020 /* Adaptive Idle Timer Control */
Angel Pons1d4044a2021-03-27 19:11:51 +01002021 mchbar_write32(C0AIT + 0, 0x000006c4);
2022 mchbar_write32(C0AIT + 4, 0x871a066d);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002023
Angel Pons1d4044a2021-03-27 19:11:51 +01002024 mchbar_write32(C1AIT + 0, 0x000006c4);
2025 mchbar_write32(C1AIT + 4, 0x871a066d);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002026}
2027
2028#define EA_DUALCHANNEL_XOR_BANK_RANK_MODE (0xd4 << 24)
2029#define EA_DUALCHANNEL_XOR_BANK_MODE (0xf4 << 24)
2030#define EA_DUALCHANNEL_BANK_RANK_MODE (0xc2 << 24)
2031#define EA_DUALCHANNEL_BANK_MODE (0xe2 << 24)
2032#define EA_SINGLECHANNEL_XOR_BANK_RANK_MODE (0x91 << 24)
2033#define EA_SINGLECHANNEL_XOR_BANK_MODE (0xb1 << 24)
2034#define EA_SINGLECHANNEL_BANK_RANK_MODE (0x80 << 24)
2035#define EA_SINGLECHANNEL_BANK_MODE (0xa0 << 24)
2036
2037static void sdram_enhanced_addressing_mode(struct sys_info *sysinfo)
2038{
2039 u32 chan0 = 0, chan1 = 0;
Paul Menzeld789b6582020-03-14 11:50:34 +01002040 bool chan0_dualsided, chan1_dualsided, chan0_populated, chan1_populated;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002041
Paul Menzel842dd332020-03-14 10:37:40 +01002042 chan0_populated = (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002043 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED);
Elyes HAOUAS308aeff2017-02-24 12:53:07 +01002044 chan1_populated = (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002045 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002046 chan0_dualsided = (sysinfo->banksize[1] || sysinfo->banksize[3]);
2047 chan1_dualsided = (sysinfo->banksize[5] || sysinfo->banksize[7]);
2048
2049 if (sdram_capabilities_enhanced_addressing_xor()) {
2050 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002051 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002052 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002053 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002054 chan0 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002055 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002056 chan0 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002057 }
2058 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002059 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002060 chan1 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002061 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002062 chan1 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002063 }
2064 } else {
2065 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002066 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002067 chan0 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002068 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002069 chan0 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002070
Arthur Heymans70a8e342017-03-09 11:30:23 +01002071 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002072 chan1 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002073 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002074 chan1 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002075 }
2076 } else {
2077 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002078 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002079 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002080 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002081 chan0 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002082 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002083 chan0 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002084 }
2085 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002086 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002087 chan1 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002088 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002089 chan1 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002090 }
2091 } else {
2092 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002093 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002094 chan0 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002095 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002096 chan0 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002097
Arthur Heymans70a8e342017-03-09 11:30:23 +01002098 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002099 chan1 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002100 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002101 chan1 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002102 }
2103 }
2104
Angel Pons1d4044a2021-03-27 19:11:51 +01002105 mchbar_clrbits32(C0DRC1, 0xff << 24);
2106 mchbar_setbits32(C0DRC1, chan0);
2107 mchbar_clrbits32(C1DRC1, 0xff << 24);
2108 mchbar_setbits32(C1DRC1, chan1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002109}
2110
2111static void sdram_post_jedec_initialization(struct sys_info *sysinfo)
2112{
2113 u32 reg32;
2114
2115 /* Enable Channel XORing for Dual Channel Interleave */
2116 if (sysinfo->interleaved) {
Angel Pons1d4044a2021-03-27 19:11:51 +01002117 reg32 = mchbar_read32(DCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002118 reg32 &= ~(1 << 10);
Stefan Reinauer30140a52009-03-11 16:20:39 +00002119 reg32 |= (1 << 9);
Angel Pons1d4044a2021-03-27 19:11:51 +01002120 mchbar_write32(DCC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002121 }
2122
2123 /* DRAM mode optimizations */
2124 sdram_enhanced_addressing_mode(sysinfo);
2125
Angel Pons1d4044a2021-03-27 19:11:51 +01002126 reg32 = mchbar_read32(FSBPMC3);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002127 reg32 &= ~(1 << 1);
Angel Pons1d4044a2021-03-27 19:11:51 +01002128 mchbar_write32(FSBPMC3, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002129
Angel Pons1d4044a2021-03-27 19:11:51 +01002130 reg32 = mchbar_read32(SBTEST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002131 reg32 &= ~(1 << 2);
Angel Pons1d4044a2021-03-27 19:11:51 +01002132 mchbar_write32(SBTEST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002133
Angel Pons1d4044a2021-03-27 19:11:51 +01002134 reg32 = mchbar_read32(SBOCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002135 reg32 &= 0xffbdb6ff;
2136 reg32 |= (0xbdb6 << 8) | (1 << 0);
Angel Pons1d4044a2021-03-27 19:11:51 +01002137 mchbar_write32(SBOCC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002138}
2139
2140static void sdram_power_management(struct sys_info *sysinfo)
2141{
Stefan Reinauer278534d2008-10-29 04:51:07 +00002142 u16 reg16;
2143 u32 reg32;
Elyes HAOUAS187bec72021-12-12 07:00:50 +01002144 bool integrated_graphics = true;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002145 int i;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002146
Elyes HAOUAS8f20b122021-02-14 13:22:10 +01002147 if (!(pci_read_config8(HOST_BRIDGE, DEVEN) & (DEVEN_D2F0 | DEVEN_D2F1)))
2148 integrated_graphics = false;
2149
Angel Pons1d4044a2021-03-27 19:11:51 +01002150 reg32 = mchbar_read32(C0DRT2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002151 reg32 &= 0xffffff00;
2152 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002153 reg32 |= (1 << 5) | (1 << 4);
Angel Pons1d4044a2021-03-27 19:11:51 +01002154 mchbar_write32(C0DRT2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002155
Angel Pons1d4044a2021-03-27 19:11:51 +01002156 reg32 = mchbar_read32(C1DRT2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002157 reg32 &= 0xffffff00;
2158 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002159 reg32 |= (1 << 5) | (1 << 4);
Angel Pons1d4044a2021-03-27 19:11:51 +01002160 mchbar_write32(C1DRT2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002161
Angel Pons1d4044a2021-03-27 19:11:51 +01002162 reg32 = mchbar_read32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002163
2164 reg32 |= (1 << 12) | (1 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01002165 mchbar_write32(C0DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002166
Angel Pons1d4044a2021-03-27 19:11:51 +01002167 reg32 = mchbar_read32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002168
2169 reg32 |= (1 << 12) | (1 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01002170 mchbar_write32(C1DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002171
Julius Wernercd49cce2019-03-05 16:53:33 -08002172 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002173 if (i945_silicon_revision() > 1) {
2174 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2175 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002176
Angel Pons1d4044a2021-03-27 19:11:51 +01002177 mchbar_write16(UPMC1, 0x1010 | peg_bits);
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002178 } else {
2179 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2180 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002181
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002182 /* Rev 0 and 1 */
Angel Pons1d4044a2021-03-27 19:11:51 +01002183 mchbar_write16(UPMC1, 0x0010 | peg_bits);
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002184 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002185 }
2186
Angel Pons1d4044a2021-03-27 19:11:51 +01002187 reg16 = mchbar_read16(UPMC2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002188 reg16 &= 0xfc00;
2189 reg16 |= 0x0100;
Angel Pons1d4044a2021-03-27 19:11:51 +01002190 mchbar_write16(UPMC2, reg16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002191
Angel Pons1d4044a2021-03-27 19:11:51 +01002192 mchbar_write32(UPMC3, 0x000f06ff);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002193
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002194 for (i = 0; i < 5; i++) {
Angel Pons1d4044a2021-03-27 19:11:51 +01002195 mchbar_clrbits32(UPMC3, 1 << 16);
2196 mchbar_setbits32(UPMC3, 1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002197 }
2198
Angel Pons1d4044a2021-03-27 19:11:51 +01002199 mchbar_write32(GIPMC1, 0x8000000c);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002200
Angel Pons1d4044a2021-03-27 19:11:51 +01002201 reg16 = mchbar_read16(CPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002202 reg16 &= ~(7 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002203 if (i945_silicon_revision() > 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002204 reg16 |= (6 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002205 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002206 reg16 |= (4 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01002207 mchbar_write16(CPCTL, reg16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002208
Angel Pons3580d812020-06-11 14:13:33 +02002209#if 0
Angel Pons1d4044a2021-03-27 19:11:51 +01002210 if ((mchbar_read32(ECO) & (1 << 16)) != 0) {
Angel Pons3580d812020-06-11 14:13:33 +02002211#else
Stefan Reinauer30140a52009-03-11 16:20:39 +00002212 if (i945_silicon_revision() != 0) {
Angel Pons3580d812020-06-11 14:13:33 +02002213#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002214 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002215 case 667:
Angel Pons1d4044a2021-03-27 19:11:51 +01002216 mchbar_write32(HGIPMC2, 0x0d590d59);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002217 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002218 case 533:
Angel Pons1d4044a2021-03-27 19:11:51 +01002219 mchbar_write32(HGIPMC2, 0x155b155b);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002220 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002221 }
2222 } else {
2223 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002224 case 667:
Angel Pons1d4044a2021-03-27 19:11:51 +01002225 mchbar_write32(HGIPMC2, 0x09c409c4);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002226 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002227 case 533:
Angel Pons1d4044a2021-03-27 19:11:51 +01002228 mchbar_write32(HGIPMC2, 0x0fa00fa0);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002229 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002230 }
2231 }
2232
Angel Pons1d4044a2021-03-27 19:11:51 +01002233 mchbar_write32(FSBPMC1, 0x8000000c);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002234
Angel Pons1d4044a2021-03-27 19:11:51 +01002235 reg32 = mchbar_read32(C2C3TT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002236 reg32 &= 0xffff0000;
2237 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002238 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002239 reg32 |= 0x0600;
2240 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002241 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002242 reg32 |= 0x0480;
2243 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002244 }
Angel Pons1d4044a2021-03-27 19:11:51 +01002245 mchbar_write32(C2C3TT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002246
Angel Pons1d4044a2021-03-27 19:11:51 +01002247 reg32 = mchbar_read32(C3C4TT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002248 reg32 &= 0xffff0000;
2249 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002250 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002251 reg32 |= 0x0b80;
2252 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002253 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002254 reg32 |= 0x0980;
2255 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002256 }
Angel Pons1d4044a2021-03-27 19:11:51 +01002257 mchbar_write32(C3C4TT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002258
Arthur Heymans70a8e342017-03-09 11:30:23 +01002259 if (i945_silicon_revision() == 0)
Angel Pons1d4044a2021-03-27 19:11:51 +01002260 mchbar_clrbits32(ECO, 1 << 16);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002261 else
Angel Pons1d4044a2021-03-27 19:11:51 +01002262 mchbar_setbits32(ECO, 1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002263
Angel Pons1d4044a2021-03-27 19:11:51 +01002264 mchbar_clrbits32(FSBPMC3, 1 << 29);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002265
Angel Pons1d4044a2021-03-27 19:11:51 +01002266 mchbar_setbits32(FSBPMC3, 1 << 21);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002267
Angel Pons1d4044a2021-03-27 19:11:51 +01002268 mchbar_clrbits32(FSBPMC3, 1 << 19);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002269
Angel Pons1d4044a2021-03-27 19:11:51 +01002270 mchbar_clrbits32(FSBPMC3, 1 << 13);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002271
Angel Pons1d4044a2021-03-27 19:11:51 +01002272 reg32 = mchbar_read32(FSBPMC4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002273 reg32 &= ~(3 << 24);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002274 reg32 |= (2 << 24);
Angel Pons1d4044a2021-03-27 19:11:51 +01002275 mchbar_write32(FSBPMC4, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002276
Angel Pons1d4044a2021-03-27 19:11:51 +01002277 mchbar_setbits32(FSBPMC4, 1 << 21);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002278
Angel Pons1d4044a2021-03-27 19:11:51 +01002279 mchbar_setbits32(FSBPMC4, 1 << 5);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002280
Arthur Heymans70a8e342017-03-09 11:30:23 +01002281 if ((i945_silicon_revision() < 2)) { /* || cpuid() = 0x6e8 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002282 /* stepping 0 and 1 or CPUID 6e8 */
Angel Pons1d4044a2021-03-27 19:11:51 +01002283 mchbar_clrbits32(FSBPMC4, 1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002284 } else {
Angel Pons1d4044a2021-03-27 19:11:51 +01002285 mchbar_setbits32(FSBPMC4, 1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002286 }
2287
Angel Pons3580d812020-06-11 14:13:33 +02002288 pci_or_config8(HOST_BRIDGE, 0xfc, 1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002289
Angel Pons3580d812020-06-11 14:13:33 +02002290 pci_or_config8(IGD_DEV, 0xc1, 1 << 2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002291
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002292 if (integrated_graphics) {
Angel Pons1d4044a2021-03-27 19:11:51 +01002293 mchbar_write16(MIPMC4, 0x04f8);
2294 mchbar_write16(MIPMC5, 0x04fc);
2295 mchbar_write16(MIPMC6, 0x04fc);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002296 } else {
Angel Pons1d4044a2021-03-27 19:11:51 +01002297 mchbar_write16(MIPMC4, 0x64f8);
2298 mchbar_write16(MIPMC5, 0x64fc);
2299 mchbar_write16(MIPMC6, 0x64fc);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002300 }
2301
Angel Pons1d4044a2021-03-27 19:11:51 +01002302 reg32 = mchbar_read32(PMCFG);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002303 reg32 &= ~(3 << 17);
2304 reg32 |= (2 << 17);
Angel Pons1d4044a2021-03-27 19:11:51 +01002305 mchbar_write32(PMCFG, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002306
Angel Pons1d4044a2021-03-27 19:11:51 +01002307 mchbar_setbits32(PMCFG, 1 << 4);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002308
Angel Pons1d4044a2021-03-27 19:11:51 +01002309 reg32 = mchbar_read32(UPMC4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002310 reg32 &= 0xffffff00;
2311 reg32 |= 0x01;
Angel Pons1d4044a2021-03-27 19:11:51 +01002312 mchbar_write32(UPMC4, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002313
Angel Pons1d4044a2021-03-27 19:11:51 +01002314 mchbar_clrbits32(0xb18, 1 << 21);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002315}
2316
2317static void sdram_thermal_management(void)
2318{
Stefan Reinauer278534d2008-10-29 04:51:07 +00002319
Angel Pons1d4044a2021-03-27 19:11:51 +01002320 mchbar_write8(TCO1, 0);
2321 mchbar_write8(TCO0, 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002322
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002323 /* The Thermal Sensors for DIMMs at 0x50, 0x52 are at I2C addr 0x30/0x32. */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002324
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002325 /* TODO This is not implemented yet. Volunteers? */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002326}
2327
2328static void sdram_save_receive_enable(void)
2329{
2330 int i;
2331 u32 reg32;
2332 u8 values[4];
2333
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002334 /* The following values are stored to an unused CMOS area and restored instead of
2335 * recalculated in case of an S3 resume.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002336 *
Arthur Heymans70a8e342017-03-09 11:30:23 +01002337 * C0WL0REOST [7:0] -> 8 bit
2338 * C1WL0REOST [7:0] -> 8 bit
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002339 * RCVENMT [11:8] [3:0] -> 8 bit
2340 * C0DRT1 [27:24] -> 4 bit
2341 * C1DRT1 [27:24] -> 4 bit
2342 */
2343
Angel Pons1d4044a2021-03-27 19:11:51 +01002344 values[0] = mchbar_read8(C0WL0REOST);
2345 values[1] = mchbar_read8(C1WL0REOST);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002346
Angel Pons1d4044a2021-03-27 19:11:51 +01002347 reg32 = mchbar_read32(RCVENMT);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002348 values[2] = (u8)((reg32 >> (8 - 4)) & 0xf0) | (reg32 & 0x0f);
2349
Angel Pons1d4044a2021-03-27 19:11:51 +01002350 reg32 = mchbar_read32(C0DRT1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002351 values[3] = (reg32 >> 24) & 0x0f;
Angel Pons1d4044a2021-03-27 19:11:51 +01002352 reg32 = mchbar_read32(C1DRT1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002353 values[3] |= (reg32 >> (24 - 4)) & 0xf0;
2354
2355 /* coreboot only uses bytes 0 - 127 for its CMOS values so far
Edwin Beasanteb50c7d2010-07-06 21:05:04 +00002356 * so we grab bytes 128 - 131 to save the receive enable values
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002357 */
2358
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002359 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002360 cmos_write(values[i], 128 + i);
2361}
2362
2363static void sdram_recover_receive_enable(void)
2364{
2365 int i;
2366 u32 reg32;
2367 u8 values[4];
2368
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002369 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002370 values[i] = cmos_read(128 + i);
2371
Angel Pons1d4044a2021-03-27 19:11:51 +01002372 mchbar_write8(C0WL0REOST, values[0]);
2373 mchbar_write8(C1WL0REOST, values[1]);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002374
Angel Pons1d4044a2021-03-27 19:11:51 +01002375 reg32 = mchbar_read32(RCVENMT);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002376 reg32 &= ~((0x0f << 8) | (0x0f << 0));
2377 reg32 |= ((u32)(values[2] & 0xf0) << (8 - 4)) | (values[2] & 0x0f);
Angel Pons1d4044a2021-03-27 19:11:51 +01002378 mchbar_write32(RCVENMT, reg32);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002379
Angel Pons1d4044a2021-03-27 19:11:51 +01002380 reg32 = mchbar_read32(C0DRT1) & ~(0x0f << 24);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002381 reg32 |= (u32)(values[3] & 0x0f) << 24;
Angel Pons1d4044a2021-03-27 19:11:51 +01002382 mchbar_write32(C0DRT1, reg32);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002383
Angel Pons1d4044a2021-03-27 19:11:51 +01002384 reg32 = mchbar_read32(C1DRT1) & ~(0x0f << 24);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002385 reg32 |= (u32)(values[3] & 0xf0) << (24 - 4);
Angel Pons1d4044a2021-03-27 19:11:51 +01002386 mchbar_write32(C1DRT1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002387}
2388
Stefan Reinauer278534d2008-10-29 04:51:07 +00002389static void sdram_program_receive_enable(struct sys_info *sysinfo)
2390{
Angel Pons1d4044a2021-03-27 19:11:51 +01002391 mchbar_setbits32(REPC, 1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002392
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002393 /* Program Receive Enable Timings */
2394 if (sysinfo->boot_path == BOOT_PATH_RESUME) {
2395 sdram_recover_receive_enable();
2396 } else {
2397 receive_enable_adjust(sysinfo);
2398 sdram_save_receive_enable();
2399 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002400
Angel Pons1d4044a2021-03-27 19:11:51 +01002401 mchbar_setbits32(C0DRC1, 1 << 6);
2402 mchbar_setbits32(C1DRC1, 1 << 6);
2403 mchbar_clrbits32(C0DRC1, 1 << 6);
2404 mchbar_clrbits32(C1DRC1, 1 << 6);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002405
Angel Pons1d4044a2021-03-27 19:11:51 +01002406 mchbar_setbits32(MIPMC3, 0x0f << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002407}
2408
2409/**
2410 * @brief Enable On-Die Termination for DDR2.
2411 *
2412 */
2413
2414static void sdram_on_die_termination(struct sys_info *sysinfo)
2415{
2416 static const u32 odt[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002417 0x00024911, 0xe0010000,
2418 0x00049211, 0xe0020000,
2419 0x0006db11, 0xe0030000,
Stefan Reinauer278534d2008-10-29 04:51:07 +00002420 };
2421
2422 u32 reg32;
2423 int cas;
2424
Angel Pons1d4044a2021-03-27 19:11:51 +01002425 reg32 = mchbar_read32(ODTC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002426 reg32 &= ~(3 << 16);
2427 reg32 |= (1 << 14) | (1 << 6) | (2 << 16);
Angel Pons1d4044a2021-03-27 19:11:51 +01002428 mchbar_write32(ODTC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002429
Paul Menzelb4d9f222020-03-14 10:34:29 +01002430 if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002431 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
Elyes HAOUAS38424982016-08-21 12:01:04 +02002432 printk(BIOS_DEBUG, "one dimm per channel config..\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002433
Angel Pons1d4044a2021-03-27 19:11:51 +01002434 reg32 = mchbar_read32(C0ODT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002435 reg32 &= ~(7 << 28);
Angel Pons1d4044a2021-03-27 19:11:51 +01002436 mchbar_write32(C0ODT, reg32);
2437 reg32 = mchbar_read32(C1ODT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002438 reg32 &= ~(7 << 28);
Angel Pons1d4044a2021-03-27 19:11:51 +01002439 mchbar_write32(C1ODT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002440 }
2441
2442 cas = sysinfo->cas;
2443
Angel Pons1d4044a2021-03-27 19:11:51 +01002444 reg32 = mchbar_read32(C0ODT) & 0xfff00000;
Angel Pons30492572020-06-11 13:24:54 +02002445 reg32 |= odt[(cas - 3) * 2];
Angel Pons1d4044a2021-03-27 19:11:51 +01002446 mchbar_write32(C0ODT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002447
Angel Pons1d4044a2021-03-27 19:11:51 +01002448 reg32 = mchbar_read32(C1ODT) & 0xfff00000;
Angel Pons30492572020-06-11 13:24:54 +02002449 reg32 |= odt[(cas - 3) * 2];
Angel Pons1d4044a2021-03-27 19:11:51 +01002450 mchbar_write32(C1ODT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002451
Angel Pons1d4044a2021-03-27 19:11:51 +01002452 reg32 = mchbar_read32(C0ODT + 4) & 0x1fc8ffff;
Angel Pons30492572020-06-11 13:24:54 +02002453 reg32 |= odt[((cas - 3) * 2) + 1];
Angel Pons1d4044a2021-03-27 19:11:51 +01002454 mchbar_write32(C0ODT + 4, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002455
Angel Pons1d4044a2021-03-27 19:11:51 +01002456 reg32 = mchbar_read32(C1ODT + 4) & 0x1fc8ffff;
Angel Pons30492572020-06-11 13:24:54 +02002457 reg32 |= odt[((cas - 3) * 2) + 1];
Angel Pons1d4044a2021-03-27 19:11:51 +01002458 mchbar_write32(C1ODT + 4, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002459}
2460
2461/**
2462 * @brief Enable clocks to populated sockets
2463 */
2464
2465static void sdram_enable_memory_clocks(struct sys_info *sysinfo)
2466{
2467 u8 clocks[2] = { 0, 0 };
2468
Julius Wernercd49cce2019-03-05 16:53:33 -08002469#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002470#define CLOCKS_WIDTH 2
Julius Wernercd49cce2019-03-05 16:53:33 -08002471#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002472#define CLOCKS_WIDTH 3
2473#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002474 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002475 clocks[0] |= (1 << CLOCKS_WIDTH) - 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002476
2477 if (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002478 clocks[0] |= ((1 << CLOCKS_WIDTH) - 1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002479
2480 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002481 clocks[1] |= (1 << CLOCKS_WIDTH) - 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002482
2483 if (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002484 clocks[1] |= ((1 << CLOCKS_WIDTH) - 1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002485
Julius Wernercd49cce2019-03-05 16:53:33 -08002486#if CONFIG(OVERRIDE_CLOCK_DISABLE)
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002487 /* Usually system firmware turns off system memory clock signals to unused SO-DIMM slots
2488 * to reduce EMI and power consumption.
2489 * However, the Kontron 986LCD-M does not like unused clock signals to be disabled.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002490 */
2491
2492 clocks[0] = 0xf; /* force all clock gate pairs to enable */
2493 clocks[1] = 0xf; /* force all clock gate pairs to enable */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002494#endif
2495
Angel Pons1d4044a2021-03-27 19:11:51 +01002496 mchbar_write8(C0DCLKDIS, clocks[0]);
2497 mchbar_write8(C1DCLKDIS, clocks[1]);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002498}
2499
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002500#define RTT_ODT_NONE 0
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002501#define RTT_ODT_50_OHM ((1 << 9) | (1 << 5))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002502#define RTT_ODT_75_OHM (1 << 5)
2503#define RTT_ODT_150_OHM (1 << 9)
2504
Arthur Heymans70a8e342017-03-09 11:30:23 +01002505#define EMRS_OCD_DEFAULT ((1 << 12) | (1 << 11) | (1 << 10))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002506
2507#define MRS_CAS_3 (3 << 7)
2508#define MRS_CAS_4 (4 << 7)
2509#define MRS_CAS_5 (5 << 7)
2510
2511#define MRS_TWR_3 (2 << 12)
2512#define MRS_TWR_4 (3 << 12)
2513#define MRS_TWR_5 (4 << 12)
2514
2515#define MRS_BT (1 << 6)
2516
2517#define MRS_BL4 (2 << 3)
2518#define MRS_BL8 (3 << 3)
2519
2520static void sdram_jedec_enable(struct sys_info *sysinfo)
2521{
2522 int i, nonzero;
2523 u32 bankaddr = 0, tmpaddr, mrsaddr = 0;
2524
2525 for (i = 0, nonzero = -1; i < 8; i++) {
Elyes HAOUAS01912202019-01-19 16:36:38 +01002526 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002527 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002528
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002529 printk(BIOS_DEBUG, "jedec enable sequence: bank %d\n", i);
Elyes HAOUAS01912202019-01-19 16:36:38 +01002530
2531 if (nonzero != -1) {
2532 if (sysinfo->interleaved && nonzero < 4 && i >= 4) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002533 bankaddr = 0x40;
Elyes HAOUAS01912202019-01-19 16:36:38 +01002534 } else {
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002535 printk(BIOS_DEBUG, "bankaddr from bank size of rank %d\n",
2536 nonzero);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002537 bankaddr += sysinfo->banksize[nonzero] <<
2538 (sysinfo->interleaved ? 26 : 25);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002539 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002540 }
2541
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002542 /*
2543 * We have a bank with a non-zero size... Remember it
Stefan Reinauer278534d2008-10-29 04:51:07 +00002544 * for the next offset we have to calculate
2545 */
2546 nonzero = i;
2547
2548 /* Get CAS latency set up */
2549 switch (sysinfo->cas) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002550 case 5:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002551 mrsaddr = MRS_CAS_5;
2552 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002553 case 4:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002554 mrsaddr = MRS_CAS_4;
2555 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002556 case 3:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002557 mrsaddr = MRS_CAS_3;
2558 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002559 default:
2560 die("Jedec Error (CAS).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002561 }
2562
2563 /* Get tWR set */
2564 switch (sysinfo->twr) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002565 case 5:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002566 mrsaddr |= MRS_TWR_5;
2567 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002568 case 4:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002569 mrsaddr |= MRS_TWR_4;
2570 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002571 case 3:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002572 mrsaddr |= MRS_TWR_3;
2573 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002574 default:
2575 die("Jedec Error (tWR).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002576 }
2577
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002578 /* Set "Burst Type" */
2579 mrsaddr |= MRS_BT;
2580
Stefan Reinauer278534d2008-10-29 04:51:07 +00002581 /* Interleaved */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002582 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002583 mrsaddr = mrsaddr << 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002584
2585 /* Only burst length 8 supported */
2586 mrsaddr |= MRS_BL8;
2587
2588 /* Apply NOP */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002589 PRINTK_DEBUG("Apply NOP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002590 do_ram_command(RAM_COMMAND_NOP);
2591 ram_read32(bankaddr);
2592
2593 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002594 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002595 do_ram_command(RAM_COMMAND_PRECHARGE);
2596 ram_read32(bankaddr);
2597
2598 /* Extended Mode Register Set (2) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002599 PRINTK_DEBUG("Extended Mode Register Set(2)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002600 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_2);
2601 ram_read32(bankaddr);
2602
2603 /* Extended Mode Register Set (3) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002604 PRINTK_DEBUG("Extended Mode Register Set(3)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002605 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_3);
2606 ram_read32(bankaddr);
2607
2608 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002609 PRINTK_DEBUG("Extended Mode Register Set\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002610 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2611 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002612 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002613 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002614 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002615 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002616 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002617 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002618 ram_read32(tmpaddr);
2619
2620 /* Mode Register Set: Reset DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002621 PRINTK_DEBUG("MRS: Reset DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002622 do_ram_command(RAM_COMMAND_MRS);
2623 tmpaddr = bankaddr;
2624 tmpaddr |= mrsaddr;
2625 /* Set DLL reset bit */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002626 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002627 tmpaddr |= (1 << 12);
2628 else
2629 tmpaddr |= (1 << 11);
2630 ram_read32(tmpaddr);
2631
2632 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002633 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002634 do_ram_command(RAM_COMMAND_PRECHARGE);
2635 ram_read32(bankaddr);
2636
2637 /* CAS before RAS Refresh */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002638 PRINTK_DEBUG("CAS before RAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002639 do_ram_command(RAM_COMMAND_CBR);
2640
2641 /* CBR wants two READs */
2642 ram_read32(bankaddr);
2643 ram_read32(bankaddr);
2644
2645 /* Mode Register Set: Enable DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002646 PRINTK_DEBUG("MRS: Enable DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002647 do_ram_command(RAM_COMMAND_MRS);
2648
2649 tmpaddr = bankaddr;
2650 tmpaddr |= mrsaddr;
2651 ram_read32(tmpaddr);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002652
Stefan Reinauer278534d2008-10-29 04:51:07 +00002653 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002654 PRINTK_DEBUG("Extended Mode Register Set: ODT/OCD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002655 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002656
Stefan Reinauer278534d2008-10-29 04:51:07 +00002657 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002658 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002659 tmpaddr |= RTT_ODT_75_OHM | EMRS_OCD_DEFAULT;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002660 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002661 tmpaddr |= ((RTT_ODT_150_OHM | EMRS_OCD_DEFAULT) << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002662 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002663 tmpaddr |= RTT_ODT_150_OHM | EMRS_OCD_DEFAULT;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002664 ram_read32(tmpaddr);
2665
2666 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002667 PRINTK_DEBUG("Extended Mode Register Set: OCD Exit\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002668 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2669
2670 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002671 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002672 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002673 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002674 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002675 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002676 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002677 ram_read32(tmpaddr);
2678 }
2679}
2680
2681static void sdram_init_complete(void)
2682{
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002683 PRINTK_DEBUG("Normal Operation\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002684 do_ram_command(RAM_COMMAND_NORMAL);
2685}
2686
2687static void sdram_setup_processor_side(void)
2688{
2689 if (i945_silicon_revision() == 0)
Angel Pons1d4044a2021-03-27 19:11:51 +01002690 mchbar_setbits32(FSBPMC3, 1 << 2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002691
Angel Pons1d4044a2021-03-27 19:11:51 +01002692 mchbar_setbits8(0xb00, 1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002693
2694 if (i945_silicon_revision() == 0)
Angel Pons1d4044a2021-03-27 19:11:51 +01002695 mchbar_setbits32(SLPCTL, 1 << 8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002696}
2697
Stefan Reinauer278534d2008-10-29 04:51:07 +00002698/**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002699 * @param boot_path: 0 = normal, 1 = reset, 2 = resume from s3
Martin Rothf4cb4122015-01-06 10:27:39 -07002700 * @param spd_addresses pointer to a list of SPD addresses
Stefan Reinauer278534d2008-10-29 04:51:07 +00002701 */
Sven Schnelle541269b2011-02-21 09:39:17 +00002702void sdram_initialize(int boot_path, const u8 *spd_addresses)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002703{
2704 struct sys_info sysinfo;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002705
Jakub Czapigaad6157e2022-02-15 11:50:31 +01002706 timestamp_add_now(TS_INITRAM_START);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002707 printk(BIOS_DEBUG, "Setting up RAM controller.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002708
2709 memset(&sysinfo, 0, sizeof(sysinfo));
2710
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002711 sysinfo.boot_path = boot_path;
Sven Schnelle541269b2011-02-21 09:39:17 +00002712 sysinfo.spd_addresses = spd_addresses;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002713
Stefan Reinauer278534d2008-10-29 04:51:07 +00002714 /* Look at the type of DIMMs and verify all DIMMs are x8 or x16 width */
2715 sdram_get_dram_configuration(&sysinfo);
2716
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002717 /* If error, do cold boot */
2718 sdram_detect_errors(&sysinfo);
2719
Stefan Reinauer278534d2008-10-29 04:51:07 +00002720 /* Program PLL settings */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002721 sdram_program_pll_settings(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002722
Arthur Heymans18537812016-12-28 21:20:45 +01002723 /*
2724 * Program Graphics Frequency
2725 * Set core display and render clock on 945GC to the max
2726 */
Julius Wernercd49cce2019-03-05 16:53:33 -08002727 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM))
Arthur Heymans18537812016-12-28 21:20:45 +01002728 sdram_program_graphics_frequency(&sysinfo);
2729 else
Angel Pons3580d812020-06-11 14:13:33 +02002730 pci_write_config16(IGD_DEV, GCFC, 0x0534);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002731
2732 /* Program System Memory Frequency */
2733 sdram_program_memory_frequency(&sysinfo);
2734
2735 /* Determine Mode of Operation (Interleaved etc) */
2736 sdram_set_channel_mode(&sysinfo);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002737
Stefan Reinauer278534d2008-10-29 04:51:07 +00002738 /* Program Clock Crossing values */
2739 sdram_program_clock_crossing();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002740
Stefan Reinauer278534d2008-10-29 04:51:07 +00002741 /* Disable fast dispatch */
2742 sdram_disable_fast_dispatch();
2743
2744 /* Enable WIODLL Power Down in ACPI states */
Angel Pons1d4044a2021-03-27 19:11:51 +01002745 mchbar_setbits32(C0DMC, 1 << 24);
2746 mchbar_setbits32(C1DMC, 1 << 24);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002747
2748 /* Program DRAM Row Boundary/Attribute Registers */
2749
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002750 /* program row size DRB and set TOLUD */
2751 sdram_program_row_boundaries(&sysinfo);
2752
2753 /* program page size DRA */
2754 sdram_set_row_attributes(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002755
2756 /* Program CxBNKARC */
2757 sdram_set_bank_architecture(&sysinfo);
2758
2759 /* Program DRAM Timing and Control registers based on SPD */
2760 sdram_set_timing_and_control(&sysinfo);
2761
2762 /* On-Die Termination Adjustment */
2763 sdram_on_die_termination(&sysinfo);
2764
2765 /* Pre Jedec Initialization */
2766 sdram_pre_jedec_initialization();
2767
2768 /* Perform System Memory IO Initialization */
2769 sdram_initialize_system_memory_io(&sysinfo);
2770
2771 /* Perform System Memory IO Buffer Enable */
2772 sdram_enable_system_memory_io(&sysinfo);
2773
2774 /* Enable System Memory Clocks */
2775 sdram_enable_memory_clocks(&sysinfo);
2776
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002777 if (boot_path == BOOT_PATH_NORMAL) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002778 /* Jedec Initialization sequence */
2779 sdram_jedec_enable(&sysinfo);
2780 }
2781
2782 /* Program Power Management Registers */
2783 sdram_power_management(&sysinfo);
2784
2785 /* Post Jedec Init */
2786 sdram_post_jedec_initialization(&sysinfo);
2787
2788 /* Program DRAM Throttling */
2789 sdram_thermal_management();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002790
Stefan Reinauer278534d2008-10-29 04:51:07 +00002791 /* Normal Operations */
Stefan Reinaueraca6ec62009-10-26 17:12:21 +00002792 sdram_init_complete();
Stefan Reinauer278534d2008-10-29 04:51:07 +00002793
2794 /* Program Receive Enable Timings */
2795 sdram_program_receive_enable(&sysinfo);
2796
2797 /* Enable Periodic RCOMP */
2798 sdram_enable_rcomp();
2799
2800 /* Tell ICH7 that we're done */
Angel Ponse3c68d22020-06-08 12:09:03 +02002801 pci_and_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, (u8)~(1 << 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +00002802
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002803 printk(BIOS_DEBUG, "RAM initialization finished.\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002804
Stefan Reinauer278534d2008-10-29 04:51:07 +00002805 sdram_setup_processor_side();
Jakub Czapigaad6157e2022-02-15 11:50:31 +01002806 timestamp_add_now(TS_INITRAM_END);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002807}