120c9226cSAndreas Engel /* 220c9226cSAndreas Engel * (C) Copyright 2000 320c9226cSAndreas Engel * Rob Taylor, Flying Pig Systems. robt@flyingpig.com. 420c9226cSAndreas Engel * 520c9226cSAndreas Engel * (C) Copyright 2004 620c9226cSAndreas Engel * ARM Ltd. 720c9226cSAndreas Engel * Philippe Robin, <philippe.robin@arm.com> 820c9226cSAndreas Engel * 91a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 1020c9226cSAndreas Engel */ 1120c9226cSAndreas Engel 1248d0192fSAndreas Engel /* Simple U-Boot driver for the PrimeCell PL010/PL011 UARTs */ 1320c9226cSAndreas Engel 1420c9226cSAndreas Engel #include <common.h> 15*aed2fbefSSimon Glass #include <errno.h> 1620c9226cSAndreas Engel #include <watchdog.h> 17249d5219SMatt Waddel #include <asm/io.h> 1839f61477SMarek Vasut #include <serial.h> 19*aed2fbefSSimon Glass #include <serial_pl01x.h> 2039f61477SMarek Vasut #include <linux/compiler.h> 21*aed2fbefSSimon Glass #include "serial_pl01x_internal.h" 2220c9226cSAndreas Engel 2320c9226cSAndreas Engel static volatile unsigned char *const port[] = CONFIG_PL01x_PORTS; 24*aed2fbefSSimon Glass static enum pl01x_type pl01x_type __attribute__ ((section(".data"))); 25*aed2fbefSSimon Glass static struct pl01x_regs *base_regs __attribute__ ((section(".data"))); 2620c9226cSAndreas Engel #define NUM_PORTS (sizeof(port)/sizeof(port[0])) 2720c9226cSAndreas Engel 28249d5219SMatt Waddel DECLARE_GLOBAL_DATA_PTR; 2920c9226cSAndreas Engel 30*aed2fbefSSimon Glass static int pl01x_putc(struct pl01x_regs *regs, char c) 3172d5e44cSRabin Vincent { 3220c9226cSAndreas Engel /* Wait until there is space in the FIFO */ 33*aed2fbefSSimon Glass if (readl(®s->fr) & UART_PL01x_FR_TXFF) 34*aed2fbefSSimon Glass return -EAGAIN; 3520c9226cSAndreas Engel 3620c9226cSAndreas Engel /* Send the character */ 3772d5e44cSRabin Vincent writel(c, ®s->dr); 38*aed2fbefSSimon Glass 39*aed2fbefSSimon Glass return 0; 4020c9226cSAndreas Engel } 4120c9226cSAndreas Engel 42*aed2fbefSSimon Glass static int pl01x_getc(struct pl01x_regs *regs) 4320c9226cSAndreas Engel { 4420c9226cSAndreas Engel unsigned int data; 4520c9226cSAndreas Engel 4620c9226cSAndreas Engel /* Wait until there is data in the FIFO */ 47*aed2fbefSSimon Glass if (readl(®s->fr) & UART_PL01x_FR_RXFE) 48*aed2fbefSSimon Glass return -EAGAIN; 4920c9226cSAndreas Engel 5072d5e44cSRabin Vincent data = readl(®s->dr); 5120c9226cSAndreas Engel 5220c9226cSAndreas Engel /* Check for an error flag */ 5320c9226cSAndreas Engel if (data & 0xFFFFFF00) { 5420c9226cSAndreas Engel /* Clear the error */ 5572d5e44cSRabin Vincent writel(0xFFFFFFFF, ®s->ecr); 5620c9226cSAndreas Engel return -1; 5720c9226cSAndreas Engel } 5820c9226cSAndreas Engel 5920c9226cSAndreas Engel return (int) data; 6020c9226cSAndreas Engel } 6120c9226cSAndreas Engel 62*aed2fbefSSimon Glass static int pl01x_tstc(struct pl01x_regs *regs) 6320c9226cSAndreas Engel { 6420c9226cSAndreas Engel WATCHDOG_RESET(); 6572d5e44cSRabin Vincent return !(readl(®s->fr) & UART_PL01x_FR_RXFE); 6620c9226cSAndreas Engel } 6739f61477SMarek Vasut 68*aed2fbefSSimon Glass static int pl01x_generic_serial_init(struct pl01x_regs *regs, 69*aed2fbefSSimon Glass enum pl01x_type type) 70*aed2fbefSSimon Glass { 71*aed2fbefSSimon Glass unsigned int lcr; 72*aed2fbefSSimon Glass 73*aed2fbefSSimon Glass #ifdef CONFIG_PL011_SERIAL_FLUSH_ON_INIT 74*aed2fbefSSimon Glass if (type == TYPE_PL011) { 75*aed2fbefSSimon Glass /* Empty RX fifo if necessary */ 76*aed2fbefSSimon Glass if (readl(®s->pl011_cr) & UART_PL011_CR_UARTEN) { 77*aed2fbefSSimon Glass while (!(readl(®s->fr) & UART_PL01x_FR_RXFE)) 78*aed2fbefSSimon Glass readl(®s->dr); 79*aed2fbefSSimon Glass } 80*aed2fbefSSimon Glass } 81*aed2fbefSSimon Glass #endif 82*aed2fbefSSimon Glass 83*aed2fbefSSimon Glass /* First, disable everything */ 84*aed2fbefSSimon Glass writel(0, ®s->pl010_cr); 85*aed2fbefSSimon Glass 86*aed2fbefSSimon Glass /* Set the UART to be 8 bits, 1 stop bit, no parity, fifo enabled */ 87*aed2fbefSSimon Glass lcr = UART_PL011_LCRH_WLEN_8 | UART_PL011_LCRH_FEN; 88*aed2fbefSSimon Glass writel(lcr, ®s->pl011_lcrh); 89*aed2fbefSSimon Glass 90*aed2fbefSSimon Glass switch (type) { 91*aed2fbefSSimon Glass case TYPE_PL010: 92*aed2fbefSSimon Glass break; 93*aed2fbefSSimon Glass case TYPE_PL011: { 94*aed2fbefSSimon Glass #ifdef CONFIG_PL011_SERIAL_RLCR 95*aed2fbefSSimon Glass int i; 96*aed2fbefSSimon Glass 97*aed2fbefSSimon Glass /* 98*aed2fbefSSimon Glass * Program receive line control register after waiting 99*aed2fbefSSimon Glass * 10 bus cycles. Delay be writing to readonly register 100*aed2fbefSSimon Glass * 10 times 101*aed2fbefSSimon Glass */ 102*aed2fbefSSimon Glass for (i = 0; i < 10; i++) 103*aed2fbefSSimon Glass writel(lcr, ®s->fr); 104*aed2fbefSSimon Glass 105*aed2fbefSSimon Glass writel(lcr, ®s->pl011_rlcr); 106*aed2fbefSSimon Glass /* lcrh needs to be set again for change to be effective */ 107*aed2fbefSSimon Glass writel(lcr, ®s->pl011_lcrh); 108*aed2fbefSSimon Glass #endif 109*aed2fbefSSimon Glass break; 110*aed2fbefSSimon Glass } 111*aed2fbefSSimon Glass default: 112*aed2fbefSSimon Glass return -EINVAL; 113*aed2fbefSSimon Glass } 114*aed2fbefSSimon Glass 115*aed2fbefSSimon Glass return 0; 116*aed2fbefSSimon Glass } 117*aed2fbefSSimon Glass 118*aed2fbefSSimon Glass static int pl01x_generic_setbrg(struct pl01x_regs *regs, enum pl01x_type type, 119*aed2fbefSSimon Glass int clock, int baudrate) 120*aed2fbefSSimon Glass { 121*aed2fbefSSimon Glass switch (type) { 122*aed2fbefSSimon Glass case TYPE_PL010: { 123*aed2fbefSSimon Glass unsigned int divisor; 124*aed2fbefSSimon Glass 125*aed2fbefSSimon Glass switch (baudrate) { 126*aed2fbefSSimon Glass case 9600: 127*aed2fbefSSimon Glass divisor = UART_PL010_BAUD_9600; 128*aed2fbefSSimon Glass break; 129*aed2fbefSSimon Glass case 19200: 130*aed2fbefSSimon Glass divisor = UART_PL010_BAUD_9600; 131*aed2fbefSSimon Glass break; 132*aed2fbefSSimon Glass case 38400: 133*aed2fbefSSimon Glass divisor = UART_PL010_BAUD_38400; 134*aed2fbefSSimon Glass break; 135*aed2fbefSSimon Glass case 57600: 136*aed2fbefSSimon Glass divisor = UART_PL010_BAUD_57600; 137*aed2fbefSSimon Glass break; 138*aed2fbefSSimon Glass case 115200: 139*aed2fbefSSimon Glass divisor = UART_PL010_BAUD_115200; 140*aed2fbefSSimon Glass break; 141*aed2fbefSSimon Glass default: 142*aed2fbefSSimon Glass divisor = UART_PL010_BAUD_38400; 143*aed2fbefSSimon Glass } 144*aed2fbefSSimon Glass 145*aed2fbefSSimon Glass writel((divisor & 0xf00) >> 8, ®s->pl010_lcrm); 146*aed2fbefSSimon Glass writel(divisor & 0xff, ®s->pl010_lcrl); 147*aed2fbefSSimon Glass 148*aed2fbefSSimon Glass /* Finally, enable the UART */ 149*aed2fbefSSimon Glass writel(UART_PL010_CR_UARTEN, ®s->pl010_cr); 150*aed2fbefSSimon Glass break; 151*aed2fbefSSimon Glass } 152*aed2fbefSSimon Glass case TYPE_PL011: { 153*aed2fbefSSimon Glass unsigned int temp; 154*aed2fbefSSimon Glass unsigned int divider; 155*aed2fbefSSimon Glass unsigned int remainder; 156*aed2fbefSSimon Glass unsigned int fraction; 157*aed2fbefSSimon Glass 158*aed2fbefSSimon Glass /* 159*aed2fbefSSimon Glass * Set baud rate 160*aed2fbefSSimon Glass * 161*aed2fbefSSimon Glass * IBRD = UART_CLK / (16 * BAUD_RATE) 162*aed2fbefSSimon Glass * FBRD = RND((64 * MOD(UART_CLK,(16 * BAUD_RATE))) 163*aed2fbefSSimon Glass * / (16 * BAUD_RATE)) 164*aed2fbefSSimon Glass */ 165*aed2fbefSSimon Glass temp = 16 * baudrate; 166*aed2fbefSSimon Glass divider = clock / temp; 167*aed2fbefSSimon Glass remainder = clock % temp; 168*aed2fbefSSimon Glass temp = (8 * remainder) / baudrate; 169*aed2fbefSSimon Glass fraction = (temp >> 1) + (temp & 1); 170*aed2fbefSSimon Glass 171*aed2fbefSSimon Glass writel(divider, ®s->pl011_ibrd); 172*aed2fbefSSimon Glass writel(fraction, ®s->pl011_fbrd); 173*aed2fbefSSimon Glass 174*aed2fbefSSimon Glass /* Finally, enable the UART */ 175*aed2fbefSSimon Glass writel(UART_PL011_CR_UARTEN | UART_PL011_CR_TXE | 176*aed2fbefSSimon Glass UART_PL011_CR_RXE | UART_PL011_CR_RTS, ®s->pl011_cr); 177*aed2fbefSSimon Glass break; 178*aed2fbefSSimon Glass } 179*aed2fbefSSimon Glass default: 180*aed2fbefSSimon Glass return -EINVAL; 181*aed2fbefSSimon Glass } 182*aed2fbefSSimon Glass 183*aed2fbefSSimon Glass return 0; 184*aed2fbefSSimon Glass } 185*aed2fbefSSimon Glass 186*aed2fbefSSimon Glass #ifndef CONFIG_DM_SERIAL 187*aed2fbefSSimon Glass static void pl01x_serial_init_baud(int baudrate) 188*aed2fbefSSimon Glass { 189*aed2fbefSSimon Glass int clock = 0; 190*aed2fbefSSimon Glass 191*aed2fbefSSimon Glass #if defined(CONFIG_PL010_SERIAL) 192*aed2fbefSSimon Glass pl01x_type = TYPE_PL010; 193*aed2fbefSSimon Glass #elif defined(CONFIG_PL011_SERIAL) 194*aed2fbefSSimon Glass pl01x_type = TYPE_PL011; 195*aed2fbefSSimon Glass clock = CONFIG_PL011_CLOCK; 196*aed2fbefSSimon Glass #endif 197*aed2fbefSSimon Glass base_regs = (struct pl01x_regs *)port[CONFIG_CONS_INDEX]; 198*aed2fbefSSimon Glass 199*aed2fbefSSimon Glass pl01x_generic_serial_init(base_regs, pl01x_type); 200*aed2fbefSSimon Glass pl01x_generic_setbrg(base_regs, TYPE_PL010, clock, baudrate); 201*aed2fbefSSimon Glass } 202*aed2fbefSSimon Glass 203*aed2fbefSSimon Glass /* 204*aed2fbefSSimon Glass * Integrator AP has two UARTs, we use the first one, at 38400-8-N-1 205*aed2fbefSSimon Glass * Integrator CP has two UARTs, use the first one, at 38400-8-N-1 206*aed2fbefSSimon Glass * Versatile PB has four UARTs. 207*aed2fbefSSimon Glass */ 208*aed2fbefSSimon Glass int pl01x_serial_init(void) 209*aed2fbefSSimon Glass { 210*aed2fbefSSimon Glass pl01x_serial_init_baud(CONFIG_BAUDRATE); 211*aed2fbefSSimon Glass 212*aed2fbefSSimon Glass return 0; 213*aed2fbefSSimon Glass } 214*aed2fbefSSimon Glass 215*aed2fbefSSimon Glass static void pl01x_serial_putc(const char c) 216*aed2fbefSSimon Glass { 217*aed2fbefSSimon Glass if (c == '\n') 218*aed2fbefSSimon Glass while (pl01x_putc(base_regs, '\r') == -EAGAIN); 219*aed2fbefSSimon Glass 220*aed2fbefSSimon Glass while (pl01x_putc(base_regs, c) == -EAGAIN); 221*aed2fbefSSimon Glass } 222*aed2fbefSSimon Glass 223*aed2fbefSSimon Glass static int pl01x_serial_getc(void) 224*aed2fbefSSimon Glass { 225*aed2fbefSSimon Glass while (1) { 226*aed2fbefSSimon Glass int ch = pl01x_getc(base_regs); 227*aed2fbefSSimon Glass 228*aed2fbefSSimon Glass if (ch == -EAGAIN) { 229*aed2fbefSSimon Glass WATCHDOG_RESET(); 230*aed2fbefSSimon Glass continue; 231*aed2fbefSSimon Glass } 232*aed2fbefSSimon Glass 233*aed2fbefSSimon Glass return ch; 234*aed2fbefSSimon Glass } 235*aed2fbefSSimon Glass } 236*aed2fbefSSimon Glass 237*aed2fbefSSimon Glass static int pl01x_serial_tstc(void) 238*aed2fbefSSimon Glass { 239*aed2fbefSSimon Glass return pl01x_tstc(base_regs); 240*aed2fbefSSimon Glass } 241*aed2fbefSSimon Glass 242*aed2fbefSSimon Glass static void pl01x_serial_setbrg(void) 243*aed2fbefSSimon Glass { 244*aed2fbefSSimon Glass /* 245*aed2fbefSSimon Glass * Flush FIFO and wait for non-busy before changing baudrate to avoid 246*aed2fbefSSimon Glass * crap in console 247*aed2fbefSSimon Glass */ 248*aed2fbefSSimon Glass while (!(readl(&base_regs->fr) & UART_PL01x_FR_TXFE)) 249*aed2fbefSSimon Glass WATCHDOG_RESET(); 250*aed2fbefSSimon Glass while (readl(&base_regs->fr) & UART_PL01x_FR_BUSY) 251*aed2fbefSSimon Glass WATCHDOG_RESET(); 252*aed2fbefSSimon Glass pl01x_serial_init_baud(gd->baudrate); 253*aed2fbefSSimon Glass } 254*aed2fbefSSimon Glass 25539f61477SMarek Vasut static struct serial_device pl01x_serial_drv = { 25639f61477SMarek Vasut .name = "pl01x_serial", 25739f61477SMarek Vasut .start = pl01x_serial_init, 25839f61477SMarek Vasut .stop = NULL, 25939f61477SMarek Vasut .setbrg = pl01x_serial_setbrg, 26039f61477SMarek Vasut .putc = pl01x_serial_putc, 261ec3fd689SMarek Vasut .puts = default_serial_puts, 26239f61477SMarek Vasut .getc = pl01x_serial_getc, 26339f61477SMarek Vasut .tstc = pl01x_serial_tstc, 26439f61477SMarek Vasut }; 26539f61477SMarek Vasut 26639f61477SMarek Vasut void pl01x_serial_initialize(void) 26739f61477SMarek Vasut { 26839f61477SMarek Vasut serial_register(&pl01x_serial_drv); 26939f61477SMarek Vasut } 27039f61477SMarek Vasut 27139f61477SMarek Vasut __weak struct serial_device *default_serial_console(void) 27239f61477SMarek Vasut { 27339f61477SMarek Vasut return &pl01x_serial_drv; 27439f61477SMarek Vasut } 275*aed2fbefSSimon Glass 276*aed2fbefSSimon Glass #endif /* nCONFIG_DM_SERIAL */ 277