d2e8af897092513309ac77a818e275c1e64863c1
[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
9  * the License.
10  *
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.
15  *
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
19  */
20
21 #include <string.h>
22 #include <cpu/x86/mtrr.h>
23 #include <cpu/x86/cache.h>
24 #include <spd.h>
25 #include "raminit.h"
26 #include "sch.h"
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         reg32 = sch_port_access_read(5, 3, 4);
46         if (reg32 & BIT(3)) {
47                 sysinfo->fsb_frequency = 533;
48         } else {
49                 sysinfo->fsb_frequency = 400;
50         }
51 }
52
53 static u32 detect_softstrap_base(void)
54 {
55         u32 reg32, base_addr;
56         reg32 = sch_port_access_read(4, 0x71, 2);
57         reg32 &= 0x700;
58         reg32 = reg32 >> 7;
59         switch (reg32) {
60         case 7:
61                 base_addr = 0xFFFB0000;
62                 break;
63         case 6:
64                 base_addr = 0xFFFC0000;
65                 break;
66         case 5:
67                 base_addr = 0xFFFD0000;
68                 break;
69         case 4:
70                 base_addr = 0xFFFE0000;
71                 break;
72         }
73         return base_addr;
74 }
75
76 static void detect_softstraps(struct sys_info *sysinfo)
77 {
78         u8 reg8, temp;
79         u32 sbase = detect_softstrap_base();
80
81         reg8 = SOFTSTRSP(sbase, 0x87f2);
82         sysinfo->ranks = reg8;
83         if (reg8 == 0) {
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!");
87                 return;
88         } else {
89                 sysinfo->ram_param_source = RAM_PARAM_SOURCE_SOFTSTRAP;
90                 /*Timings from soft strap */
91                 reg8 = SOFTSTRSP(sbase, 0x87f0);
92                 temp = reg8 & 0x30;
93                 temp = temp >> 4;
94                 sysinfo->cl = temp;
95                 temp = reg8 & 0x0c;
96                 temp = temp >> 2;
97                 sysinfo->trcd = temp;
98                 temp = reg8 & 0x03;
99                 sysinfo->trp = temp;
100
101                 /*Geometry from Softstrap */
102                 reg8 = SOFTSTRSP(sbase, 0x87f1);
103
104                 temp = reg8 & 0x06;
105                 temp = temp >> 1;
106                 sysinfo->device_density = temp;
107
108                 temp = reg8 & 0x01;
109                 sysinfo->data_width = temp;
110
111                 /*Refresh rate default 7.8us */
112                 sysinfo->refresh = 3;
113         }
114 }
115
116 static void program_sch_dram_data(struct sys_info *sysinfo)
117 {
118         u32 reg32;
119
120         /* Program DRP DRAM Rank Population and Interface Register
121          * as per data in sysinfo SCH port 1 register 0 .. 0XFF
122          */
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);
130
131         /*
132          Program  DTR DRAM Timing Register as per data in sysinfo SCH port 1 register 1
133          tRD_dly = 2 (15:13 = 010b)
134          0X3F
135         */
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 */
138
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);
144
145
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 */
149
150         if (sysinfo->fsb_frequency == 533) {
151                 reg32 |= 1;
152         } else {
153                 reg32 &= ~(BIT(0));
154         }
155         reg32 = 0x006911c; // FIXME ?
156
157         sch_port_access_write(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DCO, 4, reg32);
158 }
159
160 static void program_dll_config(struct sys_info *sysinfo)
161 {
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);
165         } else {
166                 sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x21, 4, 0x58585858);
167                 sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x22, 4, 0x58585858);
168         }
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);
172         } else {
173                 sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x20, 4, 0xCC3B);
174         }
175 }
176
177 static void do_jedec_init(struct sys_info *sysinfo)
178 {
179         u32 reg32, rank, cmd, temp, num_ranks;
180         /* Performs JEDEC memory initializattion for all memory rows */
181         /* Set CKE0/1 low */
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);
186         rank = 0;
187         num_ranks = sysinfo->ranks;
188         do {
189
190                 /* Start clocks */
191                 reg32 =
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);
197                 if (rank == 0) {
198                         program_dll_config(sysinfo);
199
200                 }
201                 printk(BIOS_DEBUG, "Setting up RAM \n");
202                 /*
203                    Wait 200us
204                    reg32 = inb(ACPI_BASE + 8); PM1 Timer
205                    reg32 &=0xFFFFFF;
206                    reg32 +=0x2EE;
207                    do
208                    {
209                    reg32 = inb(ACPI_BASE + 8);PM1 Timer
210                    reg32 &= 0xFFFFFF;
211                    }while (reg32 < 0x2EE); */
212                 /* Apply NOP */
213                 cmd = rank;
214                 cmd |= SCH_DRAMINIT_CMD_NOP;
215                 sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, SCH_MSG_DUNIT_PORT, 0, cmd);
216                 /* Set CKE=high */
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)
221                    Precharge all
222                  */
223                 reg32 = sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DRP, 4);
224                 cmd = rank;
225                 cmd |= SCH_DRAMINIT_CMD_PALL;
226                 sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, SCH_MSG_DUNIT_PORT, 0, cmd);
227
228                 /*EMRS(2); High temp self refresh=disabled, partial array self refresh=full */
229                 cmd = rank;
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) */
233                 cmd = rank;
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) */
237                 cmd = rank;
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) */
241                 cmd = rank;
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);
245                 /*Precharge all */
246                 cmd = rank;
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 */
250                 cmd = rank;
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) */
255                 cmd = rank;
256                 cmd |= (SCH_DRAMINIT_CMD_MRS + JEDEC_STATIC_PARAM);     /*Static param */
257                 temp = sysinfo->cl;
258                 temp += TCL_LOW;        /*Adjust for the TCL base */
259                 temp = temp << ((SCH_JEDEC_CL_OFFSET + SCH_DRAMINIT_ADDR_OFFSET));      /*Ready the CAS latency */
260                 cmd |= temp;
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
264                  */
265                 cmd = rank;
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. */
270                 cmd = rank;
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;
275                 num_ranks--;
276         } while (num_ranks);
277 }
278
279 /**
280  * @param boot_mode: 0 = normal, 1 = resume
281  */
282
283 void sdram_initialize(int boot_mode)
284 {
285         struct sys_info sysinfo;
286         u32 reg32;
287
288         printk(BIOS_DEBUG, "Setting up RAM controller.\n");
289
290         memset(&sysinfo, 0, sizeof(sysinfo));
291
292
293         detect_fsb(&sysinfo);
294         detect_softstraps(&sysinfo);
295
296         program_sch_dram_data(&sysinfo);
297
298         /* cold boot */
299         if (boot_mode == BOOT_MODE_NORMAL) {
300                 do_jedec_init(&sysinfo);
301         } else {
302                 program_dll_config(&sysinfo);
303         }
304
305         /* raminit complete */
306         reg32 = sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DCO, 4);
307         reg32 |= DCO_IC;
308         reg32 |= ((sysinfo.refresh) << 2);
309         reg32 = 0x006919c;
310         sch_port_access_write(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DCO, 4, reg32);
311
312         /* setting up TOM */
313         reg32 = 0x10000000;
314         reg32 = reg32 >> sysinfo.data_width;
315         reg32 = reg32 << sysinfo.device_density;
316         reg32 = reg32 << sysinfo.ranks;
317         reg32 = 0x40000000;
318         sch_port_access_write(2, 8, 4, reg32);
319
320         /* resume mode */
321         if (boot_mode == BOOT_MODE_RESUME) {
322                 sch_port_access_write_ram_cmd(SCH_OPCODE_WAKEFULLON,
323                                               SCH_MSG_DUNIT_PORT, 0, 0);
324         }
325
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);
330 }
331