201 lines
5.3 KiB
C
Executable File
201 lines
5.3 KiB
C
Executable File
#include <common.h>
|
|
#include <command.h>
|
|
#include <dm.h>
|
|
#include <rtc.h>
|
|
#include <asm/io.h>
|
|
#include <compiler.h>
|
|
#include <stdlib.h>
|
|
#include <asm/armv7.h>
|
|
#include <asm/arch/IOAddress.h>
|
|
#include <asm/arch/hardware.h>
|
|
#include <asm/nvt-common/nvt_types.h>
|
|
#include <asm/nvt-common/nvt_common.h>
|
|
#include <asm/nvt-common/rcw_macro.h>
|
|
#include "rtc_reg.h"
|
|
|
|
|
|
#define RTC_INT_KEY 0xA
|
|
#define RTC_INT_OSC_ANALOG_CFG 0x9
|
|
#define YEAR_OFFSET 1900
|
|
|
|
#define RTC_GETREG(ofs) INW(IOADDR_RTC_REG_BASE+(ofs))
|
|
#define RTC_SETREG(ofs, value) OUTW(IOADDR_RTC_REG_BASE +(ofs),(value))
|
|
|
|
static const unsigned short rtc_ydays[2][13] = {
|
|
/* Normal years */
|
|
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
|
|
/* Leap years */
|
|
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
|
|
};
|
|
|
|
void rtc_trigger_cset(void)
|
|
{
|
|
union RTC_STATUS_REG status_reg;
|
|
union RTC_CTRL_REG ctrl_reg;
|
|
|
|
/*Wait for RTC SRST done*/
|
|
do {
|
|
status_reg.reg = RTC_GETREG(RTC_STATUS_REG_OFS);
|
|
} while (status_reg.bit.srst_sts == 1);
|
|
|
|
/*Wait for RTC is ready for next CSET*/
|
|
do {
|
|
ctrl_reg.reg = RTC_GETREG(RTC_CTRL_REG_OFS);
|
|
} while (ctrl_reg.bit.cset == 1);
|
|
|
|
/*Trigger CSET*/
|
|
ctrl_reg.reg = RTC_GETREG(RTC_CTRL_REG_OFS);
|
|
ctrl_reg.bit.cset = 1;
|
|
ctrl_reg.bit.cset_inten = 1;
|
|
RTC_SETREG(RTC_CTRL_REG_OFS, ctrl_reg.reg);
|
|
|
|
}
|
|
|
|
int rtc_get(struct rtc_time *tm)
|
|
{
|
|
uint32_t days, months, years, month_days;
|
|
union RTC_TIMER_REG timer_reg;
|
|
union RTC_DAYKEY_REG daykey_reg;
|
|
|
|
|
|
timer_reg.reg = RTC_GETREG(RTC_TIMER_REG_OFS);
|
|
daykey_reg.reg = RTC_GETREG(RTC_DAYKEY_REG_OFS);
|
|
days = daykey_reg.bit.day;
|
|
|
|
|
|
|
|
for (years = 0; days >= rtc_ydays[is_leap_year(years + 1900)][12]; years++) {
|
|
days -= rtc_ydays[is_leap_year(years + 1900)][12];
|
|
}
|
|
|
|
for (months = 1; months < 13; months++) {
|
|
if (days <= rtc_ydays[is_leap_year(years + 1900)][months]) {
|
|
days -= rtc_ydays[is_leap_year(years + 1900)][months-1];
|
|
months--;
|
|
break;
|
|
}
|
|
}
|
|
|
|
month_days = rtc_ydays[is_leap_year(years + 1900)][months+1] - rtc_ydays[is_leap_year(years + 1900)][months];
|
|
|
|
if (days == month_days) {
|
|
months++;
|
|
days = 1;
|
|
} else
|
|
days++; /*Align linux time format*/
|
|
|
|
|
|
|
|
tm->tm_sec = timer_reg.bit.sec;
|
|
tm->tm_min = timer_reg.bit.min;
|
|
tm->tm_hour = timer_reg.bit.hour;
|
|
tm->tm_mday = days;
|
|
tm->tm_mon = months;
|
|
tm->tm_year = years + YEAR_OFFSET;
|
|
rtc_calc_weekday(tm);
|
|
|
|
debug("after read time: sec = %d, min = %d, hour = %d, mday = %d," \
|
|
"mon = %d, year = %d, wday = %d, yday = %d," \
|
|
"\n", tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, \
|
|
tm->tm_mon, tm->tm_year, tm->tm_wday, tm->tm_yday);
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rtc_set(struct rtc_time *tm)
|
|
{
|
|
|
|
int year_looper ;
|
|
uint32_t days = 0;
|
|
union RTC_TIMER_REG timer_reg;
|
|
union RTC_DAYKEY_REG daykey_reg;
|
|
union RTC_CTRL_REG ctrl_reg;
|
|
|
|
debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
|
|
tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
|
|
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
|
|
|
tm->tm_year=tm->tm_year - YEAR_OFFSET;
|
|
|
|
for (year_looper = 0; year_looper < tm->tm_year; year_looper++)
|
|
days += rtc_ydays[is_leap_year(year_looper + 1900)][12];
|
|
|
|
days += rtc_ydays[is_leap_year(year_looper + 1900)][tm->tm_mon];
|
|
tm->tm_mday--; /*subtract the day which is not ended*/
|
|
days += tm->tm_mday;
|
|
|
|
|
|
ctrl_reg.reg = RTC_GETREG(RTC_CTRL_REG_OFS);
|
|
ctrl_reg.bit.cset = 0;
|
|
ctrl_reg.bit.day_sel = 1;
|
|
ctrl_reg.bit.time_sel = 1;
|
|
RTC_SETREG(RTC_CTRL_REG_OFS, ctrl_reg.reg);
|
|
|
|
timer_reg.reg = 0;
|
|
timer_reg.bit.sec = tm->tm_sec;
|
|
timer_reg.bit.min = tm->tm_min;
|
|
timer_reg.bit.hour = tm->tm_hour;
|
|
RTC_SETREG(RTC_TIMER_REG_OFS, timer_reg.reg);
|
|
|
|
daykey_reg.reg = RTC_GETREG(RTC_DAYKEY_REG_OFS);
|
|
daykey_reg.bit.day = days;
|
|
RTC_SETREG(RTC_DAYKEY_REG_OFS, daykey_reg.reg);
|
|
|
|
rtc_trigger_cset();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
void rtc_reset(void)
|
|
{
|
|
//u32 reg_data;
|
|
|
|
|
|
union RTC_OSCAN_REG oscan_reg;
|
|
union RTC_STATUS_REG status_reg;
|
|
union RTC_DAYKEY_REG daykey_reg;
|
|
union RTC_CTRL_REG ctrl_reg;
|
|
|
|
// Wait for previous SRST done
|
|
do {
|
|
status_reg.reg = RTC_GETREG(RTC_STATUS_REG_OFS);
|
|
} while (status_reg.bit.srst_sts);
|
|
|
|
// Wait for RTC is ready for next CSET
|
|
do {
|
|
ctrl_reg.reg = RTC_GETREG(RTC_CTRL_REG_OFS);
|
|
} while (ctrl_reg.bit.cset);
|
|
|
|
// Do software reset
|
|
ctrl_reg.reg = 0;
|
|
ctrl_reg.bit.srst = 1;
|
|
RTC_SETREG(RTC_CTRL_REG_OFS, ctrl_reg.reg);
|
|
|
|
// Wait for RTC is ready for next CSET
|
|
do {
|
|
ctrl_reg.reg = RTC_GETREG(RTC_CTRL_REG_OFS);
|
|
} while (ctrl_reg.bit.srst);
|
|
|
|
|
|
ctrl_reg.reg = RTC_GETREG(RTC_CTRL_REG_OFS);
|
|
ctrl_reg.bit.cset = 0;
|
|
ctrl_reg.bit.key_sel = 1;
|
|
ctrl_reg.bit.pwralarmday_sel = 1;
|
|
ctrl_reg.bit.day_sel = 1;
|
|
RTC_SETREG(RTC_CTRL_REG_OFS, ctrl_reg.reg);
|
|
|
|
daykey_reg.reg = RTC_GETREG(RTC_DAYKEY_REG_OFS);
|
|
daykey_reg.bit.key = RTC_INT_KEY;
|
|
RTC_SETREG(RTC_DAYKEY_REG_OFS, daykey_reg.reg);
|
|
|
|
/*Set OSC analog parameter*/
|
|
oscan_reg.reg = RTC_GETREG(RTC_OSCAN_REG_OFS);
|
|
oscan_reg.bit.osc_analogcfg = RTC_INT_OSC_ANALOG_CFG;
|
|
RTC_SETREG(RTC_OSCAN_REG_OFS, oscan_reg.reg);
|
|
|
|
rtc_trigger_cset();
|
|
|
|
}
|