uboot/drivers/serial/serial_mxs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2023 Marek Vasut <marex@denx.de>
   4 */
   5#include <common.h>
   6#include <dm.h>
   7#include <malloc.h>
   8#include <serial.h>
   9#include <wait_bit.h>
  10
  11#define SET_REG                                 0x4
  12#define CLR_REG                                 0x8
  13
  14#define AUART_CTRL0                             0x00
  15#define AUART_CTRL1                             0x10
  16#define AUART_CTRL2                             0x20
  17#define AUART_LINECTRL                          0x30
  18#define AUART_INTR                              0x50
  19#define AUART_DATA                              0x60
  20#define AUART_STAT                              0x70
  21
  22#define AUART_CTRL0_SFTRST                      BIT(31)
  23#define AUART_CTRL0_CLKGATE                     BIT(30)
  24
  25#define AUART_CTRL2_UARTEN                      BIT(0)
  26
  27#define AUART_LINECTRL_BAUD_DIVINT(v)           (((v) & 0xffff) << 16)
  28#define AUART_LINECTRL_BAUD_DIVFRAC(v)          (((v) & 0x3f) << 8)
  29#define AUART_LINECTRL_WLEN(v)                  ((((v) - 5) & 0x3) << 5)
  30
  31#define AUART_STAT_TXFE                         BIT(27)
  32#define AUART_STAT_TXFF                         BIT(25)
  33#define AUART_STAT_RXFE                         BIT(24)
  34
  35#define AUART_CLK                               24000000
  36
  37struct mxs_auart_uart_priv {
  38        void __iomem *base;
  39};
  40
  41static int mxs_auart_uart_setbrg(struct udevice *dev, int baudrate)
  42{
  43        struct mxs_auart_uart_priv *priv = dev_get_priv(dev);
  44        u32 div;
  45
  46        writel(AUART_CTRL0_CLKGATE, priv->base + AUART_CTRL0 + CLR_REG);
  47        writel(AUART_CTRL0_SFTRST, priv->base + AUART_CTRL0 + CLR_REG);
  48
  49        writel(AUART_CTRL2_UARTEN, priv->base + AUART_CTRL2 + SET_REG);
  50
  51        writel(0, priv->base + AUART_INTR);
  52
  53        div = DIV_ROUND_CLOSEST(AUART_CLK * 32, baudrate);
  54
  55        /* Disable FIFO, baudrate, 8N1. */
  56        writel(AUART_LINECTRL_BAUD_DIVFRAC(div & 0x3F) |
  57               AUART_LINECTRL_BAUD_DIVINT(div >> 6) |
  58               AUART_LINECTRL_WLEN(8),
  59               priv->base + AUART_LINECTRL);
  60
  61        return 0;
  62}
  63
  64static int mxs_auart_uart_pending(struct udevice *dev, bool input)
  65{
  66        struct mxs_auart_uart_priv *priv = dev_get_priv(dev);
  67        u32 stat = readl(priv->base + AUART_STAT);
  68
  69        if (input)
  70                return !(stat & AUART_STAT_RXFE);
  71
  72        return !!(stat & AUART_STAT_TXFE);
  73}
  74
  75static int mxs_auart_uart_putc(struct udevice *dev, const char ch)
  76{
  77        struct mxs_auart_uart_priv *priv = dev_get_priv(dev);
  78        u32 stat = readl(priv->base + AUART_STAT);
  79
  80        if (stat & AUART_STAT_TXFF)
  81                return -EAGAIN;
  82
  83        writel(ch, priv->base + AUART_DATA);
  84
  85        return 0;
  86}
  87
  88static int mxs_auart_uart_getc(struct udevice *dev)
  89{
  90        struct mxs_auart_uart_priv *priv = dev_get_priv(dev);
  91
  92        if (!mxs_auart_uart_pending(dev, true))
  93                return -EAGAIN;
  94
  95        return readl(priv->base + AUART_DATA) & 0xff;
  96}
  97
  98static int mxs_auart_uart_probe(struct udevice *dev)
  99{
 100        struct mxs_auart_uart_priv *priv = dev_get_priv(dev);
 101
 102        priv->base = dev_read_addr_ptr(dev);
 103        if (!priv->base)
 104                return -EINVAL;
 105
 106        return mxs_auart_uart_setbrg(dev, CONFIG_BAUDRATE);
 107}
 108
 109static const struct dm_serial_ops mxs_auart_uart_ops = {
 110        .putc           = mxs_auart_uart_putc,
 111        .pending        = mxs_auart_uart_pending,
 112        .getc           = mxs_auart_uart_getc,
 113        .setbrg         = mxs_auart_uart_setbrg,
 114};
 115
 116static const struct udevice_id mxs_auart_uart_ids[] = {
 117        { .compatible = "fsl,imx23-auart", },
 118        { .compatible = "fsl,imx28-auart", },
 119        { /* sentinel */ }
 120};
 121
 122U_BOOT_DRIVER(mxs_auart_serial) = {
 123        .name           = "mxs-auart",
 124        .id             = UCLASS_SERIAL,
 125        .of_match       = mxs_auart_uart_ids,
 126        .probe          = mxs_auart_uart_probe,
 127        .ops            = &mxs_auart_uart_ops,
 128        .priv_auto      = sizeof(struct mxs_auart_uart_priv),
 129};
 130