blob: f85f68e6199c1f6564de5a23b3b00ce11448971c [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.
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000017 */
18
19#include <spd.h>
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000020#include <delay.h>
21#include "cn700.h"
22
Stefan Reinauerd4814bd2011-04-21 20:45:45 +000023#if CONFIG_DEBUG_RAM_SETUP
Stefan Reinauer65b72ab2015-01-05 12:59:54 -080024#define PRINT_DEBUG_MEM(x) printk(BIOS_DEBUG, x)
25#define PRINT_DEBUG_MEM_HEX8(x) printk(BIOS_DEBUG, "%02x", x)
26#define PRINT_DEBUG_MEM_HEX16(x) printk(BIOS_DEBUG, "%04x", x)
27#define PRINT_DEBUG_MEM_HEX32(x) printk(BIOS_DEBUG, "%08x", x)
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000028#define DUMPNORTH() dump_pci_device(PCI_DEV(0, 0, 0))
29#else
30#define PRINT_DEBUG_MEM(x)
31#define PRINT_DEBUG_MEM_HEX8(x)
32#define PRINT_DEBUG_MEM_HEX16(x)
33#define PRINT_DEBUG_MEM_HEX32(x)
34#define DUMPNORTH()
35#endif
36
Aaron Lwefcb2a312008-05-19 12:17:43 +000037static void do_ram_command(device_t dev, u8 command)
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000038{
39 u8 reg;
40
41 /* TODO: Support for multiple DIMMs. */
42
43 reg = pci_read_config8(dev, DRAM_MISC_CTL);
44 reg &= 0xf8; /* Clear bits 2-0. */
45 reg |= command;
46 pci_write_config8(dev, DRAM_MISC_CTL, reg);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000047}
48
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000049/**
Stefan Reinauer14e22772010-04-27 06:56:47 +000050 * Configure the bus between the CPU and the northbridge. This might be able to
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000051 * be moved to post-ram code in the future. For the most part, these registers
52 * should not be messed around with. These are too complex to explain short of
53 * copying the datasheets into the comments, but most of these values are from
54 * the BIOS Porting Guide, so they should work on any board. If they don't,
55 * try the values from your factory BIOS.
56 *
Uwe Hermannea7b5182008-10-09 17:08:32 +000057 * TODO: Changing the DRAM frequency doesn't work (hard lockup).
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000058 *
Uwe Hermannea7b5182008-10-09 17:08:32 +000059 * @param dev The northbridge's CPU Host Interface (D0F2).
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000060 */
61static void c7_cpu_setup(device_t dev)
62{
63 /* Host bus interface registers (D0F2 0x50-0x67) */
64 /* Request phase control */
65 pci_write_config8(dev, 0x50, 0x88);
66 /* CPU Interface Control */
67 pci_write_config8(dev, 0x51, 0x7a);
68 pci_write_config8(dev, 0x52, 0x6f);
69 /* Arbitration */
70 pci_write_config8(dev, 0x53, 0x88);
71 /* Miscellaneous Control */
Aaron Lwefcb2a312008-05-19 12:17:43 +000072 pci_write_config8(dev, 0x54, 0x1e);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000073 pci_write_config8(dev, 0x55, 0x16);
74 /* Write Policy */
75 pci_write_config8(dev, 0x56, 0x01);
76 /* Miscellaneous Control */
Uwe Hermannea7b5182008-10-09 17:08:32 +000077 /*
78 * DRAM Operating Frequency (bits 7:5)
79 * 000 : 100MHz 001 : 133MHz
80 * 010 : 166MHz 011 : 200MHz
81 * 100 : 266MHz 101 : 333MHz
82 * 110/111 : Reserved
83 */
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000084 /* CPU Miscellaneous Control */
Uwe Hermannea7b5182008-10-09 17:08:32 +000085 pci_write_config8(dev, 0x59, 0x44);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +000086 /* Write Policy */
87 pci_write_config8(dev, 0x5d, 0xb2);
88 /* Bandwidth Timer */
89 pci_write_config8(dev, 0x5e, 0x88);
90 /* CPU Miscellaneous Control */
91 pci_write_config8(dev, 0x5f, 0xc7);
92
93 /* Line DRDY# Timing Control */
94 pci_write_config8(dev, 0x60, 0xff);
95 pci_write_config8(dev, 0x61, 0xff);
96 pci_write_config8(dev, 0x62, 0x0f);
97 /* QW DRDY# Timing Control */
98 pci_write_config8(dev, 0x63, 0xff);
99 pci_write_config8(dev, 0x64, 0xff);
100 pci_write_config8(dev, 0x65, 0x0f);
101 /* Read Line Burst DRDY# Timing Control */
102 pci_write_config8(dev, 0x66, 0xff);
Aaron Lwefcb2a312008-05-19 12:17:43 +0000103 pci_write_config8(dev, 0x67, 0x30);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000104
105 /* Host Bus I/O Circuit (see datasheet) */
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000106 /* Host Address Pullup/down Driving */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000107 pci_write_config8(dev, 0x70, 0x11);
108 pci_write_config8(dev, 0x71, 0x11);
109 pci_write_config8(dev, 0x72, 0x11);
110 pci_write_config8(dev, 0x73, 0x11);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000111 /* Miscellaneous Control */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000112 pci_write_config8(dev, 0x74, 0x35);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000113 /* AGTL+ I/O Circuit */
114 pci_write_config8(dev, 0x75, 0x28);
115 /* AGTL+ Compensation Status */
116 pci_write_config8(dev, 0x76, 0x74);
117 /* AGTL+ Auto Compensation Offest */
118 pci_write_config8(dev, 0x77, 0x00);
119 /* Host FSB CKG Control */
120 pci_write_config8(dev, 0x78, 0x0a);
121 /* Address/Address Clock Output Delay Control */
122 pci_write_config8(dev, 0x79, 0xaa);
123 /* Address Strobe Input Delay Control */
124 pci_write_config8(dev, 0x7a, 0x24);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000125 /* Address CKG Rising/Falling Time Control */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000126 pci_write_config8(dev, 0x7b, 0xaa);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000127 /* Address CKG Clock Rising/Falling Time Control */
128 pci_write_config8(dev, 0x7c, 0x00);
129 /* Undefined (can't remember why I did this) */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000130 pci_write_config8(dev, 0x7d, 0x6d);
131 pci_write_config8(dev, 0x7e, 0x00);
132 pci_write_config8(dev, 0x7f, 0x00);
133 pci_write_config8(dev, 0x80, 0x1b);
134 pci_write_config8(dev, 0x81, 0x0a);
135 pci_write_config8(dev, 0x82, 0x0a);
136 pci_write_config8(dev, 0x83, 0x0a);
137}
138
139/**
Uwe Hermannea7b5182008-10-09 17:08:32 +0000140 * Set up DRAM size according to SPD data. Eventually, DRAM timings should be
Aaron Lwefcb2a312008-05-19 12:17:43 +0000141 * done in a similar manner.
142 *
Uwe Hermannea7b5182008-10-09 17:08:32 +0000143 * @param ctrl The northbridge devices and SPD addresses.
Aaron Lwefcb2a312008-05-19 12:17:43 +0000144 */
145static void sdram_set_size(const struct mem_controller *ctrl)
146{
147 u8 density, ranks, result, col;
148
149 ranks = spd_read_byte(ctrl->channel0[0], SPD_NUM_DIMM_BANKS);
150 ranks = (ranks & 0x07) + 1;
Uwe Hermannea7b5182008-10-09 17:08:32 +0000151 density = spd_read_byte(ctrl->channel0[0],
152 SPD_DENSITY_OF_EACH_ROW_ON_MODULE);
153 switch (density) {
154 case 0x80:
155 result = 0x08; /* 512MB / 64MB = 0x08 */
156 break;
157 case 0x40:
158 result = 0x04;
159 break;
160 case 0x20:
161 result = 0x02;
162 break;
163 case 0x10:
164 result = 0xff; /* 16GB */
165 break;
166 case 0x08:
167 result = 0xff; /* 8GB */
168 break;
169 case 0x04:
170 result = 0xff; /* 4GB */
171 break;
172 case 0x02:
173 result = 0x20; /* 2GB */
174 break;
175 case 0x01:
176 result = 0x10; /* 1GB */
177 break;
Stefan Reinauer89fcdec2011-10-13 17:03:04 -0700178 default:
179 result = 0;
Aaron Lwefcb2a312008-05-19 12:17:43 +0000180 }
181
Stefan Reinauer89fcdec2011-10-13 17:03:04 -0700182 switch (result) {
183 case 0xff:
Stefan Reinauer64ed2b72010-03-31 14:47:43 +0000184 die("DRAM module size too big, not supported by CN700\n");
Stefan Reinauer89fcdec2011-10-13 17:03:04 -0700185 break;
186 case 0:
187 die("DRAM module has unknown density\n");
188 break;
189 default:
Corey Osgoodf9765482010-08-01 17:20:20 +0000190 printk(BIOS_DEBUG, "Found %iMB of ram\n", result * ranks * 64);
Stefan Reinauer89fcdec2011-10-13 17:03:04 -0700191 }
Aaron Lwefcb2a312008-05-19 12:17:43 +0000192
193 pci_write_config8(ctrl->d0f3, 0x40, result);
194 pci_write_config8(ctrl->d0f3, 0x48, 0x00);
195 if (ranks == 2) {
196 pci_write_config8(ctrl->d0f3, 0x41, result * ranks);
197 pci_write_config8(ctrl->d0f3, 0x49, result);
198 }
Uwe Hermannea7b5182008-10-09 17:08:32 +0000199 /* Size mirror */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000200 pci_write_config8(ctrl->d0f7, 0xe5, (result * ranks) << 2);
201 pci_write_config8(ctrl->d0f7, 0x57, (result * ranks) << 2);
202 /* Low Top Address */
203 pci_write_config8(ctrl->d0f3, 0x84, 0x00);
204 pci_write_config8(ctrl->d0f3, 0x85, (result * ranks) << 2);
205 pci_write_config8(ctrl->d0f3, 0x88, (result * ranks) << 2);
206
207 /* Physical-Virtual Mapping */
208 if (ranks == 2)
Uwe Hermannea7b5182008-10-09 17:08:32 +0000209 pci_write_config8(ctrl->d0f3, 0x54,
210 1 << 7 | 0 << 4 | 1 << 3 | 1 << 0);
Aaron Lwefcb2a312008-05-19 12:17:43 +0000211 if (ranks == 1)
212 pci_write_config8(ctrl->d0f3, 0x54, 1 << 7 | 0 << 4);
213 pci_write_config8(ctrl->d0f3, 0x55, 0x00);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000214 /* Virtual rank interleave, disable */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000215 pci_write_config32(ctrl->d0f3, 0x58, 0x00);
216
217 /* MA Map Type */
218 result = spd_read_byte(ctrl->channel0[0], SPD_NUM_BANKS_PER_SDRAM);
219 if (result == 8) {
220 col = spd_read_byte(ctrl->channel0[0], SPD_NUM_COLUMNS);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000221 switch (col) {
222 case 10:
223 pci_write_config8(ctrl->d0f3, 0x50, 0xa0);
224 break;
225 case 11:
226 pci_write_config8(ctrl->d0f3, 0x50, 0xc0);
227 break;
228 case 12:
229 pci_write_config8(ctrl->d0f3, 0x50, 0xe0);
230 break;
Aaron Lwefcb2a312008-05-19 12:17:43 +0000231 }
Uwe Hermannea7b5182008-10-09 17:08:32 +0000232 } else if (result == 4) {
Aaron Lwefcb2a312008-05-19 12:17:43 +0000233 col = spd_read_byte(ctrl->channel0[0], SPD_NUM_COLUMNS);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000234 switch (col) {
235 case 9:
236 pci_write_config8(ctrl->d0f3, 0x50, 0x00);
237 break;
238 case 10:
239 pci_write_config8(ctrl->d0f3, 0x50, 0x20);
240 break;
241 case 11:
242 pci_write_config8(ctrl->d0f3, 0x50, 0x40);
243 break;
244 case 12:
245 pci_write_config8(ctrl->d0f3, 0x50, 0x60);
246 break;
Aaron Lwefcb2a312008-05-19 12:17:43 +0000247 }
248 }
249 pci_write_config8(ctrl->d0f3, 0x51, 0x00);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000250}
251
252/**
Stefan Reinauer14e22772010-04-27 06:56:47 +0000253 * Set up various RAM and other control registers statically. Some of these may
Uwe Hermannea7b5182008-10-09 17:08:32 +0000254 * not be needed, other should be done with SPD info, but that's a project for
255 * the future.
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000256 */
257static void sdram_set_registers(const struct mem_controller *ctrl)
258{
Aaron Lwefcb2a312008-05-19 12:17:43 +0000259 u8 reg;
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000260
Aaron Lwefcb2a312008-05-19 12:17:43 +0000261 /* Set WR=5 */
262 pci_write_config8(ctrl->d0f3, 0x61, 0xe0);
263 /* Set CAS=4 */
264 pci_write_config8(ctrl->d0f3, 0x62, 0xfa);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000265 /* DRAM timing-3 */
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000266 pci_write_config8(ctrl->d0f3, 0x63, 0xca);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000267 /* DRAM timing-4 */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000268 pci_write_config8(ctrl->d0f3, 0x64, 0xcc);
269 /* DIMM command / Address Selection */
270 pci_write_config8(ctrl->d0f3, 0x67, 0x00);
271 /* Disable cross bank/multi page mode */
272 pci_write_config8(ctrl->d0f3, 0x69, 0x00);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000273 /* Disable refresh now */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000274 pci_write_config8(ctrl->d0f3, 0x6a, 0x00);
275
Uwe Hermannea7b5182008-10-09 17:08:32 +0000276 /* Frequency 100 MHz */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000277 pci_write_config8(ctrl->d0f3, 0x90, 0x00);
278 pci_write_config8(ctrl->d0f2, 0x57, 0x18);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000279 /* Allow manual DLL reset */
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000280 pci_write_config8(ctrl->d0f3, 0x6b, 0x10);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000281
Aaron Lwefcb2a312008-05-19 12:17:43 +0000282 /* Bank/Rank Interleave Address Select */
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000283 pci_write_config8(ctrl->d0f3, 0x52, 0x33);
284 pci_write_config8(ctrl->d0f3, 0x53, 0x3f);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000285
286 /* Set to DDR2 SDRAM, BL=8 (0xc8, 0xc0 for bl=4) */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000287 pci_write_config8(ctrl->d0f3, 0x6c, 0xc8);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000288
Aaron Lwefcb2a312008-05-19 12:17:43 +0000289 /* DRAM Bus Turn-Around Setting */
290 pci_write_config8(ctrl->d0f3, 0x60, 0x03);
291 /* DRAM Arbitration Control */
292 pci_write_config8(ctrl->d0f3, 0x66, 0x80);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000293 /*
294 * DQS Tuning: testing on a couple different boards has shown this is
Aaron Lwefcb2a312008-05-19 12:17:43 +0000295 * static, or close enough that it can be. Which is good, because the
Uwe Hermannea7b5182008-10-09 17:08:32 +0000296 * tuning function used too many registers.
Aaron Lwefcb2a312008-05-19 12:17:43 +0000297 */
Uwe Hermannea7b5182008-10-09 17:08:32 +0000298 /* DQS Output Delay for Channel A */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000299 pci_write_config8(ctrl->d0f3, 0x70, 0x00);
300 /* MD Output Delay for Channel A */
301 pci_write_config8(ctrl->d0f3, 0x71, 0x01);
302 pci_write_config8(ctrl->d0f3, 0x73, 0x01);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000303
Uwe Hermannea7b5182008-10-09 17:08:32 +0000304 /* DRAM arbitration timer */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000305 pci_write_config8(ctrl->d0f3, 0x65, 0xd9);
306
Uwe Hermannea7b5182008-10-09 17:08:32 +0000307 /* DRAM signal timing control */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000308 pci_write_config8(ctrl->d0f3, 0x74, 0x01);
309 pci_write_config8(ctrl->d0f3, 0x75, 0x01);
310 pci_write_config8(ctrl->d0f3, 0x76, 0x06);
311 pci_write_config8(ctrl->d0f3, 0x77, 0x92);
312 pci_write_config8(ctrl->d0f3, 0x78, 0x83);
313 pci_write_config8(ctrl->d0f3, 0x79, 0x83);
314 pci_write_config8(ctrl->d0f3, 0x7a, 0x00);
315 pci_write_config8(ctrl->d0f3, 0x7b, 0x10);
316
Uwe Hermannea7b5182008-10-09 17:08:32 +0000317 /* DRAM clocking control */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000318 pci_write_config8(ctrl->d0f3, 0x91, 0x01);
319 /* CS/CKE Clock Phase Control */
320 pci_write_config8(ctrl->d0f3, 0x92, 0x02);
321 /* SCMD/MA Clock Phase Control */
322 pci_write_config8(ctrl->d0f3, 0x93, 0x02);
323 /* DCLKO Feedback Mode Output Control */
324 pci_write_config8(ctrl->d0f3, 0x94, 0x00);
325 pci_write_config8(ctrl->d0f3, 0x9d, 0x0f);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000326
Aaron Lwefcb2a312008-05-19 12:17:43 +0000327 /* SDRAM ODT Control */
328 pci_write_config8(ctrl->d0f3, 0xda, 0x80);
329 /* Channel A DQ/DQS CKG Output Delay Control */
330 pci_write_config8(ctrl->d0f3, 0xdc, 0x54);
331 /* Channel A DQ/DQS CKG Output Delay Control */
332 pci_write_config8(ctrl->d0f3, 0xdd, 0x55);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000333 /* ODT lookup table */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000334 pci_write_config8(ctrl->d0f3, 0xd8, 0x01);
335 pci_write_config8(ctrl->d0f3, 0xd9, 0x0a);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000336
Uwe Hermannea7b5182008-10-09 17:08:32 +0000337 /* DDR SDRAM control */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000338 pci_write_config8(ctrl->d0f3, 0x6d, 0xc0);
339 pci_write_config8(ctrl->d0f3, 0x6f, 0x41);
340
341 /* DQ/DQS Strength Control */
342 pci_write_config8(ctrl->d0f3, 0xd0, 0xaa);
343
344 /* Compensation Control */
Uwe Hermannea7b5182008-10-09 17:08:32 +0000345 pci_write_config8(ctrl->d0f3, 0xd3, 0x01); /* Enable autocompensation */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000346 /* ODT (some are set with driving select above) */
347 pci_write_config8(ctrl->d0f3, 0xd4, 0x80);
348 pci_write_config8(ctrl->d0f3, 0xd5, 0x8a);
349 /* Memory Pads Driving and Range Select */
350 pci_write_config8(ctrl->d0f3, 0xd6, 0xaa);
351
352 pci_write_config8(ctrl->d0f3, 0xe0, 0xee);
353 pci_write_config8(ctrl->d0f3, 0xe2, 0xac);
354 pci_write_config8(ctrl->d0f3, 0xe4, 0x66);
355 pci_write_config8(ctrl->d0f3, 0xe6, 0x33);
356 pci_write_config8(ctrl->d0f3, 0xe8, 0x86);
357 /* DQS / DQ CKG Duty Cycle Control */
358 pci_write_config8(ctrl->d0f3, 0xec, 0x00);
359 /* MCLK Output Duty Control */
360 pci_write_config8(ctrl->d0f3, 0xee, 0x00);
361 /* DQS CKG Input Delay Control */
362 pci_write_config8(ctrl->d0f3, 0xef, 0x10);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000363
364 /* DRAM duty control */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000365 pci_write_config8(ctrl->d0f3, 0xed, 0x10);
366
Bari Arid4759d02008-09-01 01:48:07 +0000367 /* SMM and APIC decoding, we do not use SMM */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000368 reg = 0x29;
369 pci_write_config8(ctrl->d0f3, 0x86, reg);
370 /* SMM and APIC decoding mirror */
371 pci_write_config8(ctrl->d0f7, 0xe6, reg);
372
Uwe Hermannea7b5182008-10-09 17:08:32 +0000373 /* DRAM module configuration */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000374 pci_write_config8(ctrl->d0f3, 0x6e, 0x89);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000375}
376
Aaron Lwefcb2a312008-05-19 12:17:43 +0000377static void sdram_set_post(const struct mem_controller *ctrl)
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000378{
Aaron Lwefcb2a312008-05-19 12:17:43 +0000379 device_t dev = ctrl->d0f3;
Uwe Hermannea7b5182008-10-09 17:08:32 +0000380
Aaron Lwefcb2a312008-05-19 12:17:43 +0000381 /* Enable multipage mode. */
382 pci_write_config8(dev, 0x69, 0x03);
383
384 /* Enable refresh. */
385 pci_write_config8(dev, 0x6a, 0x32);
386
Uwe Hermannea7b5182008-10-09 17:08:32 +0000387 /* VGA device. */
388 pci_write_config16(dev, 0xa0, (1 << 15));
Aaron Lwefcb2a312008-05-19 12:17:43 +0000389 pci_write_config16(dev, 0xa4, 0x0010);
Aaron Lwefcb2a312008-05-19 12:17:43 +0000390}
391
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800392static void sdram_enable(device_t dev, u8 *rank_address)
Aaron Lwefcb2a312008-05-19 12:17:43 +0000393{
394 u8 i;
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000395
396 /* 1. Apply NOP. */
Stefan Reinauer64ed2b72010-03-31 14:47:43 +0000397 PRINT_DEBUG_MEM("RAM Enable 1: Apply NOP\n");
Aaron Lwefcb2a312008-05-19 12:17:43 +0000398 do_ram_command(dev, RAM_COMMAND_NOP);
399 udelay(100);
400 read32(rank_address + 0x10);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000401
402 /* 2. Precharge all. */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000403 udelay(400);
Stefan Reinauer64ed2b72010-03-31 14:47:43 +0000404 PRINT_DEBUG_MEM("RAM Enable 2: Precharge all\n");
Aaron Lwefcb2a312008-05-19 12:17:43 +0000405 do_ram_command(dev, RAM_COMMAND_PRECHARGE);
406 read32(rank_address + 0x10);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000407
408 /* 3. Mode register set. */
Corey Osgoodf9765482010-08-01 17:20:20 +0000409 PRINT_DEBUG_MEM("RAM Enable 3: Mode register set\n");
Aaron Lwefcb2a312008-05-19 12:17:43 +0000410 do_ram_command(dev, RAM_COMMAND_MRS);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000411 read32(rank_address + 0x120000); /* EMRS DLL Enable */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800412 read32(rank_address + 0x800); /* MRS DLL Reset */
Uwe Hermannea7b5182008-10-09 17:08:32 +0000413
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000414 /* 4. Precharge all again. */
Corey Osgoodf9765482010-08-01 17:20:20 +0000415 PRINT_DEBUG_MEM("RAM Enable 4: Precharge all\n");
Aaron Lwefcb2a312008-05-19 12:17:43 +0000416 do_ram_command(dev, RAM_COMMAND_PRECHARGE);
417 read32(rank_address + 0x0);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000418
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000419 /* 5. Perform 8 refresh cycles. Wait tRC each time. */
Corey Osgoodf9765482010-08-01 17:20:20 +0000420 PRINT_DEBUG_MEM("RAM Enable 5: CBR\n");
Aaron Lwefcb2a312008-05-19 12:17:43 +0000421 do_ram_command(dev, RAM_COMMAND_CBR);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000422 for (i = 0; i < 8; i++) {
Aaron Lwefcb2a312008-05-19 12:17:43 +0000423 read32(rank_address + 0x20);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000424 udelay(100);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000425 }
426
427 /* 6. Mode register set. */
Corey Osgoodf9765482010-08-01 17:20:20 +0000428 PRINT_DEBUG_MEM("RAM Enable 6: Mode register set\n");
Uwe Hermannea7b5182008-10-09 17:08:32 +0000429 /* Safe value for now, BL=8, WR=5, CAS=4 */
430 /*
Stefan Reinauer14e22772010-04-27 06:56:47 +0000431 * (E)MRS values are from the BPG. No direct explanation is given, but
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000432 * they should somehow conform to the JEDEC DDR2 SDRAM Specification
Uwe Hermannea7b5182008-10-09 17:08:32 +0000433 * (JESD79-2C).
434 */
Aaron Lwefcb2a312008-05-19 12:17:43 +0000435 do_ram_command(dev, RAM_COMMAND_MRS);
Uwe Hermannea7b5182008-10-09 17:08:32 +0000436 read32(rank_address + 0x002258); /* MRS command */
437 read32(rank_address + 0x121c20); /* EMRS OCD Default */
438 read32(rank_address + 0x120020); /* EMRS OCD Calibration Mode Exit */
439
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000440 /* 8. Normal operation */
Corey Osgoodf9765482010-08-01 17:20:20 +0000441 PRINT_DEBUG_MEM("RAM Enable 7: Normal operation\n");
Aaron Lwefcb2a312008-05-19 12:17:43 +0000442 do_ram_command(dev, RAM_COMMAND_NORMAL);
443 read32(rank_address + 0x30);
Corey Osgoodbd3f93e2008-02-21 00:56:14 +0000444}
Aaron Lwefcb2a312008-05-19 12:17:43 +0000445
446/*
Uwe Hermannea7b5182008-10-09 17:08:32 +0000447 * Support one DIMM with up to 2 ranks.
Aaron Lwefcb2a312008-05-19 12:17:43 +0000448 */
449static void ddr_ram_setup(const struct mem_controller *ctrl)
450{
451 u8 reg;
452
453 c7_cpu_setup(ctrl->d0f2);
454 sdram_set_registers(ctrl);
455 sdram_set_size(ctrl);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800456 sdram_enable(ctrl->d0f3, (u8 *)0);
Aaron Lwefcb2a312008-05-19 12:17:43 +0000457 reg = pci_read_config8(ctrl->d0f3, 0x41);
458 if (reg != 0)
Uwe Hermannea7b5182008-10-09 17:08:32 +0000459 sdram_enable(ctrl->d0f3,
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800460 (u8 *)(pci_read_config8(ctrl->d0f3, 0x40) << 26));
Aaron Lwefcb2a312008-05-19 12:17:43 +0000461 sdram_set_post(ctrl);
462}