linux/arch/microblaze/kernel/early_printk.c
<<
>>
Prefs
   1/*
   2 * Early printk support for Microblaze.
   3 *
   4 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
   5 * Copyright (C) 2007-2009 PetaLogix
   6 * Copyright (C) 2003-2006 Yasushi SHOJI <yashi@atmark-techno.com>
   7 *
   8 * This file is subject to the terms and conditions of the GNU General Public
   9 * License. See the file "COPYING" in the main directory of this archive
  10 * for more details.
  11 */
  12
  13#include <linux/console.h>
  14#include <linux/kernel.h>
  15#include <linux/init.h>
  16#include <linux/string.h>
  17#include <linux/tty.h>
  18#include <linux/io.h>
  19#include <asm/processor.h>
  20#include <linux/fcntl.h>
  21#include <asm/setup.h>
  22#include <asm/prom.h>
  23
  24static u32 early_console_initialized;
  25static u32 base_addr;
  26
  27#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
  28static void early_printk_uartlite_putc(char c)
  29{
  30        /*
  31         * Limit how many times we'll spin waiting for TX FIFO status.
  32         * This will prevent lockups if the base address is incorrectly
  33         * set, or any other issue on the UARTLITE.
  34         * This limit is pretty arbitrary, unless we are at about 10 baud
  35         * we'll never timeout on a working UART.
  36         */
  37
  38        unsigned retries = 1000000;
  39        /* read status bit - 0x8 offset */
  40        while (--retries && (in_be32(base_addr + 8) & (1 << 3)))
  41                ;
  42
  43        /* Only attempt the iowrite if we didn't timeout */
  44        /* write to TX_FIFO - 0x4 offset */
  45        if (retries)
  46                out_be32(base_addr + 4, c & 0xff);
  47}
  48
  49static void early_printk_uartlite_write(struct console *unused,
  50                                        const char *s, unsigned n)
  51{
  52        while (*s && n-- > 0) {
  53                if (*s == '\n')
  54                        early_printk_uartlite_putc('\r');
  55                early_printk_uartlite_putc(*s);
  56                s++;
  57        }
  58}
  59
  60static struct console early_serial_uartlite_console = {
  61        .name = "earlyser",
  62        .write = early_printk_uartlite_write,
  63        .flags = CON_PRINTBUFFER | CON_BOOT,
  64        .index = -1,
  65};
  66#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */
  67
  68#ifdef CONFIG_SERIAL_8250_CONSOLE
  69static void early_printk_uart16550_putc(char c)
  70{
  71        /*
  72         * Limit how many times we'll spin waiting for TX FIFO status.
  73         * This will prevent lockups if the base address is incorrectly
  74         * set, or any other issue on the UARTLITE.
  75         * This limit is pretty arbitrary, unless we are at about 10 baud
  76         * we'll never timeout on a working UART.
  77         */
  78
  79        #define UART_LSR_TEMT   0x40 /* Transmitter empty */
  80        #define UART_LSR_THRE   0x20 /* Transmit-hold-register empty */
  81        #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
  82
  83        unsigned retries = 10000;
  84
  85        while (--retries &&
  86                !((in_be32(base_addr + 0x14) & BOTH_EMPTY) == BOTH_EMPTY))
  87                ;
  88
  89        if (retries)
  90                out_be32(base_addr, c & 0xff);
  91}
  92
  93static void early_printk_uart16550_write(struct console *unused,
  94                                        const char *s, unsigned n)
  95{
  96        while (*s && n-- > 0) {
  97                if (*s == '\n')
  98                        early_printk_uart16550_putc('\r');
  99                early_printk_uart16550_putc(*s);
 100                s++;
 101        }
 102}
 103
 104static struct console early_serial_uart16550_console = {
 105        .name = "earlyser",
 106        .write = early_printk_uart16550_write,
 107        .flags = CON_PRINTBUFFER | CON_BOOT,
 108        .index = -1,
 109};
 110#endif /* CONFIG_SERIAL_8250_CONSOLE */
 111
 112static struct console *early_console;
 113
 114void early_printk(const char *fmt, ...)
 115{
 116        char buf[512];
 117        int n;
 118        va_list ap;
 119
 120        if (early_console_initialized) {
 121                va_start(ap, fmt);
 122                n = vscnprintf(buf, 512, fmt, ap);
 123                early_console->write(early_console, buf, n);
 124                va_end(ap);
 125        }
 126}
 127
 128int __init setup_early_printk(char *opt)
 129{
 130        int version = 0;
 131
 132        if (early_console_initialized)
 133                return 1;
 134
 135        base_addr = of_early_console(&version);
 136        if (base_addr) {
 137#ifdef CONFIG_MMU
 138                early_console_reg_tlb_alloc(base_addr);
 139#endif
 140                switch (version) {
 141#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
 142                case UARTLITE:
 143                        printk(KERN_INFO "Early console on uartlite "
 144                                                "at 0x%08x\n", base_addr);
 145                        early_console = &early_serial_uartlite_console;
 146                        break;
 147#endif
 148#ifdef CONFIG_SERIAL_8250_CONSOLE
 149                case UART16550:
 150                        printk(KERN_INFO "Early console on uart16650 "
 151                                                "at 0x%08x\n", base_addr);
 152                        early_console = &early_serial_uart16550_console;
 153                        break;
 154#endif
 155                default:
 156                        printk(KERN_INFO  "Unsupported early console %d\n",
 157                                                                version);
 158                        return 1;
 159                }
 160
 161                register_console(early_console);
 162                early_console_initialized = 1;
 163                return 0;
 164        }
 165        return 1;
 166}
 167
 168/* Remap early console to virtual address and do not allocate one TLB
 169 * only for early console because of performance degression */
 170void __init remap_early_printk(void)
 171{
 172        if (!early_console_initialized || !early_console)
 173                return;
 174        printk(KERN_INFO "early_printk_console remapping from 0x%x to ",
 175                                                                base_addr);
 176        base_addr = (u32) ioremap(base_addr, PAGE_SIZE);
 177        printk(KERN_CONT "0x%x\n", base_addr);
 178
 179#ifdef CONFIG_MMU
 180        /*
 181         * Early console is on the top of skipped TLB entries
 182         * decrease tlb_skip size ensure that hardcoded TLB entry will be
 183         * used by generic algorithm
 184         * FIXME check if early console mapping is on the top by rereading
 185         * TLB entry and compare baseaddr
 186         *  mts  rtlbx, (tlb_skip - 1)
 187         *  nop
 188         *  mfs  rX, rtlblo
 189         *  nop
 190         *  cmp rX, orig_base_addr
 191         */
 192        tlb_skip -= 1;
 193#endif
 194}
 195
 196void __init disable_early_printk(void)
 197{
 198        if (!early_console_initialized || !early_console)
 199                return;
 200        printk(KERN_WARNING "disabling early console\n");
 201        unregister_console(early_console);
 202        early_console_initialized = 0;
 203}
 204