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/* $esc:(#include <autoconf.h>) */ 14 15$esc:(#ifndef CONFIG_PLAT_KZM) 16 17$esc:(#include <stdint.h>) 18$esc:(#include <stdlib.h>) 19$esc:(#include <string.h>) 20$esc:(#include "platsupport/serial.h") 21$esc:(#include "platsupport/plat/serial.h") 22 23$esc:(#include "chardev.h") 24 25$esc:(#ifndef UART_REF_CLK) 26$esc:(#error "UART_REF_CLK undefined") 27$esc:(#endif) 28 29 30/* Cogent types */ 31typedef struct _Machine SysState; 32 33/* The global state */ 34struct _Machine { 35 void *priv; 36 ps_chardevice_t *dev; 37}; 38 39 40#include "generated.c" 41 42struct imx_uart_regs { 43 uint32_t rxd; /* 0x000 Receiver Register */ 44 uint32_t res0[15]; 45 uint32_t txd; /* 0x040 Transmitter Register */ 46 uint32_t res1[15]; 47 uint32_t cr1; /* 0x080 Control Register 1 */ 48 uint32_t cr2; /* 0x084 Control Register 2 */ 49 uint32_t cr3; /* 0x088 Control Register 3 */ 50 uint32_t cr4; /* 0x08C Control Register 4 */ 51 uint32_t fcr; /* 0x090 FIFO Control Register */ 52 uint32_t sr1; /* 0x094 Status Register 1 */ 53 uint32_t sr2; /* 0x098 Status Register 2 */ 54 uint32_t esc; /* 0x09c Escape Character Register */ 55 uint32_t tim; /* 0x0a0 Escape Timer Register */ 56 uint32_t bir; /* 0x0a4 BRM Incremental Register */ 57 uint32_t bmr; /* 0x0a8 BRM Modulator Register */ 58 uint32_t brc; /* 0x0ac Baud Rate Counter Register */ 59 uint32_t onems; /* 0x0b0 One Millisecond Register */ 60 uint32_t ts; /* 0x0b4 Test Register */ 61}; 62typedef volatile struct imx_uart_regs imx_uart_regs_t; 63 64static inline imx_uart_regs_t *imx_uart_get_priv(ps_chardevice_t *d) 65{ 66 return (imx_uart_regs_t *)d->vaddr; 67} 68 69 70/** 71 * Register readers and writers. 72 */ 73#define REG_RW_FN(REG) \ 74$ty:((U32, SysState)) $id:(imx_uart_regs_read_##REG)($ty:(SysState) st) \ 75{ \ 76 imx_uart_regs_t *regs; \ 77 $ty:((U32, SysState)) ret; \ 78 \ 79 regs = imx_uart_get_priv(st->dev); \ 80 ret.p1 = regs->REG; \ 81 ret.p2 = st; \ 82 \ 83 return ret; \ 84} \ 85 \ 86$ty:((SysState)) imx_uart_regs_write_##REG($ty:((U32, SysState)) args) \ 87{ \ 88 $ty:(SysState) st = args.p2; \ 89 imx_uart_regs_t *regs; \ 90 \ 91 regs = imx_uart_get_priv(st->dev); \ 92 regs->REG = args.p1; \ 93 \ 94 return st; \ 95} 96 97REG_RW_FN(rxd) 98REG_RW_FN(txd) 99REG_RW_FN(cr1) 100REG_RW_FN(cr2) 101REG_RW_FN(cr3) 102REG_RW_FN(cr4) 103REG_RW_FN(fcr) 104REG_RW_FN(sr1) 105REG_RW_FN(sr2) 106REG_RW_FN(esc) 107REG_RW_FN(tim) 108REG_RW_FN(bir) 109REG_RW_FN(bmr) 110REG_RW_FN(brc) 111REG_RW_FN(onems) 112REG_RW_FN(ts) 113 114static void uart_handle_irq(ps_chardevice_t* d) 115{ 116 /* TODO */ 117} 118 119int uart_getchar(ps_chardevice_t* d) 120{ 121 $ty:((SysState, U32)) ret; 122 SysState st; 123 uint32_t reg = 0; 124 int c = -1; 125 126 st.dev = d; 127 ret = uart_getchar_cg(&st); 128 129 c = ret.p2; 130 131 return c; 132} 133 134int uart_putchar(ps_chardevice_t* d, int c) 135{ 136 imx_uart_regs_t* regs = imx_uart_get_priv(d); 137 if (regs->sr2 & UART_SR2_TXFIFO_EMPTY) { 138 if (c == '\n' && (d->flags & SERIAL_AUTO_CR)) { 139 uart_putchar(d, '\r'); 140 } 141 regs->txd = c; 142 return c; 143 } else { 144 return -1; 145 } 146} 147 148$ty:((SysState)) uart_setup_phase1_ac($ty:((SysState)) state) 149{ 150 imx_uart_regs_t* regs = imx_uart_get_priv(state->dev); 151 152 while (!(regs->cr2 & UART_CR2_SRST)); 153 154 return state; 155} 156 157int uart_init(const struct dev_defn *defn, 158 const ps_io_ops_t *ops, 159 ps_chardevice_t *dev) 160{ 161 imx_uart_regs_t* regs; 162 SysState st; 163 $ty:((SysState)) ret; 164 165 /* Attempt to map the virtual address, assure this works */ 166 void* vaddr = chardev_map(defn, ops); 167 if (vaddr == NULL) { 168 return -1; 169 } 170 171 memset(dev, 0, sizeof(*dev)); 172 173 /* Set up all the device properties. */ 174 dev->id = defn->id; 175 dev->vaddr = (void*)vaddr; 176 dev->read = &uart_read; 177 dev->write = &uart_write; 178 dev->handle_irq = &uart_handle_irq; 179 dev->irqs = defn->irqs; 180 dev->ioops = *ops; 181 dev->flags = SERIAL_AUTO_CR; 182 183 st.dev = dev; 184 ret = $exp:uart_setup(&st); 185 186 $escstm:(#ifdef CONFIG_PLAT_IMX6) 187 /* The UART1 on the IMX6 has the problem that the MUX is not correctly set, 188 * and the RX PIN is not routed correctly. 189 */ 190 if ((defn->id == IMX_UART1) && mux_sys_valid(&ops->mux_sys)) { 191 if (mux_feature_enable(&ops->mux_sys, MUX_UART1, 0)) { 192 // Failed to configure the mux 193 return -1; 194 } 195 } 196 $escstm:(#endif) 197 return 0; 198} 199 200$esc:(#endif) /* end of !CONFIG_PLAT_KZM */ 201