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:
parent
e2905c09cb
commit
b9fc192779
2 changed files with 51 additions and 0 deletions
|
@ -20,4 +20,25 @@ config UART_PL011_PORT1
|
||||||
help
|
help
|
||||||
Build the driver to utilize UART controller Port 1.
|
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
|
endif # UART_PL011
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
#include <soc.h>
|
#include <soc.h>
|
||||||
#include <drivers/uart.h>
|
#include <drivers/uart.h>
|
||||||
|
|
||||||
|
#if defined(CONFIG_SHARED_IRQ)
|
||||||
|
#include <shared_irq.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* UART PL011 register map structure
|
* UART PL011 register map structure
|
||||||
|
@ -43,6 +46,9 @@ struct pl011_data {
|
||||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||||
uart_irq_callback_user_data_t irq_cb;
|
uart_irq_callback_user_data_t irq_cb;
|
||||||
void *irq_cb_data;
|
void *irq_cb_data;
|
||||||
|
#if defined(CONFIG_UART_PL011_SHARED_IRQ)
|
||||||
|
char *shared_irq_dev_name;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -423,6 +429,9 @@ static struct uart_device_config pl011_cfg_port_0 = {
|
||||||
|
|
||||||
static struct pl011_data pl011_data_port_0 = {
|
static struct pl011_data pl011_data_port_0 = {
|
||||||
.baud_rate = DT_PL011_PORT0_BAUD_RATE,
|
.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,
|
DEVICE_AND_API_INIT(pl011_port_0,
|
||||||
|
@ -436,6 +445,14 @@ DEVICE_AND_API_INIT(pl011_port_0,
|
||||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||||
static void pl011_irq_config_func_0(struct device *dev)
|
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,
|
IRQ_CONNECT(DT_PL011_PORT0_IRQ_TX,
|
||||||
DT_PL011_PORT0_IRQ_PRI,
|
DT_PL011_PORT0_IRQ_PRI,
|
||||||
pl011_isr,
|
pl011_isr,
|
||||||
|
@ -456,6 +473,7 @@ static void pl011_irq_config_func_0(struct device *dev)
|
||||||
DEVICE_GET(pl011_port_0),
|
DEVICE_GET(pl011_port_0),
|
||||||
0);
|
0);
|
||||||
irq_enable(DT_PL011_PORT0_IRQ_RXTIM);
|
irq_enable(DT_PL011_PORT0_IRQ_RXTIM);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -477,6 +495,9 @@ static struct uart_device_config pl011_cfg_port_1 = {
|
||||||
|
|
||||||
static struct pl011_data pl011_data_port_1 = {
|
static struct pl011_data pl011_data_port_1 = {
|
||||||
.baud_rate = DT_PL011_PORT1_BAUD_RATE,
|
.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,
|
DEVICE_AND_API_INIT(pl011_port_1,
|
||||||
|
@ -490,6 +511,14 @@ DEVICE_AND_API_INIT(pl011_port_1,
|
||||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||||
static void pl011_irq_config_func_1(struct device *dev)
|
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,
|
IRQ_CONNECT(DT_PL011_PORT1_IRQ_TX,
|
||||||
DT_PL011_PORT1_IRQ_PRI,
|
DT_PL011_PORT1_IRQ_PRI,
|
||||||
pl011_isr,
|
pl011_isr,
|
||||||
|
@ -510,6 +539,7 @@ static void pl011_irq_config_func_1(struct device *dev)
|
||||||
DEVICE_GET(pl011_port_1),
|
DEVICE_GET(pl011_port_1),
|
||||||
0);
|
0);
|
||||||
irq_enable(DT_PL011_PORT1_IRQ_RXTIM);
|
irq_enable(DT_PL011_PORT1_IRQ_RXTIM);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue