[U-Boot] [PATCH 1/4 v3] serial: Add Zynq serial driver

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);

Device driver for Zynq Gem IP.
Signed-off-by: Michal Simek monstr@monstr.eu CC: Joe Hershberger joe.hershberger@gmail.com CC: Marek Vasut marex@denx.de
--- v2: Remove phylib protection Rename driver file name xilinx_gem to zynq_gem Rename XEMACPSS to ZYNQ_GEM Rename gemac_priv to zynq_gem_priv Rename gem_regs to zynq_gem_regs Add zynq_ prefix to several functions Remove phy detection Rename driver name XGem to Gem Change setup_mac function to reflect u-boot style
v3: Remove magic variables Remove initialized flag Optimize waiting loop by WATCHDOG_RESET Fix uninitialized variable Use setbits_le32 Use const u32 mask variables Implement zynq_gem_halt --- drivers/net/Makefile | 1 + drivers/net/zynq_gem.c | 440 ++++++++++++++++++++++++++++++++++++++++++++++++ include/netdev.h | 2 +- 3 files changed, 442 insertions(+), 1 deletions(-) create mode 100644 drivers/net/zynq_gem.c
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 011cd51..e4abac7 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -80,6 +80,7 @@ COBJS-$(CONFIG_XILINX_AXIEMAC) += xilinx_axi_emac.o COBJS-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o COBJS-$(CONFIG_XILINX_LL_TEMAC) += xilinx_ll_temac.o xilinx_ll_temac_mdio.o \ xilinx_ll_temac_fifo.o xilinx_ll_temac_sdma.o +COBJS-$(CONFIG_ZYNQ_GEM) += zynq_gem.o
COBJS := $(sort $(COBJS-y)) SRCS := $(COBJS:.o=.c) diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c new file mode 100644 index 0000000..3596065 --- /dev/null +++ b/drivers/net/zynq_gem.c @@ -0,0 +1,440 @@ +/* + * (C) Copyright 2011 Michal Simek + * + * Michal SIMEK monstr@monstr.eu + * + * Based on Xilinx gmac driver: + * (C) Copyright 2011 Xilinx + * + * 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 <net.h> +#include <config.h> +#include <malloc.h> +#include <asm/io.h> +#include <phy.h> +#include <miiphy.h> +#include <watchdog.h> + +#if !defined(CONFIG_PHYLIB) +# error XILINX_GEM_ETHERNET requires PHYLIB +#endif + +/* Bit/mask specification */ +#define ZYNQ_GEM_PHYMNTNC_OP_MASK 0x40020000 /* operation mask bits */ +#define ZYNQ_GEM_PHYMNTNC_OP_R_MASK 0x20000000 /* read operation */ +#define ZYNQ_GEM_PHYMNTNC_OP_W_MASK 0x10000000 /* write operation */ +#define ZYNQ_GEM_PHYMNTNC_PHYAD_SHIFT_MASK 23 /* Shift bits for PHYAD */ +#define ZYNQ_GEM_PHYMNTNC_PHREG_SHIFT_MASK 18 /* Shift bits for PHREG */ + +#define ZYNQ_GEM_RXBUF_EOF_MASK 0x00008000 /* End of frame. */ +#define ZYNQ_GEM_RXBUF_SOF_MASK 0x00004000 /* Start of frame. */ +#define ZYNQ_GEM_RXBUF_LEN_MASK 0x00003FFF /* Mask for length field */ + +#define ZYNQ_GEM_RXBUF_WRAP_MASK 0x00000002 /* Wrap bit, last BD */ +#define ZYNQ_GEM_RXBUF_NEW_MASK 0x00000001 /* Used bit.. */ +#define ZYNQ_GEM_RXBUF_ADD_MASK 0xFFFFFFFC /* Mask for address */ + +/* Wrap bit, last descriptor */ +#define ZYNQ_GEM_TXBUF_WRAP_MASK 0x40000000 +#define ZYNQ_GEM_TXBUF_LAST_MASK 0x00008000 /* Last buffer */ + +#define ZYNQ_GEM_TXSR_HRESPNOK_MASK 0x00000100 /* Transmit hresp not OK */ +#define ZYNQ_GEM_TXSR_URUN_MASK 0x00000040 /* Transmit underrun */ +/* Transmit buffs exhausted mid frame */ +#define ZYNQ_GEM_TXSR_BUFEXH_MASK 0x00000010 + +#define ZYNQ_GEM_NWCTRL_TXEN_MASK 0x00000008 /* Enable transmit */ +#define ZYNQ_GEM_NWCTRL_RXEN_MASK 0x00000004 /* Enable receive */ +#define ZYNQ_GEM_NWCTRL_MDEN_MASK 0x00000010 /* Enable MDIO port */ +#define ZYNQ_GEM_NWCTRL_STARTTX_MASK 0x00000200 /* Start tx (tx_go) */ + +#define ZYNQ_GEM_NWCFG_SPEED 0x00000001 /* 100 Mbps operation */ +#define ZYNQ_GEM_NWCFG_FDEN 0x00000002 /* Full Duplex mode */ +#define ZYNQ_GEM_NWCFG_FSREM 0x00020000 /* FCS removal */ +#define ZYNQ_GEM_NWCFG_MDCCLKDIV 0x000080000 /* Div pclk by 32, 80MHz */ + +#define ZYNQ_GEM_NWCFG_INIT (ZYNQ_GEM_NWCFG_SPEED | \ + ZYNQ_GEM_NWCFG_FDEN | \ + ZYNQ_GEM_NWCFG_FSREM | \ + ZYNQ_GEM_NWCFG_MDCCLKDIV) + +#define ZYNQ_GEM_NWSR_MDIOIDLE_MASK 0x00000004 /* PHY management idle */ + +#define ZYNQ_GEM_DMACR_BLENGTH 0x00000004 /* INCR4 AHB bursts */ +/* Use full configured addressable space (8 Kb) */ +#define ZYNQ_GEM_DMACR_RXSIZE 0x00000300 +/* Use full configured addressable space (4 Kb) */ +#define ZYNQ_GEM_DMACR_TXSIZE 0x00000400 +/* Set with binary 00011000 to use 1536 byte(1*max length frame/buffer) */ +#define ZYNQ_GEM_DMACR_RXBUF 0x00180000 + +#define ZYNQ_GEM_DMACR_INIT (ZYNQ_GEM_DMACR_BLENGTH | \ + ZYNQ_GEM_DMACR_RXSIZE | \ + ZYNQ_GEM_DMACR_TXSIZE | \ + ZYNQ_GEM_DMACR_RXBUF) + +/* Device registers */ +struct zynq_gem_regs { + u32 nwctrl; /* Network Control reg */ + u32 nwcfg; /* Network Config reg */ + u32 nwsr; /* Network Status reg */ + u32 reserved1; + u32 dmacr; /* DMA Control reg */ + u32 txsr; /* TX Status reg */ + u32 rxqbase; /* RX Q Base address reg */ + u32 txqbase; /* TX Q Base address reg */ + u32 rxsr; /* RX Status reg */ + u32 reserved2[2]; + u32 idr; /* Interrupt Disable reg */ + u32 reserved3; + u32 phymntnc; /* Phy Maintaince reg */ + u32 reserved4[18]; + u32 hashl; /* Hash Low address reg */ + u32 hashh; /* Hash High address reg */ +#define LADDR_LOW 0 +#define LADDR_HIGH 1 + u32 laddr[4][LADDR_HIGH + 1]; /* Specific1 addr low/high reg */ + u32 match[4]; /* Type ID1 Match reg */ + u32 reserved6[18]; + u32 stat[44]; /* Octects transmitted Low reg - stat start */ +}; + +/* BD descriptors */ +struct emac_bd { + u32 addr; /* Next descriptor pointer */ + u32 status; +}; + +#define RX_BUF 3 + +/* Initialized, rxbd_current, rx_first_buf must be 0 after init */ +struct zynq_gem_priv { + struct emac_bd tx_bd; + struct emac_bd rx_bd[RX_BUF]; + char rxbuffers[RX_BUF * PKTSIZE_ALIGN]; + u32 rxbd_current; + u32 rx_first_buf; + int phyaddr; + struct phy_device *phydev; + struct mii_dev *bus; +}; + +static inline int mdio_wait(struct eth_device *dev) +{ + struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase; + u32 timeout = 200; + + /* Wait till MDIO interface is ready to accept a new transaction. */ + while (--timeout) { + if (readl(®s->nwsr) & ZYNQ_GEM_NWSR_MDIOIDLE_MASK) + break; + WATCHDOG_RESET(); + } + + if (!timeout) { + printf("%s: Timeout\n", __func__); + return 1; + } + + return 0; +} + +static u32 phy_setup_op(struct eth_device *dev, u32 phy_addr, u32 regnum, + u32 op, u16 *data) +{ + u32 mgtcr; + struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase; + + if (mdio_wait(dev)) + return 1; + + /* Construct mgtcr mask for the operation */ + mgtcr = ZYNQ_GEM_PHYMNTNC_OP_MASK | op | + (phy_addr << ZYNQ_GEM_PHYMNTNC_PHYAD_SHIFT_MASK) | + (regnum << ZYNQ_GEM_PHYMNTNC_PHREG_SHIFT_MASK) | *data; + + /* Write mgtcr and wait for completion */ + writel(mgtcr, ®s->phymntnc); + + if (mdio_wait(dev)) + return 1; + + if (op == ZYNQ_GEM_PHYMNTNC_OP_R_MASK) + *data = readl(®s->phymntnc); + + return 0; +} + +static u32 phyread(struct eth_device *dev, u32 phy_addr, u32 regnum, u16 *val) +{ + return phy_setup_op(dev, phy_addr, regnum, + ZYNQ_GEM_PHYMNTNC_OP_R_MASK, val); +} + +static u32 phywrite(struct eth_device *dev, u32 phy_addr, u32 regnum, u16 data) +{ + return phy_setup_op(dev, phy_addr, regnum, + ZYNQ_GEM_PHYMNTNC_OP_W_MASK, &data); +} + +static int zynq_gem_setup_mac(struct eth_device *dev) +{ + u32 i, macaddrlow, macaddrhigh; + struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase; + + /* Set the MAC bits [31:0] in BOT */ + macaddrlow = dev->enetaddr[0]; + macaddrlow |= dev->enetaddr[1] << 8; + macaddrlow |= dev->enetaddr[2] << 16; + macaddrlow |= dev->enetaddr[3] << 24; + + /* Set MAC bits [47:32] in TOP */ + macaddrhigh = dev->enetaddr[4]; + macaddrhigh |= dev->enetaddr[5] << 8; + + for (i = 0; i < 4; i++) { + writel(0, ®s->laddr[i][LADDR_LOW]); + writel(0, ®s->laddr[i][LADDR_HIGH]); + /* Do not use MATCHx register */ + writel(0, ®s->match[i]); + } + + writel(macaddrlow, ®s->laddr[0][LADDR_LOW]); + writel(macaddrhigh, ®s->laddr[0][LADDR_HIGH]); + + return 0; +} + +static int zynq_gem_init(struct eth_device *dev, bd_t * bis) +{ + u32 i; + struct phy_device *phydev; + const u32 stat_size = (sizeof(struct zynq_gem_regs) - + offsetof(struct zynq_gem_regs, stat)) / 4; + struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase; + struct zynq_gem_priv *priv = dev->priv; + const u32 supported = SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full; + + /* Disable all interrupts */ + writel(0xFFFFFFFF, ®s->idr); + + /* Disable the receiver & transmitter */ + writel(0, ®s->nwctrl); + writel(0, ®s->txsr); + writel(0, ®s->rxsr); + writel(0, ®s->phymntnc); + + /* Clear the Hash registers for the mac address pointed by AddressPtr */ + writel(0x0, ®s->hashl); + /* Write bits [63:32] in TOP */ + writel(0x0, ®s->hashh); + + /* Clear all counters */ + for (i = 0; i <= stat_size; i++) + readl(®s->stat[i]); + + /* Setup RxBD space */ + memset(&(priv->rx_bd), 0, sizeof(priv->rx_bd)); + /* Create the RxBD ring */ + memset(&(priv->rxbuffers), 0, sizeof(priv->rxbuffers)); + + for (i = 0; i < RX_BUF; i++) { + priv->rx_bd[i].status = 0xF0000000; + priv->rx_bd[i].addr = (u32)((char *) &(priv->rxbuffers) + + (i * PKTSIZE_ALIGN)); + } + /* WRAP bit to last BD */ + priv->rx_bd[--i].addr |= ZYNQ_GEM_RXBUF_WRAP_MASK; + /* Write RxBDs to IP */ + writel((u32) &(priv->rx_bd), ®s->rxqbase); + + /* MAC Setup */ + /* Setup Network Configuration register */ + writel(ZYNQ_GEM_NWCFG_INIT, ®s->nwcfg); + + /* Setup for DMA Configuration register */ + writel(ZYNQ_GEM_DMACR_INIT, ®s->dmacr); + + /* Setup for Network Control register, MDIO, Rx and Tx enable */ + setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_MDEN_MASK | + ZYNQ_GEM_NWCTRL_RXEN_MASK | ZYNQ_GEM_NWCTRL_TXEN_MASK); + + /* interface - look at tsec */ + phydev = phy_connect(priv->bus, priv->phyaddr, dev, 0); + + phydev->supported &= supported; + phydev->advertising = phydev->supported; + priv->phydev = phydev; + phy_config(phydev); + phy_startup(phydev); + + return 0; +} + +static int zynq_gem_send(struct eth_device *dev, void *ptr, int len) +{ + u32 status; + struct zynq_gem_priv *priv = dev->priv; + struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase; + const u32 mask = ZYNQ_GEM_TXSR_HRESPNOK_MASK | \ + ZYNQ_GEM_TXSR_URUN_MASK | ZYNQ_GEM_TXSR_BUFEXH_MASK; + + /* setup BD */ + writel((u32)&(priv->tx_bd), ®s->txqbase); + + /* Setup Tx BD */ + memset((void *) &(priv->tx_bd), 0, sizeof(struct emac_bd)); + + priv->tx_bd.addr = (u32)ptr; + priv->tx_bd.status = len | ZYNQ_GEM_TXBUF_LAST_MASK | + ZYNQ_GEM_TXBUF_WRAP_MASK; + + /* Start transmit */ + setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_STARTTX_MASK); + + /* Read the stat register to know if the packet has been transmitted */ + status = readl(®s->txsr); + if (status & mask) + printf("Something has gone wrong here!? Status is 0x%x.\n", + status); + + /* Clear Tx status register before leaving . */ + writel(status, ®s->txsr); + return 0; +} + +/* Do not check frame_recd flag in rx_status register 0x20 - just poll BD */ +static int zynq_gem_recv(struct eth_device *dev) +{ + int frame_len; + struct zynq_gem_priv *priv = dev->priv; + struct emac_bd *current_bd = &priv->rx_bd[priv->rxbd_current]; + struct emac_bd *first_bd; + + if (!(current_bd->addr & ZYNQ_GEM_RXBUF_NEW_MASK)) + return 0; + + if (!(current_bd->status & + (ZYNQ_GEM_RXBUF_SOF_MASK | ZYNQ_GEM_RXBUF_EOF_MASK))) { + printf("GEM: SOF or EOF not set for last buffer received!\n"); + return 0; + } + + frame_len = current_bd->status & ZYNQ_GEM_RXBUF_LEN_MASK; + if (frame_len) { + NetReceive((u8 *) (current_bd->addr & + ZYNQ_GEM_RXBUF_ADD_MASK), frame_len); + + if (current_bd->status & ZYNQ_GEM_RXBUF_SOF_MASK) + priv->rx_first_buf = priv->rxbd_current; + else { + current_bd->addr &= ~ZYNQ_GEM_RXBUF_NEW_MASK; + current_bd->status = 0xF0000000; /* FIXME */ + } + + if (current_bd->status & ZYNQ_GEM_RXBUF_EOF_MASK) { + first_bd = &priv->rx_bd[priv->rx_first_buf]; + first_bd->addr &= ~ZYNQ_GEM_RXBUF_NEW_MASK; + first_bd->status = 0xF0000000; + } + + if ((++priv->rxbd_current) >= RX_BUF) + priv->rxbd_current = 0; + + return frame_len; + } + + return 0; +} + +static void zynq_gem_halt(struct eth_device *dev) +{ + struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase; + + /* Disable the receiver & transmitter */ + writel(0, ®s->nwctrl); +} + +static int zynq_gem_miiphyread(const char *devname, uchar addr, + uchar reg, ushort *val) +{ + struct eth_device *dev = eth_get_dev(); + int ret; + + ret = phyread(dev, addr, reg, val); + debug("%s 0x%x, 0x%x, 0x%x\n", __func__, addr, reg, *val); + return ret; +} + +static int zynq_gem_miiphy_write(const char *devname, uchar addr, + uchar reg, ushort val) +{ + struct eth_device *dev = eth_get_dev(); + + debug("%s 0x%x, 0x%x, 0x%x\n", __func__, addr, reg, val); + return phywrite(dev, addr, reg, val); +} + +int zynq_gem_initialize(bd_t *bis, int base_addr) +{ + struct eth_device *dev; + struct zynq_gem_priv *priv; + + dev = calloc(1, sizeof(*dev)); + if (dev == NULL) + return -1; + + dev->priv = calloc(1, sizeof(struct zynq_gem_priv)); + if (dev->priv == NULL) { + free(dev); + return -1; + } + priv = dev->priv; + +#ifdef CONFIG_PHY_ADDR + priv->phyaddr = CONFIG_PHY_ADDR; +#else + priv->phyaddr = -1; +#endif + + sprintf(dev->name, "Gem.%x", base_addr); + + dev->iobase = base_addr; + + dev->init = zynq_gem_init; + dev->halt = zynq_gem_halt; + dev->send = zynq_gem_send; + dev->recv = zynq_gem_recv; + dev->write_hwaddr = zynq_gem_setup_mac; + + eth_register(dev); + + miiphy_register(dev->name, zynq_gem_miiphyread, zynq_gem_miiphy_write); + priv->bus = miiphy_get_dev_by_name(dev->name); + + return 1; +} diff --git a/include/netdev.h b/include/netdev.h index d1aaf0c..b8d303d 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -104,7 +104,7 @@ int xilinx_emaclite_initialize(bd_t *bis, unsigned long base_addr, int txpp, int rxpp); int xilinx_ll_temac_eth_init(bd_t *bis, unsigned long base_addr, int flags, unsigned long ctrl_addr); - +int zynq_gem_initialize(bd_t *bis, int base_addr); /* * As long as the Xilinx xps_ll_temac ethernet driver has not its own interface * exported by a public hader file, we need a global definition at this point.

Dear Michal Simek,
Device driver for Zynq Gem IP.
Signed-off-by: Michal Simek monstr@monstr.eu CC: Joe Hershberger joe.hershberger@gmail.com CC: Marek Vasut marex@denx.de
v2: Remove phylib protection Rename driver file name xilinx_gem to zynq_gem Rename XEMACPSS to ZYNQ_GEM Rename gemac_priv to zynq_gem_priv Rename gem_regs to zynq_gem_regs Add zynq_ prefix to several functions Remove phy detection Rename driver name XGem to Gem Change setup_mac function to reflect u-boot style
v3: Remove magic variables Remove initialized flag Optimize waiting loop by WATCHDOG_RESET Fix uninitialized variable Use setbits_le32 Use const u32 mask variables Implement zynq_gem_halt
[...] Acked-by: Marek Vasut marex@denx.de
Best regards, Marek Vasut

Hi Michal,
On Fri, Sep 14, 2012 at 1:23 AM, Michal Simek monstr@monstr.eu wrote:
Device driver for Zynq Gem IP.
Signed-off-by: Michal Simek monstr@monstr.eu CC: Joe Hershberger joe.hershberger@gmail.com CC: Marek Vasut marex@denx.de
Applied, thanks.
-Joe

Add timer driver.
Signed-off-by: Michal Simek monstr@monstr.eu CC: Joe Hershberger joe.hershberger@gmail.com CC: Marek Vasut marex@denx.de
--- v2: Move lowlevel_init.S from board to cpu folder Remove XPSS prefix Rename XSCUTIMER -> SCUTIMER
v3: Using clrsetbits_le32 Fix compilation warning Move reset_cpu from board to cpu.c Move lowlevel_init to cpu.c --- arch/arm/cpu/armv7/zynq/Makefile | 51 +++++++++++++ arch/arm/cpu/armv7/zynq/cpu.c | 31 ++++++++ arch/arm/cpu/armv7/zynq/timer.c | 150 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 232 insertions(+), 0 deletions(-) create mode 100644 arch/arm/cpu/armv7/zynq/Makefile create mode 100644 arch/arm/cpu/armv7/zynq/cpu.c create mode 100644 arch/arm/cpu/armv7/zynq/timer.c
diff --git a/arch/arm/cpu/armv7/zynq/Makefile b/arch/arm/cpu/armv7/zynq/Makefile new file mode 100644 index 0000000..499ace4 --- /dev/null +++ b/arch/arm/cpu/armv7/zynq/Makefile @@ -0,0 +1,51 @@ +# +# (C) Copyright 2000-2003 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# (C) Copyright 2008 +# Guennadi Liakhovetki, DENX Software Engineering, lg@denx.de +# +# 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 $(TOPDIR)/config.mk + +LIB = $(obj)lib$(SOC).o + +COBJS-y := timer.o +COBJS-y += cpu.o + +COBJS := $(COBJS-y) + +SRCS := $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/arm/cpu/armv7/zynq/cpu.c b/arch/arm/cpu/armv7/zynq/cpu.c new file mode 100644 index 0000000..ab615cc --- /dev/null +++ b/arch/arm/cpu/armv7/zynq/cpu.c @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2012 Michal Simek monstr@monstr.eu + * Copyright (C) 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> + +inline void lowlevel_init(void) {} + +void reset_cpu(ulong addr) +{ + while (1) + ; +} diff --git a/arch/arm/cpu/armv7/zynq/timer.c b/arch/arm/cpu/armv7/zynq/timer.c new file mode 100644 index 0000000..323e7b5 --- /dev/null +++ b/arch/arm/cpu/armv7/zynq/timer.c @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2012 Michal Simek monstr@monstr.eu + * Copyright (C) 2011-2012 Xilinx, Inc. All rights reserved. + * + * (C) Copyright 2008 + * Guennadi Liakhovetki, DENX Software Engineering, lg@denx.de + * + * (C) Copyright 2004 + * Philippe Robin, ARM Ltd. philippe.robin@arm.com + * + * (C) Copyright 2002-2004 + * Gary Jennejohn, DENX Software Engineering, gj@denx.de + * + * (C) Copyright 2003 + * Texas Instruments <www.ti.com> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger mgroeger@sysgo.de + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke azu@sysgo.de + * + * 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 <div64.h> +#include <asm/io.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct scu_timer { + u32 load; /* Timer Load Register */ + u32 counter; /* Timer Counter Register */ + u32 control; /* Timer Control Register */ +}; + +static struct scu_timer *timer_base = + (struct scu_timer *) CONFIG_SCUTIMER_BASEADDR; + +#define SCUTIMER_CONTROL_PRESCALER_MASK 0x0000FF00 /* Prescaler */ +#define SCUTIMER_CONTROL_PRESCALER_SHIFT 8 +#define SCUTIMER_CONTROL_AUTO_RELOAD_MASK 0x00000002 /* Auto-reload */ +#define SCUTIMER_CONTROL_ENABLE_MASK 0x00000001 /* Timer enable */ + +#define TIMER_LOAD_VAL 0xFFFFFFFF +#define TIMER_PRESCALE 255 +#define TIMER_TICK_HZ (CONFIG_CPU_FREQ_HZ / 2 / TIMER_PRESCALE) + +int timer_init(void) +{ + const u32 emask = SCUTIMER_CONTROL_AUTO_RELOAD_MASK | + (TIMER_PRESCALE << SCUTIMER_CONTROL_PRESCALER_SHIFT) | + SCUTIMER_CONTROL_ENABLE_MASK; + + /* Load the timer counter register */ + writel(0xFFFFFFFF, &timer_base->counter); + + /* + * Start the A9Timer device + * Enable Auto reload mode, Clear prescaler control bits + * Set prescaler value, Enable the decrementer + */ + clrsetbits_le32(&timer_base->control, SCUTIMER_CONTROL_PRESCALER_MASK, + emask); + + /* Reset time */ + gd->lastinc = readl(&timer_base->counter) / + (TIMER_TICK_HZ / CONFIG_SYS_HZ); + gd->tbl = 0; + + return 0; +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM it just returns the timer value. + */ +ulong get_timer_masked(void) +{ + ulong now; + + now = readl(&timer_base->counter) / (TIMER_TICK_HZ / CONFIG_SYS_HZ); + + if (gd->lastinc >= now) { + /* Normal mode */ + gd->tbl += gd->lastinc - now; + } else { + /* We have an overflow ... */ + gd->tbl += gd->lastinc + TIMER_LOAD_VAL - now; + } + gd->lastinc = now; + + return gd->tbl; +} + +void __udelay(unsigned long usec) +{ + unsigned long long tmp; + ulong tmo; + + tmo = usec / (1000000 / CONFIG_SYS_HZ); + tmp = get_ticks() + tmo; /* Get current timestamp */ + + while (get_ticks() < tmp) { /* Loop till event */ + /* NOP */; + } +} + +/* Timer without interrupts */ +ulong get_timer(ulong base) +{ + return get_timer_masked() - base; +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM it just returns the timer value. + */ +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk(void) +{ + return CONFIG_SYS_HZ; +}

Dear Michal Simek,
Add timer driver.
Signed-off-by: Michal Simek monstr@monstr.eu CC: Joe Hershberger joe.hershberger@gmail.com CC: Marek Vasut marex@denx.de
v2: Move lowlevel_init.S from board to cpu folder Remove XPSS prefix Rename XSCUTIMER -> SCUTIMER
v3: Using clrsetbits_le32 Fix compilation warning Move reset_cpu from board to cpu.c Move lowlevel_init to cpu.c
[...]
+#include <common.h>
+inline void lowlevel_init(void) {}
+void reset_cpu(ulong addr) +{
- while (1)
;
+}
I wonder how useful such CPU is if simple endless loop restarts it ;-)
[...]
Acked-by: Marek Vasut marex@denx.de

On 09/14/2012 09:50 AM, Marek Vasut wrote:
Dear Michal Simek,
Add timer driver.
Signed-off-by: Michal Simek monstr@monstr.eu CC: Joe Hershberger joe.hershberger@gmail.com CC: Marek Vasut marex@denx.de
v2: Move lowlevel_init.S from board to cpu folder Remove XPSS prefix Rename XSCUTIMER -> SCUTIMER
v3: Using clrsetbits_le32 Fix compilation warning Move reset_cpu from board to cpu.c Move lowlevel_init to cpu.c
[...]
+#include <common.h>
+inline void lowlevel_init(void) {}
+void reset_cpu(ulong addr) +{
- while (1)
;
+}
I wonder how useful such CPU is if simple endless loop restarts it ;-)
Don't be scared it will be fixed when slcr is ready.
Thanks, Michal

Dear Michal Simek,
On 09/14/2012 09:50 AM, Marek Vasut wrote:
Dear Michal Simek,
Add timer driver.
Signed-off-by: Michal Simek monstr@monstr.eu CC: Joe Hershberger joe.hershberger@gmail.com CC: Marek Vasut marex@denx.de
v2: Move lowlevel_init.S from board to cpu folder
Remove XPSS prefix Rename XSCUTIMER -> SCUTIMER
v3: Using clrsetbits_le32
Fix compilation warning Move reset_cpu from board to cpu.c Move lowlevel_init to cpu.c
[...]
+#include <common.h>
+inline void lowlevel_init(void) {}
+void reset_cpu(ulong addr) +{
- while (1)
;
+}
I wonder how useful such CPU is if simple endless loop restarts it ;-)
Don't be scared it will be fixed when slcr is ready.
Nay, I was just rambling and giving you a bit of torture :-)
What's SLCR ?
Thanks, Michal
Best regards, Marek Vasut

On 09/14/2012 11:59 AM, Marek Vasut wrote:
Dear Michal Simek,
On 09/14/2012 09:50 AM, Marek Vasut wrote:
Dear Michal Simek,
Add timer driver.
Signed-off-by: Michal Simek monstr@monstr.eu CC: Joe Hershberger joe.hershberger@gmail.com CC: Marek Vasut marex@denx.de
v2: Move lowlevel_init.S from board to cpu folder
Remove XPSS prefix Rename XSCUTIMER -> SCUTIMER
v3: Using clrsetbits_le32
Fix compilation warning Move reset_cpu from board to cpu.c Move lowlevel_init to cpu.c
[...]
+#include <common.h>
+inline void lowlevel_init(void) {}
+void reset_cpu(ulong addr) +{
- while (1)
;
+}
I wonder how useful such CPU is if simple endless loop restarts it ;-)
Don't be scared it will be fixed when slcr is ready.
Nay, I was just rambling and giving you a bit of torture :-)
:-)
What's SLCR ?
System level control registers. For example for clock setup, unit reset, ddr setup configuration pin setup, etc.
Thanks, Michal

Dear Michal Simek,
On 09/14/2012 11:59 AM, Marek Vasut wrote:
Dear Michal Simek,
On 09/14/2012 09:50 AM, Marek Vasut wrote:
Dear Michal Simek,
Add timer driver.
Signed-off-by: Michal Simek monstr@monstr.eu CC: Joe Hershberger joe.hershberger@gmail.com CC: Marek Vasut marex@denx.de
v2: Move lowlevel_init.S from board to cpu folder
Remove XPSS prefix Rename XSCUTIMER -> SCUTIMER
v3: Using clrsetbits_le32
Fix compilation warning Move reset_cpu from board to cpu.c Move lowlevel_init to cpu.c
[...]
+#include <common.h>
+inline void lowlevel_init(void) {}
+void reset_cpu(ulong addr) +{
- while (1)
;
+}
I wonder how useful such CPU is if simple endless loop restarts it ;-)
Don't be scared it will be fixed when slcr is ready.
Nay, I was just rambling and giving you a bit of torture :-)
: :-) :
What's SLCR ?
System level control registers. For example for clock setup, unit reset, ddr setup configuration pin setup, etc.
Shouldn't that be part of this patchset then?
Thanks, Michal
Best regards, Marek Vasut

On 09/14/2012 12:58 PM, Marek Vasut wrote:
Dear Michal Simek,
On 09/14/2012 11:59 AM, Marek Vasut wrote:
Dear Michal Simek,
On 09/14/2012 09:50 AM, Marek Vasut wrote:
Dear Michal Simek,
Add timer driver.
Signed-off-by: Michal Simek monstr@monstr.eu CC: Joe Hershberger joe.hershberger@gmail.com CC: Marek Vasut marex@denx.de
v2: Move lowlevel_init.S from board to cpu folder
Remove XPSS prefix Rename XSCUTIMER -> SCUTIMER
v3: Using clrsetbits_le32
Fix compilation warning Move reset_cpu from board to cpu.c Move lowlevel_init to cpu.c
[...]
+#include <common.h>
+inline void lowlevel_init(void) {}
+void reset_cpu(ulong addr) +{
- while (1)
;
+}
I wonder how useful such CPU is if simple endless loop restarts it ;-)
Don't be scared it will be fixed when slcr is ready.
Nay, I was just rambling and giving you a bit of torture :-)
: :-) :
What's SLCR ?
System level control registers. For example for clock setup, unit reset, ddr setup configuration pin setup, etc.
Shouldn't that be part of this patchset then?
No. Basic setup is done in first stage bootloader. I will talk with Xilinx how to handle this. I think that special driver(in zynq cpu folder) for slcr make sense to have all SLCR operation at one place and not to call it directly.
Thanks, Michal

Add support for Xilinx Zynq board.
Signed-off-by: Michal Simek monstr@monstr.eu CC: Joe Hershberger joe.hershberger@gmail.com CC: Marek Vasut marex@denx.de
--- v2: Forget to also add config file
v3: Change name for serial driver Remove lowlevel_init from board folder Remove XPSS part from timer baseaddr Change name for Zynq gem driver Clean coding style Remove mac + ip addresses from config file Remove additional PHYs
v4: Move reset_cpu to cpu folder Remove empty board_late_init Enable SERIAL_MULTI Setup SYS_TEXT_BASE Changed eth initialization --- board/xilinx/zynq/Makefile | 54 +++++++++++++++++++++ board/xilinx/zynq/board.c | 54 +++++++++++++++++++++ boards.cfg | 1 + include/configs/zynq.h | 112 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 221 insertions(+), 0 deletions(-) create mode 100644 board/xilinx/zynq/Makefile create mode 100644 board/xilinx/zynq/board.c create mode 100644 include/configs/zynq.h
diff --git a/board/xilinx/zynq/Makefile b/board/xilinx/zynq/Makefile new file mode 100644 index 0000000..ef4faa1 --- /dev/null +++ b/board/xilinx/zynq/Makefile @@ -0,0 +1,54 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# 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 $(TOPDIR)/config.mk +ifneq ($(OBJTREE),$(SRCTREE)) +$(shell mkdir -p $(obj)../common) +endif + +LIB = $(obj)lib$(BOARD).o + +COBJS-y := board.o + +COBJS := $(sort $(COBJS-y)) + +SRCS := $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) + +$(LIB): $(obj).depend $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +clean: + rm -f $(OBJS) + +distclean: clean + rm -f $(LIB) core *.bak $(obj).depend + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/board/xilinx/zynq/board.c b/board/xilinx/zynq/board.c new file mode 100644 index 0000000..8ed75c3 --- /dev/null +++ b/board/xilinx/zynq/board.c @@ -0,0 +1,54 @@ +/* + * (C) Copyright 2012 Michal Simek monstr@monstr.eu + * + * 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 <netdev.h> + +DECLARE_GLOBAL_DATA_PTR; + +int board_init(void) +{ + icache_enable(); + + return 0; +} + + +#ifdef CONFIG_CMD_NET +int board_eth_init(bd_t *bis) +{ + u32 ret = 0; + +#if defined(CONFIG_ZYNQ_GEM) && defined(CONFIG_ZYNQ_GEM_BASEADDR0) + ret = zynq_gem_initialize(bis, CONFIG_ZYNQ_GEM_BASEADDR0); +#endif + + return ret; +} +#endif + +int dram_init(void) +{ + gd->ram_size = CONFIG_SYS_SDRAM_SIZE; + + return 0; +} diff --git a/boards.cfg b/boards.cfg index 72e7803..323dcc0 100644 --- a/boards.cfg +++ b/boards.cfg @@ -272,6 +272,7 @@ ventana arm armv7:arm720t ventana nvidia whistler arm armv7:arm720t whistler nvidia tegra20 u8500_href arm armv7 u8500 st-ericsson u8500 snowball arm armv7 snowball st-ericsson u8500 +zynq arm armv7 zynq xilinx zynq actux1_4_16 arm ixp actux1 - - actux1:FLASH2X2 actux1_4_32 arm ixp actux1 - - actux1:FLASH2X2,RAM_32MB actux1_8_16 arm ixp actux1 - - actux1:FLASH1X8 diff --git a/include/configs/zynq.h b/include/configs/zynq.h new file mode 100644 index 0000000..34ac3ef --- /dev/null +++ b/include/configs/zynq.h @@ -0,0 +1,112 @@ +/* + * (C) Copyright 2012 Michal Simek monstr@monstr.eu + * + * 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 + */ + +#ifndef __CONFIG_ZYNQ_H +#define __CONFIG_ZYNQ_H + +#define CONFIG_ARMV7 /* This is an ARM V7 CPU core */ +#define CONFIG_ZYNQ + +/* CPU clock */ +#define CONFIG_CPU_FREQ_HZ 800000000 +#define CONFIG_SYS_HZ 1000 + +/* Ram */ +#define CONFIG_NR_DRAM_BANKS 1 +#define CONFIG_SYS_TEXT_BASE 0 +#define CONFIG_SYS_SDRAM_BASE 0 +#define CONFIG_SYS_SDRAM_SIZE 0x40000000 +#define CONFIG_SYS_MEMTEST_START CONFIG_SYS_SDRAM_BASE +#define CONFIG_SYS_MEMTEST_END (CONFIG_SYS_SDRAM_BASE + 0x1000) + +/* The following table includes the supported baudrates */ +#define CONFIG_SYS_BAUDRATE_TABLE \ + {300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400} + +#define CONFIG_BAUDRATE 115200 + +/* XPSS Serial driver */ +#define CONFIG_SERIAL_MULTI +#define CONFIG_ZYNQ_SERIAL +#define CONFIG_ZYNQ_SERIAL_BASEADDR0 0xE0001000 +#define CONFIG_ZYNQ_SERIAL_BAUDRATE0 CONFIG_BAUDRATE +#define CONFIG_ZYNQ_SERIAL_CLOCK0 50000000 + +/* SCU timer address is hardcoded */ +#define CONFIG_SCUTIMER_BASEADDR 0xF8F00600 + +/* Ethernet driver */ +#define CONFIG_NET_MULTI +#define CONFIG_ZYNQ_GEM +#define CONFIG_ZYNQ_GEM_BASEADDR0 0xE000B000 + +#define CONFIG_BOOTP_SERVERIP +#define CONFIG_BOOTP_BOOTPATH +#define CONFIG_BOOTP_GATEWAY +#define CONFIG_BOOTP_HOSTNAME +#define CONFIG_BOOTP_MAY_FAIL + +/* MII and Phylib */ +#define CONFIG_MII +#define CONFIG_SYS_FAULT_ECHO_LINK_DOWN +#define CONFIG_PHYLIB +#define CONFIG_PHY_MARVELL + +/* Environment */ +#define CONFIG_ENV_IS_NOWHERE +#define CONFIG_ENV_SIZE 0x10000 + +#define CONFIG_SYS_NO_FLASH + +#define CONFIG_SYS_MALLOC_LEN 0x400000 +#define CONFIG_SYS_INIT_RAM_ADDR CONFIG_SYS_SDRAM_BASE +#define CONFIG_SYS_INIT_RAM_SIZE CONFIG_SYS_MALLOC_LEN +#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_INIT_RAM_ADDR + \ + CONFIG_SYS_INIT_RAM_SIZE - \ + GENERATED_GBL_DATA_SIZE) + +#define CONFIG_SYS_PROMPT "U-Boot> " +#define CONFIG_SYS_CBSIZE 256 /* Console I/O Buffer Size */ +#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + \ + sizeof(CONFIG_SYS_PROMPT) + 16) + +#define CONFIG_SYS_LOAD_ADDR 0 +#define CONFIG_SYS_MAXARGS 15 /* max number of command args */ +#define CONFIG_SYS_LONGHELP +#define CONFIG_AUTO_COMPLETE +#define CONFIG_CMDLINE_EDITING + +#define CONFIG_SYS_HUSH_PARSER +#define CONFIG_SYS_PROMPT_HUSH_PS2 "> " + +/* OF */ +#define CONFIG_FIT +#define CONFIG_OF_LIBFDT + +/* Commands */ +#include <config_cmd_default.h> + +#define CONFIG_CMD_PING +#define CONFIG_CMD_DHCP +#define CONFIG_CMD_MII + +#endif /* __CONFIG_ZYNQ_H */

Dear Michal Simek,
Add support for Xilinx Zynq board.
Signed-off-by: Michal Simek monstr@monstr.eu CC: Joe Hershberger joe.hershberger@gmail.com CC: Marek Vasut marex@denx.de
v2: Forget to also add config file
v3: Change name for serial driver Remove lowlevel_init from board folder Remove XPSS part from timer baseaddr Change name for Zynq gem driver Clean coding style Remove mac + ip addresses from config file Remove additional PHYs
v4: Move reset_cpu to cpu folder Remove empty board_late_init Enable SERIAL_MULTI Setup SYS_TEXT_BASE Changed eth initialization
[...]
Acked-by: Marek Vasut marex@denx.de
Best regards, Marek Vasut

Hi Michal,
On Fri, 14 Sep 2012 08:23:36 +0200, Michal Simek monstr@monstr.eu wrote:
Add support for Xilinx Zynq board.
Signed-off-by: Michal Simek monstr@monstr.eu CC: Joe Hershberger joe.hershberger@gmail.com CC: Marek Vasut marex@denx.de
v2: Forget to also add config file
v3: Change name for serial driver Remove lowlevel_init from board folder Remove XPSS part from timer baseaddr Change name for Zynq gem driver Clean coding style Remove mac + ip addresses from config file Remove additional PHYs
v4: Move reset_cpu to cpu folder Remove empty board_late_init Enable SERIAL_MULTI Setup SYS_TEXT_BASE Changed eth initialization
board/xilinx/zynq/Makefile | 54 +++++++++++++++++++++ board/xilinx/zynq/board.c | 54 +++++++++++++++++++++ boards.cfg | 1 + include/configs/zynq.h | 112 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 221 insertions(+), 0 deletions(-) create mode 100644 board/xilinx/zynq/Makefile create mode 100644 board/xilinx/zynq/board.c create mode 100644 include/configs/zynq.h
Sorry for barging in late... Can you make a V5 with the MAINTAINERS file updated?
Amicalement,

Hi Albert,
On 09/28/2012 09:30 PM, Albert ARIBAUD wrote:
Hi Michal,
On Fri, 14 Sep 2012 08:23:36 +0200, Michal Simek monstr@monstr.eu wrote:
Add support for Xilinx Zynq board.
Signed-off-by: Michal Simek monstr@monstr.eu CC: Joe Hershberger joe.hershberger@gmail.com CC: Marek Vasut marex@denx.de
v2: Forget to also add config file
v3: Change name for serial driver Remove lowlevel_init from board folder Remove XPSS part from timer baseaddr Change name for Zynq gem driver Clean coding style Remove mac + ip addresses from config file Remove additional PHYs
v4: Move reset_cpu to cpu folder Remove empty board_late_init Enable SERIAL_MULTI Setup SYS_TEXT_BASE Changed eth initialization
board/xilinx/zynq/Makefile | 54 +++++++++++++++++++++ board/xilinx/zynq/board.c | 54 +++++++++++++++++++++ boards.cfg | 1 + include/configs/zynq.h | 112 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 221 insertions(+), 0 deletions(-) create mode 100644 board/xilinx/zynq/Makefile create mode 100644 board/xilinx/zynq/board.c create mode 100644 include/configs/zynq.h
Sorry for barging in late... Can you make a V5 with the MAINTAINERS file updated?
I have sent v5 patch to the mailing list. I have also updated master-zynq branch in my microblaze custodian repo (git://git.denx.de/u-boot-microblaze.git).
Thanks, Michal

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

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
participants (5)
-
Albert ARIBAUD
-
Joe Hershberger
-
Marek Vasut
-
Michal Simek
-
Tom Rini