blob: 72fbde08e5ee2218f05fe007223aba9d488cf395 [file] [log] [blame]
Andrew Wu8522f992013-07-05 17:29:41 +08001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2012 Andrew Wu <arw@dmp.com.tw>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
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 <stdint.h>
22#include <arch/io.h>
23#include <stdlib.h>
24#include <console/console.h>
25#include "cpu/x86/mtrr/earlymtrr.c"
26#include "drivers/pc80/i8254.c"
27#include "northbridge/dmp/vortex86ex/northbridge.h"
28#include "southbridge/dmp/vortex86ex/southbridge.h"
29#include "northbridge/dmp/vortex86ex/raminit.c"
30
31#define DMP_CPUID_SX 0x31504d44
32#define DMP_CPUID_DX 0x32504d44
33#define DMP_CPUID_MX 0x33504d44
34#define DMP_CPUID_DX2 0x34504d44
35#define DMP_CPUID_MX_PLUS 0x35504d44
36#define DMP_CPUID_EX 0x37504d44
37
38/* Post codes */
39#define POST_DMP_ID_ERR 0x85
40#define POST_DRAM_TEST_ERR 0x86
41#define POST_DRAM_SIZING_ERR 0x77
42
43static u32 get_dmp_id(void)
44{
45 return pci_read_config32(NB, NB_REG_CID);
46}
47
48/* Indirect access registers for Watch-dog timer, GPIO PORT 0,1
49 * Index port is for I/O port 22h
50 * Index port 13h (00: lock register, C5h: unlock register) for lock/unlock function
51 * Index port 37h, 39h, 3Ah, 3Bh, 3Ch for Watchdog timer
52 * Index port 46h, 47h, 4Ch, 4Dh, 4Eh, 4Fh for GPIO port 0, 1
53 */
54static void write_indirect_reg(u8 index, u8 data)
55{
56 outb(index, 0x22);
57 outb(data, 0x23);
58}
59
60static void lock_indirect_reg(void)
61{
62 write_indirect_reg(0x13, 0x00);
63}
64
65static void unlock_indirect_reg(void)
66{
67 write_indirect_reg(0x13, 0xc5);
68}
69
70static void disable_watchdog(void)
71{
72 unlock_indirect_reg();
73 // disable watchdog timer
74 write_indirect_reg(0x37, 0x0);
75}
76
77void set_ex_powerdown_control(void)
78{
79 u32 powerdown_ctrl;
80 powerdown_ctrl = pci_read_config32(SB, 0xbc);
81#if CONFIG_TEMP_POWERDOWN
82 powerdown_ctrl |= (1 << 31);
83#endif
84#if CONFIG_SATA_POWERDOWN
85 powerdown_ctrl |= (1 << 30);
86#endif
87#if CONFIG_ADC_POWERDOWN
88 powerdown_ctrl |= (1 << 28);
89#endif
90#if CONFIG_PCIE0_POWERDOWN
91 powerdown_ctrl |= (1 << 13);
92#endif
93#if CONFIG_MAC_POWERDOWN
94 powerdown_ctrl |= (1 << 3);
95#endif
96#if CONFIG_USB1_POWERDOWN
97 powerdown_ctrl |= (1 << 1);
98#endif
99#if CONFIG_IDE_POWERDOWN
100 powerdown_ctrl |= (1 << 0);
101#endif
102 pci_write_config32(SB, 0xbc, powerdown_ctrl);
103}
104
105static void set_pci_nb_pmcr(void)
106{
107 u8 pmcr = pci_read_config8(NB, NB_REG_PMCR);
108 /*
109 * Set PCI Master Max Cycle Length (MCL) to 32 PCI clocks.
110 * Set PCI Master Burst Write Length (BL) to Burst length over 3.
111 */
112 pmcr |= 0x0f;
113 pci_write_config8(NB, NB_REG_PMCR, pmcr);
114}
115
116static void set_pci_sb_lpccr(void)
117{
118 u8 lpccr = pci_read_config8(SB, SB_REG_LPCCR);
119 /* Set PCI Soft Reset Control to 1.
120 * (When the CPU soft reset is initialized, PCIRST# will be active.)
121 * Set P92FE to 1. (I/O port 92 Register Write Function Enable.)
122 * Set P92S to 1. (Internal Port 92h Selected.)
123 */
124 lpccr |= 0x16;
125 pci_write_config8(SB, SB_REG_LPCCR, lpccr);
126 /* enable fast ga20 */
127 outb(inb(SYSTEM_CTL_PORT) | 0x02, SYSTEM_CTL_PORT);
128}
129
130static u32 make_uart_config(u16 base, u8 irq)
131{
132 /* Set base IO address only, skip IRQ. IRQ will be setup in
133 * southbridge stage. */
134 u32 cfg = 0;
135 cfg |= 1 << 23; // UE = enabled.
136 cfg |= base; // UIOA.
137 return cfg;
138}
139
140#define SETUP_UART(n) \
141 uart_cfg = make_uart_config(CONFIG_UART##n##_IO, CONFIG_UART##n##_IRQ);\
142 outl(uart_cfg, 0xc00 + (n - 1) * 4);
143
144static void ex_uart_early_init(void)
145{
146#if CONFIG_TTYS0_BASE
147 u32 uart_cfg = 0;
148 /* Set UART Config I/O base address to 0xc00 */
149 pci_write_config16(SB, 0x60, 0xc01);
150 /* If serial console base address is defined, find out which
151 * UART uses this address, and setup this UART first. */
152#if CONFIG_TTYS0_BASE == CONFIG_UART1_IO
153 SETUP_UART(1)
154#elif CONFIG_TTYS0_BASE == CONFIG_UART2_IO
155 SETUP_UART(2)
156#elif CONFIG_TTYS0_BASE == CONFIG_UART3_IO
157 SETUP_UART(3)
158#elif CONFIG_TTYS0_BASE == CONFIG_UART4_IO
159 SETUP_UART(4)
160#elif CONFIG_TTYS0_BASE == CONFIG_UART5_IO
161 SETUP_UART(5)
162#elif CONFIG_TTYS0_BASE == CONFIG_UART6_IO
163 SETUP_UART(6)
164#elif CONFIG_TTYS0_BASE == CONFIG_UART7_IO
165 SETUP_UART(7)
166#elif CONFIG_TTYS0_BASE == CONFIG_UART8_IO
167 SETUP_UART(8)
168#elif CONFIG_TTYS0_BASE == CONFIG_UART9_IO
169 SETUP_UART(9)
170#elif CONFIG_TTYS0_BASE == CONFIG_UART10_IO
171 SETUP_UART(10)
172#endif
173#endif
174}
175
176static void init_wdt1(void)
177{
178#if CONFIG_WDT1_INITIALIZE
179#if CONFIG_WDT1_ENABLE
180 outb(0x1 << 6, 0xa8);
181#endif
182 u8 wdt1_signal_reg = 0;
183#if CONFIG_WDT1_SINGAL_NMI
184 wdt1_signal_reg = 0x0c << 4;
185#elif CONFIG_WDT1_SIGNAL_RESET
186 wdt1_signal_reg = 0x0d << 4;
187#elif CONFIG_WDT1_SIGNAL_SMI
188 wdt1_signal_reg = 0x0e << 4;
189#endif
190 outb(wdt1_signal_reg, 0xa9);
191#endif
192}
193
194/* Fill 32bit pattern into specified DRAM region. */
195static void fill_dram(u32 * p, u32 pattern, u32 test_len)
196{
197 if (test_len == 0)
198 return;
199#if 0
200 // C version, very slow.
201 for (p = (u32 *) 0; (u32) p < test_len; p++) {
202 *p = pattern;
203 }
204#endif
205 // ASM version, much faster.
206 asm volatile (
207 "cld\n\t"
208 "rep\n\t"
209 "stosl"
210 : /* no output registers */
211 : "c" (test_len / 4), "a" (pattern), "D" (p)
212 );
213}
214
215/* Verify 32bit pattern in specified DRAM region.
216 * Return -1 if ok, failed memory address if error. */
217static int verify_dram(u32 * p, u32 pattern, u32 test_len)
218{
219 if (test_len == 0)
220 return -1;
221#if 0
222 // C version, very slow.
223 for (p = (u32 *) 0; (u32) p < test_len; p++) {
224 if (*p != pattern) {
225 return (int)p;
226 }
227 }
228 return -1;
229#endif
230 u16 flags;
231 int addr;
232 asm volatile (
233 "cld\n\t"
234 "rep\n\t"
235 "scasl\n\t"
236 "lahf\n\t"
237 : "=a" (flags), "=D" (addr)
238 : "c" (test_len / 4), "a" (pattern), "D" (p)
239 );
240 if (flags & (1 << (6 + 8))) // x86 zero flag = bit 6.
241 {
242 return -1; // verify ok
243 }
244 return addr - 4; // verify error, return error address.
245}
246
247static void test_dram_stability(void)
248{
249 u32 test_len = 2048 * 1024;
250 u32 pat = 0x5aa5a55a;
251 u32 ext_mem_start = 0xc0000;
252 u32 base_mem_test_len = test_len > 640 * 1024 ? 640 * 1024 : test_len;
253 u32 ext_mem_test_len = test_len > ext_mem_start ? test_len - ext_mem_start : 0;
254 if (ext_mem_test_len > 0) {
255 /* Enable all shadow RAM region C0000 - FFFFF. */
256 pci_write_config32(NB, NB_REG_MAR, 0x3ffffff0);
257 }
258 int v;
259 fill_dram((u32 *) 0, pat, base_mem_test_len);
260 fill_dram((u32 *) ext_mem_start, pat, ext_mem_test_len);
261 v = verify_dram((u32 *) 0, pat, base_mem_test_len);
262 if (v == -1) {
263 v = verify_dram((u32 *) ext_mem_start, pat, ext_mem_test_len);
264 }
265 /* Change pattern and test again */
266 if (v == -1) {
267 pat = 0xa55a5aa5;
268 fill_dram((u32 *) 0, pat, base_mem_test_len);
269 fill_dram((u32 *) ext_mem_start, pat, ext_mem_test_len);
270 v = verify_dram((u32 *) 0, pat, base_mem_test_len);
271 if (v == -1) {
272 v = verify_dram((u32 *) ext_mem_start, pat, ext_mem_test_len);
273 }
274 }
275 if (v != -1) {
276 post_code(POST_DRAM_TEST_ERR);
277 print_emerg("DRAM stablility test error!\nADDR = ");
278 print_emerg_hex32(v);
279 print_emerg(", WRITE = ");
280 print_emerg_hex32(pat);
281 u32 r = *(u32 *) v;
282 print_emerg(", READ = ");
283 print_emerg_hex32(r);
284 print_emerg(", XOR = ");
285 print_emerg_hex32(r ^ pat);
286 print_emerg("\n");
287 die("System halted.\n");
288 }
289 if (ext_mem_test_len > 0) {
290 /* Disable shadow RAM. */
291 pci_write_config32(NB, NB_REG_MAR, 0x0);
292 }
293}
294
295static void enable_l2_cache(void)
296{
297 /*
298 * Enable L2 cache by setting PCI N/B function 1 L2 cache
299 * control register (0xe8) bit 0 (L2_EN) and bit 1 (L2_WB_EN).
300 */
301 u32 reg_nb_f1_e8;
302 reg_nb_f1_e8 = pci_read_config8(NB1, 0xe8);
303 reg_nb_f1_e8 |= 3;
304 pci_write_config8(NB1, 0xe8, reg_nb_f1_e8);
305}
306
307static void main(unsigned long bist)
308{
309 device_t dev;
310 u32 dmp_id;
311
312 dmp_id = get_dmp_id();
313 if (dmp_id != DMP_CPUID_EX) {
314 /* Not DMP Vortex86EX CPU. */
315 post_code(POST_DMP_ID_ERR);
316 while (1)
317 hlt();
318 }
319 disable_watchdog();
320 set_ex_powerdown_control();
321 set_pci_nb_pmcr();
322 set_pci_sb_lpccr();
323 ex_uart_early_init();
324
325 console_init();
326
327 init_wdt1();
328
329 /* Initialize i8254 timers */
330 post_code(0x42);
331 setup_i8254();
332
333 /* Initialize DRAM */
334 u8 reg_nb_f1_cc;
335 /* Setup DDR3 Timing reg 0-3 / Config reg */
336 pci_write_config16(NB, 0x6e, 0x0a2f);
337 pci_write_config32(NB, 0x74, 0x84010200);
338 pci_write_config32(NB, 0x78, 0x33405544);
339 pci_write_config32(NB, 0x7c, 0x2e0f0e0b);
340 /* Disable enhance read push write */
341 reg_nb_f1_cc = pci_read_config8(NB1, 0xcc);
342 reg_nb_f1_cc &= ~(1 << 4);
343 pci_write_config8(NB1, 0xcc, reg_nb_f1_cc);
344 if (detect_ddr3_dram_size()) {
345 post_code(POST_DRAM_SIZING_ERR);
346 die("DRAM sizing error!\n");
347 }
348 /* Reset enhance read push write to default(enable) */
349 reg_nb_f1_cc |= (1 << 4);
350 pci_write_config8(NB1, 0xcc, reg_nb_f1_cc);
351
352 print_ddr3_memory_setup();
353 test_dram_stability();
354
355 /* CPU setup, romcc pukes on invd() */
356 asm volatile ("invd");
357 enable_cache();
358
359 enable_l2_cache();
360}