| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * arch/sh/kernel/early_printk.c | 
|  | 3 | * | 
|  | 4 | *  Copyright (C) 1999, 2000  Niibe Yutaka | 
|  | 5 | *  Copyright (C) 2002  M. R. Brown | 
| Paul Mundt | a80fd21 | 2006-09-27 14:26:53 +0900 | [diff] [blame] | 6 | *  Copyright (C) 2004 - 2006  Paul Mundt | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7 | * | 
|  | 8 | * This file is subject to the terms and conditions of the GNU General Public | 
|  | 9 | * License.  See the file "COPYING" in the main directory of this archive | 
|  | 10 | * for more details. | 
|  | 11 | */ | 
|  | 12 | #include <linux/console.h> | 
|  | 13 | #include <linux/tty.h> | 
|  | 14 | #include <linux/init.h> | 
| Paul Mundt | 6fc21b8 | 2006-11-27 12:10:23 +0900 | [diff] [blame] | 15 | #include <linux/io.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 16 |  | 
|  | 17 | #ifdef CONFIG_SH_STANDARD_BIOS | 
|  | 18 | #include <asm/sh_bios.h> | 
|  | 19 |  | 
|  | 20 | /* | 
|  | 21 | *	Print a string through the BIOS | 
|  | 22 | */ | 
|  | 23 | static void sh_console_write(struct console *co, const char *s, | 
|  | 24 | unsigned count) | 
|  | 25 | { | 
|  | 26 | sh_bios_console_write(s, count); | 
|  | 27 | } | 
|  | 28 |  | 
|  | 29 | /* | 
|  | 30 | *	Setup initial baud/bits/parity. We do two things here: | 
|  | 31 | *	- construct a cflag setting for the first rs_open() | 
|  | 32 | *	- initialize the serial port | 
|  | 33 | *	Return non-zero if we didn't find a serial port. | 
|  | 34 | */ | 
|  | 35 | static int __init sh_console_setup(struct console *co, char *options) | 
|  | 36 | { | 
|  | 37 | int	cflag = CREAD | HUPCL | CLOCAL; | 
|  | 38 |  | 
|  | 39 | /* | 
|  | 40 | *	Now construct a cflag setting. | 
|  | 41 | *	TODO: this is a totally bogus cflag, as we have | 
|  | 42 | *	no idea what serial settings the BIOS is using, or | 
|  | 43 | *	even if its using the serial port at all. | 
|  | 44 | */ | 
|  | 45 | cflag |= B115200 | CS8 | /*no parity*/0; | 
|  | 46 |  | 
|  | 47 | co->cflag = cflag; | 
|  | 48 |  | 
|  | 49 | return 0; | 
|  | 50 | } | 
|  | 51 |  | 
| Paul Mundt | a80fd21 | 2006-09-27 14:26:53 +0900 | [diff] [blame] | 52 | static struct console bios_console = { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 53 | .name		= "bios", | 
|  | 54 | .write		= sh_console_write, | 
|  | 55 | .setup		= sh_console_setup, | 
|  | 56 | .flags		= CON_PRINTBUFFER, | 
|  | 57 | .index		= -1, | 
|  | 58 | }; | 
|  | 59 | #endif | 
|  | 60 |  | 
|  | 61 | #ifdef CONFIG_EARLY_SCIF_CONSOLE | 
| Paul Mundt | a80fd21 | 2006-09-27 14:26:53 +0900 | [diff] [blame] | 62 | #include <linux/serial_core.h> | 
|  | 63 | #include "../../../drivers/serial/sh-sci.h" | 
|  | 64 |  | 
| Paul Mundt | a80fd21 | 2006-09-27 14:26:53 +0900 | [diff] [blame] | 65 | static struct uart_port scif_port = { | 
| Paul Mundt | 6fc21b8 | 2006-11-27 12:10:23 +0900 | [diff] [blame] | 66 | .mapbase	= CONFIG_EARLY_SCIF_CONSOLE_PORT, | 
|  | 67 | .membase	= (char __iomem *)CONFIG_EARLY_SCIF_CONSOLE_PORT, | 
| Paul Mundt | a80fd21 | 2006-09-27 14:26:53 +0900 | [diff] [blame] | 68 | }; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 69 |  | 
|  | 70 | static void scif_sercon_putc(int c) | 
|  | 71 | { | 
| Paul Mundt | a80fd21 | 2006-09-27 14:26:53 +0900 | [diff] [blame] | 72 | while (((sci_in(&scif_port, SCFDR) & 0x1f00 >> 8) == 16)) | 
|  | 73 | ; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 74 |  | 
| Paul Mundt | a80fd21 | 2006-09-27 14:26:53 +0900 | [diff] [blame] | 75 | sci_out(&scif_port, SCxTDR, c); | 
|  | 76 | sci_in(&scif_port, SCxSR); | 
|  | 77 | sci_out(&scif_port, SCxSR, 0xf3 & ~(0x20 | 0x40)); | 
|  | 78 |  | 
|  | 79 | while ((sci_in(&scif_port, SCxSR) & 0x40) == 0); | 
|  | 80 | ; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 81 |  | 
|  | 82 | if (c == '\n') | 
|  | 83 | scif_sercon_putc('\r'); | 
|  | 84 | } | 
|  | 85 |  | 
| Paul Mundt | a80fd21 | 2006-09-27 14:26:53 +0900 | [diff] [blame] | 86 | static void scif_sercon_write(struct console *con, const char *s, | 
|  | 87 | unsigned count) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 88 | { | 
|  | 89 | while (count-- > 0) | 
|  | 90 | scif_sercon_putc(*s++); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 91 | } | 
|  | 92 |  | 
|  | 93 | static int __init scif_sercon_setup(struct console *con, char *options) | 
|  | 94 | { | 
|  | 95 | con->cflag = CREAD | HUPCL | CLOCAL | B115200 | CS8; | 
|  | 96 |  | 
|  | 97 | return 0; | 
|  | 98 | } | 
|  | 99 |  | 
| Paul Mundt | a80fd21 | 2006-09-27 14:26:53 +0900 | [diff] [blame] | 100 | static struct console scif_console = { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 101 | .name		= "sercon", | 
|  | 102 | .write		= scif_sercon_write, | 
|  | 103 | .setup		= scif_sercon_setup, | 
|  | 104 | .flags		= CON_PRINTBUFFER, | 
|  | 105 | .index		= -1, | 
|  | 106 | }; | 
|  | 107 |  | 
| Paul Mundt | 6fc21b8 | 2006-11-27 12:10:23 +0900 | [diff] [blame] | 108 | #if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_STANDARD_BIOS) | 
|  | 109 | /* | 
|  | 110 | * Simple SCIF init, primarily aimed at SH7750 and other similar SH-4 | 
|  | 111 | * devices that aren't using sh-ipl+g. | 
|  | 112 | */ | 
| Paul Mundt | a80fd21 | 2006-09-27 14:26:53 +0900 | [diff] [blame] | 113 | static void scif_sercon_init(int baud) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 114 | { | 
| Paul Mundt | 6fc21b8 | 2006-11-27 12:10:23 +0900 | [diff] [blame] | 115 | ctrl_outw(0, scif_port.mapbase + 8); | 
|  | 116 | ctrl_outw(0, scif_port.mapbase); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 117 |  | 
|  | 118 | /* Set baud rate */ | 
|  | 119 | ctrl_outb((CONFIG_SH_PCLK_FREQ + 16 * baud) / | 
| Paul Mundt | 6fc21b8 | 2006-11-27 12:10:23 +0900 | [diff] [blame] | 120 | (32 * baud) - 1, scif_port.mapbase + 4); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 121 |  | 
| Paul Mundt | 6fc21b8 | 2006-11-27 12:10:23 +0900 | [diff] [blame] | 122 | ctrl_outw(12, scif_port.mapbase + 24); | 
|  | 123 | ctrl_outw(8, scif_port.mapbase + 24); | 
|  | 124 | ctrl_outw(0, scif_port.mapbase + 32); | 
|  | 125 | ctrl_outw(0x60, scif_port.mapbase + 16); | 
|  | 126 | ctrl_outw(0, scif_port.mapbase + 36); | 
|  | 127 | ctrl_outw(0x30, scif_port.mapbase + 8); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 128 | } | 
| Paul Mundt | 6fc21b8 | 2006-11-27 12:10:23 +0900 | [diff] [blame] | 129 | #endif /* CONFIG_CPU_SH4 && !CONFIG_SH_STANDARD_BIOS */ | 
|  | 130 | #endif /* CONFIG_EARLY_SCIF_CONSOLE */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 131 |  | 
| Paul Mundt | a80fd21 | 2006-09-27 14:26:53 +0900 | [diff] [blame] | 132 | /* | 
|  | 133 | * Setup a default console, if more than one is compiled in, rely on the | 
|  | 134 | * earlyprintk= parsing to give priority. | 
|  | 135 | */ | 
|  | 136 | static struct console *early_console = | 
|  | 137 | #ifdef CONFIG_SH_STANDARD_BIOS | 
|  | 138 | &bios_console | 
|  | 139 | #elif defined(CONFIG_EARLY_SCIF_CONSOLE) | 
|  | 140 | &scif_console | 
|  | 141 | #else | 
|  | 142 | NULL | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 143 | #endif | 
| Paul Mundt | a80fd21 | 2006-09-27 14:26:53 +0900 | [diff] [blame] | 144 | ; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 145 |  | 
| Paul Mundt | a80fd21 | 2006-09-27 14:26:53 +0900 | [diff] [blame] | 146 | static int __initdata keep_early; | 
| Paul Mundt | b641fe0 | 2006-12-12 09:00:47 +0900 | [diff] [blame] | 147 | static int early_console_initialized; | 
| Paul Mundt | a80fd21 | 2006-09-27 14:26:53 +0900 | [diff] [blame] | 148 |  | 
| Paul Mundt | b641fe0 | 2006-12-12 09:00:47 +0900 | [diff] [blame] | 149 | int __init setup_early_printk(char *buf) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 150 | { | 
| Paul Mundt | b641fe0 | 2006-12-12 09:00:47 +0900 | [diff] [blame] | 151 | if (!buf) | 
|  | 152 | return 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 153 |  | 
| Paul Mundt | b641fe0 | 2006-12-12 09:00:47 +0900 | [diff] [blame] | 154 | if (early_console_initialized) | 
|  | 155 | return 0; | 
|  | 156 | early_console_initialized = 1; | 
| Paul Mundt | a80fd21 | 2006-09-27 14:26:53 +0900 | [diff] [blame] | 157 |  | 
|  | 158 | if (strstr(buf, "keep")) | 
|  | 159 | keep_early = 1; | 
|  | 160 |  | 
|  | 161 | #ifdef CONFIG_SH_STANDARD_BIOS | 
|  | 162 | if (!strncmp(buf, "bios", 4)) | 
|  | 163 | early_console = &bios_console; | 
|  | 164 | #endif | 
|  | 165 | #if defined(CONFIG_EARLY_SCIF_CONSOLE) | 
|  | 166 | if (!strncmp(buf, "serial", 6)) { | 
|  | 167 | early_console = &scif_console; | 
|  | 168 |  | 
| Paul Mundt | 6fc21b8 | 2006-11-27 12:10:23 +0900 | [diff] [blame] | 169 | #if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_STANDARD_BIOS) | 
| Paul Mundt | a80fd21 | 2006-09-27 14:26:53 +0900 | [diff] [blame] | 170 | scif_sercon_init(115200); | 
|  | 171 | #endif | 
|  | 172 | } | 
|  | 173 | #endif | 
|  | 174 |  | 
|  | 175 | if (likely(early_console)) | 
|  | 176 | register_console(early_console); | 
|  | 177 |  | 
| Paul Mundt | b641fe0 | 2006-12-12 09:00:47 +0900 | [diff] [blame] | 178 | return 0; | 
| Paul Mundt | a80fd21 | 2006-09-27 14:26:53 +0900 | [diff] [blame] | 179 | } | 
| Paul Mundt | b641fe0 | 2006-12-12 09:00:47 +0900 | [diff] [blame] | 180 | early_param("earlyprintk", setup_early_printk); | 
| Paul Mundt | a80fd21 | 2006-09-27 14:26:53 +0900 | [diff] [blame] | 181 |  | 
|  | 182 | void __init disable_early_printk(void) | 
|  | 183 | { | 
| Paul Mundt | b641fe0 | 2006-12-12 09:00:47 +0900 | [diff] [blame] | 184 | if (!early_console_initialized || !early_console) | 
|  | 185 | return; | 
| Paul Mundt | a80fd21 | 2006-09-27 14:26:53 +0900 | [diff] [blame] | 186 | if (!keep_early) { | 
|  | 187 | printk("disabling early console\n"); | 
|  | 188 | unregister_console(early_console); | 
|  | 189 | } else | 
|  | 190 | printk("keeping early console\n"); | 
|  | 191 | } |