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

Jason u-boot at lakedaemon.net
Mon Aug 1 14:06:35 CEST 2011


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 at 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 at 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.


More information about the U-Boot mailing list