Hi, On 20/01/2026 13:00, Pranav Tilak wrote: > 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. > > The calibration write previously in zynqmp_rtc_set() has been moved to > the probe function. The earlier implementation wrote calibration on > every time update to clear the tick counter, but since calibration is > now dynamically configured from clock framework or device tree during probe, > it only requires one-time initialization. This avoids repeated tick > counter resets and unnecessary overhead. > > Signed-off-by: Pranav Tilak <[email protected]>
Reviewed-by: Tomas Melin <[email protected]> > --- > Changes in v3: > - Reorder includes alphabetically > - Update the commit message > > Changes in v2: > - Rename variable from clk_freq to calibval > - Handle case where clock node exists but has no clock-frequency > property > - Treat invalid clock frequency as error instead of warning > - Move calibration validation outside if-else to apply to all code paths > > drivers/rtc/zynqmp_rtc.c | 64 +++++++++++++++++++++++++++------------- > 1 file changed, 44 insertions(+), 20 deletions(-) > > diff --git a/drivers/rtc/zynqmp_rtc.c b/drivers/rtc/zynqmp_rtc.c > index 15122a04838..4fee75bf9cf 100644 > --- a/drivers/rtc/zynqmp_rtc.c > +++ b/drivers/rtc/zynqmp_rtc.c > @@ -5,26 +5,30 @@ > > #define LOG_CATEGORY UCLASS_RTC > > +#include <clk.h> > #include <dm.h> > #include <rtc.h> > #include <asm/io.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 calibval; > }; > > 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,44 @@ 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; > + unsigned long clk_rate; > + > + /* Get the RTC clock rate */ > + ret = clk_get_by_name_optional(dev, "rtc", &rtc_clk); > + if (!ret) { > + clk_rate = clk_get_rate(&rtc_clk); > + /* Use clock frequency if valid, fallback to > calibration value */ > + if (clk_rate > 0 && clk_rate <= RTC_FREQ_MAX) { > + /* Valid clock frequency */ > + priv->calibval = clk_rate - 1; > + } else if (clk_rate == 0) { > + priv->calibval = dev_read_u32_default(dev, > "calibration", > + > RTC_CALIB_DEF); > + } else { > + dev_err(dev, "Invalid clock frequency 0x%lx\n", > + clk_rate); > + return -EINVAL; > + } > + } else { > + /* Clock framework unavailable, use DT calibration */ > + priv->calibval = dev_read_u32_default(dev, > "calibration", > + RTC_CALIB_DEF); > + } > + > + /* Validate final calibration value */ > + if (priv->calibval > RTC_FREQ_MAX) { > + dev_err(dev, "Invalid calibration 0x%lx\n", > + priv->calibval); > + return -EINVAL; > + } > + > + writel(priv->calibval, (priv->base + RTC_CALIB_WR)); > + } else { > + priv->calibval = ret & RTC_CALIB_MASK; > + } > > ret = zynqmp_rtc_init(dev); >

