1/* 2 * Copyright 2017, 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 <stdlib.h> 14#include <platsupport/serial.h> 15#include <platsupport/plat/serial.h> 16#include <string.h> 17#include <stdio.h> 18#include "../../chardev.h" 19 20#define AXI_UARTLITE_CR_RST_TX_FIFO BIT(0) 21#define AXI_UARTLITE_CR_RST_RX_FIFO BIT(1) 22#define AXI_UARTLITE_CR_ENABLE_INTR BIT(4) 23 24#define AXI_UARTLITE_SR_RX_FIFO_VALID BIT(0) 25#define AXI_UARTLITE_SR_RX_FIFO_FULL BIT(1) 26#define AXI_UARTLITE_SR_TX_FIFO_EMPTY BIT(2) 27#define AXI_UARTLITE_SR_TX_FIFO_FULL BIT(3) 28#define AXI_UARTLITE_SR_INTR_ENABLED BIT(4) 29#define AXI_UARTLITE_SR_OVERRUN_ERROR BIT(5) 30#define AXI_UARTLITE_SR_FRAME_ERROR BIT(6) 31#define AXI_UARTLITE_SR_PARITY_ERROR BIT(7) 32 33struct zynq_axi_uartlite_regs { 34 uint32_t rx_fifo; /* 0x0 Receive FIFO */ 35 uint32_t tx_fifo; /* 0x4 Transmit FIFO */ 36 uint32_t sr; /* 0x8 Status Register */ 37 uint32_t cr; /* 0xC Control Register */ 38}; 39typedef volatile struct zynq_axi_uartlite_regs zynq_axi_uartlite_regs_t; 40 41static inline zynq_axi_uartlite_regs_t* 42zynq_axi_uartlite_get_priv(ps_chardevice_t *d) 43{ 44 return (zynq_axi_uartlite_regs_t*)d->vaddr; 45} 46 47static int axi_uartlite_getchar(ps_chardevice_t *d) 48{ 49 zynq_axi_uartlite_regs_t *regs = 50 zynq_axi_uartlite_get_priv(d); 51 52 int c = -1; 53 54 /* check if there is at least one byte in the fifo */ 55 if (regs->sr & AXI_UARTLITE_SR_RX_FIFO_VALID) { 56 c = regs->rx_fifo; 57 } 58 59 return c; 60} 61 62static int axi_uartlite_putchar(ps_chardevice_t *d, int c) 63{ 64 65 static int needs_newline = 0; 66 67 zynq_axi_uartlite_regs_t *regs = 68 zynq_axi_uartlite_get_priv(d); 69 70 /* check if fifo is full */ 71 if (regs->sr & AXI_UARTLITE_SR_TX_FIFO_FULL) { 72 return -1; 73 } else { 74 if (needs_newline) { 75 /* if the last putchar was a '\n' and the fifo filled after 76 * only the '\r' was sent, send the remaining '\n' here */ 77 regs->tx_fifo = '\n'; 78 needs_newline = 0; 79 if (regs->sr & AXI_UARTLITE_SR_TX_FIFO_FULL) { 80 return -1; 81 } 82 } 83 if (c == '\n') { 84 regs->tx_fifo = '\r'; 85 /* the fifo may have filled after sending the '\r' */ 86 if (regs->sr & AXI_UARTLITE_SR_TX_FIFO_FULL) { 87 needs_newline = 1; 88 /* even if the '\n' didn't get sent on this call, still 89 * return '\n', as it will still eventually be sent */ 90 } else { 91 regs->tx_fifo = '\n'; 92 } 93 } else { 94 regs->tx_fifo = c; 95 } 96 return c; 97 } 98} 99 100static ssize_t axi_uartlite_write(ps_chardevice_t* d, const void* vdata, 101 size_t count, chardev_callback_t rcb UNUSED, 102 void* token UNUSED) 103{ 104 const char *data = (const char*)vdata; 105 for (int i = 0; i < count; i++) { 106 if (axi_uartlite_putchar(d, *data++) < 0) { 107 return i; 108 } 109 } 110 return count; 111} 112 113static ssize_t axi_uartlite_read(ps_chardevice_t* d, void* vdata, 114 size_t count, chardev_callback_t rcb UNUSED, 115 void* token UNUSED) 116{ 117 char *data = (char*)vdata; 118 for (int i = 0; i < count; i++) { 119 int ch = axi_uartlite_getchar(d); 120 if (ch != EOF) { 121 *data++ = ch; 122 } else { 123 return i; 124 } 125 } 126 return count; 127} 128 129int axi_uartlite_init(void* vaddr, ps_chardevice_t* dev) 130{ 131 132 memset(dev, 0, sizeof(*dev)); 133 134 dev->vaddr = vaddr; 135 dev->read = &axi_uartlite_read; 136 dev->write = &axi_uartlite_write; 137 138 zynq_axi_uartlite_regs_t *regs = zynq_axi_uartlite_get_priv(dev); 139 140 // clear the fifos 141 regs->cr |= (AXI_UARTLITE_CR_RST_TX_FIFO | AXI_UARTLITE_CR_RST_RX_FIFO); 142 143 // disable interrupts 144 regs->cr &= ~AXI_UARTLITE_CR_ENABLE_INTR; 145 146 return 0; 147} 148 149int axi_uartlite_init_defn(const struct dev_defn* defn, 150 const ps_io_ops_t* ops, 151 ps_chardevice_t* dev) 152{ 153 154 void *vaddr = chardev_map(defn, ops); 155 if (vaddr == NULL) { 156 return -1; 157 } 158 159 axi_uartlite_init(vaddr, dev); 160 161 dev->id = defn->id; 162 dev->irqs = defn->irqs; 163 dev->ioops = *ops; 164 165 return 0; 166} 167