summaryrefslogtreecommitdiffstats
path: root/cfe/cfe/arch/mips/board/bcm63xx_ram/src/dev_bcm63xx_uart.c
diff options
context:
space:
mode:
Diffstat (limited to 'cfe/cfe/arch/mips/board/bcm63xx_ram/src/dev_bcm63xx_uart.c')
-rwxr-xr-xcfe/cfe/arch/mips/board/bcm63xx_ram/src/dev_bcm63xx_uart.c211
1 files changed, 211 insertions, 0 deletions
diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/src/dev_bcm63xx_uart.c b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/dev_bcm63xx_uart.c
new file mode 100755
index 0000000..3b2ce63
--- /dev/null
+++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/dev_bcm63xx_uart.c
@@ -0,0 +1,211 @@
+#include "cfe.h"
+#include "lib_types.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+#include "cfe_iocb.h"
+#include "cfe_device.h"
+#include "cfe_ioctl.h"
+
+#include "sbmips.h"
+#include "bsp_config.h"
+
+#include "bcm_hwdefs.h"
+#include "bcm_map.h"
+
+static void bcm63xx_uart_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr);
+
+static int bcm63xx_uart_open(cfe_devctx_t *ctx);
+static int bcm63xx_uart_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int bcm63xx_uart_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
+static int bcm63xx_uart_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int bcm63xx_uart_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int bcm63xx_uart_close(cfe_devctx_t *ctx);
+
+const static cfe_devdisp_t bcm63xx_uart_dispatch = {
+ bcm63xx_uart_open,
+ bcm63xx_uart_read,
+ bcm63xx_uart_inpstat,
+ bcm63xx_uart_write,
+ bcm63xx_uart_ioctl,
+ bcm63xx_uart_close,
+ NULL,
+ NULL
+};
+
+
+const cfe_driver_t bcm63xx_uart = {
+ "BCM63xx DUART",
+ "uart",
+ CFE_DEV_SERIAL,
+ &bcm63xx_uart_dispatch,
+ bcm63xx_uart_probe
+};
+
+
+typedef struct bcm63xx_uart_s {
+ int baudrate;
+} bcm63xx_uart_t;
+
+
+static void bcm63xx_set_baudrate( bcm63xx_uart_t * softc )
+{
+ uint32_t baudwd;
+
+ baudwd = (FPERIPH / softc->baudrate) / 16;
+ if( baudwd & 0x1 ) {
+ baudwd = baudwd / 2;
+ } else {
+ baudwd = baudwd / 2 - 1;
+ }
+ UART->baudword = baudwd;
+}
+
+
+static void bcm63xx_uart_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr)
+{
+ bcm63xx_uart_t * softc;
+ char descr[80];
+
+ /* enable the transmitter interrupt? */
+
+ /*
+ * probe_a is the DUART base address.
+ * probe_b is the channel-number-within-duart (0 or 1)
+ * probe_ptr is unused.
+ */
+ softc = (bcm63xx_uart_t *) KMALLOC(sizeof(bcm63xx_uart_t),0);
+ if (softc) {
+ xsprintf( descr, "%s channel %d", drv->drv_description, probe_b );
+ cfe_attach( drv, softc, NULL, descr );
+ }
+}
+
+static int bcm63xx_uart_open(cfe_devctx_t *ctx)
+{
+ bcm63xx_uart_t * softc = ctx->dev_softc;
+
+ /* Enable the UART clock */
+ softc->baudrate = CFG_SERIAL_BAUD_RATE;
+ bcm63xx_set_baudrate( softc );
+
+ UART->control = BRGEN | TXEN | RXEN;
+ UART->config = BITS8SYM | ONESTOP;
+ UART->fifoctl = RSTTXFIFOS | RSTRXFIFOS;
+ UART->intMask = 0;
+
+ return 0;
+}
+
+
+static int bcm63xx_uart_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+ unsigned char * bptr;
+ int blen;
+ uint32_t status;
+ char inval;
+
+ bptr = buffer->buf_ptr;
+ blen = buffer->buf_length;
+
+ while (blen > 0) {
+ status = UART->intStatus;
+ if(status & (RXOVFERR | RXPARERR | RXFRAMERR | RXBRK)) {
+ /* RX over flow */
+ if(status & RXOVFERR) {
+ /* reset RX FIFO to clr interrupt */
+ UART->fifoctl |= RSTRXFIFOS;
+ }
+
+ /* other errors just read the bad character to clear the bit */
+ inval = UART->Data;
+ }
+ else if(status & RXFIFONE) {
+ *bptr++ = UART->Data;
+ blen--;
+ }
+ else
+ break;
+ }
+
+ buffer->buf_retlen = buffer->buf_length - blen;
+ return 0;
+}
+
+
+static int bcm63xx_uart_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat)
+{
+ inpstat->inp_status = UART->intStatus & RXFIFONE;
+ return 0;
+}
+
+
+static int bcm63xx_uart_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+ unsigned char * bptr;
+ int blen;
+ uint32_t status;
+
+ bptr = buffer->buf_ptr;
+ blen = buffer->buf_length;
+
+ status = 0;
+ while( (blen > 0) && !status ) {
+ /* Wait for the buffer to empty before we write the next character */
+ /* FIXME - The serial port should be able to accept more than one */
+ /* character at a time. Why doesn't it work though? */
+ do {
+ status = UART->intStatus & TXFIFOEMT;
+ } while( !status );
+ UART->Data = *bptr;
+ bptr++;
+ blen--;
+
+ status = UART->intStatus & (TXOVFERR|TXUNDERR);
+ }
+
+ if( status ) {
+ /* Reset TX FIFO */
+ UART->fifoctl |= RSTTXFIFOS;
+ blen++;
+ }
+
+ buffer->buf_retlen = buffer->buf_length - blen;
+ return 0;
+}
+
+
+static int bcm63xx_uart_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+ bcm63xx_uart_t * softc = ctx->dev_softc;
+ unsigned int * info = (unsigned int *) buffer->buf_ptr;
+
+ switch ((int)buffer->buf_ioctlcmd) {
+ case IOCTL_SERIAL_GETSPEED:
+ *info = softc->baudrate;
+ break;
+ case IOCTL_SERIAL_SETSPEED:
+ softc->baudrate = *info;
+ bcm63xx_set_baudrate( softc );
+ break;
+ case IOCTL_SERIAL_GETFLOW:
+ *info = SERIAL_FLOW_NONE;
+ break;
+ case IOCTL_SERIAL_SETFLOW:
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int bcm63xx_uart_close(cfe_devctx_t *ctx)
+{
+ /* Turn off the UART clock. */
+ return 0;
+}