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

Signed-off-by: Wills Wang wills.wang@live.com ---
Changes in v4: None Changes in v3: None Changes in v2: None
drivers/serial/Makefile | 1 + drivers/serial/serial_ar933x.c | 225 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 226 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..efca93c --- /dev/null +++ b/drivers/serial/serial_ar933x.c @@ -0,0 +1,225 @@ +/* + * (C) Copyright 2015 + * Wills Wang, wills.wang@live.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <serial.h> +#include <asm/io.h> +#include <asm/addrspace.h> +#include <asm/div64.h> +#include <asm/types.h> +#include <asm/arch/ar71xx_regs.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define AR933X_UART_DATA_REG 0x00 +#define AR933X_UART_CS_REG 0x04 +#define AR933X_UART_CLK_REG 0x08 + +#define AR933X_UART_DATA_TX_RX_MASK 0xff +#define AR933X_UART_DATA_RX_CSR BIT(8) +#define AR933X_UART_DATA_TX_CSR BIT(9) +#define AR933X_UART_CS_IF_MODE_S 2 +#define AR933X_UART_CS_IF_MODE_M 0x3 +#define AR933X_UART_CS_IF_MODE_DTE 1 +#define AR933X_UART_CS_IF_MODE_DCE 2 +#define AR933X_UART_CS_TX_RDY_ORIDE BIT(7) +#define AR933X_UART_CS_RX_RDY_ORIDE BIT(8) +#define AR933X_UART_CLK_STEP_M 0xffff +#define AR933X_UART_CLK_SCALE_M 0xfff +#define AR933X_UART_CLK_SCALE_S 16 +#define AR933X_UART_CLK_STEP_S 0 + +struct ar933x_serial_platdata { + void __iomem *regs; +}; + +struct ar933x_serial_priv { + void __iomem *regs; +}; + +static inline u32 ar933x_serial_read(struct udevice *dev, u32 offset) +{ + struct ar933x_serial_priv *priv = dev_get_priv(dev); + return readl(priv->regs + offset); +} + +static inline void ar933x_serial_write(struct udevice *dev, + u32 val, u32 offset) +{ + struct ar933x_serial_priv *priv = dev_get_priv(dev); + writel(val, priv->regs + offset); +} + +/* + * baudrate = (clk / (scale + 1)) * (step * (1 / 2^17)) + */ +static u32 ar933x_serial_get_baud(u32 clk, u32 scale, u32 step) +{ + u64 t; + u32 div; + + div = (2 << 16) * (scale + 1); + t = clk; + t *= step; + t += (div / 2); + do_div(t, div); + + return t; +} + +static void ar933x_serial_get_scale_step(u32 clk, u32 baud, + u32 *scale, u32 *step) +{ + u32 tscale, baudrate; + long min_diff; + + *scale = 0; + *step = 0; + + min_diff = baud; + for (tscale = 0; tscale < AR933X_UART_CLK_SCALE_M; tscale++) { + u64 tstep; + int diff; + + tstep = baud * (tscale + 1); + tstep *= (2 << 16); + do_div(tstep, clk); + + if (tstep > AR933X_UART_CLK_STEP_M) + break; + + baudrate = ar933x_serial_get_baud(clk, tscale, tstep); + diff = abs(baudrate - baud); + if (diff < min_diff) { + min_diff = diff; + *scale = tscale; + *step = tstep; + } + } +} + +static int ar933x_serial_setbrg(struct udevice *dev, int baudrate) +{ + u32 val, scale, step; + + val = get_serial_clock(); + ar933x_serial_get_scale_step(val, baudrate, &scale, &step); + + val = (scale & AR933X_UART_CLK_SCALE_M) + << AR933X_UART_CLK_SCALE_S; + val |= (step & AR933X_UART_CLK_STEP_M) + << AR933X_UART_CLK_STEP_S; + ar933x_serial_write(dev, val, AR933X_UART_CLK_REG); + + return 0; +} + +static int ar933x_serial_putc(struct udevice *dev, const char c) +{ + u32 data; + + if (c == '\n') + ar933x_serial_putc(dev, '\r'); + + do { + data = ar933x_serial_read(dev, AR933X_UART_DATA_REG); + } while (!(data & AR933X_UART_DATA_TX_CSR)); + + data = (u32)c | AR933X_UART_DATA_TX_CSR; + ar933x_serial_write(dev, data, AR933X_UART_DATA_REG); + + return 0; +} + +static int ar933x_serial_getc(struct udevice *dev) +{ + u32 data; + + do { + data = ar933x_serial_read(dev, AR933X_UART_DATA_REG); + } while (!(data & AR933X_UART_DATA_RX_CSR)); + + data = ar933x_serial_read(dev, AR933X_UART_DATA_REG); + ar933x_serial_write(dev, AR933X_UART_DATA_RX_CSR, + AR933X_UART_DATA_REG); + return data & AR933X_UART_DATA_TX_RX_MASK; +} + +static int ar933x_serial_pending(struct udevice *dev, bool input) +{ + u32 data; + + data = ar933x_serial_read(dev, 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) +{ + struct ar933x_serial_priv *priv = dev_get_priv(dev); + struct ar933x_serial_platdata *plat = dev_get_platdata(dev); + u32 val; + + priv->regs = plat->regs; + + /* + * UART controller configuration: + * - no DMA + * - no interrupt + * - DCE mode + * - no flow control + * - set RX ready oride + * - set TX ready oride + */ + val = (AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S) | + AR933X_UART_CS_TX_RDY_ORIDE | AR933X_UART_CS_RX_RDY_ORIDE; + ar933x_serial_write(dev, val, AR933X_UART_CS_REG); + return 0; +} + +static int ar933x_serial_ofdata_to_platdata(struct udevice *dev) +{ + struct ar933x_serial_platdata *plat = dev_get_platdata(dev); + fdt_addr_t addr; + + addr = dev_get_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + plat->regs = map_physmem(addr, + AR933X_UART_SIZE, + MAP_NOCACHE); + 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, + .ofdata_to_platdata = ar933x_serial_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct ar933x_serial_platdata), + .priv_auto_alloc_size = sizeof(struct ar933x_serial_priv), + .probe = ar933x_serial_probe, + .ops = &ar933x_serial_ops, + .flags = DM_FLAG_PRE_RELOC, +};

Am 25.12.2015 um 19:56 schrieb Wills Wang:
Signed-off-by: Wills Wang wills.wang@live.com
Changes in v4: None Changes in v3: None Changes in v2: None
drivers/serial/Makefile | 1 + drivers/serial/serial_ar933x.c | 225 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 226 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..efca93c --- /dev/null +++ b/drivers/serial/serial_ar933x.c @@ -0,0 +1,225 @@ +/*
- (C) Copyright 2015
- Wills Wang, wills.wang@live.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <dm.h> +#include <errno.h> +#include <serial.h> +#include <asm/io.h> +#include <asm/addrspace.h> +#include <asm/div64.h>
use the existing and generic implementation in include/div64.h
+#include <asm/types.h> +#include <asm/arch/ar71xx_regs.h>
#include <mach/ar71xx_regs.h>
I wonder how you can stil compile your code
+DECLARE_GLOBAL_DATA_PTR;
+#define AR933X_UART_DATA_REG 0x00 +#define AR933X_UART_CS_REG 0x04 +#define AR933X_UART_CLK_REG 0x08
+#define AR933X_UART_DATA_TX_RX_MASK 0xff +#define AR933X_UART_DATA_RX_CSR BIT(8) +#define AR933X_UART_DATA_TX_CSR BIT(9) +#define AR933X_UART_CS_IF_MODE_S 2 +#define AR933X_UART_CS_IF_MODE_M 0x3 +#define AR933X_UART_CS_IF_MODE_DTE 1 +#define AR933X_UART_CS_IF_MODE_DCE 2 +#define AR933X_UART_CS_TX_RDY_ORIDE BIT(7) +#define AR933X_UART_CS_RX_RDY_ORIDE BIT(8) +#define AR933X_UART_CLK_STEP_M 0xffff +#define AR933X_UART_CLK_SCALE_M 0xfff +#define AR933X_UART_CLK_SCALE_S 16 +#define AR933X_UART_CLK_STEP_S 0
+struct ar933x_serial_platdata {
- void __iomem *regs;
+};
if you always support device-tree, you do not need platform data
+struct ar933x_serial_priv {
- void __iomem *regs;
+};
+static inline u32 ar933x_serial_read(struct udevice *dev, u32 offset) +{
- struct ar933x_serial_priv *priv = dev_get_priv(dev);
- return readl(priv->regs + offset);
+}
+static inline void ar933x_serial_write(struct udevice *dev,
u32 val, u32 offset)
+{
- struct ar933x_serial_priv *priv = dev_get_priv(dev);
- writel(val, priv->regs + offset);
+}
+/*
- baudrate = (clk / (scale + 1)) * (step * (1 / 2^17))
- */
+static u32 ar933x_serial_get_baud(u32 clk, u32 scale, u32 step) +{
- u64 t;
- u32 div;
- div = (2 << 16) * (scale + 1);
- t = clk;
- t *= step;
- t += (div / 2);
- do_div(t, div);
- return t;
+}
+static void ar933x_serial_get_scale_step(u32 clk, u32 baud,
u32 *scale, u32 *step)
+{
- u32 tscale, baudrate;
- long min_diff;
- *scale = 0;
- *step = 0;
- min_diff = baud;
- for (tscale = 0; tscale < AR933X_UART_CLK_SCALE_M; tscale++) {
u64 tstep;
int diff;
tstep = baud * (tscale + 1);
tstep *= (2 << 16);
do_div(tstep, clk);
if (tstep > AR933X_UART_CLK_STEP_M)
break;
baudrate = ar933x_serial_get_baud(clk, tscale, tstep);
diff = abs(baudrate - baud);
if (diff < min_diff) {
min_diff = diff;
*scale = tscale;
*step = tstep;
}
- }
+}
+static int ar933x_serial_setbrg(struct udevice *dev, int baudrate) +{
- u32 val, scale, step;
- val = get_serial_clock();
- ar933x_serial_get_scale_step(val, baudrate, &scale, &step);
- val = (scale & AR933X_UART_CLK_SCALE_M)
<< AR933X_UART_CLK_SCALE_S;
- val |= (step & AR933X_UART_CLK_STEP_M)
<< AR933X_UART_CLK_STEP_S;
- ar933x_serial_write(dev, val, AR933X_UART_CLK_REG);
- return 0;
+}
+static int ar933x_serial_putc(struct udevice *dev, const char c) +{
- u32 data;
- if (c == '\n')
ar933x_serial_putc(dev, '\r');
remove this, the serial core driver takes care of it
- do {
data = ar933x_serial_read(dev, AR933X_UART_DATA_REG);
- } while (!(data & AR933X_UART_DATA_TX_CSR));
remove this, the serial core driver takes care of it via your pending callback (ar933x_serial_pending)
- data = (u32)c | AR933X_UART_DATA_TX_CSR;
- ar933x_serial_write(dev, data, AR933X_UART_DATA_REG);
- return 0;
+}
+static int ar933x_serial_getc(struct udevice *dev) +{
- u32 data;
- do {
data = ar933x_serial_read(dev, AR933X_UART_DATA_REG);
- } while (!(data & AR933X_UART_DATA_RX_CSR));
dito
- data = ar933x_serial_read(dev, AR933X_UART_DATA_REG);
- ar933x_serial_write(dev, AR933X_UART_DATA_RX_CSR,
AR933X_UART_DATA_REG);
- return data & AR933X_UART_DATA_TX_RX_MASK;
+}
+static int ar933x_serial_pending(struct udevice *dev, bool input) +{
- u32 data;
- data = ar933x_serial_read(dev, 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) +{
- struct ar933x_serial_priv *priv = dev_get_priv(dev);
- struct ar933x_serial_platdata *plat = dev_get_platdata(dev);
- u32 val;
- priv->regs = plat->regs;
- /*
* UART controller configuration:
* - no DMA
* - no interrupt
* - DCE mode
* - no flow control
* - set RX ready oride
* - set TX ready oride
*/
- val = (AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S) |
AR933X_UART_CS_TX_RDY_ORIDE | AR933X_UART_CS_RX_RDY_ORIDE;
- ar933x_serial_write(dev, val, AR933X_UART_CS_REG);
- return 0;
+}
+static int ar933x_serial_ofdata_to_platdata(struct udevice *dev) +{
- struct ar933x_serial_platdata *plat = dev_get_platdata(dev);
- fdt_addr_t addr;
- addr = dev_get_addr(dev);
- if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
- plat->regs = map_physmem(addr,
AR933X_UART_SIZE,
MAP_NOCACHE);
move this code to function ar933x_serial_probe and drop this function
- 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,
- .ofdata_to_platdata = ar933x_serial_ofdata_to_platdata,
- .platdata_auto_alloc_size = sizeof(struct ar933x_serial_platdata),
drop the two lines, you do not need to allocate platdata
- .priv_auto_alloc_size = sizeof(struct ar933x_serial_priv),
- .probe = ar933x_serial_probe,
- .ops = &ar933x_serial_ops,
- .flags = DM_FLAG_PRE_RELOC,
+};

On 12/26/2015 09:20 PM, Daniel Schwierzeck wrote:
Am 25.12.2015 um 19:56 schrieb Wills Wang:
Signed-off-by: Wills Wang wills.wang@live.com
Changes in v4: None Changes in v3: None Changes in v2: None
drivers/serial/Makefile | 1 + drivers/serial/serial_ar933x.c | 225 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 226 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..efca93c --- /dev/null +++ b/drivers/serial/serial_ar933x.c @@ -0,0 +1,225 @@ +/*
- (C) Copyright 2015
- Wills Wang, wills.wang@live.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <dm.h> +#include <errno.h> +#include <serial.h> +#include <asm/io.h> +#include <asm/addrspace.h> +#include <asm/div64.h>
use the existing and generic implementation in include/div64.h
Ok.
+#include <asm/types.h> +#include <asm/arch/ar71xx_regs.h>
#include <mach/ar71xx_regs.h>
I wonder how you can stil compile your code
U-boot create symbolic links from arch/mips/mach-ath79/include/mach to arch/mips/include/asm/arch.
+DECLARE_GLOBAL_DATA_PTR;
+#define AR933X_UART_DATA_REG 0x00 +#define AR933X_UART_CS_REG 0x04 +#define AR933X_UART_CLK_REG 0x08
+#define AR933X_UART_DATA_TX_RX_MASK 0xff +#define AR933X_UART_DATA_RX_CSR BIT(8) +#define AR933X_UART_DATA_TX_CSR BIT(9) +#define AR933X_UART_CS_IF_MODE_S 2 +#define AR933X_UART_CS_IF_MODE_M 0x3 +#define AR933X_UART_CS_IF_MODE_DTE 1 +#define AR933X_UART_CS_IF_MODE_DCE 2 +#define AR933X_UART_CS_TX_RDY_ORIDE BIT(7) +#define AR933X_UART_CS_RX_RDY_ORIDE BIT(8) +#define AR933X_UART_CLK_STEP_M 0xffff +#define AR933X_UART_CLK_SCALE_M 0xfff +#define AR933X_UART_CLK_SCALE_S 16 +#define AR933X_UART_CLK_STEP_S 0
+struct ar933x_serial_platdata {
- void __iomem *regs;
+};
if you always support device-tree, you do not need platform data
Ok.
+struct ar933x_serial_priv {
- void __iomem *regs;
+};
+static inline u32 ar933x_serial_read(struct udevice *dev, u32 offset) +{
- struct ar933x_serial_priv *priv = dev_get_priv(dev);
- return readl(priv->regs + offset);
+}
+static inline void ar933x_serial_write(struct udevice *dev,
u32 val, u32 offset)
+{
- struct ar933x_serial_priv *priv = dev_get_priv(dev);
- writel(val, priv->regs + offset);
+}
+/*
- baudrate = (clk / (scale + 1)) * (step * (1 / 2^17))
- */
+static u32 ar933x_serial_get_baud(u32 clk, u32 scale, u32 step) +{
- u64 t;
- u32 div;
- div = (2 << 16) * (scale + 1);
- t = clk;
- t *= step;
- t += (div / 2);
- do_div(t, div);
- return t;
+}
+static void ar933x_serial_get_scale_step(u32 clk, u32 baud,
u32 *scale, u32 *step)
+{
- u32 tscale, baudrate;
- long min_diff;
- *scale = 0;
- *step = 0;
- min_diff = baud;
- for (tscale = 0; tscale < AR933X_UART_CLK_SCALE_M; tscale++) {
u64 tstep;
int diff;
tstep = baud * (tscale + 1);
tstep *= (2 << 16);
do_div(tstep, clk);
if (tstep > AR933X_UART_CLK_STEP_M)
break;
baudrate = ar933x_serial_get_baud(clk, tscale, tstep);
diff = abs(baudrate - baud);
if (diff < min_diff) {
min_diff = diff;
*scale = tscale;
*step = tstep;
}
- }
+}
+static int ar933x_serial_setbrg(struct udevice *dev, int baudrate) +{
- u32 val, scale, step;
- val = get_serial_clock();
- ar933x_serial_get_scale_step(val, baudrate, &scale, &step);
- val = (scale & AR933X_UART_CLK_SCALE_M)
<< AR933X_UART_CLK_SCALE_S;
- val |= (step & AR933X_UART_CLK_STEP_M)
<< AR933X_UART_CLK_STEP_S;
- ar933x_serial_write(dev, val, AR933X_UART_CLK_REG);
- return 0;
+}
+static int ar933x_serial_putc(struct udevice *dev, const char c) +{
- u32 data;
- if (c == '\n')
ar933x_serial_putc(dev, '\r');
remove this, the serial core driver takes care of it
Ok.
- do {
data = ar933x_serial_read(dev, AR933X_UART_DATA_REG);
- } while (!(data & AR933X_UART_DATA_TX_CSR));
remove this, the serial core driver takes care of it via your pending callback (ar933x_serial_pending)
Ok.
- data = (u32)c | AR933X_UART_DATA_TX_CSR;
- ar933x_serial_write(dev, data, AR933X_UART_DATA_REG);
- return 0;
+}
+static int ar933x_serial_getc(struct udevice *dev) +{
- u32 data;
- do {
data = ar933x_serial_read(dev, AR933X_UART_DATA_REG);
- } while (!(data & AR933X_UART_DATA_RX_CSR));
dito
Ok.
- data = ar933x_serial_read(dev, AR933X_UART_DATA_REG);
- ar933x_serial_write(dev, AR933X_UART_DATA_RX_CSR,
AR933X_UART_DATA_REG);
- return data & AR933X_UART_DATA_TX_RX_MASK;
+}
+static int ar933x_serial_pending(struct udevice *dev, bool input) +{
- u32 data;
- data = ar933x_serial_read(dev, 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) +{
- struct ar933x_serial_priv *priv = dev_get_priv(dev);
- struct ar933x_serial_platdata *plat = dev_get_platdata(dev);
- u32 val;
- priv->regs = plat->regs;
- /*
* UART controller configuration:
* - no DMA
* - no interrupt
* - DCE mode
* - no flow control
* - set RX ready oride
* - set TX ready oride
*/
- val = (AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S) |
AR933X_UART_CS_TX_RDY_ORIDE | AR933X_UART_CS_RX_RDY_ORIDE;
- ar933x_serial_write(dev, val, AR933X_UART_CS_REG);
- return 0;
+}
+static int ar933x_serial_ofdata_to_platdata(struct udevice *dev) +{
- struct ar933x_serial_platdata *plat = dev_get_platdata(dev);
- fdt_addr_t addr;
- addr = dev_get_addr(dev);
- if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
- plat->regs = map_physmem(addr,
AR933X_UART_SIZE,
MAP_NOCACHE);
move this code to function ar933x_serial_probe and drop this function
Ok.
- 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,
- .ofdata_to_platdata = ar933x_serial_ofdata_to_platdata,
- .platdata_auto_alloc_size = sizeof(struct ar933x_serial_platdata),
drop the two lines, you do not need to allocate platdata
Ok.
- .priv_auto_alloc_size = sizeof(struct ar933x_serial_priv),
- .probe = ar933x_serial_probe,
- .ops = &ar933x_serial_ops,
- .flags = DM_FLAG_PRE_RELOC,
+};

Am 26.12.2015 um 17:54 schrieb Wills Wang:
On 12/26/2015 09:20 PM, Daniel Schwierzeck wrote:
Am 25.12.2015 um 19:56 schrieb Wills Wang:
Signed-off-by: Wills Wang wills.wang@live.com
Changes in v4: None Changes in v3: None Changes in v2: None
drivers/serial/Makefile | 1 + drivers/serial/serial_ar933x.c | 225 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 226 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..efca93c --- /dev/null +++ b/drivers/serial/serial_ar933x.c @@ -0,0 +1,225 @@ +/*
- (C) Copyright 2015
- Wills Wang, wills.wang@live.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <dm.h> +#include <errno.h> +#include <serial.h> +#include <asm/io.h> +#include <asm/addrspace.h> +#include <asm/div64.h>
use the existing and generic implementation in include/div64.h
Ok.
+#include <asm/types.h> +#include <asm/arch/ar71xx_regs.h>
#include <mach/ar71xx_regs.h>
I wonder how you can stil compile your code
U-boot create symbolic links from arch/mips/mach-ath79/include/mach to arch/mips/include/asm/arch.
but it should not. Only if you enable CREATE_ARCH_SYMLINK. Maybe this is some magic for backward compatibility. Anyway the long-term goal is to remove the creation of symbolic links and to use "#include <mach/file.h>".
+DECLARE_GLOBAL_DATA_PTR;
+#define AR933X_UART_DATA_REG 0x00 +#define AR933X_UART_CS_REG 0x04 +#define AR933X_UART_CLK_REG 0x08
+#define AR933X_UART_DATA_TX_RX_MASK 0xff +#define AR933X_UART_DATA_RX_CSR BIT(8) +#define AR933X_UART_DATA_TX_CSR BIT(9) +#define AR933X_UART_CS_IF_MODE_S 2 +#define AR933X_UART_CS_IF_MODE_M 0x3 +#define AR933X_UART_CS_IF_MODE_DTE 1 +#define AR933X_UART_CS_IF_MODE_DCE 2 +#define AR933X_UART_CS_TX_RDY_ORIDE BIT(7) +#define AR933X_UART_CS_RX_RDY_ORIDE BIT(8) +#define AR933X_UART_CLK_STEP_M 0xffff +#define AR933X_UART_CLK_SCALE_M 0xfff +#define AR933X_UART_CLK_SCALE_S 16 +#define AR933X_UART_CLK_STEP_S 0
+struct ar933x_serial_platdata {
- void __iomem *regs;
+};
if you always support device-tree, you do not need platform data
Ok.
+struct ar933x_serial_priv {
- void __iomem *regs;
+};
+static inline u32 ar933x_serial_read(struct udevice *dev, u32 offset) +{
- struct ar933x_serial_priv *priv = dev_get_priv(dev);
- return readl(priv->regs + offset);
+}
+static inline void ar933x_serial_write(struct udevice *dev,
u32 val, u32 offset)
+{
- struct ar933x_serial_priv *priv = dev_get_priv(dev);
- writel(val, priv->regs + offset);
+}
+/*
- baudrate = (clk / (scale + 1)) * (step * (1 / 2^17))
- */
+static u32 ar933x_serial_get_baud(u32 clk, u32 scale, u32 step) +{
- u64 t;
- u32 div;
- div = (2 << 16) * (scale + 1);
- t = clk;
- t *= step;
- t += (div / 2);
- do_div(t, div);
- return t;
+}
+static void ar933x_serial_get_scale_step(u32 clk, u32 baud,
u32 *scale, u32 *step)
+{
- u32 tscale, baudrate;
- long min_diff;
- *scale = 0;
- *step = 0;
- min_diff = baud;
- for (tscale = 0; tscale < AR933X_UART_CLK_SCALE_M; tscale++) {
u64 tstep;
int diff;
tstep = baud * (tscale + 1);
tstep *= (2 << 16);
do_div(tstep, clk);
if (tstep > AR933X_UART_CLK_STEP_M)
break;
baudrate = ar933x_serial_get_baud(clk, tscale, tstep);
diff = abs(baudrate - baud);
if (diff < min_diff) {
min_diff = diff;
*scale = tscale;
*step = tstep;
}
- }
+}
+static int ar933x_serial_setbrg(struct udevice *dev, int baudrate) +{
- u32 val, scale, step;
- val = get_serial_clock();
- ar933x_serial_get_scale_step(val, baudrate, &scale, &step);
- val = (scale & AR933X_UART_CLK_SCALE_M)
<< AR933X_UART_CLK_SCALE_S;
- val |= (step & AR933X_UART_CLK_STEP_M)
<< AR933X_UART_CLK_STEP_S;
- ar933x_serial_write(dev, val, AR933X_UART_CLK_REG);
- return 0;
+}
+static int ar933x_serial_putc(struct udevice *dev, const char c) +{
- u32 data;
- if (c == '\n')
ar933x_serial_putc(dev, '\r');
remove this, the serial core driver takes care of it
Ok.
- do {
data = ar933x_serial_read(dev, AR933X_UART_DATA_REG);
- } while (!(data & AR933X_UART_DATA_TX_CSR));
remove this, the serial core driver takes care of it via your pending callback (ar933x_serial_pending)
Ok.
- data = (u32)c | AR933X_UART_DATA_TX_CSR;
- ar933x_serial_write(dev, data, AR933X_UART_DATA_REG);
- return 0;
+}
+static int ar933x_serial_getc(struct udevice *dev) +{
- u32 data;
- do {
data = ar933x_serial_read(dev, AR933X_UART_DATA_REG);
- } while (!(data & AR933X_UART_DATA_RX_CSR));
dito
Ok.
- data = ar933x_serial_read(dev, AR933X_UART_DATA_REG);
- ar933x_serial_write(dev, AR933X_UART_DATA_RX_CSR,
AR933X_UART_DATA_REG);
- return data & AR933X_UART_DATA_TX_RX_MASK;
+}
+static int ar933x_serial_pending(struct udevice *dev, bool input) +{
- u32 data;
- data = ar933x_serial_read(dev, 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) +{
- struct ar933x_serial_priv *priv = dev_get_priv(dev);
- struct ar933x_serial_platdata *plat = dev_get_platdata(dev);
- u32 val;
- priv->regs = plat->regs;
- /*
* UART controller configuration:
* - no DMA
* - no interrupt
* - DCE mode
* - no flow control
* - set RX ready oride
* - set TX ready oride
*/
- val = (AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S) |
AR933X_UART_CS_TX_RDY_ORIDE | AR933X_UART_CS_RX_RDY_ORIDE;
- ar933x_serial_write(dev, val, AR933X_UART_CS_REG);
- return 0;
+}
+static int ar933x_serial_ofdata_to_platdata(struct udevice *dev) +{
- struct ar933x_serial_platdata *plat = dev_get_platdata(dev);
- fdt_addr_t addr;
- addr = dev_get_addr(dev);
- if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
- plat->regs = map_physmem(addr,
AR933X_UART_SIZE,
MAP_NOCACHE);
move this code to function ar933x_serial_probe and drop this function
Ok.
- 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,
- .ofdata_to_platdata = ar933x_serial_ofdata_to_platdata,
- .platdata_auto_alloc_size = sizeof(struct ar933x_serial_platdata),
drop the two lines, you do not need to allocate platdata
Ok.
- .priv_auto_alloc_size = sizeof(struct ar933x_serial_priv),
- .probe = ar933x_serial_probe,
- .ops = &ar933x_serial_ops,
- .flags = DM_FLAG_PRE_RELOC,
+};

On 12/26/2015 09:20 PM, Daniel Schwierzeck wrote:
Am 25.12.2015 um 19:56 schrieb Wills Wang:
Signed-off-by: Wills Wang wills.wang@live.com
Changes in v4: None Changes in v3: None Changes in v2: None
drivers/serial/Makefile | 1 + drivers/serial/serial_ar933x.c | 225 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 226 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..efca93c --- /dev/null +++ b/drivers/serial/serial_ar933x.c @@ -0,0 +1,225 @@ +/*
- (C) Copyright 2015
- Wills Wang, wills.wang@live.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <dm.h> +#include <errno.h> +#include <serial.h> +#include <asm/io.h> +#include <asm/addrspace.h> +#include <asm/div64.h>
use the existing and generic implementation in include/div64.h
+#include <asm/types.h> +#include <asm/arch/ar71xx_regs.h>
#include <mach/ar71xx_regs.h>
I wonder how you can stil compile your code
+DECLARE_GLOBAL_DATA_PTR;
+#define AR933X_UART_DATA_REG 0x00 +#define AR933X_UART_CS_REG 0x04 +#define AR933X_UART_CLK_REG 0x08
+#define AR933X_UART_DATA_TX_RX_MASK 0xff +#define AR933X_UART_DATA_RX_CSR BIT(8) +#define AR933X_UART_DATA_TX_CSR BIT(9) +#define AR933X_UART_CS_IF_MODE_S 2 +#define AR933X_UART_CS_IF_MODE_M 0x3 +#define AR933X_UART_CS_IF_MODE_DTE 1 +#define AR933X_UART_CS_IF_MODE_DCE 2 +#define AR933X_UART_CS_TX_RDY_ORIDE BIT(7) +#define AR933X_UART_CS_RX_RDY_ORIDE BIT(8) +#define AR933X_UART_CLK_STEP_M 0xffff +#define AR933X_UART_CLK_SCALE_M 0xfff +#define AR933X_UART_CLK_SCALE_S 16 +#define AR933X_UART_CLK_STEP_S 0
+struct ar933x_serial_platdata {
- void __iomem *regs;
+};
if you always support device-tree, you do not need platform data
+struct ar933x_serial_priv {
- void __iomem *regs;
+};
+static inline u32 ar933x_serial_read(struct udevice *dev, u32 offset) +{
- struct ar933x_serial_priv *priv = dev_get_priv(dev);
- return readl(priv->regs + offset);
+}
+static inline void ar933x_serial_write(struct udevice *dev,
u32 val, u32 offset)
+{
- struct ar933x_serial_priv *priv = dev_get_priv(dev);
- writel(val, priv->regs + offset);
+}
+/*
- baudrate = (clk / (scale + 1)) * (step * (1 / 2^17))
- */
+static u32 ar933x_serial_get_baud(u32 clk, u32 scale, u32 step) +{
- u64 t;
- u32 div;
- div = (2 << 16) * (scale + 1);
- t = clk;
- t *= step;
- t += (div / 2);
- do_div(t, div);
- return t;
+}
+static void ar933x_serial_get_scale_step(u32 clk, u32 baud,
u32 *scale, u32 *step)
+{
- u32 tscale, baudrate;
- long min_diff;
- *scale = 0;
- *step = 0;
- min_diff = baud;
- for (tscale = 0; tscale < AR933X_UART_CLK_SCALE_M; tscale++) {
u64 tstep;
int diff;
tstep = baud * (tscale + 1);
tstep *= (2 << 16);
do_div(tstep, clk);
if (tstep > AR933X_UART_CLK_STEP_M)
break;
baudrate = ar933x_serial_get_baud(clk, tscale, tstep);
diff = abs(baudrate - baud);
if (diff < min_diff) {
min_diff = diff;
*scale = tscale;
*step = tstep;
}
- }
+}
+static int ar933x_serial_setbrg(struct udevice *dev, int baudrate) +{
- u32 val, scale, step;
- val = get_serial_clock();
- ar933x_serial_get_scale_step(val, baudrate, &scale, &step);
- val = (scale & AR933X_UART_CLK_SCALE_M)
<< AR933X_UART_CLK_SCALE_S;
- val |= (step & AR933X_UART_CLK_STEP_M)
<< AR933X_UART_CLK_STEP_S;
- ar933x_serial_write(dev, val, AR933X_UART_CLK_REG);
- return 0;
+}
+static int ar933x_serial_putc(struct udevice *dev, const char c) +{
- u32 data;
- if (c == '\n')
ar933x_serial_putc(dev, '\r');
remove this, the serial core driver takes care of it
- do {
data = ar933x_serial_read(dev, AR933X_UART_DATA_REG);
- } while (!(data & AR933X_UART_DATA_TX_CSR));
remove this, the serial core driver takes care of it via your pending callback (ar933x_serial_pending)
Serial core driver don't query and wait the pending function before "serial_getc" and "serial_putc", so these statements can't remove, or board don't work.
- data = (u32)c | AR933X_UART_DATA_TX_CSR;
- ar933x_serial_write(dev, data, AR933X_UART_DATA_REG);
- return 0;
+}
+static int ar933x_serial_getc(struct udevice *dev) +{
- u32 data;
- do {
data = ar933x_serial_read(dev, AR933X_UART_DATA_REG);
- } while (!(data & AR933X_UART_DATA_RX_CSR));
dito
ditto
- data = ar933x_serial_read(dev, AR933X_UART_DATA_REG);
- ar933x_serial_write(dev, AR933X_UART_DATA_RX_CSR,
AR933X_UART_DATA_REG);
- return data & AR933X_UART_DATA_TX_RX_MASK;
+}
+static int ar933x_serial_pending(struct udevice *dev, bool input) +{
- u32 data;
- data = ar933x_serial_read(dev, 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) +{
- struct ar933x_serial_priv *priv = dev_get_priv(dev);
- struct ar933x_serial_platdata *plat = dev_get_platdata(dev);
- u32 val;
- priv->regs = plat->regs;
- /*
* UART controller configuration:
* - no DMA
* - no interrupt
* - DCE mode
* - no flow control
* - set RX ready oride
* - set TX ready oride
*/
- val = (AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S) |
AR933X_UART_CS_TX_RDY_ORIDE | AR933X_UART_CS_RX_RDY_ORIDE;
- ar933x_serial_write(dev, val, AR933X_UART_CS_REG);
- return 0;
+}
+static int ar933x_serial_ofdata_to_platdata(struct udevice *dev) +{
- struct ar933x_serial_platdata *plat = dev_get_platdata(dev);
- fdt_addr_t addr;
- addr = dev_get_addr(dev);
- if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
- plat->regs = map_physmem(addr,
AR933X_UART_SIZE,
MAP_NOCACHE);
move this code to function ar933x_serial_probe and drop this function
- 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,
- .ofdata_to_platdata = ar933x_serial_ofdata_to_platdata,
- .platdata_auto_alloc_size = sizeof(struct ar933x_serial_platdata),
drop the two lines, you do not need to allocate platdata
- .priv_auto_alloc_size = sizeof(struct ar933x_serial_priv),
- .probe = ar933x_serial_probe,
- .ops = &ar933x_serial_ops,
- .flags = DM_FLAG_PRE_RELOC,
+};

Hi Wills,
On 2015年12月27日 14:28, Wills Wang wrote:
+static int ar933x_serial_putc(struct udevice *dev, const char c) +{
- u32 data;
- if (c == '\n')
ar933x_serial_putc(dev, '\r');
remove this, the serial core driver takes care of it
- do {
data = ar933x_serial_read(dev, AR933X_UART_DATA_REG);
- } while (!(data & AR933X_UART_DATA_TX_CSR));
remove this, the serial core driver takes care of it via your pending callback (ar933x_serial_pending)
Serial core driver don't query and wait the pending function before "serial_getc" and "serial_putc", so these statements can't remove, or board don't work.
As I wrote in the v3 patch review, both the getc() and putc() should return -EAGAIN if there is no available data to read or not ready to write. The polling is done in the serial-uclass.c
Regards, Thomas

Hi Wills,
Please note the following,
1. add this uart to drivers/serial/Kconfig .
2. add debug uart support. see include/debug_uart.h . also add it to Kconfig
3. cp linux/Documentation/devicetree/bindings/serial/qca,ar9330-uart.txt u-boot/doc/device-tree-bindings/serial/
4. to save change to xxx_defconfig, run make savedefconfig cp defconfig configs/xxx_defconfig
Best regards, Thomas

Hi Wills,
On 2015年12月26日 21:20, Daniel Schwierzeck wrote:
+static int ar933x_serial_probe(struct udevice *dev) +{
- struct ar933x_serial_priv *priv = dev_get_priv(dev);
- struct ar933x_serial_platdata *plat = dev_get_platdata(dev);
- u32 val;
- priv->regs = plat->regs;
- /*
* UART controller configuration:
* - no DMA
* - no interrupt
* - DCE mode
* - no flow control
* - set RX ready oride
* - set TX ready oride
*/
- val = (AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S) |
AR933X_UART_CS_TX_RDY_ORIDE | AR933X_UART_CS_RX_RDY_ORIDE;
- ar933x_serial_write(dev, val, AR933X_UART_CS_REG);
- return 0;
+}
+static int ar933x_serial_ofdata_to_platdata(struct udevice *dev) +{
- struct ar933x_serial_platdata *plat = dev_get_platdata(dev);
- fdt_addr_t addr;
- addr = dev_get_addr(dev);
- if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
- plat->regs = map_physmem(addr,
AR933X_UART_SIZE,
MAP_NOCACHE);
move this code to function ar933x_serial_probe and drop this function
- 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,
- .ofdata_to_platdata = ar933x_serial_ofdata_to_platdata,
- .platdata_auto_alloc_size = sizeof(struct ar933x_serial_platdata),
drop the two lines, you do not need to allocate platdata
It might be another option to keep platdata and ofdata_to_platdata(), and remove the priv data. Let ofdata_to_platdata() do the DT conversion and probe() detect and initialize the hardware. This is what these func expected to do. The priv data is needed only when there is variable data to save per device.
Best regards, Thomas
participants (3)
-
Daniel Schwierzeck
-
Thomas Chou
-
Wills Wang