Re: [PATCH 3/9] soc/tegra: pmc: Add wake event support
On 21/09/2018 19.25, Thierry Reding wrote: ... + /* route wake to tier 2 (XXX conditionally enable this) */ + value = readl(pmc->wake + WAKE_AOWAKE_TIER2_CTRL); + writel(0x1, pmc->wake + WAKE_AOWAKE_TIER2_CTRL); This doesn't seem right Cheers, Mikko
Re: [PATCH 3/9] soc/tegra: pmc: Add wake event support
On 21/09/2018 19.25, Thierry Reding wrote: ... + /* route wake to tier 2 (XXX conditionally enable this) */ + value = readl(pmc->wake + WAKE_AOWAKE_TIER2_CTRL); + writel(0x1, pmc->wake + WAKE_AOWAKE_TIER2_CTRL); This doesn't seem right Cheers, Mikko
[PATCH 3/9] soc/tegra: pmc: Add wake event support
From: Thierry Reding The power management controller has top-level controls that allow certain interrupts (such as from the RTC or a subset of GPIOs) to wake the system from sleep. Implement infrastructure to support these wake events. Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 230 1 file changed, 230 insertions(+) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index c08f0b942020..eeef5a1f2837 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -29,9 +29,12 @@ #include #include #include +#include +#include #include #include #include +#include #include #include #include @@ -48,6 +51,7 @@ #include #include +#include #include #define PMC_CNTRL 0x0 @@ -126,6 +130,18 @@ #define GPU_RG_CNTRL 0x2d4 /* Tegra186 and later */ +#define WAKE_AOWAKE_CNTRL(x) (0x000 + ((x) << 2)) +#define WAKE_AOWAKE_CNTRL_LEVEL (1 << 3) +#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)) +#define WAKE_AOWAKE_STATUS_R(x) (0x48c + ((x) << 2)) +#define WAKE_AOWAKE_TIER1_CTRL 0x4ac +#define WAKE_AOWAKE_TIER2_CTRL 0x4b0 +#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_CTRL 0x4f4 #define WAKE_AOWAKE_CTRL_INTR_POLARITY BIT(0) @@ -153,6 +169,38 @@ struct tegra_pmc_regs { unsigned int dpd2_status; }; +struct tegra_wake_event { + const char *name; + unsigned int id; + unsigned int irq; + struct { + unsigned int instance; + unsigned int pin; + } gpio; +}; + +#define TEGRA_WAKE_IRQ(_name, _id, _irq) \ + { \ + .name = _name, \ + .id = _id, \ + .irq = _irq,\ + .gpio = { \ + .instance = UINT_MAX, \ + .pin = UINT_MAX,\ + }, \ + } + +#define TEGRA_WAKE_GPIO(_name, _id, _instance, _pin) \ + { \ + .name = _name, \ + .id = _id, \ + .irq = 0, \ + .gpio = { \ + .instance = _instance, \ + .pin = _pin,\ + }, \ + } + struct tegra_pmc_soc { unsigned int num_powergates; const char *const *powergates; @@ -175,6 +223,9 @@ struct tegra_pmc_soc { void (*setup_irq_polarity)(struct tegra_pmc *pmc, struct device_node *np, bool invert); + + const struct tegra_wake_event *wake_events; + unsigned int num_wake_events; }; /** @@ -230,6 +281,9 @@ struct tegra_pmc { struct mutex powergates_lock; struct pinctrl_dev *pctl_dev; + + struct irq_domain *domain; + struct irq_chip irq; }; static struct tegra_pmc *pmc = &(struct tegra_pmc) { @@ -1543,6 +1597,178 @@ static int tegra_pmc_pinctrl_init(struct tegra_pmc *pmc) return err; } +static int tegra_pmc_irq_translate(struct irq_domain *domain, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) +{ + if (WARN_ON(fwspec->param_count < 2)) + return -EINVAL; + + *hwirq = fwspec->param[0]; + *type = fwspec->param[1]; + + return 0; +} + +static int tegra_pmc_irq_alloc(struct irq_domain *domain, unsigned int virq, + unsigned int num_irqs, void *data) +{ + struct tegra_pmc *pmc = domain->host_data; + struct irq_fwspec *fwspec = data; + unsigned int i; + int err = 0; + + for (i = 0; i < pmc->soc->num_wake_events; i++) { + const struct tegra_wake_event *event = >soc->wake_events[i]; + + if (fwspec->param_count == 2) { + struct irq_fwspec spec; + + if (event->id != fwspec->param[0]) + continue; + + err = irq_domain_set_hwirq_and_chip(domain, virq, + event->id, + >irq, pmc); + if (err < 0) +
[PATCH 3/9] soc/tegra: pmc: Add wake event support
From: Thierry Reding The power management controller has top-level controls that allow certain interrupts (such as from the RTC or a subset of GPIOs) to wake the system from sleep. Implement infrastructure to support these wake events. Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 230 1 file changed, 230 insertions(+) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index c08f0b942020..eeef5a1f2837 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -29,9 +29,12 @@ #include #include #include +#include +#include #include #include #include +#include #include #include #include @@ -48,6 +51,7 @@ #include #include +#include #include #define PMC_CNTRL 0x0 @@ -126,6 +130,18 @@ #define GPU_RG_CNTRL 0x2d4 /* Tegra186 and later */ +#define WAKE_AOWAKE_CNTRL(x) (0x000 + ((x) << 2)) +#define WAKE_AOWAKE_CNTRL_LEVEL (1 << 3) +#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)) +#define WAKE_AOWAKE_STATUS_R(x) (0x48c + ((x) << 2)) +#define WAKE_AOWAKE_TIER1_CTRL 0x4ac +#define WAKE_AOWAKE_TIER2_CTRL 0x4b0 +#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_CTRL 0x4f4 #define WAKE_AOWAKE_CTRL_INTR_POLARITY BIT(0) @@ -153,6 +169,38 @@ struct tegra_pmc_regs { unsigned int dpd2_status; }; +struct tegra_wake_event { + const char *name; + unsigned int id; + unsigned int irq; + struct { + unsigned int instance; + unsigned int pin; + } gpio; +}; + +#define TEGRA_WAKE_IRQ(_name, _id, _irq) \ + { \ + .name = _name, \ + .id = _id, \ + .irq = _irq,\ + .gpio = { \ + .instance = UINT_MAX, \ + .pin = UINT_MAX,\ + }, \ + } + +#define TEGRA_WAKE_GPIO(_name, _id, _instance, _pin) \ + { \ + .name = _name, \ + .id = _id, \ + .irq = 0, \ + .gpio = { \ + .instance = _instance, \ + .pin = _pin,\ + }, \ + } + struct tegra_pmc_soc { unsigned int num_powergates; const char *const *powergates; @@ -175,6 +223,9 @@ struct tegra_pmc_soc { void (*setup_irq_polarity)(struct tegra_pmc *pmc, struct device_node *np, bool invert); + + const struct tegra_wake_event *wake_events; + unsigned int num_wake_events; }; /** @@ -230,6 +281,9 @@ struct tegra_pmc { struct mutex powergates_lock; struct pinctrl_dev *pctl_dev; + + struct irq_domain *domain; + struct irq_chip irq; }; static struct tegra_pmc *pmc = &(struct tegra_pmc) { @@ -1543,6 +1597,178 @@ static int tegra_pmc_pinctrl_init(struct tegra_pmc *pmc) return err; } +static int tegra_pmc_irq_translate(struct irq_domain *domain, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) +{ + if (WARN_ON(fwspec->param_count < 2)) + return -EINVAL; + + *hwirq = fwspec->param[0]; + *type = fwspec->param[1]; + + return 0; +} + +static int tegra_pmc_irq_alloc(struct irq_domain *domain, unsigned int virq, + unsigned int num_irqs, void *data) +{ + struct tegra_pmc *pmc = domain->host_data; + struct irq_fwspec *fwspec = data; + unsigned int i; + int err = 0; + + for (i = 0; i < pmc->soc->num_wake_events; i++) { + const struct tegra_wake_event *event = >soc->wake_events[i]; + + if (fwspec->param_count == 2) { + struct irq_fwspec spec; + + if (event->id != fwspec->param[0]) + continue; + + err = irq_domain_set_hwirq_and_chip(domain, virq, + event->id, + >irq, pmc); + if (err < 0) +