1 /*
2  * Early printk for Nios2.
3  *
4  * Copyright (C) 2015, Altera Corporation
5  * Copyright (C) 2010, Tobias Klauser <tklauser@distanz.ch>
6  * Copyright (C) 2009, Wind River Systems Inc
7  *   Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
8  *
9  * This file is subject to the terms and conditions of the GNU General Public
10  * License. See the file "COPYING" in the main directory of this archive
11  * for more details.
12  */
13 
14 #include <linux/console.h>
15 #include <linux/init.h>
16 #include <linux/kernel.h>
17 #include <linux/io.h>
18 
19 #include <asm/prom.h>
20 
21 static unsigned long base_addr;
22 
23 #if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE)
24 
25 #define ALTERA_JTAGUART_DATA_REG		0
26 #define ALTERA_JTAGUART_CONTROL_REG		4
27 #define ALTERA_JTAGUART_CONTROL_WSPACE_MSK	0xFFFF0000
28 #define ALTERA_JTAGUART_CONTROL_AC_MSK		0x00000400
29 
30 #define JUART_GET_CR() \
31 	__builtin_ldwio((void *)(base_addr + ALTERA_JTAGUART_CONTROL_REG))
32 #define JUART_SET_CR(v) \
33 	__builtin_stwio((void *)(base_addr + ALTERA_JTAGUART_CONTROL_REG), v)
34 #define JUART_SET_TX(v) \
35 	__builtin_stwio((void *)(base_addr + ALTERA_JTAGUART_DATA_REG), v)
36 
early_console_write(struct console * con,const char * s,unsigned n)37 static void early_console_write(struct console *con, const char *s, unsigned n)
38 {
39 	unsigned long status;
40 
41 	while (n-- && *s) {
42 		while (((status = JUART_GET_CR())
43 				& ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) {
44 #if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS)
45 			if ((status & ALTERA_JTAGUART_CONTROL_AC_MSK) == 0)
46 				return;	/* no connection activity */
47 #endif
48 		}
49 		JUART_SET_TX(*s);
50 		s++;
51 	}
52 }
53 
54 #elif defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE)
55 
56 #define ALTERA_UART_TXDATA_REG		4
57 #define ALTERA_UART_STATUS_REG		8
58 #define ALTERA_UART_STATUS_TRDY		0x0040
59 
60 #define UART_GET_SR() \
61 	__builtin_ldwio((void *)(base_addr + ALTERA_UART_STATUS_REG))
62 #define UART_SET_TX(v) \
63 	__builtin_stwio((void *)(base_addr + ALTERA_UART_TXDATA_REG), v)
64 
early_console_putc(char c)65 static void early_console_putc(char c)
66 {
67 	while (!(UART_GET_SR() & ALTERA_UART_STATUS_TRDY))
68 		;
69 
70 	UART_SET_TX(c);
71 }
72 
early_console_write(struct console * con,const char * s,unsigned n)73 static void early_console_write(struct console *con, const char *s, unsigned n)
74 {
75 	while (n-- && *s) {
76 		early_console_putc(*s);
77 		if (*s == '\n')
78 			early_console_putc('\r');
79 		s++;
80 	}
81 }
82 
83 #else
84 # error Neither SERIAL_ALTERA_JTAGUART_CONSOLE nor SERIAL_ALTERA_UART_CONSOLE \
85 selected
86 #endif
87 
88 static struct console early_console_prom = {
89 	.name	= "early",
90 	.write	= early_console_write,
91 	.flags	= CON_PRINTBUFFER | CON_BOOT,
92 	.index	= -1
93 };
94 
setup_early_printk(void)95 void __init setup_early_printk(void)
96 {
97 #if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE) ||	\
98 	defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE)
99 	base_addr = of_early_console();
100 #else
101 	base_addr = 0;
102 #endif
103 
104 	if (!base_addr)
105 		return;
106 
107 #if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS)
108 	/* Clear activity bit so BYPASS doesn't stall if we've used JTAG for
109 	 * downloading the kernel. This might cause early data to be lost even
110 	 * if the JTAG terminal is running.
111 	 */
112 	JUART_SET_CR(JUART_GET_CR() | ALTERA_JTAGUART_CONTROL_AC_MSK);
113 #endif
114 
115 	early_console = &early_console_prom;
116 	register_console(early_console);
117 	pr_info("early_console initialized at 0x%08lx\n", base_addr);
118 }
119