From nobody Mon Sep 28 17:49:25 2026 Received: from mx1.white.stw.pengutronix.de (mx1.white.stw.pengutronix.de [185.203.200.13]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 46DD22D781B for ; Wed, 19 Aug 2026 12:33:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.203.200.13 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787142834; cv=none; b=ceI1RJ1rYGRIUAypz8rTez0Fh8O7IcRpTDNxDvc9dB/AxlaHFq3igVs+H6u4kXccVU/uuEvofvtLK54xBNM51jC0sTTUUVWx5DIK4JNsqtysHDt0+DwPIrZ/+kkzVsPPpAtmv7h3YZvMzK2erzYLR0xO4cw/2P+Mb/ozx6QclCI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787142834; c=relaxed/simple; bh=JUOv2YQFxHzCiwuPai8MsTMoxDi4z66T/QnFydy6+6Y=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To:Cc; b=gp50MXAo7YBHGrQmsiioA3xJOzP4uZd/oTskItRsqlh43hwGKbJZye/3LWu643SmrJt6oO8N6s6msZpFX/0DLBshltkdc1TX397KA9Q0I0wqTOLoBfQ0Z/BBwKKt4DgscaX2NBPzL8MRpYwINbjZ+qxcC4tkk4o+I9EVF1CqghM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de; spf=pass smtp.mailfrom=pengutronix.de; arc=none smtp.client-ip=185.203.200.13 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pengutronix.de Received: from drehscheibe.grey.stw.pengutronix.de (drehscheibe.grey.stw.pengutronix.de [IPv6:2a0a:edc0:0:c01:1d::a2]) (Authenticated sender: relay-from-drehscheibe.grey.stw.pengutronix.de) by mx1.white.stw.pengutronix.de (Postfix) with ESMTPSA id 2139320102E; Wed, 19 Aug 2026 14:33:46 +0200 (CEST) Received: from dude02.red.stw.pengutronix.de ([2a0a:edc0:0:1101:1d::28]) by drehscheibe.grey.stw.pengutronix.de with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wwfUI-002I86-04; Wed, 19 Aug 2026 14:33:46 +0200 Received: from [::1] (helo=dude02.red.stw.pengutronix.de) by dude02.red.stw.pengutronix.de with esmtp (Exim 4.98.2) (envelope-from ) id 1wwfUH-00000000Os3-3vJg; Wed, 19 Aug 2026 14:33:45 +0200 From: Sascha Hauer Date: Wed, 19 Aug 2026 14:33:45 +0200 Subject: [PATCH] nvmem: rockchip-otp: convert to runtime PM Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260819-rockchip-nvmem-pmruntime-v1-1-01f1acf80dba@pengutronix.de> X-B4-Tracking: v=1; b=H4sIAKiihWoC/x3MQQqDMBBA0avIrDuQpCXaXqW4iHHUQRLDRKUgu buhy7f4/4JMwpTh01wgdHLmLVboRwN+cXEm5LEajDJWdfqNsvnVL5wwnoECpiBH3DkQdmYY1ev ZOqMt1DwJTfz7r799KTdsRtGoagAAAA== X-Change-ID: 20260819-rockchip-nvmem-pmruntime-82bd0437a216 To: Srinivas Kandagatla , Heiko Stuebner Cc: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-rockchip@lists.infradead.org, Stefan Kerkmann , Sascha Hauer X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1787142825; l=5657; i=s.hauer@pengutronix.de; s=20230412; h=from:subject:message-id; bh=2yti8HCNJ9vDWc5LoiWpTCzTx6WQbqJof4FNdXwCzW0=; b=lGUOTpDwTXUXJKBUI2UaN3PB7VrEdmGpsSo9rThy2fcy67xjmLo1t+6/BibPY9JGg008Riqi6 Wwht32P4bNGApnaFpPWhBuTg5H3W02fo2FmdXtOw89pjO0riveA4/Oz X-Developer-Key: i=s.hauer@pengutronix.de; a=ed25519; pk=4kuc9ocmECiBJKWxYgqyhtZOHj5AWi7+d0n/UjhkwTg= From: Stefan Kerkmann 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=3Dn 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 Signed-off-by: Sascha Hauer --- 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=3Dn 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 #include #include +#include =20 /* OTP Register Offsets */ #define OTPC_SBPI_CTRL 0x0020 @@ -272,9 +273,9 @@ static int rockchip_otp_read(void *context, unsigned in= t offset, if (!otp->data || !otp->data->reg_read) return -EINVAL; =20 - ret =3D clk_bulk_prepare_enable(otp->data->num_clks, otp->clks); + ret =3D 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; } =20 @@ -306,7 +307,7 @@ static int rockchip_otp_read(void *context, unsigned in= t offset, } =20 err: - clk_bulk_disable_unprepare(otp->data->num_clks, otp->clks); + pm_runtime_put(otp->dev); =20 return ret; } @@ -457,18 +458,50 @@ static int rockchip_otp_probe(struct platform_device = *pdev) otp_config.priv =3D otp; otp_config.dev =3D dev; =20 + platform_set_drvdata(pdev, otp); + ret =3D devm_pm_runtime_enable(dev); + if (ret) + return dev_err_probe(dev, ret, "failed to enable runtime PM\n"); + nvmem =3D 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 =3D dev_get_drvdata(dev); + + clk_bulk_disable_unprepare(otp->data->num_clks, otp->clks); + return 0; } =20 +static int rockchip_otp_runtime_resume(struct device *dev) +{ + struct rockchip_otp *otp =3D dev_get_drvdata(dev); + int ret; + + ret =3D 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 =3D { .probe =3D rockchip_otp_probe, .driver =3D { .name =3D "rockchip-otp", .of_match_table =3D rockchip_otp_match, + .pm =3D pm_ptr(&rockchip_otp_pm_ops), }, }; =20 --- base-commit: bd5f485f3f026225b86573e559af0b7254ef4184 change-id: 20260819-rockchip-nvmem-pmruntime-82bd0437a216 Best regards, --=20 Sascha Hauer