
Hi WIlls,
On 24 December 2015 at 04:22, Wills Wang wills.wang@live.com wrote:
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');
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