[U-Boot] [PATCH v7 4/9] STiH410: Add STi serial driver

patrice.chotard at st.com patrice.chotard at st.com
Tue Feb 21 12:37:07 UTC 2017


From: Patrice Chotard <patrice.chotard at 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 at st.com>
Reviewed-by: Simon Glass <sjg at chromium.org>
---
 arch/arm/Kconfig                |   2 +
 drivers/serial/Kconfig          |   8 ++
 drivers/serial/Makefile         |   1 +
 drivers/serial/serial_sti_asc.c | 211 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 222 insertions(+)
 create mode 100644 drivers/serial/serial_sti_asc.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 4aa5eb9..b91a5b7 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -985,6 +985,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/drivers/serial/Kconfig b/drivers/serial/Kconfig
index b11f3ff..7cb0eaa 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -413,4 +413,12 @@ 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. This is a basic implementation,  it supports
+	  following baudrate 9600, 19200, 38400, 57600 and 115200.
+
 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..ce26c94
--- /dev/null
+++ b/drivers/serial/serial_sti_asc.c
@@ -0,0 +1,211 @@
+/*
+ * Support for Serial I/O using STMicroelectronics' on-chip ASC.
+ *
+ *  Copyright (c) 2017
+ *  Patrice Chotard <patrice.chotard at st.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#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 = dev_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,
+};
+
-- 
1.9.1



More information about the U-Boot mailing list