[U-Boot] Implement AUART for i.MX28

Marek Vasut marex at denx.de
Wed Jul 10 00:46:31 CEST 2013


Hi Andreas,

> I have tried to implement an AUART driver for i.MX28.
> However for it to work I must print 1 character to the
> debug UART via the serial_pl01x driver. If I do this
> the AUART will start working. If I don't nothing will
> be printed to the AUART. Anybody can see any obvious errors?
> 
> Signed-off-by: Andreas Wass <andreas.wass at dalelven.com>

I have to wonder, is the AUART no standard UART IP ? Probably not as Linux also 
has a separate driver for this ...

Lots of rambling follows below, but please dont be put off by it.

Make sure to CC me and Fabio on the next submission. I can help you debugging 
the driver if you clean it up a bit.

>  drivers/serial/Makefile           |    1 +
>  drivers/serial/mxs-regs-uartapp.h |  307
> +++++++++++++++++++++++++++++++++++++ drivers/serial/mxs_auart.c        | 
> 161 +++++++++++++++++++
>  drivers/serial/serial.c           |   11 +-
>  drivers/serial/serial_pl01x.c     |   19 ++-
>  5 files changed, 492 insertions(+), 7 deletions(-)
>  create mode 100644 drivers/serial/mxs-regs-uartapp.h
>  create mode 100644 drivers/serial/mxs_auart.c
> 
> diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
> index fbc4e97..f4e0d45 100644
> --- a/drivers/serial/Makefile
> +++ b/drivers/serial/Makefile
> @@ -52,6 +52,7 @@ COBJS-$(CONFIG_XILINX_UARTLITE) += serial_xuartlite.o
>  COBJS-$(CONFIG_SANDBOX_SERIAL) += sandbox.o
>  COBJS-$(CONFIG_SCIF_CONSOLE) += serial_sh.o
>  COBJS-$(CONFIG_ZYNQ_SERIAL) += serial_zynq.o
> +COBJS-$(CONFIG_MXS_AUART) += mxs_auart.o
> 
>  ifndef CONFIG_SPL_BUILD
>  COBJS-$(CONFIG_USB_TTY) += usbtty.o
> diff --git a/drivers/serial/mxs-regs-uartapp.h
> b/drivers/serial/mxs-regs-uartapp.h new file mode 100644
> index 0000000..aad9a78
> --- /dev/null
> +++ b/drivers/serial/mxs-regs-uartapp.h
[...]

Please follow the pattern of arch/arm/include/asm/arch-mxs/regs-*.h with regards 
to struct-based access and using (1 << n) to declare bits.

> diff --git a/drivers/serial/mxs_auart.c b/drivers/serial/mxs_auart.c
> new file mode 100644
> index 0000000..b9a4e82

[...]

> +#include <common.h>
> +#include <serial.h>
> +#include <linux/compiler.h>
> +#include "mxs-regs-uartapp.h"
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +#define REGS_UARTAPP3_BASE	(0x80070000)

Use arch/arm/include/asm/arch-mxs/regs-base.h , but since there are multiple, 
you can add a config option to select which AUART to use.

> +#define REGS_UARTAPP_BASE REGS_UARTAPP3_BASE
> +#define REG_RD(base, reg) \
> +		(*(volatile unsigned int *)((base) + (reg)))
> +#define REG_WR(base, reg, value) \
> +		((*(volatile unsigned int *)((base) + (reg))) = (value))

Use readl() / writel() / clrsetbits_le32() etc.

> +/* HACK should be removed when issue is fixed! */
> +void dbg_puts(const char *s);
> +
> +static void mxs_auart_reset(void)

mxs_reset_block();

[...]

> +/*
> + * Set baud rate. The settings are always 8n1
> + */
> +void mxs_auart_setbrg(void)
> +{
> +	u32 div;
> +	u32 linectrl = 0;
> +
> +	div = (CONFIG_MXS_AUART_CLK * 32) / CONFIG_BAUDRATE;

Does this not integrate with the MXS clock stuff in 
arch/arm/cpu/arm926ejs/mxs/clock.c ? You might want to implement a function 
there to govern the clock speed somehow.

> +	linectrl |= BF_UARTAPP_LINECTRL_BAUD_DIVFRAC(div & 0x3F);
> +	linectrl |= BF_UARTAPP_LINECTRL_BAUD_DIVINT(div >> 6);
> +	linectrl |= BF_UARTAPP_LINECTRL_WLEN(3);
> +	linectrl |= BM_UARTAPP_LINECTRL_FEN;
> +
> +	REG_WR(REGS_UARTAPP_BASE, HW_UARTAPP_LINECTRL, linectrl);
> +}
> +
> +void mxs_auart_init(void)
> +{
> +	mxs_auart_reset();

mxs_reset_block() and drop the above ;-)

> +	REG_WR(REGS_UARTAPP_BASE, HW_UARTAPP_INTR, 0);
> +	serial_setbrg();
> +
> +	REG_WR(REGS_UARTAPP_BASE, HW_UARTAPP_CTRL2_CLR,
> +			BM_UARTAPP_CTRL2_RTSEN | BM_UARTAPP_CTRL2_CTSEN |
> +			BM_UARTAPP_CTRL2_USE_LCR2);
> +	REG_WR(REGS_UARTAPP_BASE, HW_UARTAPP_CTRL2_SET,
> +			BM_UARTAPP_CTRL2_RXE | BM_UARTAPP_CTRL2_TXE |
> +			BM_UARTAPP_CTRL2_UARTEN);
> +
> +	/* HACK, the driver will not work without this.
> +	 * Don't know how to fix
> +	 */

See http://www.denx.de/wiki/U-Boot/CodingStyle about the comments.

> +	dbg_puts("\n");

Is your AUART set as default uart ? Or how do you operate it ?

> +	return 0;
> +}
> +
> +void mxs_auart_putc(const char c)
> +{
> +	while (REG_RD(REGS_UARTAPP_BASE, HW_UARTAPP_STAT) &
> +			BM_UARTAPP_STAT_TXFF)
> +		;

Careful about endless loop here.

> +	REG_WR(REGS_UARTAPP_BASE, HW_UARTAPP_DATA, c);
> +	if (c == '\n')
> +		mxs_auart_putc('\r');
> +
> +}
> +
> +void mxs_auart_puts(const char *s)
> +{
> +	while (*s)
> +		mxs_auart_putc(*s++);

Use default_serial_puts() 

> +}
> +
> +int mxs_auart_tstc(void)
> +{
> +	return !(REG_RD(REGS_UARTAPP_BASE, HW_UARTAPP_STAT) &
> +			BM_UARTAPP_STAT_RXFE);
> +}
> +
> +int mxs_auart_getc(void)
> +{
> +	while (!mxs_auart_tstc())
> +		;
> +
> +	return REG_RD(REGS_UARTAPP_BASE, HW_UARTAPP_DATA) & 0xff;
> +}
> +
> +static struct serial_device mxs_auart_drv = {
> +	.name = "mxs_auart_serial",
> +	.start = mxs_auart_init,
> +	.stop = NULL,
> +	.setbrg = mxs_auart_setbrg,
> +	.putc = mxs_auart_putc,
> +	.puts = mxs_auart_puts,
> +	.getc = mxs_auart_getc,
> +	.tstc = mxs_auart_tstc,
> +};
> +
> +void mxs_auart_initialize(void)
> +{
> +	serial_register(&mxs_auart_drv);
> +}
> +
> +__weak struct serial_device *default_serial_console(void)
> +{
> +	return &mxs_auart_drv;
> +}

[...]


More information about the U-Boot mailing list