This is the mail archive of the
ecos-patches@sourceware.org
mailing list for the eCos project.
Fix of Synopsys DesignWare Bug in Serial Driver
- From: "Rene Nielsen" <rbn at vitesse dot com>
- To: <ecos-patches at sourceware dot org>
- Date: Thu, 12 Feb 2009 11:11:47 +0100
- Subject: 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 {