sim: bfin: implement loop back support in the UARTs
authorMike Frysinger <vapier@gentoo.org>
Sat, 14 May 2011 15:59:09 +0000 (15:59 +0000)
committerMike Frysinger <vapier@gentoo.org>
Sat, 14 May 2011 15:59:09 +0000 (15:59 +0000)
The UART has a LOOP_ENA bit in its MCR register where writes to the THR
go to the RBR.  Implement support for this mode.

Signed-off-by: Mike Frysinger <vapier@gentoo.org>
sim/bfin/ChangeLog
sim/bfin/dv-bfin_uart.c
sim/bfin/dv-bfin_uart.h
sim/bfin/dv-bfin_uart2.c

index 6785044..a69d6e2 100644 (file)
@@ -1,3 +1,18 @@
+2011-05-14  Mike Frysinger  <vapier@gentoo.org>
+
+       * dv-bfin_uart.c (bfin_uart_write_byte): Add a mcr arg.  Declare a
+       local uart.  When LOOP_ENA is set in mcr, write to the saved byte
+       and count fields of the uart.
+       (bfin_uart_io_write_buffer): Pass uart->mcr to bfin_uart_write_byte
+       and bfin_uart_get_next_byte.
+       (bfin_uart_get_next_byte): Add a mcr arg.  Move uart->saved_count
+       check first, and skip the remaining code when LOOP_ENA is set in mcr.
+       * dv-bfin_uart.h (bfin_uart_write_byte): Add an mcr argument.
+       (bfin_uart_get_next_byte): Likewise.
+       (XOFF, MRTS, RFIT, RFRT, LOOP_ENA, FCPOL, ARTS, ACTS): Define.
+       * dv-bfin_uart2.c (bfin_uart_io_write_buffer): Padd uart->mcr when
+       calling bfin_uart_write_byte and bfin_uart_get_next_byte.
+
 2011-05-09  Mike Frysinger  <vapier@gentoo.org>
 
        * dv-bfin_uart2.c (bfin_uart_io_read_buffer): Clear DR/THRE/TEMT bits
index f05ee15..697fa96 100644 (file)
@@ -117,10 +117,21 @@ bfin_uart_reschedule (struct hw *me)
 }
 
 bu16
-bfin_uart_write_byte (struct hw *me, bu16 thr)
+bfin_uart_write_byte (struct hw *me, bu16 thr, bu16 mcr)
 {
+  struct bfin_uart *uart = hw_data (me);
   unsigned char ch = thr;
+
+  if (mcr & LOOP_ENA)
+    {
+      /* XXX: This probably doesn't work exactly right with
+              external FIFOs ...  */
+      uart->saved_byte = thr;
+      uart->saved_count = 1;
+    }
+
   bfin_uart_write_buffer (me, &ch, 1);
+
   return thr;
 }
 
@@ -149,7 +160,7 @@ bfin_uart_io_write_buffer (struct hw *me, const void *source,
        uart->dll = value;
       else
        {
-         uart->thr = bfin_uart_write_byte (me, value);
+         uart->thr = bfin_uart_write_byte (me, value, uart->mcr);
 
          if (uart->ier & ETBEI)
            hw_port_event (me, DV_PORT_TX, 1);
@@ -184,7 +195,7 @@ bfin_uart_io_write_buffer (struct hw *me, const void *source,
 
 /* Switch between socket and stdin on the fly.  */
 bu16
-bfin_uart_get_next_byte (struct hw *me, bu16 rbr, bool *fresh)
+bfin_uart_get_next_byte (struct hw *me, bu16 rbr, bu16 mcr, bool *fresh)
 {
   SIM_DESC sd = hw_system (me);
   struct bfin_uart *uart = hw_data (me);
@@ -197,23 +208,26 @@ bfin_uart_get_next_byte (struct hw *me, bu16 rbr, bool *fresh)
     fresh = &_fresh;
 
   *fresh = false;
-  if (status & DV_SOCKSER_DISCONNECTED)
+
+  if (uart->saved_count > 0)
+    {
+      *fresh = true;
+      rbr = uart->saved_byte;
+      --uart->saved_count;
+    }
+  else if (mcr & LOOP_ENA)
+    {
+      /* RX is disconnected, so only return local data.  */
+    }
+  else if (status & DV_SOCKSER_DISCONNECTED)
     {
-      if (uart->saved_count > 0)
+      char byte;
+      int ret = sim_io_poll_read (sd, 0/*STDIN*/, &byte, 1);
+
+      if (ret > 0)
        {
          *fresh = true;
-         rbr = uart->saved_byte;
-         --uart->saved_count;
-       }
-      else
-       {
-         char byte;
-         int ret = sim_io_poll_read (sd, 0/*STDIN*/, &byte, 1);
-         if (ret > 0)
-           {
-             *fresh = true;
-             rbr = byte;
-           }
+         rbr = byte;
        }
     }
   else
@@ -239,7 +253,7 @@ bfin_uart_get_status (struct hw *me)
     }
   else
     lsr |= (status & DV_SOCKSER_INPUT_EMPTY ? 0 : DR) |
-                (status & DV_SOCKSER_OUTPUT_EMPTY ? TEMT | THRE : 0);
+          (status & DV_SOCKSER_OUTPUT_EMPTY ? TEMT | THRE : 0);
 
   return lsr;
 }
@@ -266,7 +280,7 @@ bfin_uart_io_read_buffer (struct hw *me, void *dest,
        dv_store_2 (dest, uart->dll);
       else
        {
-         uart->rbr = bfin_uart_get_next_byte (me, uart->rbr, NULL);
+         uart->rbr = bfin_uart_get_next_byte (me, uart->rbr, uart->mcr, NULL);
          dv_store_2 (dest, uart->rbr);
        }
       break;
index ccb7af4..52074f6 100644 (file)
@@ -26,8 +26,8 @@
 #define BFIN_MMR_UART_SIZE     0x30
 
 struct bfin_uart;
-bu16 bfin_uart_get_next_byte (struct hw *, bu16, bool *fresh);
-bu16 bfin_uart_write_byte (struct hw *, bu16);
+bu16 bfin_uart_get_next_byte (struct hw *, bu16, bu16, bool *fresh);
+bu16 bfin_uart_write_byte (struct hw *, bu16, bu16);
 bu16 bfin_uart_get_status (struct hw *);
 unsigned bfin_uart_write_buffer (struct hw *, const unsigned char *, unsigned);
 unsigned bfin_uart_read_buffer (struct hw *, unsigned char *, unsigned);
@@ -51,4 +51,14 @@ void bfin_uart_reschedule (struct hw *);
 #define ETBEI  (1 << 1)
 #define ELSI   (1 << 2)
 
+/* UART_MCR */
+#define XOFF           (1 << 0)
+#define MRTS           (1 << 1)
+#define RFIT           (1 << 2)
+#define RFRT           (1 << 3)
+#define LOOP_ENA       (1 << 4)
+#define FCPOL          (1 << 5)
+#define ARTS           (1 << 6)
+#define ACTS           (1 << 7)
+
 #endif
index 179574d..16ede50 100644 (file)
@@ -89,7 +89,7 @@ bfin_uart_io_write_buffer (struct hw *me, const void *source,
   switch (mmr_off)
     {
     case mmr_offset(thr):
-      uart->thr = bfin_uart_write_byte (me, value);
+      uart->thr = bfin_uart_write_byte (me, value, uart->mcr);
       if (uart->ier & ETBEI)
        hw_port_event (me, DV_PORT_TX, 1);
       break;
@@ -142,7 +142,7 @@ bfin_uart_io_read_buffer (struct hw *me, void *dest,
   switch (mmr_off)
     {
     case mmr_offset(rbr):
-      uart->rbr = bfin_uart_get_next_byte (me, uart->rbr, NULL);
+      uart->rbr = bfin_uart_get_next_byte (me, uart->rbr, uart->mcr, NULL);
       dv_store_2 (dest, uart->rbr);
       break;
     case mmr_offset(ier_set):