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