drivers: uart_pl011: Enable shared interrupts support

The PrimeCell UART (PL011) IP can use one single combined/shared
interrupt line instead than different IRQ lines for TX/RX/Err/... This
is the most common configuration supported in the Linux world but not
currently supported in Zephyr. QEMU emulates a PL011 UART with a single
interrupt line as well.

To support this configuration we have to hookup the PL011 driver with a
shared IRQ driver and add two new configuration options when the shared
IRQ line is used.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
This commit is contained in:
Carlo Caione 2019-11-25 14:51:39 +00:00 committed by Andrew Boie
parent e2905c09cb
commit b9fc192779
2 changed files with 51 additions and 0 deletions

View file

@ -20,4 +20,25 @@ config UART_PL011_PORT1
help
Build the driver to utilize UART controller Port 1.
config UART_PL011_SHARED_IRQ
bool
config UART_PL011_PORT0_SHARED_IRQ
bool "Shared IRQ for UART 0"
depends on SHARED_IRQ_0
depends on UART_PL011_PORT0
select UART_PL011_SHARED_IRQ
help
When interrupts fire, the shared IRQ driver is notified. Then the shared IRQ
driver dispatches the interrupt to the UART driver.
config UART_PL011_PORT1_SHARED_IRQ
bool "Shared IRQ for UART 1"
depends on SHARED_IRQ_1
depends on UART_PL011_PORT1
select UART_PL011_SHARED_IRQ
help
When interrupts fire, the shared IRQ driver is notified. Then the shared IRQ
driver dispatches the interrupt to the UART driver.
endif # UART_PL011

View file

@ -11,6 +11,9 @@
#include <soc.h>
#include <drivers/uart.h>
#if defined(CONFIG_SHARED_IRQ)
#include <shared_irq.h>
#endif
/*
* UART PL011 register map structure
@ -43,6 +46,9 @@ struct pl011_data {
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
uart_irq_callback_user_data_t irq_cb;
void *irq_cb_data;
#if defined(CONFIG_UART_PL011_SHARED_IRQ)
char *shared_irq_dev_name;
#endif
#endif
};
@ -423,6 +429,9 @@ static struct uart_device_config pl011_cfg_port_0 = {
static struct pl011_data pl011_data_port_0 = {
.baud_rate = DT_PL011_PORT0_BAUD_RATE,
#if defined(CONFIG_UART_PL011_SHARED_IRQ)
.shared_irq_dev_name = DT_INST_0_SHARED_IRQ_LABEL,
#endif
};
DEVICE_AND_API_INIT(pl011_port_0,
@ -436,6 +445,14 @@ DEVICE_AND_API_INIT(pl011_port_0,
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
static void pl011_irq_config_func_0(struct device *dev)
{
#if defined(CONFIG_UART_PL011_PORT0_SHARED_IRQ)
struct device *shared_irq_dev;
shared_irq_dev = device_get_binding(DEV_DATA(dev)->shared_irq_dev_name);
__ASSERT(shared_irq_dev != NULL, "Failed to get shared irq");
shared_irq_isr_register(shared_irq_dev, (isr_t)pl011_isr, dev);
shared_irq_enable(shared_irq_dev, dev);
#else
IRQ_CONNECT(DT_PL011_PORT0_IRQ_TX,
DT_PL011_PORT0_IRQ_PRI,
pl011_isr,
@ -456,6 +473,7 @@ static void pl011_irq_config_func_0(struct device *dev)
DEVICE_GET(pl011_port_0),
0);
irq_enable(DT_PL011_PORT0_IRQ_RXTIM);
#endif
}
#endif
@ -477,6 +495,9 @@ static struct uart_device_config pl011_cfg_port_1 = {
static struct pl011_data pl011_data_port_1 = {
.baud_rate = DT_PL011_PORT1_BAUD_RATE,
#if defined(CONFIG_UART_PL011_SHARED_IRQ)
.shared_irq_dev_name = DT_INST_1_SHARED_IRQ_LABEL,
#endif
};
DEVICE_AND_API_INIT(pl011_port_1,
@ -490,6 +511,14 @@ DEVICE_AND_API_INIT(pl011_port_1,
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
static void pl011_irq_config_func_1(struct device *dev)
{
#if defined(CONFIG_UART_PL011_PORT1_SHARED_IRQ)
struct device *shared_irq_dev;
shared_irq_dev = device_get_binding(DEV_DATA(dev)->shared_irq_dev_name);
__ASSERT(shared_irq_dev != NULL, "Failed to get shared irq");
shared_irq_isr_register(shared_irq_dev, (isr_t)pl011_isr, dev);
shared_irq_enable(shared_irq_dev, dev);
#else
IRQ_CONNECT(DT_PL011_PORT1_IRQ_TX,
DT_PL011_PORT1_IRQ_PRI,
pl011_isr,
@ -510,6 +539,7 @@ static void pl011_irq_config_func_1(struct device *dev)
DEVICE_GET(pl011_port_1),
0);
irq_enable(DT_PL011_PORT1_IRQ_RXTIM);
#endif
}
#endif