blob: ce905bae6e4c1833f53692a7516a0f53c4a7ee94 [file] [log] [blame] [edit]
/*
* 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 <autoconf.h>) */
$esc:(#ifndef CONFIG_PLAT_KZM)
$esc:(#include <stdint.h>)
$esc:(#include <stdlib.h>)
$esc:(#include <string.h>)
$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 */