1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * udbg for NS16550 compatible serial ports 4 * 5 * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp 6 */ 7 #include <linux/types.h> 8 #include <asm/udbg.h> 9 #include <asm/io.h> 10 #include <asm/reg_a2.h> 11 #include <asm/early_ioremap.h> 12 13 extern u8 real_readb(volatile u8 __iomem *addr); 14 extern void real_writeb(u8 data, volatile u8 __iomem *addr); 15 extern u8 real_205_readb(volatile u8 __iomem *addr); 16 extern void real_205_writeb(u8 data, volatile u8 __iomem *addr); 17 18 #define UART_RBR 0 19 #define UART_IER 1 20 #define UART_FCR 2 21 #define UART_LCR 3 22 #define UART_MCR 4 23 #define UART_LSR 5 24 #define UART_MSR 6 25 #define UART_SCR 7 26 #define UART_THR UART_RBR 27 #define UART_IIR UART_FCR 28 #define UART_DLL UART_RBR 29 #define UART_DLM UART_IER 30 #define UART_DLAB UART_LCR 31 32 #define LSR_DR 0x01 /* Data ready */ 33 #define LSR_OE 0x02 /* Overrun */ 34 #define LSR_PE 0x04 /* Parity error */ 35 #define LSR_FE 0x08 /* Framing error */ 36 #define LSR_BI 0x10 /* Break */ 37 #define LSR_THRE 0x20 /* Xmit holding register empty */ 38 #define LSR_TEMT 0x40 /* Xmitter empty */ 39 #define LSR_ERR 0x80 /* Error */ 40 41 #define LCR_DLAB 0x80 42 43 static u8 (*udbg_uart_in)(unsigned int reg); 44 static void (*udbg_uart_out)(unsigned int reg, u8 data); 45 46 static void udbg_uart_flush(void) 47 { 48 if (!udbg_uart_in) 49 return; 50 51 /* wait for idle */ 52 while ((udbg_uart_in(UART_LSR) & LSR_THRE) == 0) 53 cpu_relax(); 54 } 55 56 static void udbg_uart_putc(char c) 57 { 58 if (!udbg_uart_out) 59 return; 60 61 if (c == '\n') 62 udbg_uart_putc('\r'); 63 udbg_uart_flush(); 64 udbg_uart_out(UART_THR, c); 65 } 66 67 static int udbg_uart_getc_poll(void) 68 { 69 if (!udbg_uart_in) 70 return -1; 71 72 if (!(udbg_uart_in(UART_LSR) & LSR_DR)) 73 return udbg_uart_in(UART_RBR); 74 75 return -1; 76 } 77 78 static int udbg_uart_getc(void) 79 { 80 if (!udbg_uart_in) 81 return -1; 82 /* wait for char */ 83 while (!(udbg_uart_in(UART_LSR) & LSR_DR)) 84 cpu_relax(); 85 return udbg_uart_in(UART_RBR); 86 } 87 88 static void __init udbg_use_uart(void) 89 { 90 udbg_putc = udbg_uart_putc; 91 udbg_flush = udbg_uart_flush; 92 udbg_getc = udbg_uart_getc; 93 udbg_getc_poll = udbg_uart_getc_poll; 94 } 95 96 void __init udbg_uart_setup(unsigned int speed, unsigned int clock) 97 { 98 unsigned int dll, base_bauds; 99 100 if (!udbg_uart_out) 101 return; 102 103 if (clock == 0) 104 clock = 1843200; 105 if (speed == 0) 106 speed = 9600; 107 108 base_bauds = clock / 16; 109 dll = base_bauds / speed; 110 111 udbg_uart_out(UART_LCR, 0x00); 112 udbg_uart_out(UART_IER, 0xff); 113 udbg_uart_out(UART_IER, 0x00); 114 udbg_uart_out(UART_LCR, LCR_DLAB); 115 udbg_uart_out(UART_DLL, dll & 0xff); 116 udbg_uart_out(UART_DLM, dll >> 8); 117 /* 8 data, 1 stop, no parity */ 118 udbg_uart_out(UART_LCR, 0x3); 119 /* RTS/DTR */ 120 udbg_uart_out(UART_MCR, 0x3); 121 /* Clear & enable FIFOs */ 122 udbg_uart_out(UART_FCR, 0x7); 123 } 124 125 unsigned int __init udbg_probe_uart_speed(unsigned int clock) 126 { 127 unsigned int dll, dlm, divisor, prescaler, speed; 128 u8 old_lcr; 129 130 old_lcr = udbg_uart_in(UART_LCR); 131 132 /* select divisor latch registers. */ 133 udbg_uart_out(UART_LCR, old_lcr | LCR_DLAB); 134 135 /* now, read the divisor */ 136 dll = udbg_uart_in(UART_DLL); 137 dlm = udbg_uart_in(UART_DLM); 138 divisor = dlm << 8 | dll; 139 140 /* check prescaling */ 141 if (udbg_uart_in(UART_MCR) & 0x80) 142 prescaler = 4; 143 else 144 prescaler = 1; 145 146 /* restore the LCR */ 147 udbg_uart_out(UART_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 static union { 160 unsigned char __iomem *mmio_base; 161 unsigned long pio_base; 162 } udbg_uart; 163 164 static unsigned int udbg_uart_stride = 1; 165 166 static u8 udbg_uart_in_pio(unsigned int reg) 167 { 168 return inb(udbg_uart.pio_base + (reg * udbg_uart_stride)); 169 } 170 171 static void udbg_uart_out_pio(unsigned int reg, u8 data) 172 { 173 outb(data, udbg_uart.pio_base + (reg * udbg_uart_stride)); 174 } 175 176 void __init udbg_uart_init_pio(unsigned long port, unsigned int stride) 177 { 178 if (!port) 179 return; 180 udbg_uart.pio_base = port; 181 udbg_uart_stride = stride; 182 udbg_uart_in = udbg_uart_in_pio; 183 udbg_uart_out = udbg_uart_out_pio; 184 udbg_use_uart(); 185 } 186 187 static u8 udbg_uart_in_mmio(unsigned int reg) 188 { 189 return in_8(udbg_uart.mmio_base + (reg * udbg_uart_stride)); 190 } 191 192 static void udbg_uart_out_mmio(unsigned int reg, u8 data) 193 { 194 out_8(udbg_uart.mmio_base + (reg * udbg_uart_stride), data); 195 } 196 197 198 void __init udbg_uart_init_mmio(void __iomem *addr, unsigned int stride) 199 { 200 if (!addr) 201 return; 202 udbg_uart.mmio_base = addr; 203 udbg_uart_stride = stride; 204 udbg_uart_in = udbg_uart_in_mmio; 205 udbg_uart_out = udbg_uart_out_mmio; 206 udbg_use_uart(); 207 } 208 209 #ifdef CONFIG_PPC_MAPLE 210 211 #define UDBG_UART_MAPLE_ADDR ((void __iomem *)0xf40003f8) 212 213 static u8 udbg_uart_in_maple(unsigned int reg) 214 { 215 return real_readb(UDBG_UART_MAPLE_ADDR + reg); 216 } 217 218 static void udbg_uart_out_maple(unsigned int reg, u8 val) 219 { 220 real_writeb(val, UDBG_UART_MAPLE_ADDR + reg); 221 } 222 223 void __init udbg_init_maple_realmode(void) 224 { 225 udbg_uart_in = udbg_uart_in_maple; 226 udbg_uart_out = udbg_uart_out_maple; 227 udbg_use_uart(); 228 } 229 230 #endif /* CONFIG_PPC_MAPLE */ 231 232 #ifdef CONFIG_PPC_PASEMI 233 234 #define UDBG_UART_PAS_ADDR ((void __iomem *)0xfcff03f8UL) 235 236 static u8 udbg_uart_in_pas(unsigned int reg) 237 { 238 return real_205_readb(UDBG_UART_PAS_ADDR + reg); 239 } 240 241 static void udbg_uart_out_pas(unsigned int reg, u8 val) 242 { 243 real_205_writeb(val, UDBG_UART_PAS_ADDR + reg); 244 } 245 246 void __init udbg_init_pas_realmode(void) 247 { 248 udbg_uart_in = udbg_uart_in_pas; 249 udbg_uart_out = udbg_uart_out_pas; 250 udbg_use_uart(); 251 } 252 253 #endif /* CONFIG_PPC_PASEMI */ 254 255 #ifdef CONFIG_PPC_EARLY_DEBUG_44x 256 257 #include <platforms/44x/44x.h> 258 259 static u8 udbg_uart_in_44x_as1(unsigned int reg) 260 { 261 return as1_readb((void __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR + reg); 262 } 263 264 static void udbg_uart_out_44x_as1(unsigned int reg, u8 val) 265 { 266 as1_writeb(val, (void __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR + reg); 267 } 268 269 void __init udbg_init_44x_as1(void) 270 { 271 udbg_uart_in = udbg_uart_in_44x_as1; 272 udbg_uart_out = udbg_uart_out_44x_as1; 273 udbg_use_uart(); 274 } 275 276 #endif /* CONFIG_PPC_EARLY_DEBUG_44x */ 277 278 #ifdef CONFIG_PPC_EARLY_DEBUG_40x 279 280 static u8 udbg_uart_in_40x(unsigned int reg) 281 { 282 return real_readb((void __iomem *)CONFIG_PPC_EARLY_DEBUG_40x_PHYSADDR 283 + reg); 284 } 285 286 static void udbg_uart_out_40x(unsigned int reg, u8 val) 287 { 288 real_writeb(val, (void __iomem *)CONFIG_PPC_EARLY_DEBUG_40x_PHYSADDR 289 + reg); 290 } 291 292 void __init udbg_init_40x_realmode(void) 293 { 294 udbg_uart_in = udbg_uart_in_40x; 295 udbg_uart_out = udbg_uart_out_40x; 296 udbg_use_uart(); 297 } 298 299 #endif /* CONFIG_PPC_EARLY_DEBUG_40x */ 300 301 #ifdef CONFIG_PPC_EARLY_DEBUG_16550 302 303 static void __iomem *udbg_uart_early_addr; 304 305 void __init udbg_init_debug_16550(void) 306 { 307 udbg_uart_early_addr = early_ioremap(CONFIG_PPC_EARLY_DEBUG_16550_PHYSADDR, 0x1000); 308 udbg_uart_init_mmio(udbg_uart_early_addr, CONFIG_PPC_EARLY_DEBUG_16550_STRIDE); 309 } 310 311 static int __init udbg_init_debug_16550_ioremap(void) 312 { 313 void __iomem *addr; 314 315 if (!udbg_uart_early_addr) 316 return 0; 317 318 addr = ioremap(CONFIG_PPC_EARLY_DEBUG_16550_PHYSADDR, 0x1000); 319 if (WARN_ON(!addr)) 320 return -ENOMEM; 321 322 udbg_uart_init_mmio(addr, CONFIG_PPC_EARLY_DEBUG_16550_STRIDE); 323 early_iounmap(udbg_uart_early_addr, 0x1000); 324 udbg_uart_early_addr = NULL; 325 326 return 0; 327 } 328 329 early_initcall(udbg_init_debug_16550_ioremap); 330 331 #endif /* CONFIG_PPC_EARLY_DEBUG_16550 */ 332