Enable X-Gene standby GPIO as interrupt controller
v5 cover Enable X-Gene standby GPIO as interrupt controller
V5 Changes:
- Add optional properties to describe HW specifics
- Use irq_create_fwspec_mapping() instead of low level functions
- Move gpiochip_lock_as_irq() to activate method
- Remove redundant checks
- Add optional HW properties description to DT binding document
- Update "interrupts" property description in DT binding document.
V4 Changes:
- Convert to hierarchical irq domain
V3 Changes:
- Picking up from version 2 of "Y Vo <[email protected]>"
- Get HW resource information from DT
- Avoid keeping parent IRQ controller
V2 Changes:
- Support X-Gene standby GPIO as an interrupt controller.
Quan Nguyen (3):
gpio: xgene: Enable X-Gene standby GPIO as interrupt controller
Documentation: gpio: Update description for X-Gene standby GPIO
controller DTS binding
arm64: dts: Update X-Gene standby GPIO controller DTS entries
.../devicetree/bindings/gpio/gpio-xgene-sb.txt | 47 +++- arch/arm64/boot/dts/apm/apm-storm.dtsi | 3 + drivers/gpio/gpio-xgene-sb.c | 275 ++++++++++++++++++--- 3 files changed, 286 insertions(+), 39 deletions(-)
Signature · 1 line
1.7.12.4
PATCH v5 1/3 gpio: xgene: Enable X-Gene standby GPIO as interrupt controller
Enable X-Gene standby GPIO controller as interrupt controller to provide its own resources. This avoids ambiguity where GIC interrupt resource is use as X-Gene standby GPIO interrupt resource in user driver.
--- drivers/gpio/gpio-xgene-sb.c | 275 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 243 insertions(+), 32 deletions(-)
drivers/gpio/gpio-xgene-sb.c +243 -32
@@ -2,8 +2,9 @@* AppliedMicro X-Gene SoC GPIO-Standby Driver * * Copyright (c) 2014, Applied Micro Circuits Corporation -* Author: Tin Huynh <[email protected]>. -* Y Vo <[email protected]>. +* Author: Tin Huynh <[email protected]>. +* Y Vo <[email protected]>. +* Quan Nguyen <[email protected]>. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the
@@ -28,9 +29,14 @@#include "gpiolib.h" -#define XGENE_MAX_GPIO_DS 22 -#define XGENE_MAX_GPIO_DS_IRQ 6 +/* Common property names */ +#define XGENE_NIRQ_PROPERTY "apm,nr-irqs" +#define XGENE_NGPIO_PROPERTY "apm,nr-gpios" +#define XGENE_IRQ_START_PROPERTY "apm,irq-start" +#define XGENE_DFLT_MAX_NGPIO 22 +#define XGENE_DFLT_MAX_NIRQ 6 +#define XGENE_DFLT_IRQ_START_PIN 8#define GPIO_MASK (x) (1U << ((x) % 32))#define MPA_GPIO_INT_LVL 0x0290
@@ -39,19 +45,32 @@#define MPA_GPIO_IN_ADDR 0x02a4#define MPA_GPIO_SEL_LO 0x0294 +#define GPIO_INT_LEVEL_H 0x000001 +#define GPIO_INT_LEVEL_L 0x000000 +/** * struct xgene_gpio_sb - GPIO-Standby private data structure. * @gc: memory-mapped GPIO controllers. -* @irq: Mapping GPIO pins and interrupt number -* nirq: Number of GPIO pins that supports interrupt +* @regs: GPIO register base offset +* @irq_domain: GPIO interrupt domain +* @irq_start: GPIO pin that start support interrupt +* @nirq: Number of GPIO pins that supports interrupt +* @parent_irq_base: Start parent HWIRQ */ struct xgene_gpio_sb {struct gpio_chip gc; -u32 *irq; -u32 nirq; +void __iomem *regs; +struct irq_domain *irq_domain; +u16 irq_start; +u16 nirq; +u16 parent_irq_base; }; -static void xgene_gpio_set_bit (struct gpio_chip *gc,void __iomem *reg,u32 gpio,int val) +#define HWIRQ_TO_GPIO (priv, hwirq) ((hwirq) + (priv)->irq_start) +#define GPIO_TO_HWIRQ (priv, gpio) ((gpio) - (priv)->irq_start) + +static void xgene_gpio_set_bit (struct gpio_chip *gc, +void __iomem *reg,u32 gpio,int val) {u32 data;
@@ -63,23 +82,180 @@ static void xgene_gpio_set_bit(struct gpio_chip *gc, void __iomem *reg, u32 gpio gc->write_reg (reg, data); } -static int apm_gpio_sb_to_irq (struct gpio_chip *gc,u32 gpio) +static int xgene_gpio_sb_irq_set_type (struct irq_data *d,unsigned int type) +{ +struct xgene_gpio_sb *priv =irq_data_get_irq_chip_data (d); +int gpio =HWIRQ_TO_GPIO (priv, d->hwirq); +int lvl_type =GPIO_INT_LEVEL_H ; + +switch (type &IRQ_TYPE_SENSE_MASK ) { +case IRQ_TYPE_EDGE_RISING : +case IRQ_TYPE_LEVEL_HIGH : + lvl_type =GPIO_INT_LEVEL_H ; +break ; +case IRQ_TYPE_EDGE_FALLING : +case IRQ_TYPE_LEVEL_LOW : + lvl_type =GPIO_INT_LEVEL_L ; +break ; +default : +break ; + } + +xgene_gpio_set_bit (&priv->gc, priv->regs +MPA_GPIO_SEL_LO , + gpio *2 ,1 ); +xgene_gpio_set_bit (&priv->gc, priv->regs +MPA_GPIO_INT_LVL , + d->hwirq, lvl_type); + +/* Propagate IRQ type setting to parent */ +if (type &IRQ_TYPE_EDGE_BOTH ) +return irq_chip_set_type_parent (d,IRQ_TYPE_EDGE_RISING ); +else +return irq_chip_set_type_parent (d,IRQ_TYPE_LEVEL_HIGH ); +} + +static void xgene_gpio_sb_irq_shutdown (struct irq_data *d) +{ +struct xgene_gpio_sb *priv =irq_data_get_irq_chip_data (d); + +gpiochip_unlock_as_irq (&priv->gc,HWIRQ_TO_GPIO (priv, d->hwirq)); +} + +static struct irq_chip xgene_gpio_sb_irq_chip = { + .name ="sbgpio" , + .irq_ack = irq_chip_ack_parent, + .irq_eoi = irq_chip_eoi_parent, + .irq_mask = irq_chip_mask_parent, + .irq_unmask = irq_chip_unmask_parent, + .irq_set_type = xgene_gpio_sb_irq_set_type, + .irq_shutdown = xgene_gpio_sb_irq_shutdown, +}; + +static int xgene_gpio_sb_to_irq (struct gpio_chip *gc,u32 gpio) {struct xgene_gpio_sb *priv =gpiochip_get_data (gc); +struct irq_fwspec fwspec; + +if ((gpio < priv->irq_start) || + (gpio >HWIRQ_TO_GPIO (priv, priv->nirq))) +return -ENXIO ; + +if (gc->parent->of_node) + fwspec.fwnode =of_node_to_fwnode (gc->parent->of_node); +else + fwspec.fwnode = gc->parent->fwnode; + fwspec.param_count =2 ; + fwspec.param[0 ] =GPIO_TO_HWIRQ (priv, gpio); + fwspec.param[1 ] =IRQ_TYPE_NONE ; +return irq_create_fwspec_mapping (&fwspec); +} + +static void xgene_gpio_sb_domain_activate (struct irq_domain *d, +struct irq_data *irq_data) +{ +struct xgene_gpio_sb *priv = d->host_data; +u32 gpio =HWIRQ_TO_GPIO (priv, irq_data->hwirq); + +if (gpiochip_lock_as_irq (&priv->gc, gpio)) { +dev_err (priv->gc.parent, +"Unable to configure XGene GPIO standby pin %d as IRQ\n" , + gpio); +return ; + } + +xgene_gpio_set_bit (&priv->gc, priv->regs +MPA_GPIO_SEL_LO , + gpio *2 ,1 ); +} + +static void xgene_gpio_sb_domain_deactivate (struct irq_domain *d, +struct irq_data *irq_data) +{ +struct xgene_gpio_sb *priv = d->host_data; +u32 gpio =HWIRQ_TO_GPIO (priv, irq_data->hwirq); + +gpiochip_unlock_as_irq (&priv->gc, gpio); +xgene_gpio_set_bit (&priv->gc, priv->regs +MPA_GPIO_SEL_LO , + gpio *2 ,0 ); +} -if (priv->irq[gpio]) -return priv->irq[gpio]; +static int xgene_gpio_sb_domain_translate (struct irq_domain *d, +struct irq_fwspec *fwspec, +unsigned long *hwirq, +unsigned int *type) +{ +struct xgene_gpio_sb *priv = d->host_data; + +if ((fwspec->param_count !=2 ) || + (fwspec->param[0 ] >= priv->nirq)) +return -EINVAL ; + *hwirq = fwspec->param[0 ]; + *type = fwspec->param[1 ]; +return 0 ; +} + +static int xgene_gpio_sb_domain_alloc (struct irq_domain *domain, +unsigned int virq, +unsigned int nr_irqs,void *data) +{ +struct irq_fwspec *fwspec = data; +struct irq_fwspec parent_fwspec; +struct xgene_gpio_sb *priv = domain->host_data; +irq_hw_number_t hwirq; +unsigned int i; + + hwirq = fwspec->param[0 ]; +for (i =0 ; i < nr_irqs; i++) +irq_domain_set_hwirq_and_chip (domain, virq + i, hwirq + i, + &xgene_gpio_sb_irq_chip, priv); + +if (is_of_node (domain->parent->fwnode)) { + parent_fwspec.fwnode = domain->parent->fwnode; + parent_fwspec.param_count =3 ; + parent_fwspec.param[0 ] =0 ;/* SPI */ +/* Skip SGIs and PPIs*/ + parent_fwspec.param[1 ] = hwirq + priv->parent_irq_base -32 ; + parent_fwspec.param[2 ] = fwspec->param[1 ]; + }else if (is_fwnode_irqchip (domain->parent->fwnode)) { + parent_fwspec.fwnode = domain->parent->fwnode; + parent_fwspec.param_count =2 ; + parent_fwspec.param[0 ] = hwirq + priv->parent_irq_base; + parent_fwspec.param[1 ] = fwspec->param[1 ]; + }else +return -EINVAL ; -return -ENXIO ; +return irq_domain_alloc_irqs_parent (domain, virq, nr_irqs, + &parent_fwspec); } +static void xgene_gpio_sb_domain_free (struct irq_domain *domain, +unsigned int virq, +unsigned int nr_irqs) +{ +struct irq_data *d; +unsigned int i; + +for (i =0 ; i < nr_irqs; i++) { + d =irq_domain_get_irq_data (domain, virq + i); +irq_domain_reset_irq_data (d); + } +} + +static const struct irq_domain_ops xgene_gpio_sb_domain_ops = { + .translate = xgene_gpio_sb_domain_translate, + .alloc = xgene_gpio_sb_domain_alloc, + .free = xgene_gpio_sb_domain_free, + .activate = xgene_gpio_sb_domain_activate, + .deactivate = xgene_gpio_sb_domain_deactivate, +}; +static int xgene_gpio_sb_probe (struct platform_device *pdev) {struct xgene_gpio_sb *priv; -u32 ret, i; -u32 default_lines[] = {0x08 ,0x09 ,0x0A ,0x0B ,0x0C ,0x0D }; +u32 ret;struct resource *res;void __iomem *regs; +struct irq_domain *parent_domain =NULL ; +struct fwnode_handle *fwnode; +u32 val32; priv =devm_kzalloc (&pdev->dev,sizeof (*priv),GFP_KERNEL );if (!priv)
@@ -90,6 +266,18 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)if (IS_ERR (regs))return PTR_ERR (regs); + priv->regs = regs; + + ret =platform_get_irq (pdev,0 ); +if (ret >0 ) { + priv->parent_irq_base =irq_get_irq_data (ret)->hwirq; + parent_domain =irq_get_irq_data (ret)->domain; + } +if (!parent_domain) { +dev_err (&pdev->dev,"unable to obtain parent domain\n" ); +return -ENODEV ; + } + ret = bgpio_init(&priv->gc, &pdev->dev, 4, regs + MPA_GPIO_IN_ADDR, regs + MPA_GPIO_OUT_ADDR, NULL,
@@ -97,30 +285,51 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)if (ret)return ret; - priv->gc.to_irq = apm_gpio_sb_to_irq; - priv->gc.ngpio =XGENE_MAX_GPIO_DS ; + priv->gc.to_irq = xgene_gpio_sb_to_irq; - priv->nirq =XGENE_MAX_GPIO_DS_IRQ ; +/* Retrieve start irq pin, use default if property not found */ + priv->irq_start =XGENE_DFLT_IRQ_START_PIN ; +if (!device_property_read_u32 (&pdev->dev, +XGENE_IRQ_START_PROPERTY , &val32)) + priv->irq_start = val32; - priv->irq =devm_kzalloc (&pdev->dev,sizeof (u32) *XGENE_MAX_GPIO_DS , -GFP_KERNEL ); -if (!priv->irq) -return -ENOMEM ; +/* Retrieve number irqs, use default if property not found */ + priv->nirq =XGENE_DFLT_MAX_NIRQ ; +if (!device_property_read_u32 (&pdev->dev,XGENE_NIRQ_PROPERTY , &val32)) + priv->nirq = val32; -for (i =0 ; i < priv->nirq; i++) { - priv->irq[default_lines[i]] =platform_get_irq (pdev, i); -xgene_gpio_set_bit (&priv->gc, regs +MPA_GPIO_SEL_LO , - default_lines[i] *2 ,1 ); -xgene_gpio_set_bit (&priv->gc, regs +MPA_GPIO_INT_LVL , i,1 ); - } +/* Retrieve number gpio, use default if property not found */ + priv->gc.ngpio =XGENE_DFLT_MAX_NGPIO ; +if (!device_property_read_u32 (&pdev->dev,XGENE_NGPIO_PROPERTY , &val32)) + priv->gc.ngpio = val32; + +dev_info (&pdev->dev,"Support %d gpios, %d irqs start from pin %d\n" , + priv->gc.ngpio, priv->nirq, priv->irq_start);platform_set_drvdata (pdev, priv); - ret =gpiochip_add_data (&priv->gc, priv); -if (ret) -dev_err (&pdev->dev,"failed to register X-Gene GPIO Standby driver\n" ); +if (pdev->dev.of_node) + fwnode =of_node_to_fwnode (pdev->dev.of_node);else -dev_info (&pdev->dev,"X-Gene GPIO Standby driver registered\n" ); + fwnode = pdev->dev.fwnode; + + priv->irq_domain =irq_domain_create_hierarchy (parent_domain, +0 , priv->nirq, fwnode, + &xgene_gpio_sb_domain_ops, priv); +if (!priv->irq_domain) +return -ENODEV ; + + priv->gc.irqdomain = priv->irq_domain; + + ret =gpiochip_add_data (&priv->gc, priv); +if (ret) { +dev_err (&pdev->dev, +"failed to register X-Gene GPIO Standby driver\n" ); +irq_domain_remove (priv->irq_domain); +return ret; + } + +dev_info (&pdev->dev,"X-Gene GPIO Standby driver registered\n" );if (priv->nirq >0 ) {/* Register interrupt handlers for gpio signaled acpi events */
@@ -138,6 +347,8 @@ static int xgene_gpio_sb_remove(struct platform_device *pdev)acpi_gpiochip_free_interrupts (&priv->gc); } +irq_domain_remove (priv->irq_domain); +gpiochip_remove (&priv->gc);return 0 ; }
Signature · 1 line
1.7.12.4
PATCH v5 1/3 gpio: xgene: Enable X-Gene standby GPIO as interrupt controller
Quoted 6 lines · Quan Nguyen
Enable X-Gene standby GPIO controller as interrupt controller to provide its own resources. This avoids ambiguity where GIC interrupt resource is use as X-Gene standby GPIO interrupt resource in user driver.
Signed-off-by Y Vo <[email protected]>Signed-off-by Quan Nguyen <[email protected]>
I want Marc's ACK on this before I merge it.
But it is looking way more acceptable than earlier incarnations! :)
drivers/gpio/gpio-xgene-sb.c static void xgene_gpio_set_bit(struct gpio_chip *gc, void __iomem *reg, u32 gpio · line 113
Quoted 5 lines
drivers/gpio/gpio-xgene-sb.c +5
-0+/* Propagate IRQ type setting to parent */ +if (type &IRQ_TYPE_EDGE_BOTH ) +return irq_chip_set_type_parent (d,IRQ_TYPE_EDGE_RISING ); +else +return irq_chip_set_type_parent (d,IRQ_TYPE_LEVEL_HIGH );
This makes it look much more solid, nice.
drivers/gpio/gpio-xgene-sb.c static void xgene_gpio_set_bit(struct gpio_chip *gc, void __iomem *reg, u32 gpio · line 120
Quoted 5 lines
drivers/gpio/gpio-xgene-sb.c +5
-0+static void xgene_gpio_sb_irq_shutdown (struct irq_data *d) +{ +struct xgene_gpio_sb *priv =irq_data_get_irq_chip_data (d); + +gpiochip_unlock_as_irq (&priv->gc,HWIRQ_TO_GPIO (priv, d->hwirq));
Oh really. Well.
Quoted 4 lines
drivers/gpio/gpio-xgene-sb.c +4
-0+if (is_of_node (domain->parent->fwnode)) { + parent_fwspec.fwnode = domain->parent->fwnode; + parent_fwspec.param_count =3 ; + parent_fwspec.param[0 ] =0 ;/* SPI */
drivers/gpio/gpio-xgene-sb.c static void xgene_gpio_set_bit(struct gpio_chip *gc, void __iomem *reg, u32 gpio · line 223
Quoted 10 lines
drivers/gpio/gpio-xgene-sb.c +10
-0+/* Skip SGIs and PPIs*/ + parent_fwspec.param[1 ] = hwirq + priv->parent_irq_base -32 ; + parent_fwspec.param[2 ] = fwspec->param[1 ]; + }else if (is_fwnode_irqchip (domain->parent->fwnode)) { + parent_fwspec.fwnode = domain->parent->fwnode; + parent_fwspec.param_count =2 ; + parent_fwspec.param[0 ] = hwirq + priv->parent_irq_base; + parent_fwspec.param[1 ] = fwspec->param[1 ]; + }else +return -EINVAL ;
This kind of stuff hardcodes knowledge of the GIC into this controller, like that the SGI+PPI occupy the first 32 hwIRQs. But maybe there is no better way to do it?
Yours,
Linus Walleij
PATCH v5 1/3 gpio: xgene: Enable X-Gene standby GPIO as interrupt controller
In reply to Quan NguyenQuan,
This is getting better. Some comments below.
Quoted 117 lines · Quan Nguyen
Enable X-Gene standby GPIO controller as interrupt controller to provide its own resources. This avoids ambiguity where GIC interrupt resource is use as X-Gene standby GPIO interrupt resource in user driver.
Signed-off-by Y Vo <[email protected]>Signed-off-by Quan Nguyen <[email protected]>--- drivers/gpio/gpio-xgene-sb.c | 275 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 243 insertions(+), 32 deletions(-)drivers/gpio/gpio-xgene-sb.c +59
-10@@ -2,8 +2,9 @@* AppliedMicro X-Gene SoC GPIO-Standby Driver * * Copyright (c) 2014, Applied Micro Circuits Corporation -* Author: Tin Huynh <[email protected]>. -* Y Vo <[email protected]>. +* Author: Tin Huynh <[email protected]>. +* Y Vo <[email protected]>. +* Quan Nguyen <[email protected]>. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -28,9 +29,14 @@#include "gpiolib.h" -#define XGENE_MAX_GPIO_DS 22 -#define XGENE_MAX_GPIO_DS_IRQ 6 +/* Common property names */ +#define XGENE_NIRQ_PROPERTY "apm,nr-irqs" +#define XGENE_NGPIO_PROPERTY "apm,nr-gpios" +#define XGENE_IRQ_START_PROPERTY "apm,irq-start" +#define XGENE_DFLT_MAX_NGPIO 22 +#define XGENE_DFLT_MAX_NIRQ 6 +#define XGENE_DFLT_IRQ_START_PIN 8#define GPIO_MASK (x) (1U << ((x) % 32))#define MPA_GPIO_INT_LVL 0x0290@@ -39,19 +45,32 @@#define MPA_GPIO_IN_ADDR 0x02a4#define MPA_GPIO_SEL_LO 0x0294 +#define GPIO_INT_LEVEL_H 0x000001 +#define GPIO_INT_LEVEL_L 0x000000 +/** * struct xgene_gpio_sb - GPIO-Standby private data structure. * @gc: memory-mapped GPIO controllers. -* @irq: Mapping GPIO pins and interrupt number -* nirq: Number of GPIO pins that supports interrupt +* @regs: GPIO register base offset +* @irq_domain: GPIO interrupt domain +* @irq_start: GPIO pin that start support interrupt +* @nirq: Number of GPIO pins that supports interrupt +* @parent_irq_base: Start parent HWIRQ */ struct xgene_gpio_sb {struct gpio_chip gc; -u32 *irq; -u32 nirq; +void __iomem *regs; +struct irq_domain *irq_domain; +u16 irq_start; +u16 nirq; +u16 parent_irq_base; }; -static void xgene_gpio_set_bit (struct gpio_chip *gc,void __iomem *reg,u32 gpio,int val) +#define HWIRQ_TO_GPIO (priv, hwirq) ((hwirq) + (priv)->irq_start) +#define GPIO_TO_HWIRQ (priv, gpio) ((gpio) - (priv)->irq_start) + +static void xgene_gpio_set_bit (struct gpio_chip *gc, +void __iomem *reg,u32 gpio,int val) {u32 data;@@ -63,23 +82,180 @@ static void xgene_gpio_set_bit(struct gpio_chip *gc, void __iomem *reg, u32 gpio gc->write_reg (reg, data); } -static int apm_gpio_sb_to_irq (struct gpio_chip *gc,u32 gpio) +static int xgene_gpio_sb_irq_set_type (struct irq_data *d,unsigned int type) +{ +struct xgene_gpio_sb *priv =irq_data_get_irq_chip_data (d); +int gpio =HWIRQ_TO_GPIO (priv, d->hwirq); +int lvl_type =GPIO_INT_LEVEL_H ; + +switch (type &IRQ_TYPE_SENSE_MASK ) { +case IRQ_TYPE_EDGE_RISING : +case IRQ_TYPE_LEVEL_HIGH : + lvl_type =GPIO_INT_LEVEL_H ; +break ; +case IRQ_TYPE_EDGE_FALLING : +case IRQ_TYPE_LEVEL_LOW : + lvl_type =GPIO_INT_LEVEL_L ; +break ; +default : +break ; + } + +xgene_gpio_set_bit (&priv->gc, priv->regs +MPA_GPIO_SEL_LO , + gpio *2 ,1 ); +xgene_gpio_set_bit (&priv->gc, priv->regs +MPA_GPIO_INT_LVL , + d->hwirq, lvl_type); + +/* Propagate IRQ type setting to parent */ +if (type &IRQ_TYPE_EDGE_BOTH ) +return irq_chip_set_type_parent (d,IRQ_TYPE_EDGE_RISING ); +else +return irq_chip_set_type_parent (d,IRQ_TYPE_LEVEL_HIGH ); +} +
drivers/gpio/gpio-xgene-sb.c static void xgene_gpio_set_bit(struct gpio_chip *gc, void __iomem *reg, u32 gpio · line 125
Quoted 10 lines
drivers/gpio/gpio-xgene-sb.c +10
-0+static void xgene_gpio_sb_irq_shutdown (struct irq_data *d) +{ +struct xgene_gpio_sb *priv =irq_data_get_irq_chip_data (d); + +gpiochip_unlock_as_irq (&priv->gc,HWIRQ_TO_GPIO (priv, d->hwirq)); +} + +static struct irq_chip xgene_gpio_sb_irq_chip = { + .name ="sbgpio" , + .irq_ack = irq_chip_ack_parent,
There is no point calling irq_chip_ack_parent, as the GIC doesn't implement an irq_ack method at all.
Quoted 40 lines
drivers/gpio/gpio-xgene-sb.c +38
-0+ .irq_eoi = irq_chip_eoi_parent, + .irq_mask = irq_chip_mask_parent, + .irq_unmask = irq_chip_unmask_parent, + .irq_set_type = xgene_gpio_sb_irq_set_type, + .irq_shutdown = xgene_gpio_sb_irq_shutdown, +}; + +static int xgene_gpio_sb_to_irq (struct gpio_chip *gc,u32 gpio) {struct xgene_gpio_sb *priv =gpiochip_get_data (gc); +struct irq_fwspec fwspec; + +if ((gpio < priv->irq_start) || + (gpio >HWIRQ_TO_GPIO (priv, priv->nirq))) +return -ENXIO ; + +if (gc->parent->of_node) + fwspec.fwnode =of_node_to_fwnode (gc->parent->of_node); +else + fwspec.fwnode = gc->parent->fwnode; + fwspec.param_count =2 ; + fwspec.param[0 ] =GPIO_TO_HWIRQ (priv, gpio); + fwspec.param[1 ] =IRQ_TYPE_NONE ; +return irq_create_fwspec_mapping (&fwspec); +} + +static void xgene_gpio_sb_domain_activate (struct irq_domain *d, +struct irq_data *irq_data) +{ +struct xgene_gpio_sb *priv = d->host_data; +u32 gpio =HWIRQ_TO_GPIO (priv, irq_data->hwirq); + +if (gpiochip_lock_as_irq (&priv->gc, gpio)) { +dev_err (priv->gc.parent, +"Unable to configure XGene GPIO standby pin %d as IRQ\n" , + gpio); +return ; + } + + xgene_gpio_set_bit(&priv->gc, priv->regs + MPA_GPIO_SEL_LO,
drivers/gpio/gpio-xgene-sb.c static void xgene_gpio_set_bit(struct gpio_chip *gc, void __iomem *reg, u32 gpio · line 175
Quoted 10 lines
drivers/gpio/gpio-xgene-sb.c +10
-0+ gpio * 2, 1); +} + +static void xgene_gpio_sb_domain_deactivate (struct irq_domain *d, +struct irq_data *irq_data) +{ +struct xgene_gpio_sb *priv = d->host_data; +u32 gpio =HWIRQ_TO_GPIO (priv, irq_data->hwirq); + +gpiochip_unlock_as_irq (&priv->gc, gpio);
Is it right to do the unlock both in irq_shutdown and domain_deactivate? This seems a bit odd to me to have such an inbalance. My hunch is that you should either implement irq_startup, do the locking there and drop the unlock drop deactivate, or kill irq_shutdown.
Linus, what do you think?
Quoted 35 lines
drivers/gpio/gpio-xgene-sb.c +32
-2+xgene_gpio_set_bit (&priv->gc, priv->regs +MPA_GPIO_SEL_LO , + gpio *2 ,0 ); +} -if (priv->irq[gpio]) -return priv->irq[gpio]; +static int xgene_gpio_sb_domain_translate (struct irq_domain *d, +struct irq_fwspec *fwspec, +unsigned long *hwirq, +unsigned int *type) +{ +struct xgene_gpio_sb *priv = d->host_data; + +if ((fwspec->param_count !=2 ) || + (fwspec->param[0 ] >= priv->nirq)) +return -EINVAL ; + *hwirq = fwspec->param[0 ]; + *type = fwspec->param[1 ]; +return 0 ; +} + +static int xgene_gpio_sb_domain_alloc (struct irq_domain *domain, +unsigned int virq, +unsigned int nr_irqs,void *data) +{ +struct irq_fwspec *fwspec = data; +struct irq_fwspec parent_fwspec; +struct xgene_gpio_sb *priv = domain->host_data; +irq_hw_number_t hwirq; +unsigned int i; + + hwirq = fwspec->param[0 ]; +for (i =0 ; i < nr_irqs; i++) +irq_domain_set_hwirq_and_chip (domain, virq + i, hwirq + i, + &xgene_gpio_sb_irq_chip, priv);
drivers/gpio/gpio-xgene-sb.c static void xgene_gpio_set_bit(struct gpio_chip *gc, void __iomem *reg, u32 gpio · line 218
Quoted 10 lines
drivers/gpio/gpio-xgene-sb.c +10
-0+ +if (is_of_node (domain->parent->fwnode)) { + parent_fwspec.fwnode = domain->parent->fwnode; + parent_fwspec.param_count =3 ; + parent_fwspec.param[0 ] =0 ;/* SPI */ +/* Skip SGIs and PPIs*/ + parent_fwspec.param[1 ] = hwirq + priv->parent_irq_base -32 ; + parent_fwspec.param[2 ] = fwspec->param[1 ]; + }else if (is_fwnode_irqchip (domain->parent->fwnode)) { + parent_fwspec.fwnode = domain->parent->fwnode;
nit: You can move this out of the if/else, and always assign the fwnode.
Quoted 68 lines
drivers/gpio/gpio-xgene-sb.c +44
-3+ parent_fwspec.param_count =2 ; + parent_fwspec.param[0 ] = hwirq + priv->parent_irq_base; + parent_fwspec.param[1 ] = fwspec->param[1 ]; + }else +return -EINVAL ; -return -ENXIO ; +return irq_domain_alloc_irqs_parent (domain, virq, nr_irqs, + &parent_fwspec); } +static void xgene_gpio_sb_domain_free (struct irq_domain *domain, +unsigned int virq, +unsigned int nr_irqs) +{ +struct irq_data *d; +unsigned int i; + +for (i =0 ; i < nr_irqs; i++) { + d =irq_domain_get_irq_data (domain, virq + i); +irq_domain_reset_irq_data (d); + } +} + +static const struct irq_domain_ops xgene_gpio_sb_domain_ops = { + .translate = xgene_gpio_sb_domain_translate, + .alloc = xgene_gpio_sb_domain_alloc, + .free = xgene_gpio_sb_domain_free, + .activate = xgene_gpio_sb_domain_activate, + .deactivate = xgene_gpio_sb_domain_deactivate, +}; +static int xgene_gpio_sb_probe (struct platform_device *pdev) {struct xgene_gpio_sb *priv; -u32 ret, i; -u32 default_lines[] = {0x08 ,0x09 ,0x0A ,0x0B ,0x0C ,0x0D }; +u32 ret;struct resource *res;void __iomem *regs; +struct irq_domain *parent_domain =NULL ; +struct fwnode_handle *fwnode; +u32 val32; priv =devm_kzalloc (&pdev->dev,sizeof (*priv),GFP_KERNEL );if (!priv)@@ -90,6 +266,18 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)if (IS_ERR (regs))return PTR_ERR (regs); + priv->regs = regs; + + ret =platform_get_irq (pdev,0 ); +if (ret >0 ) { + priv->parent_irq_base =irq_get_irq_data (ret)->hwirq; + parent_domain =irq_get_irq_data (ret)->domain; + } +if (!parent_domain) { +dev_err (&pdev->dev,"unable to obtain parent domain\n" ); +return -ENODEV ; + } + ret = bgpio_init(&priv->gc, &pdev->dev, 4, regs + MPA_GPIO_IN_ADDR, regs + MPA_GPIO_OUT_ADDR, NULL,@@ -97,30 +285,51 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)if (ret)return ret;
drivers/gpio/gpio-xgene-sb.c static int xgene_gpio_sb_probe(struct platform_device *pdev) · line 293
Quoted 10 lines
drivers/gpio/gpio-xgene-sb.c +5
-3- priv->gc.to_irq = apm_gpio_sb_to_irq; - priv->gc.ngpio =XGENE_MAX_GPIO_DS ; + priv->gc.to_irq = xgene_gpio_sb_to_irq; - priv->nirq =XGENE_MAX_GPIO_DS_IRQ ; +/* Retrieve start irq pin, use default if property not found */ + priv->irq_start =XGENE_DFLT_IRQ_START_PIN ; +if (!device_property_read_u32 (&pdev->dev, +XGENE_IRQ_START_PROPERTY , &val32))
Is that for ACPI as well?
Quoted 58 lines
drivers/gpio/gpio-xgene-sb.c +33
-14+ priv->irq_start = val32; - priv->irq =devm_kzalloc (&pdev->dev,sizeof (u32) *XGENE_MAX_GPIO_DS , -GFP_KERNEL ); -if (!priv->irq) -return -ENOMEM ; +/* Retrieve number irqs, use default if property not found */ + priv->nirq =XGENE_DFLT_MAX_NIRQ ; +if (!device_property_read_u32 (&pdev->dev,XGENE_NIRQ_PROPERTY , &val32)) + priv->nirq = val32; -for (i =0 ; i < priv->nirq; i++) { - priv->irq[default_lines[i]] =platform_get_irq (pdev, i); -xgene_gpio_set_bit (&priv->gc, regs +MPA_GPIO_SEL_LO , - default_lines[i] *2 ,1 ); -xgene_gpio_set_bit (&priv->gc, regs +MPA_GPIO_INT_LVL , i,1 ); - } +/* Retrieve number gpio, use default if property not found */ + priv->gc.ngpio =XGENE_DFLT_MAX_NGPIO ; +if (!device_property_read_u32 (&pdev->dev,XGENE_NGPIO_PROPERTY , &val32)) + priv->gc.ngpio = val32; + +dev_info (&pdev->dev,"Support %d gpios, %d irqs start from pin %d\n" , + priv->gc.ngpio, priv->nirq, priv->irq_start);platform_set_drvdata (pdev, priv); - ret =gpiochip_add_data (&priv->gc, priv); -if (ret) -dev_err (&pdev->dev,"failed to register X-Gene GPIO Standby driver\n" ); +if (pdev->dev.of_node) + fwnode =of_node_to_fwnode (pdev->dev.of_node);else -dev_info (&pdev->dev,"X-Gene GPIO Standby driver registered\n" ); + fwnode = pdev->dev.fwnode; + + priv->irq_domain =irq_domain_create_hierarchy (parent_domain, +0 , priv->nirq, fwnode, + &xgene_gpio_sb_domain_ops, priv); +if (!priv->irq_domain) +return -ENODEV ; + + priv->gc.irqdomain = priv->irq_domain; + + ret =gpiochip_add_data (&priv->gc, priv); +if (ret) { +dev_err (&pdev->dev, +"failed to register X-Gene GPIO Standby driver\n" ); +irq_domain_remove (priv->irq_domain); +return ret; + } + +dev_info (&pdev->dev,"X-Gene GPIO Standby driver registered\n" );if (priv->nirq >0 ) {/* Register interrupt handlers for gpio signaled acpi events */
drivers/gpio/gpio-xgene-sb.c static int xgene_gpio_sb_remove(struct platform_device *pdev) · line 354
Quoted 8 lines
drivers/gpio/gpio-xgene-sb.c +2
-0@@ -138,6 +347,8 @@ static int xgene_gpio_sb_remove(struct platform_device *pdev)acpi_gpiochip_free_interrupts (&priv->gc); } +irq_domain_remove (priv->irq_domain); +gpiochip_remove (&priv->gc);return 0 ; }
Thanks,
M.
Signature · 1 line
Jazz is not dead. It just smells funny...
PATCH v5 1/3 gpio: xgene: Enable X-Gene standby GPIO as interrupt controller
Quoted 127 lines · Marc Zyngier
Quan,
This is getting better. Some comments below.
Quoted 122 lines · Quan Nguyen
Enable X-Gene standby GPIO controller as interrupt controller to provide its own resources. This avoids ambiguity where GIC interrupt resource is use as X-Gene standby GPIO interrupt resource in user driver.
Signed-off-by Y Vo <[email protected]>Signed-off-by Quan Nguyen <[email protected]>--- drivers/gpio/gpio-xgene-sb.c | 275 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 243 insertions(+), 32 deletions(-)drivers/gpio/gpio-xgene-sb.c +64
-10@@ -2,8 +2,9 @@* AppliedMicro X-Gene SoC GPIO-Standby Driver * * Copyright (c) 2014, Applied Micro Circuits Corporation -* Author: Tin Huynh <[email protected]>. -* Y Vo <[email protected]>. +* Author: Tin Huynh <[email protected]>. +* Y Vo <[email protected]>. +* Quan Nguyen <[email protected]>. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -28,9 +29,14 @@#include "gpiolib.h" -#define XGENE_MAX_GPIO_DS 22 -#define XGENE_MAX_GPIO_DS_IRQ 6 +/* Common property names */ +#define XGENE_NIRQ_PROPERTY "apm,nr-irqs" +#define XGENE_NGPIO_PROPERTY "apm,nr-gpios" +#define XGENE_IRQ_START_PROPERTY "apm,irq-start" +#define XGENE_DFLT_MAX_NGPIO 22 +#define XGENE_DFLT_MAX_NIRQ 6 +#define XGENE_DFLT_IRQ_START_PIN 8#define GPIO_MASK (x) (1U << ((x) % 32))#define MPA_GPIO_INT_LVL 0x0290@@ -39,19 +45,32 @@#define MPA_GPIO_IN_ADDR 0x02a4#define MPA_GPIO_SEL_LO 0x0294 +#define GPIO_INT_LEVEL_H 0x000001 +#define GPIO_INT_LEVEL_L 0x000000 +/** * struct xgene_gpio_sb - GPIO-Standby private data structure. * @gc: memory-mapped GPIO controllers. -* @irq: Mapping GPIO pins and interrupt number -* nirq: Number of GPIO pins that supports interrupt +* @regs: GPIO register base offset +* @irq_domain: GPIO interrupt domain +* @irq_start: GPIO pin that start support interrupt +* @nirq: Number of GPIO pins that supports interrupt +* @parent_irq_base: Start parent HWIRQ */ struct xgene_gpio_sb {struct gpio_chip gc; -u32 *irq; -u32 nirq; +void __iomem *regs; +struct irq_domain *irq_domain; +u16 irq_start; +u16 nirq; +u16 parent_irq_base; }; -static void xgene_gpio_set_bit (struct gpio_chip *gc,void __iomem *reg,u32 gpio,int val) +#define HWIRQ_TO_GPIO (priv, hwirq) ((hwirq) + (priv)->irq_start) +#define GPIO_TO_HWIRQ (priv, gpio) ((gpio) - (priv)->irq_start) + +static void xgene_gpio_set_bit (struct gpio_chip *gc, +void __iomem *reg,u32 gpio,int val) {u32 data;@@ -63,23 +82,180 @@ static void xgene_gpio_set_bit(struct gpio_chip *gc, void __iomem *reg, u32 gpio gc->write_reg (reg, data); } -static int apm_gpio_sb_to_irq (struct gpio_chip *gc,u32 gpio) +static int xgene_gpio_sb_irq_set_type (struct irq_data *d,unsigned int type) +{ +struct xgene_gpio_sb *priv =irq_data_get_irq_chip_data (d); +int gpio =HWIRQ_TO_GPIO (priv, d->hwirq); +int lvl_type =GPIO_INT_LEVEL_H ; + +switch (type &IRQ_TYPE_SENSE_MASK ) { +case IRQ_TYPE_EDGE_RISING : +case IRQ_TYPE_LEVEL_HIGH : + lvl_type =GPIO_INT_LEVEL_H ; +break ; +case IRQ_TYPE_EDGE_FALLING : +case IRQ_TYPE_LEVEL_LOW : + lvl_type =GPIO_INT_LEVEL_L ; +break ; +default : +break ; + } + +xgene_gpio_set_bit (&priv->gc, priv->regs +MPA_GPIO_SEL_LO , + gpio *2 ,1 ); +xgene_gpio_set_bit (&priv->gc, priv->regs +MPA_GPIO_INT_LVL , + d->hwirq, lvl_type); + +/* Propagate IRQ type setting to parent */ +if (type &IRQ_TYPE_EDGE_BOTH ) +return irq_chip_set_type_parent (d,IRQ_TYPE_EDGE_RISING ); +else +return irq_chip_set_type_parent (d,IRQ_TYPE_LEVEL_HIGH ); +} + +static void xgene_gpio_sb_irq_shutdown (struct irq_data *d) +{ +struct xgene_gpio_sb *priv =irq_data_get_irq_chip_data (d); + +gpiochip_unlock_as_irq (&priv->gc,HWIRQ_TO_GPIO (priv, d->hwirq));
Quoted 9 lines
drivers/gpio/gpio-xgene-sb.c static void xgene_gpio_set_bit(struct gpio_chip *gc, void __iomem *reg, u32 gpio · line 125
Quoted 5 lines
drivers/gpio/gpio-xgene-sb.c +5
-0+} + +static struct irq_chip xgene_gpio_sb_irq_chip = { + .name ="sbgpio" , + .irq_ack = irq_chip_ack_parent,There is no point calling
irq_chip_ack_parent, as the GIC doesn't implement anirq_ackmethod at all.
Thanks Marc, let me remove it.
Quoted 56 lines
Quoted 40 lines
drivers/gpio/gpio-xgene-sb.c +38
-0+ .irq_eoi = irq_chip_eoi_parent, + .irq_mask = irq_chip_mask_parent, + .irq_unmask = irq_chip_unmask_parent, + .irq_set_type = xgene_gpio_sb_irq_set_type, + .irq_shutdown = xgene_gpio_sb_irq_shutdown, +}; + +static int xgene_gpio_sb_to_irq (struct gpio_chip *gc,u32 gpio) {struct xgene_gpio_sb *priv =gpiochip_get_data (gc); +struct irq_fwspec fwspec; + +if ((gpio < priv->irq_start) || + (gpio >HWIRQ_TO_GPIO (priv, priv->nirq))) +return -ENXIO ; + +if (gc->parent->of_node) + fwspec.fwnode =of_node_to_fwnode (gc->parent->of_node); +else + fwspec.fwnode = gc->parent->fwnode; + fwspec.param_count =2 ; + fwspec.param[0 ] =GPIO_TO_HWIRQ (priv, gpio); + fwspec.param[1 ] =IRQ_TYPE_NONE ; +return irq_create_fwspec_mapping (&fwspec); +} + +static void xgene_gpio_sb_domain_activate (struct irq_domain *d, +struct irq_data *irq_data) +{ +struct xgene_gpio_sb *priv = d->host_data; +u32 gpio =HWIRQ_TO_GPIO (priv, irq_data->hwirq); + +if (gpiochip_lock_as_irq (&priv->gc, gpio)) { +dev_err (priv->gc.parent, +"Unable to configure XGene GPIO standby pin %d as IRQ\n" , + gpio); +return ; + } + + xgene_gpio_set_bit(&priv->gc, priv->regs + MPA_GPIO_SEL_LO,drivers/gpio/gpio-xgene-sb.c static void xgene_gpio_set_bit(struct gpio_chip *gc, void __iomem *reg, u32 gpio · line 175
Quoted 10 lines
drivers/gpio/gpio-xgene-sb.c +10
-0+ gpio * 2, 1); +} + +static void xgene_gpio_sb_domain_deactivate (struct irq_domain *d, +struct irq_data *irq_data) +{ +struct xgene_gpio_sb *priv = d->host_data; +u32 gpio =HWIRQ_TO_GPIO (priv, irq_data->hwirq); + +gpiochip_unlock_as_irq (&priv->gc, gpio);Is it right to do the unlock both in
irq_shutdownanddomain_deactivate? This seems a bit odd to me to have such an inbalance. My hunch is that you should either implementirq_startup, do the locking there and drop the unlock drop deactivate, or killirq_shutdown.
Quoted 2 lines
Linus, what do you think?
I refer to kill irq_shutdown.
Quoted 39 lines
Quoted 39 lines
drivers/gpio/gpio-xgene-sb.c +36
-2+xgene_gpio_set_bit (&priv->gc, priv->regs +MPA_GPIO_SEL_LO , + gpio *2 ,0 ); +} -if (priv->irq[gpio]) -return priv->irq[gpio]; +static int xgene_gpio_sb_domain_translate (struct irq_domain *d, +struct irq_fwspec *fwspec, +unsigned long *hwirq, +unsigned int *type) +{ +struct xgene_gpio_sb *priv = d->host_data; + +if ((fwspec->param_count !=2 ) || + (fwspec->param[0 ] >= priv->nirq)) +return -EINVAL ; + *hwirq = fwspec->param[0 ]; + *type = fwspec->param[1 ]; +return 0 ; +} + +static int xgene_gpio_sb_domain_alloc (struct irq_domain *domain, +unsigned int virq, +unsigned int nr_irqs,void *data) +{ +struct irq_fwspec *fwspec = data; +struct irq_fwspec parent_fwspec; +struct xgene_gpio_sb *priv = domain->host_data; +irq_hw_number_t hwirq; +unsigned int i; + + hwirq = fwspec->param[0 ]; +for (i =0 ; i < nr_irqs; i++) +irq_domain_set_hwirq_and_chip (domain, virq + i, hwirq + i, + &xgene_gpio_sb_irq_chip, priv); + +if (is_of_node (domain->parent->fwnode)) { + parent_fwspec.fwnode = domain->parent->fwnode; + parent_fwspec.param_count =3 ;
Quoted 8 lines
drivers/gpio/gpio-xgene-sb.c static void xgene_gpio_set_bit(struct gpio_chip *gc, void __iomem *reg, u32 gpio · line 218
Quoted 6 lines
drivers/gpio/gpio-xgene-sb.c +6
-0+ parent_fwspec.param[0 ] =0 ;/* SPI */ +/* Skip SGIs and PPIs*/ + parent_fwspec.param[1 ] = hwirq + priv->parent_irq_base -32 ; + parent_fwspec.param[2 ] = fwspec->param[1 ]; + }else if (is_fwnode_irqchip (domain->parent->fwnode)) { + parent_fwspec.fwnode = domain->parent->fwnode;nit: You can move this out of the if/else, and always assign the fwnode.
Thanks Marc, let me change it.
Quoted 74 lines
Quoted 74 lines
drivers/gpio/gpio-xgene-sb.c +45
-5+ parent_fwspec.param_count =2 ; + parent_fwspec.param[0 ] = hwirq + priv->parent_irq_base; + parent_fwspec.param[1 ] = fwspec->param[1 ]; + }else +return -EINVAL ; -return -ENXIO ; +return irq_domain_alloc_irqs_parent (domain, virq, nr_irqs, + &parent_fwspec); } +static void xgene_gpio_sb_domain_free (struct irq_domain *domain, +unsigned int virq, +unsigned int nr_irqs) +{ +struct irq_data *d; +unsigned int i; + +for (i =0 ; i < nr_irqs; i++) { + d =irq_domain_get_irq_data (domain, virq + i); +irq_domain_reset_irq_data (d); + } +} + +static const struct irq_domain_ops xgene_gpio_sb_domain_ops = { + .translate = xgene_gpio_sb_domain_translate, + .alloc = xgene_gpio_sb_domain_alloc, + .free = xgene_gpio_sb_domain_free, + .activate = xgene_gpio_sb_domain_activate, + .deactivate = xgene_gpio_sb_domain_deactivate, +}; +static int xgene_gpio_sb_probe (struct platform_device *pdev) {struct xgene_gpio_sb *priv; -u32 ret, i; -u32 default_lines[] = {0x08 ,0x09 ,0x0A ,0x0B ,0x0C ,0x0D }; +u32 ret;struct resource *res;void __iomem *regs; +struct irq_domain *parent_domain =NULL ; +struct fwnode_handle *fwnode; +u32 val32; priv =devm_kzalloc (&pdev->dev,sizeof (*priv),GFP_KERNEL );if (!priv)@@ -90,6 +266,18 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)if (IS_ERR (regs))return PTR_ERR (regs); + priv->regs = regs; + + ret =platform_get_irq (pdev,0 ); +if (ret >0 ) { + priv->parent_irq_base =irq_get_irq_data (ret)->hwirq; + parent_domain =irq_get_irq_data (ret)->domain; + } +if (!parent_domain) { +dev_err (&pdev->dev,"unable to obtain parent domain\n" ); +return -ENODEV ; + } + ret = bgpio_init(&priv->gc, &pdev->dev, 4, regs + MPA_GPIO_IN_ADDR, regs + MPA_GPIO_OUT_ADDR, NULL,@@ -97,30 +285,51 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)if (ret)return ret; - priv->gc.to_irq = apm_gpio_sb_to_irq; - priv->gc.ngpio =XGENE_MAX_GPIO_DS ; + priv->gc.to_irq = xgene_gpio_sb_to_irq;
Quoted 8 lines
drivers/gpio/gpio-xgene-sb.c static int xgene_gpio_sb_probe(struct platform_device *pdev) · line 293
Quoted 5 lines
drivers/gpio/gpio-xgene-sb.c +4
-1- priv->nirq =XGENE_MAX_GPIO_DS_IRQ ; +/* Retrieve start irq pin, use default if property not found */ + priv->irq_start =XGENE_DFLT_IRQ_START_PIN ; +if (!device_property_read_u32 (&pdev->dev, +XGENE_IRQ_START_PROPERTY , &val32))Is that for ACPI as well?
Yes, Marc.
Quoted 72 lines
Quoted 58 lines
drivers/gpio/gpio-xgene-sb.c +33
-14+ priv->irq_start = val32; - priv->irq =devm_kzalloc (&pdev->dev,sizeof (u32) *XGENE_MAX_GPIO_DS , -GFP_KERNEL ); -if (!priv->irq) -return -ENOMEM ; +/* Retrieve number irqs, use default if property not found */ + priv->nirq =XGENE_DFLT_MAX_NIRQ ; +if (!device_property_read_u32 (&pdev->dev,XGENE_NIRQ_PROPERTY , &val32)) + priv->nirq = val32; -for (i =0 ; i < priv->nirq; i++) { - priv->irq[default_lines[i]] =platform_get_irq (pdev, i); -xgene_gpio_set_bit (&priv->gc, regs +MPA_GPIO_SEL_LO , - default_lines[i] *2 ,1 ); -xgene_gpio_set_bit (&priv->gc, regs +MPA_GPIO_INT_LVL , i,1 ); - } +/* Retrieve number gpio, use default if property not found */ + priv->gc.ngpio =XGENE_DFLT_MAX_NGPIO ; +if (!device_property_read_u32 (&pdev->dev,XGENE_NGPIO_PROPERTY , &val32)) + priv->gc.ngpio = val32; + +dev_info (&pdev->dev,"Support %d gpios, %d irqs start from pin %d\n" , + priv->gc.ngpio, priv->nirq, priv->irq_start);platform_set_drvdata (pdev, priv); - ret =gpiochip_add_data (&priv->gc, priv); -if (ret) -dev_err (&pdev->dev,"failed to register X-Gene GPIO Standby driver\n" ); +if (pdev->dev.of_node) + fwnode =of_node_to_fwnode (pdev->dev.of_node);else -dev_info (&pdev->dev,"X-Gene GPIO Standby driver registered\n" ); + fwnode = pdev->dev.fwnode; + + priv->irq_domain =irq_domain_create_hierarchy (parent_domain, +0 , priv->nirq, fwnode, + &xgene_gpio_sb_domain_ops, priv); +if (!priv->irq_domain) +return -ENODEV ; + + priv->gc.irqdomain = priv->irq_domain; + + ret =gpiochip_add_data (&priv->gc, priv); +if (ret) { +dev_err (&pdev->dev, +"failed to register X-Gene GPIO Standby driver\n" ); +irq_domain_remove (priv->irq_domain); +return ret; + } + +dev_info (&pdev->dev,"X-Gene GPIO Standby driver registered\n" );if (priv->nirq >0 ) {/* Register interrupt handlers for gpio signaled acpi events */ drivers/gpio/gpio-xgene-sb.c static int xgene_gpio_sb_remove(struct platform_device *pdev) · line 354
Quoted 8 lines
drivers/gpio/gpio-xgene-sb.c +2
-0@@ -138,6 +347,8 @@ static int xgene_gpio_sb_remove(struct platform_device *pdev)acpi_gpiochip_free_interrupts (&priv->gc); } +irq_domain_remove (priv->irq_domain); +gpiochip_remove (&priv->gc);return 0 ; }Thanks,
M.--
Jazz is not dead. It just smells funny...
PATCH v5 1/3 gpio: xgene: Enable X-Gene standby GPIO as interrupt controller
In reply to Marc ZyngierQuoted 15 lines · Marc Zyngier
drivers/gpio/gpio-xgene-sb.c static void xgene_gpio_set_bit(struct gpio_chip *gc, void __iomem *reg, u32 gpio · line 175
Quoted 7 lines · Quan Nguyen
drivers/gpio/gpio-xgene-sb.c +7
-0+static void xgene_gpio_sb_domain_deactivate (struct irq_domain *d, +struct irq_data *irq_data) +{ +struct xgene_gpio_sb *priv = d->host_data; +u32 gpio =HWIRQ_TO_GPIO (priv, irq_data->hwirq); + +gpiochip_unlock_as_irq (&priv->gc, gpio);Is it right to do the unlock both in
irq_shutdownanddomain_deactivate? This seems a bit odd to me to have such an inbalance. My hunch is that you should either implementirq_startup, do the locking there and drop the unlock drop deactivate, or killirq_shutdown.
Quoted 1 line
Linus, what do you think?
Those functions should be called in .irq_alloc/release_resources(), that is why Gleixner added those callbacks in the first place.
Yours,
Linus Walleij
PATCH v5 2/3 Documentation: gpio: Update description for X-Gene standby GPIO controller DTS binding
In reply to Quan NguyenUpdate description for X-Gene standby GPIO controller DTS binding to support GPIO line configuration as input, output or external IRQ pin.
--- .../devicetree/bindings/gpio/gpio-xgene-sb.txt | 47 ++++++++++++++++++---- 1 file changed, 40 insertions(+), 7 deletions(-)
Documentation/devicetree/bindings/gpio/gpio-xgene-sb.txt +40 -7
@@ -1,10 +1,20 @@ APM X-Gene Standby GPIO controller bindings -This is a gpio controller in the standby domain. - -There are 20 GPIO pins from 0..21. There is no GPIO_DS14 or GPIO_DS15, -only GPIO_DS8..GPIO_DS13 support interrupts. The IRQ mapping -is currently 1-to-1 on interrupts 0x28 thru 0x2d. +This is a gpio controller in the standby domain. It also supports interrupt in +some particular pins which are sourced to its parent interrupt controller +as diagram below: + +-----------------+ + | X-Gene standby | + | GPIO controller +--------- GPIO_0 ++------------+ | | ... +| Parent IRQ | | +--------- GPIO_8/EXT_INT_0 +| controller | EXT_INT_0 | | ... +| (GICv2) +-------------+ +--------- GPIO_[N+8]/EXT_INT_N +| | ... | | +| | EXT_INT_N | +--------- GPIO_[N+9] +| +-------------+ | ... +| | | +--------- GPIO_MAX ++------------+ +-----------------+ Required properties: - compatible: "apm,xgene-gpio-sb" for the X-Gene Standby GPIO controller
@@ -15,10 +25,18 @@ Required properties: 0 = active high 1 = active low - gpio-controller: Marks the device node as a GPIO controller. -- interrupts: Shall contain exactly 6 interrupts. +- interrupts: The EXT_INT_0 parent interrupt resource must be listed first. +- interrupt-parent: Phandle of the parent interrupt controller. +- interrupt-cells: Should be two. + - first cell is 0-N coresponding for EXT_INT_0 to EXT_INT_N. + - second cell is used to specify flags. +- interrupt-controller: Marks the device node as an interrupt controller. +- apm,nr-gpios: Optional, specify number of gpios pin. +- apm,nr-irqs: Optional, specify number of interrupt pins. +- apm,irq-start: Optional, specify lowest gpio pin support interrupt. Example: - sbgpio: sbgpio at 17001000 { + sbgpio: gpio at 17001000{ compatible = "apm,xgene-gpio-sb"; reg = <0x0 0x17001000 0x0 0x400>; #gpio-cells = <2>;
@@ -29,4 +47,19 @@ Example: <0x0 0x2b 0x1>, <0x0 0x2c 0x1>, <0x0 0x2d 0x1>; + interrupt-parent = <&gic>; + #interrupt-cells = <2>; + interrupt-controller; + apm,nr-gpios = <22>; + apm,nr-irqs = <6>; + apm,irq-start = <8>; + }; + + testuser { + compatible = "example,testuser"; + /* Use the GPIO_13/EXT_INT_5 line as an active high triggered + * level interrupt + */ + interrupts = <5 4>; + interrupt-parent = <&sbgpio>; };
Signature · 1 line
1.7.12.4
Rob Herring
maintainerPATCH v5 2/3 Documentation: gpio: Update description for X-Gene standby GPIO controller DTS binding
Quoted 42 lines · Quan Nguyen
Update description for X-Gene standby GPIO controller DTS binding to support GPIO line configuration as input, output or external IRQ pin.
Signed-off-by Y Vo <[email protected]>Signed-off-by Quan Nguyen <[email protected]>--- .../devicetree/bindings/gpio/gpio-xgene-sb.txt | 47 ++++++++++++++++++---- 1 file changed, 40 insertions(+), 7 deletions(-)Documentation/devicetree/bindings/gpio/gpio-xgene-sb.txt +15
-5@@ -1,10 +1,20 @@ APM X-Gene Standby GPIO controller bindings -This is a gpio controller in the standby domain. - -There are 20 GPIO pins from 0..21. There is no GPIO_DS14 or GPIO_DS15, -only GPIO_DS8..GPIO_DS13 support interrupts. The IRQ mapping -is currently 1-to-1 on interrupts 0x28 thru 0x2d. +This is a gpio controller in the standby domain. It also supports interrupt in +some particular pins which are sourced to its parent interrupt controller +as diagram below: + +-----------------+ + | X-Gene standby | + | GPIO controller +--------- GPIO_0 ++------------+ | | ... +| Parent IRQ | | +--------- GPIO_8/EXT_INT_0 +| controller | EXT_INT_0 | | ... +| (GICv2) +-------------+ +--------- GPIO_[N+8]/EXT_INT_N +| | ... | | +| | EXT_INT_N | +--------- GPIO_[N+9] +| +-------------+ | ... +| | | +--------- GPIO_MAX ++------------+ +-----------------+ Required properties: - compatible: "apm,xgene-gpio-sb" for the X-Gene Standby GPIO controller@@ -15,10 +25,18 @@ Required properties: 0 = active high 1 = active low
Documentation/devicetree/bindings/gpio/gpio-xgene-sb.txt Required properties: · line 35
Quoted 10 lines
Documentation/devicetree/bindings/gpio/gpio-xgene-sb.txt +8
-1- gpio-controller: Marks the device node as a GPIO controller. -- interrupts: Shall contain exactly 6 interrupts. +- interrupts: The EXT_INT_0 parent interrupt resource must be listed first. +- interrupt-parent: Phandle of the parent interrupt controller. +- interrupt-cells: Should be two. + - first cell is 0-N coresponding for EXT_INT_0 to EXT_INT_N. + - second cell is used to specify flags. +- interrupt-controller: Marks the device node as an interrupt controller. +- apm,nr-gpios: Optional, specify number of gpios pin. +- apm,nr-irqs: Optional, specify number of interrupt pins.
When is this not 6?
Documentation/devicetree/bindings/gpio/gpio-xgene-sb.txt Required properties: · line 36
Quoted 1 line
Documentation/devicetree/bindings/gpio/gpio-xgene-sb.txt +1
-0+- apm,irq-start: Optional, specify lowest gpio pin support interrupt.
What determines this value? What value is assumed if not present?
Rob
PATCH v5 2/3 Documentation: gpio: Update description for X-Gene standby GPIO controller DTS binding
Quoted 47 lines · Rob Herring
Quoted 46 lines · Quan Nguyen
Update description for X-Gene standby GPIO controller DTS binding to support GPIO line configuration as input, output or external IRQ pin.
Signed-off-by Y Vo <[email protected]>Signed-off-by Quan Nguyen <[email protected]>--- .../devicetree/bindings/gpio/gpio-xgene-sb.txt | 47 ++++++++++++++++++---- 1 file changed, 40 insertions(+), 7 deletions(-)Documentation/devicetree/bindings/gpio/gpio-xgene-sb.txt +17
-6@@ -1,10 +1,20 @@ APM X-Gene Standby GPIO controller bindings -This is a gpio controller in the standby domain. - -There are 20 GPIO pins from 0..21. There is no GPIO_DS14 or GPIO_DS15, -only GPIO_DS8..GPIO_DS13 support interrupts. The IRQ mapping -is currently 1-to-1 on interrupts 0x28 thru 0x2d. +This is a gpio controller in the standby domain. It also supports interrupt in +some particular pins which are sourced to its parent interrupt controller +as diagram below: + +-----------------+ + | X-Gene standby | + | GPIO controller +--------- GPIO_0 ++------------+ | | ... +| Parent IRQ | | +--------- GPIO_8/EXT_INT_0 +| controller | EXT_INT_0 | | ... +| (GICv2) +-------------+ +--------- GPIO_[N+8]/EXT_INT_N +| | ... | | +| | EXT_INT_N | +--------- GPIO_[N+9] +| +-------------+ | ... +| | | +--------- GPIO_MAX ++------------+ +-----------------+ Required properties: - compatible: "apm,xgene-gpio-sb" for the X-Gene Standby GPIO controller@@ -15,10 +25,18 @@ Required properties: 0 = active high 1 = active low - gpio-controller: Marks the device node as a GPIO controller. -- interrupts: Shall contain exactly 6 interrupts. +- interrupts: The EXT_INT_0 parent interrupt resource must be listed first. +- interrupt-parent: Phandle of the parent interrupt controller.
Quoted 9 lines
Documentation/devicetree/bindings/gpio/gpio-xgene-sb.txt Required properties: · line 35
Quoted 6 lines
Documentation/devicetree/bindings/gpio/gpio-xgene-sb.txt +6
-0+- interrupt-cells: Should be two. + - first cell is 0-N coresponding for EXT_INT_0 to EXT_INT_N. + - second cell is used to specify flags. +- interrupt-controller: Marks the device node as an interrupt controller. +- apm,nr-gpios: Optional, specify number of gpios pin. +- apm,nr-irqs: Optional, specify number of interrupt pins.When is this not 6?
Hi Rob, by default, this should be 6, but I think this property can help in cases:
+ Used only 5(or less) first pin as interrupt.
+ For similar device which has different interrupt pins (8 for example). My idea is to make it a bit more generic by using this optional property.
Quoted 4 lines
Documentation/devicetree/bindings/gpio/gpio-xgene-sb.txt Required properties: · line 36
Quoted 1 line
Documentation/devicetree/bindings/gpio/gpio-xgene-sb.txt +1
-0+- apm,irq-start: Optional, specify lowest gpio pin support interrupt.What determines this value? What value is assumed if not present?
This value will tell interrupt is support from which gpio pin, as in this case interrupt support from pin 8 (ie: only pin 8, 9,10 ... supports interrupt) as default.
If not specify the default (ie: 8) will be used.
Thanks,
-- Quan Nguyen
Rob Herring
maintainerPATCH v5 2/3 Documentation: gpio: Update description for X-Gene standby GPIO controller DTS binding
Quoted 57 lines · Quan Nguyen
Quoted 47 lines · Rob Herring
Quoted 46 lines · Quan Nguyen
Update description for X-Gene standby GPIO controller DTS binding to support GPIO line configuration as input, output or external IRQ pin.
Signed-off-by Y Vo <[email protected]>Signed-off-by Quan Nguyen <[email protected]>--- .../devicetree/bindings/gpio/gpio-xgene-sb.txt | 47 ++++++++++++++++++---- 1 file changed, 40 insertions(+), 7 deletions(-)Documentation/devicetree/bindings/gpio/gpio-xgene-sb.txt +17
-6@@ -1,10 +1,20 @@ APM X-Gene Standby GPIO controller bindings -This is a gpio controller in the standby domain. - -There are 20 GPIO pins from 0..21. There is no GPIO_DS14 or GPIO_DS15, -only GPIO_DS8..GPIO_DS13 support interrupts. The IRQ mapping -is currently 1-to-1 on interrupts 0x28 thru 0x2d. +This is a gpio controller in the standby domain. It also supports interrupt in +some particular pins which are sourced to its parent interrupt controller +as diagram below: + +-----------------+ + | X-Gene standby | + | GPIO controller +--------- GPIO_0 ++------------+ | | ... +| Parent IRQ | | +--------- GPIO_8/EXT_INT_0 +| controller | EXT_INT_0 | | ... +| (GICv2) +-------------+ +--------- GPIO_[N+8]/EXT_INT_N +| | ... | | +| | EXT_INT_N | +--------- GPIO_[N+9] +| +-------------+ | ... +| | | +--------- GPIO_MAX ++------------+ +-----------------+ Required properties: - compatible: "apm,xgene-gpio-sb" for the X-Gene Standby GPIO controller@@ -15,10 +25,18 @@ Required properties: 0 = active high 1 = active low - gpio-controller: Marks the device node as a GPIO controller. -- interrupts: Shall contain exactly 6 interrupts. +- interrupts: The EXT_INT_0 parent interrupt resource must be listed first. +- interrupt-parent: Phandle of the parent interrupt controller.Quoted 9 lines
Documentation/devicetree/bindings/gpio/gpio-xgene-sb.txt Required properties: · line 35
Quoted 6 lines
Documentation/devicetree/bindings/gpio/gpio-xgene-sb.txt +6
-0+- interrupt-cells: Should be two. + - first cell is 0-N coresponding for EXT_INT_0 to EXT_INT_N. + - second cell is used to specify flags. +- interrupt-controller: Marks the device node as an interrupt controller. +- apm,nr-gpios: Optional, specify number of gpios pin. +- apm,nr-irqs: Optional, specify number of interrupt pins.When is this not 6?
Quoted 5 lines
Hi Rob, by default, this should be 6, but I think this property can help in cases:
+ Used only 5(or less) first pin as interrupt.
+ For similar device which has different interrupt pins (8 for example). My idea is to make it a bit more generic by using this optional property.
What is similar device? Another SoC? board? Is 6 fixed in the SoC? I think you need more specific compatible string with the SoC name in it to determine these setting rather than trying to do something generic.
Rob
PATCH v5 2/3 Documentation: gpio: Update description for X-Gene standby GPIO controller DTS binding
Quoted 64 lines · Rob Herring
Quoted 57 lines · Quan Nguyen
Quoted 47 lines · Rob Herring
Quoted 46 lines · Quan Nguyen
Update description for X-Gene standby GPIO controller DTS binding to support GPIO line configuration as input, output or external IRQ pin.
Signed-off-by Y Vo <[email protected]>Signed-off-by Quan Nguyen <[email protected]>--- .../devicetree/bindings/gpio/gpio-xgene-sb.txt | 47 ++++++++++++++++++---- 1 file changed, 40 insertions(+), 7 deletions(-)Documentation/devicetree/bindings/gpio/gpio-xgene-sb.txt +17
-6@@ -1,10 +1,20 @@ APM X-Gene Standby GPIO controller bindings -This is a gpio controller in the standby domain. - -There are 20 GPIO pins from 0..21. There is no GPIO_DS14 or GPIO_DS15, -only GPIO_DS8..GPIO_DS13 support interrupts. The IRQ mapping -is currently 1-to-1 on interrupts 0x28 thru 0x2d. +This is a gpio controller in the standby domain. It also supports interrupt in +some particular pins which are sourced to its parent interrupt controller +as diagram below: + +-----------------+ + | X-Gene standby | + | GPIO controller +--------- GPIO_0 ++------------+ | | ... +| Parent IRQ | | +--------- GPIO_8/EXT_INT_0 +| controller | EXT_INT_0 | | ... +| (GICv2) +-------------+ +--------- GPIO_[N+8]/EXT_INT_N +| | ... | | +| | EXT_INT_N | +--------- GPIO_[N+9] +| +-------------+ | ... +| | | +--------- GPIO_MAX ++------------+ +-----------------+ Required properties: - compatible: "apm,xgene-gpio-sb" for the X-Gene Standby GPIO controller@@ -15,10 +25,18 @@ Required properties: 0 = active high 1 = active low - gpio-controller: Marks the device node as a GPIO controller. -- interrupts: Shall contain exactly 6 interrupts. +- interrupts: The EXT_INT_0 parent interrupt resource must be listed first. +- interrupt-parent: Phandle of the parent interrupt controller.Quoted 9 lines
Documentation/devicetree/bindings/gpio/gpio-xgene-sb.txt Required properties: · line 35
Quoted 6 lines
Documentation/devicetree/bindings/gpio/gpio-xgene-sb.txt +6
-0+- interrupt-cells: Should be two. + - first cell is 0-N coresponding for EXT_INT_0 to EXT_INT_N. + - second cell is used to specify flags. +- interrupt-controller: Marks the device node as an interrupt controller. +- apm,nr-gpios: Optional, specify number of gpios pin. +- apm,nr-irqs: Optional, specify number of interrupt pins.When is this not 6?
Quoted 5 lines
Hi Rob, by default, this should be 6, but I think this property can help in cases:
+ Used only 5(or less) first pin as interrupt.
+ For similar device which has different interrupt pins (8 for example). My idea is to make it a bit more generic by using this optional property.
Quoted 4 lines
What is similar device? Another SoC? board? Is 6 fixed in the SoC? I think you need more specific compatible string with the SoC name in it to determine these setting rather than trying to do something generic.
I agree, Rob, compatible string should be suit for other SoC, but I think we still need this property for case of less than 6 interrupts are needed.
Thanks,
-- Quan Nguyen
PATCH v5 3/3 arm64: dts: Update X-Gene standby GPIO controller DTS entries
In reply to Quan NguyenUpdate APM X-Gene standby GPIO controller DTS entries to enable it as interrupt controller.
--- arch/arm64/boot/dts/apm/apm-storm.dtsi | 3 +++ 1 file changed, 3 insertions(+)
arch/arm64/boot/dts/apm/apm-storm.dtsi +3 -0
@@ -883,6 +883,9 @@ <0x0 0x2b 0x1>, <0x0 0x2c 0x1>, <0x0 0x2d 0x1>; + interrupt-parent = <&gic>; + #interrupt-cells = <2>; + interrupt-controller; }; rtc: rtc at 10510000 {
Signature · 1 line
1.7.12.4