[v3,2/3] pinctrl: mediatek: introduce multiple memory bases support

Sam Shih
2022-04-01T08:56:20Z

Pinctrl design of some mediatek SoC need to access registers that
distribute in multiple memory base address. this patch introduce new
mechanism in mediatek pinctrl driver to support the chips which have
the new design.

This patch add a member 'base_calc' in pinctrl private data, and changed
original 'base' private data to an array of *iomem.

When 'base_calc' attribute is set, it will requests multiplue regs base
from the DT, if 'base_calc' attribute is not set, it only use legacy way
to request single reg resource from the DT.

Signed-off-by: Sam Shih <sam.shih@mediatek.com>
---
v3: fix v2 patch series misapplied
v2: fix build fail caused by patch [2/3]
---
drivers/pinctrl/mediatek/pinctrl-mtk-common.c | 55 +++++++++++++------
drivers/pinctrl/mediatek/pinctrl-mtk-common.h | 22 +++++++-
2 files changed, 57 insertions(+), 20 deletions(-)

diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
index 4ae328699e..ebab43e50a 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
@@ -45,18 +45,18 @@ static const struct mtk_drive_desc mtk_drive[] = {

static const char *mtk_pinctrl_dummy_name = "_dummy";

-static void mtk_w32(struct udevice *dev, u32 reg, u32 val)
+static void mtk_w32(struct udevice *dev, u8 i, u32 reg, u32 val)
{
struct mtk_pinctrl_priv *priv = dev_get_priv(dev);

- __raw_writel(val, priv->base + reg);
+ __raw_writel(val, priv->base[i] + reg);
}

-static u32 mtk_r32(struct udevice *dev, u32 reg)
+static u32 mtk_r32(struct udevice *dev, u8 i, u32 reg)
{
struct mtk_pinctrl_priv *priv = dev_get_priv(dev);

- return __raw_readl(priv->base + reg);
+ return __raw_readl(priv->base[i] + reg);
}

static inline int get_count_order(unsigned int count)
@@ -70,21 +70,28 @@ static inline int get_count_order(unsigned int count)
}

void mtk_rmw(struct udevice *dev, u32 reg, u32 mask, u32 set)
+{
+ return mtk_i_rmw(dev, 0, reg, mask, set);
+}
+
+void mtk_i_rmw(struct udevice *dev, u8 i, u32 reg, u32 mask, u32 set)
{
u32 val;

- val = mtk_r32(dev, reg);
+ val = mtk_r32(dev, i, reg);
val &= ~mask;
val |= set;
- mtk_w32(dev, reg, val);
+ mtk_w32(dev, i, reg, val);
}

static int mtk_hw_pin_field_lookup(struct udevice *dev, int pin,
const struct mtk_pin_reg_calc *rc,
struct mtk_pin_field *pfd)
{
+ struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
const struct mtk_pin_field_calc *c, *e;
u32 bits;
+ u32 base_calc = priv->soc->base_calc;

c = rc->range;
e = c + rc->nranges;
@@ -111,6 +118,11 @@ static int mtk_hw_pin_field_lookup(struct udevice *dev, int pin,
pfd->bitpos = bits % c->sz_reg;
pfd->mask = (1 << c->x_bits) - 1;

+ if (base_calc)
+ pfd->index = c->i_base;
+ else
+ pfd->index = 0;
+
/* pfd->next is used for indicating that bit wrapping-around happens
* which requires the manipulation for bit 0 starting in the next
* register to form the complete field read/write.
@@ -150,10 +162,10 @@ static void mtk_hw_write_cross_field(struct udevice *dev,

mtk_hw_bits_part(pf, &nbits_h, &nbits_l);

- mtk_rmw(dev, pf->offset, pf->mask << pf->bitpos,
+ mtk_i_rmw(dev, pf->index, pf->offset, pf->mask << pf->bitpos,
(value & pf->mask) << pf->bitpos);

- mtk_rmw(dev, pf->offset + pf->next, BIT(nbits_h) - 1,
+ mtk_i_rmw(dev, pf->index, pf->offset + pf->next, BIT(nbits_h) - 1,
(value & pf->mask) >> nbits_l);
}

@@ -164,8 +176,8 @@ static void mtk_hw_read_cross_field(struct udevice *dev,

mtk_hw_bits_part(pf, &nbits_h, &nbits_l);

- l = (mtk_r32(dev, pf->offset) >> pf->bitpos) & (BIT(nbits_l) - 1);
- h = (mtk_r32(dev, pf->offset + pf->next)) & (BIT(nbits_h) - 1);
+ l = (mtk_r32(dev, pf->index, pf->offset) >> pf->bitpos) & (BIT(nbits_l) - 1);
+ h = (mtk_r32(dev, pf->index, pf->offset + pf->next)) & (BIT(nbits_h) - 1);

*value = (h << nbits_l) | l;
}
@@ -181,7 +193,7 @@ static int mtk_hw_set_value(struct udevice *dev, int pin, int field,
return err;

if (!pf.next)
- mtk_rmw(dev, pf.offset, pf.mask << pf.bitpos,
+ mtk_i_rmw(dev, pf.index, pf.offset, pf.mask << pf.bitpos,
(value & pf.mask) << pf.bitpos);
else
mtk_hw_write_cross_field(dev, &pf, value);
@@ -200,7 +212,7 @@ static int mtk_hw_get_value(struct udevice *dev, int pin, int field,
return err;

if (!pf.next)
- *value = (mtk_r32(dev, pf.offset) >> pf.bitpos) & pf.mask;
+ *value = (mtk_r32(dev, pf.index, pf.offset) >> pf.bitpos) & pf.mask;
else
mtk_hw_read_cross_field(dev, &pf, value);

@@ -236,7 +248,6 @@ static int mtk_get_pin_muxing(struct udevice *dev, unsigned int selector,
char *buf, int size)
{
int val, err;
-
err = mtk_hw_get_value(dev, selector, PINCTRL_PIN_REG_MODE, &val);
if (err)
return err;
@@ -722,13 +733,23 @@ int mtk_pinctrl_common_probe(struct udevice *dev,
{
struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
int ret = 0;
-
- priv->base = dev_read_addr_ptr(dev);
- if (!priv->base)
- return -EINVAL;
+ u32 i = 0;
+ fdt_addr_t addr;
+ u32 base_calc = soc->base_calc;
+ u32 nbase_names = soc->nbase_names;

priv->soc = soc;

+ if (!base_calc)
+ nbase_names = 1;
+
+ for (i = 0; i < nbase_names; i++) {
+ addr = devfdt_get_addr_index(dev, i);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+ priv->base[i] = (void __iomem *)addr;
+ }
+
#if CONFIG_IS_ENABLED(DM_GPIO) || \
(defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_GPIO))
ret = mtk_gpiochip_register(dev);
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
index 735fb6fef8..91a8c0581f 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
@@ -8,6 +8,8 @@

#define MTK_PINCTRL_V0 0x0
#define MTK_PINCTRL_V1 0x1
+#define BASE_CALC_NONE 0
+#define MAX_BASE_CALC 10

#define MTK_RANGE(_a) { .range = (_a), .nranges = ARRAY_SIZE(_a), }
#define MTK_PIN(_number, _name, _drv_n) { \
@@ -24,10 +26,11 @@
id##_funcs, \
}

-#define PIN_FIELD_CALC(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, \
- _x_bits, _sz_reg, _fixed) { \
+#define PIN_FIELD_BASE_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, \
+ _s_bit, _x_bits, _sz_reg, _fixed) { \
.s_pin = _s_pin, \
.e_pin = _e_pin, \
+ .i_base = _i_base, \
.s_addr = _s_addr, \
.x_addrs = _x_addrs, \
.s_bit = _s_bit, \
@@ -36,6 +39,11 @@
.fixed = _fixed, \
}

+#define PIN_FIELD_CALC(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, \
+ _x_bits, _sz_reg, _fixed) \
+ PIN_FIELD_BASE_CALC(_s_pin, _e_pin, BASE_CALC_NONE, _s_addr, \
+ _x_addrs, _s_bit, _x_bits, _sz_reg, _fixed)
+
/* List these attributes which could be modified for the pin */
enum {
PINCTRL_PIN_REG_MODE,
@@ -70,6 +78,7 @@ enum {
/**
* struct mtk_pin_field - the structure that holds the information of the field
* used to describe the attribute for the pin
+ * @index: the index pointing to the entry in base address list
* @offset: the register offset relative to the base address
* @mask: the mask used to filter out the field from the register
* @bitpos: the start bit relative to the register
@@ -77,6 +86,7 @@ enum {
next register
*/
struct mtk_pin_field {
+ u8 index;
u32 offset;
u32 mask;
u8 bitpos;
@@ -88,6 +98,7 @@ struct mtk_pin_field {
* the guide used to look up the relevant field
* @s_pin: the start pin within the range
* @e_pin: the end pin within the range
+ * @i_base: the index pointing to the entry in base address list
* @s_addr: the start address for the range
* @x_addrs: the address distance between two consecutive registers
* within the range
@@ -101,6 +112,7 @@ struct mtk_pin_field {
struct mtk_pin_field_calc {
u16 s_pin;
u16 e_pin;
+ u8 i_base;
u32 s_addr;
u8 x_addrs;
u8 s_bit;
@@ -171,7 +183,10 @@ struct mtk_pinctrl_soc {
const struct mtk_function_desc *funcs;
int nfuncs;
int gpio_mode;
+ const char * const *base_names;
+ unsigned int nbase_names;
int rev;
+ int base_calc;
};

/**
@@ -181,7 +196,7 @@ struct mtk_pinctrl_soc {
* @soc: SoC specific data
*/
struct mtk_pinctrl_priv {
- void __iomem *base;
+ void __iomem *base[MAX_BASE_CALC];
struct mtk_pinctrl_soc *soc;
};

@@ -189,6 +204,7 @@ extern const struct pinctrl_ops mtk_pinctrl_ops;

/* A common read-modify-write helper for MediaTek chips */
void mtk_rmw(struct udevice *dev, u32 reg, u32 mask, u32 set);
+void mtk_i_rmw(struct udevice *dev, u8 i, u32 reg, u32 mask, u32 set);
int mtk_pinctrl_common_probe(struct udevice *dev,
struct mtk_pinctrl_soc *soc);

--
2.18.0