diff mbox

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

Message ID BLU436-SMTP105F72B3D2C0F70924E92CEFFF80@phx.gbl
State Superseded
Delegated to: Daniel Schwierzeck
Headers show

Commit Message

Wills Wang Dec. 25, 2015, 6:56 p.m. UTC
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

Comments

Daniel Schwierzeck Dec. 26, 2015, 1:20 p.m. UTC | #1
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,
> +};
>
Wills Wang Dec. 26, 2015, 4:54 p.m. UTC | #2
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,
>> +};
>>
Daniel Schwierzeck Dec. 26, 2015, 5:19 p.m. UTC | #3
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,
>>> +};
>>>
>
Wills Wang Dec. 27, 2015, 6:28 a.m. UTC | #4
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,
>> +};
>>
Thomas Chou Dec. 27, 2015, 8:21 a.m. UTC | #5
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
Thomas Chou Dec. 27, 2015, 8:31 a.m. UTC | #6
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
Thomas Chou Dec. 27, 2015, 1:07 p.m. UTC | #7
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
diff mbox

Patch

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,
+};