Commit 4fb1ee77 authored by Volodymyr Babchuk's avatar Volodymyr Babchuk Committed by Anas Nashif
Browse files

drivers: pl011: add SBSA mode



ARM Server Base System Architecture defines Generic UART interface,
which is subset of PL011 UART.

Minimal SBSA UART implementation does not define UART hardware
configuration registers. Basically, only FIFOs and interrupt management
operation are defined.

Add SBSA mode to PL011 UART driver, so it can be used at SBSA-compatible
platforms, like Xen guest.

Signed-off-by: default avatarVolodymyr Babchuk <volodymyr_babchuk@epam.com>
parent 490408fa
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -20,4 +20,12 @@ config UART_PL011_PORT1
	help
	  Build the driver to utilize UART controller Port 1.

config UART_PL011_SBSA
	bool "Enable SBSA UART"
	help
	  Enable SBSA mode for PL011 driver. SBSA stands for
	  Server Based System Architecture. This specification
	  among other things defines simplified UART interface
	  which is subset of PL011 interface.

endif # UART_PL011
+91 −36
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
 */

#define DT_DRV_COMPAT arm_pl011
#define SBSA_COMPAT arm_sbsa_uart

#include <kernel.h>
#include <arch/cpu.h>
@@ -41,6 +42,7 @@ struct pl011_regs {
/* Device data structure */
struct pl011_data {
	uint32_t baud_rate;	/* Baud rate */
	bool sbsa;		/* SBSA mode */
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
	uart_irq_callback_user_data_t irq_cb;
	void *irq_cb_data;
@@ -199,13 +201,12 @@ static int pl011_set_baudrate(const struct device *dev,

static bool pl011_is_readable(const struct device *dev)
{
	if ((PL011_REGS(dev)->cr & PL011_CR_UARTEN) &&
	    (PL011_REGS(dev)->cr & PL011_CR_RXE) &&
	   ((PL011_REGS(dev)->fr & PL011_FR_RXFE) == 0U)) {
		return true;
	}

	if (!DEV_DATA(dev)->sbsa &&
	    (!(PL011_REGS(dev)->cr & PL011_CR_UARTEN) ||
	     !(PL011_REGS(dev)->cr & PL011_CR_RXE)))
		return false;

	return (PL011_REGS(dev)->fr & PL011_FR_RXFE) == 0U;
}

static int pl011_poll_in(const struct device *dev, unsigned char *c)
@@ -276,8 +277,10 @@ static int pl011_irq_tx_complete(const struct device *dev)

static int pl011_irq_tx_ready(const struct device *dev)
{
	return ((PL011_REGS(dev)->cr & PL011_CR_TXE) &&
		(PL011_REGS(dev)->imsc & PL011_IMSC_TXIM) &&
	if (!DEV_DATA(dev)->sbsa && !(PL011_REGS(dev)->cr & PL011_CR_TXE))
		return false;

	return ((PL011_REGS(dev)->imsc & PL011_IMSC_TXIM) &&
		pl011_irq_tx_complete(dev));
}

@@ -295,8 +298,10 @@ static void pl011_irq_rx_disable(const struct device *dev)

static int pl011_irq_rx_ready(const struct device *dev)
{
	return ((PL011_REGS(dev)->cr & PL011_CR_RXE) &&
		(PL011_REGS(dev)->imsc & PL011_IMSC_RXIM) &&
	if (!DEV_DATA(dev)->sbsa && !(PL011_REGS(dev)->cr & PL011_CR_RXE))
		return false;

	return ((PL011_REGS(dev)->imsc & PL011_IMSC_RXIM) &&
		(!(PL011_REGS(dev)->fr & PL011_FR_RXFE)));
}

@@ -356,6 +361,12 @@ static int pl011_init(const struct device *dev)
	int ret;
	uint32_t lcrh;

	/*
	 * If working in SBSA mode, we assume that UART is already configured,
	 * or does not require configuration at all (if UART is emulated by
	 * virtualization software).
	 */
	if (!DEV_DATA(dev)->sbsa) {
		/* disable the uart */
		pl011_disable(dev);
		pl011_disable_fifo(dev);
@@ -375,20 +386,22 @@ static int pl011_init(const struct device *dev)

		/* Enabling the FIFOs */
		pl011_enable_fifo(dev);

	}
	/* initialize all IRQs as masked */
	PL011_REGS(dev)->imsc = 0U;
	PL011_REGS(dev)->icr = PL011_IMSC_MASK_ALL;

	if (!DEV_DATA(dev)->sbsa) {
		PL011_REGS(dev)->dmacr = 0U;
		__ISB();
		PL011_REGS(dev)->cr &= ~(BIT(14) | BIT(15) | BIT(1));
		PL011_REGS(dev)->cr |= PL011_CR_RXE | PL011_CR_TXE;
		__ISB();

	}
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
	DEV_CFG(dev)->irq_config_func(dev);
#endif
	if (!DEV_DATA(dev)->sbsa)
		pl011_enable(dev);

	return 0;
@@ -532,3 +545,45 @@ static void pl011_irq_config_func_1(const struct device *dev)
#endif

#endif /* CONFIG_UART_PL011_PORT1 */

#ifdef CONFIG_UART_PL011_SBSA

#undef DT_DRV_COMPAT
#define DT_DRV_COMPAT SBSA_COMPAT

#ifdef CONFIG_UART_INTERRUPT_DRIVEN
static void pl011_irq_config_func_sbsa(const struct device *dev);
#endif

static struct uart_device_config pl011_cfg_sbsa = {
	.base = (uint8_t *)DT_INST_REG_ADDR(0),
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
	.irq_config_func = pl011_irq_config_func_sbsa,
#endif
};

static struct pl011_data pl011_data_sbsa = {
	.sbsa = true,
};

DEVICE_DT_INST_DEFINE(0,
		      &pl011_init,
		      device_pm_control_nop,
		      &pl011_data_sbsa,
		      &pl011_cfg_sbsa, PRE_KERNEL_1,
		      CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
		      &pl011_driver_api);

#ifdef CONFIG_UART_INTERRUPT_DRIVEN
static void pl011_irq_config_func_sbsa(const struct device *dev)
{
	IRQ_CONNECT(DT_INST_IRQN(0),
		    DT_INST_IRQ(0, priority),
		    pl011_isr,
		    DEVICE_GET(pl011_sbsa),
		    0);
	irq_enable(DT_INST_IRQN(0));
}
#endif

#endif /* CONFIG_UART_PL011_SBSA */
+12 −0
Original line number Diff line number Diff line
description: ARM SBSA UART

compatible: "arm,sbsa-uart"

include: uart-controller.yaml

properties:
    reg:
      required: true

    interrupts:
      required: false