Patchwork [U-Boot,4/5] tegra: Provide tegra_pre_console_panic() for early panics

login
register
mail settings
Submitter Simon Glass
Date March 19, 2012, 8:27 p.m.
Message ID <1332188824-5447-4-git-send-email-sjg@chromium.org>
Download mbox | patch
Permalink /patch/147621/
State New, archived
Headers show

Comments

Simon Glass - March 19, 2012, 8:27 p.m.
This function is made available to board which want to display a message
when a panic() occurs before the console is set up. This would otherwise
result in a silent hang or reboot.

Boards should call tegra_pre_console_panic() and pass the UARTs which
are available and safe for a message, as well as the selected clock and
serial multiplier values. Defaults are available as
CONFIG_DEFAULT_NS16550_CLK and CONFIG_DEFAULT_NS16550_MULT.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 arch/arm/cpu/armv7/tegra2/board.c        |   44 ++++++++++++++++++++++++++++++
 arch/arm/include/asm/arch-tegra2/board.h |   13 +++++++++
 include/configs/tegra2-common.h          |    4 +++
 3 files changed, 61 insertions(+), 0 deletions(-)
Stephen Warren - March 19, 2012, 9:16 p.m.
On 03/19/2012 02:27 PM, Simon Glass wrote:
> This function is made available to board which want to display a message
> when a panic() occurs before the console is set up. This would otherwise
> result in a silent hang or reboot.
> 
> Boards should call tegra_pre_console_panic() and pass the UARTs which
> are available and safe for a message, as well as the selected clock and
> serial multiplier values. Defaults are available as
> CONFIG_DEFAULT_NS16550_CLK and CONFIG_DEFAULT_NS16550_MULT.
...
> diff --git a/arch/arm/cpu/armv7/tegra2/board.c b/arch/arm/cpu/armv7/tegra2/board.c
...
> +void tegra_pre_console_panic(int uart_ids, unsigned clock_freq,
> +			     unsigned multiplier, const char *str)
> +{
> +	int baudrate, divisor;
> +	const u32 *uart_addr;
> +
> +	/* Enable all permitted UARTs */
> +	tegra_setup_uarts(uart_ids);

That call honors uart_ids. ...

> +	/*
> +	 * Now send the string out all the selected  UARTs. We don't try all
> +	 * possible configurations, but this could be added if required.
> +	 */
> +	baudrate = CONFIG_BAUDRATE;
> +	divisor = (clock_freq + (baudrate * (multiplier / 2))) /
> +			(multiplier * baudrate);
> +
> +	for (uart_addr = uart_reg_addr; *uart_addr; uart_addr++) {

Shouldn't this loop also honor uart_ids, and skip sending data to UARTS
not in uart_ids? Sure, they aren't set up above, but perhaps they were
set up elsewhere in the code and hence are capable of sending out data
anyway?

> +		NS16550_t regs = (NS16550_t)*uart_addr;
> +		const char *s;
> +
> +		NS16550_init(regs, divisor);
> +		for (s = str; *s; s++) {
> +			NS16550_putc(regs, *s);
> +			if (*s == '\n')
> +				NS16550_putc(regs, '\r');
> +		}
> +		NS16550_putc(regs, '\n');
> +		NS16550_putc(regs, '\r');
> +	}
> +}
Simon Glass - March 19, 2012, 10:55 p.m.
Hi Stephen,

On Mon, Mar 19, 2012 at 2:16 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 03/19/2012 02:27 PM, Simon Glass wrote:
>> This function is made available to board which want to display a message
>> when a panic() occurs before the console is set up. This would otherwise
>> result in a silent hang or reboot.
>>
>> Boards should call tegra_pre_console_panic() and pass the UARTs which
>> are available and safe for a message, as well as the selected clock and
>> serial multiplier values. Defaults are available as
>> CONFIG_DEFAULT_NS16550_CLK and CONFIG_DEFAULT_NS16550_MULT.
> ...
>> diff --git a/arch/arm/cpu/armv7/tegra2/board.c b/arch/arm/cpu/armv7/tegra2/board.c
> ...
>> +void tegra_pre_console_panic(int uart_ids, unsigned clock_freq,
>> +                          unsigned multiplier, const char *str)
>> +{
>> +     int baudrate, divisor;
>> +     const u32 *uart_addr;
>> +
>> +     /* Enable all permitted UARTs */
>> +     tegra_setup_uarts(uart_ids);
>
> That call honors uart_ids. ...
>
>> +     /*
>> +      * Now send the string out all the selected  UARTs. We don't try all
>> +      * possible configurations, but this could be added if required.
>> +      */
>> +     baudrate = CONFIG_BAUDRATE;
>> +     divisor = (clock_freq + (baudrate * (multiplier / 2))) /
>> +                     (multiplier * baudrate);
>> +
>> +     for (uart_addr = uart_reg_addr; *uart_addr; uart_addr++) {
>
> Shouldn't this loop also honor uart_ids, and skip sending data to UARTS
> not in uart_ids? Sure, they aren't set up above, but perhaps they were
> set up elsewhere in the code and hence are capable of sending out data
> anyway?

No, my intent was to use the same value but I overlooked it. I will fix this.

>
>> +             NS16550_t regs = (NS16550_t)*uart_addr;
>> +             const char *s;
>> +
>> +             NS16550_init(regs, divisor);
>> +             for (s = str; *s; s++) {
>> +                     NS16550_putc(regs, *s);
>> +                     if (*s == '\n')
>> +                             NS16550_putc(regs, '\r');
>> +             }
>> +             NS16550_putc(regs, '\n');
>> +             NS16550_putc(regs, '\r');
>> +     }
>> +}

Regards,
Simon

Patch

diff --git a/arch/arm/cpu/armv7/tegra2/board.c b/arch/arm/cpu/armv7/tegra2/board.c
index c9a7520..6e76dbe 100644
--- a/arch/arm/cpu/armv7/tegra2/board.c
+++ b/arch/arm/cpu/armv7/tegra2/board.c
@@ -22,6 +22,7 @@ 
  */
 
 #include <common.h>
+#include <ns16550.h>
 #include <asm/io.h>
 #include "ap20.h"
 #include <asm/arch/board.h>
@@ -137,3 +138,46 @@  void enable_caches(void)
 	dcache_enable();
 }
 #endif
+
+/*
+ * Possible UART locations: we ignore UARTC at 0x70006200 and UARTE at
+ * 0x70006400, since we don't have code to init them
+ */
+static const u32 uart_reg_addr[] = {
+	NV_PA_APB_UARTA_BASE,
+	NV_PA_APB_UARTB_BASE,
+	NV_PA_APB_UARTD_BASE,
+	0
+};
+
+void tegra_pre_console_panic(int uart_ids, unsigned clock_freq,
+			     unsigned multiplier, const char *str)
+{
+	int baudrate, divisor;
+	const u32 *uart_addr;
+
+	/* Enable all permitted UARTs */
+	tegra_setup_uarts(uart_ids);
+
+	/*
+	 * Now send the string out all the selected  UARTs. We don't try all
+	 * possible configurations, but this could be added if required.
+	 */
+	baudrate = CONFIG_BAUDRATE;
+	divisor = (clock_freq + (baudrate * (multiplier / 2))) /
+			(multiplier * baudrate);
+
+	for (uart_addr = uart_reg_addr; *uart_addr; uart_addr++) {
+		NS16550_t regs = (NS16550_t)*uart_addr;
+		const char *s;
+
+		NS16550_init(regs, divisor);
+		for (s = str; *s; s++) {
+			NS16550_putc(regs, *s);
+			if (*s == '\n')
+				NS16550_putc(regs, '\r');
+		}
+		NS16550_putc(regs, '\n');
+		NS16550_putc(regs, '\r');
+	}
+}
diff --git a/arch/arm/include/asm/arch-tegra2/board.h b/arch/arm/include/asm/arch-tegra2/board.h
index fb88517..fd2489f 100644
--- a/arch/arm/include/asm/arch-tegra2/board.h
+++ b/arch/arm/include/asm/arch-tegra2/board.h
@@ -41,6 +41,19 @@  enum {
  */
 void tegra_setup_uarts(int uart_ids);
 
+/**
+ * Display a panic message on selected UARTs.
+ *
+ * This is called when we have no console yet but have hit a panic(). It
+ * is normally called from board_pre_console_panic(), which passes in the
+ * UARTs that we are permitted to output to.
+ *
+ * We display a message on each UART in the hope that one will reach the
+ * user.
+ */
+void tegra_pre_console_panic(int uart_ids, unsigned clock_freq,
+			     unsigned multiplier, const char *str);
+
 /* Setup UARTs for the board according to the selected config */
 void board_init_uart_f(void);
 
diff --git a/include/configs/tegra2-common.h b/include/configs/tegra2-common.h
index 837f859..14d7602 100644
--- a/include/configs/tegra2-common.h
+++ b/include/configs/tegra2-common.h
@@ -84,6 +84,10 @@ 
 #define CONFIG_SYS_BAUDRATE_TABLE	{4800, 9600, 19200, 38400, 57600,\
 					115200}
 
+/* Default serial clock and multiplier */
+#define CONFIG_DEFAULT_NS16550_CLK	V_NS16550_CLK
+#define CONFIG_DEFAULT_NS16550_MULT	16
+
 /*
  * This parameter affects a TXFILLTUNING field that controls how much data is
  * sent to the latency fifo before it is sent to the wire. Without this