From 2caf8ad92addc4bea39309f3ec873e69065c9496 Mon Sep 17 00:00:00 2001 From: AI Dev Date: Tue, 20 Oct 2026 13:13:57 +0000 Subject: [PATCH 1/3] arm: dts: hi3516cv300: let rtc-hibvt bind the RTC The RTC node said "hisilicon,hi_rtc", which no in-tree driver matches. rtc-hibvt matches "hisilicon,hi35xx-rtc" and drives the same block (SPI bridge at 0x12090000, the same register map as the SDK's hi3516cv300 RTC module), so with CONFIG_RTC_DRV_HIBVT the board still had no /dev/rtc0. That is OpenIPC/firmware#191: hwclock has no RTC to open, and the SDK module only offers private HI_RTC_* ioctls, so pointing /dev/rtc0 at it fails with EPERM. --- arch/arm/boot/dts/hi3516cv300.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/hi3516cv300.dtsi b/arch/arm/boot/dts/hi3516cv300.dtsi index 2832476cce0..856a286d97a 100644 --- a/arch/arm/boot/dts/hi3516cv300.dtsi +++ b/arch/arm/boot/dts/hi3516cv300.dtsi @@ -641,7 +641,7 @@ }; rtc: rtc@12090000 { - compatible = "hisilicon,hi_rtc"; + compatible = "hisilicon,hi35xx-rtc"; interrupts = <2>; reg = <0x12090000 0x10000>; }; From 2d792bd2663a75878a521690808dada725aa67c8 Mon Sep 17 00:00:00 2001 From: AI Dev Date: Tue, 20 Oct 2026 13:13:57 +0000 Subject: [PATCH 2/3] rtc: hibvt: judge the time by its counter, and leave hi3516cv300's CLK_CFG alone Port of the hisilicon-hi3536dv100 change (OpenIPC/linux#81), which this branch's copy of the driver matches byte for byte: - read_time() no longer fails, or logs, because of the low-voltage flag. The flag was "cleared" by writing 1 to RTC_INT_CLR, which is the alarm bit, so once set it never cleared and the RTC stayed unreadable. It is not a verdict on the time anyway: on a hi3516ev300 it stays set with a backup cell that keeps the time. - A counter before 2000-01-01, which is what a counter that lost power reads, is reported as unset, so hctosys does not set the clock to 1970. set_time() refuses the same range. - The flag is cleared with LV_INT_MASK. On hi3516cv300, skip the RTC_CLK_CFG write. The SDK's own hi3516cv300 RTC driver never writes it, and it reads 0 on a running board; the 0x01 here is the hi3536cv100 value. --- drivers/rtc/rtc-hibvt.c | 47 ++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/drivers/rtc/rtc-hibvt.c b/drivers/rtc/rtc-hibvt.c index 28d0bae6739..2051c3db2a8 100644 --- a/drivers/rtc/rtc-hibvt.c +++ b/drivers/rtc/rtc-hibvt.c @@ -98,6 +98,13 @@ union u_spi_rw { #define REG_LOCK_STAT BIT(1) #define REG_LOCK_BYPASS BIT(2) +/* + * A counter that lost every supply restarts from zero and reads as 1970. + * Times before 2000-01-01 are refused both ways, so such a counter reads + * as unset and every time set_time() accepts can be read back. + */ +#define RTC_MIN_VALID_SEC 946684800UL + #define RETRY_CNT 500 #define DATE_TO_SEC(d, h, m, s) (s + m*60 + h*60*60 + d*24*60*60) @@ -191,12 +198,15 @@ static int hibvt_rtc_read_time(struct device *dev, struct rtc_time *time) return ret; } - if (raw_value & LV_INT_MASK) { - dev_err(dev, - "low voltage detected, date/time is not reliable.\n"); - hibvt_spi_write(rtc->regs, RTC_INT_CLR, 1); - return -EINVAL; - } + /* + * Not a verdict on the time: on a hi3516ev300 the flag stays set, + * and returns about half a second after each clear, with a fresh + * backup cell that keeps the counter through a power cut, exactly as + * it did with a flat one. The counter below is what tells. Clear the + * flag by its own bit: writing 1 acknowledged the alarm instead. + */ + if (raw_value & LV_INT_MASK) + hibvt_spi_write(rtc->regs, RTC_INT_CLR, LV_INT_MASK); ret |= hibvt_spi_rtc_read(rtc->regs, RTC_LORD, &raw_value); if (raw_value & REG_LOCK_BYPASS) @@ -230,6 +240,13 @@ static int hibvt_rtc_read_time(struct device *dev, struct rtc_time *time) day = (dayl | (dayh << 8)); seconds = DATE_TO_SEC(day, hour, minute, second); + /* + * Report a counter that restarted from zero as unset, so hctosys + * leaves the clock alone instead of stepping it to 1970. + */ + if (seconds < RTC_MIN_VALID_SEC) + return -EINVAL; + rtc_time_to_tm(seconds, time); return rtc_valid_tm(time); @@ -247,6 +264,8 @@ static int hibvt_rtc_set_time(struct device *dev, struct rtc_time *time) ret = rtc_tm_to_time(time, &seconds); if (ret) return ret; + if (seconds < RTC_MIN_VALID_SEC) + return -EINVAL; days = SEC_TO_DAY(seconds); ret |= hibvt_spi_rtc_write(rtc->regs, RTC_LR_10MS, 0); @@ -486,8 +505,15 @@ static int hibvt_rtc_init(struct hibvt_rtc *rtc) ret |= hibvt_spi_rtc_write(spi_reg, RTC_IMSC, INT_MSK_DEFAULT); ret |= hibvt_spi_rtc_write(spi_reg, RTC_SAR_CTRL, LV_CTL_DEFAULT); - + +#ifndef CONFIG_ARCH_HI3516CV300 + /* + * The HiSilicon SDK's own hi3516cv300 RTC driver never writes + * RTC_CLK_CFG, and the register reads 0 on a running board, so leave + * the oscillator settings of that family as they come. + */ ret |= hibvt_spi_rtc_write(spi_reg, RTC_CLK_CFG, 0x01); +#endif /* default FREQ COEF */ ret |= hibvt_spi_rtc_write(spi_reg, RTC_FREQ_H, FREQ_H_DEFAULT); @@ -500,11 +526,8 @@ static int hibvt_rtc_init(struct hibvt_rtc *rtc) return ret; } - if (val & LV_INT_MASK) { - dev_err(&rtc->rtc_dev->dev, - "low voltage detected, date/time is not reliable.\n"); - hibvt_spi_write(rtc->regs, RTC_INT_CLR, 1); - } + if (val & LV_INT_MASK) + hibvt_spi_write(rtc->regs, RTC_INT_CLR, LV_INT_MASK); return ret; } From 9c8655514e268cefa791dc415b8732b20c8b5396 Mon Sep 17 00:00:00 2001 From: AI Dev Date: Tue, 20 Oct 2026 14:03:12 +0000 Subject: [PATCH 3/3] rtc: hibvt: return set_time()'s SPI errors as errors set_time() collected the SPI write results in an unsigned char, so a bridge timeout (-EIO) came back as 251: RTC_SET_TIME reported success for a write that never reached the RTC. Every other function here already uses int. --- drivers/rtc/rtc-hibvt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-hibvt.c b/drivers/rtc/rtc-hibvt.c index 2051c3db2a8..dccac991ddc 100644 --- a/drivers/rtc/rtc-hibvt.c +++ b/drivers/rtc/rtc-hibvt.c @@ -255,7 +255,7 @@ static int hibvt_rtc_read_time(struct device *dev, struct rtc_time *time) static int hibvt_rtc_set_time(struct device *dev, struct rtc_time *time) { struct hibvt_rtc *rtc = dev_get_drvdata(dev); - unsigned char ret = 0; + int ret = 0; unsigned int days; unsigned long seconds = 0; unsigned int cnt = RETRY_CNT;