[U-Boot] [PATCH 1/4] serial: Add Dragonfire serial driver
Michal Simek
monstr at monstr.eu
Tue Aug 14 18:38:18 CEST 2012
On 08/14/2012 04:09 PM, Joe Hershberger wrote:
> Hi Michal,
>
> On Tue, Aug 14, 2012 at 6:42 AM, Michal Simek <monstr at monstr.eu> wrote:
>> The driver is used on Xilinx Zynq platform.
>>
>> Signed-off-by: Michal Simek <monstr at monstr.eu>
>> ---
>> drivers/serial/Makefile | 1 +
>> drivers/serial/serial_xpssuart.c | 218 ++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 219 insertions(+), 0 deletions(-)
>> create mode 100644 drivers/serial/serial_xpssuart.c
>
> I think this would be clearer if it was named serial_zynq.c
>
>> diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
>> index 65d0f23..81350d0 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_XPSS_SERIAL) += serial_xpssuart.o
>
> Replace every reference to "XPSS" with "ZYNQ".
>
>> ifndef CONFIG_SPL_BUILD
>> COBJS-$(CONFIG_USB_TTY) += usbtty.o
>> diff --git a/drivers/serial/serial_xpssuart.c b/drivers/serial/serial_xpssuart.c
>> new file mode 100644
>> index 0000000..3c6d838
>> --- /dev/null
>> +++ b/drivers/serial/serial_xpssuart.c
>> @@ -0,0 +1,218 @@
>> +/*
>> + * U-Boot driver for Xilinx Dragonfire UART.
>
> Use the released name "Zynq" not the old codename "Dragonfire".
ok.
>
>> + *
>> + * Copyright (C) 2012 Michal Simek <monstr at 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 <serial.h>
>> +
>> +#define XDFUART_SR_TXFULL 0x00000010 /* TX FIFO full */
>> +#define XDFUART_SR_RXEMPTY 0x00000002 /* RX FIFO empty */
>
> Replace all references to "XDFUART" with "ZYNQ_UART".
agree.
>
>> +
>> +#define XDFUART_CR_TX_EN 0x00000010 /* TX enabled */
>> +#define XDFUART_CR_RX_EN 0x00000004 /* RX enabled */
>> +#define XDFUART_CR_TXRST 0x00000002 /* TX logic reset */
>> +#define XDFUART_CR_RXRST 0x00000001 /* RX logic reset */
>> +
>> +#define XDFUART_MR_PARITY_NONE 0x00000020 /* No parity mode */
>> +
>> +/* Some clock/baud constants */
>> +#define XDFUART_BDIV 15 /* Default/reset BDIV value */
>> +#define XDFUART_BASECLK 3125000L /* master / (bdiv + 1) */
>> +
>> +struct xdfuart {
>> + 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 xdfuart *xdf_ports[4] = {
>> +#ifdef CONFIG_XPSS_SERIAL_BASEADDR0
>> + [0] = (struct xdfuart *)CONFIG_XPSS_SERIAL_BASEADDR0,
>> +#endif
>> +#ifdef CONFIG_XPSS_SERIAL_BASEADDR1
>> + [1] = (struct xdfuart *)CONFIG_XPSS_SERIAL_BASEADDR1,
>> +#endif
>
> There are 2 UARTS in hard silicon.
My fault.
They should be supported with
> their known base addresses (0xE0000000 and 0xE0001000) here without
> pushing that into the config header.
I am not sure that hardcoding addresses here is the right thing to do.
The main reason is that none has tested option that hard IPs can be
also used from programmable logic. It means that this driver
could be possible to use from Microblaze with address translation.
No problem to setup these addresses in config file.
>
>> +#ifdef CONFIG_XPSS_SERIAL_BASEADDR2
>> + [2] = (struct xdfuart *)CONFIG_XPSS_SERIAL_BASEADDR2,
>> +#endif
>> +#ifdef CONFIG_XPSS_SERIAL_BASEADDR3
>> + [3] = (struct xdfuart *)CONFIG_XPSS_SERIAL_BASEADDR3,
>> +#endif
>> +};
>> +
>> +struct xdfuart_params {
>> + u32 baudrate;
>> + u32 clock;
>> +};
>> +
>> +static struct xdfuart_params xdf_ports_param[4] = {
>> +#if defined(CONFIG_XPSS_SERIAL_BAUDRATE0) && defined(CONFIG_XPSS_SERIAL_CLOCK0)
>> + [0].baudrate = CONFIG_XPSS_SERIAL_BAUDRATE0,
>> + [0].clock = CONFIG_XPSS_SERIAL_CLOCK0,
>> +#endif
>> +#if defined(CONFIG_XPSS_SERIAL_BAUDRATE1) && defined(CONFIG_XPSS_SERIAL_CLOCK1)
>> + [1].baudrate = CONFIG_XPSS_SERIAL_BAUDRATE1,
>> + [1].clock = CONFIG_XPSS_SERIAL_CLOCK1,
>> +#endif
>> +#if defined(CONFIG_XPSS_SERIAL_BAUDRATE2) && defined(CONFIG_XPSS_SERIAL_CLOCK2)
>> + [2].baudrate = CONFIG_XPSS_SERIAL_BAUDRATE2,
>> + [2].clock = CONFIG_XPSS_SERIAL_CLOCK2,
>> +#endif
>> +#if defined(CONFIG_XPSS_SERIAL_BAUDRATE3) && defined(CONFIG_XPSS_SERIAL_CLOCK3)
>> + [3].baudrate = CONFIG_XPSS_SERIAL_BAUDRATE3,
>> + [3].clock = CONFIG_XPSS_SERIAL_CLOCK3,
>> +#endif
>> +};
>> +
>> +/* Set up the baud rate in gd struct */
>> +static void xdfuart_serial_setbrg(const int port)
>> +{
>> + /* Calculation results. */
>> + unsigned int calc_bauderror, bdiv, bgen;
>> + unsigned long calc_baud = 0;
>> + unsigned long baud = xdf_ports_param[port].baudrate;
>> + unsigned long clock = xdf_ports_param[port].clock;
>> + struct xdfuart *regs = xdf_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 xdfuart_serial_init(const int port)
>> +{
>> + struct xdfuart *regs = xdf_ports[port];
>> +
>> + if (!regs)
>> + return -1;
>> +
>> + /* RX/TX enabled & reset */
>> + writel(XDFUART_CR_TX_EN | XDFUART_CR_RX_EN | XDFUART_CR_TXRST | \
>> + XDFUART_CR_RXRST, ®s->control);
>> + writel(XDFUART_MR_PARITY_NONE, ®s->mode); /* 8 bit, no parity */
>> + xdfuart_serial_setbrg(port);
>> +
>> + return 0;
>> +}
>> +
>> +static void xdfuart_serial_putc(const char c, const int port)
>> +{
>> + struct xdfuart *regs = xdf_ports[port];
>> +
>> + while ((readl(®s->channel_sts) & XDFUART_SR_TXFULL) != 0)
>> + WATCHDOG_RESET();
>> +
>> + if (c == '\n') {
>> + writel('\r', ®s->tx_rx_fifo);
>> + while ((readl(®s->channel_sts) & XDFUART_SR_TXFULL) != 0)
>> + WATCHDOG_RESET();
>> + }
>> + writel(c, ®s->tx_rx_fifo);
>> +}
>> +
>> +static void xdfuart_serial_puts(const char *s, const int port)
>> +{
>> + while (*s)
>> + xdfuart_serial_putc(*s++, port);
>> +}
>> +
>> +static int xdfuart_serial_tstc(const int port)
>> +{
>> + struct xdfuart *regs = xdf_ports[port];
>> +
>> + return (readl(®s->channel_sts) & XDFUART_SR_RXEMPTY) == 0;
>> +}
>> +
>> +static int xdfuart_serial_getc(const int port)
>> +{
>> + struct xdfuart *regs = xdf_ports[port];
>> +
>> + while (!xdfuart_serial_tstc(port))
>> + WATCHDOG_RESET();
>> + return readl(®s->tx_rx_fifo);
>> +}
>> +
>> +#if !defined(CONFIG_SERIAL_MULTI)
>> +int serial_init(void)
>> +{
>> + return xdfuart_serial_init(0);
>
> If there is no SERIAL_MULTI support, there should be a config to
> select which one to use.
Not right now but I will add it in the next patch.
But yes, this ifdef shouldn't be here.
Thanks,
Michal
--
Michal Simek, Ing. (M.Eng)
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel 2.6 Microblaze Linux - http://www.monstr.eu/fdt/
Microblaze U-BOOT custodian
More information about the U-Boot
mailing list