uboot/drivers/serial/serial_xuartlite.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2008 - 2015 Michal Simek <monstr@monstr.eu>
   4 * Clean driver and add xilinx constant from header file
   5 *
   6 * (C) Copyright 2004 Atmark Techno, Inc.
   7 * Yasushi SHOJI <yashi@atmark-techno.com>
   8 */
   9
  10#include <config.h>
  11#include <common.h>
  12#include <dm.h>
  13#include <asm/io.h>
  14#include <linux/bitops.h>
  15#include <linux/compiler.h>
  16#include <serial.h>
  17
  18#define SR_TX_FIFO_FULL         BIT(3) /* transmit FIFO full */
  19#define SR_TX_FIFO_EMPTY        BIT(2) /* transmit FIFO empty */
  20#define SR_RX_FIFO_VALID_DATA   BIT(0) /* data in receive FIFO */
  21#define SR_RX_FIFO_FULL         BIT(1) /* receive FIFO full */
  22
  23#define ULITE_CONTROL_RST_TX    0x01
  24#define ULITE_CONTROL_RST_RX    0x02
  25
  26static bool little_endian;
  27
  28struct uartlite {
  29        unsigned int rx_fifo;
  30        unsigned int tx_fifo;
  31        unsigned int status;
  32        unsigned int control;
  33};
  34
  35struct uartlite_plat {
  36        struct uartlite *regs;
  37};
  38
  39static u32 uart_in32(void __iomem *addr)
  40{
  41        if (little_endian)
  42                return in_le32(addr);
  43        else
  44                return in_be32(addr);
  45}
  46
  47static void uart_out32(void __iomem *addr, u32 val)
  48{
  49        if (little_endian)
  50                out_le32(addr, val);
  51        else
  52                out_be32(addr, val);
  53}
  54
  55static int uartlite_serial_putc(struct udevice *dev, const char ch)
  56{
  57        struct uartlite_plat *plat = dev_get_plat(dev);
  58        struct uartlite *regs = plat->regs;
  59
  60        if (uart_in32(&regs->status) & SR_TX_FIFO_FULL)
  61                return -EAGAIN;
  62
  63        uart_out32(&regs->tx_fifo, ch & 0xff);
  64
  65        return 0;
  66}
  67
  68static int uartlite_serial_getc(struct udevice *dev)
  69{
  70        struct uartlite_plat *plat = dev_get_plat(dev);
  71        struct uartlite *regs = plat->regs;
  72
  73        if (!(uart_in32(&regs->status) & SR_RX_FIFO_VALID_DATA))
  74                return -EAGAIN;
  75
  76        return uart_in32(&regs->rx_fifo) & 0xff;
  77}
  78
  79static int uartlite_serial_pending(struct udevice *dev, bool input)
  80{
  81        struct uartlite_plat *plat = dev_get_plat(dev);
  82        struct uartlite *regs = plat->regs;
  83
  84        if (input)
  85                return uart_in32(&regs->status) & SR_RX_FIFO_VALID_DATA;
  86
  87        return !(uart_in32(&regs->status) & SR_TX_FIFO_EMPTY);
  88}
  89
  90static int uartlite_serial_probe(struct udevice *dev)
  91{
  92        struct uartlite_plat *plat = dev_get_plat(dev);
  93        struct uartlite *regs = plat->regs;
  94        int ret;
  95
  96        uart_out32(&regs->control, 0);
  97        uart_out32(&regs->control, ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX);
  98        ret = uart_in32(&regs->status);
  99        /* Endianness detection */
 100        if ((ret & SR_TX_FIFO_EMPTY) != SR_TX_FIFO_EMPTY) {
 101                little_endian = true;
 102                uart_out32(&regs->control, ULITE_CONTROL_RST_RX |
 103                           ULITE_CONTROL_RST_TX);
 104        }
 105
 106        return 0;
 107}
 108
 109static int uartlite_serial_of_to_plat(struct udevice *dev)
 110{
 111        struct uartlite_plat *plat = dev_get_plat(dev);
 112
 113        plat->regs = dev_read_addr_ptr(dev);
 114
 115        return 0;
 116}
 117
 118static const struct dm_serial_ops uartlite_serial_ops = {
 119        .putc = uartlite_serial_putc,
 120        .pending = uartlite_serial_pending,
 121        .getc = uartlite_serial_getc,
 122};
 123
 124static const struct udevice_id uartlite_serial_ids[] = {
 125        { .compatible = "xlnx,opb-uartlite-1.00.b", },
 126        { .compatible = "xlnx,xps-uartlite-1.00.a" },
 127        { }
 128};
 129
 130U_BOOT_DRIVER(serial_uartlite) = {
 131        .name   = "serial_uartlite",
 132        .id     = UCLASS_SERIAL,
 133        .of_match = uartlite_serial_ids,
 134        .of_to_plat = uartlite_serial_of_to_plat,
 135        .plat_auto      = sizeof(struct uartlite_plat),
 136        .probe = uartlite_serial_probe,
 137        .ops    = &uartlite_serial_ops,
 138};
 139
 140#ifdef CONFIG_DEBUG_UART_UARTLITE
 141
 142#include <debug_uart.h>
 143
 144static inline void _debug_uart_init(void)
 145{
 146        struct uartlite *regs = (struct uartlite *)CONFIG_DEBUG_UART_BASE;
 147        int ret;
 148
 149        uart_out32(&regs->control, 0);
 150        uart_out32(&regs->control, ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX);
 151        ret = uart_in32(&regs->status);
 152        /* Endianness detection */
 153        if ((ret & SR_TX_FIFO_EMPTY) != SR_TX_FIFO_EMPTY) {
 154                little_endian = true;
 155                uart_out32(&regs->control, ULITE_CONTROL_RST_RX |
 156                           ULITE_CONTROL_RST_TX);
 157        }
 158}
 159
 160static inline void _debug_uart_putc(int ch)
 161{
 162        struct uartlite *regs = (struct uartlite *)CONFIG_DEBUG_UART_BASE;
 163
 164        while (uart_in32(&regs->status) & SR_TX_FIFO_FULL)
 165                ;
 166
 167        uart_out32(&regs->tx_fifo, ch & 0xff);
 168}
 169
 170DEBUG_UART_FUNCS
 171#endif
 172