
Signed-off-by: Wills Wang wills.wang@live.com ---
drivers/serial/Makefile | 1 + drivers/serial/serial_ar933x.c | 337 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 338 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..6ea500a --- /dev/null +++ b/drivers/serial/serial_ar933x.c @@ -0,0 +1,337 @@ +/* + * (C) Copyright 2015 + * Wills Wang, wills.wang@live.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/addrspace.h> +#include <asm/types.h> +#include <config.h> +#include <serial.h> +#include <asm/arch/ar71xx_regs.h> +#include <asm/arch/ar933x_uart.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define REG_READ(b, o) readl(KSEG1ADDR(b + o)) +#define REG_WRITE(b, o, v) writel(v, KSEG1ADDR((b + o))) +#define UART_READ(a) REG_READ(AR933X_UART_BASE, a) +#define UART_WRITE(a, v) REG_WRITE(AR933X_UART_BASE, a, v) + +static void ar933x_serial_get_scale_step(u32 *uart_scale, u32 *uart_step) +{ + u32 val; + + val = REG_READ(AR71XX_RESET_BASE, AR933X_RESET_REG_BOOTSTRAP); + if (val & AR933X_BOOTSTRAP_REF_CLK_40) { + switch (gd->baudrate) { + case 600: + *uart_scale = 255; + *uart_step = 503; + break; + case 1200: + *uart_scale = 249; + *uart_step = 983; + break; + case 2400: + *uart_scale = 167; + *uart_step = 1321; + break; + case 4800: + *uart_scale = 87; + *uart_step = 1384; + break; + case 9600: + *uart_scale = 45; + *uart_step = 1447; + break; + case 14400: + *uart_scale = 53; + *uart_step = 2548; + break; + case 19200: + *uart_scale = 22; + *uart_step = 1447; + break; + case 28800: + *uart_scale = 26; + *uart_step = 2548; + break; + case 38400: + *uart_scale = 28; + *uart_step = 3649; + break; + case 56000: + *uart_scale = 7; + *uart_step = 1468; + break; + case 57600: + *uart_scale = 34; + *uart_step = 6606; + break; + case 115200: + *uart_scale = 28; + *uart_step = 10947; + break; + case 128000: + *uart_scale = 6; + *uart_step = 2936; + break; + case 153600: + *uart_scale = 18; + *uart_step = 9563; + break; + case 230400: + *uart_scale = 16; + *uart_step = 12834; + break; + case 250000: + *uart_scale = 4; + *uart_step = 4096; + break; + case 256000: + *uart_scale = 6; + *uart_step = 5872; + break; + case 460800: + *uart_scale = 7; + *uart_step = 12079; + break; + case 576000: + *uart_scale = 4; + *uart_step = 9437; + break; + case 921600: + *uart_scale = 3; + *uart_step = 12079; + break; + case 1000000: + *uart_scale = 2; + *uart_step = 9830; + break; + case 1152000: + *uart_scale = 2; + *uart_step = 11324; + break; + case 1500000: + *uart_scale = 0; + *uart_step = 4915; + break; + case 2000000: + *uart_scale = 0; + *uart_step = 6553; + break; + default: + *uart_scale = (40000000 / (16 * gd->baudrate)) - 1; + *uart_step = 8192; + } + } else { + switch (gd->baudrate) { + case 600: + *uart_scale = 255; + *uart_step = 805; + break; + case 1200: + *uart_scale = 209; + *uart_step = 1321; + break; + case 2400: + *uart_scale = 104; + *uart_step = 1321; + break; + case 4800: + *uart_scale = 54; + *uart_step = 1384; + break; + case 9600: + *uart_scale = 78; + *uart_step = 3976; + break; + case 14400: + *uart_scale = 98; + *uart_step = 7474; + break; + case 19200: + *uart_scale = 55; + *uart_step = 5637; + break; + case 28800: + *uart_scale = 77; + *uart_step = 11777; + break; + case 38400: + *uart_scale = 36; + *uart_step = 7449; + break; + case 56000: + *uart_scale = 4; + *uart_step = 1468; + break; + case 57600: + *uart_scale = 35; + *uart_step = 10871; + break; + case 115200: + *uart_scale = 20; + *uart_step = 12683; + break; + case 128000: + *uart_scale = 11; + *uart_step = 8053; + break; + case 153600: + *uart_scale = 9; + *uart_step = 8053; + break; + case 230400: + *uart_scale = 9; + *uart_step = 12079; + break; + case 250000: + *uart_scale = 6; + *uart_step = 9175; + break; + case 256000: + *uart_scale = 5; + *uart_step = 8053; + break; + case 460800: + *uart_scale = 4; + *uart_step = 12079; + break; + case 576000: + *uart_scale = 3; + *uart_step = 12079; + break; + case 921600: + *uart_scale = 1; + *uart_step = 9663; + break; + case 1000000: + *uart_scale = 1; + *uart_step = 10485; + break; + case 1152000: + *uart_scale = 1; + *uart_step = 12079; + break; + case 1500000: + *uart_scale = 0; + *uart_step = 7864; + break; + case 2000000: + *uart_scale = 0; + *uart_step = 10485; + break; + default: + *uart_scale = (25000000 / (16 * gd->baudrate)) - 1; + *uart_step = 8192; + } + } +} + +static void ar933x_serial_setbrg(void) +{ + /* TODO: better clock calculation, baudrate, etc. */ + u32 val, scale, step; + + ar933x_serial_get_scale_step(&scale, &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); + UART_WRITE(AR933X_UART_CLOCK_REG, val); +} + +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 = REG_READ(AR71XX_GPIO_BASE, AR71XX_GPIO_REG_OE); + val |= BIT(10); + REG_WRITE(AR71XX_GPIO_BASE, AR71XX_GPIO_REG_OE, val); + + val = REG_READ(AR71XX_GPIO_BASE, AR71XX_GPIO_REG_FUNC); + val |= (AR933X_GPIO_FUNC_UART_EN | BIT(15)); + REG_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); + UART_WRITE(AR933X_UART_CS_REG, val); + ar933x_serial_setbrg(); + + return 0; +} + +void ar933x_serial_putc(const char c) +{ + u32 data; + + if (c == '\n') + ar933x_serial_putc('\r'); + + do { + data = UART_READ(AR933X_UART_DATA_REG); + } while (!(data & AR933X_UART_DATA_TX_CSR)); + + data = (u32)c | AR933X_UART_DATA_TX_CSR; + UART_WRITE(AR933X_UART_DATA_REG, data); +} + +static int ar933x_serial_getc(void) +{ + u32 data; + + do { + data = UART_READ(AR933X_UART_DATA_REG); + } while (!(data & AR933X_UART_DATA_RX_CSR)); + + data = UART_READ(AR933X_UART_DATA_REG); + UART_WRITE(AR933X_UART_DATA_REG, AR933X_UART_DATA_RX_CSR); + return (int)(data & AR933X_UART_DATA_TX_RX_MASK); +} + +static int ar933x_serial_tstc(void) +{ + u32 data; + + data = UART_READ(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; +}