1 /* 2 * (C) Copyright 2000 3 * Rob Taylor, Flying Pig Systems. robt@flyingpig.com. 4 * 5 * (C) Copyright 2004 6 * ARM Ltd. 7 * Philippe Robin, <philippe.robin@arm.com> 8 * 9 * SPDX-License-Identifier: GPL-2.0+ 10 */ 11 12 /* Simple U-Boot driver for the PrimeCell PL010/PL011 UARTs */ 13 14 #include <common.h> 15 #include <dm.h> 16 #include <errno.h> 17 #include <watchdog.h> 18 #include <asm/io.h> 19 #include <serial.h> 20 #include <dm/platform_data/serial_pl01x.h> 21 #include <linux/compiler.h> 22 #include "serial_pl01x_internal.h" 23 24 #ifndef CONFIG_DM_SERIAL 25 26 static volatile unsigned char *const port[] = CONFIG_PL01x_PORTS; 27 static enum pl01x_type pl01x_type __attribute__ ((section(".data"))); 28 static struct pl01x_regs *base_regs __attribute__ ((section(".data"))); 29 #define NUM_PORTS (sizeof(port)/sizeof(port[0])) 30 31 DECLARE_GLOBAL_DATA_PTR; 32 #endif 33 34 static int pl01x_putc(struct pl01x_regs *regs, char c) 35 { 36 /* Wait until there is space in the FIFO */ 37 if (readl(®s->fr) & UART_PL01x_FR_TXFF) 38 return -EAGAIN; 39 40 /* Send the character */ 41 writel(c, ®s->dr); 42 43 return 0; 44 } 45 46 static int pl01x_getc(struct pl01x_regs *regs) 47 { 48 unsigned int data; 49 50 /* Wait until there is data in the FIFO */ 51 if (readl(®s->fr) & UART_PL01x_FR_RXFE) 52 return -EAGAIN; 53 54 data = readl(®s->dr); 55 56 /* Check for an error flag */ 57 if (data & 0xFFFFFF00) { 58 /* Clear the error */ 59 writel(0xFFFFFFFF, ®s->ecr); 60 return -1; 61 } 62 63 return (int) data; 64 } 65 66 static int pl01x_tstc(struct pl01x_regs *regs) 67 { 68 WATCHDOG_RESET(); 69 return !(readl(®s->fr) & UART_PL01x_FR_RXFE); 70 } 71 72 static int pl01x_generic_serial_init(struct pl01x_regs *regs, 73 enum pl01x_type type) 74 { 75 unsigned int lcr; 76 77 #ifdef CONFIG_PL011_SERIAL_FLUSH_ON_INIT 78 if (type == TYPE_PL011) { 79 /* Empty RX fifo if necessary */ 80 if (readl(®s->pl011_cr) & UART_PL011_CR_UARTEN) { 81 while (!(readl(®s->fr) & UART_PL01x_FR_RXFE)) 82 readl(®s->dr); 83 } 84 } 85 #endif 86 87 /* First, disable everything */ 88 writel(0, ®s->pl010_cr); 89 90 /* Set the UART to be 8 bits, 1 stop bit, no parity, fifo enabled */ 91 lcr = UART_PL011_LCRH_WLEN_8 | UART_PL011_LCRH_FEN; 92 writel(lcr, ®s->pl011_lcrh); 93 94 switch (type) { 95 case TYPE_PL010: 96 break; 97 case TYPE_PL011: { 98 #ifdef CONFIG_PL011_SERIAL_RLCR 99 int i; 100 101 /* 102 * Program receive line control register after waiting 103 * 10 bus cycles. Delay be writing to readonly register 104 * 10 times 105 */ 106 for (i = 0; i < 10; i++) 107 writel(lcr, ®s->fr); 108 109 writel(lcr, ®s->pl011_rlcr); 110 /* lcrh needs to be set again for change to be effective */ 111 writel(lcr, ®s->pl011_lcrh); 112 #endif 113 break; 114 } 115 default: 116 return -EINVAL; 117 } 118 119 return 0; 120 } 121 122 static int pl01x_generic_setbrg(struct pl01x_regs *regs, enum pl01x_type type, 123 int clock, int baudrate) 124 { 125 unsigned int lcr; 126 switch (type) { 127 case TYPE_PL010: { 128 unsigned int divisor; 129 130 switch (baudrate) { 131 case 9600: 132 divisor = UART_PL010_BAUD_9600; 133 break; 134 case 19200: 135 divisor = UART_PL010_BAUD_9600; 136 break; 137 case 38400: 138 divisor = UART_PL010_BAUD_38400; 139 break; 140 case 57600: 141 divisor = UART_PL010_BAUD_57600; 142 break; 143 case 115200: 144 divisor = UART_PL010_BAUD_115200; 145 break; 146 default: 147 divisor = UART_PL010_BAUD_38400; 148 } 149 150 writel((divisor & 0xf00) >> 8, ®s->pl010_lcrm); 151 writel(divisor & 0xff, ®s->pl010_lcrl); 152 153 /* Finally, enable the UART */ 154 writel(UART_PL010_CR_UARTEN, ®s->pl010_cr); 155 break; 156 } 157 case TYPE_PL011: { 158 unsigned int temp; 159 unsigned int divider; 160 unsigned int remainder; 161 unsigned int fraction; 162 163 /* 164 * Set baud rate 165 * 166 * IBRD = UART_CLK / (16 * BAUD_RATE) 167 * FBRD = RND((64 * MOD(UART_CLK,(16 * BAUD_RATE))) 168 * / (16 * BAUD_RATE)) 169 */ 170 temp = 16 * baudrate; 171 divider = clock / temp; 172 remainder = clock % temp; 173 temp = (8 * remainder) / baudrate; 174 fraction = (temp >> 1) + (temp & 1); 175 176 writel(divider, ®s->pl011_ibrd); 177 writel(fraction, ®s->pl011_fbrd); 178 179 /* 180 * Internal update of baud rate register require line 181 * control register write 182 */ 183 lcr = UART_PL011_LCRH_WLEN_8 | UART_PL011_LCRH_FEN; 184 writel(lcr, ®s->pl011_lcrh); 185 186 /* Finally, enable the UART */ 187 writel(UART_PL011_CR_UARTEN | UART_PL011_CR_TXE | 188 UART_PL011_CR_RXE | UART_PL011_CR_RTS, ®s->pl011_cr); 189 break; 190 } 191 default: 192 return -EINVAL; 193 } 194 195 return 0; 196 } 197 198 #ifndef CONFIG_DM_SERIAL 199 static void pl01x_serial_init_baud(int baudrate) 200 { 201 int clock = 0; 202 203 #if defined(CONFIG_PL010_SERIAL) 204 pl01x_type = TYPE_PL010; 205 #elif defined(CONFIG_PL011_SERIAL) 206 pl01x_type = TYPE_PL011; 207 clock = CONFIG_PL011_CLOCK; 208 #endif 209 base_regs = (struct pl01x_regs *)port[CONFIG_CONS_INDEX]; 210 211 pl01x_generic_serial_init(base_regs, pl01x_type); 212 pl01x_generic_setbrg(base_regs, pl01x_type, clock, baudrate); 213 } 214 215 /* 216 * Integrator AP has two UARTs, we use the first one, at 38400-8-N-1 217 * Integrator CP has two UARTs, use the first one, at 38400-8-N-1 218 * Versatile PB has four UARTs. 219 */ 220 int pl01x_serial_init(void) 221 { 222 pl01x_serial_init_baud(CONFIG_BAUDRATE); 223 224 return 0; 225 } 226 227 static void pl01x_serial_putc(const char c) 228 { 229 if (c == '\n') 230 while (pl01x_putc(base_regs, '\r') == -EAGAIN); 231 232 while (pl01x_putc(base_regs, c) == -EAGAIN); 233 } 234 235 static int pl01x_serial_getc(void) 236 { 237 while (1) { 238 int ch = pl01x_getc(base_regs); 239 240 if (ch == -EAGAIN) { 241 WATCHDOG_RESET(); 242 continue; 243 } 244 245 return ch; 246 } 247 } 248 249 static int pl01x_serial_tstc(void) 250 { 251 return pl01x_tstc(base_regs); 252 } 253 254 static void pl01x_serial_setbrg(void) 255 { 256 /* 257 * Flush FIFO and wait for non-busy before changing baudrate to avoid 258 * crap in console 259 */ 260 while (!(readl(&base_regs->fr) & UART_PL01x_FR_TXFE)) 261 WATCHDOG_RESET(); 262 while (readl(&base_regs->fr) & UART_PL01x_FR_BUSY) 263 WATCHDOG_RESET(); 264 pl01x_serial_init_baud(gd->baudrate); 265 } 266 267 static struct serial_device pl01x_serial_drv = { 268 .name = "pl01x_serial", 269 .start = pl01x_serial_init, 270 .stop = NULL, 271 .setbrg = pl01x_serial_setbrg, 272 .putc = pl01x_serial_putc, 273 .puts = default_serial_puts, 274 .getc = pl01x_serial_getc, 275 .tstc = pl01x_serial_tstc, 276 }; 277 278 void pl01x_serial_initialize(void) 279 { 280 serial_register(&pl01x_serial_drv); 281 } 282 283 __weak struct serial_device *default_serial_console(void) 284 { 285 return &pl01x_serial_drv; 286 } 287 288 #endif /* nCONFIG_DM_SERIAL */ 289 290 #ifdef CONFIG_DM_SERIAL 291 292 struct pl01x_priv { 293 struct pl01x_regs *regs; 294 enum pl01x_type type; 295 }; 296 297 static int pl01x_serial_setbrg(struct udevice *dev, int baudrate) 298 { 299 struct pl01x_serial_platdata *plat = dev_get_platdata(dev); 300 struct pl01x_priv *priv = dev_get_priv(dev); 301 302 pl01x_generic_setbrg(priv->regs, priv->type, plat->clock, baudrate); 303 304 return 0; 305 } 306 307 static int pl01x_serial_probe(struct udevice *dev) 308 { 309 struct pl01x_serial_platdata *plat = dev_get_platdata(dev); 310 struct pl01x_priv *priv = dev_get_priv(dev); 311 312 priv->regs = (struct pl01x_regs *)plat->base; 313 priv->type = plat->type; 314 return pl01x_generic_serial_init(priv->regs, priv->type); 315 } 316 317 static int pl01x_serial_getc(struct udevice *dev) 318 { 319 struct pl01x_priv *priv = dev_get_priv(dev); 320 321 return pl01x_getc(priv->regs); 322 } 323 324 static int pl01x_serial_putc(struct udevice *dev, const char ch) 325 { 326 struct pl01x_priv *priv = dev_get_priv(dev); 327 328 return pl01x_putc(priv->regs, ch); 329 } 330 331 static int pl01x_serial_pending(struct udevice *dev, bool input) 332 { 333 struct pl01x_priv *priv = dev_get_priv(dev); 334 unsigned int fr = readl(&priv->regs->fr); 335 336 if (input) 337 return pl01x_tstc(priv->regs); 338 else 339 return fr & UART_PL01x_FR_TXFF ? 0 : 1; 340 } 341 342 static const struct dm_serial_ops pl01x_serial_ops = { 343 .putc = pl01x_serial_putc, 344 .pending = pl01x_serial_pending, 345 .getc = pl01x_serial_getc, 346 .setbrg = pl01x_serial_setbrg, 347 }; 348 349 U_BOOT_DRIVER(serial_pl01x) = { 350 .name = "serial_pl01x", 351 .id = UCLASS_SERIAL, 352 .probe = pl01x_serial_probe, 353 .ops = &pl01x_serial_ops, 354 .flags = DM_FLAG_PRE_RELOC, 355 }; 356 357 #endif 358