FreeBSD 14.4 on NanoPi NEO 512: Enabling NAS Dock v1.2 Hardware

FreeBSD 14.4 on NanoPi NEO 512: Enabling NAS Dock v1.2 features including the DS1307 RTC​

System​

  • Board: NanoPi NEO (Allwinner H3, 512 MB RAM)
  • NAS board: FriendlyElec NAS Dock v1.2
  • Operating System: FreeBSD 14.4-RELEASE-p6
  • Boot loader: U-Boot
  • Kernel: GENERIC or custom NANOPI

Project Goal​

Enable the onboard hardware provided by the NanoPi NAS Dock v1.2 under FreeBSD.

This includes:

  • USB Host Port 1
  • USB Host Port 2
  • SSD connected through the NAS Dock
  • I²C0 bus
  • I²C1 bus
  • SPI0 bus
  • Dallas DS1307 Real-Time Clock connected through I²C
After completing these steps, NanoPi NEO + NAS Dock v1.2 becomes a usable FreeBSD NAS platform.


STEP 1 — Enable Device Tree Overlays​

The overlay files are located in:

/boot/dtb/overlays/

Edit:
ee /boot/loader.conf

Add:
fdt_overlays="sun8i-h3-i2c0.dtbo,sun8i-h3-i2c1.dtbo,sun8i-h3-spi0.dtbo,sun8i-h3-usb1.dtbo,sun8i-h3-usb2.dtbo"

Reboot:
shutdown -r now

During boot, U-Boot should report:
Loading DTB overlays:
sun8i-h3-i2c0.dtbo
sun8i-h3-i2c1.dtbo
sun8i-h3-spi0.dtbo
sun8i-h3-usb1.dtbo
sun8i-h3-usb2.dtbo
After reboot, the following controllers should be available:
  • I²C0
  • I²C1
  • SPI0
  • USB1
  • USB2
The NAS Dock hardware interfaces are now enabled.


STEP 2 — Add Support for the Onboard DS1307 RTC​

Create a custom Device Tree overlay for the DS1307 RTC.

Create:
ee /boot/dtb/overlays/sun8i-h3-ds1307.dtso

Content:
/dts-v1/;
/plugin/;
/ {
compatible = "allwinner,sun8i-h3";

fragment@0 {
target = <&i2c0>;
__overlay__ {
status = "okay";
rtc@68 {
compatible = "dallas,ds1307";
reg = <0x68>;
};
};
};
};

Compile:
dtc -@ -I dts -O dtb \
-o /boot/dtb/overlays/sun8i-h3-ds1307.dtbo \
/boot/dtb/overlays/sun8i-h3-ds1307.dtso

Add the new overlay to /boot/loader.conf:
fdt_overlays="sun8i-h3-i2c0.dtbo,sun8i-h3-i2c1.dtbo,sun8i-h3-spi0.dtbo,sun8i-h3-usb1.dtbo,sun8i-h3-usb2.dtbo,sun8i-h3-ds1307.dtbo"

reboot:
shutdown -r now

Verify:
dmesg | grep -Ei "rtc|ds1307|iic|i2c"

Expected result:
ds13070: <Dallas DS1307> at addr 0xd0 on iicbus0
ds13070: registered as a time-of-day clock, resolution 1.000000s

Note:
The overlay uses address 0x68. FreeBSD reports 0xd0. This is expected: 0x68 is the 7-bit I²C address, while 0xd0 is the 8-bit form.

If the RTC was never initialized before, FreeBSD may report:
ds13070: WARNING: RTC clock stopped, check the battery.

This is normal on first use. After setting a valid time, the warning should disappear.

Initialize the DS1307 using the current system time:
date `date "+%Y%m%d%H%M.%S"`

Reboot:
shutdown -r now

Verify again:
dmesg | grep -Ei "rtc|ds1307"
date

Expected result:
rtc0: <Allwinner RTC>
rtc0: registered as a time-of-day clock
ds13070: <Dallas DS1307> at addr 0xd0 on iicbus0
ds13070: registered as a time-of-day clock
Sat Jul 4 08:31:29 IST 2026

At this point, the DS1307 is detected and initialized.


STEP 3 — Prioritize the DS1307 RTC​

Verify that the DS1307 stores the correct time:
i2c -a 0x68 -d r -o 0 -c 8 -v

The DS1307 returns time registers in BCD format:
SS MM HH DW DD MM YY CTRL

Example:
59 41 08 06 04 07 26 03

Decoded:
2026-07-04 08:41:59

FreeBSD registers both RTC devices as time-of-day clocks:
rtc0: registered as a time-of-day clock, resolution 1.000000s
ds13070: registered as a time-of-day clock, resolution 1.000000s

The RTC framework in:
/usr/src/sys/kern/subr_rtc.c

Contains:
/*
* Registered clocks are kept in a list which is sorted by resolution;
* the more accurate clocks get the first shot at providing the time.
*/

Because both RTC devices have the same resolution, the internal Allwinner RTC is used first. It returns the default 2010 date, so the DS1307 is not used during boot.
Do not disable the internal Allwinner RTC in Device Tree. It also provides clock sources required by the SoC.

Instead, edit:
ee /usr/src/sys/dev/iicbus/rtc/ds1307.c

Replace:
clock_register_flags(dev, 1000000, CLOCKF_SETTIME_NO_ADJ);

with:
clock_register_flags(dev, 500000, CLOCKF_SETTIME_NO_ADJ);

This gives the DS1307 a higher priority than the internal Allwinner RTC.

Before building the kernel, make sure the system time is correct:
date

If needed, set it manually:
date YYYYMMDDHHMM.SS

Build and install the kernel:
cd /usr/src
make buildkernel KERNCONF=GENERIC
make installkernel KERNCONF=GENERIC

Or, for a custom kernel:
cd /usr/src
make buildkernel KERNCONF=NANOPI
make installkernel KERNCONF=NANOPI

Reboot:
shutdown -r now

Verify:
dmesg | grep -Ei "rtc|ds1307"

Expected result:
rtc0: registered as a time-of-day clock, resolution 1.000000s
ds13070: registered as a time-of-day clock, resolution 0.500000s
This confirms that DS1307 now has higher priority.


STEP 4 — Verify Cold Boot without NTP​

Disable NTP temporarily:
sysrc ntpd_enable="NO"
service ntpd stop

Power off the system:
shutdown -p now

Disconnect power from the NAS Dock.
Wait at least 5 minutes.
Reconnect power and boot the system.

Check the date:
date

Check that NTP is still not running:
service ntpd status

Expected result:
Sat Jul 4 12:19:24 IST 2026
ntpd is not running.

This confirms that FreeBSD initialized the system clock from the onboard DS1307 RTC, without network time synchronization.

Re-enable NTP:
sysrc ntpd_enable="YES"
service ntpd start

Result​

  • USB Host Port 1 works with JMicron External Disk 3.0 controler.
  • USB Host Port 2 works.
  • SSD connected through the NAS Dock works.
  • I²C0 works.
  • I²C1 works.
  • SPI0 works.
  • The onboard DS1307 RTC is detected.
  • The DS1307 stores valid time.
  • FreeBSD boots with correct time from DS1307 without NTP.
Status: SUCCESS!
 
Back
Top