[PATCH] rtc: zynqmp: Add clock framework support with calibration fallback
Tomas Melin
tomas.melin at vaisala.com
Wed Jan 7 13:47:24 CET 2026
Hi,
On 06/01/2026 12:12, Pranav Tilak wrote:
> [Some people who received this message don't often get email from pranav.vinaytilak at amd.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
>
> Add support for reading RTC clock from device tree using clock
> framework also update the default calibration value to 0x7FFF
> as per RTC specifications.
> Falls back to 'calibration' property if clock unavailable, and uses
> default calibration if neither is present. Only writes calibration when
> hardware register reads zero.
>
> Signed-off-by: Pranav Tilak <pranav.vinaytilak at amd.com>
> ---
> drivers/rtc/zynqmp_rtc.c | 51 ++++++++++++++++++++++++----------------
> 1 file changed, 31 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/rtc/zynqmp_rtc.c b/drivers/rtc/zynqmp_rtc.c
> index 15122a04838..83d66aa1aaa 100644
> --- a/drivers/rtc/zynqmp_rtc.c
> +++ b/drivers/rtc/zynqmp_rtc.c
> @@ -8,23 +8,27 @@
> #include <dm.h>
> #include <rtc.h>
> #include <asm/io.h>
> +#include <clk.h>
> +#include <dm/device_compat.h>
>
> /* RTC Registers */
> #define RTC_SET_TM_WR 0x00
> #define RTC_SET_TM_RD 0x04
> #define RTC_CALIB_WR 0x08
> +#define RTC_CALIB_RD 0x0C
> #define RTC_CUR_TM 0x10
> #define RTC_INT_STS 0x20
> #define RTC_CTRL 0x40
>
> #define RTC_INT_SEC BIT(0)
> #define RTC_BATT_EN BIT(31)
> -#define RTC_CALIB_DEF 0x198233
> +#define RTC_CALIB_DEF 0x7FFF
> +#define RTC_FREQ_MAX 0x10000
> #define RTC_CALIB_MASK 0x1FFFFF
>
> struct zynqmp_rtc_priv {
> fdt_addr_t base;
> - unsigned int calibval;
> + unsigned long clk_freq;
Using calibval as variable name might actually be better here as the
value corresponds to register value, and not the actual frequency.
> };
>
> static int zynqmp_rtc_get(struct udevice *dev, struct rtc_time *tm)
> @@ -70,13 +74,6 @@ static int zynqmp_rtc_set(struct udevice *dev, const struct rtc_time *tm)
> */
> new_time = rtc_mktime(tm) + 1;
>
> - /*
> - * Writing into calibration register will clear the Tick Counter and
> - * force the next second to be signaled exactly in 1 second period
> - */
> - priv->calibval &= RTC_CALIB_MASK;
> - writel(priv->calibval, (priv->base + RTC_CALIB_WR));
> -
> writel(new_time, priv->base + RTC_SET_TM_WR);
>
> /*
> @@ -107,15 +104,6 @@ static int zynqmp_rtc_init(struct udevice *dev)
> rtc_ctrl |= RTC_BATT_EN;
> writel(rtc_ctrl, priv->base + RTC_CTRL);
>
> - /*
> - * Based on crystal freq of 33.330 KHz
> - * set the seconds counter and enable, set fractions counter
> - * to default value suggested as per design spec
> - * to correct RTC delay in frequency over period of time.
> - */
> - priv->calibval &= RTC_CALIB_MASK;
> - writel(priv->calibval, (priv->base + RTC_CALIB_WR));
> -
> return 0;
> }
>
> @@ -128,8 +116,31 @@ static int zynqmp_rtc_probe(struct udevice *dev)
> if (priv->base == FDT_ADDR_T_NONE)
> return -EINVAL;
>
> - priv->calibval = dev_read_u32_default(dev, "calibration",
> - RTC_CALIB_DEF);
> + ret = readl(priv->base + RTC_CALIB_RD);
> + if (!ret) {
> + struct clk rtc_clk;
> +
> + /* Get the RTC clock rate */
> + ret = clk_get_by_name_optional(dev, "rtc", &rtc_clk);
> + if (!ret) {
In case the rtc clock reference is missing, this will still return 0. I
think in this case idea was to read the calibration devicetree value
instead?
> + priv->clk_freq = clk_get_rate(&rtc_clk);
> + /* Use clock frequency if valid, fallback to calibration value */
> + if (priv->clk_freq > 0 && priv->clk_freq <= RTC_FREQ_MAX) {
> + priv->clk_freq = priv->clk_freq - 1;
> + } else {
> + dev_warn(dev, "Invalid frequency 0x%lx, using default to 0x%x\n",
> + priv->clk_freq, RTC_CALIB_DEF);
In case the frequency is invalid, that is a user error and it should
IMHO be treated as error, and bail out here.
Thanks,
Tomas
> + priv->clk_freq = RTC_CALIB_DEF;
> + }
> + } else {
> + priv->clk_freq = dev_read_u32_default(dev, "calibration",
> + RTC_CALIB_DEF);
> + }
> +
> + writel(priv->clk_freq, (priv->base + RTC_CALIB_WR));
> + } else {
> + priv->clk_freq = ret & RTC_CALIB_MASK;
> + }
>
> ret = zynqmp_rtc_init(dev);
>
> --
> 2.34.1
>
More information about the U-Boot
mailing list