Skip to content

Commit 4fb1ee7

Browse files
lorcnashif
authored andcommitted
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: Volodymyr Babchuk <[email protected]>
1 parent 490408f commit 4fb1ee7

File tree

3 files changed

+111
-36
lines changed

3 files changed

+111
-36
lines changed

drivers/serial/Kconfig.pl011

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,12 @@ config UART_PL011_PORT1
2020
help
2121
Build the driver to utilize UART controller Port 1.
2222

23+
config UART_PL011_SBSA
24+
bool "Enable SBSA UART"
25+
help
26+
Enable SBSA mode for PL011 driver. SBSA stands for
27+
Server Based System Architecture. This specification
28+
among other things defines simplified UART interface
29+
which is subset of PL011 interface.
30+
2331
endif # UART_PL011

drivers/serial/uart_pl011.c

Lines changed: 91 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
#define DT_DRV_COMPAT arm_pl011
8+
#define SBSA_COMPAT arm_sbsa_uart
89

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

200202
static bool pl011_is_readable(const struct device *dev)
201203
{
202-
if ((PL011_REGS(dev)->cr & PL011_CR_UARTEN) &&
203-
(PL011_REGS(dev)->cr & PL011_CR_RXE) &&
204-
((PL011_REGS(dev)->fr & PL011_FR_RXFE) == 0U)) {
205-
return true;
206-
}
204+
if (!DEV_DATA(dev)->sbsa &&
205+
(!(PL011_REGS(dev)->cr & PL011_CR_UARTEN) ||
206+
!(PL011_REGS(dev)->cr & PL011_CR_RXE)))
207+
return false;
207208

208-
return false;
209+
return (PL011_REGS(dev)->fr & PL011_FR_RXFE) == 0U;
209210
}
210211

211212
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)
276277

277278
static int pl011_irq_tx_ready(const struct device *dev)
278279
{
279-
return ((PL011_REGS(dev)->cr & PL011_CR_TXE) &&
280-
(PL011_REGS(dev)->imsc & PL011_IMSC_TXIM) &&
280+
if (!DEV_DATA(dev)->sbsa && !(PL011_REGS(dev)->cr & PL011_CR_TXE))
281+
return false;
282+
283+
return ((PL011_REGS(dev)->imsc & PL011_IMSC_TXIM) &&
281284
pl011_irq_tx_complete(dev));
282285
}
283286

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

296299
static int pl011_irq_rx_ready(const struct device *dev)
297300
{
298-
return ((PL011_REGS(dev)->cr & PL011_CR_RXE) &&
299-
(PL011_REGS(dev)->imsc & PL011_IMSC_RXIM) &&
301+
if (!DEV_DATA(dev)->sbsa && !(PL011_REGS(dev)->cr & PL011_CR_RXE))
302+
return false;
303+
304+
return ((PL011_REGS(dev)->imsc & PL011_IMSC_RXIM) &&
300305
(!(PL011_REGS(dev)->fr & PL011_FR_RXFE)));
301306
}
302307

@@ -356,40 +361,48 @@ static int pl011_init(const struct device *dev)
356361
int ret;
357362
uint32_t lcrh;
358363

359-
/* disable the uart */
360-
pl011_disable(dev);
361-
pl011_disable_fifo(dev);
362-
363-
/* Set baud rate */
364-
ret = pl011_set_baudrate(dev, DEV_CFG(dev)->sys_clk_freq,
365-
DEV_DATA(dev)->baud_rate);
366-
if (ret != 0) {
367-
return ret;
364+
/*
365+
* If working in SBSA mode, we assume that UART is already configured,
366+
* or does not require configuration at all (if UART is emulated by
367+
* virtualization software).
368+
*/
369+
if (!DEV_DATA(dev)->sbsa) {
370+
/* disable the uart */
371+
pl011_disable(dev);
372+
pl011_disable_fifo(dev);
373+
374+
/* Set baud rate */
375+
ret = pl011_set_baudrate(dev, DEV_CFG(dev)->sys_clk_freq,
376+
DEV_DATA(dev)->baud_rate);
377+
if (ret != 0) {
378+
return ret;
379+
}
380+
381+
/* Setting the default character format */
382+
lcrh = PL011_REGS(dev)->lcr_h & ~(PL011_LCRH_FORMAT_MASK);
383+
lcrh &= ~(BIT(0) | BIT(7));
384+
lcrh |= PL011_LCRH_WLEN_SIZE(8) << PL011_LCRH_WLEN_SHIFT;
385+
PL011_REGS(dev)->lcr_h = lcrh;
386+
387+
/* Enabling the FIFOs */
388+
pl011_enable_fifo(dev);
368389
}
369-
370-
/* Setting the default character format */
371-
lcrh = PL011_REGS(dev)->lcr_h & ~(PL011_LCRH_FORMAT_MASK);
372-
lcrh &= ~(BIT(0) | BIT(7));
373-
lcrh |= PL011_LCRH_WLEN_SIZE(8) << PL011_LCRH_WLEN_SHIFT;
374-
PL011_REGS(dev)->lcr_h = lcrh;
375-
376-
/* Enabling the FIFOs */
377-
pl011_enable_fifo(dev);
378-
379390
/* initialize all IRQs as masked */
380391
PL011_REGS(dev)->imsc = 0U;
381392
PL011_REGS(dev)->icr = PL011_IMSC_MASK_ALL;
382393

383-
PL011_REGS(dev)->dmacr = 0U;
384-
__ISB();
385-
PL011_REGS(dev)->cr &= ~(BIT(14) | BIT(15) | BIT(1));
386-
PL011_REGS(dev)->cr |= PL011_CR_RXE | PL011_CR_TXE;
387-
__ISB();
388-
394+
if (!DEV_DATA(dev)->sbsa) {
395+
PL011_REGS(dev)->dmacr = 0U;
396+
__ISB();
397+
PL011_REGS(dev)->cr &= ~(BIT(14) | BIT(15) | BIT(1));
398+
PL011_REGS(dev)->cr |= PL011_CR_RXE | PL011_CR_TXE;
399+
__ISB();
400+
}
389401
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
390402
DEV_CFG(dev)->irq_config_func(dev);
391403
#endif
392-
pl011_enable(dev);
404+
if (!DEV_DATA(dev)->sbsa)
405+
pl011_enable(dev);
393406

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

534547
#endif /* CONFIG_UART_PL011_PORT1 */
548+
549+
#ifdef CONFIG_UART_PL011_SBSA
550+
551+
#undef DT_DRV_COMPAT
552+
#define DT_DRV_COMPAT SBSA_COMPAT
553+
554+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
555+
static void pl011_irq_config_func_sbsa(const struct device *dev);
556+
#endif
557+
558+
static struct uart_device_config pl011_cfg_sbsa = {
559+
.base = (uint8_t *)DT_INST_REG_ADDR(0),
560+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
561+
.irq_config_func = pl011_irq_config_func_sbsa,
562+
#endif
563+
};
564+
565+
static struct pl011_data pl011_data_sbsa = {
566+
.sbsa = true,
567+
};
568+
569+
DEVICE_DT_INST_DEFINE(0,
570+
&pl011_init,
571+
device_pm_control_nop,
572+
&pl011_data_sbsa,
573+
&pl011_cfg_sbsa, PRE_KERNEL_1,
574+
CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
575+
&pl011_driver_api);
576+
577+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
578+
static void pl011_irq_config_func_sbsa(const struct device *dev)
579+
{
580+
IRQ_CONNECT(DT_INST_IRQN(0),
581+
DT_INST_IRQ(0, priority),
582+
pl011_isr,
583+
DEVICE_GET(pl011_sbsa),
584+
0);
585+
irq_enable(DT_INST_IRQN(0));
586+
}
587+
#endif
588+
589+
#endif /* CONFIG_UART_PL011_SBSA */
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
description: ARM SBSA UART
2+
3+
compatible: "arm,sbsa-uart"
4+
5+
include: uart-controller.yaml
6+
7+
properties:
8+
reg:
9+
required: true
10+
11+
interrupts:
12+
required: false

0 commit comments

Comments
 (0)