2 * This file is part of the coreboot project.
4 * Copyright (C) 2009-2010 iWave Systems
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; version 2 of
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include <cpu/x86/mtrr.h>
23 #include <cpu/x86/cache.h>
27 #define DEBUG_RAM_SETUP
28 #define SOFTSTRSP(base, off) *((volatile u8 *)((base) + (off)))
30 /* Debugging macros. */
31 #if defined(DEBUG_RAM_SETUP)
32 #define PRINTK_DEBUG(x...) printk(BIOS_DEBUG, x)
34 #define PRINTK_DEBUG(x...)
37 #define BOOT_MODE_RESUME 1
38 #define BOOT_MODE_NORMAL 0
40 #include "port_access.c"
42 static void detect_fsb(struct sys_info *sysinfo)
45 reg32 = sch_port_access_read(5, 3, 4);
47 sysinfo->fsb_frequency = 533;
49 sysinfo->fsb_frequency = 400;
53 static u32 detect_softstrap_base(void)
56 reg32 = sch_port_access_read(4, 0x71, 2);
61 base_addr = 0xFFFB0000;
64 base_addr = 0xFFFC0000;
67 base_addr = 0xFFFD0000;
70 base_addr = 0xFFFE0000;
76 static void detect_softstraps(struct sys_info *sysinfo)
79 u32 sbase = detect_softstrap_base();
81 reg8 = SOFTSTRSP(sbase, 0x87f2);
82 sysinfo->ranks = reg8;
84 sysinfo->ram_param_source = RAM_PARAM_SOURCE_SPD;
85 /* FIXME: implement SPD reading */
86 die("no support for reading DIMM config from SPD yet!");
89 sysinfo->ram_param_source = RAM_PARAM_SOURCE_SOFTSTRAP;
90 /*Timings from soft strap */
91 reg8 = SOFTSTRSP(sbase, 0x87f0);
101 /*Geometry from Softstrap */
102 reg8 = SOFTSTRSP(sbase, 0x87f1);
106 sysinfo->device_density = temp;
109 sysinfo->data_width = temp;
111 /*Refresh rate default 7.8us */
112 sysinfo->refresh = 3;
116 static void program_sch_dram_data(struct sys_info *sysinfo)
120 /* Program DRP DRAM Rank Population and Interface Register
121 * as per data in sysinfo SCH port 1 register 0 .. 0XFF
123 reg32 = sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DRP, 4);
124 reg32 &= ~(DRP_FIELDS); /* Clear all DRP fields we'll change */
125 /* Rank0 Device Width, Density, Enable */
126 reg32 |= (sysinfo->data_width) | ((sysinfo->device_density) << 1) | (1 << 3);
127 /* Rank1 Device Width, Density, Enable */
128 reg32 |= (sysinfo->data_width << 4) | ((sysinfo->device_density) << 5) | (1 << 7);
129 sch_port_access_write(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DRP, 4, reg32);
132 Program DTR DRAM Timing Register as per data in sysinfo SCH port 1 register 1
133 tRD_dly = 2 (15:13 = 010b)
136 reg32 = sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DTR, 4);
137 reg32 &= ~(DTR_FIELDS); /* Clear all DTR fields we'll change */
139 reg32 = (sysinfo->trp);
140 reg32 |= (sysinfo->trcd) << 2;
141 reg32 |= (sysinfo->cl) << 4;
142 reg32 |= 0X4000; /* tRD_dly = 2 (15:13 = 010b) */
143 sch_port_access_write(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DTR, 4, reg32);
146 /* DCO DRAM Controller Operation Register as per data in sysinfo SCH port 1 register 2 0XF */
147 reg32 = sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DCO, 4);
148 reg32 &= ~(DCO_FIELDS); /*Clear all DTR fields we'll change */
150 if (sysinfo->fsb_frequency == 533) {
155 reg32 = 0x006911c; // FIXME ?
157 sch_port_access_write(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DCO, 4, reg32);
160 static void program_dll_config(struct sys_info *sysinfo)
162 if (sysinfo->fsb_frequency == 533) {
163 sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x21, 4, 0x46464646);
164 sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x22, 4, 0x46464646);
166 sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x21, 4, 0x58585858);
167 sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x22, 4, 0x58585858);
169 sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x23, 4, 0x2222);
170 if (sysinfo->fsb_frequency == 533) {
171 sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x20, 4, 0x993B);
173 sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x20, 4, 0xCC3B);
177 static void do_jedec_init(struct sys_info *sysinfo)
179 u32 reg32, rank, cmd, temp, num_ranks;
180 /* Performs JEDEC memory initializattion for all memory rows */
182 reg32 = sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DRP, 4);
183 reg32 |= DRP_CKE_DIS;
184 sch_port_access_write(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DRP, 4, reg32);
185 reg32 = sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DRP, 4);
187 num_ranks = sysinfo->ranks;
192 sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DRP, 4);
193 reg32 &= ~(DRP_SCK_DIS); /* Enable all SCK/SCKB by def. */
194 sch_port_access_write(1, SCH_MSG_DUNIT_REG_DRP, 4, reg32);
195 /* Program miscellaneous SCH registers on rank 0 initialization */
196 reg32 = sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DRP, 4);
198 program_dll_config(sysinfo);
201 printk(BIOS_DEBUG, "Setting up RAM \n");
204 reg32 = inb(ACPI_BASE + 8); PM1 Timer
209 reg32 = inb(ACPI_BASE + 8);PM1 Timer
211 }while (reg32 < 0x2EE); */
214 cmd |= SCH_DRAMINIT_CMD_NOP;
215 sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, SCH_MSG_DUNIT_PORT, 0, cmd);
217 reg32 = sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DRP, 4);
218 reg32 &= 0xFFFF9FFF; /* Clear both the CKE static disables */
219 sch_port_access_write(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DRP, 4, reg32);
220 /* Wait 400ns (not needed when executing from flash)
223 reg32 = sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DRP, 4);
225 cmd |= SCH_DRAMINIT_CMD_PALL;
226 sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, SCH_MSG_DUNIT_PORT, 0, cmd);
228 /*EMRS(2); High temp self refresh=disabled, partial array self refresh=full */
230 cmd |= SCH_DRAMINIT_CMD_EMRS2;
231 sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, SCH_MSG_DUNIT_PORT, 0, cmd);
232 /*EMRS(3) (no command) */
234 cmd |= SCH_DRAMINIT_CMD_EMRS3;
235 sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, SCH_MSG_DUNIT_PORT, 0, cmd);
236 /*EMRS(1); Enable DLL (Leave all bits in the command at 0) */
238 cmd |= SCH_DRAMINIT_CMD_EMRS1;
239 sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, SCH_MSG_DUNIT_PORT, 0, cmd);
240 /*MRS; Reset DLL (Set memory address bit 8) */
242 cmd |= SCH_DRAMINIT_CMD_MRS;
243 cmd |= (SCH_JEDEC_DLLRESET << SCH_DRAMINIT_ADDR_OFFSET);
244 sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, SCH_MSG_DUNIT_PORT, 0, cmd);
247 cmd |= SCH_DRAMINIT_CMD_PALL;
248 sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, SCH_MSG_DUNIT_PORT, 0, cmd);
249 /*Issue 2 auto-refresh commands */
251 cmd |= SCH_DRAMINIT_CMD_AREF;
252 sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, SCH_MSG_DUNIT_PORT, 0, cmd);
253 sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, SCH_MSG_DUNIT_PORT, 0, cmd);
254 /*MRS command including tCL, tWR, burst length (always 4) */
256 cmd |= (SCH_DRAMINIT_CMD_MRS + JEDEC_STATIC_PARAM); /*Static param */
258 temp += TCL_LOW; /*Adjust for the TCL base */
259 temp = temp << ((SCH_JEDEC_CL_OFFSET + SCH_DRAMINIT_ADDR_OFFSET)); /*Ready the CAS latency */
261 sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, SCH_MSG_DUNIT_PORT, 0, cmd);
262 /* Wait 200 clocks (max of 1us, so no need to delay)
263 Issue EMRS(1):OCD default
266 cmd |= SCH_DRAMINIT_CMD_EMRS1;
267 cmd |= (SCH_JEDEC_OCD_DEFAULT << SCH_DRAMINIT_ADDR_OFFSET);
268 sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, SCH_MSG_DUNIT_PORT, 0, cmd);
269 /*Issue EMRS(1): OCD cal. mode exit. */
271 cmd |= SCH_DRAMINIT_CMD_EMRS1;
272 cmd |= (SCH_JEDEC_DQS_DIS << SCH_DRAMINIT_ADDR_OFFSET);
273 sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, SCH_MSG_DUNIT_PORT, 0, cmd);
274 rank += SCH_DRAMINIT_RANK_MASK;
280 * @param boot_mode: 0 = normal, 1 = resume
283 void sdram_initialize(int boot_mode)
285 struct sys_info sysinfo;
288 printk(BIOS_DEBUG, "Setting up RAM controller.\n");
290 memset(&sysinfo, 0, sizeof(sysinfo));
293 detect_fsb(&sysinfo);
294 detect_softstraps(&sysinfo);
296 program_sch_dram_data(&sysinfo);
299 if (boot_mode == BOOT_MODE_NORMAL) {
300 do_jedec_init(&sysinfo);
302 program_dll_config(&sysinfo);
305 /* raminit complete */
306 reg32 = sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DCO, 4);
308 reg32 |= ((sysinfo.refresh) << 2);
310 sch_port_access_write(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DCO, 4, reg32);
314 reg32 = reg32 >> sysinfo.data_width;
315 reg32 = reg32 << sysinfo.device_density;
316 reg32 = reg32 << sysinfo.ranks;
318 sch_port_access_write(2, 8, 4, reg32);
321 if (boot_mode == BOOT_MODE_RESUME) {
322 sch_port_access_write_ram_cmd(SCH_OPCODE_WAKEFULLON,
323 SCH_MSG_DUNIT_PORT, 0, 0);
326 sch_port_access_write(2, 0, 4, 0x98);
327 sch_port_access_write(2, 3, 4, 0x7);
328 sch_port_access_write(3, 2, 4, 0x408);
329 sch_port_access_write(4, 0x71, 4, 0x600);