From 64e609f9299d457a88dec0bce68b42a434a78502 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 3 Feb 2025 16:25:29 +0100 Subject: [PATCH 01/12] ata: ahci_tegra: Explicitly specify PMC instance to use 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. Acked-by: Damien Le Moal Acked-by: Jon Hunter Signed-off-by: Thierry Reding --- 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); From 3ef27f1ad5ed0e36c2dac82876ef7dde33a588f2 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 3 Feb 2025 16:27:02 +0100 Subject: [PATCH 02/12] drm/nouveau: tegra: Explicitly specify PMC instance to use 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. Acked-by: Danilo Krummrich Acked-by: Jon Hunter Signed-off-by: Thierry Reding --- 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. */ From e68c4244136b8e9c2a9fc3aaa4d748be83afddef Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 3 Feb 2025 16:28:38 +0100 Subject: [PATCH 03/12] drm/tegra: Explicitly specify PMC instance to use 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. Acked-by: Jon Hunter Signed-off-by: Thierry Reding --- 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); From c4d22e0d4458b79c716c64b57bee4022cead2b5e Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 3 Feb 2025 16:29:35 +0100 Subject: [PATCH 04/12] media: vde: Explicitly specify PMC instance to use 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. Acked-by: Jon Hunter Signed-off-by: Thierry Reding --- 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; From 5f726aeb505c9e5dde87530c78a11b88a44b9edd Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 3 Feb 2025 16:30:24 +0100 Subject: [PATCH 05/12] PCI: tegra: Explicitly specify PMC instance to use 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. Acked-by: Manivannan Sadhasivam Acked-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/pci/controller/pci-tegra.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/pci/controller/pci-tegra.c b/drivers/pci/controller/pci-tegra.c index 512309763d1f..229c69534476 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,11 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie) return err; } + pcie->pmc = devm_tegra_pmc_get(dev); + if (IS_ERR(pcie->pmc)) + return dev_err_probe(dev, PTR_ERR(pcie->pmc), + "failed to get PMC\n"); + if (soc->program_uphy) { err = tegra_pcie_phys_get(pcie); if (err < 0) { From 258cff9857918615897bd5b57c588dc13c0058b6 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 3 Feb 2025 16:31:14 +0100 Subject: [PATCH 06/12] usb: xhci: tegra: Explicitly specify PMC instance to use 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. Acked-by: Mathias Nyman Acked-by: Jon Hunter Signed-off-by: Thierry Reding --- 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) From 4d61f03426892b14d498e160be245edcb9dd8359 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 3 Feb 2025 18:12:58 +0100 Subject: [PATCH 07/12] soc/tegra: pmc: Create PMC context dynamically 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). Acked-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 208 ++++++++++++++++++++++------------------ 1 file changed, 115 insertions(+), 93 deletions(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 2ee6539d796a..ff748d209d40 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -390,8 +390,7 @@ struct tegra_pmc_soc { const struct tegra_pmc_regs *regs; void (*init)(struct tegra_pmc *pmc); void (*setup_irq_polarity)(struct tegra_pmc *pmc, - struct device_node *np, - bool invert); + struct device_node *np); void (*set_wake_filters)(struct tegra_pmc *pmc); int (*irq_set_wake)(struct irq_data *data, unsigned int on); int (*irq_set_type)(struct irq_data *data, unsigned int type); @@ -444,6 +443,7 @@ struct tegra_pmc_soc { * @cpu_pwr_good_en: CPU power good signal is enabled * @lp0_vec_phys: physical base address of the LP0 warm boot code * @lp0_vec_size: size of the LP0 warm boot code + * @invert_irq: polarity of the PMU IRQ is inverted * @powergates_available: Bitmap of available power gates * @powergates_lock: mutex for power gate register access * @pctl_dev: pin controller exposed by the PMC @@ -486,6 +486,8 @@ struct tegra_pmc { bool cpu_pwr_good_en; u32 lp0_vec_phys; u32 lp0_vec_size; + bool invert_irq; + DECLARE_BITMAP(powergates_available, TEGRA_POWERGATE_MAX); struct mutex powergates_lock; @@ -512,7 +514,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 +1071,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 +1095,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 +1132,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 +1194,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 +1223,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 +1238,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 +1253,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 +1535,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 +1833,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 +1889,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 +1978,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 +1986,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 +2001,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 +2011,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 @@ -2094,6 +2096,8 @@ static int tegra_pmc_parse_dt(struct tegra_pmc *pmc, struct device_node *np) pmc->lp0_vec_phys = values[0]; pmc->lp0_vec_size = values[1]; + pmc->invert_irq = of_property_read_bool(np, "nvidia,invert-interrupt"); + return 0; } @@ -3110,6 +3114,51 @@ 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, struct device_node *np) +{ + unsigned int i; + + if (pmc->soc->maybe_tz_only) + 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); + + /* + * Invert the interrupt polarity if a PMC device tree node exists and + * contains the nvidia,invert-interrupt property. + */ + pmc->soc->setup_irq_polarity(pmc, np); +} + static void tegra_pmc_reset_suspend_mode(void *data) { struct tegra_pmc *pmc = data; @@ -3119,7 +3168,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,12 +3177,20 @@ 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); + mutex_init(&pmc->powergates_lock); + pmc->dev = &pdev->dev; + err = tegra_pmc_parse_dt(pmc, pdev->dev.of_node); if (err < 0) - return err; + return dev_err_probe(&pdev->dev, err, "failed to parse DT\n"); err = devm_add_action_or_reset(&pdev->dev, tegra_pmc_reset_suspend_mode, pmc); @@ -3141,14 +3198,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 +3224,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)) @@ -3182,6 +3239,8 @@ static int tegra_pmc_probe(struct platform_device *pdev) return dev_err_probe(&pdev->dev, PTR_ERR(pmc->clk), "failed to get pclk\n"); + tegra_pmc_init_common(pmc, pdev->dev.of_node); + /* * PMC should be last resort for restarting since it soft-resets * CPU without resetting everything else. @@ -3243,8 +3302,6 @@ static int tegra_pmc_probe(struct platform_device *pdev) pmc->rate = clk_get_rate(pmc->clk); } - pmc->dev = &pdev->dev; - err = tegra_pmc_init(pmc); if (err < 0) { dev_err(&pdev->dev, "failed to initialize PMC: %d\n", err); @@ -3271,10 +3328,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); @@ -3523,14 +3580,13 @@ static void tegra20_pmc_init(struct tegra_pmc *pmc) } static void tegra20_pmc_setup_irq_polarity(struct tegra_pmc *pmc, - struct device_node *np, - bool invert) + struct device_node *np) { u32 value; value = tegra_pmc_readl(pmc, PMC_CNTRL); - if (invert) + if (pmc->invert_irq) value |= PMC_CNTRL_INTR_POLARITY; else value &= ~PMC_CNTRL_INTR_POLARITY; @@ -4136,8 +4192,7 @@ static void tegra186_pmc_init(struct tegra_pmc *pmc) } static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc, - struct device_node *np, - bool invert) + struct device_node *np) { struct resource regs; void __iomem *wake; @@ -4160,7 +4215,7 @@ static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc, value = readl(wake + pmc->soc->regs->aowake_ctrl); - if (invert) + if (pmc->invert_irq) value |= WAKE_AOWAKE_CTRL_INTR_POLARITY; else value &= ~WAKE_AOWAKE_CTRL_INTR_POLARITY; @@ -4799,6 +4854,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 +4912,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 +4921,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; + int err; - 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,31 +4964,24 @@ static int __init tegra_pmc_early_init(void) } } - pmc->base = ioremap(regs.start, resource_size(®s)); - if (!pmc->base) { + early_pmc->base = ioremap(regs.start, resource_size(®s)); + 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; + early_pmc->soc = match->data; - if (pmc->soc->maybe_tz_only) - pmc->tz_only = tegra_pmc_detect_tz_only(pmc); + err = tegra_pmc_parse_dt(early_pmc, np); + if (err < 0) { + pr_err("failed to parse DT: %d\n", err); + of_node_put(np); + return err; + } - /* 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); - - /* - * Invert the interrupt polarity if a PMC device tree node - * exists and contains the nvidia,invert-interrupt property. - */ - invert = of_property_read_bool(np, "nvidia,invert-interrupt"); - - pmc->soc->setup_irq_polarity(pmc, np, invert); + tegra_pmc_init_common(early_pmc, np); of_node_put(np); } From 72a2a9023c329aca7e7f8d3997c9a26aa317a1fd Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 4 Feb 2025 19:45:19 +0100 Subject: [PATCH 08/12] soc/tegra: pmc: Remove unused legacy functions 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. Acked-by: Jon Hunter Signed-off-by: Thierry Reding --- 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 ff748d209d40..0acc25e7b732 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -1065,16 +1065,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 @@ -1089,16 +1079,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 @@ -1126,16 +1106,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 @@ -1183,21 +1153,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 @@ -1825,18 +1780,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 @@ -1881,18 +1824,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) { } From 8318af5dd29c819d95ec5b878e7dab6090a9ed2b Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 4 Feb 2025 19:04:51 +0100 Subject: [PATCH 09/12] soc/tegra: pmc: Move legacy code behind CONFIG_ARM guard 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. Acked-by: Jon Hunter Signed-off-by: Thierry Reding --- 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 0acc25e7b732..da60e7e5927d 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -514,10 +514,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) @@ -1153,68 +1155,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) { @@ -1488,11 +1428,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) @@ -1906,57 +1841,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]; @@ -3103,6 +2987,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 @@ -3110,6 +2995,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) @@ -3259,10 +3145,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); @@ -4843,6 +4731,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. @@ -4920,3 +4927,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,6 +203,24 @@ tegra_pmc_io_pad_power_disable(struct tegra_pmc *pmc, enum tegra_io_pad id) { return -ENOSYS; } +#endif /* CONFIG_SOC_TEGRA_PMC */ + +/* 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_set_suspend_mode(enum tegra_suspend_mode mode) { @@ -221,21 +229,13 @@ static inline void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode) static inline void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode) { } - +#endif +#else +/* needed for COMPILE_TEST */ static inline bool tegra_pmc_core_domain_state_synced(void) { 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); -#else -static inline enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void) -{ - return TEGRA_SUSPEND_NONE; -} #endif #endif /* __SOC_TEGRA_PMC_H__ */ From e9bfdf06fb05168e72d3d9d6163b04e2316e0aa2 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 22 May 2026 16:58:24 +0100 Subject: [PATCH 10/12] soc/tegra: pmc: Populate powergate debugfs only when needed The 'powergate' debugfs node is used to show the state of the powergates but for some devices the 'num_powergates' is 0 and so it displays nothing. Therefore, only populate this debugfs entry for devices where num_powergates is greater than 0. Signed-off-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index da60e7e5927d..d4edf701a40f 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -3160,7 +3160,8 @@ static int tegra_pmc_probe(struct platform_device *pdev) if (pmc->soc->set_wake_filters) pmc->soc->set_wake_filters(pmc); - debugfs_create_file("powergate", 0444, NULL, pmc, &powergate_fops); + if (pmc->soc->num_powergates) + debugfs_create_file("powergate", 0444, NULL, pmc, &powergate_fops); return 0; From 2545b16e3ea049a266ec8b0e509d4e093b26b906 Mon Sep 17 00:00:00 2001 From: Diogo Ivo Date: Thu, 21 May 2026 15:48:48 +0200 Subject: [PATCH 11/12] soc/tegra: pmc: Restrict power-off handler to Nexus 7 The Tegra PMC power-off handler exists solely to reboot the Nexus 7 into a special bootloader mode when a USB cable is connected, so that the bootloader can display battery status instead of powering off. There is no reason to register it on any other Tegra board. Guard the registration behind of_machine_is_compatible("asus,grouper") and rename the handler to tegra_pmc_grouper_power_off_handler to make its scope explicit. The of_machine_is_compatible() check inside the handler itself is now redundant and is removed. This also avoids occupying SYS_OFF_PRIO_FIRMWARE on boards that have other handlers at that priority level. Assisted-by: Claude:claude-sonnet-4-6 Signed-off-by: Diogo Ivo Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index d4edf701a40f..873edc3e7a22 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -1207,7 +1207,7 @@ static int tegra_pmc_restart_handler(struct sys_off_data *data) return NOTIFY_DONE; } -static int tegra_pmc_power_off_handler(struct sys_off_data *data) +static int tegra_pmc_grouper_power_off_handler(struct sys_off_data *data) { struct tegra_pmc *pmc = data->cb_data; @@ -1215,8 +1215,7 @@ static int tegra_pmc_power_off_handler(struct sys_off_data *data) * Reboot Nexus 7 into special bootloader mode if USB cable is * connected in order to display battery status and power off. */ - if (of_machine_is_compatible("asus,grouper") && - power_supply_is_system_supplied()) { + if (power_supply_is_system_supplied()) { const u32 go_to_charger_mode = 0xa5a55a5a; tegra_pmc_writel(pmc, go_to_charger_mode, PMC_SCRATCH37); @@ -3087,18 +3086,20 @@ static int tegra_pmc_probe(struct platform_device *pdev) } /* - * PMC should be primary power-off method if it soft-resets CPU, - * asking bootloader to shutdown hardware. + * PMC should be primary power-off method on Grouper if it soft-resets + * CPU, asking bootloader to shutdown hardware. */ - err = devm_register_sys_off_handler(&pdev->dev, - SYS_OFF_MODE_POWER_OFF, - SYS_OFF_PRIO_FIRMWARE, - tegra_pmc_power_off_handler, - pmc); - if (err) { - dev_err(&pdev->dev, "failed to register sys-off handler: %d\n", - err); - return err; + if (of_machine_is_compatible("asus,grouper")) { + err = devm_register_sys_off_handler(&pdev->dev, + SYS_OFF_MODE_POWER_OFF, + SYS_OFF_PRIO_FIRMWARE, + tegra_pmc_grouper_power_off_handler, + pmc); + if (err) { + dev_err(&pdev->dev, "failed to register sys-off handler: %d\n", + err); + return err; + } } /* From 2cee7da9743396aff1fd13124109c78975c92ad8 Mon Sep 17 00:00:00 2001 From: Prathamesh Shete Date: Mon, 18 May 2026 10:14:20 +0000 Subject: [PATCH 12/12] soc/tegra: pmc: Add Tegra238 support The Tegra238 PMC is largely similar to that found on earlier chips, but not completely compatible. Add support for the PMC on Tegra238. Signed-off-by: Prathamesh Shete Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 159 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 873edc3e7a22..f419a5395545 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -4471,6 +4471,164 @@ static const struct tegra_pmc_soc tegra234_pmc_soc = { .has_single_mmio_aperture = false, }; +static const struct tegra_io_pad_soc tegra238_io_pads[] = { + TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP0, 0, 0xe028, 0xe02c, "hdmi-dp0"), + TEGRA_IO_PAD(TEGRA_IO_PAD_UFS, 0, 0xe06c, 0xe070, "ufs"), + TEGRA_IO_PAD(TEGRA_IO_PAD_EDP, 2, 0xe040, 0xe044, "edp"), + TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1_HV, 0, 0xe058, 0xe05c, "sdmmc1-hv"), + TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3_HV, UINT_MAX, UINT_MAX, UINT_MAX, "sdmmc3-hv"), + TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO_HV, UINT_MAX, UINT_MAX, UINT_MAX, "audio-hv"), + TEGRA_IO_PAD(TEGRA_IO_PAD_AO_HV, UINT_MAX, UINT_MAX, UINT_MAX, "ao-hv"), +}; + +static const struct tegra_io_pad_vctrl tegra238_io_pad_vctrls[] = { + TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_SDMMC1_HV, PMC_IMPL_E_33V_PWR, 4), + TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_SDMMC3_HV, PMC_IMPL_E_33V_PWR, 6), + TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_AUDIO_HV, PMC_IMPL_E_33V_PWR, 1), + TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_AO_HV, PMC_IMPL_E_33V_PWR, 0), +}; + +static const struct pinctrl_pin_desc tegra238_pin_descs[] = { + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI_DP0, "hdmi-dp0"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UFS, "ufs"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_EDP, "edp"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC1_HV, "sdmmc1-hv"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC3_HV, "sdmmc3-hv"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AUDIO_HV, "audio-hv"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AO_HV, "ao-hv"), +}; + +static const struct tegra_pmc_regs tegra238_pmc_regs = { + .scratch0 = 0x2000, + .rst_status = 0x70, + .rst_source_shift = 0x2, + .rst_source_mask = 0xfc, + .rst_level_shift = 0x0, + .rst_level_mask = 0x3, + .aowake_mask_w = 0x180, + .aowake_status_w = 0x30c, + .aowake_status_r = 0x48c, + .aowake_tier2_routing = 0x4cc, + .aowake_sw_status_w = 0x49c, + .aowake_sw_status = 0x4a0, + .aowake_latch_sw = 0x498, + .aowake_ctrl = 0x4f4, +}; + +static const char * const tegra238_reset_sources[] = { + "SYS_RESET_N", /* 0 */ + "AOWDT", + NULL, + "BPMPWDT", + NULL, + "SPEWDT", /* 5 */ + NULL, + NULL, + "SENSOR", + NULL, + NULL, /* 10 */ + "MAINSWRST", + "SC7", + NULL, + NULL, + NULL, /* 15 */ + NULL, + NULL, + "RTC_XTAL_CSDC", + "BPMPBOOT", + "FUSECRC", /* 20 */ + NULL, + "PSCWDT", + "PSC_SW", + "CSITE_SW", + NULL, /* 25 */ + NULL, + "VREFRO_POWERBAD", + NULL, + NULL, + NULL, /* 30 */ + NULL, + NULL, + NULL, + NULL, + NULL, /* 35 */ + NULL, + NULL, + "TOP0WDT", + "TOP1WDT", + "TOP2WDT", /* 40 */ + "APE_C0WDT", + "APE_C1WDT", + "APE_C2WDT", + "APE_C3WDT", + "SCPM_SOC_XTAL", /* 45 */ + "SCPM_RTC_XTAL", + "SCPM_BPMP_CORE_CLK", + "SCPM_PSC_SE_CLK", + "FMON_32K", + "FMON_OSC", /* 50 */ + "VMON_SOC", + "VMON_CPU0", + NULL, + "POD_CPU", + "POD_GPU", /* 55 */ + "POD_RTC", + NULL, + "POD_IO", + "POD_PLUS_SOC", + "POD_PLUS_IO_VMON", /* 60 */ + "POD_PLUS_IO_PSCPLL", + "VMON_PLUS_0", + "VMON_PLUS_1", /* 63 */ +}; + +static const struct tegra_wake_event tegra238_wake_events[] = { + TEGRA_WAKE_IRQ("rtc", 73, 10), + TEGRA_WAKE_IRQ("pmu", 24, 209), + TEGRA_WAKE_IRQ("usb3-port-0", 76, 167), + TEGRA_WAKE_IRQ("usb3-port-1", 77, 167), + TEGRA_WAKE_IRQ("usb3-port-2", 78, 167), + TEGRA_WAKE_IRQ("usb2-port-0", 79, 167), + TEGRA_WAKE_IRQ("usb2-port-1", 80, 167), + TEGRA_WAKE_IRQ("usb2-port-2", 81, 167), +}; + +static const struct tegra_pmc_soc tegra238_pmc_soc = { + .num_powergates = 0, + .powergates = NULL, + .num_cpu_powergates = 0, + .cpu_powergates = NULL, + .has_tsense_reset = false, + .has_gpu_clamps = false, + .needs_mbist_war = false, + .has_io_pad_wren = false, + .maybe_tz_only = false, + .num_io_pads = ARRAY_SIZE(tegra238_io_pads), + .io_pads = tegra238_io_pads, + .num_io_pad_vctrls = ARRAY_SIZE(tegra238_io_pad_vctrls), + .io_pad_vctrls = tegra238_io_pad_vctrls, + .num_pin_descs = ARRAY_SIZE(tegra238_pin_descs), + .pin_descs = tegra238_pin_descs, + .regs = &tegra238_pmc_regs, + .init = tegra186_pmc_init, + .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, + .set_wake_filters = tegra186_pmc_set_wake_filters, + .irq_set_wake = tegra186_pmc_irq_set_wake, + .irq_set_type = tegra186_pmc_irq_set_type, + .reset_sources = tegra238_reset_sources, + .num_reset_sources = ARRAY_SIZE(tegra238_reset_sources), + .reset_levels = tegra186_reset_levels, + .num_reset_levels = ARRAY_SIZE(tegra186_reset_levels), + .num_wake_events = ARRAY_SIZE(tegra238_wake_events), + .wake_events = tegra238_wake_events, + .max_wake_events = 96, + .max_wake_vectors = 3, + .pmc_clks_data = NULL, + .num_pmc_clks = 0, + .has_blink_output = false, + .has_single_mmio_aperture = false, +}; + #define TEGRA264_IO_PAD_VCTRL(_id, _offset, _ena_3v3, _ena_1v8) \ ((struct tegra_io_pad_vctrl) { \ .id = (_id), \ @@ -4661,6 +4819,7 @@ static const struct tegra_pmc_soc tegra264_pmc_soc = { static const struct of_device_id tegra_pmc_match[] = { { .compatible = "nvidia,tegra264-pmc", .data = &tegra264_pmc_soc }, + { .compatible = "nvidia,tegra238-pmc", .data = &tegra238_pmc_soc }, { .compatible = "nvidia,tegra234-pmc", .data = &tegra234_pmc_soc }, { .compatible = "nvidia,tegra194-pmc", .data = &tegra194_pmc_soc }, { .compatible = "nvidia,tegra186-pmc", .data = &tegra186_pmc_soc },