linux/arch/powerpc/kernel/udbg_16550.c
<<
>>
Prefs
   1/*
   2 * udbg for NS16550 compatable 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
  15extern u8 real_readb(volatile u8 __iomem  *addr);
  16extern void real_writeb(u8 data, volatile u8 __iomem *addr);
  17extern u8 real_205_readb(volatile u8 __iomem  *addr);
  18extern void real_205_writeb(u8 data, volatile u8 __iomem *addr);
  19
  20struct NS16550 {
  21        /* this struct must be packed */
  22        unsigned char rbr;  /* 0 */
  23        unsigned char ier;  /* 1 */
  24        unsigned char fcr;  /* 2 */
  25        unsigned char lcr;  /* 3 */
  26        unsigned char mcr;  /* 4 */
  27        unsigned char lsr;  /* 5 */
  28        unsigned char msr;  /* 6 */
  29        unsigned char scr;  /* 7 */
  30};
  31
  32#define thr rbr
  33#define iir fcr
  34#define dll rbr
  35#define dlm ier
  36#define dlab lcr
  37
  38#define LSR_DR   0x01  /* Data ready */
  39#define LSR_OE   0x02  /* Overrun */
  40#define LSR_PE   0x04  /* Parity error */
  41#define LSR_FE   0x08  /* Framing error */
  42#define LSR_BI   0x10  /* Break */
  43#define LSR_THRE 0x20  /* Xmit holding register empty */
  44#define LSR_TEMT 0x40  /* Xmitter empty */
  45#define LSR_ERR  0x80  /* Error */
  46
  47#define LCR_DLAB 0x80
  48
  49static struct NS16550 __iomem *udbg_comport;
  50
  51static void udbg_550_flush(void)
  52{
  53        if (udbg_comport) {
  54                while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0)
  55                        /* wait for idle */;
  56        }
  57}
  58
  59static void udbg_550_putc(char c)
  60{
  61        if (udbg_comport) {
  62                if (c == '\n')
  63                        udbg_550_putc('\r');
  64                udbg_550_flush();
  65                out_8(&udbg_comport->thr, c);
  66        }
  67}
  68
  69static int udbg_550_getc_poll(void)
  70{
  71        if (udbg_comport) {
  72                if ((in_8(&udbg_comport->lsr) & LSR_DR) != 0)
  73                        return in_8(&udbg_comport->rbr);
  74                else
  75                        return -1;
  76        }
  77        return -1;
  78}
  79
  80static int udbg_550_getc(void)
  81{
  82        if (udbg_comport) {
  83                while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0)
  84                        /* wait for char */;
  85                return in_8(&udbg_comport->rbr);
  86        }
  87        return -1;
  88}
  89
  90void udbg_init_uart(void __iomem *comport, unsigned int speed,
  91                    unsigned int clock)
  92{
  93        unsigned int dll, base_bauds;
  94
  95        if (clock == 0)
  96                clock = 1843200;
  97        if (speed == 0)
  98                speed = 9600;
  99
 100        base_bauds = clock / 16;
 101        dll = base_bauds / speed;
 102
 103        if (comport) {
 104                udbg_comport = (struct NS16550 __iomem *)comport;
 105                out_8(&udbg_comport->lcr, 0x00);
 106                out_8(&udbg_comport->ier, 0xff);
 107                out_8(&udbg_comport->ier, 0x00);
 108                out_8(&udbg_comport->lcr, LCR_DLAB);
 109                out_8(&udbg_comport->dll, dll & 0xff);
 110                out_8(&udbg_comport->dlm, dll >> 8);
 111                /* 8 data, 1 stop, no parity */
 112                out_8(&udbg_comport->lcr, 0x03);
 113                /* RTS/DTR */
 114                out_8(&udbg_comport->mcr, 0x03);
 115                /* Clear & enable FIFOs */
 116                out_8(&udbg_comport->fcr ,0x07);
 117                udbg_putc = udbg_550_putc;
 118                udbg_flush = udbg_550_flush;
 119                udbg_getc = udbg_550_getc;
 120                udbg_getc_poll = udbg_550_getc_poll;
 121        }
 122}
 123
 124unsigned int udbg_probe_uart_speed(void __iomem *comport, unsigned int clock)
 125{
 126        unsigned int dll, dlm, divisor, prescaler, speed;
 127        u8 old_lcr;
 128        struct NS16550 __iomem *port = comport;
 129
 130        old_lcr = in_8(&port->lcr);
 131
 132        /* select divisor latch registers.  */
 133        out_8(&port->lcr, LCR_DLAB);
 134
 135        /* now, read the divisor */
 136        dll = in_8(&port->dll);
 137        dlm = in_8(&port->dlm);
 138        divisor = dlm << 8 | dll;
 139
 140        /* check prescaling */
 141        if (in_8(&port->mcr) & 0x80)
 142                prescaler = 4;
 143        else
 144                prescaler = 1;
 145
 146        /* restore the LCR */
 147        out_8(&port->lcr, old_lcr);
 148
 149        /* calculate speed */
 150        speed = (clock / prescaler) / (divisor * 16);
 151
 152        /* sanity check */
 153        if (speed > (clock / 16))
 154                speed = 9600;
 155
 156        return speed;
 157}
 158
 159#ifdef CONFIG_PPC_MAPLE
 160void udbg_maple_real_flush(void)
 161{
 162        if (udbg_comport) {
 163                while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
 164                        /* wait for idle */;
 165        }
 166}
 167
 168void udbg_maple_real_putc(char c)
 169{
 170        if (udbg_comport) {
 171                if (c == '\n')
 172                        udbg_maple_real_putc('\r');
 173                udbg_maple_real_flush();
 174                real_writeb(c, &udbg_comport->thr); eieio();
 175        }
 176}
 177
 178void __init udbg_init_maple_realmode(void)
 179{
 180        udbg_comport = (struct NS16550 __iomem *)0xf40003f8;
 181
 182        udbg_putc = udbg_maple_real_putc;
 183        udbg_flush = udbg_maple_real_flush;
 184        udbg_getc = NULL;
 185        udbg_getc_poll = NULL;
 186}
 187#endif /* CONFIG_PPC_MAPLE */
 188
 189#ifdef CONFIG_PPC_PASEMI
 190void udbg_pas_real_flush(void)
 191{
 192        if (udbg_comport) {
 193                while ((real_205_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
 194                        /* wait for idle */;
 195        }
 196}
 197
 198void udbg_pas_real_putc(char c)
 199{
 200        if (udbg_comport) {
 201                if (c == '\n')
 202                        udbg_pas_real_putc('\r');
 203                udbg_pas_real_flush();
 204                real_205_writeb(c, &udbg_comport->thr); eieio();
 205        }
 206}
 207
 208void udbg_init_pas_realmode(void)
 209{
 210        udbg_comport = (struct NS16550 __iomem *)0xfcff03f8UL;
 211
 212        udbg_putc = udbg_pas_real_putc;
 213        udbg_flush = udbg_pas_real_flush;
 214        udbg_getc = NULL;
 215        udbg_getc_poll = NULL;
 216}
 217#endif /* CONFIG_PPC_MAPLE */
 218
 219#ifdef CONFIG_PPC_EARLY_DEBUG_44x
 220#include <platforms/44x/44x.h>
 221
 222static void udbg_44x_as1_flush(void)
 223{
 224        if (udbg_comport) {
 225                while ((as1_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
 226                        /* wait for idle */;
 227        }
 228}
 229
 230static void udbg_44x_as1_putc(char c)
 231{
 232        if (udbg_comport) {
 233                if (c == '\n')
 234                        udbg_44x_as1_putc('\r');
 235                udbg_44x_as1_flush();
 236                as1_writeb(c, &udbg_comport->thr); eieio();
 237        }
 238}
 239
 240static int udbg_44x_as1_getc(void)
 241{
 242        if (udbg_comport) {
 243                while ((as1_readb(&udbg_comport->lsr) & LSR_DR) == 0)
 244                        ; /* wait for char */
 245                return as1_readb(&udbg_comport->rbr);
 246        }
 247        return -1;
 248}
 249
 250void __init udbg_init_44x_as1(void)
 251{
 252        udbg_comport =
 253                (struct NS16550 __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR;
 254
 255        udbg_putc = udbg_44x_as1_putc;
 256        udbg_flush = udbg_44x_as1_flush;
 257        udbg_getc = udbg_44x_as1_getc;
 258}
 259#endif /* CONFIG_PPC_EARLY_DEBUG_44x */
 260
 261#ifdef CONFIG_PPC_EARLY_DEBUG_40x
 262static void udbg_40x_real_flush(void)
 263{
 264        if (udbg_comport) {
 265                while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
 266                        /* wait for idle */;
 267        }
 268}
 269
 270static void udbg_40x_real_putc(char c)
 271{
 272        if (udbg_comport) {
 273                if (c == '\n')
 274                        udbg_40x_real_putc('\r');
 275                udbg_40x_real_flush();
 276                real_writeb(c, &udbg_comport->thr); eieio();
 277        }
 278}
 279
 280static int udbg_40x_real_getc(void)
 281{
 282        if (udbg_comport) {
 283                while ((real_readb(&udbg_comport->lsr) & LSR_DR) == 0)
 284                        ; /* wait for char */
 285                return real_readb(&udbg_comport->rbr);
 286        }
 287        return -1;
 288}
 289
 290void __init udbg_init_40x_realmode(void)
 291{
 292        udbg_comport = (struct NS16550 __iomem *)
 293                CONFIG_PPC_EARLY_DEBUG_40x_PHYSADDR;
 294
 295        udbg_putc = udbg_40x_real_putc;
 296        udbg_flush = udbg_40x_real_flush;
 297        udbg_getc = udbg_40x_real_getc;
 298        udbg_getc_poll = NULL;
 299}
 300#endif /* CONFIG_PPC_EARLY_DEBUG_40x */
 301