early_printk.c 4.3 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5
/*
 * arch/sh/kernel/early_printk.c
 *
 *  Copyright (C) 1999, 2000  Niibe Yutaka
 *  Copyright (C) 2002  M. R. Brown
6
 *  Copyright (C) 2004 - 2006  Paul Mundt
L
Linus Torvalds 已提交
7 8 9 10 11 12 13 14
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 */
#include <linux/console.h>
#include <linux/tty.h>
#include <linux/init.h>
15
#include <linux/io.h>
L
Linus Torvalds 已提交
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51

#ifdef CONFIG_SH_STANDARD_BIOS
#include <asm/sh_bios.h>

/*
 *	Print a string through the BIOS
 */
static void sh_console_write(struct console *co, const char *s,
				 unsigned count)
{
	sh_bios_console_write(s, count);
}

/*
 *	Setup initial baud/bits/parity. We do two things here:
 *	- construct a cflag setting for the first rs_open()
 *	- initialize the serial port
 *	Return non-zero if we didn't find a serial port.
 */
static int __init sh_console_setup(struct console *co, char *options)
{
	int	cflag = CREAD | HUPCL | CLOCAL;

	/*
	 *	Now construct a cflag setting.
	 *	TODO: this is a totally bogus cflag, as we have
	 *	no idea what serial settings the BIOS is using, or
	 *	even if its using the serial port at all.
	 */
	cflag |= B115200 | CS8 | /*no parity*/0;

	co->cflag = cflag;

	return 0;
}

52
static struct console bios_console = {
L
Linus Torvalds 已提交
53 54 55 56 57 58 59 60 61
	.name		= "bios",
	.write		= sh_console_write,
	.setup		= sh_console_setup,
	.flags		= CON_PRINTBUFFER,
	.index		= -1,
};
#endif

#ifdef CONFIG_EARLY_SCIF_CONSOLE
62 63 64 65
#include <linux/serial_core.h>
#include "../../../drivers/serial/sh-sci.h"

static struct uart_port scif_port = {
66 67
	.mapbase	= CONFIG_EARLY_SCIF_CONSOLE_PORT,
	.membase	= (char __iomem *)CONFIG_EARLY_SCIF_CONSOLE_PORT,
68
};
L
Linus Torvalds 已提交
69 70 71

static void scif_sercon_putc(int c)
{
72 73
	while (((sci_in(&scif_port, SCFDR) & 0x1f00 >> 8) == 16))
		;
L
Linus Torvalds 已提交
74

75 76 77 78 79 80
	sci_out(&scif_port, SCxTDR, c);
	sci_in(&scif_port, SCxSR);
	sci_out(&scif_port, SCxSR, 0xf3 & ~(0x20 | 0x40));

	while ((sci_in(&scif_port, SCxSR) & 0x40) == 0);
		;
L
Linus Torvalds 已提交
81 82 83 84 85

	if (c == '\n')
		scif_sercon_putc('\r');
}

86 87
static void scif_sercon_write(struct console *con, const char *s,
			      unsigned count)
L
Linus Torvalds 已提交
88 89 90 91 92 93 94 95 96 97 98 99
{
	while (count-- > 0)
		scif_sercon_putc(*s++);
}

static int __init scif_sercon_setup(struct console *con, char *options)
{
	con->cflag = CREAD | HUPCL | CLOCAL | B115200 | CS8;

	return 0;
}

100
static struct console scif_console = {
L
Linus Torvalds 已提交
101 102 103 104 105 106 107
	.name		= "sercon",
	.write		= scif_sercon_write,
	.setup		= scif_sercon_setup,
	.flags		= CON_PRINTBUFFER,
	.index		= -1,
};

108 109 110 111 112
#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_STANDARD_BIOS)
/*
 * Simple SCIF init, primarily aimed at SH7750 and other similar SH-4
 * devices that aren't using sh-ipl+g.
 */
113
static void scif_sercon_init(int baud)
L
Linus Torvalds 已提交
114
{
115 116
	ctrl_outw(0, scif_port.mapbase + 8);
	ctrl_outw(0, scif_port.mapbase);
L
Linus Torvalds 已提交
117 118 119

	/* Set baud rate */
	ctrl_outb((CONFIG_SH_PCLK_FREQ + 16 * baud) /
120 121 122 123 124 125 126 127
		  (32 * baud) - 1, scif_port.mapbase + 4);

	ctrl_outw(12, scif_port.mapbase + 24);
	ctrl_outw(8, scif_port.mapbase + 24);
	ctrl_outw(0, scif_port.mapbase + 32);
	ctrl_outw(0x60, scif_port.mapbase + 16);
	ctrl_outw(0, scif_port.mapbase + 36);
	ctrl_outw(0x30, scif_port.mapbase + 8);
L
Linus Torvalds 已提交
128
}
129 130
#endif /* CONFIG_CPU_SH4 && !CONFIG_SH_STANDARD_BIOS */
#endif /* CONFIG_EARLY_SCIF_CONSOLE */
L
Linus Torvalds 已提交
131

132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
/*
 * Setup a default console, if more than one is compiled in, rely on the
 * earlyprintk= parsing to give priority.
 */
static struct console *early_console =
#ifdef CONFIG_SH_STANDARD_BIOS
	&bios_console
#elif defined(CONFIG_EARLY_SCIF_CONSOLE)
	&scif_console
#else
	NULL
#endif
	;

static int __initdata keep_early;
147
static int early_console_initialized;
148

149
int __init setup_early_printk(char *buf)
L
Linus Torvalds 已提交
150
{
151 152
	if (!buf)
		return 0;
153

154 155 156
	if (early_console_initialized)
		return 0;
	early_console_initialized = 1;
157 158 159 160 161 162 163 164 165 166 167 168

	if (strstr(buf, "keep"))
		keep_early = 1;

#ifdef CONFIG_SH_STANDARD_BIOS
	if (!strncmp(buf, "bios", 4))
		early_console = &bios_console;
#endif
#if defined(CONFIG_EARLY_SCIF_CONSOLE)
	if (!strncmp(buf, "serial", 6)) {
		early_console = &scif_console;

169
#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_STANDARD_BIOS)
170 171 172
		scif_sercon_init(115200);
#endif
	}
L
Linus Torvalds 已提交
173
#endif
174 175 176 177

	if (likely(early_console))
		register_console(early_console);

178
	return 0;
L
Linus Torvalds 已提交
179
}
180
early_param("earlyprintk", setup_early_printk);
L
Linus Torvalds 已提交
181

182
void __init disable_early_printk(void)
L
Linus Torvalds 已提交
183
{
184 185
	if (!early_console_initialized || !early_console)
		return;
186 187 188 189 190
	if (!keep_early) {
		printk("disabling early console\n");
		unregister_console(early_console);
	} else
		printk("keeping early console\n");
L
Linus Torvalds 已提交
191
}