[PATCH 0/4] xilinx: Add RTC support for Xilinx ZynqMP

Hi,
this series is correcting RTC uclass behavior to match RTC aliases to enable RTC_EMULATION driver with ZYNQMP driver. If DT node is present ZynqMP RTC is used. If not RTC emaulation is used.
The driver has been tested on Xilinx zcu104 also with booting to Linux to make sure that U-Boot format match with Linux format.
Thanks, Michal
Michal Simek (4): dm: rtc: uclass: Add flag to control sequence numbering cmd: date: rtc: Update command to read the first RTC with seq 0 rtc: zynqmp: Add support for ZynqMP RTC xilinx: zynqmp: Enable CMD_RTC command with Zynqmp RTC driver
MAINTAINERS | 1 + cmd/date.c | 9 +- configs/xilinx_zynqmp_virt_defconfig | 2 + drivers/rtc/Kconfig | 7 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-uclass.c | 1 + drivers/rtc/zynqmp_rtc.c | 158 +++++++++++++++++++++++++++ 7 files changed, 176 insertions(+), 3 deletions(-) create mode 100644 drivers/rtc/zynqmp_rtc.c

RTCs are using aliases for sequences. That's why enable DM_UC_FLAG_SEQ_ALIAS for exact RTC indentification. The same flag is used by a lot of other uclasses like mmc, pci, serial, spi, timer, tpm, etc.
Signed-off-by: Michal Simek michal.simek@xilinx.com ---
drivers/rtc/rtc-uclass.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/rtc/rtc-uclass.c b/drivers/rtc/rtc-uclass.c index be6a2ddb6671..321b8732ed9a 100644 --- a/drivers/rtc/rtc-uclass.c +++ b/drivers/rtc/rtc-uclass.c @@ -176,6 +176,7 @@ int rtc_write32(struct udevice *dev, unsigned int reg, u32 value) UCLASS_DRIVER(rtc) = { .name = "rtc", .id = UCLASS_RTC, + .flags = DM_UC_FLAG_SEQ_ALIAS, #if !CONFIG_IS_ENABLED(OF_PLATDATA) .post_bind = dm_scan_fdt_dev, #endif

RTCs are using sequence number defined in aliases node. Date command with DM_RTC enabled is looking for the first RTC with index 0. But when RTC_EMULATION is enabled it gets likely most of the time index 0 even when system has rtc0 device via aliases node and gets sequence number 0. That's why extend the code to look for sequence 0 number first. If this fails continue to use existing device with index 0.
Signed-off-by: Michal Simek michal.simek@xilinx.com ---
cmd/date.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/cmd/date.c b/cmd/date.c index 0e1189475313..5d5c20a59af9 100644 --- a/cmd/date.c +++ b/cmd/date.c @@ -41,10 +41,13 @@ static int do_date(struct cmd_tbl *cmdtp, int flag, int argc, #ifdef CONFIG_DM_RTC struct udevice *dev;
- rcode = uclass_get_device(UCLASS_RTC, 0, &dev); + rcode = uclass_get_device_by_seq(UCLASS_RTC, 0, &dev); if (rcode) { - printf("Cannot find RTC: err=%d\n", rcode); - return CMD_RET_FAILURE; + rcode = uclass_get_device(UCLASS_RTC, 0, &dev); + if (rcode) { + printf("Cannot find RTC: err=%d\n", rcode); + return CMD_RET_FAILURE; + } } #elif defined(CONFIG_SYS_I2C) old_bus = i2c_get_bus_num();

The whole driver logic is taken from Linux kernel but only set/get/reset functions are implemented. When device is power off RTC is power out of battery.
Signed-off-by: Michal Simek michal.simek@xilinx.com ---
MAINTAINERS | 1 + drivers/rtc/Kconfig | 7 ++ drivers/rtc/Makefile | 1 + drivers/rtc/zynqmp_rtc.c | 158 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 167 insertions(+) create mode 100644 drivers/rtc/zynqmp_rtc.c
diff --git a/MAINTAINERS b/MAINTAINERS index 8a18b3b6d939..5734ebb80363 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -600,6 +600,7 @@ F: drivers/mtd/nand/raw/zynq_nand.c F: drivers/net/phy/xilinx_phy.c F: drivers/net/zynq_gem.c F: drivers/serial/serial_zynq.c +F: drivers/rtc/zynqmp_rtc.c F: drivers/spi/zynq_qspi.c F: drivers/spi/zynq_spi.c F: drivers/timer/cadence-ttc.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index cbdfddb80f66..b6692e62df1c 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -195,4 +195,11 @@ config RTC_DAVINCI Say "yes" here to support the on chip real time clock present on TI OMAP1, AM33xx, DA8xx/OMAP-L13x, AM43xx and DRA7xx.
+config RTC_ZYNQMP + bool "Enable ZynqMP RTC driver" + depends on ARCH_ZYNQMP + help + Say "yes" here to support the on chip real time clock + present on Xilinx ZynqMP SoC. + endmenu diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 331a49ab599a..d621be622848 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -57,3 +57,4 @@ obj-$(CONFIG_RTC_STM32) += stm32_rtc.o obj-$(CONFIG_SANDBOX) += sandbox_rtc.o obj-$(CONFIG_RTC_X1205) += x1205.o obj-$(CONFIG_RTC_ABX80X) += abx80x.o +obj-$(CONFIG_RTC_ZYNQMP) += zynqmp_rtc.o diff --git a/drivers/rtc/zynqmp_rtc.c b/drivers/rtc/zynqmp_rtc.c new file mode 100644 index 000000000000..ab9b93ca9793 --- /dev/null +++ b/drivers/rtc/zynqmp_rtc.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021, Xilinx, Inc. + */ + +#define LOG_CATEGORY UCLASS_RTC + +#include <common.h> +#include <dm.h> +#include <rtc.h> +#include <asm/io.h> + +/* RTC Registers */ +#define RTC_SET_TM_WR 0x00 +#define RTC_SET_TM_RD 0x04 +#define RTC_CALIB_WR 0x08 +#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_MASK 0x1FFFFF + +struct zynqmp_rtc_priv { + fdt_addr_t base; + unsigned int calibval; +}; + +static int zynqmp_rtc_get(struct udevice *dev, struct rtc_time *tm) +{ + struct zynqmp_rtc_priv *priv = dev_get_priv(dev); + u32 status; + unsigned long read_time; + + status = readl(priv->base + RTC_INT_STS); + + if (status & RTC_INT_SEC) { + /* + * RTC has updated the CURRENT_TIME with the time written into + * SET_TIME_WRITE register. + */ + read_time = readl(priv->base + RTC_CUR_TM); + } else { + /* + * Time written in SET_TIME_WRITE has not yet updated into + * the seconds read register, so read the time from the + * SET_TIME_WRITE instead of CURRENT_TIME register. + * Since we add +1 sec while writing, we need to -1 sec while + * reading. + */ + read_time = readl(priv->base + RTC_SET_TM_RD) - 1; + } + + rtc_to_tm(read_time, tm); + + return 0; +} + +static int zynqmp_rtc_set(struct udevice *dev, const struct rtc_time *tm) +{ + struct zynqmp_rtc_priv *priv = dev_get_priv(dev); + unsigned long new_time = 0; + + if (tm) + /* + * The value written will be updated after 1 sec into the + * seconds read register, so we need to program time +1 sec + * to get the correct time on read. + */ + 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); + + /* + * Clear the rtc interrupt status register after setting the + * time. During a read_time function, the code should read the + * RTC_INT_STATUS register and if bit 0 is still 0, it means + * that one second has not elapsed yet since RTC was set and + * the current time should be read from SET_TIME_READ register; + * otherwise, CURRENT_TIME register is read to report the time + */ + writel(RTC_INT_SEC, priv->base + RTC_INT_STS); + + return 0; +} + +static int zynqmp_rtc_reset(struct udevice *dev) +{ + return zynqmp_rtc_set(dev, NULL); +} + +static int zynqmp_rtc_init(struct udevice *dev) +{ + struct zynqmp_rtc_priv *priv = dev_get_priv(dev); + u32 rtc_ctrl; + + /* Enable RTC switch to battery when VCC_PSAUX is not available */ + rtc_ctrl = readl(priv->base + RTC_CTRL); + 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; +} + +static int zynqmp_rtc_probe(struct udevice *dev) +{ + struct zynqmp_rtc_priv *priv = dev_get_priv(dev); + int ret; + + priv->base = dev_read_addr(dev); + if (priv->base == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->calibval = dev_read_u32_default(dev, "calibration", + RTC_CALIB_DEF); + + ret = zynqmp_rtc_init(dev); + + return ret; +} + +static const struct rtc_ops zynqmp_rtc_ops = { + .get = zynqmp_rtc_get, + .set = zynqmp_rtc_set, + .reset = zynqmp_rtc_reset, +}; + +static const struct udevice_id zynqmp_rtc_ids[] = { + { .compatible = "xlnx,zynqmp-rtc" }, + { } +}; + +U_BOOT_DRIVER(rtc_zynqmp) = { + .name = "rtc-zynqmp", + .id = UCLASS_RTC, + .probe = zynqmp_rtc_probe, + .of_match = zynqmp_rtc_ids, + .ops = &zynqmp_rtc_ops, + .priv_auto = sizeof(struct zynqmp_rtc_priv), +};

Enable RTC command to be able to check available. And also enable ZynqMP RTC driver to be possible to use by default.
Here is the list when both drivers are enabled: ZynqMP> rtc list RTC #0 - rtc_emul RTC #1 - rtc@ffa60000
Signed-off-by: Michal Simek michal.simek@xilinx.com ---
configs/xilinx_zynqmp_virt_defconfig | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig index a1a3526f3c5f..9a45ccb5287c 100644 --- a/configs/xilinx_zynqmp_virt_defconfig +++ b/configs/xilinx_zynqmp_virt_defconfig @@ -62,6 +62,7 @@ CONFIG_CMD_TFTPPUT=y CONFIG_CMD_BMP=y CONFIG_CMD_CACHE=y CONFIG_CMD_EFIDEBUG=y +CONFIG_CMD_RTC=y CONFIG_CMD_TIME=y CONFIG_CMD_GETTIME=y CONFIG_CMD_TIMER=y @@ -153,6 +154,7 @@ CONFIG_DM_REGULATOR=y CONFIG_DM_REGULATOR_FIXED=y CONFIG_DM_RTC=y CONFIG_RTC_EMULATION=y +CONFIG_RTC_ZYNQMP=y CONFIG_SCSI=y CONFIG_DM_SCSI=y CONFIG_ARM_DCC=y

čt 29. 7. 2021 v 13:36 odesílatel Michal Simek michal.simek@xilinx.com napsal:
Hi,
this series is correcting RTC uclass behavior to match RTC aliases to enable RTC_EMULATION driver with ZYNQMP driver. If DT node is present ZynqMP RTC is used. If not RTC emaulation is used.
The driver has been tested on Xilinx zcu104 also with booting to Linux to make sure that U-Boot format match with Linux format.
Thanks, Michal
Michal Simek (4): dm: rtc: uclass: Add flag to control sequence numbering cmd: date: rtc: Update command to read the first RTC with seq 0 rtc: zynqmp: Add support for ZynqMP RTC xilinx: zynqmp: Enable CMD_RTC command with Zynqmp RTC driver
MAINTAINERS | 1 + cmd/date.c | 9 +- configs/xilinx_zynqmp_virt_defconfig | 2 + drivers/rtc/Kconfig | 7 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-uclass.c | 1 + drivers/rtc/zynqmp_rtc.c | 158 +++++++++++++++++++++++++++ 7 files changed, 176 insertions(+), 3 deletions(-) create mode 100644 drivers/rtc/zynqmp_rtc.c
-- 2.32.0
Applied. M
participants (2)
-
Michal Simek
-
Michal Simek