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