* [PATCH v5 0/1] Add EINT support for multiple addresses
@ 2025-03-22 3:52 Hao Chang
2025-03-22 3:52 ` [PATCH v5 1/1] pinctrl: mediatek: " Hao Chang
0 siblings, 1 reply; 5+ messages in thread
From: Hao Chang @ 2025-03-22 3:52 UTC (permalink / raw)
To: Sean Wang, Linus Walleij, Matthias Brugger,
AngeloGioacchino Del Regno
Cc: Wenbin Mei, Axe Yang, Qingliang Li, Hanks Chen, Chunhui Li,
linux-mediatek, linux-gpio, linux-kernel, linux-arm-kernel,
Hao Chang
v5 changes:
1)Upload common code and remove irrelevant ones
2)Add pin list to find eint number
v4 changes:
1)Add err statement for exception handling
2)Add check for invalid pins
3)Use defined eint pins
v3 changes:
1)Add error judgment
v2 changes:
1)Remove instance structure
2)Modify the way to obtain eint address
Hao Chang (1):
pinctrl: mediatek: Add EINT support for multiple addresses
drivers/pinctrl/mediatek/mtk-eint.c | 313 +++++++++++-------
drivers/pinctrl/mediatek/mtk-eint.h | 23 +-
.../pinctrl/mediatek/pinctrl-mtk-common-v2.c | 37 ++-
.../pinctrl/mediatek/pinctrl-mtk-common-v2.h | 1 +
drivers/pinctrl/mediatek/pinctrl-paris.h | 7 +
5 files changed, 254 insertions(+), 127 deletions(-)
--
2.46.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v5 1/1] pinctrl: mediatek: Add EINT support for multiple addresses
2025-03-22 3:52 [PATCH v5 0/1] Add EINT support for multiple addresses Hao Chang
@ 2025-03-22 3:52 ` Hao Chang
2025-03-24 7:53 ` Linus Walleij
2025-04-14 14:57 ` Uwe Kleine-König
0 siblings, 2 replies; 5+ messages in thread
From: Hao Chang @ 2025-03-22 3:52 UTC (permalink / raw)
To: Sean Wang, Linus Walleij, Matthias Brugger,
AngeloGioacchino Del Regno
Cc: Wenbin Mei, Axe Yang, Qingliang Li, Hanks Chen, Chunhui Li,
linux-mediatek, linux-gpio, linux-kernel, linux-arm-kernel,
Hao Chang
For flexible routing, eint will be divided into 5 bases,
and it will obtain the operation address through the pins array.
Signed-off-by: Hao Chang <ot_chhao.chang@mediatek.com>
Signed-off-by: Qingliang Li <qingliang.li@mediatek.com>
---
drivers/pinctrl/mediatek/mtk-eint.c | 313 +++++++++++-------
drivers/pinctrl/mediatek/mtk-eint.h | 23 +-
.../pinctrl/mediatek/pinctrl-mtk-common-v2.c | 37 ++-
.../pinctrl/mediatek/pinctrl-mtk-common-v2.h | 1 +
drivers/pinctrl/mediatek/pinctrl-paris.h | 7 +
5 files changed, 254 insertions(+), 127 deletions(-)
diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c
index 27f0a54e12bf..ced4ee509b5b 100644
--- a/drivers/pinctrl/mediatek/mtk-eint.c
+++ b/drivers/pinctrl/mediatek/mtk-eint.c
@@ -1,11 +1,13 @@
// SPDX-License-Identifier: GPL-2.0
-// Copyright (c) 2014-2018 MediaTek Inc.
+// Copyright (c) 2014-2025 MediaTek Inc.
/*
* Library for MediaTek External Interrupt Support
*
* Author: Maoguang Meng <maoguang.meng@mediatek.com>
* Sean Wang <sean.wang@mediatek.com>
+ * Hao Chang <ot_chhao.chang@mediatek.com>
+ * Qingliang Li <qingliang.li@mediatek.com>
*
*/
@@ -20,6 +22,7 @@
#include <linux/platform_device.h>
#include "mtk-eint.h"
+#include "pinctrl-mtk-common-v2.h"
#define MTK_EINT_EDGE_SENSITIVE 0
#define MTK_EINT_LEVEL_SENSITIVE 1
@@ -68,13 +71,11 @@ static void __iomem *mtk_eint_get_offset(struct mtk_eint *eint,
unsigned int eint_num,
unsigned int offset)
{
- unsigned int eint_base = 0;
+ unsigned int idx = eint->pins[eint_num].index;
+ unsigned int inst = eint->pins[eint_num].instance;
void __iomem *reg;
- if (eint_num >= eint->hw->ap_num)
- eint_base = eint->hw->ap_num;
-
- reg = eint->base + offset + ((eint_num - eint_base) / 32) * 4;
+ reg = eint->base[inst] + offset + (idx / 32 * 4);
return reg;
}
@@ -83,7 +84,7 @@ static unsigned int mtk_eint_can_en_debounce(struct mtk_eint *eint,
unsigned int eint_num)
{
unsigned int sens;
- unsigned int bit = BIT(eint_num % 32);
+ unsigned int bit = BIT(eint->pins[eint_num].index % 32);
void __iomem *reg = mtk_eint_get_offset(eint, eint_num,
eint->regs->sens);
@@ -92,7 +93,7 @@ static unsigned int mtk_eint_can_en_debounce(struct mtk_eint *eint,
else
sens = MTK_EINT_EDGE_SENSITIVE;
- if (eint_num < eint->hw->db_cnt && sens != MTK_EINT_EDGE_SENSITIVE)
+ if (eint->pins[eint_num].debounce && sens != MTK_EINT_EDGE_SENSITIVE)
return 1;
else
return 0;
@@ -102,9 +103,9 @@ static int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq)
{
int start_level, curr_level;
unsigned int reg_offset;
- u32 mask = BIT(hwirq & 0x1f);
- u32 port = (hwirq >> 5) & eint->hw->port_mask;
- void __iomem *reg = eint->base + (port << 2);
+ unsigned int mask = BIT(eint->pins[hwirq].index & 0x1f);
+ unsigned int port = (eint->pins[hwirq].index >> 5) & eint->hw->port_mask;
+ void __iomem *reg = eint->base[eint->pins[hwirq].instance] + (port << 2);
curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl, hwirq);
@@ -126,11 +127,13 @@ static int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq)
static void mtk_eint_mask(struct irq_data *d)
{
struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
- u32 mask = BIT(d->hwirq & 0x1f);
+ unsigned int idx = eint->pins[d->hwirq].index;
+ unsigned int inst = eint->pins[d->hwirq].instance;
+ unsigned int mask = BIT(idx & 0x1f);
void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq,
eint->regs->mask_set);
- eint->cur_mask[d->hwirq >> 5] &= ~mask;
+ eint->cur_mask[inst][idx >> 5] &= ~mask;
writel(mask, reg);
}
@@ -138,22 +141,24 @@ static void mtk_eint_mask(struct irq_data *d)
static void mtk_eint_unmask(struct irq_data *d)
{
struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
- u32 mask = BIT(d->hwirq & 0x1f);
+ unsigned int idx = eint->pins[d->hwirq].index;
+ unsigned int inst = eint->pins[d->hwirq].instance;
+ unsigned int mask = BIT(idx & 0x1f);
void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq,
eint->regs->mask_clr);
- eint->cur_mask[d->hwirq >> 5] |= mask;
+ eint->cur_mask[inst][idx >> 5] |= mask;
writel(mask, reg);
- if (eint->dual_edge[d->hwirq])
+ if (eint->pins[d->hwirq].dual_edge)
mtk_eint_flip_edge(eint, d->hwirq);
}
static unsigned int mtk_eint_get_mask(struct mtk_eint *eint,
unsigned int eint_num)
{
- unsigned int bit = BIT(eint_num % 32);
+ unsigned int bit = BIT(eint->pins[eint_num].index % 32);
void __iomem *reg = mtk_eint_get_offset(eint, eint_num,
eint->regs->mask);
@@ -163,7 +168,7 @@ static unsigned int mtk_eint_get_mask(struct mtk_eint *eint,
static void mtk_eint_ack(struct irq_data *d)
{
struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
- u32 mask = BIT(d->hwirq & 0x1f);
+ unsigned int mask = BIT(eint->pins[d->hwirq].index & 0x1f);
void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq,
eint->regs->ack);
@@ -174,7 +179,7 @@ static int mtk_eint_set_type(struct irq_data *d, unsigned int type)
{
struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
bool masked;
- u32 mask = BIT(d->hwirq & 0x1f);
+ unsigned int mask = BIT(eint->pins[d->hwirq].index & 0x1f);
void __iomem *reg;
if (((type & IRQ_TYPE_EDGE_BOTH) && (type & IRQ_TYPE_LEVEL_MASK)) ||
@@ -186,9 +191,9 @@ static int mtk_eint_set_type(struct irq_data *d, unsigned int type)
}
if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
- eint->dual_edge[d->hwirq] = 1;
+ eint->pins[d->hwirq].dual_edge = 1;
else
- eint->dual_edge[d->hwirq] = 0;
+ eint->pins[d->hwirq].dual_edge = 0;
if (!mtk_eint_get_mask(eint, d->hwirq)) {
mtk_eint_mask(d);
@@ -223,27 +228,32 @@ static int mtk_eint_set_type(struct irq_data *d, unsigned int type)
static int mtk_eint_irq_set_wake(struct irq_data *d, unsigned int on)
{
struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
- int shift = d->hwirq & 0x1f;
- int reg = d->hwirq >> 5;
+ unsigned int idx = eint->pins[d->hwirq].index;
+ unsigned int inst = eint->pins[d->hwirq].instance;
+ unsigned int shift = idx & 0x1f;
+ unsigned int port = idx >> 5;
if (on)
- eint->wake_mask[reg] |= BIT(shift);
+ eint->wake_mask[inst][port] |= BIT(shift);
else
- eint->wake_mask[reg] &= ~BIT(shift);
+ eint->wake_mask[inst][port] &= ~BIT(shift);
return 0;
}
static void mtk_eint_chip_write_mask(const struct mtk_eint *eint,
- void __iomem *base, u32 *buf)
+ void __iomem *base, unsigned int **buf)
{
- int port;
+ int inst, port, port_num;
void __iomem *reg;
- for (port = 0; port < eint->hw->ports; port++) {
- reg = base + (port << 2);
- writel_relaxed(~buf[port], reg + eint->regs->mask_set);
- writel_relaxed(buf[port], reg + eint->regs->mask_clr);
+ for (inst = 0; inst < eint->nbase; inst++) {
+ port_num = DIV_ROUND_UP(eint->base_pin_num[inst], 32);
+ for (port = 0; port < port_num; port++) {
+ reg = eint->base[inst] + (port << 2);
+ writel_relaxed(~buf[inst][port], reg + eint->regs->mask_set);
+ writel_relaxed(buf[inst][port], reg + eint->regs->mask_clr);
+ }
}
}
@@ -303,15 +313,18 @@ static struct irq_chip mtk_eint_irq_chip = {
static unsigned int mtk_eint_hw_init(struct mtk_eint *eint)
{
- void __iomem *dom_en = eint->base + eint->regs->dom_en;
- void __iomem *mask_set = eint->base + eint->regs->mask_set;
- unsigned int i;
-
- for (i = 0; i < eint->hw->ap_num; i += 32) {
- writel(0xffffffff, dom_en);
- writel(0xffffffff, mask_set);
- dom_en += 4;
- mask_set += 4;
+ void __iomem *dom_reg, *mask_reg;
+ unsigned int i, j;
+
+ for (i = 0; i < eint->nbase; i++) {
+ dom_reg = eint->base[i] + eint->regs->dom_en;
+ mask_reg = eint->base[i] + eint->regs->mask_set;
+ for (j = 0; j < eint->base_pin_num[i]; j += 32) {
+ writel(0xffffffff, dom_reg);
+ writel(0xffffffff, mask_reg);
+ dom_reg += 4;
+ mask_reg += 4;
+ }
}
return 0;
@@ -322,14 +335,16 @@ mtk_eint_debounce_process(struct mtk_eint *eint, int index)
{
unsigned int rst, ctrl_offset;
unsigned int bit, dbnc;
+ unsigned int inst = eint->pins[index].instance;
+ unsigned int idx = eint->pins[index].index;
- ctrl_offset = (index / 4) * 4 + eint->regs->dbnc_ctrl;
- dbnc = readl(eint->base + ctrl_offset);
- bit = MTK_EINT_DBNC_SET_EN << ((index % 4) * 8);
+ ctrl_offset = (idx / 4) * 4 + eint->regs->dbnc_ctrl;
+ dbnc = readl(eint->base[inst] + ctrl_offset);
+ bit = MTK_EINT_DBNC_SET_EN << ((idx % 4) * 8);
if ((bit & dbnc) > 0) {
- ctrl_offset = (index / 4) * 4 + eint->regs->dbnc_set;
- rst = MTK_EINT_DBNC_RST_BIT << ((index % 4) * 8);
- writel(rst, eint->base + ctrl_offset);
+ ctrl_offset = (idx / 4) * 4 + eint->regs->dbnc_set;
+ rst = MTK_EINT_DBNC_RST_BIT << ((idx % 4) * 8);
+ writel(rst, eint->base[inst] + ctrl_offset);
}
}
@@ -337,65 +352,68 @@ static void mtk_eint_irq_handler(struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
struct mtk_eint *eint = irq_desc_get_handler_data(desc);
- unsigned int status, eint_num;
- int offset, mask_offset, index;
- void __iomem *reg = mtk_eint_get_offset(eint, 0, eint->regs->stat);
+ unsigned int i, j, port, status, shift, mask, eint_num;
+ void __iomem *reg;
int dual_edge, start_level, curr_level;
chained_irq_enter(chip, desc);
- for (eint_num = 0; eint_num < eint->hw->ap_num; eint_num += 32,
- reg += 4) {
- status = readl(reg);
- while (status) {
- offset = __ffs(status);
- mask_offset = eint_num >> 5;
- index = eint_num + offset;
- status &= ~BIT(offset);
-
- /*
- * If we get an interrupt on pin that was only required
- * for wake (but no real interrupt requested), mask the
- * interrupt (as would mtk_eint_resume do anyway later
- * in the resume sequence).
- */
- if (eint->wake_mask[mask_offset] & BIT(offset) &&
- !(eint->cur_mask[mask_offset] & BIT(offset))) {
- writel_relaxed(BIT(offset), reg -
- eint->regs->stat +
- eint->regs->mask_set);
- }
-
- dual_edge = eint->dual_edge[index];
- if (dual_edge) {
- /*
- * Clear soft-irq in case we raised it last
- * time.
- */
- writel(BIT(offset), reg - eint->regs->stat +
- eint->regs->soft_clr);
-
- start_level =
- eint->gpio_xlate->get_gpio_state(eint->pctl,
- index);
- }
-
- generic_handle_domain_irq(eint->domain, index);
-
- if (dual_edge) {
- curr_level = mtk_eint_flip_edge(eint, index);
+ for (i = 0; i < eint->nbase; i++) {
+ for (j = 0; j < eint->base_pin_num[i]; j += 32) {
+ port = j >> 5;
+ status = readl(eint->base[i] + port * 4 + eint->regs->stat);
+ while (status) {
+ shift = __ffs(status);
+ status &= ~BIT(shift);
+ mask = BIT(shift);
+ eint_num = eint->pin_list[i][shift + j];
/*
- * If level changed, we might lost one edge
- * interrupt, raised it through soft-irq.
+ * If we get an interrupt on pin that was only required
+ * for wake (but no real interrupt requested), mask the
+ * interrupt (as would mtk_eint_resume do anyway later
+ * in the resume sequence).
*/
- if (start_level != curr_level)
- writel(BIT(offset), reg -
- eint->regs->stat +
- eint->regs->soft_set);
+ if (eint->wake_mask[i][port] & mask &&
+ !(eint->cur_mask[i][port] & mask)) {
+ reg = mtk_eint_get_offset(eint, eint_num,
+ eint->regs->mask_set);
+ writel_relaxed(mask, reg);
+ }
+
+ dual_edge = eint->pins[eint_num].dual_edge;
+ if (dual_edge) {
+ /*
+ * Clear soft-irq in case we raised it last
+ * time.
+ */
+ reg = mtk_eint_get_offset(eint, eint_num,
+ eint->regs->soft_clr);
+ writel(mask, reg);
+
+ start_level =
+ eint->gpio_xlate->get_gpio_state(eint->pctl,
+ eint_num);
+ }
+
+ generic_handle_domain_irq(eint->domain, eint_num);
+
+ if (dual_edge) {
+ curr_level = mtk_eint_flip_edge(eint, eint_num);
+
+ /*
+ * If level changed, we might lost one edge
+ * interrupt, raised it through soft-irq.
+ */
+ if (start_level != curr_level) {
+ reg = mtk_eint_get_offset(eint, eint_num,
+ eint->regs->soft_set);
+ writel(mask, reg);
+ }
+ }
+
+ if (eint->pins[eint_num].debounce)
+ mtk_eint_debounce_process(eint, eint_num);
}
-
- if (index < eint->hw->db_cnt)
- mtk_eint_debounce_process(eint, index);
}
}
chained_irq_exit(chip, desc);
@@ -423,6 +441,8 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num,
int virq, eint_offset;
unsigned int set_offset, bit, clr_bit, clr_offset, rst, i, unmask,
dbnc;
+ unsigned int inst = eint->pins[eint_num].instance;
+ unsigned int idx = eint->pins[eint_num].index;
struct irq_data *d;
if (!eint->hw->db_time)
@@ -432,8 +452,8 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num,
eint_offset = (eint_num % 4) * 8;
d = irq_get_irq_data(virq);
- set_offset = (eint_num / 4) * 4 + eint->regs->dbnc_set;
- clr_offset = (eint_num / 4) * 4 + eint->regs->dbnc_clr;
+ set_offset = (idx / 4) * 4 + eint->regs->dbnc_set;
+ clr_offset = (idx / 4) * 4 + eint->regs->dbnc_clr;
if (!mtk_eint_can_en_debounce(eint, eint_num))
return -EINVAL;
@@ -454,12 +474,12 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num,
}
clr_bit = 0xff << eint_offset;
- writel(clr_bit, eint->base + clr_offset);
+ writel(clr_bit, eint->base[inst] + clr_offset);
bit = ((dbnc << MTK_EINT_DBNC_SET_DBNC_BITS) | MTK_EINT_DBNC_SET_EN) <<
eint_offset;
rst = MTK_EINT_DBNC_RST_BIT << eint_offset;
- writel(rst | bit, eint->base + set_offset);
+ writel(rst | bit, eint->base[inst] + set_offset);
/*
* Delay a while (more than 2T) to wait for hw debounce counter reset
@@ -487,32 +507,69 @@ EXPORT_SYMBOL_GPL(mtk_eint_find_irq);
int mtk_eint_do_init(struct mtk_eint *eint)
{
- int i;
+ unsigned int size, i, port, inst = 0;
+ struct mtk_pinctrl *hw = (struct mtk_pinctrl *)eint->pctl;
/* If clients don't assign a specific regs, let's use generic one */
if (!eint->regs)
eint->regs = &mtk_generic_eint_regs;
- eint->wake_mask = devm_kcalloc(eint->dev, eint->hw->ports,
- sizeof(*eint->wake_mask), GFP_KERNEL);
- if (!eint->wake_mask)
+ eint->base_pin_num = devm_kmalloc_array(eint->dev, eint->nbase, sizeof(u16),
+ GFP_KERNEL | __GFP_ZERO);
+ if (!eint->base_pin_num)
return -ENOMEM;
- eint->cur_mask = devm_kcalloc(eint->dev, eint->hw->ports,
- sizeof(*eint->cur_mask), GFP_KERNEL);
- if (!eint->cur_mask)
- return -ENOMEM;
+ if (eint->nbase == 1) {
+ size = eint->hw->ap_num * sizeof(struct mtk_eint_pin);
+ eint->pins = devm_kmalloc(eint->dev, size, GFP_KERNEL);
+ if (!eint->pins)
+ goto err_pins;
+
+ eint->base_pin_num[inst] = eint->hw->ap_num;
+ for (i = 0; i < eint->hw->ap_num; i++) {
+ eint->pins[i].instance = inst;
+ eint->pins[i].index = i;
+ eint->pins[i].debounce = (i < eint->hw->db_cnt) ? 1 : 0;
+ }
+ }
- eint->dual_edge = devm_kcalloc(eint->dev, eint->hw->ap_num,
- sizeof(int), GFP_KERNEL);
- if (!eint->dual_edge)
- return -ENOMEM;
+ if (hw && hw->soc && hw->soc->eint_pin) {
+ eint->pins = hw->soc->eint_pin;
+ for (i = 0; i < eint->hw->ap_num; i++) {
+ inst = eint->pins[i].instance;
+ if (inst >= eint->nbase)
+ continue;
+ eint->base_pin_num[inst]++;
+ }
+ }
+
+ eint->pin_list = devm_kmalloc(eint->dev, eint->nbase * sizeof(u16 *), GFP_KERNEL);
+ if (!eint->pin_list)
+ goto err_pin_list;
+
+ eint->wake_mask = devm_kmalloc(eint->dev, eint->nbase * sizeof(u32 *), GFP_KERNEL);
+ if (!eint->wake_mask)
+ goto err_wake_mask;
+
+ eint->cur_mask = devm_kmalloc(eint->dev, eint->nbase * sizeof(u32 *), GFP_KERNEL);
+ if (!eint->cur_mask)
+ goto err_cur_mask;
+
+ for (i = 0; i < eint->nbase; i++) {
+ eint->pin_list[i] = devm_kzalloc(eint->dev, eint->base_pin_num[i] * sizeof(u16),
+ GFP_KERNEL);
+ port = DIV_ROUND_UP(eint->base_pin_num[i], 32);
+ eint->wake_mask[i] = devm_kzalloc(eint->dev, port * sizeof(u32), GFP_KERNEL);
+ eint->cur_mask[i] = devm_kzalloc(eint->dev, port * sizeof(u32), GFP_KERNEL);
+ if (!eint->pin_list[i] || !eint->wake_mask[i] || !eint->cur_mask[i])
+ goto err_eint;
+ }
eint->domain = irq_domain_add_linear(eint->dev->of_node,
eint->hw->ap_num,
&irq_domain_simple_ops, NULL);
if (!eint->domain)
- return -ENOMEM;
+ goto err_eint;
if (eint->hw->db_time) {
for (i = 0; i < MTK_EINT_DBNC_MAX; i++)
@@ -523,8 +580,11 @@ int mtk_eint_do_init(struct mtk_eint *eint)
mtk_eint_hw_init(eint);
for (i = 0; i < eint->hw->ap_num; i++) {
+ inst = eint->pins[i].instance;
+ if (inst >= eint->nbase)
+ continue;
+ eint->pin_list[inst][eint->pins[i].index] = i;
int virq = irq_create_mapping(eint->domain, i);
-
irq_set_chip_and_handler(virq, &mtk_eint_irq_chip,
handle_level_irq);
irq_set_chip_data(virq, eint);
@@ -534,6 +594,27 @@ int mtk_eint_do_init(struct mtk_eint *eint)
eint);
return 0;
+
+err_eint:
+ for (i = 0; i < eint->nbase; i++) {
+ if (eint->cur_mask[i])
+ devm_kfree(eint->dev, eint->cur_mask[i]);
+ if (eint->wake_mask[i])
+ devm_kfree(eint->dev, eint->wake_mask[i]);
+ if (eint->pin_list[i])
+ devm_kfree(eint->dev, eint->pin_list[i]);
+ }
+ devm_kfree(eint->dev, eint->cur_mask);
+err_cur_mask:
+ devm_kfree(eint->dev, eint->wake_mask);
+err_wake_mask:
+ devm_kfree(eint->dev, eint->pin_list);
+err_pin_list:
+ if (eint->nbase == 1)
+ devm_kfree(eint->dev, eint->pins);
+err_pins:
+ devm_kfree(eint->dev, eint->base_pin_num);
+ return -ENOMEM;
}
EXPORT_SYMBOL_GPL(mtk_eint_do_init);
diff --git a/drivers/pinctrl/mediatek/mtk-eint.h b/drivers/pinctrl/mediatek/mtk-eint.h
index 6139b16cd225..f7f58cca0d5e 100644
--- a/drivers/pinctrl/mediatek/mtk-eint.h
+++ b/drivers/pinctrl/mediatek/mtk-eint.h
@@ -1,10 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * Copyright (C) 2014-2018 MediaTek Inc.
+ * Copyright (C) 2014-2025 MediaTek Inc.
*
* Author: Maoguang Meng <maoguang.meng@mediatek.com>
* Sean Wang <sean.wang@mediatek.com>
- *
+ * Hao Chang <ot_chhao.chang@mediatek.com>
+ * Qingliang Li <qingliang.li@mediatek.com>
*/
#ifndef __MTK_EINT_H
#define __MTK_EINT_H
@@ -40,6 +41,14 @@ struct mtk_eint_hw {
const unsigned int *db_time;
};
+struct mtk_eint_pin {
+ u16 number;
+ u8 instance;
+ u8 index;
+ bool debounce;
+ bool dual_edge;
+};
+
extern const unsigned int debounce_time_mt2701[];
extern const unsigned int debounce_time_mt6765[];
extern const unsigned int debounce_time_mt6795[];
@@ -56,17 +65,21 @@ struct mtk_eint_xt {
struct mtk_eint {
struct device *dev;
- void __iomem *base;
+ void __iomem **base;
+ u8 nbase;
+ u16 *base_pin_num;
struct irq_domain *domain;
int irq;
int *dual_edge;
- u32 *wake_mask;
- u32 *cur_mask;
+ u16 **pin_list;
+ u32 **wake_mask;
+ u32 **cur_mask;
/* Used to fit into various EINT device */
const struct mtk_eint_hw *hw;
const struct mtk_eint_regs *regs;
+ struct mtk_eint_pin *pins;
u16 num_db_time;
/* Used to fit into various pinctrl device */
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
index 00e95682b9f8..d1556b75d9ef 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
@@ -13,6 +13,7 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/of_address.h>
#include <linux/of_irq.h>
#include "mtk-eint.h"
@@ -367,7 +368,7 @@ static const struct mtk_eint_xt mtk_eint_xt = {
int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- int ret;
+ int ret, i, j, count_reg_names;
if (!IS_ENABLED(CONFIG_EINT_MTK))
return 0;
@@ -379,10 +380,24 @@ int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev)
if (!hw->eint)
return -ENOMEM;
- hw->eint->base = devm_platform_ioremap_resource_byname(pdev, "eint");
- if (IS_ERR(hw->eint->base)) {
- ret = PTR_ERR(hw->eint->base);
- goto err_free_eint;
+ count_reg_names = of_property_count_strings(np, "reg-names");
+ if (count_reg_names < hw->soc->nbase_names)
+ return -EINVAL;
+
+ hw->eint->nbase = count_reg_names - hw->soc->nbase_names;
+ hw->eint->base = devm_kmalloc_array(&pdev->dev, hw->eint->nbase,
+ sizeof(*hw->eint->base), GFP_KERNEL | __GFP_ZERO);
+ if (!hw->eint->base) {
+ ret = -ENOMEM;
+ goto err_free_base;
+ }
+
+ for (i = hw->soc->nbase_names, j = 0; i < count_reg_names; i++, j++) {
+ hw->eint->base[j] = of_iomap(np, i);
+ if (IS_ERR(hw->eint->base[j])) {
+ ret = PTR_ERR(hw->eint->base[j]);
+ goto err_free_eint;
+ }
}
hw->eint->irq = irq_of_parse_and_map(np, 0);
@@ -401,9 +416,19 @@ int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev)
hw->eint->pctl = hw;
hw->eint->gpio_xlate = &mtk_eint_xt;
- return mtk_eint_do_init(hw->eint);
+ ret = mtk_eint_do_init(hw->eint);
+ if (ret)
+ goto err_free_eint;
+
+ return 0;
err_free_eint:
+ for (j = 0; j < hw->eint->nbase; j++) {
+ if (hw->eint->base[j])
+ iounmap(hw->eint->base[j]);
+ }
+ devm_kfree(hw->dev, hw->eint->base);
+err_free_base:
devm_kfree(hw->dev, hw->eint);
hw->eint = NULL;
return ret;
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h
index 9c271dc2b521..36d2898037dd 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h
@@ -242,6 +242,7 @@ struct mtk_pin_soc {
unsigned int nfuncs;
const struct mtk_eint_regs *eint_regs;
const struct mtk_eint_hw *eint_hw;
+ struct mtk_eint_pin *eint_pin;
/* Specific parameters per SoC */
u8 gpio_m;
diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.h b/drivers/pinctrl/mediatek/pinctrl-paris.h
index 948ce126aa0c..d8c1822662fc 100644
--- a/drivers/pinctrl/mediatek/pinctrl-paris.h
+++ b/drivers/pinctrl/mediatek/pinctrl-paris.h
@@ -49,6 +49,13 @@
__VA_ARGS__, { } }, \
}
+#define MTK_EINT_PIN(_number, _instance, _index, _debounce) { \
+ .number = _number, \
+ .instance = _instance, \
+ .index = _index, \
+ .debounce = _debounce, \
+ }
+
#define PINCTRL_PIN_GROUP(_name_, id) \
{ \
.grp = PINCTRL_PINGROUP(_name_,id##_pins, ARRAY_SIZE(id##_pins)), \
--
2.46.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v5 1/1] pinctrl: mediatek: Add EINT support for multiple addresses
2025-03-22 3:52 ` [PATCH v5 1/1] pinctrl: mediatek: " Hao Chang
@ 2025-03-24 7:53 ` Linus Walleij
2025-04-14 14:57 ` Uwe Kleine-König
1 sibling, 0 replies; 5+ messages in thread
From: Linus Walleij @ 2025-03-24 7:53 UTC (permalink / raw)
To: Hao Chang
Cc: Sean Wang, Matthias Brugger, AngeloGioacchino Del Regno,
Wenbin Mei, Axe Yang, Qingliang Li, Hanks Chen, Chunhui Li,
linux-mediatek, linux-gpio, linux-kernel, linux-arm-kernel
On Sat, Mar 22, 2025 at 4:53 AM Hao Chang <ot_chhao.chang@mediatek.com> wrote:
> For flexible routing, eint will be divided into 5 bases,
> and it will obtain the operation address through the pins array.
>
> Signed-off-by: Hao Chang <ot_chhao.chang@mediatek.com>
> Signed-off-by: Qingliang Li <qingliang.li@mediatek.com>
Patch applied as the last pinctrl patch for v6.15!
Thanks for respinning this, I think it will make things easier.
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v5 1/1] pinctrl: mediatek: Add EINT support for multiple addresses
2025-03-22 3:52 ` [PATCH v5 1/1] pinctrl: mediatek: " Hao Chang
2025-03-24 7:53 ` Linus Walleij
@ 2025-04-14 14:57 ` Uwe Kleine-König
2025-04-16 8:36 ` Linus Walleij
1 sibling, 1 reply; 5+ messages in thread
From: Uwe Kleine-König @ 2025-04-14 14:57 UTC (permalink / raw)
To: Hao Chang
Cc: Sean Wang, Linus Walleij, Matthias Brugger,
AngeloGioacchino Del Regno, Wenbin Mei, Axe Yang, Qingliang Li,
Hanks Chen, Chunhui Li, linux-mediatek, linux-gpio, linux-kernel,
linux-arm-kernel, regressions
[-- Attachment #1: Type: text/plain, Size: 8091 bytes --]
Hello,
this patch became commit 3ef9f710efcb in v6.15-rc1. It breaks booting a
mt8365-evk.
With earlycon it's possible to see a null pointer exception:
[ 0.072938] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000002
[ 0.074101] Mem abort info:
[ 0.074468] ESR = 0x0000000096000004
[ 0.074984] EC = 0x25: DABT (current EL), IL = 32 bits
[ 0.075681] SET = 0, FnV = 0
[ 0.076083] EA = 0, S1PTW = 0
[ 0.076495] FSC = 0x04: level 0 translation fault
[ 0.077134] Data abort info:
[ 0.077511] ISV = 0, ISS = 0x00000004, ISS2 = 0x00000000
[ 0.078229] CM = 0, WnR = 0, TnD = 0, TagAccess = 0
[ 0.078891] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
[ 0.079593] [0000000000000002] user address but active_mm is swapper
[ 0.080426] Internal error: Oops: 0000000096000004 [#1] PREEMPT SMP
[ 0.081248] Modules linked in:
[ 0.081656] CPU: 0 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.14.0-rc3-00113-g3ef9f710efcb #18
[ 0.082796] Hardware name: MediaTek MT8365 Open Platform EVK (DT)
[ 0.083594] pstate: 80000005 (Nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[ 0.084507] pc : mtk_eint_do_init+0x470/0x580
[ 0.085088] lr : mtk_eint_do_init+0x37c/0x580
[ 0.085663] sp : ffff80008160b7e0
[ 0.086098] x29: ffff80008160b850 x28: 0000000000000000 x27: ffff8000812600b0
[ 0.087040] x26: ffff0000bf9b7a80 x25: ffff0000bf9baac8 x24: ffff0000bf9baac8
[ 0.087981] x23: 0000000000000000 x22: ffff8000800cebe0 x21: ffff80008147e418
[ 0.088922] x20: 0000000000000000 x19: ffff0000021be780 x18: 00000000ffffffff
[ 0.089863] x17: 0000000000000003 x16: ffff000001832b00 x15: ffff0000021b70e0
[ 0.090804] x14: 0000000000000001 x13: ffff0000021b70e3 x12: ffff000001832c00
[ 0.091744] x11: 0000000000000000 x10: ffff800080f11cc0 x9 : ffff80008160b780
[ 0.092685] x8 : ffff80008160b780 x7 : 0000000000000000 x6 : 00000000ffffffff
[ 0.093626] x5 : 0000000000000000 x4 : 0000000000000000 x3 : ffff800080d0dbb0
[ 0.094567] x2 : 0000000000000000 x1 : ffff800080d53100 x0 : 0000000000000000
[ 0.095509] Call trace:
[ 0.095831] mtk_eint_do_init+0x470/0x580 (P)
[ 0.096408] mtk_pctrl_init+0x464/0x4fc
[ 0.096917] mtk_pctrl_common_probe+0x30/0x60
[ 0.097494] platform_probe+0x68/0xdc
[ 0.097981] really_probe+0xbc/0x2c0
[ 0.098457] __driver_probe_device+0xcc/0x120
[ 0.099035] driver_probe_device+0x3c/0x154
[ 0.099590] __device_attach_driver+0xb8/0x140
[ 0.100179] bus_for_each_drv+0x88/0xe8
[ 0.100688] __device_attach+0xa0/0x190
[ 0.101197] device_initial_probe+0x14/0x20
[ 0.101752] bus_probe_device+0xb4/0xc0
[ 0.102261] device_add+0x554/0x72c
[ 0.102724] of_device_add+0x54/0x64
[ 0.103201] of_platform_device_create_pdata+0x8c/0x118
[ 0.103891] of_platform_bus_create+0x190/0x38c
[ 0.104491] of_platform_bus_create+0x1d8/0x38c
[ 0.105091] of_platform_populate+0x74/0x108
[ 0.105656] of_platform_default_populate_init+0xe8/0x10c
[ 0.106369] do_one_initcall+0x60/0x1d4
[ 0.106879] kernel_init_freeable+0x210/0x274
[ 0.107456] kernel_init+0x20/0x140
[ 0.107921] ret_from_fork+0x10/0x20
[ 0.108400] Code: 14000002 39404265 f9403260 8b170000 (39400802)
[ 0.109199] ---[ end trace 0000000000000000 ]---
[ 0.109821] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b
[ 0.110824] SMP: stopping secondary CPUs
[ 0.111345] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]---
The problem is that ...
On Sat, Mar 22, 2025 at 11:52:28AM +0800, Hao Chang wrote:
> int mtk_eint_do_init(struct mtk_eint *eint)
> {
> - int i;
> + unsigned int size, i, port, inst = 0;
> + struct mtk_pinctrl *hw = (struct mtk_pinctrl *)eint->pctl;
>
> /* If clients don't assign a specific regs, let's use generic one */
> if (!eint->regs)
> eint->regs = &mtk_generic_eint_regs;
>
> - eint->wake_mask = devm_kcalloc(eint->dev, eint->hw->ports,
> - sizeof(*eint->wake_mask), GFP_KERNEL);
> - if (!eint->wake_mask)
> + eint->base_pin_num = devm_kmalloc_array(eint->dev, eint->nbase, sizeof(u16),
> + GFP_KERNEL | __GFP_ZERO);
> + if (!eint->base_pin_num)
> return -ENOMEM;
>
> - eint->cur_mask = devm_kcalloc(eint->dev, eint->hw->ports,
> - sizeof(*eint->cur_mask), GFP_KERNEL);
> - if (!eint->cur_mask)
> - return -ENOMEM;
> + if (eint->nbase == 1) {
> + size = eint->hw->ap_num * sizeof(struct mtk_eint_pin);
> + eint->pins = devm_kmalloc(eint->dev, size, GFP_KERNEL);
> + if (!eint->pins)
> + goto err_pins;
> +
> + eint->base_pin_num[inst] = eint->hw->ap_num;
> + for (i = 0; i < eint->hw->ap_num; i++) {
> + eint->pins[i].instance = inst;
> + eint->pins[i].index = i;
> + eint->pins[i].debounce = (i < eint->hw->db_cnt) ? 1 : 0;
> + }
> + }
>
> - eint->dual_edge = devm_kcalloc(eint->dev, eint->hw->ap_num,
> - sizeof(int), GFP_KERNEL);
> - if (!eint->dual_edge)
> - return -ENOMEM;
> + if (hw && hw->soc && hw->soc->eint_pin) {
> + eint->pins = hw->soc->eint_pin;
> + for (i = 0; i < eint->hw->ap_num; i++) {
> + inst = eint->pins[i].instance;
> + if (inst >= eint->nbase)
> + continue;
> + eint->base_pin_num[inst]++;
> + }
> + }
> +
> + eint->pin_list = devm_kmalloc(eint->dev, eint->nbase * sizeof(u16 *), GFP_KERNEL);
> + if (!eint->pin_list)
> + goto err_pin_list;
> +
> + eint->wake_mask = devm_kmalloc(eint->dev, eint->nbase * sizeof(u32 *), GFP_KERNEL);
> + if (!eint->wake_mask)
> + goto err_wake_mask;
> +
> + eint->cur_mask = devm_kmalloc(eint->dev, eint->nbase * sizeof(u32 *), GFP_KERNEL);
> + if (!eint->cur_mask)
> + goto err_cur_mask;
> +
> + for (i = 0; i < eint->nbase; i++) {
> + eint->pin_list[i] = devm_kzalloc(eint->dev, eint->base_pin_num[i] * sizeof(u16),
> + GFP_KERNEL);
> + port = DIV_ROUND_UP(eint->base_pin_num[i], 32);
> + eint->wake_mask[i] = devm_kzalloc(eint->dev, port * sizeof(u32), GFP_KERNEL);
> + eint->cur_mask[i] = devm_kzalloc(eint->dev, port * sizeof(u32), GFP_KERNEL);
> + if (!eint->pin_list[i] || !eint->wake_mask[i] || !eint->cur_mask[i])
> + goto err_eint;
> + }
>
> eint->domain = irq_domain_add_linear(eint->dev->of_node,
> eint->hw->ap_num,
> &irq_domain_simple_ops, NULL);
> if (!eint->domain)
> - return -ENOMEM;
> + goto err_eint;
>
> if (eint->hw->db_time) {
> for (i = 0; i < MTK_EINT_DBNC_MAX; i++)
> @@ -523,8 +580,11 @@ int mtk_eint_do_init(struct mtk_eint *eint)
>
> mtk_eint_hw_init(eint);
> for (i = 0; i < eint->hw->ap_num; i++) {
> + inst = eint->pins[i].instance;
... here eint->pins is NULL.
> + if (inst >= eint->nbase)
> + continue;
> + eint->pin_list[inst][eint->pins[i].index] = i;
> int virq = irq_create_mapping(eint->domain, i);
> -
> irq_set_chip_and_handler(virq, &mtk_eint_irq_chip,
> handle_level_irq);
> irq_set_chip_data(virq, eint);
> @@ -534,6 +594,27 @@ int mtk_eint_do_init(struct mtk_eint *eint)
> eint);
>
> return 0;
> +
> +err_eint:
> + for (i = 0; i < eint->nbase; i++) {
> + if (eint->cur_mask[i])
> + devm_kfree(eint->dev, eint->cur_mask[i]);
> + if (eint->wake_mask[i])
> + devm_kfree(eint->dev, eint->wake_mask[i]);
> + if (eint->pin_list[i])
> + devm_kfree(eint->dev, eint->pin_list[i]);
> + }
> + devm_kfree(eint->dev, eint->cur_mask);
> +err_cur_mask:
> + devm_kfree(eint->dev, eint->wake_mask);
> +err_wake_mask:
> + devm_kfree(eint->dev, eint->pin_list);
> +err_pin_list:
> + if (eint->nbase == 1)
> + devm_kfree(eint->dev, eint->pins);
> +err_pins:
> + devm_kfree(eint->dev, eint->base_pin_num);
> + return -ENOMEM;
> }
> EXPORT_SYMBOL_GPL(mtk_eint_do_init);
That commit can be cleanly reverted on top of v6.15-rc2 which makes my
machine boot again.
Best regards
Uwe
#regzbot introduced: 3ef9f710efcb
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v5 1/1] pinctrl: mediatek: Add EINT support for multiple addresses
2025-04-14 14:57 ` Uwe Kleine-König
@ 2025-04-16 8:36 ` Linus Walleij
0 siblings, 0 replies; 5+ messages in thread
From: Linus Walleij @ 2025-04-16 8:36 UTC (permalink / raw)
To: Uwe Kleine-König
Cc: Hao Chang, Sean Wang, Matthias Brugger,
AngeloGioacchino Del Regno, Wenbin Mei, Axe Yang, Qingliang Li,
Hanks Chen, Chunhui Li, linux-mediatek, linux-gpio, linux-kernel,
linux-arm-kernel, regressions
On Mon, Apr 14, 2025 at 4:57 PM Uwe Kleine-König
<u.kleine-koenig@baylibre.com> wrote:
> this patch became commit 3ef9f710efcb in v6.15-rc1. It breaks booting a
> mt8365-evk.
>
> With earlycon it's possible to see a null pointer exception:
Argh, does this patch fix it:
https://lore.kernel.org/all/20250415112339.2385454-1-wenst@chromium.org/
I have applied that one for fixes.
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2025-04-16 10:31 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-22 3:52 [PATCH v5 0/1] Add EINT support for multiple addresses Hao Chang
2025-03-22 3:52 ` [PATCH v5 1/1] pinctrl: mediatek: " Hao Chang
2025-03-24 7:53 ` Linus Walleij
2025-04-14 14:57 ` Uwe Kleine-König
2025-04-16 8:36 ` Linus Walleij
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox