diff mbox

i.MX: add support for lower and upper interrupt in GPIO.

Message ID 1445985169-13999-1-git-send-email-jcd@tribudubois.net
State New
Headers show

Commit Message

Jean-Christophe Dubois Oct. 27, 2015, 10:32 p.m. UTC
The i.MX6 GPIO device supports 2 interrupts instead of one.

* 1 for the lower 16 GPIOs.
* 1 for the upper 16 GPIOs.

i.MX31 and i.MX25 only support 1 interrupt for the 32 GPIOs.

So we add a property to turn the behavior on when required.

Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
---
 hw/gpio/imx_gpio.c         | 12 ++++++++++--
 include/hw/gpio/imx_gpio.h |  3 ++-
 2 files changed, 12 insertions(+), 3 deletions(-)

Comments

Peter Crosthwaite Oct. 27, 2015, 10:41 p.m. UTC | #1
On Tue, Oct 27, 2015 at 3:32 PM, Jean-Christophe Dubois <jcd@tribudubois.net
> wrote:

> The i.MX6 GPIO device supports 2 interrupts instead of one.
>
> * 1 for the lower 16 GPIOs.
> * 1 for the upper 16 GPIOs.
>
> i.MX31 and i.MX25 only support 1 interrupt for the 32 GPIOs.
>
>
So an architectural question, is it the case that the IP always has two
outbound interrupt lines but MX31 and 25 always OR together on the SoC
level?

If that is the case I think it would be cleaner to do on the board level.

Regards,
Peter



> So we add a property to turn the behavior on when required.
>
> Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
> ---
>  hw/gpio/imx_gpio.c         | 12 ++++++++++--
>  include/hw/gpio/imx_gpio.h |  3 ++-
>  2 files changed, 12 insertions(+), 3 deletions(-)
>
> diff --git a/hw/gpio/imx_gpio.c b/hw/gpio/imx_gpio.c
> index 3170585..a6d7cab 100644
> --- a/hw/gpio/imx_gpio.c
> +++ b/hw/gpio/imx_gpio.c
> @@ -62,7 +62,12 @@ static const char *imx_gpio_reg_name(uint32_t reg)
>
>  static void imx_gpio_update_int(IMXGPIOState *s)
>  {
> -    qemu_set_irq(s->irq, (s->isr & s->imr) ? 1 : 0);
> +    if (s->has_upper_pin_irq) {
> +        qemu_set_irq(s->irq[0], (s->isr & s->imr & 0x0000FFFF) ? 1 : 0);
> +        qemu_set_irq(s->irq[1], (s->isr & s->imr & 0xFFFF0000) ? 1 : 0);
> +    } else {
> +        qemu_set_irq(s->irq[0], (s->isr & s->imr) ? 1 : 0);
> +    }
>  }
>
>  static void imx_gpio_set_int_line(IMXGPIOState *s, int line, IMXGPIOLevel
> level)
> @@ -282,6 +287,8 @@ static const VMStateDescription vmstate_imx_gpio = {
>
>  static Property imx_gpio_properties[] = {
>      DEFINE_PROP_BOOL("has-edge-sel", IMXGPIOState, has_edge_sel, true),
> +    DEFINE_PROP_BOOL("has-upper-pin-irq", IMXGPIOState, has_upper_pin_irq,
> +                     false),
>      DEFINE_PROP_END_OF_LIST(),
>  };
>
> @@ -311,7 +318,8 @@ static void imx_gpio_realize(DeviceState *dev, Error
> **errp)
>      qdev_init_gpio_in(DEVICE(s), imx_gpio_set, IMX_GPIO_PIN_COUNT);
>      qdev_init_gpio_out(DEVICE(s), s->output, IMX_GPIO_PIN_COUNT);
>
> -    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
> +    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[0]);
> +    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[1]);
>      sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
>  }
>
> diff --git a/include/hw/gpio/imx_gpio.h b/include/hw/gpio/imx_gpio.h
> index 517b261..b15a09f 100644
> --- a/include/hw/gpio/imx_gpio.h
> +++ b/include/hw/gpio/imx_gpio.h
> @@ -54,8 +54,9 @@ typedef struct IMXGPIOState {
>      uint32_t isr;
>      bool has_edge_sel;
>      uint32_t edge_sel;
> +    bool has_upper_pin_irq;
>
> -    qemu_irq irq;
> +    qemu_irq irq[2];
>      qemu_irq output[IMX_GPIO_PIN_COUNT];
>  } IMXGPIOState;
>
> --
> 2.5.0
>
>
Jean-Christophe Dubois Oct. 28, 2015, 7:10 a.m. UTC | #2
Le 27/10/2015 23:41, Peter Crosthwaite a écrit :
>
>
> On Tue, Oct 27, 2015 at 3:32 PM, Jean-Christophe Dubois 
> <jcd@tribudubois.net <mailto:jcd@tribudubois.net>> wrote:
>
>     The i.MX6 GPIO device supports 2 interrupts instead of one.
>
>     * 1 for the lower 16 GPIOs.
>     * 1 for the upper 16 GPIOs.
>
>     i.MX31 and i.MX25 only support 1 interrupt for the 32 GPIOs.
>
>
> So an architectural question, is it the case that the IP always has 
> two outbound interrupt lines but MX31 and 25 always OR together on the 
> SoC level?

Well, I am not part of Freescale so I just don't know anything about 
internal implementation details of this IP and its use inside the SOC.

What we can say is that the dual interrupt version (i.MX6) is newer than 
the single one (i.MX31, i.MX25). So my guess is that this is an 
evolution of the IP and the goal was to make GPIO interrupt handling 
easier, faster and prioritisable.

>
> If that is the case I think it would be cleaner to do on the board level.

At the SOC level I was planning to set (or not) the new property and to 
assign 1 (or 2) IRQ to the device.

Regards

JC

>
> Regards,
> Peter
>
>     So we add a property to turn the behavior on when required.
>
>     Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net
>     <mailto:jcd@tribudubois.net>>
>     ---
>      hw/gpio/imx_gpio.c         | 12 ++++++++++--
>      include/hw/gpio/imx_gpio.h |  3 ++-
>      2 files changed, 12 insertions(+), 3 deletions(-)
>
>     diff --git a/hw/gpio/imx_gpio.c b/hw/gpio/imx_gpio.c
>     index 3170585..a6d7cab 100644
>     --- a/hw/gpio/imx_gpio.c
>     +++ b/hw/gpio/imx_gpio.c
>     @@ -62,7 +62,12 @@ static const char *imx_gpio_reg_name(uint32_t reg)
>
>      static void imx_gpio_update_int(IMXGPIOState *s)
>      {
>     -    qemu_set_irq(s->irq, (s->isr & s->imr) ? 1 : 0);
>     +    if (s->has_upper_pin_irq) {
>     +        qemu_set_irq(s->irq[0], (s->isr & s->imr & 0x0000FFFF) ?
>     1 : 0);
>     +        qemu_set_irq(s->irq[1], (s->isr & s->imr & 0xFFFF0000) ?
>     1 : 0);
>     +    } else {
>     +        qemu_set_irq(s->irq[0], (s->isr & s->imr) ? 1 : 0);
>     +    }
>      }
>
>      static void imx_gpio_set_int_line(IMXGPIOState *s, int line,
>     IMXGPIOLevel level)
>     @@ -282,6 +287,8 @@ static const VMStateDescription
>     vmstate_imx_gpio = {
>
>      static Property imx_gpio_properties[] = {
>          DEFINE_PROP_BOOL("has-edge-sel", IMXGPIOState, has_edge_sel,
>     true),
>     +    DEFINE_PROP_BOOL("has-upper-pin-irq", IMXGPIOState,
>     has_upper_pin_irq,
>     +                     false),
>          DEFINE_PROP_END_OF_LIST(),
>      };
>
>     @@ -311,7 +318,8 @@ static void imx_gpio_realize(DeviceState *dev,
>     Error **errp)
>          qdev_init_gpio_in(DEVICE(s), imx_gpio_set, IMX_GPIO_PIN_COUNT);
>          qdev_init_gpio_out(DEVICE(s), s->output, IMX_GPIO_PIN_COUNT);
>
>     -    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
>     +    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[0]);
>     +    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[1]);
>          sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
>      }
>
>     diff --git a/include/hw/gpio/imx_gpio.h b/include/hw/gpio/imx_gpio.h
>     index 517b261..b15a09f 100644
>     --- a/include/hw/gpio/imx_gpio.h
>     +++ b/include/hw/gpio/imx_gpio.h
>     @@ -54,8 +54,9 @@ typedef struct IMXGPIOState {
>          uint32_t isr;
>          bool has_edge_sel;
>          uint32_t edge_sel;
>     +    bool has_upper_pin_irq;
>
>     -    qemu_irq irq;
>     +    qemu_irq irq[2];
>          qemu_irq output[IMX_GPIO_PIN_COUNT];
>      } IMXGPIOState;
>
>     --
>     2.5.0
>
>
Peter Crosthwaite Nov. 13, 2015, 6:53 a.m. UTC | #3
On Wed, Oct 28, 2015 at 12:10 AM, Jean-Christophe DUBOIS
<jcd@tribudubois.net> wrote:
> Le 27/10/2015 23:41, Peter Crosthwaite a écrit :
>
>
>
> On Tue, Oct 27, 2015 at 3:32 PM, Jean-Christophe Dubois
> <jcd@tribudubois.net> wrote:
>>
>> The i.MX6 GPIO device supports 2 interrupts instead of one.
>>
>> * 1 for the lower 16 GPIOs.
>> * 1 for the upper 16 GPIOs.
>>
>> i.MX31 and i.MX25 only support 1 interrupt for the 32 GPIOs.
>>
>
> So an architectural question, is it the case that the IP always has two
> outbound interrupt lines but MX31 and 25 always OR together on the SoC
> level?
>
>
> Well, I am not part of Freescale so I just don't know anything about
> internal implementation details of this IP and its use inside the SOC.
>
> What we can say is that the dual interrupt version (i.MX6) is newer than the
> single one (i.MX31, i.MX25). So my guess is that this is an evolution of the
> IP and the goal was to make GPIO interrupt handling easier, faster and
> prioritisable.
>
>
>
> If that is the case I think it would be cleaner to do on the board level.
>
>
> At the SOC level I was planning to set (or not) the new property and to
> assign 1 (or 2) IRQ to the device.
>

Ok, there were no architecture clues in the TRM so this approach wins.

Reviewed-by: Peter Crosthwaite <crosthwaite.peter@gmail.com>

One possibility is to do some lightweight subclasses for the imx25/31
and imx6 versions, to avoid SoCs having to manipulate number
properties for fixed IPs. See hw/usb/hcd-ehci-sysbus.c for some
examples of SoCs tweaking a peripheral to get their own version of it
as a customized device type.

Regards,
Peter

> Regards
>
> JC
>
>
>
> Regards,
> Peter
>
>
>>
>> So we add a property to turn the behavior on when required.
>>
>> Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>

>>      uint32_t isr;
>>      bool has_edge_sel;
>>      uint32_t edge_sel;
>> +    bool has_upper_pin_irq;
>>
>> -    qemu_irq irq;
>> +    qemu_irq irq[2];
>>      qemu_irq output[IMX_GPIO_PIN_COUNT];
>>  } IMXGPIOState;
>>
>> --
>> 2.5.0
>>
>
>
diff mbox

Patch

diff --git a/hw/gpio/imx_gpio.c b/hw/gpio/imx_gpio.c
index 3170585..a6d7cab 100644
--- a/hw/gpio/imx_gpio.c
+++ b/hw/gpio/imx_gpio.c
@@ -62,7 +62,12 @@  static const char *imx_gpio_reg_name(uint32_t reg)
 
 static void imx_gpio_update_int(IMXGPIOState *s)
 {
-    qemu_set_irq(s->irq, (s->isr & s->imr) ? 1 : 0);
+    if (s->has_upper_pin_irq) {
+        qemu_set_irq(s->irq[0], (s->isr & s->imr & 0x0000FFFF) ? 1 : 0);
+        qemu_set_irq(s->irq[1], (s->isr & s->imr & 0xFFFF0000) ? 1 : 0);
+    } else {
+        qemu_set_irq(s->irq[0], (s->isr & s->imr) ? 1 : 0);
+    }
 }
 
 static void imx_gpio_set_int_line(IMXGPIOState *s, int line, IMXGPIOLevel level)
@@ -282,6 +287,8 @@  static const VMStateDescription vmstate_imx_gpio = {
 
 static Property imx_gpio_properties[] = {
     DEFINE_PROP_BOOL("has-edge-sel", IMXGPIOState, has_edge_sel, true),
+    DEFINE_PROP_BOOL("has-upper-pin-irq", IMXGPIOState, has_upper_pin_irq,
+                     false),
     DEFINE_PROP_END_OF_LIST(),
 };
 
@@ -311,7 +318,8 @@  static void imx_gpio_realize(DeviceState *dev, Error **errp)
     qdev_init_gpio_in(DEVICE(s), imx_gpio_set, IMX_GPIO_PIN_COUNT);
     qdev_init_gpio_out(DEVICE(s), s->output, IMX_GPIO_PIN_COUNT);
 
-    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
+    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[0]);
+    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[1]);
     sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
 }
 
diff --git a/include/hw/gpio/imx_gpio.h b/include/hw/gpio/imx_gpio.h
index 517b261..b15a09f 100644
--- a/include/hw/gpio/imx_gpio.h
+++ b/include/hw/gpio/imx_gpio.h
@@ -54,8 +54,9 @@  typedef struct IMXGPIOState {
     uint32_t isr;
     bool has_edge_sel;
     uint32_t edge_sel;
+    bool has_upper_pin_irq;
 
-    qemu_irq irq;
+    qemu_irq irq[2];
     qemu_irq output[IMX_GPIO_PIN_COUNT];
 } IMXGPIOState;