Re: [PATCH 3/9] soc/tegra: pmc: Add wake event support

2018-09-21 Thread Mikko Perttunen

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

2018-09-21 Thread Mikko Perttunen

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

2018-09-21 Thread Thierry Reding
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

2018-09-21 Thread Thierry Reding
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)
+