| /* | |
| * udbg for for NS16550 compatable serial ports | |
| * | |
| * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp | |
| * | |
| * This program is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU General Public License | |
| * as published by the Free Software Foundation; either version | |
| * 2 of the License, or (at your option) any later version. | |
| */ | |
| #include <linux/types.h> | |
| #include <asm/udbg.h> | |
| #include <asm/io.h> | |
| extern u8 real_readb(volatile u8 __iomem *addr); | |
| extern void real_writeb(u8 data, volatile u8 __iomem *addr); | |
| struct NS16550 { | |
| /* this struct must be packed */ | |
| unsigned char rbr; /* 0 */ | |
| unsigned char ier; /* 1 */ | |
| unsigned char fcr; /* 2 */ | |
| unsigned char lcr; /* 3 */ | |
| unsigned char mcr; /* 4 */ | |
| unsigned char lsr; /* 5 */ | |
| unsigned char msr; /* 6 */ | |
| unsigned char scr; /* 7 */ | |
| }; | |
| #define thr rbr | |
| #define iir fcr | |
| #define dll rbr | |
| #define dlm ier | |
| #define dlab lcr | |
| #define LSR_DR 0x01 /* Data ready */ | |
| #define LSR_OE 0x02 /* Overrun */ | |
| #define LSR_PE 0x04 /* Parity error */ | |
| #define LSR_FE 0x08 /* Framing error */ | |
| #define LSR_BI 0x10 /* Break */ | |
| #define LSR_THRE 0x20 /* Xmit holding register empty */ | |
| #define LSR_TEMT 0x40 /* Xmitter empty */ | |
| #define LSR_ERR 0x80 /* Error */ | |
| #define LCR_DLAB 0x80 | |
| static volatile struct NS16550 __iomem *udbg_comport; | |
| static void udbg_550_putc(char c) | |
| { | |
| if (udbg_comport) { | |
| while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0) | |
| /* wait for idle */; | |
| out_8(&udbg_comport->thr, c); | |
| if (c == '\n') | |
| udbg_550_putc('\r'); | |
| } | |
| } | |
| static int udbg_550_getc_poll(void) | |
| { | |
| if (udbg_comport) { | |
| if ((in_8(&udbg_comport->lsr) & LSR_DR) != 0) | |
| return in_8(&udbg_comport->rbr); | |
| else | |
| return -1; | |
| } | |
| return -1; | |
| } | |
| static int udbg_550_getc(void) | |
| { | |
| if (udbg_comport) { | |
| while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0) | |
| /* wait for char */; | |
| return in_8(&udbg_comport->rbr); | |
| } | |
| return -1; | |
| } | |
| void udbg_init_uart(void __iomem *comport, unsigned int speed, | |
| unsigned int clock) | |
| { | |
| unsigned int dll, base_bauds; | |
| if (clock == 0) | |
| clock = 1843200; | |
| if (speed == 0) | |
| speed = 9600; | |
| base_bauds = clock / 16; | |
| dll = base_bauds / speed; | |
| if (comport) { | |
| udbg_comport = (struct NS16550 __iomem *)comport; | |
| out_8(&udbg_comport->lcr, 0x00); | |
| out_8(&udbg_comport->ier, 0xff); | |
| out_8(&udbg_comport->ier, 0x00); | |
| out_8(&udbg_comport->lcr, LCR_DLAB); | |
| out_8(&udbg_comport->dll, dll & 0xff); | |
| out_8(&udbg_comport->dlm, dll >> 8); | |
| /* 8 data, 1 stop, no parity */ | |
| out_8(&udbg_comport->lcr, 0x03); | |
| /* RTS/DTR */ | |
| out_8(&udbg_comport->mcr, 0x03); | |
| /* Clear & enable FIFOs */ | |
| out_8(&udbg_comport->fcr ,0x07); | |
| udbg_putc = udbg_550_putc; | |
| udbg_getc = udbg_550_getc; | |
| udbg_getc_poll = udbg_550_getc_poll; | |
| } | |
| } | |
| unsigned int udbg_probe_uart_speed(void __iomem *comport, unsigned int clock) | |
| { | |
| unsigned int dll, dlm, divisor, prescaler, speed; | |
| u8 old_lcr; | |
| volatile struct NS16550 __iomem *port = comport; | |
| old_lcr = in_8(&port->lcr); | |
| /* select divisor latch registers. */ | |
| out_8(&port->lcr, LCR_DLAB); | |
| /* now, read the divisor */ | |
| dll = in_8(&port->dll); | |
| dlm = in_8(&port->dlm); | |
| divisor = dlm << 8 | dll; | |
| /* check prescaling */ | |
| if (in_8(&port->mcr) & 0x80) | |
| prescaler = 4; | |
| else | |
| prescaler = 1; | |
| /* restore the LCR */ | |
| out_8(&port->lcr, old_lcr); | |
| /* calculate speed */ | |
| speed = (clock / prescaler) / (divisor * 16); | |
| /* sanity check */ | |
| if (speed < 0 || speed > (clock / 16)) | |
| speed = 9600; | |
| return speed; | |
| } | |
| #ifdef CONFIG_PPC_MAPLE | |
| void udbg_maple_real_putc(char c) | |
| { | |
| if (udbg_comport) { | |
| while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0) | |
| /* wait for idle */; | |
| real_writeb(c, &udbg_comport->thr); eieio(); | |
| if (c == '\n') | |
| udbg_maple_real_putc('\r'); | |
| } | |
| } | |
| void __init udbg_init_maple_realmode(void) | |
| { | |
| udbg_comport = (volatile struct NS16550 __iomem *)0xf40003f8; | |
| udbg_putc = udbg_maple_real_putc; | |
| udbg_getc = NULL; | |
| udbg_getc_poll = NULL; | |
| } | |
| #endif /* CONFIG_PPC_MAPLE */ |