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