blob: dee697f5e580021773980f5ea21f715e34c9c45e [file] [log] [blame]
Corey Osgoodbd3f93e2008-02-21 00:56:14 +00001/*
2 * This file is part of the coreboot project.
3 *
Aaron Lwefcb2a312008-05-19 12:17:43 +00004 * Copyright (C) 2008 VIA Technologies, Inc.
5 * (Written by Aaron Lwe <aaron.lwe@gmail.com> for VIA)
Corey Osgoodbd3f93e2008-02-21 00:56:14 +00006 * Copyright (C) 2007 Corey Osgood <corey.osgood@gmail.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
Patrick Georgib890a122015-03-26 15:17:45 +010020 * Foundation, Inc.
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000021 */
22
23#include <spd.h>
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000024#include <delay.h>
25#include "cn700.h"
26
Stefan Reinauerd4814bd2011-04-21 20:45:45 +000027#if CONFIG_DEBUG_RAM_SETUP
Stefan Reinauer65b72ab2015-01-05 12:59:54 -080028#define PRINT_DEBUG_MEM(x) printk(BIOS_DEBUG, x)
29#define PRINT_DEBUG_MEM_HEX8(x) printk(BIOS_DEBUG, "%02x", x)
30#define PRINT_DEBUG_MEM_HEX16(x) printk(BIOS_DEBUG, "%04x", x)
31#define PRINT_DEBUG_MEM_HEX32(x) printk(BIOS_DEBUG, "%08x", x)
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000032#define DUMPNORTH() dump_pci_device(PCI_DEV(0, 0, 0))
33#else
34#define PRINT_DEBUG_MEM(x)
35#define PRINT_DEBUG_MEM_HEX8(x)
36#define PRINT_DEBUG_MEM_HEX16(x)
37#define PRINT_DEBUG_MEM_HEX32(x)
38#define DUMPNORTH()
39#endif
40
Aaron Lwefcb2a312008-05-19 12:17:43 +000041static void do_ram_command(device_t dev, u8 command)
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000042{
43 u8 reg;
44
45 /* TODO: Support for multiple DIMMs. */
46
47 reg = pci_read_config8(dev, DRAM_MISC_CTL);
48 reg &= 0xf8; /* Clear bits 2-0. */
49 reg |= command;
50 pci_write_config8(dev, DRAM_MISC_CTL, reg);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000051}
52
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000053/**
Stefan Reinauer14e22772010-04-27 06:56:47 +000054 * Configure the bus between the CPU and the northbridge. This might be able to
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000055 * be moved to post-ram code in the future. For the most part, these registers
56 * should not be messed around with. These are too complex to explain short of
57 * copying the datasheets into the comments, but most of these values are from
58 * the BIOS Porting Guide, so they should work on any board. If they don't,
59 * try the values from your factory BIOS.
60 *
Uwe Hermannea7b5182008-10-09 17:08:32 +000061 * TODO: Changing the DRAM frequency doesn't work (hard lockup).
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000062 *
Uwe Hermannea7b5182008-10-09 17:08:32 +000063 * @param dev The northbridge's CPU Host Interface (D0F2).
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000064 */
65static void c7_cpu_setup(device_t dev)
66{
67 /* Host bus interface registers (D0F2 0x50-0x67) */
68 /* Request phase control */
69 pci_write_config8(dev, 0x50, 0x88);
70 /* CPU Interface Control */
71 pci_write_config8(dev, 0x51, 0x7a);
72 pci_write_config8(dev, 0x52, 0x6f);
73 /* Arbitration */
74 pci_write_config8(dev, 0x53, 0x88);
75 /* Miscellaneous Control */
Aaron Lwefcb2a312008-05-19 12:17:43 +000076 pci_write_config8(dev, 0x54, 0x1e);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000077 pci_write_config8(dev, 0x55, 0x16);
78 /* Write Policy */
79 pci_write_config8(dev, 0x56, 0x01);
80 /* Miscellaneous Control */
Uwe Hermannea7b5182008-10-09 17:08:32 +000081 /*
82 * DRAM Operating Frequency (bits 7:5)
83 * 000 : 100MHz 001 : 133MHz
84 * 010 : 166MHz 011 : 200MHz
85 * 100 : 266MHz 101 : 333MHz
86 * 110/111 : Reserved
87 */
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000088 /* CPU Miscellaneous Control */
Uwe Hermannea7b5182008-10-09 17:08:32 +000089 pci_write_config8(dev, 0x59, 0x44);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000090 /* Write Policy */
91 pci_write_config8(dev, 0x5d, 0xb2);
92 /* Bandwidth Timer */
93 pci_write_config8(dev, 0x5e, 0x88);
94 /* CPU Miscellaneous Control */
95 pci_write_config8(dev, 0x5f, 0xc7);
96
97 /* Line DRDY# Timing Control */
98 pci_write_config8(dev, 0x60, 0xff);
99 pci_write_config8(dev, 0x61, 0xff);
100 pci_write_config8(dev, 0x62, 0x0f);
101 /* QW DRDY# Timing Control */
102 pci_write_config8(dev, 0x63, 0xff);
103 pci_write_config8(dev, 0x64, 0xff);
104 pci_write_config8(dev, 0x65, 0x0f);
105 /* Read Line Burst DRDY# Timing Control */
106 pci_write_config8(dev, 0x66, 0xff);
Aaron Lwefcb2a312008-05-19 12:17:43 +0000107 pci_write_config8(dev, 0x67, 0x30);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000108
109 /* Host Bus I/O Circuit (see datasheet) */
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000110 /* Host Address Pullup/down Driving */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000111 pci_write_config8(dev, 0x70, 0x11);
112 pci_write_config8(dev, 0x71, 0x11);
113 pci_write_config8(dev, 0x72, 0x11);
114 pci_write_config8(dev, 0x73, 0x11);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000115 /* Miscellaneous Control */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000116 pci_write_config8(dev, 0x74, 0x35);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000117 /* AGTL+ I/O Circuit */
118 pci_write_config8(dev, 0x75, 0x28);
119 /* AGTL+ Compensation Status */
120 pci_write_config8(dev, 0x76, 0x74);
121 /* AGTL+ Auto Compensation Offest */
122 pci_write_config8(dev, 0x77, 0x00);
123 /* Host FSB CKG Control */
124 pci_write_config8(dev, 0x78, 0x0a);
125 /* Address/Address Clock Output Delay Control */
126 pci_write_config8(dev, 0x79, 0xaa);
127 /* Address Strobe Input Delay Control */
128 pci_write_config8(dev, 0x7a, 0x24);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000129 /* Address CKG Rising/Falling Time Control */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000130 pci_write_config8(dev, 0x7b, 0xaa);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000131 /* Address CKG Clock Rising/Falling Time Control */
132 pci_write_config8(dev, 0x7c, 0x00);
133 /* Undefined (can't remember why I did this) */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000134 pci_write_config8(dev, 0x7d, 0x6d);
135 pci_write_config8(dev, 0x7e, 0x00);
136 pci_write_config8(dev, 0x7f, 0x00);
137 pci_write_config8(dev, 0x80, 0x1b);
138 pci_write_config8(dev, 0x81, 0x0a);
139 pci_write_config8(dev, 0x82, 0x0a);
140 pci_write_config8(dev, 0x83, 0x0a);
141}
142
143/**
Uwe Hermannea7b5182008-10-09 17:08:32 +0000144 * Set up DRAM size according to SPD data. Eventually, DRAM timings should be
Aaron Lwefcb2a312008-05-19 12:17:43 +0000145 * done in a similar manner.
146 *
Uwe Hermannea7b5182008-10-09 17:08:32 +0000147 * @param ctrl The northbridge devices and SPD addresses.
Aaron Lwefcb2a312008-05-19 12:17:43 +0000148 */
149static void sdram_set_size(const struct mem_controller *ctrl)
150{
151 u8 density, ranks, result, col;
152
153 ranks = spd_read_byte(ctrl->channel0[0], SPD_NUM_DIMM_BANKS);
154 ranks = (ranks & 0x07) + 1;
Uwe Hermannea7b5182008-10-09 17:08:32 +0000155 density = spd_read_byte(ctrl->channel0[0],
156 SPD_DENSITY_OF_EACH_ROW_ON_MODULE);
157 switch (density) {
158 case 0x80:
159 result = 0x08; /* 512MB / 64MB = 0x08 */
160 break;
161 case 0x40:
162 result = 0x04;
163 break;
164 case 0x20:
165 result = 0x02;
166 break;
167 case 0x10:
168 result = 0xff; /* 16GB */
169 break;
170 case 0x08:
171 result = 0xff; /* 8GB */
172 break;
173 case 0x04:
174 result = 0xff; /* 4GB */
175 break;
176 case 0x02:
177 result = 0x20; /* 2GB */
178 break;
179 case 0x01:
180 result = 0x10; /* 1GB */
181 break;
Stefan Reinauer89fcdec2011-10-13 17:03:04 -0700182 default:
183 result = 0;
Aaron Lwefcb2a312008-05-19 12:17:43 +0000184 }
185
Stefan Reinauer89fcdec2011-10-13 17:03:04 -0700186 switch (result) {
187 case 0xff:
Stefan Reinauer64ed2b72010-03-31 14:47:43 +0000188 die("DRAM module size too big, not supported by CN700\n");
Stefan Reinauer89fcdec2011-10-13 17:03:04 -0700189 break;
190 case 0:
191 die("DRAM module has unknown density\n");
192 break;
193 default:
Corey Osgoodf9765482010-08-01 17:20:20 +0000194 printk(BIOS_DEBUG, "Found %iMB of ram\n", result * ranks * 64);
Stefan Reinauer89fcdec2011-10-13 17:03:04 -0700195 }
Aaron Lwefcb2a312008-05-19 12:17:43 +0000196
197 pci_write_config8(ctrl->d0f3, 0x40, result);
198 pci_write_config8(ctrl->d0f3, 0x48, 0x00);
199 if (ranks == 2) {
200 pci_write_config8(ctrl->d0f3, 0x41, result * ranks);
201 pci_write_config8(ctrl->d0f3, 0x49, result);
202 }
Uwe Hermannea7b5182008-10-09 17:08:32 +0000203 /* Size mirror */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000204 pci_write_config8(ctrl->d0f7, 0xe5, (result * ranks) << 2);
205 pci_write_config8(ctrl->d0f7, 0x57, (result * ranks) << 2);
206 /* Low Top Address */
207 pci_write_config8(ctrl->d0f3, 0x84, 0x00);
208 pci_write_config8(ctrl->d0f3, 0x85, (result * ranks) << 2);
209 pci_write_config8(ctrl->d0f3, 0x88, (result * ranks) << 2);
210
211 /* Physical-Virtual Mapping */
212 if (ranks == 2)
Uwe Hermannea7b5182008-10-09 17:08:32 +0000213 pci_write_config8(ctrl->d0f3, 0x54,
214 1 << 7 | 0 << 4 | 1 << 3 | 1 << 0);
Aaron Lwefcb2a312008-05-19 12:17:43 +0000215 if (ranks == 1)
216 pci_write_config8(ctrl->d0f3, 0x54, 1 << 7 | 0 << 4);
217 pci_write_config8(ctrl->d0f3, 0x55, 0x00);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000218 /* Virtual rank interleave, disable */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000219 pci_write_config32(ctrl->d0f3, 0x58, 0x00);
220
221 /* MA Map Type */
222 result = spd_read_byte(ctrl->channel0[0], SPD_NUM_BANKS_PER_SDRAM);
223 if (result == 8) {
224 col = spd_read_byte(ctrl->channel0[0], SPD_NUM_COLUMNS);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000225 switch (col) {
226 case 10:
227 pci_write_config8(ctrl->d0f3, 0x50, 0xa0);
228 break;
229 case 11:
230 pci_write_config8(ctrl->d0f3, 0x50, 0xc0);
231 break;
232 case 12:
233 pci_write_config8(ctrl->d0f3, 0x50, 0xe0);
234 break;
Aaron Lwefcb2a312008-05-19 12:17:43 +0000235 }
Uwe Hermannea7b5182008-10-09 17:08:32 +0000236 } else if (result == 4) {
Aaron Lwefcb2a312008-05-19 12:17:43 +0000237 col = spd_read_byte(ctrl->channel0[0], SPD_NUM_COLUMNS);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000238 switch (col) {
239 case 9:
240 pci_write_config8(ctrl->d0f3, 0x50, 0x00);
241 break;
242 case 10:
243 pci_write_config8(ctrl->d0f3, 0x50, 0x20);
244 break;
245 case 11:
246 pci_write_config8(ctrl->d0f3, 0x50, 0x40);
247 break;
248 case 12:
249 pci_write_config8(ctrl->d0f3, 0x50, 0x60);
250 break;
Aaron Lwefcb2a312008-05-19 12:17:43 +0000251 }
252 }
253 pci_write_config8(ctrl->d0f3, 0x51, 0x00);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000254}
255
256/**
Stefan Reinauer14e22772010-04-27 06:56:47 +0000257 * Set up various RAM and other control registers statically. Some of these may
Uwe Hermannea7b5182008-10-09 17:08:32 +0000258 * not be needed, other should be done with SPD info, but that's a project for
259 * the future.
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000260 */
261static void sdram_set_registers(const struct mem_controller *ctrl)
262{
Aaron Lwefcb2a312008-05-19 12:17:43 +0000263 u8 reg;
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000264
Aaron Lwefcb2a312008-05-19 12:17:43 +0000265 /* Set WR=5 */
266 pci_write_config8(ctrl->d0f3, 0x61, 0xe0);
267 /* Set CAS=4 */
268 pci_write_config8(ctrl->d0f3, 0x62, 0xfa);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000269 /* DRAM timing-3 */
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000270 pci_write_config8(ctrl->d0f3, 0x63, 0xca);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000271 /* DRAM timing-4 */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000272 pci_write_config8(ctrl->d0f3, 0x64, 0xcc);
273 /* DIMM command / Address Selection */
274 pci_write_config8(ctrl->d0f3, 0x67, 0x00);
275 /* Disable cross bank/multi page mode */
276 pci_write_config8(ctrl->d0f3, 0x69, 0x00);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000277 /* Disable refresh now */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000278 pci_write_config8(ctrl->d0f3, 0x6a, 0x00);
279
Uwe Hermannea7b5182008-10-09 17:08:32 +0000280 /* Frequency 100 MHz */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000281 pci_write_config8(ctrl->d0f3, 0x90, 0x00);
282 pci_write_config8(ctrl->d0f2, 0x57, 0x18);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000283 /* Allow manual DLL reset */
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000284 pci_write_config8(ctrl->d0f3, 0x6b, 0x10);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000285
Aaron Lwefcb2a312008-05-19 12:17:43 +0000286 /* Bank/Rank Interleave Address Select */
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000287 pci_write_config8(ctrl->d0f3, 0x52, 0x33);
288 pci_write_config8(ctrl->d0f3, 0x53, 0x3f);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000289
290 /* Set to DDR2 SDRAM, BL=8 (0xc8, 0xc0 for bl=4) */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000291 pci_write_config8(ctrl->d0f3, 0x6c, 0xc8);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000292
Aaron Lwefcb2a312008-05-19 12:17:43 +0000293 /* DRAM Bus Turn-Around Setting */
294 pci_write_config8(ctrl->d0f3, 0x60, 0x03);
295 /* DRAM Arbitration Control */
296 pci_write_config8(ctrl->d0f3, 0x66, 0x80);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000297 /*
298 * DQS Tuning: testing on a couple different boards has shown this is
Aaron Lwefcb2a312008-05-19 12:17:43 +0000299 * static, or close enough that it can be. Which is good, because the
Uwe Hermannea7b5182008-10-09 17:08:32 +0000300 * tuning function used too many registers.
Aaron Lwefcb2a312008-05-19 12:17:43 +0000301 */
Uwe Hermannea7b5182008-10-09 17:08:32 +0000302 /* DQS Output Delay for Channel A */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000303 pci_write_config8(ctrl->d0f3, 0x70, 0x00);
304 /* MD Output Delay for Channel A */
305 pci_write_config8(ctrl->d0f3, 0x71, 0x01);
306 pci_write_config8(ctrl->d0f3, 0x73, 0x01);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000307
Uwe Hermannea7b5182008-10-09 17:08:32 +0000308 /* DRAM arbitration timer */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000309 pci_write_config8(ctrl->d0f3, 0x65, 0xd9);
310
Uwe Hermannea7b5182008-10-09 17:08:32 +0000311 /* DRAM signal timing control */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000312 pci_write_config8(ctrl->d0f3, 0x74, 0x01);
313 pci_write_config8(ctrl->d0f3, 0x75, 0x01);
314 pci_write_config8(ctrl->d0f3, 0x76, 0x06);
315 pci_write_config8(ctrl->d0f3, 0x77, 0x92);
316 pci_write_config8(ctrl->d0f3, 0x78, 0x83);
317 pci_write_config8(ctrl->d0f3, 0x79, 0x83);
318 pci_write_config8(ctrl->d0f3, 0x7a, 0x00);
319 pci_write_config8(ctrl->d0f3, 0x7b, 0x10);
320
Uwe Hermannea7b5182008-10-09 17:08:32 +0000321 /* DRAM clocking control */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000322 pci_write_config8(ctrl->d0f3, 0x91, 0x01);
323 /* CS/CKE Clock Phase Control */
324 pci_write_config8(ctrl->d0f3, 0x92, 0x02);
325 /* SCMD/MA Clock Phase Control */
326 pci_write_config8(ctrl->d0f3, 0x93, 0x02);
327 /* DCLKO Feedback Mode Output Control */
328 pci_write_config8(ctrl->d0f3, 0x94, 0x00);
329 pci_write_config8(ctrl->d0f3, 0x9d, 0x0f);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000330
Aaron Lwefcb2a312008-05-19 12:17:43 +0000331 /* SDRAM ODT Control */
332 pci_write_config8(ctrl->d0f3, 0xda, 0x80);
333 /* Channel A DQ/DQS CKG Output Delay Control */
334 pci_write_config8(ctrl->d0f3, 0xdc, 0x54);
335 /* Channel A DQ/DQS CKG Output Delay Control */
336 pci_write_config8(ctrl->d0f3, 0xdd, 0x55);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000337 /* ODT lookup table */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000338 pci_write_config8(ctrl->d0f3, 0xd8, 0x01);
339 pci_write_config8(ctrl->d0f3, 0xd9, 0x0a);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000340
Uwe Hermannea7b5182008-10-09 17:08:32 +0000341 /* DDR SDRAM control */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000342 pci_write_config8(ctrl->d0f3, 0x6d, 0xc0);
343 pci_write_config8(ctrl->d0f3, 0x6f, 0x41);
344
345 /* DQ/DQS Strength Control */
346 pci_write_config8(ctrl->d0f3, 0xd0, 0xaa);
347
348 /* Compensation Control */
Uwe Hermannea7b5182008-10-09 17:08:32 +0000349 pci_write_config8(ctrl->d0f3, 0xd3, 0x01); /* Enable autocompensation */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000350 /* ODT (some are set with driving select above) */
351 pci_write_config8(ctrl->d0f3, 0xd4, 0x80);
352 pci_write_config8(ctrl->d0f3, 0xd5, 0x8a);
353 /* Memory Pads Driving and Range Select */
354 pci_write_config8(ctrl->d0f3, 0xd6, 0xaa);
355
356 pci_write_config8(ctrl->d0f3, 0xe0, 0xee);
357 pci_write_config8(ctrl->d0f3, 0xe2, 0xac);
358 pci_write_config8(ctrl->d0f3, 0xe4, 0x66);
359 pci_write_config8(ctrl->d0f3, 0xe6, 0x33);
360 pci_write_config8(ctrl->d0f3, 0xe8, 0x86);
361 /* DQS / DQ CKG Duty Cycle Control */
362 pci_write_config8(ctrl->d0f3, 0xec, 0x00);
363 /* MCLK Output Duty Control */
364 pci_write_config8(ctrl->d0f3, 0xee, 0x00);
365 /* DQS CKG Input Delay Control */
366 pci_write_config8(ctrl->d0f3, 0xef, 0x10);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000367
368 /* DRAM duty control */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000369 pci_write_config8(ctrl->d0f3, 0xed, 0x10);
370
Bari Arid4759d02008-09-01 01:48:07 +0000371 /* SMM and APIC decoding, we do not use SMM */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000372 reg = 0x29;
373 pci_write_config8(ctrl->d0f3, 0x86, reg);
374 /* SMM and APIC decoding mirror */
375 pci_write_config8(ctrl->d0f7, 0xe6, reg);
376
Uwe Hermannea7b5182008-10-09 17:08:32 +0000377 /* DRAM module configuration */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000378 pci_write_config8(ctrl->d0f3, 0x6e, 0x89);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000379}
380
Aaron Lwefcb2a312008-05-19 12:17:43 +0000381static void sdram_set_post(const struct mem_controller *ctrl)
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000382{
Aaron Lwefcb2a312008-05-19 12:17:43 +0000383 device_t dev = ctrl->d0f3;
Uwe Hermannea7b5182008-10-09 17:08:32 +0000384
Aaron Lwefcb2a312008-05-19 12:17:43 +0000385 /* Enable multipage mode. */
386 pci_write_config8(dev, 0x69, 0x03);
387
388 /* Enable refresh. */
389 pci_write_config8(dev, 0x6a, 0x32);
390
Uwe Hermannea7b5182008-10-09 17:08:32 +0000391 /* VGA device. */
392 pci_write_config16(dev, 0xa0, (1 << 15));
Aaron Lwefcb2a312008-05-19 12:17:43 +0000393 pci_write_config16(dev, 0xa4, 0x0010);
Aaron Lwefcb2a312008-05-19 12:17:43 +0000394}
395
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800396static void sdram_enable(device_t dev, u8 *rank_address)
Aaron Lwefcb2a312008-05-19 12:17:43 +0000397{
398 u8 i;
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000399
400 /* 1. Apply NOP. */
Stefan Reinauer64ed2b72010-03-31 14:47:43 +0000401 PRINT_DEBUG_MEM("RAM Enable 1: Apply NOP\n");
Aaron Lwefcb2a312008-05-19 12:17:43 +0000402 do_ram_command(dev, RAM_COMMAND_NOP);
403 udelay(100);
404 read32(rank_address + 0x10);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000405
406 /* 2. Precharge all. */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000407 udelay(400);
Stefan Reinauer64ed2b72010-03-31 14:47:43 +0000408 PRINT_DEBUG_MEM("RAM Enable 2: Precharge all\n");
Aaron Lwefcb2a312008-05-19 12:17:43 +0000409 do_ram_command(dev, RAM_COMMAND_PRECHARGE);
410 read32(rank_address + 0x10);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000411
412 /* 3. Mode register set. */
Corey Osgoodf9765482010-08-01 17:20:20 +0000413 PRINT_DEBUG_MEM("RAM Enable 3: Mode register set\n");
Aaron Lwefcb2a312008-05-19 12:17:43 +0000414 do_ram_command(dev, RAM_COMMAND_MRS);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000415 read32(rank_address + 0x120000); /* EMRS DLL Enable */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800416 read32(rank_address + 0x800); /* MRS DLL Reset */
Uwe Hermannea7b5182008-10-09 17:08:32 +0000417
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000418 /* 4. Precharge all again. */
Corey Osgoodf9765482010-08-01 17:20:20 +0000419 PRINT_DEBUG_MEM("RAM Enable 4: Precharge all\n");
Aaron Lwefcb2a312008-05-19 12:17:43 +0000420 do_ram_command(dev, RAM_COMMAND_PRECHARGE);
421 read32(rank_address + 0x0);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000422
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000423 /* 5. Perform 8 refresh cycles. Wait tRC each time. */
Corey Osgoodf9765482010-08-01 17:20:20 +0000424 PRINT_DEBUG_MEM("RAM Enable 5: CBR\n");
Aaron Lwefcb2a312008-05-19 12:17:43 +0000425 do_ram_command(dev, RAM_COMMAND_CBR);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000426 for (i = 0; i < 8; i++) {
Aaron Lwefcb2a312008-05-19 12:17:43 +0000427 read32(rank_address + 0x20);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000428 udelay(100);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000429 }
430
431 /* 6. Mode register set. */
Corey Osgoodf9765482010-08-01 17:20:20 +0000432 PRINT_DEBUG_MEM("RAM Enable 6: Mode register set\n");
Uwe Hermannea7b5182008-10-09 17:08:32 +0000433 /* Safe value for now, BL=8, WR=5, CAS=4 */
434 /*
Stefan Reinauer14e22772010-04-27 06:56:47 +0000435 * (E)MRS values are from the BPG. No direct explanation is given, but
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000436 * they should somehow conform to the JEDEC DDR2 SDRAM Specification
Uwe Hermannea7b5182008-10-09 17:08:32 +0000437 * (JESD79-2C).
438 */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000439 do_ram_command(dev, RAM_COMMAND_MRS);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000440 read32(rank_address + 0x002258); /* MRS command */
441 read32(rank_address + 0x121c20); /* EMRS OCD Default */
442 read32(rank_address + 0x120020); /* EMRS OCD Calibration Mode Exit */
443
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000444 /* 8. Normal operation */
Corey Osgoodf9765482010-08-01 17:20:20 +0000445 PRINT_DEBUG_MEM("RAM Enable 7: Normal operation\n");
Aaron Lwefcb2a312008-05-19 12:17:43 +0000446 do_ram_command(dev, RAM_COMMAND_NORMAL);
447 read32(rank_address + 0x30);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000448}
Aaron Lwefcb2a312008-05-19 12:17:43 +0000449
450/*
Uwe Hermannea7b5182008-10-09 17:08:32 +0000451 * Support one DIMM with up to 2 ranks.
Aaron Lwefcb2a312008-05-19 12:17:43 +0000452 */
453static void ddr_ram_setup(const struct mem_controller *ctrl)
454{
455 u8 reg;
456
457 c7_cpu_setup(ctrl->d0f2);
458 sdram_set_registers(ctrl);
459 sdram_set_size(ctrl);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800460 sdram_enable(ctrl->d0f3, (u8 *)0);
Aaron Lwefcb2a312008-05-19 12:17:43 +0000461 reg = pci_read_config8(ctrl->d0f3, 0x41);
462 if (reg != 0)
Uwe Hermannea7b5182008-10-09 17:08:32 +0000463 sdram_enable(ctrl->d0f3,
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800464 (u8 *)(pci_read_config8(ctrl->d0f3, 0x40) << 26));
Aaron Lwefcb2a312008-05-19 12:17:43 +0000465 sdram_set_post(ctrl);
466}