[U-Boot] [PATCH v3 2/4] mips: ath79: add serial driver for ar933x SOC

Wills Wang wills.wang at live.com
Thu Dec 24 12:22:01 CET 2015


Signed-off-by: Wills Wang <wills.wang at live.com>
---

Changes in v3: None
Changes in v2: None

 drivers/serial/Makefile        |   1 +
 drivers/serial/serial_ar933x.c | 274 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 275 insertions(+)
 create mode 100644 drivers/serial/serial_ar933x.c

diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index dd87147..9a7ad89 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -17,6 +17,7 @@ endif
 
 obj-$(CONFIG_ALTERA_UART) += altera_uart.o
 obj-$(CONFIG_ALTERA_JTAG_UART) += altera_jtag_uart.o
+obj-$(CONFIG_AR933X_SERIAL) += serial_ar933x.o
 obj-$(CONFIG_ARM_DCC) += arm_dcc.o
 obj-$(CONFIG_ATMEL_USART) += atmel_usart.o
 obj-$(CONFIG_EFI_APP) += serial_efi.o
diff --git a/drivers/serial/serial_ar933x.c b/drivers/serial/serial_ar933x.c
new file mode 100644
index 0000000..6c0d726
--- /dev/null
+++ b/drivers/serial/serial_ar933x.c
@@ -0,0 +1,274 @@
+/*
+ * (C) Copyright 2015
+ * Wills Wang, <wills.wang at live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <serial.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <asm/arch/ar71xx_regs.h>
+#include <asm/arch/ar933x_uart.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct ar933x_serial_baudrate{
+	u32 baudrate;
+	u32 scale;
+	u32 step;
+};
+
+const struct ar933x_serial_baudrate baudrate_table_40mhz[] = {
+/*  baudrate,   scale,  step */
+	{600,       255,    503},
+	{1200,      249,    983},
+	{2400,      167,    1321},
+	{4800,      87,     1384},
+	{9600,      45,     1447},
+	{14400,     53,     2548},
+	{19200,     22,     1447},
+	{28800,     26,     2548},
+	{38400,     28,     3649},
+	{56000,     7,      1468},
+	{57600,     34,     6606},
+	{115200,    28,     10947},
+	{128000,    6,      2936},
+	{153600,    18,     9563},
+	{230400,    16,     12834},
+	{250000,    4,      4096},
+	{256000,    6,      5872},
+	{460800,    7,      12079},
+	{576000,    4,      9437},
+	{921600,    3,      12079},
+	{1000000,   2,      9830},
+	{1152000,   2,      11324},
+	{1500000,   0,      4915},
+	{2000000,   0,      6553},
+ };
+
+const struct ar933x_serial_baudrate baudrate_table_25mhz[] = {
+/*  baudrate,   scale,  step */
+	{600,       255,    805},
+	{1200,      209,    1321},
+	{2400,      104,    1321},
+	{4800,      54,     1384},
+	{9600,      78,     3976},
+	{14400,     98,     7474},
+	{19200,     55,     5637},
+	{28800,     77,     11777},
+	{38400,     36,     7449},
+	{56000,     4,      1468},
+	{57600,     35,     10871},
+	{115200,    20,     12683},
+	{128000,    11,     8053},
+	{153600,    9,      8053},
+	{230400,    9,      12079},
+	{250000,    6,      9175},
+	{256000,    5,      8053},
+	{460800,    4,      12079},
+	{576000,    3,      12079},
+	{921600,    1,      9663},
+	{1000000,   1,      10485},
+	{1152000,   1,      12079},
+	{1500000,   0,      7864},
+	{2000000,   0,      10485},
+};
+
+static inline u32 ar933x_read(u32 base, u32 offset)
+{
+	return readl(KSEG1ADDR(base + offset));
+}
+
+static inline void ar933x_write(u32 base, u32 offset, u32 val)
+{
+	writel(val, KSEG1ADDR(base + offset));
+}
+
+static int ar933x_serial_init(void)
+{
+	u32 val;
+
+	/*
+	 * Set GPIO10 (UART_SO) as output and enable UART,
+	 * BIT(15) in GPIO_FUNCTION_1 register must be written with 1
+	 */
+	val = ar933x_read(AR71XX_GPIO_BASE, AR71XX_GPIO_REG_OE);
+	val |= BIT(10);
+	ar933x_write(AR71XX_GPIO_BASE, AR71XX_GPIO_REG_OE, val);
+
+	val = ar933x_read(AR71XX_GPIO_BASE, AR71XX_GPIO_REG_FUNC);
+	val |= (AR933X_GPIO_FUNC_UART_EN | BIT(15));
+	ar933x_write(AR71XX_GPIO_BASE, AR71XX_GPIO_REG_FUNC, val);
+
+	/*
+	 * UART controller configuration:
+	 * - no DMA
+	 * - no interrupt
+	 * - DCE mode
+	 * - no flow control
+	 * - set RX ready oride
+	 * - set TX ready oride
+	 */
+	val = AR933X_UART_CS_TX_READY_ORIDE | AR933X_UART_CS_RX_READY_ORIDE
+		| (AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S);
+	ar933x_write(AR933X_UART_BASE, AR933X_UART_CS_REG, val);
+	return 0;
+}
+
+#ifdef CONFIG_DM_SERIAL
+static int ar933x_serial_setbrg(struct udevice *dev, int baudrate)
+{
+#else
+static void ar933x_serial_setbrg(void)
+{
+	int baudrate = gd->baudrate;
+#endif
+	u32 val, scale, step;
+	const struct ar933x_serial_baudrate *baudrate_table;
+	int i, baudrate_table_size;
+
+	val = ar933x_read(AR71XX_RESET_BASE, AR933X_RESET_REG_BOOTSTRAP);
+	if (val & AR933X_BOOTSTRAP_REF_CLK_40) {
+		baudrate_table = baudrate_table_40mhz;
+		baudrate_table_size = ARRAY_SIZE(baudrate_table_40mhz);
+		scale = (40000000 / (16 * baudrate)) - 1;
+		step = 8192;
+	} else {
+		baudrate_table = baudrate_table_25mhz;
+		baudrate_table_size = ARRAY_SIZE(baudrate_table_25mhz);
+		scale = (25000000 / (16 * baudrate)) - 1;
+		step = 8192;
+	}
+
+	for (i = 0; i < baudrate_table_size; i++) {
+		if (baudrate_table[i].baudrate == gd->baudrate) {
+			scale = baudrate_table[i].scale;
+			step = baudrate_table[i].step;
+		}
+	}
+
+	val  = ((scale & AR933X_UART_CLOCK_SCALE_M)
+			<< AR933X_UART_CLOCK_SCALE_S);
+	val |= ((step & AR933X_UART_CLOCK_STEP_M)
+			<< AR933X_UART_CLOCK_STEP_S);
+	ar933x_write(AR933X_UART_BASE, AR933X_UART_CLOCK_REG, val);
+#ifdef CONFIG_DM_SERIAL
+	return 0;
+#endif
+}
+
+#ifdef CONFIG_DM_SERIAL
+static int ar933x_serial_putc(struct udevice *dev, const char c)
+#else
+static void ar933x_serial_putc(const char c)
+#endif
+{
+	u32 data;
+
+	if (c == '\n')
+#ifdef CONFIG_DM_SERIAL
+		ar933x_serial_putc(dev, '\r');
+#else
+		ar933x_serial_putc('\r');
+#endif
+	do {
+		data = ar933x_read(AR933X_UART_BASE, AR933X_UART_DATA_REG);
+	} while (!(data & AR933X_UART_DATA_TX_CSR));
+
+	data  = (u32)c | AR933X_UART_DATA_TX_CSR;
+	ar933x_write(AR933X_UART_BASE, AR933X_UART_DATA_REG, data);
+#ifdef CONFIG_DM_SERIAL
+	return 0;
+#endif
+}
+
+#ifdef CONFIG_DM_SERIAL
+static int ar933x_serial_getc(struct udevice *dev)
+#else
+static int ar933x_serial_getc(void)
+#endif
+{
+	u32 data;
+
+	do {
+		data = ar933x_read(AR933X_UART_BASE, AR933X_UART_DATA_REG);
+	} while (!(data & AR933X_UART_DATA_RX_CSR));
+
+	data = ar933x_read(AR933X_UART_BASE, AR933X_UART_DATA_REG);
+	ar933x_write(AR933X_UART_BASE, AR933X_UART_DATA_REG, AR933X_UART_DATA_RX_CSR);
+	return data & AR933X_UART_DATA_TX_RX_MASK;
+}
+
+#ifdef CONFIG_DM_SERIAL
+static int ar933x_serial_pending(struct udevice *dev, bool input)
+{
+	u32 data;
+
+	data = ar933x_read(AR933X_UART_BASE, AR933X_UART_DATA_REG);
+	if (input)
+		return (data & AR933X_UART_DATA_RX_CSR) ? 1 : 0;
+	else
+		return (data & AR933X_UART_DATA_TX_CSR) ? 0 : 1;
+}
+
+static int ar933x_serial_probe(struct udevice *dev)
+{
+	ar933x_serial_init();
+	return 0;
+}
+
+static const struct dm_serial_ops ar933x_serial_ops = {
+	.putc = ar933x_serial_putc,
+	.pending = ar933x_serial_pending,
+	.getc = ar933x_serial_getc,
+	.setbrg = ar933x_serial_setbrg,
+};
+
+static const struct udevice_id ar933x_serial_ids[] = {
+	{ .compatible = "ath79,ar933x-uart" },
+	{ }
+};
+
+U_BOOT_DRIVER(serial_ar933x) = {
+	.name   = "serial_ar933x",
+	.id = UCLASS_SERIAL,
+	.of_match = ar933x_serial_ids,
+	.probe = ar933x_serial_probe,
+	.ops    = &ar933x_serial_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+#else
+static int ar933x_serial_tstc(void)
+{
+	u32 data;
+
+	data = ar933x_read(AR933X_UART_BASE, AR933X_UART_DATA_REG);
+	return (data & AR933X_UART_DATA_RX_CSR) ? 1 : 0;
+}
+
+static struct serial_device ar933x_serial_drv = {
+	.name   = "ar933x_serial",
+	.start  = ar933x_serial_init,
+	.stop   = NULL,
+	.setbrg = ar933x_serial_setbrg,
+	.putc   = ar933x_serial_putc,
+	.puts   = default_serial_puts,
+	.getc   = ar933x_serial_getc,
+	.tstc   = ar933x_serial_tstc,
+};
+
+void ar933x_serial_initialize(void)
+{
+	serial_register(&ar933x_serial_drv);
+}
+
+__weak struct serial_device *default_serial_console(void)
+{
+	return &ar933x_serial_drv;
+}
+#endif
-- 
1.9.1



More information about the U-Boot mailing list