linux/arch/powerpc/kernel/udbg_16550.c
<<
>>
Prefs
   1/*
   2 * udbg for 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 volatile struct NS16550 __iomem *udbg_comport;
  50
  51static void udbg_550_putc(char c)
  52{
  53        if (udbg_comport) {
  54                while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0)
  55                        /* wait for idle */;
  56                out_8(&udbg_comport->thr, c);
  57                if (c == '\n')
  58                        udbg_550_putc('\r');
  59        }
  60}
  61
  62static int udbg_550_getc_poll(void)
  63{
  64        if (udbg_comport) {
  65                if ((in_8(&udbg_comport->lsr) & LSR_DR) != 0)
  66                        return in_8(&udbg_comport->rbr);
  67                else
  68                        return -1;
  69        }
  70        return -1;
  71}
  72
  73static int udbg_550_getc(void)
  74{
  75        if (udbg_comport) {
  76                while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0)
  77                        /* wait for char */;
  78                return in_8(&udbg_comport->rbr);
  79        }
  80        return -1;
  81}
  82
  83void udbg_init_uart(void __iomem *comport, unsigned int speed,
  84                    unsigned int clock)
  85{
  86        unsigned int dll, base_bauds;
  87
  88        if (clock == 0)
  89                clock = 1843200;
  90        if (speed == 0)
  91                speed = 9600;
  92
  93        base_bauds = clock / 16;
  94        dll = base_bauds / speed;
  95
  96        if (comport) {
  97                udbg_comport = (struct NS16550 __iomem *)comport;
  98                out_8(&udbg_comport->lcr, 0x00);
  99                out_8(&udbg_comport->ier, 0xff);
 100                out_8(&udbg_comport->ier, 0x00);
 101                out_8(&udbg_comport->lcr, LCR_DLAB);
 102                out_8(&udbg_comport->dll, dll & 0xff);
 103                out_8(&udbg_comport->dlm, dll >> 8);
 104                /* 8 data, 1 stop, no parity */
 105                out_8(&udbg_comport->lcr, 0x03);
 106                /* RTS/DTR */
 107                out_8(&udbg_comport->mcr, 0x03);
 108                /* Clear & enable FIFOs */
 109                out_8(&udbg_comport->fcr ,0x07);
 110                udbg_putc = udbg_550_putc;
 111                udbg_getc = udbg_550_getc;
 112                udbg_getc_poll = udbg_550_getc_poll;
 113        }
 114}
 115
 116unsigned int udbg_probe_uart_speed(void __iomem *comport, unsigned int clock)
 117{
 118        unsigned int dll, dlm, divisor, prescaler, speed;
 119        u8 old_lcr;
 120        volatile struct NS16550 __iomem *port = comport;
 121
 122        old_lcr = in_8(&port->lcr);
 123
 124        /* select divisor latch registers.  */
 125        out_8(&port->lcr, LCR_DLAB);
 126
 127        /* now, read the divisor */
 128        dll = in_8(&port->dll);
 129        dlm = in_8(&port->dlm);
 130        divisor = dlm << 8 | dll;
 131
 132        /* check prescaling */
 133        if (in_8(&port->mcr) & 0x80)
 134                prescaler = 4;
 135        else
 136                prescaler = 1;
 137
 138        /* restore the LCR */
 139        out_8(&port->lcr, old_lcr);
 140
 141        /* calculate speed */
 142        speed = (clock / prescaler) / (divisor * 16);
 143
 144        /* sanity check */
 145        if (speed < 0 || speed > (clock / 16))
 146                speed = 9600;
 147
 148        return speed;
 149}
 150
 151#ifdef CONFIG_PPC_MAPLE
 152void udbg_maple_real_putc(char c)
 153{
 154        if (udbg_comport) {
 155                while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
 156                        /* wait for idle */;
 157                real_writeb(c, &udbg_comport->thr); eieio();
 158                if (c == '\n')
 159                        udbg_maple_real_putc('\r');
 160        }
 161}
 162
 163void __init udbg_init_maple_realmode(void)
 164{
 165        udbg_comport = (volatile struct NS16550 __iomem *)0xf40003f8;
 166
 167        udbg_putc = udbg_maple_real_putc;
 168        udbg_getc = NULL;
 169        udbg_getc_poll = NULL;
 170}
 171#endif /* CONFIG_PPC_MAPLE */
 172
 173#ifdef CONFIG_PPC_PASEMI
 174void udbg_pas_real_putc(char c)
 175{
 176        if (udbg_comport) {
 177                while ((real_205_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
 178                        /* wait for idle */;
 179                real_205_writeb(c, &udbg_comport->thr); eieio();
 180                if (c == '\n')
 181                        udbg_pas_real_putc('\r');
 182        }
 183}
 184
 185void udbg_init_pas_realmode(void)
 186{
 187        udbg_comport = (volatile struct NS16550 __iomem *)0xfcff03f8UL;
 188
 189        udbg_putc = udbg_pas_real_putc;
 190        udbg_getc = NULL;
 191        udbg_getc_poll = NULL;
 192}
 193#endif /* CONFIG_PPC_MAPLE */
 194
 195#ifdef CONFIG_PPC_EARLY_DEBUG_44x
 196#include <platforms/44x/44x.h>
 197
 198static void udbg_44x_as1_putc(char c)
 199{
 200        if (udbg_comport) {
 201                while ((as1_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
 202                        /* wait for idle */;
 203                as1_writeb(c, &udbg_comport->thr); eieio();
 204                if (c == '\n')
 205                        udbg_44x_as1_putc('\r');
 206        }
 207}
 208
 209static int udbg_44x_as1_getc(void)
 210{
 211        if (udbg_comport) {
 212                while ((as1_readb(&udbg_comport->lsr) & LSR_DR) == 0)
 213                        ; /* wait for char */
 214                return as1_readb(&udbg_comport->rbr);
 215        }
 216        return -1;
 217}
 218
 219void __init udbg_init_44x_as1(void)
 220{
 221        udbg_comport =
 222                (volatile struct NS16550 __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR;
 223
 224        udbg_putc = udbg_44x_as1_putc;
 225        udbg_getc = udbg_44x_as1_getc;
 226}
 227#endif /* CONFIG_PPC_EARLY_DEBUG_44x */
 228