[U-Boot-Users] [PATCH/review] Blackfin: make baud calculation more accurate

We should use the algorithm in the Linux kernel so that the UART divisor calculation is more accurate. It also fixes problems on some picky UARTs that have sampling anomalies.
Signed-off-by: Mike Frysinger vapier@gentoo.org --- cpu/blackfin/serial.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/cpu/blackfin/serial.h b/cpu/blackfin/serial.h index 1f0f4b4..d268da5 100644 --- a/cpu/blackfin/serial.h +++ b/cpu/blackfin/serial.h @@ -179,7 +179,7 @@ static inline void serial_early_set_baud(uint32_t baud) * The +1 is to make sure we over sample just a little * rather than under sample the incoming signals. */ - uint16_t divisor = (get_sclk() / (baud * 16)) + 1; + uint16_t divisor = (get_sclk() + (baud * 8)) / (baud * 16);
/* Set DLAB in LCR to Access DLL and DLH */ ACCESS_LATCH();

Some Blackfin UARTs are read-to-clear while others are write-to-clear. This can cause problems when we poll the LSR and then later try and handle any errors detected.
Signed-off-by: Mike Frysinger vapier@gentoo.org --- cpu/blackfin/serial.c | 72 ++++++++++++++++++++++++++++++++++++++++-------- 1 files changed, 60 insertions(+), 12 deletions(-)
diff --git a/cpu/blackfin/serial.c b/cpu/blackfin/serial.c index 0dfee51..6134474 100644 --- a/cpu/blackfin/serial.c +++ b/cpu/blackfin/serial.c @@ -35,6 +35,32 @@
#include "serial.h"
+#ifdef CONFIG_DEBUG_SERIAL +uint16_t cached_lsr[256]; +uint16_t cached_rbr[256]; +size_t cache_count; + +/* The LSR is read-to-clear on some parts, so we have to make sure status + * bits aren't inadvertently lost when doing various tests. + */ +static uint16_t uart_lsr_save; +static uint16_t uart_lsr_read(void) +{ + uint16_t lsr = *pUART_LSR; + uart_lsr_save |= (lsr & (OE|PE|FE|BI)); + return lsr | uart_lsr_save; +} +/* Just do the clear for everyone since it can't hurt. */ +static void uart_lsr_clear(void) +{ + uart_lsr_save = 0; + *pUART_LSR |= -1; +} +#else +static inline uint16_t uart_lsr_read(void) { return *pUART_LSR; } +static inline void uart_lsr_clear(void) { *pUART_LSR = -1; } +#endif + /* Symbol for our assembly to call. */ void serial_set_baud(uint32_t baud) { @@ -61,6 +87,12 @@ int serial_init(void) { serial_initialize(); serial_setbrg(); + uart_lsr_clear(); +#ifdef CONFIG_DEBUG_SERIAL + cache_count = 0; + memset(cached_lsr, 0x00, sizeof(cached_lsr)); + memset(cached_rbr, 0x00, sizeof(cached_rbr)); +#endif return 0; }
@@ -73,7 +105,7 @@ void serial_putc(const char c) WATCHDOG_RESET();
/* wait for the hardware fifo to clear up */ - while (!(*pUART_LSR & THRE)) + while (!(uart_lsr_read() & THRE)) continue;
/* queue the character for transmission */ @@ -83,38 +115,54 @@ void serial_putc(const char c) WATCHDOG_RESET();
/* wait for the byte to be shifted over the line */ - while (!(*pUART_LSR & TEMT)) + while (!(uart_lsr_read() & TEMT)) continue; }
int serial_tstc(void) { WATCHDOG_RESET(); - return (*pUART_LSR & DR) ? 1 : 0; + return (uart_lsr_read() & DR) ? 1 : 0; }
int serial_getc(void) { - uint16_t uart_lsr_val, uart_rbr_val; + uint16_t uart_rbr_val;
/* wait for data ! */ while (!serial_tstc()) continue;
- /* clear the status and grab the new byte */ - uart_lsr_val = *pUART_LSR; + /* grab the new byte */ uart_rbr_val = *pUART_RBR;
+#ifdef CONFIG_DEBUG_SERIAL + /* grab & clear the LSR */ + uint16_t uart_lsr_val = uart_lsr_read(); + uart_lsr_clear(); + + cached_lsr[cache_count] = uart_lsr_val; + cached_rbr[cache_count] = uart_rbr_val; + cache_count = (cache_count + 1) % ARRAY_SIZE(cached_lsr); + if (uart_lsr_val & (OE|PE|FE|BI)) { - /* Some parts are read-to-clear while others are - * write-to-clear. Just do the write for everyone - * since it cant hurt (other than code size). - */ - *pUART_LSR = (OE|PE|FE|BI); + uint16_t dll, dlh; + printf("\n[SERIAL ERROR]\n"); + ACCESS_LATCH(); + dll = *pUART_DLL; + dlh = *pUART_DLH; + ACCESS_PORT_IER(); + printf("\tDLL=0x%x DLH=0x%x\n", dll, dlh); + do { + --cache_count; + printf("\t%3i: RBR=0x%02x LSR=0x%02x\n", cache_count, + cached_rbr[cache_count], cached_lsr[cache_count]); + } while (cache_count > 0); return -1; } +#endif
- return uart_rbr_val & 0xFF; + return uart_rbr_val; }
void serial_puts(const char *s)

In message 1207721182-29697-2-git-send-email-vapier@gentoo.org you wrote:
Some Blackfin UARTs are read-to-clear while others are write-to-clear. This can cause problems when we poll the LSR and then later try and handle any errors detected.
Signed-off-by: Mike Frysinger vapier@gentoo.org
I guess I will receive a pull request for the BF custodian repo for this and the other "PATCH/review" messages you posted?
Do you have any plan when you will send the pull request?
Best regards,
Wolfgang Denk

On Sunday 20 April 2008, Wolfgang Denk wrote:
In message 1207721182-29697-2-git-send-email-vapier@gentoo.org you wrote:
Some Blackfin UARTs are read-to-clear while others are write-to-clear. This can cause problems when we poll the LSR and then later try and handle any errors detected.
Signed-off-by: Mike Frysinger vapier@gentoo.org
I guess I will receive a pull request for the BF custodian repo for this and the other "PATCH/review" messages you posted?
anything i post with "PATCH/review" is intended for review only. i'll stick them into the BF repo and have you pull them later since you didnt like me asking for straight pulls.
Do you have any plan when you will send the pull request?
that's why i asked about the merge window. since it's closed, i wont make any requests until it's open. -mike

In message 1207721182-29697-1-git-send-email-vapier@gentoo.org you wrote:
We should use the algorithm in the Linux kernel so that the UART divisor calculation is more accurate. It also fixes problems on some picky UARTs that have sampling anomalies.
Signed-off-by: Mike Frysinger vapier@gentoo.org
cpu/blackfin/serial.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/cpu/blackfin/serial.h b/cpu/blackfin/serial.h index 1f0f4b4..d268da5 100644 --- a/cpu/blackfin/serial.h +++ b/cpu/blackfin/serial.h @@ -179,7 +179,7 @@ static inline void serial_early_set_baud(uint32_t baud) * The +1 is to make sure we over sample just a little
^^^^^^^^^^^^^^^^^^^
Fix!
* rather than under sample the incoming signals. */
- uint16_t divisor = (get_sclk() / (baud * 16)) + 1;
- uint16_t divisor = (get_sclk() + (baud * 8)) / (baud * 16);
Please make sure to adjust the comment, as there is no "+1" any more in the new code.
Best regards,
Wolfgang Denk
participants (2)
-
Mike Frysinger
-
Wolfgang Denk