blob: a37754b7f3e1827e2909f4fb38d6ef8a1f13291d [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
Stefan Reinauerbc8613e2010-08-25 18:35:42 +000054static __attribute__((noinline)) void do_ram_command(u32 command)
Stefan Reinauer278534d2008-10-29 04:51:07 +000055{
56 u32 reg32;
57
Angel Pons1d4044a2021-03-27 19:11:51 +010058 reg32 = mchbar_read32(DCC);
Angel Pons30492572020-06-11 13:24:54 +020059 reg32 &= ~((3 << 21) | (1 << 20) | (1 << 19) | (7 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +000060 reg32 |= command;
61
62 /* Also set Init Complete */
63 if (command == RAM_COMMAND_NORMAL)
64 reg32 |= RAM_INITIALIZATION_COMPLETE;
65
66 PRINTK_DEBUG(" Sending RAM command 0x%08x", reg32);
67
Angel Pons1d4044a2021-03-27 19:11:51 +010068 mchbar_write32(DCC, reg32); /* This is the actual magic */
Stefan Reinauer278534d2008-10-29 04:51:07 +000069
Stefan Reinauer779b3e32008-11-10 15:43:37 +000070 PRINTK_DEBUG("...done\n");
Stefan Reinauerd058ad12010-08-26 12:43:58 +000071
72 udelay(1);
Stefan Reinauer278534d2008-10-29 04:51:07 +000073}
74
Elyes HAOUAS964055d2022-01-14 18:56:49 +010075static void ram_read32(uintptr_t offset)
Stefan Reinauer278534d2008-10-29 04:51:07 +000076{
Elyes Haouase8bb6d22022-10-04 14:16:09 +020077 PRINTK_DEBUG(" RAM read: %" PRIxPTR "\n", offset);
Stefan Reinauer278534d2008-10-29 04:51:07 +000078
Elyes Haouas712c70b2022-02-25 10:05:22 +010079 read32p(offset);
Stefan Reinauer278534d2008-10-29 04:51:07 +000080}
81
Stefan Reinauer3c0bfaf2010-12-27 11:34:57 +000082void sdram_dump_mchbar_registers(void)
Stefan Reinauer278534d2008-10-29 04:51:07 +000083{
84 int i;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000085 printk(BIOS_DEBUG, "Dumping MCHBAR Registers\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +000086
Arthur Heymans70a8e342017-03-09 11:30:23 +010087 for (i = 0; i < 0xfff; i += 4) {
Angel Pons1d4044a2021-03-27 19:11:51 +010088 if (mchbar_read32(i) == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +000089 continue;
Angel Pons1d4044a2021-03-27 19:11:51 +010090 printk(BIOS_DEBUG, "0x%04x: 0x%08x\n", i, mchbar_read32(i));
Stefan Reinauer278534d2008-10-29 04:51:07 +000091 }
92}
Stefan Reinauer278534d2008-10-29 04:51:07 +000093
Stefan Reinauer24b4df52010-01-17 13:47:35 +000094static int memclk(void)
95{
Julius Wernercd49cce2019-03-05 16:53:33 -080096 int offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Elyes HAOUASc9848a82016-10-09 20:24:20 +020097
Angel Pons1d4044a2021-03-27 19:11:51 +010098 switch (((mchbar_read32(CLKCFG) >> 4) & 7) - offset) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +000099 case 1: return 400;
100 case 2: return 533;
101 case 3: return 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100102 default:
Elyes HAOUAS3cd43272020-03-05 22:01:17 +0100103 printk(BIOS_DEBUG, "%s: unknown register value %x\n", __func__,
Angel Pons1d4044a2021-03-27 19:11:51 +0100104 ((mchbar_read32(CLKCFG) >> 4) & 7) - offset);
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000105 }
106 return -1;
107}
108
Peter Stuge76d91432010-10-01 10:02:33 +0000109static u16 fsbclk(void)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000110{
Julius Wernercd49cce2019-03-05 16:53:33 -0800111 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Angel Pons1d4044a2021-03-27 19:11:51 +0100112 switch (mchbar_read32(CLKCFG) & 7) {
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200113 case 0: return 400;
114 case 1: return 533;
115 case 3: return 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100116 default:
Elyes HAOUAS3cd43272020-03-05 22:01:17 +0100117 printk(BIOS_DEBUG, "%s: unknown register value %x\n", __func__,
Angel Pons1d4044a2021-03-27 19:11:51 +0100118 mchbar_read32(CLKCFG) & 7);
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200119 }
120 return 0xffff;
Julius Wernercd49cce2019-03-05 16:53:33 -0800121 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Angel Pons1d4044a2021-03-27 19:11:51 +0100122 switch (mchbar_read32(CLKCFG) & 7) {
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200123 case 0: return 1066;
124 case 1: return 533;
125 case 2: return 800;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100126 default:
Elyes HAOUAS3cd43272020-03-05 22:01:17 +0100127 printk(BIOS_DEBUG, "%s: unknown register value %x\n", __func__,
Angel Pons1d4044a2021-03-27 19:11:51 +0100128 mchbar_read32(CLKCFG) & 7);
Elyes HAOUASc9848a82016-10-09 20:24:20 +0200129 }
130 return 0xffff;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000131 }
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000132}
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000133
Stefan Reinauer278534d2008-10-29 04:51:07 +0000134static int sdram_capabilities_max_supported_memory_frequency(void)
135{
136 u32 reg32;
137
Patrick Georgi77d66832010-10-01 08:02:45 +0000138#if CONFIG_MAXIMUM_SUPPORTED_FREQUENCY
139 return CONFIG_MAXIMUM_SUPPORTED_FREQUENCY;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000140#endif
141
Angel Pons3580d812020-06-11 14:13:33 +0200142 reg32 = pci_read_config32(HOST_BRIDGE, 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000143 reg32 &= (7 << 0);
144
145 switch (reg32) {
146 case 4: return 400;
147 case 3: return 533;
148 case 2: return 667;
149 }
150 /* Newer revisions of this chipset rather support faster memory clocks,
151 * so if it's a reserved value, return the fastest memory clock that we
152 * know of and can handle
153 */
154 return 667;
155}
156
157/**
158 * @brief determine whether chipset is capable of dual channel interleaved mode
159 *
160 * @return 1 if interleaving is supported, 0 otherwise
161 */
162static int sdram_capabilities_interleave(void)
163{
164 u32 reg32;
165
Angel Pons3580d812020-06-11 14:13:33 +0200166 reg32 = pci_read_config32(HOST_BRIDGE, 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000167 reg32 >>= 25;
168 reg32 &= 1;
169
170 return (!reg32);
171}
172
173/**
174 * @brief determine whether chipset is capable of two memory channels
175 *
176 * @return 1 if dual channel operation is supported, 0 otherwise
177 */
178static int sdram_capabilities_dual_channel(void)
179{
180 u32 reg32;
181
Angel Pons3580d812020-06-11 14:13:33 +0200182 reg32 = pci_read_config32(HOST_BRIDGE, 0xe4); /* CAPID0 + 4 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000183 reg32 >>= 24;
184 reg32 &= 1;
185
186 return (!reg32);
187}
188
189static int sdram_capabilities_enhanced_addressing_xor(void)
190{
191 u8 reg8;
192
Angel Pons3580d812020-06-11 14:13:33 +0200193 reg8 = pci_read_config8(HOST_BRIDGE, 0xe5); /* CAPID0 + 5 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000194 reg8 &= (1 << 7);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000195
Stefan Reinauer278534d2008-10-29 04:51:07 +0000196 return (!reg8);
197}
198
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000199#define GFX_FREQUENCY_CAP_166MHZ 0x04
200#define GFX_FREQUENCY_CAP_200MHZ 0x03
201#define GFX_FREQUENCY_CAP_250MHZ 0x02
202#define GFX_FREQUENCY_CAP_ALL 0x00
203
204static int sdram_capabilities_core_frequencies(void)
205{
206 u8 reg8;
207
Angel Pons3580d812020-06-11 14:13:33 +0200208 reg8 = pci_read_config8(HOST_BRIDGE, 0xe5); /* CAPID0 + 5 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000209 reg8 &= (1 << 3) | (1 << 2) | (1 << 1);
210 reg8 >>= 1;
211
Arthur Heymans70a8e342017-03-09 11:30:23 +0100212 return reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000213}
214
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000215static void sdram_detect_errors(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000216{
217 u8 reg8;
Elyes Haouas90156652022-10-07 12:27:22 +0200218 bool do_reset = false;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000219
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100220 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000221
Angel Pons30492572020-06-11 13:24:54 +0200222 if (reg8 & ((1 << 7) | (1 << 2))) {
223 if (reg8 & (1 << 2)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000224 printk(BIOS_DEBUG, "SLP S4# Assertion Width Violation.\n");
Stefan Reinauerf98ad3a2010-03-05 18:25:19 +0000225 /* Write back clears bit 2 */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100226 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Elyes Haouas90156652022-10-07 12:27:22 +0200227 do_reset = true;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000228 }
229
Angel Pons30492572020-06-11 13:24:54 +0200230 if (reg8 & (1 << 7)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000231 printk(BIOS_DEBUG, "DRAM initialization was interrupted.\n");
Angel Pons30492572020-06-11 13:24:54 +0200232 reg8 &= ~(1 << 7);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100233 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, reg8);
Elyes Haouas90156652022-10-07 12:27:22 +0200234 do_reset = true;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000235 }
236
237 /* Set SLP_S3# Assertion Stretch Enable */
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100238 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000239 reg8 |= (1 << 3);
Elyes HAOUAS32b9a992019-01-21 14:54:31 +0100240 pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000241
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000242 if (do_reset) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000243 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200244 full_reset();
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000245 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000246 }
247
248 /* Set DRAM initialization bit in ICH7 */
Angel Ponse3c68d22020-06-08 12:09:03 +0200249 pci_or_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, 1 << 7);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000250
Peter Stuge751508a2012-01-27 22:17:09 +0100251 /* clear self refresh status if check is disabled or not a resume */
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200252 if (!CONFIG(CHECK_SLFRCS_ON_RESUME) || sysinfo->boot_path != BOOT_PATH_RESUME) {
Angel Pons1d4044a2021-03-27 19:11:51 +0100253 mchbar_setbits8(SLFRCS, 3);
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000254 } else {
255 /* Validate self refresh config */
256 if (((sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED) ||
257 (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)) &&
Angel Pons1d4044a2021-03-27 19:11:51 +0100258 !(mchbar_read8(SLFRCS) & (1 << 0))) {
Elyes Haouas90156652022-10-07 12:27:22 +0200259 do_reset = true;
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000260 }
261 if (((sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED) ||
262 (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) &&
Angel Pons1d4044a2021-03-27 19:11:51 +0100263 !(mchbar_read8(SLFRCS) & (1 << 1))) {
Elyes Haouas90156652022-10-07 12:27:22 +0200264 do_reset = true;
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000265 }
266 }
267
268 if (do_reset) {
269 printk(BIOS_DEBUG, "Reset required.\n");
Elyes HAOUAS420d7e02019-04-21 18:39:34 +0200270 full_reset();
Stefan Reinauerbf264e92010-05-14 19:09:20 +0000271 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000272}
Stefan Reinauer278534d2008-10-29 04:51:07 +0000273
Arthur Heymans0ab49042017-02-06 22:40:14 +0100274struct timings {
275 u32 min_tCLK_cas[8];
276 u32 min_tRAS;
277 u32 min_tRP;
278 u32 min_tRCD;
279 u32 min_tWR;
280 u32 min_tRFC;
281 u32 max_tRR;
282 u8 cas_mask;
283};
Stefan Reinauer278534d2008-10-29 04:51:07 +0000284
Arthur Heymans0ab49042017-02-06 22:40:14 +0100285/**
286 * @brief loop over dimms and save maximal timings
287 */
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200288static void gather_common_timing(struct sys_info *sysinfo, struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000289{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100290 int i, j;
291 u8 raw_spd[SPD_SIZE_MAX_DDR2];
292 u8 dimm_mask = 0;
293
294 memset(saved_timings, 0, sizeof(*saved_timings));
295 saved_timings->max_tRR = UINT32_MAX;
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200296 saved_timings->cas_mask = SPD_CAS_LATENCY_DDR2_3 | SPD_CAS_LATENCY_DDR2_4
297 | SPD_CAS_LATENCY_DDR2_5;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000298
299 /**
300 * i945 supports two DIMMs, in two configurations:
301 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000302 * - single channel with two DIMMs
303 * - dual channel with one DIMM per channel
Stefan Reinauer278534d2008-10-29 04:51:07 +0000304 *
Uwe Hermannd773fd32010-11-20 20:23:08 +0000305 * In practice dual channel mainboards have their SPD at 0x50/0x52
306 * whereas single channel configurations have their SPD at 0x50/0x51.
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000307 *
Stefan Reinauer278534d2008-10-29 04:51:07 +0000308 * The capability register knows a lot about the channel configuration
Uwe Hermannd773fd32010-11-20 20:23:08 +0000309 * but for now we stick with the information we gather via SPD.
Stefan Reinauer278534d2008-10-29 04:51:07 +0000310 */
311
Arthur Heymans0ab49042017-02-06 22:40:14 +0100312 printk(BIOS_DEBUG, "This mainboard supports ");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000313 if (sdram_capabilities_dual_channel()) {
Elyes Haouas49446092022-09-28 14:14:05 +0200314 sysinfo->dual_channel = true;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100315 printk(BIOS_DEBUG, "Dual Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000316 } else {
Elyes Haouas49446092022-09-28 14:14:05 +0200317 sysinfo->dual_channel = false;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100318 printk(BIOS_DEBUG, "only Single Channel Operation.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000319 }
320
Arthur Heymans70a8e342017-03-09 11:30:23 +0100321 for (i = 0; i < (2 * DIMM_SOCKETS); i++) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100322 int device = get_dimm_spd_address(sysinfo, i), bytes_read;
Arthur Heymansfc31e442018-02-12 15:12:34 +0100323 struct dimm_attr_ddr2_st dimm_info;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000324
325 /* Initialize the socket information with a sane value */
326 sysinfo->dimm[i] = SYSINFO_DIMM_NOT_POPULATED;
327
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000328 /* Dual Channel not supported, but Channel 1? Bail out */
329 if (!sdram_capabilities_dual_channel() && (i >> 1))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000330 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000331
Kyösti Mälkkibd659852020-01-05 20:00:18 +0200332 if (smbus_read_byte(device, SPD_MEMORY_TYPE) !=
Arthur Heymans0ab49042017-02-06 22:40:14 +0100333 SPD_MEMORY_TYPE_SDRAM_DDR2) {
334 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: N/A\n",
335 (i >> 1), (i & 1));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000336 continue;
337 }
338
Arthur Heymans0ab49042017-02-06 22:40:14 +0100339 /*
340 * spd_decode_ddr2() needs a 128-byte sized array but
341 * only the first 64 bytes contain data needed for raminit.
342 */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000343
Kyösti Mälkkic01a5052019-01-30 09:39:23 +0200344 bytes_read = i2c_eeprom_read(device, 0, 64, raw_spd);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100345 printk(BIOS_DEBUG, "Reading SPD using i2c block operation.\n");
Julius Wernercd49cce2019-03-05 16:53:33 -0800346 if (CONFIG(DEBUG_RAM_SETUP) && bytes_read > 0)
Arthur Heymans0ab49042017-02-06 22:40:14 +0100347 hexdump(raw_spd, bytes_read);
Arthur Heymans56619452017-09-21 09:12:42 +0200348 if (bytes_read != 64) {
Arthur Heymans0ab49042017-02-06 22:40:14 +0100349 /* Try again with SMBUS byte read */
350 printk(BIOS_DEBUG, "i2c block operation failed,"
Paul Menzel105e3682017-09-21 08:11:05 +0200351 " trying smbus byte operation.\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100352 for (j = 0; j < 64; j++)
Kyösti Mälkkibd659852020-01-05 20:00:18 +0200353 raw_spd[j] = smbus_read_byte(device, j);
Julius Wernercd49cce2019-03-05 16:53:33 -0800354 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100355 hexdump(raw_spd, 64);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100356 }
Arthur Heymans56619452017-09-21 09:12:42 +0200357
358 if (spd_decode_ddr2(&dimm_info, raw_spd) != SPD_STATUS_OK) {
359 printk(BIOS_WARNING, "Encountered problems with SPD, "
360 "skipping this DIMM.\n");
361 continue;
362 }
363
Julius Wernercd49cce2019-03-05 16:53:33 -0800364 if (CONFIG(DEBUG_RAM_SETUP))
Arthur Heymans0ab49042017-02-06 22:40:14 +0100365 dram_print_spd_ddr2(&dimm_info);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000366
Arthur Heymans0ab49042017-02-06 22:40:14 +0100367 if (dimm_info.flags.is_ecc)
368 die("\nError: ECC memory not supported by this chipset\n");
369
370 if (spd_dimm_is_registered_ddr2(dimm_info.dimm_type))
371 die("\nError: Registered memory not supported by this chipset\n");
372
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200373 printk(BIOS_DEBUG, "DDR II Channel %d Socket %d: ", (i >> 1), (i & 1));
Arthur Heymans0ab49042017-02-06 22:40:14 +0100374 /**
375 * There are 5 different possible populations for a DIMM socket:
376 * 0. x16 double ranked (X16DS)
377 * 1. x8 double ranked (X8DS)
378 * 2. x16 single ranked (X16SS)
379 * 3. x8 double stacked (X8DDS)
380 * 4. Unpopulated
381 */
382 switch (dimm_info.width) {
383 case 8:
384 switch (dimm_info.ranks) {
385 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000386 printk(BIOS_DEBUG, "x8DDS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000387 sysinfo->dimm[i] = SYSINFO_DIMM_X8DDS;
388 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100389 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000390 printk(BIOS_DEBUG, "x8DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000391 sysinfo->dimm[i] = SYSINFO_DIMM_X8DS;
392 break;
393 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000394 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000395 }
396 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100397 case 16:
398 switch (dimm_info.ranks) {
399 case 2:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000400 printk(BIOS_DEBUG, "x16DS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000401 sysinfo->dimm[i] = SYSINFO_DIMM_X16DS;
402 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100403 case 1:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000404 printk(BIOS_DEBUG, "x16SS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000405 sysinfo->dimm[i] = SYSINFO_DIMM_X16SS;
406 break;
407 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000408 printk(BIOS_DEBUG, "Unsupported.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000409 }
410 break;
411 default:
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000412 die("Unsupported DDR-II memory width.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000413 }
414
Arthur Heymans0ab49042017-02-06 22:40:14 +0100415 /* Is the current DIMM a stacked DIMM? */
416 if (dimm_info.flags.stacked)
417 sysinfo->package = SYSINFO_PACKAGE_STACKED;
418
419 if (!dimm_info.flags.bl8)
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100420 die("Only DDR-II RAM with burst length 8 is supported.\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100421
422 if (dimm_info.ranksize_mb < 128)
423 die("DDR-II rank size smaller than 128MB is not supported.\n");
424
425 sysinfo->banksize[i * 2] = dimm_info.ranksize_mb / 32;
Elyes Haouas26fc2a42022-10-07 11:25:25 +0200426 printk(BIOS_DEBUG, "DIMM %d side 0 = %zu MB\n", i,
427 sysinfo->banksize[i * 2] * 32);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100428 if (dimm_info.ranks == 2) {
429 sysinfo->banksize[(i * 2) + 1] =
430 dimm_info.ranksize_mb / 32;
Elyes Haouas26fc2a42022-10-07 11:25:25 +0200431 printk(BIOS_DEBUG, "DIMM %d side 1 = %zu MB\n",
Arthur Heymans0ab49042017-02-06 22:40:14 +0100432 i, sysinfo->banksize[(i * 2) + 1] * 32);
433 }
434
Arthur Heymans0ab49042017-02-06 22:40:14 +0100435 sysinfo->rows[i] = dimm_info.row_bits;
436 sysinfo->cols[i] = dimm_info.col_bits;
437 sysinfo->banks[i] = dimm_info.banks;
438
439 /* int min_tRAS, min_tRP, min_tRCD, min_tWR, min_tRFC; */
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200440 saved_timings->min_tRAS = MAX(saved_timings->min_tRAS, dimm_info.tRAS);
441 saved_timings->min_tRP = MAX(saved_timings->min_tRP, dimm_info.tRP);
442 saved_timings->min_tRCD = MAX(saved_timings->min_tRCD, dimm_info.tRCD);
443 saved_timings->min_tWR = MAX(saved_timings->min_tWR, dimm_info.tWR);
444 saved_timings->min_tRFC = MAX(saved_timings->min_tRFC, dimm_info.tRFC);
445 saved_timings->max_tRR = MIN(saved_timings->max_tRR, dimm_info.tRR);
Arthur Heymans0ab49042017-02-06 22:40:14 +0100446 saved_timings->cas_mask &= dimm_info.cas_supported;
447 for (j = 0; j < 8; j++) {
448 if (!(saved_timings->cas_mask & (1 << j)))
449 saved_timings->min_tCLK_cas[j] = 0;
450 else
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200451 saved_timings->min_tCLK_cas[j] = MAX(dimm_info.cycle_time[j],
Arthur Heymans0ab49042017-02-06 22:40:14 +0100452 saved_timings->min_tCLK_cas[j]);
453 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000454 dimm_mask |= (1 << i);
455 }
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200456 if (!dimm_mask)
Stefan Reinauer779b3e32008-11-10 15:43:37 +0000457 die("No memory installed.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000458
Elyes HAOUAS9749a852018-05-09 19:06:46 +0200459 if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1)))
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100460 /* FIXME: Possibly does not boot in this case */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000461 printk(BIOS_INFO, "Channel 0 has no memory populated.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000462}
463
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200464static void choose_tclk(struct sys_info *sysinfo, struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000465{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100466 u32 ctrl_min_tclk;
467 int try_cas;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000468
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200469 ctrl_min_tclk = 2 * 256 * 1000 / sdram_capabilities_max_supported_memory_frequency();
Arthur Heymans0ab49042017-02-06 22:40:14 +0100470 normalize_tck(&ctrl_min_tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000471
Arthur Heymans0ab49042017-02-06 22:40:14 +0100472 try_cas = spd_get_msbs(saved_timings->cas_mask);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000473
Arthur Heymans0ab49042017-02-06 22:40:14 +0100474 while (saved_timings->cas_mask & (1 << try_cas) && try_cas > 0) {
475 sysinfo->cas = try_cas;
476 sysinfo->tclk = saved_timings->min_tCLK_cas[try_cas];
477 if (sysinfo->tclk >= ctrl_min_tclk &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200478 saved_timings->min_tCLK_cas[try_cas] !=
479 saved_timings->min_tCLK_cas[try_cas - 1])
Stefan Reinauer278534d2008-10-29 04:51:07 +0000480 break;
Arthur Heymans0ab49042017-02-06 22:40:14 +0100481 try_cas--;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000482 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000483
Arthur Heymans0ab49042017-02-06 22:40:14 +0100484 normalize_tck(&sysinfo->tclk);
485
486 if ((sysinfo->cas < 3) || (sysinfo->tclk == 0))
Stefan Reinauer278534d2008-10-29 04:51:07 +0000487 die("Could not find common memory frequency and CAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000488
Arthur Heymans0ab49042017-02-06 22:40:14 +0100489 /*
490 * The loop can still results in a timing too fast for the
491 * memory controller.
492 */
493 if (sysinfo->tclk < ctrl_min_tclk)
494 sysinfo->tclk = ctrl_min_tclk;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000495
Arthur Heymans0ab49042017-02-06 22:40:14 +0100496 switch (sysinfo->tclk) {
497 case TCK_200MHZ:
498 sysinfo->memory_frequency = 400;
499 break;
500 case TCK_266MHZ:
501 sysinfo->memory_frequency = 533;
502 break;
503 case TCK_333MHZ:
504 sysinfo->memory_frequency = 667;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100505 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000506 }
507
Arthur Heymans0ab49042017-02-06 22:40:14 +0100508 printk(BIOS_DEBUG,
509 "Memory will be driven at %dMT with CAS=%d clocks\n",
510 sysinfo->memory_frequency, sysinfo->cas);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000511}
512
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200513static void derive_timings(struct sys_info *sysinfo, struct timings *saved_timings)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000514{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100515 sysinfo->tras = DIV_ROUND_UP(saved_timings->min_tRAS, sysinfo->tclk);
516 if (sysinfo->tras > 0x18)
517 die("DDR-II Module does not support this frequency (tRAS error)\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000518
Arthur Heymans0ab49042017-02-06 22:40:14 +0100519 sysinfo->trp = DIV_ROUND_UP(saved_timings->min_tRP, sysinfo->tclk);
520 if (sysinfo->trp > 6)
521 die("DDR-II Module does not support this frequency (tRP error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000522
Arthur Heymans0ab49042017-02-06 22:40:14 +0100523 sysinfo->trcd = DIV_ROUND_UP(saved_timings->min_tRCD, sysinfo->tclk);
524 if (sysinfo->trcd > 6)
525 die("DDR-II Module does not support this frequency (tRCD error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000526
Arthur Heymans0ab49042017-02-06 22:40:14 +0100527 sysinfo->twr = DIV_ROUND_UP(saved_timings->min_tWR, sysinfo->tclk);
528 if (sysinfo->twr > 5)
529 die("DDR-II Module does not support this frequency (tWR error)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000530
Arthur Heymans0ab49042017-02-06 22:40:14 +0100531 sysinfo->trfc = DIV_ROUND_UP(saved_timings->min_tRFC, sysinfo->tclk);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000532
Arthur Heymans0ab49042017-02-06 22:40:14 +0100533 printk(BIOS_DEBUG, "tRAS = %d cycles\n", sysinfo->tras);
534 printk(BIOS_DEBUG, "tRP = %d cycles\n", sysinfo->trp);
535 printk(BIOS_DEBUG, "tRCD = %d cycles\n", sysinfo->trcd);
536 printk(BIOS_DEBUG, "tWR = %d cycles\n", sysinfo->twr);
537 printk(BIOS_DEBUG, "tRFC = %d cycles\n", sysinfo->trfc);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000538
Arthur Heymans0ab49042017-02-06 22:40:14 +0100539 /* Refresh is slower than 15.6us, use 15.6us */
540 /* tRR is decoded in units of 1/256us */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000541
Arthur Heymans0ab49042017-02-06 22:40:14 +0100542#define T_RR_7_8US 2000000
543#define T_RR_15_6US 4000000
544#define REFRESH_7_8US 1
545#define REFRESH_15_6US 0
Stefan Reinauer278534d2008-10-29 04:51:07 +0000546
Arthur Heymans0ab49042017-02-06 22:40:14 +0100547 if (saved_timings->max_tRR < T_RR_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000548 die("DDR-II module has unsupported refresh value\n");
Arthur Heymans0ab49042017-02-06 22:40:14 +0100549 else if (saved_timings->max_tRR < T_RR_15_6US)
550 sysinfo->refresh = REFRESH_7_8US;
551 else
552 sysinfo->refresh = REFRESH_15_6US;
Angel Pons30492572020-06-11 13:24:54 +0200553 printk(BIOS_DEBUG, "Refresh: %s\n", sysinfo->refresh ? "7.8us" : "15.6us");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000554}
555
Arthur Heymans0ab49042017-02-06 22:40:14 +0100556/**
557 * @brief Get generic DIMM parameters.
558 * @param sysinfo Central memory controller information structure
559 *
560 * This function gathers several pieces of information for each system DIMM:
561 * o DIMM width (x8 / x16)
562 * o DIMM rank (single ranked / dual ranked)
563 *
564 * Also, some non-supported scenarios are detected.
565 */
566
567static void sdram_get_dram_configuration(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000568{
Arthur Heymans0ab49042017-02-06 22:40:14 +0100569 struct timings saved_timings;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000570
Arthur Heymans0ab49042017-02-06 22:40:14 +0100571 gather_common_timing(sysinfo, &saved_timings);
572 choose_tclk(sysinfo, &saved_timings);
573 derive_timings(sysinfo, &saved_timings);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000574}
575
Arthur Heymans70a8e342017-03-09 11:30:23 +0100576static void sdram_program_dram_width(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +0000577{
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200578 u16 c0dramw = 0, c1dramw = 0;
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200579 int i, idx;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000580
581 if (sysinfo->dual_channel)
582 idx = 2;
583 else
584 idx = 1;
585
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200586 for (i = 0; i < DIMM_SOCKETS; i++) { /* Channel 0 */
587 switch (sysinfo->dimm[i]) {
588 case SYSINFO_DIMM_X16DS:
Angel Pons30492572020-06-11 13:24:54 +0200589 c0dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200590 break;
591 case SYSINFO_DIMM_X8DS:
Angel Pons30492572020-06-11 13:24:54 +0200592 c0dramw |= (0x0001) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200593 break;
594 case SYSINFO_DIMM_X16SS:
Angel Pons30492572020-06-11 13:24:54 +0200595 c0dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200596 break;
597 case SYSINFO_DIMM_X8DDS:
Angel Pons30492572020-06-11 13:24:54 +0200598 c0dramw |= (0x0005) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200599 break;
600 case SYSINFO_DIMM_NOT_POPULATED:
Angel Pons30492572020-06-11 13:24:54 +0200601 c0dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200602 break;
603 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000604 }
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200605 for (i = DIMM_SOCKETS; i < idx * DIMM_SOCKETS; i++) { /* Channel 1 */
606 switch (sysinfo->dimm[i]) {
607 case SYSINFO_DIMM_X16DS:
Angel Pons30492572020-06-11 13:24:54 +0200608 c1dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200609 break;
610 case SYSINFO_DIMM_X8DS:
Angel Pons30492572020-06-11 13:24:54 +0200611 c1dramw |= (0x0010) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200612 break;
613 case SYSINFO_DIMM_X16SS:
Angel Pons30492572020-06-11 13:24:54 +0200614 c1dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200615 break;
616 case SYSINFO_DIMM_X8DDS:
Angel Pons30492572020-06-11 13:24:54 +0200617 c1dramw |= (0x0050) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200618 break;
619 case SYSINFO_DIMM_NOT_POPULATED:
Angel Pons30492572020-06-11 13:24:54 +0200620 c1dramw |= (0x0000) << 4 * (i % 2);
Elyes HAOUASa4fc7be2018-06-30 10:39:24 +0200621 break;
622 }
Stefan Reinauer278534d2008-10-29 04:51:07 +0000623 }
624
Angel Pons1d4044a2021-03-27 19:11:51 +0100625 mchbar_write16(C0DRAMW, c0dramw);
626 mchbar_write16(C1DRAMW, c1dramw);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000627}
628
629static void sdram_write_slew_rates(u32 offset, const u32 *slew_rate_table)
630{
631 int i;
632
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +0200633 for (i = 0; i < 16; i++)
Angel Pons1d4044a2021-03-27 19:11:51 +0100634 mchbar_write32(offset + (i * 4), slew_rate_table[i]);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000635}
636
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000637static const u32 dq2030[] = {
638 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
639 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
640 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
641 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
642};
643
644static const u32 dq2330[] = {
645 0x08070706, 0x0a090908, 0x0d0c0b0a, 0x12100f0e,
646 0x1a181614, 0x22201e1c, 0x2a282624, 0x3934302d,
647 0x0a090908, 0x0c0b0b0a, 0x0e0d0d0c, 0x1211100f,
648 0x19171513, 0x211f1d1b, 0x2d292623, 0x3f393531
649};
650
651static const u32 cmd2710[] = {
652 0x07060605, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
653 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
654 0x1110100f, 0x0f0d0b09, 0x19171411, 0x1f1f1d1b,
655 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
656};
657
658static const u32 cmd3210[] = {
659 0x0f0d0b0a, 0x17151311, 0x1f1d1b19, 0x1f1f1f1f,
660 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f,
661 0x18171615, 0x1f1f1c1a, 0x1f1f1f1f, 0x1f1f1f1f,
662 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f, 0x1f1f1f1f
663};
664
665static const u32 clk2030[] = {
666 0x0e0d0d0c, 0x100f0f0e, 0x100f0e0d, 0x15131211,
667 0x1d1b1917, 0x2523211f, 0x2a282927, 0x32302e2c,
668 0x17161514, 0x1b1a1918, 0x1f1e1d1c, 0x23222120,
669 0x27262524, 0x2d2b2928, 0x3533312f, 0x3d3b3937
670};
671
672static const u32 ctl3215[] = {
673 0x01010000, 0x03020101, 0x07060504, 0x0b0a0908,
674 0x100f0e0d, 0x14131211, 0x18171615, 0x1c1b1a19,
675 0x05040403, 0x07060605, 0x0a090807, 0x0f0d0c0b,
676 0x14131211, 0x18171615, 0x1c1b1a19, 0x201f1e1d
677};
678
679static const u32 ctl3220[] = {
680 0x05040403, 0x07060505, 0x0e0c0a08, 0x1a171411,
681 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e,
682 0x09080807, 0x0b0a0a09, 0x0f0d0c0b, 0x1b171311,
683 0x2825221f, 0x35322f2b, 0x3e3e3b38, 0x3e3e3e3e
684};
685
686static const u32 nc[] = {
687 0x00000000, 0x00000000, 0x00000000, 0x00000000,
688 0x00000000, 0x00000000, 0x00000000, 0x00000000,
689 0x00000000, 0x00000000, 0x00000000, 0x00000000,
690 0x00000000, 0x00000000, 0x00000000, 0x00000000
691};
692
693enum {
694 DQ2030,
695 DQ2330,
696 CMD2710,
697 CMD3210,
698 CLK2030,
699 CTL3215,
700 CTL3220,
701 NC,
702};
703
704static const u8 dual_channel_slew_group_lookup[] = {
705 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
706 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
707 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
708 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
709 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
710
711 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
712 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
713 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
714 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
715 DQ2030, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
716
717 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
718 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
719 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
720 DQ2030, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD2710,
721 DQ2030, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
722
723 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
724 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
725 DQ2030, CMD2710, CTL3215, CTL3215, CLK2030, CLK2030, DQ2030, CMD3210,
726 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, DQ2030, CMD2710,
727 DQ2030, CMD2710, CTL3215, NC, CLK2030, NC, NC, NC,
728
729 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
730 NC, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
731 NC, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
732 NC, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD2710
733};
734
735static const u8 single_channel_slew_group_lookup[] = {
736 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
737 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
738 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
739 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
740 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
741
742 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
743 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
744 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
745 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
746 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
747
748 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
749 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
750 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, DQ2330, CMD3210,
751 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
752 DQ2330, CMD3210, NC, CTL3215, NC, CLK2030, NC, NC,
753
754 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
755 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
756 DQ2330, CMD3210, CTL3215, CTL3215, CLK2030, CLK2030, DQ2330, CMD3210,
757 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, DQ2330, CMD3210,
758 DQ2330, CMD3210, CTL3215, NC, CLK2030, NC, NC, NC,
759
760 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
761 DQ2330, NC, CTL3215, NC, CLK2030, NC, DQ2030, CMD3210,
762 DQ2330, NC, NC, CTL3215, NC, CLK2030, DQ2030, CMD3210,
763 DQ2330, NC, CTL3215, NC, CLK2030, CLK2030, DQ2030, CMD3210
764};
765
Elyes Haouas49446092022-09-28 14:14:05 +0200766static const u32 *slew_group_lookup(bool dual_channel, int index)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000767{
768 const u8 *slew_group;
769 /* Dual Channel needs different tables. */
770 if (dual_channel)
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100771 slew_group = dual_channel_slew_group_lookup;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000772 else
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100773 slew_group = single_channel_slew_group_lookup;
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000774
775 switch (slew_group[index]) {
776 case DQ2030: return dq2030;
777 case DQ2330: return dq2330;
778 case CMD2710: return cmd2710;
779 case CMD3210: return cmd3210;
780 case CLK2030: return clk2030;
781 case CTL3215: return ctl3215;
782 case CTL3220: return ctl3220;
783 case NC: return nc;
784 }
785
786 return nc;
787}
788
Julius Wernercd49cce2019-03-05 16:53:33 -0800789#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000790/* Strength multiplier tables */
791static const u8 dual_channel_strength_multiplier[] = {
792 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
793 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
794 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
795 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
796 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
797 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
798 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
799 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
800 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
801 0x44, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
802 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
803 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
804 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
805 0x44, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x22,
806 0x44, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
807 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
808 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
809 0x44, 0x22, 0x11, 0x11, 0x44, 0x44, 0x44, 0x11,
810 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x44, 0x22,
811 0x44, 0x22, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
812 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
813 0x00, 0x00, 0x11, 0x00, 0x44, 0x00, 0x44, 0x11,
814 0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x11,
815 0x00, 0x00, 0x11, 0x00, 0x44, 0x44, 0x44, 0x22
816};
817
818static const u8 single_channel_strength_multiplier[] = {
819 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
820 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
821 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
822 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
823 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
824 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
825 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
826 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
827 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
828 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
829 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
830 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
831 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
832 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
833 0x33, 0x11, 0x00, 0x11, 0x00, 0x44, 0x00, 0x00,
834 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
835 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
836 0x33, 0x11, 0x11, 0x11, 0x44, 0x44, 0x33, 0x11,
837 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
838 0x33, 0x11, 0x11, 0x00, 0x44, 0x00, 0x00, 0x00,
839 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
840 0x33, 0x00, 0x11, 0x00, 0x44, 0x00, 0x33, 0x11,
841 0x33, 0x00, 0x00, 0x11, 0x00, 0x44, 0x33, 0x11,
842 0x33, 0x00, 0x11, 0x00, 0x44, 0x44, 0x33, 0x11
843};
Julius Wernercd49cce2019-03-05 16:53:33 -0800844#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000845static const u8 dual_channel_strength_multiplier[] = {
846 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
847 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
848 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
849 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
850 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
851 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
852 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
853 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
854 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
855 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
856 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
857 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
858 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
859 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
860 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
861 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
862 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
863 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
864 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33,
865 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
866 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
867 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
868 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x22,
869 0x44, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x33
870};
871
872static const u8 single_channel_strength_multiplier[] = {
873 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
874 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
875 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
876 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
877 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
878 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
879 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
880 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
881 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
882 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
883 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
884 0x44, 0x44, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
885 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
886 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
887 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
888 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
889 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
890 0x44, 0x55, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
891 0x44, 0x88, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
892 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
893 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
894 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
895 0x44, 0x22, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00,
896 0x44, 0x33, 0x00, 0x00, 0x44, 0x44, 0x44, 0x00
897};
898#endif
899
Stefan Reinauer278534d2008-10-29 04:51:07 +0000900static void sdram_rcomp_buffer_strength_and_slew(struct sys_info *sysinfo)
901{
Arthur Heymans70a8e342017-03-09 11:30:23 +0100902 const u8 *strength_multiplier;
Elyes Haouas49446092022-09-28 14:14:05 +0200903 int idx;
904 bool dual_channel;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000905
906 /* Set Strength Multipliers */
907
908 /* Dual Channel needs different tables. */
909 if (sdram_capabilities_dual_channel()) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000910 printk(BIOS_DEBUG, "Programming Dual Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000911 strength_multiplier = dual_channel_strength_multiplier;
Elyes Haouas49446092022-09-28 14:14:05 +0200912 dual_channel = true;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +0100913 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[2];
Stefan Reinauer278534d2008-10-29 04:51:07 +0000914 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000915 printk(BIOS_DEBUG, "Programming Single Channel RCOMP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +0000916 strength_multiplier = single_channel_strength_multiplier;
Elyes Haouas49446092022-09-28 14:14:05 +0200917 dual_channel = false;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000918 idx = 5 * sysinfo->dimm[0] + sysinfo->dimm[1];
919 }
920
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000921 printk(BIOS_DEBUG, "Table Index: %d\n", idx);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000922
Angel Pons1d4044a2021-03-27 19:11:51 +0100923 mchbar_write8(G1SC, strength_multiplier[idx * 8 + 0]);
924 mchbar_write8(G2SC, strength_multiplier[idx * 8 + 1]);
925 mchbar_write8(G3SC, strength_multiplier[idx * 8 + 2]);
926 mchbar_write8(G4SC, strength_multiplier[idx * 8 + 3]);
927 mchbar_write8(G5SC, strength_multiplier[idx * 8 + 4]);
928 mchbar_write8(G6SC, strength_multiplier[idx * 8 + 5]);
929 mchbar_write8(G7SC, strength_multiplier[idx * 8 + 6]);
930 mchbar_write8(G8SC, strength_multiplier[idx * 8 + 7]);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000931
932 /* Channel 0 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000933 sdram_write_slew_rates(G1SRPUT, slew_group_lookup(dual_channel, idx * 8 + 0));
934 sdram_write_slew_rates(G2SRPUT, slew_group_lookup(dual_channel, idx * 8 + 1));
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200935 if ((slew_group_lookup(dual_channel, idx * 8 + 2) != nc) &&
936 (sysinfo->package == SYSINFO_PACKAGE_STACKED))
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000937
Stefan Reinauer278534d2008-10-29 04:51:07 +0000938 sdram_write_slew_rates(G3SRPUT, ctl3220);
Arthur Heymans70a8e342017-03-09 11:30:23 +0100939 else
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000940 sdram_write_slew_rates(G3SRPUT, slew_group_lookup(dual_channel, idx * 8 + 2));
Arthur Heymans70a8e342017-03-09 11:30:23 +0100941
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000942 sdram_write_slew_rates(G4SRPUT, slew_group_lookup(dual_channel, idx * 8 + 3));
943 sdram_write_slew_rates(G5SRPUT, slew_group_lookup(dual_channel, idx * 8 + 4));
944 sdram_write_slew_rates(G6SRPUT, slew_group_lookup(dual_channel, idx * 8 + 5));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000945
946 /* Channel 1 */
947 if (sysinfo->dual_channel) {
Stefan Reinauer24b4df52010-01-17 13:47:35 +0000948 sdram_write_slew_rates(G7SRPUT, slew_group_lookup(dual_channel, idx * 8 + 6));
949 sdram_write_slew_rates(G8SRPUT, slew_group_lookup(dual_channel, idx * 8 + 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +0000950 } else {
951 sdram_write_slew_rates(G7SRPUT, nc);
952 sdram_write_slew_rates(G8SRPUT, nc);
953 }
954}
955
956static void sdram_enable_rcomp(void)
957{
958 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000959 /* Enable Global Periodic RCOMP */
Stefan Reinauer278534d2008-10-29 04:51:07 +0000960 udelay(300);
Angel Pons1d4044a2021-03-27 19:11:51 +0100961 reg32 = mchbar_read32(GBRCOMPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000962 reg32 &= ~(1 << 23);
Angel Pons1d4044a2021-03-27 19:11:51 +0100963 mchbar_write32(GBRCOMPCTL, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000964}
965
966static void sdram_program_dll_timings(struct sys_info *sysinfo)
967{
Elyes HAOUAS44a30662017-02-23 13:14:44 +0100968 u32 channeldll = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +0000969 int i;
970
Elyes HAOUAS38424982016-08-21 12:01:04 +0200971 printk(BIOS_DEBUG, "Programming DLL Timings...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +0000972
Angel Pons1d4044a2021-03-27 19:11:51 +0100973 mchbar_clrbits16(DQSMT, 3 << 12 | 1 << 10 | 0xf << 0);
974 mchbar_setbits16(DQSMT, 1 << 13 | 0xc << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +0000975
976 /* We drive both channels with the same speed */
Julius Wernercd49cce2019-03-05 16:53:33 -0800977 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +0100978 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +0100979 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200980 channeldll = 0x26262626;
981 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100982 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200983 channeldll = 0x22222222;
984 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100985 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200986 channeldll = 0x11111111;
987 break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +0100988 }
Julius Wernercd49cce2019-03-05 16:53:33 -0800989 } else if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +0100990 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +0100991 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200992 channeldll = 0x33333333;
993 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100994 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200995 channeldll = 0x24242424;
996 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +0100997 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +0200998 channeldll = 0x25252525;
999 break;
Elyes HAOUAS39bfc6c2016-10-31 10:49:33 +01001000 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001001 }
1002
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001003 for (i = 0; i < 4; i++) {
Angel Pons1d4044a2021-03-27 19:11:51 +01001004 mchbar_write32(C0R0B00DQST + (i * 0x10) + 0, channeldll);
1005 mchbar_write32(C0R0B00DQST + (i * 0x10) + 4, channeldll);
1006 mchbar_write32(C1R0B00DQST + (i * 0x10) + 0, channeldll);
1007 mchbar_write32(C1R0B00DQST + (i * 0x10) + 4, channeldll);
Julius Wernercd49cce2019-03-05 16:53:33 -08001008 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)) {
Angel Pons1d4044a2021-03-27 19:11:51 +01001009 mchbar_write8(C0R0B00DQST + (i * 0x10) + 8, channeldll & 0xff);
1010 mchbar_write8(C1R0B00DQST + (i * 0x10) + 8, channeldll & 0xff);
Paul Menzelbce7e332017-02-22 18:46:27 +01001011 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001012 }
1013}
1014
1015static void sdram_force_rcomp(void)
1016{
1017 u32 reg32;
1018 u8 reg8;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001019
Angel Pons1d4044a2021-03-27 19:11:51 +01001020 reg32 = mchbar_read32(ODTC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001021 reg32 |= (1 << 28);
Angel Pons1d4044a2021-03-27 19:11:51 +01001022 mchbar_write32(ODTC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001023
Angel Pons1d4044a2021-03-27 19:11:51 +01001024 reg32 = mchbar_read32(SMSRCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001025 reg32 |= (1 << 0);
Angel Pons1d4044a2021-03-27 19:11:51 +01001026 mchbar_write32(SMSRCTL, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001027
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001028 /* Start initial RCOMP */
Angel Pons1d4044a2021-03-27 19:11:51 +01001029 reg32 = mchbar_read32(GBRCOMPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001030 reg32 |= (1 << 8);
Angel Pons1d4044a2021-03-27 19:11:51 +01001031 mchbar_write32(GBRCOMPCTL, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001032
1033 reg8 = i945_silicon_revision();
Angel Pons1d4044a2021-03-27 19:11:51 +01001034 if ((reg8 == 0 && (mchbar_read32(DCC) & (3 << 0)) == 0) || (reg8 == 1)) {
1035 reg32 = mchbar_read32(GBRCOMPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001036 reg32 |= (3 << 5);
Angel Pons1d4044a2021-03-27 19:11:51 +01001037 mchbar_write32(GBRCOMPCTL, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001038 }
1039}
1040
1041static void sdram_initialize_system_memory_io(struct sys_info *sysinfo)
1042{
1043 u8 reg8;
1044 u32 reg32;
1045
Elyes HAOUAS38424982016-08-21 12:01:04 +02001046 printk(BIOS_DEBUG, "Initializing System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001047 /* Enable Data Half Clock Pushout */
Angel Pons1d4044a2021-03-27 19:11:51 +01001048 reg8 = mchbar_read8(C0HCTC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001049 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001050 reg8 |= (1 << 0);
Angel Pons1d4044a2021-03-27 19:11:51 +01001051 mchbar_write8(C0HCTC, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001052
Angel Pons1d4044a2021-03-27 19:11:51 +01001053 reg8 = mchbar_read8(C1HCTC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001054 reg8 &= ~0x1f;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001055 reg8 |= (1 << 0);
Angel Pons1d4044a2021-03-27 19:11:51 +01001056 mchbar_write8(C1HCTC, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001057
Angel Pons1d4044a2021-03-27 19:11:51 +01001058 mchbar_clrbits16(WDLLBYPMODE, 1 << 9 | 1 << 6 | 1 << 4 | 1 << 3 | 1 << 1);
1059 mchbar_setbits16(WDLLBYPMODE, 1 << 8 | 1 << 7 | 1 << 5 | 1 << 2 | 1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001060
Angel Pons1d4044a2021-03-27 19:11:51 +01001061 mchbar_write8(C0WDLLCMC, 0);
1062 mchbar_write8(C1WDLLCMC, 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001063
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001064 /* Program RCOMP Settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001065 sdram_program_dram_width(sysinfo);
1066
1067 sdram_rcomp_buffer_strength_and_slew(sysinfo);
1068
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001069 /* Indicate that RCOMP programming is done */
Angel Pons1d4044a2021-03-27 19:11:51 +01001070 reg32 = mchbar_read32(GBRCOMPCTL);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001071 reg32 &= ~((1 << 29) | (1 << 26) | (3 << 21) | (3 << 2));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001072 reg32 |= (3 << 27) | (3 << 0);
Angel Pons1d4044a2021-03-27 19:11:51 +01001073 mchbar_write32(GBRCOMPCTL, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001074
Angel Pons1d4044a2021-03-27 19:11:51 +01001075 mchbar_setbits32(GBRCOMPCTL, 1 << 10);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001076
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001077 /* Program DLL Timings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001078 sdram_program_dll_timings(sysinfo);
1079
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001080 /* Force RCOMP cycle */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001081 sdram_force_rcomp();
1082}
1083
1084static void sdram_enable_system_memory_io(struct sys_info *sysinfo)
1085{
1086 u32 reg32;
1087
Elyes HAOUAS38424982016-08-21 12:01:04 +02001088 printk(BIOS_DEBUG, "Enabling System Memory IO...\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001089
Angel Pons1d4044a2021-03-27 19:11:51 +01001090 reg32 = mchbar_read32(RCVENMT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001091 reg32 &= ~(0x3f << 6);
Angel Pons1d4044a2021-03-27 19:11:51 +01001092 mchbar_write32(RCVENMT, reg32); /* [11:6] = 0 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001093
1094 reg32 |= (1 << 11) | (1 << 9);
Angel Pons1d4044a2021-03-27 19:11:51 +01001095 mchbar_write32(RCVENMT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001096
Angel Pons1d4044a2021-03-27 19:11:51 +01001097 reg32 = mchbar_read32(DRTST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001098 reg32 |= (1 << 3) | (1 << 2);
Angel Pons1d4044a2021-03-27 19:11:51 +01001099 mchbar_write32(DRTST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001100
Angel Pons1d4044a2021-03-27 19:11:51 +01001101 reg32 = mchbar_read32(DRTST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001102 reg32 |= (1 << 6) | (1 << 4);
Angel Pons1d4044a2021-03-27 19:11:51 +01001103 mchbar_write32(DRTST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001104
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001105 asm volatile ("nop; nop;" ::: "memory");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001106
Angel Pons1d4044a2021-03-27 19:11:51 +01001107 reg32 = mchbar_read32(DRTST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001108
1109 /* Is channel 0 populated? */
1110 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001111 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001112 reg32 |= (1 << 7) | (1 << 5);
1113 else
1114 reg32 |= (1 << 31);
1115
1116 /* Is channel 1 populated? */
1117 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001118 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001119 reg32 |= (1 << 9) | (1 << 8);
1120 else
1121 reg32 |= (1 << 30);
1122
Angel Pons1d4044a2021-03-27 19:11:51 +01001123 mchbar_write32(DRTST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001124
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001125 /* Activate DRAM Channel IO Buffers */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001126 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001127 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) {
Angel Pons1d4044a2021-03-27 19:11:51 +01001128 reg32 = mchbar_read32(C0DRC1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001129 reg32 |= (1 << 8);
Angel Pons1d4044a2021-03-27 19:11:51 +01001130 mchbar_write32(C0DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001131 }
1132 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001133 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED) {
Angel Pons1d4044a2021-03-27 19:11:51 +01001134 reg32 = mchbar_read32(C1DRC1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001135 reg32 |= (1 << 8);
Angel Pons1d4044a2021-03-27 19:11:51 +01001136 mchbar_write32(C1DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001137 }
1138}
1139
Stefan Reinauer278534d2008-10-29 04:51:07 +00001140static int sdram_program_row_boundaries(struct sys_info *sysinfo)
1141{
1142 int i;
Elyes Haouas26fc2a42022-10-07 11:25:25 +02001143 size_t cum0, cum1, tolud, tom, pci_mmio_size;
Arthur Heymans885c2892016-10-03 17:16:48 +02001144 const struct device *dev;
1145 const struct northbridge_intel_i945_config *cfg = NULL;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001146
Paul Menzel84283bc2014-07-17 08:16:04 +02001147 printk(BIOS_DEBUG, "Setting RAM size...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001148
1149 cum0 = 0;
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001150 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001151 cum0 += sysinfo->banksize[i];
Angel Pons1d4044a2021-03-27 19:11:51 +01001152 mchbar_write8(C0DRB0 + i, cum0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001153 }
1154
1155 /* Assume we continue in Channel 1 where we stopped in Channel 0 */
1156 cum1 = cum0;
1157
1158 /* Exception: Interleaved starts from the beginning */
1159 if (sysinfo->interleaved)
1160 cum1 = 0;
1161
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001162 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001163 cum1 += sysinfo->banksize[i + 4];
Angel Pons1d4044a2021-03-27 19:11:51 +01001164 mchbar_write8(C1DRB0 + i, cum1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001165 }
1166
1167 /* Set TOLUD Top Of Low Usable DRAM */
1168 if (sysinfo->interleaved)
1169 tolud = (cum0 + cum1) << 1;
1170 else
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001171 tolud = (cum1 ? cum1 : cum0) << 1;
Stefan Reinauer779b3e32008-11-10 15:43:37 +00001172
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001173 /* The TOM register has a different format */
1174 tom = tolud >> 3;
1175
1176 /* Limit the value of TOLUD to leave some space for PCI memory. */
Kyösti Mälkkic70eed12018-05-22 02:18:00 +03001177 dev = pcidev_on_root(0, 0);
Arthur Heymans885c2892016-10-03 17:16:48 +02001178 if (dev)
1179 cfg = dev->chip_info;
1180
1181 /* Don't use pci mmio sizes smaller than 768M */
1182 if (!cfg || cfg->pci_mmio_size <= DEFAULT_PCI_MMIO_SIZE)
1183 pci_mmio_size = DEFAULT_PCI_MMIO_SIZE;
1184 else
1185 pci_mmio_size = cfg->pci_mmio_size;
1186
1187 tolud = MIN(((4096 - pci_mmio_size) / 128) << 3, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001188
Angel Pons3580d812020-06-11 14:13:33 +02001189 pci_write_config8(HOST_BRIDGE, TOLUD, tolud);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001190
Angel Pons1d4044a2021-03-27 19:11:51 +01001191 printk(BIOS_DEBUG, "C0DRB = 0x%08x\n", mchbar_read32(C0DRB0));
1192 printk(BIOS_DEBUG, "C1DRB = 0x%08x\n", mchbar_read32(C1DRB0));
Angel Pons3580d812020-06-11 14:13:33 +02001193 printk(BIOS_DEBUG, "TOLUD = 0x%04x\n", pci_read_config8(HOST_BRIDGE, TOLUD));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001194
Angel Pons3580d812020-06-11 14:13:33 +02001195 pci_write_config16(HOST_BRIDGE, TOM, tom);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001196
1197 return 0;
1198}
1199
Stefan Reinauer278534d2008-10-29 04:51:07 +00001200static int sdram_set_row_attributes(struct sys_info *sysinfo)
1201{
Arthur Heymans0ab49042017-02-06 22:40:14 +01001202 int i;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001203 u16 dra0 = 0, dra1 = 0, dra = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001204
Elyes HAOUAS38424982016-08-21 12:01:04 +02001205 printk(BIOS_DEBUG, "Setting row attributes...\n");
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001206 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001207 u8 columnsrows;
1208
Arthur Heymans70a8e342017-03-09 11:30:23 +01001209 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001210 continue;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001211
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001212 columnsrows = (sysinfo->rows[i] & 0x0f) | (sysinfo->cols[i] & 0xf) << 4;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001213
1214 switch (columnsrows) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001215 case 0x9d:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001216 dra = 2;
1217 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001218 case 0xad:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001219 dra = 3;
1220 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001221 case 0xbd:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001222 dra = 4;
1223 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001224 case 0xae:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001225 dra = 3;
1226 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001227 case 0xbe:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001228 dra = 4;
1229 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001230 default:
1231 die("Unsupported Rows/Columns. (DRA)");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001232 }
1233
1234 /* Double Sided DIMMs? */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001235 if (sysinfo->banksize[(2 * i) + 1] != 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001236 dra = (dra << 4) | dra;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001237
Stefan Reinauer278534d2008-10-29 04:51:07 +00001238 if (i < DIMM_SOCKETS)
Angel Pons30492572020-06-11 13:24:54 +02001239 dra0 |= (dra << (i * 8));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001240 else
Angel Pons30492572020-06-11 13:24:54 +02001241 dra1 |= (dra << ((i - DIMM_SOCKETS) * 8));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001242 }
1243
Angel Pons1d4044a2021-03-27 19:11:51 +01001244 mchbar_write16(C0DRA0, dra0);
1245 mchbar_write16(C1DRA0, dra1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001246
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001247 printk(BIOS_DEBUG, "C0DRA = 0x%04x\n", dra0);
1248 printk(BIOS_DEBUG, "C1DRA = 0x%04x\n", dra1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001249
1250 return 0;
1251}
1252
1253static void sdram_set_bank_architecture(struct sys_info *sysinfo)
1254{
1255 u32 off32;
1256 int i;
1257
Angel Pons1d4044a2021-03-27 19:11:51 +01001258 mchbar_clrbits16(C1BNKARC, 0xff);
1259 mchbar_clrbits16(C0BNKARC, 0xff);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001260
1261 off32 = C0BNKARC;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001262 for (i = 0; i < 2 * DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001263 /* Switch to second channel */
1264 if (i == DIMM_SOCKETS)
1265 off32 = C1BNKARC;
1266
1267 if (sysinfo->dimm[i] == SYSINFO_DIMM_NOT_POPULATED)
1268 continue;
1269
1270 if (sysinfo->banks[i] != 8)
1271 continue;
1272
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001273 printk(BIOS_SPEW, "DIMM%d has 8 banks.\n", i);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001274
1275 if (i & 1)
Angel Pons1d4044a2021-03-27 19:11:51 +01001276 mchbar_setbits16(off32, 5 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001277 else
Angel Pons1d4044a2021-03-27 19:11:51 +01001278 mchbar_setbits16(off32, 5 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001279 }
1280}
1281
Stefan Reinauer278534d2008-10-29 04:51:07 +00001282static void sdram_program_refresh_rate(struct sys_info *sysinfo)
1283{
1284 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001285
Arthur Heymans70a8e342017-03-09 11:30:23 +01001286 if (sysinfo->refresh == REFRESH_7_8US)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001287 reg32 = (2 << 8); /* Refresh enabled at 7.8us */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001288 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001289 reg32 = (1 << 8); /* Refresh enabled at 15.6us */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001290
Angel Pons1d4044a2021-03-27 19:11:51 +01001291 mchbar_clrbits32(C0DRC0, 7 << 8);
1292 mchbar_setbits32(C0DRC0, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001293
Angel Pons1d4044a2021-03-27 19:11:51 +01001294 mchbar_clrbits32(C1DRC0, 7 << 8);
1295 mchbar_setbits32(C1DRC0, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001296}
1297
1298static void sdram_program_cke_tristate(struct sys_info *sysinfo)
1299{
1300 u32 reg32;
1301 int i;
1302
Angel Pons1d4044a2021-03-27 19:11:51 +01001303 reg32 = mchbar_read32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001304
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001305 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001306 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001307 reg32 |= (1 << (16 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001308 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001309
Stefan Reinauer278534d2008-10-29 04:51:07 +00001310 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001311
Stefan Reinauer278534d2008-10-29 04:51:07 +00001312 reg32 |= (1 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01001313 mchbar_write32(C0DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001314
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001315 /* Do we have to do this if we're in Single Channel Mode? */
Angel Pons1d4044a2021-03-27 19:11:51 +01001316 reg32 = mchbar_read32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001317
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001318 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001319 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001320 reg32 |= (1 << (12 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001321 }
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001322
Stefan Reinauer278534d2008-10-29 04:51:07 +00001323 reg32 |= (1 << 12);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001324
Stefan Reinauer278534d2008-10-29 04:51:07 +00001325 reg32 |= (1 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01001326 mchbar_write32(C1DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001327}
1328
1329static void sdram_program_odt_tristate(struct sys_info *sysinfo)
1330{
1331 u32 reg32;
1332 int i;
1333
Angel Pons1d4044a2021-03-27 19:11:51 +01001334 reg32 = mchbar_read32(C0DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001335
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001336 for (i = 0; i < 4; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001337 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001338 reg32 |= (1 << (24 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001339 }
Angel Pons1d4044a2021-03-27 19:11:51 +01001340 mchbar_write32(C0DRC2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001341
Angel Pons1d4044a2021-03-27 19:11:51 +01001342 reg32 = mchbar_read32(C1DRC2);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001343
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001344 for (i = 4; i < 8; i++) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001345 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001346 reg32 |= (1 << (20 + i));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001347 }
Angel Pons1d4044a2021-03-27 19:11:51 +01001348 mchbar_write32(C1DRC2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001349}
1350
1351static void sdram_set_timing_and_control(struct sys_info *sysinfo)
1352{
Arthur Heymans25027232017-02-12 23:34:39 +01001353 u32 reg32, tRD_min;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001354 u32 tWTR;
1355 u32 temp_drt;
1356 int i, page_size;
1357
Edward O'Callaghan2f237c12014-05-25 06:24:39 +10001358 static const u8 cas_table[] = {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001359 2, 1, 0, 3
1360 };
1361
Angel Pons1d4044a2021-03-27 19:11:51 +01001362 reg32 = mchbar_read32(C0DRC0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001363 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001364 reg32 &= ~((1 << 13) | (1 << 12));
Angel Pons1d4044a2021-03-27 19:11:51 +01001365 mchbar_write32(C0DRC0, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001366
Angel Pons1d4044a2021-03-27 19:11:51 +01001367 reg32 = mchbar_read32(C1DRC0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001368 reg32 |= (1 << 2); /* Burst Length 8 */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001369 reg32 &= ~((1 << 13) | (1 << 12));
Angel Pons1d4044a2021-03-27 19:11:51 +01001370 mchbar_write32(C1DRC0, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001371
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001372 if (!sysinfo->dual_channel && sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED) {
Angel Pons1d4044a2021-03-27 19:11:51 +01001373 reg32 = mchbar_read32(C0DRC0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001374 reg32 |= (1 << 15);
Angel Pons1d4044a2021-03-27 19:11:51 +01001375 mchbar_write32(C0DRC0, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001376 }
1377
1378 sdram_program_refresh_rate(sysinfo);
1379
1380 sdram_program_cke_tristate(sysinfo);
1381
1382 sdram_program_odt_tristate(sysinfo);
1383
1384 /* Calculate DRT0 */
1385
1386 temp_drt = 0;
1387
1388 /* B2B Write Precharge (same bank) = CL-1 + BL/2 + tWR */
1389 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + sysinfo->twr;
1390 temp_drt |= (reg32 << 28);
1391
1392 /* Write Auto Precharge (same bank) = CL-1 + BL/2 + tWR + tRP */
1393 reg32 += sysinfo->trp;
1394 temp_drt |= (reg32 << 4);
1395
Arthur Heymans70a8e342017-03-09 11:30:23 +01001396 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001397 tWTR = 3; /* 667MHz */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001398 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001399 tWTR = 2; /* 400 and 533 */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001400
1401 /* B2B Write to Read Command Spacing */
1402 reg32 = (sysinfo->cas - 1) + (BURSTLENGTH / 2) + tWTR;
1403 temp_drt |= (reg32 << 24);
1404
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001405 /* CxDRT0 [23:22], [21:20], [19:18] [16] have fixed values */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001406 temp_drt |= ((1 << 22) | (3 << 20) | (1 << 18) | (0 << 16));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001407
Arthur Heymans25027232017-02-12 23:34:39 +01001408 /*
1409 * tRD is the delay the memory controller is waiting on the FSB,
1410 * in mclk domain.
1411 * This parameter is important for stability and performance.
1412 * Those values might not be optimal but seem stable.
1413 */
1414 tRD_min = sysinfo->cas;
Arthur Heymanse1897612016-10-15 23:29:18 +02001415 switch (sysinfo->fsb_frequency) {
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001416 case 533:
Arthur Heymanse1897612016-10-15 23:29:18 +02001417 break;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001418 case 667:
1419 tRD_min += 1;
Arthur Heymanse1897612016-10-15 23:29:18 +02001420 break;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001421 case 800:
1422 tRD_min += 2;
1423 break;
1424 case 1066:
1425 tRD_min += 3;
Arthur Heymanse1897612016-10-15 23:29:18 +02001426 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001427 }
Arthur Heymanse1897612016-10-15 23:29:18 +02001428
Arthur Heymans25027232017-02-12 23:34:39 +01001429 temp_drt |= (tRD_min << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001430
1431 /* Read Auto Precharge to Activate */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001432
Stefan Reinauer278534d2008-10-29 04:51:07 +00001433 temp_drt |= (8 << 0);
1434
Angel Pons1d4044a2021-03-27 19:11:51 +01001435 mchbar_write32(C0DRT0, temp_drt);
1436 mchbar_write32(C1DRT0, temp_drt);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001437
1438 /* Calculate DRT1 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001439
Angel Pons1d4044a2021-03-27 19:11:51 +01001440 temp_drt = mchbar_read32(C0DRT1) & 0x00020088;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001441
1442 /* DRAM RASB Precharge */
1443 temp_drt |= (sysinfo->trp - 2) << 0;
1444
1445 /* DRAM RASB to CASB Delay */
1446 temp_drt |= (sysinfo->trcd - 2) << 4;
1447
1448 /* CASB Latency */
1449 temp_drt |= (cas_table[sysinfo->cas - 3]) << 8;
1450
1451 /* Refresh Cycle Time */
1452 temp_drt |= (sysinfo->trfc) << 10;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001453
Stefan Reinauer278534d2008-10-29 04:51:07 +00001454 /* Pre-All to Activate Delay */
1455 temp_drt |= (0 << 16);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001456
Stefan Reinauer278534d2008-10-29 04:51:07 +00001457 /* Precharge to Precharge Delay stays at 1 clock */
1458 temp_drt |= (0 << 18);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001459
Stefan Reinauer278534d2008-10-29 04:51:07 +00001460 /* Activate to Precharge Delay */
1461 temp_drt |= (sysinfo->tras << 19);
1462
1463 /* Read to Precharge (tRTP) */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001464 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001465 temp_drt |= (1 << 28);
Arthur Heymans70a8e342017-03-09 11:30:23 +01001466 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001467 temp_drt |= (0 << 28);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001468
1469 /* Determine page size */
1470 reg32 = 0;
1471 page_size = 1; /* Default: 1k pagesize */
Arthur Heymans70a8e342017-03-09 11:30:23 +01001472 for (i = 0; i < 2*DIMM_SOCKETS; i++) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001473 if (sysinfo->dimm[i] == SYSINFO_DIMM_X16DS ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001474 sysinfo->dimm[i] == SYSINFO_DIMM_X16SS)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001475 page_size = 2; /* 2k pagesize */
1476 }
1477
Arthur Heymans70a8e342017-03-09 11:30:23 +01001478 if (sysinfo->memory_frequency == 533 && page_size == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001479 reg32 = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001480 if (sysinfo->memory_frequency == 667)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001481 reg32 = page_size;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001482
Stefan Reinauer278534d2008-10-29 04:51:07 +00001483 temp_drt |= (reg32 << 30);
1484
Angel Pons1d4044a2021-03-27 19:11:51 +01001485 mchbar_write32(C0DRT1, temp_drt);
1486 mchbar_write32(C1DRT1, temp_drt);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001487
1488 /* Program DRT2 */
Angel Pons1d4044a2021-03-27 19:11:51 +01001489 reg32 = mchbar_read32(C0DRT2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001490 reg32 &= ~(1 << 8);
Angel Pons1d4044a2021-03-27 19:11:51 +01001491 mchbar_write32(C0DRT2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001492
Angel Pons1d4044a2021-03-27 19:11:51 +01001493 reg32 = mchbar_read32(C1DRT2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001494 reg32 &= ~(1 << 8);
Angel Pons1d4044a2021-03-27 19:11:51 +01001495 mchbar_write32(C1DRT2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001496
1497 /* Calculate DRT3 */
Angel Pons1d4044a2021-03-27 19:11:51 +01001498 temp_drt = mchbar_read32(C0DRT3) & ~0x07ffffff;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001499
1500 /* Get old tRFC value */
Angel Pons1d4044a2021-03-27 19:11:51 +01001501 reg32 = mchbar_read32(C0DRT1) >> 10;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001502 reg32 &= 0x3f;
1503
1504 /* 788nS - tRFC */
1505 switch (sysinfo->memory_frequency) {
1506 case 400: /* 5nS */
1507 reg32 = ((78800 / 500) - reg32) & 0x1ff;
1508 reg32 |= (0x8c << 16) | (0x0c << 10); /* 1 us */
1509 break;
1510 case 533: /* 3.75nS */
1511 reg32 = ((78800 / 375) - reg32) & 0x1ff;
1512 reg32 |= (0xba << 16) | (0x10 << 10); /* 1 us */
1513 break;
1514 case 667: /* 3nS */
1515 reg32 = ((78800 / 300) - reg32) & 0x1ff;
1516 reg32 |= (0xe9 << 16) | (0x14 << 10); /* 1 us */
1517 break;
1518 }
1519
1520 temp_drt |= reg32;
1521
Angel Pons1d4044a2021-03-27 19:11:51 +01001522 mchbar_write32(C0DRT3, temp_drt);
1523 mchbar_write32(C1DRT3, temp_drt);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001524}
1525
1526static void sdram_set_channel_mode(struct sys_info *sysinfo)
1527{
1528 u32 reg32;
1529
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001530 printk(BIOS_DEBUG, "Setting mode of operation for memory channels...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001531
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001532 if (sdram_capabilities_interleave() &&
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001533 ((sysinfo->banksize[0] + sysinfo->banksize[1] +
1534 sysinfo->banksize[2] + sysinfo->banksize[3]) ==
1535 (sysinfo->banksize[4] + sysinfo->banksize[5] +
1536 sysinfo->banksize[6] + sysinfo->banksize[7]))) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001537 /* Both channels equipped with DIMMs of the same size */
Elyes Haouas49446092022-09-28 14:14:05 +02001538 sysinfo->interleaved = true;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001539 } else {
Elyes Haouas49446092022-09-28 14:14:05 +02001540 sysinfo->interleaved = false;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001541 }
1542
Angel Pons1d4044a2021-03-27 19:11:51 +01001543 reg32 = mchbar_read32(DCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001544 reg32 &= ~(7 << 0);
1545
Elyes HAOUAS12df9502016-08-23 21:29:48 +02001546 if (sysinfo->interleaved) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001547 /* Dual Channel Interleaved */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001548 printk(BIOS_DEBUG, "Dual Channel Interleaved.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001549 reg32 |= (1 << 1);
1550 } else if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001551 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001552 /* Channel 1 only */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001553 printk(BIOS_DEBUG, "Single Channel 1 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001554 reg32 |= (1 << 2);
Elyes HAOUAS75da1fb2017-02-16 18:59:13 +01001555 } else if (sdram_capabilities_dual_channel() &&
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001556 (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
1557 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)) {
Martin Roth128c1042016-11-18 09:29:03 -07001558 /* Dual Channel Asymmetric */
1559 printk(BIOS_DEBUG, "Dual Channel Asymmetric.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001560 reg32 |= (1 << 0);
1561 } else {
1562 /* All bits 0 means Single Channel 0 operation */
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001563 printk(BIOS_DEBUG, "Single Channel 0 only.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001564 }
1565
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001566 /* Now disable channel XORing */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001567 reg32 |= (1 << 10);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001568
Angel Pons1d4044a2021-03-27 19:11:51 +01001569 mchbar_write32(DCC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001570
Angel Pons1d4044a2021-03-27 19:11:51 +01001571 PRINTK_DEBUG("DCC = 0x%08x\n", mchbar_read32(DCC));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001572}
1573
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001574static void sdram_program_pll_settings(struct sys_info *sysinfo)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001575{
Angel Pons1d4044a2021-03-27 19:11:51 +01001576 mchbar_write32(PLLMON, 0x80800000);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001577
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001578 sysinfo->fsb_frequency = fsbclk();
Peter Stuge76d91432010-10-01 10:02:33 +00001579 if (sysinfo->fsb_frequency == 0xffff)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001580 die("Unsupported FSB speed");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001581
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001582 /* Program CPCTL according to FSB speed */
1583 /* Only write the lower byte */
1584 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001585 case 400:
Angel Pons1d4044a2021-03-27 19:11:51 +01001586 mchbar_write8(CPCTL, 0x90);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001587 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001588 case 533:
Angel Pons1d4044a2021-03-27 19:11:51 +01001589 mchbar_write8(CPCTL, 0x95);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001590 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001591 case 667:
Angel Pons1d4044a2021-03-27 19:11:51 +01001592 mchbar_write8(CPCTL, 0x8d);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001593 break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001594 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00001595
Angel Pons1d4044a2021-03-27 19:11:51 +01001596 mchbar_clrbits16(CPCTL, 1 << 11);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001597
Angel Pons1d4044a2021-03-27 19:11:51 +01001598 mchbar_read16(CPCTL); /* Read back register to activate settings */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001599}
1600
1601static void sdram_program_graphics_frequency(struct sys_info *sysinfo)
1602{
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001603 u8 reg8;
Elyes Haouasd9dade32022-10-07 12:05:38 +02001604 u8 freq, voltage;
1605 bool second_vco = false;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001606
1607#define CRCLK_166MHz 0x00
1608#define CRCLK_200MHz 0x01
1609#define CRCLK_250MHz 0x03
1610#define CRCLK_400MHz 0x05
1611
1612#define CDCLK_200MHz 0x00
1613#define CDCLK_320MHz 0x40
1614
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001615#define VOLTAGE_1_05 0x00
1616#define VOLTAGE_1_50 0x01
1617
Paul Menzeldaf9e502014-07-15 23:49:16 +02001618 printk(BIOS_DEBUG, "Setting Graphics Frequency...\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001619
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001620 printk(BIOS_DEBUG, "FSB: %d MHz ", sysinfo->fsb_frequency);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001621
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001622 voltage = VOLTAGE_1_05;
Angel Pons1d4044a2021-03-27 19:11:51 +01001623 if (mchbar_read32(DFT_STRAP1) & (1 << 20))
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001624 voltage = VOLTAGE_1_50;
Angel Pons30492572020-06-11 13:24:54 +02001625 printk(BIOS_DEBUG, "Voltage: %s ", (voltage == VOLTAGE_1_05) ? "1.05V" : "1.5V");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001626
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001627 /* Gate graphics hardware for frequency change */
Angel Pons30492572020-06-11 13:24:54 +02001628 reg8 = (1 << 3) | (1 << 1); /* disable crclk, gate cdclk */
Angel Pons3580d812020-06-11 14:13:33 +02001629 pci_write_config8(IGD_DEV, GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001630
1631 /* Get graphics frequency capabilities */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001632 reg8 = sdram_capabilities_core_frequencies();
1633
Stefan Reinauer278534d2008-10-29 04:51:07 +00001634 freq = CRCLK_250MHz;
1635 switch (reg8) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001636 case GFX_FREQUENCY_CAP_ALL:
1637 if (voltage == VOLTAGE_1_05)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001638 freq = CRCLK_250MHz;
1639 else
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001640 freq = CRCLK_400MHz; /* 1.5V requires 400MHz */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001641 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001642 case GFX_FREQUENCY_CAP_250MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001643 freq = CRCLK_250MHz;
1644 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001645 case GFX_FREQUENCY_CAP_200MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001646 freq = CRCLK_200MHz;
1647 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001648 case GFX_FREQUENCY_CAP_166MHZ:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001649 freq = CRCLK_166MHz;
1650 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001651 }
1652
1653 if (freq != CRCLK_400MHz) {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001654 /* What chipset are we? Force 166MHz for GMS */
Angel Pons3580d812020-06-11 14:13:33 +02001655 reg8 = (pci_read_config8(HOST_BRIDGE, 0xe7) & 0x70) >> 4;
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001656 if (reg8 == 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001657 freq = CRCLK_166MHz;
1658 }
1659
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001660 printk(BIOS_DEBUG, "Render: ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001661 switch (freq) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001662 case CRCLK_166MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001663 printk(BIOS_DEBUG, "166MHz");
1664 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001665 case CRCLK_200MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001666 printk(BIOS_DEBUG, "200MHz");
1667 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001668 case CRCLK_250MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001669 printk(BIOS_DEBUG, "250MHz");
1670 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001671 case CRCLK_400MHz:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001672 printk(BIOS_DEBUG, "400MHz");
1673 break;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001674 }
1675
Arthur Heymans70a8e342017-03-09 11:30:23 +01001676 if (i945_silicon_revision() == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001677 sysinfo->mvco4x = 1;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001678 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00001679 sysinfo->mvco4x = 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001680
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001681 if (voltage == VOLTAGE_1_50) {
Elyes Haouasd9dade32022-10-07 12:05:38 +02001682 second_vco = true;
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01001683 } else if ((i945_silicon_revision() > 0) && (freq == CRCLK_250MHz)) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00001684 u16 mem = sysinfo->memory_frequency;
1685 u16 fsb = sysinfo->fsb_frequency;
1686
Arthur Heymans70a8e342017-03-09 11:30:23 +01001687 if ((fsb == 667 && mem == 533) ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001688 (fsb == 533 && mem == 533) ||
1689 (fsb == 533 && mem == 400)) {
Elyes Haouasd9dade32022-10-07 12:05:38 +02001690 second_vco = true;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001691 }
1692
1693 if (fsb == 667 && mem == 533)
1694 sysinfo->mvco4x = 1;
1695 }
1696
Elyes Haouasd9dade32022-10-07 12:05:38 +02001697 sysinfo->clkcfg_bit7 = second_vco;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001698
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001699 /* Graphics Core Render Clock */
Angel Pons3580d812020-06-11 14:13:33 +02001700 pci_update_config16(IGD_DEV, GCFC, ~((7 << 0) | (1 << 13)), freq);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001701
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001702 /* Graphics Core Display Clock */
Angel Pons3580d812020-06-11 14:13:33 +02001703 reg8 = pci_read_config8(IGD_DEV, GCFC);
Angel Ponse3c68d22020-06-08 12:09:03 +02001704 reg8 &= ~((1 << 7) | (7 << 4));
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001705
1706 if (voltage == VOLTAGE_1_05) {
1707 reg8 |= CDCLK_200MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001708 printk(BIOS_DEBUG, " Display: 200MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001709 } else {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001710 reg8 |= CDCLK_320MHz;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001711 printk(BIOS_DEBUG, " Display: 320MHz\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001712 }
Angel Pons3580d812020-06-11 14:13:33 +02001713 pci_write_config8(IGD_DEV, GCFC, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001714
Angel Pons3580d812020-06-11 14:13:33 +02001715 reg8 = pci_read_config8(IGD_DEV, GCFC + 1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001716
Angel Ponse3c68d22020-06-08 12:09:03 +02001717 reg8 |= (1 << 3) | (1 << 1);
Angel Pons3580d812020-06-11 14:13:33 +02001718 pci_write_config8(IGD_DEV, GCFC + 1, reg8);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001719
1720 reg8 |= 0x0f;
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 /* Ungate core render and display clocks */
1724 reg8 &= 0xf0;
Angel Pons3580d812020-06-11 14:13:33 +02001725 pci_write_config8(IGD_DEV, GCFC + 1, reg8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001726}
1727
1728static void sdram_program_memory_frequency(struct sys_info *sysinfo)
1729{
1730 u32 clkcfg;
Julius Wernercd49cce2019-03-05 16:53:33 -08001731 u8 offset = CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM) ? 1 : 0;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001732
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001733 printk(BIOS_DEBUG, "Setting Memory Frequency... ");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001734
Angel Pons1d4044a2021-03-27 19:11:51 +01001735 clkcfg = mchbar_read32(CLKCFG);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001736
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02001737 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001738
Arthur Heymans70a8e342017-03-09 11:30:23 +01001739 clkcfg &= ~((1 << 12) | (1 << 7) | (7 << 4));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001740
1741 if (sysinfo->mvco4x) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001742 printk(BIOS_DEBUG, "MVCO 4x, ");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001743 clkcfg &= ~(1 << 12);
1744 }
1745
1746 if (sysinfo->clkcfg_bit7) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001747 printk(BIOS_DEBUG, "second VCO, ");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001748 clkcfg |= (1 << 7);
1749 }
1750
1751 switch (sysinfo->memory_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001752 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001753 clkcfg |= ((1 + offset) << 4);
1754 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001755 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001756 clkcfg |= ((2 + offset) << 4);
1757 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001758 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001759 clkcfg |= ((3 + offset) << 4);
1760 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001761 default:
1762 die("Target Memory Frequency Error");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001763 }
1764
Angel Pons1d4044a2021-03-27 19:11:51 +01001765 if (mchbar_read32(CLKCFG) == clkcfg) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001766 printk(BIOS_DEBUG, "ok (unchanged)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001767 return;
1768 }
1769
Angel Pons1d4044a2021-03-27 19:11:51 +01001770 mchbar_write32(CLKCFG, clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001771
Petr Cveke75bb012022-06-16 17:13:22 +02001772 /*
1773 * Make sure the following code is in the cache before we execute it.
1774 * TODO: Experiments (i945GM) without any cache_code/delay_update
1775 * _seem_ to work even when XIP is disabled. Also on Pentium 4
1776 * the code is not cached at all by default.
1777 */
1778 asm volatile (
1779 " jmp cache_code\n"
1780 "vco_update:\n"
1781 : /* No outputs */
1782 : /* No inputs */
1783 : "memory"
1784 );
1785
Angel Ponse3c68d22020-06-08 12:09:03 +02001786 pci_and_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, (u8)~(1 << 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +00001787
Stefan Reinauer278534d2008-10-29 04:51:07 +00001788 clkcfg &= ~(1 << 10);
Angel Pons1d4044a2021-03-27 19:11:51 +01001789 mchbar_write32(CLKCFG, clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001790 clkcfg |= (1 << 10);
Angel Pons1d4044a2021-03-27 19:11:51 +01001791 mchbar_write32(CLKCFG, clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001792
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001793 asm volatile (
Stefan Reinauer278534d2008-10-29 04:51:07 +00001794 " movl $0x100, %%ecx\n"
1795 "delay_update:\n"
1796 " nop\n"
1797 " nop\n"
1798 " nop\n"
1799 " nop\n"
1800 " loop delay_update\n"
1801 : /* No outputs */
1802 : /* No inputs */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001803 : "%ecx", "memory"
Stefan Reinauer278534d2008-10-29 04:51:07 +00001804 );
1805
Stefan Reinauer278534d2008-10-29 04:51:07 +00001806 clkcfg &= ~(1 << 10);
Angel Pons1d4044a2021-03-27 19:11:51 +01001807 mchbar_write32(CLKCFG, clkcfg);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001808
Petr Cveke75bb012022-06-16 17:13:22 +02001809 asm volatile (
1810 " jmp out\n"
1811 "cache_code:\n"
1812 " jmp vco_update\n"
1813 "out:\n"
1814 : /* No outputs */
1815 : /* No inputs */
1816 : "memory"
1817 );
Stefan Reinauer278534d2008-10-29 04:51:07 +00001818
Angel Pons1d4044a2021-03-27 19:11:51 +01001819 printk(BIOS_DEBUG, "CLKCFG = 0x%08x, ", mchbar_read32(CLKCFG));
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001820 printk(BIOS_DEBUG, "ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001821}
1822
1823static void sdram_program_clock_crossing(void)
1824{
Stefan Reinauer278534d2008-10-29 04:51:07 +00001825 int idx = 0;
1826
1827 /**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001828 * We add the indices according to our clocks from CLKCFG.
Stefan Reinauer278534d2008-10-29 04:51:07 +00001829 */
Julius Wernercd49cce2019-03-05 16:53:33 -08001830#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer278534d2008-10-29 04:51:07 +00001831 static const u32 data_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001832 0x00100401, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001833 0xffffffff, 0xffffffff, /* nonexistent */
1834 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001835
Stefan Reinauer278534d2008-10-29 04:51:07 +00001836 0x08040120, 0x00000000, /* DDR400 FSB533 */
1837 0x00100401, 0x00000000, /* DDR533 FSB533 */
Stefan Reinauerbf264e92010-05-14 19:09:20 +00001838 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001839
1840 0x04020120, 0x00000010, /* DDR400 FSB667 */
1841 0x10040280, 0x00000040, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001842 0x00100401, 0x00000000, /* DDR667 FSB667 */
1843
Martin Roth2ed0aa22016-01-05 20:58:58 -07001844 0xffffffff, 0xffffffff, /* nonexistent */
1845 0xffffffff, 0xffffffff, /* nonexistent */
1846 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001847
Martin Roth2ed0aa22016-01-05 20:58:58 -07001848 0xffffffff, 0xffffffff, /* nonexistent */
1849 0xffffffff, 0xffffffff, /* nonexistent */
1850 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001851 };
1852
1853 static const u32 command_clock_crossing[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001854 0x04020208, 0x00000000, /* DDR400 FSB400 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001855 0xffffffff, 0xffffffff, /* nonexistent */
1856 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001857
Stefan Reinauer278534d2008-10-29 04:51:07 +00001858 0x00060108, 0x00000000, /* DDR400 FSB533 */
1859 0x04020108, 0x00000000, /* DDR533 FSB533 */
Martin Roth2ed0aa22016-01-05 20:58:58 -07001860 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001861
1862 0x00040318, 0x00000000, /* DDR400 FSB667 */
1863 0x04020118, 0x00000000, /* DDR533 FSB667 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001864 0x02010804, 0x00000000, /* DDR667 FSB667 */
1865
Martin Roth2ed0aa22016-01-05 20:58:58 -07001866 0xffffffff, 0xffffffff, /* nonexistent */
1867 0xffffffff, 0xffffffff, /* nonexistent */
1868 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001869
Martin Roth2ed0aa22016-01-05 20:58:58 -07001870 0xffffffff, 0xffffffff, /* nonexistent */
1871 0xffffffff, 0xffffffff, /* nonexistent */
1872 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer278534d2008-10-29 04:51:07 +00001873 };
1874
Julius Wernercd49cce2019-03-05 16:53:33 -08001875#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001876 /* i945 G/P */
1877 static const u32 data_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001878 0xffffffff, 0xffffffff, /* nonexistent */
1879 0xffffffff, 0xffffffff, /* nonexistent */
1880 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001881
1882 0x10080201, 0x00000000, /* DDR400 FSB533 */
1883 0x00100401, 0x00000000, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001884 0x00010402, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001885
Martin Roth2ed0aa22016-01-05 20:58:58 -07001886 0xffffffff, 0xffffffff, /* nonexistent */
1887 0xffffffff, 0xffffffff, /* nonexistent */
1888 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001889
1890 0x04020108, 0x00000000, /* DDR400 FSB800 */
1891 0x00020108, 0x00000000, /* DDR533 FSB800 */
1892 0x00080201, 0x00000000, /* DDR667 FSB800 */
1893
1894 0x00010402, 0x00000000, /* DDR400 FSB1066 */
1895 0x04020108, 0x00000000, /* DDR533 FSB1066 */
1896 0x08040110, 0x00000000, /* DDR667 FSB1066 */
1897 };
1898
1899 static const u32 command_clock_crossing[] = {
Martin Roth2ed0aa22016-01-05 20:58:58 -07001900 0xffffffff, 0xffffffff, /* nonexistent */
1901 0xffffffff, 0xffffffff, /* nonexistent */
1902 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001903
1904 0x00010800, 0x00000402, /* DDR400 FSB533 */
1905 0x01000400, 0x00000200, /* DDR533 FSB533 */
Patrick Georgi682ea3c2010-04-20 15:52:57 +00001906 0x00020904, 0x00000000, /* DDR667 FSB533 - fake values */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001907
Martin Roth2ed0aa22016-01-05 20:58:58 -07001908 0xffffffff, 0xffffffff, /* nonexistent */
1909 0xffffffff, 0xffffffff, /* nonexistent */
1910 0xffffffff, 0xffffffff, /* nonexistent */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001911
1912 0x02010804, 0x00000000, /* DDR400 FSB800 */
1913 0x00010402, 0x00000000, /* DDR533 FSB800 */
Arthur Heymans8b6df622016-10-16 10:58:01 +02001914 0x04020130, 0x00000008, /* DDR667 FSB800 */
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001915
1916 0x00020904, 0x00000000, /* DDR400 FSB1066 */
1917 0x02010804, 0x00000000, /* DDR533 FSB1066 */
1918 0x180601c0, 0x00000020, /* DDR667 FSB1066 */
1919 };
1920#endif
1921
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001922 printk(BIOS_DEBUG, "Programming Clock Crossing...");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001923
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001924 printk(BIOS_DEBUG, "MEM=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001925 switch (memclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001926 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001927 printk(BIOS_DEBUG, "400");
1928 idx += 0;
1929 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001930 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001931 printk(BIOS_DEBUG, "533");
1932 idx += 2;
1933 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001934 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001935 printk(BIOS_DEBUG, "667");
1936 idx += 4;
1937 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001938 default:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001939 printk(BIOS_DEBUG, "RSVD %x", memclk());
1940 return;
Stefan Reinauer278534d2008-10-29 04:51:07 +00001941 }
1942
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001943 printk(BIOS_DEBUG, " FSB=");
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001944 switch (fsbclk()) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01001945 case 400:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001946 printk(BIOS_DEBUG, "400");
1947 idx += 0;
1948 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001949 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001950 printk(BIOS_DEBUG, "533");
1951 idx += 6;
1952 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001953 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001954 printk(BIOS_DEBUG, "667");
1955 idx += 12;
1956 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001957 case 800:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001958 printk(BIOS_DEBUG, "800");
1959 idx += 18;
1960 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001961 case 1066:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001962 printk(BIOS_DEBUG, "1066");
1963 idx += 24;
1964 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01001965 default:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02001966 printk(BIOS_DEBUG, "RSVD %x\n", fsbclk());
1967 return;
Stefan Reinauer24b4df52010-01-17 13:47:35 +00001968 }
1969
Arthur Heymans70a8e342017-03-09 11:30:23 +01001970 if (command_clock_crossing[idx] == 0xffffffff)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001971 printk(BIOS_DEBUG, "Invalid MEM/FSB combination!\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001972
Angel Pons1d4044a2021-03-27 19:11:51 +01001973 mchbar_write32(CCCFT + 0, command_clock_crossing[idx]);
1974 mchbar_write32(CCCFT + 4, command_clock_crossing[idx + 1]);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00001975
Angel Pons1d4044a2021-03-27 19:11:51 +01001976 mchbar_write32(C0DCCFT + 0, data_clock_crossing[idx]);
1977 mchbar_write32(C0DCCFT + 4, data_clock_crossing[idx + 1]);
1978 mchbar_write32(C1DCCFT + 0, data_clock_crossing[idx]);
1979 mchbar_write32(C1DCCFT + 4, data_clock_crossing[idx + 1]);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001980
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001981 printk(BIOS_DEBUG, "... ok\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00001982}
1983
1984static void sdram_disable_fast_dispatch(void)
1985{
1986 u32 reg32;
1987
Angel Pons1d4044a2021-03-27 19:11:51 +01001988 reg32 = mchbar_read32(FSBPMC3);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001989 reg32 |= (1 << 1);
Angel Pons1d4044a2021-03-27 19:11:51 +01001990 mchbar_write32(FSBPMC3, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001991
Angel Pons1d4044a2021-03-27 19:11:51 +01001992 reg32 = mchbar_read32(SBTEST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001993 reg32 |= (3 << 1);
Angel Pons1d4044a2021-03-27 19:11:51 +01001994 mchbar_write32(SBTEST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00001995}
1996
1997static void sdram_pre_jedec_initialization(void)
1998{
1999 u32 reg32;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002000
Angel Pons1d4044a2021-03-27 19:11:51 +01002001 reg32 = mchbar_read32(WCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002002 reg32 &= 0x113ff3ff;
2003 reg32 |= (4 << 29) | (3 << 25) | (1 << 10);
Angel Pons1d4044a2021-03-27 19:11:51 +01002004 mchbar_write32(WCC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002005
Angel Pons1d4044a2021-03-27 19:11:51 +01002006 mchbar_setbits32(SMVREFC, 1 << 6);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002007
Angel Pons1d4044a2021-03-27 19:11:51 +01002008 mchbar_clrbits32(MMARB0, 3 << 17);
2009 mchbar_setbits32(MMARB0, 1 << 21 | 1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002010
Angel Pons1d4044a2021-03-27 19:11:51 +01002011 mchbar_clrbits32(MMARB1, 7 << 8);
2012 mchbar_setbits32(MMARB1, 3 << 8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002013
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002014 /* Adaptive Idle Timer Control */
Angel Pons1d4044a2021-03-27 19:11:51 +01002015 mchbar_write32(C0AIT + 0, 0x000006c4);
2016 mchbar_write32(C0AIT + 4, 0x871a066d);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002017
Angel Pons1d4044a2021-03-27 19:11:51 +01002018 mchbar_write32(C1AIT + 0, 0x000006c4);
2019 mchbar_write32(C1AIT + 4, 0x871a066d);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002020}
2021
2022#define EA_DUALCHANNEL_XOR_BANK_RANK_MODE (0xd4 << 24)
2023#define EA_DUALCHANNEL_XOR_BANK_MODE (0xf4 << 24)
2024#define EA_DUALCHANNEL_BANK_RANK_MODE (0xc2 << 24)
2025#define EA_DUALCHANNEL_BANK_MODE (0xe2 << 24)
2026#define EA_SINGLECHANNEL_XOR_BANK_RANK_MODE (0x91 << 24)
2027#define EA_SINGLECHANNEL_XOR_BANK_MODE (0xb1 << 24)
2028#define EA_SINGLECHANNEL_BANK_RANK_MODE (0x80 << 24)
2029#define EA_SINGLECHANNEL_BANK_MODE (0xa0 << 24)
2030
2031static void sdram_enhanced_addressing_mode(struct sys_info *sysinfo)
2032{
2033 u32 chan0 = 0, chan1 = 0;
Paul Menzeld789b6582020-03-14 11:50:34 +01002034 bool chan0_dualsided, chan1_dualsided, chan0_populated, chan1_populated;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002035
Paul Menzel842dd332020-03-14 10:37:40 +01002036 chan0_populated = (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002037 sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED);
Elyes HAOUAS308aeff2017-02-24 12:53:07 +01002038 chan1_populated = (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002039 sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002040 chan0_dualsided = (sysinfo->banksize[1] || sysinfo->banksize[3]);
2041 chan1_dualsided = (sysinfo->banksize[5] || sysinfo->banksize[7]);
2042
2043 if (sdram_capabilities_enhanced_addressing_xor()) {
2044 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002045 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002046 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002047 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002048 chan0 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002049 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002050 chan0 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002051 }
2052 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002053 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002054 chan1 = EA_SINGLECHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002055 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002056 chan1 = EA_SINGLECHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002057 }
2058 } else {
2059 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002060 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002061 chan0 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002062 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002063 chan0 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002064
Arthur Heymans70a8e342017-03-09 11:30:23 +01002065 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002066 chan1 = EA_DUALCHANNEL_XOR_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002067 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002068 chan1 = EA_DUALCHANNEL_XOR_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002069 }
2070 } else {
2071 if (!sysinfo->interleaved) {
Martin Roth128c1042016-11-18 09:29:03 -07002072 /* Single Channel & Dual Channel Asymmetric */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002073 if (chan0_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002074 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002075 chan0 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002076 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002077 chan0 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002078 }
2079 if (chan1_populated) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002080 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002081 chan1 = EA_SINGLECHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002082 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002083 chan1 = EA_SINGLECHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002084 }
2085 } else {
2086 /* Interleaved has always both channels populated */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002087 if (chan0_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002088 chan0 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002089 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002090 chan0 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002091
Arthur Heymans70a8e342017-03-09 11:30:23 +01002092 if (chan1_dualsided)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002093 chan1 = EA_DUALCHANNEL_BANK_RANK_MODE;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002094 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002095 chan1 = EA_DUALCHANNEL_BANK_MODE;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002096 }
2097 }
2098
Angel Pons1d4044a2021-03-27 19:11:51 +01002099 mchbar_clrbits32(C0DRC1, 0xff << 24);
2100 mchbar_setbits32(C0DRC1, chan0);
2101 mchbar_clrbits32(C1DRC1, 0xff << 24);
2102 mchbar_setbits32(C1DRC1, chan1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002103}
2104
2105static void sdram_post_jedec_initialization(struct sys_info *sysinfo)
2106{
2107 u32 reg32;
2108
2109 /* Enable Channel XORing for Dual Channel Interleave */
2110 if (sysinfo->interleaved) {
Angel Pons1d4044a2021-03-27 19:11:51 +01002111 reg32 = mchbar_read32(DCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002112 reg32 &= ~(1 << 10);
Stefan Reinauer30140a52009-03-11 16:20:39 +00002113 reg32 |= (1 << 9);
Angel Pons1d4044a2021-03-27 19:11:51 +01002114 mchbar_write32(DCC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002115 }
2116
2117 /* DRAM mode optimizations */
2118 sdram_enhanced_addressing_mode(sysinfo);
2119
Angel Pons1d4044a2021-03-27 19:11:51 +01002120 reg32 = mchbar_read32(FSBPMC3);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002121 reg32 &= ~(1 << 1);
Angel Pons1d4044a2021-03-27 19:11:51 +01002122 mchbar_write32(FSBPMC3, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002123
Angel Pons1d4044a2021-03-27 19:11:51 +01002124 reg32 = mchbar_read32(SBTEST);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002125 reg32 &= ~(1 << 2);
Angel Pons1d4044a2021-03-27 19:11:51 +01002126 mchbar_write32(SBTEST, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002127
Angel Pons1d4044a2021-03-27 19:11:51 +01002128 reg32 = mchbar_read32(SBOCC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002129 reg32 &= 0xffbdb6ff;
2130 reg32 |= (0xbdb6 << 8) | (1 << 0);
Angel Pons1d4044a2021-03-27 19:11:51 +01002131 mchbar_write32(SBOCC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002132}
2133
2134static void sdram_power_management(struct sys_info *sysinfo)
2135{
Stefan Reinauer278534d2008-10-29 04:51:07 +00002136 u16 reg16;
2137 u32 reg32;
Elyes HAOUAS187bec72021-12-12 07:00:50 +01002138 bool integrated_graphics = true;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002139 int i;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002140
Elyes HAOUAS8f20b122021-02-14 13:22:10 +01002141 if (!(pci_read_config8(HOST_BRIDGE, DEVEN) & (DEVEN_D2F0 | DEVEN_D2F1)))
2142 integrated_graphics = false;
2143
Angel Pons1d4044a2021-03-27 19:11:51 +01002144 reg32 = mchbar_read32(C0DRT2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002145 reg32 &= 0xffffff00;
2146 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002147 reg32 |= (1 << 5) | (1 << 4);
Angel Pons1d4044a2021-03-27 19:11:51 +01002148 mchbar_write32(C0DRT2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002149
Angel Pons1d4044a2021-03-27 19:11:51 +01002150 reg32 = mchbar_read32(C1DRT2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002151 reg32 &= 0xffffff00;
2152 /* Idle timer = 8 clocks, CKE idle timer = 16 clocks */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002153 reg32 |= (1 << 5) | (1 << 4);
Angel Pons1d4044a2021-03-27 19:11:51 +01002154 mchbar_write32(C1DRT2, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002155
Angel Pons1d4044a2021-03-27 19:11:51 +01002156 reg32 = mchbar_read32(C0DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002157
2158 reg32 |= (1 << 12) | (1 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01002159 mchbar_write32(C0DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002160
Angel Pons1d4044a2021-03-27 19:11:51 +01002161 reg32 = mchbar_read32(C1DRC1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002162
2163 reg32 |= (1 << 12) | (1 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01002164 mchbar_write32(C1DRC1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002165
Julius Wernercd49cce2019-03-05 16:53:33 -08002166 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)) {
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002167 if (i945_silicon_revision() > 1) {
2168 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2169 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002170
Angel Pons1d4044a2021-03-27 19:11:51 +01002171 mchbar_write16(UPMC1, 0x1010 | peg_bits);
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002172 } else {
2173 /* FIXME bits 5 and 0 only if PCIe graphics is disabled */
2174 u16 peg_bits = (1 << 5) | (1 << 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002175
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002176 /* Rev 0 and 1 */
Angel Pons1d4044a2021-03-27 19:11:51 +01002177 mchbar_write16(UPMC1, 0x0010 | peg_bits);
Arthur Heymans2f6b52e2017-03-02 23:51:09 +01002178 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002179 }
2180
Angel Pons1d4044a2021-03-27 19:11:51 +01002181 reg16 = mchbar_read16(UPMC2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002182 reg16 &= 0xfc00;
2183 reg16 |= 0x0100;
Angel Pons1d4044a2021-03-27 19:11:51 +01002184 mchbar_write16(UPMC2, reg16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002185
Angel Pons1d4044a2021-03-27 19:11:51 +01002186 mchbar_write32(UPMC3, 0x000f06ff);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002187
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002188 for (i = 0; i < 5; i++) {
Angel Pons1d4044a2021-03-27 19:11:51 +01002189 mchbar_clrbits32(UPMC3, 1 << 16);
2190 mchbar_setbits32(UPMC3, 1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002191 }
2192
Angel Pons1d4044a2021-03-27 19:11:51 +01002193 mchbar_write32(GIPMC1, 0x8000000c);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002194
Angel Pons1d4044a2021-03-27 19:11:51 +01002195 reg16 = mchbar_read16(CPCTL);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002196 reg16 &= ~(7 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002197 if (i945_silicon_revision() > 2)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002198 reg16 |= (6 << 11);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002199 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002200 reg16 |= (4 << 11);
Angel Pons1d4044a2021-03-27 19:11:51 +01002201 mchbar_write16(CPCTL, reg16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002202
Angel Pons3580d812020-06-11 14:13:33 +02002203#if 0
Angel Pons1d4044a2021-03-27 19:11:51 +01002204 if ((mchbar_read32(ECO) & (1 << 16)) != 0) {
Angel Pons3580d812020-06-11 14:13:33 +02002205#else
Stefan Reinauer30140a52009-03-11 16:20:39 +00002206 if (i945_silicon_revision() != 0) {
Angel Pons3580d812020-06-11 14:13:33 +02002207#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002208 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002209 case 667:
Angel Pons1d4044a2021-03-27 19:11:51 +01002210 mchbar_write32(HGIPMC2, 0x0d590d59);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002211 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002212 case 533:
Angel Pons1d4044a2021-03-27 19:11:51 +01002213 mchbar_write32(HGIPMC2, 0x155b155b);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002214 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002215 }
2216 } else {
2217 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002218 case 667:
Angel Pons1d4044a2021-03-27 19:11:51 +01002219 mchbar_write32(HGIPMC2, 0x09c409c4);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002220 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002221 case 533:
Angel Pons1d4044a2021-03-27 19:11:51 +01002222 mchbar_write32(HGIPMC2, 0x0fa00fa0);
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002223 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002224 }
2225 }
2226
Angel Pons1d4044a2021-03-27 19:11:51 +01002227 mchbar_write32(FSBPMC1, 0x8000000c);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002228
Angel Pons1d4044a2021-03-27 19:11:51 +01002229 reg32 = mchbar_read32(C2C3TT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002230 reg32 &= 0xffff0000;
2231 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002232 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002233 reg32 |= 0x0600;
2234 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002235 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002236 reg32 |= 0x0480;
2237 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002238 }
Angel Pons1d4044a2021-03-27 19:11:51 +01002239 mchbar_write32(C2C3TT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002240
Angel Pons1d4044a2021-03-27 19:11:51 +01002241 reg32 = mchbar_read32(C3C4TT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002242 reg32 &= 0xffff0000;
2243 switch (sysinfo->fsb_frequency) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002244 case 667:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002245 reg32 |= 0x0b80;
2246 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002247 case 533:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002248 reg32 |= 0x0980;
2249 break;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002250 }
Angel Pons1d4044a2021-03-27 19:11:51 +01002251 mchbar_write32(C3C4TT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002252
Arthur Heymans70a8e342017-03-09 11:30:23 +01002253 if (i945_silicon_revision() == 0)
Angel Pons1d4044a2021-03-27 19:11:51 +01002254 mchbar_clrbits32(ECO, 1 << 16);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002255 else
Angel Pons1d4044a2021-03-27 19:11:51 +01002256 mchbar_setbits32(ECO, 1 << 16);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002257
Angel Pons1d4044a2021-03-27 19:11:51 +01002258 mchbar_clrbits32(FSBPMC3, 1 << 29);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002259
Angel Pons1d4044a2021-03-27 19:11:51 +01002260 mchbar_setbits32(FSBPMC3, 1 << 21);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002261
Angel Pons1d4044a2021-03-27 19:11:51 +01002262 mchbar_clrbits32(FSBPMC3, 1 << 19);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002263
Angel Pons1d4044a2021-03-27 19:11:51 +01002264 mchbar_clrbits32(FSBPMC3, 1 << 13);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002265
Angel Pons1d4044a2021-03-27 19:11:51 +01002266 reg32 = mchbar_read32(FSBPMC4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002267 reg32 &= ~(3 << 24);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002268 reg32 |= (2 << 24);
Angel Pons1d4044a2021-03-27 19:11:51 +01002269 mchbar_write32(FSBPMC4, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002270
Angel Pons1d4044a2021-03-27 19:11:51 +01002271 mchbar_setbits32(FSBPMC4, 1 << 21);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002272
Angel Pons1d4044a2021-03-27 19:11:51 +01002273 mchbar_setbits32(FSBPMC4, 1 << 5);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002274
Arthur Heymans70a8e342017-03-09 11:30:23 +01002275 if ((i945_silicon_revision() < 2)) { /* || cpuid() = 0x6e8 */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002276 /* stepping 0 and 1 or CPUID 6e8 */
Angel Pons1d4044a2021-03-27 19:11:51 +01002277 mchbar_clrbits32(FSBPMC4, 1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002278 } else {
Angel Pons1d4044a2021-03-27 19:11:51 +01002279 mchbar_setbits32(FSBPMC4, 1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002280 }
2281
Angel Pons3580d812020-06-11 14:13:33 +02002282 pci_or_config8(HOST_BRIDGE, 0xfc, 1 << 4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002283
Angel Pons3580d812020-06-11 14:13:33 +02002284 pci_or_config8(IGD_DEV, 0xc1, 1 << 2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002285
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002286 if (integrated_graphics) {
Angel Pons1d4044a2021-03-27 19:11:51 +01002287 mchbar_write16(MIPMC4, 0x04f8);
2288 mchbar_write16(MIPMC5, 0x04fc);
2289 mchbar_write16(MIPMC6, 0x04fc);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002290 } else {
Angel Pons1d4044a2021-03-27 19:11:51 +01002291 mchbar_write16(MIPMC4, 0x64f8);
2292 mchbar_write16(MIPMC5, 0x64fc);
2293 mchbar_write16(MIPMC6, 0x64fc);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002294 }
2295
Angel Pons1d4044a2021-03-27 19:11:51 +01002296 reg32 = mchbar_read32(PMCFG);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002297 reg32 &= ~(3 << 17);
2298 reg32 |= (2 << 17);
Angel Pons1d4044a2021-03-27 19:11:51 +01002299 mchbar_write32(PMCFG, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002300
Angel Pons1d4044a2021-03-27 19:11:51 +01002301 mchbar_setbits32(PMCFG, 1 << 4);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002302
Angel Pons1d4044a2021-03-27 19:11:51 +01002303 reg32 = mchbar_read32(UPMC4);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002304 reg32 &= 0xffffff00;
2305 reg32 |= 0x01;
Angel Pons1d4044a2021-03-27 19:11:51 +01002306 mchbar_write32(UPMC4, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002307
Angel Pons1d4044a2021-03-27 19:11:51 +01002308 mchbar_clrbits32(0xb18, 1 << 21);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002309}
2310
2311static void sdram_thermal_management(void)
2312{
Angel Pons1d4044a2021-03-27 19:11:51 +01002313 mchbar_write8(TCO1, 0);
2314 mchbar_write8(TCO0, 0);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002315
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002316 /* The Thermal Sensors for DIMMs at 0x50, 0x52 are at I2C addr 0x30/0x32. */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002317
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002318 /* TODO This is not implemented yet. Volunteers? */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002319}
2320
2321static void sdram_save_receive_enable(void)
2322{
2323 int i;
2324 u32 reg32;
2325 u8 values[4];
2326
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002327 /* The following values are stored to an unused CMOS area and restored instead of
2328 * recalculated in case of an S3 resume.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002329 *
Arthur Heymans70a8e342017-03-09 11:30:23 +01002330 * C0WL0REOST [7:0] -> 8 bit
2331 * C1WL0REOST [7:0] -> 8 bit
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002332 * RCVENMT [11:8] [3:0] -> 8 bit
2333 * C0DRT1 [27:24] -> 4 bit
2334 * C1DRT1 [27:24] -> 4 bit
2335 */
2336
Angel Pons1d4044a2021-03-27 19:11:51 +01002337 values[0] = mchbar_read8(C0WL0REOST);
2338 values[1] = mchbar_read8(C1WL0REOST);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002339
Angel Pons1d4044a2021-03-27 19:11:51 +01002340 reg32 = mchbar_read32(RCVENMT);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002341 values[2] = (u8)((reg32 >> (8 - 4)) & 0xf0) | (reg32 & 0x0f);
2342
Angel Pons1d4044a2021-03-27 19:11:51 +01002343 reg32 = mchbar_read32(C0DRT1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002344 values[3] = (reg32 >> 24) & 0x0f;
Angel Pons1d4044a2021-03-27 19:11:51 +01002345 reg32 = mchbar_read32(C1DRT1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002346 values[3] |= (reg32 >> (24 - 4)) & 0xf0;
2347
2348 /* coreboot only uses bytes 0 - 127 for its CMOS values so far
Edwin Beasanteb50c7d2010-07-06 21:05:04 +00002349 * so we grab bytes 128 - 131 to save the receive enable values
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002350 */
2351
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002352 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002353 cmos_write(values[i], 128 + i);
2354}
2355
2356static void sdram_recover_receive_enable(void)
2357{
2358 int i;
2359 u32 reg32;
2360 u8 values[4];
2361
Elyes HAOUAS0a15fe92016-09-17 19:12:27 +02002362 for (i = 0; i < 4; i++)
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002363 values[i] = cmos_read(128 + i);
2364
Angel Pons1d4044a2021-03-27 19:11:51 +01002365 mchbar_write8(C0WL0REOST, values[0]);
2366 mchbar_write8(C1WL0REOST, values[1]);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002367
Angel Pons1d4044a2021-03-27 19:11:51 +01002368 reg32 = mchbar_read32(RCVENMT);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002369 reg32 &= ~((0x0f << 8) | (0x0f << 0));
2370 reg32 |= ((u32)(values[2] & 0xf0) << (8 - 4)) | (values[2] & 0x0f);
Angel Pons1d4044a2021-03-27 19:11:51 +01002371 mchbar_write32(RCVENMT, reg32);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002372
Angel Pons1d4044a2021-03-27 19:11:51 +01002373 reg32 = mchbar_read32(C0DRT1) & ~(0x0f << 24);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002374 reg32 |= (u32)(values[3] & 0x0f) << 24;
Angel Pons1d4044a2021-03-27 19:11:51 +01002375 mchbar_write32(C0DRT1, reg32);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002376
Angel Pons1d4044a2021-03-27 19:11:51 +01002377 reg32 = mchbar_read32(C1DRT1) & ~(0x0f << 24);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002378 reg32 |= (u32)(values[3] & 0xf0) << (24 - 4);
Angel Pons1d4044a2021-03-27 19:11:51 +01002379 mchbar_write32(C1DRT1, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002380}
2381
Stefan Reinauer278534d2008-10-29 04:51:07 +00002382static void sdram_program_receive_enable(struct sys_info *sysinfo)
2383{
Angel Pons1d4044a2021-03-27 19:11:51 +01002384 mchbar_setbits32(REPC, 1 << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002385
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002386 /* Program Receive Enable Timings */
2387 if (sysinfo->boot_path == BOOT_PATH_RESUME) {
2388 sdram_recover_receive_enable();
2389 } else {
2390 receive_enable_adjust(sysinfo);
2391 sdram_save_receive_enable();
2392 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002393
Angel Pons1d4044a2021-03-27 19:11:51 +01002394 mchbar_setbits32(C0DRC1, 1 << 6);
2395 mchbar_setbits32(C1DRC1, 1 << 6);
2396 mchbar_clrbits32(C0DRC1, 1 << 6);
2397 mchbar_clrbits32(C1DRC1, 1 << 6);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002398
Angel Pons1d4044a2021-03-27 19:11:51 +01002399 mchbar_setbits32(MIPMC3, 0x0f << 0);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002400}
2401
2402/**
2403 * @brief Enable On-Die Termination for DDR2.
2404 *
2405 */
2406
2407static void sdram_on_die_termination(struct sys_info *sysinfo)
2408{
2409 static const u32 odt[] = {
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002410 0x00024911, 0xe0010000,
2411 0x00049211, 0xe0020000,
2412 0x0006db11, 0xe0030000,
Stefan Reinauer278534d2008-10-29 04:51:07 +00002413 };
2414
2415 u32 reg32;
2416 int cas;
2417
Angel Pons1d4044a2021-03-27 19:11:51 +01002418 reg32 = mchbar_read32(ODTC);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002419 reg32 &= ~(3 << 16);
2420 reg32 |= (1 << 14) | (1 << 6) | (2 << 16);
Angel Pons1d4044a2021-03-27 19:11:51 +01002421 mchbar_write32(ODTC, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002422
Paul Menzelb4d9f222020-03-14 10:34:29 +01002423 if (sysinfo->dimm[0] == SYSINFO_DIMM_NOT_POPULATED ||
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002424 sysinfo->dimm[1] == SYSINFO_DIMM_NOT_POPULATED) {
Elyes HAOUAS38424982016-08-21 12:01:04 +02002425 printk(BIOS_DEBUG, "one dimm per channel config..\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002426
Angel Pons1d4044a2021-03-27 19:11:51 +01002427 reg32 = mchbar_read32(C0ODT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002428 reg32 &= ~(7 << 28);
Angel Pons1d4044a2021-03-27 19:11:51 +01002429 mchbar_write32(C0ODT, reg32);
2430 reg32 = mchbar_read32(C1ODT);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002431 reg32 &= ~(7 << 28);
Angel Pons1d4044a2021-03-27 19:11:51 +01002432 mchbar_write32(C1ODT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002433 }
2434
2435 cas = sysinfo->cas;
2436
Angel Pons1d4044a2021-03-27 19:11:51 +01002437 reg32 = mchbar_read32(C0ODT) & 0xfff00000;
Angel Pons30492572020-06-11 13:24:54 +02002438 reg32 |= odt[(cas - 3) * 2];
Angel Pons1d4044a2021-03-27 19:11:51 +01002439 mchbar_write32(C0ODT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002440
Angel Pons1d4044a2021-03-27 19:11:51 +01002441 reg32 = mchbar_read32(C1ODT) & 0xfff00000;
Angel Pons30492572020-06-11 13:24:54 +02002442 reg32 |= odt[(cas - 3) * 2];
Angel Pons1d4044a2021-03-27 19:11:51 +01002443 mchbar_write32(C1ODT, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002444
Angel Pons1d4044a2021-03-27 19:11:51 +01002445 reg32 = mchbar_read32(C0ODT + 4) & 0x1fc8ffff;
Angel Pons30492572020-06-11 13:24:54 +02002446 reg32 |= odt[((cas - 3) * 2) + 1];
Angel Pons1d4044a2021-03-27 19:11:51 +01002447 mchbar_write32(C0ODT + 4, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002448
Angel Pons1d4044a2021-03-27 19:11:51 +01002449 reg32 = mchbar_read32(C1ODT + 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(C1ODT + 4, reg32);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002452}
2453
2454/**
2455 * @brief Enable clocks to populated sockets
2456 */
2457
2458static void sdram_enable_memory_clocks(struct sys_info *sysinfo)
2459{
2460 u8 clocks[2] = { 0, 0 };
2461
Julius Wernercd49cce2019-03-05 16:53:33 -08002462#if CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002463#define CLOCKS_WIDTH 2
Julius Wernercd49cce2019-03-05 16:53:33 -08002464#elif CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GC)
Stefan Reinauer24b4df52010-01-17 13:47:35 +00002465#define CLOCKS_WIDTH 3
2466#endif
Stefan Reinauer278534d2008-10-29 04:51:07 +00002467 if (sysinfo->dimm[0] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002468 clocks[0] |= (1 << CLOCKS_WIDTH) - 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002469
2470 if (sysinfo->dimm[1] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002471 clocks[0] |= ((1 << CLOCKS_WIDTH) - 1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002472
2473 if (sysinfo->dimm[2] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002474 clocks[1] |= (1 << CLOCKS_WIDTH) - 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002475
2476 if (sysinfo->dimm[3] != SYSINFO_DIMM_NOT_POPULATED)
Angel Pons30492572020-06-11 13:24:54 +02002477 clocks[1] |= ((1 << CLOCKS_WIDTH) - 1) << CLOCKS_WIDTH;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002478
Julius Wernercd49cce2019-03-05 16:53:33 -08002479#if CONFIG(OVERRIDE_CLOCK_DISABLE)
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002480 /* Usually system firmware turns off system memory clock signals to unused SO-DIMM slots
2481 * to reduce EMI and power consumption.
2482 * However, the Kontron 986LCD-M does not like unused clock signals to be disabled.
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002483 */
2484
2485 clocks[0] = 0xf; /* force all clock gate pairs to enable */
2486 clocks[1] = 0xf; /* force all clock gate pairs to enable */
Stefan Reinauer278534d2008-10-29 04:51:07 +00002487#endif
2488
Angel Pons1d4044a2021-03-27 19:11:51 +01002489 mchbar_write8(C0DCLKDIS, clocks[0]);
2490 mchbar_write8(C1DCLKDIS, clocks[1]);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002491}
2492
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002493#define RTT_ODT_NONE 0
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002494#define RTT_ODT_50_OHM ((1 << 9) | (1 << 5))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002495#define RTT_ODT_75_OHM (1 << 5)
2496#define RTT_ODT_150_OHM (1 << 9)
2497
Arthur Heymans70a8e342017-03-09 11:30:23 +01002498#define EMRS_OCD_DEFAULT ((1 << 12) | (1 << 11) | (1 << 10))
Stefan Reinauer278534d2008-10-29 04:51:07 +00002499
2500#define MRS_CAS_3 (3 << 7)
2501#define MRS_CAS_4 (4 << 7)
2502#define MRS_CAS_5 (5 << 7)
2503
2504#define MRS_TWR_3 (2 << 12)
2505#define MRS_TWR_4 (3 << 12)
2506#define MRS_TWR_5 (4 << 12)
2507
2508#define MRS_BT (1 << 6)
2509
2510#define MRS_BL4 (2 << 3)
2511#define MRS_BL8 (3 << 3)
2512
2513static void sdram_jedec_enable(struct sys_info *sysinfo)
2514{
2515 int i, nonzero;
2516 u32 bankaddr = 0, tmpaddr, mrsaddr = 0;
2517
2518 for (i = 0, nonzero = -1; i < 8; i++) {
Elyes HAOUAS01912202019-01-19 16:36:38 +01002519 if (sysinfo->banksize[i] == 0)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002520 continue;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002521
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002522 printk(BIOS_DEBUG, "jedec enable sequence: bank %d\n", i);
Elyes HAOUAS01912202019-01-19 16:36:38 +01002523
2524 if (nonzero != -1) {
2525 if (sysinfo->interleaved && nonzero < 4 && i >= 4) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002526 bankaddr = 0x40;
Elyes HAOUAS01912202019-01-19 16:36:38 +01002527 } else {
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002528 printk(BIOS_DEBUG, "bankaddr from bank size of rank %d\n",
2529 nonzero);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002530 bankaddr += sysinfo->banksize[nonzero] <<
2531 (sysinfo->interleaved ? 26 : 25);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002532 }
Stefan Reinauer278534d2008-10-29 04:51:07 +00002533 }
2534
Elyes HAOUAS95cdd9f2020-03-26 12:20:38 +01002535 /*
2536 * We have a bank with a non-zero size... Remember it
Stefan Reinauer278534d2008-10-29 04:51:07 +00002537 * for the next offset we have to calculate
2538 */
2539 nonzero = i;
2540
2541 /* Get CAS latency set up */
2542 switch (sysinfo->cas) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002543 case 5:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002544 mrsaddr = MRS_CAS_5;
2545 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002546 case 4:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002547 mrsaddr = MRS_CAS_4;
2548 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002549 case 3:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002550 mrsaddr = MRS_CAS_3;
2551 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002552 default:
2553 die("Jedec Error (CAS).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002554 }
2555
2556 /* Get tWR set */
2557 switch (sysinfo->twr) {
Arthur Heymans70a8e342017-03-09 11:30:23 +01002558 case 5:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002559 mrsaddr |= MRS_TWR_5;
2560 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002561 case 4:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002562 mrsaddr |= MRS_TWR_4;
2563 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002564 case 3:
Elyes HAOUAS3dff32c2020-03-30 17:16:51 +02002565 mrsaddr |= MRS_TWR_3;
2566 break;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002567 default:
2568 die("Jedec Error (tWR).\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002569 }
2570
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002571 /* Set "Burst Type" */
2572 mrsaddr |= MRS_BT;
2573
Stefan Reinauer278534d2008-10-29 04:51:07 +00002574 /* Interleaved */
Arthur Heymans70a8e342017-03-09 11:30:23 +01002575 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002576 mrsaddr = mrsaddr << 1;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002577
2578 /* Only burst length 8 supported */
2579 mrsaddr |= MRS_BL8;
2580
2581 /* Apply NOP */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002582 PRINTK_DEBUG("Apply NOP\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002583 do_ram_command(RAM_COMMAND_NOP);
2584 ram_read32(bankaddr);
2585
2586 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002587 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002588 do_ram_command(RAM_COMMAND_PRECHARGE);
2589 ram_read32(bankaddr);
2590
2591 /* Extended Mode Register Set (2) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002592 PRINTK_DEBUG("Extended Mode Register Set(2)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002593 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_2);
2594 ram_read32(bankaddr);
2595
2596 /* Extended Mode Register Set (3) */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002597 PRINTK_DEBUG("Extended Mode Register Set(3)\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002598 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_3);
2599 ram_read32(bankaddr);
2600
2601 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002602 PRINTK_DEBUG("Extended Mode Register Set\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002603 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2604 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002605 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002606 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002607 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002608 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002609 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002610 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002611 ram_read32(tmpaddr);
2612
2613 /* Mode Register Set: Reset DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002614 PRINTK_DEBUG("MRS: Reset DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002615 do_ram_command(RAM_COMMAND_MRS);
2616 tmpaddr = bankaddr;
2617 tmpaddr |= mrsaddr;
2618 /* Set DLL reset bit */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002619 if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002620 tmpaddr |= (1 << 12);
2621 else
2622 tmpaddr |= (1 << 11);
2623 ram_read32(tmpaddr);
2624
2625 /* Precharge all banks */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002626 PRINTK_DEBUG("All Banks Precharge\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002627 do_ram_command(RAM_COMMAND_PRECHARGE);
2628 ram_read32(bankaddr);
2629
2630 /* CAS before RAS Refresh */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002631 PRINTK_DEBUG("CAS before RAS\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002632 do_ram_command(RAM_COMMAND_CBR);
2633
2634 /* CBR wants two READs */
2635 ram_read32(bankaddr);
2636 ram_read32(bankaddr);
2637
2638 /* Mode Register Set: Enable DLLs */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002639 PRINTK_DEBUG("MRS: Enable DLLs\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002640 do_ram_command(RAM_COMMAND_MRS);
2641
2642 tmpaddr = bankaddr;
2643 tmpaddr |= mrsaddr;
2644 ram_read32(tmpaddr);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002645
Stefan Reinauer278534d2008-10-29 04:51:07 +00002646 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002647 PRINTK_DEBUG("Extended Mode Register Set: ODT/OCD\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002648 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002649
Stefan Reinauer278534d2008-10-29 04:51:07 +00002650 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002651 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002652 tmpaddr |= RTT_ODT_75_OHM | EMRS_OCD_DEFAULT;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002653 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002654 tmpaddr |= ((RTT_ODT_150_OHM | EMRS_OCD_DEFAULT) << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002655 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002656 tmpaddr |= RTT_ODT_150_OHM | EMRS_OCD_DEFAULT;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002657 ram_read32(tmpaddr);
2658
2659 /* Extended Mode Register Set */
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002660 PRINTK_DEBUG("Extended Mode Register Set: OCD Exit\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002661 do_ram_command(RAM_COMMAND_EMRS | RAM_EMRS_1);
2662
2663 tmpaddr = bankaddr;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002664 if (!sdram_capabilities_dual_channel())
Stefan Reinauer278534d2008-10-29 04:51:07 +00002665 tmpaddr |= RTT_ODT_75_OHM;
Arthur Heymans70a8e342017-03-09 11:30:23 +01002666 else if (sysinfo->interleaved)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002667 tmpaddr |= (RTT_ODT_150_OHM << 1);
Arthur Heymans70a8e342017-03-09 11:30:23 +01002668 else
Stefan Reinauer278534d2008-10-29 04:51:07 +00002669 tmpaddr |= RTT_ODT_150_OHM;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002670 ram_read32(tmpaddr);
2671 }
2672}
2673
2674static void sdram_init_complete(void)
2675{
Stefan Reinauer779b3e32008-11-10 15:43:37 +00002676 PRINTK_DEBUG("Normal Operation\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002677 do_ram_command(RAM_COMMAND_NORMAL);
2678}
2679
2680static void sdram_setup_processor_side(void)
2681{
2682 if (i945_silicon_revision() == 0)
Angel Pons1d4044a2021-03-27 19:11:51 +01002683 mchbar_setbits32(FSBPMC3, 1 << 2);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002684
Angel Pons1d4044a2021-03-27 19:11:51 +01002685 mchbar_setbits8(0xb00, 1);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002686
2687 if (i945_silicon_revision() == 0)
Angel Pons1d4044a2021-03-27 19:11:51 +01002688 mchbar_setbits32(SLPCTL, 1 << 8);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002689}
2690
Stefan Reinauer278534d2008-10-29 04:51:07 +00002691/**
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002692 * @param boot_path: 0 = normal, 1 = reset, 2 = resume from s3
Martin Rothf4cb4122015-01-06 10:27:39 -07002693 * @param spd_addresses pointer to a list of SPD addresses
Stefan Reinauer278534d2008-10-29 04:51:07 +00002694 */
Sven Schnelle541269b2011-02-21 09:39:17 +00002695void sdram_initialize(int boot_path, const u8 *spd_addresses)
Stefan Reinauer278534d2008-10-29 04:51:07 +00002696{
2697 struct sys_info sysinfo;
Stefan Reinauer278534d2008-10-29 04:51:07 +00002698
Jakub Czapigaad6157e2022-02-15 11:50:31 +01002699 timestamp_add_now(TS_INITRAM_START);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002700 printk(BIOS_DEBUG, "Setting up RAM controller.\n");
Stefan Reinauer278534d2008-10-29 04:51:07 +00002701
2702 memset(&sysinfo, 0, sizeof(sysinfo));
2703
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002704 sysinfo.boot_path = boot_path;
Sven Schnelle541269b2011-02-21 09:39:17 +00002705 sysinfo.spd_addresses = spd_addresses;
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002706
Stefan Reinauer278534d2008-10-29 04:51:07 +00002707 /* Look at the type of DIMMs and verify all DIMMs are x8 or x16 width */
2708 sdram_get_dram_configuration(&sysinfo);
2709
Stefan Reinauerbf264e92010-05-14 19:09:20 +00002710 /* If error, do cold boot */
2711 sdram_detect_errors(&sysinfo);
2712
Stefan Reinauer278534d2008-10-29 04:51:07 +00002713 /* Program PLL settings */
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002714 sdram_program_pll_settings(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002715
Arthur Heymans18537812016-12-28 21:20:45 +01002716 /*
2717 * Program Graphics Frequency
2718 * Set core display and render clock on 945GC to the max
2719 */
Julius Wernercd49cce2019-03-05 16:53:33 -08002720 if (CONFIG(NORTHBRIDGE_INTEL_SUBTYPE_I945GM))
Arthur Heymans18537812016-12-28 21:20:45 +01002721 sdram_program_graphics_frequency(&sysinfo);
2722 else
Angel Pons3580d812020-06-11 14:13:33 +02002723 pci_write_config16(IGD_DEV, GCFC, 0x0534);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002724
2725 /* Program System Memory Frequency */
2726 sdram_program_memory_frequency(&sysinfo);
2727
2728 /* Determine Mode of Operation (Interleaved etc) */
2729 sdram_set_channel_mode(&sysinfo);
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002730
Stefan Reinauer278534d2008-10-29 04:51:07 +00002731 /* Program Clock Crossing values */
2732 sdram_program_clock_crossing();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002733
Stefan Reinauer278534d2008-10-29 04:51:07 +00002734 /* Disable fast dispatch */
2735 sdram_disable_fast_dispatch();
2736
2737 /* Enable WIODLL Power Down in ACPI states */
Angel Pons1d4044a2021-03-27 19:11:51 +01002738 mchbar_setbits32(C0DMC, 1 << 24);
2739 mchbar_setbits32(C1DMC, 1 << 24);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002740
2741 /* Program DRAM Row Boundary/Attribute Registers */
2742
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002743 /* program row size DRB and set TOLUD */
2744 sdram_program_row_boundaries(&sysinfo);
2745
2746 /* program page size DRA */
2747 sdram_set_row_attributes(&sysinfo);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002748
2749 /* Program CxBNKARC */
2750 sdram_set_bank_architecture(&sysinfo);
2751
2752 /* Program DRAM Timing and Control registers based on SPD */
2753 sdram_set_timing_and_control(&sysinfo);
2754
2755 /* On-Die Termination Adjustment */
2756 sdram_on_die_termination(&sysinfo);
2757
2758 /* Pre Jedec Initialization */
2759 sdram_pre_jedec_initialization();
2760
2761 /* Perform System Memory IO Initialization */
2762 sdram_initialize_system_memory_io(&sysinfo);
2763
2764 /* Perform System Memory IO Buffer Enable */
2765 sdram_enable_system_memory_io(&sysinfo);
2766
2767 /* Enable System Memory Clocks */
2768 sdram_enable_memory_clocks(&sysinfo);
2769
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002770 if (boot_path == BOOT_PATH_NORMAL) {
Stefan Reinauer278534d2008-10-29 04:51:07 +00002771 /* Jedec Initialization sequence */
2772 sdram_jedec_enable(&sysinfo);
2773 }
2774
2775 /* Program Power Management Registers */
2776 sdram_power_management(&sysinfo);
2777
2778 /* Post Jedec Init */
2779 sdram_post_jedec_initialization(&sysinfo);
2780
2781 /* Program DRAM Throttling */
2782 sdram_thermal_management();
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002783
Stefan Reinauer278534d2008-10-29 04:51:07 +00002784 /* Normal Operations */
Stefan Reinaueraca6ec62009-10-26 17:12:21 +00002785 sdram_init_complete();
Stefan Reinauer278534d2008-10-29 04:51:07 +00002786
2787 /* Program Receive Enable Timings */
2788 sdram_program_receive_enable(&sysinfo);
2789
2790 /* Enable Periodic RCOMP */
2791 sdram_enable_rcomp();
2792
2793 /* Tell ICH7 that we're done */
Angel Ponse3c68d22020-06-08 12:09:03 +02002794 pci_and_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_2, (u8)~(1 << 7));
Stefan Reinauer278534d2008-10-29 04:51:07 +00002795
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00002796 printk(BIOS_DEBUG, "RAM initialization finished.\n");
Stefan Reinauer71a3d962009-07-21 21:44:24 +00002797
Stefan Reinauer278534d2008-10-29 04:51:07 +00002798 sdram_setup_processor_side();
Jakub Czapigaad6157e2022-02-15 11:50:31 +01002799 timestamp_add_now(TS_INITRAM_END);
Stefan Reinauer278534d2008-10-29 04:51:07 +00002800}