mirror of
https://github.com/apache/nuttx.git
synced 2026-05-22 22:20:01 +08:00
arch/risc-v/src/mpfs: Add mpfs_gpiosetevent and gpio irq handling functions
Add a function to easily enable event handling on fabric and mss gpios. This is similar to what exists e.g. for stm32 arm chips. Also fix some small bugs in mpfs_configgpio related to IRQ bits configuration Signed-off-by: Jukka Laitinen <jukkax@ssrc.tii.ae>
This commit is contained in:
committed by
Xiang Xiao
parent
412539e66c
commit
ba1b8d0712
@@ -27,18 +27,137 @@
|
||||
#include "riscv_internal.h"
|
||||
#include "hardware/mpfs_gpio.h"
|
||||
#include "mpfs_gpio.h"
|
||||
#include <arch/barriers.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
static uintptr_t g_gpio_base[] =
|
||||
struct gpio_callback_s
|
||||
{
|
||||
xcpt_t callback;
|
||||
void *arg;
|
||||
gpio_pinset_t cfgset;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const uintptr_t g_gpio_base[] =
|
||||
{
|
||||
MPFS_GPIO0_LO_BASE, /* Bank-0 Normal GPIO */
|
||||
MPFS_GPIO1_LO_BASE, /* Bank-1 Normal GPIO */
|
||||
MPFS_GPIO2_LO_BASE /* Bank-2 Fabric only */
|
||||
};
|
||||
|
||||
/* The GPIO interrupts are multiplexed. Total GPIO interrupts are 41.
|
||||
* 41 = (14 from GPIO0 + 24 from GPIO1 + 3 non direct interrupts)
|
||||
* GPIO2 interrupts are not available by default.
|
||||
* Setting the corresponding bitcin GPIO_INTERRUPT_FAB_CR(31:0) will enable
|
||||
* GPIO2(31:0) corresponding interrupt on PLIC.
|
||||
*
|
||||
* PLIC | GPIO_INTERRUPT_FAB_CR
|
||||
* | 0 1
|
||||
* -----------------------------------
|
||||
* 0 | GPIO0 bit 0 GPIO2 bit 0
|
||||
* 1 | GPIO0 bit 1 GPIO2 bit 1
|
||||
* . |
|
||||
* . |
|
||||
* 12 | GPIO0 bit 12 GPIO2 bit 12
|
||||
* 13 | GPIO0 bit 13 GPIO2 bit 13
|
||||
* 14 | GPIO1 bit 0 GPIO2 bit 14
|
||||
* 15 | GPIO1 bit 1 GPIO2 bit 15
|
||||
* . |
|
||||
* . |
|
||||
* . |
|
||||
* 30 | GPIO1 bit 16 GPIO2 bit 30
|
||||
* 31 | GPIO1 bit 17 GPIO2 bit 31
|
||||
* 32 | GPIO1 bit 18
|
||||
* 33 | GPIO1 bit 19
|
||||
* 34 | GPIO1 bit 20
|
||||
* 35 | GPIO1 bit 21
|
||||
* 36 | GPIO1 bit 22
|
||||
* 37 | GPIO1 bit 23
|
||||
* 38 Or of all GPIO0 interrupts who do not have a direct connection enabled
|
||||
* 39 Or of all GPIO1 interrupts who do not have a direct connection enabled
|
||||
* 40 Or of all GPIO2 interrupts who do not have a direct connection enabled
|
||||
*/
|
||||
|
||||
/* IRQ handlers for GPIO2 (FABRIC) */
|
||||
|
||||
static struct gpio_callback_s g_fab_gpio_callbacks[GPIO_BANK2_NUM_PINS];
|
||||
|
||||
/* IRQ handlers for GPIO0 and GPIO1 (MSSIO) */
|
||||
|
||||
static struct gpio_callback_s g_mss_gpio_callbacks[GPIO_BANK0_NUM_PINS +
|
||||
GPIO_BANK1_NUM_PINS];
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
static void mpfs_gpio_irq_clear(int bank, int pin)
|
||||
{
|
||||
putreg32(1 << pin, g_gpio_base[bank] + MPFS_GPIO_INTR_OFFSET);
|
||||
__DMB();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Interrupt Service Routines - Dispatchers
|
||||
****************************************************************************/
|
||||
|
||||
static int mpfs_gpio_isr(int irq, void *context, void *arg)
|
||||
{
|
||||
uint8_t irq_n = irq - MPFS_IRQ_GPIO02_BIT0;
|
||||
int ret = OK;
|
||||
|
||||
uint8_t mss_bank = irq_n < GPIO_BANK1_NUM_PINS ? 0 : 1;
|
||||
uint8_t pin = mss_bank == 1 ? irq_n - GPIO_BANK0_NUM_PINS : irq_n;
|
||||
uint32_t event_reg;
|
||||
struct gpio_callback_s *cb;
|
||||
|
||||
/* if mss gpio interrupt is enabled and there is an event */
|
||||
|
||||
/* bank 0 and bank 1 pins */
|
||||
|
||||
cb = &g_mss_gpio_callbacks[irq_n];
|
||||
event_reg = getreg32(g_gpio_base[mss_bank] + MPFS_GPIO_INTR_OFFSET);
|
||||
|
||||
/* if the callback is registered and there is an interrupt on the mss_pin */
|
||||
|
||||
if (cb->callback != NULL && (event_reg & (1 << pin)) != 0)
|
||||
{
|
||||
/* clear the pending interrupt */
|
||||
|
||||
mpfs_gpio_irq_clear(mss_bank, pin);
|
||||
|
||||
/* dispatch the interrupt to the handler */
|
||||
|
||||
ret = cb->callback(irq, context, cb->arg);
|
||||
}
|
||||
|
||||
/* handle the muxed gpio bank2 interrupt */
|
||||
|
||||
if (irq_n < GPIO_BANK2_NUM_PINS)
|
||||
{
|
||||
cb = &g_fab_gpio_callbacks[irq_n];
|
||||
event_reg = getreg32(g_gpio_base[2] + MPFS_GPIO_INTR_OFFSET);
|
||||
if (cb->callback != NULL && (event_reg & (1 << pin)) != 0)
|
||||
{
|
||||
/* clear the pending interrupt */
|
||||
|
||||
mpfs_gpio_irq_clear(2, pin);
|
||||
|
||||
/* dispatch the interrupt to the handler */
|
||||
|
||||
ret = cb->callback(irq, context, cb->arg);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
@@ -112,19 +231,24 @@ int mpfs_configgpio(gpio_pinset_t cfgset)
|
||||
cfg |= GPIO_CONFIG_EN_OE_BUF;
|
||||
}
|
||||
|
||||
if (cfgset & GPIO_IRQ_ENABLE)
|
||||
{
|
||||
cfg |= GPIO_CONFIG_EN_INT;
|
||||
|
||||
/* Clear irq bit */
|
||||
|
||||
putreg32(1 << pin, baseaddr + MPFS_GPIO_INTR_OFFSET);
|
||||
}
|
||||
|
||||
/* set irq mode bits */
|
||||
|
||||
irq_mode &= 7;
|
||||
cfg |= irq_mode << 5;
|
||||
irq_mode &= GPIO_CONFIG_INT_MASK;
|
||||
cfg |= irq_mode << GPIO_CONFIG_INT_SHIFT;
|
||||
|
||||
/* set/clear irq enable */
|
||||
|
||||
if (cfgset & GPIO_IRQ_ENABLE)
|
||||
{
|
||||
/* clear irq before enabling */
|
||||
|
||||
mpfs_gpio_irq_clear(bank, pin);
|
||||
cfg |= GPIO_CONFIG_EN_INT;
|
||||
}
|
||||
else
|
||||
{
|
||||
cfg &= ~GPIO_CONFIG_EN_INT;
|
||||
}
|
||||
|
||||
putreg32(cfg, baseaddr);
|
||||
|
||||
@@ -202,3 +326,145 @@ bool mpfs_gpioread(gpio_pinset_t pinset)
|
||||
return ((getreg32(baseaddr + MPFS_GPIO_GPIN_OFFSET) & (1 << pin)) ? 1 : 0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mpfs_gpiosetevent
|
||||
*
|
||||
* Description:
|
||||
* Sets/clears GPIO based event and interrupt triggers.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int mpfs_gpiosetevent(gpio_pinset_t pinset, bool risingedge,
|
||||
bool fallingedge, bool high, bool low, bool event,
|
||||
xcpt_t func, void *arg)
|
||||
{
|
||||
uint8_t pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT;
|
||||
uint8_t bank = (pinset & GPIO_BANK_MASK) >> GPIO_BANK_SHIFT;
|
||||
bool edge = risingedge || fallingedge;
|
||||
bool level = high || low;
|
||||
|
||||
uint16_t irq_n = bank == 1 ? pin + GPIO_BANK0_NUM_PINS : pin;
|
||||
uint16_t plic_irq;
|
||||
struct gpio_callback_s *cb;
|
||||
int ret;
|
||||
|
||||
if (bank > 2 || /* invalid bank */
|
||||
(edge && level) || /* edge and level irq at the same */
|
||||
(high && low) || /* level high and low at the same */
|
||||
irq_n >= GPIO_BANK0_NUM_PINS + GPIO_BANK1_NUM_PINS ||
|
||||
(bank == 2 && irq_n >= GPIO_BANK2_NUM_PINS))
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* if func is NULL, make sure to disable interrupt */
|
||||
|
||||
if (func == NULL)
|
||||
{
|
||||
risingedge = false;
|
||||
fallingedge = false;
|
||||
high = false;
|
||||
low = false;
|
||||
}
|
||||
|
||||
cb = bank == 2 ? &g_fab_gpio_callbacks[irq_n]
|
||||
: &g_mss_gpio_callbacks[irq_n];
|
||||
|
||||
/* make sure the GPIO is input */
|
||||
|
||||
pinset &= ~GPIO_MODE_MASK;
|
||||
pinset |= GPIO_INPUT;
|
||||
|
||||
/* set the irq mask for the gpio */
|
||||
|
||||
pinset &= ~GPIO_IRQ_MASK;
|
||||
|
||||
if (edge)
|
||||
{
|
||||
if (risingedge && fallingedge)
|
||||
{
|
||||
pinset |= GPIO_IRQ_EDGE_BOTH;
|
||||
}
|
||||
else if (fallingedge)
|
||||
{
|
||||
pinset |= GPIO_IRQ_EDGE_NEG;
|
||||
}
|
||||
else if (risingedge)
|
||||
{
|
||||
pinset |= GPIO_IRQ_EDGE_POS;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (high)
|
||||
{
|
||||
pinset |= GPIO_IRQ_HIGH;
|
||||
}
|
||||
else if (low)
|
||||
{
|
||||
pinset |= GPIO_IRQ_LOW;
|
||||
}
|
||||
}
|
||||
|
||||
/* if event, set ENABLE bit, otherwise leave it 0 */
|
||||
|
||||
if (event)
|
||||
{
|
||||
pinset |= GPIO_IRQ_ENABLE;
|
||||
}
|
||||
|
||||
if (mpfs_configgpio(pinset) != OK)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* set/reset the GPIO_INTERRUPT_FAB_CR for bank 2 */
|
||||
|
||||
if (bank == 2)
|
||||
{
|
||||
if (event)
|
||||
{
|
||||
modifyreg32(MPFS_SYSREG_BASE +
|
||||
MPFS_SYSREG_GPIO_INTERRUPT_FAB_CR_OFFSET,
|
||||
0, SYSREG_GPIO_INTERRUPT_FAB_CR(pin));
|
||||
}
|
||||
else
|
||||
{
|
||||
modifyreg32(MPFS_SYSREG_BASE +
|
||||
MPFS_SYSREG_GPIO_INTERRUPT_FAB_CR_OFFSET,
|
||||
SYSREG_GPIO_INTERRUPT_FAB_CR(pin), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* calculate the plic vector location from gpio irq number */
|
||||
|
||||
plic_irq = irq_n + MPFS_IRQ_GPIO02_BIT0;
|
||||
|
||||
/* attach the plic irq */
|
||||
|
||||
if (event)
|
||||
{
|
||||
ret = irq_attach(plic_irq, mpfs_gpio_isr, NULL);
|
||||
if (ret == OK)
|
||||
{
|
||||
cb->callback = func;
|
||||
cb->arg = arg;
|
||||
|
||||
up_enable_irq(plic_irq);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = irq_detach(plic_irq);
|
||||
if (ret == OK)
|
||||
{
|
||||
cb->callback = NULL;
|
||||
}
|
||||
|
||||
/* disable the irq even in case detach fails */
|
||||
|
||||
up_disable_irq(plic_irq);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -138,6 +138,10 @@
|
||||
#define GPIO_BANK1 (1 << GPIO_BANK_SHIFT)
|
||||
#define GPIO_BANK2 (2 << GPIO_BANK_SHIFT)
|
||||
|
||||
#define GPIO_BANK0_NUM_PINS 14
|
||||
#define GPIO_BANK1_NUM_PINS 24
|
||||
#define GPIO_BANK2_NUM_PINS 32
|
||||
|
||||
/* This identifies the bit in the bank:
|
||||
*
|
||||
* 1111 1100 0000 0000
|
||||
@@ -256,6 +260,32 @@ void mpfs_gpiowrite(gpio_pinset_t pinset, bool value);
|
||||
|
||||
bool mpfs_gpioread(gpio_pinset_t pinset);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mpfs_gpiosetevent
|
||||
*
|
||||
* Description:
|
||||
* Sets/clears GPIO based event and interrupt triggers.
|
||||
*
|
||||
* Input Parameters:
|
||||
* - pinset: GPIO pin configuration
|
||||
* - risingedge: Enables interrupt on rising edges
|
||||
* - fallingedge: Enables interrupt on falling edges
|
||||
* - high: Enables interrupt on level high
|
||||
* - low: Enables interrupt on level low
|
||||
* - event: Generate event when set
|
||||
* - func: When non-NULL, generate interrupt
|
||||
* - arg: Argument passed to the interrupt callback
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno value on failure indicating the
|
||||
* nature of the failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int mpfs_gpiosetevent(gpio_pinset_t pinset, bool risingedge,
|
||||
bool fallingedge, bool high, bool low, bool event,
|
||||
xcpt_t func, void *arg);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mpfs_gpio_initialize
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user