1/*
2 * allow a console to be used for early printk
3 * derived from arch/x86/kernel/early_printk.c
4 *
5 * Copyright 2007-2009 Analog Devices Inc.
6 *
7 * Licensed under the GPL-2
8 */
9
10#include <linux/kernel.h>
11#include <linux/init.h>
12#include <linux/serial_core.h>
13#include <linux/console.h>
14#include <linux/string.h>
15#include <linux/reboot.h>
16#include <asm/blackfin.h>
17#include <asm/irq_handler.h>
18#include <asm/early_printk.h>
19
20#ifdef CONFIG_SERIAL_BFIN
21extern struct console *bfin_earlyserial_init(unsigned int port,
22						unsigned int cflag);
23#endif
24#ifdef CONFIG_BFIN_JTAG_COMM
25extern struct console *bfin_jc_early_init(void);
26#endif
27
28/* Default console */
29#define DEFAULT_PORT 0
30#define DEFAULT_CFLAG CS8|B57600
31
32/* Default console for early crashes */
33#define DEFAULT_EARLY_PORT "serial,uart0,57600"
34
35#ifdef CONFIG_SERIAL_CORE
36/* What should get here is "0,57600" */
37static struct console * __init earlyserial_init(char *buf)
38{
39	int baud, bit;
40	char parity;
41	unsigned int serial_port = DEFAULT_PORT;
42	unsigned int cflag = DEFAULT_CFLAG;
43
44	serial_port = simple_strtoul(buf, &buf, 10);
45	buf++;
46
47	cflag = 0;
48	baud = simple_strtoul(buf, &buf, 10);
49	switch (baud) {
50	case 1200:
51		cflag |= B1200;
52		break;
53	case 2400:
54		cflag |= B2400;
55		break;
56	case 4800:
57		cflag |= B4800;
58		break;
59	case 9600:
60		cflag |= B9600;
61		break;
62	case 19200:
63		cflag |= B19200;
64		break;
65	case 38400:
66		cflag |= B38400;
67		break;
68	case 115200:
69		cflag |= B115200;
70		break;
71	default:
72		cflag |= B57600;
73	}
74
75	parity = buf[0];
76	buf++;
77	switch (parity) {
78	case 'e':
79		cflag |= PARENB;
80		break;
81	case 'o':
82		cflag |= PARODD;
83		break;
84	}
85
86	bit = simple_strtoul(buf, &buf, 10);
87	switch (bit) {
88	case 5:
89		cflag |= CS5;
90		break;
91	case 6:
92		cflag |= CS6;
93		break;
94	case 7:
95		cflag |= CS7;
96		break;
97	default:
98		cflag |= CS8;
99	}
100
101#ifdef CONFIG_SERIAL_BFIN
102	return bfin_earlyserial_init(serial_port, cflag);
103#else
104	return NULL;
105#endif
106
107}
108#endif
109
110int __init setup_early_printk(char *buf)
111{
112
113	/* Crashing in here would be really bad, so check both the var
114	   and the pointer before we start using it
115	 */
116	if (!buf)
117		return 0;
118
119	if (!*buf)
120		return 0;
121
122	if (early_console != NULL)
123		return 0;
124
125#ifdef CONFIG_SERIAL_BFIN
126	/* Check for Blackfin Serial */
127	if (!strncmp(buf, "serial,uart", 11)) {
128		buf += 11;
129		early_console = earlyserial_init(buf);
130	}
131#endif
132
133#ifdef CONFIG_BFIN_JTAG_COMM
134	/* Check for Blackfin JTAG */
135	if (!strncmp(buf, "jtag", 4)) {
136		buf += 4;
137		early_console = bfin_jc_early_init();
138	}
139#endif
140
141#ifdef CONFIG_FB
142		/* TODO: add framebuffer console support */
143#endif
144
145	if (likely(early_console)) {
146		early_console->flags |= CON_BOOT;
147
148		register_console(early_console);
149		printk(KERN_INFO "early printk enabled on %s%d\n",
150			early_console->name,
151			early_console->index);
152	}
153
154	return 0;
155}
156
157/*
158 * Set up a temporary Event Vector Table, so if something bad happens before
159 * the kernel is fully started, it doesn't vector off into somewhere we don't
160 * know
161 */
162
163asmlinkage void __init init_early_exception_vectors(void)
164{
165	u32 evt;
166	SSYNC();
167
168	/*
169	 * This starts up the shadow buffer, incase anything crashes before
170	 * setup arch
171	 */
172	mark_shadow_error();
173	early_shadow_puts(linux_banner);
174	early_shadow_stamp();
175
176	if (CPUID != bfin_cpuid()) {
177		early_shadow_puts("Running on wrong machine type, expected");
178		early_shadow_reg(CPUID, 16);
179		early_shadow_puts(", but running on");
180		early_shadow_reg(bfin_cpuid(), 16);
181		early_shadow_puts("\n");
182	}
183
184	/* cannot program in software:
185	 * evt0 - emulation (jtag)
186	 * evt1 - reset
187	 */
188	for (evt = EVT2; evt <= EVT15; evt += 4)
189		bfin_write32(evt, early_trap);
190	CSYNC();
191
192	/* Set all the return from interrupt, exception, NMI to a known place
193	 * so if we do a RETI, RETX or RETN by mistake - we go somewhere known
194	 * Note - don't change RETS - we are in a subroutine, or
195	 * RETE - since it might screw up if emulator is attached
196	 */
197	asm("\tRETI = %0; RETX = %0; RETN = %0;\n"
198		: : "p"(early_trap));
199
200}
201
202__attribute__((__noreturn__))
203asmlinkage void __init early_trap_c(struct pt_regs *fp, void *retaddr)
204{
205	/* This can happen before the uart is initialized, so initialize
206	 * the UART now (but only if we are running on the processor we think
207	 * we are compiled for - otherwise we write to MMRs that don't exist,
208	 * and cause other problems. Nothing comes out the UART, but it does
209	 * end up in the __buf_log.
210	 */
211	if (likely(early_console == NULL) && CPUID == bfin_cpuid())
212		setup_early_printk(DEFAULT_EARLY_PORT);
213
214	if (!shadow_console_enabled()) {
215		/* crap - we crashed before setup_arch() */
216		early_shadow_puts("panic before setup_arch\n");
217		early_shadow_puts("IPEND:");
218		early_shadow_reg(fp->ipend, 16);
219		if (fp->seqstat & SEQSTAT_EXCAUSE) {
220			early_shadow_puts("\nEXCAUSE:");
221			early_shadow_reg(fp->seqstat & SEQSTAT_EXCAUSE, 8);
222		}
223		if (fp->seqstat & SEQSTAT_HWERRCAUSE) {
224			early_shadow_puts("\nHWERRCAUSE:");
225			early_shadow_reg(
226				(fp->seqstat & SEQSTAT_HWERRCAUSE) >> 14, 8);
227		}
228		early_shadow_puts("\nErr @");
229		if (fp->ipend & EVT_EVX)
230			early_shadow_reg(fp->retx, 32);
231		else
232			early_shadow_reg(fp->pc, 32);
233#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
234		early_shadow_puts("\nTrace:");
235		if (likely(bfin_read_TBUFSTAT() & TBUFCNT)) {
236			while (bfin_read_TBUFSTAT() & TBUFCNT) {
237				early_shadow_puts("\nT  :");
238				early_shadow_reg(bfin_read_TBUF(), 32);
239				early_shadow_puts("\n S :");
240				early_shadow_reg(bfin_read_TBUF(), 32);
241			}
242		}
243#endif
244		early_shadow_puts("\nUse bfin-elf-addr2line to determine "
245			"function names\n");
246		/*
247		 * We should panic(), but we can't - since panic calls printk,
248		 * and printk uses memcpy.
249		 * we want to reboot, but if the machine type is different,
250		 * can't due to machine specific reboot sequences
251		 */
252		if (CPUID == bfin_cpuid()) {
253			early_shadow_puts("Trying to restart\n");
254			machine_restart("");
255		}
256
257		early_shadow_puts("Halting, since it is not safe to restart\n");
258		while (1)
259			asm volatile ("EMUEXCPT; IDLE;\n");
260
261	} else {
262		printk(KERN_EMERG "Early panic\n");
263		show_regs(fp);
264		dump_bfin_trace_buffer();
265	}
266
267	panic("Died early");
268}
269
270early_param("earlyprintk", setup_early_printk);
271