ARM: brcmstb: Add earlyprintk support using run-time checks
authorFlorian Fainelli <f.fainelli@gmail.com>
Tue, 28 Jun 2016 19:18:51 +0000 (12:18 -0700)
committerFlorian Fainelli <f.fainelli@gmail.com>
Mon, 8 Aug 2016 18:14:09 +0000 (11:14 -0700)
The SUN_TOP_CTRL_FAMILY_ID register  is at a fixed absolute address for
all of our supported chips, so utilize its value to determine what the
UARTA base address should be based on the value we read.

Since the code is called both during decompressor when the MMU is off,
and after the MMU has been turned on in the kernel, and we want to do
the lookup only once, we use the same technique as tegra.S and have a
shared storage location between the decompressor and the kernel.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
arch/arm/Kconfig.debug
arch/arm/include/debug/brcmstb.S [new file with mode: 0644]
arch/arm/mach-bcm/brcmstb.c

index a9693b6987a6e41c69702f1003d0d8bd2279530e..a660508a58bd5631aaeae67b210b7e339d2917e2 100644 (file)
@@ -186,10 +186,11 @@ choice
        config DEBUG_BRCMSTB_UART
                bool "Use BRCMSTB UART for low-level debug"
                depends on ARCH_BRCMSTB
-               select DEBUG_UART_8250
                help
                  Say Y here if you want the debug print routines to direct
-                 their output to the first serial port on these devices.
+                 their output to the first serial port on these devices. The
+                 UART physical and virtual address is automatically provided
+                 based on the chip identification register value.
 
                  If you have a Broadcom STB chip and would like early print
                  messages to appear over the UART, select this option.
@@ -1430,6 +1431,7 @@ config DEBUG_LL_INCLUDE
        default "debug/zynq.S" if DEBUG_ZYNQ_UART0 || DEBUG_ZYNQ_UART1
        default "debug/bcm63xx.S" if DEBUG_BCM63XX_UART
        default "debug/digicolor.S" if DEBUG_DIGICOLOR_UA0
+       default "debug/brcmstb.S" if DEBUG_BRCMSTB_UART
        default "mach/debug-macro.S"
 
 # Compatibility options for PL01x
@@ -1520,7 +1522,6 @@ config DEBUG_UART_PHYS
        default 0xe6e60000 if DEBUG_RCAR_GEN2_SCIF0
        default 0xe8008000 if DEBUG_R7S72100_SCIF2
        default 0xf0000be0 if ARCH_EBSA110
-       default 0xf040ab00 if DEBUG_BRCMSTB_UART
        default 0xf1012000 if DEBUG_MVEBU_UART0_ALTERNATE
        default 0xf1012100 if DEBUG_MVEBU_UART1_ALTERNATE
        default 0xf7fc9000 if DEBUG_BERLIN_UART
@@ -1604,7 +1605,6 @@ config DEBUG_UART_VIRT
        default 0xfb009000 if DEBUG_REALVIEW_STD_PORT
        default 0xfb00c000 if DEBUG_AT91_SAMA5D4_USART3
        default 0xfb10c000 if DEBUG_REALVIEW_PB1176_PORT
-       default 0xfc40ab00 if DEBUG_BRCMSTB_UART
        default 0xfc705000 if DEBUG_ZTE_ZX
        default 0xfcfe8600 if DEBUG_BCM63XX_UART
        default 0xfd000000 if DEBUG_SPEAR3XX || DEBUG_SPEAR13XX
@@ -1677,8 +1677,7 @@ config DEBUG_UART_8250_WORD
                DEBUG_ALPINE_UART0 || \
                DEBUG_DAVINCI_DMx_UART0 || DEBUG_DAVINCI_DA8XX_UART1 || \
                DEBUG_DAVINCI_DA8XX_UART2 || \
-               DEBUG_BCM_KONA_UART || DEBUG_RK32_UART2 || \
-               DEBUG_BRCMSTB_UART
+               DEBUG_BCM_KONA_UART || DEBUG_RK32_UART2
 
 config DEBUG_UART_8250_PALMCHIP
        bool "8250 UART is Palmchip BK-310x"
@@ -1697,7 +1696,8 @@ config DEBUG_UNCOMPRESS
        bool
        depends on ARCH_MULTIPLATFORM || PLAT_SAMSUNG || ARM_SINGLE_ARMV7M
        default y if DEBUG_LL && !DEBUG_OMAP2PLUS_UART && \
-                    (!DEBUG_TEGRA_UART || !ZBOOT_ROM)
+                    (!DEBUG_TEGRA_UART || !ZBOOT_ROM) && \
+                    !DEBUG_BRCMSTB_UART
        help
          This option influences the normal decompressor output for
          multiplatform kernels.  Normally, multiplatform kernels disable
diff --git a/arch/arm/include/debug/brcmstb.S b/arch/arm/include/debug/brcmstb.S
new file mode 100644 (file)
index 0000000..9113d7b
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2016 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/serial_reg.h>
+
+/* Physical register offset and virtual register offset */
+#define REG_PHYS_BASE          0xf0000000
+#define REG_VIRT_BASE          0xfc000000
+#define REG_PHYS_ADDR(x)       ((x) + REG_PHYS_BASE)
+
+/* Product id can be read from here */
+#define SUN_TOP_CTRL_BASE      REG_PHYS_ADDR(0x404000)
+
+#define UARTA_3390             REG_PHYS_ADDR(0x40a900)
+#define UARTA_7250             REG_PHYS_ADDR(0x40b400)
+#define UARTA_7268             REG_PHYS_ADDR(0x40c000)
+#define UARTA_7271             UARTA_7268
+#define UARTA_7364             REG_PHYS_ADDR(0x40b000)
+#define UARTA_7366             UARTA_7364
+#define UARTA_74371            REG_PHYS_ADDR(0x406b00)
+#define UARTA_7439             REG_PHYS_ADDR(0x40a900)
+#define UARTA_7445             REG_PHYS_ADDR(0x40ab00)
+
+#define UART_SHIFT             2
+
+#define checkuart(rp, rv, family_id, family) \
+               /* Load family id */ \
+               ldr     rp, =family_id ; \
+               /* Compare SUN_TOP_CTRL value against it */ \
+               cmp     rp, rv ; \
+               /* Passed test, load address */ \
+               ldreq   rp, =UARTA_##family ; \
+               /* Jump to save UART address */ \
+               beq     91f
+
+               .macro  addruart, rp, rv, tmp
+               adr     \rp, 99f                @ actual addr of 99f
+               ldr     \rv, [\rp]              @ linked addr is stored there
+               sub     \rv, \rv, \rp           @ offset between the two
+               ldr     \rp, [\rp, #4]          @ linked brcmstb_uart_config
+               sub     \tmp, \rp, \rv          @ actual brcmstb_uart_config
+               ldr     \rp, [\tmp]             @ Load brcmstb_uart_config
+               cmp     \rp, #1                 @ needs initialization?
+               bne     100f                    @ no; go load the addresses
+               mov     \rv, #0                 @ yes; record init is done
+               str     \rv, [\tmp]
+
+               /* Check SUN_TOP_CTRL base */
+               ldr     \rp, =SUN_TOP_CTRL_BASE @ load SUN_TOP_CTRL PA
+               ldr     \rv, [\rp, #0]          @ get register contents
+               and     \rv, \rv, #0xffffff00   @ strip revision bits [7:0]
+
+               /* Chip specific detection starts here */
+20:            checkuart(\rp, \rv, 0x33900000, 3390)
+21:            checkuart(\rp, \rv, 0x72500000, 7250)
+22:            checkuart(\rp, \rv, 0x72680000, 7268)
+23:            checkuart(\rp, \rv, 0x72710000, 7271)
+24:            checkuart(\rp, \rv, 0x73640000, 7364)
+25:            checkuart(\rp, \rv, 0x73660000, 7366)
+26:            checkuart(\rp, \rv, 0x07437100, 74371)
+27:            checkuart(\rp, \rv, 0x74390000, 7439)
+28:            checkuart(\rp, \rv, 0x74450000, 7445)
+
+               /* No valid UART found */
+90:            mov     \rp, #0
+               /* fall through */
+
+               /* Record whichever UART we chose */
+91:            str     \rp, [\tmp, #4]         @ Store in brcmstb_uart_phys
+               cmp     \rp, #0                 @ Valid UART address?
+               bne     92f                     @ Yes, go process it
+               str     \rp, [\tmp, #8]         @ Store 0 in brcmstb_uart_virt
+               b       100f                    @ Done
+92:            and     \rv, \rp, #0xffffff     @ offset within 16MB section
+               add     \rv, \rv, #REG_VIRT_BASE
+               str     \rv, [\tmp, #8]         @ Store in brcmstb_uart_virt
+               b       100f
+
+               .align
+99:            .word   .
+               .word   brcmstb_uart_config
+               .ltorg
+
+               /* Load previously selected UART address */
+100:           ldr     \rp, [\tmp, #4]         @ Load brcmstb_uart_phys
+               ldr     \rv, [\tmp, #8]         @ Load brcmstb_uart_virt
+               .endm
+
+               .macro  store, rd, rx:vararg
+               str     \rd, \rx
+               .endm
+
+               .macro  load, rd, rx:vararg
+               ldr     \rd, \rx
+               .endm
+
+               .macro  senduart,rd,rx
+               store   \rd, [\rx, #UART_TX << UART_SHIFT]
+               .endm
+
+               .macro  busyuart,rd,rx
+1002:          load    \rd, [\rx, #UART_LSR << UART_SHIFT]
+               and     \rd, \rd, #UART_LSR_TEMT | UART_LSR_THRE
+               teq     \rd, #UART_LSR_TEMT | UART_LSR_THRE
+               bne     1002b
+               .endm
+
+               .macro  waituart,rd,rx
+               .endm
+
+/*
+ * Storage for the state maintained by the macros above.
+ *
+ * In the kernel proper, this data is located in arch/arm/mach-bcm/brcmstb.c.
+ * That's because this header is included from multiple files, and we only
+ * want a single copy of the data. In particular, the UART probing code above
+ * assumes it's running using physical addresses. This is true when this file
+ * is included from head.o, but not when included from debug.o. So we need
+ * to share the probe results between the two copies, rather than having
+ * to re-run the probing again later.
+ *
+ * In the decompressor, we put the symbol/storage right here, since common.c
+ * isn't included in the decompressor build. This symbol gets put in .text
+ * even though it's really data, since .data is discarded from the
+ * decompressor. Luckily, .text is writeable in the decompressor, unless
+ * CONFIG_ZBOOT_ROM. That dependency is handled in arch/arm/Kconfig.debug.
+ */
+#if defined(ZIMAGE)
+brcmstb_uart_config:
+       /* Debug UART initialization required */
+       .word 1
+       /* Debug UART physical address */
+       .word 0
+       /* Debug UART virtual address */
+       .word 0
+#endif
index 99a67cfb7c0d5c129dfad0ec721ba24e402171fd..07e3a86c6466a954d87f0e30290d3ec9a3c27f34 100644 (file)
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
+/*
+ * Storage for debug-macro.S's state.
+ *
+ * This must be in .data not .bss so that it gets initialized each time the
+ * kernel is loaded. The data is declared here rather than debug-macro.S so
+ * that multiple inclusions of debug-macro.S point at the same data.
+ */
+u32 brcmstb_uart_config[3] = {
+       /* Debug UART initialization required */
+       1,
+       /* Debug UART physical address */
+       0,
+       /* Debug UART virtual address */
+       0,
+};
+
 static void __init brcmstb_init_irq(void)
 {
        irqchip_init();