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