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