Skip to content

Commit

Permalink
pinctrl: mediatek: introduce multiple memory bases support
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
SamShih33 authored and trini committed May 5, 2022
1 parent dafe0fb commit 10334e0
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 20 deletions.
55 changes: 38 additions & 17 deletions drivers/pinctrl/mediatek/pinctrl-mtk-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;
Expand All @@ -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.
Expand Down Expand Up @@ -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);
}

Expand All @@ -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;
}
Expand All @@ -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);
Expand All @@ -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);

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
22 changes: 19 additions & 3 deletions drivers/pinctrl/mediatek/pinctrl-mtk-common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) { \
Expand All @@ -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, \
Expand All @@ -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,
Expand Down Expand Up @@ -70,13 +78,15 @@ 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
* @next: the indication that the field would be extended to the
next register
*/
struct mtk_pin_field {
u8 index;
u32 offset;
u32 mask;
u8 bitpos;
Expand All @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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;
};

/**
Expand All @@ -181,14 +196,15 @@ 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;
};

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);

Expand Down

0 comments on commit 10334e0

Please sign in to comment.