123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * Support for Serial I/O using STMicroelectronics' on-chip ASC.
- *
- * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
- * Author(s): Patrice Chotard, <patrice.chotard@st.com> for STMicroelectronics.
- */
- #include <common.h>
- #include <dm.h>
- #include <serial.h>
- #include <asm/io.h>
- DECLARE_GLOBAL_DATA_PTR;
- #define BAUDMODE 0x00001000
- #define RXENABLE 0x00000100
- #define RUN 0x00000080
- #define MODE 0x00000001
- #define MODE_8BIT 0x0001
- #define STOP_1BIT 0x0008
- #define PARITYODD 0x0020
- #define STA_TF BIT(9)
- #define STA_RBF BIT(0)
- struct sti_asc_uart {
- u32 baudrate;
- u32 txbuf;
- u32 rxbuf;
- u32 control;
- u32 inten;
- u32 status;
- u32 guardtime;
- u32 timeout;
- u32 txreset;
- u32 rxreset;
- };
- struct sti_asc_serial {
- /* address of registers in physical memory */
- struct sti_asc_uart *regs;
- };
- /* Values for the BAUDRATE Register */
- #define PCLK (200ul * 1000000ul)
- #define BAUDRATE_VAL_M0(bps) (PCLK / (16 * (bps)))
- #define BAUDRATE_VAL_M1(bps) ((bps * (1 << 14)) + (1<<13)) / (PCLK/(1 << 6))
- /*
- * MODE 0
- * ICCLK
- * ASCBaudRate = ----------------
- * baudrate * 16
- *
- * MODE 1
- * baudrate * 16 * 2^16
- * ASCBaudRate = ------------------------
- * ICCLK
- *
- * NOTE:
- * Mode 1 should be used for baudrates of 19200, and above, as it
- * has a lower deviation error than Mode 0 for higher frequencies.
- * Mode 0 should be used for all baudrates below 19200.
- */
- static int sti_asc_pending(struct udevice *dev, bool input)
- {
- struct sti_asc_serial *priv = dev_get_priv(dev);
- struct sti_asc_uart *const uart = priv->regs;
- unsigned long status;
- status = readl(&uart->status);
- if (input)
- return status & STA_RBF;
- else
- return status & STA_TF;
- }
- static int _sti_asc_serial_setbrg(struct sti_asc_uart *uart, int baudrate)
- {
- unsigned long val;
- int t, mode = 1;
- switch (baudrate) {
- case 9600:
- t = BAUDRATE_VAL_M0(9600);
- mode = 0;
- break;
- case 19200:
- t = BAUDRATE_VAL_M1(19200);
- break;
- case 38400:
- t = BAUDRATE_VAL_M1(38400);
- break;
- case 57600:
- t = BAUDRATE_VAL_M1(57600);
- break;
- default:
- debug("ASC: unsupported baud rate: %d, using 115200 instead.\n",
- baudrate);
- case 115200:
- t = BAUDRATE_VAL_M1(115200);
- break;
- }
- /* disable the baudrate generator */
- val = readl(&uart->control);
- writel(val & ~RUN, &uart->control);
- /* set baud generator reload value */
- writel(t, &uart->baudrate);
- /* reset the RX & TX buffers */
- writel(1, &uart->txreset);
- writel(1, &uart->rxreset);
- /* set baud generator mode */
- if (mode)
- val |= BAUDMODE;
- /* finally, write value and enable ASC */
- writel(val, &uart->control);
- return 0;
- }
- /* called to adjust baud-rate */
- static int sti_asc_serial_setbrg(struct udevice *dev, int baudrate)
- {
- struct sti_asc_serial *priv = dev_get_priv(dev);
- struct sti_asc_uart *const uart = priv->regs;
- return _sti_asc_serial_setbrg(uart, baudrate);
- }
- /* blocking function, that returns next char */
- static int sti_asc_serial_getc(struct udevice *dev)
- {
- struct sti_asc_serial *priv = dev_get_priv(dev);
- struct sti_asc_uart *const uart = priv->regs;
- /* polling wait: for a char to be read */
- if (!sti_asc_pending(dev, true))
- return -EAGAIN;
- return readl(&uart->rxbuf);
- }
- /* write write out a single char */
- static int sti_asc_serial_putc(struct udevice *dev, const char c)
- {
- struct sti_asc_serial *priv = dev_get_priv(dev);
- struct sti_asc_uart *const uart = priv->regs;
- /* wait till safe to write next char */
- if (sti_asc_pending(dev, false))
- return -EAGAIN;
- /* finally, write next char */
- writel(c, &uart->txbuf);
- return 0;
- }
- /* initialize the ASC */
- static int sti_asc_serial_probe(struct udevice *dev)
- {
- struct sti_asc_serial *priv = dev_get_priv(dev);
- unsigned long val;
- fdt_addr_t base;
- base = devfdt_get_addr(dev);
- if (base == FDT_ADDR_T_NONE)
- return -EINVAL;
- priv->regs = (struct sti_asc_uart *)base;
- sti_asc_serial_setbrg(dev, gd->baudrate);
- /*
- * build up the value to be written to CONTROL
- * set character length, bit stop number, odd parity
- */
- val = RXENABLE | RUN | MODE_8BIT | STOP_1BIT | PARITYODD;
- writel(val, &priv->regs->control);
- return 0;
- }
- static const struct dm_serial_ops sti_asc_serial_ops = {
- .putc = sti_asc_serial_putc,
- .pending = sti_asc_pending,
- .getc = sti_asc_serial_getc,
- .setbrg = sti_asc_serial_setbrg,
- };
- static const struct udevice_id sti_serial_of_match[] = {
- { .compatible = "st,asc" },
- { }
- };
- U_BOOT_DRIVER(serial_sti_asc) = {
- .name = "serial_sti_asc",
- .id = UCLASS_SERIAL,
- .of_match = sti_serial_of_match,
- .ops = &sti_asc_serial_ops,
- .probe = sti_asc_serial_probe,
- .priv_auto_alloc_size = sizeof(struct sti_asc_serial),
- .flags = DM_FLAG_PRE_RELOC,
- };
|