This is the mail archive of the ecos-patches@sourceware.org mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Fix of Synopsys DesignWare Bug in Serial Driver


The following patch circumvents a bug in the Synopsys DesignWare
16550-compatible UART.
The UART would (a.o.) hang if a character is received while the
baud-rate is being reconfigured.
 
Regards,
Rene Schipp von Branitz Nielsen
Vitesse Semiconductors

Index: ser_16x5x.c
===================================================================
RCS file:
/cvs/ecos/ecos/packages/devs/serial/generic/16x5x/current/src/ser_16x5x.
c,v
retrieving revision 1.17
diff -u -r1.17 ser_16x5x.c
--- ser_16x5x.c 29 Jan 2009 17:48:39 -0000      1.17
+++ ser_16x5x.c 12 Feb 2009 10:05:07 -0000
@@ -77,6 +77,10 @@
 #define REG_msr SER_REG(6)    // Modem status register
 #define REG_scr SER_REG(7)    // Scratch register
 
+#if CYGPKG_IO_SERIAL_GENERIC_16X5X_SYNOPSYS_DESIGNWARE
+#define REG_usr SER_REG(0x1F) // UART status register
+#endif
+
 // Transmit control Registers
 #define REG_thr SER_REG(0)    // Transmit holding register
 #define REG_ier SER_REG(1)    // Interrupt enable register
@@ -129,6 +133,9 @@
 #define ISR_Tx        0x02
 #define ISR_Rx        0x04
 #define ISR_LS        0x06
+#if CYGPKG_IO_SERIAL_GENERIC_16X5X_SYNOPSYS_DESIGNWARE
+#define ISR_BUSY      0x07
+#endif
 #define ISR_RxTO      0x0C
 #define ISR_64BFIFO   0x20
 #define ISR_FIFOworks 0x40
@@ -259,10 +266,39 @@
     _lcr = select_word_length[new_config->word_length -
CYGNUM_SERIAL_WORD_LENGTH_5] | 
         select_stop_bits[new_config->stop] |
         select_parity[new_config->parity];
+   
+#if CYGPKG_IO_SERIAL_GENERIC_16X5X_SYNOPSYS_DESIGNWARE
+    while(1) {
+        // Gotta wait until the LCR_DL bit is set.
+        unsigned char _lcr_rd, _usr;
+        HAL_WRITE_UINT8(base+REG_lcr, _lcr | LCR_DL);
+        HAL_READ_UINT8(base+REG_lcr, _lcr_rd);
+        if(_lcr_rd & LCR_DL)
+            break;
+        // Read the USR to clear any busy interrupts
+        HAL_READ_UINT8(base+REG_usr, _usr);
+    }
+#else
     HAL_WRITE_UINT8(base+REG_lcr, _lcr | LCR_DL);
+#endif
+
     HAL_WRITE_UINT8(base+REG_mdl, baud_divisor >> 8);
     HAL_WRITE_UINT8(base+REG_ldl, baud_divisor & 0xFF);
+
+#if CYGPKG_IO_SERIAL_GENERIC_16X5X_SYNOPSYS_DESIGNWARE
+    while(1) {
+        unsigned char _lcr_rd, _usr;
+        HAL_WRITE_UINT8(base+REG_lcr, _lcr);
+        HAL_READ_UINT8(base+REG_lcr, _lcr_rd);
+        if(!(_lcr_rd & LCR_DL))
+            break;
+        // Read the USR to clear any busy interrupts
+        HAL_READ_UINT8(base+REG_usr, _usr);
+    }
+#else
     HAL_WRITE_UINT8(base+REG_lcr, _lcr);
+#endif
+
     if (init) {
 #ifdef CYGPKG_IO_SERIAL_GENERIC_16X5X_FIFO
         unsigned char _fcr_thresh;
@@ -581,6 +617,19 @@
     // Check if we have an interrupt pending - note that the interrupt
     // is pending of the low bit of the isr is *0*, not 1.
     HAL_READ_UINT8(base+REG_isr, _isr);
+
+#if CYGPKG_IO_SERIAL_GENERIC_16X5X_SYNOPSYS_DESIGNWARE
+    if(_isr & ISR_BUSY) {
+        // This must be checked before the loop below, because
+        // the LSBit is set in the ISR_BUSY mask.
+        // Read uart status register to clear this interrupt, which
+        // may occur if writing to the LCR register while the UART is
busy.
+        cyg_uint8 _usr;
+        HAL_READ_UINT8(base+REG_usr, _usr);
+        HAL_READ_UINT8(base+REG_isr, _isr);
+    }
+#endif
+
     while ((_isr & ISR_nIP) == 0) {
         switch (_isr&0xE) {
         case ISR_Rx:


Index: ser_generic_16x5x.cdl
===================================================================
RCS file:
/cvs/ecos/ecos/packages/devs/serial/generic/16x5x/current/cdl/ser_generi
c_16x5x.cdl,v
retrieving revision 1.10
diff -u -r1.10 ser_generic_16x5x.cdl
--- ser_generic_16x5x.cdl       29 Jan 2009 17:48:39 -0000      1.10
+++ ser_generic_16x5x.cdl       12 Feb 2009 10:06:21 -0000
@@ -121,6 +121,19 @@
                Configures the maximum number of bytes written to the
                16x5x UART transmit FIFO when the TX interrupt occurs."
        }
+        
+    cdl_option CYGPKG_IO_SERIAL_GENERIC_16X5X_SYNOPSYS_DESIGNWARE {
+        display       "16x5x UART is from Synopsys"
+        flavor        bool
+        default_value 0
+        description   "
+            In designs using Synopsys's DesignWare APB UART v.3.04a or
+            earlier, or v.3.05a or later with UART_16550_COMPATIBLE set
+            to 'No', the UART's busy-functionality may cause the UART
+            to hang when programming new divisors while receiving a
+            character. Enabling this option fixes this problem."
+    }
+
     }
             
     cdl_component CYGPKG_IO_SERIAL_GENERIC_16X5X_OPTIONS {


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]