|  | /* | 
|  | * allow a console to be used for early printk | 
|  | * derived from arch/x86/kernel/early_printk.c | 
|  | * | 
|  | * Copyright 2007-2009 Analog Devices Inc. | 
|  | * | 
|  | * Licensed under the GPL-2 | 
|  | */ | 
|  |  | 
|  | #include <linux/kernel.h> | 
|  | #include <linux/init.h> | 
|  | #include <linux/serial_core.h> | 
|  | #include <linux/console.h> | 
|  | #include <linux/string.h> | 
|  | #include <linux/reboot.h> | 
|  | #include <asm/blackfin.h> | 
|  | #include <asm/irq_handler.h> | 
|  | #include <asm/early_printk.h> | 
|  |  | 
|  | #ifdef CONFIG_SERIAL_BFIN | 
|  | extern struct console *bfin_earlyserial_init(unsigned int port, | 
|  | unsigned int cflag); | 
|  | #endif | 
|  | #ifdef CONFIG_BFIN_JTAG_COMM | 
|  | extern struct console *bfin_jc_early_init(void); | 
|  | #endif | 
|  |  | 
|  | /* Default console */ | 
|  | #define DEFAULT_PORT 0 | 
|  | #define DEFAULT_CFLAG CS8|B57600 | 
|  |  | 
|  | /* Default console for early crashes */ | 
|  | #define DEFAULT_EARLY_PORT "serial,uart0,57600" | 
|  |  | 
|  | #ifdef CONFIG_SERIAL_CORE | 
|  | /* What should get here is "0,57600" */ | 
|  | static struct console * __init earlyserial_init(char *buf) | 
|  | { | 
|  | int baud, bit; | 
|  | char parity; | 
|  | unsigned int serial_port = DEFAULT_PORT; | 
|  | unsigned int cflag = DEFAULT_CFLAG; | 
|  |  | 
|  | serial_port = simple_strtoul(buf, &buf, 10); | 
|  | buf++; | 
|  |  | 
|  | cflag = 0; | 
|  | baud = simple_strtoul(buf, &buf, 10); | 
|  | switch (baud) { | 
|  | case 1200: | 
|  | cflag |= B1200; | 
|  | break; | 
|  | case 2400: | 
|  | cflag |= B2400; | 
|  | break; | 
|  | case 4800: | 
|  | cflag |= B4800; | 
|  | break; | 
|  | case 9600: | 
|  | cflag |= B9600; | 
|  | break; | 
|  | case 19200: | 
|  | cflag |= B19200; | 
|  | break; | 
|  | case 38400: | 
|  | cflag |= B38400; | 
|  | break; | 
|  | case 115200: | 
|  | cflag |= B115200; | 
|  | break; | 
|  | default: | 
|  | cflag |= B57600; | 
|  | } | 
|  |  | 
|  | parity = buf[0]; | 
|  | buf++; | 
|  | switch (parity) { | 
|  | case 'e': | 
|  | cflag |= PARENB; | 
|  | break; | 
|  | case 'o': | 
|  | cflag |= PARODD; | 
|  | break; | 
|  | } | 
|  |  | 
|  | bit = simple_strtoul(buf, &buf, 10); | 
|  | switch (bit) { | 
|  | case 5: | 
|  | cflag |= CS5; | 
|  | break; | 
|  | case 6: | 
|  | cflag |= CS6; | 
|  | break; | 
|  | case 7: | 
|  | cflag |= CS7; | 
|  | break; | 
|  | default: | 
|  | cflag |= CS8; | 
|  | } | 
|  |  | 
|  | #ifdef CONFIG_SERIAL_BFIN | 
|  | return bfin_earlyserial_init(serial_port, cflag); | 
|  | #else | 
|  | return NULL; | 
|  | #endif | 
|  |  | 
|  | } | 
|  | #endif | 
|  |  | 
|  | int __init setup_early_printk(char *buf) | 
|  | { | 
|  |  | 
|  | /* Crashing in here would be really bad, so check both the var | 
|  | and the pointer before we start using it | 
|  | */ | 
|  | if (!buf) | 
|  | return 0; | 
|  |  | 
|  | if (!*buf) | 
|  | return 0; | 
|  |  | 
|  | if (early_console != NULL) | 
|  | return 0; | 
|  |  | 
|  | #ifdef CONFIG_SERIAL_BFIN | 
|  | /* Check for Blackfin Serial */ | 
|  | if (!strncmp(buf, "serial,uart", 11)) { | 
|  | buf += 11; | 
|  | early_console = earlyserial_init(buf); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | #ifdef CONFIG_BFIN_JTAG_COMM | 
|  | /* Check for Blackfin JTAG */ | 
|  | if (!strncmp(buf, "jtag", 4)) { | 
|  | buf += 4; | 
|  | early_console = bfin_jc_early_init(); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | #ifdef CONFIG_FB | 
|  | /* TODO: add framebuffer console support */ | 
|  | #endif | 
|  |  | 
|  | if (likely(early_console)) { | 
|  | early_console->flags |= CON_BOOT; | 
|  |  | 
|  | register_console(early_console); | 
|  | printk(KERN_INFO "early printk enabled on %s%d\n", | 
|  | early_console->name, | 
|  | early_console->index); | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Set up a temporary Event Vector Table, so if something bad happens before | 
|  | * the kernel is fully started, it doesn't vector off into somewhere we don't | 
|  | * know | 
|  | */ | 
|  |  | 
|  | asmlinkage void __init init_early_exception_vectors(void) | 
|  | { | 
|  | u32 evt; | 
|  | SSYNC(); | 
|  |  | 
|  | /* | 
|  | * This starts up the shadow buffer, incase anything crashes before | 
|  | * setup arch | 
|  | */ | 
|  | mark_shadow_error(); | 
|  | early_shadow_puts(linux_banner); | 
|  | early_shadow_stamp(); | 
|  |  | 
|  | if (CPUID != bfin_cpuid()) { | 
|  | early_shadow_puts("Running on wrong machine type, expected"); | 
|  | early_shadow_reg(CPUID, 16); | 
|  | early_shadow_puts(", but running on"); | 
|  | early_shadow_reg(bfin_cpuid(), 16); | 
|  | early_shadow_puts("\n"); | 
|  | } | 
|  |  | 
|  | /* cannot program in software: | 
|  | * evt0 - emulation (jtag) | 
|  | * evt1 - reset | 
|  | */ | 
|  | for (evt = EVT2; evt <= EVT15; evt += 4) | 
|  | bfin_write32(evt, early_trap); | 
|  | CSYNC(); | 
|  |  | 
|  | /* Set all the return from interrupt, exception, NMI to a known place | 
|  | * so if we do a RETI, RETX or RETN by mistake - we go somewhere known | 
|  | * Note - don't change RETS - we are in a subroutine, or | 
|  | * RETE - since it might screw up if emulator is attached | 
|  | */ | 
|  | asm("\tRETI = %0; RETX = %0; RETN = %0;\n" | 
|  | : : "p"(early_trap)); | 
|  |  | 
|  | } | 
|  |  | 
|  | __attribute__((__noreturn__)) | 
|  | asmlinkage void __init early_trap_c(struct pt_regs *fp, void *retaddr) | 
|  | { | 
|  | /* This can happen before the uart is initialized, so initialize | 
|  | * the UART now (but only if we are running on the processor we think | 
|  | * we are compiled for - otherwise we write to MMRs that don't exist, | 
|  | * and cause other problems. Nothing comes out the UART, but it does | 
|  | * end up in the __buf_log. | 
|  | */ | 
|  | if (likely(early_console == NULL) && CPUID == bfin_cpuid()) | 
|  | setup_early_printk(DEFAULT_EARLY_PORT); | 
|  |  | 
|  | if (!shadow_console_enabled()) { | 
|  | /* crap - we crashed before setup_arch() */ | 
|  | early_shadow_puts("panic before setup_arch\n"); | 
|  | early_shadow_puts("IPEND:"); | 
|  | early_shadow_reg(fp->ipend, 16); | 
|  | if (fp->seqstat & SEQSTAT_EXCAUSE) { | 
|  | early_shadow_puts("\nEXCAUSE:"); | 
|  | early_shadow_reg(fp->seqstat & SEQSTAT_EXCAUSE, 8); | 
|  | } | 
|  | if (fp->seqstat & SEQSTAT_HWERRCAUSE) { | 
|  | early_shadow_puts("\nHWERRCAUSE:"); | 
|  | early_shadow_reg( | 
|  | (fp->seqstat & SEQSTAT_HWERRCAUSE) >> 14, 8); | 
|  | } | 
|  | early_shadow_puts("\nErr @"); | 
|  | if (fp->ipend & EVT_EVX) | 
|  | early_shadow_reg(fp->retx, 32); | 
|  | else | 
|  | early_shadow_reg(fp->pc, 32); | 
|  | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON | 
|  | early_shadow_puts("\nTrace:"); | 
|  | if (likely(bfin_read_TBUFSTAT() & TBUFCNT)) { | 
|  | while (bfin_read_TBUFSTAT() & TBUFCNT) { | 
|  | early_shadow_puts("\nT  :"); | 
|  | early_shadow_reg(bfin_read_TBUF(), 32); | 
|  | early_shadow_puts("\n S :"); | 
|  | early_shadow_reg(bfin_read_TBUF(), 32); | 
|  | } | 
|  | } | 
|  | #endif | 
|  | early_shadow_puts("\nUse bfin-elf-addr2line to determine " | 
|  | "function names\n"); | 
|  | /* | 
|  | * We should panic(), but we can't - since panic calls printk, | 
|  | * and printk uses memcpy. | 
|  | * we want to reboot, but if the machine type is different, | 
|  | * can't due to machine specific reboot sequences | 
|  | */ | 
|  | if (CPUID == bfin_cpuid()) { | 
|  | early_shadow_puts("Trying to restart\n"); | 
|  | machine_restart(""); | 
|  | } | 
|  |  | 
|  | early_shadow_puts("Halting, since it is not safe to restart\n"); | 
|  | while (1) | 
|  | asm volatile ("EMUEXCPT; IDLE;\n"); | 
|  |  | 
|  | } else { | 
|  | printk(KERN_EMERG "Early panic\n"); | 
|  | show_regs(fp); | 
|  | dump_bfin_trace_buffer(); | 
|  | } | 
|  |  | 
|  | panic("Died early"); | 
|  | } | 
|  |  | 
|  | early_param("earlyprintk", setup_early_printk); |