Patchwork [U-Boot,1/4,v2] serial: Add Zynq serial driver

login
register
mail settings
Submitter Michal Simek
Date Aug. 16, 2012, 6:30 a.m.
Message ID <1345098630-27902-1-git-send-email-monstr@monstr.eu>
Download mbox | patch
Permalink /patch/177907/
State Superseded
Delegated to: Albert ARIBAUD
Headers show

Comments

Michal Simek - Aug. 16, 2012, 6:30 a.m.
The driver is used on Xilinx Zynq platform.

Signed-off-by: Michal Simek <monstr@monstr.eu>

---
v2: Use Zynq name instead of Dragonfire and XPSS/XDFUART
    Rename driver name
    Remove driver description
---
 drivers/serial/Makefile      |    1 +
 drivers/serial/serial_zynq.c |  200 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 201 insertions(+), 0 deletions(-)
 create mode 100644 drivers/serial/serial_zynq.c
Michal Simek - Sept. 12, 2012, 10:20 a.m.
On 08/16/2012 08:30 AM, Michal Simek wrote:
> The driver is used on Xilinx Zynq platform.
>
> Signed-off-by: Michal Simek <monstr@monstr.eu>
>
> ---
> v2: Use Zynq name instead of Dragonfire and XPSS/XDFUART
>      Rename driver name
>      Remove driver description
> ---
>   drivers/serial/Makefile      |    1 +
>   drivers/serial/serial_zynq.c |  200 ++++++++++++++++++++++++++++++++++++++++++
>   2 files changed, 201 insertions(+), 0 deletions(-)
>   create mode 100644 drivers/serial/serial_zynq.c

Joe: you have reviewed the first version of this patch.
Can you comment it?

Thanks,
Michal
Marek Vasut - Sept. 13, 2012, 9:21 a.m.
Dear Michal Simek,

> The driver is used on Xilinx Zynq platform.
> 
> Signed-off-by: Michal Simek <monstr@monstr.eu>
> 
> ---
> v2: Use Zynq name instead of Dragonfire and XPSS/XDFUART
>     Rename driver name
>     Remove driver description
> ---
>  drivers/serial/Makefile      |    1 +
>  drivers/serial/serial_zynq.c |  200
> ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 201
> insertions(+), 0 deletions(-)
>  create mode 100644 drivers/serial/serial_zynq.c
[...]

It looks ok, but can you make it support CONFIG_SERIAL_MULTI right away please?

Best regards,
Marek Vasut
Michal Simek - Sept. 13, 2012, 9:45 a.m.
On 09/13/2012 11:21 AM, Marek Vasut wrote:
> Dear Michal Simek,
>
>> The driver is used on Xilinx Zynq platform.
>>
>> Signed-off-by: Michal Simek <monstr@monstr.eu>
>>
>> ---
>> v2: Use Zynq name instead of Dragonfire and XPSS/XDFUART
>>      Rename driver name
>>      Remove driver description
>> ---
>>   drivers/serial/Makefile      |    1 +
>>   drivers/serial/serial_zynq.c |  200
>> ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 201
>> insertions(+), 0 deletions(-)
>>   create mode 100644 drivers/serial/serial_zynq.c
> [...]
>
> It looks ok, but can you make it support CONFIG_SERIAL_MULTI right away please?

Yes, it will add serial_multi in the next patch.
Can you give me your ACK or reviewed-by line? :-)


Maybe you have seen it. I have asked for pulling serial multi for uartlite.

Thanks,
Michal
Marek Vasut - Sept. 13, 2012, 12:33 p.m.
Dear Michal Simek,

> On 09/13/2012 11:21 AM, Marek Vasut wrote:
> > Dear Michal Simek,
> > 
> >> The driver is used on Xilinx Zynq platform.
> >> 
> >> Signed-off-by: Michal Simek <monstr@monstr.eu>
> >> 
> >> ---
> >> v2: Use Zynq name instead of Dragonfire and XPSS/XDFUART
> >> 
> >>      Rename driver name
> >>      Remove driver description
> >> 
> >> ---
> >> 
> >>   drivers/serial/Makefile      |    1 +
> >>   drivers/serial/serial_zynq.c |  200
> >> 
> >> ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 201
> >> insertions(+), 0 deletions(-)
> >> 
> >>   create mode 100644 drivers/serial/serial_zynq.c
> > 
> > [...]
> > 
> > It looks ok, but can you make it support CONFIG_SERIAL_MULTI right away
> > please?
> 
> Yes, it will add serial_multi in the next patch.
> Can you give me your ACK or reviewed-by line? :-)

Just squash them into one patch please.

> Maybe you have seen it. I have asked for pulling serial multi for uartlite.

Pulling ?

> Thanks,
> Michal

Best regards,
Marek Vasut
Michal Simek - Sept. 13, 2012, 1:54 p.m.
On 09/13/2012 02:33 PM, Marek Vasut wrote:
> Dear Michal Simek,
>
>> On 09/13/2012 11:21 AM, Marek Vasut wrote:
>>> Dear Michal Simek,
>>>
>>>> The driver is used on Xilinx Zynq platform.
>>>>
>>>> Signed-off-by: Michal Simek <monstr@monstr.eu>
>>>>
>>>> ---
>>>> v2: Use Zynq name instead of Dragonfire and XPSS/XDFUART
>>>>
>>>>       Rename driver name
>>>>       Remove driver description
>>>>
>>>> ---
>>>>
>>>>    drivers/serial/Makefile      |    1 +
>>>>    drivers/serial/serial_zynq.c |  200
>>>>
>>>> ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 201
>>>> insertions(+), 0 deletions(-)
>>>>
>>>>    create mode 100644 drivers/serial/serial_zynq.c
>>>
>>> [...]
>>>
>>> It looks ok, but can you make it support CONFIG_SERIAL_MULTI right away
>>> please?
>>
>> Yes, it will add serial_multi in the next patch.
>> Can you give me your ACK or reviewed-by line? :-)
>
> Just squash them into one patch please.

Done.

Michal
Marek Vasut - Sept. 13, 2012, 2:01 p.m.
Dear Michal Simek,

> On 09/13/2012 02:33 PM, Marek Vasut wrote:
> > Dear Michal Simek,
> > 
> >> On 09/13/2012 11:21 AM, Marek Vasut wrote:
> >>> Dear Michal Simek,
> >>> 
> >>>> The driver is used on Xilinx Zynq platform.
> >>>> 
> >>>> Signed-off-by: Michal Simek <monstr@monstr.eu>
> >>>> 
> >>>> ---
> >>>> v2: Use Zynq name instead of Dragonfire and XPSS/XDFUART
> >>>> 
> >>>>       Rename driver name
> >>>>       Remove driver description
> >>>> 
> >>>> ---
> >>>> 
> >>>>    drivers/serial/Makefile      |    1 +
> >>>>    drivers/serial/serial_zynq.c |  200
> >>>> 
> >>>> ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 201
> >>>> insertions(+), 0 deletions(-)
> >>>> 
> >>>>    create mode 100644 drivers/serial/serial_zynq.c
> >>> 
> >>> [...]
> >>> 
> >>> It looks ok, but can you make it support CONFIG_SERIAL_MULTI right away
> >>> please?
> >> 
> >> Yes, it will add serial_multi in the next patch.
> >> Can you give me your ACK or reviewed-by line? :-)
> > 
> > Just squash them into one patch please.
> 
> Done.

Thanks ... my idea is to switch to serial_multi completely, then rework stdio, 
unify serial on top of it and clean up the whole subsystem. Thanks for helping!

> Michal

Best regards,
Marek Vasut
Joe Hershberger - Sept. 14, 2012, 4:09 a.m.
Hi Marek,

On Thu, Sep 13, 2012 at 9:01 AM, Marek Vasut <marex@denx.de> wrote:
> Dear Michal Simek,
>
>> On 09/13/2012 02:33 PM, Marek Vasut wrote:
>> > Dear Michal Simek,
>> >
>> >> On 09/13/2012 11:21 AM, Marek Vasut wrote:
>> >>> Dear Michal Simek,
>> >>>
>> >>>> The driver is used on Xilinx Zynq platform.
>> >>>>
>> >>>> Signed-off-by: Michal Simek <monstr@monstr.eu>
>> >>>>
>> >>>> ---
>> >>>> v2: Use Zynq name instead of Dragonfire and XPSS/XDFUART
>> >>>>
>> >>>>       Rename driver name
>> >>>>       Remove driver description
>> >>>>
>> >>>> ---
>> >>>>
>> >>>>    drivers/serial/Makefile      |    1 +
>> >>>>    drivers/serial/serial_zynq.c |  200
>> >>>>
>> >>>> ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 201
>> >>>> insertions(+), 0 deletions(-)
>> >>>>
>> >>>>    create mode 100644 drivers/serial/serial_zynq.c
>> >>>
>> >>> [...]
>> >>>
>> >>> It looks ok, but can you make it support CONFIG_SERIAL_MULTI right away
>> >>> please?
>> >>
>> >> Yes, it will add serial_multi in the next patch.
>> >> Can you give me your ACK or reviewed-by line? :-)
>> >
>> > Just squash them into one patch please.
>>
>> Done.
>
> Thanks ... my idea is to switch to serial_multi completely, then rework stdio,
> unify serial on top of it and clean up the whole subsystem. Thanks for helping!

I have a patch that I'll send soon that moves the "nulldev" driver to
the serial driver (if CONFIG_SERIAL_MULTI is defined) so that it is
possible to avoid serial init.  I had the problem that the serial port
on my Zynq product lives in the fabric instead of using the hard-core
ones.  This means that the FPGA neds to be configured first, but since
I'm using u-boot for that too, I need it to start as null and switch
to the fabric serial after the FPGA is configured.  Anyway, just more
support for supporting CONFIG_SERIAL_MULTI.

-Joe
Marek Vasut - Sept. 14, 2012, 4:47 a.m.
Dear Joe Hershberger,

> Hi Marek,
> 
> On Thu, Sep 13, 2012 at 9:01 AM, Marek Vasut <marex@denx.de> wrote:
> > Dear Michal Simek,
> > 
> >> On 09/13/2012 02:33 PM, Marek Vasut wrote:
> >> > Dear Michal Simek,
> >> > 
> >> >> On 09/13/2012 11:21 AM, Marek Vasut wrote:
> >> >>> Dear Michal Simek,
> >> >>> 
> >> >>>> The driver is used on Xilinx Zynq platform.
> >> >>>> 
> >> >>>> Signed-off-by: Michal Simek <monstr@monstr.eu>
> >> >>>> 
> >> >>>> ---
> >> >>>> v2: Use Zynq name instead of Dragonfire and XPSS/XDFUART
> >> >>>> 
> >> >>>>       Rename driver name
> >> >>>>       Remove driver description
> >> >>>> 
> >> >>>> ---
> >> >>>> 
> >> >>>>    drivers/serial/Makefile      |    1 +
> >> >>>>    drivers/serial/serial_zynq.c |  200
> >> >>>> 
> >> >>>> ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 201
> >> >>>> insertions(+), 0 deletions(-)
> >> >>>> 
> >> >>>>    create mode 100644 drivers/serial/serial_zynq.c
> >> >>> 
> >> >>> [...]
> >> >>> 
> >> >>> It looks ok, but can you make it support CONFIG_SERIAL_MULTI right
> >> >>> away please?
> >> >> 
> >> >> Yes, it will add serial_multi in the next patch.
> >> >> Can you give me your ACK or reviewed-by line? :-)
> >> > 
> >> > Just squash them into one patch please.
> >> 
> >> Done.
> > 
> > Thanks ... my idea is to switch to serial_multi completely, then rework
> > stdio, unify serial on top of it and clean up the whole subsystem.
> > Thanks for helping!
> 
> I have a patch that I'll send soon that moves the "nulldev" driver to
> the serial driver (if CONFIG_SERIAL_MULTI is defined) so that it is
> possible to avoid serial init.

Thanks, this will break my massive patchset though. Can you check 
git://git.denx.de/u-boot-marex.git / stdio branch ? I did something to nulldev 
there. Probably ignore the top 7 patches, they're bogus and need further work. 
It's all still work in progress to some point.

> I had the problem that the serial port
> on my Zynq product lives in the fabric instead of using the hard-core
> ones.

I see ... why don't you implement nulldev_serial instead and leave nulldev stdio 
as is?

> This means that the FPGA neds to be configured first, but since
> I'm using u-boot for that too, I need it to start as null and switch
> to the fabric serial after the FPGA is configured.  Anyway, just more
> support for supporting CONFIG_SERIAL_MULTI.
> 
> -Joe

Best regards,
Marek Vasut
Joe Hershberger - Sept. 14, 2012, 5:23 a.m.
Hi Marek,

On Thu, Sep 13, 2012 at 11:47 PM, Marek Vasut <marex@denx.de> wrote:
> Dear Joe Hershberger,
>
>> Hi Marek,
>>
>> On Thu, Sep 13, 2012 at 9:01 AM, Marek Vasut <marex@denx.de> wrote:
>> > Dear Michal Simek,
>> >
>> >> On 09/13/2012 02:33 PM, Marek Vasut wrote:
>> >> > Dear Michal Simek,
>> >> >
>> >> >> On 09/13/2012 11:21 AM, Marek Vasut wrote:
>> >> >>> Dear Michal Simek,
>> >> >>>
>> >> >>>> The driver is used on Xilinx Zynq platform.
>> >> >>>>
>> >> >>>> Signed-off-by: Michal Simek <monstr@monstr.eu>
>> >> >>>>
>> >> >>>> ---
>> >> >>>> v2: Use Zynq name instead of Dragonfire and XPSS/XDFUART
>> >> >>>>
>> >> >>>>       Rename driver name
>> >> >>>>       Remove driver description
>> >> >>>>
>> >> >>>> ---
>> >> >>>>
>> >> >>>>    drivers/serial/Makefile      |    1 +
>> >> >>>>    drivers/serial/serial_zynq.c |  200
>> >> >>>>
>> >> >>>> ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 201
>> >> >>>> insertions(+), 0 deletions(-)
>> >> >>>>
>> >> >>>>    create mode 100644 drivers/serial/serial_zynq.c
>> >> >>>
>> >> >>> [...]
>> >> >>>
>> >> >>> It looks ok, but can you make it support CONFIG_SERIAL_MULTI right
>> >> >>> away please?
>> >> >>
>> >> >> Yes, it will add serial_multi in the next patch.
>> >> >> Can you give me your ACK or reviewed-by line? :-)
>> >> >
>> >> > Just squash them into one patch please.
>> >>
>> >> Done.
>> >
>> > Thanks ... my idea is to switch to serial_multi completely, then rework
>> > stdio, unify serial on top of it and clean up the whole subsystem.
>> > Thanks for helping!
>>
>> I have a patch that I'll send soon that moves the "nulldev" driver to
>> the serial driver (if CONFIG_SERIAL_MULTI is defined) so that it is
>> possible to avoid serial init.
>
> Thanks, this will break my massive patchset though. Can you check
> git://git.denx.de/u-boot-marex.git / stdio branch ? I did something to nulldev
> there. Probably ignore the top 7 patches, they're bogus and need further work.
> It's all still work in progress to some point.

Too bad I can't just browse this at gitweb.

>> I had the problem that the serial port
>> on my Zynq product lives in the fabric instead of using the hard-core
>> ones.
>
> I see ... why don't you implement nulldev_serial instead and leave nulldev stdio
> as is?

Mostly because there is little point in supporting both at the same time.

-Joe
Marek Vasut - Sept. 14, 2012, 7:39 a.m.
Dear Joe Hershberger,

> Hi Marek,
> 
> On Thu, Sep 13, 2012 at 11:47 PM, Marek Vasut <marex@denx.de> wrote:
> > Dear Joe Hershberger,
> > 
> >> Hi Marek,
> >> 
> >> On Thu, Sep 13, 2012 at 9:01 AM, Marek Vasut <marex@denx.de> wrote:
> >> > Dear Michal Simek,
> >> > 
> >> >> On 09/13/2012 02:33 PM, Marek Vasut wrote:
> >> >> > Dear Michal Simek,
> >> >> > 
> >> >> >> On 09/13/2012 11:21 AM, Marek Vasut wrote:
> >> >> >>> Dear Michal Simek,
> >> >> >>> 
> >> >> >>>> The driver is used on Xilinx Zynq platform.
> >> >> >>>> 
> >> >> >>>> Signed-off-by: Michal Simek <monstr@monstr.eu>
> >> >> >>>> 
> >> >> >>>> ---
> >> >> >>>> v2: Use Zynq name instead of Dragonfire and XPSS/XDFUART
> >> >> >>>> 
> >> >> >>>>       Rename driver name
> >> >> >>>>       Remove driver description
> >> >> >>>> 
> >> >> >>>> ---
> >> >> >>>> 
> >> >> >>>>    drivers/serial/Makefile      |    1 +
> >> >> >>>>    drivers/serial/serial_zynq.c |  200
> >> >> >>>> 
> >> >> >>>> ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 201
> >> >> >>>> insertions(+), 0 deletions(-)
> >> >> >>>> 
> >> >> >>>>    create mode 100644 drivers/serial/serial_zynq.c
> >> >> >>> 
> >> >> >>> [...]
> >> >> >>> 
> >> >> >>> It looks ok, but can you make it support CONFIG_SERIAL_MULTI
> >> >> >>> right away please?
> >> >> >> 
> >> >> >> Yes, it will add serial_multi in the next patch.
> >> >> >> Can you give me your ACK or reviewed-by line? :-)
> >> >> > 
> >> >> > Just squash them into one patch please.
> >> >> 
> >> >> Done.
> >> > 
> >> > Thanks ... my idea is to switch to serial_multi completely, then
> >> > rework stdio, unify serial on top of it and clean up the whole
> >> > subsystem. Thanks for helping!
> >> 
> >> I have a patch that I'll send soon that moves the "nulldev" driver to
> >> the serial driver (if CONFIG_SERIAL_MULTI is defined) so that it is
> >> possible to avoid serial init.
> > 
> > Thanks, this will break my massive patchset though. Can you check
> > git://git.denx.de/u-boot-marex.git / stdio branch ? I did something to
> > nulldev there. Probably ignore the top 7 patches, they're bogus and need
> > further work. It's all still work in progress to some point.
> 
> Too bad I can't just browse this at gitweb.

Intended ... just

git remote add marex git://...
git fetch marex
git checkout -t -b stdio marex/stdio

And enjoy the horror show :-)

> >> I had the problem that the serial port
> >> on my Zynq product lives in the fabric instead of using the hard-core
> >> ones.
> > 
> > I see ... why don't you implement nulldev_serial instead and leave
> > nulldev stdio as is?
> 
> Mostly because there is little point in supporting both at the same time.

Can you enlighten me ? stdio != serial, the purpose is different really.

If someone wants to setenv stdout serial and have serial null, be my guest. But 
then there really should be a direct, explicit stdio nulldev too.

> -Joe

Best regards,
Marek Vasut

Patch

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..c49da3b
--- /dev/null
+++ b/drivers/serial/serial_zynq.c
@@ -0,0 +1,200 @@ 
+/*
+ * 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 <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 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[2] = {
+#ifdef CONFIG_ZYNQ_SERIAL_BASEADDR0
+	[0] = (struct xdfuart *)CONFIG_ZYNQ_SERIAL_BASEADDR0,
+#endif
+#ifdef CONFIG_ZYNQ_SERIAL_BASEADDR1
+	[1] = (struct xdfuart *)CONFIG_ZYNQ_SERIAL_BASEADDR1,
+#endif
+};
+
+struct xdfuart_params {
+	u32 baudrate;
+	u32 clock;
+};
+
+static struct xdfuart_params xdf_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 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, &regs->baud_rate_divider);
+	writel(bgen, &regs->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(ZYNQ_UART_CR_TX_EN | ZYNQ_UART_CR_RX_EN | ZYNQ_UART_CR_TXRST | \
+					ZYNQ_UART_CR_RXRST, &regs->control);
+	writel(ZYNQ_UART_MR_PARITY_NONE, &regs->mode); /* 8 bit, no parity */
+	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(&regs->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0)
+		WATCHDOG_RESET();
+
+	if (c == '\n') {
+		writel('\r', &regs->tx_rx_fifo);
+		while ((readl(&regs->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0)
+			WATCHDOG_RESET();
+	}
+	writel(c, &regs->tx_rx_fifo);
+}
+
+static void 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(&regs->channel_sts) & ZYNQ_UART_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(&regs->tx_rx_fifo);
+}
+
+int serial_init(void)
+{
+	return xdfuart_serial_init(0);
+}
+
+void serial_setbrg(void)
+{
+	xdfuart_serial_setbrg(0);
+}
+
+void serial_putc(const char c)
+{
+	xdfuart_serial_putc(c, 0);
+}
+
+void serial_puts(const char *s)
+{
+	xdfuart_serial_puts(s, 0);
+}
+
+int serial_getc(void)
+{
+	return xdfuart_serial_getc(0);
+}
+
+int serial_tstc(void)
+{
+	return xdfuart_serial_tstc(0);
+}