/* unsigned int timeout_ms; */
/* bool_t probing, intr_works; */
bool sbsa; /* ARM SBSA generic interface */
+ bool mmio32; /* 32-bit only MMIO */
} pl011_com = {0};
/* These parity settings can be ORed directly into the LCR. */
#define PARITY_MARK (PEN|SPS)
#define PARITY_SPACE (PEN|EPS|SPS)
-/* SBSA v2.x document requires, all reads/writes must be 32-bit accesses */
-#define pl011_read(uart, off) readl((uart)->regs + (off))
-#define pl011_write(uart, off,val) writel((val), (uart)->regs + (off))
+/*
+ * By default, PL011 accesses shall be done using 8/16-bit accessors to
+ * support legacy devices that cannot cope with 32-bit. On the other hand,
+ * there are implementations of PL011 that can only handle 32-bit MMIO. Also,
+ * SBSA v2.x requires 32-bit accesses. Note that for default case, we use
+ * largest-common accessors (i.e. 16-bit) not to end up using different ones
+ * depending on the actual register size.
+ */
+static inline void
+pl011_write(struct pl011 *uart, unsigned int offset, unsigned int val)
+{
+ if ( uart->mmio32 )
+ writel(val, uart->regs + offset);
+ else
+ writew(val, uart->regs + offset);
+}
+
+static inline unsigned int pl011_read(struct pl011 *uart, unsigned int offset)
+{
+ if ( uart->mmio32 )
+ return readl(uart->regs + offset);
+
+ return readw(uart->regs + offset);
+}
static unsigned int pl011_intr_status(struct pl011 *uart)
{
.vuart_info = pl011_vuart,
};
-static int __init pl011_uart_init(int irq, paddr_t addr, paddr_t size, bool sbsa)
+static int __init
+pl011_uart_init(int irq, paddr_t addr, paddr_t size, bool sbsa, bool mmio32)
{
struct pl011 *uart;
uart->stop_bits = 1;
uart->sbsa = sbsa;
+ /* Set 32-bit MMIO also for SBSA since v2.x requires it */
+ uart->mmio32 = (mmio32 || sbsa);
+
uart->regs = ioremap_nocache(addr, size);
if ( !uart->regs )
{
const char *config = data;
int res;
paddr_t addr, size;
+ uint32_t io_width;
+ bool mmio32 = false;
if ( strcmp(config, "") )
{
return -EINVAL;
}
- res = pl011_uart_init(res, addr, size, false);
+ /* See linux Documentation/devicetree/bindings/serial/pl011.yaml */
+ if ( dt_property_read_u32(dev, "reg-io-width", &io_width) )
+ {
+ if ( io_width == 4 )
+ mmio32 = true;
+ else if ( io_width != 1 )
+ {
+ printk("pl011: Unsupported reg-io-width (%"PRIu32")\n", io_width);
+ return -EINVAL;
+ }
+ }
+
+ res = pl011_uart_init(res, addr, size, false, mmio32);
if ( res < 0 )
{
printk("pl011: Unable to initialize\n");
/* trigger/polarity information is not available in spcr */
irq_set_type(spcr->interrupt, IRQ_TYPE_LEVEL_HIGH);
+ /* TODO - mmio32 proper handling (for now set to true) */
res = pl011_uart_init(spcr->interrupt, spcr->serial_port.address,
- PAGE_SIZE, sbsa);
+ PAGE_SIZE, sbsa, true);
if ( res < 0 )
{
printk("pl011: Unable to initialize\n");