mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-19 03:15:00 +00:00
pinctrl: sunxi: remove struct sunxi_gpio
So far every Allwinner SoC used the same basic pincontroller/GPIO register frame, and just differed by the number of implemented banks and pins, plus some special functionality from time to time. However the D1 and successors use a slightly different pinctrl register layout. Use that opportunity to drop "struct sunxi_gpio", that described that MMIO frame in a C struct. That approach is somewhat frowned upon in the Linux world and rarely used there, though still popular with U-Boot. Switching from a C struct to a "base address plus offset" approach allows to switch between the two models more dynamically, without reverting to preprocessor macros and #ifdef's. Model the pinctrl MMIO register frame in the usual "base address + offset" way, and replace a hard-to-parse CPP macro with a more readable static function. All the users get converted over. There are no functional changes at this point, it just prepares the stages for the D1 and friends. Signed-off-by: Andre Przywara <andre.przywara@arm.com> Reviewed-by: Samuel Holland <samuel@sholland.org> Tested-by: Samuel Holland <samuel@sholland.org>
This commit is contained in:
parent
316ec7ffbd
commit
30097ee3d2
3 changed files with 66 additions and 76 deletions
|
@ -31,13 +31,6 @@
|
||||||
#define SUNXI_GPIO_H 7
|
#define SUNXI_GPIO_H 7
|
||||||
#define SUNXI_GPIO_I 8
|
#define SUNXI_GPIO_I 8
|
||||||
|
|
||||||
/*
|
|
||||||
* This defines the number of GPIO banks for the _main_ GPIO controller.
|
|
||||||
* You should fix up the padding in struct sunxi_gpio_reg below if you
|
|
||||||
* change this.
|
|
||||||
*/
|
|
||||||
#define SUNXI_GPIO_BANKS 9
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sun6i/sun8i and later SoCs have an additional GPIO controller (R_PIO)
|
* sun6i/sun8i and later SoCs have an additional GPIO controller (R_PIO)
|
||||||
* at a different register offset.
|
* at a different register offset.
|
||||||
|
@ -55,32 +48,11 @@
|
||||||
#define SUNXI_GPIO_M 12
|
#define SUNXI_GPIO_M 12
|
||||||
#define SUNXI_GPIO_N 13
|
#define SUNXI_GPIO_N 13
|
||||||
|
|
||||||
struct sunxi_gpio {
|
|
||||||
u32 cfg[4];
|
|
||||||
u32 dat;
|
|
||||||
u32 drv[2];
|
|
||||||
u32 pull[2];
|
|
||||||
};
|
|
||||||
|
|
||||||
/* gpio interrupt control */
|
|
||||||
struct sunxi_gpio_int {
|
|
||||||
u32 cfg[3];
|
|
||||||
u32 ctl;
|
|
||||||
u32 sta;
|
|
||||||
u32 deb; /* interrupt debounce */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sunxi_gpio_reg {
|
|
||||||
struct sunxi_gpio gpio_bank[SUNXI_GPIO_BANKS];
|
|
||||||
u8 res[0xbc];
|
|
||||||
struct sunxi_gpio_int gpio_int;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define SUN50I_H6_GPIO_POW_MOD_SEL 0x340
|
#define SUN50I_H6_GPIO_POW_MOD_SEL 0x340
|
||||||
#define SUN50I_H6_GPIO_POW_MOD_VAL 0x348
|
#define SUN50I_H6_GPIO_POW_MOD_VAL 0x348
|
||||||
|
|
||||||
/* GPIO bank sizes */
|
|
||||||
#define SUNXI_GPIOS_PER_BANK 32
|
#define SUNXI_GPIOS_PER_BANK 32
|
||||||
|
#define SUNXI_PINCTRL_BANK_SIZE 0x24
|
||||||
|
|
||||||
#define SUNXI_GPIO_NEXT(__gpio) \
|
#define SUNXI_GPIO_NEXT(__gpio) \
|
||||||
((__gpio##_START) + SUNXI_GPIOS_PER_BANK)
|
((__gpio##_START) + SUNXI_GPIOS_PER_BANK)
|
||||||
|
@ -200,19 +172,19 @@ enum sunxi_gpio_number {
|
||||||
#define SUNXI_GPIO_AXP0_GPIO_COUNT 6
|
#define SUNXI_GPIO_AXP0_GPIO_COUNT 6
|
||||||
|
|
||||||
struct sunxi_gpio_plat {
|
struct sunxi_gpio_plat {
|
||||||
struct sunxi_gpio *regs;
|
void *regs;
|
||||||
char bank_name[3];
|
char bank_name[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* prototypes for the non-DM GPIO/pinctrl functions, used in the SPL */
|
/* prototypes for the non-DM GPIO/pinctrl functions, used in the SPL */
|
||||||
void sunxi_gpio_set_cfgbank(struct sunxi_gpio *pio, int bank_offset, u32 val);
|
void sunxi_gpio_set_cfgbank(void *bank_base, int pin_offset, u32 val);
|
||||||
void sunxi_gpio_set_cfgpin(u32 pin, u32 val);
|
void sunxi_gpio_set_cfgpin(u32 pin, u32 val);
|
||||||
int sunxi_gpio_get_cfgbank(struct sunxi_gpio *pio, int bank_offset);
|
int sunxi_gpio_get_cfgbank(void *bank_base, int pin_offset);
|
||||||
int sunxi_gpio_get_cfgpin(u32 pin);
|
int sunxi_gpio_get_cfgpin(u32 pin);
|
||||||
void sunxi_gpio_set_drv(u32 pin, u32 val);
|
void sunxi_gpio_set_drv(u32 pin, u32 val);
|
||||||
void sunxi_gpio_set_drv_bank(struct sunxi_gpio *pio, u32 bank_offset, u32 val);
|
void sunxi_gpio_set_drv_bank(void *bank_base, u32 pin_offset, u32 val);
|
||||||
void sunxi_gpio_set_pull(u32 pin, u32 val);
|
void sunxi_gpio_set_pull(u32 pin, u32 val);
|
||||||
void sunxi_gpio_set_pull_bank(struct sunxi_gpio *pio, int bank_offset, u32 val);
|
void sunxi_gpio_set_pull_bank(void *bank_base, int pin_offset, u32 val);
|
||||||
int sunxi_name_to_gpio(const char *name);
|
int sunxi_name_to_gpio(const char *name);
|
||||||
|
|
||||||
#if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO
|
#if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO
|
||||||
|
|
|
@ -29,45 +29,61 @@
|
||||||
* =======================================================================
|
* =======================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define BANK_TO_GPIO(bank) (((bank) < SUNXI_GPIO_L) ? \
|
|
||||||
&((struct sunxi_gpio_reg *)SUNXI_PIO_BASE)->gpio_bank[bank] : \
|
|
||||||
&((struct sunxi_gpio_reg *)SUNXI_R_PIO_BASE)->gpio_bank[(bank) - SUNXI_GPIO_L])
|
|
||||||
|
|
||||||
#define GPIO_BANK(pin) ((pin) >> 5)
|
#define GPIO_BANK(pin) ((pin) >> 5)
|
||||||
#define GPIO_NUM(pin) ((pin) & 0x1f)
|
#define GPIO_NUM(pin) ((pin) & 0x1f)
|
||||||
|
|
||||||
|
#define GPIO_CFG_REG_OFFSET 0x00
|
||||||
#define GPIO_CFG_INDEX(pin) (((pin) & 0x1f) >> 3)
|
#define GPIO_CFG_INDEX(pin) (((pin) & 0x1f) >> 3)
|
||||||
#define GPIO_CFG_OFFSET(pin) ((((pin) & 0x1f) & 0x7) << 2)
|
#define GPIO_CFG_OFFSET(pin) ((((pin) & 0x1f) & 0x7) << 2)
|
||||||
|
|
||||||
|
#define GPIO_DAT_REG_OFFSET 0x10
|
||||||
|
|
||||||
|
#define GPIO_DRV_REG_OFFSET 0x14
|
||||||
#define GPIO_DRV_INDEX(pin) (((pin) & 0x1f) >> 4)
|
#define GPIO_DRV_INDEX(pin) (((pin) & 0x1f) >> 4)
|
||||||
#define GPIO_DRV_OFFSET(pin) ((((pin) & 0x1f) & 0xf) << 1)
|
#define GPIO_DRV_OFFSET(pin) ((((pin) & 0x1f) & 0xf) << 1)
|
||||||
|
|
||||||
|
#define GPIO_PULL_REG_OFFSET 0x1c
|
||||||
#define GPIO_PULL_INDEX(pin) (((pin) & 0x1f) >> 4)
|
#define GPIO_PULL_INDEX(pin) (((pin) & 0x1f) >> 4)
|
||||||
#define GPIO_PULL_OFFSET(pin) ((((pin) & 0x1f) & 0xf) << 1)
|
#define GPIO_PULL_OFFSET(pin) ((((pin) & 0x1f) & 0xf) << 1)
|
||||||
|
|
||||||
void sunxi_gpio_set_cfgbank(struct sunxi_gpio *pio, int bank_offset, u32 val)
|
static void* BANK_TO_GPIO(int bank)
|
||||||
{
|
{
|
||||||
u32 index = GPIO_CFG_INDEX(bank_offset);
|
void *pio_base;
|
||||||
u32 offset = GPIO_CFG_OFFSET(bank_offset);
|
|
||||||
|
|
||||||
clrsetbits_le32(&pio->cfg[index], 0xf << offset, val << offset);
|
if (bank < SUNXI_GPIO_L) {
|
||||||
|
pio_base = (void *)(uintptr_t)SUNXI_PIO_BASE;
|
||||||
|
} else {
|
||||||
|
pio_base = (void *)(uintptr_t)SUNXI_R_PIO_BASE;
|
||||||
|
bank -= SUNXI_GPIO_L;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pio_base + bank * SUNXI_PINCTRL_BANK_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sunxi_gpio_set_cfgbank(void *bank_base, int pin_offset, u32 val)
|
||||||
|
{
|
||||||
|
u32 index = GPIO_CFG_INDEX(pin_offset);
|
||||||
|
u32 offset = GPIO_CFG_OFFSET(pin_offset);
|
||||||
|
|
||||||
|
clrsetbits_le32(bank_base + GPIO_CFG_REG_OFFSET + index * 4,
|
||||||
|
0xfU << offset, val << offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sunxi_gpio_set_cfgpin(u32 pin, u32 val)
|
void sunxi_gpio_set_cfgpin(u32 pin, u32 val)
|
||||||
{
|
{
|
||||||
u32 bank = GPIO_BANK(pin);
|
u32 bank = GPIO_BANK(pin);
|
||||||
struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
|
void *pio = BANK_TO_GPIO(bank);
|
||||||
|
|
||||||
sunxi_gpio_set_cfgbank(pio, pin, val);
|
sunxi_gpio_set_cfgbank(pio, GPIO_NUM(pin), val);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sunxi_gpio_get_cfgbank(struct sunxi_gpio *pio, int bank_offset)
|
int sunxi_gpio_get_cfgbank(void *bank_base, int pin_offset)
|
||||||
{
|
{
|
||||||
u32 index = GPIO_CFG_INDEX(bank_offset);
|
u32 index = GPIO_CFG_INDEX(pin_offset);
|
||||||
u32 offset = GPIO_CFG_OFFSET(bank_offset);
|
u32 offset = GPIO_CFG_OFFSET(pin_offset);
|
||||||
u32 cfg;
|
u32 cfg;
|
||||||
|
|
||||||
cfg = readl(&pio->cfg[index]);
|
cfg = readl(bank_base + GPIO_CFG_REG_OFFSET + index * 4);
|
||||||
cfg >>= offset;
|
cfg >>= offset;
|
||||||
|
|
||||||
return cfg & 0xf;
|
return cfg & 0xf;
|
||||||
|
@ -76,54 +92,56 @@ int sunxi_gpio_get_cfgbank(struct sunxi_gpio *pio, int bank_offset)
|
||||||
int sunxi_gpio_get_cfgpin(u32 pin)
|
int sunxi_gpio_get_cfgpin(u32 pin)
|
||||||
{
|
{
|
||||||
u32 bank = GPIO_BANK(pin);
|
u32 bank = GPIO_BANK(pin);
|
||||||
struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
|
void *bank_base = BANK_TO_GPIO(bank);
|
||||||
|
|
||||||
return sunxi_gpio_get_cfgbank(pio, pin);
|
return sunxi_gpio_get_cfgbank(bank_base, GPIO_NUM(pin));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sunxi_gpio_set_value_bank(struct sunxi_gpio *pio,
|
static void sunxi_gpio_set_value_bank(void *bank_base, int pin, bool set)
|
||||||
int pin, bool set)
|
|
||||||
{
|
{
|
||||||
u32 mask = 1U << pin;
|
u32 mask = 1U << pin;
|
||||||
|
|
||||||
clrsetbits_le32(&pio->dat, set ? 0 : mask, set ? mask : 0);
|
clrsetbits_le32(bank_base + GPIO_DAT_REG_OFFSET,
|
||||||
|
set ? 0 : mask, set ? mask : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sunxi_gpio_get_value_bank(struct sunxi_gpio *pio, int pin)
|
static int sunxi_gpio_get_value_bank(void *bank_base, int pin)
|
||||||
{
|
{
|
||||||
return !!(readl(&pio->dat) & (1U << pin));
|
return !!(readl(bank_base + GPIO_DAT_REG_OFFSET) & (1U << pin));
|
||||||
}
|
}
|
||||||
|
|
||||||
void sunxi_gpio_set_drv(u32 pin, u32 val)
|
void sunxi_gpio_set_drv(u32 pin, u32 val)
|
||||||
{
|
{
|
||||||
u32 bank = GPIO_BANK(pin);
|
u32 bank = GPIO_BANK(pin);
|
||||||
struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
|
void *bank_base = BANK_TO_GPIO(bank);
|
||||||
|
|
||||||
sunxi_gpio_set_drv_bank(pio, pin, val);
|
sunxi_gpio_set_drv_bank(bank_base, GPIO_NUM(pin), val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sunxi_gpio_set_drv_bank(struct sunxi_gpio *pio, u32 bank_offset, u32 val)
|
void sunxi_gpio_set_drv_bank(void *bank_base, u32 pin_offset, u32 val)
|
||||||
{
|
{
|
||||||
u32 index = GPIO_DRV_INDEX(bank_offset);
|
u32 index = GPIO_DRV_INDEX(pin_offset);
|
||||||
u32 offset = GPIO_DRV_OFFSET(bank_offset);
|
u32 offset = GPIO_DRV_OFFSET(pin_offset);
|
||||||
|
|
||||||
clrsetbits_le32(&pio->drv[index], 0x3 << offset, val << offset);
|
clrsetbits_le32(bank_base + GPIO_DRV_REG_OFFSET + index * 4,
|
||||||
|
0x3U << offset, val << offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sunxi_gpio_set_pull(u32 pin, u32 val)
|
void sunxi_gpio_set_pull(u32 pin, u32 val)
|
||||||
{
|
{
|
||||||
u32 bank = GPIO_BANK(pin);
|
u32 bank = GPIO_BANK(pin);
|
||||||
struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
|
void *bank_base = BANK_TO_GPIO(bank);
|
||||||
|
|
||||||
sunxi_gpio_set_pull_bank(pio, pin, val);
|
sunxi_gpio_set_pull_bank(bank_base, GPIO_NUM(pin), val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sunxi_gpio_set_pull_bank(struct sunxi_gpio *pio, int bank_offset, u32 val)
|
void sunxi_gpio_set_pull_bank(void *bank_base, int pin_offset, u32 val)
|
||||||
{
|
{
|
||||||
u32 index = GPIO_PULL_INDEX(bank_offset);
|
u32 index = GPIO_PULL_INDEX(pin_offset);
|
||||||
u32 offset = GPIO_PULL_OFFSET(bank_offset);
|
u32 offset = GPIO_PULL_OFFSET(pin_offset);
|
||||||
|
|
||||||
clrsetbits_le32(&pio->pull[index], 0x3 << offset, val << offset);
|
clrsetbits_le32(bank_base + GPIO_PULL_REG_OFFSET + index * 4,
|
||||||
|
0x3U << offset, val << offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -133,7 +151,7 @@ void sunxi_gpio_set_pull_bank(struct sunxi_gpio *pio, int bank_offset, u32 val)
|
||||||
static void sunxi_gpio_set_value(u32 pin, bool set)
|
static void sunxi_gpio_set_value(u32 pin, bool set)
|
||||||
{
|
{
|
||||||
u32 bank = GPIO_BANK(pin);
|
u32 bank = GPIO_BANK(pin);
|
||||||
struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
|
void *pio = BANK_TO_GPIO(bank);
|
||||||
|
|
||||||
sunxi_gpio_set_value_bank(pio, GPIO_NUM(pin), set);
|
sunxi_gpio_set_value_bank(pio, GPIO_NUM(pin), set);
|
||||||
}
|
}
|
||||||
|
@ -141,7 +159,7 @@ static void sunxi_gpio_set_value(u32 pin, bool set)
|
||||||
static int sunxi_gpio_get_value(u32 pin)
|
static int sunxi_gpio_get_value(u32 pin)
|
||||||
{
|
{
|
||||||
u32 bank = GPIO_BANK(pin);
|
u32 bank = GPIO_BANK(pin);
|
||||||
struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
|
void *pio = BANK_TO_GPIO(bank);
|
||||||
|
|
||||||
return sunxi_gpio_get_value_bank(pio, GPIO_NUM(pin));
|
return sunxi_gpio_get_value_bank(pio, GPIO_NUM(pin));
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ struct sunxi_pinctrl_desc {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sunxi_pinctrl_plat {
|
struct sunxi_pinctrl_plat {
|
||||||
struct sunxi_gpio __iomem *base;
|
void __iomem *base;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int sunxi_pinctrl_get_pins_count(struct udevice *dev)
|
static int sunxi_pinctrl_get_pins_count(struct udevice *dev)
|
||||||
|
@ -86,8 +86,8 @@ static int sunxi_pinctrl_pinmux_set(struct udevice *dev, uint pin_selector,
|
||||||
sunxi_pinctrl_get_function_name(dev, func_selector),
|
sunxi_pinctrl_get_function_name(dev, func_selector),
|
||||||
desc->functions[func_selector].mux);
|
desc->functions[func_selector].mux);
|
||||||
|
|
||||||
sunxi_gpio_set_cfgbank(plat->base + bank, pin,
|
sunxi_gpio_set_cfgbank(plat->base + bank * SUNXI_PINCTRL_BANK_SIZE,
|
||||||
desc->functions[func_selector].mux);
|
pin, desc->functions[func_selector].mux);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ static const struct pinconf_param sunxi_pinctrl_pinconf_params[] = {
|
||||||
static int sunxi_pinctrl_pinconf_set_pull(struct sunxi_pinctrl_plat *plat,
|
static int sunxi_pinctrl_pinconf_set_pull(struct sunxi_pinctrl_plat *plat,
|
||||||
uint bank, uint pin, uint bias)
|
uint bank, uint pin, uint bias)
|
||||||
{
|
{
|
||||||
struct sunxi_gpio *regs = &plat->base[bank];
|
void *regs = plat->base + bank * SUNXI_PINCTRL_BANK_SIZE;
|
||||||
|
|
||||||
sunxi_gpio_set_pull_bank(regs, pin, bias);
|
sunxi_gpio_set_pull_bank(regs, pin, bias);
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ static int sunxi_pinctrl_pinconf_set_pull(struct sunxi_pinctrl_plat *plat,
|
||||||
static int sunxi_pinctrl_pinconf_set_drive(struct sunxi_pinctrl_plat *plat,
|
static int sunxi_pinctrl_pinconf_set_drive(struct sunxi_pinctrl_plat *plat,
|
||||||
uint bank, uint pin, uint drive)
|
uint bank, uint pin, uint drive)
|
||||||
{
|
{
|
||||||
struct sunxi_gpio *regs = &plat->base[bank];
|
void *regs = plat->base + bank * SUNXI_PINCTRL_BANK_SIZE;
|
||||||
|
|
||||||
if (drive < 10 || drive > 40)
|
if (drive < 10 || drive > 40)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -148,7 +148,7 @@ static int sunxi_pinctrl_get_pin_muxing(struct udevice *dev, uint pin_selector,
|
||||||
struct sunxi_pinctrl_plat *plat = dev_get_plat(dev);
|
struct sunxi_pinctrl_plat *plat = dev_get_plat(dev);
|
||||||
int bank = pin_selector / SUNXI_GPIOS_PER_BANK;
|
int bank = pin_selector / SUNXI_GPIOS_PER_BANK;
|
||||||
int pin = pin_selector % SUNXI_GPIOS_PER_BANK;
|
int pin = pin_selector % SUNXI_GPIOS_PER_BANK;
|
||||||
int mux = sunxi_gpio_get_cfgbank(plat->base + bank, pin);
|
int mux = sunxi_gpio_get_cfgbank(plat->base + bank * SUNXI_PINCTRL_BANK_SIZE, pin);
|
||||||
|
|
||||||
switch (mux) {
|
switch (mux) {
|
||||||
case SUNXI_GPIO_INPUT:
|
case SUNXI_GPIO_INPUT:
|
||||||
|
@ -206,7 +206,7 @@ static int sunxi_pinctrl_bind(struct udevice *dev)
|
||||||
if (!gpio_plat)
|
if (!gpio_plat)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
gpio_plat->regs = plat->base + i;
|
gpio_plat->regs = plat->base + i * SUNXI_PINCTRL_BANK_SIZE;
|
||||||
gpio_plat->bank_name[0] = 'P';
|
gpio_plat->bank_name[0] = 'P';
|
||||||
gpio_plat->bank_name[1] = 'A' + desc->first_bank + i;
|
gpio_plat->bank_name[1] = 'A' + desc->first_bank + i;
|
||||||
gpio_plat->bank_name[2] = '\0';
|
gpio_plat->bank_name[2] = '\0';
|
||||||
|
|
Loading…
Add table
Reference in a new issue