mediatek/mt8173: Add EINT support
Add basic support to configure GPIOs to poll for external interrupts (EINT). BRANCH=none BUG=b:36786804 TEST=Boot rowan w/ serial enabled, verify coreboot and depthcharge are configured to use IRQ flow control when talking to the Cr50 TPM. Change-Id: I9d52591661a5a74ec1fd9a081f606f0a08a3a6ab Signed-off-by: Daniel Kurtz <djkurtz@chromium.org> Reviewed-on: https://review.coreboot.org/19362 Reviewed-by: Julius Werner <jwerner@chromium.org> Tested-by: build bot (Jenkins)
This commit is contained in:
parent
732618975e
commit
50340f5480
|
@ -25,6 +25,7 @@ enum {
|
||||||
MAX_GPIO_REG_BITS = 16,
|
MAX_GPIO_REG_BITS = 16,
|
||||||
MAX_GPIO_MODE_PER_REG = 5,
|
MAX_GPIO_MODE_PER_REG = 5,
|
||||||
GPIO_MODE_BITS = 3,
|
GPIO_MODE_BITS = 3,
|
||||||
|
MAX_EINT_REG_BITS = 32,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -48,6 +49,12 @@ static void pos_bit_calc_for_mode(u32 pin, u32 *pos, u32 *bit)
|
||||||
*bit = (pin % MAX_GPIO_MODE_PER_REG) * GPIO_MODE_BITS;
|
*bit = (pin % MAX_GPIO_MODE_PER_REG) * GPIO_MODE_BITS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pos_bit_calc_for_eint(u32 pin, u32 *pos, u32 *bit)
|
||||||
|
{
|
||||||
|
*pos = pin / MAX_EINT_REG_BITS;
|
||||||
|
*bit = pin % MAX_EINT_REG_BITS;
|
||||||
|
}
|
||||||
|
|
||||||
static s32 gpio_set_dir(u32 pin, u32 dir)
|
static s32 gpio_set_dir(u32 pin, u32 dir)
|
||||||
{
|
{
|
||||||
u32 pos;
|
u32 pos;
|
||||||
|
@ -175,3 +182,58 @@ void gpio_output(gpio_t gpio, int value)
|
||||||
gpio_set_dir(gpio, GPIO_DIRECTION_OUT);
|
gpio_set_dir(gpio, GPIO_DIRECTION_OUT);
|
||||||
gpio_set_mode(gpio, GPIO_MODE);
|
gpio_set_mode(gpio, GPIO_MODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int gpio_eint_poll(gpio_t gpio)
|
||||||
|
{
|
||||||
|
u32 pos;
|
||||||
|
u32 bit;
|
||||||
|
u32 status;
|
||||||
|
|
||||||
|
assert(gpio <= MAX_8173_GPIO);
|
||||||
|
|
||||||
|
pos_bit_calc_for_eint(gpio, &pos, &bit);
|
||||||
|
|
||||||
|
status = (read32(&mt8173_eint->sta.regs[pos]) >> bit) & 0x1;
|
||||||
|
|
||||||
|
if (status)
|
||||||
|
write32(&mt8173_eint->ack.regs[pos], 1 << bit);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gpio_eint_configure(gpio_t gpio, enum gpio_irq_type type)
|
||||||
|
{
|
||||||
|
u32 pos;
|
||||||
|
u32 bit, mask;
|
||||||
|
|
||||||
|
assert(gpio <= MAX_8173_GPIO);
|
||||||
|
|
||||||
|
pos_bit_calc_for_eint(gpio, &pos, &bit);
|
||||||
|
mask = 1 << bit;
|
||||||
|
|
||||||
|
/* Make it an input first. */
|
||||||
|
gpio_input_pullup(gpio);
|
||||||
|
|
||||||
|
write32(&mt8173_eint->d0en[pos], mask);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case IRQ_TYPE_EDGE_FALLING:
|
||||||
|
write32(&mt8173_eint->sens_clr.regs[pos], mask);
|
||||||
|
write32(&mt8173_eint->pol_clr.regs[pos], mask);
|
||||||
|
break;
|
||||||
|
case IRQ_TYPE_EDGE_RISING:
|
||||||
|
write32(&mt8173_eint->sens_clr.regs[pos], mask);
|
||||||
|
write32(&mt8173_eint->pol_set.regs[pos], mask);
|
||||||
|
break;
|
||||||
|
case IRQ_TYPE_LEVEL_LOW:
|
||||||
|
write32(&mt8173_eint->sens_set.regs[pos], mask);
|
||||||
|
write32(&mt8173_eint->pol_clr.regs[pos], mask);
|
||||||
|
break;
|
||||||
|
case IRQ_TYPE_LEVEL_HIGH:
|
||||||
|
write32(&mt8173_eint->sens_set.regs[pos], mask);
|
||||||
|
write32(&mt8173_eint->pol_set.regs[pos], mask);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
write32(&mt8173_eint->mask_clr.regs[pos], mask);
|
||||||
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ enum {
|
||||||
SPM_BASE = IO_PHYS + 0x6000,
|
SPM_BASE = IO_PHYS + 0x6000,
|
||||||
RGU_BASE = IO_PHYS + 0x7000,
|
RGU_BASE = IO_PHYS + 0x7000,
|
||||||
GPT_BASE = IO_PHYS + 0x8000,
|
GPT_BASE = IO_PHYS + 0x8000,
|
||||||
|
EINT_BASE = IO_PHYS + 0xB000,
|
||||||
PMIC_WRAP_BASE = IO_PHYS + 0xD000,
|
PMIC_WRAP_BASE = IO_PHYS + 0xD000,
|
||||||
CHA_DDRPHY_BASE = IO_PHYS + 0xF000,
|
CHA_DDRPHY_BASE = IO_PHYS + 0xF000,
|
||||||
CHB_DRAMCAO_BASE = IO_PHYS + 0x11000,
|
CHB_DRAMCAO_BASE = IO_PHYS + 0x11000,
|
||||||
|
|
|
@ -87,4 +87,55 @@ void gpio_set_pull(gpio_t gpio, enum pull_enable enable,
|
||||||
void gpio_set_mode(gpio_t gpio, int mode);
|
void gpio_set_mode(gpio_t gpio, int mode);
|
||||||
void gpio_init(enum external_power);
|
void gpio_init(enum external_power);
|
||||||
|
|
||||||
|
enum gpio_irq_type {
|
||||||
|
IRQ_TYPE_EDGE_RISING,
|
||||||
|
IRQ_TYPE_EDGE_FALLING,
|
||||||
|
IRQ_TYPE_LEVEL_HIGH,
|
||||||
|
IRQ_TYPE_LEVEL_LOW,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct eint_section {
|
||||||
|
uint32_t regs[7];
|
||||||
|
uint32_t align1[9];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct eint_regs {
|
||||||
|
struct eint_section sta;
|
||||||
|
struct eint_section ack;
|
||||||
|
struct eint_section mask;
|
||||||
|
struct eint_section mask_set;
|
||||||
|
struct eint_section mask_clr;
|
||||||
|
struct eint_section sens;
|
||||||
|
struct eint_section sens_set;
|
||||||
|
struct eint_section sens_clr;
|
||||||
|
struct eint_section soft;
|
||||||
|
struct eint_section soft_set;
|
||||||
|
struct eint_section soft_clr;
|
||||||
|
struct eint_section rsv00;
|
||||||
|
struct eint_section pol;
|
||||||
|
struct eint_section pol_set;
|
||||||
|
struct eint_section pol_clr;
|
||||||
|
struct eint_section rsv01;
|
||||||
|
uint32_t d0en[7];
|
||||||
|
uint32_t rsv02;
|
||||||
|
uint32_t d1en[7];
|
||||||
|
};
|
||||||
|
|
||||||
|
check_member(eint_regs, d1en, 0x420);
|
||||||
|
|
||||||
|
static struct eint_regs *const mt8173_eint = (void *)(EINT_BASE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Firmware never enables interrupts on this platform. This function
|
||||||
|
* reads current EINT status and clears the pending interrupt.
|
||||||
|
*
|
||||||
|
* Returns 1 if the interrupt was pending, else 0.
|
||||||
|
*/
|
||||||
|
int gpio_eint_poll(gpio_t gpio);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configure a GPIO to handle external interrupts (EINT) of given irq type.
|
||||||
|
*/
|
||||||
|
void gpio_eint_configure(gpio_t gpio, enum gpio_irq_type type);
|
||||||
|
|
||||||
#endif /* SOC_MEDIATEK_MT8173_GPIO_H */
|
#endif /* SOC_MEDIATEK_MT8173_GPIO_H */
|
||||||
|
|
Loading…
Reference in New Issue