diff --git a/arch/arm/include/imx9/chip.h b/arch/arm/include/imx9/chip.h index 0b46efc3827..466b45451c0 100644 --- a/arch/arm/include/imx9/chip.h +++ b/arch/arm/include/imx9/chip.h @@ -47,6 +47,6 @@ #define NVIC_SYSH_PRIORITY_MAX 0x00 /* Zero is maximum priority */ #define NVIC_SYSH_PRIORITY_STEP 0x40 /* Two bits of interrupt pri used */ -#define IMX9_GPIO_NPORTS 4 +#define IMX9_GPIO_NPORTS 5 #endif /* __ARCH_ARM_INCLUDE_IMX9_CHIP_H */ diff --git a/arch/arm/src/imx9/Kconfig b/arch/arm/src/imx9/Kconfig index 32d52ce3043..0fe2d362e41 100644 --- a/arch/arm/src/imx9/Kconfig +++ b/arch/arm/src/imx9/Kconfig @@ -382,18 +382,118 @@ config IMX9_GPIO1_IRQ bool "GPIO1 Interrupt" default n +choice + prompt "GPIO1 IRQ output select" + depends on IMX9_GPIO1_IRQ + default IMX9_GPIO1_IRQ_OUT_LINE1 + ---help--- + Each IMX9 GPIO controller provides two IRQ output lines. These + lines may be shared with other cores or domains in the SoC + (e.g. A55 vs M7), so selecting the correct line avoids conflicts. + + By default this subsystem uses IRQ line 1, leaving line 0 available + for the A55 or other system components that typically rely on it. + +config IMX9_GPIO1_IRQ_OUT_LINE0 + bool "Use GPIO1 IRQ line 0" + +config IMX9_GPIO1_IRQ_OUT_LINE1 + bool "Use GPIO1 IRQ line 1" +endchoice + config IMX9_GPIO2_IRQ bool "GPIO2 Interrupt" default n +choice + prompt "GPIO2 IRQ output select" + depends on IMX9_GPIO2_IRQ + default IMX9_GPIO2_IRQ_OUT_LINE1 + ---help--- + Each IMX9 GPIO controller provides two IRQ output lines. These + lines may be shared with other cores or domains in the SoC + (e.g. A55 vs M7), so selecting the correct line avoids conflicts. + + By default this subsystem uses IRQ line 1, leaving line 0 available + for the A55 or other system components that typically rely on it. + +config IMX9_GPIO2_IRQ_OUT_LINE0 + bool "Use GPIO2 IRQ line 0" + +config IMX9_GPIO2_IRQ_OUT_LINE1 + bool "Use GPIO2 IRQ line 1" +endchoice + config IMX9_GPIO3_IRQ bool "GPIO3 Interrupt" default n +choice + prompt "GPIO3 IRQ output select" + depends on IMX9_GPIO3_IRQ + default IMX9_GPIO3_IRQ_OUT_LINE1 + ---help--- + Each IMX9 GPIO controller provides two IRQ output lines. These + lines may be shared with other cores or domains in the SoC + (e.g. A55 vs M7), so selecting the correct line avoids conflicts. + + By default this subsystem uses IRQ line 1, leaving line 0 available + for the A55 or other system components that typically rely on it. + +config IMX9_GPIO3_IRQ_OUT_LINE0 + bool "Use GPIO3 IRQ line 0" + +config IMX9_GPIO3_IRQ_OUT_LINE1 + bool "Use GPIO3 IRQ line 1" +endchoice + config IMX9_GPIO4_IRQ bool "GPIO4 Interrupt" default n +choice + prompt "GPIO4 IRQ output select" + depends on IMX9_GPIO4_IRQ + default IMX9_GPIO4_IRQ_OUT_LINE1 + ---help--- + Each IMX9 GPIO controller provides two IRQ output lines. These + lines may be shared with other cores or domains in the SoC + (e.g. A55 vs M7), so selecting the correct line avoids conflicts. + + By default this subsystem uses IRQ line 1, leaving line 0 available + for the A55 or other system components that typically rely on it. + +config IMX9_GPIO4_IRQ_OUT_LINE0 + bool "Use GPIO4 IRQ line 0" + +config IMX9_GPIO4_IRQ_OUT_LINE1 + bool "Use GPIO4 IRQ line 1" +endchoice + +config IMX9_GPIO5_IRQ + bool "GPIO5 Interrupt" + default n + +choice + prompt "GPIO5 IRQ output select" + depends on IMX9_GPIO5_IRQ + default IMX9_GPIO5_IRQ_OUT_LINE1 + ---help--- + Each IMX9 GPIO controller provides two IRQ output lines. These + lines may be shared with other cores or domains in the SoC + (e.g. A55 vs M7), so selecting the correct line avoids conflicts. + + By default this subsystem uses IRQ line 1, leaving line 0 available + for the A55 or other system components that typically rely on it. + +config IMX9_GPIO5_IRQ_OUT_LINE0 + bool "Use GPIO5 IRQ line 0" + +config IMX9_GPIO5_IRQ_OUT_LINE1 + bool "Use GPIO5 IRQ line 1" +endchoice + + endmenu # GPIO Interrupt Configuration config IMX9_LPI2C diff --git a/arch/arm/src/imx9/imx9_gpio.c b/arch/arm/src/imx9/imx9_gpio.c index 60e20c36e8b..346bf3c95aa 100644 --- a/arch/arm/src/imx9/imx9_gpio.c +++ b/arch/arm/src/imx9/imx9_gpio.c @@ -124,9 +124,14 @@ static int imx9_gpio_configinput(gpio_pinset_t pinset) { uint32_t port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; uint32_t pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + uint32_t reg; DEBUGASSERT((unsigned int)port < IMX9_GPIO_NPORTS); + reg = getreg32(IMX9_GPIO_PCNS(port)); + reg &= ~(1 << pin); + putreg32(reg, IMX9_GPIO_PCNS(port)); + /* Configure pin as in input */ imx9_gpio_dirin(port, pin); diff --git a/arch/arm/src/imx9/imx9_gpioirq.c b/arch/arm/src/imx9/imx9_gpioirq.c index b040ffd5dd9..e2118b83327 100644 --- a/arch/arm/src/imx9/imx9_gpioirq.c +++ b/arch/arm/src/imx9/imx9_gpioirq.c @@ -68,6 +68,66 @@ static struct imx9_portisr_s g_isrtab[IMX9_GPIO_NPORTS]; * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: imx9_get_irqline_for_port + * + * Description: + * iMX9 has two interrupt sources for each pin, this function fetches + * which line is configured for a given port + * + ****************************************************************************/ + +static inline uint32_t imx9_get_irqline_for_port(uint32_t port) +{ + switch (port) + { + case GPIO1: +#ifdef CONFIG_IMX9_GPIO1_IRQ_OUT_LINE0 + return 0; +#elif defined(CONFIG_IMX9_GPIO1_IRQ_OUT_LINE1) + return 1; +#endif + break; + + case GPIO2: +#ifdef CONFIG_IMX9_GPIO2_IRQ_OUT_LINE0 + return 0; +#elif defined(CONFIG_IMX9_GPIO2_IRQ_OUT_LINE1) + return 1; +#endif + break; + + case GPIO3: +#ifdef CONFIG_IMX9_GPIO3_IRQ_OUT_LINE0 + return 0; +#elif defined(CONFIG_IMX9_GPIO3_IRQ_OUT_LINE1) + return 1; +#endif + break; + + case GPIO4: +#ifdef CONFIG_IMX9_GPIO4_IRQ_OUT_LINE0 + return 0; +#elif defined(CONFIG_IMX9_GPIO4_IRQ_OUT_LINE1) + return 1; +#endif + break; + + case GPIO5: +#ifdef CONFIG_IMX9_GPIO5_IRQ_OUT_LINE0 + return 0; +#elif defined(CONFIG_IMX9_GPIO5_IRQ_OUT_LINE1) + return 1; +#endif + break; + + default: + return 0; + } + + return 0; +} + /**************************************************************************** * Name: imx9_gpio_interrupt * @@ -86,7 +146,15 @@ static int imx9_gpio_interrupt(int irq, void *context, void *arg) /* Get the pending interrupt indications */ - regaddr = IMX9_GPIO_ISFR0(port); + if (imx9_get_irqline_for_port(port)) + { + regaddr = IMX9_GPIO_ISFR1(port); + } + else + { + regaddr = IMX9_GPIO_ISFR0(port); + } + status = getreg32(regaddr); /* Decode the pending interrupts */ @@ -170,31 +238,70 @@ void imx9_gpioirq_initialize(void) up_disable_irq(IMX9_IRQ_GPIO4_0); up_disable_irq(IMX9_IRQ_GPIO4_1); + up_disable_irq(IMX9_IRQ_GPIO5_0); + up_disable_irq(IMX9_IRQ_GPIO5_1); + /* Attach the common GPIO interrupt handler and enable the interrupt */ -#ifdef CONFIG_IMX9_GPIO1_IRQ +#ifdef CONFIG_IMX9_GPIO1_IRQ_OUT_LINE0 DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO1_0, imx9_gpio_interrupt, (void *)GPIO_PORT1)); up_enable_irq(IMX9_IRQ_GPIO1_0); #endif -#ifdef CONFIG_IMX9_GPIO2_IRQ +#ifdef CONFIG_IMX9_GPIO1_IRQ_OUT_LINE0 + DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO1_1, + imx9_gpio_interrupt, (void *)GPIO_PORT1)); + up_enable_irq(IMX9_IRQ_GPIO1_1); +#endif + +#ifdef CONFIG_IMX9_GPIO2_IRQ_OUT_LINE0 DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO2_0, imx9_gpio_interrupt, (void *)GPIO_PORT2)); up_enable_irq(IMX9_IRQ_GPIO2_0); #endif -#ifdef CONFIG_IMX9_GPIO3_IRQ +#ifdef CONFIG_IMX9_GPIO2_IRQ_OUT_LINE1 + DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO2_1, + imx9_gpio_interrupt, (void *)GPIO_PORT2)); + up_enable_irq(IMX9_IRQ_GPIO2_1); +#endif + +#ifdef CONFIG_IMX9_GPIO3_IRQ_OUT_LINE0 DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO3_0, imx9_gpio_interrupt, (void *)GPIO_PORT3)); up_enable_irq(IMX9_IRQ_GPIO3_0); #endif -#ifdef CONFIG_IMX9_GPIO4_IRQ +#ifdef CONFIG_IMX9_GPIO3_IRQ_OUT_LINE1 + DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO3_1, + imx9_gpio_interrupt, (void *)GPIO_PORT3)); + up_enable_irq(IMX9_IRQ_GPIO3_1); +#endif + +#ifdef CONFIG_IMX9_GPIO4_IRQ_OUT_LINE0 DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO4_0, imx9_gpio_interrupt, (void *)GPIO_PORT4)); up_enable_irq(IMX9_IRQ_GPIO4_0); #endif + +#ifdef CONFIG_IMX9_GPIO4_IRQ_OUT_LINE1 + DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO4_1, + imx9_gpio_interrupt, (void *)GPIO_PORT4)); + up_enable_irq(IMX9_IRQ_GPIO4_1); +#endif + +#ifdef CONFIG_IMX9_GPIO5_IRQ_OUT_LINE0 + DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO5_0, + imx9_gpio_interrupt, (void *)GPIO_PORT5)); + up_enable_irq(IMX9_IRQ_GPIO5_0); +#endif + +#ifdef CONFIG_IMX9_GPIO5_IRQ_OUT_LINE1 + DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO5_1, + imx9_gpio_interrupt, (void *)GPIO_PORT5)); + up_enable_irq(IMX9_IRQ_GPIO5_1); +#endif } /**************************************************************************** @@ -258,6 +365,10 @@ int imx9_gpioirq_enable(gpio_pinset_t pinset) uint32_t regval; uintptr_t regaddr; + regval = getreg32(IMX9_GPIO_ICNS(port)); + regval &= ~(1 << (imx9_get_irqline_for_port(port))); + putreg32(regval, IMX9_GPIO_ICNS(port)); + /* Perform RMW to the specific pin */ regaddr = IMX9_GPIO_ICRN(port, pin); @@ -285,6 +396,11 @@ int imx9_gpioirq_enable(gpio_pinset_t pinset) regval |= IMX9_GPIO_ICRN_FALLING; } + if (imx9_get_irqline_for_port(port)) + { + regval |= IMX9_GPIO_ICRN_IRQS; + } + putreg32(regval, regaddr); return OK; }