RTC Time Persistence Problem on Samsung Galaxy Tab S9 Ultra (SM-X910 / gts9uwifi)
Device
Samsung Galaxy Tab S8 Ultra (SM-X910 / gts9uwifi)
WiFi-only variant (no modem → no NITZ time sync)
LineageOS 23.2 (Android 15), self-compiled from samsung-sm8550-tab repos
Kernel: 5.15, Qualcomm SM8550 (Snapdragon 8 Gen 2)
Problem
Every reboot, system time resets to 1970-02-25 (compilation timestamp / RTC default). Time only becomes correct after connecting to WiFi and NTP sync. Offline usage has wrong time.
Root Cause Chain
WiFi-only tablet has no modem → time_daemon gets no time from baseband
time_daemon is restricted to start only on encrypted devices (ro.crypto.state=encrypted && ro.crypto.type=file) — it CAN run here but gets no modem time
Hardware RTC exists (rtc-pm8xxx on PMK8550 PMIC, /dev/rtc0) and CONFIG_RTC_HCTOSYS=y is set, so kernel would auto-restore from RTC on boot
But the RTC is write-locked: the driver rtc-pm8xxx.c line 155 checks if (!rtc_dd->allow_set_time) return -EACCES;
allow_set_time defaults to false and is only set to true by the DTS property allow-set-time; — which is not present in the device tree
Qualcomm's com.qualcomm.timeservice (in /vendor/app/TimeService) receives TIME_SET broadcasts and writes to /data/vendor/time/ats_2 — but nothing reads it back on boot
Evidence
# RTC can be read but not written
$ adb root
$ adb shell "hwclock -r -f /dev/rtc0"
1970-02-25 08:11:38+0000 # factory default value
$ adb shell "hwclock -w -f /dev/rtc0"
hwclock: ioctl 4024700a: Permission denied # EACCES from driver
# Kernel config supports RTC restore
$ adb shell "zcat /proc/config.gz | grep RTC_HCTOSYS"
CONFIG_RTC_HCTOSYS=y
CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
# The infamous driver check
$ grep -n "allow_set_time" drivers/rtc/rtc-pm8xxx.c
155: if (!rtc_dd->allow_set_time)
156: return -EACCES;
671: rtc_dd->allow_set_time = of_property_read_bool(pdev->dev.of_node,
672: "allow-set-time");
# time_daemon runs but gets no time (no modem)
$ adb shell "dmesg | grep time_daemon"
init: starting service 'time_daemon'...
init: ... started service 'time_daemon' has pid 1215
# ats_2 files exist (written by com.qualcomm.timeservice) but never restored
$ adb shell "ls -la /data/vendor/time/ats_2"
-rw-rw-rw- 1 root root 3 ... /data/vendor/time/ats_2
What I Tried
Attempt 1: init.rc + hwclock (system user)
Created init.timekeep.rc:
on post-fs-data
exec - system system -- /system/bin/hwclock -s -f /dev/rtc0
on property:sys.shutdown.requested=*
exec - system system -- /system/bin/hwclock -w -f /dev/rtc0
Result: SELinux denied { read } on rtc_device. Added toolbox.te policy — SELinux passed but hwclock -s exited with status 1 and hwclock -w returned EACCES (ioctl blocked by driver).
Attempt 2: Root user in init
Changed to exec - root root -- hwclock ...
Result: Same EACCES — driver check is at kernel level, not user level.
Attempt 3: DTS allow-set-time property
Added allow-set-time; to the RTC node in 3 DTS files:
arch/arm64/boot/dts/qcom/pmk8350.dtsi
arch/arm64/boot/dts/vendor/qcom/pmk8550.dtsi
arch/arm64/boot/dts/vendor/samsung/gts9uwifi_eur_open_w00_r03.dts
Cleared KERNEL_OBJ cache, rebuilt boot.img
Result: Property never appeared in final DTB. strings boot.img | grep allow-set-time returned nothing. Device /sys/firmware/devicetree/ showed no allow-set-time. The QCOM merge script (BOARD_USES_QCOM_MERGE_DTBS_SCRIPT := true) appears to drop or override DTBO properties during base+overlay merge.
Attempt 4: Hardcode driver bypass
Changed rtc-pm8xxx.c: if (false) // was: if (!rtc_dd->allow_set_time)
Rebuilt vendor_dlkm.img (the .ko module lives there)
Result: Bypassed driver check, but then RTC core layer (drivers/rtc/dev.c) returned EPERM:
hwclock: ioctl 4024700a: Operation not permitted