All of lore.kernel.org
 help / color / mirror / Atom feed
From: Michal Simek <monstr@monstr.eu>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH 1/4 v3] serial: Add Zynq serial driver
Date: Fri, 14 Sep 2012 08:38:16 +0200	[thread overview]
Message-ID: <5052D0D8.1060007@monstr.eu> (raw)
In-Reply-To: <1347603816-24772-1-git-send-email-monstr@monstr.eu>

Hi John,

sorry I forget you to cc you with this new series in spite of
I promised to John W to do so.
My big apology it wasn't intention. Just forget to do it.
I will forward you them.

Sorry,
Michal



On 09/14/2012 08:23 AM, Michal Simek wrote:
> The driver is used on Xilinx Zynq platform.
>
> Signed-off-by: Michal Simek <monstr@monstr.eu>
> CC: Joe Hershberger <joe.hershberger@gmail.com>
> CC: Marek Vasut <marex@denx.de>
>
> ---
> v2: Use Zynq name instead of Dragonfire and XPSS/XDFUART
>      Rename driver name
>      Remove driver description
>
> v3: SERIAL_MULTI support
>      Rename xdfuart to uart_zynq
> ---
>   common/serial.c              |    8 ++
>   drivers/serial/Makefile      |    1 +
>   drivers/serial/serial_zynq.c |  246 ++++++++++++++++++++++++++++++++++++++++++
>   include/serial.h             |    5 +
>   4 files changed, 260 insertions(+), 0 deletions(-)
>   create mode 100644 drivers/serial/serial_zynq.c
>
> diff --git a/common/serial.c b/common/serial.c
> index 75cc1bb..4f2bc7f 100644
> --- a/common/serial.c
> +++ b/common/serial.c
> @@ -122,6 +122,14 @@ void serial_initialize(void)
>   	serial_register(&uartlite_serial3_device);
>   # endif /* XILINX_UARTLITE_BASEADDR3 */
>   #endif /* CONFIG_XILINX_UARTLITE */
> +#if defined(CONFIG_ZYNQ_SERIAL)
> +# ifdef CONFIG_ZYNQ_SERIAL_BASEADDR0
> +	serial_register(&uart_zynq_serial0_device);
> +# endif
> +# ifdef CONFIG_ZYNQ_SERIAL_BASEADDR1
> +	serial_register(&uart_zynq_serial1_device);
> +# endif
> +#endif
>   	serial_assign(default_serial_console()->name);
>   }
>
> diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
> index 65d0f23..dfc22a4 100644
> --- a/drivers/serial/Makefile
> +++ b/drivers/serial/Makefile
> @@ -56,6 +56,7 @@ COBJS-$(CONFIG_S3C44B0_SERIAL) += serial_s3c44b0.o
>   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
>
>   ifndef CONFIG_SPL_BUILD
>   COBJS-$(CONFIG_USB_TTY) += usbtty.o
> diff --git a/drivers/serial/serial_zynq.c b/drivers/serial/serial_zynq.c
> new file mode 100644
> index 0000000..30f2445
> --- /dev/null
> +++ b/drivers/serial/serial_zynq.c
> @@ -0,0 +1,246 @@
> +/*
> + * Copyright (C) 2012 Michal Simek <monstr@monstr.eu>
> + * Copyright (C) 2011-2012 Xilinx, Inc. All rights reserved.
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#include <common.h>
> +#include <watchdog.h>
> +#include <asm/io.h>
> +#include <linux/compiler.h>
> +#include <serial.h>
> +
> +#define ZYNQ_UART_SR_TXFULL	0x00000010 /* TX FIFO full */
> +#define ZYNQ_UART_SR_RXEMPTY	0x00000002 /* RX FIFO empty */
> +
> +#define ZYNQ_UART_CR_TX_EN	0x00000010 /* TX enabled */
> +#define ZYNQ_UART_CR_RX_EN	0x00000004 /* RX enabled */
> +#define ZYNQ_UART_CR_TXRST	0x00000002 /* TX logic reset */
> +#define ZYNQ_UART_CR_RXRST	0x00000001 /* RX logic reset */
> +
> +#define ZYNQ_UART_MR_PARITY_NONE	0x00000020  /* No parity mode */
> +
> +/* Some clock/baud constants */
> +#define ZYNQ_UART_BDIV	15 /* Default/reset BDIV value */
> +#define ZYNQ_UART_BASECLK	3125000L /* master / (bdiv + 1) */
> +
> +struct uart_zynq {
> +	u32 control; /* Control Register [8:0] */
> +	u32 mode; /* Mode Register [10:0] */
> +	u32 reserved1[4];
> +	u32 baud_rate_gen; /* Baud Rate Generator [15:0] */
> +	u32 reserved2[4];
> +	u32 channel_sts; /* Channel Status [11:0] */
> +	u32 tx_rx_fifo; /* FIFO [15:0] or [7:0] */
> +	u32 baud_rate_divider; /* Baud Rate Divider [7:0] */
> +};
> +
> +static struct uart_zynq *uart_zynq_ports[2] = {
> +#ifdef CONFIG_ZYNQ_SERIAL_BASEADDR0
> +	[0] = (struct uart_zynq *)CONFIG_ZYNQ_SERIAL_BASEADDR0,
> +#endif
> +#ifdef CONFIG_ZYNQ_SERIAL_BASEADDR1
> +	[1] = (struct uart_zynq *)CONFIG_ZYNQ_SERIAL_BASEADDR1,
> +#endif
> +};
> +
> +struct uart_zynq_params {
> +	u32 baudrate;
> +	u32 clock;
> +};
> +
> +static struct uart_zynq_params uart_zynq_ports_param[2] = {
> +#if defined(CONFIG_ZYNQ_SERIAL_BAUDRATE0) && defined(CONFIG_ZYNQ_SERIAL_CLOCK0)
> +	[0].baudrate = CONFIG_ZYNQ_SERIAL_BAUDRATE0,
> +	[0].clock = CONFIG_ZYNQ_SERIAL_CLOCK0,
> +#endif
> +#if defined(CONFIG_ZYNQ_SERIAL_BAUDRATE1) && defined(CONFIG_ZYNQ_SERIAL_CLOCK1)
> +	[1].baudrate = CONFIG_ZYNQ_SERIAL_BAUDRATE1,
> +	[1].clock = CONFIG_ZYNQ_SERIAL_CLOCK1,
> +#endif
> +};
> +
> +/* Set up the baud rate in gd struct */
> +static void uart_zynq_serial_setbrg(const int port)
> +{
> +	/* Calculation results. */
> +	unsigned int calc_bauderror, bdiv, bgen;
> +	unsigned long calc_baud = 0;
> +	unsigned long baud = uart_zynq_ports_param[port].baudrate;
> +	unsigned long clock = uart_zynq_ports_param[port].clock;
> +	struct uart_zynq *regs = uart_zynq_ports[port];
> +
> +	/*                master clock
> +	 * Baud rate = ------------------
> +	 *              bgen * (bdiv + 1)
> +	 *
> +	 * Find acceptable values for baud generation.
> +	 */
> +	for (bdiv = 4; bdiv < 255; bdiv++) {
> +		bgen = clock / (baud * (bdiv + 1));
> +		if (bgen < 2 || bgen > 65535)
> +			continue;
> +
> +		calc_baud = clock / (bgen * (bdiv + 1));
> +
> +		/*
> +		 * Use first calculated baudrate with
> +		 * an acceptable (<3%) error
> +		 */
> +		if (baud > calc_baud)
> +			calc_bauderror = baud - calc_baud;
> +		else
> +			calc_bauderror = calc_baud - baud;
> +		if (((calc_bauderror * 100) / baud) < 3)
> +			break;
> +	}
> +
> +	writel(bdiv, &regs->baud_rate_divider);
> +	writel(bgen, &regs->baud_rate_gen);
> +}
> +
> +/* Initialize the UART, with...some settings. */
> +static int uart_zynq_serial_init(const int port)
> +{
> +	struct uart_zynq *regs = uart_zynq_ports[port];
> +
> +	if (!regs)
> +		return -1;
> +
> +	/* RX/TX enabled & reset */
> +	writel(ZYNQ_UART_CR_TX_EN | ZYNQ_UART_CR_RX_EN | ZYNQ_UART_CR_TXRST | \
> +					ZYNQ_UART_CR_RXRST, &regs->control);
> +	writel(ZYNQ_UART_MR_PARITY_NONE, &regs->mode); /* 8 bit, no parity */
> +	uart_zynq_serial_setbrg(port);
> +
> +	return 0;
> +}
> +
> +static void uart_zynq_serial_putc(const char c, const int port)
> +{
> +	struct uart_zynq *regs = uart_zynq_ports[port];
> +
> +	while ((readl(&regs->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0)
> +		WATCHDOG_RESET();
> +
> +	if (c == '\n') {
> +		writel('\r', &regs->tx_rx_fifo);
> +		while ((readl(&regs->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0)
> +			WATCHDOG_RESET();
> +	}
> +	writel(c, &regs->tx_rx_fifo);
> +}
> +
> +static void uart_zynq_serial_puts(const char *s, const int port)
> +{
> +	while (*s)
> +		uart_zynq_serial_putc(*s++, port);
> +}
> +
> +static int uart_zynq_serial_tstc(const int port)
> +{
> +	struct uart_zynq *regs = uart_zynq_ports[port];
> +
> +	return (readl(&regs->channel_sts) & ZYNQ_UART_SR_RXEMPTY) == 0;
> +}
> +
> +static int uart_zynq_serial_getc(const int port)
> +{
> +	struct uart_zynq *regs = uart_zynq_ports[port];
> +
> +	while (!uart_zynq_serial_tstc(port))
> +		WATCHDOG_RESET();
> +	return readl(&regs->tx_rx_fifo);
> +}
> +
> +#if !defined(CONFIG_SERIAL_MULTI)
> +int serial_init(void)
> +{
> +	return uart_zynq_serial_init(0);
> +}
> +
> +void serial_setbrg(void)
> +{
> +	uart_zynq_serial_setbrg(0);
> +}
> +
> +void serial_putc(const char c)
> +{
> +	uart_zynq_serial_putc(c, 0);
> +}
> +
> +void serial_puts(const char *s)
> +{
> +	uart_zynq_serial_puts(s, 0);
> +}
> +
> +int serial_getc(void)
> +{
> +	return uart_zynq_serial_getc(0);
> +}
> +
> +int serial_tstc(void)
> +{
> +	return uart_zynq_serial_tstc(0);
> +}
> +#else
> +/* Multi serial device functions */
> +#define DECLARE_PSSERIAL_FUNCTIONS(port) \
> +	int uart_zynq##port##_init(void) \
> +				{ return uart_zynq_serial_init(port); } \
> +	void uart_zynq##port##_setbrg(void) \
> +				{ return uart_zynq_serial_setbrg(port); } \
> +	int uart_zynq##port##_getc(void) \
> +				{ return uart_zynq_serial_getc(port); } \
> +	int uart_zynq##port##_tstc(void) \
> +				{ return uart_zynq_serial_tstc(port); } \
> +	void uart_zynq##port##_putc(const char c) \
> +				{ uart_zynq_serial_putc(c, port); } \
> +	void uart_zynq##port##_puts(const char *s) \
> +				{ uart_zynq_serial_puts(s, port); }
> +
> +/* Serial device descriptor */
> +#define INIT_PSSERIAL_STRUCTURE(port, name) {\
> +	  name,\
> +	  uart_zynq##port##_init,\
> +	  NULL,\
> +	  uart_zynq##port##_setbrg,\
> +	  uart_zynq##port##_getc,\
> +	  uart_zynq##port##_tstc,\
> +	  uart_zynq##port##_putc,\
> +	  uart_zynq##port##_puts, }
> +
> +DECLARE_PSSERIAL_FUNCTIONS(0);
> +struct serial_device uart_zynq_serial0_device =
> +	INIT_PSSERIAL_STRUCTURE(0, "ttyPS0");
> +DECLARE_PSSERIAL_FUNCTIONS(1);
> +struct serial_device uart_zynq_serial1_device =
> +	INIT_PSSERIAL_STRUCTURE(1, "ttyPS1");
> +
> +__weak struct serial_device *default_serial_console(void)
> +{
> +	if (uart_zynq_ports[0])
> +		return &uart_zynq_serial0_device;
> +	if (uart_zynq_ports[1])
> +		return &uart_zynq_serial1_device;
> +
> +	return NULL;
> +}
> +#endif
> diff --git a/include/serial.h b/include/serial.h
> index cbdf8a9..dc8e9b4 100644
> --- a/include/serial.h
> +++ b/include/serial.h
> @@ -89,6 +89,11 @@ extern struct serial_device bfin_serial2_device;
>   extern struct serial_device bfin_serial3_device;
>   #endif
>
> +#if defined(CONFIG_ZYNQ_SERIAL)
> +extern struct serial_device uart_zynq_serial0_device;
> +extern struct serial_device uart_zynq_serial1_device;
> +#endif
> +
>   extern void serial_register(struct serial_device *);
>   extern void serial_initialize(void);
>   extern void serial_stdio_init(void);
>


-- 
Michal Simek, Ing. (M.Eng)
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel 2.6 Microblaze Linux - http://www.monstr.eu/fdt/
Microblaze U-BOOT custodian

  parent reply	other threads:[~2012-09-14  6:38 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-09-14  6:23 [U-Boot] [PATCH 1/4 v3] serial: Add Zynq serial driver Michal Simek
2012-09-14  6:23 ` [U-Boot] [PATCH 2/4 v3] net: Add driver for Zynq Gem IP Michal Simek
2012-09-14  7:48   ` Marek Vasut
2012-09-28 16:04   ` Joe Hershberger
2012-09-14  6:23 ` [U-Boot] [PATCH 3/4 v3] arm: Support new Xilinx Zynq platform Michal Simek
2012-09-14  7:50   ` Marek Vasut
2012-09-14  8:10     ` Michal Simek
2012-09-14  9:59       ` Marek Vasut
2012-09-14 10:42         ` Michal Simek
2012-09-14 10:58           ` Marek Vasut
2012-09-14 11:09             ` Michal Simek
2012-09-14  6:23 ` [U-Boot] [PATCH 4/4 v4] xilinx: Add new Zynq board Michal Simek
2012-09-14  7:51   ` Marek Vasut
2012-09-28 19:30   ` Albert ARIBAUD
2012-09-28 20:00     ` Michal Simek
2012-09-14  6:38 ` Michal Simek [this message]
2012-09-14  7:45 ` [U-Boot] [PATCH 1/4 v3] serial: Add Zynq serial driver Marek Vasut
2012-09-14  8:19   ` Michal Simek
2012-09-14 10:03     ` Marek Vasut
2012-09-14 10:49       ` Michal Simek
2012-09-14 11:00         ` Marek Vasut
2012-09-14 11:05           ` Michal Simek
2012-09-14 16:58             ` Marek Vasut
2012-09-14 18:53           ` Joe Hershberger
2012-09-19 10:40             ` Michal Simek
2012-09-19 10:52               ` Marek Vasut
2012-09-19 10:56                 ` Michal Simek
2012-09-19 17:38                   ` Tom Rini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5052D0D8.1060007@monstr.eu \
    --to=monstr@monstr.eu \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.