blob: 2613b81670d639aa52caee68b9728b18398cda7d [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;
Elyes Haouas90156652022-10-07 12:27:22 +0200219 bool do_reset = false;
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);
Elyes Haouas90156652022-10-07 12:27:22 +0200228 do_reset = true;
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);
Elyes Haouas90156652022-10-07 12:27:22 +0200236 do_reset = true;
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))) {
Elyes Haouas90156652022-10-07 12:27:22 +0200261 do_reset = true;
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000262 }
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))) {
Elyes Haouas90156652022-10-07 12:27:22 +0200266 do_reset = true;
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000267 }
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 Haouas26fc2a42022-10-07 11:25:25 +0200429 printk(BIOS_DEBUG, "DIMM %d side 0 = %zu MB\n", i,
430 sysinfo->banksize[i * 2] * 32);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100431 if (dimm_info.ranks == 2) {
432 sysinfo->banksize[(i * 2) + 1] =
433 dimm_info.ranksize_mb / 32;
Elyes Haouas26fc2a42022-10-07 11:25:25 +0200434 printk(BIOS_DEBUG, "DIMM %d side 1 = %zu MB\n",
Arthur Heymans0ab49042017-02-06 22:40:14 +0100435 i, sysinfo->banksize[(i * 2) + 1] * 32);
436 }
437
Arthur Heymans0ab49042017-02-06 22:40:14 +0100438 sysinfo->rows[i] = dimm_info.row_bits;
439 sysinfo->cols[i] = dimm_info.col_bits;
440 sysinfo->banks[i] = dimm_info.banks;
441
442 /* int min_tRAS, min_tRP, min_tRCD, min_tWR, min_tRFC; */
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200443 saved_timings->min_tRAS = MAX(saved_timings->min_tRAS, dimm_info.tRAS);
444 saved_timings->min_tRP = MAX(saved_timings->min_tRP, dimm_info.tRP);
445 saved_timings->min_tRCD = MAX(saved_timings->min_tRCD, dimm_info.tRCD);
446 saved_timings->min_tWR = MAX(saved_timings->min_tWR, dimm_info.tWR);
447 saved_timings->min_tRFC = MAX(saved_timings->min_tRFC, dimm_info.tRFC);
448 saved_timings->max_tRR = MIN(saved_timings->max_tRR, dimm_info.tRR);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100449 saved_timings->cas_mask &= dimm_info.cas_supported;
450 for (j = 0; j < 8; j++) {
451 if (!(saved_timings->cas_mask & (1 << j)))
452 saved_timings->min_tCLK_cas[j] = 0;
453 else
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200454 saved_timings->min_tCLK_cas[j] = MAX(dimm_info.cycle_time[j],
Arthur Heymans0ab49042017-02-06 22:40:14 +0100455 saved_timings->min_tCLK_cas[j]);
456 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000457 dimm_mask |= (1 << i);
458 }
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200459 if (!dimm_mask)
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000460 die("No memory installed.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000461
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200462 if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1)))
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100463 /* FIXME: Possibly does not boot in this case */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000464 printk(BIOS_INFO, "Channel 0 has no memory populated.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000465}
466
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200467static void choose_tclk(struct sys_info *sysinfo, struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000468{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100469 u32 ctrl_min_tclk;
470 int try_cas;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000471
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200472 ctrl_min_tclk = 2 * 256 * 1000 / sdram_capabilities_max_supported_memory_frequency();
Arthur Heymans0ab49042017-02-06 22:40:14 +0100473 normalize_tck(&ctrl_min_tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000474
Arthur Heymans0ab49042017-02-06 22:40:14 +0100475 try_cas = spd_get_msbs(saved_timings->cas_mask);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000476
Arthur Heymans0ab49042017-02-06 22:40:14 +0100477 while (saved_timings->cas_mask & (1 << try_cas) && try_cas > 0) {
478 sysinfo->cas = try_cas;
479 sysinfo->tclk = saved_timings->min_tCLK_cas[try_cas];
480 if (sysinfo->tclk >= ctrl_min_tclk &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200481 saved_timings->min_tCLK_cas[try_cas] !=
482 saved_timings->min_tCLK_cas[try_cas - 1])
Stefan Reinauer278534d2008-10-29 04:51:07 +0000483 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100484 try_cas--;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000485 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000486
Arthur Heymans0ab49042017-02-06 22:40:14 +0100487 normalize_tck(&sysinfo->tclk);
488
489 if ((sysinfo->cas < 3) || (sysinfo->tclk == 0))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000490 die("Could not find common memory frequency and CAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000491
Arthur Heymans0ab49042017-02-06 22:40:14 +0100492 /*
493 * The loop can still results in a timing too fast for the
494 * memory controller.
495 */
496 if (sysinfo->tclk < ctrl_min_tclk)
497 sysinfo->tclk = ctrl_min_tclk;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000498
Arthur Heymans0ab49042017-02-06 22:40:14 +0100499 switch (sysinfo->tclk) {
500 case TCK_200MHZ:
501 sysinfo->memory_frequency = 400;
502 break;
503 case TCK_266MHZ:
504 sysinfo->memory_frequency = 533;
505 break;
506 case TCK_333MHZ:
507 sysinfo->memory_frequency = 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100508 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000509 }
510
Arthur Heymans0ab49042017-02-06 22:40:14 +0100511 printk(BIOS_DEBUG,
512 "Memory will be driven at %dMT with CAS=%d clocks\n",
513 sysinfo->memory_frequency, sysinfo->cas);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000514}
515
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200516static void derive_timings(struct sys_info *sysinfo, struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000517{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100518 sysinfo->tras = DIV_ROUND_UP(saved_timings->min_tRAS, sysinfo->tclk);
519 if (sysinfo->tras > 0x18)
520 die("DDR-II Module does not support this frequency (tRAS error)\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000521
Arthur Heymans0ab49042017-02-06 22:40:14 +0100522 sysinfo->trp = DIV_ROUND_UP(saved_timings->min_tRP, sysinfo->tclk);
523 if (sysinfo->trp > 6)
524 die("DDR-II Module does not support this frequency (tRP error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000525
Arthur Heymans0ab49042017-02-06 22:40:14 +0100526 sysinfo->trcd = DIV_ROUND_UP(saved_timings->min_tRCD, sysinfo->tclk);
527 if (sysinfo->trcd > 6)
528 die("DDR-II Module does not support this frequency (tRCD error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000529
Arthur Heymans0ab49042017-02-06 22:40:14 +0100530 sysinfo->twr = DIV_ROUND_UP(saved_timings->min_tWR, sysinfo->tclk);
531 if (sysinfo->twr > 5)
532 die("DDR-II Module does not support this frequency (tWR error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000533
Arthur Heymans0ab49042017-02-06 22:40:14 +0100534 sysinfo->trfc = DIV_ROUND_UP(saved_timings->min_tRFC, sysinfo->tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000535
Arthur Heymans0ab49042017-02-06 22:40:14 +0100536 printk(BIOS_DEBUG, "tRAS = %d cycles\n", sysinfo->tras);
537 printk(BIOS_DEBUG, "tRP = %d cycles\n", sysinfo->trp);
538 printk(BIOS_DEBUG, "tRCD = %d cycles\n", sysinfo->trcd);
539 printk(BIOS_DEBUG, "tWR = %d cycles\n", sysinfo->twr);
540 printk(BIOS_DEBUG, "tRFC = %d cycles\n", sysinfo->trfc);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000541
Arthur Heymans0ab49042017-02-06 22:40:14 +0100542 /* Refresh is slower than 15.6us, use 15.6us */
543 /* tRR is decoded in units of 1/256us */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000544
Arthur Heymans0ab49042017-02-06 22:40:14 +0100545#define T_RR_7_8US 2000000
546#define T_RR_15_6US 4000000
547#define REFRESH_7_8US 1
548#define REFRESH_15_6US 0
Stefan Reinauer278534d2008-10-29 04:51:07 +0000549
Arthur Heymans0ab49042017-02-06 22:40:14 +0100550 if (saved_timings->max_tRR < T_RR_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000551 die("DDR-II module has unsupported refresh value\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100552 else if (saved_timings->max_tRR < T_RR_15_6US)
553 sysinfo->refresh = REFRESH_7_8US;
554 else
555 sysinfo->refresh = REFRESH_15_6US;
Angel Pons30492572020-06-11 13:24:54 +0200556 printk(BIOS_DEBUG, "Refresh: %s\n", sysinfo->refresh ? "7.8us" : "15.6us");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000557}
558
Arthur Heymans0ab49042017-02-06 22:40:14 +0100559/**
560 * @brief Get generic DIMM parameters.
561 * @param sysinfo Central memory controller information structure
562 *
563 * This function gathers several pieces of information for each system DIMM:
564 * o DIMM width (x8 / x16)
565 * o DIMM rank (single ranked / dual ranked)
566 *
567 * Also, some non-supported scenarios are detected.
568 */
569
570static void sdram_get_dram_configuration(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000571{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100572 struct timings saved_timings;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000573
Arthur Heymans0ab49042017-02-06 22:40:14 +0100574 gather_common_timing(sysinfo, &saved_timings);
575 choose_tclk(sysinfo, &saved_timings);
576 derive_timings(sysinfo, &saved_timings);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000577}
578
Arthur Heymans70a8e342017-03-09 11:30:23 +0100579static void sdram_program_dram_width(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000580{
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200581 u16 c0dramw = 0, c1dramw = 0;
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200582 int i, idx;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000583
584 if (sysinfo->dual_channel)
585 idx = 2;
586 else
587 idx = 1;
588
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200589 for (i = 0; i < DIMM_SOCKETS; i++) { /* Channel 0 */
590 switch (sysinfo->dimm[i]) {
591 case SYSINFO_DIMM_X16DS:
Angel Pons30492572020-06-11 13:24:54 +0200592 c0dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200593 break;
594 case SYSINFO_DIMM_X8DS:
Angel Pons30492572020-06-11 13:24:54 +0200595 c0dramw |= (0x0001) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200596 break;
597 case SYSINFO_DIMM_X16SS:
Angel Pons30492572020-06-11 13:24:54 +0200598 c0dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200599 break;
600 case SYSINFO_DIMM_X8DDS:
Angel Pons30492572020-06-11 13:24:54 +0200601 c0dramw |= (0x0005) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200602 break;
603 case SYSINFO_DIMM_NOT_POPULATED:
Angel Pons30492572020-06-11 13:24:54 +0200604 c0dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200605 break;
606 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000607 }
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200608 for (i = DIMM_SOCKETS; i < idx * DIMM_SOCKETS; i++) { /* Channel 1 */
609 switch (sysinfo->dimm[i]) {
610 case SYSINFO_DIMM_X16DS:
Angel Pons30492572020-06-11 13:24:54 +0200611 c1dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200612 break;
613 case SYSINFO_DIMM_X8DS:
Angel Pons30492572020-06-11 13:24:54 +0200614 c1dramw |= (0x0010) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200615 break;
616 case SYSINFO_DIMM_X16SS:
Angel Pons30492572020-06-11 13:24:54 +0200617 c1dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200618 break;
619 case SYSINFO_DIMM_X8DDS:
Angel Pons30492572020-06-11 13:24:54 +0200620 c1dramw |= (0x0050) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200621 break;
622 case SYSINFO_DIMM_NOT_POPULATED:
Angel Pons30492572020-06-11 13:24:54 +0200623 c1dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200624 break;
625 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000626 }
627
Angel Pons1d4044a2021-03-27 19:11:51 +0100628 mchbar_write16(C0DRAMW, c0dramw);
629 mchbar_write16(C1DRAMW, c1dramw);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000630}
631
632static void sdram_write_slew_rates(u32 offset, const u32 *slew_rate_table)
633{
634 int i;
635
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200636 for (i = 0; i < 16; i++)
Angel Pons1d4044a2021-03-27 19:11:51 +0100637 mchbar_write32(offset + (i * 4), slew_rate_table[i]);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000638}
639
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000640static const u32 dq2030[] = {
641 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
642 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
643 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
644 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
645};
646
647static const u32 dq2330[] = {
648 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
649 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
650 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
651 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
652};
653
654static const u32 cmd2710[] = {
655 0x07060605, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
656 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
657 0x1110100f, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
658 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
659};
660
661static const u32 cmd3210[] = {
662 0x0f0d0b0a, 0x17151311, 0x1f1d1b19, 0x1f1f1f1f,
663 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
664 0x18171615, 0x1f1f1c1a, 0x1f1f1f1f, 0x1f1f1f1f,
665 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
666};
667
668static const u32 clk2030[] = {
669 0x0e0d0d0c, 0x100f0f0e, 0x100f0e0d, 0x15131211,
670 0x1d1b1917, 0x2523211f, 0x2a282927, 0x32302e2c,
671 0x17161514, 0x1b1a1918, 0x1f1e1d1c, 0x23222120,
672 0x27262524, 0x2d2b2928, 0x3533312f, 0x3d3b3937
673};
674
675static const u32 ctl3215[] = {
676 0x01010000, 0x03020101, 0x07060504, 0x0b0a0908,
677 0x100f0e0d, 0x14131211, 0x18171615, 0x1c1b1a19,
678 0x05040403, 0x07060605, 0x0a090807, 0x0f0d0c0b,
679 0x14131211, 0x18171615, 0x1c1b1a19, 0x201f1e1d
680};
681
682static const u32 ctl3220[] = {
683 0x05040403, 0x07060505, 0x0e0c0a08, 0x1a171411,
684 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e,
685 0x09080807, 0x0b0a0a09, 0x0f0d0c0b, 0x1b171311,
686 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e
687};
688
689static const u32 nc[] = {
690 0x00000000, 0x00000000, 0x00000000, 0x00000000,
691 0x00000000, 0x00000000, 0x00000000, 0x00000000,
692 0x00000000, 0x00000000, 0x00000000, 0x00000000,
693 0x00000000, 0x00000000, 0x00000000, 0x00000000
694};
695
696enum {
697 DQ2030,
698 DQ2330,
699 CMD2710,
700 CMD3210,
701 CLK2030,
702 CTL3215,
703 CTL3220,
704 NC,
705};
706
707static const u8 dual_channel_slew_group_lookup[] = {
708 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
709 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
710 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
711 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
712 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
713
714 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
715 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
716 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
717 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
718 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
719
720 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
721 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
722 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
723 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
724 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
725
726 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
727 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
728 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
729 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
730 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, NC, NC,
731
732 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
733 NC, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
734 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
735 NC, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD2710
736};
737
738static const u8 single_channel_slew_group_lookup[] = {
739 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
740 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
741 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
742 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
743 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
744
745 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
746 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
747 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
748 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
749 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
750
751 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
752 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
753 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
754 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
755 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
756
757 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
758 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
759 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
760 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
761 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
762
763 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
764 DQ2330, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
765 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
766 DQ2330, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD3210
767};
768
Elyes Haouas49446092022-09-28 14:14:05 +0200769static const u32 *slew_group_lookup(bool dual_channel, int index)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000770{
771 const u8 *slew_group;
772 /* Dual Channel needs different tables. */
773 if (dual_channel)
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100774 slew_group = dual_channel_slew_group_lookup;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000775 else
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100776 slew_group = single_channel_slew_group_lookup;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000777
778 switch (slew_group[index]) {
779 case DQ2030: return dq2030;
780 case DQ2330: return dq2330;
781 case CMD2710: return cmd2710;
782 case CMD3210: return cmd3210;
783 case CLK2030: return clk2030;
784 case CTL3215: return ctl3215;
785 case CTL3220: return ctl3220;
786 case NC: return nc;
787 }
788
789 return nc;
790}
791
Julius Wernercd49cce2019-03-05 16:53:33 -0800792#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000793/* Strength multiplier tables */
794static const u8 dual_channel_strength_multiplier[] = {
795 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
796 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
797 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
798 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
799 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
800 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
801 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
802 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
803 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
804 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
805 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
806 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
807 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
808 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
809 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
810 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
811 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
812 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
813 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
814 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
815 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
816 0x00, 0x00, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
817 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
818 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x44, 0x22
819};
820
821static const u8 single_channel_strength_multiplier[] = {
822 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
823 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
824 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
825 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
826 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
827 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
828 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
829 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
830 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
831 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
832 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
833 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
834 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
835 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
836 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
837 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
838 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
839 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
840 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
841 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
842 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
843 0x33, 0x00, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
844 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
845 0x33, 0x00, 0x11, 0x00, 0x44, 0x44, 0x33, 0x11
846};
Julius Wernercd49cce2019-03-05 16:53:33 -0800847#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000848static const u8 dual_channel_strength_multiplier[] = {
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, 0x22,
852 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
853 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
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, 0x22,
857 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
858 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
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, 0x22,
862 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
863 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
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, 0x22,
867 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
868 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
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, 0x22,
872 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33
873};
874
875static const u8 single_channel_strength_multiplier[] = {
876 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
877 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
878 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
879 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
880 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
881 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
882 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
883 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
884 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
885 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
886 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
887 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
888 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
889 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
890 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
891 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
892 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
893 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
894 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
895 0x44, 0x33, 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, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
899 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00
900};
901#endif
902
Stefan Reinauer278534d2008-10-29 04:51:07 +0000903static void sdram_rcomp_buffer_strength_and_slew(struct sys_info *sysinfo)
904{
Arthur Heymans70a8e342017-03-09 11:30:23 +0100905 const u8 *strength_multiplier;
Elyes Haouas49446092022-09-28 14:14:05 +0200906 int idx;
907 bool dual_channel;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000908
909 /* Set Strength Multipliers */
910
911 /* Dual Channel needs different tables. */
912 if (sdram_capabilities_dual_channel()) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000913 printk(BIOS_DEBUG, "Programming Dual Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000914 strength_multiplier = dual_channel_strength_multiplier;
Elyes Haouas49446092022-09-28 14:14:05 +0200915 dual_channel = true;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100916 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[2];
Stefan Reinauer278534d2008-10-29 04:51:07 +0000917 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000918 printk(BIOS_DEBUG, "Programming Single Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000919 strength_multiplier = single_channel_strength_multiplier;
Elyes Haouas49446092022-09-28 14:14:05 +0200920 dual_channel = false;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000921 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[1];
922 }
923
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000924 printk(BIOS_DEBUG, "Table Index: %d\n", idx);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000925
Angel Pons1d4044a2021-03-27 19:11:51 +0100926 mchbar_write8(G1SC, strength_multiplier[idx * 8 + 0]);
927 mchbar_write8(G2SC, strength_multiplier[idx * 8 + 1]);
928 mchbar_write8(G3SC, strength_multiplier[idx * 8 + 2]);
929 mchbar_write8(G4SC, strength_multiplier[idx * 8 + 3]);
930 mchbar_write8(G5SC, strength_multiplier[idx * 8 + 4]);
931 mchbar_write8(G6SC, strength_multiplier[idx * 8 + 5]);
932 mchbar_write8(G7SC, strength_multiplier[idx * 8 + 6]);
933 mchbar_write8(G8SC, strength_multiplier[idx * 8 + 7]);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000934
935 /* Channel 0 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000936 sdram_write_slew_rates(G1SRPUT, slew_group_lookup(dual_channel, idx * 8 + 0));
937 sdram_write_slew_rates(G2SRPUT, slew_group_lookup(dual_channel, idx * 8 + 1));
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200938 if ((slew_group_lookup(dual_channel, idx * 8 + 2) != nc) &&
939 (sysinfo->package == SYSINFO_PACKAGE_STACKED))
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000940
Stefan Reinauer278534d2008-10-29 04:51:07 +0000941 sdram_write_slew_rates(G3SRPUT, ctl3220);
Arthur Heymans70a8e342017-03-09 11:30:23 +0100942 else
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000943 sdram_write_slew_rates(G3SRPUT, slew_group_lookup(dual_channel, idx * 8 + 2));
Arthur Heymans70a8e342017-03-09 11:30:23 +0100944
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000945 sdram_write_slew_rates(G4SRPUT, slew_group_lookup(dual_channel, idx * 8 + 3));
946 sdram_write_slew_rates(G5SRPUT, slew_group_lookup(dual_channel, idx * 8 + 4));
947 sdram_write_slew_rates(G6SRPUT, slew_group_lookup(dual_channel, idx * 8 + 5));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000948
949 /* Channel 1 */
950 if (sysinfo->dual_channel) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000951 sdram_write_slew_rates(G7SRPUT, slew_group_lookup(dual_channel, idx * 8 + 6));
952 sdram_write_slew_rates(G8SRPUT, slew_group_lookup(dual_channel, idx * 8 + 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000953 } else {
954 sdram_write_slew_rates(G7SRPUT, nc);
955 sdram_write_slew_rates(G8SRPUT, nc);
956 }
957}
958
959static void sdram_enable_rcomp(void)
960{
961 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000962 /* Enable Global Periodic RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000963 udelay(300);
Angel Pons1d4044a2021-03-27 19:11:51 +0100964 reg32 = mchbar_read32(GBRCOMPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000965 reg32 &= ~(1 << 23);
Angel Pons1d4044a2021-03-27 19:11:51 +0100966 mchbar_write32(GBRCOMPCTL, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000967}
968
969static void sdram_program_dll_timings(struct sys_info *sysinfo)
970{
Elyes HAOUAS44a30662017-02-23 13:14:44 +0100971 u32 channeldll = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000972 int i;
973
Elyes HAOUAS38424982016-08-21 12:01:04 +0200974 printk(BIOS_DEBUG, "Programming DLL Timings...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000975
Angel Pons1d4044a2021-03-27 19:11:51 +0100976 mchbar_clrbits16(DQSMT, 3 << 12 | 1 << 10 | 0xf << 0);
977 mchbar_setbits16(DQSMT, 1 << 13 | 0xc << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000978
979 /* We drive both channels with the same speed */
Julius Wernercd49cce2019-03-05 16:53:33 -0800980 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +0100981 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +0100982 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200983 channeldll = 0x26262626;
984 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100985 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200986 channeldll = 0x22222222;
987 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100988 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200989 channeldll = 0x11111111;
990 break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +0100991 }
Julius Wernercd49cce2019-03-05 16:53:33 -0800992 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +0100993 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +0100994 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200995 channeldll = 0x33333333;
996 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100997 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200998 channeldll = 0x24242424;
999 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001000 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001001 channeldll = 0x25252525;
1002 break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001003 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001004 }
1005
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001006 for (i = 0; i < 4; i++) {
Angel Pons1d4044a2021-03-27 19:11:51 +01001007 mchbar_write32(C0R0B00DQST + (i * 0x10) + 0, channeldll);
1008 mchbar_write32(C0R0B00DQST + (i * 0x10) + 4, channeldll);
1009 mchbar_write32(C1R0B00DQST + (i * 0x10) + 0, channeldll);
1010 mchbar_write32(C1R0B00DQST + (i * 0x10) + 4, channeldll);
Julius Wernercd49cce2019-03-05 16:53:33 -08001011 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Angel Pons1d4044a2021-03-27 19:11:51 +01001012 mchbar_write8(C0R0B00DQST + (i * 0x10) + 8, channeldll & 0xff);
1013 mchbar_write8(C1R0B00DQST + (i * 0x10) + 8, channeldll & 0xff);
Paul Menzelbce7e332017-02-22 18:46:27 +01001014 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001015 }
1016}
1017
1018static void sdram_force_rcomp(void)
1019{
1020 u32 reg32;
1021 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001022
Angel Pons1d4044a2021-03-27 19:11:51 +01001023 reg32 = mchbar_read32(ODTC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001024 reg32 |= (1 << 28);
Angel Pons1d4044a2021-03-27 19:11:51 +01001025 mchbar_write32(ODTC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001026
Angel Pons1d4044a2021-03-27 19:11:51 +01001027 reg32 = mchbar_read32(SMSRCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001028 reg32 |= (1 << 0);
Angel Pons1d4044a2021-03-27 19:11:51 +01001029 mchbar_write32(SMSRCTL, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001030
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001031 /* Start initial RCOMP */
Angel Pons1d4044a2021-03-27 19:11:51 +01001032 reg32 = mchbar_read32(GBRCOMPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001033 reg32 |= (1 << 8);
Angel Pons1d4044a2021-03-27 19:11:51 +01001034 mchbar_write32(GBRCOMPCTL, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001035
1036 reg8 = i945_silicon_revision();
Angel Pons1d4044a2021-03-27 19:11:51 +01001037 if ((reg8 == 0 && (mchbar_read32(DCC) & (3 << 0)) == 0) || (reg8 == 1)) {
1038 reg32 = mchbar_read32(GBRCOMPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001039 reg32 |= (3 << 5);
Angel Pons1d4044a2021-03-27 19:11:51 +01001040 mchbar_write32(GBRCOMPCTL, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001041 }
1042}
1043
1044static void sdram_initialize_system_memory_io(struct sys_info *sysinfo)
1045{
1046 u8 reg8;
1047 u32 reg32;
1048
Elyes HAOUAS38424982016-08-21 12:01:04 +02001049 printk(BIOS_DEBUG, "Initializing System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001050 /* Enable Data Half Clock Pushout */
Angel Pons1d4044a2021-03-27 19:11:51 +01001051 reg8 = mchbar_read8(C0HCTC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001052 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001053 reg8 |= (1 << 0);
Angel Pons1d4044a2021-03-27 19:11:51 +01001054 mchbar_write8(C0HCTC, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001055
Angel Pons1d4044a2021-03-27 19:11:51 +01001056 reg8 = mchbar_read8(C1HCTC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001057 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001058 reg8 |= (1 << 0);
Angel Pons1d4044a2021-03-27 19:11:51 +01001059 mchbar_write8(C1HCTC, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001060
Angel Pons1d4044a2021-03-27 19:11:51 +01001061 mchbar_clrbits16(WDLLBYPMODE, 1 << 9 | 1 << 6 | 1 << 4 | 1 << 3 | 1 << 1);
1062 mchbar_setbits16(WDLLBYPMODE, 1 << 8 | 1 << 7 | 1 << 5 | 1 << 2 | 1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001063
Angel Pons1d4044a2021-03-27 19:11:51 +01001064 mchbar_write8(C0WDLLCMC, 0);
1065 mchbar_write8(C1WDLLCMC, 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001066
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001067 /* Program RCOMP Settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001068 sdram_program_dram_width(sysinfo);
1069
1070 sdram_rcomp_buffer_strength_and_slew(sysinfo);
1071
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001072 /* Indicate that RCOMP programming is done */
Angel Pons1d4044a2021-03-27 19:11:51 +01001073 reg32 = mchbar_read32(GBRCOMPCTL);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001074 reg32 &= ~((1 << 29) | (1 << 26) | (3 << 21) | (3 << 2));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001075 reg32 |= (3 << 27) | (3 << 0);
Angel Pons1d4044a2021-03-27 19:11:51 +01001076 mchbar_write32(GBRCOMPCTL, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001077
Angel Pons1d4044a2021-03-27 19:11:51 +01001078 mchbar_setbits32(GBRCOMPCTL, 1 << 10);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001079
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001080 /* Program DLL Timings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001081 sdram_program_dll_timings(sysinfo);
1082
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001083 /* Force RCOMP cycle */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001084 sdram_force_rcomp();
1085}
1086
1087static void sdram_enable_system_memory_io(struct sys_info *sysinfo)
1088{
1089 u32 reg32;
1090
Elyes HAOUAS38424982016-08-21 12:01:04 +02001091 printk(BIOS_DEBUG, "Enabling System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001092
Angel Pons1d4044a2021-03-27 19:11:51 +01001093 reg32 = mchbar_read32(RCVENMT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001094 reg32 &= ~(0x3f << 6);
Angel Pons1d4044a2021-03-27 19:11:51 +01001095 mchbar_write32(RCVENMT, reg32); /* [11:6] = 0 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001096
1097 reg32 |= (1 << 11) | (1 << 9);
Angel Pons1d4044a2021-03-27 19:11:51 +01001098 mchbar_write32(RCVENMT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001099
Angel Pons1d4044a2021-03-27 19:11:51 +01001100 reg32 = mchbar_read32(DRTST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001101 reg32 |= (1 << 3) | (1 << 2);
Angel Pons1d4044a2021-03-27 19:11:51 +01001102 mchbar_write32(DRTST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001103
Angel Pons1d4044a2021-03-27 19:11:51 +01001104 reg32 = mchbar_read32(DRTST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001105 reg32 |= (1 << 6) | (1 << 4);
Angel Pons1d4044a2021-03-27 19:11:51 +01001106 mchbar_write32(DRTST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001107
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001108 asm volatile ("nop; nop;" ::: "memory");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001109
Angel Pons1d4044a2021-03-27 19:11:51 +01001110 reg32 = mchbar_read32(DRTST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001111
1112 /* Is channel 0 populated? */
1113 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001114 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001115 reg32 |= (1 << 7) | (1 << 5);
1116 else
1117 reg32 |= (1 << 31);
1118
1119 /* Is channel 1 populated? */
1120 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001121 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001122 reg32 |= (1 << 9) | (1 << 8);
1123 else
1124 reg32 |= (1 << 30);
1125
Angel Pons1d4044a2021-03-27 19:11:51 +01001126 mchbar_write32(DRTST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001127
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001128 /* Activate DRAM Channel IO Buffers */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001129 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001130 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) {
Angel Pons1d4044a2021-03-27 19:11:51 +01001131 reg32 = mchbar_read32(C0DRC1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001132 reg32 |= (1 << 8);
Angel Pons1d4044a2021-03-27 19:11:51 +01001133 mchbar_write32(C0DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001134 }
1135 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001136 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED) {
Angel Pons1d4044a2021-03-27 19:11:51 +01001137 reg32 = mchbar_read32(C1DRC1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001138 reg32 |= (1 << 8);
Angel Pons1d4044a2021-03-27 19:11:51 +01001139 mchbar_write32(C1DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001140 }
1141}
1142
Stefan Reinauer278534d2008-10-29 04:51:07 +00001143static int sdram_program_row_boundaries(struct sys_info *sysinfo)
1144{
1145 int i;
Elyes Haouas26fc2a42022-10-07 11:25:25 +02001146 size_t cum0, cum1, tolud, tom, pci_mmio_size;
Arthur Heymans885c2892016-10-03 17:16:48 +02001147 const struct device *dev;
1148 const struct northbridge_intel_i945_config *cfg = NULL;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001149
Paul Menzel84283bc2014-07-17 08:16:04 +02001150 printk(BIOS_DEBUG, "Setting RAM size...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001151
1152 cum0 = 0;
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001153 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001154 cum0 += sysinfo->banksize[i];
Angel Pons1d4044a2021-03-27 19:11:51 +01001155 mchbar_write8(C0DRB0 + i, cum0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001156 }
1157
1158 /* Assume we continue in Channel 1 where we stopped in Channel 0 */
1159 cum1 = cum0;
1160
1161 /* Exception: Interleaved starts from the beginning */
1162 if (sysinfo->interleaved)
1163 cum1 = 0;
1164
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001165 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001166 cum1 += sysinfo->banksize[i + 4];
Angel Pons1d4044a2021-03-27 19:11:51 +01001167 mchbar_write8(C1DRB0 + i, cum1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001168 }
1169
1170 /* Set TOLUD Top Of Low Usable DRAM */
1171 if (sysinfo->interleaved)
1172 tolud = (cum0 + cum1) << 1;
1173 else
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001174 tolud = (cum1 ? cum1 : cum0) << 1;
Stefan Reinauer779b3e32008-11-10 15:43:37 +00001175
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001176 /* The TOM register has a different format */
1177 tom = tolud >> 3;
1178
1179 /* Limit the value of TOLUD to leave some space for PCI memory. */
Kyösti Mälkkic70eed12018-05-22 02:18:00 +03001180 dev = pcidev_on_root(0, 0);
Arthur Heymans885c2892016-10-03 17:16:48 +02001181 if (dev)
1182 cfg = dev->chip_info;
1183
1184 /* Don't use pci mmio sizes smaller than 768M */
1185 if (!cfg || cfg->pci_mmio_size <= DEFAULT_PCI_MMIO_SIZE)
1186 pci_mmio_size = DEFAULT_PCI_MMIO_SIZE;
1187 else
1188 pci_mmio_size = cfg->pci_mmio_size;
1189
1190 tolud = MIN(((4096 - pci_mmio_size) / 128) << 3, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001191
Angel Pons3580d812020-06-11 14:13:33 +02001192 pci_write_config8(HOST_BRIDGE, TOLUD, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001193
Angel Pons1d4044a2021-03-27 19:11:51 +01001194 printk(BIOS_DEBUG, "C0DRB = 0x%08x\n", mchbar_read32(C0DRB0));
1195 printk(BIOS_DEBUG, "C1DRB = 0x%08x\n", mchbar_read32(C1DRB0));
Angel Pons3580d812020-06-11 14:13:33 +02001196 printk(BIOS_DEBUG, "TOLUD = 0x%04x\n", pci_read_config8(HOST_BRIDGE, TOLUD));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001197
Angel Pons3580d812020-06-11 14:13:33 +02001198 pci_write_config16(HOST_BRIDGE, TOM, tom);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001199
1200 return 0;
1201}
1202
Stefan Reinauer278534d2008-10-29 04:51:07 +00001203static int sdram_set_row_attributes(struct sys_info *sysinfo)
1204{
Arthur Heymans0ab49042017-02-06 22:40:14 +01001205 int i;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001206 u16 dra0 = 0, dra1 = 0, dra = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001207
Elyes HAOUAS38424982016-08-21 12:01:04 +02001208 printk(BIOS_DEBUG, "Setting row attributes...\n");
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001209 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001210 u8 columnsrows;
1211
Arthur Heymans70a8e342017-03-09 11:30:23 +01001212 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001213 continue;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001214
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001215 columnsrows = (sysinfo->rows[i] & 0x0f) | (sysinfo->cols[i] & 0xf) << 4;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001216
1217 switch (columnsrows) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001218 case 0x9d:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001219 dra = 2;
1220 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001221 case 0xad:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001222 dra = 3;
1223 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001224 case 0xbd:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001225 dra = 4;
1226 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001227 case 0xae:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001228 dra = 3;
1229 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001230 case 0xbe:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001231 dra = 4;
1232 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001233 default:
1234 die("Unsupported Rows/Columns. (DRA)");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001235 }
1236
1237 /* Double Sided DIMMs? */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001238 if (sysinfo->banksize[(2 * i) + 1] != 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001239 dra = (dra << 4) | dra;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001240
Stefan Reinauer278534d2008-10-29 04:51:07 +00001241 if (i < DIMM_SOCKETS)
Angel Pons30492572020-06-11 13:24:54 +02001242 dra0 |= (dra << (i * 8));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001243 else
Angel Pons30492572020-06-11 13:24:54 +02001244 dra1 |= (dra << ((i - DIMM_SOCKETS) * 8));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001245 }
1246
Angel Pons1d4044a2021-03-27 19:11:51 +01001247 mchbar_write16(C0DRA0, dra0);
1248 mchbar_write16(C1DRA0, dra1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001249
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001250 printk(BIOS_DEBUG, "C0DRA = 0x%04x\n", dra0);
1251 printk(BIOS_DEBUG, "C1DRA = 0x%04x\n", dra1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001252
1253 return 0;
1254}
1255
1256static void sdram_set_bank_architecture(struct sys_info *sysinfo)
1257{
1258 u32 off32;
1259 int i;
1260
Angel Pons1d4044a2021-03-27 19:11:51 +01001261 mchbar_clrbits16(C1BNKARC, 0xff);
1262 mchbar_clrbits16(C0BNKARC, 0xff);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001263
1264 off32 = C0BNKARC;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001265 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001266 /* Switch to second channel */
1267 if (i == DIMM_SOCKETS)
1268 off32 = C1BNKARC;
1269
1270 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
1271 continue;
1272
1273 if (sysinfo->banks[i] != 8)
1274 continue;
1275
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001276 printk(BIOS_SPEW, "DIMM%d has 8 banks.\n", i);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001277
1278 if (i & 1)
Angel Pons1d4044a2021-03-27 19:11:51 +01001279 mchbar_setbits16(off32, 5 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001280 else
Angel Pons1d4044a2021-03-27 19:11:51 +01001281 mchbar_setbits16(off32, 5 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001282 }
1283}
1284
Stefan Reinauer278534d2008-10-29 04:51:07 +00001285static void sdram_program_refresh_rate(struct sys_info *sysinfo)
1286{
1287 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001288
Arthur Heymans70a8e342017-03-09 11:30:23 +01001289 if (sysinfo->refresh == REFRESH_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001290 reg32 = (2 << 8); /* Refresh enabled at 7.8us */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001291 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001292 reg32 = (1 << 8); /* Refresh enabled at 15.6us */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001293
Angel Pons1d4044a2021-03-27 19:11:51 +01001294 mchbar_clrbits32(C0DRC0, 7 << 8);
1295 mchbar_setbits32(C0DRC0, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001296
Angel Pons1d4044a2021-03-27 19:11:51 +01001297 mchbar_clrbits32(C1DRC0, 7 << 8);
1298 mchbar_setbits32(C1DRC0, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001299}
1300
1301static void sdram_program_cke_tristate(struct sys_info *sysinfo)
1302{
1303 u32 reg32;
1304 int i;
1305
Angel Pons1d4044a2021-03-27 19:11:51 +01001306 reg32 = mchbar_read32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001307
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001308 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001309 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001310 reg32 |= (1 << (16 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001311 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001312
Stefan Reinauer278534d2008-10-29 04:51:07 +00001313 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001314
Stefan Reinauer278534d2008-10-29 04:51:07 +00001315 reg32 |= (1 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01001316 mchbar_write32(C0DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001317
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001318 /* Do we have to do this if we're in Single Channel Mode? */
Angel Pons1d4044a2021-03-27 19:11:51 +01001319 reg32 = mchbar_read32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001320
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001321 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001322 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001323 reg32 |= (1 << (12 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001324 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001325
Stefan Reinauer278534d2008-10-29 04:51:07 +00001326 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001327
Stefan Reinauer278534d2008-10-29 04:51:07 +00001328 reg32 |= (1 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01001329 mchbar_write32(C1DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001330}
1331
1332static void sdram_program_odt_tristate(struct sys_info *sysinfo)
1333{
1334 u32 reg32;
1335 int i;
1336
Angel Pons1d4044a2021-03-27 19:11:51 +01001337 reg32 = mchbar_read32(C0DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001338
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001339 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001340 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001341 reg32 |= (1 << (24 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001342 }
Angel Pons1d4044a2021-03-27 19:11:51 +01001343 mchbar_write32(C0DRC2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001344
Angel Pons1d4044a2021-03-27 19:11:51 +01001345 reg32 = mchbar_read32(C1DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001346
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001347 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001348 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001349 reg32 |= (1 << (20 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001350 }
Angel Pons1d4044a2021-03-27 19:11:51 +01001351 mchbar_write32(C1DRC2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001352}
1353
1354static void sdram_set_timing_and_control(struct sys_info *sysinfo)
1355{
Arthur Heymans25027232017-02-12 23:34:39 +01001356 u32 reg32, tRD_min;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001357 u32 tWTR;
1358 u32 temp_drt;
1359 int i, page_size;
1360
Edward O'Callaghan2f237c12014-05-25 06:24:39 +10001361 static const u8 cas_table[] = {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001362 2, 1, 0, 3
1363 };
1364
Angel Pons1d4044a2021-03-27 19:11:51 +01001365 reg32 = mchbar_read32(C0DRC0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001366 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001367 reg32 &= ~((1 << 13) | (1 << 12));
Angel Pons1d4044a2021-03-27 19:11:51 +01001368 mchbar_write32(C0DRC0, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001369
Angel Pons1d4044a2021-03-27 19:11:51 +01001370 reg32 = mchbar_read32(C1DRC0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001371 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001372 reg32 &= ~((1 << 13) | (1 << 12));
Angel Pons1d4044a2021-03-27 19:11:51 +01001373 mchbar_write32(C1DRC0, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001374
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001375 if (!sysinfo->dual_channel && sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) {
Angel Pons1d4044a2021-03-27 19:11:51 +01001376 reg32 = mchbar_read32(C0DRC0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001377 reg32 |= (1 << 15);
Angel Pons1d4044a2021-03-27 19:11:51 +01001378 mchbar_write32(C0DRC0, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001379 }
1380
1381 sdram_program_refresh_rate(sysinfo);
1382
1383 sdram_program_cke_tristate(sysinfo);
1384
1385 sdram_program_odt_tristate(sysinfo);
1386
1387 /* Calculate DRT0 */
1388
1389 temp_drt = 0;
1390
1391 /* B2B Write Precharge (same bank) = CL-1 + BL/2 + tWR */
1392 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + sysinfo->twr;
1393 temp_drt |= (reg32 << 28);
1394
1395 /* Write Auto Precharge (same bank) = CL-1 + BL/2 + tWR + tRP */
1396 reg32 += sysinfo->trp;
1397 temp_drt |= (reg32 << 4);
1398
Arthur Heymans70a8e342017-03-09 11:30:23 +01001399 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001400 tWTR = 3; /* 667MHz */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001401 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001402 tWTR = 2; /* 400 and 533 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001403
1404 /* B2B Write to Read Command Spacing */
1405 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + tWTR;
1406 temp_drt |= (reg32 << 24);
1407
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001408 /* CxDRT0 [23:22], [21:20], [19:18] [16] have fixed values */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001409 temp_drt |= ((1 << 22) | (3 << 20) | (1 << 18) | (0 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001410
Arthur Heymans25027232017-02-12 23:34:39 +01001411 /*
1412 * tRD is the delay the memory controller is waiting on the FSB,
1413 * in mclk domain.
1414 * This parameter is important for stability and performance.
1415 * Those values might not be optimal but seem stable.
1416 */
1417 tRD_min = sysinfo->cas;
Arthur Heymanse1897612016-10-15 23:29:18 +02001418 switch (sysinfo->fsb_frequency) {
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001419 case 533:
Arthur Heymanse1897612016-10-15 23:29:18 +02001420 break;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001421 case 667:
1422 tRD_min += 1;
Arthur Heymanse1897612016-10-15 23:29:18 +02001423 break;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001424 case 800:
1425 tRD_min += 2;
1426 break;
1427 case 1066:
1428 tRD_min += 3;
Arthur Heymanse1897612016-10-15 23:29:18 +02001429 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001430 }
Arthur Heymanse1897612016-10-15 23:29:18 +02001431
Arthur Heymans25027232017-02-12 23:34:39 +01001432 temp_drt |= (tRD_min << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001433
1434 /* Read Auto Precharge to Activate */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001435
Stefan Reinauer278534d2008-10-29 04:51:07 +00001436 temp_drt |= (8 << 0);
1437
Angel Pons1d4044a2021-03-27 19:11:51 +01001438 mchbar_write32(C0DRT0, temp_drt);
1439 mchbar_write32(C1DRT0, temp_drt);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001440
1441 /* Calculate DRT1 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001442
Angel Pons1d4044a2021-03-27 19:11:51 +01001443 temp_drt = mchbar_read32(C0DRT1) & 0x00020088;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001444
1445 /* DRAM RASB Precharge */
1446 temp_drt |= (sysinfo->trp - 2) << 0;
1447
1448 /* DRAM RASB to CASB Delay */
1449 temp_drt |= (sysinfo->trcd - 2) << 4;
1450
1451 /* CASB Latency */
1452 temp_drt |= (cas_table[sysinfo->cas - 3]) << 8;
1453
1454 /* Refresh Cycle Time */
1455 temp_drt |= (sysinfo->trfc) << 10;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001456
Stefan Reinauer278534d2008-10-29 04:51:07 +00001457 /* Pre-All to Activate Delay */
1458 temp_drt |= (0 << 16);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001459
Stefan Reinauer278534d2008-10-29 04:51:07 +00001460 /* Precharge to Precharge Delay stays at 1 clock */
1461 temp_drt |= (0 << 18);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001462
Stefan Reinauer278534d2008-10-29 04:51:07 +00001463 /* Activate to Precharge Delay */
1464 temp_drt |= (sysinfo->tras << 19);
1465
1466 /* Read to Precharge (tRTP) */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001467 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001468 temp_drt |= (1 << 28);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001469 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001470 temp_drt |= (0 << 28);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001471
1472 /* Determine page size */
1473 reg32 = 0;
1474 page_size = 1; /* Default: 1k pagesize */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001475 for (i = 0; i < 2*DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001476 if (sysinfo->dimm[i] == SYSINFO_DIMM_X16DS ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001477 sysinfo->dimm[i] == SYSINFO_DIMM_X16SS)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001478 page_size = 2; /* 2k pagesize */
1479 }
1480
Arthur Heymans70a8e342017-03-09 11:30:23 +01001481 if (sysinfo->memory_frequency == 533 && page_size == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001482 reg32 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001483 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001484 reg32 = page_size;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001485
Stefan Reinauer278534d2008-10-29 04:51:07 +00001486 temp_drt |= (reg32 << 30);
1487
Angel Pons1d4044a2021-03-27 19:11:51 +01001488 mchbar_write32(C0DRT1, temp_drt);
1489 mchbar_write32(C1DRT1, temp_drt);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001490
1491 /* Program DRT2 */
Angel Pons1d4044a2021-03-27 19:11:51 +01001492 reg32 = mchbar_read32(C0DRT2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001493 reg32 &= ~(1 << 8);
Angel Pons1d4044a2021-03-27 19:11:51 +01001494 mchbar_write32(C0DRT2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001495
Angel Pons1d4044a2021-03-27 19:11:51 +01001496 reg32 = mchbar_read32(C1DRT2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001497 reg32 &= ~(1 << 8);
Angel Pons1d4044a2021-03-27 19:11:51 +01001498 mchbar_write32(C1DRT2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001499
1500 /* Calculate DRT3 */
Angel Pons1d4044a2021-03-27 19:11:51 +01001501 temp_drt = mchbar_read32(C0DRT3) & ~0x07ffffff;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001502
1503 /* Get old tRFC value */
Angel Pons1d4044a2021-03-27 19:11:51 +01001504 reg32 = mchbar_read32(C0DRT1) >> 10;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001505 reg32 &= 0x3f;
1506
1507 /* 788nS - tRFC */
1508 switch (sysinfo->memory_frequency) {
1509 case 400: /* 5nS */
1510 reg32 = ((78800 / 500) - reg32) & 0x1ff;
1511 reg32 |= (0x8c << 16) | (0x0c << 10); /* 1 us */
1512 break;
1513 case 533: /* 3.75nS */
1514 reg32 = ((78800 / 375) - reg32) & 0x1ff;
1515 reg32 |= (0xba << 16) | (0x10 << 10); /* 1 us */
1516 break;
1517 case 667: /* 3nS */
1518 reg32 = ((78800 / 300) - reg32) & 0x1ff;
1519 reg32 |= (0xe9 << 16) | (0x14 << 10); /* 1 us */
1520 break;
1521 }
1522
1523 temp_drt |= reg32;
1524
Angel Pons1d4044a2021-03-27 19:11:51 +01001525 mchbar_write32(C0DRT3, temp_drt);
1526 mchbar_write32(C1DRT3, temp_drt);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001527}
1528
1529static void sdram_set_channel_mode(struct sys_info *sysinfo)
1530{
1531 u32 reg32;
1532
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001533 printk(BIOS_DEBUG, "Setting mode of operation for memory channels...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001534
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001535 if (sdram_capabilities_interleave() &&
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001536 ((sysinfo->banksize[0] + sysinfo->banksize[1] +
1537 sysinfo->banksize[2] + sysinfo->banksize[3]) ==
1538 (sysinfo->banksize[4] + sysinfo->banksize[5] +
1539 sysinfo->banksize[6] + sysinfo->banksize[7]))) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001540 /* Both channels equipped with DIMMs of the same size */
Elyes Haouas49446092022-09-28 14:14:05 +02001541 sysinfo->interleaved = true;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001542 } else {
Elyes Haouas49446092022-09-28 14:14:05 +02001543 sysinfo->interleaved = false;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001544 }
1545
Angel Pons1d4044a2021-03-27 19:11:51 +01001546 reg32 = mchbar_read32(DCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001547 reg32 &= ~(7 << 0);
1548
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001549 if (sysinfo->interleaved) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001550 /* Dual Channel Interleaved */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001551 printk(BIOS_DEBUG, "Dual Channel Interleaved.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001552 reg32 |= (1 << 1);
1553 } else if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001554 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001555 /* Channel 1 only */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001556 printk(BIOS_DEBUG, "Single Channel 1 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001557 reg32 |= (1 << 2);
Elyes HAOUAS75da1fb2017-02-16 18:59:13 +01001558 } else if (sdram_capabilities_dual_channel() &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001559 (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1560 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) {
Martin Roth128c1042016-11-18 09:29:03 -07001561 /* Dual Channel Asymmetric */
1562 printk(BIOS_DEBUG, "Dual Channel Asymmetric.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001563 reg32 |= (1 << 0);
1564 } else {
1565 /* All bits 0 means Single Channel 0 operation */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001566 printk(BIOS_DEBUG, "Single Channel 0 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001567 }
1568
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001569 /* Now disable channel XORing */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001570 reg32 |= (1 << 10);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001571
Angel Pons1d4044a2021-03-27 19:11:51 +01001572 mchbar_write32(DCC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001573
Angel Pons1d4044a2021-03-27 19:11:51 +01001574 PRINTK_DEBUG("DCC = 0x%08x\n", mchbar_read32(DCC));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001575}
1576
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001577static void sdram_program_pll_settings(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001578{
Angel Pons1d4044a2021-03-27 19:11:51 +01001579 mchbar_write32(PLLMON, 0x80800000);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001580
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001581 sysinfo->fsb_frequency = fsbclk();
Peter Stuge76d91432010-10-01 10:02:33 +00001582 if (sysinfo->fsb_frequency == 0xffff)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001583 die("Unsupported FSB speed");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001584
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001585 /* Program CPCTL according to FSB speed */
1586 /* Only write the lower byte */
1587 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001588 case 400:
Angel Pons1d4044a2021-03-27 19:11:51 +01001589 mchbar_write8(CPCTL, 0x90);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001590 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001591 case 533:
Angel Pons1d4044a2021-03-27 19:11:51 +01001592 mchbar_write8(CPCTL, 0x95);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001593 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001594 case 667:
Angel Pons1d4044a2021-03-27 19:11:51 +01001595 mchbar_write8(CPCTL, 0x8d);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001596 break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001597 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001598
Angel Pons1d4044a2021-03-27 19:11:51 +01001599 mchbar_clrbits16(CPCTL, 1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001600
Angel Pons1d4044a2021-03-27 19:11:51 +01001601 mchbar_read16(CPCTL); /* Read back register to activate settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001602}
1603
1604static void sdram_program_graphics_frequency(struct sys_info *sysinfo)
1605{
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001606 u8 reg8;
Elyes Haouasd9dade32022-10-07 12:05:38 +02001607 u8 freq, voltage;
1608 bool second_vco = false;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001609
1610#define CRCLK_166MHz 0x00
1611#define CRCLK_200MHz 0x01
1612#define CRCLK_250MHz 0x03
1613#define CRCLK_400MHz 0x05
1614
1615#define CDCLK_200MHz 0x00
1616#define CDCLK_320MHz 0x40
1617
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001618#define VOLTAGE_1_05 0x00
1619#define VOLTAGE_1_50 0x01
1620
Paul Menzeldaf9e502014-07-15 23:49:16 +02001621 printk(BIOS_DEBUG, "Setting Graphics Frequency...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001622
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001623 printk(BIOS_DEBUG, "FSB: %d MHz ", sysinfo->fsb_frequency);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001624
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001625 voltage = VOLTAGE_1_05;
Angel Pons1d4044a2021-03-27 19:11:51 +01001626 if (mchbar_read32(DFT_STRAP1) & (1 << 20))
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001627 voltage = VOLTAGE_1_50;
Angel Pons30492572020-06-11 13:24:54 +02001628 printk(BIOS_DEBUG, "Voltage: %s ", (voltage == VOLTAGE_1_05) ? "1.05V" : "1.5V");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001629
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001630 /* Gate graphics hardware for frequency change */
Angel Pons30492572020-06-11 13:24:54 +02001631 reg8 = (1 << 3) | (1 << 1); /* disable crclk, gate cdclk */
Angel Pons3580d812020-06-11 14:13:33 +02001632 pci_write_config8(IGD_DEV, GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001633
1634 /* Get graphics frequency capabilities */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001635 reg8 = sdram_capabilities_core_frequencies();
1636
Stefan Reinauer278534d2008-10-29 04:51:07 +00001637 freq = CRCLK_250MHz;
1638 switch (reg8) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001639 case GFX_FREQUENCY_CAP_ALL:
1640 if (voltage == VOLTAGE_1_05)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001641 freq = CRCLK_250MHz;
1642 else
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001643 freq = CRCLK_400MHz; /* 1.5V requires 400MHz */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001644 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001645 case GFX_FREQUENCY_CAP_250MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001646 freq = CRCLK_250MHz;
1647 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001648 case GFX_FREQUENCY_CAP_200MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001649 freq = CRCLK_200MHz;
1650 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001651 case GFX_FREQUENCY_CAP_166MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001652 freq = CRCLK_166MHz;
1653 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001654 }
1655
1656 if (freq != CRCLK_400MHz) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001657 /* What chipset are we? Force 166MHz for GMS */
Angel Pons3580d812020-06-11 14:13:33 +02001658 reg8 = (pci_read_config8(HOST_BRIDGE, 0xe7) & 0x70) >> 4;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001659 if (reg8 == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001660 freq = CRCLK_166MHz;
1661 }
1662
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001663 printk(BIOS_DEBUG, "Render: ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001664 switch (freq) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001665 case CRCLK_166MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001666 printk(BIOS_DEBUG, "166MHz");
1667 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001668 case CRCLK_200MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001669 printk(BIOS_DEBUG, "200MHz");
1670 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001671 case CRCLK_250MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001672 printk(BIOS_DEBUG, "250MHz");
1673 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001674 case CRCLK_400MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001675 printk(BIOS_DEBUG, "400MHz");
1676 break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001677 }
1678
Arthur Heymans70a8e342017-03-09 11:30:23 +01001679 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001680 sysinfo->mvco4x = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001681 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001682 sysinfo->mvco4x = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001683
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001684 if (voltage == VOLTAGE_1_50) {
Elyes Haouasd9dade32022-10-07 12:05:38 +02001685 second_vco = true;
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)) {
Elyes Haouasd9dade32022-10-07 12:05:38 +02001693 second_vco = true;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001694 }
1695
1696 if (fsb == 667 && mem == 533)
1697 sysinfo->mvco4x = 1;
1698 }
1699
Elyes Haouasd9dade32022-10-07 12:05:38 +02001700 sysinfo->clkcfg_bit7 = second_vco;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001701
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001702 /* Graphics Core Render Clock */
Angel Pons3580d812020-06-11 14:13:33 +02001703 pci_update_config16(IGD_DEV, GCFC, ~((7 << 0) | (1 << 13)), freq);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001704
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001705 /* Graphics Core Display Clock */
Angel Pons3580d812020-06-11 14:13:33 +02001706 reg8 = pci_read_config8(IGD_DEV, GCFC);
Angel Ponse3c68d22020-06-08 12:09:03 +02001707 reg8 &= ~((1 << 7) | (7 << 4));
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001708
1709 if (voltage == VOLTAGE_1_05) {
1710 reg8 |= CDCLK_200MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001711 printk(BIOS_DEBUG, " Display: 200MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001712 } else {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001713 reg8 |= CDCLK_320MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001714 printk(BIOS_DEBUG, " Display: 320MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001715 }
Angel Pons3580d812020-06-11 14:13:33 +02001716 pci_write_config8(IGD_DEV, GCFC, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001717
Angel Pons3580d812020-06-11 14:13:33 +02001718 reg8 = pci_read_config8(IGD_DEV, GCFC + 1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001719
Angel Ponse3c68d22020-06-08 12:09:03 +02001720 reg8 |= (1 << 3) | (1 << 1);
Angel Pons3580d812020-06-11 14:13:33 +02001721 pci_write_config8(IGD_DEV, GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001722
1723 reg8 |= 0x0f;
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 /* Ungate core render and display clocks */
1727 reg8 &= 0xf0;
Angel Pons3580d812020-06-11 14:13:33 +02001728 pci_write_config8(IGD_DEV, GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001729}
1730
1731static void sdram_program_memory_frequency(struct sys_info *sysinfo)
1732{
1733 u32 clkcfg;
Julius Wernercd49cce2019-03-05 16:53:33 -08001734 u8 offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001735
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001736 printk(BIOS_DEBUG, "Setting Memory Frequency... ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001737
Angel Pons1d4044a2021-03-27 19:11:51 +01001738 clkcfg = mchbar_read32(CLKCFG);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001739
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001740 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001741
Arthur Heymans70a8e342017-03-09 11:30:23 +01001742 clkcfg &= ~((1 << 12) | (1 << 7) | (7 << 4));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001743
1744 if (sysinfo->mvco4x) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001745 printk(BIOS_DEBUG, "MVCO 4x, ");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001746 clkcfg &= ~(1 << 12);
1747 }
1748
1749 if (sysinfo->clkcfg_bit7) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001750 printk(BIOS_DEBUG, "second VCO, ");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001751 clkcfg |= (1 << 7);
1752 }
1753
1754 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001755 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001756 clkcfg |= ((1 + offset) << 4);
1757 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001758 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001759 clkcfg |= ((2 + offset) << 4);
1760 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001761 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001762 clkcfg |= ((3 + offset) << 4);
1763 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001764 default:
1765 die("Target Memory Frequency Error");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001766 }
1767
Angel Pons1d4044a2021-03-27 19:11:51 +01001768 if (mchbar_read32(CLKCFG) == clkcfg) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001769 printk(BIOS_DEBUG, "ok (unchanged)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001770 return;
1771 }
1772
Angel Pons1d4044a2021-03-27 19:11:51 +01001773 mchbar_write32(CLKCFG, clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001774
Petr Cveke75bb012022-06-16 17:13:22 +02001775 /*
1776 * Make sure the following code is in the cache before we execute it.
1777 * TODO: Experiments (i945GM) without any cache_code/delay_update
1778 * _seem_ to work even when XIP is disabled. Also on Pentium 4
1779 * the code is not cached at all by default.
1780 */
1781 asm volatile (
1782 " jmp cache_code\n"
1783 "vco_update:\n"
1784 : /* No outputs */
1785 : /* No inputs */
1786 : "memory"
1787 );
1788
Angel Ponse3c68d22020-06-08 12:09:03 +02001789 pci_and_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, (u8)~(1 << 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001790
Stefan Reinauer278534d2008-10-29 04:51:07 +00001791 clkcfg &= ~(1 << 10);
Angel Pons1d4044a2021-03-27 19:11:51 +01001792 mchbar_write32(CLKCFG, clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001793 clkcfg |= (1 << 10);
Angel Pons1d4044a2021-03-27 19:11:51 +01001794 mchbar_write32(CLKCFG, clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001795
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001796 asm volatile (
Stefan Reinauer278534d2008-10-29 04:51:07 +00001797 " movl $0x100, %%ecx\n"
1798 "delay_update:\n"
1799 " nop\n"
1800 " nop\n"
1801 " nop\n"
1802 " nop\n"
1803 " loop delay_update\n"
1804 : /* No outputs */
1805 : /* No inputs */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001806 : "%ecx", "memory"
Stefan Reinauer278534d2008-10-29 04:51:07 +00001807 );
1808
Stefan Reinauer278534d2008-10-29 04:51:07 +00001809 clkcfg &= ~(1 << 10);
Angel Pons1d4044a2021-03-27 19:11:51 +01001810 mchbar_write32(CLKCFG, clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001811
Petr Cveke75bb012022-06-16 17:13:22 +02001812 asm volatile (
1813 " jmp out\n"
1814 "cache_code:\n"
1815 " jmp vco_update\n"
1816 "out:\n"
1817 : /* No outputs */
1818 : /* No inputs */
1819 : "memory"
1820 );
Stefan Reinauer278534d2008-10-29 04:51:07 +00001821
Angel Pons1d4044a2021-03-27 19:11:51 +01001822 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", mchbar_read32(CLKCFG));
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001823 printk(BIOS_DEBUG, "ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001824}
1825
1826static void sdram_program_clock_crossing(void)
1827{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001828 int idx = 0;
1829
1830 /**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001831 * We add the indices according to our clocks from CLKCFG.
Stefan Reinauer278534d2008-10-29 04:51:07 +00001832 */
Julius Wernercd49cce2019-03-05 16:53:33 -08001833#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001834 static const u32 data_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001835 0x00100401, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001836 0xffffffff, 0xffffffff, /* nonexistent */
1837 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001838
Stefan Reinauer278534d2008-10-29 04:51:07 +00001839 0x08040120, 0x00000000, /* DDR400 FSB533 */
1840 0x00100401, 0x00000000, /* DDR533 FSB533 */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001841 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001842
1843 0x04020120, 0x00000010, /* DDR400 FSB667 */
1844 0x10040280, 0x00000040, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001845 0x00100401, 0x00000000, /* DDR667 FSB667 */
1846
Martin Roth2ed0aa22016-01-05 20:58:58 -07001847 0xffffffff, 0xffffffff, /* nonexistent */
1848 0xffffffff, 0xffffffff, /* nonexistent */
1849 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001850
Martin Roth2ed0aa22016-01-05 20:58:58 -07001851 0xffffffff, 0xffffffff, /* nonexistent */
1852 0xffffffff, 0xffffffff, /* nonexistent */
1853 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001854 };
1855
1856 static const u32 command_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001857 0x04020208, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001858 0xffffffff, 0xffffffff, /* nonexistent */
1859 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001860
Stefan Reinauer278534d2008-10-29 04:51:07 +00001861 0x00060108, 0x00000000, /* DDR400 FSB533 */
1862 0x04020108, 0x00000000, /* DDR533 FSB533 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001863 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001864
1865 0x00040318, 0x00000000, /* DDR400 FSB667 */
1866 0x04020118, 0x00000000, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001867 0x02010804, 0x00000000, /* DDR667 FSB667 */
1868
Martin Roth2ed0aa22016-01-05 20:58:58 -07001869 0xffffffff, 0xffffffff, /* nonexistent */
1870 0xffffffff, 0xffffffff, /* nonexistent */
1871 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001872
Martin Roth2ed0aa22016-01-05 20:58:58 -07001873 0xffffffff, 0xffffffff, /* nonexistent */
1874 0xffffffff, 0xffffffff, /* nonexistent */
1875 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001876 };
1877
Julius Wernercd49cce2019-03-05 16:53:33 -08001878#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001879 /* i945 G/P */
1880 static const u32 data_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001881 0xffffffff, 0xffffffff, /* nonexistent */
1882 0xffffffff, 0xffffffff, /* nonexistent */
1883 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001884
1885 0x10080201, 0x00000000, /* DDR400 FSB533 */
1886 0x00100401, 0x00000000, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001887 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001888
Martin Roth2ed0aa22016-01-05 20:58:58 -07001889 0xffffffff, 0xffffffff, /* nonexistent */
1890 0xffffffff, 0xffffffff, /* nonexistent */
1891 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001892
1893 0x04020108, 0x00000000, /* DDR400 FSB800 */
1894 0x00020108, 0x00000000, /* DDR533 FSB800 */
1895 0x00080201, 0x00000000, /* DDR667 FSB800 */
1896
1897 0x00010402, 0x00000000, /* DDR400 FSB1066 */
1898 0x04020108, 0x00000000, /* DDR533 FSB1066 */
1899 0x08040110, 0x00000000, /* DDR667 FSB1066 */
1900 };
1901
1902 static const u32 command_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001903 0xffffffff, 0xffffffff, /* nonexistent */
1904 0xffffffff, 0xffffffff, /* nonexistent */
1905 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001906
1907 0x00010800, 0x00000402, /* DDR400 FSB533 */
1908 0x01000400, 0x00000200, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001909 0x00020904, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001910
Martin Roth2ed0aa22016-01-05 20:58:58 -07001911 0xffffffff, 0xffffffff, /* nonexistent */
1912 0xffffffff, 0xffffffff, /* nonexistent */
1913 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001914
1915 0x02010804, 0x00000000, /* DDR400 FSB800 */
1916 0x00010402, 0x00000000, /* DDR533 FSB800 */
Arthur Heymans8b6df622016-10-16 10:58:01 +02001917 0x04020130, 0x00000008, /* DDR667 FSB800 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001918
1919 0x00020904, 0x00000000, /* DDR400 FSB1066 */
1920 0x02010804, 0x00000000, /* DDR533 FSB1066 */
1921 0x180601c0, 0x00000020, /* DDR667 FSB1066 */
1922 };
1923#endif
1924
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001925 printk(BIOS_DEBUG, "Programming Clock Crossing...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001926
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001927 printk(BIOS_DEBUG, "MEM=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001928 switch (memclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001929 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001930 printk(BIOS_DEBUG, "400");
1931 idx += 0;
1932 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001933 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001934 printk(BIOS_DEBUG, "533");
1935 idx += 2;
1936 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001937 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001938 printk(BIOS_DEBUG, "667");
1939 idx += 4;
1940 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001941 default:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001942 printk(BIOS_DEBUG, "RSVD %x", memclk());
1943 return;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001944 }
1945
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001946 printk(BIOS_DEBUG, " FSB=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001947 switch (fsbclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001948 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001949 printk(BIOS_DEBUG, "400");
1950 idx += 0;
1951 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001952 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001953 printk(BIOS_DEBUG, "533");
1954 idx += 6;
1955 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001956 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001957 printk(BIOS_DEBUG, "667");
1958 idx += 12;
1959 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001960 case 800:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001961 printk(BIOS_DEBUG, "800");
1962 idx += 18;
1963 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001964 case 1066:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001965 printk(BIOS_DEBUG, "1066");
1966 idx += 24;
1967 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001968 default:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001969 printk(BIOS_DEBUG, "RSVD %x\n", fsbclk());
1970 return;
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001971 }
1972
Arthur Heymans70a8e342017-03-09 11:30:23 +01001973 if (command_clock_crossing[idx] == 0xffffffff)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001974 printk(BIOS_DEBUG, "Invalid MEM/FSB combination!\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001975
Angel Pons1d4044a2021-03-27 19:11:51 +01001976 mchbar_write32(CCCFT + 0, command_clock_crossing[idx]);
1977 mchbar_write32(CCCFT + 4, command_clock_crossing[idx + 1]);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001978
Angel Pons1d4044a2021-03-27 19:11:51 +01001979 mchbar_write32(C0DCCFT + 0, data_clock_crossing[idx]);
1980 mchbar_write32(C0DCCFT + 4, data_clock_crossing[idx + 1]);
1981 mchbar_write32(C1DCCFT + 0, data_clock_crossing[idx]);
1982 mchbar_write32(C1DCCFT + 4, data_clock_crossing[idx + 1]);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001983
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001984 printk(BIOS_DEBUG, "... ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001985}
1986
1987static void sdram_disable_fast_dispatch(void)
1988{
1989 u32 reg32;
1990
Angel Pons1d4044a2021-03-27 19:11:51 +01001991 reg32 = mchbar_read32(FSBPMC3);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001992 reg32 |= (1 << 1);
Angel Pons1d4044a2021-03-27 19:11:51 +01001993 mchbar_write32(FSBPMC3, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001994
Angel Pons1d4044a2021-03-27 19:11:51 +01001995 reg32 = mchbar_read32(SBTEST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001996 reg32 |= (3 << 1);
Angel Pons1d4044a2021-03-27 19:11:51 +01001997 mchbar_write32(SBTEST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001998}
1999
2000static void sdram_pre_jedec_initialization(void)
2001{
2002 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002003
Angel Pons1d4044a2021-03-27 19:11:51 +01002004 reg32 = mchbar_read32(WCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002005 reg32 &= 0x113ff3ff;
2006 reg32 |= (4 << 29) | (3 << 25) | (1 << 10);
Angel Pons1d4044a2021-03-27 19:11:51 +01002007 mchbar_write32(WCC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002008
Angel Pons1d4044a2021-03-27 19:11:51 +01002009 mchbar_setbits32(SMVREFC, 1 << 6);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002010
Angel Pons1d4044a2021-03-27 19:11:51 +01002011 mchbar_clrbits32(MMARB0, 3 << 17);
2012 mchbar_setbits32(MMARB0, 1 << 21 | 1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002013
Angel Pons1d4044a2021-03-27 19:11:51 +01002014 mchbar_clrbits32(MMARB1, 7 << 8);
2015 mchbar_setbits32(MMARB1, 3 << 8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002016
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002017 /* Adaptive Idle Timer Control */
Angel Pons1d4044a2021-03-27 19:11:51 +01002018 mchbar_write32(C0AIT + 0, 0x000006c4);
2019 mchbar_write32(C0AIT + 4, 0x871a066d);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002020
Angel Pons1d4044a2021-03-27 19:11:51 +01002021 mchbar_write32(C1AIT + 0, 0x000006c4);
2022 mchbar_write32(C1AIT + 4, 0x871a066d);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002023}
2024
2025#define EA_DUALCHANNEL_XOR_BANK_RANK_MODE (0xd4 << 24)
2026#define EA_DUALCHANNEL_XOR_BANK_MODE (0xf4 << 24)
2027#define EA_DUALCHANNEL_BANK_RANK_MODE (0xc2 << 24)
2028#define EA_DUALCHANNEL_BANK_MODE (0xe2 << 24)
2029#define EA_SINGLECHANNEL_XOR_BANK_RANK_MODE (0x91 << 24)
2030#define EA_SINGLECHANNEL_XOR_BANK_MODE (0xb1 << 24)
2031#define EA_SINGLECHANNEL_BANK_RANK_MODE (0x80 << 24)
2032#define EA_SINGLECHANNEL_BANK_MODE (0xa0 << 24)
2033
2034static void sdram_enhanced_addressing_mode(struct sys_info *sysinfo)
2035{
2036 u32 chan0 = 0, chan1 = 0;
Paul Menzeld789b6582020-03-14 11:50:34 +01002037 bool chan0_dualsided, chan1_dualsided, chan0_populated, chan1_populated;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002038
Paul Menzel842dd332020-03-14 10:37:40 +01002039 chan0_populated = (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002040 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED);
Elyes HAOUAS308aeff2017-02-24 12:53:07 +01002041 chan1_populated = (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002042 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002043 chan0_dualsided = (sysinfo->banksize[1] || sysinfo->banksize[3]);
2044 chan1_dualsided = (sysinfo->banksize[5] || sysinfo->banksize[7]);
2045
2046 if (sdram_capabilities_enhanced_addressing_xor()) {
2047 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002048 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002049 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002050 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002051 chan0 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002052 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002053 chan0 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002054 }
2055 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002056 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002057 chan1 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002058 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002059 chan1 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002060 }
2061 } else {
2062 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002063 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002064 chan0 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002065 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002066 chan0 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002067
Arthur Heymans70a8e342017-03-09 11:30:23 +01002068 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002069 chan1 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002070 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002071 chan1 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002072 }
2073 } else {
2074 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002075 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002076 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002077 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002078 chan0 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002079 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002080 chan0 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002081 }
2082 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002083 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002084 chan1 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002085 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002086 chan1 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002087 }
2088 } else {
2089 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002090 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002091 chan0 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002092 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002093 chan0 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002094
Arthur Heymans70a8e342017-03-09 11:30:23 +01002095 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002096 chan1 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002097 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002098 chan1 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002099 }
2100 }
2101
Angel Pons1d4044a2021-03-27 19:11:51 +01002102 mchbar_clrbits32(C0DRC1, 0xff << 24);
2103 mchbar_setbits32(C0DRC1, chan0);
2104 mchbar_clrbits32(C1DRC1, 0xff << 24);
2105 mchbar_setbits32(C1DRC1, chan1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002106}
2107
2108static void sdram_post_jedec_initialization(struct sys_info *sysinfo)
2109{
2110 u32 reg32;
2111
2112 /* Enable Channel XORing for Dual Channel Interleave */
2113 if (sysinfo->interleaved) {
Angel Pons1d4044a2021-03-27 19:11:51 +01002114 reg32 = mchbar_read32(DCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002115 reg32 &= ~(1 << 10);
Stefan Reinauer30140a52009-03-11 16:20:39 +00002116 reg32 |= (1 << 9);
Angel Pons1d4044a2021-03-27 19:11:51 +01002117 mchbar_write32(DCC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002118 }
2119
2120 /* DRAM mode optimizations */
2121 sdram_enhanced_addressing_mode(sysinfo);
2122
Angel Pons1d4044a2021-03-27 19:11:51 +01002123 reg32 = mchbar_read32(FSBPMC3);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002124 reg32 &= ~(1 << 1);
Angel Pons1d4044a2021-03-27 19:11:51 +01002125 mchbar_write32(FSBPMC3, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002126
Angel Pons1d4044a2021-03-27 19:11:51 +01002127 reg32 = mchbar_read32(SBTEST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002128 reg32 &= ~(1 << 2);
Angel Pons1d4044a2021-03-27 19:11:51 +01002129 mchbar_write32(SBTEST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002130
Angel Pons1d4044a2021-03-27 19:11:51 +01002131 reg32 = mchbar_read32(SBOCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002132 reg32 &= 0xffbdb6ff;
2133 reg32 |= (0xbdb6 << 8) | (1 << 0);
Angel Pons1d4044a2021-03-27 19:11:51 +01002134 mchbar_write32(SBOCC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002135}
2136
2137static void sdram_power_management(struct sys_info *sysinfo)
2138{
Stefan Reinauer278534d2008-10-29 04:51:07 +00002139 u16 reg16;
2140 u32 reg32;
Elyes HAOUAS187bec72021-12-12 07:00:50 +01002141 bool integrated_graphics = true;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002142 int i;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002143
Elyes HAOUAS8f20b122021-02-14 13:22:10 +01002144 if (!(pci_read_config8(HOST_BRIDGE, DEVEN) & (DEVEN_D2F0 | DEVEN_D2F1)))
2145 integrated_graphics = false;
2146
Angel Pons1d4044a2021-03-27 19:11:51 +01002147 reg32 = mchbar_read32(C0DRT2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002148 reg32 &= 0xffffff00;
2149 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002150 reg32 |= (1 << 5) | (1 << 4);
Angel Pons1d4044a2021-03-27 19:11:51 +01002151 mchbar_write32(C0DRT2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002152
Angel Pons1d4044a2021-03-27 19:11:51 +01002153 reg32 = mchbar_read32(C1DRT2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002154 reg32 &= 0xffffff00;
2155 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002156 reg32 |= (1 << 5) | (1 << 4);
Angel Pons1d4044a2021-03-27 19:11:51 +01002157 mchbar_write32(C1DRT2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002158
Angel Pons1d4044a2021-03-27 19:11:51 +01002159 reg32 = mchbar_read32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002160
2161 reg32 |= (1 << 12) | (1 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01002162 mchbar_write32(C0DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002163
Angel Pons1d4044a2021-03-27 19:11:51 +01002164 reg32 = mchbar_read32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002165
2166 reg32 |= (1 << 12) | (1 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01002167 mchbar_write32(C1DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002168
Julius Wernercd49cce2019-03-05 16:53:33 -08002169 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002170 if (i945_silicon_revision() > 1) {
2171 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2172 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002173
Angel Pons1d4044a2021-03-27 19:11:51 +01002174 mchbar_write16(UPMC1, 0x1010 | peg_bits);
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002175 } else {
2176 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2177 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002178
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002179 /* Rev 0 and 1 */
Angel Pons1d4044a2021-03-27 19:11:51 +01002180 mchbar_write16(UPMC1, 0x0010 | peg_bits);
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002181 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002182 }
2183
Angel Pons1d4044a2021-03-27 19:11:51 +01002184 reg16 = mchbar_read16(UPMC2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002185 reg16 &= 0xfc00;
2186 reg16 |= 0x0100;
Angel Pons1d4044a2021-03-27 19:11:51 +01002187 mchbar_write16(UPMC2, reg16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002188
Angel Pons1d4044a2021-03-27 19:11:51 +01002189 mchbar_write32(UPMC3, 0x000f06ff);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002190
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002191 for (i = 0; i < 5; i++) {
Angel Pons1d4044a2021-03-27 19:11:51 +01002192 mchbar_clrbits32(UPMC3, 1 << 16);
2193 mchbar_setbits32(UPMC3, 1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002194 }
2195
Angel Pons1d4044a2021-03-27 19:11:51 +01002196 mchbar_write32(GIPMC1, 0x8000000c);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002197
Angel Pons1d4044a2021-03-27 19:11:51 +01002198 reg16 = mchbar_read16(CPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002199 reg16 &= ~(7 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002200 if (i945_silicon_revision() > 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002201 reg16 |= (6 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002202 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002203 reg16 |= (4 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01002204 mchbar_write16(CPCTL, reg16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002205
Angel Pons3580d812020-06-11 14:13:33 +02002206#if 0
Angel Pons1d4044a2021-03-27 19:11:51 +01002207 if ((mchbar_read32(ECO) & (1 << 16)) != 0) {
Angel Pons3580d812020-06-11 14:13:33 +02002208#else
Stefan Reinauer30140a52009-03-11 16:20:39 +00002209 if (i945_silicon_revision() != 0) {
Angel Pons3580d812020-06-11 14:13:33 +02002210#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002211 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002212 case 667:
Angel Pons1d4044a2021-03-27 19:11:51 +01002213 mchbar_write32(HGIPMC2, 0x0d590d59);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002214 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002215 case 533:
Angel Pons1d4044a2021-03-27 19:11:51 +01002216 mchbar_write32(HGIPMC2, 0x155b155b);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002217 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002218 }
2219 } else {
2220 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002221 case 667:
Angel Pons1d4044a2021-03-27 19:11:51 +01002222 mchbar_write32(HGIPMC2, 0x09c409c4);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002223 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002224 case 533:
Angel Pons1d4044a2021-03-27 19:11:51 +01002225 mchbar_write32(HGIPMC2, 0x0fa00fa0);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002226 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002227 }
2228 }
2229
Angel Pons1d4044a2021-03-27 19:11:51 +01002230 mchbar_write32(FSBPMC1, 0x8000000c);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002231
Angel Pons1d4044a2021-03-27 19:11:51 +01002232 reg32 = mchbar_read32(C2C3TT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002233 reg32 &= 0xffff0000;
2234 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002235 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002236 reg32 |= 0x0600;
2237 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002238 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002239 reg32 |= 0x0480;
2240 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002241 }
Angel Pons1d4044a2021-03-27 19:11:51 +01002242 mchbar_write32(C2C3TT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002243
Angel Pons1d4044a2021-03-27 19:11:51 +01002244 reg32 = mchbar_read32(C3C4TT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002245 reg32 &= 0xffff0000;
2246 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002247 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002248 reg32 |= 0x0b80;
2249 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002250 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002251 reg32 |= 0x0980;
2252 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002253 }
Angel Pons1d4044a2021-03-27 19:11:51 +01002254 mchbar_write32(C3C4TT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002255
Arthur Heymans70a8e342017-03-09 11:30:23 +01002256 if (i945_silicon_revision() == 0)
Angel Pons1d4044a2021-03-27 19:11:51 +01002257 mchbar_clrbits32(ECO, 1 << 16);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002258 else
Angel Pons1d4044a2021-03-27 19:11:51 +01002259 mchbar_setbits32(ECO, 1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002260
Angel Pons1d4044a2021-03-27 19:11:51 +01002261 mchbar_clrbits32(FSBPMC3, 1 << 29);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002262
Angel Pons1d4044a2021-03-27 19:11:51 +01002263 mchbar_setbits32(FSBPMC3, 1 << 21);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002264
Angel Pons1d4044a2021-03-27 19:11:51 +01002265 mchbar_clrbits32(FSBPMC3, 1 << 19);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002266
Angel Pons1d4044a2021-03-27 19:11:51 +01002267 mchbar_clrbits32(FSBPMC3, 1 << 13);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002268
Angel Pons1d4044a2021-03-27 19:11:51 +01002269 reg32 = mchbar_read32(FSBPMC4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002270 reg32 &= ~(3 << 24);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002271 reg32 |= (2 << 24);
Angel Pons1d4044a2021-03-27 19:11:51 +01002272 mchbar_write32(FSBPMC4, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002273
Angel Pons1d4044a2021-03-27 19:11:51 +01002274 mchbar_setbits32(FSBPMC4, 1 << 21);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002275
Angel Pons1d4044a2021-03-27 19:11:51 +01002276 mchbar_setbits32(FSBPMC4, 1 << 5);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002277
Arthur Heymans70a8e342017-03-09 11:30:23 +01002278 if ((i945_silicon_revision() < 2)) { /* || cpuid() = 0x6e8 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002279 /* stepping 0 and 1 or CPUID 6e8 */
Angel Pons1d4044a2021-03-27 19:11:51 +01002280 mchbar_clrbits32(FSBPMC4, 1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002281 } else {
Angel Pons1d4044a2021-03-27 19:11:51 +01002282 mchbar_setbits32(FSBPMC4, 1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002283 }
2284
Angel Pons3580d812020-06-11 14:13:33 +02002285 pci_or_config8(HOST_BRIDGE, 0xfc, 1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002286
Angel Pons3580d812020-06-11 14:13:33 +02002287 pci_or_config8(IGD_DEV, 0xc1, 1 << 2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002288
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002289 if (integrated_graphics) {
Angel Pons1d4044a2021-03-27 19:11:51 +01002290 mchbar_write16(MIPMC4, 0x04f8);
2291 mchbar_write16(MIPMC5, 0x04fc);
2292 mchbar_write16(MIPMC6, 0x04fc);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002293 } else {
Angel Pons1d4044a2021-03-27 19:11:51 +01002294 mchbar_write16(MIPMC4, 0x64f8);
2295 mchbar_write16(MIPMC5, 0x64fc);
2296 mchbar_write16(MIPMC6, 0x64fc);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002297 }
2298
Angel Pons1d4044a2021-03-27 19:11:51 +01002299 reg32 = mchbar_read32(PMCFG);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002300 reg32 &= ~(3 << 17);
2301 reg32 |= (2 << 17);
Angel Pons1d4044a2021-03-27 19:11:51 +01002302 mchbar_write32(PMCFG, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002303
Angel Pons1d4044a2021-03-27 19:11:51 +01002304 mchbar_setbits32(PMCFG, 1 << 4);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002305
Angel Pons1d4044a2021-03-27 19:11:51 +01002306 reg32 = mchbar_read32(UPMC4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002307 reg32 &= 0xffffff00;
2308 reg32 |= 0x01;
Angel Pons1d4044a2021-03-27 19:11:51 +01002309 mchbar_write32(UPMC4, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002310
Angel Pons1d4044a2021-03-27 19:11:51 +01002311 mchbar_clrbits32(0xb18, 1 << 21);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002312}
2313
2314static void sdram_thermal_management(void)
2315{
Stefan Reinauer278534d2008-10-29 04:51:07 +00002316
Angel Pons1d4044a2021-03-27 19:11:51 +01002317 mchbar_write8(TCO1, 0);
2318 mchbar_write8(TCO0, 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002319
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002320 /* The Thermal Sensors for DIMMs at 0x50, 0x52 are at I2C addr 0x30/0x32. */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002321
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002322 /* TODO This is not implemented yet. Volunteers? */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002323}
2324
2325static void sdram_save_receive_enable(void)
2326{
2327 int i;
2328 u32 reg32;
2329 u8 values[4];
2330
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002331 /* The following values are stored to an unused CMOS area and restored instead of
2332 * recalculated in case of an S3 resume.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002333 *
Arthur Heymans70a8e342017-03-09 11:30:23 +01002334 * C0WL0REOST [7:0] -> 8 bit
2335 * C1WL0REOST [7:0] -> 8 bit
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002336 * RCVENMT [11:8] [3:0] -> 8 bit
2337 * C0DRT1 [27:24] -> 4 bit
2338 * C1DRT1 [27:24] -> 4 bit
2339 */
2340
Angel Pons1d4044a2021-03-27 19:11:51 +01002341 values[0] = mchbar_read8(C0WL0REOST);
2342 values[1] = mchbar_read8(C1WL0REOST);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002343
Angel Pons1d4044a2021-03-27 19:11:51 +01002344 reg32 = mchbar_read32(RCVENMT);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002345 values[2] = (u8)((reg32 >> (8 - 4)) & 0xf0) | (reg32 & 0x0f);
2346
Angel Pons1d4044a2021-03-27 19:11:51 +01002347 reg32 = mchbar_read32(C0DRT1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002348 values[3] = (reg32 >> 24) & 0x0f;
Angel Pons1d4044a2021-03-27 19:11:51 +01002349 reg32 = mchbar_read32(C1DRT1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002350 values[3] |= (reg32 >> (24 - 4)) & 0xf0;
2351
2352 /* coreboot only uses bytes 0 - 127 for its CMOS values so far
Edwin Beasanteb50c7d2010-07-06 21:05:04 +00002353 * so we grab bytes 128 - 131 to save the receive enable values
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002354 */
2355
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002356 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002357 cmos_write(values[i], 128 + i);
2358}
2359
2360static void sdram_recover_receive_enable(void)
2361{
2362 int i;
2363 u32 reg32;
2364 u8 values[4];
2365
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002366 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002367 values[i] = cmos_read(128 + i);
2368
Angel Pons1d4044a2021-03-27 19:11:51 +01002369 mchbar_write8(C0WL0REOST, values[0]);
2370 mchbar_write8(C1WL0REOST, values[1]);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002371
Angel Pons1d4044a2021-03-27 19:11:51 +01002372 reg32 = mchbar_read32(RCVENMT);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002373 reg32 &= ~((0x0f << 8) | (0x0f << 0));
2374 reg32 |= ((u32)(values[2] & 0xf0) << (8 - 4)) | (values[2] & 0x0f);
Angel Pons1d4044a2021-03-27 19:11:51 +01002375 mchbar_write32(RCVENMT, reg32);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002376
Angel Pons1d4044a2021-03-27 19:11:51 +01002377 reg32 = mchbar_read32(C0DRT1) & ~(0x0f << 24);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002378 reg32 |= (u32)(values[3] & 0x0f) << 24;
Angel Pons1d4044a2021-03-27 19:11:51 +01002379 mchbar_write32(C0DRT1, reg32);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002380
Angel Pons1d4044a2021-03-27 19:11:51 +01002381 reg32 = mchbar_read32(C1DRT1) & ~(0x0f << 24);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002382 reg32 |= (u32)(values[3] & 0xf0) << (24 - 4);
Angel Pons1d4044a2021-03-27 19:11:51 +01002383 mchbar_write32(C1DRT1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002384}
2385
Stefan Reinauer278534d2008-10-29 04:51:07 +00002386static void sdram_program_receive_enable(struct sys_info *sysinfo)
2387{
Angel Pons1d4044a2021-03-27 19:11:51 +01002388 mchbar_setbits32(REPC, 1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002389
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002390 /* Program Receive Enable Timings */
2391 if (sysinfo->boot_path == BOOT_PATH_RESUME) {
2392 sdram_recover_receive_enable();
2393 } else {
2394 receive_enable_adjust(sysinfo);
2395 sdram_save_receive_enable();
2396 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002397
Angel Pons1d4044a2021-03-27 19:11:51 +01002398 mchbar_setbits32(C0DRC1, 1 << 6);
2399 mchbar_setbits32(C1DRC1, 1 << 6);
2400 mchbar_clrbits32(C0DRC1, 1 << 6);
2401 mchbar_clrbits32(C1DRC1, 1 << 6);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002402
Angel Pons1d4044a2021-03-27 19:11:51 +01002403 mchbar_setbits32(MIPMC3, 0x0f << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002404}
2405
2406/**
2407 * @brief Enable On-Die Termination for DDR2.
2408 *
2409 */
2410
2411static void sdram_on_die_termination(struct sys_info *sysinfo)
2412{
2413 static const u32 odt[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002414 0x00024911, 0xe0010000,
2415 0x00049211, 0xe0020000,
2416 0x0006db11, 0xe0030000,
Stefan Reinauer278534d2008-10-29 04:51:07 +00002417 };
2418
2419 u32 reg32;
2420 int cas;
2421
Angel Pons1d4044a2021-03-27 19:11:51 +01002422 reg32 = mchbar_read32(ODTC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002423 reg32 &= ~(3 << 16);
2424 reg32 |= (1 << 14) | (1 << 6) | (2 << 16);
Angel Pons1d4044a2021-03-27 19:11:51 +01002425 mchbar_write32(ODTC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002426
Paul Menzelb4d9f222020-03-14 10:34:29 +01002427 if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002428 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
Elyes HAOUAS38424982016-08-21 12:01:04 +02002429 printk(BIOS_DEBUG, "one dimm per channel config..\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002430
Angel Pons1d4044a2021-03-27 19:11:51 +01002431 reg32 = mchbar_read32(C0ODT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002432 reg32 &= ~(7 << 28);
Angel Pons1d4044a2021-03-27 19:11:51 +01002433 mchbar_write32(C0ODT, reg32);
2434 reg32 = mchbar_read32(C1ODT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002435 reg32 &= ~(7 << 28);
Angel Pons1d4044a2021-03-27 19:11:51 +01002436 mchbar_write32(C1ODT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002437 }
2438
2439 cas = sysinfo->cas;
2440
Angel Pons1d4044a2021-03-27 19:11:51 +01002441 reg32 = mchbar_read32(C0ODT) & 0xfff00000;
Angel Pons30492572020-06-11 13:24:54 +02002442 reg32 |= odt[(cas - 3) * 2];
Angel Pons1d4044a2021-03-27 19:11:51 +01002443 mchbar_write32(C0ODT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002444
Angel Pons1d4044a2021-03-27 19:11:51 +01002445 reg32 = mchbar_read32(C1ODT) & 0xfff00000;
Angel Pons30492572020-06-11 13:24:54 +02002446 reg32 |= odt[(cas - 3) * 2];
Angel Pons1d4044a2021-03-27 19:11:51 +01002447 mchbar_write32(C1ODT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002448
Angel Pons1d4044a2021-03-27 19:11:51 +01002449 reg32 = mchbar_read32(C0ODT + 4) & 0x1fc8ffff;
Angel Pons30492572020-06-11 13:24:54 +02002450 reg32 |= odt[((cas - 3) * 2) + 1];
Angel Pons1d4044a2021-03-27 19:11:51 +01002451 mchbar_write32(C0ODT + 4, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002452
Angel Pons1d4044a2021-03-27 19:11:51 +01002453 reg32 = mchbar_read32(C1ODT + 4) & 0x1fc8ffff;
Angel Pons30492572020-06-11 13:24:54 +02002454 reg32 |= odt[((cas - 3) * 2) + 1];
Angel Pons1d4044a2021-03-27 19:11:51 +01002455 mchbar_write32(C1ODT + 4, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002456}
2457
2458/**
2459 * @brief Enable clocks to populated sockets
2460 */
2461
2462static void sdram_enable_memory_clocks(struct sys_info *sysinfo)
2463{
2464 u8 clocks[2] = { 0, 0 };
2465
Julius Wernercd49cce2019-03-05 16:53:33 -08002466#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002467#define CLOCKS_WIDTH 2
Julius Wernercd49cce2019-03-05 16:53:33 -08002468#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002469#define CLOCKS_WIDTH 3
2470#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002471 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002472 clocks[0] |= (1 << CLOCKS_WIDTH) - 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002473
2474 if (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002475 clocks[0] |= ((1 << CLOCKS_WIDTH) - 1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002476
2477 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002478 clocks[1] |= (1 << CLOCKS_WIDTH) - 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002479
2480 if (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002481 clocks[1] |= ((1 << CLOCKS_WIDTH) - 1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002482
Julius Wernercd49cce2019-03-05 16:53:33 -08002483#if CONFIG(OVERRIDE_CLOCK_DISABLE)
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002484 /* Usually system firmware turns off system memory clock signals to unused SO-DIMM slots
2485 * to reduce EMI and power consumption.
2486 * However, the Kontron 986LCD-M does not like unused clock signals to be disabled.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002487 */
2488
2489 clocks[0] = 0xf; /* force all clock gate pairs to enable */
2490 clocks[1] = 0xf; /* force all clock gate pairs to enable */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002491#endif
2492
Angel Pons1d4044a2021-03-27 19:11:51 +01002493 mchbar_write8(C0DCLKDIS, clocks[0]);
2494 mchbar_write8(C1DCLKDIS, clocks[1]);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002495}
2496
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002497#define RTT_ODT_NONE 0
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002498#define RTT_ODT_50_OHM ((1 << 9) | (1 << 5))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002499#define RTT_ODT_75_OHM (1 << 5)
2500#define RTT_ODT_150_OHM (1 << 9)
2501
Arthur Heymans70a8e342017-03-09 11:30:23 +01002502#define EMRS_OCD_DEFAULT ((1 << 12) | (1 << 11) | (1 << 10))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002503
2504#define MRS_CAS_3 (3 << 7)
2505#define MRS_CAS_4 (4 << 7)
2506#define MRS_CAS_5 (5 << 7)
2507
2508#define MRS_TWR_3 (2 << 12)
2509#define MRS_TWR_4 (3 << 12)
2510#define MRS_TWR_5 (4 << 12)
2511
2512#define MRS_BT (1 << 6)
2513
2514#define MRS_BL4 (2 << 3)
2515#define MRS_BL8 (3 << 3)
2516
2517static void sdram_jedec_enable(struct sys_info *sysinfo)
2518{
2519 int i, nonzero;
2520 u32 bankaddr = 0, tmpaddr, mrsaddr = 0;
2521
2522 for (i = 0, nonzero = -1; i < 8; i++) {
Elyes HAOUAS01912202019-01-19 16:36:38 +01002523 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002524 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002525
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002526 printk(BIOS_DEBUG, "jedec enable sequence: bank %d\n", i);
Elyes HAOUAS01912202019-01-19 16:36:38 +01002527
2528 if (nonzero != -1) {
2529 if (sysinfo->interleaved && nonzero < 4 && i >= 4) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002530 bankaddr = 0x40;
Elyes HAOUAS01912202019-01-19 16:36:38 +01002531 } else {
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002532 printk(BIOS_DEBUG, "bankaddr from bank size of rank %d\n",
2533 nonzero);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002534 bankaddr += sysinfo->banksize[nonzero] <<
2535 (sysinfo->interleaved ? 26 : 25);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002536 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002537 }
2538
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002539 /*
2540 * We have a bank with a non-zero size... Remember it
Stefan Reinauer278534d2008-10-29 04:51:07 +00002541 * for the next offset we have to calculate
2542 */
2543 nonzero = i;
2544
2545 /* Get CAS latency set up */
2546 switch (sysinfo->cas) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002547 case 5:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002548 mrsaddr = MRS_CAS_5;
2549 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002550 case 4:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002551 mrsaddr = MRS_CAS_4;
2552 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002553 case 3:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002554 mrsaddr = MRS_CAS_3;
2555 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002556 default:
2557 die("Jedec Error (CAS).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002558 }
2559
2560 /* Get tWR set */
2561 switch (sysinfo->twr) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002562 case 5:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002563 mrsaddr |= MRS_TWR_5;
2564 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002565 case 4:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002566 mrsaddr |= MRS_TWR_4;
2567 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002568 case 3:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002569 mrsaddr |= MRS_TWR_3;
2570 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002571 default:
2572 die("Jedec Error (tWR).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002573 }
2574
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002575 /* Set "Burst Type" */
2576 mrsaddr |= MRS_BT;
2577
Stefan Reinauer278534d2008-10-29 04:51:07 +00002578 /* Interleaved */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002579 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002580 mrsaddr = mrsaddr << 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002581
2582 /* Only burst length 8 supported */
2583 mrsaddr |= MRS_BL8;
2584
2585 /* Apply NOP */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002586 PRINTK_DEBUG("Apply NOP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002587 do_ram_command(RAM_COMMAND_NOP);
2588 ram_read32(bankaddr);
2589
2590 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002591 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002592 do_ram_command(RAM_COMMAND_PRECHARGE);
2593 ram_read32(bankaddr);
2594
2595 /* Extended Mode Register Set (2) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002596 PRINTK_DEBUG("Extended Mode Register Set(2)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002597 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_2);
2598 ram_read32(bankaddr);
2599
2600 /* Extended Mode Register Set (3) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002601 PRINTK_DEBUG("Extended Mode Register Set(3)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002602 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_3);
2603 ram_read32(bankaddr);
2604
2605 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002606 PRINTK_DEBUG("Extended Mode Register Set\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002607 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2608 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002609 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002610 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002611 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002612 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002613 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002614 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002615 ram_read32(tmpaddr);
2616
2617 /* Mode Register Set: Reset DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002618 PRINTK_DEBUG("MRS: Reset DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002619 do_ram_command(RAM_COMMAND_MRS);
2620 tmpaddr = bankaddr;
2621 tmpaddr |= mrsaddr;
2622 /* Set DLL reset bit */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002623 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002624 tmpaddr |= (1 << 12);
2625 else
2626 tmpaddr |= (1 << 11);
2627 ram_read32(tmpaddr);
2628
2629 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002630 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002631 do_ram_command(RAM_COMMAND_PRECHARGE);
2632 ram_read32(bankaddr);
2633
2634 /* CAS before RAS Refresh */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002635 PRINTK_DEBUG("CAS before RAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002636 do_ram_command(RAM_COMMAND_CBR);
2637
2638 /* CBR wants two READs */
2639 ram_read32(bankaddr);
2640 ram_read32(bankaddr);
2641
2642 /* Mode Register Set: Enable DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002643 PRINTK_DEBUG("MRS: Enable DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002644 do_ram_command(RAM_COMMAND_MRS);
2645
2646 tmpaddr = bankaddr;
2647 tmpaddr |= mrsaddr;
2648 ram_read32(tmpaddr);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002649
Stefan Reinauer278534d2008-10-29 04:51:07 +00002650 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002651 PRINTK_DEBUG("Extended Mode Register Set: ODT/OCD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002652 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002653
Stefan Reinauer278534d2008-10-29 04:51:07 +00002654 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002655 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002656 tmpaddr |= RTT_ODT_75_OHM | EMRS_OCD_DEFAULT;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002657 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002658 tmpaddr |= ((RTT_ODT_150_OHM | EMRS_OCD_DEFAULT) << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002659 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002660 tmpaddr |= RTT_ODT_150_OHM | EMRS_OCD_DEFAULT;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002661 ram_read32(tmpaddr);
2662
2663 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002664 PRINTK_DEBUG("Extended Mode Register Set: OCD Exit\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002665 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2666
2667 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002668 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002669 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002670 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002671 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002672 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002673 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002674 ram_read32(tmpaddr);
2675 }
2676}
2677
2678static void sdram_init_complete(void)
2679{
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002680 PRINTK_DEBUG("Normal Operation\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002681 do_ram_command(RAM_COMMAND_NORMAL);
2682}
2683
2684static void sdram_setup_processor_side(void)
2685{
2686 if (i945_silicon_revision() == 0)
Angel Pons1d4044a2021-03-27 19:11:51 +01002687 mchbar_setbits32(FSBPMC3, 1 << 2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002688
Angel Pons1d4044a2021-03-27 19:11:51 +01002689 mchbar_setbits8(0xb00, 1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002690
2691 if (i945_silicon_revision() == 0)
Angel Pons1d4044a2021-03-27 19:11:51 +01002692 mchbar_setbits32(SLPCTL, 1 << 8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002693}
2694
Stefan Reinauer278534d2008-10-29 04:51:07 +00002695/**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002696 * @param boot_path: 0 = normal, 1 = reset, 2 = resume from s3
Martin Rothf4cb4122015-01-06 10:27:39 -07002697 * @param spd_addresses pointer to a list of SPD addresses
Stefan Reinauer278534d2008-10-29 04:51:07 +00002698 */
Sven Schnelle541269b2011-02-21 09:39:17 +00002699void sdram_initialize(int boot_path, const u8 *spd_addresses)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002700{
2701 struct sys_info sysinfo;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002702
Jakub Czapigaad6157e2022-02-15 11:50:31 +01002703 timestamp_add_now(TS_INITRAM_START);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002704 printk(BIOS_DEBUG, "Setting up RAM controller.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002705
2706 memset(&sysinfo, 0, sizeof(sysinfo));
2707
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002708 sysinfo.boot_path = boot_path;
Sven Schnelle541269b2011-02-21 09:39:17 +00002709 sysinfo.spd_addresses = spd_addresses;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002710
Stefan Reinauer278534d2008-10-29 04:51:07 +00002711 /* Look at the type of DIMMs and verify all DIMMs are x8 or x16 width */
2712 sdram_get_dram_configuration(&sysinfo);
2713
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002714 /* If error, do cold boot */
2715 sdram_detect_errors(&sysinfo);
2716
Stefan Reinauer278534d2008-10-29 04:51:07 +00002717 /* Program PLL settings */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002718 sdram_program_pll_settings(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002719
Arthur Heymans18537812016-12-28 21:20:45 +01002720 /*
2721 * Program Graphics Frequency
2722 * Set core display and render clock on 945GC to the max
2723 */
Julius Wernercd49cce2019-03-05 16:53:33 -08002724 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM))
Arthur Heymans18537812016-12-28 21:20:45 +01002725 sdram_program_graphics_frequency(&sysinfo);
2726 else
Angel Pons3580d812020-06-11 14:13:33 +02002727 pci_write_config16(IGD_DEV, GCFC, 0x0534);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002728
2729 /* Program System Memory Frequency */
2730 sdram_program_memory_frequency(&sysinfo);
2731
2732 /* Determine Mode of Operation (Interleaved etc) */
2733 sdram_set_channel_mode(&sysinfo);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002734
Stefan Reinauer278534d2008-10-29 04:51:07 +00002735 /* Program Clock Crossing values */
2736 sdram_program_clock_crossing();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002737
Stefan Reinauer278534d2008-10-29 04:51:07 +00002738 /* Disable fast dispatch */
2739 sdram_disable_fast_dispatch();
2740
2741 /* Enable WIODLL Power Down in ACPI states */
Angel Pons1d4044a2021-03-27 19:11:51 +01002742 mchbar_setbits32(C0DMC, 1 << 24);
2743 mchbar_setbits32(C1DMC, 1 << 24);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002744
2745 /* Program DRAM Row Boundary/Attribute Registers */
2746
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002747 /* program row size DRB and set TOLUD */
2748 sdram_program_row_boundaries(&sysinfo);
2749
2750 /* program page size DRA */
2751 sdram_set_row_attributes(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002752
2753 /* Program CxBNKARC */
2754 sdram_set_bank_architecture(&sysinfo);
2755
2756 /* Program DRAM Timing and Control registers based on SPD */
2757 sdram_set_timing_and_control(&sysinfo);
2758
2759 /* On-Die Termination Adjustment */
2760 sdram_on_die_termination(&sysinfo);
2761
2762 /* Pre Jedec Initialization */
2763 sdram_pre_jedec_initialization();
2764
2765 /* Perform System Memory IO Initialization */
2766 sdram_initialize_system_memory_io(&sysinfo);
2767
2768 /* Perform System Memory IO Buffer Enable */
2769 sdram_enable_system_memory_io(&sysinfo);
2770
2771 /* Enable System Memory Clocks */
2772 sdram_enable_memory_clocks(&sysinfo);
2773
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002774 if (boot_path == BOOT_PATH_NORMAL) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002775 /* Jedec Initialization sequence */
2776 sdram_jedec_enable(&sysinfo);
2777 }
2778
2779 /* Program Power Management Registers */
2780 sdram_power_management(&sysinfo);
2781
2782 /* Post Jedec Init */
2783 sdram_post_jedec_initialization(&sysinfo);
2784
2785 /* Program DRAM Throttling */
2786 sdram_thermal_management();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002787
Stefan Reinauer278534d2008-10-29 04:51:07 +00002788 /* Normal Operations */
Stefan Reinaueraca6ec62009-10-26 17:12:21 +00002789 sdram_init_complete();
Stefan Reinauer278534d2008-10-29 04:51:07 +00002790
2791 /* Program Receive Enable Timings */
2792 sdram_program_receive_enable(&sysinfo);
2793
2794 /* Enable Periodic RCOMP */
2795 sdram_enable_rcomp();
2796
2797 /* Tell ICH7 that we're done */
Angel Ponse3c68d22020-06-08 12:09:03 +02002798 pci_and_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, (u8)~(1 << 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +00002799
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002800 printk(BIOS_DEBUG, "RAM initialization finished.\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002801
Stefan Reinauer278534d2008-10-29 04:51:07 +00002802 sdram_setup_processor_side();
Jakub Czapigaad6157e2022-02-15 11:50:31 +01002803 timestamp_add_now(TS_INITRAM_END);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002804}