1/*
2 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7#include <devices_gen.h>
8#include <drivers/common.h>
9#include <drivers/uart.h>
10
11#include <elfloader_common.h>
12
13#define ULCON       0x0000 /* line control */
14#define UCON        0x0004 /*control */
15#define UFCON       0x0008 /* fifo control */
16#define UMCON       0x000C /* modem control */
17#define UTRSTAT     0x0010 /* TX/RX status */
18#define UERSTAT     0x0014 /* RX error status */
19#define UFSTAT      0x0018 /* FIFO status */
20#define UMSTAT      0x001C /* modem status */
21#define UTXH        0x0020 /* TX buffer */
22#define URXH        0x0024 /* RX buffer */
23#define UBRDIV      0x0028 /* baud rate divisor */
24#define UFRACVAL    0x002C /* divisor fractional value */
25#define UINTP       0x0030 /* interrupt pending */
26#define UINTSP      0x0034 /* interrupt source pending */
27#define UINTM       0x0038 /* interrupt mask */
28
29#define UART_REG(mmio, x) ((volatile uint32_t *)(mmio + (x)))
30
31/* ULCON */
32#define WORD_LENGTH_8   (3<<0)
33
34/* UTRSTAT */
35#define TX_EMPTY        (1<<2)
36#define TXBUF_EMPTY     (1<<1)
37
38static int exynos_uart_putchar(struct elfloader_device *dev, unsigned int c)
39{
40    volatile void *mmio = dev->region_bases[0];
41
42    /* Wait until UART ready for the next character. */
43    while (!(*UART_REG(mmio, UTRSTAT) & TXBUF_EMPTY));
44
45    /* Put in the register to be sent*/
46    *UART_REG(mmio, UTXH) = (c & 0xff);
47
48    return 0;
49}
50
51static int exynos_uart_init(struct elfloader_device *dev, UNUSED void *match_data)
52{
53    uart_set_out(dev);
54    return 0;
55}
56
57static const struct dtb_match_table exynos_uart_matches[] = {
58    { .compatible = "samsung,exynos4210-uart" },
59    { .compatible = NULL /* sentinel */ },
60};
61
62static const struct elfloader_uart_ops exynos_uart_ops = {
63    .putc = &exynos_uart_putchar,
64};
65
66static const struct elfloader_driver exynos_uart = {
67    .match_table = exynos_uart_matches,
68    .type = DRIVER_UART,
69    .init = &exynos_uart_init,
70    .ops = &exynos_uart_ops,
71};
72
73ELFLOADER_DRIVER(exynos_uart);
74