[U-Boot] [PATCH v1 1/3] blackfin: Enable early print via the generic serial API.

From: Sonic Zhang sonic.zhang@analog.com
Remove blackfin specific implementation of the generic serial API when early print macro is defined.
In BFIN_BOOT_BYPASS mode, don't call generic serial_puts, because early print in bypass mode is running before code binary is relocated to the link address.
Signed-off-by: Sonic Zhang sonic.zhang@analog.com --- arch/blackfin/cpu/serial.c | 71 ++++++++++++------------------------ arch/blackfin/cpu/serial.h | 10 +++--- include/configs/bfin_adi_common.h | 3 -- 3 files changed, 29 insertions(+), 55 deletions(-)
diff --git a/arch/blackfin/cpu/serial.c b/arch/blackfin/cpu/serial.c index 36d2a5c..89290d6 100644 --- a/arch/blackfin/cpu/serial.c +++ b/arch/blackfin/cpu/serial.c @@ -197,13 +197,16 @@ static void uart_loop(uint32_t uart_base, int state)
static inline void __serial_set_baud(uint32_t uart_base, uint32_t baud) { +#ifdef CONFIG_DEBUG_EARLY_SERIAL + serial_early_set_baud(uart_base, baud); +#else 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); +#endif } -#ifdef CONFIG_SYS_BFIN_UART
static void uart_puts(uint32_t uart_base, const char *s) { @@ -313,65 +316,39 @@ void bfin_serial_initialize(void) #endif }
-#else - -/* Symbol for our assembly to call. */ -void serial_set_baud(uint32_t baud) -{ - serial_early_set_baud(UART_BASE, baud); -} - -/* Symbol for common u-boot code to call. - * Setup the baudrate (brg: baudrate generator). - */ -void serial_setbrg(void) +#ifdef CONFIG_DEBUG_EARLY_SERIAL +inline void uart_early_putc(uint32_t uart_base, const char c) { - serial_set_baud(gd->baudrate); -} - -/* Symbol for our assembly to call. */ -void serial_initialize(void) -{ - serial_early_init(UART_BASE); -} - -/* Symbol for common u-boot code to call. */ -int serial_init(void) -{ - serial_initialize(); - serial_setbrg(); - uart_lsr_clear(UART_BASE); - return 0; -} + /* send a \r for compatibility */ + if (c == '\n') + uart_early_putc(uart_base, '\r');
-int serial_tstc(void) -{ - return uart_tstc(UART_BASE); -} + /* wait for the hardware fifo to clear up */ + while (!(_lsr_read(pUART) & THRE)) + continue;
-int serial_getc(void) -{ - return uart_getc(UART_BASE); + /* queue the character for transmission */ + bfin_write(&pUART->thr, c); + SSYNC(); }
-void serial_putc(const char c) +void uart_early_puts(const char *s) { - uart_putc(UART_BASE, c); + while (*s) + uart_early_putc(UART_BASE, *s++); }
-void serial_puts(const char *s) +/* Symbol for our assembly to call. */ +void _serial_early_set_baud(uint32_t baud) { - while (*s) - serial_putc(*s++); + serial_early_set_baud(UART_BASE, baud); }
-LOOP( -void serial_loop(int state) +/* Symbol for our assembly to call. */ +void _serial_early_init(void) { - uart_loop(UART_BASE, state); + serial_early_init(UART_BASE); } -) - #endif
#endif diff --git a/arch/blackfin/cpu/serial.h b/arch/blackfin/cpu/serial.h index d67fd81..87a337d 100644 --- a/arch/blackfin/cpu/serial.h +++ b/arch/blackfin/cpu/serial.h @@ -78,16 +78,16 @@ static inline void serial_early_puts(const char *s) #else
.macro serial_early_init -#if defined(CONFIG_DEBUG_EARLY_SERIAL) && defined(BFIN_BOOT_BYPASS) - call _serial_initialize; +#if defined(CONFIG_DEBUG_EARLY_SERIAL) && !defined(CONFIG_UART_MEM) + call __serial_early_init; #endif .endm
.macro serial_early_set_baud -#if defined(CONFIG_DEBUG_EARLY_SERIAL) && defined(BFIN_BOOT_BYPASS) +#if defined(CONFIG_DEBUG_EARLY_SERIAL) && !defined(CONFIG_UART_MEM) R0.L = LO(CONFIG_BAUDRATE); R0.H = HI(CONFIG_BAUDRATE); - call _serial_set_baud; + call __serial_early_set_baud; #endif .endm
@@ -121,7 +121,7 @@ static inline void serial_early_puts(const char *s) R0.L = 7b; \ R0.H = 7b; \ update_serial_early_string_addr \ - call _serial_puts; + call _uart_early_puts; #else # define serial_early_puts(str) #endif diff --git a/include/configs/bfin_adi_common.h b/include/configs/bfin_adi_common.h index d3ae3a7..c986ba3 100644 --- a/include/configs/bfin_adi_common.h +++ b/include/configs/bfin_adi_common.h @@ -111,9 +111,6 @@ #ifndef CONFIG_BAUDRATE # define CONFIG_BAUDRATE 57600 #endif -#ifndef CONFIG_DEBUG_EARLY_SERIAL -# define CONFIG_SYS_BFIN_UART -#endif
/* * Debug Settings

From: Sonic Zhang sonic.zhang@analog.com
Signed-off-by: Sonic Zhang sonic.zhang@analog.com --- arch/blackfin/cpu/serial.c | 60 +++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 59 insertions(+), 1 deletions(-)
diff --git a/arch/blackfin/cpu/serial.c b/arch/blackfin/cpu/serial.c index 89290d6..c453a03 100644 --- a/arch/blackfin/cpu/serial.c +++ b/arch/blackfin/cpu/serial.c @@ -351,4 +351,62 @@ void _serial_early_init(void) } #endif
-#endif +#elif defined(CONFIG_UART_MEM) + +char serial_logbuf[CONFIG_UART_MEM]; +char *serial_logbuf_head = serial_logbuf; + +int serial_mem_init(void) +{ + serial_logbuf_head = serial_logbuf; + return 0; +} + +void serial_mem_setbrg(void) +{ +} + +int serial_mem_tstc(void) +{ + return 0; +} + +int serial_mem_getc(void) +{ + return 0; +} + +void serial_mem_putc(const char c) +{ + *serial_logbuf_head = c; + if (++serial_logbuf_head == serial_logbuf + CONFIG_UART_MEM) + serial_logbuf_head = serial_logbuf; +} + +void serial_mem_puts(const char *s) +{ + while (*s) + serial_putc(*s++); +} + +struct serial_device bfin_serial_mem_device = { + .name = "bfin_uart_mem", + .start = serial_mem_init, + .setbrg = serial_mem_setbrg, + .getc = serial_mem_getc, + .tstc = serial_mem_tstc, + .putc = serial_mem_putc, + .puts = serial_mem_puts, +}; + + +__weak struct serial_device *default_serial_console(void) +{ + return &bfin_serial_mem_device; +} + +void bfin_serial_initialize(void) +{ + serial_register(&bfin_serial_mem_device); +} +#endif /* CONFIG_UART_MEM */

From: Sonic Zhang sonic.zhang@analog.com
Signed-off-by: Sonic Zhang sonic.zhang@analog.com --- arch/blackfin/cpu/initcode.c | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/arch/blackfin/cpu/initcode.c b/arch/blackfin/cpu/initcode.c index 4b10b6c..8ef0b92 100644 --- a/arch/blackfin/cpu/initcode.c +++ b/arch/blackfin/cpu/initcode.c @@ -715,8 +715,8 @@ update_serial_clocks(ADI_BOOT_DATA *bs, uint sdivB, uint divB, uint vcoB) * for dividing which means we'd generate a libgcc reference. */ unsigned int sdivR, vcoR; - unsigned int dividend = sdivB * divB * vcoR; - unsigned int divisor = vcoB * sdivR; + unsigned int dividend; + unsigned int divisor; unsigned int quotient;
serial_putc('a'); @@ -729,6 +729,9 @@ update_serial_clocks(ADI_BOOT_DATA *bs, uint sdivB, uint divB, uint vcoB) sdivR = bfin_read_PLL_DIV() & 0xf; vcoR = (bfin_read_PLL_CTL() >> 9) & 0x3f; #endif + + dividend = sdivB * divB * vcoR; + divisor = vcoB * sdivR; quotient = early_division(dividend, divisor); serial_early_put_div(quotient - ANOMALY_05000230); serial_putc('c');

On Monday 13 May 2013 00:20:15 Sonic Zhang wrote:
Remove blackfin specific implementation of the generic serial API when early print macro is defined.
In BFIN_BOOT_BYPASS mode, don't call generic serial_puts, because early print in bypass mode is running before code binary is relocated to the link address.
the link address of the function doesn't matter. all Blackfin func calls are pcrel based, not absolute address calls. i specifically crafted all of this early serial code so that this does work regardless of the address where the code happens to be executing.
what doesn't work is if you try to use the early serial console with CONFIG_SYS_BFIN_UART (which allows all the serial devices to be selected on the fly). but the header file specifically handles that: #ifndef CONFIG_DEBUG_EARLY_SERIAL # define CONFIG_SYS_BFIN_UART #endif
i guess the problem is that this commit is wrong:
commit 820edc18b5aefa8c82d420f6cba3e13b5631f9b8 Author: Sonic Zhang sonic.zhang@analog.com Date: Fri Nov 30 17:39:32 2012 +0800
blackfin: Correct early serial mess output in BYPASS boot mode.
it shouldn't be messing with the addresses there -mike

Hi Mike,
On Mon, May 13, 2013 at 12:42 PM, Mike Frysinger vapier@gentoo.org wrote:
On Monday 13 May 2013 00:20:15 Sonic Zhang wrote:
Remove blackfin specific implementation of the generic serial API when early print macro is defined.
In BFIN_BOOT_BYPASS mode, don't call generic serial_puts, because early print in bypass mode is running before code binary is relocated to the link address.
the link address of the function doesn't matter. all Blackfin func calls are pcrel based, not absolute address calls. i specifically crafted all of this early serial code so that this does work regardless of the address where the code happens to be executing.
When you developed the bfin serial driver, the generic serial API serial_puts() is implemented in bfin serial driver directly. No such link address issue.
void serial_putc(const char c) { uart_putc(UART_BASE, c); }
void serial_puts(const char *s) { while (*s) serial_putc(*s++); }
While in latest generic serial.c, serial_puts() calls uart_puts() function in bfin serial via a pointer to the default serial_device structure, which contains the link address in DRAM, other than a relative jump.
void serial_puts(const char *s) { get_current()->puts(s); }
This has nothing to do with the patch " blackfin: Correct early serial mess output in BYPASS boot mode.".
07f572c8 <_get_current>: 7f572c8: 67 01 [--SP] = RETS; 7f572ca: 58 a0 R0 = [P3 + 0x4]; 7f572cc: a6 6f SP += -0xc; /* (-12) */ 7f572ce: 00 48 CC = !BITTST (R0, 0x0); /* bit 0 */ 7f572d0: 08 18 IF CC JUMP 0x7f572e0 <_get_current+0x18>; 7f572d2: 4a e1 f8 07 P2.H = 0x7f8; /* (2040) P2=0x7f8e77c <_serial_devices> */ 7f572d6: 0a e1 80 e7 P2.L = 0xe780; /* (-6272) P2=0x7f8e780 <_serial_current> */ 7f572da: 10 91 R0 = [P2]; 7f572dc: 00 0c CC = R0 == 0x0; 7f572de: 0b 14 IF !CC JUMP 0x7f572f4 <_get_current+0x2c> (BP);
7f572e0: 00 e3 02 02 CALL 0x7f576e4 <_default_serial_console>; 7f572e4: 00 0c CC = R0 == 0x0;
7f572e6: 07 14 IF !CC JUMP 0x7f572f4 <_get_current+0x2c> (BP); 7f572e8: 40 e1 f7 07 R0.H = 0x7f7; /* (2039) R0=0x7f7e764(133687140) */ 7f572ec: 00 e1 cc 03 R0.L = 0x3cc; /* (972) R0=0x7f703cc(133628876) */ 7f572f0: 00 e3 8e 3e CALL 0x7f5f00c <_panic>; 7f572f4: 66 6c SP += 0xc; /* ( 12) */ 7f572f6: 27 01 RETS = [SP++]; 7f572f8: 10 00 RTS; ...
07f572fc <_serial_puts>: 7f572fc: 78 05 [--SP] = (R7:7); 7f572fe: 67 01 [--SP] = RETS; 7f57300: 38 30 R7 = R0; 7f57302: a6 6f SP += -0xc; /* (-12) */ 7f57304: ff e3 e2 ff CALL 0x7f572c8 <_get_current>;
7f57308: 10 32 P2 = R0;
7f5730a: 66 6c SP += 0xc; /* ( 12) */ 7f5730c: 27 01 RETS = [SP++]; 7f5730e: 07 30 R0 = R7; 7f57310: 38 05 (R7:7) = [SP++]; 7f57312: 92 ae P2 = [P2 + 0x28];
7f57314: 52 00 JUMP (P2);
Regards,
Sonic
what doesn't work is if you try to use the early serial console with CONFIG_SYS_BFIN_UART (which allows all the serial devices to be selected on the fly). but the header file specifically handles that: #ifndef CONFIG_DEBUG_EARLY_SERIAL # define CONFIG_SYS_BFIN_UART #endif
i guess the problem is that this commit is wrong:
commit 820edc18b5aefa8c82d420f6cba3e13b5631f9b8 Author: Sonic Zhang sonic.zhang@analog.com Date: Fri Nov 30 17:39:32 2012 +0800
blackfin: Correct early serial mess output in BYPASS boot mode.
it shouldn't be messing with the addresses there -mike
participants (2)
-
Mike Frysinger
-
Sonic Zhang