Re: [PATCH] pinctrl: mediatek: add eint new design for mt8196

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Il 24/10/24 16:15, chang hao ha scritto:
From: Chhao Chang <ot_chhao.chang@xxxxxxxxxxxx>

eint is divided from the original base address into base addresses
in five directions: east, south, west, north, and center.
Stores a limited number of eint numbers in each direction.

Signed-off-by: Chhao Chang <ot_chhao.chang@xxxxxxxxxxxx>
---
  drivers/pinctrl/mediatek/mtk-eint.c           | 830 +++++++++++++-----
  drivers/pinctrl/mediatek/mtk-eint.h           |  75 +-
  .../pinctrl/mediatek/pinctrl-mtk-common-v2.c  |  50 +-
  3 files changed, 722 insertions(+), 233 deletions(-)

diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c
index 27f0a54e12bf..0bb017eb1893 100644
--- a/drivers/pinctrl/mediatek/mtk-eint.c
+++ b/drivers/pinctrl/mediatek/mtk-eint.c
@@ -17,16 +17,13 @@
  #include <linux/irqdomain.h>
  #include <linux/module.h>
  #include <linux/of_irq.h>
+#include <linux/of_address.h>
  #include <linux/platform_device.h>
#include "mtk-eint.h" -#define MTK_EINT_EDGE_SENSITIVE 0
-#define MTK_EINT_LEVEL_SENSITIVE          1
-#define MTK_EINT_DBNC_SET_DBNC_BITS	  4
-#define MTK_EINT_DBNC_MAX		  16
-#define MTK_EINT_DBNC_RST_BIT		  (0x1 << 1)
-#define MTK_EINT_DBNC_SET_EN		  (0x1 << 0)
+static struct mtk_eint *global_eintc;
+struct mtk_eint_pin pin;

Noupe, don't introduce these globals.

static const struct mtk_eint_regs mtk_generic_eint_regs = {
  	.stat      = 0x000,
@@ -47,6 +44,10 @@ static const struct mtk_eint_regs mtk_generic_eint_regs = {
  	.dbnc_ctrl = 0x500,
  	.dbnc_set  = 0x600,
  	.dbnc_clr  = 0x700,
+	.event     = 0x800,
+	.event_set = 0x840,
+	.event_clr = 0x880,
+	.raw_stat  = 0xa00,
  };
const unsigned int debounce_time_mt2701[] = {
@@ -64,60 +65,145 @@ const unsigned int debounce_time_mt6795[] = {
  };
  EXPORT_SYMBOL_GPL(debounce_time_mt6795);
-static void __iomem *mtk_eint_get_offset(struct mtk_eint *eint,
+/*
+ * Return the iomem of specific register ofset and decode the coordinate
+ * (instance, index) from global eint number.
+ * If return NULL, then it must be either out-of-range or do-not-support.
+ */
+static void __iomem *mtk_eint_get_ofset(struct mtk_eint *eint,

You're replacing this with a typo....

  					 unsigned int eint_num,
-					 unsigned int offset)
+					 unsigned int ofset,

and you're typoing offset on purpose again?! :-\

+					 unsigned int *instance,
+					 unsigned int *index)
  {
-	unsigned int eint_base = 0;
  	void __iomem *reg;
- if (eint_num >= eint->hw->ap_num)
-		eint_base = eint->hw->ap_num;
+	if (eint_num >= eint->total_pin_number ||
+	    !eint->pins[eint_num].enabled) {
+		WARN_ON(1);
+		return NULL;
+	}
- reg = eint->base + offset + ((eint_num - eint_base) / 32) * 4;
+	*instance = eint->pins[eint_num].instance;
+	*index = eint->pins[eint_num].index;
+	reg = eint->instances[*instance].base + ofset + (*index / MAX_BIT * REG_OFSET);
return reg;
  }
+/*
+ * Generate helper function to access property register of a dedicate pin.
+ */

...and you don't need this (sorry, ugly!) macro either, as this is only
helping you to create a mass-duplication situation here.

If you need a helper, write *one* function that retrieves the data for you
from a chosen register.

+#define DEFINE_EINT_GET_FUNCTION(_NAME, _OFSET) \
+static unsigned int mtk_eint_get_##_NAME(struct mtk_eint *eint, \
+				   unsigned int eint_num) \
+{ \
+	unsigned int instance, index; \
+	void __iomem *reg = mtk_eint_get_ofset(eint, eint_num, \
+						_OFSET, \
+						&instance, &index); \
+	unsigned int bit = BIT(index & 0x1f);\
+\
+	if (!reg) { \
+		dev_err(eint->dev, "%s invalid eint_num %d\n", \
+			__func__, eint_num); \
+		return 0;\
+	} \
+\
+	return !!(readl(reg) & bit); \
+}
+
+DEFINE_EINT_GET_FUNCTION(stat, eint->comp->regs->stat);
+DEFINE_EINT_GET_FUNCTION(mask, eint->comp->regs->mask);
+DEFINE_EINT_GET_FUNCTION(sens, eint->comp->regs->sens);
+DEFINE_EINT_GET_FUNCTION(pol, eint->comp->regs->pol);
+DEFINE_EINT_GET_FUNCTION(dom_en, eint->comp->regs->dom_en);
+DEFINE_EINT_GET_FUNCTION(event, eint->comp->regs->event);
+DEFINE_EINT_GET_FUNCTION(raw_stat, eint->comp->regs->raw_stat);
+
+int dump_eint_pin_status(unsigned int eint_num)

I don't think that this is necessary... also because, there's already irq/debugfs.c
for debugging. If you really need debug, hook it to the right APIs.

+{
+       unsigned int stat, raw_stat, mask, sens, pol, dom_en, event;
+
+       if (eint_num < 0 || eint_num > global_eintc->total_pin_number)
+               return ENODEV;
+
+       stat = mtk_eint_get_stat(global_eintc, eint_num);
+       raw_stat = mtk_eint_get_raw_stat(global_eintc, eint_num);
+       mask = mtk_eint_get_mask(global_eintc, eint_num);
+       sens = mtk_eint_get_sens(global_eintc, eint_num);
+       pol = mtk_eint_get_pol(global_eintc, eint_num);
+       dom_en = mtk_eint_get_dom_en(global_eintc, eint_num);
+       event = mtk_eint_get_event(global_eintc, eint_num);
+       dev_info(global_eintc->dev, "%s eint_num:%u=stat:%u,raw:%u, \
+		       mask:%u, sens:%u,pol:%u,dom_en:%u,event:%u\n",
+		       __func__, eint_num, stat, raw_stat, mask, sens,
+		       pol, dom_en, event);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(dump_eint_pin_status);
+
  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);
-	void __iomem *reg = mtk_eint_get_offset(eint, eint_num,
-						eint->regs->sens);
+	unsigned int instance, index;
+	void __iomem *reg = mtk_eint_get_ofset(eint, eint_num,
+						eint->comp->regs->sens,
+						&instance, &index);
+	unsigned int bit = BIT(index & 0x1f);

I'm not sure why you can't use BIT(eint_num % 32) anymore.

Even though your EINT is split in 5, that should be still aligned the same as
the "old" EINT.

+
+	if (!reg) {

That won't ever happen, because you're already checking that in callers of
this function, hence this check is redundant, or looks like it is anyway.

+		dev_err(eint->dev, "%s invalid eint_num %d\n",
+			__func__, eint_num);
+		return 0;
+	}
if (readl(reg) & bit)
  		sens = MTK_EINT_LEVEL_SENSITIVE;
  	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;
  }
-static int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq)
+static int mtk_eint_flip_edge(struct mtk_eint *eint, int eint_num)

Why are you changing the parameter name from hwirq to eint_num?!

  {
  	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 reg_ofset;
+	unsigned int instance, index, mask, port;
+	void __iomem *reg;
- curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl, hwirq);
+	reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
+				  &instance, &index);
+
+	if (!reg) {
+		dev_err(eint->dev, "%s invalid eint_num %d\n",
+			__func__, eint_num);
+		return 0;
+	}
+
+	mask = BIT(index & 0x1f);
+	port = index >> REG_GROUP;
+	reg = eint->instances[instance].base + port * REG_OFSET;
+


..snip..

@@ -403,7 +572,20 @@ static void mtk_eint_irq_handler(struct irq_desc *desc)
int mtk_eint_do_suspend(struct mtk_eint *eint)
  {
-	mtk_eint_chip_write_mask(eint, eint->base, eint->wake_mask);
+	unsigned int i, j, port;
+
+	for (i = 0; i < eint->instance_number; i++) {
+		struct mtk_eint_instance inst = eint->instances[i];

Just register five different instances if they really have to be separated,
which I don't believe they do, anyway.

You should really read what mtk_eint_hw is for.

+
+		for (j = 0; j < inst.number; j += MAX_BIT) {
+			port = j >> REG_GROUP;
+			writel_relaxed(~inst.wake_mask[port],
+				       inst.base + port*REG_OFSET + eint->comp->regs->mask_set);
+			writel_relaxed(inst.wake_mask[port],
+				       inst.base + port*REG_OFSET + eint->comp->regs->mask_clr);
+		}
+	}
+	dsb(sy);
return 0;
  }

..snip..

@@ -420,27 +615,45 @@ EXPORT_SYMBOL_GPL(mtk_eint_do_resume);
  int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num,
  			  unsigned int debounce)
  {
-	int virq, eint_offset;
-	unsigned int set_offset, bit, clr_bit, clr_offset, rst, i, unmask,
+	int virq, eint_ofset;
+	unsigned int set_ofset, bit, clr_bit, clr_ofset, rst, i, unmask,
  		     dbnc;
+	static const unsigned int debounce_time[] = { 156, 313, 625, 1250,
+		20000, 40000, 80000, 160000, 320000, 640000 };

This is another mtk_eint_hw array that you're carelessly hardcoding inside of the
eint driver.

  	struct irq_data *d;
+	unsigned int instance, index;
+	void __iomem *reg;
- if (!eint->hw->db_time)
-		return -EOPNOTSUPP;
+	/*
+	 * Due to different number of bit field, we only decode
+	 * the coordinate here, instead of get the VA.
+	 */
+	reg = mtk_eint_get_ofset(eint, eint_num, MTK_EINT_NO_OFSET,
+				  &instance, &index);
+
+	if (!reg) {
+		dev_err(eint->dev, "%s invalid eint_num %lu\n",
+			__func__, eint_num);
+		return 0;
+	}
virq = irq_find_mapping(eint->domain, eint_num);
-	eint_offset = (eint_num % 4) * 8;
+	eint_ofset = (index % REG_OFSET) * DB_GROUP;
  	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;
+	reg = eint->instances[instance].base;
+	set_ofset = (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_set;
+	clr_ofset = (index / REG_OFSET) * REG_OFSET + eint->comp->regs->dbnc_clr;
if (!mtk_eint_can_en_debounce(eint, eint_num))
  		return -EINVAL;
- dbnc = eint->num_db_time;
-	for (i = 0; i < eint->num_db_time; i++) {
-		if (debounce <= eint->hw->db_time[i]) {
+	/*
+	 * Check eint number to avoid access out-of-range
+	 */
+	dbnc = ARRAY_SIZE(debounce_time) - 1;

And here, you carelessly break every other supported MediaTek SoC.

+	for (i = 0; i < ARRAY_SIZE(debounce_time); i++) {
+		if (debounce <= debounce_time[i]) {
  			dbnc = i;
  			break;
  		}

..snip..

+
+int mtk_eint_do_init_v2(struct mtk_eint *eint)
+{
+	int i, virq, matrix_number = 0;
+	struct device_node *node;
+	unsigned int ret, size, ofset;
+	unsigned int id, inst, idx, support_deb;
+
+	const phandle *ph;
+
+	ph = of_get_property(eint->dev->of_node, "mediatek,eint", NULL);

No, a SoC always has the same eint controller(s), always mapped to the same pins.

This is not something for devicetree - but rather something that was already
resolved in the past, when `struct mtk_eint_hw` was introduced.

You should just look at how this driver works upstream and implement support for
the new EINT in there.... not by copy-pasting something from downstream to upstream
and expecting it to be accepted.

+	if (!ph) {
+		dev_err(eint->dev, "Cannot find EINT phandle in PIO node.\n");
+		return -ENODEV;
+	}
+
+	node = of_find_node_by_phandle(be32_to_cpup(ph));
+	if (!node) {
+		dev_err(eint->dev, "Cannot find EINT node by phandle.\n");
+		return -ENODEV;
+	}
+
+	ret = of_property_read_u32(node, "mediatek,total-pin-number",
+				   &eint->total_pin_number);

eint_hw->ap_num is the same thing as this.

+	if (ret) {
+		dev_err(eint->dev,
+		       "%s cannot read total-pin-number from device node.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	dev_info(eint->dev, "%s eint total %u pins.\n", __func__,
+		eint->total_pin_number);
+
+	ret = of_property_read_u32(node, "mediatek,instance-num",
+				   &eint->instance_number);
+	if (ret)
+		eint->instance_number = 1; // only 1 instance in legacy chip
+
+	size = eint->instance_number * sizeof(struct mtk_eint_instance);
+	eint->instances = devm_kzalloc(eint->dev, size, GFP_KERNEL);
+	if (!eint->instances)
  		return -ENOMEM;
- eint->dual_edge = devm_kcalloc(eint->dev, eint->hw->ap_num,
-				       sizeof(int), GFP_KERNEL);
-	if (!eint->dual_edge)
+	size = eint->total_pin_number * sizeof(struct mtk_eint_pin);
+	eint->pins = devm_kzalloc(eint->dev, size, GFP_KERNEL);
+	if (!eint->pins)
  		return -ENOMEM;
+ for (i = 0; i < eint->instance_number; i++) {
+		ret = of_property_read_string_index(node, "reg-name", i,
+						    &(eint->instances[i].name));
+		if (ret) {
+			dev_info(eint->dev,
+				 "%s cannot read the name of instance %d.\n",
+				 __func__, i);
+		}
+
+		eint->instances[i].base = of_iomap(node, i);
+		if (!eint->instances[i].base)
+			return -ENOMEM;
+	}
+
+	matrix_number = of_property_count_u32_elems(node, "mediatek,pins") / ARRAY_0;
+	if (matrix_number < 0) {
+		matrix_number = eint->total_pin_number;
+		dev_info(eint->dev, "%s eint in legacy mode, assign the matrix number to %u.\n",
+			 __func__, matrix_number);
+	} else
+		dev_info(eint->dev, "%s eint in new mode, assign the matrix number to %u.\n",
+			 __func__, matrix_number);
+
+	for (i = 0; i < matrix_number; i++) {
+		ofset = i * REG_OFSET;
+
+		ret = of_property_read_u32_index(node, "mediatek,pins",
+					   ofset, &id);

So basically this means that if a SoC has 200 EINT pins, you'll have 200 values
in devicetree?!

+		ret |= of_property_read_u32_index(node, "mediatek,pins",
+					   ofset+FIRST, &inst);
+		ret |= of_property_read_u32_index(node, "mediatek,pins",
+					   ofset+SECOND, &idx);
+		ret |= of_property_read_u32_index(node, "mediatek,pins",
+					   ofset+THIRD, &support_deb);
+
+		/* Legacy chip which no need to give coordinate list */
+		if (ret) {
+			id = i;
+			inst = 0;
+			idx = i;
+			support_deb = (i < MAX_BIT) ? 1 : 0;
+		}
+
+		eint->pins[id].enabled = true;
+		eint->pins[id].instance = inst;
+		eint->pins[id].index = idx;
+		eint->pins[id].debounce = support_deb;
+
+		eint->instances[inst].pin_list[idx] = id;
+		eint->instances[inst].number++;
+

..snip..

diff --git a/drivers/pinctrl/mediatek/mtk-eint.h b/drivers/pinctrl/mediatek/mtk-eint.h
index 6139b16cd225..aa17a6073029 100644
--- a/drivers/pinctrl/mediatek/mtk-eint.h
+++ b/drivers/pinctrl/mediatek/mtk-eint.h
@@ -11,6 +11,25 @@
#include <linux/irqdomain.h> +#define MAX_PIN 999
+#define MTK_EINT_EDGE_SENSITIVE           0
+#define MTK_EINT_LEVEL_SENSITIVE          1
+#define MTK_EINT_DBNC_SET_DBNC_BITS       4
+#define MTK_EINT_DBNC_RST_BIT             (0x1 << 1)
+#define MTK_EINT_DBNC_SET_EN              (0x1 << 0)
+#define MTK_EINT_NO_OFSET                 0

+#define MAX_BIT                           32

MAX_BIT==32? Ok, so I was right in saying that the new eint is just the old one
but with more than one instance.

+#define REG_OFSET                         4
+#define REG_GROUP                         5
+#define REG_VAL                           0xFFFFFFFF


+#define DB_GROUP                          8
+#define FIRST                             1
+#define SECOND                            2
+#define THIRD                             3
+#define ARRAY_0                           4
+
+//#define MTK_EINT_DEBUG

Those definitions are either cryptic or unneeded.
And I'll stop my review here.

To be clear, the response is a huge "NACK"; you really have to redo everything
from scratch, but this time, just implement support for the new design on the base
of this upstream driver.

Regards,
Angelo




[Index of Archives]     [Linux SPI]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux