uboot/drivers/serial/serial_sti_asc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Support for Serial I/O using STMicroelectronics' on-chip ASC.
   4 *
   5 * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
   6 * Author(s): Patrice Chotard, <patrice.chotard@st.com> for STMicroelectronics.
   7 */
   8
   9#include <common.h>
  10#include <dm.h>
  11#include <serial.h>
  12#include <asm/io.h>
  13
  14DECLARE_GLOBAL_DATA_PTR;
  15
  16#define BAUDMODE        0x00001000
  17#define RXENABLE        0x00000100
  18#define RUN             0x00000080
  19#define MODE            0x00000001
  20#define MODE_8BIT       0x0001
  21#define STOP_1BIT       0x0008
  22#define PARITYODD       0x0020
  23
  24#define STA_TF          BIT(9)
  25#define STA_RBF         BIT(0)
  26
  27struct sti_asc_uart {
  28        u32 baudrate;
  29        u32 txbuf;
  30        u32 rxbuf;
  31        u32 control;
  32        u32 inten;
  33        u32 status;
  34        u32 guardtime;
  35        u32 timeout;
  36        u32 txreset;
  37        u32 rxreset;
  38};
  39
  40struct sti_asc_serial {
  41        /* address of registers in physical memory */
  42        struct sti_asc_uart *regs;
  43};
  44
  45/* Values for the BAUDRATE Register */
  46#define PCLK                    (200ul * 1000000ul)
  47#define BAUDRATE_VAL_M0(bps)    (PCLK / (16 * (bps)))
  48#define BAUDRATE_VAL_M1(bps)    ((bps * (1 << 14)) + (1<<13)) / (PCLK/(1 << 6))
  49
  50/*
  51 * MODE 0
  52 *                       ICCLK
  53 * ASCBaudRate =   ----------------
  54 *                   baudrate * 16
  55 *
  56 * MODE 1
  57 *                   baudrate * 16 * 2^16
  58 * ASCBaudRate =   ------------------------
  59 *                          ICCLK
  60 *
  61 * NOTE:
  62 * Mode 1 should be used for baudrates of 19200, and above, as it
  63 * has a lower deviation error than Mode 0 for higher frequencies.
  64 * Mode 0 should be used for all baudrates below 19200.
  65 */
  66
  67static int sti_asc_pending(struct udevice *dev, bool input)
  68{
  69        struct sti_asc_serial *priv = dev_get_priv(dev);
  70        struct sti_asc_uart *const uart = priv->regs;
  71        unsigned long status;
  72
  73        status = readl(&uart->status);
  74        if (input)
  75                return status & STA_RBF;
  76        else
  77                return status & STA_TF;
  78}
  79
  80static int _sti_asc_serial_setbrg(struct sti_asc_uart *uart, int baudrate)
  81{
  82        unsigned long val;
  83        int t, mode = 1;
  84
  85        switch (baudrate) {
  86        case 9600:
  87                t = BAUDRATE_VAL_M0(9600);
  88                mode = 0;
  89                break;
  90        case 19200:
  91                t = BAUDRATE_VAL_M1(19200);
  92                break;
  93        case 38400:
  94                t = BAUDRATE_VAL_M1(38400);
  95                break;
  96        case 57600:
  97                t = BAUDRATE_VAL_M1(57600);
  98                break;
  99        default:
 100                debug("ASC: unsupported baud rate: %d, using 115200 instead.\n",
 101                      baudrate);
 102        case 115200:
 103                t = BAUDRATE_VAL_M1(115200);
 104                break;
 105        }
 106
 107        /* disable the baudrate generator */
 108        val = readl(&uart->control);
 109        writel(val & ~RUN, &uart->control);
 110
 111        /* set baud generator reload value */
 112        writel(t, &uart->baudrate);
 113        /* reset the RX & TX buffers */
 114        writel(1, &uart->txreset);
 115        writel(1, &uart->rxreset);
 116
 117        /* set baud generator mode */
 118        if (mode)
 119                val |= BAUDMODE;
 120
 121        /* finally, write value and enable ASC */
 122        writel(val, &uart->control);
 123
 124        return 0;
 125}
 126
 127/* called to adjust baud-rate */
 128static int sti_asc_serial_setbrg(struct udevice *dev, int baudrate)
 129{
 130        struct sti_asc_serial *priv = dev_get_priv(dev);
 131        struct sti_asc_uart *const uart = priv->regs;
 132
 133        return _sti_asc_serial_setbrg(uart, baudrate);
 134}
 135
 136/* blocking function, that returns next char */
 137static int sti_asc_serial_getc(struct udevice *dev)
 138{
 139        struct sti_asc_serial *priv = dev_get_priv(dev);
 140        struct sti_asc_uart *const uart = priv->regs;
 141
 142        /* polling wait: for a char to be read */
 143        if (!sti_asc_pending(dev, true))
 144                return -EAGAIN;
 145
 146        return readl(&uart->rxbuf);
 147}
 148
 149/* write write out a single char */
 150static int sti_asc_serial_putc(struct udevice *dev, const char c)
 151{
 152        struct sti_asc_serial *priv = dev_get_priv(dev);
 153        struct sti_asc_uart *const uart = priv->regs;
 154
 155        /* wait till safe to write next char */
 156        if (sti_asc_pending(dev, false))
 157                return -EAGAIN;
 158
 159        /* finally, write next char */
 160        writel(c, &uart->txbuf);
 161
 162        return 0;
 163}
 164
 165/* initialize the ASC */
 166static int sti_asc_serial_probe(struct udevice *dev)
 167{
 168        struct sti_asc_serial *priv = dev_get_priv(dev);
 169        unsigned long val;
 170        fdt_addr_t base;
 171
 172        base = devfdt_get_addr(dev);
 173        if (base == FDT_ADDR_T_NONE)
 174                return -EINVAL;
 175
 176        priv->regs = (struct sti_asc_uart *)base;
 177        sti_asc_serial_setbrg(dev, gd->baudrate);
 178
 179        /*
 180         * build up the value to be written to CONTROL
 181         * set character length, bit stop number, odd parity
 182         */
 183        val = RXENABLE | RUN | MODE_8BIT | STOP_1BIT | PARITYODD;
 184        writel(val, &priv->regs->control);
 185
 186        return 0;
 187}
 188
 189static const struct dm_serial_ops sti_asc_serial_ops = {
 190        .putc = sti_asc_serial_putc,
 191        .pending = sti_asc_pending,
 192        .getc = sti_asc_serial_getc,
 193        .setbrg = sti_asc_serial_setbrg,
 194};
 195
 196static const struct udevice_id sti_serial_of_match[] = {
 197        { .compatible = "st,asc" },
 198        { }
 199};
 200
 201U_BOOT_DRIVER(serial_sti_asc) = {
 202        .name = "serial_sti_asc",
 203        .id = UCLASS_SERIAL,
 204        .of_match = sti_serial_of_match,
 205        .ops = &sti_asc_serial_ops,
 206        .probe = sti_asc_serial_probe,
 207        .priv_auto_alloc_size = sizeof(struct sti_asc_serial),
 208};
 209
 210