diff mbox series

[OpenWrt-Devel] mvebu: Replace RTC initialization patch with upstreamed version

Message ID 1536467037-7544-1-git-send-email-rosenp@gmail.com
State Accepted
Delegated to: John Crispin
Headers show
Series [OpenWrt-Devel] mvebu: Replace RTC initialization patch with upstreamed version | expand

Commit Message

Rosen Penev Sept. 9, 2018, 4:23 a.m. UTC
While we're at it, rename the patches to their proper git format-patch
name.

Tested on a Turris Omnia.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
 From IRC, it is my understanding that the old patch 421 breaks the Linksys
 WRT series. The new one may make patch 423 invalid. Although functionally,
 it does look the same. Just throwing that out there since I have no
 hardware to test.
 ...rmada38x-add-support-for-trimming-the-RTC.patch | 143 +++++++++++++++++++++
 .../patches-4.14/420-rtc-trimming-support.patch    | 143 ---------------------
 ...-rtc-armada38x-reset-after-rtc-power-loss.patch |  78 +++++++++++
 .../mvebu/patches-4.14/421-rtc-initialize.patch    |  74 -----------
 4 files changed, 221 insertions(+), 217 deletions(-)
 create mode 100644 target/linux/mvebu/patches-4.14/420-rtc-armada38x-add-support-for-trimming-the-RTC.patch
 delete mode 100644 target/linux/mvebu/patches-4.14/420-rtc-trimming-support.patch
 create mode 100644 target/linux/mvebu/patches-4.14/421-rtc-armada38x-reset-after-rtc-power-loss.patch
 delete mode 100644 target/linux/mvebu/patches-4.14/421-rtc-initialize.patch
diff mbox series

Patch

diff --git a/target/linux/mvebu/patches-4.14/420-rtc-armada38x-add-support-for-trimming-the-RTC.patch b/target/linux/mvebu/patches-4.14/420-rtc-armada38x-add-support-for-trimming-the-RTC.patch
new file mode 100644
index 0000000..2974a69
--- /dev/null
+++ b/target/linux/mvebu/patches-4.14/420-rtc-armada38x-add-support-for-trimming-the-RTC.patch
@@ -0,0 +1,143 @@ 
+commit f94ffbc2c2a4128c4412bb483d0807722dfb682b
+Author: Russell King <rmk+kernel@armlinux.org.uk>
+Date:   Fri Sep 29 11:23:31 2017 +0100
+
+    rtc: armada38x: add support for trimming the RTC
+    
+    Add support for trimming the RTC using the offset mechanism.  This RTC
+    supports two modes: low update mode and high update mode.  Low update
+    mode has finer precision than high update mode, so we use the low mode
+    where possible.
+    
+    Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+    Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
+
+--- a/drivers/rtc/rtc-armada38x.c
++++ b/drivers/rtc/rtc-armada38x.c
+@@ -28,6 +28,8 @@
+ #define RTC_IRQ_AL_EN		    BIT(0)
+ #define RTC_IRQ_FREQ_EN		    BIT(1)
+ #define RTC_IRQ_FREQ_1HZ	    BIT(2)
++#define RTC_CCR		    0x18
++#define RTC_CCR_MODE		    BIT(15)
+ 
+ #define RTC_TIME	    0xC
+ #define RTC_ALARM1	    0x10
+@@ -343,18 +345,117 @@ static irqreturn_t armada38x_rtc_alarm_i
+ 	return IRQ_HANDLED;
+ }
+ 
++/*
++ * The information given in the Armada 388 functional spec is complex.
++ * They give two different formulas for calculating the offset value,
++ * but when considering "Offset" as an 8-bit signed integer, they both
++ * reduce down to (we shall rename "Offset" as "val" here):
++ *
++ *   val = (f_ideal / f_measured - 1) / resolution   where f_ideal = 32768
++ *
++ * Converting to time, f = 1/t:
++ *   val = (t_measured / t_ideal - 1) / resolution   where t_ideal = 1/32768
++ *
++ *   =>  t_measured / t_ideal = val * resolution + 1
++ *
++ * "offset" in the RTC interface is defined as:
++ *   t = t0 * (1 + offset * 1e-9)
++ * where t is the desired period, t0 is the measured period with a zero
++ * offset, which is t_measured above. With t0 = t_measured and t = t_ideal,
++ *   offset = (t_ideal / t_measured - 1) / 1e-9
++ *
++ *   => t_ideal / t_measured = offset * 1e-9 + 1
++ *
++ * so:
++ *
++ *   offset * 1e-9 + 1 = 1 / (val * resolution + 1)
++ *
++ * We want "resolution" to be an integer, so resolution = R * 1e-9, giving
++ *   offset = 1e18 / (val * R + 1e9) - 1e9
++ *   val = (1e18 / (offset + 1e9) - 1e9) / R
++ * with a common transformation:
++ *   f(x) = 1e18 / (x + 1e9) - 1e9
++ *   offset = f(val * R)
++ *   val = f(offset) / R
++ *
++ * Armada 38x supports two modes, fine mode (954ppb) and coarse mode (3815ppb).
++ */
++static long armada38x_ppb_convert(long ppb)
++{
++	long div = ppb + 1000000000L;
++
++	return div_s64(1000000000000000000LL + div / 2, div) - 1000000000L;
++}
++
++static int armada38x_rtc_read_offset(struct device *dev, long *offset)
++{
++	struct armada38x_rtc *rtc = dev_get_drvdata(dev);
++	unsigned long ccr, flags;
++	long ppb_cor;
++
++	spin_lock_irqsave(&rtc->lock, flags);
++	ccr = rtc->data->read_rtc_reg(rtc, RTC_CCR);
++	spin_unlock_irqrestore(&rtc->lock, flags);
++
++	ppb_cor = (ccr & RTC_CCR_MODE ? 3815 : 954) * (s8)ccr;
++	/* ppb_cor + 1000000000L can never be zero */
++	*offset = armada38x_ppb_convert(ppb_cor);
++
++	return 0;
++}
++
++static int armada38x_rtc_set_offset(struct device *dev, long offset)
++{
++	struct armada38x_rtc *rtc = dev_get_drvdata(dev);
++	unsigned long ccr = 0;
++	long ppb_cor, off;
++
++	/*
++	 * The maximum ppb_cor is -128 * 3815 .. 127 * 3815, but we
++	 * need to clamp the input.  This equates to -484270 .. 488558.
++	 * Not only is this to stop out of range "off" but also to
++	 * avoid the division by zero in armada38x_ppb_convert().
++	 */
++	offset = clamp(offset, -484270L, 488558L);
++
++	ppb_cor = armada38x_ppb_convert(offset);
++
++	/*
++	 * Use low update mode where possible, which gives a better
++	 * resolution of correction.
++	 */
++	off = DIV_ROUND_CLOSEST(ppb_cor, 954);
++	if (off > 127 || off < -128) {
++		ccr = RTC_CCR_MODE;
++		off = DIV_ROUND_CLOSEST(ppb_cor, 3815);
++	}
++
++	/*
++	 * Armada 388 requires a bit pattern in bits 14..8 depending on
++	 * the sign bit: { 0, ~S, S, S, S, S, S }
++	 */
++	ccr |= (off & 0x3fff) ^ 0x2000;
++	rtc_delayed_write(ccr, rtc, RTC_CCR);
++
++	return 0;
++}
++
+ static const struct rtc_class_ops armada38x_rtc_ops = {
+ 	.read_time = armada38x_rtc_read_time,
+ 	.set_time = armada38x_rtc_set_time,
+ 	.read_alarm = armada38x_rtc_read_alarm,
+ 	.set_alarm = armada38x_rtc_set_alarm,
+ 	.alarm_irq_enable = armada38x_rtc_alarm_irq_enable,
++	.read_offset = armada38x_rtc_read_offset,
++	.set_offset = armada38x_rtc_set_offset,
+ };
+ 
+ static const struct rtc_class_ops armada38x_rtc_ops_noirq = {
+ 	.read_time = armada38x_rtc_read_time,
+ 	.set_time = armada38x_rtc_set_time,
+ 	.read_alarm = armada38x_rtc_read_alarm,
++	.read_offset = armada38x_rtc_read_offset,
++	.set_offset = armada38x_rtc_set_offset,
+ };
+ 
+ static const struct armada38x_rtc_data armada38x_data = {
diff --git a/target/linux/mvebu/patches-4.14/420-rtc-trimming-support.patch b/target/linux/mvebu/patches-4.14/420-rtc-trimming-support.patch
deleted file mode 100644
index 2974a69..0000000
--- a/target/linux/mvebu/patches-4.14/420-rtc-trimming-support.patch
+++ /dev/null
@@ -1,143 +0,0 @@ 
-commit f94ffbc2c2a4128c4412bb483d0807722dfb682b
-Author: Russell King <rmk+kernel@armlinux.org.uk>
-Date:   Fri Sep 29 11:23:31 2017 +0100
-
-    rtc: armada38x: add support for trimming the RTC
-    
-    Add support for trimming the RTC using the offset mechanism.  This RTC
-    supports two modes: low update mode and high update mode.  Low update
-    mode has finer precision than high update mode, so we use the low mode
-    where possible.
-    
-    Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
-    Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
-
---- a/drivers/rtc/rtc-armada38x.c
-+++ b/drivers/rtc/rtc-armada38x.c
-@@ -28,6 +28,8 @@
- #define RTC_IRQ_AL_EN		    BIT(0)
- #define RTC_IRQ_FREQ_EN		    BIT(1)
- #define RTC_IRQ_FREQ_1HZ	    BIT(2)
-+#define RTC_CCR		    0x18
-+#define RTC_CCR_MODE		    BIT(15)
- 
- #define RTC_TIME	    0xC
- #define RTC_ALARM1	    0x10
-@@ -343,18 +345,117 @@ static irqreturn_t armada38x_rtc_alarm_i
- 	return IRQ_HANDLED;
- }
- 
-+/*
-+ * The information given in the Armada 388 functional spec is complex.
-+ * They give two different formulas for calculating the offset value,
-+ * but when considering "Offset" as an 8-bit signed integer, they both
-+ * reduce down to (we shall rename "Offset" as "val" here):
-+ *
-+ *   val = (f_ideal / f_measured - 1) / resolution   where f_ideal = 32768
-+ *
-+ * Converting to time, f = 1/t:
-+ *   val = (t_measured / t_ideal - 1) / resolution   where t_ideal = 1/32768
-+ *
-+ *   =>  t_measured / t_ideal = val * resolution + 1
-+ *
-+ * "offset" in the RTC interface is defined as:
-+ *   t = t0 * (1 + offset * 1e-9)
-+ * where t is the desired period, t0 is the measured period with a zero
-+ * offset, which is t_measured above. With t0 = t_measured and t = t_ideal,
-+ *   offset = (t_ideal / t_measured - 1) / 1e-9
-+ *
-+ *   => t_ideal / t_measured = offset * 1e-9 + 1
-+ *
-+ * so:
-+ *
-+ *   offset * 1e-9 + 1 = 1 / (val * resolution + 1)
-+ *
-+ * We want "resolution" to be an integer, so resolution = R * 1e-9, giving
-+ *   offset = 1e18 / (val * R + 1e9) - 1e9
-+ *   val = (1e18 / (offset + 1e9) - 1e9) / R
-+ * with a common transformation:
-+ *   f(x) = 1e18 / (x + 1e9) - 1e9
-+ *   offset = f(val * R)
-+ *   val = f(offset) / R
-+ *
-+ * Armada 38x supports two modes, fine mode (954ppb) and coarse mode (3815ppb).
-+ */
-+static long armada38x_ppb_convert(long ppb)
-+{
-+	long div = ppb + 1000000000L;
-+
-+	return div_s64(1000000000000000000LL + div / 2, div) - 1000000000L;
-+}
-+
-+static int armada38x_rtc_read_offset(struct device *dev, long *offset)
-+{
-+	struct armada38x_rtc *rtc = dev_get_drvdata(dev);
-+	unsigned long ccr, flags;
-+	long ppb_cor;
-+
-+	spin_lock_irqsave(&rtc->lock, flags);
-+	ccr = rtc->data->read_rtc_reg(rtc, RTC_CCR);
-+	spin_unlock_irqrestore(&rtc->lock, flags);
-+
-+	ppb_cor = (ccr & RTC_CCR_MODE ? 3815 : 954) * (s8)ccr;
-+	/* ppb_cor + 1000000000L can never be zero */
-+	*offset = armada38x_ppb_convert(ppb_cor);
-+
-+	return 0;
-+}
-+
-+static int armada38x_rtc_set_offset(struct device *dev, long offset)
-+{
-+	struct armada38x_rtc *rtc = dev_get_drvdata(dev);
-+	unsigned long ccr = 0;
-+	long ppb_cor, off;
-+
-+	/*
-+	 * The maximum ppb_cor is -128 * 3815 .. 127 * 3815, but we
-+	 * need to clamp the input.  This equates to -484270 .. 488558.
-+	 * Not only is this to stop out of range "off" but also to
-+	 * avoid the division by zero in armada38x_ppb_convert().
-+	 */
-+	offset = clamp(offset, -484270L, 488558L);
-+
-+	ppb_cor = armada38x_ppb_convert(offset);
-+
-+	/*
-+	 * Use low update mode where possible, which gives a better
-+	 * resolution of correction.
-+	 */
-+	off = DIV_ROUND_CLOSEST(ppb_cor, 954);
-+	if (off > 127 || off < -128) {
-+		ccr = RTC_CCR_MODE;
-+		off = DIV_ROUND_CLOSEST(ppb_cor, 3815);
-+	}
-+
-+	/*
-+	 * Armada 388 requires a bit pattern in bits 14..8 depending on
-+	 * the sign bit: { 0, ~S, S, S, S, S, S }
-+	 */
-+	ccr |= (off & 0x3fff) ^ 0x2000;
-+	rtc_delayed_write(ccr, rtc, RTC_CCR);
-+
-+	return 0;
-+}
-+
- static const struct rtc_class_ops armada38x_rtc_ops = {
- 	.read_time = armada38x_rtc_read_time,
- 	.set_time = armada38x_rtc_set_time,
- 	.read_alarm = armada38x_rtc_read_alarm,
- 	.set_alarm = armada38x_rtc_set_alarm,
- 	.alarm_irq_enable = armada38x_rtc_alarm_irq_enable,
-+	.read_offset = armada38x_rtc_read_offset,
-+	.set_offset = armada38x_rtc_set_offset,
- };
- 
- static const struct rtc_class_ops armada38x_rtc_ops_noirq = {
- 	.read_time = armada38x_rtc_read_time,
- 	.set_time = armada38x_rtc_set_time,
- 	.read_alarm = armada38x_rtc_read_alarm,
-+	.read_offset = armada38x_rtc_read_offset,
-+	.set_offset = armada38x_rtc_set_offset,
- };
- 
- static const struct armada38x_rtc_data armada38x_data = {
diff --git a/target/linux/mvebu/patches-4.14/421-rtc-armada38x-reset-after-rtc-power-loss.patch b/target/linux/mvebu/patches-4.14/421-rtc-armada38x-reset-after-rtc-power-loss.patch
new file mode 100644
index 0000000..e9291c4
--- /dev/null
+++ b/target/linux/mvebu/patches-4.14/421-rtc-armada38x-reset-after-rtc-power-loss.patch
@@ -0,0 +1,78 @@ 
+From 1a990fefb641398fb580a0ea0be99b0ff27cbb9b Mon Sep 17 00:00:00 2001
+From: Baruch Siach <baruch@tkos.co.il>
+Date: Thu, 21 Jun 2018 20:40:23 +0300
+Subject: [PATCH] rtc: armada38x: reset after rtc power loss
+
+When the RTC block looses power it needs a reset sequence to make it
+usable again. Otherwise, writes to the time register have no effect.
+
+This reset sequence combines information from the mvebu_rtc driver in
+the Marvell provided U-Boot, and the SolidRun provided U-Boot repo.
+
+Tested on the Armada 388 based SolidRun Clearfog Base.
+
+Signed-off-by: Baruch Siach <baruch@tkos.co.il>
+Acked-by: Gregory CLEMENT <gregory.clement@bootlin.com>
+Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
+---
+ drivers/rtc/rtc-armada38x.c | 23 +++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c
+index 1e4978c..bde53c8c 100644
+--- a/drivers/rtc/rtc-armada38x.c
++++ b/drivers/rtc/rtc-armada38x.c
+@@ -30,6 +30,8 @@
+ #define RTC_IRQ_FREQ_1HZ	    BIT(2)
+ #define RTC_CCR		    0x18
+ #define RTC_CCR_MODE		    BIT(15)
++#define RTC_CONF_TEST	    0x1C
++#define RTC_NOMINAL_TIMING	    BIT(13)
+ 
+ #define RTC_TIME	    0xC
+ #define RTC_ALARM1	    0x10
+@@ -75,6 +77,7 @@ struct armada38x_rtc {
+ 	void __iomem	    *regs_soc;
+ 	spinlock_t	    lock;
+ 	int		    irq;
++	bool		    initialized;
+ 	struct value_to_freq *val_to_freq;
+ 	struct armada38x_rtc_data *data;
+ };
+@@ -226,6 +229,23 @@ static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm)
+ 	return 0;
+ }
+ 
++static void armada38x_rtc_reset(struct armada38x_rtc *rtc)
++{
++	u32 reg;
++
++	reg = rtc->data->read_rtc_reg(rtc, RTC_CONF_TEST);
++	/* If bits [7:0] are non-zero, assume RTC was uninitialized */
++	if (reg & 0xff) {
++		rtc_delayed_write(0, rtc, RTC_CONF_TEST);
++		msleep(500); /* Oscillator startup time */
++		rtc_delayed_write(0, rtc, RTC_TIME);
++		rtc_delayed_write(SOC_RTC_ALARM1 | SOC_RTC_ALARM2, rtc,
++				  RTC_STATUS);
++		rtc_delayed_write(RTC_NOMINAL_TIMING, rtc, RTC_CCR);
++	}
++	rtc->initialized = true;
++}
++
+ static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm)
+ {
+ 	struct armada38x_rtc *rtc = dev_get_drvdata(dev);
+@@ -237,6 +257,9 @@ static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm)
+ 	if (ret)
+ 		goto out;
+ 
++	if (!rtc->initialized)
++		armada38x_rtc_reset(rtc);
++
+ 	spin_lock_irqsave(&rtc->lock, flags);
+ 	rtc_delayed_write(time, rtc, RTC_TIME);
+ 	spin_unlock_irqrestore(&rtc->lock, flags);
+-- 
+2.7.4
+
diff --git a/target/linux/mvebu/patches-4.14/421-rtc-initialize.patch b/target/linux/mvebu/patches-4.14/421-rtc-initialize.patch
deleted file mode 100644
index 47a5acc..0000000
--- a/target/linux/mvebu/patches-4.14/421-rtc-initialize.patch
+++ /dev/null
@@ -1,74 +0,0 @@ 
-Some boards like the Turris Omnia have an RTC chip that does not get
-initialized. Initializing the RTC at the driver level helps get rid of
-bootloader hacks that write special register values.
-
---- a/drivers/rtc/rtc-armada38x.c
-+++ b/drivers/rtc/rtc-armada38x.c
-@@ -30,6 +30,9 @@
- #define RTC_IRQ_FREQ_1HZ	    BIT(2)
- #define RTC_CCR		    0x18
- #define RTC_CCR_MODE		    BIT(15)
-+#define RTC_CCR_NORMAL_PPB	    0x2000
-+#define RTC_TEST_CONF		    0x1c
-+#define RTC_TEST_CONF_MASK	    0xff
- 
- #define RTC_TIME	    0xC
- #define RTC_ALARM1	    0x10
-@@ -91,6 +94,7 @@ struct armada38x_rtc_data {
- 	void (*clear_isr)(struct armada38x_rtc *rtc);
- 	void (*unmask_interrupt)(struct armada38x_rtc *rtc);
- 	u32 alarm;
-+	void (*init_rtc)(struct armada38x_rtc *rtc);
- };
- 
- /*
-@@ -202,6 +206,23 @@ static void armada38x_unmask_interrupt(s
- 	writel(val | SOC_RTC_ALARM1_MASK, rtc->regs_soc + SOC_RTC_INTERRUPT);
- }
- 
-+static void armada38x_rtc_init(struct armada38x_rtc *rtc)
-+{
-+	u32 reg;
-+
-+	/* Test RTC test configuration register bits [7:0] */
-+	reg = readl(rtc->regs + RTC_TEST_CONF);
-+	/* If bits [7:0] are non-zero, assume RTC was uninitialized */
-+	if (reg & RTC_TEST_CONF_MASK) {
-+		rtc_delayed_write(0, rtc, RTC_TEST_CONF);
-+		rtc_delayed_write(0, rtc, RTC_TIME);
-+		rtc_delayed_write((RTC_STATUS_ALARM1 | RTC_STATUS_ALARM2),
-+				rtc, RTC_STATUS);
-+		rtc_delayed_write(RTC_CCR_NORMAL_PPB, rtc, RTC_CCR);
-+	}
-+	return;
-+}
-+
- static void armada8k_clear_isr(struct armada38x_rtc *rtc)
- {
- 	writel(RTC_8K_ALARM2, rtc->regs_soc + RTC_8K_ISR);
-@@ -464,6 +485,7 @@ static const struct armada38x_rtc_data a
- 	.clear_isr = armada38x_clear_isr,
- 	.unmask_interrupt = armada38x_unmask_interrupt,
- 	.alarm = ALARM1,
-+	.init_rtc = armada38x_rtc_init,
- };
- 
- static const struct armada38x_rtc_data armada8k_data = {
-@@ -558,6 +580,17 @@ static __init int armada38x_rtc_probe(st
- 		dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
- 		return ret;
- 	}
-+
-+	/*
-+	 * Try to detect if RTC is in uninitialized state.
-+	 * It is not definitive to know if the RTC is in an uninialized state or not,
-+	 * but the following call will read some bits in the RTC unit and guess if
-+	 * if it's in that state, and accordingly set it to sane default values.
-+	 */
-+	if (rtc->data->init_rtc) {
-+		rtc->data->init_rtc(rtc);
-+	}
-+
- 	return 0;
- }
-