mirror of
https://github.com/u-boot/u-boot.git
synced 2024-11-23 20:24:26 +08:00
pinctrl: mediatek: introduce multiple memory bases support
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>
This commit is contained in:
parent
dafe0fbfb0
commit
10334e0bc8
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user