
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