linux/arch/powerpc/kernel/udbg_16550.c
<<
>>
Prefs
   1/*
   2 * udbg for NS16550 compatible serial ports
   3 *
   4 * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp
   5 *
   6 *      This program is free software; you can redistribute it and/or
   7 *      modify it under the terms of the GNU General Public License
   8 *      as published by the Free Software Foundation; either version
   9 *      2 of the License, or (at your option) any later version.
  10 */
  11#include <linux/types.h>
  12#include <asm/udbg.h>
  13#include <asm/io.h>
  14#include <asm/reg_a2.h>
  15
  16extern u8 real_readb(volatile u8 __iomem  *addr);
  17extern void real_writeb(u8 data, volatile u8 __iomem *addr);
  18extern u8 real_205_readb(volatile u8 __iomem  *addr);
  19extern void real_205_writeb(u8 data, volatile u8 __iomem *addr);
  20
  21#define UART_RBR        0
  22#define UART_IER        1
  23#define UART_FCR        2
  24#define UART_LCR        3
  25#define UART_MCR        4
  26#define UART_LSR        5
  27#define UART_MSR        6
  28#define UART_SCR        7
  29#define UART_THR        UART_RBR
  30#define UART_IIR        UART_FCR
  31#define UART_DLL        UART_RBR
  32#define UART_DLM        UART_IER
  33#define UART_DLAB       UART_LCR
  34
  35#define LSR_DR   0x01  /* Data ready */
  36#define LSR_OE   0x02  /* Overrun */
  37#define LSR_PE   0x04  /* Parity error */
  38#define LSR_FE   0x08  /* Framing error */
  39#define LSR_BI   0x10  /* Break */
  40#define LSR_THRE 0x20  /* Xmit holding register empty */
  41#define LSR_TEMT 0x40  /* Xmitter empty */
  42#define LSR_ERR  0x80  /* Error */
  43
  44#define LCR_DLAB 0x80
  45
  46static u8 (*udbg_uart_in)(unsigned int reg);
  47static void (*udbg_uart_out)(unsigned int reg, u8 data);
  48
  49static void udbg_uart_flush(void)
  50{
  51        if (!udbg_uart_in)
  52                return;
  53
  54        /* wait for idle */
  55        while ((udbg_uart_in(UART_LSR) & LSR_THRE) == 0)
  56                cpu_relax();
  57}
  58
  59static void udbg_uart_putc(char c)
  60{
  61        if (!udbg_uart_out)
  62                return;
  63
  64        if (c == '\n')
  65                udbg_uart_putc('\r');
  66        udbg_uart_flush();
  67        udbg_uart_out(UART_THR, c);
  68}
  69
  70static int udbg_uart_getc_poll(void)
  71{
  72        if (!udbg_uart_in)
  73                return -1;
  74
  75        if (!(udbg_uart_in(UART_LSR) & LSR_DR))
  76                return udbg_uart_in(UART_RBR);
  77
  78        return -1;
  79}
  80
  81static int udbg_uart_getc(void)
  82{
  83        if (!udbg_uart_in)
  84                return -1;
  85        /* wait for char */
  86        while (!(udbg_uart_in(UART_LSR) & LSR_DR))
  87                cpu_relax();
  88        return udbg_uart_in(UART_RBR);
  89}
  90
  91static void udbg_use_uart(void)
  92{
  93        udbg_putc = udbg_uart_putc;
  94        udbg_flush = udbg_uart_flush;
  95        udbg_getc = udbg_uart_getc;
  96        udbg_getc_poll = udbg_uart_getc_poll;
  97}
  98
  99void udbg_uart_setup(unsigned int speed, unsigned int clock)
 100{
 101        unsigned int dll, base_bauds;
 102
 103        if (!udbg_uart_out)
 104                return;
 105
 106        if (clock == 0)
 107                clock = 1843200;
 108        if (speed == 0)
 109                speed = 9600;
 110
 111        base_bauds = clock / 16;
 112        dll = base_bauds / speed;
 113
 114        udbg_uart_out(UART_LCR, 0x00);
 115        udbg_uart_out(UART_IER, 0xff);
 116        udbg_uart_out(UART_IER, 0x00);
 117        udbg_uart_out(UART_LCR, LCR_DLAB);
 118        udbg_uart_out(UART_DLL, dll & 0xff);
 119        udbg_uart_out(UART_DLM, dll >> 8);
 120        /* 8 data, 1 stop, no parity */
 121        udbg_uart_out(UART_LCR, 0x3);
 122        /* RTS/DTR */
 123        udbg_uart_out(UART_MCR, 0x3);
 124        /* Clear & enable FIFOs */
 125        udbg_uart_out(UART_FCR, 0x7);
 126}
 127
 128unsigned int udbg_probe_uart_speed(unsigned int clock)
 129{
 130        unsigned int dll, dlm, divisor, prescaler, speed;
 131        u8 old_lcr;
 132
 133        old_lcr = udbg_uart_in(UART_LCR);
 134
 135        /* select divisor latch registers.  */
 136        udbg_uart_out(UART_LCR, old_lcr | LCR_DLAB);
 137
 138        /* now, read the divisor */
 139        dll = udbg_uart_in(UART_DLL);
 140        dlm = udbg_uart_in(UART_DLM);
 141        divisor = dlm << 8 | dll;
 142
 143        /* check prescaling */
 144        if (udbg_uart_in(UART_MCR) & 0x80)
 145                prescaler = 4;
 146        else
 147                prescaler = 1;
 148
 149        /* restore the LCR */
 150        udbg_uart_out(UART_LCR, old_lcr);
 151
 152        /* calculate speed */
 153        speed = (clock / prescaler) / (divisor * 16);
 154
 155        /* sanity check */
 156        if (speed > (clock / 16))
 157                speed = 9600;
 158
 159        return speed;
 160}
 161
 162static union {
 163        unsigned char __iomem *mmio_base;
 164        unsigned long pio_base;
 165} udbg_uart;
 166
 167static unsigned int udbg_uart_stride = 1;
 168
 169static u8 udbg_uart_in_pio(unsigned int reg)
 170{
 171        return inb(udbg_uart.pio_base + (reg * udbg_uart_stride));
 172}
 173
 174static void udbg_uart_out_pio(unsigned int reg, u8 data)
 175{
 176        outb(data, udbg_uart.pio_base + (reg * udbg_uart_stride));
 177}
 178
 179void udbg_uart_init_pio(unsigned long port, unsigned int stride)
 180{
 181        if (!port)
 182                return;
 183        udbg_uart.pio_base = port;
 184        udbg_uart_stride = stride;
 185        udbg_uart_in = udbg_uart_in_pio;
 186        udbg_uart_out = udbg_uart_out_pio;
 187        udbg_use_uart();
 188}
 189
 190static u8 udbg_uart_in_mmio(unsigned int reg)
 191{
 192        return in_8(udbg_uart.mmio_base + (reg * udbg_uart_stride));
 193}
 194
 195static void udbg_uart_out_mmio(unsigned int reg, u8 data)
 196{
 197        out_8(udbg_uart.mmio_base + (reg * udbg_uart_stride), data);
 198}
 199
 200
 201void udbg_uart_init_mmio(void __iomem *addr, unsigned int stride)
 202{
 203        if (!addr)
 204                return;
 205        udbg_uart.mmio_base = addr;
 206        udbg_uart_stride = stride;
 207        udbg_uart_in = udbg_uart_in_mmio;
 208        udbg_uart_out = udbg_uart_out_mmio;
 209        udbg_use_uart();
 210}
 211
 212#ifdef CONFIG_PPC_MAPLE
 213
 214#define UDBG_UART_MAPLE_ADDR    ((void __iomem *)0xf40003f8)
 215
 216static u8 udbg_uart_in_maple(unsigned int reg)
 217{
 218        return real_readb(UDBG_UART_MAPLE_ADDR + reg);
 219}
 220
 221static void udbg_uart_out_maple(unsigned int reg, u8 val)
 222{
 223        real_writeb(val, UDBG_UART_MAPLE_ADDR + reg);
 224}
 225
 226void __init udbg_init_maple_realmode(void)
 227{
 228        udbg_uart_in = udbg_uart_in_maple;
 229        udbg_uart_out = udbg_uart_out_maple;
 230        udbg_use_uart();
 231}
 232
 233#endif /* CONFIG_PPC_MAPLE */
 234
 235#ifdef CONFIG_PPC_PASEMI
 236
 237#define UDBG_UART_PAS_ADDR      ((void __iomem *)0xfcff03f8UL)
 238
 239static u8 udbg_uart_in_pas(unsigned int reg)
 240{
 241        return real_205_readb(UDBG_UART_PAS_ADDR + reg);
 242}
 243
 244static void udbg_uart_out_pas(unsigned int reg, u8 val)
 245{
 246        real_205_writeb(val, UDBG_UART_PAS_ADDR + reg);
 247}
 248
 249void __init udbg_init_pas_realmode(void)
 250{
 251        udbg_uart_in = udbg_uart_in_pas;
 252        udbg_uart_out = udbg_uart_out_pas;
 253        udbg_use_uart();
 254}
 255
 256#endif /* CONFIG_PPC_PASEMI */
 257
 258#ifdef CONFIG_PPC_EARLY_DEBUG_44x
 259
 260#include <platforms/44x/44x.h>
 261
 262static u8 udbg_uart_in_44x_as1(unsigned int reg)
 263{
 264        return as1_readb((void __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR + reg);
 265}
 266
 267static void udbg_uart_out_44x_as1(unsigned int reg, u8 val)
 268{
 269        as1_writeb(val, (void __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR + reg);
 270}
 271
 272void __init udbg_init_44x_as1(void)
 273{
 274        udbg_uart_in = udbg_uart_in_44x_as1;
 275        udbg_uart_out = udbg_uart_out_44x_as1;
 276        udbg_use_uart();
 277}
 278
 279#endif /* CONFIG_PPC_EARLY_DEBUG_44x */
 280
 281#ifdef CONFIG_PPC_EARLY_DEBUG_40x
 282
 283static u8 udbg_uart_in_40x(unsigned int reg)
 284{
 285        return real_readb((void __iomem *)CONFIG_PPC_EARLY_DEBUG_40x_PHYSADDR
 286                          + reg);
 287}
 288
 289static void udbg_uart_out_40x(unsigned int reg, u8 val)
 290{
 291        real_writeb(val, (void __iomem *)CONFIG_PPC_EARLY_DEBUG_40x_PHYSADDR
 292                    + reg);
 293}
 294
 295void __init udbg_init_40x_realmode(void)
 296{
 297        udbg_uart_in = udbg_uart_in_40x;
 298        udbg_uart_out = udbg_uart_out_40x;
 299        udbg_use_uart();
 300}
 301
 302#endif /* CONFIG_PPC_EARLY_DEBUG_40x */
 303