uboot/drivers/rtc/zynqmp_rtc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2021, Xilinx, Inc.
   4 */
   5
   6#define LOG_CATEGORY UCLASS_RTC
   7
   8#include <common.h>
   9#include <dm.h>
  10#include <rtc.h>
  11#include <asm/io.h>
  12
  13/* RTC Registers */
  14#define RTC_SET_TM_WR           0x00
  15#define RTC_SET_TM_RD           0x04
  16#define RTC_CALIB_WR            0x08
  17#define RTC_CUR_TM              0x10
  18#define RTC_INT_STS             0x20
  19#define RTC_CTRL                0x40
  20
  21#define RTC_INT_SEC             BIT(0)
  22#define RTC_BATT_EN             BIT(31)
  23#define RTC_CALIB_DEF           0x198233
  24#define RTC_CALIB_MASK          0x1FFFFF
  25
  26struct zynqmp_rtc_priv {
  27        fdt_addr_t      base;
  28        unsigned int    calibval;
  29};
  30
  31static int zynqmp_rtc_get(struct udevice *dev, struct rtc_time *tm)
  32{
  33        struct zynqmp_rtc_priv *priv = dev_get_priv(dev);
  34        u32 status;
  35        unsigned long read_time;
  36
  37        status = readl(priv->base + RTC_INT_STS);
  38
  39        if (status & RTC_INT_SEC) {
  40                /*
  41                 * RTC has updated the CURRENT_TIME with the time written into
  42                 * SET_TIME_WRITE register.
  43                 */
  44                read_time = readl(priv->base + RTC_CUR_TM);
  45        } else {
  46                /*
  47                 * Time written in SET_TIME_WRITE has not yet updated into
  48                 * the seconds read register, so read the time from the
  49                 * SET_TIME_WRITE instead of CURRENT_TIME register.
  50                 * Since we add +1 sec while writing, we need to -1 sec while
  51                 * reading.
  52                 */
  53                read_time = readl(priv->base + RTC_SET_TM_RD) - 1;
  54        }
  55
  56        rtc_to_tm(read_time, tm);
  57
  58        return 0;
  59}
  60
  61static int zynqmp_rtc_set(struct udevice *dev, const struct rtc_time *tm)
  62{
  63        struct zynqmp_rtc_priv *priv = dev_get_priv(dev);
  64        unsigned long new_time = 0;
  65
  66        if (tm)
  67                /*
  68                 * The value written will be updated after 1 sec into the
  69                 * seconds read register, so we need to program time +1 sec
  70                 * to get the correct time on read.
  71                 */
  72                new_time = rtc_mktime(tm) + 1;
  73
  74        /*
  75         * Writing into calibration register will clear the Tick Counter and
  76         * force the next second to be signaled exactly in 1 second period
  77         */
  78        priv->calibval &= RTC_CALIB_MASK;
  79        writel(priv->calibval, (priv->base + RTC_CALIB_WR));
  80
  81        writel(new_time, priv->base + RTC_SET_TM_WR);
  82
  83        /*
  84         * Clear the rtc interrupt status register after setting the
  85         * time. During a read_time function, the code should read the
  86         * RTC_INT_STATUS register and if bit 0 is still 0, it means
  87         * that one second has not elapsed yet since RTC was set and
  88         * the current time should be read from SET_TIME_READ register;
  89         * otherwise, CURRENT_TIME register is read to report the time
  90         */
  91        writel(RTC_INT_SEC, priv->base + RTC_INT_STS);
  92
  93        return 0;
  94}
  95
  96static int zynqmp_rtc_reset(struct udevice *dev)
  97{
  98        return zynqmp_rtc_set(dev, NULL);
  99}
 100
 101static int zynqmp_rtc_init(struct udevice *dev)
 102{
 103        struct zynqmp_rtc_priv *priv = dev_get_priv(dev);
 104        u32 rtc_ctrl;
 105
 106        /* Enable RTC switch to battery when VCC_PSAUX is not available */
 107        rtc_ctrl = readl(priv->base + RTC_CTRL);
 108        rtc_ctrl |= RTC_BATT_EN;
 109        writel(rtc_ctrl, priv->base + RTC_CTRL);
 110
 111        /*
 112         * Based on crystal freq of 33.330 KHz
 113         * set the seconds counter and enable, set fractions counter
 114         * to default value suggested as per design spec
 115         * to correct RTC delay in frequency over period of time.
 116         */
 117        priv->calibval &= RTC_CALIB_MASK;
 118        writel(priv->calibval, (priv->base + RTC_CALIB_WR));
 119
 120        return 0;
 121}
 122
 123static int zynqmp_rtc_probe(struct udevice *dev)
 124{
 125        struct zynqmp_rtc_priv *priv = dev_get_priv(dev);
 126        int ret;
 127
 128        priv->base = dev_read_addr(dev);
 129        if (priv->base == FDT_ADDR_T_NONE)
 130                return -EINVAL;
 131
 132        priv->calibval = dev_read_u32_default(dev, "calibration",
 133                                              RTC_CALIB_DEF);
 134
 135        ret = zynqmp_rtc_init(dev);
 136
 137        return ret;
 138}
 139
 140static const struct rtc_ops zynqmp_rtc_ops = {
 141        .get = zynqmp_rtc_get,
 142        .set = zynqmp_rtc_set,
 143        .reset = zynqmp_rtc_reset,
 144};
 145
 146static const struct udevice_id zynqmp_rtc_ids[] = {
 147        { .compatible = "xlnx,zynqmp-rtc" },
 148        { }
 149};
 150
 151U_BOOT_DRIVER(rtc_zynqmp) = {
 152        .name = "rtc-zynqmp",
 153        .id = UCLASS_RTC,
 154        .probe = zynqmp_rtc_probe,
 155        .of_match = zynqmp_rtc_ids,
 156        .ops = &zynqmp_rtc_ops,
 157        .priv_auto = sizeof(struct zynqmp_rtc_priv),
 158};
 159