blob: 639eac7fa232e66bfb3c608e60b60746310415b5 [file] [log] [blame]
Rudolf Marek15bf50d2009-04-13 18:34:35 +00001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2009 Rudolf Marek <r.marek@assembler.cz>
5 *
6 * This program is free software; you can redistribute it and/or modify
Uwe Hermannc70e9fc2010-02-15 23:10:19 +00007 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
Rudolf Marek15bf50d2009-04-13 18:34:35 +00009 *
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.
Rudolf Marek15bf50d2009-04-13 18:34:35 +000014 */
15
Stefan Reinauerd55e26f2010-04-25 13:54:30 +000016#include "raminit.h"
17
Rudolf Marek15bf50d2009-04-13 18:34:35 +000018void exit_from_self(int controllers, const struct mem_controller *ctrl,
19 struct sys_info *sysinfo)
20{
21 int i;
22 u32 dcl, dch;
23 u32 pcidev;
24 u8 bitmask;
25 u8 is_post_rev_g;
Myles Watson6e235762009-09-29 14:56:15 +000026 u32 local_cpuid;
Rudolf Marek15bf50d2009-04-13 18:34:35 +000027
28 for (i = 0; i < controllers; i++) {
29 if (!sysinfo->ctrl_present[i])
30 continue;
31 /* Skip everything if I don't have any memory on this controller */
32 dch = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_HIGH);
33 if (!(dch & DCH_MemClkFreqVal)) {
34 continue;
35 }
36
Myles Watson6e235762009-09-29 14:56:15 +000037 local_cpuid = pci_read_config32(ctrl[i].f3, 0xfc);
38 is_post_rev_g = ((local_cpuid & 0xfff00) > 0x50f00);
Rudolf Marek15bf50d2009-04-13 18:34:35 +000039
40 /* ChipKill */
41 dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW);
42 if (dcl & DCL_DimmEccEn) {
43 u32 mnc;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000044 printk(BIOS_SPEW, "ECC enabled\n");
Rudolf Marek15bf50d2009-04-13 18:34:35 +000045 mnc = pci_read_config32(ctrl[i].f3, MCA_NB_CONFIG);
46 mnc |= MNC_ECC_EN;
47 if (dcl & DCL_Width128) {
48 mnc |= MNC_CHIPKILL_EN;
49 }
50 pci_write_config32(ctrl[i].f3, MCA_NB_CONFIG, mnc);
51 }
52
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000053 printk(BIOS_DEBUG, "before resume errata #%d\n",
Rudolf Marek15bf50d2009-04-13 18:34:35 +000054 (is_post_rev_g) ? 270 : 125);
Stefan Reinauer14e22772010-04-27 06:56:47 +000055 /*
Rudolf Marek15bf50d2009-04-13 18:34:35 +000056 1. Restore memory controller registers as normal.
57 2. Set the DisAutoRefresh bit (Dev:2x8C[18]). (270 only)
58 3. Set the EnDramInit bit (Dev:2x7C[31]), clear all other bits in the same register).
59 4. Wait at least 750 us.
60 5. Clear the EnDramInit bit.
61 6. Clear the DisAutoRefresh bit. (270 only)
62 7. Read the value of Dev:2x80 and write that value back to Dev:2x80.
63 8. Set the exit from the self refresh bit (Dev:2x90[1]).
64 9. Clear the exit from self refresh bit immediately.
65 Note: Steps 8 and 9 must be executed in a single 64-byte aligned uninterrupted instruction stream.
66 */
67
68 enable_lapic();
69 init_timer();
70
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000071 printk(BIOS_DEBUG, "before exit errata - timer enabled\n");
Rudolf Marek15bf50d2009-04-13 18:34:35 +000072
73 if (is_post_rev_g) {
74 dcl =
75 pci_read_config32(ctrl[i].f2,
76 DRAM_TIMING_HIGH);
77 dcl |= (1 << 18);
78 pci_write_config32(ctrl[i].f2, DRAM_TIMING_HIGH,
79 dcl);
80 }
81
82 dcl = DI_EnDramInit;
83 pci_write_config32(ctrl[i].f2, DRAM_INIT, dcl);
84
85 udelay(800);
86
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000087 printk(BIOS_DEBUG, "before exit errata - after mdelay\n");
Rudolf Marek15bf50d2009-04-13 18:34:35 +000088
89 dcl = pci_read_config32(ctrl[i].f2, DRAM_INIT);
90 dcl &= ~DI_EnDramInit;
91 pci_write_config32(ctrl[i].f2, DRAM_INIT, dcl);
92
93 if (is_post_rev_g) {
94 dcl =
95 pci_read_config32(ctrl[i].f2,
96 DRAM_TIMING_HIGH);
97 dcl &= ~(1 << 18);
98 pci_write_config32(ctrl[i].f2, DRAM_TIMING_HIGH,
99 dcl);
100 }
101
102 dcl = pci_read_config32(ctrl[i].f2, DRAM_BANK_ADDR_MAP);
103 pci_write_config32(ctrl[i].f2, DRAM_BANK_ADDR_MAP, dcl);
104
105 /* I was unable to do that like: ctrl[i].f2->path.pci.devfn << 8 */
106 pcidev =
107 0x80000000 | ((((ctrl[i].node_id + 0x18) << 3) | 0x2)
108 << 8) | 0x90;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000109 printk(BIOS_DEBUG, "pcidev is %x\n", pcidev);
Rudolf Marek15bf50d2009-04-13 18:34:35 +0000110 bitmask = 2;
111 __asm__ __volatile__("pushl %0\n\t"
112 "movw $0xcf8, %%dx\n\t"
113 "out %%eax, (%%dx)\n\t"
114 "movw $0xcfc, %%dx\n\t"
115 "inl %%dx, %%eax\n\t"
116 "orb %1, %%al\n\t"
117 "not %1\n\t"
118 ".align 64\n\t"
119 "outl %%eax, (%%dx) \n\t"
120 "andb %1, %%al\n\t"
121 "outl %%eax, (%%dx)\n\t"
122 "popl %0\n\t"::"a"(pcidev),
123 "q"(bitmask):"edx");
124 }
125
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000126 printk(BIOS_DEBUG, "after exit errata\n");
Rudolf Marek15bf50d2009-04-13 18:34:35 +0000127
128
129 for (i = 0; i < controllers; i++) {
130 u32 dcm;
131 if (!sysinfo->ctrl_present[i])
132 continue;
133 /* Skip everything if I don't have any memory on this controller */
134 if (sysinfo->meminfo[i].dimm_mask == 0x00)
135 continue;
136
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000137 printk(BIOS_DEBUG, "Exiting memory from self refresh: ");
Rudolf Marek15bf50d2009-04-13 18:34:35 +0000138 int loops = 0;
139 do {
140 loops++;
141 if ((loops & 1023) == 0) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000142 printk(BIOS_DEBUG, ".");
Rudolf Marek15bf50d2009-04-13 18:34:35 +0000143 }
144 dcm =
145 pci_read_config32(ctrl[i].f2, DRAM_CTRL_MISC);
146 } while (((dcm & DCM_MemClrStatus) ==
147 0) /* || ((dcm & DCM_DramEnabled) == 0) */ );
148
149 if (loops >= TIMEOUT_LOOPS) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000150 printk(BIOS_DEBUG, "timeout with with cntrl[%d]\n", i);
Rudolf Marek15bf50d2009-04-13 18:34:35 +0000151 continue;
152 }
153
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000154 printk(BIOS_DEBUG, " done\n");
Rudolf Marek15bf50d2009-04-13 18:34:35 +0000155 }
156
Stefan Reinauer08670622009-06-30 15:17:49 +0000157#if CONFIG_HW_MEM_HOLE_SIZEK != 0
Rudolf Marek15bf50d2009-04-13 18:34:35 +0000158 /* init hw mem hole here */
159 /* DramHoleValid bit only can be set after MemClrStatus is set by Hardware */
160 set_hw_mem_hole(controllers, ctrl);
161#endif
162
163 /* store tom to sysinfo, and it will be used by dqs_timing */
164 {
165 msr_t msr;
166 //[1M, TOM)
167 msr = rdmsr(TOP_MEM);
168 sysinfo->tom_k = ((msr.hi << 24) | (msr.lo >> 8)) >> 2;
169
170 //[4G, TOM2)
171 msr = rdmsr(TOP_MEM2);
172 sysinfo->tom2_k = ((msr.hi << 24) | (msr.lo >> 8)) >> 2;
173 }
174
175 for (i = 0; i < controllers; i++) {
176
177 if (!sysinfo->ctrl_present[i])
178 continue;
179
180 /* Skip everything if I don't have any memory on this controller */
181 if (sysinfo->meminfo[i].dimm_mask == 0x00)
182 continue;
183
184 dqs_restore_MC_NVRAM((ctrl + i)->f2);
185 sysinfo->mem_trained[i] = 1; // mem was trained
186 }
187}