2011-03-14 14:18:22     Problem with CONFIG_DEBUG_EARLY_SERIAL

Document created by Aaronwu Employee on Aug 26, 2013
Version 1Show Document
  • View in full screen mode

2011-03-14 14:18:22     Problem with CONFIG_DEBUG_EARLY_SERIAL

Timur Aydin (TURKEY)

Message: 98924   

 

I was debugging an intermittent boot issue with my blackfin BF537-0.3 board. I defined the CONFIG_DEBUG_EARLY_SERIAL option in the hope of getting more insight into the problem. But to my surprise, the characters on my minicom terminal were mostly messed up. The most strange thing was that uppercase characters and some symbols were looking correct, but lowercase characters were not !

 

After several hours of frustration, I tried using the -8 option to minicom and then the early serial output looked good (not completely good, see below ...) This is really odd, because when I use u-boot normally, without the early debug, I didn't need to specify the -8 option. Anyboby can explain this ?

 

And the other issue is that, even when using the -8 option, the first line of output that is generated when CONFIG_DEBUG_EARLY_SERIAL is enabled was still messed up. This first line was completely garbage, both uppercase, lowercase and symbols... I am still trying to understand why this is happening. Basically, all characters up to the "Early:_start.S: Init Registers" string is bogus, after that string, everything is fine. Here, the -8 setting of minicom doesn't help.

 

What could be the problem?

QuoteReplyEditDelete

 

 

2011-03-14 14:28:10     Re: Problem with CONFIG_DEBUG_EARLY_SERIAL

Timur Aydin (TURKEY)

Message: 98925   

 

One thing that seemed odd to me is the conversion of the baud rate to a DLH and DLL value for the UART. The calculation was taking the project's VCO multiplier and divider into account:

 

/* We cannot use get_sclk() early on as it uses caches in external memory */

#if defined(BFIN_IN_INITCODE) || defined(CONFIG_DEBUG_EARLY_SERIAL)

# define get_sclk() (CONFIG_CLKIN_HZ * CONFIG_VCO_MULT / CONFIG_SCLK_DIV)

#endif

 

 

But nobody has configured the PLL yet, so the PLL still has the default multiplier of 10 and default divider of 5 (according to the HRM). I tried using 10 and 5 instead of the project settings, this made some improvement (some characters weren't junk anymore, but still there was a problem).

 

 

 

But going down the initcode() function, the program_clocks function is called, which initializes the PLL. But even after that, the serial output was garbage. So much for the PLL theory ...

 

 

 

Once the _start entry point in start.S is entered and the following code is executed:

 

    /* Turn on the serial for debugging the init process */

    serial_early_init

    serial_early_set_baud

 

    serial_early_puts("Init Registers");

 

 

the serial output returns to normal. The "Init Registers" string is fine.

 

 

 

Another observation: If I reset uboot from the command line, then all characters are 100% fine, no problem at all. But if I do a power cycle of the board, all characters up to the "Init Registers" line are bad...

QuoteReplyEditDelete

 

 

2011-03-14 14:50:34     Re: Problem with CONFIG_DEBUG_EARLY_SERIAL

Mike Frysinger (UNITED STATES)

Message: 98928   

 

the early serial is known to not work 100% before the PLL is programmed.  doing so in the past would require 64bit math which is not allowed in the initcode, as well as the comment you already highlighted.

 

the PLL is not reset when doing a software reset ... this is by hardware design.

QuoteReplyEditDelete

 

 

2011-03-15 10:32:14     Re: Problem with CONFIG_DEBUG_EARLY_SERIAL

Timur Aydin (TURKEY)

Message: 98946   

 

Hello Mike,

 

The following changes allow CONFIG_DEBUG_EARLY_SERIAL to work right from the beginning. What I basically did is, when the UART is initialized for the first time (init_serial() in initcode.c), I use the reset defaults for VCO multiplier and divider (10 and 5, respectively). This allows all serial_putc calls to function correctly. Then, in the program_clocks function, immediately after the PLL is updated and has locked, I reinitialize the UART with the desired VCO multiplier and divider (20 and 5, in my board config). I also removed serial_putc calls that are in the path where the PLL is initialized, but not locked yet.

 

Here is the patch:

 

diff --git a/arch/blackfin/cpu/initcode.c b/arch/blackfin/cpu/initcode.c

index 433d477..71c6923 100644

--- a/arch/blackfin/cpu/initcode.c

+++ b/arch/blackfin/cpu/initcode.c

@@ -71,7 +71,12 @@ static inline void serial_init(void)

          * the baud rate ourselves initially.

          */

         if (ucen != UCEN)

-            serial_early_set_baud(CONFIG_BAUDRATE);

+                {

+            /* use the reset default value for PLL_CTL and

+             * PLL_DIV so that early serial works as

+             * expected */

+            serial_early_put_div(((CONFIG_CLKIN_HZ * 10 / 5) + (CONFIG_BAUDRATE * 8)) / (CONFIG_BAUDRATE * 16) - ANOMALY_05000230);

+                }

     }

}

 

@@ -281,21 +286,10 @@ program_nmi_handler(void)

#endif

 

__attribute__((always_inline)) static inline void

-program_early_devices(ADI_BOOT_DATA *bs, uint *sdivB, uint *divB, uint *vcoB)

+program_early_devices(ADI_BOOT_DATA *bs)

{

     serial_putc('a');

 

-    /* Save the clock pieces that are used in baud rate calculation */

-    if (BFIN_DEBUG_EARLY_SERIAL || CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_UART) {

-        serial_putc('b');

-        *sdivB = bfin_read_PLL_DIV() & 0xf;

-        *vcoB = (bfin_read_PLL_CTL() >> 9) & 0x3f;

-        *divB = serial_early_get_div();

-        serial_putc('c');

-    }

-

-    serial_putc('d');

-

#ifdef CONFIG_HW_WATCHDOG

# ifndef CONFIG_HW_WATCHDOG_TIMEOUT_INITCODE

#  define CONFIG_HW_WATCHDOG_TIMEOUT_INITCODE 20000

@@ -307,14 +301,14 @@ program_early_devices(ADI_BOOT_DATA *bs, uint *sdivB, uint *divB, uint *vcoB)

      * timeout, so don't clobber that.

      */

     if (CONFIG_BFIN_BOOT_MODE != BFIN_BOOT_BYPASS) {

-        serial_putc('e');

+        serial_putc('b');

         bfin_write_WDOG_CNT(MSEC_TO_SCLK(CONFIG_HW_WATCHDOG_TIMEOUT_INITCODE));

         bfin_write_WDOG_CTL(0);

-        serial_putc('f');

+        serial_putc('c');

     }

#endif

 

-    serial_putc('g');

+    serial_putc('d');

 

     /* Blackfin bootroms use the SPI slow read opcode instead of the SPI

      * fast read, so we need to slow down the SPI clock a lot more during

@@ -322,14 +316,14 @@ program_early_devices(ADI_BOOT_DATA *bs, uint *sdivB, uint *divB, uint *vcoB)

      * increase the speed appropriately.

      */

     if (CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_SPI_MASTER) {

-        serial_putc('h');

+        serial_putc('e');

         if (BOOTROM_SUPPORTS_SPI_FAST_READ && CONFIG_SPI_BAUD_INITBLOCK < 4)

             bs->dFlags |= BFLAG_FASTREAD;

         bfin_write_SPI_BAUD(CONFIG_SPI_BAUD_INITBLOCK);

-        serial_putc('i');

+        serial_putc('f');

     }

 

-    serial_putc('j');

+    serial_putc('g');

}

 

__attribute__((always_inline)) static inline bool

@@ -460,18 +454,17 @@ program_clocks(ADI_BOOT_DATA *bs, bool put_into_srfs)

 

         bfin_write_PLL_DIV(CONFIG_PLL_DIV_VAL);

 

-        serial_putc('l');

-

         /* Only reprogram when needed to avoid triggering unnecessary

          * PLL relock sequences.

          */

         if (ANOMALY_05000242 || bfin_read_PLL_CTL() != CONFIG_PLL_CTL_VAL) {

-            serial_putc('?');

             bfin_write_PLL_CTL(CONFIG_PLL_CTL_VAL);

             asm("idle;");

-            serial_putc('!');

         }

 

+        /* update the UART, because sclk might have changed */

+        serial_early_set_baud(CONFIG_BAUDRATE);

+

         serial_putc('m');

 

         /* Restore all peripheral wakeups. */

@@ -497,33 +490,6 @@ 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) {

-        serial_putc('b');

-        unsigned int sdivR, vcoR;

-        sdivR = bfin_read_PLL_DIV() & 0xf;

-        vcoR = (bfin_read_PLL_CTL() >> 9) & 0x3f;

-        int dividend = sdivB * divB * vcoR;

-        int divisor = vcoB * sdivR;

-        unsigned int quotient;

-        for (quotient = 0; dividend > 0; ++quotient)

-            dividend -= divisor;

-        serial_early_put_div(quotient - ANOMALY_05000230);

-        serial_putc('c');

-    }

-

-    serial_putc('d');

-}

-

-__attribute__((always_inline)) static inline void

program_memory_controller(ADI_BOOT_DATA *bs, bool put_into_srfs)

{

     serial_putc('a');

@@ -684,15 +650,11 @@ void initcode(ADI_BOOT_DATA *bs)

     bool put_into_srfs = maybe_self_refresh(bs);

 

     serial_putc('C');

-    uint sdivB, divB, vcoB;

-    program_early_devices(bs, &sdivB, &divB, &vcoB);

+    program_early_devices(bs);

 

     serial_putc('D');

     u16 vr_ctl = program_clocks(bs, put_into_srfs);

 

-    serial_putc('E');

-    update_serial_clocks(bs, sdivB, divB, vcoB);

-

     serial_putc('F');

     program_memory_controller(bs, put_into_srfs);

QuoteReplyEditDelete

 

 

2011-03-15 12:33:24     Re: Problem with CONFIG_DEBUG_EARLY_SERIAL

Timur Aydin (TURKEY)

Message: 98947   

 

But this configuring of the UART once and then re-configuring it a second time after the clocks are configured can be avoided if the first thing that is done in initcode() is the configuration of the clocks. If there a reason the clocks are configured at a later stage as opposed to being configured immediately after uboot starts running?

Attachments

    Outcomes