summaryrefslogtreecommitdiff
path: root/drivers/soc/tegra/pmc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/soc/tegra/pmc.c')
-rw-r--r--drivers/soc/tegra/pmc.c150
1 files changed, 141 insertions, 9 deletions
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index e0d67bfe955c..2a5f24ee858c 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -418,7 +418,6 @@ struct tegra_pmc_soc {
* @irq: chip implementation for the IRQ domain
* @clk_nb: pclk clock changes handler
* @core_domain_state_synced: flag marking the core domain's state as synced
- * @core_domain_registered: flag marking the core domain as registered
* @wake_type_level_map: Bitmap indicating level type for non-dual edge wakes
* @wake_type_dual_edge_map: Bitmap indicating if a wake is dual-edge or not
* @wake_sw_status_map: Bitmap to hold raw status of wakes without mask
@@ -462,7 +461,6 @@ struct tegra_pmc {
struct notifier_block clk_nb;
bool core_domain_state_synced;
- bool core_domain_registered;
unsigned long *wake_type_level_map;
unsigned long *wake_type_dual_edge_map;
@@ -1297,6 +1295,7 @@ static int tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
pg->id = id;
pg->genpd.name = np->name;
+ pg->genpd.flags = GENPD_FLAG_NO_SYNC_STATE;
pg->genpd.power_off = tegra_genpd_power_off;
pg->genpd.power_on = tegra_genpd_power_on;
pg->pmc = pmc;
@@ -1406,6 +1405,7 @@ static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np)
return -ENOMEM;
genpd->name = "core";
+ genpd->flags = GENPD_FLAG_NO_SYNC_STATE;
genpd->set_performance_state = tegra_pmc_core_pd_set_performance_state;
err = devm_pm_opp_set_regulators(pmc->dev, rname);
@@ -1425,8 +1425,6 @@ static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np)
goto remove_genpd;
}
- pmc->core_domain_registered = true;
-
return 0;
remove_genpd:
@@ -2500,8 +2498,7 @@ static int tegra_pmc_irq_init(struct tegra_pmc *pmc)
pmc->irq.irq_set_type = pmc->soc->irq_set_type;
pmc->irq.irq_set_wake = pmc->soc->irq_set_wake;
- pmc->domain = irq_domain_create_hierarchy(parent, 0, 96,
- of_fwnode_handle(pmc->dev->of_node),
+ pmc->domain = irq_domain_create_hierarchy(parent, 0, 96, dev_fwnode(pmc->dev),
&tegra_pmc_irq_domain_ops, pmc);
if (!pmc->domain) {
dev_err(pmc->dev, "failed to allocate domain\n");
@@ -4248,7 +4245,128 @@ static const struct tegra_pmc_soc tegra234_pmc_soc = {
.has_single_mmio_aperture = false,
};
+static const struct tegra_pmc_regs tegra264_pmc_regs = {
+ .scratch0 = 0x684,
+ .rst_status = 0x4,
+ .rst_source_shift = 0x2,
+ .rst_source_mask = 0x1fc,
+ .rst_level_shift = 0x0,
+ .rst_level_mask = 0x3,
+};
+
+static const char * const tegra264_reset_sources[] = {
+ "SYS_RESET_N", /* 0x0 */
+ "CSDC_RTC_XTAL",
+ "VREFRO_POWER_BAD",
+ "SCPM_SOC_XTAL",
+ "SCPM_RTC_XTAL",
+ "FMON_32K",
+ "FMON_OSC",
+ "POD_RTC",
+ "POD_IO", /* 0x8 */
+ "POD_PLUS_IO_SPLL",
+ "POD_PLUS_SOC",
+ "VMON_PLUS_UV",
+ "VMON_PLUS_OV",
+ "FUSECRC_FAULT",
+ "OSC_FAULT",
+ "BPMP_BOOT_FAULT",
+ "SCPM_BPMP_CORE_CLK", /* 0x10 */
+ "SCPM_PSC_SE_CLK",
+ "VMON_SOC_MIN",
+ "VMON_SOC_MAX",
+ "VMON_MSS_MIN",
+ "VMON_MSS_MAX",
+ "POD_PLUS_IO_VMON",
+ "NVJTAG_SEL_MONITOR",
+ "NV_THERM_FAULT", /* 0x18 */
+ "FSI_THERM_FAULT",
+ "PSC_SW",
+ "SCPM_OESP_SE_CLK",
+ "SCPM_SB_SE_CLK",
+ "POD_CPU",
+ "POD_GPU",
+ "DCLS_GPU",
+ "POD_MSS", /* 0x20 */
+ "FMON_FSI",
+ "POD_FSI",
+ "VMON_FSI_MIN",
+ "VMON_FSI_MAX",
+ "VMON_CPU0_MIN",
+ "VMON_CPU0_MAX",
+ "BPMP_FMON",
+ "AO_WDT_POR", /* 0x28 */
+ "BPMP_WDT_POR",
+ "AO_TKE_WDT_POR",
+ "RCE0_WDT_POR",
+ "RCE1_WDT_POR",
+ "DCE_WDT_POR",
+ "FSI_R5_WDT_POR",
+ "FSI_R52_0_WDT_POR",
+ "FSI_R52_1_WDT_POR", /* 0x30 */
+ "FSI_R52_2_WDT_POR",
+ "FSI_R52_3_WDT_POR",
+ "TOP_0_WDT_POR",
+ "TOP_1_WDT_POR",
+ "TOP_2_WDT_POR",
+ "APE_C0_WDT_POR",
+ "APE_C1_WDT_POR",
+ "GPU_TKE_WDT_POR", /* 0x38 */
+ "PSC_WDT_POR",
+ "OESP_WDT_POR",
+ "SB_WDT_POR",
+ "SW_MAIN",
+ "L0L1_RST_OUT_N",
+ "FSI_HSM",
+ "CSITE_SW",
+ "AO_WDT_DBG", /* 0x40 */
+ "BPMP_WDT_DBG",
+ "AO_TKE_WDT_DBG",
+ "RCE0_WDT_DBG",
+ "RCE1_WDT_DBG",
+ "DCE_WDT_DBG",
+ "FSI_R5_WDT_DBG",
+ "FSI_R52_0_WDT_DBG",
+ "FSI_R52_1_WDT_DBG", /* 0x48 */
+ "FSI_R52_2_WDT_DBG",
+ "FSI_R52_3_WDT_DBG",
+ "TOP_0_WDT_DBG",
+ "TOP_1_WDT_DBG",
+ "TOP_2_WDT_DBG",
+ "APE_C0_WDT_DBG",
+ "APE_C1_WDT_DBG",
+ "PSC_WDT_DBG", /* 0x50 */
+ "OESP_WDT_DBG",
+ "SB_WDT_DBG",
+ "TSC_0_WDT_DBG",
+ "TSC_1_WDT_DBG",
+ "L2_RST_OUT_N",
+ "SC7"
+};
+
+static const struct tegra_wake_event tegra264_wake_events[] = {
+};
+
+static const struct tegra_pmc_soc tegra264_pmc_soc = {
+ .has_impl_33v_pwr = true,
+ .regs = &tegra264_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 = tegra264_reset_sources,
+ .num_reset_sources = ARRAY_SIZE(tegra264_reset_sources),
+ .reset_levels = tegra186_reset_levels,
+ .num_reset_levels = ARRAY_SIZE(tegra186_reset_levels),
+ .wake_events = tegra264_wake_events,
+ .num_wake_events = ARRAY_SIZE(tegra264_wake_events),
+ .max_wake_events = 128,
+ .max_wake_vectors = 4,
+};
+
static const struct of_device_id tegra_pmc_match[] = {
+ { .compatible = "nvidia,tegra264-pmc", .data = &tegra264_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 },
@@ -4263,8 +4381,25 @@ static const struct of_device_id tegra_pmc_match[] = {
static void tegra_pmc_sync_state(struct device *dev)
{
+ struct device_node *np, *child;
int err;
+ np = of_get_child_by_name(dev->of_node, "powergates");
+ if (!np)
+ return;
+
+ for_each_child_of_node(np, child)
+ of_genpd_sync_state(child);
+
+ of_node_put(np);
+
+ np = of_get_child_by_name(dev->of_node, "core-domain");
+ if (!np)
+ return;
+
+ of_genpd_sync_state(np);
+ of_node_put(np);
+
/*
* Newer device-trees have power domains, but we need to prepare all
* device drivers with runtime PM and OPP support first, otherwise
@@ -4278,9 +4413,6 @@ static void tegra_pmc_sync_state(struct device *dev)
* no dependencies that will block the state syncing. We shouldn't
* mark the domain as synced in this case.
*/
- if (!pmc->core_domain_registered)
- return;
-
pmc->core_domain_state_synced = true;
/* this is a no-op if core regulator isn't used */