
From: Patrice Chotard patrice.chotard@st.com
This patch adds support to ASC (asynchronous serial controller) driver, which is basically a standard serial driver. This IP is common across other STMicroelectronics SoCs
Signed-off-by: Patrice Chotard patrice.chotard@st.com --- arch/arm/Kconfig | 2 + arch/arm/include/asm/arch-stih410/sti.h | 6 + board/st/stih410-b2260/board.c | 13 ++ drivers/serial/Kconfig | 7 + drivers/serial/Makefile | 1 + drivers/serial/serial_sti_asc.c | 219 ++++++++++++++++++++++++++++++ include/configs/stih410-b2260.h | 1 + include/dm/platform_data/serial_sti_asc.h | 17 +++ 8 files changed, 266 insertions(+) create mode 100644 drivers/serial/serial_sti_asc.c create mode 100644 include/dm/platform_data/serial_sti_asc.h
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 56a017c..98546ae 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -895,6 +895,8 @@ config STM32 config ARCH_STI bool "Support STMicrolectronics SoCs" select CPU_V7 + select DM + select DM_SERIAL help Support for STMicroelectronics STiH407/10 SoC family. This SoC is used on Linaro 96Board STiH410-B2260 diff --git a/arch/arm/include/asm/arch-stih410/sti.h b/arch/arm/include/asm/arch-stih410/sti.h index d35c4f0..f167560 100644 --- a/arch/arm/include/asm/arch-stih410/sti.h +++ b/arch/arm/include/asm/arch-stih410/sti.h @@ -11,4 +11,10 @@ #define STI_A9_CONFIG_BASE 0x08760000 #define STI_A9_GLOBAL_TIMER_BASE (STI_A9_CONFIG_BASE + 0x0200)
+/* STiH410 control registers */ +#define STIH410_COMMS_BASE 0x09800000 + +/* ASC UART located in the main "COMMs" block */ +#define STIH410_ASC1_BASE (STIH410_COMMS_BASE + 0x00031000) + #endif /* _STI_H_ */ diff --git a/board/st/stih410-b2260/board.c b/board/st/stih410-b2260/board.c index 0c06bca..72b0042 100644 --- a/board/st/stih410-b2260/board.c +++ b/board/st/stih410-b2260/board.c @@ -7,6 +7,9 @@ */
#include <common.h> +#include <asm/arch/sti.h> +#include <dm/platdata.h> +#include <dm/platform_data/serial_sti_asc.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -26,3 +29,13 @@ int board_init(void) { return 0; } + + +static const struct sti_asc_serial_platdata serial_platdata = { + .base = (struct sti_asc_uart *)STIH410_ASC1_BASE, +}; + +U_BOOT_DEVICE(sti_asc) = { + .name = "serial_sti_asc", + .platdata = &serial_platdata, +}; diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index b11f3ff..7557632 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -413,4 +413,11 @@ config PXA_SERIAL If you have a machine based on a Marvell XScale PXA2xx CPU you can enable its onboard serial ports by enabling this option.
+config STI_ASC_SERIAL + bool "STMicroelectronics on-chip UART" + depends on DM_SERIAL && ARCH_STI + help + Select this to enable Asynchronous Serial Controller available + on STiH410 SoC. + endmenu diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 8430668..84a22ce 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_FSL_LINFLEXUART) += serial_linflexuart.o obj-$(CONFIG_ARC_SERIAL) += serial_arc.o obj-$(CONFIG_UNIPHIER_SERIAL) += serial_uniphier.o obj-$(CONFIG_STM32_SERIAL) += serial_stm32.o +obj-$(CONFIG_STI_ASC_SERIAL) += serial_sti_asc.o obj-$(CONFIG_PIC32_SERIAL) += serial_pic32.o obj-$(CONFIG_STM32X7_SERIAL) += serial_stm32x7.o obj-$(CONFIG_BCM283X_MU_SERIAL) += serial_bcm283x_mu.o diff --git a/drivers/serial/serial_sti_asc.c b/drivers/serial/serial_sti_asc.c new file mode 100644 index 0000000..5279836 --- /dev/null +++ b/drivers/serial/serial_sti_asc.c @@ -0,0 +1,219 @@ +/* + * Support for Serial I/O using STMicroelectronics' on-chip ASC. + * + * Copyright (c) 2017 + * Patrice Chotard patrice.chotard@st.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <dm.h> +#include <serial.h> +#include <asm/arch/sti.h> +#include <asm/io.h> +#include <dm/platform_data/serial_sti_asc.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 0x0200 +#define STA_RBF 0x0001 + +struct sti_asc_uart { + u32 baudrate; + u32 txbuf; + u32 rxbuf; + u32 control; + u32 inten; + u32 status; + u32 guardtime; + u32 timeout; + u32 txreset; + u32 rxreset; +}; + +/*---- 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_platdata *plat = dev->platdata; + struct sti_asc_uart *const uart = plat->base; + unsigned long status; + + status = readl(&uart->status); + if (input) + return status & STA_RBF; + else + return status & STA_TF; +} + +/* called to adjust baud-rate */ +static int sti_asc_serial_setbrg(struct udevice *dev, int baudrate) +{ + struct sti_asc_serial_platdata *plat = dev->platdata; + struct sti_asc_uart *const uart = plat->base; + + 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: + printf("ASC: unsupported baud rate: %d, using 115200 instead.\n", + baudrate); + case 115200: + t = BAUDRATE_VAL_M1(115200); + break; + } + + /* wait for end of current transmission */ + while (sti_asc_pending(dev, false)) + ; + + /* 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; +} + +/* initialize the ASC */ +static int sti_asc_serial_probe(struct udevice *dev) +{ + struct sti_asc_serial_platdata *plat = dev->platdata; + struct sti_asc_uart *const uart = plat->base; + unsigned long val; + + 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, &uart->control); + + return 0; +} + +/* blocking function, that returns next char */ +static int sti_asc_serial_getc(struct udevice *dev) +{ + struct sti_asc_serial_platdata *plat = dev->platdata; + struct sti_asc_uart *const uart = plat->base; + + /* 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_platdata *plat = dev->platdata; + struct sti_asc_uart *const uart = plat->base; + + /* Stream-LF to CR+LF conversion */ + if (c == 10) + sti_asc_serial_putc(dev, '\r'); + + /* wait till safe to write next char */ + while (sti_asc_pending(dev, false)) + ; + + /* finally, write next char */ + writel(c, &uart->txbuf); + + return 0; +} + +static int sti_ofdata_to_platdata(struct udevice *dev) +{ + struct sti_asc_serial_platdata *priv = dev_get_priv(dev); + fdt_addr_t base; + + base = dev_get_addr(dev); + if (base == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->base = (struct sti_asc_uart *)base; + + 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, + .ofdata_to_platdata = sti_ofdata_to_platdata, + .probe = sti_asc_serial_probe, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/include/configs/stih410-b2260.h b/include/configs/stih410-b2260.h index 78103c6..b4b3d75 100644 --- a/include/configs/stih410-b2260.h +++ b/include/configs/stih410-b2260.h @@ -17,6 +17,7 @@ #define CONFIG_SYS_LOAD_ADDR PHYS_SDRAM_1 /* default load addr */
#define CONFIG_BAUDRATE 115200 +#define CONFIG_SYS_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200 }
#define CONFIG_SYS_HZ_CLOCK 1000000000 /* 1 GHz */
diff --git a/include/dm/platform_data/serial_sti_asc.h b/include/dm/platform_data/serial_sti_asc.h new file mode 100644 index 0000000..c8631f1 --- /dev/null +++ b/include/dm/platform_data/serial_sti_asc.h @@ -0,0 +1,17 @@ +/* + * (C) Copyright 2017 + * Patrice Chotard patrice.chotard@st.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __SERIAL_STI_ASC_H +#define __SERIAL_STI_ASC_H + +/* Information about a serial port */ +struct sti_asc_serial_platdata { + /* address of registers in physical memory */ + struct sti_asc_uart *base; +}; + +#endif /* __SERIAL_STI_ASC_H */