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 15 extern u8 real_readb(volatile u8 __iomem *addr); 16 extern void real_writeb(u8 data, volatile u8 __iomem *addr); 17 extern u8 real_205_readb(volatile u8 __iomem *addr); 18 extern void real_205_writeb(u8 data, volatile u8 __iomem *addr); 19 20 struct 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 49 static volatile struct NS16550 __iomem *udbg_comport; 50 51 static 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 62 static 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 73 static 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 83 void 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 116 unsigned 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 152 void 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 163 void __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 174 void 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 185 void udbg_init_pas_realmode(void) 186 { 187 udbg_comport = (volatile struct NS16550 __iomem *)0xfcff03f8; 188 189 udbg_putc = udbg_pas_real_putc; 190 udbg_getc = NULL; 191 udbg_getc_poll = NULL; 192 } 193 #endif /* CONFIG_PPC_MAPLE */ 194