uboot/drivers/serial/serial_meson.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2016 Beniamino Galvani <b.galvani@gmail.com>
   4 */
   5
   6#include <common.h>
   7#include <dm.h>
   8#include <errno.h>
   9#include <fdtdec.h>
  10#include <linux/compiler.h>
  11#include <serial.h>
  12
  13struct meson_uart {
  14        u32 wfifo;
  15        u32 rfifo;
  16        u32 control;
  17        u32 status;
  18        u32 misc;
  19};
  20
  21struct meson_serial_platdata {
  22        struct meson_uart *reg;
  23};
  24
  25/* AML_UART_STATUS bits */
  26#define AML_UART_PARITY_ERR             BIT(16)
  27#define AML_UART_FRAME_ERR              BIT(17)
  28#define AML_UART_TX_FIFO_WERR           BIT(18)
  29#define AML_UART_RX_EMPTY               BIT(20)
  30#define AML_UART_TX_FULL                BIT(21)
  31#define AML_UART_TX_EMPTY               BIT(22)
  32#define AML_UART_XMIT_BUSY              BIT(25)
  33#define AML_UART_ERR                    (AML_UART_PARITY_ERR | \
  34                                         AML_UART_FRAME_ERR  | \
  35                                         AML_UART_TX_FIFO_WERR)
  36
  37/* AML_UART_CONTROL bits */
  38#define AML_UART_TX_EN                  BIT(12)
  39#define AML_UART_RX_EN                  BIT(13)
  40#define AML_UART_TX_RST                 BIT(22)
  41#define AML_UART_RX_RST                 BIT(23)
  42#define AML_UART_CLR_ERR                BIT(24)
  43
  44static void meson_serial_init(struct meson_uart *uart)
  45{
  46        u32 val;
  47
  48        val = readl(&uart->control);
  49        val |= (AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLR_ERR);
  50        writel(val, &uart->control);
  51        val &= ~(AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLR_ERR);
  52        writel(val, &uart->control);
  53        val |= (AML_UART_RX_EN | AML_UART_TX_EN);
  54        writel(val, &uart->control);
  55}
  56
  57static int meson_serial_probe(struct udevice *dev)
  58{
  59        struct meson_serial_platdata *plat = dev->platdata;
  60        struct meson_uart *const uart = plat->reg;
  61
  62        meson_serial_init(uart);
  63
  64        return 0;
  65}
  66
  67static int meson_serial_getc(struct udevice *dev)
  68{
  69        struct meson_serial_platdata *plat = dev->platdata;
  70        struct meson_uart *const uart = plat->reg;
  71
  72        if (readl(&uart->status) & AML_UART_RX_EMPTY)
  73                return -EAGAIN;
  74
  75        return readl(&uart->rfifo) & 0xff;
  76}
  77
  78static int meson_serial_putc(struct udevice *dev, const char ch)
  79{
  80        struct meson_serial_platdata *plat = dev->platdata;
  81        struct meson_uart *const uart = plat->reg;
  82
  83        if (readl(&uart->status) & AML_UART_TX_FULL)
  84                return -EAGAIN;
  85
  86        writel(ch, &uart->wfifo);
  87
  88        return 0;
  89}
  90
  91static int meson_serial_pending(struct udevice *dev, bool input)
  92{
  93        struct meson_serial_platdata *plat = dev->platdata;
  94        struct meson_uart *const uart = plat->reg;
  95        uint32_t status = readl(&uart->status);
  96
  97        if (input)
  98                return !(status & AML_UART_RX_EMPTY);
  99        else
 100                return !(status & AML_UART_TX_FULL);
 101}
 102
 103static int meson_serial_ofdata_to_platdata(struct udevice *dev)
 104{
 105        struct meson_serial_platdata *plat = dev->platdata;
 106        fdt_addr_t addr;
 107
 108        addr = devfdt_get_addr(dev);
 109        if (addr == FDT_ADDR_T_NONE)
 110                return -EINVAL;
 111
 112        plat->reg = (struct meson_uart *)addr;
 113
 114        return 0;
 115}
 116
 117static const struct dm_serial_ops meson_serial_ops = {
 118        .putc = meson_serial_putc,
 119        .pending = meson_serial_pending,
 120        .getc = meson_serial_getc,
 121};
 122
 123static const struct udevice_id meson_serial_ids[] = {
 124        { .compatible = "amlogic,meson-uart" },
 125        { .compatible = "amlogic,meson-gx-uart" },
 126        { }
 127};
 128
 129U_BOOT_DRIVER(serial_meson) = {
 130        .name           = "serial_meson",
 131        .id             = UCLASS_SERIAL,
 132        .of_match       = meson_serial_ids,
 133        .probe          = meson_serial_probe,
 134        .ops            = &meson_serial_ops,
 135        .ofdata_to_platdata = meson_serial_ofdata_to_platdata,
 136        .platdata_auto_alloc_size = sizeof(struct meson_serial_platdata),
 137};
 138
 139#ifdef CONFIG_DEBUG_UART_MESON
 140
 141#include <debug_uart.h>
 142
 143static inline void _debug_uart_init(void)
 144{
 145}
 146
 147static inline void _debug_uart_putc(int ch)
 148{
 149        struct meson_uart *regs = (struct meson_uart *)CONFIG_DEBUG_UART_BASE;
 150
 151        while (readl(&regs->status) & AML_UART_TX_FULL)
 152                ;
 153
 154        writel(ch, &regs->wfifo);
 155}
 156
 157DEBUG_UART_FUNCS
 158
 159#endif
 160