/* * Copyright 2019, Data61 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) * ABN 41 687 119 230. * * This software may be distributed and modified according to the terms of * the BSD 2-Clause license. Note that NO WARRANTY is provided. * See "LICENSE_BSD2.txt" for details. * * @TAG(DATA61_BSD) */ /* $esc:(#include ) */ $esc:(#ifndef CONFIG_PLAT_KZM) $esc:(#include ) $esc:(#include ) $esc:(#include ) $esc:(#include "platsupport/serial.h") $esc:(#include "platsupport/plat/serial.h") $esc:(#include "chardev.h") $esc:(#ifndef UART_REF_CLK) $esc:(#error "UART_REF_CLK undefined") $esc:(#endif) /* Cogent types */ typedef struct _Machine SysState; /* The global state */ struct _Machine { void *priv; ps_chardevice_t *dev; }; #include "generated.c" struct imx_uart_regs { uint32_t rxd; /* 0x000 Receiver Register */ uint32_t res0[15]; uint32_t txd; /* 0x040 Transmitter Register */ uint32_t res1[15]; uint32_t cr1; /* 0x080 Control Register 1 */ uint32_t cr2; /* 0x084 Control Register 2 */ uint32_t cr3; /* 0x088 Control Register 3 */ uint32_t cr4; /* 0x08C Control Register 4 */ uint32_t fcr; /* 0x090 FIFO Control Register */ uint32_t sr1; /* 0x094 Status Register 1 */ uint32_t sr2; /* 0x098 Status Register 2 */ uint32_t esc; /* 0x09c Escape Character Register */ uint32_t tim; /* 0x0a0 Escape Timer Register */ uint32_t bir; /* 0x0a4 BRM Incremental Register */ uint32_t bmr; /* 0x0a8 BRM Modulator Register */ uint32_t brc; /* 0x0ac Baud Rate Counter Register */ uint32_t onems; /* 0x0b0 One Millisecond Register */ uint32_t ts; /* 0x0b4 Test Register */ }; typedef volatile struct imx_uart_regs imx_uart_regs_t; static inline imx_uart_regs_t *imx_uart_get_priv(ps_chardevice_t *d) { return (imx_uart_regs_t *)d->vaddr; } /** * Register readers and writers. */ #define REG_RW_FN(REG) \ $ty:((U32, SysState)) $id:(imx_uart_regs_read_##REG)($ty:(SysState) st) \ { \ imx_uart_regs_t *regs; \ $ty:((U32, SysState)) ret; \ \ regs = imx_uart_get_priv(st->dev); \ ret.p1 = regs->REG; \ ret.p2 = st; \ \ return ret; \ } \ \ $ty:((SysState)) imx_uart_regs_write_##REG($ty:((U32, SysState)) args) \ { \ $ty:(SysState) st = args.p2; \ imx_uart_regs_t *regs; \ \ regs = imx_uart_get_priv(st->dev); \ regs->REG = args.p1; \ \ return st; \ } REG_RW_FN(rxd) REG_RW_FN(txd) REG_RW_FN(cr1) REG_RW_FN(cr2) REG_RW_FN(cr3) REG_RW_FN(cr4) REG_RW_FN(fcr) REG_RW_FN(sr1) REG_RW_FN(sr2) REG_RW_FN(esc) REG_RW_FN(tim) REG_RW_FN(bir) REG_RW_FN(bmr) REG_RW_FN(brc) REG_RW_FN(onems) REG_RW_FN(ts) static void uart_handle_irq(ps_chardevice_t* d) { /* TODO */ } int uart_getchar(ps_chardevice_t* d) { $ty:((SysState, U32)) ret; SysState st; uint32_t reg = 0; int c = -1; st.dev = d; ret = uart_getchar_cg(&st); c = ret.p2; return c; } int uart_putchar(ps_chardevice_t* d, int c) { imx_uart_regs_t* regs = imx_uart_get_priv(d); if (regs->sr2 & UART_SR2_TXFIFO_EMPTY) { if (c == '\n' && (d->flags & SERIAL_AUTO_CR)) { uart_putchar(d, '\r'); } regs->txd = c; return c; } else { return -1; } } $ty:((SysState)) uart_setup_phase1_ac($ty:((SysState)) state) { imx_uart_regs_t* regs = imx_uart_get_priv(state->dev); while (!(regs->cr2 & UART_CR2_SRST)); return state; } int uart_init(const struct dev_defn *defn, const ps_io_ops_t *ops, ps_chardevice_t *dev) { imx_uart_regs_t* regs; SysState st; $ty:((SysState)) ret; /* Attempt to map the virtual address, assure this works */ void* vaddr = chardev_map(defn, ops); if (vaddr == NULL) { return -1; } memset(dev, 0, sizeof(*dev)); /* Set up all the device properties. */ dev->id = defn->id; dev->vaddr = (void*)vaddr; dev->read = &uart_read; dev->write = &uart_write; dev->handle_irq = &uart_handle_irq; dev->irqs = defn->irqs; dev->ioops = *ops; dev->flags = SERIAL_AUTO_CR; st.dev = dev; ret = $exp:uart_setup(&st); $escstm:(#ifdef CONFIG_PLAT_IMX6) /* The UART1 on the IMX6 has the problem that the MUX is not correctly set, * and the RX PIN is not routed correctly. */ if ((defn->id == IMX_UART1) && mux_sys_valid(&ops->mux_sys)) { if (mux_feature_enable(&ops->mux_sys, MUX_UART1, 0)) { // Failed to configure the mux return -1; } } $escstm:(#endif) return 0; } $esc:(#endif) /* end of !CONFIG_PLAT_KZM */