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 base_addr;
  25
  26#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
  27static void early_printk_uartlite_putc(char c)
  28{
  29        /*
  30         * Limit how many times we'll spin waiting for TX FIFO status.
  31         * This will prevent lockups if the base address is incorrectly
  32         * set, or any other issue on the UARTLITE.
  33         * This limit is pretty arbitrary, unless we are at about 10 baud
  34         * we'll never timeout on a working UART.
  35         */
  36
  37        unsigned retries = 1000000;
  38        /* read status bit - 0x8 offset */
  39        while (--retries && (in_be32(base_addr + 8) & (1 << 3)))
  40                ;
  41
  42        /* Only attempt the iowrite if we didn't timeout */
  43        /* write to TX_FIFO - 0x4 offset */
  44        if (retries)
  45                out_be32(base_addr + 4, c & 0xff);
  46}
  47
  48static void early_printk_uartlite_write(struct console *unused,
  49                                        const char *s, unsigned n)
  50{
  51        while (*s && n-- > 0) {
  52                if (*s == '\n')
  53                        early_printk_uartlite_putc('\r');
  54                early_printk_uartlite_putc(*s);
  55                s++;
  56        }
  57}
  58
  59static struct console early_serial_uartlite_console = {
  60        .name = "earlyser",
  61        .write = early_printk_uartlite_write,
  62        .flags = CON_PRINTBUFFER | CON_BOOT,
  63        .index = -1,
  64};
  65#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */
  66
  67#ifdef CONFIG_SERIAL_8250_CONSOLE
  68static void early_printk_uart16550_putc(char c)
  69{
  70        /*
  71         * Limit how many times we'll spin waiting for TX FIFO status.
  72         * This will prevent lockups if the base address is incorrectly
  73         * set, or any other issue on the UARTLITE.
  74         * This limit is pretty arbitrary, unless we are at about 10 baud
  75         * we'll never timeout on a working UART.
  76         */
  77
  78        #define UART_LSR_TEMT   0x40 /* Transmitter empty */
  79        #define UART_LSR_THRE   0x20 /* Transmit-hold-register empty */
  80        #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
  81
  82        unsigned retries = 10000;
  83
  84        while (--retries &&
  85                !((in_be32(base_addr + 0x14) & BOTH_EMPTY) == BOTH_EMPTY))
  86                ;
  87
  88        if (retries)
  89                out_be32(base_addr, c & 0xff);
  90}
  91
  92static void early_printk_uart16550_write(struct console *unused,
  93                                        const char *s, unsigned n)
  94{
  95        while (*s && n-- > 0) {
  96                if (*s == '\n')
  97                        early_printk_uart16550_putc('\r');
  98                early_printk_uart16550_putc(*s);
  99                s++;
 100        }
 101}
 102
 103static struct console early_serial_uart16550_console = {
 104        .name = "earlyser",
 105        .write = early_printk_uart16550_write,
 106        .flags = CON_PRINTBUFFER | CON_BOOT,
 107        .index = -1,
 108};
 109#endif /* CONFIG_SERIAL_8250_CONSOLE */
 110
 111int __init setup_early_printk(char *opt)
 112{
 113        int version = 0;
 114
 115        if (early_console)
 116                return 1;
 117
 118        base_addr = of_early_console(&version);
 119        if (base_addr) {
 120#ifdef CONFIG_MMU
 121                early_console_reg_tlb_alloc(base_addr);
 122#endif
 123                switch (version) {
 124#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
 125                case UARTLITE:
 126                        pr_info("Early console on uartlite at 0x%08x\n",
 127                                                                base_addr);
 128                        early_console = &early_serial_uartlite_console;
 129                        break;
 130#endif
 131#ifdef CONFIG_SERIAL_8250_CONSOLE
 132                case UART16550:
 133                        pr_info("Early console on uart16650 at 0x%08x\n",
 134                                                                base_addr);
 135                        early_console = &early_serial_uart16550_console;
 136                        break;
 137#endif
 138                default:
 139                        pr_info("Unsupported early console %d\n",
 140                                                                version);
 141                        return 1;
 142                }
 143
 144                register_console(early_console);
 145                return 0;
 146        }
 147        return 1;
 148}
 149
 150/* Remap early console to virtual address and do not allocate one TLB
 151 * only for early console because of performance degression */
 152void __init remap_early_printk(void)
 153{
 154        if (!early_console)
 155                return;
 156        pr_info("early_printk_console remapping from 0x%x to ", base_addr);
 157        base_addr = (u32) ioremap(base_addr, PAGE_SIZE);
 158        pr_cont("0x%x\n", base_addr);
 159
 160#ifdef CONFIG_MMU
 161        /*
 162         * Early console is on the top of skipped TLB entries
 163         * decrease tlb_skip size ensure that hardcoded TLB entry will be
 164         * used by generic algorithm
 165         * FIXME check if early console mapping is on the top by rereading
 166         * TLB entry and compare baseaddr
 167         *  mts  rtlbx, (tlb_skip - 1)
 168         *  nop
 169         *  mfs  rX, rtlblo
 170         *  nop
 171         *  cmp rX, orig_base_addr
 172         */
 173        tlb_skip -= 1;
 174#endif
 175}
 176
 177void __init disable_early_printk(void)
 178{
 179        if (!early_console)
 180                return;
 181        pr_warn("disabling early console\n");
 182        unregister_console(early_console);
 183        early_console = NULL;
 184}
 185