]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
blackfin: Set correct early debug serial baudrate.
authorSonic Zhang <sonic.zhang@analog.com>
Tue, 5 Feb 2013 11:10:34 +0000 (19:10 +0800)
committerSonic Zhang <sonic.zhang@analog.com>
Mon, 13 May 2013 07:47:24 +0000 (15:47 +0800)
Calculate the early uart clock from the system clock registers set by
the bootrom other than the predefine uboot clock macros.

Split the early baudrate setting function and the normal baudrate
setting one.

Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
arch/blackfin/cpu/initcode.c
arch/blackfin/cpu/serial.c
arch/blackfin/cpu/serial1.h
arch/blackfin/cpu/serial4.h
arch/blackfin/include/asm/clock.h [new file with mode: 0644]
arch/blackfin/lib/clocks.c

index e8ea0ba66aff956020433b0f77e1e3b04a2e3c92..5c12726d779a4d1b9b7955efb5087898534807cb 100644 (file)
@@ -194,15 +194,8 @@ static inline void serial_init(void)
 #endif
 
        if (BFIN_DEBUG_EARLY_SERIAL) {
-               int enabled = serial_early_enabled(uart_base);
-
                serial_early_init(uart_base);
-
-               /* If the UART is off, that means we need to program
-                * the baud rate ourselves initially.
-                */
-               if (!enabled)
-                       serial_early_set_baud(uart_base, CONFIG_BAUDRATE);
+               serial_early_set_baud(uart_base, CONFIG_BAUDRATE);
        }
 }
 
@@ -714,37 +707,29 @@ program_clocks(ADI_BOOT_DATA *bs, bool put_into_srfs)
 __attribute__((always_inline)) static inline void
 update_serial_clocks(ADI_BOOT_DATA *bs, uint sdivB, uint divB, uint vcoB)
 {
-       serial_putc('a');
-
        /* Since we've changed the SCLK above, we may need to update
         * the UART divisors (UART baud rates are based on SCLK).
         * Do the division by hand as there are no native instructions
         * for dividing which means we'd generate a libgcc reference.
         */
-       if (CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_UART) {
-               unsigned int sdivR, vcoR;
-               int dividend = sdivB * divB * vcoR;
-               int divisor = vcoB * sdivR;
-               unsigned int quotient;
+       unsigned int sdivR, vcoR;
+       unsigned int dividend = sdivB * divB * vcoR;
+       unsigned int divisor = vcoB * sdivR;
+       unsigned int quotient;
 
-               serial_putc('b');
+       serial_putc('a');
 
 #ifdef __ADSPBF60x__
-               sdivR = bfin_read_CGU_DIV();
-               sdivR = ((sdivR >> 8) & 0x1f) * ((sdivR >> 5) & 0x7);
-               vcoR = (bfin_read_CGU_CTL() >> 8) & 0x7f;
+       sdivR = bfin_read_CGU_DIV();
+       sdivR = ((sdivR >> 8) & 0x1f) * ((sdivR >> 5) & 0x7);
+       vcoR = (bfin_read_CGU_CTL() >> 8) & 0x7f;
 #else
-               sdivR = bfin_read_PLL_DIV() & 0xf;
-               vcoR = (bfin_read_PLL_CTL() >> 9) & 0x3f;
+       sdivR = bfin_read_PLL_DIV() & 0xf;
+       vcoR = (bfin_read_PLL_CTL() >> 9) & 0x3f;
 #endif
-
-               for (quotient = 0; dividend > 0; ++quotient)
-                       dividend -= divisor;
-               serial_early_put_div(quotient - ANOMALY_05000230);
-               serial_putc('c');
-       }
-
-       serial_putc('d');
+       quotient = early_division(dividend, divisor);
+       serial_early_put_div(quotient - ANOMALY_05000230);
+       serial_putc('c');
 }
 
 __attribute__((always_inline)) static inline void
index 9847e9f2c5cc80d2e61ea211b6903567e6753885..36d2a5c8e4121546de3a17e9615530ad98707c5a 100644 (file)
@@ -195,6 +195,14 @@ static void uart_loop(uint32_t uart_base, int state)
 
 #endif
 
+static inline void __serial_set_baud(uint32_t uart_base, uint32_t baud)
+{
+       uint16_t divisor = (get_uart_clk() + (baud * 8)) / (baud * 16)
+                       - ANOMALY_05000230;
+
+       /* Program the divisor to get the baud rate we want */
+       serial_set_divisor(uart_base, divisor);
+}
 #ifdef CONFIG_SYS_BFIN_UART
 
 static void uart_puts(uint32_t uart_base, const char *s)
@@ -209,7 +217,7 @@ static int uart##n##_init(void) \
        const unsigned short pins[] = { _P_UART(n, RX), _P_UART(n, TX), 0, }; \
        peripheral_request_list(pins, "bfin-uart"); \
        uart_init(MMR_UART(n)); \
-       serial_early_set_baud(MMR_UART(n), gd->baudrate); \
+       __serial_set_baud(MMR_UART(n), gd->baudrate); \
        uart_lsr_clear(MMR_UART(n)); \
        return 0; \
 } \
@@ -221,7 +229,7 @@ static int uart##n##_uninit(void) \
 \
 static void uart##n##_setbrg(void) \
 { \
-       serial_early_set_baud(MMR_UART(n), gd->baudrate); \
+       __serial_set_baud(MMR_UART(n), gd->baudrate); \
 } \
 \
 static int uart##n##_getc(void) \
index a20175bc7f323992dc6fa1db2a0b5006a9a7ce0e..52f1c62eb95a9a5e59fb626927c0ae56c9269b66 100644 (file)
@@ -15,6 +15,8 @@
 
 #ifndef __ASSEMBLY__
 
+#include <asm/clock.h>
+
 #define MMR_UART(n) _PASTE_UART(n, UART, DLL)
 #ifdef UART_DLL
 # define UART0_DLL UART_DLL
@@ -229,19 +231,6 @@ static inline void serial_early_do_portmux(void)
        SSYNC();
 }
 
-__attribute__((always_inline))
-static inline uint32_t uart_sclk(void)
-{
-#if defined(BFIN_IN_INITCODE) || defined(CONFIG_DEBUG_EARLY_SERIAL)
-       /* We cannot use get_sclk() early on as it uses
-        * caches in external memory
-        */
-       return CONFIG_CLKIN_HZ * CONFIG_VCO_MULT / CONFIG_SCLK_DIV;
-#else
-       return get_sclk();
-#endif
-}
-
 __attribute__((always_inline))
 static inline int uart_init(uint32_t uart_base)
 {
@@ -275,21 +264,8 @@ static inline int serial_early_uninit(uint32_t uart_base)
 }
 
 __attribute__((always_inline))
-static inline int serial_early_enabled(uint32_t uart_base)
+static inline void serial_set_divisor(uint32_t uart_base, uint16_t divisor)
 {
-       return bfin_read(&pUART->gctl) & UCEN;
-}
-
-__attribute__((always_inline))
-static inline void serial_early_set_baud(uint32_t uart_base, uint32_t baud)
-{
-       /* Translate from baud into divisor in terms of SCLK.  The
-        * weird multiplication is to make sure we over sample just
-        * a little rather than under sample the incoming signals.
-        */
-       uint16_t divisor = (uart_sclk() + (baud * 8)) / (baud * 16) -
-                       ANOMALY_05000230;
-
        /* Set DLAB in LCR to Access DLL and DLH */
        ACCESS_LATCH();
        SSYNC();
@@ -304,6 +280,19 @@ static inline void serial_early_set_baud(uint32_t uart_base, uint32_t baud)
        SSYNC();
 }
 
+__attribute__((always_inline))
+static inline void serial_early_set_baud(uint32_t uart_base, uint32_t baud)
+{
+       /* Translate from baud into divisor in terms of SCLK.  The
+        * weird multiplication is to make sure we over sample just
+        * a little rather than under sample the incoming signals.
+        */
+       uint16_t divisor = early_division(early_get_uart_clk() + (baud * 8),
+                       baud * 16) - ANOMALY_05000230;
+
+       serial_set_divisor(uart_base, divisor);
+}
+
 __attribute__((always_inline))
 static inline void serial_early_put_div(uint16_t divisor)
 {
index 887845c1863321f946d4856bbe19ab940481613f..65483960b9cb092eb2d8388840460d9717dd9c9f 100644 (file)
@@ -15,6 +15,8 @@
 
 #ifndef __ASSEMBLY__
 
+#include <asm/clock.h>
+
 #define MMR_UART(n) _PASTE_UART(n, UART, REVID)
 #define UART_BASE MMR_UART(CONFIG_UART_CONSOLE)
 
@@ -83,20 +85,6 @@ static inline void serial_early_do_portmux(void)
        SSYNC();
 }
 
-__attribute__((always_inline))
-static inline uint32_t uart_sclk(void)
-{
-#if defined(BFIN_IN_INITCODE) || defined(CONFIG_DEBUG_EARLY_SERIAL)
-       /* We cannot use get_sclk() early on as it uses caches in
-        * external memory
-        */
-       return CONFIG_CLKIN_HZ * CONFIG_VCO_MULT / CONFIG_SCLK_DIV /
-               CONFIG_SCLK0_DIV;
-#else
-       return get_sclk0();
-#endif
-}
-
 __attribute__((always_inline))
 static inline int uart_init(uint32_t uart_base)
 {
@@ -127,19 +115,20 @@ static inline int serial_early_uninit(uint32_t uart_base)
 }
 
 __attribute__((always_inline))
-static inline int serial_early_enabled(uint32_t uart_base)
+static inline void serial_set_divisor(uint32_t uart_base, uint16_t divisor)
 {
-       return bfin_read(&pUART->control) & UEN;
+       /* Program the divisor to get the baud rate we want */
+       bfin_write(&pUART->clock, divisor);
+       SSYNC();
 }
 
 __attribute__((always_inline))
 static inline void serial_early_set_baud(uint32_t uart_base, uint32_t baud)
 {
-       uint32_t divisor = uart_sclk() / (baud * 16);
+       uint16_t divisor = early_division(early_get_uart_clk(), baud * 16);
 
        /* Program the divisor to get the baud rate we want */
-       bfin_write(&pUART->clock, divisor);
-       SSYNC();
+       serial_set_divisor(uart_base, divisor);
 }
 
 __attribute__((always_inline))
diff --git a/arch/blackfin/include/asm/clock.h b/arch/blackfin/include/asm/clock.h
new file mode 100644 (file)
index 0000000..df6cd68
--- /dev/null
@@ -0,0 +1,74 @@
+
+/*
+ * Copyright (C) 2012 Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __CLOCK_H__
+#define __CLOCK_H__
+
+#include <asm/blackfin.h>
+#ifdef PLL_CTL
+#include <asm/mach-common/bits/pll.h>
+# define pll_is_bypassed() (bfin_read_PLL_STAT() & DF)
+#else
+#include <asm/mach-common/bits/cgu.h>
+# define pll_is_bypassed() (bfin_read_CGU_STAT() & PLLBP)
+# define bfin_read_PLL_CTL() bfin_read_CGU_CTL()
+# define bfin_read_PLL_DIV() bfin_read_CGU_DIV()
+# define SSEL SYSSEL
+# define SSEL_P SYSSEL_P
+#endif
+
+__attribute__((always_inline))
+static inline uint32_t early_division(uint32_t dividend, uint32_t divisor)
+{
+       uint32_t quotient;
+       uint32_t i, j;
+
+       for (quotient = 1, i = 1; dividend > divisor; ++i) {
+               j = divisor << i;
+               if (j > dividend || (j & 0x80000000)) {
+                       --i;
+                       quotient += (1 << i);
+                       dividend -= (divisor << i);
+                       i = 0;
+               }
+       }
+
+       return quotient;
+}
+
+__attribute__((always_inline))
+static inline uint32_t early_get_uart_clk(void)
+{
+       uint32_t msel, pll_ctl, vco;
+       uint32_t div, ssel, sclk, uclk;
+
+       pll_ctl = bfin_read_PLL_CTL();
+       msel = (pll_ctl & MSEL) >> MSEL_P;
+       if (msel == 0)
+               msel = (MSEL >> MSEL_P) + 1;
+
+       vco = (CONFIG_CLKIN_HZ >> (pll_ctl & DF)) * msel;
+       sclk = vco;
+       if (!pll_is_bypassed()) {
+               div = bfin_read_PLL_DIV();
+               ssel = (div & SSEL) >> SSEL_P;
+               sclk = early_division(vco, ssel);
+       }
+       uclk = sclk;
+#ifdef CGU_DIV
+       ssel = (div & S0SEL) >> S0SEL_P;
+       uclk = early_division(sclk, ssel);
+#endif
+       return uclk;
+}
+
+#ifdef CGU_DIV
+# define get_uart_clk get_sclk0
+#else
+# define get_uart_clk get_sclk
+#endif
+
+#endif
index d852f5ebed8feb80117acf02552a3f9fefeb6aa2..97795e11ac993498d60848ecda562df08d625872 100644 (file)
@@ -7,17 +7,7 @@
  */
 
 #include <common.h>
-#include <asm/blackfin.h>
-
-#ifdef PLL_CTL
-# include <asm/mach-common/bits/pll.h>
-# define pll_is_bypassed() (bfin_read_PLL_STAT() & DF)
-#else
-# include <asm/mach-common/bits/cgu.h>
-# define pll_is_bypassed() (bfin_read_CGU_STAT() & PLLBP)
-# define bfin_read_PLL_CTL() bfin_read_CGU_CTL()
-# define bfin_read_PLL_DIV() bfin_read_CGU_DIV()
-#endif
+#include <asm/clock.h>
 
 /* Get the voltage input multiplier */
 u_long get_vco(void)