Message ID | 20191119005842.16010-3-vladimir.olovyannikov@broadcom.com |
---|---|
State | Changes Requested |
Delegated to: | Simon Glass |
Headers | show |
Series | Add error logging support for Broadcom boards | expand |
Hi Vladimir, On Mon, 18 Nov 2019 at 17:59, Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com> wrote: > > From: Sheetal Tigadoli <sheetal.tigadoli@broadcom.com> > > Allow ELOG to use DDR for logging. > > Signed-off-by: Sheetal Tigadoli <sheetal.tigadoli@broadcom.com> > Signed-off-by: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com> > --- > common/Kconfig | 8 ++++++++ > common/Makefile | 1 + > common/bcm_elog.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++ > common/console.c | 22 +++++++++++++++++++++ > include/bcm_elog.h | 37 ++++++++++++++++++++++++++++++++++ > 5 files changed, 117 insertions(+) > create mode 100644 common/bcm_elog.c > create mode 100644 include/bcm_elog.h > > diff --git a/common/Kconfig b/common/Kconfig > index d9ecf79e0a..f78296ec63 100644 > --- a/common/Kconfig > +++ b/common/Kconfig > @@ -632,6 +632,14 @@ config SYS_STDIO_DEREGISTER > removed (for example a USB keyboard) then this option can be > enabled to ensure this is handled correctly. > > +config BCM_ELOG > + bool "Broadcom error logging support" > + default n > + help > + Enables broadcom error logging support to be used with brcm > + platforms, say Y to this option to enable the logging support. > + If unsure, say N. > + > endmenu > > menu "Logging" > diff --git a/common/Makefile b/common/Makefile > index 302d8beaf3..5f1338f281 100644 > --- a/common/Makefile > +++ b/common/Makefile > @@ -95,6 +95,7 @@ else > obj-$(CONFIG_SPL_SERIAL_SUPPORT) += console.o > endif > else > +obj-$(CONFIG_BCM_ELOG) += bcm_elog.o > obj-y += console.o > endif # CONFIG_SPL_BUILD > > diff --git a/common/bcm_elog.c b/common/bcm_elog.c > new file mode 100644 > index 0000000000..9f51636b24 > --- /dev/null > +++ b/common/bcm_elog.c > @@ -0,0 +1,49 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * (C) Copyright 2019 Broadcom > + */ > + > +#include <bcm_elog.h> > + > +/* Log one character */ > +int log2ddr(const char ch) > +{ > + u32 offset, len; > + uintptr_t base = BCM_ELOG_UBOOT_BASE; > + > + offset = readl(base + BCM_ELOG_OFF_OFFSET); > + len = readl(base + BCM_ELOG_LEN_OFFSET); > + writeb(ch, base + offset); > + offset++; > + > + /* log buffer is now full and need to wrap around */ > + if (offset >= BCM_ELOG_UBOOT_SIZE) > + offset = BCM_ELOG_HEADER_LEN; > + > + /* only increment length when log buffer is not full */ > + if (len < BCM_ELOG_UBOOT_SIZE - BCM_ELOG_HEADER_LEN) > + len++; > + > + writel(offset, base + BCM_ELOG_OFF_OFFSET); > + writel(len, base + BCM_ELOG_LEN_OFFSET); > + > + return 0; > +} > + > +/* Routine to initialize error logging */ > +void bcm_elog_init(uintptr_t base, u32 size) > +{ > + u32 val; > + > + /* > + * If a valid signature is found, it means logging is already > + * initialize. In this case, we should not re-initialize the entry > + * header in the designated memory > + */ > + val = readl(base + BCM_ELOG_SIG_OFFSET); > + if (val != BCM_ELOG_SIG_VAL) { > + writel(base + BCM_ELOG_SIG_OFFSET, BCM_ELOG_SIG_VAL); > + writel(base + BCM_ELOG_OFF_OFFSET, BCM_ELOG_HEADER_LEN); > + writel(base + BCM_ELOG_LEN_OFFSET, 0); > + } > +} > diff --git a/common/console.c b/common/console.c > index 168ba60d0d..25ebd6e431 100644 > --- a/common/console.c > +++ b/common/console.c > @@ -20,6 +20,10 @@ > #include <env_internal.h> > #include <watchdog.h> > > +#ifdef CONFIG_BCM_ELOG > +#include <bcm_elog.h> > +#endif > + > DECLARE_GLOBAL_DATA_PTR; > > static int on_console(const char *name, const char *value, enum env_op op, > @@ -536,6 +540,9 @@ void putc(const char c) > if (!gd->have_console) > return pre_console_putc(c); > > +#ifdef CONFIG_BCM_ELOG > + log2ddr(c); > +#endif > if (gd->flags & GD_FLG_DEVINIT) { > /* Send to the standard output */ > fputc(stdout, c); > @@ -587,6 +594,17 @@ void puts(const char *s) > if (!gd->have_console) > return pre_console_puts(s); > > +#ifdef CONFIG_BCM_ELOG > + { > + const char *tmp = s; > + > + while (*tmp) { > + int c = *tmp++; > + > + log2ddr(c); > + } > + } > +#endif Firstly this change to a common file should be in a separate patch. Secondly, we really can't do this sort of hack. You could use the existing log() subsystem with a driver for your log system. See log_console.c for an example. Then, when enabled, log data can go to your driver. > if (gd->flags & GD_FLG_DEVINIT) { > /* Send to the standard output */ > fputs(stdout, s); > @@ -776,6 +794,10 @@ int console_init_f(void) > > print_pre_console_buffer(PRE_CONSOLE_FLUSHPOINT1_SERIAL); > > +#ifdef CONFIG_BCM_ELOG > + bcm_elog_init(BCM_ELOG_UBOOT_BASE, BCM_ELOG_UBOOT_SIZE); > +#endif > + > return 0; > } > > diff --git a/include/bcm_elog.h b/include/bcm_elog.h > new file mode 100644 > index 0000000000..62352bf5a3 > --- /dev/null > +++ b/include/bcm_elog.h > @@ -0,0 +1,37 @@ > +/* SPDX-License-Identifier: GPL-2.0+ */ > +/* > + * (C) Copyright 2019 Broadcom > + * > + */ > + > +#ifndef __BCM_ELOG_H__ > +#define __BCM_ELOG_H__ > + > +#include <asm/io.h> > +#include <linux/types.h> > + > +/* Default AP error logging base address */ > +#ifndef ELOG_AP_UART_LOG_BASE > +#define ELOG_AP_UART_LOG_BASE 0x8f110000 > +#endif > + > +/* Reserve 16K to store error logs */ > +#define BCM_ELOG_UBOOT_BASE ELOG_AP_UART_LOG_BASE > +#define BCM_ELOG_UBOOT_SIZE 0x4000 > + > +/* error logging signature */ > +#define BCM_ELOG_SIG_OFFSET 0x0000 > +#define BCM_ELOG_SIG_VAL 0x75767971 > + > +/* current logging offset that points to where new logs should be added */ > +#define BCM_ELOG_OFF_OFFSET 0x0004 > + > +/* current logging length (excluding header) */ > +#define BCM_ELOG_LEN_OFFSET 0x0008 > + > +#define BCM_ELOG_HEADER_LEN 12 > + > +int log2ddr(const char ch); > +void bcm_elog_init(uintptr_t base, uint32_t size); > + > +#endif /* __BCM_ELOG_H__ */ > -- > 2.17.1 > Regards, Simon
diff --git a/common/Kconfig b/common/Kconfig index d9ecf79e0a..f78296ec63 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -632,6 +632,14 @@ config SYS_STDIO_DEREGISTER removed (for example a USB keyboard) then this option can be enabled to ensure this is handled correctly. +config BCM_ELOG + bool "Broadcom error logging support" + default n + help + Enables broadcom error logging support to be used with brcm + platforms, say Y to this option to enable the logging support. + If unsure, say N. + endmenu menu "Logging" diff --git a/common/Makefile b/common/Makefile index 302d8beaf3..5f1338f281 100644 --- a/common/Makefile +++ b/common/Makefile @@ -95,6 +95,7 @@ else obj-$(CONFIG_SPL_SERIAL_SUPPORT) += console.o endif else +obj-$(CONFIG_BCM_ELOG) += bcm_elog.o obj-y += console.o endif # CONFIG_SPL_BUILD diff --git a/common/bcm_elog.c b/common/bcm_elog.c new file mode 100644 index 0000000000..9f51636b24 --- /dev/null +++ b/common/bcm_elog.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2019 Broadcom + */ + +#include <bcm_elog.h> + +/* Log one character */ +int log2ddr(const char ch) +{ + u32 offset, len; + uintptr_t base = BCM_ELOG_UBOOT_BASE; + + offset = readl(base + BCM_ELOG_OFF_OFFSET); + len = readl(base + BCM_ELOG_LEN_OFFSET); + writeb(ch, base + offset); + offset++; + + /* log buffer is now full and need to wrap around */ + if (offset >= BCM_ELOG_UBOOT_SIZE) + offset = BCM_ELOG_HEADER_LEN; + + /* only increment length when log buffer is not full */ + if (len < BCM_ELOG_UBOOT_SIZE - BCM_ELOG_HEADER_LEN) + len++; + + writel(offset, base + BCM_ELOG_OFF_OFFSET); + writel(len, base + BCM_ELOG_LEN_OFFSET); + + return 0; +} + +/* Routine to initialize error logging */ +void bcm_elog_init(uintptr_t base, u32 size) +{ + u32 val; + + /* + * If a valid signature is found, it means logging is already + * initialize. In this case, we should not re-initialize the entry + * header in the designated memory + */ + val = readl(base + BCM_ELOG_SIG_OFFSET); + if (val != BCM_ELOG_SIG_VAL) { + writel(base + BCM_ELOG_SIG_OFFSET, BCM_ELOG_SIG_VAL); + writel(base + BCM_ELOG_OFF_OFFSET, BCM_ELOG_HEADER_LEN); + writel(base + BCM_ELOG_LEN_OFFSET, 0); + } +} diff --git a/common/console.c b/common/console.c index 168ba60d0d..25ebd6e431 100644 --- a/common/console.c +++ b/common/console.c @@ -20,6 +20,10 @@ #include <env_internal.h> #include <watchdog.h> +#ifdef CONFIG_BCM_ELOG +#include <bcm_elog.h> +#endif + DECLARE_GLOBAL_DATA_PTR; static int on_console(const char *name, const char *value, enum env_op op, @@ -536,6 +540,9 @@ void putc(const char c) if (!gd->have_console) return pre_console_putc(c); +#ifdef CONFIG_BCM_ELOG + log2ddr(c); +#endif if (gd->flags & GD_FLG_DEVINIT) { /* Send to the standard output */ fputc(stdout, c); @@ -587,6 +594,17 @@ void puts(const char *s) if (!gd->have_console) return pre_console_puts(s); +#ifdef CONFIG_BCM_ELOG + { + const char *tmp = s; + + while (*tmp) { + int c = *tmp++; + + log2ddr(c); + } + } +#endif if (gd->flags & GD_FLG_DEVINIT) { /* Send to the standard output */ fputs(stdout, s); @@ -776,6 +794,10 @@ int console_init_f(void) print_pre_console_buffer(PRE_CONSOLE_FLUSHPOINT1_SERIAL); +#ifdef CONFIG_BCM_ELOG + bcm_elog_init(BCM_ELOG_UBOOT_BASE, BCM_ELOG_UBOOT_SIZE); +#endif + return 0; } diff --git a/include/bcm_elog.h b/include/bcm_elog.h new file mode 100644 index 0000000000..62352bf5a3 --- /dev/null +++ b/include/bcm_elog.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2019 Broadcom + * + */ + +#ifndef __BCM_ELOG_H__ +#define __BCM_ELOG_H__ + +#include <asm/io.h> +#include <linux/types.h> + +/* Default AP error logging base address */ +#ifndef ELOG_AP_UART_LOG_BASE +#define ELOG_AP_UART_LOG_BASE 0x8f110000 +#endif + +/* Reserve 16K to store error logs */ +#define BCM_ELOG_UBOOT_BASE ELOG_AP_UART_LOG_BASE +#define BCM_ELOG_UBOOT_SIZE 0x4000 + +/* error logging signature */ +#define BCM_ELOG_SIG_OFFSET 0x0000 +#define BCM_ELOG_SIG_VAL 0x75767971 + +/* current logging offset that points to where new logs should be added */ +#define BCM_ELOG_OFF_OFFSET 0x0004 + +/* current logging length (excluding header) */ +#define BCM_ELOG_LEN_OFFSET 0x0008 + +#define BCM_ELOG_HEADER_LEN 12 + +int log2ddr(const char ch); +void bcm_elog_init(uintptr_t base, uint32_t size); + +#endif /* __BCM_ELOG_H__ */