Message ID | 1347603816-24772-1-git-send-email-monstr@monstr.eu |
---|---|
State | Superseded |
Delegated to: | Albert ARIBAUD |
Headers | show |
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, ®s->baud_rate_divider); > + writel(bgen, ®s->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, ®s->control); > + writel(ZYNQ_UART_MR_PARITY_NONE, ®s->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(®s->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0) > + WATCHDOG_RESET(); > + > + if (c == '\n') { > + writel('\r', ®s->tx_rx_fifo); > + while ((readl(®s->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0) > + WATCHDOG_RESET(); > + } > + writel(c, ®s->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(®s->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(®s->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); >
Dear Michal Simek, > 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, ®s->baud_rate_divider); > + writel(bgen, ®s->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, ®s->control); > + writel(ZYNQ_UART_MR_PARITY_NONE, ®s->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(®s->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0) > + WATCHDOG_RESET(); > + > + if (c == '\n') { > + writel('\r', ®s->tx_rx_fifo); > + while ((readl(®s->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0) > + WATCHDOG_RESET(); > + } > + writel(c, ®s->tx_rx_fifo); > +} > + > +static void uart_zynq_serial_puts(const char *s, const int port) > +{ > + while (*s) > + uart_zynq_serial_putc(*s++, port); > +} Remark for myself ... squash all these while (*s) putc() constructs into serial core. I'll be adding a patch into my massive patchset I'm cooking for this, you don't worry as this is ok for now. > +static int uart_zynq_serial_tstc(const int port) > +{ > + struct uart_zynq *regs = uart_zynq_ports[port]; > + > + return (readl(®s->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(®s->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) {\ Rename the "name" to __name (this is because once you rename it -- see below -- name will colide with .name) > + name,\ explicitly spell out the name of structure members, so the structure instance is agile to reordering the the declaration members. > + 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 > + Let's not add this, noone uses it. > extern void serial_register(struct serial_device *); > extern void serial_initialize(void); > extern void serial_stdio_init(void);
On 09/14/2012 09:45 AM, Marek Vasut wrote: > Dear Michal Simek, > >> 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, ®s->baud_rate_divider); >> + writel(bgen, ®s->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, ®s->control); >> + writel(ZYNQ_UART_MR_PARITY_NONE, ®s->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(®s->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0) >> + WATCHDOG_RESET(); >> + >> + if (c == '\n') { >> + writel('\r', ®s->tx_rx_fifo); >> + while ((readl(®s->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0) >> + WATCHDOG_RESET(); >> + } >> + writel(c, ®s->tx_rx_fifo); >> +} >> + >> +static void uart_zynq_serial_puts(const char *s, const int port) >> +{ >> + while (*s) >> + uart_zynq_serial_putc(*s++, port); >> +} > > Remark for myself ... squash all these while (*s) putc() constructs into serial > core. I'll be adding a patch into my massive patchset I'm cooking for this, you > don't worry as this is ok for now. > >> +static int uart_zynq_serial_tstc(const int port) >> +{ >> + struct uart_zynq *regs = uart_zynq_ports[port]; >> + >> + return (readl(®s->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(®s->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) {\ > > Rename the "name" to __name (this is because once you rename it -- see below -- > name will colide with .name) > >> + name,\ > > explicitly spell out the name of structure members, so the structure instance is > agile to reordering the the declaration members. No problem to change it. I have seen it in your stdio branch > >> + 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 >> + > > Let's not add this, noone uses it. It is used by serial core where you register serial device. >> + serial_register(&uart_zynq_serial0_device); You need declaration somewhere. If you don't have it then this error message is shown. serial.c: In function 'serial_initialize': serial.c:127:19: error: 'uart_zynq_serial0_device' undeclared (first use in this function) serial.c:127:19: note: each undeclared identifier is reported only once for each function it appears in Thanks, Michal
Dear Michal Simek, > On 09/14/2012 09:45 AM, Marek Vasut wrote: > > Dear Michal Simek, > > > >> 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, ®s->baud_rate_divider); > >> + writel(bgen, ®s->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, ®s- >control); > >> + writel(ZYNQ_UART_MR_PARITY_NONE, ®s->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(®s->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0) > >> + WATCHDOG_RESET(); > >> + > >> + if (c == '\n') { > >> + writel('\r', ®s->tx_rx_fifo); > >> + while ((readl(®s->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0) > >> + WATCHDOG_RESET(); > >> + } > >> + writel(c, ®s->tx_rx_fifo); > >> +} > >> + > >> +static void uart_zynq_serial_puts(const char *s, const int port) > >> +{ > >> + while (*s) > >> + uart_zynq_serial_putc(*s++, port); > >> +} > > > > Remark for myself ... squash all these while (*s) putc() constructs into > > serial core. I'll be adding a patch into my massive patchset I'm cooking > > for this, you don't worry as this is ok for now. > > > >> +static int uart_zynq_serial_tstc(const int port) > >> +{ > >> + struct uart_zynq *regs = uart_zynq_ports[port]; > >> + > >> + return (readl(®s->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(®s->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) {\ > > > > Rename the "name" to __name (this is because once you rename it -- see > > below -- name will colide with .name) > > > >> + name,\ > > > > explicitly spell out the name of structure members, so the structure > > instance is agile to reordering the the declaration members. > > No problem to change it. I have seen it in your stdio branch > > >> + 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 > >> + > > > > Let's not add this, noone uses it. > > It is used by serial core where you register serial device. > > >> + serial_register(&uart_zynq_serial0_device); > > You need declaration somewhere. If you don't have it then this error > message is shown. serial.c: In function 'serial_initialize': > serial.c:127:19: error: 'uart_zynq_serial0_device' undeclared (first use in > this function) serial.c:127:19: note: each undeclared identifier is > reported only once for each function it appears in Oh damn, you're right ... I reworked the serial core so it's not needed -- by sticking an init func into each and every driver. Maybe we should start pushing the serial drivers through that branch of mine once I post it? I guess this platform won't make it into .10 release anyway. > Thanks, > Michal
On 09/14/2012 12:03 PM, Marek Vasut wrote: > Dear Michal Simek, > >> On 09/14/2012 09:45 AM, Marek Vasut wrote: >>> Dear Michal Simek, >>> >>>> 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, ®s->baud_rate_divider); >>>> + writel(bgen, ®s->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, ®s- >> control); >>>> + writel(ZYNQ_UART_MR_PARITY_NONE, ®s->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(®s->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0) >>>> + WATCHDOG_RESET(); >>>> + >>>> + if (c == '\n') { >>>> + writel('\r', ®s->tx_rx_fifo); >>>> + while ((readl(®s->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0) >>>> + WATCHDOG_RESET(); >>>> + } >>>> + writel(c, ®s->tx_rx_fifo); >>>> +} >>>> + >>>> +static void uart_zynq_serial_puts(const char *s, const int port) >>>> +{ >>>> + while (*s) >>>> + uart_zynq_serial_putc(*s++, port); >>>> +} >>> >>> Remark for myself ... squash all these while (*s) putc() constructs into >>> serial core. I'll be adding a patch into my massive patchset I'm cooking >>> for this, you don't worry as this is ok for now. >>> >>>> +static int uart_zynq_serial_tstc(const int port) >>>> +{ >>>> + struct uart_zynq *regs = uart_zynq_ports[port]; >>>> + >>>> + return (readl(®s->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(®s->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) {\ >>> >>> Rename the "name" to __name (this is because once you rename it -- see >>> below -- name will colide with .name) >>> >>>> + name,\ >>> >>> explicitly spell out the name of structure members, so the structure >>> instance is agile to reordering the the declaration members. >> >> No problem to change it. I have seen it in your stdio branch >> >>>> + 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 >>>> + >>> >>> Let's not add this, noone uses it. >> >> It is used by serial core where you register serial device. >> >> >> + serial_register(&uart_zynq_serial0_device); >> >> You need declaration somewhere. If you don't have it then this error >> message is shown. serial.c: In function 'serial_initialize': >> serial.c:127:19: error: 'uart_zynq_serial0_device' undeclared (first use in >> this function) serial.c:127:19: note: each undeclared identifier is >> reported only once for each function it appears in > > Oh damn, you're right ... I reworked the serial core so it's not needed -- by > sticking an init func into each and every driver. > > Maybe we should start pushing the serial drivers through that branch of mine > once I post it? You have mentioned in one email that your tree is not ready. http://lists.denx.de/pipermail/u-boot/2012-September/133836.html I will send update v4. > > I guess this platform won't make it into .10 release anyway. Why not? Any reason why these 4 patches should wait till the next release? Even if merge open is still open? They are also completely separated from others and they are not breaking anything. Thanks, Michal
Dear Michal Simek, > On 09/14/2012 12:03 PM, Marek Vasut wrote: > > Dear Michal Simek, > > > >> On 09/14/2012 09:45 AM, Marek Vasut wrote: > >>> Dear Michal Simek, > >>> > >>>> 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, ®s->baud_rate_divider); > >>>> + writel(bgen, ®s->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, ®s- > >> > >> control); > >> > >>>> + writel(ZYNQ_UART_MR_PARITY_NONE, ®s->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(®s->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0) > >>>> + WATCHDOG_RESET(); > >>>> + > >>>> + if (c == '\n') { > >>>> + writel('\r', ®s->tx_rx_fifo); > >>>> + while ((readl(®s->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0) > >>>> + WATCHDOG_RESET(); > >>>> + } > >>>> + writel(c, ®s->tx_rx_fifo); > >>>> +} > >>>> + > >>>> +static void uart_zynq_serial_puts(const char *s, const int port) > >>>> +{ > >>>> + while (*s) > >>>> + uart_zynq_serial_putc(*s++, port); > >>>> +} > >>> > >>> Remark for myself ... squash all these while (*s) putc() constructs > >>> into serial core. I'll be adding a patch into my massive patchset I'm > >>> cooking for this, you don't worry as this is ok for now. > >>> > >>>> +static int uart_zynq_serial_tstc(const int port) > >>>> +{ > >>>> + struct uart_zynq *regs = uart_zynq_ports[port]; > >>>> + > >>>> + return (readl(®s->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(®s->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) {\ > >>> > >>> Rename the "name" to __name (this is because once you rename it -- see > >>> below -- name will colide with .name) > >>> > >>>> + name,\ > >>> > >>> explicitly spell out the name of structure members, so the structure > >>> instance is agile to reordering the the declaration members. > >> > >> No problem to change it. I have seen it in your stdio branch > >> > >>>> + 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 > >>>> + > >>> > >>> Let's not add this, noone uses it. > >> > >> It is used by serial core where you register serial device. > >> > >> >> + serial_register(&uart_zynq_serial0_device); > >> > >> You need declaration somewhere. If you don't have it then this error > >> message is shown. serial.c: In function 'serial_initialize': > >> serial.c:127:19: error: 'uart_zynq_serial0_device' undeclared (first use > >> in this function) serial.c:127:19: note: each undeclared identifier is > >> reported only once for each function it appears in > > > > Oh damn, you're right ... I reworked the serial core so it's not needed > > -- by sticking an init func into each and every driver. > > > > Maybe we should start pushing the serial drivers through that branch of > > mine once I post it? > > You have mentioned in one email that your tree is not ready. > http://lists.denx.de/pipermail/u-boot/2012-September/133836.html That's the "once I post it" part of the previous sentence ;-) > > I will send update v4. > > > I guess this platform won't make it into .10 release anyway. > > Why not? Any reason why these 4 patches should wait till the next release? MW is closed (Aug. 18) > Even if merge open is still open? > They are also completely separated from others and they are not breaking > anything. > > Thanks, > Michal
On 09/14/2012 01:00 PM, Marek Vasut wrote: > Dear Michal Simek, > >> On 09/14/2012 12:03 PM, Marek Vasut wrote: >>> Dear Michal Simek, >>> >>>> On 09/14/2012 09:45 AM, Marek Vasut wrote: >>>>> Dear Michal Simek, >>>>> >>>>>> 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, ®s->baud_rate_divider); >>>>>> + writel(bgen, ®s->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, ®s- >>>> >>>> control); >>>> >>>>>> + writel(ZYNQ_UART_MR_PARITY_NONE, ®s->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(®s->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0) >>>>>> + WATCHDOG_RESET(); >>>>>> + >>>>>> + if (c == '\n') { >>>>>> + writel('\r', ®s->tx_rx_fifo); >>>>>> + while ((readl(®s->channel_sts) & ZYNQ_UART_SR_TXFULL) > != 0) >>>>>> + WATCHDOG_RESET(); >>>>>> + } >>>>>> + writel(c, ®s->tx_rx_fifo); >>>>>> +} >>>>>> + >>>>>> +static void uart_zynq_serial_puts(const char *s, const int port) >>>>>> +{ >>>>>> + while (*s) >>>>>> + uart_zynq_serial_putc(*s++, port); >>>>>> +} >>>>> >>>>> Remark for myself ... squash all these while (*s) putc() constructs >>>>> into serial core. I'll be adding a patch into my massive patchset I'm >>>>> cooking for this, you don't worry as this is ok for now. >>>>> >>>>>> +static int uart_zynq_serial_tstc(const int port) >>>>>> +{ >>>>>> + struct uart_zynq *regs = uart_zynq_ports[port]; >>>>>> + >>>>>> + return (readl(®s->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(®s->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) {\ >>>>> >>>>> Rename the "name" to __name (this is because once you rename it -- see >>>>> below -- name will colide with .name) >>>>> >>>>>> + name,\ >>>>> >>>>> explicitly spell out the name of structure members, so the structure >>>>> instance is agile to reordering the the declaration members. >>>> >>>> No problem to change it. I have seen it in your stdio branch >>>> >>>>>> + 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 >>>>>> + >>>>> >>>>> Let's not add this, noone uses it. >>>> >>>> It is used by serial core where you register serial device. >>>> >>>> >> + serial_register(&uart_zynq_serial0_device); >>>> >>>> You need declaration somewhere. If you don't have it then this error >>>> message is shown. serial.c: In function 'serial_initialize': >>>> serial.c:127:19: error: 'uart_zynq_serial0_device' undeclared (first use >>>> in this function) serial.c:127:19: note: each undeclared identifier is >>>> reported only once for each function it appears in >>> >>> Oh damn, you're right ... I reworked the serial core so it's not needed >>> -- by sticking an init func into each and every driver. >>> >>> Maybe we should start pushing the serial drivers through that branch of >>> mine once I post it? >> >> You have mentioned in one email that your tree is not ready. >> http://lists.denx.de/pipermail/u-boot/2012-September/133836.html > > That's the "once I post it" part of the previous sentence ;-) > >> >> I will send update v4. >> >>> I guess this platform won't make it into .10 release anyway. >> >> Why not? Any reason why these 4 patches should wait till the next release? > > MW is closed (Aug. 18) ok. Isn't there any "next" branch for this purpose? I believe it can go at least to custodian arm tree. Thanks, Michal
Dear Michal Simek, [...] > > MW is closed (Aug. 18) > > ok. Isn't there any "next" branch for this purpose? > I believe it can go at least to custodian arm tree. That's a question for Albert I think. > Thanks, > Michal Best regards, Marek Vasut
Hi Marek, On Fri, Sep 14, 2012 at 6:00 AM, Marek Vasut <marex@denx.de> wrote: >> > I guess this platform won't make it into .10 release anyway. >> >> Why not? Any reason why these 4 patches should wait till the next release? > > MW is closed (Aug. 18) The first version of this series was sent on Aug 14. http://patchwork.ozlabs.org/patch/177232/ -Joe
On 09/14/2012 08:53 PM, Joe Hershberger wrote: > Hi Marek, > > On Fri, Sep 14, 2012 at 6:00 AM, Marek Vasut <marex@denx.de> wrote: >>>> I guess this platform won't make it into .10 release anyway. >>> >>> Why not? Any reason why these 4 patches should wait till the next release? >> >> MW is closed (Aug. 18) > > The first version of this series was sent on Aug 14. > http://patchwork.ozlabs.org/patch/177232/ Marek any response? Thanks, Michal
Dear Michal Simek, > On 09/14/2012 08:53 PM, Joe Hershberger wrote: > > Hi Marek, > > > > On Fri, Sep 14, 2012 at 6:00 AM, Marek Vasut <marex@denx.de> wrote: > >>>> I guess this platform won't make it into .10 release anyway. > >>> > >>> Why not? Any reason why these 4 patches should wait till the next > >>> release? > >> > >> MW is closed (Aug. 18) > > > > The first version of this series was sent on Aug 14. > > http://patchwork.ozlabs.org/patch/177232/ > > Marek any response? Did I not review this? I CCed Tom to decide, I'm fine either way. Best regards, Marek Vasut
On 09/19/2012 12:52 PM, Marek Vasut wrote: > Dear Michal Simek, > >> On 09/14/2012 08:53 PM, Joe Hershberger wrote: >>> Hi Marek, >>> >>> On Fri, Sep 14, 2012 at 6:00 AM, Marek Vasut <marex@denx.de> wrote: >>>>>> I guess this platform won't make it into .10 release anyway. >>>>> >>>>> Why not? Any reason why these 4 patches should wait till the next >>>>> release? >>>> >>>> MW is closed (Aug. 18) >>> >>> The first version of this series was sent on Aug 14. >>> http://patchwork.ozlabs.org/patch/177232/ >> >> Marek any response? > > Did I not review this? I CCed Tom to decide, I'm fine either way. I didn't see your answer. Tom: are you OK to add these 4 patches to mainline tree? All of them are ACKed by Marek. I haven't got any response from Albert. I have added to my custodian tree and if you agree I can just send pull request directly to you. Please let me know what you think. Thanks, Michal
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 09/19/12 03:56, Michal Simek wrote: > On 09/19/2012 12:52 PM, Marek Vasut wrote: >> Dear Michal Simek, >> >>> On 09/14/2012 08:53 PM, Joe Hershberger wrote: >>>> Hi Marek, >>>> >>>> On Fri, Sep 14, 2012 at 6:00 AM, Marek Vasut <marex@denx.de> >>>> wrote: >>>>>>> I guess this platform won't make it into .10 release >>>>>>> anyway. >>>>>> >>>>>> Why not? Any reason why these 4 patches should wait till >>>>>> the next release? >>>>> >>>>> MW is closed (Aug. 18) >>>> >>>> The first version of this series was sent on Aug 14. >>>> http://patchwork.ozlabs.org/patch/177232/ >>> >>> Marek any response? >> >> Did I not review this? I CCed Tom to decide, I'm fine either >> way. > > I didn't see your answer. > > Tom: are you OK to add these 4 patches to mainline tree? All of > them are ACKed by Marek. I haven't got any response from Albert. > > I have added to my custodian tree and if you agree I can just send > pull request directly to you. So, lets see if I can not contradict myself as I also need to put a pull request up for Albert. I had said what, -rc2? if Albert didn't respond and at the time you had gotten more feedback from Marek, which you have addressed. So I've updated patchwork for all of the patches, assigned 3 of them to Albert and the network one to Joe. - -- Tom -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://www.enigmail.net/ iQIcBAEBAgAGBQJQWgMCAAoJENk4IS6UOR1WShYQAIiTW06y9CcBJVbBxhJFbtVI CPBOkq1FRQwGJ5lbwINdgfLxMbXsd/R9OWyo3JkTn8vnCKcx+Mu2on6GkvCbKnEL W2ycfo3N8X6EuTS2YxbSB3Dl2oDy97GHQRxsXQ3bOFrtH0fxaNFYc12ofhOsIObn m5qqIXjd8yxc5ylnNZjfNi3dPgdeZxXMt3CqA4E568PvDetgOs/OgeLnIdNR/L6S vCCnmOZhpIszJPFmbCNVK2iDHMDGfbff7A8TNkjT9dSyOftU+GQcW/E3vUoxiYVi vXt1G5m2556lYNsRa43O4Rr6cJRRg5GfzG1U/X0JnWGTTyKZytKfCdhvy7ifn1M8 lwFDlkCtw+x2cH1UNC743LqptaXQin+xGUkGD8n1L+GZhgrSKvzLtjTGTST5zre0 8X/xOQDhW8onn3ra03DCDOKPByzDZKilbO/9EDSHKWaTWFTA7KL9974dSLL7hLur yWzvHpVeqZQUSG/YC4vaWDF5JCUiDEZVZ6+mQx9n9AkrOsDSEDoyUgOefNgeZhkO 2h2Dq1l/HUyl65x8TZHFaYPw4x7m2Sj69t1R2JlGNnoFicFf1hLMV/BvLSoJCiK8 fuh9FcHy6HGw7pFiEam7DgE3Sj7ZU/L/sE4pwTe0eoUyrh2VN7ljScl9opwrbfkK RbHoZ2OJz2uYLX9/3OyN =zgGt -----END PGP SIGNATURE-----
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, ®s->baud_rate_divider); + writel(bgen, ®s->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, ®s->control); + writel(ZYNQ_UART_MR_PARITY_NONE, ®s->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(®s->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0) + WATCHDOG_RESET(); + + if (c == '\n') { + writel('\r', ®s->tx_rx_fifo); + while ((readl(®s->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0) + WATCHDOG_RESET(); + } + writel(c, ®s->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(®s->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(®s->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);
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