Merge tag 'tegra-for-7.2-pmc' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into soc/drivers

soc/tegra: pmc: Changes for v7.2-rc1

The bulk of these changes converts existing users to the modern variants
of the API that take a PMC instance as argument. This completes the
transition to multi-instance support, which then makes room for cleanups
and restricting the remaining legacy APIs to 32-bit platforms.

Some changes in this set also clean up powergate debugfs and restrict
the power-off handler to be installed only where appropriate. Lastly,
support for Tegra238 is added.

* tag 'tegra-for-7.2-pmc' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux:
  soc/tegra: pmc: Add Tegra238 support
  soc/tegra: pmc: Restrict power-off handler to Nexus 7
  soc/tegra: pmc: Populate powergate debugfs only when needed
  soc/tegra: pmc: Move legacy code behind CONFIG_ARM guard
  soc/tegra: pmc: Remove unused legacy functions
  soc/tegra: pmc: Create PMC context dynamically
  usb: xhci: tegra: Explicitly specify PMC instance to use
  PCI: tegra: Explicitly specify PMC instance to use
  media: vde: Explicitly specify PMC instance to use
  drm/tegra: Explicitly specify PMC instance to use
  drm/nouveau: tegra: Explicitly specify PMC instance to use
  ata: ahci_tegra: Explicitly specify PMC instance to use

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
Arnd Bergmann
2026-06-09 16:20:55 +02:00
13 changed files with 507 additions and 363 deletions

View File

@@ -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);

View File

@@ -18,6 +18,8 @@ struct nvkm_device_tegra {
struct regulator *vdd;
struct tegra_pmc *pmc;
struct {
/*
* Protects accesses to mm from subsystems

View File

@@ -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.
*/

View File

@@ -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);

View File

@@ -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;

View File

@@ -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.

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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,10 +514,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)
@@ -1063,16 +1067,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
@@ -1087,16 +1081,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
@@ -1124,16 +1108,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
@@ -1181,83 +1155,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 +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;
@@ -1318,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);
@@ -1531,11 +1427,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 pmc->core_domain_state_synced;
}
static int
tegra_pmc_core_pd_set_performance_state(struct generic_pm_domain *genpd,
unsigned int level)
@@ -1823,18 +1714,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(pmc, id);
}
EXPORT_SYMBOL(tegra_io_pad_power_enable);
/**
* tegra_pmc_io_pad_power_disable() - disable power to I/O pad
* @pmc: power management controller
@@ -1879,18 +1758,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(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 +1840,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];
@@ -2094,6 +1910,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 +2928,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,21 +2982,31 @@ 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);
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 +3014,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 +3040,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 +3055,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.
@@ -3211,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;
}
}
/*
@@ -3243,8 +3120,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 +3146,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 +3161,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;
@@ -3523,14 +3401,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 +4013,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 +4036,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;
@@ -4595,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), \
@@ -4785,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 },
@@ -4799,6 +4834,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 +4892,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 +5020,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 +5063,24 @@ 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;
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);
}
@@ -4967,3 +5088,4 @@ static int __init tegra_pmc_early_init(void)
return 0;
}
early_initcall(tegra_pmc_early_init);
#endif /* CONFIG_ARM */

View File

@@ -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)

View File

@@ -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,22 +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 */
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);
bool tegra_pmc_core_domain_state_synced(void);
#else
static inline struct tegra_pmc *devm_tegra_pmc_get(struct device *dev)
{
@@ -223,42 +203,23 @@ tegra_pmc_io_pad_power_disable(struct tegra_pmc *pmc, enum tegra_io_pad id)
{
return -ENOSYS;
}
#endif /* CONFIG_SOC_TEGRA_PMC */
static inline int tegra_powergate_power_on(unsigned int id)
{
return -ENOSYS;
}
/* 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);
static inline int tegra_powergate_power_off(unsigned int id)
#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 -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;
return TEGRA_SUSPEND_NONE;
}
static inline void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode)
@@ -268,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__ */