Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] nvmem: rockchip-otp: convert to runtime PM
@ 2026-08-19 12:33 Sascha Hauer
  2026-08-27 13:54 ` Heiko Stuebner
  0 siblings, 1 reply; 2+ messages in thread
From: Sascha Hauer @ 2026-08-19 12:33 UTC (permalink / raw)
  To: Srinivas Kandagatla, Heiko Stuebner
  Cc: linux-kernel, linux-arm-kernel, linux-rockchip, Stefan Kerkmann,
	Sascha Hauer

From: Stefan Kerkmann <s.kerkmann@pengutronix.de>

The driver enables the OTP clocks inside rockchip_otp_read() and drops
them again before returning, so the controller is only alive for the
duration of a nvmem read issued by Linux.

On RK3588 that is not sufficient. Part of the OTP array is readable only
from the secure world, and OP-TEE reads it through this same controller.
Its clocks are in the normal world's CRU and are plain gates, so an SMC
into OP-TEE hits a clock-gated controller unless Linux turns them on
first. OP-TEE cannot do that without a CRU driver of its own, which
would put both worlds on the same gate registers.

Move the clock handling into runtime PM callbacks. A consumer can then
take a DL_FLAG_PM_RUNTIME device link on the OTP and hold a reference
for as long as it needs the controller, without knowing anything about
its clock list. DEFINE_RUNTIME_DEV_PM_OPS() supplies the system sleep
callbacks too, so holding one does not keep the clocks on over suspend.

Enabling the clocks is now the callbacks' job alone, hence the dependency
on PM: with CONFIG_PM=n they never run and a read would go out to a gated
controller. Reads are otherwise unchanged.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Stefan Kerkmann <s.kerkmann@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
The driver enables the OTP clocks inside rockchip_otp_read() and drops
them again before returning, so the controller is only alive for the
duration of a nvmem read issued by Linux.

On RK3588 that is not sufficient. Part of the OTP array is readable only
from the secure world, and OP-TEE reads it through this same controller.
Its clocks are in the normal world's CRU and are plain gates, so an SMC
into OP-TEE hits a clock-gated controller unless Linux turns them on
first. OP-TEE cannot do that without a CRU driver of its own, which
would put both worlds on the same gate registers.

Move the clock handling into runtime PM callbacks. A consumer can then
take a DL_FLAG_PM_RUNTIME device link on the OTP and hold a reference
for as long as it needs the controller, without knowing anything about
its clock list. DEFINE_RUNTIME_DEV_PM_OPS() supplies the system sleep
callbacks too, so holding one does not keep the clocks on over suspend.

Enabling the clocks is now the callbacks' job alone, hence the dependency
on PM: with CONFIG_PM=n they never run and a read would go out to a gated
controller. Reads are otherwise unchanged.
---
 drivers/nvmem/Kconfig        |  1 +
 drivers/nvmem/rockchip-otp.c | 39 ++++++++++++++++++++++++++++++++++++---
 2 files changed, 37 insertions(+), 3 deletions(-)

diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index 74ddbd0f79b0e..3e1a66530fdea 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -337,6 +337,7 @@ config NVMEM_ROCKCHIP_OTP
 	tristate "Rockchip OTP controller support"
 	depends on ARCH_ROCKCHIP || COMPILE_TEST
 	depends on HAS_IOMEM
+	depends on PM
 	help
 	  This is a simple driver to dump specified values of Rockchip SoC
 	  from OTP, such as cpu-leakage.
diff --git a/drivers/nvmem/rockchip-otp.c b/drivers/nvmem/rockchip-otp.c
index 0ec78b5e19e7d..bf1ffb46550c2 100644
--- a/drivers/nvmem/rockchip-otp.c
+++ b/drivers/nvmem/rockchip-otp.c
@@ -18,6 +18,7 @@
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 
 /* OTP Register Offsets */
 #define OTPC_SBPI_CTRL			0x0020
@@ -272,9 +273,9 @@ static int rockchip_otp_read(void *context, unsigned int offset,
 	if (!otp->data || !otp->data->reg_read)
 		return -EINVAL;
 
-	ret = clk_bulk_prepare_enable(otp->data->num_clks, otp->clks);
+	ret = pm_runtime_resume_and_get(otp->dev);
 	if (ret < 0) {
-		dev_err(otp->dev, "failed to prepare/enable clks\n");
+		dev_err(otp->dev, "failed to resume OTP: %d\n", ret);
 		return ret;
 	}
 
@@ -306,7 +307,7 @@ static int rockchip_otp_read(void *context, unsigned int offset,
 	}
 
 err:
-	clk_bulk_disable_unprepare(otp->data->num_clks, otp->clks);
+	pm_runtime_put(otp->dev);
 
 	return ret;
 }
@@ -457,18 +458,50 @@ static int rockchip_otp_probe(struct platform_device *pdev)
 	otp_config.priv = otp;
 	otp_config.dev = dev;
 
+	platform_set_drvdata(pdev, otp);
+	ret = devm_pm_runtime_enable(dev);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to enable runtime PM\n");
+
 	nvmem = devm_nvmem_register(dev, &otp_config);
 	if (IS_ERR(nvmem))
 		return dev_err_probe(dev, PTR_ERR(nvmem),
 				     "failed to register nvmem device\n");
+
+	return 0;
+}
+
+static int rockchip_otp_runtime_suspend(struct device *dev)
+{
+	struct rockchip_otp *otp = dev_get_drvdata(dev);
+
+	clk_bulk_disable_unprepare(otp->data->num_clks, otp->clks);
+
 	return 0;
 }
 
+static int rockchip_otp_runtime_resume(struct device *dev)
+{
+	struct rockchip_otp *otp = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_bulk_prepare_enable(otp->data->num_clks, otp->clks);
+	if (ret)
+		dev_err(dev, "failed to prepare/enable clks\n");
+
+	return ret;
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(rockchip_otp_pm_ops,
+				 rockchip_otp_runtime_suspend,
+				 rockchip_otp_runtime_resume, NULL);
+
 static struct platform_driver rockchip_otp_driver = {
 	.probe = rockchip_otp_probe,
 	.driver = {
 		.name = "rockchip-otp",
 		.of_match_table = rockchip_otp_match,
+		.pm = pm_ptr(&rockchip_otp_pm_ops),
 	},
 };
 

---
base-commit: bd5f485f3f026225b86573e559af0b7254ef4184
change-id: 20260819-rockchip-nvmem-pmruntime-82bd0437a216

Best regards,
-- 
Sascha Hauer <s.hauer@pengutronix.de>



^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] nvmem: rockchip-otp: convert to runtime PM
  2026-08-19 12:33 [PATCH] nvmem: rockchip-otp: convert to runtime PM Sascha Hauer
@ 2026-08-27 13:54 ` Heiko Stuebner
  0 siblings, 0 replies; 2+ messages in thread
From: Heiko Stuebner @ 2026-08-27 13:54 UTC (permalink / raw)
  To: Srinivas Kandagatla, Sascha Hauer
  Cc: linux-kernel, linux-arm-kernel, linux-rockchip, Stefan Kerkmann,
	Sascha Hauer

Am Mittwoch, 19. August 2026, 14:33:45 Mitteleuropäische Sommerzeit schrieb Sascha Hauer:
> From: Stefan Kerkmann <s.kerkmann@pengutronix.de>
> 
> The driver enables the OTP clocks inside rockchip_otp_read() and drops
> them again before returning, so the controller is only alive for the
> duration of a nvmem read issued by Linux.
> 
> On RK3588 that is not sufficient. Part of the OTP array is readable only
> from the secure world, and OP-TEE reads it through this same controller.
> Its clocks are in the normal world's CRU and are plain gates, so an SMC
> into OP-TEE hits a clock-gated controller unless Linux turns them on
> first. OP-TEE cannot do that without a CRU driver of its own, which
> would put both worlds on the same gate registers.
> 
> Move the clock handling into runtime PM callbacks. A consumer can then
> take a DL_FLAG_PM_RUNTIME device link on the OTP and hold a reference
> for as long as it needs the controller, without knowing anything about
> its clock list. DEFINE_RUNTIME_DEV_PM_OPS() supplies the system sleep
> callbacks too, so holding one does not keep the clocks on over suspend.
> 
> Enabling the clocks is now the callbacks' job alone, hence the dependency
> on PM: with CONFIG_PM=n they never run and a read would go out to a gated
> controller. Reads are otherwise unchanged.
> 
> Assisted-by: Claude:claude-opus-5
> Signed-off-by: Stefan Kerkmann <s.kerkmann@pengutronix.de>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>

Reviewed-by: Heiko Stuebner <heiko@sntech.de>

> ---
> The driver enables the OTP clocks inside rockchip_otp_read() and drops
> them again before returning, so the controller is only alive for the
> duration of a nvmem read issued by Linux.

your commit message got duplicated here.


Heiko




^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-08-27 13:54 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-19 12:33 [PATCH] nvmem: rockchip-otp: convert to runtime PM Sascha Hauer
2026-08-27 13:54 ` Heiko Stuebner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox