ARM Sunxi Platform Development
 help / color / mirror / Atom feed
From: Enzo Adriano <enzo.adriano.code@gmail.com>
To: Andre Przywara <andre.przywara@arm.com>
Cc: linux-sunxi@lists.linux.dev, Enzo Adriano <enzo.adriano.code@gmail.com>
Subject: [PATCH] pinctrl: sunxi: fix EINT bank indexing for SoCs with empty leading banks
Date: Fri,  3 Jul 2026 23:08:21 -0400	[thread overview]
Message-ID: <20260704030821.561389-1-enzo.adriano.code@gmail.com> (raw)

The DT-table init assigns interrupt bank indices by incrementing on
every bank transition, starting from bank 0 - correct only when bank
A actually has pins. On the A733 bank A is empty, so every EINT bank
got an index one too high: the per-bank parent interrupt was taken
from the next bank's slot in the DT list (bank K falling off the end
entirely), while the EINT registers were still addressed correctly
only because the shifted index happened to coincide with the pin-bank
number under the NCAT3 layout.

Assign 0-based indices over the IRQ-capable banks that actually have
pins, record the pin bank each index refers to in an irq_bank_map,
and honour that map in the NCAT3 register-base formula the same way
the legacy layout already does.

On the Cubie A7S this makes a PB EINT consumer raise its events on
GPIOB's interrupt line instead of GPIOC's - the previously observed
'bank-B IRQ storm' with gpio-keys was the unclaimed GPIOB line
screaming while the handler listened one bank up.

Assisted-by: Claude-Code:claude-fable-5
Signed-off-by: Enzo Adriano <enzo.adriano.code@gmail.com>
---
Andre,

This sits on top of your (as-yet unmerged) A733/NCAT3 pinctrl series -
it does not apply to mainline on its own, so it is offered for you to
fold into your v2 rather than as a standalone submission. I found the
off-by-one while bringing up EINTs on the Cubie A7S; it retroactively
explains the bank-B "IRQ storm" you may have seen with gpio-keys.

Not marked Tested-by: the register-addressing and DT-list reasoning is
confirmed by inspection and the IRQ-line behaviour was observed on
hardware, but a clean end-to-end EINT boot is still blocked on an
unrelated DVFS-lane instability on my tree, so I do not want to
overclaim. Take it, adapt it, or drop it as you see fit for v2.

 drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c | 34 +++++++++++++++++-------
 drivers/pinctrl/sunxi/pinctrl-sunxi.h    |  5 ++--
 2 files changed, 28 insertions(+), 11 deletions(-)

diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c b/drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c
index 50a16f3bd..e0036df81 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c
@@ -143,12 +143,14 @@ static struct sunxi_desc_pin *init_pins_table(struct device *dev,
  */
 static int prepare_function_table(struct device *dev, struct device_node *pnode,
 				  struct sunxi_desc_pin *pins, int npins,
-				  unsigned pin_base, const u8 *irq_bank_muxes)
+				  unsigned int pin_base, const u8 *irq_bank_muxes,
+				  struct sunxi_pinctrl_desc *desc)
 {
 	struct device_node *node;
 	struct property *prop;
 	struct sunxi_desc_function *func;
-	int num_funcs, irq_bank, last_bank, i;
+	unsigned int *irq_bank_map;
+	int num_funcs, irq_bank, last_irq_bank, i;
 
 	/*
 	 * We need at least three functions per pin:
@@ -207,8 +209,20 @@ static int prepare_function_table(struct device *dev, struct device_node *pnode,
 	 * Assign the function's memory and fill in GPIOs, IRQ and a sentinel.
 	 * The extra functions will be filled in later.
 	 */
-	irq_bank = 0;
-	last_bank = 0;
+	/*
+	 * The interrupt bank index selects both the per-bank parent
+	 * interrupt (the DT lists one per IRQ-capable bank, in order)
+	 * and, through irq_bank_map, the pin bank holding the EINT
+	 * registers. The first IRQ-capable bank with any pins must get
+	 * index 0 even when lower banks (like PA here) have no pins.
+	 */
+	irq_bank_map = devm_kcalloc(dev, SUNXI_PINCTRL_MAX_BANKS,
+				    sizeof(*irq_bank_map), GFP_KERNEL);
+	if (!irq_bank_map)
+		return -ENOMEM;
+
+	irq_bank = -1;
+	last_irq_bank = -1;
 	for (i = 0; i < npins; i++) {
 		struct sunxi_desc_pin *pin = &pins[i];
 		int bank = (pin->pin.number - pin_base) / PINS_PER_BANK;
@@ -221,17 +235,17 @@ static int prepare_function_table(struct device *dev, struct device_node *pnode,
 		func[1].muxval = 1;
 
 		if (irq_mux) {
-			if (bank > last_bank)
+			if (bank != last_irq_bank) {
 				irq_bank++;
+				irq_bank_map[irq_bank] = bank;
+				last_irq_bank = bank;
+			}
 			func[lastfunc].muxval = irq_mux;
 			func[lastfunc].irqbank = irq_bank;
 			func[lastfunc].irqnum = pin->pin.number % PINS_PER_BANK;
 			func[lastfunc].name = "irq";
 		}
 
-		if (bank > last_bank)
-			last_bank = bank;
-
 		pin->functions = func;
 
 		/* Skip over the other needed functions and the sentinel. */
@@ -244,6 +258,8 @@ static int prepare_function_table(struct device *dev, struct device_node *pnode,
 		pin->variant = 2;
 	}
 
+	desc->irq_bank_map = irq_bank_map;
+
 	return 0;
 }
 
@@ -352,7 +368,7 @@ int sunxi_pinctrl_dt_table_init(struct platform_device *pdev,
 		return PTR_ERR(pins);
 
 	ret = prepare_function_table(&pdev->dev, pnode, pins, desc->npins,
-				     desc->pin_base, irq_bank_muxes);
+				     desc->pin_base, irq_bank_muxes, desc);
 	if (ret)
 		return ret;
 
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
index 699ae8850..9aab94601 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
@@ -252,8 +252,9 @@ static inline u32 sunxi_irq_hw_bank_num(const struct sunxi_pinctrl_desc *desc,
 static inline u32 sunxi_irq_base_reg(const struct sunxi_pinctrl *pctl, u16 bank)
 {
 	if (pctl->flags & SUNXI_PINCTRL_NCAT3_REG_LAYOUT)
-		return pctl->bank_offset + bank * pctl->bank_mem_size +
-		       A733_IRQ_REGS_OFFSET;
+		return pctl->bank_offset +
+		       sunxi_irq_hw_bank_num(pctl->desc, bank) *
+		       pctl->bank_mem_size + A733_IRQ_REGS_OFFSET;
 
 	return IRQ_REGS_OFFSET +
 	       sunxi_irq_hw_bank_num(pctl->desc, bank) * IRQ_MEM_SIZE;
-- 
2.53.0


                 reply	other threads:[~2026-07-04  3:08 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260704030821.561389-1-enzo.adriano.code@gmail.com \
    --to=enzo.adriano.code@gmail.com \
    --cc=andre.przywara@arm.com \
    --cc=linux-sunxi@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox