1/* 2 * Copyright 2019, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13#include <autoconf.h> 14 15#include <stdlib.h> 16#include <platsupport/serial.h> 17#include <platsupport/plat/serial.h> 18#include <string.h> 19 20#include "../../chardev.h" 21 22#define UART_TX_DATA_MASK 0xFF 23#define UART_TX_DATA_FULL BIT(31) 24 25#define UART_RX_DATA_MASK 0xFF 26#define UART_RX_DATA_EMPTY BIT(31) 27 28#define UART_TX_INT_EN BIT(0) 29#define UART_RX_INT_EN BIT(1) 30 31#define UART_TX_INT_PEND BIT(0) 32#define UART_RX_INT_PEND BIT(1) 33#define UART_BAUD_DIVISOR 4340 34struct uart { 35 uint32_t txdata; 36 uint32_t rxdata; 37 uint32_t txctrl; 38 uint32_t rxctrl; 39 uint32_t ie; 40 uint32_t ip; 41 uint32_t div; 42}; 43typedef volatile struct uart uart_regs_t; 44 45static inline uart_regs_t* 46uart_get_priv(ps_chardevice_t *d) 47{ 48 return (uart_regs_t*)d->vaddr; 49} 50 51int uart_getchar(ps_chardevice_t *d) 52{ 53 uart_regs_t* regs = uart_get_priv(d); 54 uint32_t reg = regs->rxdata; 55 int c = -1; 56 57 if (!(reg & UART_RX_DATA_EMPTY)) { 58 c = reg & UART_RX_DATA_MASK; 59 } 60 return c; 61} 62 63int uart_putchar(ps_chardevice_t* d, int c) 64{ 65 uart_regs_t* regs = uart_get_priv(d); 66 if (!(regs->txdata & UART_TX_DATA_FULL)) { 67 if (c == '\n' && (d->flags & SERIAL_AUTO_CR)) { 68 regs->txdata = '\r' & UART_TX_DATA_MASK; 69 while(regs->txdata & UART_TX_DATA_FULL) {} 70 } 71 regs->txdata = c & UART_TX_DATA_MASK; 72 return c; 73 } else { 74 return -1; 75 } 76} 77 78static void 79uart_handle_irq(ps_chardevice_t* d UNUSED) 80{ 81 // IRQs are cleared when the TX/RX watermark conditions are no longer met 82 // so there is nothing to do here. 83} 84 85int uart_init(const struct dev_defn* defn, 86 const ps_io_ops_t* ops, 87 ps_chardevice_t* dev) 88{ 89 uart_regs_t* regs; 90 /* Attempt to map the virtual address, assure this works */ 91 void* vaddr = chardev_map(defn, ops); 92 if (vaddr == NULL) { 93 return -1; 94 } 95 96 memset(dev, 0, sizeof(*dev)); 97 98 /* Set up all the device properties. */ 99 dev->id = defn->id; 100 dev->vaddr = (void*)vaddr; 101 dev->read = &uart_read; 102 dev->write = &uart_write; 103 dev->handle_irq = &uart_handle_irq; 104 dev->irqs = defn->irqs; 105 dev->ioops = *ops; 106 dev->flags = SERIAL_AUTO_CR; 107 108 regs = uart_get_priv(dev); 109 110 /* 111 * Enable TX and RX and don't set any watermark levels. 112 * 0 watermark on RX indicates an IRQ when more than 0 chars in RX buffer 113 * O watermark on TX indicates no IRQ (less than 0 chars in TX buffer) 114 */ 115 regs->txctrl = 0x00001; 116 regs->rxctrl = 0x00001; 117 /* Enable RX IRQs. We don't enable TX IRQs as we don't expect any. */ 118 regs->ie = 0x2; 119 120 if (regs->div != UART_BAUD_DIVISOR) { 121 ZF_LOGW("Warning: We require a target baud of 115200 and assume an input clk freq 500MHz."); 122 ZF_LOGW("Warning: However an incorrect divisor is set: %d, expected %d", regs->div, UART_BAUD_DIVISOR); 123 } 124 125 return 0; 126} 127