2. Cvitek RTC Operation Guide

2.1. Module Introduction

RTC (real-time clock) is an independently powered module in the processor that provides time to Linux. Because the RTC is battery-powered, it keeps time while the processor is powered off or sleeping. The Linux kernel uses the RTC to maintain the time and date, and it can also serve as an alarm to wake the kernel from sleep.

Applications can use the periodic interrupts provided by the RTC for periodic tasks.

2.1.1. Counter Clock Frequency

The RTC counter uses a 32.768 kHz clock and a 32-bit up-counter to count seconds. The maximum count duration is:

2^32 seconds = 49,710 days = 136 years

2.2. Preparation

2.2.1. Using the RTC (Default)

  • Use the U-Boot and kernel released with the SDK; no DTS modification is required.

  • Device node:/dev/rtc0.

2.2.2. Removing the RTC

To disable the RTC at board level, use delete-node delete the RTC node.

In this SDK, the RTC node is named rtc (in cv184x_base.dtsi / cv1835_asic.dtsi is defined there; the deletion example is as follows:

/ {
    /delete-node/ rtc;
};

If the node is named cvitek-rtc@3005000, use:

/delete-node/ cvitek-rtc@3005000;

The following is another node-deletion example in the same file (for reference only):

/delete-node/ i2s@04120000;
/delete-node/ sound_ext1;
/delete-node/ sound_ext2;
/delete-node/ sound_PDM;
/delete-node/ rtc;                    /* 删除 RTC */

aliases {
    /delete-property/ ethernet1;
};

2.3. Application-layer Usage

2.3.1. Device Node and Header Files

  • Device node:/dev/rtc0

  • Header files:#include <linux/rtc.h>, #include <sys/ioctl.h>

2.3.2. Common ioctl Commands

Command

Description

RTC_RD_TIME

Read the current time

RTC_SET_TIME

Set the current time

RTC_ALM_READ

Read the alarm time

RTC_ALM_SET

Set the alarm time

RTC_AIE_ON

Enable the alarm interrupt

RTC_AIE_OFF

Disable the alarm interrupt

RTC_UIE_ON

Enable the update interrupt

RTC_UIE_OFF

Disable the update interrupt

RTC_PIE_ON

Enable the periodic interrupt

RTC_PIE_OFF

Disable the periodic interrupt

RTC_IRQP_SET

Set the periodic interrupt frequency

2.3.3. rtc_time Structure

struct rtc_time {
    int tm_sec;   /* 秒 [0,59] */
    int tm_min;   /* 分 [0,59] */
    int tm_hour;  /* 时 [0,23] */
    int tm_mday;  /* 日 [1,31] */
    int tm_mon;   /* 月 [0,11],0=1月 */
    int tm_year;  /* 年,实际年 = tm_year + 1900 */
    int tm_wday;  /* 星期几 [0,6],0=周日,1=周一 */
    int tm_yday;  /* 一年中第几天 [0,365],0=1月1日 */
    int tm_isdst; /* 夏令时:1=是,0=否 */
};

Note:

  • tm_mon: 0 means 1 month, 11 means 12 month.

  • tm_year: storeis"yearcopy − 1900", if 2025 yearfill 125.

  • tm_wday: 0=Sunday, 1=weekone, according tothisanalogy.

  • tm_yday: 0=1month1day, 1=1month2day.

2.4. Example Code

2.4.1. User-space Operation Example (rtc_example.c)

theshowexamplewill"readtime / settime / setalarm"entirecombinedisoneprogram, throughparameterselectspecificoperation.

Build

arm-none-linux-uclibcgnueabihf-gcc -o rtc_example rtc_example.c -static

Run

./rtc_example [read|set|alarm]
  • read: readandprintcurrent RTC time.

  • set: will RTC setisshowexampletime (2025-03-18 12:00:00) , andprintsetaftertime.

  • alarm: willalarmsetiscurrenttime + 5 seconds, andenablealarminterrupt (part RTC maynot supportedalarminterrupt, willreturnerror) .

/*
 * Cvitek RTC 使用示例:读取时间、设置时间、设置闹钟
 * 编译: arm-none-linux-uclibcgnueabihf-gcc -o rtc_example rtc_example.c -static
 * 运行: ./rtc_example [read|set|alarm]
 */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <linux/rtc.h>
#include <sys/ioctl.h>
#include <unistd.h>

#define RTC_DEV "/dev/rtc0"

static void print_rtc_time(const struct rtc_time *t)
{
    printf("RTC 时间: %04d-%02d-%02d %02d:%02d:%02d 星期%d\n",
           t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
           t->tm_hour, t->tm_min, t->tm_sec, t->tm_wday);
}

/* 读取并打印当前 RTC 时间 */
static int do_read(int fd)
{
    struct rtc_time rtc_tm;
    if (ioctl(fd, RTC_RD_TIME, &rtc_tm) < 0) {
        perror("RTC_RD_TIME");
        return -1;
    }
    print_rtc_time(&rtc_tm);
    return 0;
}

/* 设置 RTC 时间(示例:2025-03-18 12:00:00) */
static int do_set(int fd)
{
    struct rtc_time rtc_tm = {
        .tm_sec  = 0,
        .tm_min  = 0,
        .tm_hour = 12,
        .tm_mday = 18,
        .tm_mon  = 2,   /* 3 月 */
        .tm_year = 125, /* 2025 */
        .tm_wday = 2,
        .tm_isdst = 0
    };
    if (ioctl(fd, RTC_SET_TIME, &rtc_tm) < 0) {
        perror("RTC_SET_TIME");
        return -1;
    }
    printf("已设置 RTC,当前为: ");
    return do_read(fd);
}

/* 设置闹钟为当前时间 + 5 秒,并开启闹钟中断 */
static int do_alarm(int fd)
{
    struct rtc_time rtc_tm;
    if (ioctl(fd, RTC_RD_TIME, &rtc_tm) < 0) {
        perror("RTC_RD_TIME");
        return -1;
    }
    rtc_tm.tm_sec += 5;
    if (rtc_tm.tm_sec >= 60) {
        rtc_tm.tm_sec %= 60;
        rtc_tm.tm_min++;
    }
    if (rtc_tm.tm_min >= 60) {
        rtc_tm.tm_min = 0;
        rtc_tm.tm_hour++;
    }
    if (rtc_tm.tm_hour >= 24)
        rtc_tm.tm_hour = 0;

    if (ioctl(fd, RTC_ALM_SET, &rtc_tm) < 0) {
        if (errno == EINVAL)
            fprintf(stderr, "此 RTC 不支持闹钟中断\n");
        else
            perror("RTC_ALM_SET");
        return -1;
    }
    ioctl(fd, RTC_AIE_ON, 0);
    printf("闹钟已设为 5 秒后,已开启闹钟中断\n");
    return 0;
}

int main(int argc, char **argv)
{
    const char *cmd = (argc > 1) ? argv[1] : "read";
    int fd = open(RTC_DEV, O_RDONLY);
    if (fd < 0) {
        perror("open " RTC_DEV);
        return 1;
    }

    if (strcmp(cmd, "read") == 0)
        do_read(fd);
    else if (strcmp(cmd, "set") == 0)
        do_set(fd);
    else if (strcmp(cmd, "alarm") == 0)
        do_alarm(fd);
    else {
        fprintf(stderr, "用法: %s [read|set|alarm]\n", argv[0]);
        close(fd);
        return 1;
    }

    close(fd);
    return 0;
}

2.5. Summary

operation

Procedure

Using the RTC

Keep the node and operate directly on /dev/rtc0

Removing the RTC

Add /delete-node/ rtc; (this SDK sectionpointnameis rtc)

Read time

ioctl(fd, RTC_RD_TIME, &rtc_tm)

Set time

populate struct rtc_time, then ioctl(fd, RTC_SET_TIME, &rtc_tm)

Set alarm

populatetimeafter ioctl(fd, RTC_ALM_SET, &rtc_tm), thenuse RTC_AIE_ON Enable

2.6. Timed Reboot by RTC Interrupt (Soft Reboot)

A soft reboot does not remove power or trip the power supply; it only makes the CPU/SoC run the boot process again while power remains on. Triggering it when an RTC alarm expires enables a timed soft reboot.

2.6.1. Procedure

  1. Find auto_restart_after node path on the device:

find /sys/devices/ -name auto_restart_after
  1. Write a number of seconds to this node to trigger a soft reboot after the specified delay. The example below reboots after 30 seconds; replace the path with the actual node returned by the previous find obtaintoactualsectionpoint (usuallyshapeif /sys/devices/platform/5026000.rtc/auto_restart_after) :

echo 30 > /sys/devices/platform/5026000.rtc/auto_restart_after

2.6.2. Flow from the RTC Alarm to SoC Reset

  1. Set RTC alarm: userthrough sysfs writeattribute auto_restart_after , for examplecommand echo 30 , meansabout 30 secondsafterreboot. driverread RTC currentsecondsnumber, will"currentsecondsnumber + setsecondsnumber"Write RTC alarmregisterandenablealarm.

  2. RTC alarminterrupt: topointafter RTC hardwarecomparerelativelysecondscountwithalarmtime, pullhighinterrupt. inkernel RTC driverininterruptprocessingfunctioninclearinterrupt, through rtc_update_irq() common notificationuserstate /dev/rtc0, andraisesubmitonedelayworkingitem.

  3. workingqueuecolumnintriggersendreboot: inworkingfunctionin, If thisbeforealreadythrough auto_restart_after setsetwhenreboot, thencall orderly_reboot(); If timeoutunusedrebootthenthencall kernel_restart(NULL).

  4. orderly_reboot: firsttryexecute /sbin/reboot, giveuserstatedoreceivetail (sync, scriptthisetc.) ; If executefailedthen directlyconnectcall kernel_restart(NULL).

  5. kernel_restart: enterrebootpreparationstepsegment (common notificationchain, device shutdown, migratetoreboot CPU, systemcoredisable, inkernellog dump) , Finally, callarchitecturerelated machine_restart().

  6. machine_restart (ARM64) : disableinterrupt, stopstopitsit CPU, thencall do_kernel_restart().

  7. do_kernel_restart: callthehasthrough register_restart_handler() registerrebootbackadjust.

  8. Cvitek rebootbackadjust: in cvi-reboot.c inregister cvi_restart_handler() write RTC domainregisterpleaserequestwarmresetbits (RTC_EN_WARM_RST_REQ) , etc.wait forstatusthencompleteafterwrite RTC_CTRL0 triggersend SoC internal warm reset. CPU from BootROM/firmwarere-newboot, complete devicenotpower off, completesoftreboot.

2.6.3. Key Points

  • RTC alarm: provide"topointtriggersend", use RTC currentsecondsnumber + N secondsSet alarm, withsystemtimedecouple.

  • orderly_reboot: firstexecute /sbin/reboot douserstatereceivetail, failedthen directlyconnect kernel_restart.

  • kernel_restart: disabledevice, migrate CPU, dump log, thensubmitgivearchitecture machine_restart.

  • cvi_restart_handler: Cvitek SoC softresetbitsimplement, throughwrite RTC domain WARM_RST_REQ byhardwaredo CPU/SoC warmresetbits, powerkeep powered.