Signed-off-by: Wills Wang <wills.w...@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.w...@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');