ARM64: fix framepointer check in unwind_frame
[pandora-kernel.git] / arch / arm64 / kernel / early_printk.c
1 /*
2  * Earlyprintk support.
3  *
4  * Copyright (C) 2012 ARM Ltd.
5  * Author: Catalin Marinas <catalin.marinas@arm.com>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 #include <linux/kernel.h>
20 #include <linux/console.h>
21 #include <linux/init.h>
22 #include <linux/string.h>
23 #include <linux/mm.h>
24 #include <linux/io.h>
25
26 #include <linux/amba/serial.h>
27 #include <linux/serial_reg.h>
28
29 static void __iomem *early_base;
30 static void (*printch)(char ch);
31
32 /*
33  * PL011 single character TX.
34  */
35 static void pl011_printch(char ch)
36 {
37         while (readl_relaxed(early_base + UART01x_FR) & UART01x_FR_TXFF)
38                 ;
39         writeb_relaxed(ch, early_base + UART01x_DR);
40         while (readl_relaxed(early_base + UART01x_FR) & UART01x_FR_BUSY)
41                 ;
42 }
43
44 /*
45  * Semihosting-based debug console
46  */
47 static void smh_printch(char ch)
48 {
49         asm volatile("mov  x1, %0\n"
50                      "mov  x0, #3\n"
51                      "hlt  0xf000\n"
52                      : : "r" (&ch) : "x0", "x1", "memory");
53 }
54
55 /*
56  * 8250/16550 (8-bit aligned registers) single character TX.
57  */
58 static void uart8250_8bit_printch(char ch)
59 {
60         while (!(readb_relaxed(early_base + UART_LSR) & UART_LSR_THRE))
61                 ;
62         writeb_relaxed(ch, early_base + UART_TX);
63 }
64
65 /*
66  * 8250/16550 (32-bit aligned registers) single character TX.
67  */
68 static void uart8250_32bit_printch(char ch)
69 {
70         while (!(readl_relaxed(early_base + (UART_LSR << 2)) & UART_LSR_THRE))
71                 ;
72         writel_relaxed(ch, early_base + (UART_TX << 2));
73 }
74
75 struct earlycon_match {
76         const char *name;
77         void (*printch)(char ch);
78 };
79
80 static const struct earlycon_match earlycon_match[] __initconst = {
81         { .name = "pl011", .printch = pl011_printch, },
82         { .name = "smh", .printch = smh_printch, },
83         { .name = "uart8250-8bit", .printch = uart8250_8bit_printch, },
84         { .name = "uart8250-32bit", .printch = uart8250_32bit_printch, },
85         {}
86 };
87
88 static void early_write(struct console *con, const char *s, unsigned n)
89 {
90         while (n-- > 0) {
91                 if (*s == '\n')
92                         printch('\r');
93                 printch(*s);
94                 s++;
95         }
96 }
97
98 static struct console early_console_dev = {
99         .name =         "earlycon",
100         .write =        early_write,
101         .flags =        CON_PRINTBUFFER | CON_BOOT,
102         .index =        -1,
103 };
104
105 /*
106  * Parse earlyprintk=... parameter in the format:
107  *
108  *   <name>[,<addr>][,<options>]
109  *
110  * and register the early console. It is assumed that the UART has been
111  * initialised by the bootloader already.
112  */
113 static int __init setup_early_printk(char *buf)
114 {
115         const struct earlycon_match *match = earlycon_match;
116         phys_addr_t paddr = 0;
117
118         if (!buf) {
119                 pr_warning("No earlyprintk arguments passed.\n");
120                 return 0;
121         }
122
123         while (match->name) {
124                 size_t len = strlen(match->name);
125                 if (!strncmp(buf, match->name, len)) {
126                         buf += len;
127                         break;
128                 }
129                 match++;
130         }
131         if (!match->name) {
132                 pr_warning("Unknown earlyprintk arguments: %s\n", buf);
133                 return 0;
134         }
135
136         /* I/O address */
137         if (!strncmp(buf, ",0x", 3)) {
138                 char *e;
139                 paddr = simple_strtoul(buf + 1, &e, 16);
140                 buf = e;
141         }
142         /* no options parsing yet */
143
144         if (paddr)
145                 early_base = early_io_map(paddr, EARLYCON_IOBASE);
146
147         printch = match->printch;
148         early_console = &early_console_dev;
149         register_console(&early_console_dev);
150
151         return 0;
152 }
153
154 early_param("earlyprintk", setup_early_printk);