public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/9] soc/tegra: pmc: Clean up legacy code
@ 2026-05-06 13:41 Thierry Reding
  2026-05-06 13:41 ` [PATCH 1/9] ata: ahci_tegra: Explicitly specify PMC instance to use Thierry Reding
                   ` (8 more replies)
  0 siblings, 9 replies; 11+ messages in thread
From: Thierry Reding @ 2026-05-06 13:41 UTC (permalink / raw)
  To: Damien Le Moal, Niklas Cassel, Thierry Reding, Jonathan Hunter,
	Lyude Paul, Danilo Krummrich, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Mikko Perttunen,
	Dmitry Osipenko, Mauro Carvalho Chehab, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring,
	Bjorn Helgaas, Mathias Nyman, Greg Kroah-Hartman, Philipp Zabel
  Cc: linux-ide, linux-tegra, linux-kernel, dri-devel, nouveau,
	linux-media, linux-pci, linux-usb, Thierry Reding

The Tegra PMC has accumulated a bit of cruft over the years. Most of the
legacy code has since been replaced by standard APIs, but for certain 32
bit platforms we cannot get rid of all remnants, unfortunately.

In addition, future SoC generations can have multiple instances of the
PMC, making some of the old APIs unusable. Preliminary work was merged
recently to allow passing a PMC instance to the custom PMC APIs to solve
this problem.

This series of patches is a final cleanup pass that makes use of the new
APIs in existing drivers. At the end of the series, only some old 32-bit
support code will use the old APIs, so they can be made exclusive to the
32-bit ARM builds (which is about as good as it's going to get).

Note that the first 6 patches can be applied to subsystem trees
independently since they only rely on patches that were merged into 7.0.
Patch 8 depends on these patches being applied, so some coordination is
needed. The simplest solution would probably be to merge them all
through the Tegra tree, if everyone agrees. Otherwise, maintainers
should feel free to apply patches to their subsystems and I'll monitor
things and apply the last three patches once all others have landed.

Thanks,
Thierry

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
Thierry Reding (9):
      ata: ahci_tegra: Explicitly specify PMC instance to use
      drm/nouveau: tegra: Explicitly specify PMC instance to use
      drm/tegra: Explicitly specify PMC instance to use
      media: vde: Explicitly specify PMC instance to use
      PCI: tegra: Explicitly specify PMC instance to use
      usb: xhci: tegra: Explicitly specify PMC instance to use
      soc/tegra: pmc: Create PMC context dynamically
      soc/tegra: pmc: Remove unused legacy functions
      soc/tegra: pmc: Move legacy code behind CONFIG_ARM guard

 drivers/ata/ahci_tegra.c                           |  17 +-
 drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h  |   2 +
 drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c |   9 +-
 drivers/gpu/drm/tegra/dc.c                         |  14 +-
 drivers/gpu/drm/tegra/dc.h                         |   1 +
 drivers/gpu/drm/tegra/gr3d.c                       |   9 +-
 drivers/gpu/drm/tegra/sor.c                        |  16 +-
 drivers/media/platform/nvidia/tegra-vde/vde.c      |  15 +-
 drivers/media/platform/nvidia/tegra-vde/vde.h      |   1 +
 drivers/pci/controller/pci-tegra.c                 |  20 +-
 drivers/soc/tegra/pmc.c                            | 412 +++++++++------------
 drivers/usb/host/xhci-tegra.c                      |  38 +-
 include/soc/tegra/pmc.h                            |  81 +---
 13 files changed, 305 insertions(+), 330 deletions(-)
---
base-commit: 7fd2df204f342fc17d1a0bfcd474b24232fb0f32
change-id: 20260506-pmc-42ed4ce76ee5

Best regards,
--  
Thierry Reding <treding@nvidia.com>


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

* [PATCH 1/9] ata: ahci_tegra: Explicitly specify PMC instance to use
  2026-05-06 13:41 [PATCH 0/9] soc/tegra: pmc: Clean up legacy code Thierry Reding
@ 2026-05-06 13:41 ` Thierry Reding
  2026-05-06 13:54   ` Damien Le Moal
  2026-05-06 13:41 ` [PATCH 2/9] drm/nouveau: tegra: " Thierry Reding
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 11+ messages in thread
From: Thierry Reding @ 2026-05-06 13:41 UTC (permalink / raw)
  To: Damien Le Moal, Niklas Cassel, Thierry Reding, Jonathan Hunter,
	Lyude Paul, Danilo Krummrich, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Mikko Perttunen,
	Dmitry Osipenko, Mauro Carvalho Chehab, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring,
	Bjorn Helgaas, Mathias Nyman, Greg Kroah-Hartman, Philipp Zabel
  Cc: linux-ide, linux-tegra, linux-kernel, dri-devel, nouveau,
	linux-media, linux-pci, linux-usb, Thierry Reding

From: Thierry Reding <treding@nvidia.com>

Currently the kernel relies on a global variable to reference the PMC
context. Use an explicit lookup for the PMC and pass that to the public
PMC APIs.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/ata/ahci_tegra.c | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/drivers/ata/ahci_tegra.c b/drivers/ata/ahci_tegra.c
index 44584eed6374..554f05e09f98 100644
--- a/drivers/ata/ahci_tegra.c
+++ b/drivers/ata/ahci_tegra.c
@@ -175,6 +175,7 @@ struct tegra_ahci_priv {
 	struct reset_control	   *sata_cold_rst;
 	/* Needs special handling, cannot use ahci_platform */
 	struct clk		   *sata_clk;
+	struct tegra_pmc	   *pmc;
 	struct regulator_bulk_data *supplies;
 	const struct tegra_ahci_soc *soc;
 };
@@ -246,9 +247,10 @@ static int tegra_ahci_power_on(struct ahci_host_priv *hpriv)
 		return ret;
 
 	if (!tegra->pdev->dev.pm_domain) {
-		ret = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_SATA,
-							tegra->sata_clk,
-							tegra->sata_rst);
+		ret = tegra_pmc_powergate_sequence_power_up(tegra->pmc,
+							    TEGRA_POWERGATE_SATA,
+							    tegra->sata_clk,
+							    tegra->sata_rst);
 		if (ret)
 			goto disable_regulators;
 	}
@@ -269,7 +271,7 @@ static int tegra_ahci_power_on(struct ahci_host_priv *hpriv)
 	clk_disable_unprepare(tegra->sata_clk);
 
 	if (!tegra->pdev->dev.pm_domain)
-		tegra_powergate_power_off(TEGRA_POWERGATE_SATA);
+		tegra_pmc_powergate_power_off(tegra->pmc, TEGRA_POWERGATE_SATA);
 
 disable_regulators:
 	regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies);
@@ -289,7 +291,7 @@ static void tegra_ahci_power_off(struct ahci_host_priv *hpriv)
 
 	clk_disable_unprepare(tegra->sata_clk);
 	if (!tegra->pdev->dev.pm_domain)
-		tegra_powergate_power_off(TEGRA_POWERGATE_SATA);
+		tegra_pmc_powergate_power_off(tegra->pmc, TEGRA_POWERGATE_SATA);
 
 	regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies);
 }
@@ -571,6 +573,11 @@ static int tegra_ahci_probe(struct platform_device *pdev)
 		return PTR_ERR(tegra->sata_clk);
 	}
 
+	tegra->pmc = devm_tegra_pmc_get(&pdev->dev);
+	if (IS_ERR(tegra->pmc))
+		return dev_err_probe(&pdev->dev, PTR_ERR(tegra->pmc),
+				     "failed to get PMC\n");
+
 	tegra->supplies = devm_kcalloc(&pdev->dev,
 				       tegra->soc->num_supplies,
 				       sizeof(*tegra->supplies), GFP_KERNEL);

-- 
2.52.0


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

* [PATCH 2/9] drm/nouveau: tegra: Explicitly specify PMC instance to use
  2026-05-06 13:41 [PATCH 0/9] soc/tegra: pmc: Clean up legacy code Thierry Reding
  2026-05-06 13:41 ` [PATCH 1/9] ata: ahci_tegra: Explicitly specify PMC instance to use Thierry Reding
@ 2026-05-06 13:41 ` Thierry Reding
  2026-05-06 13:41 ` [PATCH 3/9] drm/tegra: " Thierry Reding
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Thierry Reding @ 2026-05-06 13:41 UTC (permalink / raw)
  To: Damien Le Moal, Niklas Cassel, Thierry Reding, Jonathan Hunter,
	Lyude Paul, Danilo Krummrich, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Mikko Perttunen,
	Dmitry Osipenko, Mauro Carvalho Chehab, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring,
	Bjorn Helgaas, Mathias Nyman, Greg Kroah-Hartman, Philipp Zabel
  Cc: linux-ide, linux-tegra, linux-kernel, dri-devel, nouveau,
	linux-media, linux-pci, linux-usb, Thierry Reding

From: Thierry Reding <treding@nvidia.com>

Currently the kernel relies on a global variable to reference the PMC
context. Use an explicit lookup for the PMC and pass that to the public
PMC APIs.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h  | 2 ++
 drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c | 9 ++++++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h b/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h
index 57bc542780bb..6aaa30ef167f 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h
@@ -18,6 +18,8 @@ struct nvkm_device_tegra {
 
 	struct regulator *vdd;
 
+	struct tegra_pmc *pmc;
+
 	struct {
 		/*
 		 * Protects accesses to mm from subsystems
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c
index 46bb55a1f565..3c8d0878891a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c
@@ -54,7 +54,8 @@ nvkm_device_tegra_power_up(struct nvkm_device_tegra *tdev)
 		reset_control_assert(tdev->rst);
 		udelay(10);
 
-		ret = tegra_powergate_remove_clamping(TEGRA_POWERGATE_3D);
+		ret = tegra_pmc_powergate_remove_clamping(tdev->pmc,
+							  TEGRA_POWERGATE_3D);
 		if (ret)
 			goto err_clamp;
 		udelay(10);
@@ -307,6 +308,12 @@ nvkm_device_tegra_new(const struct nvkm_device_tegra_func *func,
 		goto free;
 	}
 
+	tdev->pmc = devm_tegra_pmc_get(&pdev->dev);
+	if (IS_ERR(tdev->pmc)) {
+		ret = PTR_ERR(tdev->pmc);
+		goto free;
+	}
+
 	/**
 	 * The IOMMU bit defines the upper limit of the GPU-addressable space.
 	 */

-- 
2.52.0


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

* [PATCH 3/9] drm/tegra: Explicitly specify PMC instance to use
  2026-05-06 13:41 [PATCH 0/9] soc/tegra: pmc: Clean up legacy code Thierry Reding
  2026-05-06 13:41 ` [PATCH 1/9] ata: ahci_tegra: Explicitly specify PMC instance to use Thierry Reding
  2026-05-06 13:41 ` [PATCH 2/9] drm/nouveau: tegra: " Thierry Reding
@ 2026-05-06 13:41 ` Thierry Reding
  2026-05-06 13:41 ` [PATCH 4/9] media: vde: " Thierry Reding
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Thierry Reding @ 2026-05-06 13:41 UTC (permalink / raw)
  To: Damien Le Moal, Niklas Cassel, Thierry Reding, Jonathan Hunter,
	Lyude Paul, Danilo Krummrich, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Mikko Perttunen,
	Dmitry Osipenko, Mauro Carvalho Chehab, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring,
	Bjorn Helgaas, Mathias Nyman, Greg Kroah-Hartman, Philipp Zabel
  Cc: linux-ide, linux-tegra, linux-kernel, dri-devel, nouveau,
	linux-media, linux-pci, linux-usb, Thierry Reding

From: Thierry Reding <treding@nvidia.com>

Currently the kernel relies on a global variable to reference the PMC
context. Use an explicit lookup for the PMC and pass that to the public
PMC APIs.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/gpu/drm/tegra/dc.c   | 14 ++++++++++----
 drivers/gpu/drm/tegra/dc.h   |  1 +
 drivers/gpu/drm/tegra/gr3d.c |  9 ++++++++-
 drivers/gpu/drm/tegra/sor.c  | 16 ++++++++++++----
 4 files changed, 31 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 06370b7e0e56..e6099f5aced7 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -2780,7 +2780,7 @@ static int tegra_dc_runtime_suspend(struct host1x_client *client)
 	}
 
 	if (dc->soc->has_powergate)
-		tegra_powergate_power_off(dc->powergate);
+		tegra_pmc_powergate_power_off(dc->pmc, dc->powergate);
 
 	clk_disable_unprepare(dc->clk);
 	pm_runtime_put_sync(dev);
@@ -2801,8 +2801,9 @@ static int tegra_dc_runtime_resume(struct host1x_client *client)
 	}
 
 	if (dc->soc->has_powergate) {
-		err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk,
-							dc->rst);
+		err = tegra_pmc_powergate_sequence_power_up(dc->pmc,
+							    dc->powergate,
+							    dc->clk, dc->rst);
 		if (err < 0) {
 			dev_err(dev, "failed to power partition: %d\n", err);
 			goto put_rpm;
@@ -3231,12 +3232,17 @@ static int tegra_dc_probe(struct platform_device *pdev)
 	clk_disable_unprepare(dc->clk);
 
 	if (dc->soc->has_powergate) {
+		dc->pmc = devm_tegra_pmc_get(dc->dev);
+		if (IS_ERR(dc->pmc))
+			return dev_err_probe(dc->dev, PTR_ERR(dc->pmc),
+					     "failed to get PMC\n");
+
 		if (dc->pipe == 0)
 			dc->powergate = TEGRA_POWERGATE_DIS;
 		else
 			dc->powergate = TEGRA_POWERGATE_DISB;
 
-		tegra_powergate_power_off(dc->powergate);
+		tegra_pmc_powergate_power_off(dc->pmc, dc->powergate);
 	}
 
 	err = tegra_dc_init_opp_table(dc);
diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h
index 0559fa6b1bf7..10b86250e4ca 100644
--- a/drivers/gpu/drm/tegra/dc.h
+++ b/drivers/gpu/drm/tegra/dc.h
@@ -94,6 +94,7 @@ struct tegra_dc {
 	int irq;
 
 	struct tegra_output *rgb;
+	struct tegra_pmc *pmc;
 
 	struct tegra_dc_stats stats;
 	struct list_head list;
diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c
index 42e9656ab80c..debf66fa4eeb 100644
--- a/drivers/gpu/drm/tegra/gr3d.c
+++ b/drivers/gpu/drm/tegra/gr3d.c
@@ -46,6 +46,7 @@ struct gr3d {
 	unsigned int nclocks;
 	struct reset_control_bulk_data resets[RST_GR3D_MAX];
 	unsigned int nresets;
+	struct tegra_pmc *pmc;
 	struct dev_pm_domain_list *pd_list;
 
 	DECLARE_BITMAP(addr_regs, GR3D_NUM_REGS);
@@ -353,7 +354,8 @@ static int gr3d_power_up_legacy_domain(struct device *dev, const char *name,
 	if (err) {
 		dev_err(dev, "failed to acquire %s reset: %d\n", name, err);
 	} else {
-		err = tegra_powergate_sequence_power_up(id, clk, reset);
+		err = tegra_pmc_powergate_sequence_power_up(gr3d->pmc, id,
+							    clk, reset);
 		reset_control_release(reset);
 	}
 
@@ -385,6 +387,11 @@ static int gr3d_init_power(struct device *dev, struct gr3d *gr3d)
 		if (err != -ENOENT)
 			return err;
 
+		gr3d->pmc = devm_tegra_pmc_get(dev);
+		if (IS_ERR(gr3d->pmc))
+			return dev_err_probe(dev, PTR_ERR(gr3d->pmc),
+					     "failed to get PMC\n");
+
 		/*
 		 * Older device-trees don't use GENPD. In this case we should
 		 * toggle power domain manually.
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c
index de8b2dfc4984..a76095838133 100644
--- a/drivers/gpu/drm/tegra/sor.c
+++ b/drivers/gpu/drm/tegra/sor.c
@@ -422,6 +422,8 @@ struct tegra_sor {
 	struct clk *clk_dp;
 	struct clk *clk;
 
+	struct tegra_pmc *pmc;
+
 	u8 xbar_cfg[5];
 
 	struct drm_dp_link link;
@@ -2237,7 +2239,7 @@ static void tegra_sor_hdmi_disable(struct drm_encoder *encoder)
 	if (err < 0)
 		dev_err(sor->dev, "failed to power down SOR: %d\n", err);
 
-	err = tegra_io_pad_power_disable(sor->pad);
+	err = tegra_pmc_io_pad_power_disable(sor->pmc, sor->pad);
 	if (err < 0)
 		dev_err(sor->dev, "failed to power off I/O pad: %d\n", err);
 
@@ -2277,7 +2279,7 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder)
 
 	div = clk_get_rate(sor->clk) / 1000000 * 4;
 
-	err = tegra_io_pad_power_enable(sor->pad);
+	err = tegra_pmc_io_pad_power_enable(sor->pmc, sor->pad);
 	if (err < 0)
 		dev_err(sor->dev, "failed to power on I/O pad: %d\n", err);
 
@@ -2701,7 +2703,7 @@ static void tegra_sor_dp_disable(struct drm_encoder *encoder)
 	if (err < 0)
 		dev_err(sor->dev, "failed to power down SOR: %d\n", err);
 
-	err = tegra_io_pad_power_disable(sor->pad);
+	err = tegra_pmc_io_pad_power_disable(sor->pmc, sor->pad);
 	if (err < 0)
 		dev_err(sor->dev, "failed to power off I/O pad: %d\n", err);
 
@@ -2743,7 +2745,7 @@ static void tegra_sor_dp_enable(struct drm_encoder *encoder)
 	if (err < 0)
 		dev_err(sor->dev, "failed to set safe parent clock: %d\n", err);
 
-	err = tegra_io_pad_power_enable(sor->pad);
+	err = tegra_pmc_io_pad_power_enable(sor->pmc, sor->pad);
 	if (err < 0)
 		dev_err(sor->dev, "failed to power on LVDS rail: %d\n", err);
 
@@ -3730,6 +3732,12 @@ static int tegra_sor_probe(struct platform_device *pdev)
 
 	sor->num_settings = sor->soc->num_settings;
 
+	sor->pmc = devm_tegra_pmc_get(&pdev->dev);
+	if (IS_ERR(sor->pmc)) {
+		err = PTR_ERR(sor->pmc);
+		goto put_aux;
+	}
+
 	np = of_parse_phandle(pdev->dev.of_node, "nvidia,dpaux", 0);
 	if (np) {
 		sor->aux = drm_dp_aux_find_by_of_node(np);

-- 
2.52.0


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

* [PATCH 4/9] media: vde: Explicitly specify PMC instance to use
  2026-05-06 13:41 [PATCH 0/9] soc/tegra: pmc: Clean up legacy code Thierry Reding
                   ` (2 preceding siblings ...)
  2026-05-06 13:41 ` [PATCH 3/9] drm/tegra: " Thierry Reding
@ 2026-05-06 13:41 ` Thierry Reding
  2026-05-06 13:41 ` [PATCH 5/9] PCI: tegra: " Thierry Reding
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Thierry Reding @ 2026-05-06 13:41 UTC (permalink / raw)
  To: Damien Le Moal, Niklas Cassel, Thierry Reding, Jonathan Hunter,
	Lyude Paul, Danilo Krummrich, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Mikko Perttunen,
	Dmitry Osipenko, Mauro Carvalho Chehab, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring,
	Bjorn Helgaas, Mathias Nyman, Greg Kroah-Hartman, Philipp Zabel
  Cc: linux-ide, linux-tegra, linux-kernel, dri-devel, nouveau,
	linux-media, linux-pci, linux-usb, Thierry Reding

From: Thierry Reding <treding@nvidia.com>

Currently the kernel relies on a global variable to reference the PMC
context. Use an explicit lookup for the PMC and pass that to the public
PMC APIs.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/media/platform/nvidia/tegra-vde/vde.c | 15 +++++++++++----
 drivers/media/platform/nvidia/tegra-vde/vde.h |  1 +
 2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/media/platform/nvidia/tegra-vde/vde.c b/drivers/media/platform/nvidia/tegra-vde/vde.c
index 2b3898828304..c3097085ad9d 100644
--- a/drivers/media/platform/nvidia/tegra-vde/vde.c
+++ b/drivers/media/platform/nvidia/tegra-vde/vde.c
@@ -161,7 +161,8 @@ static __maybe_unused int tegra_vde_runtime_suspend(struct device *dev)
 	int err;
 
 	if (!dev->pm_domain) {
-		err = tegra_powergate_power_off(TEGRA_POWERGATE_VDEC);
+		err = tegra_pmc_powergate_power_off(vde->pmc,
+						    TEGRA_POWERGATE_VDEC);
 		if (err) {
 			dev_err(dev, "Failed to power down HW: %d\n", err);
 			return err;
@@ -193,15 +194,16 @@ static __maybe_unused int tegra_vde_runtime_resume(struct device *dev)
 	}
 
 	if (!dev->pm_domain) {
-		err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_VDEC,
-							vde->clk, vde->rst);
+		err = tegra_pmc_powergate_sequence_power_up(vde->pmc,
+							    TEGRA_POWERGATE_VDEC,
+							    vde->clk, vde->rst);
 		if (err) {
 			dev_err(dev, "Failed to power up HW : %d\n", err);
 			goto release_reset;
 		}
 	} else {
 		/*
-		 * tegra_powergate_sequence_power_up() leaves clocks enabled,
+		 * tegra_pmc_powergate_sequence_power_up() leaves clocks enabled,
 		 * while GENPD not.
 		 */
 		err = clk_prepare_enable(vde->clk);
@@ -293,6 +295,11 @@ static int tegra_vde_probe(struct platform_device *pdev)
 		return err;
 	}
 
+	vde->pmc = devm_tegra_pmc_get(dev);
+	if (IS_ERR(vde->pmc))
+		return dev_err_probe(dev, PTR_ERR(vde->pmc),
+				     "failed to get PMC\n");
+
 	irq = platform_get_irq_byname(pdev, "sync-token");
 	if (irq < 0)
 		return irq;
diff --git a/drivers/media/platform/nvidia/tegra-vde/vde.h b/drivers/media/platform/nvidia/tegra-vde/vde.h
index b2890484b7c3..abac0221d6e4 100644
--- a/drivers/media/platform/nvidia/tegra-vde/vde.h
+++ b/drivers/media/platform/nvidia/tegra-vde/vde.h
@@ -107,6 +107,7 @@ struct tegra_vde {
 	struct list_head map_list;
 	struct reset_control *rst;
 	struct reset_control *rst_mc;
+	struct tegra_pmc *pmc;
 	struct gen_pool *iram_pool;
 	struct completion decode_completion;
 	struct clk *clk;

-- 
2.52.0


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

* [PATCH 5/9] PCI: tegra: Explicitly specify PMC instance to use
  2026-05-06 13:41 [PATCH 0/9] soc/tegra: pmc: Clean up legacy code Thierry Reding
                   ` (3 preceding siblings ...)
  2026-05-06 13:41 ` [PATCH 4/9] media: vde: " Thierry Reding
@ 2026-05-06 13:41 ` Thierry Reding
  2026-05-06 13:41 ` [PATCH 6/9] usb: xhci: " Thierry Reding
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Thierry Reding @ 2026-05-06 13:41 UTC (permalink / raw)
  To: Damien Le Moal, Niklas Cassel, Thierry Reding, Jonathan Hunter,
	Lyude Paul, Danilo Krummrich, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Mikko Perttunen,
	Dmitry Osipenko, Mauro Carvalho Chehab, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring,
	Bjorn Helgaas, Mathias Nyman, Greg Kroah-Hartman, Philipp Zabel
  Cc: linux-ide, linux-tegra, linux-kernel, dri-devel, nouveau,
	linux-media, linux-pci, linux-usb, Thierry Reding

From: Thierry Reding <treding@nvidia.com>

Currently the kernel relies on a global variable to reference the PMC
context. Use an explicit lookup for the PMC and pass that to the public
PMC APIs.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/pci/controller/pci-tegra.c | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/drivers/pci/controller/pci-tegra.c b/drivers/pci/controller/pci-tegra.c
index 512309763d1f..2c6c521e6901 100644
--- a/drivers/pci/controller/pci-tegra.c
+++ b/drivers/pci/controller/pci-tegra.c
@@ -340,6 +340,8 @@ struct tegra_pcie {
 	struct reset_control *afi_rst;
 	struct reset_control *pcie_xrst;
 
+	struct tegra_pmc *pmc;
+
 	bool legacy_phy;
 	struct phy *phy;
 
@@ -1165,7 +1167,7 @@ static void tegra_pcie_power_off(struct tegra_pcie *pcie)
 	clk_disable_unprepare(pcie->afi_clk);
 
 	if (!dev->pm_domain)
-		tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
+		tegra_pmc_powergate_power_off(pcie->pmc, TEGRA_POWERGATE_PCIE);
 
 	err = regulator_bulk_disable(pcie->num_supplies, pcie->supplies);
 	if (err < 0)
@@ -1183,7 +1185,7 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie)
 	reset_control_assert(pcie->pex_rst);
 
 	if (!dev->pm_domain)
-		tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
+		tegra_pmc_powergate_power_off(pcie->pmc, TEGRA_POWERGATE_PCIE);
 
 	/* enable regulators */
 	err = regulator_bulk_enable(pcie->num_supplies, pcie->supplies);
@@ -1191,12 +1193,14 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie)
 		dev_err(dev, "failed to enable regulators: %d\n", err);
 
 	if (!dev->pm_domain) {
-		err = tegra_powergate_power_on(TEGRA_POWERGATE_PCIE);
+		err = tegra_pmc_powergate_power_on(pcie->pmc,
+						   TEGRA_POWERGATE_PCIE);
 		if (err) {
 			dev_err(dev, "failed to power ungate: %d\n", err);
 			goto regulator_disable;
 		}
-		err = tegra_powergate_remove_clamping(TEGRA_POWERGATE_PCIE);
+		err = tegra_pmc_powergate_remove_clamping(pcie->pmc,
+							  TEGRA_POWERGATE_PCIE);
 		if (err) {
 			dev_err(dev, "failed to remove clamp: %d\n", err);
 			goto powergate;
@@ -1234,7 +1238,7 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie)
 	clk_disable_unprepare(pcie->afi_clk);
 powergate:
 	if (!dev->pm_domain)
-		tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
+		tegra_pmc_powergate_power_off(pcie->pmc, TEGRA_POWERGATE_PCIE);
 regulator_disable:
 	regulator_bulk_disable(pcie->num_supplies, pcie->supplies);
 
@@ -1432,6 +1436,12 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie)
 		return err;
 	}
 
+	pcie->pmc = devm_tegra_pmc_get(dev);
+	if (IS_ERR(pcie->pmc)) {
+		dev_err_probe(dev, PTR_ERR(pcie->pmc), "failed to get PMC\n");
+		return err;
+	}
+
 	if (soc->program_uphy) {
 		err = tegra_pcie_phys_get(pcie);
 		if (err < 0) {

-- 
2.52.0


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

* [PATCH 6/9] usb: xhci: tegra: Explicitly specify PMC instance to use
  2026-05-06 13:41 [PATCH 0/9] soc/tegra: pmc: Clean up legacy code Thierry Reding
                   ` (4 preceding siblings ...)
  2026-05-06 13:41 ` [PATCH 5/9] PCI: tegra: " Thierry Reding
@ 2026-05-06 13:41 ` Thierry Reding
  2026-05-06 13:41 ` [PATCH 7/9] soc/tegra: pmc: Create PMC context dynamically Thierry Reding
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Thierry Reding @ 2026-05-06 13:41 UTC (permalink / raw)
  To: Damien Le Moal, Niklas Cassel, Thierry Reding, Jonathan Hunter,
	Lyude Paul, Danilo Krummrich, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Mikko Perttunen,
	Dmitry Osipenko, Mauro Carvalho Chehab, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring,
	Bjorn Helgaas, Mathias Nyman, Greg Kroah-Hartman, Philipp Zabel
  Cc: linux-ide, linux-tegra, linux-kernel, dri-devel, nouveau,
	linux-media, linux-pci, linux-usb, Thierry Reding

From: Thierry Reding <treding@nvidia.com>

Currently the kernel relies on a global variable to reference the PMC
context. Use an explicit lookup for the PMC and pass that to the public
PMC APIs.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/usb/host/xhci-tegra.c | 38 ++++++++++++++++++++++++++------------
 1 file changed, 26 insertions(+), 12 deletions(-)

diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c
index d2214d309e96..122b711929ef 100644
--- a/drivers/usb/host/xhci-tegra.c
+++ b/drivers/usb/host/xhci-tegra.c
@@ -292,6 +292,7 @@ struct tegra_xusb {
 	struct reset_control *host_rst;
 	struct reset_control *ss_rst;
 
+	struct tegra_pmc *pmc;
 	struct device *genpd_dev_host;
 	struct device *genpd_dev_ss;
 	bool use_genpd;
@@ -1188,20 +1189,23 @@ static int tegra_xusb_unpowergate_partitions(struct tegra_xusb *tegra)
 			return rc;
 		}
 	} else {
-		rc = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_XUSBA,
-							tegra->ss_clk,
-							tegra->ss_rst);
+		rc = tegra_pmc_powergate_sequence_power_up(tegra->pmc,
+							   TEGRA_POWERGATE_XUSBA,
+							   tegra->ss_clk,
+							   tegra->ss_rst);
 		if (rc < 0) {
 			dev_err(dev, "failed to enable XUSB SS partition\n");
 			return rc;
 		}
 
-		rc = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_XUSBC,
-							tegra->host_clk,
-							tegra->host_rst);
+		rc = tegra_pmc_powergate_sequence_power_up(tegra->pmc,
+							   TEGRA_POWERGATE_XUSBC,
+							   tegra->host_clk,
+							   tegra->host_rst);
 		if (rc < 0) {
 			dev_err(dev, "failed to enable XUSB Host partition\n");
-			tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA);
+			tegra_pmc_powergate_power_off(tegra->pmc,
+						      TEGRA_POWERGATE_XUSBA);
 			return rc;
 		}
 	}
@@ -1228,18 +1232,21 @@ static int tegra_xusb_powergate_partitions(struct tegra_xusb *tegra)
 			return rc;
 		}
 	} else {
-		rc = tegra_powergate_power_off(TEGRA_POWERGATE_XUSBC);
+		rc = tegra_pmc_powergate_power_off(tegra->pmc,
+						   TEGRA_POWERGATE_XUSBC);
 		if (rc < 0) {
 			dev_err(dev, "failed to disable XUSB Host partition\n");
 			return rc;
 		}
 
-		rc = tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA);
+		rc = tegra_pmc_powergate_power_off(tegra->pmc,
+						   TEGRA_POWERGATE_XUSBA);
 		if (rc < 0) {
 			dev_err(dev, "failed to disable XUSB SS partition\n");
-			tegra_powergate_sequence_power_up(TEGRA_POWERGATE_XUSBC,
-							  tegra->host_clk,
-							  tegra->host_rst);
+			tegra_pmc_powergate_sequence_power_up(tegra->pmc,
+							      TEGRA_POWERGATE_XUSBC,
+							      tegra->host_clk,
+							      tegra->host_rst);
 			return rc;
 		}
 	}
@@ -1733,6 +1740,13 @@ static int tegra_xusb_probe(struct platform_device *pdev)
 				err);
 			goto put_padctl;
 		}
+
+		tegra->pmc = devm_tegra_pmc_get(&pdev->dev);
+		if (IS_ERR(tegra->pmc)) {
+			err = dev_err_probe(&pdev->dev, PTR_ERR(tegra->pmc),
+					    "failed to get PMC\n");
+			goto put_padctl;
+		}
 	} else {
 		err = tegra_xusb_powerdomain_init(&pdev->dev, tegra);
 		if (err)

-- 
2.52.0


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

* [PATCH 7/9] soc/tegra: pmc: Create PMC context dynamically
  2026-05-06 13:41 [PATCH 0/9] soc/tegra: pmc: Clean up legacy code Thierry Reding
                   ` (5 preceding siblings ...)
  2026-05-06 13:41 ` [PATCH 6/9] usb: xhci: " Thierry Reding
@ 2026-05-06 13:41 ` Thierry Reding
  2026-05-06 13:41 ` [PATCH 8/9] soc/tegra: pmc: Remove unused legacy functions Thierry Reding
  2026-05-06 13:42 ` [PATCH 9/9] soc/tegra: pmc: Move legacy code behind CONFIG_ARM guard Thierry Reding
  8 siblings, 0 replies; 11+ messages in thread
From: Thierry Reding @ 2026-05-06 13:41 UTC (permalink / raw)
  To: Damien Le Moal, Niklas Cassel, Thierry Reding, Jonathan Hunter,
	Lyude Paul, Danilo Krummrich, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Mikko Perttunen,
	Dmitry Osipenko, Mauro Carvalho Chehab, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring,
	Bjorn Helgaas, Mathias Nyman, Greg Kroah-Hartman, Philipp Zabel
  Cc: linux-ide, linux-tegra, linux-kernel, dri-devel, nouveau,
	linux-media, linux-pci, linux-usb, Thierry Reding

From: Thierry Reding <treding@nvidia.com>

For legacy purposes, an early PMC context is needed to support certain
drivers and functionalities. However, when the PMC driver is probed in
the later boot stages, the early context is no longer needed. Allocate
the PMC context dynamically at probe time so that it can be used going
forward.

While at it, rename the early PMC context to more accurately reflect
what it is used for. It's technically not only for early boot stages,
but also to support some code that doesn't have a way of obtaining the
correct context otherwise (e.g. no access to device tree).

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/soc/tegra/pmc.c | 163 ++++++++++++++++++++++++++----------------------
 1 file changed, 88 insertions(+), 75 deletions(-)

diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 2ee6539d796a..50969b07fd8c 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -512,7 +512,7 @@ struct tegra_pmc {
 	u32 *wake_status;
 };
 
-static struct tegra_pmc *pmc = &(struct tegra_pmc) {
+static struct tegra_pmc *early_pmc = &(struct tegra_pmc) {
 	.base = NULL,
 	.suspend_mode = TEGRA_SUSPEND_NOT_READY,
 };
@@ -1069,7 +1069,7 @@ EXPORT_SYMBOL(tegra_pmc_powergate_power_on);
  */
 int tegra_powergate_power_on(unsigned int id)
 {
-	return tegra_pmc_powergate_power_on(pmc, id);
+	return tegra_pmc_powergate_power_on(early_pmc, id);
 }
 EXPORT_SYMBOL(tegra_powergate_power_on);
 
@@ -1093,7 +1093,7 @@ EXPORT_SYMBOL(tegra_pmc_powergate_power_off);
  */
 int tegra_powergate_power_off(unsigned int id)
 {
-	return tegra_pmc_powergate_power_off(pmc, id);
+	return tegra_pmc_powergate_power_off(early_pmc, id);
 }
 EXPORT_SYMBOL(tegra_powergate_power_off);
 
@@ -1130,7 +1130,7 @@ EXPORT_SYMBOL(tegra_pmc_powergate_remove_clamping);
  */
 int tegra_powergate_remove_clamping(unsigned int id)
 {
-	return tegra_pmc_powergate_remove_clamping(pmc, id);
+	return tegra_pmc_powergate_remove_clamping(early_pmc, id);
 }
 EXPORT_SYMBOL(tegra_powergate_remove_clamping);
 
@@ -1192,7 +1192,7 @@ EXPORT_SYMBOL(tegra_pmc_powergate_sequence_power_up);
 int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk,
 				      struct reset_control *rst)
 {
-	return tegra_pmc_powergate_sequence_power_up(pmc, id, clk, rst);
+	return tegra_pmc_powergate_sequence_power_up(early_pmc, id, clk, rst);
 }
 EXPORT_SYMBOL(tegra_powergate_sequence_power_up);
 
@@ -1221,11 +1221,11 @@ bool tegra_pmc_cpu_is_powered(unsigned int cpuid)
 {
 	int id;
 
-	id = tegra_get_cpu_powergate_id(pmc, cpuid);
+	id = tegra_get_cpu_powergate_id(early_pmc, cpuid);
 	if (id < 0)
 		return false;
 
-	return tegra_powergate_is_powered(pmc, id);
+	return tegra_powergate_is_powered(early_pmc, id);
 }
 
 /**
@@ -1236,11 +1236,11 @@ int tegra_pmc_cpu_power_on(unsigned int cpuid)
 {
 	int id;
 
-	id = tegra_get_cpu_powergate_id(pmc, cpuid);
+	id = tegra_get_cpu_powergate_id(early_pmc, cpuid);
 	if (id < 0)
 		return id;
 
-	return tegra_powergate_set(pmc, id, true);
+	return tegra_powergate_set(early_pmc, id, true);
 }
 
 /**
@@ -1251,11 +1251,11 @@ int tegra_pmc_cpu_remove_clamping(unsigned int cpuid)
 {
 	int id;
 
-	id = tegra_get_cpu_powergate_id(pmc, cpuid);
+	id = tegra_get_cpu_powergate_id(early_pmc, cpuid);
 	if (id < 0)
 		return id;
 
-	return tegra_powergate_remove_clamping(id);
+	return tegra_pmc_powergate_remove_clamping(early_pmc, id);
 }
 
 static void tegra_pmc_program_reboot_reason(struct tegra_pmc *pmc,
@@ -1533,7 +1533,7 @@ static int tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
 
 bool tegra_pmc_core_domain_state_synced(void)
 {
-	return pmc->core_domain_state_synced;
+	return early_pmc->core_domain_state_synced;
 }
 
 static int
@@ -1831,7 +1831,7 @@ EXPORT_SYMBOL(tegra_pmc_io_pad_power_enable);
  */
 int tegra_io_pad_power_enable(enum tegra_io_pad id)
 {
-	return tegra_pmc_io_pad_power_enable(pmc, id);
+	return tegra_pmc_io_pad_power_enable(early_pmc, id);
 }
 EXPORT_SYMBOL(tegra_io_pad_power_enable);
 
@@ -1887,7 +1887,7 @@ EXPORT_SYMBOL(tegra_pmc_io_pad_power_disable);
  */
 int tegra_io_pad_power_disable(enum tegra_io_pad id)
 {
-	return tegra_pmc_io_pad_power_disable(pmc, id);
+	return tegra_pmc_io_pad_power_disable(early_pmc, id);
 }
 EXPORT_SYMBOL(tegra_io_pad_power_disable);
 
@@ -1976,7 +1976,7 @@ static int tegra_io_pad_get_voltage(struct tegra_pmc *pmc, enum tegra_io_pad id)
 #ifdef CONFIG_PM_SLEEP
 enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void)
 {
-	return pmc->suspend_mode;
+	return early_pmc->suspend_mode;
 }
 
 void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode)
@@ -1984,7 +1984,7 @@ void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode)
 	if (mode < TEGRA_SUSPEND_NONE || mode >= TEGRA_MAX_SUSPEND_MODE)
 		return;
 
-	pmc->suspend_mode = mode;
+	early_pmc->suspend_mode = mode;
 }
 
 void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode)
@@ -1999,7 +1999,7 @@ void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode)
 		break;
 
 	case TEGRA_SUSPEND_LP2:
-		rate = pmc->rate;
+		rate = early_pmc->rate;
 		break;
 
 	default:
@@ -2009,18 +2009,18 @@ void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode)
 	if (WARN_ON_ONCE(rate == 0))
 		rate = 100000000;
 
-	ticks = pmc->cpu_good_time * rate + USEC_PER_SEC - 1;
+	ticks = early_pmc->cpu_good_time * rate + USEC_PER_SEC - 1;
 	do_div(ticks, USEC_PER_SEC);
-	tegra_pmc_writel(pmc, ticks, PMC_CPUPWRGOOD_TIMER);
+	tegra_pmc_writel(early_pmc, ticks, PMC_CPUPWRGOOD_TIMER);
 
-	ticks = pmc->cpu_off_time * rate + USEC_PER_SEC - 1;
+	ticks = early_pmc->cpu_off_time * rate + USEC_PER_SEC - 1;
 	do_div(ticks, USEC_PER_SEC);
-	tegra_pmc_writel(pmc, ticks, PMC_CPUPWROFF_TIMER);
+	tegra_pmc_writel(early_pmc, ticks, PMC_CPUPWROFF_TIMER);
 
-	value = tegra_pmc_readl(pmc, PMC_CNTRL);
+	value = tegra_pmc_readl(early_pmc, PMC_CNTRL);
 	value &= ~PMC_CNTRL_SIDE_EFFECT_LP0;
 	value |= PMC_CNTRL_CPU_PWRREQ_OE;
-	tegra_pmc_writel(pmc, value, PMC_CNTRL);
+	tegra_pmc_writel(early_pmc, value, PMC_CNTRL);
 }
 #endif
 
@@ -3110,6 +3110,44 @@ static int tegra_pmc_regmap_init(struct tegra_pmc *pmc)
 	return 0;
 }
 
+static bool tegra_pmc_detect_tz_only(struct tegra_pmc *pmc)
+{
+	u32 value, saved;
+
+	saved = readl(pmc->base + pmc->soc->regs->scratch0);
+	value = saved ^ 0xffffffff;
+
+	if (value == 0xffffffff)
+		value = 0xdeadbeef;
+
+	/* write pattern and read it back */
+	writel(value, pmc->base + pmc->soc->regs->scratch0);
+	value = readl(pmc->base + pmc->soc->regs->scratch0);
+
+	/* if we read all-zeroes, access is restricted to TZ only */
+	if (value == 0) {
+		pr_info("access to PMC is restricted to TZ\n");
+		return true;
+	}
+
+	/* restore original value */
+	writel(saved, pmc->base + pmc->soc->regs->scratch0);
+
+	return false;
+}
+
+static void tegra_pmc_init_common(struct tegra_pmc *pmc)
+{
+	unsigned int i;
+
+	pmc->tz_only = tegra_pmc_detect_tz_only(pmc);
+
+	/* Create a bitmap of the available and valid partitions */
+	for (i = 0; i < pmc->soc->num_powergates; i++)
+		if (pmc->soc->powergates[i])
+			set_bit(i, pmc->powergates_available);
+}
+
 static void tegra_pmc_reset_suspend_mode(void *data)
 {
 	struct tegra_pmc *pmc = data;
@@ -3119,7 +3157,7 @@ static void tegra_pmc_reset_suspend_mode(void *data)
 
 static int tegra_pmc_probe(struct platform_device *pdev)
 {
-	void __iomem *base;
+	struct tegra_pmc *pmc;
 	struct resource *res;
 	int err;
 
@@ -3128,9 +3166,16 @@ static int tegra_pmc_probe(struct platform_device *pdev)
 	 * register mapping and setup the soc data pointer. If these
 	 * are not valid then something went badly wrong!
 	 */
-	if (WARN_ON(!pmc->base || !pmc->soc))
+	if (WARN_ON(!early_pmc->base || !early_pmc->soc))
 		return -ENODEV;
 
+	pmc = devm_kzalloc(&pdev->dev, sizeof(*pmc), GFP_KERNEL);
+	if (!pmc)
+		return -ENOMEM;
+
+	pmc->soc = device_get_match_data(&pdev->dev);
+	tegra_pmc_init_common(pmc);
+
 	err = tegra_pmc_parse_dt(pmc, pdev->dev.of_node);
 	if (err < 0)
 		return err;
@@ -3141,14 +3186,14 @@ static int tegra_pmc_probe(struct platform_device *pdev)
 		return err;
 
 	/* take over the memory region from the early initialization */
-	base = devm_platform_ioremap_resource(pdev, 0);
-	if (IS_ERR(base))
-		return PTR_ERR(base);
+	pmc->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(pmc->base))
+		return PTR_ERR(pmc->base);
 
 	if (pmc->soc->has_single_mmio_aperture) {
-		pmc->wake = base;
-		pmc->aotag = base;
-		pmc->scratch = base;
+		pmc->wake = pmc->base;
+		pmc->aotag = pmc->base;
+		pmc->scratch = pmc->base;
 	} else {
 		pmc->wake = devm_platform_ioremap_resource_byname(pdev, "wake");
 		if (IS_ERR(pmc->wake))
@@ -3167,7 +3212,7 @@ static int tegra_pmc_probe(struct platform_device *pdev)
 
 		/* "scratch" is an optional aperture */
 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-						"scratch");
+						   "scratch");
 		if (res) {
 			pmc->scratch = devm_ioremap_resource(&pdev->dev, res);
 			if (IS_ERR(pmc->scratch))
@@ -3271,10 +3316,10 @@ static int tegra_pmc_probe(struct platform_device *pdev)
 	if (err < 0)
 		goto cleanup_powergates;
 
-	mutex_lock(&pmc->powergates_lock);
-	iounmap(pmc->base);
-	pmc->base = base;
-	mutex_unlock(&pmc->powergates_lock);
+	mutex_lock(&early_pmc->powergates_lock);
+	iounmap(early_pmc->base);
+	early_pmc->base = pmc->base;
+	mutex_unlock(&early_pmc->powergates_lock);
 
 	tegra_pmc_clock_register(pmc, pdev->dev.of_node);
 	platform_set_drvdata(pdev, pmc);
@@ -4799,6 +4844,7 @@ static const struct of_device_id tegra_pmc_match[] = {
 
 static void tegra_pmc_sync_state(struct device *dev)
 {
+	struct tegra_pmc *pmc = dev_get_drvdata(dev);
 	struct device_node *np, *child;
 	int err;
 
@@ -4856,32 +4902,6 @@ static struct platform_driver tegra_pmc_driver = {
 };
 builtin_platform_driver(tegra_pmc_driver);
 
-static bool __init tegra_pmc_detect_tz_only(struct tegra_pmc *pmc)
-{
-	u32 value, saved;
-
-	saved = readl(pmc->base + pmc->soc->regs->scratch0);
-	value = saved ^ 0xffffffff;
-
-	if (value == 0xffffffff)
-		value = 0xdeadbeef;
-
-	/* write pattern and read it back */
-	writel(value, pmc->base + pmc->soc->regs->scratch0);
-	value = readl(pmc->base + pmc->soc->regs->scratch0);
-
-	/* if we read all-zeroes, access is restricted to TZ only */
-	if (value == 0) {
-		pr_info("access to PMC is restricted to TZ\n");
-		return true;
-	}
-
-	/* restore original value */
-	writel(saved, pmc->base + pmc->soc->regs->scratch0);
-
-	return false;
-}
-
 /*
  * Early initialization to allow access to registers in the very early boot
  * process.
@@ -4891,10 +4911,9 @@ static int __init tegra_pmc_early_init(void)
 	const struct of_device_id *match;
 	struct device_node *np;
 	struct resource regs;
-	unsigned int i;
 	bool invert;
 
-	mutex_init(&pmc->powergates_lock);
+	mutex_init(&early_pmc->powergates_lock);
 
 	np = of_find_matching_node_and_match(NULL, tegra_pmc_match, &match);
 	if (!np) {
@@ -4935,23 +4954,17 @@ static int __init tegra_pmc_early_init(void)
 		}
 	}
 
-	pmc->base = ioremap(regs.start, resource_size(&regs));
-	if (!pmc->base) {
+	early_pmc->base = ioremap(regs.start, resource_size(&regs));
+	if (!early_pmc->base) {
 		pr_err("failed to map PMC registers\n");
 		of_node_put(np);
 		return -ENXIO;
 	}
 
 	if (of_device_is_available(np)) {
-		pmc->soc = match->data;
-
-		if (pmc->soc->maybe_tz_only)
-			pmc->tz_only = tegra_pmc_detect_tz_only(pmc);
+		early_pmc->soc = match->data;
 
-		/* Create a bitmap of the available and valid partitions */
-		for (i = 0; i < pmc->soc->num_powergates; i++)
-			if (pmc->soc->powergates[i])
-				set_bit(i, pmc->powergates_available);
+		tegra_pmc_init_common(early_pmc);
 
 		/*
 		 * Invert the interrupt polarity if a PMC device tree node
@@ -4959,7 +4972,7 @@ static int __init tegra_pmc_early_init(void)
 		 */
 		invert = of_property_read_bool(np, "nvidia,invert-interrupt");
 
-		pmc->soc->setup_irq_polarity(pmc, np, invert);
+		early_pmc->soc->setup_irq_polarity(early_pmc, np, invert);
 
 		of_node_put(np);
 	}

-- 
2.52.0


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

* [PATCH 8/9] soc/tegra: pmc: Remove unused legacy functions
  2026-05-06 13:41 [PATCH 0/9] soc/tegra: pmc: Clean up legacy code Thierry Reding
                   ` (6 preceding siblings ...)
  2026-05-06 13:41 ` [PATCH 7/9] soc/tegra: pmc: Create PMC context dynamically Thierry Reding
@ 2026-05-06 13:41 ` Thierry Reding
  2026-05-06 13:42 ` [PATCH 9/9] soc/tegra: pmc: Move legacy code behind CONFIG_ARM guard Thierry Reding
  8 siblings, 0 replies; 11+ messages in thread
From: Thierry Reding @ 2026-05-06 13:41 UTC (permalink / raw)
  To: Damien Le Moal, Niklas Cassel, Thierry Reding, Jonathan Hunter,
	Lyude Paul, Danilo Krummrich, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Mikko Perttunen,
	Dmitry Osipenko, Mauro Carvalho Chehab, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring,
	Bjorn Helgaas, Mathias Nyman, Greg Kroah-Hartman, Philipp Zabel
  Cc: linux-ide, linux-tegra, linux-kernel, dri-devel, nouveau,
	linux-media, linux-pci, linux-usb, Thierry Reding

From: Thierry Reding <treding@nvidia.com>

All callers of these functions have been replaced by their variants
taking a PMC context as an input, so they are no longer used and can be
removed.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/soc/tegra/pmc.c | 69 -------------------------------------------------
 include/soc/tegra/pmc.h | 47 ---------------------------------
 2 files changed, 116 deletions(-)

diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 50969b07fd8c..f25c8e73475c 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -1063,16 +1063,6 @@ int tegra_pmc_powergate_power_on(struct tegra_pmc *pmc, unsigned int id)
 }
 EXPORT_SYMBOL(tegra_pmc_powergate_power_on);
 
-/**
- * tegra_powergate_power_on() - power on partition
- * @id: partition ID
- */
-int tegra_powergate_power_on(unsigned int id)
-{
-	return tegra_pmc_powergate_power_on(early_pmc, id);
-}
-EXPORT_SYMBOL(tegra_powergate_power_on);
-
 /**
  * tegra_pmc_powergate_power_off() - power off partition
  * @pmc: power management controller
@@ -1087,16 +1077,6 @@ int tegra_pmc_powergate_power_off(struct tegra_pmc *pmc, unsigned int id)
 }
 EXPORT_SYMBOL(tegra_pmc_powergate_power_off);
 
-/**
- * tegra_powergate_power_off() - power off partition
- * @id: partition ID
- */
-int tegra_powergate_power_off(unsigned int id)
-{
-	return tegra_pmc_powergate_power_off(early_pmc, id);
-}
-EXPORT_SYMBOL(tegra_powergate_power_off);
-
 /**
  * tegra_powergate_is_powered() - check if partition is powered
  * @pmc: power management controller
@@ -1124,16 +1104,6 @@ int tegra_pmc_powergate_remove_clamping(struct tegra_pmc *pmc, unsigned int id)
 }
 EXPORT_SYMBOL(tegra_pmc_powergate_remove_clamping);
 
-/**
- * tegra_powergate_remove_clamping() - remove power clamps for partition
- * @id: partition ID
- */
-int tegra_powergate_remove_clamping(unsigned int id)
-{
-	return tegra_pmc_powergate_remove_clamping(early_pmc, id);
-}
-EXPORT_SYMBOL(tegra_powergate_remove_clamping);
-
 /**
  * tegra_pmc_powergate_sequence_power_up() - power up partition
  * @pmc: power management controller
@@ -1181,21 +1151,6 @@ int tegra_pmc_powergate_sequence_power_up(struct tegra_pmc *pmc,
 }
 EXPORT_SYMBOL(tegra_pmc_powergate_sequence_power_up);
 
-/**
- * tegra_powergate_sequence_power_up() - power up partition
- * @id: partition ID
- * @clk: clock for partition
- * @rst: reset for partition
- *
- * Must be called with clk disabled, and returns with clk enabled.
- */
-int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk,
-				      struct reset_control *rst)
-{
-	return tegra_pmc_powergate_sequence_power_up(early_pmc, id, clk, rst);
-}
-EXPORT_SYMBOL(tegra_powergate_sequence_power_up);
-
 /**
  * tegra_get_cpu_powergate_id() - convert from CPU ID to partition ID
  * @pmc: power management controller
@@ -1823,18 +1778,6 @@ int tegra_pmc_io_pad_power_enable(struct tegra_pmc *pmc, enum tegra_io_pad id)
 }
 EXPORT_SYMBOL(tegra_pmc_io_pad_power_enable);
 
-/**
- * tegra_io_pad_power_enable() - enable power to I/O pad
- * @id: Tegra I/O pad ID for which to enable power
- *
- * Returns: 0 on success or a negative error code on failure.
- */
-int tegra_io_pad_power_enable(enum tegra_io_pad id)
-{
-	return tegra_pmc_io_pad_power_enable(early_pmc, id);
-}
-EXPORT_SYMBOL(tegra_io_pad_power_enable);
-
 /**
  * tegra_pmc_io_pad_power_disable() - disable power to I/O pad
  * @pmc: power management controller
@@ -1879,18 +1822,6 @@ int tegra_pmc_io_pad_power_disable(struct tegra_pmc *pmc, enum tegra_io_pad id)
 }
 EXPORT_SYMBOL(tegra_pmc_io_pad_power_disable);
 
-/**
- * tegra_io_pad_power_disable() - disable power to I/O pad
- * @id: Tegra I/O pad ID for which to disable power
- *
- * Returns: 0 on success or a negative error code on failure.
- */
-int tegra_io_pad_power_disable(enum tegra_io_pad id)
-{
-	return tegra_pmc_io_pad_power_disable(early_pmc, id);
-}
-EXPORT_SYMBOL(tegra_io_pad_power_disable);
-
 static int tegra_io_pad_is_powered(struct tegra_pmc *pmc, enum tegra_io_pad id)
 {
 	const struct tegra_io_pad_soc *pad;
diff --git a/include/soc/tegra/pmc.h b/include/soc/tegra/pmc.h
index 1fd21be02577..8b4bcdea849e 100644
--- a/include/soc/tegra/pmc.h
+++ b/include/soc/tegra/pmc.h
@@ -164,16 +164,6 @@ int tegra_pmc_io_pad_power_enable(struct tegra_pmc *pmc, enum tegra_io_pad id);
 int tegra_pmc_io_pad_power_disable(struct tegra_pmc *pmc, enum tegra_io_pad id);
 
 /* legacy */
-int tegra_powergate_power_on(unsigned int id);
-int tegra_powergate_power_off(unsigned int id);
-int tegra_powergate_remove_clamping(unsigned int id);
-
-int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk,
-				      struct reset_control *rst);
-
-int tegra_io_pad_power_enable(enum tegra_io_pad id);
-int tegra_io_pad_power_disable(enum tegra_io_pad id);
-
 void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode);
 void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode);
 
@@ -224,43 +214,6 @@ tegra_pmc_io_pad_power_disable(struct tegra_pmc *pmc, enum tegra_io_pad id)
 	return -ENOSYS;
 }
 
-static inline int tegra_powergate_power_on(unsigned int id)
-{
-	return -ENOSYS;
-}
-
-static inline int tegra_powergate_power_off(unsigned int id)
-{
-	return -ENOSYS;
-}
-
-static inline int tegra_powergate_remove_clamping(unsigned int id)
-{
-	return -ENOSYS;
-}
-
-static inline int tegra_powergate_sequence_power_up(unsigned int id,
-						    struct clk *clk,
-						    struct reset_control *rst)
-{
-	return -ENOSYS;
-}
-
-static inline int tegra_io_pad_power_enable(enum tegra_io_pad id)
-{
-	return -ENOSYS;
-}
-
-static inline int tegra_io_pad_power_disable(enum tegra_io_pad id)
-{
-	return -ENOSYS;
-}
-
-static inline int tegra_io_pad_get_voltage(enum tegra_io_pad id)
-{
-	return -ENOSYS;
-}
-
 static inline void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode)
 {
 }

-- 
2.52.0


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

* [PATCH 9/9] soc/tegra: pmc: Move legacy code behind CONFIG_ARM guard
  2026-05-06 13:41 [PATCH 0/9] soc/tegra: pmc: Clean up legacy code Thierry Reding
                   ` (7 preceding siblings ...)
  2026-05-06 13:41 ` [PATCH 8/9] soc/tegra: pmc: Remove unused legacy functions Thierry Reding
@ 2026-05-06 13:42 ` Thierry Reding
  8 siblings, 0 replies; 11+ messages in thread
From: Thierry Reding @ 2026-05-06 13:42 UTC (permalink / raw)
  To: Damien Le Moal, Niklas Cassel, Thierry Reding, Jonathan Hunter,
	Lyude Paul, Danilo Krummrich, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Mikko Perttunen,
	Dmitry Osipenko, Mauro Carvalho Chehab, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring,
	Bjorn Helgaas, Mathias Nyman, Greg Kroah-Hartman, Philipp Zabel
  Cc: linux-ide, linux-tegra, linux-kernel, dri-devel, nouveau,
	linux-media, linux-pci, linux-usb, Thierry Reding

From: Thierry Reding <treding@nvidia.com>

None of this legacy code is needed on 64-bit ARM devices, so it can be
moved behind a corresponding preprocessor guard. This more cleanly
separates out the legacy code from code needed on current platforms.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
Changes in v2:
- fix build issue for ARM && !PM_SLEEP
---
 drivers/soc/tegra/pmc.c | 244 +++++++++++++++++++++++++-----------------------
 include/soc/tegra/pmc.h |  42 ++++-----
 2 files changed, 147 insertions(+), 139 deletions(-)

diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index f25c8e73475c..210ee5124119 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -512,10 +512,12 @@ struct tegra_pmc {
 	u32 *wake_status;
 };
 
+#if defined(CONFIG_ARM)
 static struct tegra_pmc *early_pmc = &(struct tegra_pmc) {
 	.base = NULL,
 	.suspend_mode = TEGRA_SUSPEND_NOT_READY,
 };
+#endif
 
 static inline struct tegra_powergate *
 to_powergate(struct generic_pm_domain *domain)
@@ -1151,68 +1153,6 @@ int tegra_pmc_powergate_sequence_power_up(struct tegra_pmc *pmc,
 }
 EXPORT_SYMBOL(tegra_pmc_powergate_sequence_power_up);
 
-/**
- * tegra_get_cpu_powergate_id() - convert from CPU ID to partition ID
- * @pmc: power management controller
- * @cpuid: CPU partition ID
- *
- * Returns the partition ID corresponding to the CPU partition ID or a
- * negative error code on failure.
- */
-static int tegra_get_cpu_powergate_id(struct tegra_pmc *pmc,
-				      unsigned int cpuid)
-{
-	if (pmc->soc && cpuid < pmc->soc->num_cpu_powergates)
-		return pmc->soc->cpu_powergates[cpuid];
-
-	return -EINVAL;
-}
-
-/**
- * tegra_pmc_cpu_is_powered() - check if CPU partition is powered
- * @cpuid: CPU partition ID
- */
-bool tegra_pmc_cpu_is_powered(unsigned int cpuid)
-{
-	int id;
-
-	id = tegra_get_cpu_powergate_id(early_pmc, cpuid);
-	if (id < 0)
-		return false;
-
-	return tegra_powergate_is_powered(early_pmc, id);
-}
-
-/**
- * tegra_pmc_cpu_power_on() - power on CPU partition
- * @cpuid: CPU partition ID
- */
-int tegra_pmc_cpu_power_on(unsigned int cpuid)
-{
-	int id;
-
-	id = tegra_get_cpu_powergate_id(early_pmc, cpuid);
-	if (id < 0)
-		return id;
-
-	return tegra_powergate_set(early_pmc, id, true);
-}
-
-/**
- * tegra_pmc_cpu_remove_clamping() - remove power clamps for CPU partition
- * @cpuid: CPU partition ID
- */
-int tegra_pmc_cpu_remove_clamping(unsigned int cpuid)
-{
-	int id;
-
-	id = tegra_get_cpu_powergate_id(early_pmc, cpuid);
-	if (id < 0)
-		return id;
-
-	return tegra_pmc_powergate_remove_clamping(early_pmc, id);
-}
-
 static void tegra_pmc_program_reboot_reason(struct tegra_pmc *pmc,
 					    const char *cmd)
 {
@@ -1486,11 +1426,6 @@ static int tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
 	return err;
 }
 
-bool tegra_pmc_core_domain_state_synced(void)
-{
-	return early_pmc->core_domain_state_synced;
-}
-
 static int
 tegra_pmc_core_pd_set_performance_state(struct generic_pm_domain *genpd,
 					unsigned int level)
@@ -1904,57 +1839,6 @@ static int tegra_io_pad_get_voltage(struct tegra_pmc *pmc, enum tegra_io_pad id)
 	return TEGRA_IO_PAD_VOLTAGE_3V3;
 }
 
-#ifdef CONFIG_PM_SLEEP
-enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void)
-{
-	return early_pmc->suspend_mode;
-}
-
-void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode)
-{
-	if (mode < TEGRA_SUSPEND_NONE || mode >= TEGRA_MAX_SUSPEND_MODE)
-		return;
-
-	early_pmc->suspend_mode = mode;
-}
-
-void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode)
-{
-	unsigned long long rate = 0;
-	u64 ticks;
-	u32 value;
-
-	switch (mode) {
-	case TEGRA_SUSPEND_LP1:
-		rate = 32768;
-		break;
-
-	case TEGRA_SUSPEND_LP2:
-		rate = early_pmc->rate;
-		break;
-
-	default:
-		break;
-	}
-
-	if (WARN_ON_ONCE(rate == 0))
-		rate = 100000000;
-
-	ticks = early_pmc->cpu_good_time * rate + USEC_PER_SEC - 1;
-	do_div(ticks, USEC_PER_SEC);
-	tegra_pmc_writel(early_pmc, ticks, PMC_CPUPWRGOOD_TIMER);
-
-	ticks = early_pmc->cpu_off_time * rate + USEC_PER_SEC - 1;
-	do_div(ticks, USEC_PER_SEC);
-	tegra_pmc_writel(early_pmc, ticks, PMC_CPUPWROFF_TIMER);
-
-	value = tegra_pmc_readl(early_pmc, PMC_CNTRL);
-	value &= ~PMC_CNTRL_SIDE_EFFECT_LP0;
-	value |= PMC_CNTRL_CPU_PWRREQ_OE;
-	tegra_pmc_writel(early_pmc, value, PMC_CNTRL);
-}
-#endif
-
 static int tegra_pmc_parse_dt(struct tegra_pmc *pmc, struct device_node *np)
 {
 	u32 value, values[2];
@@ -3092,6 +2976,7 @@ static int tegra_pmc_probe(struct platform_device *pdev)
 	struct resource *res;
 	int err;
 
+#if defined(CONFIG_ARM)
 	/*
 	 * Early initialisation should have configured an initial
 	 * register mapping and setup the soc data pointer. If these
@@ -3099,6 +2984,7 @@ static int tegra_pmc_probe(struct platform_device *pdev)
 	 */
 	if (WARN_ON(!early_pmc->base || !early_pmc->soc))
 		return -ENODEV;
+#endif
 
 	pmc = devm_kzalloc(&pdev->dev, sizeof(*pmc), GFP_KERNEL);
 	if (!pmc)
@@ -3247,10 +3133,12 @@ static int tegra_pmc_probe(struct platform_device *pdev)
 	if (err < 0)
 		goto cleanup_powergates;
 
+#if defined(CONFIG_ARM)
 	mutex_lock(&early_pmc->powergates_lock);
 	iounmap(early_pmc->base);
 	early_pmc->base = pmc->base;
 	mutex_unlock(&early_pmc->powergates_lock);
+#endif
 
 	tegra_pmc_clock_register(pmc, pdev->dev.of_node);
 	platform_set_drvdata(pdev, pmc);
@@ -4833,6 +4721,125 @@ static struct platform_driver tegra_pmc_driver = {
 };
 builtin_platform_driver(tegra_pmc_driver);
 
+#if defined(CONFIG_ARM)
+/**
+ * tegra_get_cpu_powergate_id() - convert from CPU ID to partition ID
+ * @pmc: power management controller
+ * @cpuid: CPU partition ID
+ *
+ * Returns the partition ID corresponding to the CPU partition ID or a
+ * negative error code on failure.
+ */
+static int tegra_get_cpu_powergate_id(struct tegra_pmc *pmc,
+				      unsigned int cpuid)
+{
+	if (pmc->soc && cpuid < pmc->soc->num_cpu_powergates)
+		return pmc->soc->cpu_powergates[cpuid];
+
+	return -EINVAL;
+}
+
+/**
+ * tegra_pmc_cpu_is_powered() - check if CPU partition is powered
+ * @cpuid: CPU partition ID
+ */
+bool tegra_pmc_cpu_is_powered(unsigned int cpuid)
+{
+	int id;
+
+	id = tegra_get_cpu_powergate_id(early_pmc, cpuid);
+	if (id < 0)
+		return false;
+
+	return tegra_powergate_is_powered(early_pmc, id);
+}
+
+/**
+ * tegra_pmc_cpu_power_on() - power on CPU partition
+ * @cpuid: CPU partition ID
+ */
+int tegra_pmc_cpu_power_on(unsigned int cpuid)
+{
+	int id;
+
+	id = tegra_get_cpu_powergate_id(early_pmc, cpuid);
+	if (id < 0)
+		return id;
+
+	return tegra_powergate_set(early_pmc, id, true);
+}
+
+/**
+ * tegra_pmc_cpu_remove_clamping() - remove power clamps for CPU partition
+ * @cpuid: CPU partition ID
+ */
+int tegra_pmc_cpu_remove_clamping(unsigned int cpuid)
+{
+	int id;
+
+	id = tegra_get_cpu_powergate_id(early_pmc, cpuid);
+	if (id < 0)
+		return id;
+
+	return tegra_pmc_powergate_remove_clamping(early_pmc, id);
+}
+
+bool tegra_pmc_core_domain_state_synced(void)
+{
+	return early_pmc->core_domain_state_synced;
+}
+
+#ifdef CONFIG_PM_SLEEP
+enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void)
+{
+	return early_pmc->suspend_mode;
+}
+
+void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode)
+{
+	if (mode < TEGRA_SUSPEND_NONE || mode >= TEGRA_MAX_SUSPEND_MODE)
+		return;
+
+	early_pmc->suspend_mode = mode;
+}
+
+void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode)
+{
+	unsigned long long rate = 0;
+	u64 ticks;
+	u32 value;
+
+	switch (mode) {
+	case TEGRA_SUSPEND_LP1:
+		rate = 32768;
+		break;
+
+	case TEGRA_SUSPEND_LP2:
+		rate = early_pmc->rate;
+		break;
+
+	default:
+		break;
+	}
+
+	if (WARN_ON_ONCE(rate == 0))
+		rate = 100000000;
+
+	ticks = early_pmc->cpu_good_time * rate + USEC_PER_SEC - 1;
+	do_div(ticks, USEC_PER_SEC);
+	tegra_pmc_writel(early_pmc, ticks, PMC_CPUPWRGOOD_TIMER);
+
+	ticks = early_pmc->cpu_off_time * rate + USEC_PER_SEC - 1;
+	do_div(ticks, USEC_PER_SEC);
+	tegra_pmc_writel(early_pmc, ticks, PMC_CPUPWROFF_TIMER);
+
+	value = tegra_pmc_readl(early_pmc, PMC_CNTRL);
+	value &= ~PMC_CNTRL_SIDE_EFFECT_LP0;
+	value |= PMC_CNTRL_CPU_PWRREQ_OE;
+	tegra_pmc_writel(early_pmc, value, PMC_CNTRL);
+}
+#endif /* CONFIG_PM_SLEEP */
+
 /*
  * Early initialization to allow access to registers in the very early boot
  * process.
@@ -4911,3 +4918,4 @@ static int __init tegra_pmc_early_init(void)
 	return 0;
 }
 early_initcall(tegra_pmc_early_init);
+#endif /* CONFIG_ARM */
diff --git a/include/soc/tegra/pmc.h b/include/soc/tegra/pmc.h
index 8b4bcdea849e..4bcbf19d75ac 100644
--- a/include/soc/tegra/pmc.h
+++ b/include/soc/tegra/pmc.h
@@ -18,10 +18,6 @@ struct clk;
 struct reset_control;
 struct tegra_pmc;
 
-bool tegra_pmc_cpu_is_powered(unsigned int cpuid);
-int tegra_pmc_cpu_power_on(unsigned int cpuid);
-int tegra_pmc_cpu_remove_clamping(unsigned int cpuid);
-
 /*
  * powergate and I/O rail APIs
  */
@@ -163,12 +159,6 @@ int tegra_pmc_powergate_sequence_power_up(struct tegra_pmc *pmc,
 int tegra_pmc_io_pad_power_enable(struct tegra_pmc *pmc, enum tegra_io_pad id);
 int tegra_pmc_io_pad_power_disable(struct tegra_pmc *pmc, enum tegra_io_pad id);
 
-/* legacy */
-void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode);
-void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode);
-
-bool tegra_pmc_core_domain_state_synced(void);
-
 #else
 static inline struct tegra_pmc *devm_tegra_pmc_get(struct device *dev)
 {
@@ -213,28 +203,38 @@ tegra_pmc_io_pad_power_disable(struct tegra_pmc *pmc, enum tegra_io_pad id)
 {
 	return -ENOSYS;
 }
+#endif /* CONFIG_SOC_TEGRA_PMC */
 
-static inline void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode)
+/* 32-bit ARM platforms only */
+#if defined(CONFIG_ARM)
+bool tegra_pmc_cpu_is_powered(unsigned int cpuid);
+int tegra_pmc_cpu_power_on(unsigned int cpuid);
+int tegra_pmc_cpu_remove_clamping(unsigned int cpuid);
+bool tegra_pmc_core_domain_state_synced(void);
+
+#if defined(CONFIG_SOC_TEGRA_PMC) && defined(CONFIG_PM_SLEEP)
+enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void);
+void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode);
+void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode);
+#else
+static inline enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void)
 {
+	return TEGRA_SUSPEND_NONE;
 }
 
-static inline void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode)
+static inline void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode)
 {
 }
 
-static inline bool tegra_pmc_core_domain_state_synced(void)
+static inline void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode)
 {
-	return false;
 }
-
-#endif /* CONFIG_SOC_TEGRA_PMC */
-
-#if defined(CONFIG_SOC_TEGRA_PMC) && defined(CONFIG_PM_SLEEP)
-enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void);
+#endif
 #else
-static inline enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void)
+/* needed for COMPILE_TEST */
+static inline bool tegra_pmc_core_domain_state_synced(void)
 {
-	return TEGRA_SUSPEND_NONE;
+	return false;
 }
 #endif
 

-- 
2.52.0


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

* Re: [PATCH 1/9] ata: ahci_tegra: Explicitly specify PMC instance to use
  2026-05-06 13:41 ` [PATCH 1/9] ata: ahci_tegra: Explicitly specify PMC instance to use Thierry Reding
@ 2026-05-06 13:54   ` Damien Le Moal
  0 siblings, 0 replies; 11+ messages in thread
From: Damien Le Moal @ 2026-05-06 13:54 UTC (permalink / raw)
  To: Thierry Reding, Niklas Cassel, Jonathan Hunter, Lyude Paul,
	Danilo Krummrich, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Mikko Perttunen,
	Dmitry Osipenko, Mauro Carvalho Chehab, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring,
	Bjorn Helgaas, Mathias Nyman, Greg Kroah-Hartman, Philipp Zabel
  Cc: linux-ide, linux-tegra, linux-kernel, dri-devel, nouveau,
	linux-media, linux-pci, linux-usb, Thierry Reding

On 2026/05/06 15:41, Thierry Reding wrote:
> From: Thierry Reding <treding@nvidia.com>
> 
> Currently the kernel relies on a global variable to reference the PMC
> context. Use an explicit lookup for the PMC and pass that to the public
> PMC APIs.
> 
> Signed-off-by: Thierry Reding <treding@nvidia.com>

Acked-by: Damien Le Moal <dlemoal@kernel.org>

Applying this through the Tegra tree is fine with me.


-- 
Damien Le Moal
Western Digital Research

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

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

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-06 13:41 [PATCH 0/9] soc/tegra: pmc: Clean up legacy code Thierry Reding
2026-05-06 13:41 ` [PATCH 1/9] ata: ahci_tegra: Explicitly specify PMC instance to use Thierry Reding
2026-05-06 13:54   ` Damien Le Moal
2026-05-06 13:41 ` [PATCH 2/9] drm/nouveau: tegra: " Thierry Reding
2026-05-06 13:41 ` [PATCH 3/9] drm/tegra: " Thierry Reding
2026-05-06 13:41 ` [PATCH 4/9] media: vde: " Thierry Reding
2026-05-06 13:41 ` [PATCH 5/9] PCI: tegra: " Thierry Reding
2026-05-06 13:41 ` [PATCH 6/9] usb: xhci: " Thierry Reding
2026-05-06 13:41 ` [PATCH 7/9] soc/tegra: pmc: Create PMC context dynamically Thierry Reding
2026-05-06 13:41 ` [PATCH 8/9] soc/tegra: pmc: Remove unused legacy functions Thierry Reding
2026-05-06 13:42 ` [PATCH 9/9] soc/tegra: pmc: Move legacy code behind CONFIG_ARM guard Thierry Reding

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