Fix a few whitespace and coding style issues.
[coreboot.git] / src / northbridge / intel / sch / raminit.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2009-2010 iWave Systems
5  *
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 the License.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18  */
19
20 #include <string.h>
21 #include <cpu/x86/mtrr.h>
22 #include <cpu/x86/cache.h>
23 #include <spd.h>
24 #include "raminit.h"
25 #include "sch.h"
26
27 #define DEBUG_RAM_SETUP
28 #define SOFTSTRSP(base, off) *((volatile u8 *)((base) + (off)))
29
30 /* Debugging macros. */
31 #if defined(DEBUG_RAM_SETUP)
32 #define PRINTK_DEBUG(x...)      printk(BIOS_DEBUG, x)
33 #else
34 #define PRINTK_DEBUG(x...)
35 #endif
36
37 #define BOOT_MODE_RESUME        1
38 #define BOOT_MODE_NORMAL        0
39
40 #include "port_access.c"
41
42 static void detect_fsb(struct sys_info *sysinfo)
43 {
44         u32 reg32;
45
46         reg32 = sch_port_access_read(5, 3, 4);
47         if (reg32 & BIT(3))
48                 sysinfo->fsb_frequency = 533;
49         else
50                 sysinfo->fsb_frequency = 400;
51 }
52
53 static u32 detect_softstrap_base(void)
54 {
55         u32 reg32, base_addr;
56
57         reg32 = sch_port_access_read(4, 0x71, 2);
58         reg32 &= 0x700;
59         reg32 = reg32 >> 7;
60         switch (reg32) {
61         case 7:
62                 base_addr = 0xFFFB0000;
63                 break;
64         case 6:
65                 base_addr = 0xFFFC0000;
66                 break;
67         case 5:
68                 base_addr = 0xFFFD0000;
69                 break;
70         case 4:
71                 base_addr = 0xFFFE0000;
72                 break;
73         }
74         return base_addr;
75 }
76
77 static void detect_softstraps(struct sys_info *sysinfo)
78 {
79         u8 reg8, temp;
80         u32 sbase = detect_softstrap_base();
81
82         reg8 = SOFTSTRSP(sbase, 0x87f2);
83         sysinfo->ranks = reg8;
84         if (reg8 == 0) {
85                 sysinfo->ram_param_source = RAM_PARAM_SOURCE_SPD;
86                 /* FIXME: Implement SPD reading. */
87                 die("No support for reading DIMM config from SPD yet!");
88                 return;
89         } else {
90                 sysinfo->ram_param_source = RAM_PARAM_SOURCE_SOFTSTRAP;
91                 /* Timings from soft strap */
92                 reg8 = SOFTSTRSP(sbase, 0x87f0);
93                 temp = reg8 & 0x30;
94                 temp = temp >> 4;
95                 sysinfo->cl = temp;
96                 temp = reg8 & 0x0c;
97                 temp = temp >> 2;
98                 sysinfo->trcd = temp;
99                 temp = reg8 & 0x03;
100                 sysinfo->trp = temp;
101
102                 /* Geometry from Softstrap */
103                 reg8 = SOFTSTRSP(sbase, 0x87f1);
104
105                 temp = reg8 & 0x06;
106                 temp = temp >> 1;
107                 sysinfo->device_density = temp;
108
109                 temp = reg8 & 0x01;
110                 sysinfo->data_width = temp;
111
112                 /* Refresh rate default 7.8us */
113                 sysinfo->refresh = 3;
114         }
115 }
116
117 static void program_sch_dram_data(struct sys_info *sysinfo)
118 {
119         u32 reg32;
120
121         /*
122          * Program DRP DRAM Rank Population and Interface Register as per data
123          * in sysinfo SCH port 1 register 0..0xFF.
124          */
125         reg32 =
126             sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DRP, 4);
127         reg32 &= ~(DRP_FIELDS); /* Clear all DRP fields we'll change. */
128         /* Rank0 Device Width, Density, Enable */
129         reg32 |= sysinfo->data_width | (sysinfo->device_density << 1) | (1 << 3);
130         /* Rank1 Device Width, Density, Enable */
131         reg32 |= (sysinfo->data_width << 4)
132                  | ((sysinfo->device_density) << 5) | (1 << 7);
133         sch_port_access_write(SCH_MSG_DUNIT_PORT,
134                               SCH_MSG_DUNIT_REG_DRP, 4, reg32);
135
136         /*
137          * Program DTR DRAM Timing Register as per data in sysinfo SCH port 1
138          * register 1.
139          *
140          * tRD_dly = 2 (15:13 = 010b)
141          * 0X3F
142          */
143         reg32 =
144             sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DTR, 4);
145         reg32 &= ~(DTR_FIELDS); /* Clear all DTR fields we'll change. */
146
147         reg32 = (sysinfo->trp);
148         reg32 |= (sysinfo->trcd) << 2;
149         reg32 |= (sysinfo->cl) << 4;
150         reg32 |= 0X4000;        /* tRD_dly = 2 (15:13 = 010b) */
151         sch_port_access_write(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DTR, 4,
152                               reg32);
153
154         /*
155          * DCO DRAM Controller Operation Register as per data in sysinfo
156          * SCH port 1 register 2 0xF.
157          */
158         reg32 =
159             sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DCO, 4);
160         reg32 &= ~(DCO_FIELDS); /* Clear all DTR fields we'll change. */
161
162         if (sysinfo->fsb_frequency == 533)
163                 reg32 |= 1;
164         else
165                 reg32 &= ~(BIT(0));
166         reg32 = 0x006911c;      // FIXME ?
167
168         sch_port_access_write(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DCO, 4,
169                               reg32);
170 }
171
172 static void program_dll_config(struct sys_info *sysinfo)
173 {
174         if (sysinfo->fsb_frequency == 533) {
175                 sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x21, 4, 0x46464646);
176                 sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x22, 4, 0x46464646);
177         } else {
178                 sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x21, 4, 0x58585858);
179                 sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x22, 4, 0x58585858);
180         }
181         sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x23, 4, 0x2222);
182         if (sysinfo->fsb_frequency == 533)
183                 sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x20, 4, 0x993B);
184         else
185                 sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x20, 4, 0xCC3B);
186 }
187
188 static void do_jedec_init(struct sys_info *sysinfo)
189 {
190         u32 reg32, rank, cmd, temp, num_ranks;
191
192         /* Performs JEDEC memory initializattion for all memory rows */
193         /* Set CKE0/1 low */
194         reg32 =
195             sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DRP, 4);
196         reg32 |= DRP_CKE_DIS;
197         sch_port_access_write(SCH_MSG_DUNIT_PORT,
198                               SCH_MSG_DUNIT_REG_DRP, 4, reg32);
199         reg32 =
200             sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DRP, 4);
201         rank = 0;
202         num_ranks = sysinfo->ranks;
203
204         do {
205                 /* Start clocks */
206                 reg32 = sch_port_access_read(SCH_MSG_DUNIT_PORT,
207                                              SCH_MSG_DUNIT_REG_DRP, 4);
208                 reg32 &= ~(DRP_SCK_DIS); /* Enable all SCK/SCKB by def. */
209                 sch_port_access_write(1, SCH_MSG_DUNIT_REG_DRP, 4, reg32);
210                 /* Program misc. SCH registers on rank 0 initialization. */
211                 reg32 = sch_port_access_read(SCH_MSG_DUNIT_PORT,
212                                              SCH_MSG_DUNIT_REG_DRP, 4);
213                 if (rank == 0)
214                         program_dll_config(sysinfo);
215
216                 printk(BIOS_DEBUG, "Setting up RAM \n");
217
218                 /*
219                  * Wait 200us
220                  * reg32 = inb(ACPI_BASE + 8); PM1 Timer
221                  * reg32 &=0xFFFFFF;
222                  * reg32 +=0x2EE;
223                  * do {
224                  *      reg32 = inb(ACPI_BASE + 8);PM1 Timer
225                  *      reg32 &= 0xFFFFFF;
226                  * } while (reg32 < 0x2EE);
227                  */
228
229                 /* Apply NOP. */
230                 cmd = rank;
231                 cmd |= SCH_DRAMINIT_CMD_NOP;
232                 sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT,
233                                               SCH_MSG_DUNIT_PORT, 0, cmd);
234                 /* Set CKE=high. */
235                 reg32 = sch_port_access_read(SCH_MSG_DUNIT_PORT,
236                                              SCH_MSG_DUNIT_REG_DRP, 4);
237                 reg32 &= 0xFFFF9FFF; /* Clear both the CKE static disables. */
238                 sch_port_access_write(SCH_MSG_DUNIT_PORT,
239                                       SCH_MSG_DUNIT_REG_DRP, 4, reg32);
240                 /*
241                  * Wait 400ns (not needed when executing from flash).
242                  * Precharge all.
243                  */
244                 reg32 = sch_port_access_read(SCH_MSG_DUNIT_PORT,
245                                              SCH_MSG_DUNIT_REG_DRP, 4);
246                 cmd = rank;
247                 cmd |= SCH_DRAMINIT_CMD_PALL;
248                 sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT,
249                                               SCH_MSG_DUNIT_PORT, 0, cmd);
250
251                 /*
252                  * EMRS(2); High temp self refresh=disabled,
253                  * partial array self refresh=full.
254                  */
255                 cmd = rank;
256                 cmd |= SCH_DRAMINIT_CMD_EMRS2;
257                 sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT,
258                                               SCH_MSG_DUNIT_PORT, 0, cmd);
259
260                 /* EMRS(3) (no command). */
261                 cmd = rank;
262                 cmd |= SCH_DRAMINIT_CMD_EMRS3;
263                 sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT,
264                                               SCH_MSG_DUNIT_PORT, 0, cmd);
265
266                 /* EMRS(1); Enable DLL (Leave all bits in the command at 0). */
267                 cmd = rank;
268                 cmd |= SCH_DRAMINIT_CMD_EMRS1;
269                 sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT,
270                                               SCH_MSG_DUNIT_PORT, 0, cmd);
271
272                 /* MRS; Reset DLL (Set memory address bit 8). */
273                 cmd = rank;
274                 cmd |= SCH_DRAMINIT_CMD_MRS;
275                 cmd |= (SCH_JEDEC_DLLRESET << SCH_DRAMINIT_ADDR_OFFSET);
276                 sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT,
277                                               SCH_MSG_DUNIT_PORT, 0, cmd);
278
279                 /* Precharge all. */
280                 cmd = rank;
281                 cmd |= SCH_DRAMINIT_CMD_PALL;
282                 sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT,
283                                               SCH_MSG_DUNIT_PORT, 0, cmd);
284
285                 /* Issue 2 auto-refresh commands. */
286                 cmd = rank;
287                 cmd |= SCH_DRAMINIT_CMD_AREF;
288                 sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT,
289                                               SCH_MSG_DUNIT_PORT, 0, cmd);
290                 sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT,
291                                               SCH_MSG_DUNIT_PORT, 0, cmd);
292
293                 /* MRS command including tCL, tWR, burst length (always 4). */
294                 cmd = rank;
295                 cmd |= (SCH_DRAMINIT_CMD_MRS + JEDEC_STATIC_PARAM); /* Static param */
296                 temp = sysinfo->cl;
297                 temp += TCL_LOW;        /* Adjust for the TCL base. */
298                 temp = temp << ((SCH_JEDEC_CL_OFFSET
299                       + SCH_DRAMINIT_ADDR_OFFSET)); /* Ready the CAS latency */
300                 cmd |= temp;
301                 sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT,
302                                               SCH_MSG_DUNIT_PORT, 0, cmd);
303
304                 /*
305                  * Wait 200 clocks (max of 1us, so no need to delay).
306                  * Issue EMRS(1):OCD default.
307                  */
308                 cmd = rank;
309                 cmd |= SCH_DRAMINIT_CMD_EMRS1;
310                 cmd |= (SCH_JEDEC_OCD_DEFAULT << SCH_DRAMINIT_ADDR_OFFSET);
311                 sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT,
312                                               SCH_MSG_DUNIT_PORT, 0, cmd);
313
314                 /* Issue EMRS(1): OCD cal. mode exit. */
315                 cmd = rank;
316                 cmd |= SCH_DRAMINIT_CMD_EMRS1;
317                 cmd |= (SCH_JEDEC_DQS_DIS << SCH_DRAMINIT_ADDR_OFFSET);
318                 sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT,
319                                               SCH_MSG_DUNIT_PORT, 0, cmd);
320                 rank += SCH_DRAMINIT_RANK_MASK;
321                 num_ranks--;
322         } while (num_ranks);
323 }
324
325 /**
326  * @param boot_mode 0 = normal, 1 = resume
327  */
328 void sdram_initialize(int boot_mode)
329 {
330         struct sys_info sysinfo;
331         u32 reg32;
332
333         printk(BIOS_DEBUG, "Setting up RAM controller.\n");
334
335         memset(&sysinfo, 0, sizeof(sysinfo));
336
337         detect_fsb(&sysinfo);
338         detect_softstraps(&sysinfo);
339
340         program_sch_dram_data(&sysinfo);
341
342         /* cold boot */
343         if (boot_mode == BOOT_MODE_NORMAL)
344                 do_jedec_init(&sysinfo);
345         else
346                 program_dll_config(&sysinfo);
347
348         /* RAM init complete. */
349         reg32 =
350             sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DCO, 4);
351         reg32 |= DCO_IC;
352         reg32 |= ((sysinfo.refresh) << 2);
353         reg32 = 0x006919c;
354         sch_port_access_write(SCH_MSG_DUNIT_PORT,
355                               SCH_MSG_DUNIT_REG_DCO, 4, reg32);
356
357         /* Setting up TOM. */
358         reg32 = 0x10000000;
359         reg32 = reg32 >> sysinfo.data_width;
360         reg32 = reg32 << sysinfo.device_density;
361         reg32 = reg32 << sysinfo.ranks;
362         reg32 = 0x40000000;
363         sch_port_access_write(2, 8, 4, reg32);
364
365         /* Resume mode. */
366         if (boot_mode == BOOT_MODE_RESUME)
367                 sch_port_access_write_ram_cmd(SCH_OPCODE_WAKEFULLON,
368                                               SCH_MSG_DUNIT_PORT, 0, 0);
369
370         sch_port_access_write(2, 0, 4, 0x98);
371         sch_port_access_write(2, 3, 4, 0x7);
372         sch_port_access_write(3, 2, 4, 0x408);
373         sch_port_access_write(4, 0x71, 4, 0x600);
374 }