Re: [PATCH u-boot-marvell 1/4] rtc: add armada38x driver

2021-02-26 Thread Stefan Roese

On 09.02.21 23:55, Marek Behún wrote:

Add RTC driver for Armada 38x, based on Linux' driver.
For now implement only `marvell,armada-380-rtc` compatible.

Signed-off-by: Marek Behún 
Cc: Pali Rohár 
Cc: Stefan Roese 
Cc: Baruch Siach 
Cc: Chris Packham 
Cc: Simon Glass 
---
  drivers/rtc/Kconfig |   7 ++
  drivers/rtc/Makefile|   1 +
  drivers/rtc/armada38x.c | 185 
  3 files changed, 193 insertions(+)
  create mode 100644 drivers/rtc/armada38x.c

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index aa6d90158c..dafba35279 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -38,6 +38,13 @@ config RTC_ENABLE_32KHZ_OUTPUT
   Some real-time clocks support the output of 32kHz square waves (such 
as ds3231),
   the config symbol choose Real Time Clock device 32Khz output feature.
  
+config RTC_ARMADA38X

+   bool "Enable Armada 38x Marvell SoC RTC"
+   depends on DM_RTC && ARCH_MVEBU
+   help
+ This adds support for the in-chip RTC that can be found in the
+ Armada 38x Marvell's SoC devices.
+
  config RTC_PCF2127
bool "Enable PCF2127 driver"
depends on DM_RTC
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 6a45a9c874..15609e7b18 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_$(SPL_TPL_)DM_RTC) += rtc-uclass.o
  
  obj-$(CONFIG_RTC_AT91SAM9_RTT) += at91sam9_rtt.o

  obj-y += rtc-lib.o
+obj-$(CONFIG_RTC_ARMADA38X) += armada38x.o
  obj-$(CONFIG_RTC_DAVINCI) += davinci.o
  obj-$(CONFIG_RTC_DS1302) += ds1302.o
  obj-$(CONFIG_RTC_DS1306) += ds1306.o
diff --git a/drivers/rtc/armada38x.c b/drivers/rtc/armada38x.c
new file mode 100644
index 00..88dc9977c6
--- /dev/null
+++ b/drivers/rtc/armada38x.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * RTC driver for the Armada 38x Marvell SoCs
+ *
+ * Copyright (C) 2021 Marek Behun 
+ *
+ * Based on Linux' driver by Gregory Clement and Marvell
+ */
+
+#include 


Please don't include "common.h" any more - this is deprecated. Other
than that looks good:

Reviewed-by: Stefan Roese 

for the complete series. Please resend v2 once it's ready.

Thanks,
Stefan


+#include 
+#include 
+#include 
+#include 
+
+#define RTC_STATUS 0x0
+#define RTC_TIME   0xC
+#define RTC_CONF_TEST  0x1C
+
+/* Armada38x SoC registers  */
+#define RTC_38X_BRIDGE_TIMING_CTL  0x0
+#define RTC_38X_PERIOD_OFFS0
+#define RTC_38X_PERIOD_MASK(0x3FF << RTC_38X_PERIOD_OFFS)
+#define RTC_38X_READ_DELAY_OFFS26
+#define RTC_38X_READ_DELAY_MASK(0x1F << 
RTC_38X_READ_DELAY_OFFS)
+
+#define SAMPLE_NR  100
+
+struct armada38x_rtc {
+   void __iomem *regs;
+   void __iomem *regs_soc;
+};
+
+/*
+ * According to Erratum RES-3124064 we have to do some configuration in MBUS.
+ * To read an RTC register we need to read it 100 times and return the most
+ * frequent value.
+ * To write an RTC register we need to write 2x zero into STATUS register,
+ * followed by the proper write. Linux adds an 5 us delay after this, so we do
+ * it here as well.
+ */
+static void update_38x_mbus_timing_params(struct armada38x_rtc *rtc)
+{
+   u32 reg;
+
+   reg = readl(rtc->regs_soc + RTC_38X_BRIDGE_TIMING_CTL);
+   reg &= ~RTC_38X_PERIOD_MASK;
+   reg |= 0x3FF << RTC_38X_PERIOD_OFFS; /* Maximum value */
+   reg &= ~RTC_38X_READ_DELAY_MASK;
+   reg |= 0x1F << RTC_38X_READ_DELAY_OFFS; /* Maximum value */
+   writel(reg, rtc->regs_soc + RTC_38X_BRIDGE_TIMING_CTL);
+}
+
+static void armada38x_rtc_write(u32 val, struct armada38x_rtc *rtc, u8 reg)
+{
+   writel(0, rtc->regs + RTC_STATUS);
+   writel(0, rtc->regs + RTC_STATUS);
+   writel(val, rtc->regs + reg);
+   udelay(5);
+}
+
+static u32 armada38x_rtc_read(struct armada38x_rtc *rtc, u8 reg)
+{
+   u8 counts[SAMPLE_NR], max_idx;
+   u32 samples[SAMPLE_NR], max;
+   int i, j, last;
+
+   for (i = 0, last = 0; i < SAMPLE_NR; ++i) {
+   u32 sample = readl(rtc->regs + reg);
+
+   /* find if this value was already read */
+   for (j = 0; j < last; ++j) {
+   if (samples[j] == sample)
+   break;
+   }
+
+   if (j < last) {
+   /* if yes, increment count */
+   ++counts[j];
+   } else {
+   /* if not, add */
+   samples[last] = sample;
+   counts[last] = 1;
+   ++last;
+   }
+   }
+
+   /* finally find the sample that was read the most */
+   max = 0;
+   max_idx = 0;
+
+   for (i = 0; i < last; ++i) {
+   if (counts[i] > max) {
+   max = counts[i];
+   max_idx = i;
+   

Re: [PATCH u-boot-marvell 1/4] rtc: add armada38x driver

2021-02-19 Thread Marek Behún
Just pinging this series :)


[PATCH u-boot-marvell 1/4] rtc: add armada38x driver

2021-02-09 Thread Marek Behún
Add RTC driver for Armada 38x, based on Linux' driver.
For now implement only `marvell,armada-380-rtc` compatible.

Signed-off-by: Marek Behún 
Cc: Pali Rohár 
Cc: Stefan Roese 
Cc: Baruch Siach 
Cc: Chris Packham 
Cc: Simon Glass 
---
 drivers/rtc/Kconfig |   7 ++
 drivers/rtc/Makefile|   1 +
 drivers/rtc/armada38x.c | 185 
 3 files changed, 193 insertions(+)
 create mode 100644 drivers/rtc/armada38x.c

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index aa6d90158c..dafba35279 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -38,6 +38,13 @@ config RTC_ENABLE_32KHZ_OUTPUT
   Some real-time clocks support the output of 32kHz square waves (such 
as ds3231),
   the config symbol choose Real Time Clock device 32Khz output feature.
 
+config RTC_ARMADA38X
+   bool "Enable Armada 38x Marvell SoC RTC"
+   depends on DM_RTC && ARCH_MVEBU
+   help
+ This adds support for the in-chip RTC that can be found in the
+ Armada 38x Marvell's SoC devices.
+
 config RTC_PCF2127
bool "Enable PCF2127 driver"
depends on DM_RTC
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 6a45a9c874..15609e7b18 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_$(SPL_TPL_)DM_RTC) += rtc-uclass.o
 
 obj-$(CONFIG_RTC_AT91SAM9_RTT) += at91sam9_rtt.o
 obj-y += rtc-lib.o
+obj-$(CONFIG_RTC_ARMADA38X) += armada38x.o
 obj-$(CONFIG_RTC_DAVINCI) += davinci.o
 obj-$(CONFIG_RTC_DS1302) += ds1302.o
 obj-$(CONFIG_RTC_DS1306) += ds1306.o
diff --git a/drivers/rtc/armada38x.c b/drivers/rtc/armada38x.c
new file mode 100644
index 00..88dc9977c6
--- /dev/null
+++ b/drivers/rtc/armada38x.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * RTC driver for the Armada 38x Marvell SoCs
+ *
+ * Copyright (C) 2021 Marek Behun 
+ *
+ * Based on Linux' driver by Gregory Clement and Marvell
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define RTC_STATUS 0x0
+#define RTC_TIME   0xC
+#define RTC_CONF_TEST  0x1C
+
+/* Armada38x SoC registers  */
+#define RTC_38X_BRIDGE_TIMING_CTL  0x0
+#define RTC_38X_PERIOD_OFFS0
+#define RTC_38X_PERIOD_MASK(0x3FF << RTC_38X_PERIOD_OFFS)
+#define RTC_38X_READ_DELAY_OFFS26
+#define RTC_38X_READ_DELAY_MASK(0x1F << 
RTC_38X_READ_DELAY_OFFS)
+
+#define SAMPLE_NR  100
+
+struct armada38x_rtc {
+   void __iomem *regs;
+   void __iomem *regs_soc;
+};
+
+/*
+ * According to Erratum RES-3124064 we have to do some configuration in MBUS.
+ * To read an RTC register we need to read it 100 times and return the most
+ * frequent value.
+ * To write an RTC register we need to write 2x zero into STATUS register,
+ * followed by the proper write. Linux adds an 5 us delay after this, so we do
+ * it here as well.
+ */
+static void update_38x_mbus_timing_params(struct armada38x_rtc *rtc)
+{
+   u32 reg;
+
+   reg = readl(rtc->regs_soc + RTC_38X_BRIDGE_TIMING_CTL);
+   reg &= ~RTC_38X_PERIOD_MASK;
+   reg |= 0x3FF << RTC_38X_PERIOD_OFFS; /* Maximum value */
+   reg &= ~RTC_38X_READ_DELAY_MASK;
+   reg |= 0x1F << RTC_38X_READ_DELAY_OFFS; /* Maximum value */
+   writel(reg, rtc->regs_soc + RTC_38X_BRIDGE_TIMING_CTL);
+}
+
+static void armada38x_rtc_write(u32 val, struct armada38x_rtc *rtc, u8 reg)
+{
+   writel(0, rtc->regs + RTC_STATUS);
+   writel(0, rtc->regs + RTC_STATUS);
+   writel(val, rtc->regs + reg);
+   udelay(5);
+}
+
+static u32 armada38x_rtc_read(struct armada38x_rtc *rtc, u8 reg)
+{
+   u8 counts[SAMPLE_NR], max_idx;
+   u32 samples[SAMPLE_NR], max;
+   int i, j, last;
+
+   for (i = 0, last = 0; i < SAMPLE_NR; ++i) {
+   u32 sample = readl(rtc->regs + reg);
+
+   /* find if this value was already read */
+   for (j = 0; j < last; ++j) {
+   if (samples[j] == sample)
+   break;
+   }
+
+   if (j < last) {
+   /* if yes, increment count */
+   ++counts[j];
+   } else {
+   /* if not, add */
+   samples[last] = sample;
+   counts[last] = 1;
+   ++last;
+   }
+   }
+
+   /* finally find the sample that was read the most */
+   max = 0;
+   max_idx = 0;
+
+   for (i = 0; i < last; ++i) {
+   if (counts[i] > max) {
+   max = counts[i];
+   max_idx = i;
+   }
+   }
+
+   return samples[max_idx];
+}
+
+static int armada38x_rtc_get(struct udevice *dev, struct rtc_time *tm)
+{
+   struct armada38x_rtc *rtc = dev_get_priv(dev);
+   u32 time;
+
+   time = armada38x_rtc_read(rtc,