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 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 struct NS16550 __iomem *udbg_comport; 50 51 static 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 59 static 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 69 static 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 80 static 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 90 void 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 124 unsigned 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 160 void 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 168 void 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 178 void __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 190 void 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 198 void 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 208 void 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 222 static 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 230 static 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 240 static 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 250 void __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 262 static 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 270 static 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 280 static 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 290 void __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