uboot/drivers/serial/serial_pxa.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
   4 *
   5 * (C) Copyright 2002
   6 * Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
   7 *
   8 * (C) Copyright 2002
   9 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
  10 * Marius Groeger <mgroeger@sysgo.de>
  11 *
  12 * (C) Copyright 2002
  13 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
  14 * Alex Zuepke <azu@sysgo.de>
  15 *
  16 * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
  17 *
  18 * Modified to add driver model (DM) support
  19 * (C) Copyright 2016 Marcel Ziswiler <marcel.ziswiler@toradex.com>
  20 */
  21
  22#include <common.h>
  23#include <hang.h>
  24#include <asm/arch/pxa-regs.h>
  25#include <asm/arch/regs-uart.h>
  26#include <asm/global_data.h>
  27#include <asm/io.h>
  28#include <dm.h>
  29#include <dm/platform_data/serial_pxa.h>
  30#include <linux/compiler.h>
  31#include <serial.h>
  32#include <watchdog.h>
  33
  34DECLARE_GLOBAL_DATA_PTR;
  35
  36static uint32_t pxa_uart_get_baud_divider(int baudrate)
  37{
  38        return 921600 / baudrate;
  39}
  40
  41static void pxa_uart_toggle_clock(uint32_t uart_index, int enable)
  42{
  43        uint32_t clk_reg, clk_offset, reg;
  44
  45        clk_reg = UART_CLK_REG;
  46        clk_offset = UART_CLK_BASE << uart_index;
  47
  48        reg = readl(clk_reg);
  49
  50        if (enable)
  51                reg |= clk_offset;
  52        else
  53                reg &= ~clk_offset;
  54
  55        writel(reg, clk_reg);
  56}
  57
  58/*
  59 * Enable clock and set baud rate, parity etc.
  60 */
  61void pxa_setbrg_common(struct pxa_uart_regs *uart_regs, int port, int baudrate)
  62{
  63        uint32_t divider = pxa_uart_get_baud_divider(baudrate);
  64        if (!divider)
  65                hang();
  66
  67
  68        pxa_uart_toggle_clock(port, 1);
  69
  70        /* Disable interrupts and FIFOs */
  71        writel(0, &uart_regs->ier);
  72        writel(0, &uart_regs->fcr);
  73
  74        /* Set baud rate */
  75        writel(LCR_WLS0 | LCR_WLS1 | LCR_DLAB, &uart_regs->lcr);
  76        writel(divider & 0xff, &uart_regs->dll);
  77        writel(divider >> 8, &uart_regs->dlh);
  78        writel(LCR_WLS0 | LCR_WLS1, &uart_regs->lcr);
  79
  80        /* Enable UART */
  81        writel(IER_UUE, &uart_regs->ier);
  82}
  83
  84#ifndef CONFIG_DM_SERIAL
  85static struct pxa_uart_regs *pxa_uart_index_to_regs(uint32_t uart_index)
  86{
  87        switch (uart_index) {
  88        case FFUART_INDEX: return (struct pxa_uart_regs *)FFUART_BASE;
  89        case BTUART_INDEX: return (struct pxa_uart_regs *)BTUART_BASE;
  90        case STUART_INDEX: return (struct pxa_uart_regs *)STUART_BASE;
  91        case HWUART_INDEX: return (struct pxa_uart_regs *)HWUART_BASE;
  92        default:
  93                return NULL;
  94        }
  95}
  96
  97/*
  98 * Enable clock and set baud rate, parity etc.
  99 */
 100void pxa_setbrg_dev(uint32_t uart_index)
 101{
 102        struct pxa_uart_regs *uart_regs = pxa_uart_index_to_regs(uart_index);
 103        if (!uart_regs)
 104                panic("Failed getting UART registers\n");
 105
 106        pxa_setbrg_common(uart_regs, uart_index, gd->baudrate);
 107}
 108
 109/*
 110 * Initialise the serial port with the given baudrate. The settings
 111 * are always 8 data bits, no parity, 1 stop bit, no start bits.
 112 */
 113int pxa_init_dev(unsigned int uart_index)
 114{
 115        pxa_setbrg_dev(uart_index);
 116        return 0;
 117}
 118
 119/*
 120 * Output a single byte to the serial port.
 121 */
 122void pxa_putc_dev(unsigned int uart_index, const char c)
 123{
 124        struct pxa_uart_regs *uart_regs;
 125
 126        /* If \n, also do \r */
 127        if (c == '\n')
 128                pxa_putc_dev(uart_index, '\r');
 129
 130        uart_regs = pxa_uart_index_to_regs(uart_index);
 131        if (!uart_regs)
 132                hang();
 133
 134        while (!(readl(&uart_regs->lsr) & LSR_TEMT))
 135                WATCHDOG_RESET();
 136        writel(c, &uart_regs->thr);
 137}
 138
 139/*
 140 * Read a single byte from the serial port. Returns 1 on success, 0
 141 * otherwise. When the function is succesfull, the character read is
 142 * written into its argument c.
 143 */
 144int pxa_tstc_dev(unsigned int uart_index)
 145{
 146        struct pxa_uart_regs *uart_regs;
 147
 148        uart_regs = pxa_uart_index_to_regs(uart_index);
 149        if (!uart_regs)
 150                return -1;
 151
 152        return readl(&uart_regs->lsr) & LSR_DR;
 153}
 154
 155/*
 156 * Read a single byte from the serial port. Returns 1 on success, 0
 157 * otherwise. When the function is succesfull, the character read is
 158 * written into its argument c.
 159 */
 160int pxa_getc_dev(unsigned int uart_index)
 161{
 162        struct pxa_uart_regs *uart_regs;
 163
 164        uart_regs = pxa_uart_index_to_regs(uart_index);
 165        if (!uart_regs)
 166                return -1;
 167
 168        while (!(readl(&uart_regs->lsr) & LSR_DR))
 169                WATCHDOG_RESET();
 170        return readl(&uart_regs->rbr) & 0xff;
 171}
 172
 173void pxa_puts_dev(unsigned int uart_index, const char *s)
 174{
 175        while (*s)
 176                pxa_putc_dev(uart_index, *s++);
 177}
 178
 179#define pxa_uart(uart, UART)                                            \
 180        int uart##_init(void)                                           \
 181        {                                                               \
 182                return pxa_init_dev(UART##_INDEX);                      \
 183        }                                                               \
 184                                                                        \
 185        void uart##_setbrg(void)                                        \
 186        {                                                               \
 187                return pxa_setbrg_dev(UART##_INDEX);                    \
 188        }                                                               \
 189                                                                        \
 190        void uart##_putc(const char c)                                  \
 191        {                                                               \
 192                return pxa_putc_dev(UART##_INDEX, c);                   \
 193        }                                                               \
 194                                                                        \
 195        void uart##_puts(const char *s)                                 \
 196        {                                                               \
 197                return pxa_puts_dev(UART##_INDEX, s);                   \
 198        }                                                               \
 199                                                                        \
 200        int uart##_getc(void)                                           \
 201        {                                                               \
 202                return pxa_getc_dev(UART##_INDEX);                      \
 203        }                                                               \
 204                                                                        \
 205        int uart##_tstc(void)                                           \
 206        {                                                               \
 207                return pxa_tstc_dev(UART##_INDEX);                      \
 208        }                                                               \
 209
 210#define pxa_uart_desc(uart)                                             \
 211        struct serial_device serial_##uart##_device =                   \
 212        {                                                               \
 213                .name   = "serial_"#uart,                               \
 214                .start  = uart##_init,                                  \
 215                .stop   = NULL,                                         \
 216                .setbrg = uart##_setbrg,                                \
 217                .getc   = uart##_getc,                                  \
 218                .tstc   = uart##_tstc,                                  \
 219                .putc   = uart##_putc,                                  \
 220                .puts   = uart##_puts,                                  \
 221        };
 222
 223#define pxa_uart_multi(uart, UART)                                      \
 224        pxa_uart(uart, UART)                                            \
 225        pxa_uart_desc(uart)
 226
 227#if defined(CONFIG_HWUART)
 228        pxa_uart_multi(hwuart, HWUART)
 229#endif
 230#if defined(CONFIG_STUART)
 231        pxa_uart_multi(stuart, STUART)
 232#endif
 233#if defined(CONFIG_FFUART)
 234        pxa_uart_multi(ffuart, FFUART)
 235#endif
 236#if defined(CONFIG_BTUART)
 237        pxa_uart_multi(btuart, BTUART)
 238#endif
 239
 240__weak struct serial_device *default_serial_console(void)
 241{
 242#if CONFIG_CONS_INDEX == 1
 243        return &serial_hwuart_device;
 244#elif CONFIG_CONS_INDEX == 2
 245        return &serial_stuart_device;
 246#elif CONFIG_CONS_INDEX == 3
 247        return &serial_ffuart_device;
 248#elif CONFIG_CONS_INDEX == 4
 249        return &serial_btuart_device;
 250#else
 251#error "Bad CONFIG_CONS_INDEX."
 252#endif
 253}
 254
 255void pxa_serial_initialize(void)
 256{
 257#if defined(CONFIG_FFUART)
 258        serial_register(&serial_ffuart_device);
 259#endif
 260#if defined(CONFIG_BTUART)
 261        serial_register(&serial_btuart_device);
 262#endif
 263#if defined(CONFIG_STUART)
 264        serial_register(&serial_stuart_device);
 265#endif
 266}
 267#endif /* CONFIG_DM_SERIAL */
 268
 269#ifdef CONFIG_DM_SERIAL
 270static int pxa_serial_probe(struct udevice *dev)
 271{
 272        struct pxa_serial_plat *plat = dev_get_plat(dev);
 273
 274        pxa_setbrg_common((struct pxa_uart_regs *)plat->base, plat->port,
 275                          plat->baudrate);
 276        return 0;
 277}
 278
 279static int pxa_serial_putc(struct udevice *dev, const char ch)
 280{
 281        struct pxa_serial_plat *plat = dev_get_plat(dev);
 282        struct pxa_uart_regs *uart_regs = (struct pxa_uart_regs *)plat->base;
 283
 284        /* Wait for last character to go. */
 285        if (!(readl(&uart_regs->lsr) & LSR_TEMT))
 286                return -EAGAIN;
 287
 288        writel(ch, &uart_regs->thr);
 289
 290        return 0;
 291}
 292
 293static int pxa_serial_getc(struct udevice *dev)
 294{
 295        struct pxa_serial_plat *plat = dev_get_plat(dev);
 296        struct pxa_uart_regs *uart_regs = (struct pxa_uart_regs *)plat->base;
 297
 298        /* Wait for a character to arrive. */
 299        if (!(readl(&uart_regs->lsr) & LSR_DR))
 300                return -EAGAIN;
 301
 302        return readl(&uart_regs->rbr) & 0xff;
 303}
 304
 305int pxa_serial_setbrg(struct udevice *dev, int baudrate)
 306{
 307        struct pxa_serial_plat *plat = dev_get_plat(dev);
 308        struct pxa_uart_regs *uart_regs = (struct pxa_uart_regs *)plat->base;
 309        int port = plat->port;
 310
 311        pxa_setbrg_common(uart_regs, port, baudrate);
 312
 313        return 0;
 314}
 315
 316static int pxa_serial_pending(struct udevice *dev, bool input)
 317{
 318        struct pxa_serial_plat *plat = dev_get_plat(dev);
 319        struct pxa_uart_regs *uart_regs = (struct pxa_uart_regs *)plat->base;
 320
 321        if (input)
 322                return readl(&uart_regs->lsr) & LSR_DR ? 1 : 0;
 323        else
 324                return readl(&uart_regs->lsr) & LSR_TEMT ? 0 : 1;
 325
 326        return 0;
 327}
 328
 329static const struct dm_serial_ops pxa_serial_ops = {
 330        .putc           = pxa_serial_putc,
 331        .pending        = pxa_serial_pending,
 332        .getc           = pxa_serial_getc,
 333        .setbrg         = pxa_serial_setbrg,
 334};
 335
 336U_BOOT_DRIVER(serial_pxa) = {
 337        .name   = "serial_pxa",
 338        .id     = UCLASS_SERIAL,
 339        .probe  = pxa_serial_probe,
 340        .ops    = &pxa_serial_ops,
 341        .flags  = DM_FLAG_PRE_RELOC,
 342};
 343#endif /* CONFIG_DM_SERIAL */
 344