linux-gpio.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2] gpio: pl061: Support implementations without GPIOINTR line
@ 2021-03-18 19:10 Alexander A Sverdlin
  2021-03-18 22:17 ` kernel test robot
  2021-03-18 22:26 ` kernel test robot
  0 siblings, 2 replies; 3+ messages in thread
From: Alexander A Sverdlin @ 2021-03-18 19:10 UTC (permalink / raw)
  To: linux-gpio
  Cc: Alexander Sverdlin, Linus Walleij, Bartosz Golaszewski,
	linux-kernel, Andy Shevchenko

From: Alexander Sverdlin <alexander.sverdlin@nokia.com>

There are several implementations of PL061 which lack GPIOINTR signal in
hardware and only have individual GPIOMIS[7:0] interrupts. Use the
hierarchical interrupt support of the gpiolib in these cases (if at least 8
IRQs are configured for the PL061).

One in-tree example is arch/arm/boot/dts/axm55xx.dtsi, PL061 instances have
8 IRQs defined, but current driver supports only the first one, so only one
pin would work as IRQ trigger.

Link: https://lore.kernel.org/linux-gpio/CACRpkdZpYzpMDWqJobSYH=JHgB74HbCQihOtexs+sVyo6SRJdA@mail.gmail.com/
Signed-off-by: Alexander Sverdlin <alexander.sverdlin@nokia.com>
---
Changelog:
v2: Add pl061_populate_parent_fwspec()

 drivers/gpio/Kconfig      |  1 +
 drivers/gpio/gpio-pl061.c | 91 +++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 85 insertions(+), 7 deletions(-)

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index e3607ec..456c0a5 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -469,6 +469,7 @@ config GPIO_PL061
 	depends on ARM_AMBA
 	select IRQ_DOMAIN
 	select GPIOLIB_IRQCHIP
+	select IRQ_DOMAIN_HIERARCHY
 	help
 	  Say yes here to support the PrimeCell PL061 GPIO device
 
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index f1b53dd..e95714a 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/pm.h>
+#include <linux/of_irq.h>
 
 #define GPIODIR 0x400
 #define GPIOIS  0x404
@@ -283,6 +284,64 @@ static int pl061_irq_set_wake(struct irq_data *d, unsigned int state)
 	return irq_set_irq_wake(pl061->parent_irq, state);
 }
 
+static int pl061_child_to_parent_hwirq(struct gpio_chip *gc, unsigned int child,
+				       unsigned int child_type,
+				       unsigned int *parent,
+				       unsigned int *parent_type)
+{
+	struct amba_device *adev = to_amba_device(gc->parent);
+	unsigned int irq = adev->irq[child];
+	struct irq_data *d = irq_get_irq_data(irq);
+
+	if (!d)
+		return -EINVAL;
+
+	*parent_type = irqd_get_trigger_type(d);
+	*parent = irqd_to_hwirq(d);
+	return 0;
+}
+
+#ifdef CONFIG_OF
+void pl061_populate_parent_fwspec(struct gpio_chip *gc,
+				  struct irq_fwspec *fwspec,
+				  unsigned int parent_hwirq,
+				  unsigned int parent_type)
+{
+	struct device_node *dn = to_of_node(gc->irq.fwnode);
+	struct of_phandle_args pha;
+	int i;
+
+	fwspec->param_count = 0;
+
+	if (WARN_ON(!dn))
+		return;
+
+	/*
+	 * This brute-force here is because of the fact PL061 is often paired
+	 * with GIC-v3, which has 3-cell IRQ specifier (SPI/PPI selection), and
+	 * unexpected range shifts in hwirq mapping (SPI IRQs are shifted by
+	 * 32). So this is about reversing of gic_irq_domain_translate().
+	 */
+	for (i = 0; i < PL061_GPIO_NR; i++) {
+		unsigned int p, pt;
+
+		if (pl061_child_to_parent_hwirq(gc, i, parent_type, &p, &pt))
+			continue;
+		if (p == parent_hwirq)
+			break;
+	}
+	if (WARN_ON(i == PL061_GPIO_NR))
+		return;
+
+	if (WARN_ON(of_irq_parse_one(dn, i, &pha)))
+		return;
+
+	fwspec->param_count = pha.args_count;
+	for (i = 0; i < pha.args_count; i++)
+		fwspec->param[i] = pha.args[i];
+}
+#endif
+
 static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
 {
 	struct device *dev = &adev->dev;
@@ -330,16 +389,34 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
 
 	girq = &pl061->gc.irq;
 	girq->chip = &pl061->irq_chip;
-	girq->parent_handler = pl061_irq_handler;
-	girq->num_parents = 1;
-	girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
-				     GFP_KERNEL);
-	if (!girq->parents)
-		return -ENOMEM;
-	girq->parents[0] = irq;
 	girq->default_type = IRQ_TYPE_NONE;
 	girq->handler = handle_bad_irq;
 
+	/*
+	 * There are some PL061 implementations which lack GPIOINTR in hardware
+	 * and only have individual GPIOMIS[7:0] signals. We distinguish them by
+	 * the number of IRQs assigned to the AMBA device.
+	 */
+	if (!adev->irq[PL061_GPIO_NR - 1]) {
+		WARN_ON(adev->irq[1]);
+
+		girq->parent_handler = pl061_irq_handler;
+		girq->num_parents = 1;
+		girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
+					     GFP_KERNEL);
+		if (!girq->parents)
+			return -ENOMEM;
+		girq->parents[0] = irq;
+	} else {
+		girq->fwnode = dev->fwnode;
+		girq->parent_domain =
+			irq_get_irq_data(adev->irq[PL061_GPIO_NR - 1])->domain;
+		girq->child_to_parent_hwirq = pl061_child_to_parent_hwirq;
+#ifdef CONFIG_OF
+		girq->populate_parent_fwspec = pl061_populate_parent_fwspec;
+#endif
+	}
+
 	ret = devm_gpiochip_add_data(dev, &pl061->gc, pl061);
 	if (ret)
 		return ret;
-- 
2.10.2


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH v2] gpio: pl061: Support implementations without GPIOINTR line
  2021-03-18 19:10 [PATCH v2] gpio: pl061: Support implementations without GPIOINTR line Alexander A Sverdlin
@ 2021-03-18 22:17 ` kernel test robot
  2021-03-18 22:26 ` kernel test robot
  1 sibling, 0 replies; 3+ messages in thread
From: kernel test robot @ 2021-03-18 22:17 UTC (permalink / raw)
  To: Alexander A Sverdlin, linux-gpio
  Cc: kbuild-all, Alexander Sverdlin, Linus Walleij,
	Bartosz Golaszewski, linux-kernel, Andy Shevchenko

[-- Attachment #1: Type: text/plain, Size: 6576 bytes --]

Hi Alexander,

I love your patch! Yet something to improve:

[auto build test ERROR on gpio/for-next]
[also build test ERROR on v5.12-rc3 next-20210318]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Alexander-A-Sverdlin/gpio-pl061-Support-implementations-without-GPIOINTR-line/20210319-031352
base:   https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git for-next
config: arm-randconfig-r006-20210318 (attached as .config)
compiler: arm-linux-gnueabi-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/bbac642db33d1e12c5a11a9630822bf16706c988
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Alexander-A-Sverdlin/gpio-pl061-Support-implementations-without-GPIOINTR-line/20210319-031352
        git checkout bbac642db33d1e12c5a11a9630822bf16706c988
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arm 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All error/warnings (new ones prefixed by >>):

>> drivers/gpio/gpio-pl061.c:305:6: warning: no previous prototype for 'pl061_populate_parent_fwspec' [-Wmissing-prototypes]
     305 | void pl061_populate_parent_fwspec(struct gpio_chip *gc,
         |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/gpio/gpio-pl061.c: In function 'pl061_probe':
>> drivers/gpio/gpio-pl061.c:416:9: error: 'struct gpio_irq_chip' has no member named 'populate_parent_fwspec'; did you mean 'populate_parent_alloc_arg'?
     416 |   girq->populate_parent_fwspec = pl061_populate_parent_fwspec;
         |         ^~~~~~~~~~~~~~~~~~~~~~
         |         populate_parent_alloc_arg


vim +416 drivers/gpio/gpio-pl061.c

   303	
   304	#ifdef CONFIG_OF
 > 305	void pl061_populate_parent_fwspec(struct gpio_chip *gc,
   306					  struct irq_fwspec *fwspec,
   307					  unsigned int parent_hwirq,
   308					  unsigned int parent_type)
   309	{
   310		struct device_node *dn = to_of_node(gc->irq.fwnode);
   311		struct of_phandle_args pha;
   312		int i;
   313	
   314		fwspec->param_count = 0;
   315	
   316		if (WARN_ON(!dn))
   317			return;
   318	
   319		/*
   320		 * This brute-force here is because of the fact PL061 is often paired
   321		 * with GIC-v3, which has 3-cell IRQ specifier (SPI/PPI selection), and
   322		 * unexpected range shifts in hwirq mapping (SPI IRQs are shifted by
   323		 * 32). So this is about reversing of gic_irq_domain_translate().
   324		 */
   325		for (i = 0; i < PL061_GPIO_NR; i++) {
   326			unsigned int p, pt;
   327	
   328			if (pl061_child_to_parent_hwirq(gc, i, parent_type, &p, &pt))
   329				continue;
   330			if (p == parent_hwirq)
   331				break;
   332		}
   333		if (WARN_ON(i == PL061_GPIO_NR))
   334			return;
   335	
   336		if (WARN_ON(of_irq_parse_one(dn, i, &pha)))
   337			return;
   338	
   339		fwspec->param_count = pha.args_count;
   340		for (i = 0; i < pha.args_count; i++)
   341			fwspec->param[i] = pha.args[i];
   342	}
   343	#endif
   344	
   345	static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
   346	{
   347		struct device *dev = &adev->dev;
   348		struct pl061 *pl061;
   349		struct gpio_irq_chip *girq;
   350		int ret, irq;
   351	
   352		pl061 = devm_kzalloc(dev, sizeof(*pl061), GFP_KERNEL);
   353		if (pl061 == NULL)
   354			return -ENOMEM;
   355	
   356		pl061->base = devm_ioremap_resource(dev, &adev->res);
   357		if (IS_ERR(pl061->base))
   358			return PTR_ERR(pl061->base);
   359	
   360		raw_spin_lock_init(&pl061->lock);
   361		pl061->gc.request = gpiochip_generic_request;
   362		pl061->gc.free = gpiochip_generic_free;
   363		pl061->gc.base = -1;
   364		pl061->gc.get_direction = pl061_get_direction;
   365		pl061->gc.direction_input = pl061_direction_input;
   366		pl061->gc.direction_output = pl061_direction_output;
   367		pl061->gc.get = pl061_get_value;
   368		pl061->gc.set = pl061_set_value;
   369		pl061->gc.ngpio = PL061_GPIO_NR;
   370		pl061->gc.label = dev_name(dev);
   371		pl061->gc.parent = dev;
   372		pl061->gc.owner = THIS_MODULE;
   373	
   374		/*
   375		 * irq_chip support
   376		 */
   377		pl061->irq_chip.name = dev_name(dev);
   378		pl061->irq_chip.irq_ack	= pl061_irq_ack;
   379		pl061->irq_chip.irq_mask = pl061_irq_mask;
   380		pl061->irq_chip.irq_unmask = pl061_irq_unmask;
   381		pl061->irq_chip.irq_set_type = pl061_irq_type;
   382		pl061->irq_chip.irq_set_wake = pl061_irq_set_wake;
   383	
   384		writeb(0, pl061->base + GPIOIE); /* disable irqs */
   385		irq = adev->irq[0];
   386		if (!irq)
   387			dev_warn(&adev->dev, "IRQ support disabled\n");
   388		pl061->parent_irq = irq;
   389	
   390		girq = &pl061->gc.irq;
   391		girq->chip = &pl061->irq_chip;
   392		girq->default_type = IRQ_TYPE_NONE;
   393		girq->handler = handle_bad_irq;
   394	
   395		/*
   396		 * There are some PL061 implementations which lack GPIOINTR in hardware
   397		 * and only have individual GPIOMIS[7:0] signals. We distinguish them by
   398		 * the number of IRQs assigned to the AMBA device.
   399		 */
   400		if (!adev->irq[PL061_GPIO_NR - 1]) {
   401			WARN_ON(adev->irq[1]);
   402	
   403			girq->parent_handler = pl061_irq_handler;
   404			girq->num_parents = 1;
   405			girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
   406						     GFP_KERNEL);
   407			if (!girq->parents)
   408				return -ENOMEM;
   409			girq->parents[0] = irq;
   410		} else {
   411			girq->fwnode = dev->fwnode;
   412			girq->parent_domain =
   413				irq_get_irq_data(adev->irq[PL061_GPIO_NR - 1])->domain;
   414			girq->child_to_parent_hwirq = pl061_child_to_parent_hwirq;
   415	#ifdef CONFIG_OF
 > 416			girq->populate_parent_fwspec = pl061_populate_parent_fwspec;
   417	#endif
   418		}
   419	
   420		ret = devm_gpiochip_add_data(dev, &pl061->gc, pl061);
   421		if (ret)
   422			return ret;
   423	
   424		amba_set_drvdata(adev, pl061);
   425		dev_info(dev, "PL061 GPIO chip registered\n");
   426	
   427		return 0;
   428	}
   429	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 35308 bytes --]

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v2] gpio: pl061: Support implementations without GPIOINTR line
  2021-03-18 19:10 [PATCH v2] gpio: pl061: Support implementations without GPIOINTR line Alexander A Sverdlin
  2021-03-18 22:17 ` kernel test robot
@ 2021-03-18 22:26 ` kernel test robot
  1 sibling, 0 replies; 3+ messages in thread
From: kernel test robot @ 2021-03-18 22:26 UTC (permalink / raw)
  To: Alexander A Sverdlin, linux-gpio
  Cc: kbuild-all, Alexander Sverdlin, Linus Walleij,
	Bartosz Golaszewski, linux-kernel, Andy Shevchenko

[-- Attachment #1: Type: text/plain, Size: 3583 bytes --]

Hi Alexander,

I love your patch! Perhaps something to improve:

[auto build test WARNING on gpio/for-next]
[also build test WARNING on v5.12-rc3 next-20210318]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Alexander-A-Sverdlin/gpio-pl061-Support-implementations-without-GPIOINTR-line/20210319-031352
base:   https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git for-next
config: arm-defconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/bbac642db33d1e12c5a11a9630822bf16706c988
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Alexander-A-Sverdlin/gpio-pl061-Support-implementations-without-GPIOINTR-line/20210319-031352
        git checkout bbac642db33d1e12c5a11a9630822bf16706c988
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arm 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> drivers/gpio/gpio-pl061.c:305:6: warning: no previous prototype for 'pl061_populate_parent_fwspec' [-Wmissing-prototypes]
     305 | void pl061_populate_parent_fwspec(struct gpio_chip *gc,
         |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/gpio/gpio-pl061.c: In function 'pl061_probe':
   drivers/gpio/gpio-pl061.c:416:9: error: 'struct gpio_irq_chip' has no member named 'populate_parent_fwspec'; did you mean 'populate_parent_alloc_arg'?
     416 |   girq->populate_parent_fwspec = pl061_populate_parent_fwspec;
         |         ^~~~~~~~~~~~~~~~~~~~~~
         |         populate_parent_alloc_arg


vim +/pl061_populate_parent_fwspec +305 drivers/gpio/gpio-pl061.c

   303	
   304	#ifdef CONFIG_OF
 > 305	void pl061_populate_parent_fwspec(struct gpio_chip *gc,
   306					  struct irq_fwspec *fwspec,
   307					  unsigned int parent_hwirq,
   308					  unsigned int parent_type)
   309	{
   310		struct device_node *dn = to_of_node(gc->irq.fwnode);
   311		struct of_phandle_args pha;
   312		int i;
   313	
   314		fwspec->param_count = 0;
   315	
   316		if (WARN_ON(!dn))
   317			return;
   318	
   319		/*
   320		 * This brute-force here is because of the fact PL061 is often paired
   321		 * with GIC-v3, which has 3-cell IRQ specifier (SPI/PPI selection), and
   322		 * unexpected range shifts in hwirq mapping (SPI IRQs are shifted by
   323		 * 32). So this is about reversing of gic_irq_domain_translate().
   324		 */
   325		for (i = 0; i < PL061_GPIO_NR; i++) {
   326			unsigned int p, pt;
   327	
   328			if (pl061_child_to_parent_hwirq(gc, i, parent_type, &p, &pt))
   329				continue;
   330			if (p == parent_hwirq)
   331				break;
   332		}
   333		if (WARN_ON(i == PL061_GPIO_NR))
   334			return;
   335	
   336		if (WARN_ON(of_irq_parse_one(dn, i, &pha)))
   337			return;
   338	
   339		fwspec->param_count = pha.args_count;
   340		for (i = 0; i < pha.args_count; i++)
   341			fwspec->param[i] = pha.args[i];
   342	}
   343	#endif
   344	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 53830 bytes --]

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2021-03-18 22:27 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-03-18 19:10 [PATCH v2] gpio: pl061: Support implementations without GPIOINTR line Alexander A Sverdlin
2021-03-18 22:17 ` kernel test robot
2021-03-18 22:26 ` kernel test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).