aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
authorMark Brown <broonie@kernel.org>2026-05-29 18:09:03 +0100
committerMark Brown <broonie@kernel.org>2026-05-29 18:09:03 +0100
commit1468c70a92378ec85d66fce71a533d4bee6ed8cd (patch)
treef7ae0e67f2b3cc81a01a4ccfa472e1cf006508d8 /drivers
parent636537b990be485724c0965ceb848e7e311e0254 (diff)
parentd6c3060f8c5df453d92216fcf629a23ee0852d37 (diff)
downloadlinux-next-history-1468c70a92378ec85d66fce71a533d4bee6ed8cd.tar.gz
Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ata/ahci_tegra.c17
-rw-r--r--drivers/bus/tegra-aconnect.c14
-rw-r--r--drivers/firmware/tegra/Kconfig2
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c9
-rw-r--r--drivers/gpu/drm/tegra/dc.c14
-rw-r--r--drivers/gpu/drm/tegra/dc.h1
-rw-r--r--drivers/gpu/drm/tegra/gr3d.c9
-rw-r--r--drivers/gpu/drm/tegra/sor.c16
-rw-r--r--drivers/media/platform/nvidia/tegra-vde/vde.c15
-rw-r--r--drivers/media/platform/nvidia/tegra-vde/vde.h1
-rw-r--r--drivers/pci/controller/pci-tegra.c19
-rw-r--r--drivers/soc/tegra/fuse/fuse-tegra.c14
-rw-r--r--drivers/soc/tegra/pmc.c603
-rw-r--r--drivers/usb/host/xhci-tegra.c38
15 files changed, 475 insertions, 299 deletions
diff --git a/drivers/ata/ahci_tegra.c b/drivers/ata/ahci_tegra.c
index 44584eed63744..554f05e09f983 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 @@ disable_power:
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);
diff --git a/drivers/bus/tegra-aconnect.c b/drivers/bus/tegra-aconnect.c
index 90e3b0a108161..9b2b227332b22 100644
--- a/drivers/bus/tegra-aconnect.c
+++ b/drivers/bus/tegra-aconnect.c
@@ -32,16 +32,14 @@ static int tegra_aconnect_probe(struct platform_device *pdev)
return -ENOMEM;
aconnect->ape_clk = devm_clk_get(&pdev->dev, "ape");
- if (IS_ERR(aconnect->ape_clk)) {
- dev_err(&pdev->dev, "Can't retrieve ape clock\n");
- return PTR_ERR(aconnect->ape_clk);
- }
+ if (IS_ERR(aconnect->ape_clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(aconnect->ape_clk),
+ "can't retrieve ape clock\n");
aconnect->apb2ape_clk = devm_clk_get(&pdev->dev, "apb2ape");
- if (IS_ERR(aconnect->apb2ape_clk)) {
- dev_err(&pdev->dev, "Can't retrieve apb2ape clock\n");
- return PTR_ERR(aconnect->apb2ape_clk);
- }
+ if (IS_ERR(aconnect->apb2ape_clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(aconnect->apb2ape_clk),
+ "can't retrieve apb2ape clock\n");
dev_set_drvdata(&pdev->dev, aconnect);
pm_runtime_enable(&pdev->dev);
diff --git a/drivers/firmware/tegra/Kconfig b/drivers/firmware/tegra/Kconfig
index 91f2320c0d0f8..3a91627064390 100644
--- a/drivers/firmware/tegra/Kconfig
+++ b/drivers/firmware/tegra/Kconfig
@@ -2,7 +2,7 @@
menu "Tegra firmware driver"
config TEGRA_IVC
- bool "Tegra IVC protocol" if COMPILE_TEST
+ bool
depends on ARCH_TEGRA
help
IVC (Inter-VM Communication) protocol is part of the IPC
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h b/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h
index 57bc542780bbe..6aaa30ef167f6 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 46bb55a1f565d..3c8d0878891ad 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.
*/
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 06370b7e0e567..e6099f5aced7a 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 0559fa6b1bf70..10b86250e4ca6 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 42e9656ab80c9..debf66fa4eebc 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 de8b2dfc4984c..a76095838133e 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);
diff --git a/drivers/media/platform/nvidia/tegra-vde/vde.c b/drivers/media/platform/nvidia/tegra-vde/vde.c
index 2b3898828304d..c3097085ad9d1 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 b2890484b7c34..abac0221d6e4b 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;
diff --git a/drivers/pci/controller/pci-tegra.c b/drivers/pci/controller/pci-tegra.c
index 512309763d1fb..229c695344767 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 @@ disable_afi_clk:
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) {
diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c
index 291484595dcfa..071cd9620634c 100644
--- a/drivers/soc/tegra/fuse/fuse-tegra.c
+++ b/drivers/soc/tegra/fuse/fuse-tegra.c
@@ -182,10 +182,6 @@ static int tegra_fuse_probe(struct platform_device *pdev)
}
fuse->soc->init(fuse);
-
- err = tegra_fuse_add_lookups(fuse);
- if (err)
- return dev_err_probe(&pdev->dev, err, "failed to add FUSE lookups\n");
}
fuse->clk = devm_clk_get_optional(&pdev->dev, "fuse");
@@ -231,6 +227,10 @@ static int tegra_fuse_probe(struct platform_device *pdev)
return err;
}
+ err = tegra_fuse_add_lookups(fuse);
+ if (err)
+ return dev_err_probe(&pdev->dev, err, "failed to add FUSE lookups\n");
+
fuse->rst = devm_reset_control_get_optional(&pdev->dev, "fuse");
if (IS_ERR(fuse->rst))
return dev_err_probe(&pdev->dev, PTR_ERR(fuse->rst), "failed to get FUSE reset\n");
@@ -473,7 +473,7 @@ static int __init tegra_init_fuse(void)
const struct of_device_id *match;
struct device_node *np;
struct resource regs;
- int err;
+ int err = 0;
tegra_init_apbmisc();
@@ -566,10 +566,6 @@ static int __init tegra_init_fuse(void)
tegra_fuse_print_sku_info(&tegra_sku_info);
- err = tegra_fuse_add_lookups(fuse);
- if (err)
- pr_err("failed to add FUSE lookups\n");
-
return err;
}
early_initcall(tegra_init_fuse);
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 2ee6539d796a5..3f13d150ecaba 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -512,10 +512,12 @@ struct tegra_pmc {
u32 *wake_status;
};
-static struct tegra_pmc *pmc = &(struct tegra_pmc) {
+#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)
@@ -1064,16 +1066,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(pmc, id);
-}
-EXPORT_SYMBOL(tegra_powergate_power_on);
-
-/**
* tegra_pmc_powergate_power_off() - power off partition
* @pmc: power management controller
* @id: partition ID
@@ -1088,16 +1080,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(pmc, id);
-}
-EXPORT_SYMBOL(tegra_powergate_power_off);
-
-/**
* tegra_powergate_is_powered() - check if partition is powered
* @pmc: power management controller
* @id: partition ID
@@ -1125,16 +1107,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(pmc, id);
-}
-EXPORT_SYMBOL(tegra_powergate_remove_clamping);
-
-/**
* tegra_pmc_powergate_sequence_power_up() - power up partition
* @pmc: power management controller
* @id: partition ID
@@ -1181,83 +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(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
- * @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(pmc, cpuid);
- if (id < 0)
- return false;
-
- return tegra_powergate_is_powered(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(pmc, cpuid);
- if (id < 0)
- return id;
-
- return tegra_powergate_set(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(pmc, cpuid);
- if (id < 0)
- return id;
-
- return tegra_powergate_remove_clamping(id);
-}
-
static void tegra_pmc_program_reboot_reason(struct tegra_pmc *pmc,
const char *cmd)
{
@@ -1310,7 +1205,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;
@@ -1318,8 +1213,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);
@@ -1531,11 +1425,6 @@ free_mem:
return err;
}
-bool tegra_pmc_core_domain_state_synced(void)
-{
- return pmc->core_domain_state_synced;
-}
-
static int
tegra_pmc_core_pd_set_performance_state(struct generic_pm_domain *genpd,
unsigned int level)
@@ -1824,18 +1713,6 @@ unlock:
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(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
* @id: Tegra I/O pad ID for which to disable power
@@ -1879,18 +1756,6 @@ unlock:
}
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(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;
@@ -1973,57 +1838,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 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;
-
- 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 = pmc->rate;
- break;
-
- default:
- break;
- }
-
- if (WARN_ON_ONCE(rate == 0))
- rate = 100000000;
-
- ticks = pmc->cpu_good_time * rate + USEC_PER_SEC - 1;
- do_div(ticks, USEC_PER_SEC);
- tegra_pmc_writel(pmc, ticks, PMC_CPUPWRGOOD_TIMER);
-
- ticks = pmc->cpu_off_time * rate + USEC_PER_SEC - 1;
- do_div(ticks, USEC_PER_SEC);
- tegra_pmc_writel(pmc, ticks, PMC_CPUPWROFF_TIMER);
-
- value = tegra_pmc_readl(pmc, PMC_CNTRL);
- value &= ~PMC_CNTRL_SIDE_EFFECT_LP0;
- value |= PMC_CNTRL_CPU_PWRREQ_OE;
- tegra_pmc_writel(pmc, value, PMC_CNTRL);
-}
-#endif
-
static int tegra_pmc_parse_dt(struct tegra_pmc *pmc, struct device_node *np)
{
u32 value, values[2];
@@ -3110,6 +2924,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,17 +2971,26 @@ 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;
+#if defined(CONFIG_ARM)
/*
* Early initialisation should have configured an initial
* 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;
+#endif
+
+ 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)
@@ -3141,14 +3002,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 +3028,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))
@@ -3211,18 +3072,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;
+ }
}
/*
@@ -3271,10 +3134,12 @@ 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);
+#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);
@@ -3284,7 +3149,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;
@@ -4595,6 +4461,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), \
@@ -4785,6 +4809,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 },
@@ -4799,6 +4824,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,31 +4882,124 @@ 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)
+#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)
{
- u32 value, saved;
+ if (pmc->soc && cpuid < pmc->soc->num_cpu_powergates)
+ return pmc->soc->cpu_powergates[cpuid];
- saved = readl(pmc->base + pmc->soc->regs->scratch0);
- value = saved ^ 0xffffffff;
+ return -EINVAL;
+}
- if (value == 0xffffffff)
- value = 0xdeadbeef;
+/**
+ * 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;
- /* write pattern and read it back */
- writel(value, pmc->base + pmc->soc->regs->scratch0);
- value = readl(pmc->base + pmc->soc->regs->scratch0);
+ id = tegra_get_cpu_powergate_id(early_pmc, cpuid);
+ if (id < 0)
+ return false;
- /* 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;
+ 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;
}
- /* restore original value */
- writel(saved, pmc->base + pmc->soc->regs->scratch0);
+ if (WARN_ON_ONCE(rate == 0))
+ rate = 100000000;
- return false;
+ 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
@@ -4891,10 +5010,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 +5053,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 +5071,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);
}
@@ -4967,3 +5079,4 @@ static int __init tegra_pmc_early_init(void)
return 0;
}
early_initcall(tegra_pmc_early_init);
+#endif /* CONFIG_ARM */
diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c
index d5637b3763675..e7e6d569f1db2 100644
--- a/drivers/usb/host/xhci-tegra.c
+++ b/drivers/usb/host/xhci-tegra.c
@@ -293,6 +293,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;
@@ -1189,20 +1190,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;
}
}
@@ -1229,18 +1233,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;
}
}
@@ -1737,6 +1744,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)