blob: 8fcf3d11c51c8c19096e654dea33303618366cf1 [file] [log] [blame] [edit]
/*
* Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: GPL-2.0-only
*/
#include <devices_gen.h>
#include <drivers/common.h>
#include <drivers/uart.h>
#include <elfloader_common.h>
/* When DLAB=1, MU_IO is a baud rate register.
* Otherwise, write to TX, read to RX */
#define MU_IO 0x00
/* When DLAB=1, MU_IIR is a baud rate register.
* Otherwise IRQ enable */
#define MU_IIR 0x04
#define MU_IER 0x08
#define MU_LCR 0x0C
#define MU_MCR 0x10
#define MU_LSR 0x14
#define MU_MSR 0x18
#define MU_SCRATCH 0x1C
#define MU_CNTL 0x20
/* This bit is set if the transmit FIFO can accept at least one byte.*/
#define MU_LSR_TXEMPTY BIT(5)
/* This bit is set if the transmit FIFO is empty and the
* transmitter is idle. (Finished shifting out the last bit). */
#define MU_LSR_TXIDLE BIT(6)
#define MU_LCR_DLAB BIT(7)
#define MU_LCR_BREAK BIT(6)
#define MU_LCR_DATASIZE BIT(0)
#define UART_REG(mmio, x) ((volatile uint32_t *)((mmio) + (x)))
static int bcm2835_uart_putchar(struct elfloader_device *dev, unsigned int c)
{
volatile void *mmio = dev->region_bases[0];
/* Wait until UART ready for the next character. */
while (!(*UART_REG(mmio, MU_LSR) & MU_LSR_TXIDLE));
/* Put in the register to be sent*/
*UART_REG(mmio, MU_IO) = (c & 0xff);
return 0;
}
static int bcm2835_uart_init(struct elfloader_device *dev, UNUSED void *match_data)
{
uart_set_out(dev);
return 0;
}
static const struct dtb_match_table bcm2835_uart_matches[] = {
{ .compatible = "brcm,bcm2835-aux-uart" },
{ .compatible = NULL /* sentinel */ },
};
static const struct elfloader_uart_ops bcm2835_uart_ops = {
.putc = &bcm2835_uart_putchar,
};
static const struct elfloader_driver bcm2835_uart = {
.match_table = bcm2835_uart_matches,
.type = DRIVER_UART,
.init = &bcm2835_uart_init,
.ops = &bcm2835_uart_ops,
};
ELFLOADER_DRIVER(bcm2835_uart);