From: Alex Leibovich <al...@marvell.com>

Adding missing marvell-rtc driver and configuration,
in order to support "date" command.

Signed-off-by: Alex Leibovich <al...@marvell.com>
Reviewed-on: https://sj1git1.cavium.com/c/IP/SW/boot/u-boot/+/6322
Reviewed-by: Kostya Porotchkin <kos...@marvell.com>
Tested-by: Kostya Porotchkin <kos...@marvell.com>
Signed-off-by: Josua Mayer <jo...@solid-run.com>
---
 drivers/rtc/Kconfig       |   9 +++
 drivers/rtc/Makefile      |   1 +
 drivers/rtc/marvell_rtc.c | 185 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/rtc/marvell_rtc.h |  52 +++++++++++++
 4 files changed, 247 insertions(+)

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 
6467f20422bec546fd96b5e76643209870c8f255..aa2b292c57243f84d99d09b45aa271d66cd15a66
 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -14,6 +14,15 @@ config DM_RTC
          drivers to perform the actual functions. See rtc.h for a
          description of the API.
 
+config MARVELL_RTC
+       bool "MARVELL RTC support"
+       depends on DM_RTC
+       help
+         Choose this option to add
+         support for Marvell's
+         RTC driver, which is used
+         by Armada 7K, 8K and OcteonTX2 CN913x.
+
 config SPL_DM_RTC
        bool "Enable Driver Model for RTC drivers in SPL"
        depends on SPL_DM
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 
99b5a2a346a9680ee33249597cec398c33e8d657..65c4d875d885546efb230bc5abd78e5d056ee863
 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -7,6 +7,7 @@
 obj-$(CONFIG_$(PHASE_)DM_RTC) += rtc-uclass.o
 
 obj-$(CONFIG_RTC_ARMADA38X) += armada38x.o
+obj-$(CONFIG_MARVELL_RTC) += marvell_rtc.o
 obj-$(CONFIG_RTC_DAVINCI) += davinci.o
 obj-$(CONFIG_RTC_DS1307) += ds1307.o
 obj-$(CONFIG_RTC_DS1338) += ds1307.o
diff --git a/drivers/rtc/marvell_rtc.c b/drivers/rtc/marvell_rtc.c
new file mode 100644
index 
0000000000000000000000000000000000000000..842aeb84eb26ec79ff889d0484bcdb050da35b40
--- /dev/null
+++ b/drivers/rtc/marvell_rtc.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Marvell International Ltd.
+ */
+
+#include <asm/io.h>
+#include <rtc.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include "marvell_rtc.h"
+#include <linux/delay.h>
+
+static int marvell_rtc_get(struct udevice *dev, struct rtc_time *time)
+{
+       struct rtc_unit_config *rtc_cfg = dev_get_priv(dev);
+       uintptr_t rtc_base = (uintptr_t)rtc_cfg->rtc_base;
+
+       rtc_to_tm(RTC_READ_REG(rtc_base, RTC_TIME_REG_OFFS), time);
+
+       return 0;
+}
+
+static int marvell_rtc_set(struct udevice *dev, const struct rtc_time *time)
+{
+       unsigned long tm;
+       struct rtc_unit_config *rtc_cfg = dev_get_priv(dev);
+       uintptr_t rtc_base = (uintptr_t)rtc_cfg->rtc_base;
+
+       tm = rtc_mktime(time);
+
+#ifdef ERRATA_FE_3124064
+       RTC_WRITE_REG(0, rtc_base, RTC_STATUS_REG_OFFS);
+       RTC_WRITE_REG(0, rtc_base, RTC_STATUS_REG_OFFS);
+#endif
+       RTC_WRITE_REG(tm, rtc_base, RTC_TIME_REG_OFFS);
+
+       /* Give registers time to stabilize */
+       mdelay(100);
+
+       return 0;
+}
+
+static int marvell_rtc_reset(struct udevice *dev)
+{
+       struct rtc_unit_config *rtc_cfg = dev_get_priv(dev);
+       uintptr_t rtc_base = (uintptr_t)rtc_cfg->rtc_base;
+
+       /* Reset Test register */
+       RTC_WRITE_REG(0, rtc_base, RTC_TEST_CONFIG_REG_OFFS);
+       /* Oscillator startup time */
+       mdelay(500);
+
+       /* Reset time register */
+#ifdef ERRATA_FE_3124064
+       RTC_WRITE_REG(0, rtc_base, RTC_STATUS_REG_OFFS);
+       RTC_WRITE_REG(0, rtc_base, RTC_STATUS_REG_OFFS);
+#endif
+       RTC_WRITE_REG(0, rtc_base, RTC_TIME_REG_OFFS);
+       udelay(62);
+
+       /* Reset Status register */
+       RTC_WRITE_REG((RTC_SZ_STATUS_ALARM1_MASK | RTC_SZ_STATUS_ALARM2_MASK),
+                     rtc_base, RTC_STATUS_REG_OFFS);
+       udelay(62);
+
+       /* Turn off Int1 and Int2 sources & clear the Alarm count */
+       RTC_WRITE_REG(0, rtc_base, RTC_IRQ_1_CONFIG_REG_OFFS);
+       RTC_WRITE_REG(0, rtc_base, RTC_IRQ_2_CONFIG_REG_OFFS);
+       RTC_WRITE_REG(0, rtc_base, RTC_ALARM_1_REG_OFFS);
+       RTC_WRITE_REG(0, rtc_base, RTC_ALARM_2_REG_OFFS);
+
+       /* Setup nominal register access timing */
+       RTC_WRITE_REG(RTC_NOMINAL_TIMING, rtc_base, RTC_CLOCK_CORR_REG_OFFS);
+
+       /* Reset time register */
+#ifdef ERRATA_FE_3124064
+       RTC_WRITE_REG(0, rtc_base, RTC_STATUS_REG_OFFS);
+       RTC_WRITE_REG(0, rtc_base, RTC_STATUS_REG_OFFS);
+#endif
+       RTC_WRITE_REG(0, rtc_base, RTC_TIME_REG_OFFS);
+       udelay(10);
+
+       /* Reset Status register */
+       RTC_WRITE_REG((RTC_SZ_STATUS_ALARM1_MASK | RTC_SZ_STATUS_ALARM2_MASK),
+                     rtc_base, RTC_STATUS_REG_OFFS);
+       udelay(50);
+
+       return 0;
+}
+
+void marvell_rtc_errata(struct udevice *dev)
+{
+       unsigned long reg;
+
+       /* Get the rtc register base address */
+       struct rtc_unit_config *rtc_cfg = dev_get_priv(dev);
+       uintptr_t rtc_base;
+
+       rtc_cfg->rtc_base = (void *)devfdt_get_addr_index(dev, 0);
+       rtc_base = (uintptr_t)rtc_cfg->rtc_base;
+
+       /* Update RTC-MBUS bridge timing parameters */
+       /* Functional Errata Ref #:
+        * FE-3124064 - WA for failing time read attempts.
+        * Description:
+        *      The device supports CPU write and read access
+        *      to the RTC Time register.
+        *      However, due to this erratum,
+        *      Write to RTC TIME register may fail.
+        *      Read from RTC TIME register may fail.
+        * Workaround:
+        * 1. Configure the RTC Mbus Bridge Timing Control register
+        *    (offset 0x284080 and 0x284084)
+        *      - Write RTC WRCLK Period 0x3FF (default value is 0xFA)
+        *      - Write RTC WRCLK setup to 0x29 (default value is 0x53)
+        *      - Write RTC Read Output Delay to 0x3F (default value is 0x10)
+        *      - Write RTC WRCLK High Time to 0x53 (default value)
+        *      - Mbus - Read All Byte Enable to 0x1 (default value)
+        * 2. Configure the RTC Test Configuration Register (offset 0x28401C)
+        *    bit3 to '1' (Reserved, Marvell internal)
+        *
+        * RTC Time register write operation:
+        *      - Issue two dummy writes of 0x0 to the RTC Status register
+        *        (offset 0x284000).
+        *      - Write the time to the RTC Time register (offset 0x28400C).
+        */
+       reg = RTC_READ_REG(rtc_base, MV_RTC0_SOC_OFFSET);
+       reg &= ~RTC_WRCLK_PERIOD_MASK;
+       reg |= 0x3FF << RTC_WRCLK_PERIOD_OFFS;
+       reg &= ~RTC_WRCLK_SETUP_MASK;
+       reg |= 0x29 << RTC_WRCLK_SETUP_OFFS;
+       RTC_WRITE_REG(reg, rtc_base, MV_RTC0_SOC_OFFSET);
+
+       reg = RTC_READ_REG(rtc_base, MV_RTC1_SOC_OFFSET);
+       reg &= ~RTC_READ_OUTPUT_DELAY_MASK;
+       reg |= 0x3F << RTC_READ_OUTPUT_DELAY_OFFS;
+       RTC_WRITE_REG(reg, rtc_base, MV_RTC1_SOC_OFFSET);
+
+       reg = RTC_READ_REG(rtc_base, RTC_TEST_CONFIG_REG_OFFS);
+       reg |= 0x8;
+       RTC_WRITE_REG(reg, rtc_base, RTC_TEST_CONFIG_REG_OFFS);
+}
+
+static int marvell_rtc_probe(struct udevice *dev)
+{
+#ifdef ERRATA_FE_3124064
+       marvell_rtc_errata(dev);
+#else
+       /* Get the rtc register base address */
+       struct rtc_unit_config *rtc_cfg = dev_get_priv(dev);
+       uintptr_t rtc_base;
+       unsigned long reg;
+
+       rtc_cfg->rtc_base = (void *)devfdt_get_addr_index(dev, 0);
+       rtc_base = (uintptr_t)rtc_cfg->rtc_base;
+
+       /* Update RTC-MBUS bridge timing parameters */
+       reg = RTC_READ_REG(rtc_base, MV_RTC1_SOC_OFFSET);
+       reg &= ~RTC_READ_OUTPUT_DELAY_MASK;
+       reg |= 0x1F << RTC_READ_OUTPUT_DELAY_OFFS;
+       RTC_WRITE_REG(reg, rtc_base, MV_RTC1_SOC_OFFSET);
+#endif
+
+       return 0;
+}
+
+static const struct rtc_ops marvell_rtc_ops = {
+       .get = marvell_rtc_get,
+       .set = marvell_rtc_set,
+       .reset = marvell_rtc_reset,
+};
+
+static const struct udevice_id marvell_rtc_ids[] = {
+       { .compatible = "marvell,armada-8k-rtc" },
+       { }
+};
+
+U_BOOT_DRIVER(marvell_rtc) = {
+       .name   = "marvell_rtc",
+       .id     = UCLASS_RTC,
+       .of_match = marvell_rtc_ids,
+       .ops    = &marvell_rtc_ops,
+       .probe = marvell_rtc_probe,
+       .priv_auto = sizeof(struct rtc_unit_config),
+};
diff --git a/drivers/rtc/marvell_rtc.h b/drivers/rtc/marvell_rtc.h
new file mode 100644
index 
0000000000000000000000000000000000000000..f93b03bd2c954f1be9b645fb4de23a89e92e9dbc
--- /dev/null
+++ b/drivers/rtc/marvell_rtc.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2019 Marvell International Ltd.
+ */
+
+#ifndef _MARVELL_RTC_H
+#define _MARVELL_RTC_H
+
+/* The RTC DRS revision 1.2 indicates that firmware should wait
+ * 5us after every register write to the RTC hard macro,
+ * so that the required update can occur without holding off the system bus
+ */
+#define RTC_READ_REG(rtc_base, reg)            readl((rtc_base) + (reg))
+#define RTC_WRITE_REG(val, rtc_base, reg)              \
+       { writel((val), (rtc_base) + (reg)); udelay(5); }
+
+#define RTC_NOMINAL_TIMING             0x2000
+
+#define RTC_STATUS_REG_OFFS            0x0
+#define RTC_IRQ_1_CONFIG_REG_OFFS      0x4
+#define RTC_IRQ_2_CONFIG_REG_OFFS      0x8
+#define RTC_TIME_REG_OFFS              0xC
+#define RTC_ALARM_1_REG_OFFS           0x10
+#define RTC_ALARM_2_REG_OFFS           0x14
+#define RTC_CLOCK_CORR_REG_OFFS                0x18
+#define RTC_TEST_CONFIG_REG_OFFS       0x1C
+#define MV_RTC0_SOC_OFFSET             0x80
+#define MV_RTC1_SOC_OFFSET             0x84
+
+#define RTC_WRCLK_PERIOD_OFFS          0
+#define RTC_WRCLK_PERIOD_MASK          (0xFFFF << RTC_WRCLK_PERIOD_OFFS)
+#define RTC_WRCLK_SETUP_OFFS           16
+#define RTC_WRCLK_SETUP_MASK           (0xFFFF << RTC_WRCLK_SETUP_OFFS)
+
+#define RTC_READ_OUTPUT_DELAY_OFFS     0
+#define RTC_READ_OUTPUT_DELAY_MASK     (0xFFFF << RTC_READ_OUTPUT_DELAY_OFFS)
+#define RTC_WRCLK_CLOCK_HIGH_OFFS      16
+#define RTC_WRCLK_CLOCK_HIGH_MASK      (0xFFFF << RTC_WRCLK_CLOCK_HIGH_OFFS)
+
+#define RTC_SZ_STATUS_ALARM1_MASK              0x1
+#define RTC_SZ_STATUS_ALARM2_MASK              0x2
+#define RTC_SZ_TIMING_RESERVED1_MASK           0xFFFF0000
+#define RTC_SZ_INTERRUPT1_INT1AE_MASK          0x1
+#define RTC_SZ_INTERRUPT1_RESERVED1_MASK       0xFFFFFFC0
+#define RTC_SZ_INTERRUPT2_INT2FE_MASK          0x2
+#define RTC_SZ_INTERRUPT2_RESERVED1_MASK       0xFFFFFFC0
+
+struct rtc_unit_config {
+       void __iomem *rtc_base;
+};
+
+#endif /* _MARVELL_RTC_H */

-- 
2.43.0

Reply via email to