Skip to content

hi3516cv300: bind rtc-hibvt to the SoC RTC, and judge the time by its counter - #125

Merged
openipc-ai merged 3 commits into
hisilicon-hi3516cv300from
rtc/hibvt-cv300-hisilicon-hi3516cv300
Oct 20, 2026
Merged

openipc-ai merged 3 commits into
hisilicon-hi3516cv300from
rtc/hibvt-cv300-hisilicon-hi3516cv300

Conversation

@openipc-ai

@openipc-ai openipc-ai commented Oct 20, 2026 •

Copy link
Copy Markdown

Kernel half of OpenIPC/firmware#191: on hi3516cv300, hwclock has no RTC to use. The firmware half, which turns on the RTC options in the cv300 and ev100 kernel configs, is OpenIPC/firmware#2643. It has no effect until this is merged.

Why there is no /dev/rtc0 today

  • The device tree names the RTC something no driver matches. It says "hisilicon,hi_rtc", while rtc-hibvt matches "hisilicon,hi35xx-rtc". So even with CONFIG_RTC_DRV_HIBVT=y, nothing binds.
  • rtc-hibvt is the right driver. The block at 0x12090000 is the SPI-bridged RTC that rtc-hibvt drives. The SDK's hi3516cv300 RTC module uses the same SPI_CLK_DIV/SPI_RW offsets, the same u_spi_rw bit layout and the same register map.
  • The SDK module can't stand in for it. The image ships it as hi3516cv300_rtc.ko, but it is a character device with private HI_RTC_* ioctls. That is why pointing /dev/rtc0 at it gives RTC_RD_TIME: Operation not permitted in the issue.

Change

  1. arm: dts: hi3516cv300: the RTC compatible becomes "hisilicon,hi35xx-rtc".
  2. rtc: hibvt:
    • The changes from rtc: hibvt: judge the time by its counter, not the low-voltage flag #81, whose rtc-hibvt.c this branch matches byte for byte. The read no longer fails while the low-voltage flag is set (the flag was "cleared" with the alarm bit, so it never cleared). A counter before 2000-01-01 is refused both ways, so a counter that lost power never sets the clock to 1970. The flag is cleared with LV_INT_MASK.
    • On ARCH_HI3516CV300, the driver no longer writes RTC_CLK_CFG. The SDK's own cv300 RTC driver never touches it, and it reads 0x00 on a running board. The 0x01 written here is the hi3536cv100 value.

Verification

Lab hi3516cv300 (hi3516cv300_lite, imx291, no backup battery). I built the kernel from OpenIPC/firmware#2643's config with these two commits on top, and U-Boot loaded it over TFTP. The NOR kernel was never written. Afterwards the board went back to its own kernel and original environment.

Before, on the shipped kernel:

hwclock: can't open '/dev/misc/rtc': No such file or directory
hwclock: can't open '/dev/rtc0': No such file or directory

With this change, the first boot from power-on (the counter starts at zero with no battery):

[    2.059490] hibvt_rtc 12090000.rtc: rtc core: registered 12090000.rtc as rtc0
[    2.066670] hibvt_rtc 12090000.rtc: RTC driver for hibvt enabled
[    2.688849] hibvt_rtc 12090000.rtc: hctosys: unable to read the hardware clock
fake-hwclock: clock restored to 2026-10-20 13:02:15 UTC

Once userspace has set the time, hwclock works:

hwclock: Tue Oct 20 13:06:28 2026  0.000000 seconds
since_epoch: 1792501588

Warm reboot. The RTC kept counting, and hctosys applies it:

[    2.748957] hibvt_rtc 12090000.rtc: setting system clock to 2026-10-20 13:07:54 UTC (1792501674)

30 s PoE cut. The counter restarts, and it is refused rather than set to 1970:

[    2.689031] hibvt_rtc 12090000.rtc: hctosys: unable to read the hardware clock

set_time() and read_time() agree:

hwclock: RTC_SET_TIME: Invalid argument     # 1999-12-31 23:59:59
set 2000-01-01 rc=0
Sat Jan  1 00:00:00 2000  0.000000 seconds

Not covered:

  • A board with a backup cell. This one has none, so whether a cv300 keeps time through a power cut wasn't tested.
  • hi3516ev100. It shares this DT, the driver and the ARCH_HI3516CV300 symbol, but wasn't run on hardware.

Review fix: set_time() errors

hibvt_rtc_set_time() collected the SPI write results in an unsigned char, so a bridge timeout (-EIO) came back as 251, and RTC_SET_TIME reported success for a write that never reached the RTC (Qodo). It is now an int, like every other function in the file.

The SPI timeout can't be triggered on demand, so the error path itself is covered only by the type fix. The success path was re-run on hardware:

Linux version 3.18.20 (ai@forge-hel1) (buildroot-gcc-13.3.0) #6 Tue Oct 20 14:04
hibvt_rtc 12090000.rtc: setting system clock to 2026-10-20 14:06:39 UTC (1792505199)   # warm reboot
set now rc=0
hwclock: RTC_SET_TIME: Invalid argument      # 1999-12-31 23:59:59
restore rc=0 read: Tue Oct 20 14:14:39 2026

That is the lab hi3516cv300 again, booted over TFTP on this branch's head and then returned to its own kernel.

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.
…K_CFG alone

Port of the hisilicon-hi3536dv100 change (#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.
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Bind the hi3516cv300 RTC and reject reset counter values

🐞 Bug fix ✨ Enhancement 🕐 20-40 Minutes

Grey Divider

AI Description

• Match the hi3516cv300 RTC to rtc-hibvt so it can register as /dev/rtc0.
• Reject pre-2000 counter values so power loss cannot reset system time to 1970.
• Correct low-voltage flag clearing and preserve the cv300 family's oscillator configuration.
Diagram

graph TD
  DT["cv300 device tree"] --> Driver["rtc-hibvt driver"] --> Counter["RTC counter"] --> Valid{"Time since 2000?"} -->|yes| Core["RTC core"] --> Boot["hctosys"] --> Clock["System clock"]
  Valid -->|no: preserve| Clock
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Select oscillator settings through device-tree match data
  • ➕ Scopes the RTC_CLK_CFG exception to a specific compatible rather than every build with ARCH_HI3516CV300 enabled.
  • ➕ Supports differing RTC variants in one kernel image.
  • ➖ Requires a distinct compatible and additional driver matching logic for a currently narrow hardware difference.

Recommendation: Keep the focused device-tree binding and counter-based validity check: they address the missing RTC and avoid treating a persistent low-voltage flag as proof of bad time. The architecture guard is proportionate for the targeted SoC family; use variant-specific match data if mixed-SoC kernels need different oscillator initialization.

Files changed (2) +36 / -13

Bug fix (2) +36 / -13
hi3516cv300.dtsiBind the cv300 RTC node to rtc-hibvt +1/-1

Bind the cv300 RTC node to rtc-hibvt

• Replaces an unmatched RTC compatible with hisilicon,hi35xx-rtc. This allows the existing driver to bind the RTC node and register an RTC device when enabled.

arch/arm/boot/dts/hi3516cv300.dtsi

rtc-hibvt.cValidate RTC time by counter and preserve cv300 clock settings +35/-12

Validate RTC time by counter and preserve cv300 clock settings

• Accepts reads despite a low-voltage flag, clears that flag with its own bit, and rejects times before 2000-01-01 on both reads and writes. Skips the RTC_CLK_CFG write for ARCH_HI3516CV300 while retaining it for other builds.

drivers/rtc/rtc-hibvt.c

openipc-ai added a commit to OpenIPC/firmware that referenced this pull request Oct 20, 2026
The cv300 and ev100 kernels were built without the RTC class, so the
board had no /dev/rtc0: hwclock failed with "can't open
'/dev/misc/rtc'", hctosys never ran, and fake-hwclock had no RTC to
keep. The SDK's hi3516cv300_rtc.ko, which the image ships but nothing
loads, cannot stand in: it offers only private HI_RTC_* ioctls, so
hwclock's RTC_RD_TIME on it fails with EPERM (#191).

Turn on the RTC class with hctosys, systohc, the dev, sysfs and proc
interfaces, and rtc-hibvt. It binds once the device tree names the RTC
"hisilicon,hi35xx-rtc" (OpenIPC/linux#125); until then this costs
about 8 KB of kernel and changes nothing else.
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Clock writes can falsely report success ✓ Resolved
Description
hibvt_rtc_set_time() stores SPI write errors in an unsigned char, converting -EIO into a
positive return value of 251. Once the new compatible binds this driver to the cv300 RTC, a bridge
timeout during RTC_SET_TIME can leave userspace believing the clock was set even though a hardware
write failed.
Code

arch/arm/boot/dts/hi3516cv300.dtsi[644]

+			compatible = "hisilicon,hi35xx-rtc";
Evidence
The new compatible matches the driver's device table and activates its set-time operation for this
RTC. SPI writes can return -EIO; the unsigned status truncates that to 251, which the RTC ioctl
returns unchanged to userspace.

arch/arm/boot/dts/hi3516cv300.dtsi[643-647]
drivers/rtc/rtc-hibvt.c[122-141]
drivers/rtc/rtc-hibvt.c[255-293]
drivers/rtc/rtc-dev.c[343-350]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Binding the cv300 RTC activates a driver path that turns SPI write failures into positive `RTC_SET_TIME` results.
## Fix Focus Areas
- drivers/rtc/rtc-hibvt.c[255-268]
- drivers/rtc/rtc-hibvt.c[271-293]
## Recommended Fix
Make `hibvt_rtc_set_time()` retain and return negative SPI errors, using a signed status variable rather than `unsigned char`. Verify that a write timeout makes `RTC_SET_TIME` fail.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can open the rule or relationship behind a finding in one click

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread arch/arm/boot/dts/hi3516cv300.dtsi
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.
openipc-ai added a commit to OpenIPC/firmware that referenced this pull request Oct 20, 2026
The cv300 kernel was built without the RTC class, so the board had no
/dev/rtc0: hwclock failed with "can't open '/dev/misc/rtc'", hctosys
never ran, and fake-hwclock had no RTC to keep. The SDK's
hi3516cv300_rtc.ko, which the image ships but nothing loads, cannot
stand in: it offers only private HI_RTC_* ioctls, so hwclock's
RTC_RD_TIME on it fails with EPERM (#191).

Turn on the RTC class with hctosys, systohc, the dev, sysfs and proc
interfaces, and rtc-hibvt. It binds once the device tree names the RTC
"hisilicon,hi35xx-rtc" (OpenIPC/linux#125); until then this costs
about 8 KB of kernel and changes nothing else.

hi3516ev100 shares the kernel family but is left as it is: there is
no ev100 board to run it on.
@openipc-ai

Copy link
Copy Markdown
Author

/review

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 9c86555

@openipc-ai
openipc-ai merged commit 61d78fe into hisilicon-hi3516cv300 Oct 20, 2026
openipc-ai added a commit to OpenIPC/firmware that referenced this pull request Oct 20, 2026
The cv300 kernel was built without the RTC class, so the board had no
/dev/rtc0: hwclock failed with "can't open '/dev/misc/rtc'", hctosys
never ran, and fake-hwclock had no RTC to keep. The SDK's
hi3516cv300_rtc.ko, which the image ships but nothing loads, cannot
stand in: it offers only private HI_RTC_* ioctls, so hwclock's
RTC_RD_TIME on it fails with EPERM (#191).

Turn on the RTC class with hctosys, systohc, the dev, sysfs and proc
interfaces, and rtc-hibvt. It binds once the device tree names the RTC
"hisilicon,hi35xx-rtc" (OpenIPC/linux#125); until then this costs
about 8 KB of kernel and changes nothing else.

hi3516ev100 shares the kernel family but is left as it is: there is
no ev100 board to run it on.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant