aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobin Getz <robin.getz@analog.com>2007-10-09 05:24:49 -0400
committerBryan Wu <bryan.wu@analog.com>2007-10-09 05:24:49 -0400
commit0ae53640b54f2c30e52044f7102ba08915b988a7 (patch)
treec8d89d9856d994e0069fe3dbe9687b96c7a79162
parent1d487f468de75b8a5c664db60e106935f9dc753b (diff)
Blackfin arch: Initial patch to add earlyprintk support
This allows debugging of problems which happen eary in the kernel boot process (after bootargs are parsed, but before serial subsystem is fully initialized) Signed-off-by: Robin Getz <robin.getz@analog.com> Signed-off-by: Bryan Wu <bryan.wu@analog.com>
-rw-r--r--Documentation/kernel-parameters.txt3
-rw-r--r--arch/blackfin/Kconfig14
-rw-r--r--arch/blackfin/kernel/Makefile1
-rw-r--r--arch/blackfin/kernel/early_printk.c161
-rw-r--r--drivers/serial/bfin_5xx.c129
-rw-r--r--include/asm-blackfin/early_printk.h28
6 files changed, 307 insertions, 29 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 4d175c751246..a57c1f216b21 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -35,6 +35,7 @@ parameter is applicable:
35 APIC APIC support is enabled. 35 APIC APIC support is enabled.
36 APM Advanced Power Management support is enabled. 36 APM Advanced Power Management support is enabled.
37 AX25 Appropriate AX.25 support is enabled. 37 AX25 Appropriate AX.25 support is enabled.
38 BLACKFIN Blackfin architecture is enabled.
38 DRM Direct Rendering Management support is enabled. 39 DRM Direct Rendering Management support is enabled.
39 EDD BIOS Enhanced Disk Drive Services (EDD) is enabled 40 EDD BIOS Enhanced Disk Drive Services (EDD) is enabled
40 EFI EFI Partitioning (GPT) is enabled 41 EFI EFI Partitioning (GPT) is enabled
@@ -550,7 +551,7 @@ and is between 256 and 4096 characters. It is defined in the file
550 551
551 dtc3181e= [HW,SCSI] 552 dtc3181e= [HW,SCSI]
552 553
553 earlyprintk= [X86-32,X86-64,SH] 554 earlyprintk= [X86-32,X86-64,SH,BLACKFIN]
554 earlyprintk=vga 555 earlyprintk=vga
555 earlyprintk=serial[,ttySn[,baudrate]] 556 earlyprintk=serial[,ttySn[,baudrate]]
556 557
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index 26ebb0e8c431..cc789b988f3a 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -1164,6 +1164,20 @@ config DEBUG_BFIN_NO_KERN_HWTRACE
1164 Say Y here to disable hardware tracing in some known "jumpy" pieces 1164 Say Y here to disable hardware tracing in some known "jumpy" pieces
1165 of code so that the trace buffer will extend further back. 1165 of code so that the trace buffer will extend further back.
1166 1166
1167config EARLY_PRINTK
1168 bool "Early printk"
1169 default n
1170 help
1171 This option enables special console drivers which allow the kernel
1172 to print messages very early in the bootup process.
1173
1174 This is useful for kernel debugging when your machine crashes very
1175 early before the console code is initialized. After enabling this
1176 feature, you must add "earlyprintk=serial,uart0,57600" to the
1177 command line (bootargs). It is safe to say Y here in all cases, as
1178 all of this lives in the init section and is thrown away after the
1179 kernel boots completely.
1180
1167config DUAL_CORE_TEST_MODULE 1181config DUAL_CORE_TEST_MODULE
1168 tristate "Dual Core Test Module" 1182 tristate "Dual Core Test Module"
1169 depends on (BF561) 1183 depends on (BF561)
diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile
index 243883ec6de1..8aeb6066b19b 100644
--- a/arch/blackfin/kernel/Makefile
+++ b/arch/blackfin/kernel/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_MODULES) += module.o
13obj-$(CONFIG_BFIN_DMA_5XX) += bfin_dma_5xx.o 13obj-$(CONFIG_BFIN_DMA_5XX) += bfin_dma_5xx.o
14obj-$(CONFIG_DUAL_CORE_TEST_MODULE) += dualcore_test.o 14obj-$(CONFIG_DUAL_CORE_TEST_MODULE) += dualcore_test.o
15obj-$(CONFIG_KGDB) += kgdb.o 15obj-$(CONFIG_KGDB) += kgdb.o
16obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
diff --git a/arch/blackfin/kernel/early_printk.c b/arch/blackfin/kernel/early_printk.c
new file mode 100644
index 000000000000..9bf61706694f
--- /dev/null
+++ b/arch/blackfin/kernel/early_printk.c
@@ -0,0 +1,161 @@
1/*
2 * File: arch/blackfin/kernel/early_printk.c
3 * Based on: arch/x86_64/kernel/early_printk.c
4 * Author: Robin Getz <rgetz@blackfin.uclinux.org
5 *
6 * Created: 14Aug2007
7 * Description: allow a console to be used for early printk
8 *
9 * Modified:
10 * Copyright 2004-2007 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 */
24
25#include <linux/kernel.h>
26#include <linux/init.h>
27#include <linux/serial_core.h>
28#include <linux/console.h>
29#include <linux/string.h>
30#include <asm/blackfin.h>
31#include <asm/irq_handler.h>
32#include <asm/early_printk.h>
33
34#ifdef CONFIG_SERIAL_BFIN
35extern struct console *bfin_earlyserial_init(unsigned int port,
36 unsigned int cflag);
37#endif
38
39static struct console *early_console;
40
41/* Default console
42 * Port n == ttyBFn
43 * cflags == UART output modes
44 */
45#define DEFAULT_PORT 0
46#define DEFAULT_CFLAG CS8|B57600
47
48#ifdef CONFIG_SERIAL_CORE
49/* What should get here is "0,57600" */
50static struct console * __init earlyserial_init(char *buf)
51{
52 int baud, bit;
53 char parity;
54 unsigned int serial_port = DEFAULT_PORT;
55 unsigned int cflag = DEFAULT_CFLAG;
56
57 serial_port = simple_strtoul(buf, &buf, 10);
58 buf++;
59
60 cflag = 0;
61 baud = simple_strtoul(buf, &buf, 10);
62 switch (baud) {
63 case 1200:
64 cflag |= B1200;
65 break;
66 case 2400:
67 cflag |= B2400;
68 break;
69 case 4800:
70 cflag |= B4800;
71 break;
72 case 9600:
73 cflag |= B9600;
74 break;
75 case 19200:
76 cflag |= B19200;
77 break;
78 case 38400:
79 cflag |= B38400;
80 break;
81 case 115200:
82 cflag |= B115200;
83 break;
84 default:
85 cflag |= B57600;
86 }
87
88 parity = buf[0];
89 buf++;
90 switch (parity) {
91 case 'e':
92 cflag |= PARENB;
93 break;
94 case 'o':
95 cflag |= PARODD;
96 break;
97 }
98
99 bit = simple_strtoul(buf, &buf, 10);
100 switch (bit) {
101 case 5:
102 cflag |= CS5;
103 break;
104 case 6:
105 cflag |= CS5;
106 break;
107 case 7:
108 cflag |= CS5;
109 break;
110 default:
111 cflag |= CS8;
112 }
113
114#ifdef CONFIG_SERIAL_BFIN
115 return bfin_earlyserial_init(serial_port, cflag);
116#else
117 return NULL;
118#endif
119
120}
121#endif
122
123int __init setup_early_printk(char *buf)
124{
125
126 /* Crashing in here would be really bad, so check both the var
127 and the pointer before we start using it
128 */
129 if (!buf)
130 return 0;
131
132 if (!*buf)
133 return 0;
134
135 if (early_console != NULL)
136 return 0;
137
138#ifdef CONFIG_SERIAL_BFIN
139 /* Check for Blackfin Serial */
140 if (!strncmp(buf, "serial,uart", 11)) {
141 buf += 11;
142 early_console = earlyserial_init(buf);
143 }
144#endif
145#ifdef CONFIG_FB
146 /* TODO: add framebuffer console support */
147#endif
148
149 if (likely(early_console)) {
150 early_console->flags |= CON_BOOT;
151
152 register_console(early_console);
153 printk(KERN_INFO "early printk enabled on %s%d\n",
154 early_console->name,
155 early_console->index);
156 }
157
158 return 0;
159}
160
161early_param("earlyprintk", setup_early_printk);
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index 1e79ee605d93..5039e2675abc 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -962,30 +962,6 @@ static void __init bfin_serial_init_ports(void)
962} 962}
963 963
964#ifdef CONFIG_SERIAL_BFIN_CONSOLE 964#ifdef CONFIG_SERIAL_BFIN_CONSOLE
965static void bfin_serial_console_putchar(struct uart_port *port, int ch)
966{
967 struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
968 while (!(UART_GET_LSR(uart) & THRE))
969 barrier();
970 UART_PUT_CHAR(uart, ch);
971 SSYNC();
972}
973
974/*
975 * Interrupts are disabled on entering
976 */
977static void
978bfin_serial_console_write(struct console *co, const char *s, unsigned int count)
979{
980 struct bfin_serial_port *uart = &bfin_serial_ports[co->index];
981 int flags = 0;
982
983 spin_lock_irqsave(&uart->port.lock, flags);
984 uart_console_write(&uart->port, s, count, bfin_serial_console_putchar);
985 spin_unlock_irqrestore(&uart->port.lock, flags);
986
987}
988
989/* 965/*
990 * If the port was already initialised (eg, by a boot loader), 966 * If the port was already initialised (eg, by a boot loader),
991 * try to determine the current setup. 967 * try to determine the current setup.
@@ -1038,19 +1014,25 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
1038 } 1014 }
1039 pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __FUNCTION__, *baud, *parity, *bits); 1015 pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __FUNCTION__, *baud, *parity, *bits);
1040} 1016}
1017#endif
1018
1019#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
1020static struct uart_driver bfin_serial_reg;
1041 1021
1042static int __init 1022static int __init
1043bfin_serial_console_setup(struct console *co, char *options) 1023bfin_serial_console_setup(struct console *co, char *options)
1044{ 1024{
1045 struct bfin_serial_port *uart; 1025 struct bfin_serial_port *uart;
1026# ifdef CONFIG_SERIAL_BFIN_CONSOLE
1046 int baud = 57600; 1027 int baud = 57600;
1047 int bits = 8; 1028 int bits = 8;
1048 int parity = 'n'; 1029 int parity = 'n';
1049#ifdef CONFIG_SERIAL_BFIN_CTSRTS 1030# ifdef CONFIG_SERIAL_BFIN_CTSRTS
1050 int flow = 'r'; 1031 int flow = 'r';
1051#else 1032# else
1052 int flow = 'n'; 1033 int flow = 'n';
1053#endif 1034# endif
1035# endif
1054 1036
1055 /* 1037 /*
1056 * Check whether an invalid uart number has been specified, and 1038 * Check whether an invalid uart number has been specified, and
@@ -1061,15 +1043,45 @@ bfin_serial_console_setup(struct console *co, char *options)
1061 co->index = 0; 1043 co->index = 0;
1062 uart = &bfin_serial_ports[co->index]; 1044 uart = &bfin_serial_ports[co->index];
1063 1045
1046# ifdef CONFIG_SERIAL_BFIN_CONSOLE
1064 if (options) 1047 if (options)
1065 uart_parse_options(options, &baud, &parity, &bits, &flow); 1048 uart_parse_options(options, &baud, &parity, &bits, &flow);
1066 else 1049 else
1067 bfin_serial_console_get_options(uart, &baud, &parity, &bits); 1050 bfin_serial_console_get_options(uart, &baud, &parity, &bits);
1068 1051
1069 return uart_set_options(&uart->port, co, baud, parity, bits, flow); 1052 return uart_set_options(&uart->port, co, baud, parity, bits, flow);
1053# else
1054 return 0;
1055# endif
1056}
1057#endif /* defined (CONFIG_SERIAL_BFIN_CONSOLE) ||
1058 defined (CONFIG_EARLY_PRINTK) */
1059
1060#ifdef CONFIG_SERIAL_BFIN_CONSOLE
1061static void bfin_serial_console_putchar(struct uart_port *port, int ch)
1062{
1063 struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
1064 while (!(UART_GET_LSR(uart) & THRE))
1065 barrier();
1066 UART_PUT_CHAR(uart, ch);
1067 SSYNC();
1068}
1069
1070/*
1071 * Interrupts are disabled on entering
1072 */
1073static void
1074bfin_serial_console_write(struct console *co, const char *s, unsigned int count)
1075{
1076 struct bfin_serial_port *uart = &bfin_serial_ports[co->index];
1077 int flags = 0;
1078
1079 spin_lock_irqsave(&uart->port.lock, flags);
1080 uart_console_write(&uart->port, s, count, bfin_serial_console_putchar);
1081 spin_unlock_irqrestore(&uart->port.lock, flags);
1082
1070} 1083}
1071 1084
1072static struct uart_driver bfin_serial_reg;
1073static struct console bfin_serial_console = { 1085static struct console bfin_serial_console = {
1074 .name = BFIN_SERIAL_NAME, 1086 .name = BFIN_SERIAL_NAME,
1075 .write = bfin_serial_console_write, 1087 .write = bfin_serial_console_write,
@@ -1095,7 +1107,68 @@ console_initcall(bfin_serial_rs_console_init);
1095#define BFIN_SERIAL_CONSOLE &bfin_serial_console 1107#define BFIN_SERIAL_CONSOLE &bfin_serial_console
1096#else 1108#else
1097#define BFIN_SERIAL_CONSOLE NULL 1109#define BFIN_SERIAL_CONSOLE NULL
1110#endif /* CONFIG_SERIAL_BFIN_CONSOLE */
1111
1112
1113#ifdef CONFIG_EARLY_PRINTK
1114static __init void early_serial_putc(struct uart_port *port, int ch)
1115{
1116 unsigned timeout = 0xffff;
1117 struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
1118
1119 while ((!(UART_GET_LSR(uart) & THRE)) && --timeout)
1120 cpu_relax();
1121 UART_PUT_CHAR(uart, ch);
1122}
1123
1124static __init void early_serial_write(struct console *con, const char *s,
1125 unsigned int n)
1126{
1127 struct bfin_serial_port *uart = &bfin_serial_ports[con->index];
1128 unsigned int i;
1129
1130 for (i = 0; i < n; i++, s++) {
1131 if (*s == '\n')
1132 early_serial_putc(&uart->port, '\r');
1133 early_serial_putc(&uart->port, *s);
1134 }
1135}
1136
1137static struct __init console bfin_early_serial_console = {
1138 .name = "early_BFuart",
1139 .write = early_serial_write,
1140 .device = uart_console_device,
1141 .flags = CON_PRINTBUFFER,
1142 .setup = bfin_serial_console_setup,
1143 .index = -1,
1144 .data = &bfin_serial_reg,
1145};
1146
1147struct console __init *bfin_earlyserial_init(unsigned int port,
1148 unsigned int cflag)
1149{
1150 struct bfin_serial_port *uart;
1151 struct ktermios t;
1152
1153 if (port == -1 || port >= nr_ports)
1154 port = 0;
1155 bfin_serial_init_ports();
1156 bfin_early_serial_console.index = port;
1157#ifdef CONFIG_KGDB_UART
1158 kgdb_entry_state = 0;
1159 init_kgdb_uart();
1098#endif 1160#endif
1161 uart = &bfin_serial_ports[port];
1162 t.c_cflag = cflag;
1163 t.c_iflag = 0;
1164 t.c_oflag = 0;
1165 t.c_lflag = ICANON;
1166 t.c_line = port;
1167 bfin_serial_set_termios(&uart->port, &t, &t);
1168 return &bfin_early_serial_console;
1169}
1170
1171#endif /* CONFIG_SERIAL_BFIN_CONSOLE */
1099 1172
1100static struct uart_driver bfin_serial_reg = { 1173static struct uart_driver bfin_serial_reg = {
1101 .owner = THIS_MODULE, 1174 .owner = THIS_MODULE,
diff --git a/include/asm-blackfin/early_printk.h b/include/asm-blackfin/early_printk.h
new file mode 100644
index 000000000000..110f1c1f845c
--- /dev/null
+++ b/include/asm-blackfin/early_printk.h
@@ -0,0 +1,28 @@
1/*
2 * File: include/asm-blackfin/early_printk.h
3 * Author: Robin Getz <rgetz@blackfin.uclinux.org
4 *
5 * Created: 14Aug2007
6 * Description: function prototpyes for early printk
7 *
8 * Modified:
9 * Copyright 2004-2007 Analog Devices Inc.
10 *
11 * Bugs: Enter bugs at http://blackfin.uclinux.org/
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 */
23
24#ifdef CONFIG_EARLY_PRINTK
25extern int setup_early_printk(char *);
26#else
27#define setup_early_printk(fmt) do { } while (0)
28#endif /* CONFIG_EARLY_PRINTK */