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