Showing results for 
Show  only  | Search instead for 
Did you mean: 
Registered: ‎01-23-2019

RTC set time read initial value before one second is random.

During the boot of our Linux kernel, we reach the initialization rtc-zynqmp.c in about 80ms. 

1. We do not use U-Boot.

2. We read the set_time_read register, but the interrupt has not been set yet, because it takes a second (from documentation).

3. After a full shutdown and no battery-powered RTC, by the time we have booted, the value we read from the RTC is wrong i.e. it's not 0. 

4. This problem causes our device to boot in at the wrong date, most of the time this date is well ahead in the future, for instance, we often boot after 2050 and beyond.

I don't think the drivers take into account, the fact that if you boot inside a second, the interrupt won't be set(because it takes a second after initialization) and thus read an uninitialized value from the chip.

If we put a sleep of 1 second inside the driver we have no problem, but obviously this is not a fix.

static int xlnx_rtc_read_time(struct device *dev, struct rtc_time *tm)
	u32 status;
	unsigned long read_time;
	struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);

	status = readl(xrtcdev->reg_base + RTC_INT_STS);

	if (status & RTC_INT_SEC) {
		 * RTC has updated the CURRENT_TIME with the time written into
		 * SET_TIME_WRITE register.
		read_time = readl(xrtcdev->reg_base + RTC_CUR_TM);
		rtc_time64_to_tm(readl(xrtcdev->reg_base + RTC_CUR_TM), tm);
	} else {
		 * Time written in SET_TIME_WRITE has not yet updated into
		 * the seconds read register, so read the time from the
		 * SET_TIME_WRITE instead of CURRENT_TIME register.
		 * Since we add +1 sec while writing, we need to -1 sec while
		 * reading.
		read_time = readl(xrtcdev->reg_base + RTC_SET_TM_RD) - 1;
		rtc_time64_to_tm(read_time, tm);

	return 0;
Tags (3)
0 Kudos
0 Replies