Skip to contentSkip to conversation

arm64: dts: qcom: x1e80100: enable rtc

PATCH Applied Johan Hovold 4 participants 12 messages Feb 19, 2025 – Mar 17, 2025

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

v2 cover arm64: dts: qcom: x1e80100: enable rtc

This series adds support for utilising the UEFI firmware RTC offset to the Qualcomm PMIC RTC driver and uses that to enable the RTC on all X Elite machines.

Included is also a patch to switch the Lenovo ThinkPad X13s over to using the UEFI offset.

The RTCs in many Qualcomm devices are effectively broken due to the time registers being read-only. Instead some other non-volatile memory can be used to store an offset which a driver can take into account. On Windows on Arm laptops, the UEFI firmware (and Windows) use a UEFI variable for storing such an offset.

When RTC support for the X13s was added two years ago we did not yet have UEFI variable support for these machines in mainline and there were also some concerns regarding flash wear. [1] As not all Qualcomm platforms have UEFI firmware anyway, we instead opted to use a PMIC scratch register for storing the offset. [2]

On the UEFI machines in question this is however arguably not correct as it means that the RTC time can differ between the UEFI firmware (and Windows) and Linux.

Now that the (reverse engineered) UEFI variable implementation has been merged and thoroughly tested, let's switch to using that to store the RTC offset also on Linux. The flash wear concerns can be mitigated by deferring writes due to clock drift until shutdown.

Note that this also avoids having to wait for months for Qualcomm to provide a free PMIC SDAM scratch register for X1E and future platforms, and specifically allows us to enable the RTC on X1E laptops today.

The first version of this series (and the RFC) used a DT property to determine whether the UEFI firmware uses a variable for storing the RTC offset. This is strictly only needed if we ever are to allow (further) modular efivars implementations as otherwise a driver can just check if the variable is there during probe (and assume efivars are available at module init time).

The Qualcomm efivars implementation (qcom_qseecom_uefisecapp) cannot be built as a module currently to avoid similar problems with user space expecting efivarfs to be available during early boot. As changing this now would cause a regression, let's assume at least the Qualcomm implementation will remain built-in indefinitely.

Hopefully this all goes away (for future platforms) once Qualcomm fix their UEFI implementation so that the UEFI time (and variable) services can be used directly.

Johan

Changes in v2
- drop DT property in favour of probing for the UEFI variable (Rob)
- rebase on 6.14-rc1; use bool constant for device_init_wakeup()
- fix flash wear commit message (X13s typo, example)

Changes since UEFI offset RFC [1]:
- clarify that UEFI variable format is not arbitrary (Alexandre)
- add missing use_uefi kernel doc
- use dev_dbg() instead of dev_err() (Alexandre)
- rename epoch define RTC_TIMESTAMP_EPOCH_GPS (Alexandre)
- mitigate flash wear by deferring writes due to clock drift until shutdown

Changes since Jonathan's X1E series v3 [3]:
- tweak qcom,no-alarm binding update (and drop Krystzof's Reviewed-by tag)
- drop no-alarm flag and restructure probe() to clear feature flag before registering RTC
- use UEFI variable offset on X1E

[1] https://lore.kernel.org/lkml/[email protected]/
[2] https://lore.kernel.org/lkml/[email protected]/
[3] https://lore.kernel.org/lkml/[email protected]/

Johan Hovold (4):
rtc: pm8xxx: add support for uefi offset
rtc: pm8xxx: mitigate flash wear
arm64: dts: qcom: sc8280xp-x13s: switch to uefi rtc offset
arm64: dts: qcom: x1e80100: enable rtc

Jonathan Marek (2):
dt-bindings: rtc: qcom-pm8xxx: document qcom,no-alarm flag
rtc: pm8xxx: implement qcom,no-alarm flag for non-HLOS owned alarm

 .../bindings/rtc/qcom-pm8xxx-rtc.yaml         |   5 +
 .../qcom/sc8280xp-lenovo-thinkpad-x13s.dts    |  11 -
 arch/arm64/boot/dts/qcom/x1e80100-pmics.dtsi  |   3 +-
 drivers/rtc/rtc-pm8xxx.c                      | 225 ++++++++++++++----
 include/linux/rtc.h                           |   1 +
 5 files changed, 189 insertions(+), 56 deletions(-)
Signature · 1 line
2.45.3
#1 lore raw

PATCH v2 1/6 dt-bindings: rtc: qcom-pm8xxx: document qcom,no-alarm flag

From: Jonathan Marek <[email protected]>

Qualcomm x1e80100 firmware sets the ownership of the RTC alarm to ADSP. Thus writing to RTC alarm registers and receiving alarm interrupts is not possible.

Add a qcom,no-alarm flag to support RTC on this platform.

[ johan: move vendor property; use boolean; reword description ]
---
 Documentation/devicetree/bindings/rtc/qcom-pm8xxx-rtc.yaml | 5 +++++
 1 file changed, 5 insertions(+)
Documentation/devicetree/bindings/rtc/qcom-pm8xxx-rtc.yaml +5 -0
index d274bb7a534b..68ef3208c886 100644
@@ -50,6 +50,11 @@ properties:
     items:
       - const: offset
 
+  qcom,no-alarm:
+    type: boolean
+    description:
+      RTC alarm is not owned by the OS
+
   wakeup-source: true
 
 required:
Signature · 1 line
2.45.3
#2 lore raw

PATCH v2 2/6 rtc: pm8xxx: add support for uefi offset

In reply to Johan Hovold

On many Qualcomm platforms the PMIC RTC control and time registers are read-only so that the RTC time can not be updated. Instead an offset needs be stored in some machine-specific non-volatile memory, which the driver can take into account.

Add support for storing a 32-bit offset from the GPS time epoch in a UEFI variable so that the RTC time can be set on such platforms.

The UEFI variable is

            882f8c2b-9646-435f-8de5-f208ff80c1bd-RTCInfo

and holds a 12-byte structure where the first four bytes is a GPS time offset in little-endian byte order.

Note that this format is not arbitrary as the variable is shared with the UEFI firmware (and Windows).

---
 drivers/rtc/rtc-pm8xxx.c | 156 +++++++++++++++++++++++++++++++++------
 include/linux/rtc.h      |   1 +
 2 files changed, 133 insertions(+), 24 deletions(-)
drivers/rtc/rtc-pm8xxx.c +132 -24
index b2518aea4218..e68b10aa5352 100644
@@ -5,6 +5,7 @@
  * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
  * Copyright (c) 2023, Linaro Limited
  */
+#include <linux/efi.h>
 #include <linux/of.h>
 #include <linux/module.h>
 #include <linux/nvmem-consumer.h>
@@ -16,9 +17,10 @@
 #include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
-
 #include <linux/unaligned.h>
 
+#include <asm/byteorder.h>
+
 /* RTC_CTRL register bit fields */
 #define PM8xxx_RTC_ENABLE		BIT(7)
 #define PM8xxx_RTC_ALARM_CLEAR		BIT(0)
@@ -46,14 +48,21 @@ struct pm8xxx_rtc_regs {
 	unsigned int alarm_en;
 };
 
+struct qcom_uefi_rtc_info {
+	__le32	offset_gps;
+	u8	reserved[8];
+} __packed;
+
 /**
  * struct pm8xxx_rtc -  RTC driver internal structure
  * @rtc:		RTC device
  * @regmap:		regmap used to access registers
  * @allow_set_time:	whether the time can be set
+ * @use_uefi:		use UEFI variable as fallback for offset
  * @alarm_irq:		alarm irq number
  * @regs:		register description
  * @dev:		device structure
+ * @rtc_info:		qcom uefi rtc-info structure
  * @nvmem_cell:		nvmem cell for offset
  * @offset:		offset from epoch in seconds
  */
@@ -61,13 +70,101 @@ struct pm8xxx_rtc {
 	struct rtc_device *rtc;
 	struct regmap *regmap;
 	bool allow_set_time;
+	bool use_uefi;
 	int alarm_irq;
 	const struct pm8xxx_rtc_regs *regs;
 	struct device *dev;
+	struct qcom_uefi_rtc_info rtc_info;
 	struct nvmem_cell *nvmem_cell;
 	u32 offset;
 };
 
+#ifdef CONFIG_EFI
+
+MODULE_IMPORT_NS("EFIVAR");
+
+#define QCOM_UEFI_NAME	L"RTCInfo"
+#define QCOM_UEFI_GUID	EFI_GUID(0x882f8c2b, 0x9646, 0x435f, \
+				 0x8d, 0xe5, 0xf2, 0x08, 0xff, 0x80, 0xc1, 0xbd)
+#define QCOM_UEFI_ATTRS	(EFI_VARIABLE_NON_VOLATILE | \
+			 EFI_VARIABLE_BOOTSERVICE_ACCESS | \
+			 EFI_VARIABLE_RUNTIME_ACCESS)
+
+static int pm8xxx_rtc_read_uefi_offset(struct pm8xxx_rtc *rtc_dd)
+{
+	struct qcom_uefi_rtc_info *rtc_info = &rtc_dd->rtc_info;
+	unsigned long size = sizeof(*rtc_info);
+	struct device *dev = rtc_dd->dev;
+	efi_status_t status;
+	u32 offset_gps;
+	int rc;
+
+	rc = efivar_lock();
+	if (rc)
+		return rc;
+
+	status = efivar_get_variable(QCOM_UEFI_NAME, &QCOM_UEFI_GUID, NULL,
+				     &size, rtc_info);
+	efivar_unlock();
+
+	if (status != EFI_SUCCESS) {
+		dev_dbg(dev, "failed to read UEFI offset: %lu\n", status);
+		return efi_status_to_err(status);
+	}
+
+	if (size != sizeof(*rtc_info)) {
+		dev_dbg(dev, "unexpected UEFI structure size %lu\n", size);
+		return -EINVAL;
+	}
+
+	dev_dbg(dev, "uefi_rtc_info = %*ph\n", (int)size, rtc_info);
+
+	/* Convert from GPS to Unix time offset */
+	offset_gps = le32_to_cpu(rtc_info->offset_gps);
+	rtc_dd->offset = offset_gps + (u32)RTC_TIMESTAMP_EPOCH_GPS;
+
+	return 0;
+}
+
+static int pm8xxx_rtc_write_uefi_offset(struct pm8xxx_rtc *rtc_dd, u32 offset)
+{
+	struct qcom_uefi_rtc_info *rtc_info = &rtc_dd->rtc_info;
+	unsigned long size = sizeof(*rtc_info);
+	struct device *dev = rtc_dd->dev;
+	efi_status_t status;
+	u32 offset_gps;
+
+	/* Convert from Unix to GPS time offset */
+	offset_gps = offset - (u32)RTC_TIMESTAMP_EPOCH_GPS;
+
+	rtc_info->offset_gps = cpu_to_le32(offset_gps);
+
+	dev_dbg(dev, "efi_rtc_info = %*ph\n", (int)size, rtc_info);
+
+	status = efivar_set_variable(QCOM_UEFI_NAME, &QCOM_UEFI_GUID,
+				     QCOM_UEFI_ATTRS, size, rtc_info);
+	if (status != EFI_SUCCESS) {
+		dev_dbg(dev, "failed to write UEFI offset: %lx\n", status);
+		return efi_status_to_err(status);
+	}
+
+	return 0;
+}
+
+#else	/* CONFIG_EFI */
+
+static int pm8xxx_rtc_read_uefi_offset(struct pm8xxx_rtc *rtc_dd)
+{
+	return -ENODEV;
+}
+
+static int pm8xxx_rtc_write_uefi_offset(struct pm8xxx_rtc *rtc_dd, u32 offset)
+{
+	return -ENODEV;
+}
+
+#endif	/* CONFIG_EFI */
+
 static int pm8xxx_rtc_read_nvmem_offset(struct pm8xxx_rtc *rtc_dd)
 {
 	size_t len;
@@ -110,14 +207,6 @@ static int pm8xxx_rtc_write_nvmem_offset(struct pm8xxx_rtc *rtc_dd, u32 offset)
 	return 0;
 }
 
-static int pm8xxx_rtc_read_offset(struct pm8xxx_rtc *rtc_dd)
-{
-	if (!rtc_dd->nvmem_cell)
-		return 0;
-
-	return pm8xxx_rtc_read_nvmem_offset(rtc_dd);
-}
-
 static int pm8xxx_rtc_read_raw(struct pm8xxx_rtc *rtc_dd, u32 *secs)
 {
 	const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
@@ -155,7 +244,7 @@ static int pm8xxx_rtc_update_offset(struct pm8xxx_rtc *rtc_dd, u32 secs)
 	u32 offset;
 	int rc;
 
-	if (!rtc_dd->nvmem_cell)
+	if (!rtc_dd->nvmem_cell && !rtc_dd->use_uefi)
 		return -ENODEV;
 
 	rc = pm8xxx_rtc_read_raw(rtc_dd, &raw_secs);
@@ -167,7 +256,11 @@ static int pm8xxx_rtc_update_offset(struct pm8xxx_rtc *rtc_dd, u32 secs)
 	if (offset == rtc_dd->offset)
 		return 0;
 
-	rc = pm8xxx_rtc_write_nvmem_offset(rtc_dd, offset);
+	if (rtc_dd->nvmem_cell)
+		rc = pm8xxx_rtc_write_nvmem_offset(rtc_dd, offset);
+	else
+		rc = pm8xxx_rtc_write_uefi_offset(rtc_dd, offset);
+
 	if (rc)
 		return rc;
 
@@ -455,6 +548,30 @@ static const struct of_device_id pm8xxx_id_table[] = {
 };
 MODULE_DEVICE_TABLE(of, pm8xxx_id_table);
 
+static int pm8xxx_rtc_probe_offset(struct pm8xxx_rtc *rtc_dd)
+{
+	int rc;
+
+	rtc_dd->nvmem_cell = devm_nvmem_cell_get(rtc_dd->dev, "offset");
+	if (IS_ERR(rtc_dd->nvmem_cell)) {
+		rc = PTR_ERR(rtc_dd->nvmem_cell);
+		if (rc != -ENOENT)
+			return rc;
+		rtc_dd->nvmem_cell = NULL;
+	} else {
+		return pm8xxx_rtc_read_nvmem_offset(rtc_dd);
+	}
+
+	/* Use UEFI storage as fallback if available */
+	if (efivar_is_available()) {
+		rc = pm8xxx_rtc_read_uefi_offset(rtc_dd);
+		if (rc == 0)
+			rtc_dd->use_uefi = true;
+	}
+
+	return 0;
+}
+
 static int pm8xxx_rtc_probe(struct platform_device *pdev)
 {
 	const struct of_device_id *match;
@@ -469,6 +586,9 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
 	if (rtc_dd == NULL)
 		return -ENOMEM;
 
+	rtc_dd->regs = match->data;
+	rtc_dd->dev = &pdev->dev;
+
 	rtc_dd->regmap = dev_get_regmap(pdev->dev.parent, NULL);
 	if (!rtc_dd->regmap)
 		return -ENXIO;
@@ -479,20 +599,8 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
 
 	rtc_dd->allow_set_time = of_property_read_bool(pdev->dev.of_node,
 						      "allow-set-time");
-
-	rtc_dd->nvmem_cell = devm_nvmem_cell_get(&pdev->dev, "offset");
-	if (IS_ERR(rtc_dd->nvmem_cell)) {
-		rc = PTR_ERR(rtc_dd->nvmem_cell);
-		if (rc != -ENOENT)
-			return rc;
-		rtc_dd->nvmem_cell = NULL;
-	}
-
-	rtc_dd->regs = match->data;
-	rtc_dd->dev = &pdev->dev;
-
 	if (!rtc_dd->allow_set_time) {
-		rc = pm8xxx_rtc_read_offset(rtc_dd);
+		rc = pm8xxx_rtc_probe_offset(rtc_dd);
 		if (rc)
 			return rc;
 	}
include/linux/rtc.h +1 -0
index 3f4d315aaec9..95da051fb155 100644
@@ -170,6 +170,7 @@ struct rtc_device {
 /* useful timestamps */
 #define RTC_TIMESTAMP_BEGIN_0000	-62167219200ULL /* 0000-01-01 00:00:00 */
 #define RTC_TIMESTAMP_BEGIN_1900	-2208988800LL /* 1900-01-01 00:00:00 */
+#define RTC_TIMESTAMP_EPOCH_GPS		315964800LL /* 1980-01-06 00:00:00 */
 #define RTC_TIMESTAMP_BEGIN_2000	946684800LL /* 2000-01-01 00:00:00 */
 #define RTC_TIMESTAMP_END_2063		2966371199LL /* 2063-12-31 23:59:59 */
 #define RTC_TIMESTAMP_END_2079		3471292799LL /* 2079-12-31 23:59:59 */
Signature · 1 line
2.45.3
#3 lore raw

PATCH v2 3/6 rtc: pm8xxx: mitigate flash wear

In reply to Johan Hovold

On many Qualcomm platforms the PMIC RTC control and time registers are read-only so that the RTC time can not be updated. Instead an offset needs be stored in some machine-specific non-volatile memory, which the driver can take into account.

On machines like the Lenovo ThinkPad X13s the PMIC RTC drifts about one second every 3.5 hours, something which leads to repeated updates of the offset when NTP synchronisation is enabled.

Reduce wear of the underlying flash storage (used for UEFI variables) by deferring writes until shutdown in case they appear to be due to clock drift.

As an example, deferring writes when the new offset differs up to 30 s from the previous one reduces the number of writes on the X13s during a ten day session with the machine not suspending for more than four days in a row from up to 68 writes (every 3.5 h) to at most two (boot and shutdown).

---
 drivers/rtc/rtc-pm8xxx.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)
drivers/rtc/rtc-pm8xxx.c +26 -0
index e68b10aa5352..68140ac39365 100644
@@ -65,6 +65,7 @@ struct qcom_uefi_rtc_info {
  * @rtc_info:		qcom uefi rtc-info structure
  * @nvmem_cell:		nvmem cell for offset
  * @offset:		offset from epoch in seconds
+ * @offset_dirty:	offset needs to be stored on shutdown
  */
 struct pm8xxx_rtc {
 	struct rtc_device *rtc;
@@ -77,6 +78,7 @@ struct pm8xxx_rtc {
 	struct qcom_uefi_rtc_info rtc_info;
 	struct nvmem_cell *nvmem_cell;
 	u32 offset;
+	bool offset_dirty;
 };
 
 #ifdef CONFIG_EFI
@@ -256,6 +258,15 @@ static int pm8xxx_rtc_update_offset(struct pm8xxx_rtc *rtc_dd, u32 secs)
 	if (offset == rtc_dd->offset)
 		return 0;
 
+	/*
+	 * Reduce flash wear by deferring updates due to clock drift until
+	 * shutdown.
+	 */
+	if (abs_diff(offset, rtc_dd->offset) < 30) {
+		rtc_dd->offset_dirty = true;
+		goto out;
+	}
+
 	if (rtc_dd->nvmem_cell)
 		rc = pm8xxx_rtc_write_nvmem_offset(rtc_dd, offset);
 	else
@@ -264,6 +275,8 @@ static int pm8xxx_rtc_update_offset(struct pm8xxx_rtc *rtc_dd, u32 secs)
 	if (rc)
 		return rc;
 
+	rtc_dd->offset_dirty = false;
+out:
 	rtc_dd->offset = offset;
 
 	return 0;
@@ -643,9 +656,22 @@ static void pm8xxx_remove(struct platform_device *pdev)
 	dev_pm_clear_wake_irq(&pdev->dev);
 }
 
+static void pm8xxx_shutdown(struct platform_device *pdev)
+{
+	struct pm8xxx_rtc *rtc_dd = platform_get_drvdata(pdev);
+
+	if (rtc_dd->offset_dirty) {
+		if (rtc_dd->nvmem_cell)
+			pm8xxx_rtc_write_nvmem_offset(rtc_dd, rtc_dd->offset);
+		else
+			pm8xxx_rtc_write_uefi_offset(rtc_dd, rtc_dd->offset);
+	}
+}
+
 static struct platform_driver pm8xxx_rtc_driver = {
 	.probe		= pm8xxx_rtc_probe,
 	.remove		= pm8xxx_remove,
+	.shutdown	= pm8xxx_shutdown,
 	.driver	= {
 		.name		= "rtc-pm8xxx",
 		.of_match_table	= pm8xxx_id_table,
Signature · 1 line
2.45.3
#4 lore raw

PATCH v2 4/6 rtc: pm8xxx: implement qcom,no-alarm flag for non-HLOS owned alarm

In reply to Johan Hovold

From: Jonathan Marek <[email protected]>

Qualcomm x1e80100 firmware sets the ownership of the RTC alarm to ADSP. Thus writing to RTC alarm registers and receiving alarm interrupts is not possible.

Add a qcom,no-alarm flag to support RTC on this platform.

---
 drivers/rtc/rtc-pm8xxx.c | 43 ++++++++++++++++++++++------------------
 1 file changed, 24 insertions(+), 19 deletions(-)
drivers/rtc/rtc-pm8xxx.c +24 -19
index 68140ac39365..14707e21f343 100644
@@ -606,9 +606,11 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
 	if (!rtc_dd->regmap)
 		return -ENXIO;
 
-	rtc_dd->alarm_irq = platform_get_irq(pdev, 0);
-	if (rtc_dd->alarm_irq < 0)
-		return -ENXIO;
+	if (!of_property_read_bool(pdev->dev.of_node, "qcom,no-alarm")) {
+		rtc_dd->alarm_irq = platform_get_irq(pdev, 0);
+		if (rtc_dd->alarm_irq < 0)
+			return -ENXIO;
+	}
 
 	rtc_dd->allow_set_time = of_property_read_bool(pdev->dev.of_node,
 						      "allow-set-time");
@@ -624,8 +626,6 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, rtc_dd);
 
-	device_init_wakeup(&pdev->dev, true);
-
 	rtc_dd->rtc = devm_rtc_allocate_device(&pdev->dev);
 	if (IS_ERR(rtc_dd->rtc))
 		return PTR_ERR(rtc_dd->rtc);
@@ -633,27 +633,32 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
 	rtc_dd->rtc->ops = &pm8xxx_rtc_ops;
 	rtc_dd->rtc->range_max = U32_MAX;
 
-	rc = devm_request_any_context_irq(&pdev->dev, rtc_dd->alarm_irq,
-					  pm8xxx_alarm_trigger,
-					  IRQF_TRIGGER_RISING,
-					  "pm8xxx_rtc_alarm", rtc_dd);
-	if (rc < 0)
-		return rc;
+	if (rtc_dd->alarm_irq) {
+		rc = devm_request_any_context_irq(&pdev->dev, rtc_dd->alarm_irq,
+						  pm8xxx_alarm_trigger,
+						  IRQF_TRIGGER_RISING,
+						  "pm8xxx_rtc_alarm", rtc_dd);
+		if (rc < 0)
+			return rc;
 
-	rc = devm_rtc_register_device(rtc_dd->rtc);
-	if (rc)
-		return rc;
+		rc = dev_pm_set_wake_irq(&pdev->dev, rtc_dd->alarm_irq);
+		if (rc)
+			return rc;
 
-	rc = dev_pm_set_wake_irq(&pdev->dev, rtc_dd->alarm_irq);
-	if (rc)
-		return rc;
+		device_init_wakeup(&pdev->dev, true);
+	} else {
+		clear_bit(RTC_FEATURE_ALARM, rtc_dd->rtc->features);
+	}
 
-	return 0;
+	return devm_rtc_register_device(rtc_dd->rtc);
 }
 
 static void pm8xxx_remove(struct platform_device *pdev)
 {
-	dev_pm_clear_wake_irq(&pdev->dev);
+	struct pm8xxx_rtc *rtc_dd = platform_get_drvdata(pdev);
+
+	if (rtc_dd->alarm_irq)
+		dev_pm_clear_wake_irq(&pdev->dev);
 }
 
 static void pm8xxx_shutdown(struct platform_device *pdev)
Signature · 1 line
2.45.3
#5 lore raw

PATCH v2 5/6 arm64: dts: qcom: sc8280xp-x13s: switch to uefi rtc offset

In reply to Johan Hovold

On many Qualcomm platforms the PMIC RTC control and time registers are read-only so that the RTC time can not be updated. Instead an offset needs be stored in some machine-specific non-volatile memory, which a driver can take into account.

Switch to using the Qualcomm specific UEFI variable that is used by the UEFI firmware (and Windows) to store the RTC offset.

This specifically means that the RTC time will be synchronised between the UEFI firmware setup (or UEFI shell), Windows and Linux.

Note however that Windows stores the RTC time in local time by default, while Linux typically uses UTC (i.e. as on X86).

---
 .../boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts   | 11 -----------
 1 file changed, 11 deletions(-)
arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts +0 -11
index 38d911992475..8000254f4db5 100644
@@ -1090,18 +1090,7 @@ &pmk8280_pon_resin {
 };
 
 &pmk8280_rtc {
-	nvmem-cells = <&rtc_offset>;
-	nvmem-cell-names = "offset";
-
-	status = "okay";
-};
-
-&pmk8280_sdam_6 {
 	status = "okay";
-
-	rtc_offset: rtc-offset@bc {
-		reg = <0xbc 0x4>;
-	};
 };
 
 &pmk8280_vadc {
Signature · 1 line
2.45.3
#6 lore raw

PATCH v2 6/6 arm64: dts: qcom: x1e80100: enable rtc

In reply to Johan Hovold

On many Qualcomm platforms the PMIC RTC control and time registers are read-only so that the RTC time can not be updated. Instead an offset needs be stored in some machine-specific non-volatile memory, which a driver can take into account.

On X1E based Windows on Arm machines the offset is stored in a Qualcomm specific UEFI variable.

Unlike on previous platforms the alarm registers are also unaccessible on X1E as they are owned by the ADSP.

Assume all X1E machines use similar firmware and enable the RTC in the PMIC dtsi for now.

Based on a patch by Jonathan Marek. [1]

---
 arch/arm64/boot/dts/qcom/x1e80100-pmics.dtsi | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
arch/arm64/boot/dts/qcom/x1e80100-pmics.dtsi +1 -2
index d7a2a2b8fc6c..a59aa8e7642d 100644
@@ -223,8 +223,7 @@ pmk8550_rtc: rtc@6100 {
 			reg = <0x6100>, <0x6200>;
 			reg-names = "rtc", "alarm";
 			interrupts = <0x0 0x62 0x1 IRQ_TYPE_EDGE_RISING>;
-			/* Not yet sure what blocks access */
-			status = "reserved";
+			qcom,no-alarm; /* alarm owned by ADSP */
 		};
 
 		pmk8550_sdam_2: nvram@7100 {
Signature · 1 line
2.45.3
#7 lore raw
In reply to Johan Hovold

Hi Alexandre,

Quoted 3 lines · Johan Hovold

This series adds support for utilising the UEFI firmware RTC offset to the Qualcomm PMIC RTC driver and uses that to enable the RTC on all X Elite machines.

Do you think you could pick up the driver and binding changes here so that Bjorn can take the DT patches for 6.15?

Quoted 9 lines

Johan Hovold (4):
rtc: pm8xxx: add support for uefi offset
rtc: pm8xxx: mitigate flash wear
arm64: dts: qcom: sc8280xp-x13s: switch to uefi rtc offset
arm64: dts: qcom: x1e80100: enable rtc

Jonathan Marek (2):
dt-bindings: rtc: qcom-pm8xxx: document qcom,no-alarm flag
rtc: pm8xxx: implement qcom,no-alarm flag for non-HLOS owned alarm

Johan

#8 lore raw
Quoted 9 lines · Johan Hovold

Hi Alexandre,

Quoted 3 lines · Johan Hovold

This series adds support for utilising the UEFI firmware RTC offset to the Qualcomm PMIC RTC driver and uses that to enable the RTC on all X Elite machines.

Do you think you could pick up the driver and binding changes here so that Bjorn can take the DT patches for 6.15?

This is taken now but I had to rebase on top of patches I already took, please verify.

Quoted 12 lines
Quoted 10 lines

Johan Hovold (4):
rtc: pm8xxx: add support for uefi offset
rtc: pm8xxx: mitigate flash wear
arm64: dts: qcom: sc8280xp-x13s: switch to uefi rtc offset
arm64: dts: qcom: x1e80100: enable rtc

Jonathan Marek (2):
dt-bindings: rtc: qcom-pm8xxx: document qcom,no-alarm flag
rtc: pm8xxx: implement qcom,no-alarm flag for non-HLOS owned alarm

Johan

Signature · 3 lines
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
#9 lore raw
Quoted 8 lines · Alexandre Belloni
Quoted 7 lines · Johan Hovold

Hi Alexandre,

Quoted 3 lines · Johan Hovold

This series adds support for utilising the UEFI firmware RTC offset to the Qualcomm PMIC RTC driver and uses that to enable the RTC on all X Elite machines.

Quoted 5 lines
Quoted 2 lines

Do you think you could pick up the driver and binding changes here so that Bjorn can take the DT patches for 6.15?

This is taken now but I had to rebase on top of patches I already took, please verify.

Looks good except for the device_init_wakeup() call which you had converted to devm_device_init_wakeup(). I'll comment on your follow-up fix directly.

Thanks!

Johan

maintainer Applied
#10 lore raw

Re: (subset) [PATCH v2 0/6] arm64: dts: qcom: x1e80100: enable rtc

In reply to Johan Hovold
Quoted 8 lines · Johan Hovold

This series adds support for utilising the UEFI firmware RTC offset to the Qualcomm PMIC RTC driver and uses that to enable the RTC on all X Elite machines.

Included is also a patch to switch the Lenovo ThinkPad X13s over to using the UEFI offset.

[...]

Applied, thanks!

[1/6] dt-bindings: rtc: qcom-pm8xxx: document qcom,no-alarm flag

      https://git.kernel.org/abelloni/c/931a88914ad6
[2/6] rtc: pm8xxx: add support for uefi offset
      https://git.kernel.org/abelloni/c/bba38b874886
[3/6] rtc: pm8xxx: mitigate flash wear
      https://git.kernel.org/abelloni/c/e853658de5ef
[4/6] rtc: pm8xxx: implement qcom,no-alarm flag for non-HLOS owned alarm
      https://git.kernel.org/abelloni/c/28e5a73479fc

Best regards,

Signature · 3 lines
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
maintainer Applied
#11 lore raw

Re: (subset) [PATCH v2 0/6] arm64: dts: qcom: x1e80100: enable rtc

In reply to Johan Hovold
Quoted 8 lines · Johan Hovold

This series adds support for utilising the UEFI firmware RTC offset to the Qualcomm PMIC RTC driver and uses that to enable the RTC on all X Elite machines.

Included is also a patch to switch the Lenovo ThinkPad X13s over to using the UEFI offset.

[...]

Applied, thanks!

[5/6] arm64: dts: qcom: sc8280xp-x13s: switch to uefi rtc offset

      commit: 409803681a55e061f5ea6be82f05f14c0b9c707e
[6/6] arm64: dts: qcom: x1e80100: enable rtc
      commit: b53c2c23d3c2e50473c0be17a392d4b03a296b52

Best regards,

Signature · 1 line
Bjorn Andersson <[email protected]>