diff mbox

[U-Boot] drivers/rtc: add Marvell Integrated RTC.

Message ID 1312159685-13335-1-git-send-email-u-boot@lakedaemon.net
State Superseded
Headers show

Commit Message

u-boot@lakedaemon.net Aug. 1, 2011, 12:48 a.m. UTC
This driver can be used for kirkwood SoCs by enabling CONFIG_RTC_MVINTEG.
Tested on Global Scale Technologies Dreamplug.

Signed-off-by: Jason Cooper <u-boot@lakedaemon.net>
---
Changes from v1:
	- renamed files to mvrtc.{c,h}
	- used proper c-structs for register access
	- used existing macros for register access
	- removed RFC

 arch/arm/include/asm/arch-kirkwood/kirkwood.h |    1 +
 drivers/rtc/Makefile                          |    1 +
 drivers/rtc/mvrtc.c                           |  157 +++++++++++++++++++++++++
 drivers/rtc/mvrtc.h                           |   79 +++++++++++++
 4 files changed, 238 insertions(+), 0 deletions(-)
 create mode 100644 drivers/rtc/mvrtc.c
 create mode 100644 drivers/rtc/mvrtc.h

Comments

u-boot@lakedaemon.net Aug. 1, 2011, 12:51 a.m. UTC | #1
v2.  My apologies.

thx,

Jason.
Simon Guinot Aug. 1, 2011, 11:49 a.m. UTC | #2
Hi Jason,

On Mon, Aug 01, 2011 at 12:48:05AM +0000, Jason Cooper wrote:
> This driver can be used for kirkwood SoCs by enabling CONFIG_RTC_MVINTEG.
> Tested on Global Scale Technologies Dreamplug.
> 
> Signed-off-by: Jason Cooper <u-boot@lakedaemon.net>
> ---
> Changes from v1:
> 	- renamed files to mvrtc.{c,h}
> 	- used proper c-structs for register access
> 	- used existing macros for register access
> 	- removed RFC
> 
>  arch/arm/include/asm/arch-kirkwood/kirkwood.h |    1 +
>  drivers/rtc/Makefile                          |    1 +
>  drivers/rtc/mvrtc.c                           |  157 +++++++++++++++++++++++++
>  drivers/rtc/mvrtc.h                           |   79 +++++++++++++
>  4 files changed, 238 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/rtc/mvrtc.c
>  create mode 100644 drivers/rtc/mvrtc.h
> 
> diff --git a/arch/arm/include/asm/arch-kirkwood/kirkwood.h b/arch/arm/include/asm/arch-kirkwood/kirkwood.h
> index 0104418..3c843a0 100644
> --- a/arch/arm/include/asm/arch-kirkwood/kirkwood.h
> +++ b/arch/arm/include/asm/arch-kirkwood/kirkwood.h
> @@ -50,6 +50,7 @@
>  #define KW_MPP_BASE			(KW_REGISTER(0x10000))
>  #define KW_GPIO0_BASE			(KW_REGISTER(0x10100))
>  #define KW_GPIO1_BASE			(KW_REGISTER(0x10140))
> +#define KW_RTC_BASE			(KW_REGISTER(0x10300))
>  #define KW_NANDF_BASE			(KW_REGISTER(0x10418))
>  #define KW_SPI_BASE			(KW_REGISTER(0x10600))
>  #define KW_CPU_WIN_BASE			(KW_REGISTER(0x20000))
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index e4be4a4..e1591a0 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -55,6 +55,7 @@ COBJS-$(CONFIG_MCFRTC) += mcfrtc.o
>  COBJS-$(CONFIG_RTC_MK48T59) += mk48t59.o
>  COBJS-$(CONFIG_RTC_MPC5200) += mpc5xxx.o
>  COBJS-$(CONFIG_RTC_MPC8xx) += mpc8xx.o
> +COBJS-$(CONFIG_RTC_MVINTEG) += mvrtc.o

What about using CONFIG_RTC_MV ?

>  COBJS-$(CONFIG_RTC_PCF8563) += pcf8563.o
>  COBJS-$(CONFIG_RTC_PL031) += pl031.o
>  COBJS-$(CONFIG_RTC_PT7C4338) += pt7c4338.o
> diff --git a/drivers/rtc/mvrtc.c b/drivers/rtc/mvrtc.c
> new file mode 100644
> index 0000000..0db3b20
> --- /dev/null
> +++ b/drivers/rtc/mvrtc.c
> @@ -0,0 +1,157 @@
> +/*
> + * Copyright (C) 2011
> + * Jason Cooper <u-boot@lakedaemon.net>
> + *
> + * 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
> + */
> +
> +/*
> + * Date & Time support for Marvell Integrated RTC
> + */
> +
> +#include <common.h>
> +#include <command.h>
> +#include <rtc.h>
> +#include "mvrtc.h"
> +
> +/* This RTC does not support century, so we assume 20 */
> +#define CENTURY 20
> +
> +int rtc_get(struct rtc_time *t)
> +{
> +	u32 time;
> +	u32 date;
> +	u8  tens;
> +	u8  single;

Maybe you could use the function bcd2bin() and then hide the "tens" and
"single" split.

> +	struct mvrtc_registers *mvrtc_regs;
> +
> +	mvrtc_regs = (struct mvrtc_registers *)KW_RTC_BASE;
> +
> +	/* read the time register */
> +	time = readl(&mvrtc_regs->time);
> +
> +	/* read the date register */
> +	date = readl(&mvrtc_regs->date);

For example, you could have something like:

t->tm_sec = bcd2bin(time & 0x7f);
t->tm_min = bcd2bin((time >> MVRTC_MIN_SFT) & 0x7f);
t->tm_hour = bcd2bin((time >> MVRTC_HOUR_SFT) & 0x3f); /* 24 hour mode */
...

> +
> +	/* seconds */
> +	tens   = ((time & MVRTC_10SEC_MSK) >> MVRTC_10SEC_SFT);
> +	single = ((time & MVRTC_SEC_MSK)   >> MVRTC_SEC_SFT);
> +	t->tm_sec = 10 * tens + single;
> +
> +	/* minutes */
> +	tens   = ((time & MVRTC_10MIN_MSK) >> MVRTC_10MIN_SFT);
> +	single = ((time & MVRTC_MIN_MSK)   >> MVRTC_MIN_SFT);
> +	t->tm_min = 10 * tens + single;
> +
> +	/* hours */
> +	tens   = ((time & MVRTC_10HOUR_MSK) >> MVRTC_10HOUR_SFT);
> +	single = ((time & MVRTC_HOUR_MSK)   >> MVRTC_HOUR_SFT);
> +	t->tm_hour = 10 * tens + single;

If the RTC operates in 12 hour mode, the code above is wrong.

> +
> +	/* day */
> +	t->tm_wday = ((time & MVRTC_DAY_MSK) >> MVRTC_DAY_SFT);
> +	t->tm_wday--;
> +
> +	/* date */
> +	tens   = ((date & MVRTC_10DATE_MSK) >> MVRTC_10DATE_SFT);
> +	single = ((date & MVRTC_DATE_MSK)   >> MVRTC_DATE_SFT);
> +	t->tm_mday = 10 * tens + single;
> +
> +	/* month */
> +	tens   = ((date & MVRTC_10MON_MSK) >> MVRTC_10MON_SFT);
> +	single = ((date & MVRTC_MON_MSK)   >> MVRTC_MON_SFT);
> +	t->tm_mon = 10 * tens + single;
> +
> +	/* year */
> +	tens   = ((date & MVRTC_10YEAR_MSK) >> MVRTC_10YEAR_SFT);
> +	single = ((date & MVRTC_YEAR_MSK)   >> MVRTC_YEAR_SFT);
> +	t->tm_year = (CENTURY * 100) + (10 * tens) + single;
> +
> +	/* not supported in this RTC */
> +	t->tm_yday  = 0;
> +	t->tm_isdst = 0;
> +
> +	return 0;
> +}
> +
> +int rtc_set(struct rtc_time *t)
> +{
> +	u32 time = 0;
> +	u32 date = 0;
> +	u32 tens;
> +	u32 single;
> +	struct mvrtc_registers *mvrtc_regs;
> +
> +	mvrtc_regs = (struct mvrtc_registers *)KW_RTC_BASE;
> +
> +	/* seconds */
> +	tens   = t->tm_sec / 10;
> +	single = t->tm_sec % 10;

Again, you could use the function bin2bcd() and then get ride of this
"tens" and "single" split.

> +	time |= ((tens   << MVRTC_10SEC_SFT) & MVRTC_10SEC_MSK) |
> +		((single << MVRTC_SEC_SFT)   & MVRTC_SEC_MSK);

For example, here you could have:

time |= bin2bcd(tm->tm_sec) << MVRTC_SEC_SFT;

> +
> +	/* minutes */
> +	tens   = t->tm_min / 10;
> +	single = t->tm_min % 10;
> +	time |= ((tens   << MVRTC_10MIN_SFT) & MVRTC_10MIN_MSK) |
> +		((single << MVRTC_MIN_SFT)   & MVRTC_MIN_MSK);
> +
> +	/* hours (24) */
> +	tens   = t->tm_hour / 10;
> +	single = t->tm_hour % 10;
> +	time |= ((tens   << MVRTC_10HOUR_SFT) & MVRTC_10HOUR_MSK) |
> +		((single << MVRTC_HOUR_SFT)   & MVRTC_HOUR_MSK);
> +
> +	/* day */
> +	single = t->tm_wday + 1;
> +	time |= ((single << MVRTC_DAY_SFT) & MVRTC_DAY_MSK);
> +
> +	/* date */
> +	tens   = t->tm_mday / 10;
> +	single = t->tm_mday % 10;
> +	date |= ((tens   << MVRTC_10DATE_SFT) & MVRTC_10DATE_MSK) |
> +		((single << MVRTC_DATE_SFT)   & MVRTC_DATE_MSK);
> +
> +	/* month */
> +	tens   = t->tm_mon / 10;
> +	single = t->tm_mon % 10;
> +	date |= ((tens   << MVRTC_10MON_SFT) & MVRTC_10MON_MSK) |
> +		((single << MVRTC_MON_SFT)   & MVRTC_MON_MSK);
> +
> +	/* year */
> +	if ((t->tm_year / 100) != CENTURY)
> +		printf("Warning: Only century %d supported.\n", CENTURY);
> +	tens   = (t->tm_year % 100) / 10;
> +	single = (t->tm_year % 100) % 10;
> +	date |= ((tens   << MVRTC_10YEAR_SFT) & MVRTC_10YEAR_MSK) |
> +		((single << MVRTC_YEAR_SFT)   & MVRTC_YEAR_MSK);
> +
> +	/* write the time register */
> +	writel(time, &mvrtc_regs->time);
> +
> +	/* write the date register */
> +	writel(date, &mvrtc_regs->date);
> +
> +	return 0;
> +}
> +
> +void rtc_reset(void)
> +{
> +	/* no init routine for this RTC needed */

In the Linux driver, there is also a check to ensure that the RTC is
ticking. Maybe it could be useful here too, just to let know the RTC is 
functional (or not).

Regards,

Simon
u-boot@lakedaemon.net Aug. 1, 2011, 12:06 p.m. UTC | #3
On Mon, Aug 01, 2011 at 11:49:58AM +0000, Simon Guinot wrote:
> Hi Jason,
> 
> On Mon, Aug 01, 2011 at 12:48:05AM +0000, Jason Cooper wrote:
> > This driver can be used for kirkwood SoCs by enabling CONFIG_RTC_MVINTEG.
> > Tested on Global Scale Technologies Dreamplug.
> > 
> > Signed-off-by: Jason Cooper <u-boot@lakedaemon.net>
> > ---
> > Changes from v1:
> > 	- renamed files to mvrtc.{c,h}
> > 	- used proper c-structs for register access
> > 	- used existing macros for register access
> > 	- removed RFC
> > 
> >  arch/arm/include/asm/arch-kirkwood/kirkwood.h |    1 +
> >  drivers/rtc/Makefile                          |    1 +
> >  drivers/rtc/mvrtc.c                           |  157 +++++++++++++++++++++++++
> >  drivers/rtc/mvrtc.h                           |   79 +++++++++++++
> >  4 files changed, 238 insertions(+), 0 deletions(-)
> >  create mode 100644 drivers/rtc/mvrtc.c
> >  create mode 100644 drivers/rtc/mvrtc.h
> > 
> > diff --git a/arch/arm/include/asm/arch-kirkwood/kirkwood.h b/arch/arm/include/asm/arch-kirkwood/kirkwood.h
> > index 0104418..3c843a0 100644
> > --- a/arch/arm/include/asm/arch-kirkwood/kirkwood.h
> > +++ b/arch/arm/include/asm/arch-kirkwood/kirkwood.h
> > @@ -50,6 +50,7 @@
> >  #define KW_MPP_BASE			(KW_REGISTER(0x10000))
> >  #define KW_GPIO0_BASE			(KW_REGISTER(0x10100))
> >  #define KW_GPIO1_BASE			(KW_REGISTER(0x10140))
> > +#define KW_RTC_BASE			(KW_REGISTER(0x10300))
> >  #define KW_NANDF_BASE			(KW_REGISTER(0x10418))
> >  #define KW_SPI_BASE			(KW_REGISTER(0x10600))
> >  #define KW_CPU_WIN_BASE			(KW_REGISTER(0x20000))
> > diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> > index e4be4a4..e1591a0 100644
> > --- a/drivers/rtc/Makefile
> > +++ b/drivers/rtc/Makefile
> > @@ -55,6 +55,7 @@ COBJS-$(CONFIG_MCFRTC) += mcfrtc.o
> >  COBJS-$(CONFIG_RTC_MK48T59) += mk48t59.o
> >  COBJS-$(CONFIG_RTC_MPC5200) += mpc5xxx.o
> >  COBJS-$(CONFIG_RTC_MPC8xx) += mpc8xx.o
> > +COBJS-$(CONFIG_RTC_MVINTEG) += mvrtc.o
> 
> What about using CONFIG_RTC_MV ?

Sure.

> >  COBJS-$(CONFIG_RTC_PCF8563) += pcf8563.o
> >  COBJS-$(CONFIG_RTC_PL031) += pl031.o
> >  COBJS-$(CONFIG_RTC_PT7C4338) += pt7c4338.o
> > diff --git a/drivers/rtc/mvrtc.c b/drivers/rtc/mvrtc.c
> > new file mode 100644
> > index 0000000..0db3b20
> > --- /dev/null
> > +++ b/drivers/rtc/mvrtc.c
> > @@ -0,0 +1,157 @@
> > +/*
> > + * Copyright (C) 2011
> > + * Jason Cooper <u-boot@lakedaemon.net>
> > + *
> > + * 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
> > + */
> > +
> > +/*
> > + * Date & Time support for Marvell Integrated RTC
> > + */
> > +
> > +#include <common.h>
> > +#include <command.h>
> > +#include <rtc.h>
> > +#include "mvrtc.h"
> > +
> > +/* This RTC does not support century, so we assume 20 */
> > +#define CENTURY 20
> > +
> > +int rtc_get(struct rtc_time *t)
> > +{
> > +	u32 time;
> > +	u32 date;
> > +	u8  tens;
> > +	u8  single;
> 
> Maybe you could use the function bcd2bin() and then hide the "tens" and
> "single" split.
> 
> > +	struct mvrtc_registers *mvrtc_regs;
> > +
> > +	mvrtc_regs = (struct mvrtc_registers *)KW_RTC_BASE;
> > +
> > +	/* read the time register */
> > +	time = readl(&mvrtc_regs->time);
> > +
> > +	/* read the date register */
> > +	date = readl(&mvrtc_regs->date);
> 
> For example, you could have something like:
> 
> t->tm_sec = bcd2bin(time & 0x7f);
> t->tm_min = bcd2bin((time >> MVRTC_MIN_SFT) & 0x7f);
> t->tm_hour = bcd2bin((time >> MVRTC_HOUR_SFT) & 0x3f); /* 24 hour mode */
> ...

Awesome, thanks!  Will do.

> > +
> > +	/* seconds */
> > +	tens   = ((time & MVRTC_10SEC_MSK) >> MVRTC_10SEC_SFT);
> > +	single = ((time & MVRTC_SEC_MSK)   >> MVRTC_SEC_SFT);
> > +	t->tm_sec = 10 * tens + single;
> > +
> > +	/* minutes */
> > +	tens   = ((time & MVRTC_10MIN_MSK) >> MVRTC_10MIN_SFT);
> > +	single = ((time & MVRTC_MIN_MSK)   >> MVRTC_MIN_SFT);
> > +	t->tm_min = 10 * tens + single;
> > +
> > +	/* hours */
> > +	tens   = ((time & MVRTC_10HOUR_MSK) >> MVRTC_10HOUR_SFT);
> > +	single = ((time & MVRTC_HOUR_MSK)   >> MVRTC_HOUR_SFT);
> > +	t->tm_hour = 10 * tens + single;
> 
> If the RTC operates in 12 hour mode, the code above is wrong.

Will double check, I've been testing it in the evening without problems.
I'll set it to just before noon to see what it does.

> > +
> > +	/* day */
> > +	t->tm_wday = ((time & MVRTC_DAY_MSK) >> MVRTC_DAY_SFT);
> > +	t->tm_wday--;
> > +
> > +	/* date */
> > +	tens   = ((date & MVRTC_10DATE_MSK) >> MVRTC_10DATE_SFT);
> > +	single = ((date & MVRTC_DATE_MSK)   >> MVRTC_DATE_SFT);
> > +	t->tm_mday = 10 * tens + single;
> > +
> > +	/* month */
> > +	tens   = ((date & MVRTC_10MON_MSK) >> MVRTC_10MON_SFT);
> > +	single = ((date & MVRTC_MON_MSK)   >> MVRTC_MON_SFT);
> > +	t->tm_mon = 10 * tens + single;
> > +
> > +	/* year */
> > +	tens   = ((date & MVRTC_10YEAR_MSK) >> MVRTC_10YEAR_SFT);
> > +	single = ((date & MVRTC_YEAR_MSK)   >> MVRTC_YEAR_SFT);
> > +	t->tm_year = (CENTURY * 100) + (10 * tens) + single;
> > +
> > +	/* not supported in this RTC */
> > +	t->tm_yday  = 0;
> > +	t->tm_isdst = 0;
> > +
> > +	return 0;
> > +}
> > +
> > +int rtc_set(struct rtc_time *t)
> > +{
> > +	u32 time = 0;
> > +	u32 date = 0;
> > +	u32 tens;
> > +	u32 single;
> > +	struct mvrtc_registers *mvrtc_regs;
> > +
> > +	mvrtc_regs = (struct mvrtc_registers *)KW_RTC_BASE;
> > +
> > +	/* seconds */
> > +	tens   = t->tm_sec / 10;
> > +	single = t->tm_sec % 10;
> 
> Again, you could use the function bin2bcd() and then get ride of this
> "tens" and "single" split.
> 
> > +	time |= ((tens   << MVRTC_10SEC_SFT) & MVRTC_10SEC_MSK) |
> > +		((single << MVRTC_SEC_SFT)   & MVRTC_SEC_MSK);
> 
> For example, here you could have:
> 
> time |= bin2bcd(tm->tm_sec) << MVRTC_SEC_SFT;
> 
> > +
> > +	/* minutes */
> > +	tens   = t->tm_min / 10;
> > +	single = t->tm_min % 10;
> > +	time |= ((tens   << MVRTC_10MIN_SFT) & MVRTC_10MIN_MSK) |
> > +		((single << MVRTC_MIN_SFT)   & MVRTC_MIN_MSK);
> > +
> > +	/* hours (24) */
> > +	tens   = t->tm_hour / 10;
> > +	single = t->tm_hour % 10;
> > +	time |= ((tens   << MVRTC_10HOUR_SFT) & MVRTC_10HOUR_MSK) |
> > +		((single << MVRTC_HOUR_SFT)   & MVRTC_HOUR_MSK);
> > +
> > +	/* day */
> > +	single = t->tm_wday + 1;
> > +	time |= ((single << MVRTC_DAY_SFT) & MVRTC_DAY_MSK);
> > +
> > +	/* date */
> > +	tens   = t->tm_mday / 10;
> > +	single = t->tm_mday % 10;
> > +	date |= ((tens   << MVRTC_10DATE_SFT) & MVRTC_10DATE_MSK) |
> > +		((single << MVRTC_DATE_SFT)   & MVRTC_DATE_MSK);
> > +
> > +	/* month */
> > +	tens   = t->tm_mon / 10;
> > +	single = t->tm_mon % 10;
> > +	date |= ((tens   << MVRTC_10MON_SFT) & MVRTC_10MON_MSK) |
> > +		((single << MVRTC_MON_SFT)   & MVRTC_MON_MSK);
> > +
> > +	/* year */
> > +	if ((t->tm_year / 100) != CENTURY)
> > +		printf("Warning: Only century %d supported.\n", CENTURY);
> > +	tens   = (t->tm_year % 100) / 10;
> > +	single = (t->tm_year % 100) % 10;
> > +	date |= ((tens   << MVRTC_10YEAR_SFT) & MVRTC_10YEAR_MSK) |
> > +		((single << MVRTC_YEAR_SFT)   & MVRTC_YEAR_MSK);
> > +
> > +	/* write the time register */
> > +	writel(time, &mvrtc_regs->time);
> > +
> > +	/* write the date register */
> > +	writel(date, &mvrtc_regs->date);
> > +
> > +	return 0;
> > +}
> > +
> > +void rtc_reset(void)
> > +{
> > +	/* no init routine for this RTC needed */
> 
> In the Linux driver, there is also a check to ensure that the RTC is
> ticking. Maybe it could be useful here too, just to let know the RTC is 
> functional (or not).

Good idea, I'll take a look at the Linux code for that test and
implement similar.
> 
> Regards,
> 
> Simon

Thanks for the comments and suggestions,

Jason.
diff mbox

Patch

diff --git a/arch/arm/include/asm/arch-kirkwood/kirkwood.h b/arch/arm/include/asm/arch-kirkwood/kirkwood.h
index 0104418..3c843a0 100644
--- a/arch/arm/include/asm/arch-kirkwood/kirkwood.h
+++ b/arch/arm/include/asm/arch-kirkwood/kirkwood.h
@@ -50,6 +50,7 @@ 
 #define KW_MPP_BASE			(KW_REGISTER(0x10000))
 #define KW_GPIO0_BASE			(KW_REGISTER(0x10100))
 #define KW_GPIO1_BASE			(KW_REGISTER(0x10140))
+#define KW_RTC_BASE			(KW_REGISTER(0x10300))
 #define KW_NANDF_BASE			(KW_REGISTER(0x10418))
 #define KW_SPI_BASE			(KW_REGISTER(0x10600))
 #define KW_CPU_WIN_BASE			(KW_REGISTER(0x20000))
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index e4be4a4..e1591a0 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -55,6 +55,7 @@  COBJS-$(CONFIG_MCFRTC) += mcfrtc.o
 COBJS-$(CONFIG_RTC_MK48T59) += mk48t59.o
 COBJS-$(CONFIG_RTC_MPC5200) += mpc5xxx.o
 COBJS-$(CONFIG_RTC_MPC8xx) += mpc8xx.o
+COBJS-$(CONFIG_RTC_MVINTEG) += mvrtc.o
 COBJS-$(CONFIG_RTC_PCF8563) += pcf8563.o
 COBJS-$(CONFIG_RTC_PL031) += pl031.o
 COBJS-$(CONFIG_RTC_PT7C4338) += pt7c4338.o
diff --git a/drivers/rtc/mvrtc.c b/drivers/rtc/mvrtc.c
new file mode 100644
index 0000000..0db3b20
--- /dev/null
+++ b/drivers/rtc/mvrtc.c
@@ -0,0 +1,157 @@ 
+/*
+ * Copyright (C) 2011
+ * Jason Cooper <u-boot@lakedaemon.net>
+ *
+ * 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
+ */
+
+/*
+ * Date & Time support for Marvell Integrated RTC
+ */
+
+#include <common.h>
+#include <command.h>
+#include <rtc.h>
+#include "mvrtc.h"
+
+/* This RTC does not support century, so we assume 20 */
+#define CENTURY 20
+
+int rtc_get(struct rtc_time *t)
+{
+	u32 time;
+	u32 date;
+	u8  tens;
+	u8  single;
+	struct mvrtc_registers *mvrtc_regs;
+
+	mvrtc_regs = (struct mvrtc_registers *)KW_RTC_BASE;
+
+	/* read the time register */
+	time = readl(&mvrtc_regs->time);
+
+	/* read the date register */
+	date = readl(&mvrtc_regs->date);
+
+	/* seconds */
+	tens   = ((time & MVRTC_10SEC_MSK) >> MVRTC_10SEC_SFT);
+	single = ((time & MVRTC_SEC_MSK)   >> MVRTC_SEC_SFT);
+	t->tm_sec = 10 * tens + single;
+
+	/* minutes */
+	tens   = ((time & MVRTC_10MIN_MSK) >> MVRTC_10MIN_SFT);
+	single = ((time & MVRTC_MIN_MSK)   >> MVRTC_MIN_SFT);
+	t->tm_min = 10 * tens + single;
+
+	/* hours */
+	tens   = ((time & MVRTC_10HOUR_MSK) >> MVRTC_10HOUR_SFT);
+	single = ((time & MVRTC_HOUR_MSK)   >> MVRTC_HOUR_SFT);
+	t->tm_hour = 10 * tens + single;
+
+	/* day */
+	t->tm_wday = ((time & MVRTC_DAY_MSK) >> MVRTC_DAY_SFT);
+	t->tm_wday--;
+
+	/* date */
+	tens   = ((date & MVRTC_10DATE_MSK) >> MVRTC_10DATE_SFT);
+	single = ((date & MVRTC_DATE_MSK)   >> MVRTC_DATE_SFT);
+	t->tm_mday = 10 * tens + single;
+
+	/* month */
+	tens   = ((date & MVRTC_10MON_MSK) >> MVRTC_10MON_SFT);
+	single = ((date & MVRTC_MON_MSK)   >> MVRTC_MON_SFT);
+	t->tm_mon = 10 * tens + single;
+
+	/* year */
+	tens   = ((date & MVRTC_10YEAR_MSK) >> MVRTC_10YEAR_SFT);
+	single = ((date & MVRTC_YEAR_MSK)   >> MVRTC_YEAR_SFT);
+	t->tm_year = (CENTURY * 100) + (10 * tens) + single;
+
+	/* not supported in this RTC */
+	t->tm_yday  = 0;
+	t->tm_isdst = 0;
+
+	return 0;
+}
+
+int rtc_set(struct rtc_time *t)
+{
+	u32 time = 0;
+	u32 date = 0;
+	u32 tens;
+	u32 single;
+	struct mvrtc_registers *mvrtc_regs;
+
+	mvrtc_regs = (struct mvrtc_registers *)KW_RTC_BASE;
+
+	/* seconds */
+	tens   = t->tm_sec / 10;
+	single = t->tm_sec % 10;
+	time |= ((tens   << MVRTC_10SEC_SFT) & MVRTC_10SEC_MSK) |
+		((single << MVRTC_SEC_SFT)   & MVRTC_SEC_MSK);
+
+	/* minutes */
+	tens   = t->tm_min / 10;
+	single = t->tm_min % 10;
+	time |= ((tens   << MVRTC_10MIN_SFT) & MVRTC_10MIN_MSK) |
+		((single << MVRTC_MIN_SFT)   & MVRTC_MIN_MSK);
+
+	/* hours (24) */
+	tens   = t->tm_hour / 10;
+	single = t->tm_hour % 10;
+	time |= ((tens   << MVRTC_10HOUR_SFT) & MVRTC_10HOUR_MSK) |
+		((single << MVRTC_HOUR_SFT)   & MVRTC_HOUR_MSK);
+
+	/* day */
+	single = t->tm_wday + 1;
+	time |= ((single << MVRTC_DAY_SFT) & MVRTC_DAY_MSK);
+
+	/* date */
+	tens   = t->tm_mday / 10;
+	single = t->tm_mday % 10;
+	date |= ((tens   << MVRTC_10DATE_SFT) & MVRTC_10DATE_MSK) |
+		((single << MVRTC_DATE_SFT)   & MVRTC_DATE_MSK);
+
+	/* month */
+	tens   = t->tm_mon / 10;
+	single = t->tm_mon % 10;
+	date |= ((tens   << MVRTC_10MON_SFT) & MVRTC_10MON_MSK) |
+		((single << MVRTC_MON_SFT)   & MVRTC_MON_MSK);
+
+	/* year */
+	if ((t->tm_year / 100) != CENTURY)
+		printf("Warning: Only century %d supported.\n", CENTURY);
+	tens   = (t->tm_year % 100) / 10;
+	single = (t->tm_year % 100) % 10;
+	date |= ((tens   << MVRTC_10YEAR_SFT) & MVRTC_10YEAR_MSK) |
+		((single << MVRTC_YEAR_SFT)   & MVRTC_YEAR_MSK);
+
+	/* write the time register */
+	writel(time, &mvrtc_regs->time);
+
+	/* write the date register */
+	writel(date, &mvrtc_regs->date);
+
+	return 0;
+}
+
+void rtc_reset(void)
+{
+	/* no init routine for this RTC needed */
+}
diff --git a/drivers/rtc/mvrtc.h b/drivers/rtc/mvrtc.h
new file mode 100644
index 0000000..286b223
--- /dev/null
+++ b/drivers/rtc/mvrtc.h
@@ -0,0 +1,79 @@ 
+/*
+ * Copyright (C) 2011
+ * Jason Cooper <u-boot@lakedaemon.net>
+ *
+ * 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
+ */
+
+/*
+ * Date & Time support for Marvell Integrated RTC
+ */
+
+#ifndef _MVRTC_H_
+#define _MVRTC_H_
+
+#include <asm/arch/kirkwood.h>
+#include <compiler.h>
+
+/* RTC registers */
+struct mvrtc_registers {
+	u32 time;
+	u32 date;
+};
+
+/* time register */
+#define MVRTC_SEC_SFT		0
+#define MVRTC_SEC_MSK		(0xf << MVRTC_SEC_SFT)
+#define MVRTC_10SEC_SFT		4
+#define MVRTC_10SEC_MSK		(0x7 << MVRTC_10SEC_SFT)
+
+#define MVRTC_MIN_SFT		8
+#define MVRTC_MIN_MSK		(0xf << MVRTC_MIN_SFT)
+#define MVRTC_10MIN_SFT		12
+#define MVRTC_10MIN_MSK		(0x7 << MVRTC_10MIN_SFT)
+
+#define MVRTC_HOUR_SFT		16
+#define MVRTC_HOUR_MSK		(0xf << MVRTC_HOUR_SFT)
+#define MVRTC_10HOUR_SFT	20
+#define MVRTC_10HOUR_MSK	(0x3 << MVRTC_10HOUR_SFT)
+
+#define MVRTC_HRFMT_SFT		22
+#define MVRTC_HRFMT12_MSK	(0x1 << MVRTC_HRFMT_SFT)
+#define MVRTC_HRFMT24_MSK	(0x0 << MVRTC_HRFMT_SFT)
+
+#define MVRTC_DAY_SFT		24
+#define MVRTC_DAY_MSK		(0x7 << MVRTC_DAY_SFT)
+
+/* date register */
+#define MVRTC_DATE_SFT		0
+#define MVRTC_DATE_MSK		(0xf << MVRTC_DATE_SFT)
+#define MVRTC_10DATE_SFT	4
+#define MVRTC_10DATE_MSK	(0x3 << MVRTC_10DATE_SFT)
+
+#define MVRTC_MON_SFT		8
+#define MVRTC_MON_MSK		(0xf << MVRTC_MON_SFT)
+#define MVRTC_10MON_SFT		12
+#define MVRTC_10MON_MSK		(0x1 << MVRTC_10MON_SFT)
+
+#define MVRTC_YEAR_SFT		16
+#define MVRTC_YEAR_MSK		(0xf << MVRTC_YEAR_SFT)
+#define MVRTC_10YEAR_SFT	20
+#define MVRTC_10YEAR_MSK	(0xf << MVRTC_10YEAR_SFT)
+
+#endif