Hi WIlls, On 24 December 2015 at 04:22, Wills Wang <wills.w...@live.com> wrote: > 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');
With driver model the uclass does this for you. > +#else > + ar933x_serial_putc('\r'); > +#endif > + do { > + data = ar933x_read(AR933X_UART_BASE, AR933X_UART_DATA_REG); > + } while (!(data & AR933X_UART_DATA_TX_CSR)); You should not loop here - the uclass does it. Just return -EAGAIN. > + > + 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)); You should not loop here - the uclass does it. Just return -EAGAIN. > + > + 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 > Regards, SImon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot