arm64/a64: Fix PIO Interrupt

The current implementation of PIO Interrupt for Allwinner A64 is incomplete. This PR fixes the implementation of PIO Interrupt for all supported PIO Ports (PB, PG and PH).

### Modified Files

`arch/arm64/src/a64/a64_pio.c`, `a64_pio.h`: Add implementation of PIO Interrupt

`arch/arm64/include/a64/irq.h`: Add IRQ for PIO Port PH

`arch/arm64/src/a64/hardware/a64_pio.h`: Fix addresses of PIO Interrupt Registers
This commit is contained in:
Lee Lup Yuen 2023-01-05 13:49:56 +08:00 committed by Xiang Xiao
parent 4752dcd12a
commit 6d70b91a55
4 changed files with 193 additions and 26 deletions

View file

@ -85,6 +85,8 @@
#define A64_IRQ_TIMER0 (50) /* 0x00C8 Timer 0 interrupt */
#define A64_IRQ_TIMER1 (51) /* 0x00CC Timer 1 interrupt */
#define A64_IRQ_PH_EINT (53) /* 0x00C4 PH_EINT interrupt */
#define A64_IRQ_AC_DET (60) /* 0x00F0 Audio Codec earphone detect interrupt */
#define A64_IRQ_AUDIO_CODEC (61) /* 0x00F4 Audio Codec interrupt */
#define A64_IRQ_KEYADC (62) /* 0x00F8 KEYADC interrupt */

View file

@ -42,7 +42,7 @@
****************************************************************************/
/****************************************************************************
* Name: a64_pio_pin
* Name: a64_pio_port
*
* Description:
* Return the Port Number for the bit-encoded description of the pin.
@ -63,6 +63,42 @@ static inline int a64_pio_port(pio_pinset_t cfgset)
return port;
}
/****************************************************************************
* Name: a64_pio_ext
*
* Description:
* Return the External Port Number for the bit-encoded description of the
* pin.
*
* Input Parameters:
* cfgset - Bit-encoded description of a pin that supports External
* Interrupts
*
* Returned Value:
* 0 for Port B, 1 for Port G, 2 for Port H, -1 otherwise
*
****************************************************************************/
static inline int a64_pio_ext(pio_pinset_t cfgset)
{
int port = (cfgset & PIO_PORT_MASK) >> PIO_PORT_SHIFT;
switch (port)
{
case PIO_REG_PORTB:
return 0;
case PIO_REG_PORTG:
return 1;
case PIO_REG_PORTH:
return 2;
default:
return -1; /* External Interrupt not supported for the Port */
}
}
/****************************************************************************
* Name: a64_pio_pin
*
@ -85,6 +121,53 @@ static inline int a64_pio_pin(pio_pinset_t cfgset)
return pin;
}
/****************************************************************************
* Name: a64_pio_irq
*
* Description:
* Enable or disable the interrupt for specified PIO pin. Only Ports B, G
* and H are supported for interrupts.
*
* Input Parameters:
* pinset - Bit-encoded description of a pin. Port should be B, G or H.
* enable - True to enable interrupt; False to disable.
*
* Returned Value:
* Zero (OK) on success; -EINVAL if pin is not from Port B, G or H.
*
****************************************************************************/
static int a64_pio_irq(pio_pinset_t pinset, bool enable)
{
const unsigned int port = a64_pio_port(pinset);
const unsigned int ext = a64_pio_ext(pinset);
const unsigned int pin = a64_pio_pin(pinset);
const uint32_t pin_mask = PIO_INT_CTL(pin);
const uint32_t pin_val = enable ? pin_mask : 0;
const unsigned long pin_addr = A64_PIO_INT_CTL(ext);
irqstate_t flags;
if (ext < 0)
{
gpioerr("External Interrupt not supported for Port %d\n", port);
return -EINVAL;
}
/* Enter Critical Section */
flags = enter_critical_section();
/* Enable or disable the interrupt */
modreg32(pin_val, pin_mask, pin_addr);
/* Leave Critical Section */
leave_critical_section(flags);
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -106,6 +189,7 @@ static inline int a64_pio_pin(pio_pinset_t cfgset)
int a64_pio_config(pio_pinset_t cfgset)
{
unsigned int port = a64_pio_port(cfgset);
unsigned int ext = a64_pio_ext(cfgset);
unsigned int pin = a64_pio_pin(cfgset);
unsigned int shift;
unsigned int value;
@ -131,7 +215,7 @@ int a64_pio_config(pio_pinset_t cfgset)
A64_PIO_CFG0(port);
intaddr = (port == PIO_REG_PORTL) ?
A64_RPIO_INT_CFG0 :
A64_PIO_INT_CFG0;
A64_PIO_INT_CFG0(ext);
break;
case 1: /* PIO 8-15 */
@ -140,7 +224,7 @@ int a64_pio_config(pio_pinset_t cfgset)
A64_PIO_CFG1(port);
intaddr = (port == PIO_REG_PORTL) ?
A64_RPIO_INT_CFG1 :
A64_PIO_INT_CFG1;
A64_PIO_INT_CFG1(ext);
break;
case 2: /* PIO 16-23 */
@ -149,7 +233,7 @@ int a64_pio_config(pio_pinset_t cfgset)
A64_PIO_CFG2(port);
intaddr = (port == PIO_REG_PORTL) ?
A64_RPIO_INT_CFG2 :
A64_PIO_INT_CFG2;
A64_PIO_INT_CFG2(ext);
break;
case 3: /* PIO 24-31 */
@ -158,7 +242,7 @@ int a64_pio_config(pio_pinset_t cfgset)
A64_PIO_CFG3(port);
intaddr = (port == PIO_REG_PORTL) ?
A64_RPIO_INT_CFG3 :
A64_PIO_INT_CFG3;
A64_PIO_INT_CFG3(ext);
break;
default:
@ -180,6 +264,12 @@ int a64_pio_config(pio_pinset_t cfgset)
if ((cfgset & PIO_EINT_MASK) == PIO_EINT)
{
if (ext < 0)
{
gpioerr("External Interrupt not supported for Port %d\n", port);
return -EINVAL;
}
value = (cfgset & PIO_INT_MASK) >> PIO_INT_SHIFT;
regval = getreg32(intaddr);
@ -327,3 +417,43 @@ bool a64_pio_read(pio_pinset_t pinset)
regval = getreg32(regaddr);
return ((regval & PIO_DAT(pin)) != 0);
}
/****************************************************************************
* Name: a64_pio_irqenable
*
* Description:
* Enable the interrupt for specified PIO pin. Only Ports B, G and H are
* supported for interrupts.
*
* Input Parameters:
* cfgset - Bit-encoded description of a pin. Port should be B, G or H.
*
* Returned Value:
* Zero (OK) on success; -EINVAL if pin is not from Port B, G or H.
*
****************************************************************************/
int a64_pio_irqenable(pio_pinset_t pinset)
{
return a64_pio_irq(pinset, true);
}
/****************************************************************************
* Name: a64_pio_irqdisable
*
* Description:
* Disable the interrupt for specified PIO pin. Only Ports B, G and H are
* supported for interrupts.
*
* Input Parameters:
* cfgset - Bit-encoded description of a pin. Port should be B, G or H.
*
* Returned Value:
* Zero (OK) on success; -EINVAL if pin is not from Port B, G or H.
*
****************************************************************************/
int a64_pio_irqdisable(pio_pinset_t pinset)
{
return a64_pio_irq(pinset, false);
}

View file

@ -278,6 +278,40 @@ void a64_pio_write(pio_pinset_t pinset, bool value);
bool a64_pio_read(pio_pinset_t pinset);
/****************************************************************************
* Name: a64_pio_irqenable
*
* Description:
* Enable the interrupt for specified PIO pin. Only Ports B, G and H are
* supported for interrupts.
*
* Input Parameters:
* pinset - Bit-encoded description of a pin. Port should be B, G or H.
*
* Returned Value:
* Zero (OK) on success; -EINVAL if pin is not from Port B, G or H.
*
****************************************************************************/
int a64_pio_irqenable(pio_pinset_t pinset);
/****************************************************************************
* Name: a64_pio_irqdisable
*
* Description:
* Disable the interrupt for specified PIO pin. Only Ports B, G and H are
* supported for interrupts.
*
* Input Parameters:
* pinset - Bit-encoded description of a pin. Port should be B, G or H.
*
* Returned Value:
* Zero (OK) on success; -EINVAL if pin is not from Port B, G or H.
*
****************************************************************************/
int a64_pio_irqdisable(pio_pinset_t pinset);
#undef EXTERN
#if defined(__cplusplus)
}

View file

@ -70,13 +70,14 @@
#define A64_PIO_DRV1_OFFSET(n) (0x0018 + (n)*0x24) /* Port Multi-Driving Register 1, n=0-7 */
#define A64_PIO_PUL0_OFFSET(n) (0x001c + (n)*0x24) /* Port Pull Register 0, n=0-7 */
#define A64_PIO_PUL1_OFFSET(n) (0x0020 + (n)*0x24) /* Port Pull Register 1, n=0-7 */
#define A64_PIO_INT_CFG0_OFFSET 0x0200 /* PIO Interrupt Configure Register 0 */
#define A64_PIO_INT_CFG1_OFFSET 0x0204 /* PIO Interrupt Configure Register 1 */
#define A64_PIO_INT_CFG2_OFFSET 0x0208 /* PIO Interrupt Configure Register 2 */
#define A64_PIO_INT_CFG3_OFFSET 0x020c /* PIO Interrupt Configure Register 3 */
#define A64_PIO_INT_CTL_OFFSET 0x0210 /* PIO Interrupt Control Register */
#define A64_PIO_INT_STA_OFFSET 0x0214 /* PIO Interrupt Status Register */
#define A64_PIO_INT_DEB_OFFSET 0x0218 /* PIO Interrupt Debounce Register */
#define A64_PIO_INT_CFG0_OFFSET(n) (0x0200 + (n)*0x20) /* PIO Interrupt Configure Register 0, n=0-2 */
#define A64_PIO_INT_CFG1_OFFSET(n) (0x0204 + (n)*0x20) /* PIO Interrupt Configure Register 1, n=0-2 */
#define A64_PIO_INT_CFG2_OFFSET(n) (0x0208 + (n)*0x20) /* PIO Interrupt Configure Register 2, n=0-2 */
#define A64_PIO_INT_CFG3_OFFSET(n) (0x020c + (n)*0x20) /* PIO Interrupt Configure Register 3, n=0-2 */
#define A64_PIO_INT_CTL_OFFSET(n) (0x0210 + (n)*0x20) /* PIO Interrupt Control Register, n=0-2 */
#define A64_PIO_INT_STA_OFFSET(n) (0x0214 + (n)*0x20) /* PIO Interrupt Status Register, n=0-2 */
#define A64_PIO_INT_DEB_OFFSET(n) (0x0218 + (n)*0x20) /* PIO Interrupt Debounce Register, n=0-2 */
/* Register Addresses *******************************************************/
@ -89,13 +90,13 @@
#define A64_PIO_DRV1(n) (A64_PIO_ADDR+A64_PIO_DRV1_OFFSET(n))
#define A64_PIO_PUL0(n) (A64_PIO_ADDR+A64_PIO_PUL0_OFFSET(n))
#define A64_PIO_PUL1(n) (A64_PIO_ADDR+A64_PIO_PUL1_OFFSET(n))
#define A64_PIO_INT_CFG0 (A64_PIO_ADDR+A64_PIO_INT_CFG0_OFFSET)
#define A64_PIO_INT_CFG1 (A64_PIO_ADDR+A64_PIO_INT_CFG1_OFFSET)
#define A64_PIO_INT_CFG2 (A64_PIO_ADDR+A64_PIO_INT_CFG2_OFFSET)
#define A64_PIO_INT_CFG3 (A64_PIO_ADDR+A64_PIO_INT_CFG3_OFFSET)
#define A64_PIO_INT_CTL (A64_PIO_ADDR+A64_PIO_INT_CTL_OFFSET)
#define A64_PIO_INT_STA (A64_PIO_ADDR+A64_PIO_INT_STA_OFFSET)
#define A64_PIO_INT_DEB (A64_PIO_ADDR+A64_PIO_INT_DEB_OFFSET)
#define A64_PIO_INT_CFG0(n) (A64_PIO_ADDR+A64_PIO_INT_CFG0_OFFSET(n))
#define A64_PIO_INT_CFG1(n) (A64_PIO_ADDR+A64_PIO_INT_CFG1_OFFSET(n))
#define A64_PIO_INT_CFG2(n) (A64_PIO_ADDR+A64_PIO_INT_CFG2_OFFSET(n))
#define A64_PIO_INT_CFG3(n) (A64_PIO_ADDR+A64_PIO_INT_CFG3_OFFSET(n))
#define A64_PIO_INT_CTL(n) (A64_PIO_ADDR+A64_PIO_INT_CTL_OFFSET(n))
#define A64_PIO_INT_STA(n) (A64_PIO_ADDR+A64_PIO_INT_STA_OFFSET(n))
#define A64_PIO_INT_DEB(n) (A64_PIO_ADDR+A64_PIO_INT_DEB_OFFSET(n))
#define A64_RPIO_CFG0 (A64_RPIO_ADDR+A64_PIO_CFG0_OFFSET(0))
#define A64_RPIO_CFG1 (A64_RPIO_ADDR+A64_PIO_CFG1_OFFSET(0))
@ -106,13 +107,13 @@
#define A64_RPIO_DRV1 (A64_RPIO_ADDR+A64_PIO_DRV1_OFFSET(0))
#define A64_RPIO_PUL0 (A64_RPIO_ADDR+A64_PIO_PUL0_OFFSET(0))
#define A64_RPIO_PUL1 (A64_RPIO_ADDR+A64_PIO_PUL1_OFFSET(0))
#define A64_RPIO_INT_CFG0 (A64_RPIO_ADDR+A64_PIO_INT_CFG0_OFFSET)
#define A64_RPIO_INT_CFG1 (A64_RPIO_ADDR+A64_PIO_INT_CFG1_OFFSET)
#define A64_RPIO_INT_CFG2 (A64_RPIO_ADDR+A64_PIO_INT_CFG2_OFFSET)
#define A64_RPIO_INT_CFG3 (A64_RPIO_ADDR+A64_PIO_INT_CFG3_OFFSET)
#define A64_RPIO_INT_CTL (A64_RPIO_ADDR+A64_PIO_INT_CTL_OFFSET)
#define A64_RPIO_INT_STA (A64_RPIO_ADDR+A64_PIO_INT_STA_OFFSET)
#define A64_RPIO_INT_DEB (A64_RPIO_ADDR+A64_PIO_INT_DEB_OFFSET)
#define A64_RPIO_INT_CFG0 (A64_RPIO_ADDR+A64_PIO_INT_CFG0_OFFSET(0))
#define A64_RPIO_INT_CFG1 (A64_RPIO_ADDR+A64_PIO_INT_CFG1_OFFSET(0))
#define A64_RPIO_INT_CFG2 (A64_RPIO_ADDR+A64_PIO_INT_CFG2_OFFSET(0))
#define A64_RPIO_INT_CFG3 (A64_RPIO_ADDR+A64_PIO_INT_CFG3_OFFSET(0))
#define A64_RPIO_INT_CTL (A64_RPIO_ADDR+A64_PIO_INT_CTL_OFFSET(0))
#define A64_RPIO_INT_STA (A64_RPIO_ADDR+A64_PIO_INT_STA_OFFSET(0))
#define A64_RPIO_INT_DEB (A64_RPIO_ADDR+A64_PIO_INT_DEB_OFFSET(0))
/* Register Bit Field Definitions *******************************************/