diff mbox

[U-Boot,17/19] serial: Support an early UART for debugging

Message ID 1418653194-16873-18-git-send-email-sjg@chromium.org
State Superseded
Delegated to: Stefan Roese
Headers show

Commit Message

Simon Glass Dec. 15, 2014, 2:19 p.m. UTC
This came up in a discussion on the mailing list here:

https://patchwork.ozlabs.org/patch/384613/

My concerns at the time were:
- it doesn't need to be written in assembler
- it doesn't need to be ARM-specific

This patch provides a possible alternative. It works by allowing any serial
driver to export one init function and provide a putc() function. These
can be used to output debug data before the real serial driver is available.

This implementation does not depend on driver model, and it is possible for
it to operate without a stack on some architectures (e.g. PowerPC, ARM). It
provides the same features as the ARM-specific debug.S but with more UART
and architecture support.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/serial/Kconfig |  46 ++++++++++++++++
 include/debug_uart.h   | 139 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 185 insertions(+)
 create mode 100644 include/debug_uart.h

Comments

Masahiro Yamada Dec. 16, 2014, 4:38 a.m. UTC | #1
Hi Simon,



On Mon, 15 Dec 2014 07:19:52 -0700
Simon Glass <sjg@chromium.org> wrote:

> This came up in a discussion on the mailing list here:
> 
> https://patchwork.ozlabs.org/patch/384613/
> 
> My concerns at the time were:
> - it doesn't need to be written in assembler

Assembler can guarantee that stack is not used.


> - it doesn't need to be ARM-specific

OK.

> This patch provides a possible alternative. It works by allowing any serial
> driver to export one init function and provide a putc() function. These
> can be used to output debug data before the real serial driver is available.
> 
> This implementation does not depend on driver model,

OK.

> and it is possible for
> it to operate without a stack on some architectures (e.g. PowerPC, ARM).

It depends on the optimization option -O2 / -Os.

In 18/19, you add "static inline" to calc_divisor().

"static inline" does not force-inline the code,
but still leaves it to the compiler decision.
(Marek Vasut also mentioned this in commit 4425e62856)





Best Regards
Masahiro Yamada
Simon Glass Dec. 17, 2014, 4:46 a.m. UTC | #2
Hi Masahiro,

On 15 December 2014 at 21:38, Masahiro Yamada <yamada.m@jp.panasonic.com> wrote:
> Hi Simon,
>
>
>
> On Mon, 15 Dec 2014 07:19:52 -0700
> Simon Glass <sjg@chromium.org> wrote:
>
>> This came up in a discussion on the mailing list here:
>>
>> https://patchwork.ozlabs.org/patch/384613/
>>
>> My concerns at the time were:
>> - it doesn't need to be written in assembler
>
> Assembler can guarantee that stack is not used.

So can C if written correctly, at least on PowerPC, ARM and a few other archs.

>
>
>> - it doesn't need to be ARM-specific
>
> OK.
>
>> This patch provides a possible alternative. It works by allowing any serial
>> driver to export one init function and provide a putc() function. These
>> can be used to output debug data before the real serial driver is available.
>>
>> This implementation does not depend on driver model,
>
> OK.
>
>> and it is possible for
>> it to operate without a stack on some architectures (e.g. PowerPC, ARM).
>
> It depends on the optimization option -O2 / -Os.

OK, fair enough.

>
> In 18/19, you add "static inline" to calc_divisor().
>
> "static inline" does not force-inline the code,
> but still leaves it to the compiler decision.
> (Marek Vasut also mentioned this in commit 4425e62856)

Sure, I understand.

For me this implementation works on ARM and PowerPC, and can be
applied for any UART in U-Boot. We don't need to write assembler in
each UART for each architecture we support. That's my point.

I'm not suggesting we drop the assembler version, just that we have
another option. Of course if a particular UART driver wants to include
assembler it can.

Regards,
Simon
diff mbox

Patch

diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index a0b6e02..268bb42 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -5,6 +5,52 @@  config DM_SERIAL
 	  If you want to use driver model for serial drivers, say Y.
 	  To use legacy serial drivers, say N.
 
+config DEBUG_UART
+	bool "Enable an early debug UART for debugging"
+	help
+	  The debug UART is intended for use very early in U-Boot to debug
+	  problems when an ICE or other debug mechanism is not available.
+
+	  To use it you should:
+	  - Make sure your UART supports this interface
+	  - Enable CONFIG_DEBUG_UART
+	  - Enable the CONFIG for your UART to tell it to provide this interface
+	        (e.g. CONFIG_DEBUG_UART_NS16550)
+	  - Define the required settings as needed (see below)
+	  - Call debug_uart_init() before use
+	  - Call debug_uart_putc() to output a character
+
+	  Depending on your platform it may be possible to use this UART before
+	  a stack is available.
+
+	  If your UART does not support this interface you can probably add
+	  support quite easily. Remember that you cannot use driver model and
+	  it is preferred to use no stack.
+
+	  You must not use this UART once driver model is working and the
+	  serial drivers are up and running (done in serial_init()). Otherwise
+	  the drivers may conflict and you will get strange output.
+
+config DEBUG_UART_BASE
+	hex "Base address of UART"
+	depends on DEBUG_UART
+	help
+	  This is the base address of your UART for memory-mapped UARTs.
+
+	  A default should be provided by your board, but if not you will need
+	  to use the correct value here.
+
+config DEBUG_UART_CLOCK
+	int "UART input clock"
+	depends on DEBUG_UART
+	help
+	  The UART input clock determines the speed of the internal UART
+	  circuitry. The baud rate is derived from this by dividing the input
+	  clock down.
+
+	  A default should be provided by your board, but if not you will need
+	  to use the correct value here.
+
 config UNIPHIER_SERIAL
 	bool "UniPhier on-chip UART support"
 	depends on ARCH_UNIPHIER && DM_SERIAL
diff --git a/include/debug_uart.h b/include/debug_uart.h
new file mode 100644
index 0000000..20d8f34
--- /dev/null
+++ b/include/debug_uart.h
@@ -0,0 +1,139 @@ 
+/*
+ * Early debug UART support
+ *
+ * (C) Copyright 2014 Google, Inc
+ * Writte by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _DEBUG_UART_H
+#define _DEBUG_UART_H
+
+#include <linux/linkage.h>
+
+/*
+ * The debug UART is intended for use very early in U-Boot to debug problems
+ * when an ICE or other debug mechanism is not available.
+ *
+ * To use it you should:
+ * - Make sure your UART supports this interface
+ * - Enable CONFIG_DEBUG_UART
+ * - Enable the CONFIG for your UART to tell it to provide this interface
+ *       (e.g. CONFIG_DEBUG_UART_NS16550)
+ * - Define the required settings as needed (see below)
+ * - Call debug_uart_init() before use
+ * - Call printch() to output a character
+ *
+ * Depending on your platform it may be possible to use this UART before a
+ * stack is available.
+ *
+ * If your UART does not support this interface you can probably add support
+ * quite easily. Remember that you cannot use driver model and it is preferred
+ * to use no stack.
+ *
+ * You must not use this UART once driver model is working and the serial
+ * drivers are up and running (done in serial_init()). Otherwise the drivers
+ * may conflict and you will get strange output.
+ *
+ *
+ * To enable the debug UART in your serial driver:
+ *
+ * - #include <debug_uart.h>
+ * - Define debug_uart_init(), trying to avoid using the stack
+ * - Define _debug_uart_putc() as static inline (avoiding stack usage)
+ * - Immediately afterwards, add DEBUG_UART_FUNCS to define the rest of the
+ *     functionality (printch(), etc.)
+ */
+
+/**
+ * debug_uart_init() - Set up the debug UART ready for use
+ *
+ * This sets up the UART with the correct baud rate, etc.
+ *
+ * Available CONFIG is:
+ *
+ *    - CONFIG_DEBUG_UART_BASE: Base address of UART
+ *    - CONFIG_BAUDRATE: Requested baud rate
+ *    - CONFIG_DEBUG_UART_CLOCK: Input clock for UART
+ */
+void debug_uart_init(void);
+
+/**
+ * printch() - Output a character to the debug UART
+ *
+ * @ch:		Character to output
+ */
+void printch(int ch);
+
+/**
+ * printascii() - Output an ASCII string to the debug UART
+ *
+ * @str:	String to output
+ */
+void printascii(const char *str);
+
+/**
+ * printhex2() - Output a 2-digit hex value
+ *
+ * @value:	Value to output
+ */
+void printhex2(uint value);
+
+/**
+ * printhex4() - Output a 4-digit hex value
+ *
+ * @value:	Value to output
+ */
+void printhex4(uint value);
+
+/**
+ * printhex8() - Output a 8-digit hex value
+ *
+ * @value:	Value to output
+ */
+void printhex8(uint value);
+
+/*
+ * Now define some functions - this should be inserted into the serial driver
+ */
+#define DEBUG_UART_FUNCS \
+	asmlinkage void printch(int ch) \
+	{ \
+		_debug_uart_putc(ch); \
+	} \
+\
+	asmlinkage void printascii(const char *str) \
+	{ \
+		while (*str) \
+			_debug_uart_putc(*str++); \
+	} \
+\
+	static inline void printhex1(uint digit) \
+	{ \
+		digit &= 0xf; \
+		_debug_uart_putc(digit > 9 ? digit - 10 + 'a' : digit + '0'); \
+	} \
+\
+	static inline void printhex(uint value, int digits) \
+	{ \
+		while (digits-- > 0) \
+			printhex1(value >> (4 * digits)); \
+	} \
+\
+	asmlinkage void printhex2(uint value) \
+	{ \
+		printhex(value, 2); \
+	} \
+\
+	asmlinkage void printhex4(uint value) \
+	{ \
+		printhex(value, 4); \
+	} \
+\
+	asmlinkage void printhex8(uint value) \
+	{ \
+		printhex(value, 8); \
+	}
+
+#endif