diff options
| author | Mark Brown <broonie@kernel.org> | 2026-05-29 18:09:03 +0100 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-05-29 18:09:03 +0100 |
| commit | 1468c70a92378ec85d66fce71a533d4bee6ed8cd (patch) | |
| tree | f7ae0e67f2b3cc81a01a4ccfa472e1cf006508d8 /drivers | |
| parent | 636537b990be485724c0965ceb848e7e311e0254 (diff) | |
| parent | d6c3060f8c5df453d92216fcf629a23ee0852d37 (diff) | |
| download | linux-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.c | 17 | ||||
| -rw-r--r-- | drivers/bus/tegra-aconnect.c | 14 | ||||
| -rw-r--r-- | drivers/firmware/tegra/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c | 9 | ||||
| -rw-r--r-- | drivers/gpu/drm/tegra/dc.c | 14 | ||||
| -rw-r--r-- | drivers/gpu/drm/tegra/dc.h | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/tegra/gr3d.c | 9 | ||||
| -rw-r--r-- | drivers/gpu/drm/tegra/sor.c | 16 | ||||
| -rw-r--r-- | drivers/media/platform/nvidia/tegra-vde/vde.c | 15 | ||||
| -rw-r--r-- | drivers/media/platform/nvidia/tegra-vde/vde.h | 1 | ||||
| -rw-r--r-- | drivers/pci/controller/pci-tegra.c | 19 | ||||
| -rw-r--r-- | drivers/soc/tegra/fuse/fuse-tegra.c | 14 | ||||
| -rw-r--r-- | drivers/soc/tegra/pmc.c | 603 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-tegra.c | 38 |
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(®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; - - 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) |
