Commit 0ae53640b54f2c30e52044f7102ba08915b988a7

Authored by Robin Getz
Committed by Bryan Wu
1 parent 1d487f468d

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>

Showing 6 changed files with 307 additions and 29 deletions Side-by-side Diff

Documentation/kernel-parameters.txt
... ... @@ -35,6 +35,7 @@
35 35 APIC APIC support is enabled.
36 36 APM Advanced Power Management support is enabled.
37 37 AX25 Appropriate AX.25 support is enabled.
  38 + BLACKFIN Blackfin architecture is enabled.
38 39 DRM Direct Rendering Management support is enabled.
39 40 EDD BIOS Enhanced Disk Drive Services (EDD) is enabled
40 41 EFI EFI Partitioning (GPT) is enabled
... ... @@ -550,7 +551,7 @@
550 551  
551 552 dtc3181e= [HW,SCSI]
552 553  
553   - earlyprintk= [X86-32,X86-64,SH]
  554 + earlyprintk= [X86-32,X86-64,SH,BLACKFIN]
554 555 earlyprintk=vga
555 556 earlyprintk=serial[,ttySn[,baudrate]]
556 557  
arch/blackfin/Kconfig
... ... @@ -1164,6 +1164,20 @@
1164 1164 Say Y here to disable hardware tracing in some known "jumpy" pieces
1165 1165 of code so that the trace buffer will extend further back.
1166 1166  
  1167 +config 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 +
1167 1181 config DUAL_CORE_TEST_MODULE
1168 1182 tristate "Dual Core Test Module"
1169 1183 depends on (BF561)
arch/blackfin/kernel/Makefile
... ... @@ -13,4 +13,5 @@
13 13 obj-$(CONFIG_BFIN_DMA_5XX) += bfin_dma_5xx.o
14 14 obj-$(CONFIG_DUAL_CORE_TEST_MODULE) += dualcore_test.o
15 15 obj-$(CONFIG_KGDB) += kgdb.o
  16 +obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
arch/blackfin/kernel/early_printk.c
  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
  35 +extern struct console *bfin_earlyserial_init(unsigned int port,
  36 + unsigned int cflag);
  37 +#endif
  38 +
  39 +static 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" */
  50 +static 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 +
  123 +int __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 +
  161 +early_param("earlyprintk", setup_early_printk);
drivers/serial/bfin_5xx.c
... ... @@ -962,31 +962,7 @@
962 962 }
963 963  
964 964 #ifdef CONFIG_SERIAL_BFIN_CONSOLE
965   -static 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 965 /*
975   - * Interrupts are disabled on entering
976   - */
977   -static void
978   -bfin_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   -/*
990 966 * If the port was already initialised (eg, by a boot loader),
991 967 * try to determine the current setup.
992 968 */
993 969  
994 970  
995 971  
996 972  
997 973  
... ... @@ -1038,19 +1014,25 @@
1038 1014 }
1039 1015 pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __FUNCTION__, *baud, *parity, *bits);
1040 1016 }
  1017 +#endif
1041 1018  
  1019 +#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
  1020 +static struct uart_driver bfin_serial_reg;
  1021 +
1042 1022 static int __init
1043 1023 bfin_serial_console_setup(struct console *co, char *options)
1044 1024 {
1045 1025 struct bfin_serial_port *uart;
  1026 +# ifdef CONFIG_SERIAL_BFIN_CONSOLE
1046 1027 int baud = 57600;
1047 1028 int bits = 8;
1048 1029 int parity = 'n';
1049   -#ifdef CONFIG_SERIAL_BFIN_CTSRTS
  1030 +# ifdef CONFIG_SERIAL_BFIN_CTSRTS
1050 1031 int flow = 'r';
1051   -#else
  1032 +# else
1052 1033 int flow = 'n';
1053   -#endif
  1034 +# endif
  1035 +# endif
1054 1036  
1055 1037 /*
1056 1038 * Check whether an invalid uart number has been specified, and
1057 1039  
1058 1040  
1059 1041  
... ... @@ -1061,15 +1043,45 @@
1061 1043 co->index = 0;
1062 1044 uart = &bfin_serial_ports[co->index];
1063 1045  
  1046 +# ifdef CONFIG_SERIAL_BFIN_CONSOLE
1064 1047 if (options)
1065 1048 uart_parse_options(options, &baud, &parity, &bits, &flow);
1066 1049 else
1067 1050 bfin_serial_console_get_options(uart, &baud, &parity, &bits);
1068 1051  
1069 1052 return uart_set_options(&uart->port, co, baud, parity, bits, flow);
  1053 +# else
  1054 + return 0;
  1055 +# endif
1070 1056 }
  1057 +#endif /* defined (CONFIG_SERIAL_BFIN_CONSOLE) ||
  1058 + defined (CONFIG_EARLY_PRINTK) */
1071 1059  
1072   -static struct uart_driver bfin_serial_reg;
  1060 +#ifdef CONFIG_SERIAL_BFIN_CONSOLE
  1061 +static 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 + */
  1073 +static void
  1074 +bfin_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 +
  1083 +}
  1084 +
1073 1085 static struct console bfin_serial_console = {
1074 1086 .name = BFIN_SERIAL_NAME,
1075 1087 .write = bfin_serial_console_write,
1076 1088  
... ... @@ -1095,7 +1107,68 @@
1095 1107 #define BFIN_SERIAL_CONSOLE &bfin_serial_console
1096 1108 #else
1097 1109 #define BFIN_SERIAL_CONSOLE NULL
  1110 +#endif /* CONFIG_SERIAL_BFIN_CONSOLE */
  1111 +
  1112 +
  1113 +#ifdef CONFIG_EARLY_PRINTK
  1114 +static __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 +
  1124 +static __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 +
  1137 +static 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 +
  1147 +struct 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 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  
1100 1173 static struct uart_driver bfin_serial_reg = {
1101 1174 .owner = THIS_MODULE,
include/asm-blackfin/early_printk.h
  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
  25 +extern int setup_early_printk(char *);
  26 +#else
  27 +#define setup_early_printk(fmt) do { } while (0)
  28 +#endif /* CONFIG_EARLY_PRINTK */