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

Wills Wang
2015-12-24T11:22:01Z

Signed-off-by: Wills Wang <wills.wang@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@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