From: Alexandre Belloni <alexandre.belloni@bootlin.com>
To: Johan Hovold <johan+linaro@kernel.org>
Cc: Bjorn Andersson <andersson@kernel.org>,
Andy Gross <agross@kernel.org>,
Konrad Dybcio <konrad.dybcio@linaro.org>,
Alessandro Zummo <a.zummo@towertech.it>,
Rob Herring <robh+dt@kernel.org>,
Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>,
Maximilian Luz <luzmaximilian@gmail.com>,
linux-arm-msm@vger.kernel.org, linux-rtc@vger.kernel.org,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH 19/24] rtc: pm8xxx: add support for uefi offset
Date: Fri, 27 Jan 2023 16:19:18 +0100 [thread overview]
Message-ID: <Y9PrdqLHZpZrdGJ4@mail.local> (raw)
In-Reply-To: <20230126142057.25715-20-johan+linaro@kernel.org>
On 26/01/2023 15:20:52+0100, Johan Hovold wrote:
> 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.
>
Why are you using the GPS epoch? This seems pretty random.
> 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.
>
> Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
> ---
> drivers/rtc/rtc-pm8xxx.c | 122 +++++++++++++++++++++++++++++++++++++--
> include/linux/rtc.h | 1 +
> 2 files changed, 119 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c
> index 25bdd804b4d2..6c2324baeec6 100644
> --- a/drivers/rtc/rtc-pm8xxx.c
> +++ b/drivers/rtc/rtc-pm8xxx.c
> @@ -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>
> @@ -17,6 +18,7 @@
> #include <linux/slab.h>
> #include <linux/spinlock.h>
>
> +#include <asm/byteorder.h>
> #include <asm/unaligned.h>
>
> /* RTC_CTRL register bit fields */
> @@ -46,6 +48,11 @@ 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
> @@ -54,6 +61,7 @@ struct pm8xxx_rtc_regs {
> * @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 +69,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_err(dev, "failed to read UEFI offset: %lu\n", status);
> + return efi_status_to_err(status);
> + }
> +
> + if (size != sizeof(*rtc_info)) {
> + dev_err(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_BEGIN_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_BEGIN_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_err(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;
> @@ -112,10 +208,13 @@ static int pm8xxx_rtc_write_nvmem_offset(struct pm8xxx_rtc *rtc_dd, u32 offset)
>
> static int pm8xxx_rtc_read_offset(struct pm8xxx_rtc *rtc_dd)
> {
> - if (!rtc_dd->nvmem_cell)
> + if (!rtc_dd->nvmem_cell && !rtc_dd->use_uefi)
> return 0;
>
> - return pm8xxx_rtc_read_nvmem_offset(rtc_dd);
> + if (rtc_dd->nvmem_cell)
> + return pm8xxx_rtc_read_nvmem_offset(rtc_dd);
> + else
> + return pm8xxx_rtc_read_uefi_offset(rtc_dd);
> }
>
> static int pm8xxx_rtc_read_raw(struct pm8xxx_rtc *rtc_dd, u32 *secs)
> @@ -155,7 +254,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 +266,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;
>
> @@ -488,6 +591,17 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
> if (rc != -ENOENT)
> return rc;
> rtc_dd->nvmem_cell = NULL;
> +
> + /* Use UEFI storage as fallback if available */
> + rtc_dd->use_uefi = of_property_read_bool(pdev->dev.of_node,
> + "qcom,uefi-rtc-info");
> + }
> +
> + if (rtc_dd->use_uefi && !efivar_is_available()) {
> + if (IS_ENABLED(CONFIG_EFI))
> + return -EPROBE_DEFER;
> + dev_warn(&pdev->dev, "efivars not available\n");
> + rtc_dd->use_uefi = false;
> }
>
> rtc_dd->regs = match->data;
> diff --git a/include/linux/rtc.h b/include/linux/rtc.h
> index 1fd9c6a21ebe..1ecee2fe4214 100644
> --- a/include/linux/rtc.h
> +++ b/include/linux/rtc.h
> @@ -169,6 +169,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_BEGIN_GPS 315964800LL /* 1980-01-06 00:00:00 */
I'd use RTC_TIMESTAMP_EPOCH_GPS but really, I would prefer the UNIX epoch
to be used
> #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 */
> --
> 2.39.1
>
--
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
next prev parent reply other threads:[~2023-01-27 15:19 UTC|newest]
Thread overview: 44+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-01-26 14:20 [PATCH 00/24] rtc: pm8xxx: add support for setting time using nvmem Johan Hovold
2023-01-26 14:20 ` [PATCH 01/24] rtc: pm8xxx: fix set-alarm race Johan Hovold
2023-01-26 14:20 ` [PATCH 02/24] rtc: pm8xxx: drop spmi error messages Johan Hovold
2023-01-26 14:20 ` [PATCH 03/24] rtc: pm8xxx: use regmap_update_bits() Johan Hovold
2023-01-26 14:20 ` [PATCH 04/24] rtc: pm8xxx: drop bogus locking Johan Hovold
2023-01-26 14:20 ` [PATCH 05/24] rtc: pm8xxx: return IRQ_NONE on errors Johan Hovold
2023-01-26 14:20 ` [PATCH 06/24] rtc: pm8xxx: drop unused register defines Johan Hovold
2023-01-26 14:20 ` [PATCH 07/24] rtc: pm8xxx: use unaligned le32 helpers Johan Hovold
2023-01-26 14:20 ` [PATCH 08/24] rtc: pm8xxx: clean up time and alarm debugging Johan Hovold
2023-01-26 14:20 ` [PATCH 09/24] rtc: pm8xxx: rename struct device pointer Johan Hovold
2023-01-26 14:20 ` [PATCH 10/24] rtc: pm8xxx: rename alarm irq variable Johan Hovold
2023-01-26 14:20 ` [PATCH 11/24] rtc: pm8xxx: clean up comments Johan Hovold
2023-01-26 14:20 ` [PATCH 12/24] rtc: pm8xxx: use u32 for timestamps Johan Hovold
2023-01-26 14:20 ` [PATCH 13/24] rtc: pm8xxx: refactor read_time() Johan Hovold
2023-01-26 14:20 ` [PATCH 14/24] rtc: pm8xxx: clean up local declarations Johan Hovold
2023-01-26 14:20 ` [PATCH 15/24] dt-bindings: rtc: qcom-pm8xxx: add nvmem-cell offset Johan Hovold
2023-01-26 15:56 ` Krzysztof Kozlowski
2023-01-26 14:20 ` [PATCH 16/24] rtc: pm8xxx: add support for nvmem offset Johan Hovold
2023-01-27 14:13 ` Srinivas Kandagatla
2023-01-27 15:32 ` Johan Hovold
2023-01-27 15:09 ` Alexandre Belloni
2023-01-27 15:51 ` Johan Hovold
2023-01-27 16:05 ` Alexandre Belloni
2023-02-02 15:12 ` Johan Hovold
2023-02-02 15:21 ` Alexandre Belloni
2023-01-26 14:20 ` [PATCH 17/24] rtc: pm8xxx: add copyright notice Johan Hovold
2023-01-26 16:06 ` Alexandre Belloni
2023-01-27 13:04 ` Johan Hovold
2023-01-27 14:14 ` Krzysztof Kozlowski
2023-02-02 10:22 ` Johan Hovold
2023-01-26 14:20 ` [RFC 18/24] dt-bindings: rtc: qcom-pm8xxx: add uefi-variable offset Johan Hovold
2023-01-30 18:49 ` Rob Herring
2023-02-01 16:09 ` Johan Hovold
2023-02-09 16:59 ` Ard Biesheuvel
2023-01-26 14:20 ` [PATCH 19/24] rtc: pm8xxx: add support for uefi offset Johan Hovold
2023-01-26 14:27 ` Johan Hovold
2023-01-27 15:19 ` Alexandre Belloni [this message]
2023-01-27 15:26 ` Johan Hovold
2023-01-27 15:59 ` Alexandre Belloni
2023-01-26 14:20 ` [PATCH 20/24] arm64: defconfig: enable Qualcomm SDAM nvmem driver Johan Hovold
2023-01-26 14:20 ` [PATCH 21/24] arm64: dts: qcom: sc8280xp-pmics: add pmk8280 rtc Johan Hovold
2023-01-26 14:20 ` [PATCH 22/24] arm64: dts: qcom: sc8280xp-pmics: add pmk8280 sdam nvram Johan Hovold
2023-01-26 14:20 ` [PATCH 23/24] arm64: dts: qcom: sc8280xp-crd: enable rtc Johan Hovold
2023-01-26 14:20 ` [PATCH 24/24] arm64: dts: qcom: sc8280xp-x13s: " Johan Hovold
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Y9PrdqLHZpZrdGJ4@mail.local \
--to=alexandre.belloni@bootlin.com \
--cc=a.zummo@towertech.it \
--cc=agross@kernel.org \
--cc=andersson@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=johan+linaro@kernel.org \
--cc=konrad.dybcio@linaro.org \
--cc=krzysztof.kozlowski+dt@linaro.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-rtc@vger.kernel.org \
--cc=luzmaximilian@gmail.com \
--cc=robh+dt@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.