diff options
Diffstat (limited to 'drivers/soc/tegra/pmc.c')
| -rw-r--r-- | drivers/soc/tegra/pmc.c | 2048 |
1 files changed, 1562 insertions, 486 deletions
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 42cf37a0556b..f3760a3b3026 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -3,7 +3,7 @@ * drivers/soc/tegra/pmc.c * * Copyright (c) 2010 Google, Inc - * Copyright (c) 2018-2020, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. * * Author: * Colin Cross <ccross@google.com> @@ -23,6 +23,7 @@ #include <linux/err.h> #include <linux/export.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/io.h> #include <linux/iopoll.h> #include <linux/irqdomain.h> @@ -38,11 +39,16 @@ #include <linux/pinctrl/pinctrl.h> #include <linux/platform_device.h> #include <linux/pm_domain.h> +#include <linux/pm_opp.h> +#include <linux/power_supply.h> #include <linux/reboot.h> +#include <linux/regmap.h> #include <linux/reset.h> #include <linux/seq_file.h> #include <linux/slab.h> #include <linux/spinlock.h> +#include <linux/string_choices.h> +#include <linux/syscore_ops.h> #include <soc/tegra/common.h> #include <soc/tegra/fuse.h> @@ -52,6 +58,7 @@ #include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h> #include <dt-bindings/gpio/tegra186-gpio.h> #include <dt-bindings/gpio/tegra194-gpio.h> +#include <dt-bindings/gpio/tegra234-gpio.h> #include <dt-bindings/soc/tegra-pmc.h> #define PMC_CNTRL 0x0 @@ -102,6 +109,10 @@ #define PMC_PWR_DET_VALUE 0xe4 +#define PMC_USB_DEBOUNCE_DEL 0xec +#define PMC_USB_AO 0xf0 + +#define PMC_SCRATCH37 0x130 #define PMC_SCRATCH41 0x140 #define PMC_WAKE2_MASK 0x160 @@ -133,6 +144,13 @@ #define IO_DPD2_STATUS 0x1c4 #define SEL_DPD_TIM 0x1c8 +#define PMC_UTMIP_UHSIC_TRIGGERS 0x1ec +#define PMC_UTMIP_UHSIC_SAVED_STATE 0x1f0 + +#define PMC_UTMIP_TERM_PAD_CFG 0x1f8 +#define PMC_UTMIP_UHSIC_SLEEP_CFG 0x1fc +#define PMC_UTMIP_UHSIC_FAKE 0x218 + #define PMC_SCRATCH54 0x258 #define PMC_SCRATCH54_DATA_SHIFT 8 #define PMC_SCRATCH54_ADDR_SHIFT 0 @@ -145,11 +163,22 @@ #define PMC_SCRATCH55_CHECKSUM_SHIFT 16 #define PMC_SCRATCH55_I2CSLV1_SHIFT 0 +#define PMC_UTMIP_UHSIC_LINE_WAKEUP 0x26c + +#define PMC_UTMIP_BIAS_MASTER_CNTRL 0x270 +#define PMC_UTMIP_MASTER_CONFIG 0x274 +#define PMC_UTMIP_UHSIC2_TRIGGERS 0x27c +#define PMC_UTMIP_MASTER2_CONFIG 0x29c + #define GPU_RG_CNTRL 0x2d4 +#define PMC_UTMIP_PAD_CFG0 0x4c0 +#define PMC_UTMIP_UHSIC_SLEEP_CFG1 0x4d0 +#define PMC_UTMIP_SLEEPWALK_P3 0x4e0 /* Tegra186 and later */ #define WAKE_AOWAKE_CNTRL(x) (0x000 + ((x) << 2)) #define WAKE_AOWAKE_CNTRL_LEVEL (1 << 3) +#define WAKE_AOWAKE_CNTRL_SR_CAPTURE_EN (1 << 1) #define WAKE_AOWAKE_MASK_W(x) (0x180 + ((x) << 2)) #define WAKE_AOWAKE_MASK_R(x) (0x300 + ((x) << 2)) #define WAKE_AOWAKE_STATUS_W(x) (0x30c + ((x) << 2)) @@ -157,10 +186,15 @@ #define WAKE_AOWAKE_TIER0_ROUTING(x) (0x4b4 + ((x) << 2)) #define WAKE_AOWAKE_TIER1_ROUTING(x) (0x4c0 + ((x) << 2)) #define WAKE_AOWAKE_TIER2_ROUTING(x) (0x4cc + ((x) << 2)) +#define WAKE_AOWAKE_SW_STATUS_W_0 0x49c +#define WAKE_AOWAKE_SW_STATUS(x) (0x4a0 + ((x) << 2)) +#define WAKE_LATCH_SW 0x498 #define WAKE_AOWAKE_CTRL 0x4f4 #define WAKE_AOWAKE_CTRL_INTR_POLARITY BIT(0) +#define SW_WAKE_ID 83 /* wake83 */ + /* for secure PMC */ #define TEGRA_SMC_PMC 0xc2fffe00 #define TEGRA_SMC_PMC_READ 0xaa @@ -237,22 +271,21 @@ struct tegra_powergate { unsigned int id; struct clk **clks; unsigned int num_clks; + unsigned long *clk_rates; struct reset_control *reset; }; struct tegra_io_pad_soc { enum tegra_io_pad id; unsigned int dpd; + unsigned int request; + unsigned int status; unsigned int voltage; const char *name; }; struct tegra_pmc_regs { unsigned int scratch0; - unsigned int dpd_req; - unsigned int dpd_status; - unsigned int dpd2_req; - unsigned int dpd2_status; unsigned int rst_status; unsigned int rst_source_shift; unsigned int rst_source_mask; @@ -270,6 +303,17 @@ struct tegra_wake_event { } gpio; }; +#define TEGRA_WAKE_SIMPLE(_name, _id) \ + { \ + .name = _name, \ + .id = _id, \ + .irq = 0, \ + .gpio = { \ + .instance = UINT_MAX, \ + .pin = UINT_MAX, \ + }, \ + } + #define TEGRA_WAKE_IRQ(_name, _id, _irq) \ { \ .name = _name, \ @@ -315,8 +359,11 @@ struct tegra_pmc_soc { void (*setup_irq_polarity)(struct tegra_pmc *pmc, struct device_node *np, bool invert); + 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); + int (*powergate_set)(struct tegra_pmc *pmc, unsigned int id, + bool new_state); const char * const *reset_sources; unsigned int num_reset_sources; @@ -330,49 +377,15 @@ struct tegra_pmc_soc { */ const struct tegra_wake_event *wake_events; unsigned int num_wake_events; + unsigned int max_wake_events; + unsigned int max_wake_vectors; const struct pmc_clk_init_data *pmc_clks_data; unsigned int num_pmc_clks; bool has_blink_output; -}; - -static const char * const tegra186_reset_sources[] = { - "SYS_RESET", - "AOWDT", - "MCCPLEXWDT", - "BPMPWDT", - "SCEWDT", - "SPEWDT", - "APEWDT", - "BCCPLEXWDT", - "SENSOR", - "AOTAG", - "VFSENSOR", - "SWREST", - "SC7", - "HSM", - "CORESIGHT" -}; - -static const char * const tegra186_reset_levels[] = { - "L0", "L1", "L2", "WARM" -}; - -static const char * const tegra30_reset_sources[] = { - "POWER_ON_RESET", - "WATCHDOG", - "SENSOR", - "SW_MAIN", - "LP0" -}; - -static const char * const tegra210_reset_sources[] = { - "POWER_ON_RESET", - "WATCHDOG", - "SENSOR", - "SW_MAIN", - "LP0", - "AOTAG" + bool has_usb_sleepwalk; + bool supports_core_domain; + bool has_single_mmio_aperture; }; /** @@ -385,7 +398,6 @@ static const char * const tegra210_reset_sources[] = { * @clk: pointer to pclk clock * @soc: pointer to SoC data structure * @tz_only: flag specifying if the PMC can only be accessed via TrustZone - * @debugfs: pointer to debugfs entry * @rate: currently configured rate of pclk * @suspend_mode: lowest suspend mode available * @cpu_good_time: CPU power good time (in microseconds) @@ -405,6 +417,13 @@ static const char * const tegra210_reset_sources[] = { * @domain: IRQ domain provided by the PMC * @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 + * @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 + * @wake_cntrl_level_map: Bitmap to hold wake levels to be programmed in + * cntrl register associated with each wake during system suspend. + * @syscore: syscore suspend/resume callbacks */ struct tegra_pmc { struct device *dev; @@ -413,7 +432,6 @@ struct tegra_pmc { void __iomem *aotag; void __iomem *scratch; struct clk *clk; - struct dentry *debugfs; const struct tegra_pmc_soc *soc; bool tz_only; @@ -442,11 +460,19 @@ struct tegra_pmc { struct irq_chip irq; struct notifier_block clk_nb; + + bool core_domain_state_synced; + + unsigned long *wake_type_level_map; + unsigned long *wake_type_dual_edge_map; + unsigned long *wake_sw_status_map; + unsigned long *wake_cntrl_level_map; + struct syscore syscore; }; static struct tegra_pmc *pmc = &(struct tegra_pmc) { .base = NULL, - .suspend_mode = TEGRA_SUSPEND_NONE, + .suspend_mode = TEGRA_SUSPEND_NOT_READY, }; static inline struct tegra_powergate * @@ -556,6 +582,63 @@ static int tegra_powergate_lookup(struct tegra_pmc *pmc, const char *name) return -ENODEV; } +static int tegra20_powergate_set(struct tegra_pmc *pmc, unsigned int id, + bool new_state) +{ + unsigned int retries = 100; + bool status; + int ret; + + /* + * As per TRM documentation, the toggle command will be dropped by PMC + * if there is contention with a HW-initiated toggling (i.e. CPU core + * power-gated), the command should be retried in that case. + */ + do { + tegra_pmc_writel(pmc, PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE); + + /* wait for PMC to execute the command */ + ret = readx_poll_timeout(tegra_powergate_state, id, status, + status == new_state, 1, 10); + } while (ret == -ETIMEDOUT && retries--); + + return ret; +} + +static inline bool tegra_powergate_toggle_ready(struct tegra_pmc *pmc) +{ + return !(tegra_pmc_readl(pmc, PWRGATE_TOGGLE) & PWRGATE_TOGGLE_START); +} + +static int tegra114_powergate_set(struct tegra_pmc *pmc, unsigned int id, + bool new_state) +{ + bool status; + int err; + + /* wait while PMC power gating is contended */ + err = readx_poll_timeout(tegra_powergate_toggle_ready, pmc, status, + status == true, 1, 100); + if (err) + return err; + + tegra_pmc_writel(pmc, PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE); + + /* wait for PMC to accept the command */ + err = readx_poll_timeout(tegra_powergate_toggle_ready, pmc, status, + status == true, 1, 100); + if (err) + return err; + + /* wait for PMC to execute the command */ + err = readx_poll_timeout(tegra_powergate_state, id, status, + status == new_state, 10, 100000); + if (err) + return err; + + return 0; +} + /** * tegra_powergate_set() - set the state of a partition * @pmc: power management controller @@ -565,7 +648,6 @@ static int tegra_powergate_lookup(struct tegra_pmc *pmc, const char *name) static int tegra_powergate_set(struct tegra_pmc *pmc, unsigned int id, bool new_state) { - bool status; int err; if (id == TEGRA_POWERGATE_3D && pmc->soc->has_gpu_clamps) @@ -578,10 +660,7 @@ static int tegra_powergate_set(struct tegra_pmc *pmc, unsigned int id, return 0; } - tegra_pmc_writel(pmc, PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE); - - err = readx_poll_timeout(tegra_powergate_state, id, status, - status == new_state, 10, 100000); + err = pmc->soc->powergate_set(pmc, id, new_state); mutex_unlock(&pmc->powergates_lock); @@ -625,6 +704,57 @@ out: return 0; } +static int tegra_powergate_prepare_clocks(struct tegra_powergate *pg) +{ + unsigned long safe_rate = 100 * 1000 * 1000; + unsigned int i; + int err; + + for (i = 0; i < pg->num_clks; i++) { + pg->clk_rates[i] = clk_get_rate(pg->clks[i]); + + if (!pg->clk_rates[i]) { + err = -EINVAL; + goto out; + } + + if (pg->clk_rates[i] <= safe_rate) + continue; + + /* + * We don't know whether voltage state is okay for the + * current clock rate, hence it's better to temporally + * switch clock to a safe rate which is suitable for + * all voltages, before enabling the clock. + */ + err = clk_set_rate(pg->clks[i], safe_rate); + if (err) + goto out; + } + + return 0; + +out: + while (i--) + clk_set_rate(pg->clks[i], pg->clk_rates[i]); + + return err; +} + +static int tegra_powergate_unprepare_clocks(struct tegra_powergate *pg) +{ + unsigned int i; + int err; + + for (i = 0; i < pg->num_clks; i++) { + err = clk_set_rate(pg->clks[i], pg->clk_rates[i]); + if (err) + return err; + } + + return 0; +} + static void tegra_powergate_disable_clocks(struct tegra_powergate *pg) { unsigned int i; @@ -653,11 +783,6 @@ out: return err; } -int __weak tegra210_clk_handle_mbist_war(unsigned int id) -{ - return 0; -} - static int tegra_powergate_power_up(struct tegra_powergate *pg, bool disable_clocks) { @@ -675,9 +800,13 @@ static int tegra_powergate_power_up(struct tegra_powergate *pg, usleep_range(10, 20); + err = tegra_powergate_prepare_clocks(pg); + if (err) + goto powergate_off; + err = tegra_powergate_enable_clocks(pg); if (err) - goto disable_clks; + goto unprepare_clks; usleep_range(10, 20); @@ -689,7 +818,7 @@ static int tegra_powergate_power_up(struct tegra_powergate *pg, err = reset_control_deassert(pg->reset); if (err) - goto powergate_off; + goto disable_clks; usleep_range(10, 20); @@ -701,12 +830,19 @@ static int tegra_powergate_power_up(struct tegra_powergate *pg, if (disable_clocks) tegra_powergate_disable_clocks(pg); + err = tegra_powergate_unprepare_clocks(pg); + if (err) + return err; + return 0; disable_clks: tegra_powergate_disable_clocks(pg); usleep_range(10, 20); +unprepare_clks: + tegra_powergate_unprepare_clocks(pg); + powergate_off: tegra_powergate_set(pg->pmc, pg->id, false); @@ -717,10 +853,14 @@ static int tegra_powergate_power_down(struct tegra_powergate *pg) { int err; - err = tegra_powergate_enable_clocks(pg); + err = tegra_powergate_prepare_clocks(pg); if (err) return err; + err = tegra_powergate_enable_clocks(pg); + if (err) + goto unprepare_clks; + usleep_range(10, 20); err = reset_control_assert(pg->reset); @@ -737,6 +877,10 @@ static int tegra_powergate_power_down(struct tegra_powergate *pg) if (err) goto assert_resets; + err = tegra_powergate_unprepare_clocks(pg); + if (err) + return err; + return 0; assert_resets: @@ -748,6 +892,9 @@ assert_resets: disable_clks: tegra_powergate_disable_clocks(pg); +unprepare_clks: + tegra_powergate_unprepare_clocks(pg); + return err; } @@ -778,7 +925,8 @@ static int tegra_genpd_power_off(struct generic_pm_domain *domain) err = reset_control_acquire(pg->reset); if (err < 0) { - pr_err("failed to acquire resets: %d\n", err); + dev_err(dev, "failed to acquire resets for PM domain %s: %d\n", + pg->genpd.name, err); return err; } @@ -865,6 +1013,12 @@ int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk, if (!pg) return -ENOMEM; + pg->clk_rates = kzalloc(sizeof(*pg->clk_rates), GFP_KERNEL); + if (!pg->clk_rates) { + kfree(pg->clks); + return -ENOMEM; + } + pg->id = id; pg->clks = &clk; pg->num_clks = 1; @@ -876,6 +1030,7 @@ int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk, dev_err(pmc->dev, "failed to turn on partition %d: %d\n", id, err); + kfree(pg->clk_rates); kfree(pg); return err; @@ -944,10 +1099,8 @@ int tegra_pmc_cpu_remove_clamping(unsigned int cpuid) return tegra_powergate_remove_clamping(id); } -static int tegra_pmc_restart_notify(struct notifier_block *this, - unsigned long action, void *data) +static void tegra_pmc_program_reboot_reason(const char *cmd) { - const char *cmd = data; u32 value; value = tegra_pmc_scratch_readl(pmc, pmc->soc->regs->scratch0); @@ -965,19 +1118,54 @@ static int tegra_pmc_restart_notify(struct notifier_block *this, } tegra_pmc_scratch_writel(pmc, value, pmc->soc->regs->scratch0); +} + +static int tegra_pmc_reboot_notify(struct notifier_block *this, + unsigned long action, void *data) +{ + if (action == SYS_RESTART) + tegra_pmc_program_reboot_reason(data); + + return NOTIFY_DONE; +} + +static struct notifier_block tegra_pmc_reboot_notifier = { + .notifier_call = tegra_pmc_reboot_notify, +}; + +static void tegra_pmc_restart(void) +{ + u32 value; /* reset everything but PMC_SCRATCH0 and PMC_RST_STATUS */ value = tegra_pmc_readl(pmc, PMC_CNTRL); value |= PMC_CNTRL_MAIN_RST; tegra_pmc_writel(pmc, value, PMC_CNTRL); +} + +static int tegra_pmc_restart_handler(struct sys_off_data *data) +{ + tegra_pmc_restart(); return NOTIFY_DONE; } -static struct notifier_block tegra_pmc_restart_handler = { - .notifier_call = tegra_pmc_restart_notify, - .priority = 128, -}; +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()) { + const u32 go_to_charger_mode = 0xa5a55a5a; + + tegra_pmc_writel(pmc, go_to_charger_mode, PMC_SCRATCH37); + tegra_pmc_restart(); + } + + return NOTIFY_DONE; +} static int powergate_show(struct seq_file *s, void *data) { @@ -993,7 +1181,7 @@ static int powergate_show(struct seq_file *s, void *data) continue; seq_printf(s, " %9s %7s\n", pmc->soc->powergates[i], - status ? "yes" : "no"); + str_yes_no(status)); } return 0; @@ -1001,16 +1189,6 @@ static int powergate_show(struct seq_file *s, void *data) DEFINE_SHOW_ATTRIBUTE(powergate); -static int tegra_powergate_debugfs_init(void) -{ - pmc->debugfs = debugfs_create_file("powergate", S_IRUGO, NULL, NULL, - &powergate_fops); - if (!pmc->debugfs) - return -ENOMEM; - - return 0; -} - static int tegra_powergate_of_get_clks(struct tegra_powergate *pg, struct device_node *np) { @@ -1026,6 +1204,12 @@ static int tegra_powergate_of_get_clks(struct tegra_powergate *pg, if (!pg->clks) return -ENOMEM; + pg->clk_rates = kcalloc(count, sizeof(*pg->clk_rates), GFP_KERNEL); + if (!pg->clk_rates) { + kfree(pg->clks); + return -ENOMEM; + } + for (i = 0; i < count; i++) { pg->clks[i] = of_clk_get(np, i); if (IS_ERR(pg->clks[i])) { @@ -1042,13 +1226,14 @@ err: while (i--) clk_put(pg->clks[i]); + kfree(pg->clk_rates); kfree(pg->clks); return err; } static int tegra_powergate_of_get_resets(struct tegra_powergate *pg, - struct device_node *np, bool off) + struct device_node *np) { struct device *dev = pg->pmc->dev; int err; @@ -1063,22 +1248,6 @@ static int tegra_powergate_of_get_resets(struct tegra_powergate *pg, err = reset_control_acquire(pg->reset); if (err < 0) { pr_err("failed to acquire resets: %d\n", err); - goto out; - } - - if (off) { - err = reset_control_assert(pg->reset); - } else { - err = reset_control_deassert(pg->reset); - if (err < 0) - goto out; - - reset_control_release(pg->reset); - } - -out: - if (err) { - reset_control_release(pg->reset); reset_control_put(pg->reset); } @@ -1111,6 +1280,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; @@ -1123,20 +1293,43 @@ static int tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) goto set_available; } - err = tegra_powergate_of_get_resets(pg, np, off); + err = tegra_powergate_of_get_resets(pg, np); if (err < 0) { dev_err(dev, "failed to get resets for %pOFn: %d\n", np, err); goto remove_clks; } - if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) { - if (off) - WARN_ON(tegra_powergate_power_up(pg, true)); + /* + * If the power-domain is off, then ensure the resets are asserted. + * If the power-domain is on, then power down to ensure that when is + * it turned on the power-domain, clocks and resets are all in the + * expected state. + */ + if (off) { + err = reset_control_assert(pg->reset); + if (err) { + pr_err("failed to assert resets: %d\n", err); + goto remove_resets; + } + } else { + err = tegra_powergate_power_down(pg); + if (err) { + dev_err(dev, "failed to turn off PM domain %s: %d\n", + pg->genpd.name, err); + goto remove_resets; + } + } + /* + * If PM_GENERIC_DOMAINS is not enabled, power-on + * the domain and skip the genpd registration. + */ + if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) { + WARN_ON(tegra_powergate_power_up(pg, true)); goto remove_resets; } - err = pm_genpd_init(&pg->genpd, NULL, off); + err = pm_genpd_init(&pg->genpd, NULL, true); if (err < 0) { dev_err(dev, "failed to initialise PM domain %pOFn: %d\n", np, err); @@ -1175,22 +1368,119 @@ 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) +{ + struct dev_pm_opp *opp; + int err; + + opp = dev_pm_opp_find_level_ceil(&genpd->dev, &level); + if (IS_ERR(opp)) { + dev_err(&genpd->dev, "failed to find OPP for level %u: %pe\n", + level, opp); + return PTR_ERR(opp); + } + + mutex_lock(&pmc->powergates_lock); + err = dev_pm_opp_set_opp(pmc->dev, opp); + mutex_unlock(&pmc->powergates_lock); + + dev_pm_opp_put(opp); + + if (err) { + dev_err(&genpd->dev, "failed to set voltage to %duV: %d\n", + level, err); + return err; + } + + return 0; +} + +static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np) +{ + struct generic_pm_domain *genpd; + const char *rname[] = { "core", NULL}; + int err; + + genpd = devm_kzalloc(pmc->dev, sizeof(*genpd), GFP_KERNEL); + if (!genpd) + 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); + if (err) + return dev_err_probe(pmc->dev, err, + "failed to set core OPP regulator\n"); + + err = pm_genpd_init(genpd, NULL, false); + if (err) { + dev_err(pmc->dev, "failed to init core genpd: %d\n", err); + return err; + } + + err = of_genpd_add_provider_simple(np, genpd); + if (err) { + dev_err(pmc->dev, "failed to add core genpd: %d\n", err); + goto remove_genpd; + } + + return 0; + +remove_genpd: + pm_genpd_remove(genpd); + + return err; +} + static int tegra_powergate_init(struct tegra_pmc *pmc, struct device_node *parent) { - struct device_node *np, *child; + struct of_phandle_args child_args, parent_args; + struct device_node *np; int err = 0; + /* + * Core power domain is the parent of powergate domains, hence it + * should be registered first. + */ + np = of_get_child_by_name(parent, "core-domain"); + if (np) { + err = tegra_pmc_core_pd_add(pmc, np); + of_node_put(np); + if (err) + return err; + } + np = of_get_child_by_name(parent, "powergates"); if (!np) return 0; - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { err = tegra_powergate_add(pmc, child); - if (err < 0) { - of_node_put(child); + if (err < 0) + break; + + if (of_parse_phandle_with_args(child, "power-domains", + "#power-domain-cells", + 0, &parent_args)) + continue; + + child_args.np = child; + child_args.args_count = 0; + + err = of_genpd_add_subdomain(&parent_args, &child_args); + of_node_put(parent_args.np); + if (err) break; - } } of_node_put(np); @@ -1234,6 +1524,12 @@ static void tegra_powergate_remove_all(struct device_node *parent) } of_node_put(np); + + np = of_get_child_by_name(parent, "core-domain"); + if (np) { + of_genpd_del_provider(np); + of_genpd_remove_last(np); + } } static const struct tegra_io_pad_soc * @@ -1248,46 +1544,20 @@ tegra_io_pad_find(struct tegra_pmc *pmc, enum tegra_io_pad id) return NULL; } -static int tegra_io_pad_get_dpd_register_bit(struct tegra_pmc *pmc, - enum tegra_io_pad id, - unsigned long *request, - unsigned long *status, - u32 *mask) -{ - const struct tegra_io_pad_soc *pad; - - pad = tegra_io_pad_find(pmc, id); - if (!pad) { - dev_err(pmc->dev, "invalid I/O pad ID %u\n", id); - return -ENOENT; - } - - if (pad->dpd == UINT_MAX) - return -ENOTSUPP; - - *mask = BIT(pad->dpd % 32); - - if (pad->dpd < 32) { - *status = pmc->soc->regs->dpd_status; - *request = pmc->soc->regs->dpd_req; - } else { - *status = pmc->soc->regs->dpd2_status; - *request = pmc->soc->regs->dpd2_req; - } - - return 0; -} - -static int tegra_io_pad_prepare(struct tegra_pmc *pmc, enum tegra_io_pad id, - unsigned long *request, unsigned long *status, +static int tegra_io_pad_prepare(struct tegra_pmc *pmc, + const struct tegra_io_pad_soc *pad, + unsigned long *request, + unsigned long *status, u32 *mask) { unsigned long rate, value; - int err; - err = tegra_io_pad_get_dpd_register_bit(pmc, id, request, status, mask); - if (err) - return err; + if (pad->dpd == UINT_MAX) + return -EINVAL; + + *request = pad->request; + *status = pad->status; + *mask = BIT(pad->dpd); if (pmc->clk) { rate = pmc->rate; @@ -1339,13 +1609,20 @@ static void tegra_io_pad_unprepare(struct tegra_pmc *pmc) */ int tegra_io_pad_power_enable(enum tegra_io_pad id) { + const struct tegra_io_pad_soc *pad; unsigned long request, status; u32 mask; int err; + pad = tegra_io_pad_find(pmc, id); + if (!pad) { + dev_err(pmc->dev, "invalid I/O pad ID %u\n", id); + return -ENOENT; + } + mutex_lock(&pmc->powergates_lock); - err = tegra_io_pad_prepare(pmc, id, &request, &status, &mask); + err = tegra_io_pad_prepare(pmc, pad, &request, &status, &mask); if (err < 0) { dev_err(pmc->dev, "failed to prepare I/O pad: %d\n", err); goto unlock; @@ -1375,13 +1652,20 @@ EXPORT_SYMBOL(tegra_io_pad_power_enable); */ int tegra_io_pad_power_disable(enum tegra_io_pad id) { + const struct tegra_io_pad_soc *pad; unsigned long request, status; u32 mask; int err; + pad = tegra_io_pad_find(pmc, id); + if (!pad) { + dev_err(pmc->dev, "invalid I/O pad ID %u\n", id); + return -ENOENT; + } + mutex_lock(&pmc->powergates_lock); - err = tegra_io_pad_prepare(pmc, id, &request, &status, &mask); + err = tegra_io_pad_prepare(pmc, pad, &request, &status, &mask); if (err < 0) { dev_err(pmc->dev, "failed to prepare I/O pad: %d\n", err); goto unlock; @@ -1405,14 +1689,21 @@ EXPORT_SYMBOL(tegra_io_pad_power_disable); static int tegra_io_pad_is_powered(struct tegra_pmc *pmc, enum tegra_io_pad id) { - unsigned long request, status; + const struct tegra_io_pad_soc *pad; + unsigned long status; u32 mask, value; - int err; - err = tegra_io_pad_get_dpd_register_bit(pmc, id, &request, &status, - &mask); - if (err) - return err; + pad = tegra_io_pad_find(pmc, id); + if (!pad) { + dev_err(pmc->dev, "invalid I/O pad ID %u\n", id); + return -ENOENT; + } + + if (pad->dpd == UINT_MAX) + return -EINVAL; + + status = pad->status; + mask = BIT(pad->dpd); value = tegra_pmc_readl(pmc, status); @@ -1490,30 +1781,6 @@ static int tegra_io_pad_get_voltage(struct tegra_pmc *pmc, enum tegra_io_pad id) return TEGRA_IO_PAD_VOLTAGE_3V3; } -/** - * tegra_io_rail_power_on() - enable power to I/O rail - * @id: Tegra I/O pad ID for which to enable power - * - * See also: tegra_io_pad_power_enable() - */ -int tegra_io_rail_power_on(unsigned int id) -{ - return tegra_io_pad_power_enable(id); -} -EXPORT_SYMBOL(tegra_io_rail_power_on); - -/** - * tegra_io_rail_power_off() - disable power to I/O rail - * @id: Tegra I/O pad ID for which to disable power - * - * See also: tegra_io_pad_power_disable() - */ -int tegra_io_rail_power_off(unsigned int id) -{ - return tegra_io_pad_power_disable(id); -} -EXPORT_SYMBOL(tegra_io_rail_power_off); - #ifdef CONFIG_PM_SLEEP enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void) { @@ -1570,6 +1837,7 @@ static int tegra_pmc_parse_dt(struct tegra_pmc *pmc, struct device_node *np) u32 value, values[2]; if (of_property_read_u32(np, "nvidia,suspend-mode", &value)) { + pmc->suspend_mode = TEGRA_SUSPEND_NONE; } else { switch (value) { case 0: @@ -1637,10 +1905,30 @@ static int tegra_pmc_parse_dt(struct tegra_pmc *pmc, struct device_node *np) return 0; } -static void tegra_pmc_init(struct tegra_pmc *pmc) +static int tegra_pmc_init(struct tegra_pmc *pmc) { + if (pmc->soc->max_wake_events > 0) { + pmc->wake_type_level_map = bitmap_zalloc(pmc->soc->max_wake_events, GFP_KERNEL); + if (!pmc->wake_type_level_map) + return -ENOMEM; + + pmc->wake_type_dual_edge_map = bitmap_zalloc(pmc->soc->max_wake_events, GFP_KERNEL); + if (!pmc->wake_type_dual_edge_map) + return -ENOMEM; + + pmc->wake_sw_status_map = bitmap_zalloc(pmc->soc->max_wake_events, GFP_KERNEL); + if (!pmc->wake_sw_status_map) + return -ENOMEM; + + pmc->wake_cntrl_level_map = bitmap_zalloc(pmc->soc->max_wake_events, GFP_KERNEL); + if (!pmc->wake_cntrl_level_map) + return -ENOMEM; + } + if (pmc->soc->init) pmc->soc->init(pmc); + + return 0; } static void tegra_pmc_init_tsense_reset(struct tegra_pmc *pmc) @@ -1777,7 +2065,7 @@ static int tegra_io_pad_pinconf_get(struct pinctrl_dev *pctl_dev, arg = ret; break; - case PIN_CONFIG_LOW_POWER_MODE: + case PIN_CONFIG_MODE_LOW_POWER: ret = tegra_io_pad_is_powered(pmc, pad->id); if (ret < 0) return ret; @@ -1814,7 +2102,7 @@ static int tegra_io_pad_pinconf_set(struct pinctrl_dev *pctl_dev, arg = pinconf_to_config_argument(configs[i]); switch (param) { - case PIN_CONFIG_LOW_POWER_MODE: + case PIN_CONFIG_MODE_LOW_POWER: if (arg) err = tegra_io_pad_power_disable(pad->id); else @@ -1957,6 +2245,7 @@ static int tegra_pmc_irq_alloc(struct irq_domain *domain, unsigned int virq, for (i = 0; i < soc->num_wake_events; i++) { const struct tegra_wake_event *event = &soc->wake_events[i]; + /* IRQ and simple wake events */ if (fwspec->param_count == 2) { struct irq_fwspec spec; @@ -1969,6 +2258,12 @@ static int tegra_pmc_irq_alloc(struct irq_domain *domain, unsigned int virq, if (err < 0) break; + /* simple hierarchies stop at the PMC level */ + if (event->irq == 0) { + err = irq_domain_disconnect_hierarchy(domain->parent, virq); + break; + } + spec.fwnode = &pmc->dev->of_node->fwnode; spec.param_count = 3; spec.param[0] = GIC_SPI; @@ -1981,6 +2276,7 @@ static int tegra_pmc_irq_alloc(struct irq_domain *domain, unsigned int virq, break; } + /* GPIO wake events */ if (fwspec->param_count == 3) { if (event->gpio.instance != fwspec->param[0] || event->gpio.pin != fwspec->param[1]) @@ -1990,44 +2286,17 @@ static int tegra_pmc_irq_alloc(struct irq_domain *domain, unsigned int virq, event->id, &pmc->irq, pmc); - /* - * GPIOs don't have an equivalent interrupt in the - * parent controller (GIC). However some code, such - * as the one in irq_get_irqchip_state(), require a - * valid IRQ chip to be set. Make sure that's the - * case by passing NULL here, which will install a - * dummy IRQ chip for the interrupt in the parent - * domain. - */ - if (domain->parent) - irq_domain_set_hwirq_and_chip(domain->parent, - virq, 0, NULL, - NULL); - + /* GPIO hierarchies stop at the PMC level */ + if (!err && domain->parent) + err = irq_domain_disconnect_hierarchy(domain->parent, + virq); break; } } - /* - * For interrupts that don't have associated wake events, assign a - * dummy hardware IRQ number. This is used in the ->irq_set_type() - * and ->irq_set_wake() callbacks to return early for these IRQs. - */ - if (i == soc->num_wake_events) { - err = irq_domain_set_hwirq_and_chip(domain, virq, ULONG_MAX, - &pmc->irq, pmc); - - /* - * Interrupts without a wake event don't have a corresponding - * interrupt in the parent controller (GIC). Pass NULL for the - * chip here, which causes a dummy IRQ chip to be installed - * for the interrupt in the parent domain, to make this - * explicit. - */ - if (domain->parent) - irq_domain_set_hwirq_and_chip(domain->parent, virq, 0, - NULL, NULL); - } + /* If there is no wake-up event, there is no PMC mapping */ + if (i == soc->num_wake_events) + err = irq_domain_disconnect_hierarchy(domain, virq); return err; } @@ -2043,9 +2312,6 @@ static int tegra210_pmc_irq_set_wake(struct irq_data *data, unsigned int on) unsigned int offset, bit; u32 value; - if (data->hwirq == ULONG_MAX) - return 0; - offset = data->hwirq / 32; bit = data->hwirq % 32; @@ -2080,9 +2346,6 @@ static int tegra210_pmc_irq_set_type(struct irq_data *data, unsigned int type) unsigned int offset, bit; u32 value; - if (data->hwirq == ULONG_MAX) - return 0; - offset = data->hwirq / 32; bit = data->hwirq % 32; @@ -2117,16 +2380,23 @@ static int tegra210_pmc_irq_set_type(struct irq_data *data, unsigned int type) return 0; } +static void tegra186_pmc_set_wake_filters(struct tegra_pmc *pmc) +{ + u32 value; + + /* SW Wake (wake83) needs SR_CAPTURE filter to be enabled */ + value = readl(pmc->wake + WAKE_AOWAKE_CNTRL(SW_WAKE_ID)); + value |= WAKE_AOWAKE_CNTRL_SR_CAPTURE_EN; + writel(value, pmc->wake + WAKE_AOWAKE_CNTRL(SW_WAKE_ID)); + dev_dbg(pmc->dev, "WAKE_AOWAKE_CNTRL_83 = 0x%x\n", value); +} + static int tegra186_pmc_irq_set_wake(struct irq_data *data, unsigned int on) { struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data); unsigned int offset, bit; u32 value; - /* nothing to do if there's no associated wake event */ - if (WARN_ON(data->hwirq == ULONG_MAX)) - return 0; - offset = data->hwirq / 32; bit = data->hwirq % 32; @@ -2154,25 +2424,27 @@ static int tegra186_pmc_irq_set_type(struct irq_data *data, unsigned int type) struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data); u32 value; - /* nothing to do if there's no associated wake event */ - if (data->hwirq == ULONG_MAX) - return 0; - value = readl(pmc->wake + WAKE_AOWAKE_CNTRL(data->hwirq)); switch (type) { case IRQ_TYPE_EDGE_RISING: case IRQ_TYPE_LEVEL_HIGH: value |= WAKE_AOWAKE_CNTRL_LEVEL; + set_bit(data->hwirq, pmc->wake_type_level_map); + clear_bit(data->hwirq, pmc->wake_type_dual_edge_map); break; case IRQ_TYPE_EDGE_FALLING: case IRQ_TYPE_LEVEL_LOW: value &= ~WAKE_AOWAKE_CNTRL_LEVEL; + clear_bit(data->hwirq, pmc->wake_type_level_map); + clear_bit(data->hwirq, pmc->wake_type_dual_edge_map); break; case IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING: value ^= WAKE_AOWAKE_CNTRL_LEVEL; + clear_bit(data->hwirq, pmc->wake_type_level_map); + set_bit(data->hwirq, pmc->wake_type_dual_edge_map); break; default: @@ -2184,6 +2456,34 @@ static int tegra186_pmc_irq_set_type(struct irq_data *data, unsigned int type) return 0; } +static void tegra_irq_mask_parent(struct irq_data *data) +{ + if (data->parent_data) + irq_chip_mask_parent(data); +} + +static void tegra_irq_unmask_parent(struct irq_data *data) +{ + if (data->parent_data) + irq_chip_unmask_parent(data); +} + +static void tegra_irq_eoi_parent(struct irq_data *data) +{ + if (data->parent_data) + irq_chip_eoi_parent(data); +} + +static int tegra_irq_set_affinity_parent(struct irq_data *data, + const struct cpumask *dest, + bool force) +{ + if (data->parent_data) + return irq_chip_set_affinity_parent(data, dest, force); + + return -EINVAL; +} + static int tegra_pmc_irq_init(struct tegra_pmc *pmc) { struct irq_domain *parent = NULL; @@ -2199,15 +2499,15 @@ static int tegra_pmc_irq_init(struct tegra_pmc *pmc) return 0; pmc->irq.name = dev_name(pmc->dev); - pmc->irq.irq_mask = irq_chip_mask_parent; - pmc->irq.irq_unmask = irq_chip_unmask_parent; - pmc->irq.irq_eoi = irq_chip_eoi_parent; - pmc->irq.irq_set_affinity = irq_chip_set_affinity_parent; + pmc->irq.irq_mask = tegra_irq_mask_parent; + pmc->irq.irq_unmask = tegra_irq_unmask_parent; + pmc->irq.irq_eoi = tegra_irq_eoi_parent; + pmc->irq.irq_set_affinity = tegra_irq_set_affinity_parent; pmc->irq.irq_set_type = pmc->soc->irq_set_type; pmc->irq.irq_set_wake = pmc->soc->irq_set_wake; - pmc->domain = irq_domain_add_hierarchy(parent, 0, 96, pmc->dev->of_node, - &tegra_pmc_irq_domain_ops, pmc); + 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"); return -ENOMEM; @@ -2229,7 +2529,7 @@ static int tegra_pmc_clk_notify_cb(struct notifier_block *nb, case POST_RATE_CHANGE: pmc->rate = data->new_rate; - /* fall through */ + fallthrough; case ABORT_RATE_CHANGE: mutex_unlock(&pmc->powergates_lock); @@ -2495,6 +2795,72 @@ static void tegra_pmc_clock_register(struct tegra_pmc *pmc, err); } +static const struct regmap_range pmc_usb_sleepwalk_ranges[] = { + regmap_reg_range(PMC_USB_DEBOUNCE_DEL, PMC_USB_AO), + regmap_reg_range(PMC_UTMIP_UHSIC_TRIGGERS, PMC_UTMIP_UHSIC_SAVED_STATE), + regmap_reg_range(PMC_UTMIP_TERM_PAD_CFG, PMC_UTMIP_UHSIC_FAKE), + regmap_reg_range(PMC_UTMIP_UHSIC_LINE_WAKEUP, PMC_UTMIP_UHSIC_LINE_WAKEUP), + regmap_reg_range(PMC_UTMIP_BIAS_MASTER_CNTRL, PMC_UTMIP_MASTER_CONFIG), + regmap_reg_range(PMC_UTMIP_UHSIC2_TRIGGERS, PMC_UTMIP_MASTER2_CONFIG), + regmap_reg_range(PMC_UTMIP_PAD_CFG0, PMC_UTMIP_UHSIC_SLEEP_CFG1), + regmap_reg_range(PMC_UTMIP_SLEEPWALK_P3, PMC_UTMIP_SLEEPWALK_P3), +}; + +static const struct regmap_access_table pmc_usb_sleepwalk_table = { + .yes_ranges = pmc_usb_sleepwalk_ranges, + .n_yes_ranges = ARRAY_SIZE(pmc_usb_sleepwalk_ranges), +}; + +static int tegra_pmc_regmap_readl(void *context, unsigned int offset, unsigned int *value) +{ + struct tegra_pmc *pmc = context; + + *value = tegra_pmc_readl(pmc, offset); + return 0; +} + +static int tegra_pmc_regmap_writel(void *context, unsigned int offset, unsigned int value) +{ + struct tegra_pmc *pmc = context; + + tegra_pmc_writel(pmc, value, offset); + return 0; +} + +static const struct regmap_config usb_sleepwalk_regmap_config = { + .name = "usb_sleepwalk", + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .fast_io = true, + .rd_table = &pmc_usb_sleepwalk_table, + .wr_table = &pmc_usb_sleepwalk_table, + .reg_read = tegra_pmc_regmap_readl, + .reg_write = tegra_pmc_regmap_writel, +}; + +static int tegra_pmc_regmap_init(struct tegra_pmc *pmc) +{ + struct regmap *regmap; + int err; + + if (pmc->soc->has_usb_sleepwalk) { + regmap = devm_regmap_init(pmc->dev, NULL, pmc, &usb_sleepwalk_regmap_config); + if (IS_ERR(regmap)) { + err = PTR_ERR(regmap); + dev_err(pmc->dev, "failed to allocate register map (%d)\n", err); + return err; + } + } + + return 0; +} + +static void tegra_pmc_reset_suspend_mode(void *data) +{ + pmc->suspend_mode = TEGRA_SUSPEND_NOT_READY; +} + static int tegra_pmc_probe(struct platform_device *pdev) { void __iomem *base; @@ -2513,49 +2879,90 @@ static int tegra_pmc_probe(struct platform_device *pdev) if (err < 0) return err; + err = devm_add_action_or_reset(&pdev->dev, tegra_pmc_reset_suspend_mode, + NULL); + if (err) + return err; + /* take over the memory region from the early initialization */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wake"); - if (res) { - pmc->wake = devm_ioremap_resource(&pdev->dev, res); + if (pmc->soc->has_single_mmio_aperture) { + pmc->wake = base; + pmc->aotag = base; + pmc->scratch = base; + } else { + pmc->wake = devm_platform_ioremap_resource_byname(pdev, "wake"); if (IS_ERR(pmc->wake)) return PTR_ERR(pmc->wake); - } else { - pmc->wake = base; - } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aotag"); - if (res) { - pmc->aotag = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(pmc->aotag)) - return PTR_ERR(pmc->aotag); - } else { - pmc->aotag = base; - } + /* "aotag" is an optional aperture */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "aotag"); + if (res) { + pmc->aotag = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pmc->aotag)) + return PTR_ERR(pmc->aotag); + } else { + pmc->aotag = NULL; + } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scratch"); - if (res) { - pmc->scratch = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(pmc->scratch)) - return PTR_ERR(pmc->scratch); - } else { - pmc->scratch = base; + /* "scratch" is an optional aperture */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "scratch"); + if (res) { + pmc->scratch = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pmc->scratch)) + return PTR_ERR(pmc->scratch); + } else { + pmc->scratch = NULL; + } } - pmc->clk = devm_clk_get(&pdev->dev, "pclk"); - if (IS_ERR(pmc->clk)) { - err = PTR_ERR(pmc->clk); + pmc->clk = devm_clk_get_optional(&pdev->dev, "pclk"); + if (IS_ERR(pmc->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(pmc->clk), + "failed to get pclk\n"); - if (err != -ENOENT) { - dev_err(&pdev->dev, "failed to get pclk: %d\n", err); + /* + * PMC should be last resort for restarting since it soft-resets + * CPU without resetting everything else. + */ + if (pmc->scratch) { + err = devm_register_reboot_notifier(&pdev->dev, + &tegra_pmc_reboot_notifier); + if (err) { + dev_err(&pdev->dev, + "unable to register reboot notifier, %d\n", + err); return err; } + } - pmc->clk = NULL; + err = devm_register_sys_off_handler(&pdev->dev, + SYS_OFF_MODE_RESTART, + SYS_OFF_PRIO_LOW, + tegra_pmc_restart_handler, NULL); + if (err) { + dev_err(&pdev->dev, "failed to register sys-off handler: %d\n", + err); + return err; + } + + /* + * PMC should be primary power-off method 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, NULL); + if (err) { + dev_err(&pdev->dev, "failed to register sys-off handler: %d\n", + err); + return err; } /* @@ -2565,7 +2972,8 @@ static int tegra_pmc_probe(struct platform_device *pdev) */ if (pmc->clk) { pmc->clk_nb.notifier_call = tegra_pmc_clk_notify_cb; - err = clk_notifier_register(pmc->clk, &pmc->clk_nb); + err = devm_clk_notifier_register(&pdev->dev, pmc->clk, + &pmc->clk_nb); if (err) { dev_err(&pdev->dev, "failed to register clk notifier\n"); @@ -2577,28 +2985,23 @@ static int tegra_pmc_probe(struct platform_device *pdev) pmc->dev = &pdev->dev; - tegra_pmc_init(pmc); + err = tegra_pmc_init(pmc); + if (err < 0) { + dev_err(&pdev->dev, "failed to initialize PMC: %d\n", err); + return err; + } tegra_pmc_init_tsense_reset(pmc); tegra_pmc_reset_sysfs_init(pmc); - if (IS_ENABLED(CONFIG_DEBUG_FS)) { - err = tegra_powergate_debugfs_init(); - if (err < 0) - goto cleanup_sysfs; - } - - err = register_restart_handler(&tegra_pmc_restart_handler); - if (err) { - dev_err(&pdev->dev, "unable to register restart handler, %d\n", - err); - goto cleanup_debugfs; - } - err = tegra_pmc_pinctrl_init(pmc); if (err) - goto cleanup_restart_handler; + goto cleanup_sysfs; + + err = tegra_pmc_regmap_init(pmc); + if (err < 0) + goto cleanup_sysfs; err = tegra_powergate_init(pmc, pdev->dev.of_node); if (err < 0) @@ -2615,23 +3018,180 @@ static int tegra_pmc_probe(struct platform_device *pdev) tegra_pmc_clock_register(pmc, pdev->dev.of_node); platform_set_drvdata(pdev, pmc); + tegra_pm_init_suspend(); + + /* Some wakes require specific filter configuration */ + if (pmc->soc->set_wake_filters) + pmc->soc->set_wake_filters(pmc); + + debugfs_create_file("powergate", 0444, NULL, NULL, &powergate_fops); return 0; cleanup_powergates: tegra_powergate_remove_all(pdev->dev.of_node); -cleanup_restart_handler: - unregister_restart_handler(&tegra_pmc_restart_handler); -cleanup_debugfs: - debugfs_remove(pmc->debugfs); cleanup_sysfs: device_remove_file(&pdev->dev, &dev_attr_reset_reason); device_remove_file(&pdev->dev, &dev_attr_reset_level); - clk_notifier_unregister(pmc->clk, &pmc->clk_nb); return err; } +/* + * Ensures that sufficient time is passed for a register write to + * serialize into the 32KHz domain. + */ +static void wke_32kwritel(struct tegra_pmc *pmc, u32 value, unsigned int offset) +{ + writel(value, pmc->wake + offset); + udelay(130); +} + +static void wke_write_wake_level(struct tegra_pmc *pmc, int wake, int level) +{ + unsigned int offset = WAKE_AOWAKE_CNTRL(wake); + u32 value; + + value = readl(pmc->wake + offset); + if (level) + value |= WAKE_AOWAKE_CNTRL_LEVEL; + else + value &= ~WAKE_AOWAKE_CNTRL_LEVEL; + + writel(value, pmc->wake + offset); +} + +static void wke_write_wake_levels(struct tegra_pmc *pmc) +{ + unsigned int i; + + for (i = 0; i < pmc->soc->max_wake_events; i++) + wke_write_wake_level(pmc, i, test_bit(i, pmc->wake_cntrl_level_map)); +} + +static void wke_clear_sw_wake_status(struct tegra_pmc *pmc) +{ + wke_32kwritel(pmc, 1, WAKE_AOWAKE_SW_STATUS_W_0); +} + +static void wke_read_sw_wake_status(struct tegra_pmc *pmc) +{ + unsigned long status; + unsigned int wake, i; + + for (i = 0; i < pmc->soc->max_wake_events; i++) + wke_write_wake_level(pmc, i, 0); + + wke_clear_sw_wake_status(pmc); + + wke_32kwritel(pmc, 1, WAKE_LATCH_SW); + + /* + * WAKE_AOWAKE_SW_STATUS is edge triggered, so in order to + * obtain the current status of the input wake signals, change + * the polarity of the wake level from 0->1 while latching to force + * a positive edge if the sampled signal is '1'. + */ + for (i = 0; i < pmc->soc->max_wake_events; i++) + wke_write_wake_level(pmc, i, 1); + + /* + * Wait for the update to be synced into the 32kHz domain, + * and let enough time lapse, so that the wake signals have time to + * be sampled. + */ + udelay(300); + + wke_32kwritel(pmc, 0, WAKE_LATCH_SW); + + bitmap_zero(pmc->wake_sw_status_map, pmc->soc->max_wake_events); + + for (i = 0; i < pmc->soc->max_wake_vectors; i++) { + status = readl(pmc->wake + WAKE_AOWAKE_SW_STATUS(i)); + + for_each_set_bit(wake, &status, 32) + set_bit(wake + (i * 32), pmc->wake_sw_status_map); + } +} + +static void wke_clear_wake_status(struct tegra_pmc *pmc) +{ + unsigned long status; + unsigned int i, wake; + u32 mask; + + for (i = 0; i < pmc->soc->max_wake_vectors; i++) { + mask = readl(pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(i)); + status = readl(pmc->wake + WAKE_AOWAKE_STATUS_R(i)) & mask; + + for_each_set_bit(wake, &status, 32) + wke_32kwritel(pmc, 0x1, WAKE_AOWAKE_STATUS_W((i * 32) + wake)); + } +} + +/* translate sc7 wake sources back into IRQs to catch edge triggered wakeups */ +static void tegra186_pmc_process_wake_events(struct tegra_pmc *pmc, unsigned int index, + unsigned long status) +{ + unsigned int wake; + + dev_dbg(pmc->dev, "Wake[%d:%d] status=%#lx\n", (index * 32) + 31, index * 32, status); + + for_each_set_bit(wake, &status, 32) { + irq_hw_number_t hwirq = wake + 32 * index; + struct irq_desc *desc; + unsigned int irq; + + irq = irq_find_mapping(pmc->domain, hwirq); + + desc = irq_to_desc(irq); + if (!desc || !desc->action || !desc->action->name) { + dev_dbg(pmc->dev, "Resume caused by WAKE%ld, IRQ %d\n", hwirq, irq); + continue; + } + + dev_dbg(pmc->dev, "Resume caused by WAKE%ld, %s\n", hwirq, desc->action->name); + generic_handle_irq(irq); + } +} + +static void tegra186_pmc_wake_syscore_resume(void *data) +{ + u32 status, mask; + unsigned int i; + + for (i = 0; i < pmc->soc->max_wake_vectors; i++) { + mask = readl(pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(i)); + status = readl(pmc->wake + WAKE_AOWAKE_STATUS_R(i)) & mask; + + tegra186_pmc_process_wake_events(pmc, i, status); + } +} + +static int tegra186_pmc_wake_syscore_suspend(void *data) +{ + wke_read_sw_wake_status(pmc); + + /* flip the wakeup trigger for dual-edge triggered pads + * which are currently asserting as wakeups + */ + bitmap_andnot(pmc->wake_cntrl_level_map, pmc->wake_type_dual_edge_map, + pmc->wake_sw_status_map, pmc->soc->max_wake_events); + bitmap_or(pmc->wake_cntrl_level_map, pmc->wake_cntrl_level_map, + pmc->wake_type_level_map, pmc->soc->max_wake_events); + + /* Clear PMC Wake Status registers while going to suspend */ + wke_clear_wake_status(pmc); + wke_write_wake_levels(pmc); + + return 0; +} + +static const struct syscore_ops tegra186_pmc_wake_syscore_ops = { + .suspend = tegra186_pmc_wake_syscore_suspend, + .resume = tegra186_pmc_wake_syscore_resume, +}; + #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM) static int tegra_pmc_suspend(struct device *dev) { @@ -2657,7 +3217,7 @@ static SIMPLE_DEV_PM_OPS(tegra_pmc_pm_ops, tegra_pmc_suspend, tegra_pmc_resume); static const char * const tegra20_powergates[] = { [TEGRA_POWERGATE_CPU] = "cpu", - [TEGRA_POWERGATE_3D] = "3d", + [TEGRA_POWERGATE_3D] = "td", [TEGRA_POWERGATE_VENC] = "venc", [TEGRA_POWERGATE_VDEC] = "vdec", [TEGRA_POWERGATE_PCIE] = "pcie", @@ -2667,10 +3227,6 @@ static const char * const tegra20_powergates[] = { static const struct tegra_pmc_regs tegra20_pmc_regs = { .scratch0 = 0x50, - .dpd_req = 0x1b8, - .dpd_status = 0x1bc, - .dpd2_req = 0x1c0, - .dpd2_status = 0x1c4, .rst_status = 0x1b4, .rst_source_shift = 0x0, .rst_source_mask = 0x7, @@ -2735,6 +3291,7 @@ static void tegra20_pmc_setup_irq_polarity(struct tegra_pmc *pmc, } static const struct tegra_pmc_soc tegra20_pmc_soc = { + .supports_core_domain = true, .num_powergates = ARRAY_SIZE(tegra20_powergates), .powergates = tegra20_powergates, .num_cpu_powergates = 0, @@ -2751,6 +3308,7 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = { .regs = &tegra20_pmc_regs, .init = tegra20_pmc_init, .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, + .powergate_set = tegra20_powergate_set, .reset_sources = NULL, .num_reset_sources = 0, .reset_levels = NULL, @@ -2758,11 +3316,13 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = { .pmc_clks_data = NULL, .num_pmc_clks = 0, .has_blink_output = true, + .has_usb_sleepwalk = true, + .has_single_mmio_aperture = true, }; static const char * const tegra30_powergates[] = { [TEGRA_POWERGATE_CPU] = "cpu0", - [TEGRA_POWERGATE_3D] = "3d0", + [TEGRA_POWERGATE_3D] = "td", [TEGRA_POWERGATE_VENC] = "venc", [TEGRA_POWERGATE_VDEC] = "vdec", [TEGRA_POWERGATE_PCIE] = "pcie", @@ -2774,7 +3334,7 @@ static const char * const tegra30_powergates[] = { [TEGRA_POWERGATE_CPU2] = "cpu2", [TEGRA_POWERGATE_CPU3] = "cpu3", [TEGRA_POWERGATE_CELP] = "celp", - [TEGRA_POWERGATE_3D1] = "3d1", + [TEGRA_POWERGATE_3D1] = "td2", }; static const u8 tegra30_cpu_powergates[] = { @@ -2784,7 +3344,16 @@ static const u8 tegra30_cpu_powergates[] = { TEGRA_POWERGATE_CPU3, }; +static const char * const tegra30_reset_sources[] = { + "POWER_ON_RESET", + "WATCHDOG", + "SENSOR", + "SW_MAIN", + "LP0" +}; + static const struct tegra_pmc_soc tegra30_pmc_soc = { + .supports_core_domain = true, .num_powergates = ARRAY_SIZE(tegra30_powergates), .powergates = tegra30_powergates, .num_cpu_powergates = ARRAY_SIZE(tegra30_cpu_powergates), @@ -2801,6 +3370,7 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = { .regs = &tegra20_pmc_regs, .init = tegra20_pmc_init, .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, + .powergate_set = tegra20_powergate_set, .reset_sources = tegra30_reset_sources, .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources), .reset_levels = NULL, @@ -2808,11 +3378,13 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = { .pmc_clks_data = tegra_pmc_clks_data, .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data), .has_blink_output = true, + .has_usb_sleepwalk = true, + .has_single_mmio_aperture = true, }; static const char * const tegra114_powergates[] = { [TEGRA_POWERGATE_CPU] = "crail", - [TEGRA_POWERGATE_3D] = "3d", + [TEGRA_POWERGATE_3D] = "td", [TEGRA_POWERGATE_VENC] = "venc", [TEGRA_POWERGATE_VDEC] = "vdec", [TEGRA_POWERGATE_MPE] = "mpe", @@ -2839,6 +3411,7 @@ static const u8 tegra114_cpu_powergates[] = { }; static const struct tegra_pmc_soc tegra114_pmc_soc = { + .supports_core_domain = false, .num_powergates = ARRAY_SIZE(tegra114_powergates), .powergates = tegra114_powergates, .num_cpu_powergates = ARRAY_SIZE(tegra114_cpu_powergates), @@ -2855,6 +3428,7 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = { .regs = &tegra20_pmc_regs, .init = tegra20_pmc_init, .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, + .powergate_set = tegra114_powergate_set, .reset_sources = tegra30_reset_sources, .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources), .reset_levels = NULL, @@ -2862,6 +3436,8 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = { .pmc_clks_data = tegra_pmc_clks_data, .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data), .has_blink_output = true, + .has_usb_sleepwalk = true, + .has_single_mmio_aperture = true, }; static const char * const tegra124_powergates[] = { @@ -2897,62 +3473,90 @@ static const u8 tegra124_cpu_powergates[] = { TEGRA_POWERGATE_CPU3, }; -#define TEGRA_IO_PAD(_id, _dpd, _voltage, _name) \ - ((struct tegra_io_pad_soc) { \ - .id = (_id), \ - .dpd = (_dpd), \ - .voltage = (_voltage), \ - .name = (_name), \ +#define TEGRA_IO_PAD(_id, _dpd, _request, _status, _voltage, _name) \ + ((struct tegra_io_pad_soc) { \ + .id = (_id), \ + .dpd = (_dpd), \ + .request = (_request), \ + .status = (_status), \ + .voltage = (_voltage), \ + .name = (_name), \ }) -#define TEGRA_IO_PIN_DESC(_id, _dpd, _voltage, _name) \ - ((struct pinctrl_pin_desc) { \ - .number = (_id), \ - .name = (_name) \ +#define TEGRA_IO_PIN_DESC(_id, _name) \ + ((struct pinctrl_pin_desc) { \ + .number = (_id), \ + .name = (_name), \ }) -#define TEGRA124_IO_PAD_TABLE(_pad) \ - /* .id .dpd .voltage .name */ \ - _pad(TEGRA_IO_PAD_AUDIO, 17, UINT_MAX, "audio"), \ - _pad(TEGRA_IO_PAD_BB, 15, UINT_MAX, "bb"), \ - _pad(TEGRA_IO_PAD_CAM, 36, UINT_MAX, "cam"), \ - _pad(TEGRA_IO_PAD_COMP, 22, UINT_MAX, "comp"), \ - _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \ - _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csb"), \ - _pad(TEGRA_IO_PAD_CSIE, 44, UINT_MAX, "cse"), \ - _pad(TEGRA_IO_PAD_DSI, 2, UINT_MAX, "dsi"), \ - _pad(TEGRA_IO_PAD_DSIB, 39, UINT_MAX, "dsib"), \ - _pad(TEGRA_IO_PAD_DSIC, 40, UINT_MAX, "dsic"), \ - _pad(TEGRA_IO_PAD_DSID, 41, UINT_MAX, "dsid"), \ - _pad(TEGRA_IO_PAD_HDMI, 28, UINT_MAX, "hdmi"), \ - _pad(TEGRA_IO_PAD_HSIC, 19, UINT_MAX, "hsic"), \ - _pad(TEGRA_IO_PAD_HV, 38, UINT_MAX, "hv"), \ - _pad(TEGRA_IO_PAD_LVDS, 57, UINT_MAX, "lvds"), \ - _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \ - _pad(TEGRA_IO_PAD_NAND, 13, UINT_MAX, "nand"), \ - _pad(TEGRA_IO_PAD_PEX_BIAS, 4, UINT_MAX, "pex-bias"), \ - _pad(TEGRA_IO_PAD_PEX_CLK1, 5, UINT_MAX, "pex-clk1"), \ - _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \ - _pad(TEGRA_IO_PAD_PEX_CNTRL, 32, UINT_MAX, "pex-cntrl"), \ - _pad(TEGRA_IO_PAD_SDMMC1, 33, UINT_MAX, "sdmmc1"), \ - _pad(TEGRA_IO_PAD_SDMMC3, 34, UINT_MAX, "sdmmc3"), \ - _pad(TEGRA_IO_PAD_SDMMC4, 35, UINT_MAX, "sdmmc4"), \ - _pad(TEGRA_IO_PAD_SYS_DDC, 58, UINT_MAX, "sys_ddc"), \ - _pad(TEGRA_IO_PAD_UART, 14, UINT_MAX, "uart"), \ - _pad(TEGRA_IO_PAD_USB0, 9, UINT_MAX, "usb0"), \ - _pad(TEGRA_IO_PAD_USB1, 10, UINT_MAX, "usb1"), \ - _pad(TEGRA_IO_PAD_USB2, 11, UINT_MAX, "usb2"), \ - _pad(TEGRA_IO_PAD_USB_BIAS, 12, UINT_MAX, "usb_bias") - static const struct tegra_io_pad_soc tegra124_io_pads[] = { - TEGRA124_IO_PAD_TABLE(TEGRA_IO_PAD) + TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO, 17, 0x1b8, 0x1bc, UINT_MAX, "audio"), + TEGRA_IO_PAD(TEGRA_IO_PAD_BB, 15, 0x1b8, 0x1bc, UINT_MAX, "bb"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CAM, 4, 0x1c0, 0x1c4, UINT_MAX, "cam"), + TEGRA_IO_PAD(TEGRA_IO_PAD_COMP, 22, 0x1b8, 0x1bc, UINT_MAX, "comp"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIA, 0, 0x1b8, 0x1bc, UINT_MAX, "csia"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIB, 1, 0x1b8, 0x1bc, UINT_MAX, "csib"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIE, 12, 0x1c0, 0x1c4, UINT_MAX, "csie"), + TEGRA_IO_PAD(TEGRA_IO_PAD_DSI, 2, 0x1b8, 0x1bc, UINT_MAX, "dsi"), + TEGRA_IO_PAD(TEGRA_IO_PAD_DSIB, 7, 0x1c0, 0x1c4, UINT_MAX, "dsib"), + TEGRA_IO_PAD(TEGRA_IO_PAD_DSIC, 8, 0x1c0, 0x1c4, UINT_MAX, "dsic"), + TEGRA_IO_PAD(TEGRA_IO_PAD_DSID, 9, 0x1c0, 0x1c4, UINT_MAX, "dsid"), + TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI, 28, 0x1b8, 0x1bc, UINT_MAX, "hdmi"), + TEGRA_IO_PAD(TEGRA_IO_PAD_HSIC, 19, 0x1b8, 0x1bc, UINT_MAX, "hsic"), + TEGRA_IO_PAD(TEGRA_IO_PAD_HV, 6, 0x1c0, 0x1c4, UINT_MAX, "hv"), + TEGRA_IO_PAD(TEGRA_IO_PAD_LVDS, 25, 0x1c0, 0x1c4, UINT_MAX, "lvds"), + TEGRA_IO_PAD(TEGRA_IO_PAD_MIPI_BIAS, 3, 0x1b8, 0x1bc, UINT_MAX, "mipi-bias"), + TEGRA_IO_PAD(TEGRA_IO_PAD_NAND, 13, 0x1b8, 0x1bc, UINT_MAX, "nand"), + TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_BIAS, 4, 0x1b8, 0x1bc, UINT_MAX, "pex-bias"), + TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK1, 5, 0x1b8, 0x1bc, UINT_MAX, "pex-clk1"), + TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK2, 6, 0x1b8, 0x1bc, UINT_MAX, "pex-clk2"), + TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CNTRL, 0, 0x1c0, 0x1c4, UINT_MAX, "pex-cntrl"), + TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1, 1, 0x1c0, 0x1c4, UINT_MAX, "sdmmc1"), + TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3, 2, 0x1c0, 0x1c4, UINT_MAX, "sdmmc3"), + TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC4, 3, 0x1c0, 0x1c4, UINT_MAX, "sdmmc4"), + TEGRA_IO_PAD(TEGRA_IO_PAD_SYS_DDC, 26, 0x1c0, 0x1c4, UINT_MAX, "sys_ddc"), + TEGRA_IO_PAD(TEGRA_IO_PAD_UART, 14, 0x1b8, 0x1bc, UINT_MAX, "uart"), + TEGRA_IO_PAD(TEGRA_IO_PAD_USB0, 9, 0x1b8, 0x1bc, UINT_MAX, "usb0"), + TEGRA_IO_PAD(TEGRA_IO_PAD_USB1, 10, 0x1b8, 0x1bc, UINT_MAX, "usb1"), + TEGRA_IO_PAD(TEGRA_IO_PAD_USB2, 11, 0x1b8, 0x1bc, UINT_MAX, "usb2"), + TEGRA_IO_PAD(TEGRA_IO_PAD_USB_BIAS, 12, 0x1b8, 0x1bc, UINT_MAX, "usb_bias"), }; static const struct pinctrl_pin_desc tegra124_pin_descs[] = { - TEGRA124_IO_PAD_TABLE(TEGRA_IO_PIN_DESC) + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AUDIO, "audio"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_BB, "bb"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CAM, "cam"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_COMP, "comp"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIA, "csia"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIB, "csib"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIE, "csie"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSI, "dsi"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSIB, "dsib"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSIC, "dsic"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSID, "dsid"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI, "hdmi"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HSIC, "hsic"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HV, "hv"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_LVDS, "lvds"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_MIPI_BIAS, "mipi-bias"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_NAND, "nand"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_BIAS, "pex-bias"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK1, "pex-clk1"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK2, "pex-clk2"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CNTRL, "pex-cntrl"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC1, "sdmmc1"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC3, "sdmmc3"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC4, "sdmmc4"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SYS_DDC, "sys_ddc"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UART, "uart"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB0, "usb0"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB1, "usb1"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB2, "usb2"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB_BIAS, "usb_bias"), }; static const struct tegra_pmc_soc tegra124_pmc_soc = { + .supports_core_domain = false, .num_powergates = ARRAY_SIZE(tegra124_powergates), .powergates = tegra124_powergates, .num_cpu_powergates = ARRAY_SIZE(tegra124_cpu_powergates), @@ -2969,6 +3573,7 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = { .regs = &tegra20_pmc_regs, .init = tegra20_pmc_init, .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, + .powergate_set = tegra114_powergate_set, .reset_sources = tegra30_reset_sources, .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources), .reset_levels = NULL, @@ -2976,6 +3581,8 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = { .pmc_clks_data = tegra_pmc_clks_data, .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data), .has_blink_output = true, + .has_usb_sleepwalk = true, + .has_single_mmio_aperture = true, }; static const char * const tegra210_powergates[] = { @@ -3012,53 +3619,95 @@ static const u8 tegra210_cpu_powergates[] = { TEGRA_POWERGATE_CPU3, }; -#define TEGRA210_IO_PAD_TABLE(_pad) \ - /* .id .dpd .voltage .name */ \ - _pad(TEGRA_IO_PAD_AUDIO, 17, 5, "audio"), \ - _pad(TEGRA_IO_PAD_AUDIO_HV, 61, 18, "audio-hv"), \ - _pad(TEGRA_IO_PAD_CAM, 36, 10, "cam"), \ - _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \ - _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csib"), \ - _pad(TEGRA_IO_PAD_CSIC, 42, UINT_MAX, "csic"), \ - _pad(TEGRA_IO_PAD_CSID, 43, UINT_MAX, "csid"), \ - _pad(TEGRA_IO_PAD_CSIE, 44, UINT_MAX, "csie"), \ - _pad(TEGRA_IO_PAD_CSIF, 45, UINT_MAX, "csif"), \ - _pad(TEGRA_IO_PAD_DBG, 25, 19, "dbg"), \ - _pad(TEGRA_IO_PAD_DEBUG_NONAO, 26, UINT_MAX, "debug-nonao"), \ - _pad(TEGRA_IO_PAD_DMIC, 50, 20, "dmic"), \ - _pad(TEGRA_IO_PAD_DP, 51, UINT_MAX, "dp"), \ - _pad(TEGRA_IO_PAD_DSI, 2, UINT_MAX, "dsi"), \ - _pad(TEGRA_IO_PAD_DSIB, 39, UINT_MAX, "dsib"), \ - _pad(TEGRA_IO_PAD_DSIC, 40, UINT_MAX, "dsic"), \ - _pad(TEGRA_IO_PAD_DSID, 41, UINT_MAX, "dsid"), \ - _pad(TEGRA_IO_PAD_EMMC, 35, UINT_MAX, "emmc"), \ - _pad(TEGRA_IO_PAD_EMMC2, 37, UINT_MAX, "emmc2"), \ - _pad(TEGRA_IO_PAD_GPIO, 27, 21, "gpio"), \ - _pad(TEGRA_IO_PAD_HDMI, 28, UINT_MAX, "hdmi"), \ - _pad(TEGRA_IO_PAD_HSIC, 19, UINT_MAX, "hsic"), \ - _pad(TEGRA_IO_PAD_LVDS, 57, UINT_MAX, "lvds"), \ - _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \ - _pad(TEGRA_IO_PAD_PEX_BIAS, 4, UINT_MAX, "pex-bias"), \ - _pad(TEGRA_IO_PAD_PEX_CLK1, 5, UINT_MAX, "pex-clk1"), \ - _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \ - _pad(TEGRA_IO_PAD_PEX_CNTRL, UINT_MAX, 11, "pex-cntrl"), \ - _pad(TEGRA_IO_PAD_SDMMC1, 33, 12, "sdmmc1"), \ - _pad(TEGRA_IO_PAD_SDMMC3, 34, 13, "sdmmc3"), \ - _pad(TEGRA_IO_PAD_SPI, 46, 22, "spi"), \ - _pad(TEGRA_IO_PAD_SPI_HV, 47, 23, "spi-hv"), \ - _pad(TEGRA_IO_PAD_UART, 14, 2, "uart"), \ - _pad(TEGRA_IO_PAD_USB0, 9, UINT_MAX, "usb0"), \ - _pad(TEGRA_IO_PAD_USB1, 10, UINT_MAX, "usb1"), \ - _pad(TEGRA_IO_PAD_USB2, 11, UINT_MAX, "usb2"), \ - _pad(TEGRA_IO_PAD_USB3, 18, UINT_MAX, "usb3"), \ - _pad(TEGRA_IO_PAD_USB_BIAS, 12, UINT_MAX, "usb-bias") - static const struct tegra_io_pad_soc tegra210_io_pads[] = { - TEGRA210_IO_PAD_TABLE(TEGRA_IO_PAD) + TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO, 17, 0x1b8, 0x1bc, 5, "audio"), + TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO_HV, 29, 0x1c0, 0x1c4, 18, "audio-hv"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CAM, 4, 0x1c0, 0x1c4, 10, "cam"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIA, 0, 0x1b8, 0x1bc, UINT_MAX, "csia"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIB, 1, 0x1b8, 0x1bc, UINT_MAX, "csib"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIC, 10, 0x1c0, 0x1c4, UINT_MAX, "csic"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSID, 11, 0x1c0, 0x1c4, UINT_MAX, "csid"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIE, 12, 0x1c0, 0x1c4, UINT_MAX, "csie"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIF, 13, 0x1c0, 0x1c4, UINT_MAX, "csif"), + TEGRA_IO_PAD(TEGRA_IO_PAD_DBG, 25, 0x1b8, 0x1bc, 19, "dbg"), + TEGRA_IO_PAD(TEGRA_IO_PAD_DEBUG_NONAO, 26, 0x1b8, 0x1bc, UINT_MAX, "debug-nonao"), + TEGRA_IO_PAD(TEGRA_IO_PAD_DMIC, 18, 0x1c0, 0x1c4, 20, "dmic"), + TEGRA_IO_PAD(TEGRA_IO_PAD_DP, 19, 0x1c0, 0x1c4, UINT_MAX, "dp"), + TEGRA_IO_PAD(TEGRA_IO_PAD_DSI, 2, 0x1b8, 0x1bc, UINT_MAX, "dsi"), + TEGRA_IO_PAD(TEGRA_IO_PAD_DSIB, 7, 0x1c0, 0x1c4, UINT_MAX, "dsib"), + TEGRA_IO_PAD(TEGRA_IO_PAD_DSIC, 8, 0x1c0, 0x1c4, UINT_MAX, "dsic"), + TEGRA_IO_PAD(TEGRA_IO_PAD_DSID, 9, 0x1c0, 0x1c4, UINT_MAX, "dsid"), + TEGRA_IO_PAD(TEGRA_IO_PAD_EMMC, 3, 0x1c0, 0x1c4, UINT_MAX, "emmc"), + TEGRA_IO_PAD(TEGRA_IO_PAD_EMMC2, 5, 0x1c0, 0x1c4, UINT_MAX, "emmc2"), + TEGRA_IO_PAD(TEGRA_IO_PAD_GPIO, 27, 0x1b8, 0x1bc, 21, "gpio"), + TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI, 28, 0x1b8, 0x1bc, UINT_MAX, "hdmi"), + TEGRA_IO_PAD(TEGRA_IO_PAD_HSIC, 19, 0x1b8, 0x1bc, UINT_MAX, "hsic"), + TEGRA_IO_PAD(TEGRA_IO_PAD_LVDS, 25, 0x1c0, 0x1c4, UINT_MAX, "lvds"), + TEGRA_IO_PAD(TEGRA_IO_PAD_MIPI_BIAS, 3, 0x1b8, 0x1bc, UINT_MAX, "mipi-bias"), + TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_BIAS, 4, 0x1b8, 0x1bc, UINT_MAX, "pex-bias"), + TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK1, 5, 0x1b8, 0x1bc, UINT_MAX, "pex-clk1"), + TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK2, 6, 0x1b8, 0x1bc, UINT_MAX, "pex-clk2"), + TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CNTRL, UINT_MAX, UINT_MAX, UINT_MAX, 11, "pex-cntrl"), + TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1, 1, 0x1c0, 0x1c4, 12, "sdmmc1"), + TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3, 2, 0x1c0, 0x1c4, 13, "sdmmc3"), + TEGRA_IO_PAD(TEGRA_IO_PAD_SPI, 14, 0x1c0, 0x1c4, 22, "spi"), + TEGRA_IO_PAD(TEGRA_IO_PAD_SPI_HV, 15, 0x1c0, 0x1c4, 23, "spi-hv"), + TEGRA_IO_PAD(TEGRA_IO_PAD_UART, 14, 0x1b8, 0x1bc, 2, "uart"), + TEGRA_IO_PAD(TEGRA_IO_PAD_USB0, 9, 0x1b8, 0x1bc, UINT_MAX, "usb0"), + TEGRA_IO_PAD(TEGRA_IO_PAD_USB1, 10, 0x1b8, 0x1bc, UINT_MAX, "usb1"), + TEGRA_IO_PAD(TEGRA_IO_PAD_USB2, 11, 0x1b8, 0x1bc, UINT_MAX, "usb2"), + TEGRA_IO_PAD(TEGRA_IO_PAD_USB3, 18, 0x1b8, 0x1bc, UINT_MAX, "usb3"), + TEGRA_IO_PAD(TEGRA_IO_PAD_USB_BIAS, 12, 0x1b8, 0x1bc, UINT_MAX, "usb-bias"), }; static const struct pinctrl_pin_desc tegra210_pin_descs[] = { - TEGRA210_IO_PAD_TABLE(TEGRA_IO_PIN_DESC) + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AUDIO, "audio"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AUDIO_HV, "audio-hv"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CAM, "cam"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIA, "csia"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIB, "csib"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIC, "csic"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSID, "csid"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIE, "csie"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIF, "csif"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DBG, "dbg"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DEBUG_NONAO, "debug-nonao"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DMIC, "dmic"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DP, "dp"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSI, "dsi"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSIB, "dsib"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSIC, "dsic"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSID, "dsid"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_EMMC, "emmc"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_EMMC2, "emmc2"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_GPIO, "gpio"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI, "hdmi"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HSIC, "hsic"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_LVDS, "lvds"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_MIPI_BIAS, "mipi-bias"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_BIAS, "pex-bias"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK1, "pex-clk1"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK2, "pex-clk2"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CNTRL, "pex-cntrl"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC1, "sdmmc1"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC3, "sdmmc3"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SPI, "spi"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SPI_HV, "spi-hv"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UART, "uart"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB0, "usb0"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB1, "usb1"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB2, "usb2"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB3, "usb3"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB_BIAS, "usb-bias"), +}; + +static const char * const tegra210_reset_sources[] = { + "POWER_ON_RESET", + "WATCHDOG", + "SENSOR", + "SW_MAIN", + "LP0", + "AOTAG" }; static const struct tegra_wake_event tegra210_wake_events[] = { @@ -3067,6 +3716,7 @@ static const struct tegra_wake_event tegra210_wake_events[] = { }; static const struct tegra_pmc_soc tegra210_pmc_soc = { + .supports_core_domain = false, .num_powergates = ARRAY_SIZE(tegra210_powergates), .powergates = tegra210_powergates, .num_cpu_powergates = ARRAY_SIZE(tegra210_cpu_powergates), @@ -3083,6 +3733,7 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = { .regs = &tegra20_pmc_regs, .init = tegra20_pmc_init, .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, + .powergate_set = tegra114_powergate_set, .irq_set_wake = tegra210_pmc_irq_set_wake, .irq_set_type = tegra210_pmc_irq_set_type, .reset_sources = tegra210_reset_sources, @@ -3094,63 +3745,94 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = { .pmc_clks_data = tegra_pmc_clks_data, .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data), .has_blink_output = true, + .has_usb_sleepwalk = true, + .has_single_mmio_aperture = true, }; -#define TEGRA186_IO_PAD_TABLE(_pad) \ - /* .id .dpd .voltage .name */ \ - _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \ - _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csib"), \ - _pad(TEGRA_IO_PAD_DSI, 2, UINT_MAX, "dsi"), \ - _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \ - _pad(TEGRA_IO_PAD_PEX_CLK_BIAS, 4, UINT_MAX, "pex-clk-bias"), \ - _pad(TEGRA_IO_PAD_PEX_CLK3, 5, UINT_MAX, "pex-clk3"), \ - _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \ - _pad(TEGRA_IO_PAD_PEX_CLK1, 7, UINT_MAX, "pex-clk1"), \ - _pad(TEGRA_IO_PAD_USB0, 9, UINT_MAX, "usb0"), \ - _pad(TEGRA_IO_PAD_USB1, 10, UINT_MAX, "usb1"), \ - _pad(TEGRA_IO_PAD_USB2, 11, UINT_MAX, "usb2"), \ - _pad(TEGRA_IO_PAD_USB_BIAS, 12, UINT_MAX, "usb-bias"), \ - _pad(TEGRA_IO_PAD_UART, 14, UINT_MAX, "uart"), \ - _pad(TEGRA_IO_PAD_AUDIO, 17, UINT_MAX, "audio"), \ - _pad(TEGRA_IO_PAD_HSIC, 19, UINT_MAX, "hsic"), \ - _pad(TEGRA_IO_PAD_DBG, 25, UINT_MAX, "dbg"), \ - _pad(TEGRA_IO_PAD_HDMI_DP0, 28, UINT_MAX, "hdmi-dp0"), \ - _pad(TEGRA_IO_PAD_HDMI_DP1, 29, UINT_MAX, "hdmi-dp1"), \ - _pad(TEGRA_IO_PAD_PEX_CNTRL, 32, UINT_MAX, "pex-cntrl"), \ - _pad(TEGRA_IO_PAD_SDMMC2_HV, 34, 5, "sdmmc2-hv"), \ - _pad(TEGRA_IO_PAD_SDMMC4, 36, UINT_MAX, "sdmmc4"), \ - _pad(TEGRA_IO_PAD_CAM, 38, UINT_MAX, "cam"), \ - _pad(TEGRA_IO_PAD_DSIB, 40, UINT_MAX, "dsib"), \ - _pad(TEGRA_IO_PAD_DSIC, 41, UINT_MAX, "dsic"), \ - _pad(TEGRA_IO_PAD_DSID, 42, UINT_MAX, "dsid"), \ - _pad(TEGRA_IO_PAD_CSIC, 43, UINT_MAX, "csic"), \ - _pad(TEGRA_IO_PAD_CSID, 44, UINT_MAX, "csid"), \ - _pad(TEGRA_IO_PAD_CSIE, 45, UINT_MAX, "csie"), \ - _pad(TEGRA_IO_PAD_CSIF, 46, UINT_MAX, "csif"), \ - _pad(TEGRA_IO_PAD_SPI, 47, UINT_MAX, "spi"), \ - _pad(TEGRA_IO_PAD_UFS, 49, UINT_MAX, "ufs"), \ - _pad(TEGRA_IO_PAD_DMIC_HV, 52, 2, "dmic-hv"), \ - _pad(TEGRA_IO_PAD_EDP, 53, UINT_MAX, "edp"), \ - _pad(TEGRA_IO_PAD_SDMMC1_HV, 55, 4, "sdmmc1-hv"), \ - _pad(TEGRA_IO_PAD_SDMMC3_HV, 56, 6, "sdmmc3-hv"), \ - _pad(TEGRA_IO_PAD_CONN, 60, UINT_MAX, "conn"), \ - _pad(TEGRA_IO_PAD_AUDIO_HV, 61, 1, "audio-hv"), \ - _pad(TEGRA_IO_PAD_AO_HV, UINT_MAX, 0, "ao-hv") - static const struct tegra_io_pad_soc tegra186_io_pads[] = { - TEGRA186_IO_PAD_TABLE(TEGRA_IO_PAD) + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIA, 0, 0x74, 0x78, UINT_MAX, "csia"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIB, 1, 0x74, 0x78, UINT_MAX, "csib"), + TEGRA_IO_PAD(TEGRA_IO_PAD_DSI, 2, 0x74, 0x78, UINT_MAX, "dsi"), + TEGRA_IO_PAD(TEGRA_IO_PAD_MIPI_BIAS, 3, 0x74, 0x78, UINT_MAX, "mipi-bias"), + TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK_BIAS, 4, 0x74, 0x78, UINT_MAX, "pex-clk-bias"), + TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK3, 5, 0x74, 0x78, UINT_MAX, "pex-clk3"), + TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK2, 6, 0x74, 0x78, UINT_MAX, "pex-clk2"), + TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK1, 7, 0x74, 0x78, UINT_MAX, "pex-clk1"), + TEGRA_IO_PAD(TEGRA_IO_PAD_USB0, 9, 0x74, 0x78, UINT_MAX, "usb0"), + TEGRA_IO_PAD(TEGRA_IO_PAD_USB1, 10, 0x74, 0x78, UINT_MAX, "usb1"), + TEGRA_IO_PAD(TEGRA_IO_PAD_USB2, 11, 0x74, 0x78, UINT_MAX, "usb2"), + TEGRA_IO_PAD(TEGRA_IO_PAD_USB_BIAS, 12, 0x74, 0x78, UINT_MAX, "usb-bias"), + TEGRA_IO_PAD(TEGRA_IO_PAD_UART, 14, 0x74, 0x78, UINT_MAX, "uart"), + TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO, 17, 0x74, 0x78, UINT_MAX, "audio"), + TEGRA_IO_PAD(TEGRA_IO_PAD_HSIC, 19, 0x74, 0x78, UINT_MAX, "hsic"), + TEGRA_IO_PAD(TEGRA_IO_PAD_DBG, 25, 0x74, 0x78, UINT_MAX, "dbg"), + TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP0, 28, 0x74, 0x78, UINT_MAX, "hdmi-dp0"), + TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP1, 29, 0x74, 0x78, UINT_MAX, "hdmi-dp1"), + TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CNTRL, 0, 0x7c, 0x80, UINT_MAX, "pex-cntrl"), + TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC2_HV, 2, 0x7c, 0x80, 5, "sdmmc2-hv"), + TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC4, 4, 0x7c, 0x80, UINT_MAX, "sdmmc4"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CAM, 6, 0x7c, 0x80, UINT_MAX, "cam"), + TEGRA_IO_PAD(TEGRA_IO_PAD_DSIB, 8, 0x7c, 0x80, UINT_MAX, "dsib"), + TEGRA_IO_PAD(TEGRA_IO_PAD_DSIC, 9, 0x7c, 0x80, UINT_MAX, "dsic"), + TEGRA_IO_PAD(TEGRA_IO_PAD_DSID, 10, 0x7c, 0x80, UINT_MAX, "dsid"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIC, 11, 0x7c, 0x80, UINT_MAX, "csic"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSID, 12, 0x7c, 0x80, UINT_MAX, "csid"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIE, 13, 0x7c, 0x80, UINT_MAX, "csie"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIF, 14, 0x7c, 0x80, UINT_MAX, "csif"), + TEGRA_IO_PAD(TEGRA_IO_PAD_SPI, 15, 0x7c, 0x80, UINT_MAX, "spi"), + TEGRA_IO_PAD(TEGRA_IO_PAD_UFS, 17, 0x7c, 0x80, UINT_MAX, "ufs"), + TEGRA_IO_PAD(TEGRA_IO_PAD_DMIC_HV, 20, 0x7c, 0x80, 2, "dmic-hv"), + TEGRA_IO_PAD(TEGRA_IO_PAD_EDP, 21, 0x7c, 0x80, UINT_MAX, "edp"), + TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1_HV, 23, 0x7c, 0x80, 4, "sdmmc1-hv"), + TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3_HV, 24, 0x7c, 0x80, 6, "sdmmc3-hv"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CONN, 28, 0x7c, 0x80, UINT_MAX, "conn"), + TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO_HV, 29, 0x7c, 0x80, 1, "audio-hv"), + TEGRA_IO_PAD(TEGRA_IO_PAD_AO_HV, UINT_MAX, UINT_MAX, UINT_MAX, 0, "ao-hv"), }; static const struct pinctrl_pin_desc tegra186_pin_descs[] = { - TEGRA186_IO_PAD_TABLE(TEGRA_IO_PIN_DESC) + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIA, "csia"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIB, "csib"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSI, "dsi"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_MIPI_BIAS, "mipi-bias"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK_BIAS, "pex-clk-bias"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK3, "pex-clk3"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK2, "pex-clk2"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK1, "pex-clk1"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB0, "usb0"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB1, "usb1"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB2, "usb2"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_USB_BIAS, "usb-bias"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UART, "uart"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AUDIO, "audio"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HSIC, "hsic"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DBG, "dbg"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI_DP0, "hdmi-dp0"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI_DP1, "hdmi-dp1"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CNTRL, "pex-cntrl"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC2_HV, "sdmmc2-hv"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC4, "sdmmc4"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CAM, "cam"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSIB, "dsib"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSIC, "dsic"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DSID, "dsid"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIC, "csic"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSID, "csid"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIE, "csie"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIF, "csif"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SPI, "spi"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UFS, "ufs"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DMIC_HV, "dmic-hv"), + 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_CONN, "conn"), + 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 tegra186_pmc_regs = { .scratch0 = 0x2000, - .dpd_req = 0x74, - .dpd_status = 0x78, - .dpd2_req = 0x7c, - .dpd2_status = 0x80, .rst_status = 0x70, .rst_source_shift = 0x2, .rst_source_mask = 0x3c, @@ -3158,6 +3840,12 @@ static const struct tegra_pmc_regs tegra186_pmc_regs = { .rst_level_mask = 0x3, }; +static void tegra186_pmc_init(struct tegra_pmc *pmc) +{ + pmc->syscore.ops = &tegra186_pmc_wake_syscore_ops; + register_syscore(&pmc->syscore); +} + static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc, struct device_node *np, bool invert) @@ -3193,6 +3881,28 @@ static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc, iounmap(wake); } +static const char * const tegra186_reset_sources[] = { + "SYS_RESET", + "AOWDT", + "MCCPLEXWDT", + "BPMPWDT", + "SCEWDT", + "SPEWDT", + "APEWDT", + "BCCPLEXWDT", + "SENSOR", + "AOTAG", + "VFSENSOR", + "SWREST", + "SC7", + "HSM", + "CORESIGHT" +}; + +static const char * const tegra186_reset_levels[] = { + "L0", "L1", "L2", "WARM" +}; + static const struct tegra_wake_event tegra186_wake_events[] = { TEGRA_WAKE_IRQ("pmu", 24, 209), TEGRA_WAKE_GPIO("power", 29, 1, TEGRA186_AON_GPIO(FF, 0)), @@ -3200,6 +3910,7 @@ static const struct tegra_wake_event tegra186_wake_events[] = { }; static const struct tegra_pmc_soc tegra186_pmc_soc = { + .supports_core_domain = false, .num_powergates = 0, .powergates = NULL, .num_cpu_powergates = 0, @@ -3214,8 +3925,9 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = { .num_pin_descs = ARRAY_SIZE(tegra186_pin_descs), .pin_descs = tegra186_pin_descs, .regs = &tegra186_pmc_regs, - .init = NULL, + .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 = tegra186_reset_sources, @@ -3224,77 +3936,121 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = { .num_reset_levels = ARRAY_SIZE(tegra186_reset_levels), .num_wake_events = ARRAY_SIZE(tegra186_wake_events), .wake_events = tegra186_wake_events, + .max_wake_events = 96, + .max_wake_vectors = 3, .pmc_clks_data = NULL, .num_pmc_clks = 0, .has_blink_output = false, + .has_usb_sleepwalk = false, + .has_single_mmio_aperture = false, }; -#define TEGRA194_IO_PAD_TABLE(_pad) \ - /* .id .dpd .voltage .name */ \ - _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \ - _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csib"), \ - _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \ - _pad(TEGRA_IO_PAD_PEX_CLK_BIAS, 4, UINT_MAX, "pex-clk-bias"), \ - _pad(TEGRA_IO_PAD_PEX_CLK3, 5, UINT_MAX, "pex-clk3"), \ - _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \ - _pad(TEGRA_IO_PAD_PEX_CLK1, 7, UINT_MAX, "pex-clk1"), \ - _pad(TEGRA_IO_PAD_EQOS, 8, UINT_MAX, "eqos"), \ - _pad(TEGRA_IO_PAD_PEX_CLK_2_BIAS, 9, UINT_MAX, "pex-clk-2-bias"), \ - _pad(TEGRA_IO_PAD_PEX_CLK_2, 10, UINT_MAX, "pex-clk-2"), \ - _pad(TEGRA_IO_PAD_DAP3, 11, UINT_MAX, "dap3"), \ - _pad(TEGRA_IO_PAD_DAP5, 12, UINT_MAX, "dap5"), \ - _pad(TEGRA_IO_PAD_UART, 14, UINT_MAX, "uart"), \ - _pad(TEGRA_IO_PAD_PWR_CTL, 15, UINT_MAX, "pwr-ctl"), \ - _pad(TEGRA_IO_PAD_SOC_GPIO53, 16, UINT_MAX, "soc-gpio53"), \ - _pad(TEGRA_IO_PAD_AUDIO, 17, UINT_MAX, "audio"), \ - _pad(TEGRA_IO_PAD_GP_PWM2, 18, UINT_MAX, "gp-pwm2"), \ - _pad(TEGRA_IO_PAD_GP_PWM3, 19, UINT_MAX, "gp-pwm3"), \ - _pad(TEGRA_IO_PAD_SOC_GPIO12, 20, UINT_MAX, "soc-gpio12"), \ - _pad(TEGRA_IO_PAD_SOC_GPIO13, 21, UINT_MAX, "soc-gpio13"), \ - _pad(TEGRA_IO_PAD_SOC_GPIO10, 22, UINT_MAX, "soc-gpio10"), \ - _pad(TEGRA_IO_PAD_UART4, 23, UINT_MAX, "uart4"), \ - _pad(TEGRA_IO_PAD_UART5, 24, UINT_MAX, "uart5"), \ - _pad(TEGRA_IO_PAD_DBG, 25, UINT_MAX, "dbg"), \ - _pad(TEGRA_IO_PAD_HDMI_DP3, 26, UINT_MAX, "hdmi-dp3"), \ - _pad(TEGRA_IO_PAD_HDMI_DP2, 27, UINT_MAX, "hdmi-dp2"), \ - _pad(TEGRA_IO_PAD_HDMI_DP0, 28, UINT_MAX, "hdmi-dp0"), \ - _pad(TEGRA_IO_PAD_HDMI_DP1, 29, UINT_MAX, "hdmi-dp1"), \ - _pad(TEGRA_IO_PAD_PEX_CNTRL, 32, UINT_MAX, "pex-cntrl"), \ - _pad(TEGRA_IO_PAD_PEX_CTL2, 33, UINT_MAX, "pex-ctl2"), \ - _pad(TEGRA_IO_PAD_PEX_L0_RST_N, 34, UINT_MAX, "pex-l0-rst"), \ - _pad(TEGRA_IO_PAD_PEX_L1_RST_N, 35, UINT_MAX, "pex-l1-rst"), \ - _pad(TEGRA_IO_PAD_SDMMC4, 36, UINT_MAX, "sdmmc4"), \ - _pad(TEGRA_IO_PAD_PEX_L5_RST_N, 37, UINT_MAX, "pex-l5-rst"), \ - _pad(TEGRA_IO_PAD_CAM, 38, UINT_MAX, "cam"), \ - _pad(TEGRA_IO_PAD_CSIC, 43, UINT_MAX, "csic"), \ - _pad(TEGRA_IO_PAD_CSID, 44, UINT_MAX, "csid"), \ - _pad(TEGRA_IO_PAD_CSIE, 45, UINT_MAX, "csie"), \ - _pad(TEGRA_IO_PAD_CSIF, 46, UINT_MAX, "csif"), \ - _pad(TEGRA_IO_PAD_SPI, 47, UINT_MAX, "spi"), \ - _pad(TEGRA_IO_PAD_UFS, 49, UINT_MAX, "ufs"), \ - _pad(TEGRA_IO_PAD_CSIG, 50, UINT_MAX, "csig"), \ - _pad(TEGRA_IO_PAD_CSIH, 51, UINT_MAX, "csih"), \ - _pad(TEGRA_IO_PAD_EDP, 53, UINT_MAX, "edp"), \ - _pad(TEGRA_IO_PAD_SDMMC1_HV, 55, 4, "sdmmc1-hv"), \ - _pad(TEGRA_IO_PAD_SDMMC3_HV, 56, 6, "sdmmc3-hv"), \ - _pad(TEGRA_IO_PAD_CONN, 60, UINT_MAX, "conn"), \ - _pad(TEGRA_IO_PAD_AUDIO_HV, 61, 1, "audio-hv"), \ - _pad(TEGRA_IO_PAD_AO_HV, UINT_MAX, 0, "ao-hv") - static const struct tegra_io_pad_soc tegra194_io_pads[] = { - TEGRA194_IO_PAD_TABLE(TEGRA_IO_PAD) + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIA, 0, 0x74, 0x78, UINT_MAX, "csia"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIB, 1, 0x74, 0x78, UINT_MAX, "csib"), + TEGRA_IO_PAD(TEGRA_IO_PAD_MIPI_BIAS, 3, 0x74, 0x78, UINT_MAX, "mipi-bias"), + TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK_BIAS, 4, 0x74, 0x78, UINT_MAX, "pex-clk-bias"), + TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK3, 5, 0x74, 0x78, UINT_MAX, "pex-clk3"), + TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK2, 6, 0x74, 0x78, UINT_MAX, "pex-clk2"), + TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK1, 7, 0x74, 0x78, UINT_MAX, "pex-clk1"), + TEGRA_IO_PAD(TEGRA_IO_PAD_EQOS, 8, 0x74, 0x78, UINT_MAX, "eqos"), + TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK_2_BIAS, 9, 0x74, 0x78, UINT_MAX, "pex-clk-2-bias"), + TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK_2, 10, 0x74, 0x78, UINT_MAX, "pex-clk-2"), + TEGRA_IO_PAD(TEGRA_IO_PAD_DAP3, 11, 0x74, 0x78, UINT_MAX, "dap3"), + TEGRA_IO_PAD(TEGRA_IO_PAD_DAP5, 12, 0x74, 0x78, UINT_MAX, "dap5"), + TEGRA_IO_PAD(TEGRA_IO_PAD_UART, 14, 0x74, 0x78, UINT_MAX, "uart"), + TEGRA_IO_PAD(TEGRA_IO_PAD_PWR_CTL, 15, 0x74, 0x78, UINT_MAX, "pwr-ctl"), + TEGRA_IO_PAD(TEGRA_IO_PAD_SOC_GPIO53, 16, 0x74, 0x78, UINT_MAX, "soc-gpio53"), + TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO, 17, 0x74, 0x78, UINT_MAX, "audio"), + TEGRA_IO_PAD(TEGRA_IO_PAD_GP_PWM2, 18, 0x74, 0x78, UINT_MAX, "gp-pwm2"), + TEGRA_IO_PAD(TEGRA_IO_PAD_GP_PWM3, 19, 0x74, 0x78, UINT_MAX, "gp-pwm3"), + TEGRA_IO_PAD(TEGRA_IO_PAD_SOC_GPIO12, 20, 0x74, 0x78, UINT_MAX, "soc-gpio12"), + TEGRA_IO_PAD(TEGRA_IO_PAD_SOC_GPIO13, 21, 0x74, 0x78, UINT_MAX, "soc-gpio13"), + TEGRA_IO_PAD(TEGRA_IO_PAD_SOC_GPIO10, 22, 0x74, 0x78, UINT_MAX, "soc-gpio10"), + TEGRA_IO_PAD(TEGRA_IO_PAD_UART4, 23, 0x74, 0x78, UINT_MAX, "uart4"), + TEGRA_IO_PAD(TEGRA_IO_PAD_UART5, 24, 0x74, 0x78, UINT_MAX, "uart5"), + TEGRA_IO_PAD(TEGRA_IO_PAD_DBG, 25, 0x74, 0x78, UINT_MAX, "dbg"), + TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP3, 26, 0x74, 0x78, UINT_MAX, "hdmi-dp3"), + TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP2, 27, 0x74, 0x78, UINT_MAX, "hdmi-dp2"), + TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP0, 28, 0x74, 0x78, UINT_MAX, "hdmi-dp0"), + TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP1, 29, 0x74, 0x78, UINT_MAX, "hdmi-dp1"), + TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CNTRL, 0, 0x7c, 0x80, UINT_MAX, "pex-cntrl"), + TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CTL2, 1, 0x7c, 0x80, UINT_MAX, "pex-ctl2"), + TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_L0_RST, 2, 0x7c, 0x80, UINT_MAX, "pex-l0-rst"), + TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_L1_RST, 3, 0x7c, 0x80, UINT_MAX, "pex-l1-rst"), + TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC4, 4, 0x7c, 0x80, UINT_MAX, "sdmmc4"), + TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_L5_RST, 5, 0x7c, 0x80, UINT_MAX, "pex-l5-rst"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CAM, 6, 0x7c, 0x80, UINT_MAX, "cam"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIC, 11, 0x7c, 0x80, UINT_MAX, "csic"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSID, 12, 0x7c, 0x80, UINT_MAX, "csid"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIE, 13, 0x7c, 0x80, UINT_MAX, "csie"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIF, 14, 0x7c, 0x80, UINT_MAX, "csif"), + TEGRA_IO_PAD(TEGRA_IO_PAD_SPI, 15, 0x7c, 0x80, UINT_MAX, "spi"), + TEGRA_IO_PAD(TEGRA_IO_PAD_UFS, 17, 0x7c, 0x80, UINT_MAX, "ufs"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIG, 18, 0x7c, 0x80, UINT_MAX, "csig"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIH, 19, 0x7c, 0x80, UINT_MAX, "csih"), + TEGRA_IO_PAD(TEGRA_IO_PAD_EDP, 21, 0x7c, 0x80, UINT_MAX, "edp"), + TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1_HV, 23, 0x7c, 0x80, 4, "sdmmc1-hv"), + TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3_HV, 24, 0x7c, 0x80, 6, "sdmmc3-hv"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CONN, 28, 0x7c, 0x80, UINT_MAX, "conn"), + TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO_HV, 29, 0x7c, 0x80, 1, "audio-hv"), + TEGRA_IO_PAD(TEGRA_IO_PAD_AO_HV, UINT_MAX, UINT_MAX, UINT_MAX, 0, "ao-hv"), }; static const struct pinctrl_pin_desc tegra194_pin_descs[] = { - TEGRA194_IO_PAD_TABLE(TEGRA_IO_PIN_DESC) + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIA, "csia"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIB, "csib"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_MIPI_BIAS, "mipi-bias"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK_BIAS, "pex-clk-bias"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK3, "pex-clk3"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK2, "pex-clk2"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK1, "pex-clk1"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_EQOS, "eqos"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK_2_BIAS, "pex-clk-2-bias"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CLK_2, "pex-clk-2"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DAP3, "dap3"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DAP5, "dap5"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UART, "uart"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PWR_CTL, "pwr-ctl"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SOC_GPIO53, "soc-gpio53"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AUDIO, "audio"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_GP_PWM2, "gp-pwm2"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_GP_PWM3, "gp-pwm3"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SOC_GPIO12, "soc-gpio12"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SOC_GPIO13, "soc-gpio13"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SOC_GPIO10, "soc-gpio10"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UART4, "uart4"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UART5, "uart5"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_DBG, "dbg"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI_DP3, "hdmi-dp3"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI_DP2, "hdmi-dp2"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI_DP0, "hdmi-dp0"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI_DP1, "hdmi-dp1"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CNTRL, "pex-cntrl"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_CTL2, "pex-ctl2"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_L0_RST, "pex-l0-rst"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_L1_RST, "pex-l1-rst"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC4, "sdmmc4"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_PEX_L5_RST, "pex-l5-rst"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CAM, "cam"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIC, "csic"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSID, "csid"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIE, "csie"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIF, "csif"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SPI, "spi"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UFS, "ufs"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIG, "csig"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIH, "csih"), + 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_CONN, "conn"), + 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 tegra194_pmc_regs = { .scratch0 = 0x2000, - .dpd_req = 0x74, - .dpd_status = 0x78, - .dpd2_req = 0x7c, - .dpd2_status = 0x80, .rst_status = 0x70, .rst_source_shift = 0x2, .rst_source_mask = 0x7c, @@ -3327,12 +4083,21 @@ static const char * const tegra194_reset_sources[] = { }; static const struct tegra_wake_event tegra194_wake_events[] = { + TEGRA_WAKE_GPIO("eqos", 20, 0, TEGRA194_MAIN_GPIO(G, 4)), TEGRA_WAKE_IRQ("pmu", 24, 209), TEGRA_WAKE_GPIO("power", 29, 1, TEGRA194_AON_GPIO(EE, 4)), TEGRA_WAKE_IRQ("rtc", 73, 10), + TEGRA_WAKE_SIMPLE("usb3-port-0", 76), + TEGRA_WAKE_SIMPLE("usb3-port-1", 77), + TEGRA_WAKE_SIMPLE("usb3-port-2-3", 78), + TEGRA_WAKE_SIMPLE("usb2-port-0", 79), + TEGRA_WAKE_SIMPLE("usb2-port-1", 80), + TEGRA_WAKE_SIMPLE("usb2-port-2", 81), + TEGRA_WAKE_SIMPLE("usb2-port-3", 82), }; static const struct tegra_pmc_soc tegra194_pmc_soc = { + .supports_core_domain = false, .num_powergates = 0, .powergates = NULL, .num_cpu_powergates = 0, @@ -3347,8 +4112,9 @@ static const struct tegra_pmc_soc tegra194_pmc_soc = { .num_pin_descs = ARRAY_SIZE(tegra194_pin_descs), .pin_descs = tegra194_pin_descs, .regs = &tegra194_pmc_regs, - .init = NULL, + .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 = tegra194_reset_sources, @@ -3357,12 +4123,276 @@ static const struct tegra_pmc_soc tegra194_pmc_soc = { .num_reset_levels = ARRAY_SIZE(tegra186_reset_levels), .num_wake_events = ARRAY_SIZE(tegra194_wake_events), .wake_events = tegra194_wake_events, + .max_wake_events = 96, + .max_wake_vectors = 3, + .pmc_clks_data = NULL, + .num_pmc_clks = 0, + .has_blink_output = false, + .has_usb_sleepwalk = false, + .has_single_mmio_aperture = false, +}; + +static const struct tegra_io_pad_soc tegra234_io_pads[] = { + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIA, 0, 0xe0c0, 0xe0c4, UINT_MAX, "csia"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIB, 1, 0xe0c0, 0xe0c4, UINT_MAX, "csib"), + TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP0, 0, 0xe0d0, 0xe0d4, UINT_MAX, "hdmi-dp0"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIC, 2, 0xe0c0, 0xe0c4, UINT_MAX, "csic"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSID, 3, 0xe0c0, 0xe0c4, UINT_MAX, "csid"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIE, 4, 0xe0c0, 0xe0c4, UINT_MAX, "csie"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIF, 5, 0xe0c0, 0xe0c4, UINT_MAX, "csif"), + TEGRA_IO_PAD(TEGRA_IO_PAD_UFS, 0, 0xe064, 0xe068, UINT_MAX, "ufs"), + TEGRA_IO_PAD(TEGRA_IO_PAD_EDP, 1, 0xe05c, 0xe060, UINT_MAX, "edp"), + TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1_HV, 0, 0xe054, 0xe058, 4, "sdmmc1-hv"), + TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3_HV, UINT_MAX, UINT_MAX, UINT_MAX, 6, "sdmmc3-hv"), + TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO_HV, UINT_MAX, UINT_MAX, UINT_MAX, 1, "audio-hv"), + TEGRA_IO_PAD(TEGRA_IO_PAD_AO_HV, UINT_MAX, UINT_MAX, UINT_MAX, 0, "ao-hv"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIG, 6, 0xe0c0, 0xe0c4, UINT_MAX, "csig"), + TEGRA_IO_PAD(TEGRA_IO_PAD_CSIH, 7, 0xe0c0, 0xe0c4, UINT_MAX, "csih"), +}; + +static const struct pinctrl_pin_desc tegra234_pin_descs[] = { + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIA, "csia"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIB, "csib"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI_DP0, "hdmi-dp0"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIC, "csic"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSID, "csid"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIE, "csie"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIF, "csif"), + 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"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIG, "csig"), + TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIH, "csih"), +}; + +static const struct tegra_pmc_regs tegra234_pmc_regs = { + .scratch0 = 0x2000, + .rst_status = 0x70, + .rst_source_shift = 0x2, + .rst_source_mask = 0xfc, + .rst_level_shift = 0x0, + .rst_level_mask = 0x3, +}; + +static const char * const tegra234_reset_sources[] = { + "SYS_RESET_N", /* 0x0 */ + "AOWDT", + "BCCPLEXWDT", + "BPMPWDT", + "SCEWDT", + "SPEWDT", + "APEWDT", + "LCCPLEXWDT", + "SENSOR", /* 0x8 */ + NULL, + NULL, + "MAINSWRST", + "SC7", + "HSM", + NULL, + "RCEWDT", + NULL, /* 0x10 */ + NULL, + NULL, + "BPMPBOOT", + "FUSECRC", + "DCEWDT", + "PSCWDT", + "PSC", + "CSITE_SW", /* 0x18 */ + "POD", + "SCPM", + "VREFRO_POWERBAD", + "VMON", + "FMON", + "FSI_R5WDT", + "FSI_THERM", + "FSI_R52C0WDT", /* 0x20 */ + "FSI_R52C1WDT", + "FSI_R52C2WDT", + "FSI_R52C3WDT", + "FSI_FMON", + "FSI_VMON", /* 0x25 */ +}; + +static const struct tegra_wake_event tegra234_wake_events[] = { + TEGRA_WAKE_GPIO("sd-wake", 8, 0, TEGRA234_MAIN_GPIO(G, 7)), + TEGRA_WAKE_GPIO("eqos", 20, 0, TEGRA234_MAIN_GPIO(G, 4)), + TEGRA_WAKE_IRQ("pmu", 24, 209), + TEGRA_WAKE_GPIO("power", 29, 1, TEGRA234_AON_GPIO(EE, 4)), + TEGRA_WAKE_GPIO("mgbe", 56, 0, TEGRA234_MAIN_GPIO(Y, 3)), + TEGRA_WAKE_IRQ("rtc", 73, 10), + TEGRA_WAKE_IRQ("usb3-port-0", 76, 167), + TEGRA_WAKE_IRQ("usb3-port-1", 77, 167), + TEGRA_WAKE_IRQ("usb3-port-2-3", 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), + TEGRA_WAKE_IRQ("usb2-port-3", 82, 167), + TEGRA_WAKE_IRQ("sw-wake", SW_WAKE_ID, 179), +}; + +static const struct tegra_pmc_soc tegra234_pmc_soc = { + .supports_core_domain = false, + .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_impl_33v_pwr = true, + .maybe_tz_only = false, + .num_io_pads = ARRAY_SIZE(tegra234_io_pads), + .io_pads = tegra234_io_pads, + .num_pin_descs = ARRAY_SIZE(tegra234_pin_descs), + .pin_descs = tegra234_pin_descs, + .regs = &tegra234_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 = tegra234_reset_sources, + .num_reset_sources = ARRAY_SIZE(tegra234_reset_sources), + .reset_levels = tegra186_reset_levels, + .num_reset_levels = ARRAY_SIZE(tegra186_reset_levels), + .num_wake_events = ARRAY_SIZE(tegra234_wake_events), + .wake_events = tegra234_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, +}; + +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 }, { .compatible = "nvidia,tegra210-pmc", .data = &tegra210_pmc_soc }, @@ -3374,6 +4404,51 @@ 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 + * state syncing is unsafe. + */ + if (!pmc->soc->supports_core_domain) + return; + + /* + * Older device-trees don't have core PD, and thus, there are + * no dependencies that will block the state syncing. We shouldn't + * mark the domain as synced in this case. + */ + pmc->core_domain_state_synced = true; + + /* this is a no-op if core regulator isn't used */ + mutex_lock(&pmc->powergates_lock); + err = dev_pm_opp_sync_regulators(dev); + mutex_unlock(&pmc->powergates_lock); + + if (err) + dev_err(dev, "failed to sync regulators: %d\n", err); +} + static struct platform_driver tegra_pmc_driver = { .driver = { .name = "tegra-pmc", @@ -3382,6 +4457,7 @@ static struct platform_driver tegra_pmc_driver = { #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM) .pm = &tegra_pmc_pm_ops, #endif + .sync_state = tegra_pmc_sync_state, }, .probe = tegra_pmc_probe, }; @@ -3473,7 +4549,7 @@ static int __init tegra_pmc_early_init(void) return -ENXIO; } - if (np) { + if (of_device_is_available(np)) { pmc->soc = match->data; if (pmc->soc->maybe_tz_only) |
