• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
21 extern struct console *bfin_earlyserial_init(unsigned int port,
22 						unsigned int cflag);
23 #endif
24 #ifdef CONFIG_BFIN_JTAG_COMM
25 extern 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" */
earlyserial_init(char * buf)37 static 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 
setup_early_printk(char * buf)110 int __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 
init_early_exception_vectors(void)163 asmlinkage 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__))
early_trap_c(struct pt_regs * fp,void * retaddr)203 asmlinkage 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 
270 early_param("earlyprintk", setup_early_printk);
271