root/arch/arm/include/debug/brcmstb.S
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (C) 2016 Broadcom */
#include <linux/serial_reg.h>
#include <asm/cputype.h>

/* Physical register offset and virtual register offset */
#define REG_PHYS_BASE           0xf0000000
#define REG_PHYS_BASE_V7        0x08000000
#define REG_VIRT_BASE           0xfc000000
#define REG_PHYS_ADDR(x)        ((x) + REG_PHYS_BASE)
#define REG_PHYS_ADDR_V7(x)     ((x) + REG_PHYS_BASE_V7)

/* Product id can be read from here */
#define SUN_TOP_CTRL_BASE       REG_PHYS_ADDR(0x404000)
#define SUN_TOP_CTRL_BASE_V7    REG_PHYS_ADDR_V7(0x404000)

#define UARTA_3390              REG_PHYS_ADDR(0x40a900)
#define UARTA_72116             UARTA_7255
#define UARTA_7250              REG_PHYS_ADDR(0x40b400)
#define UARTA_7255              REG_PHYS_ADDR(0x40c000)
#define UARTA_7260              UARTA_7255
#define UARTA_7268              UARTA_7255
#define UARTA_7271              UARTA_7268
#define UARTA_7278              REG_PHYS_ADDR_V7(0x40c000)
#define UARTA_7216              UARTA_7278
#define UARTA_72164             UARTA_7278
#define UARTA_72165             UARTA_7278
#define UARTA_7364              REG_PHYS_ADDR(0x40b000)
#define UARTA_7366              UARTA_7364
#define UARTA_74165             UARTA_7278
#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 for V7 memory map if B53 */
                mrc     p15, 0, \rv, c0, c0, 0  @ get Main ID register
                ldr     \rp, =ARM_CPU_PART_MASK
                and     \rv, \rv, \rp
                ldr     \rp, =ARM_CPU_PART_BRAHMA_B53   @ check for B53 CPU
                cmp     \rv, \rp
                bne     10f

                /* if PERIPHBASE doesn't overlap REG_PHYS_BASE use V7 map */
                mrc     p15, 1, \rv, c15, c3, 0 @ get PERIPHBASE from CBAR
                ands    \rv, \rv, #REG_PHYS_BASE
                ldreq   \rp, =SUN_TOP_CTRL_BASE_V7

                /* Check SUN_TOP_CTRL base */
10:             ldrne   \rp, =SUN_TOP_CTRL_BASE @ load SUN_TOP_CTRL PA
                ldr     \rv, [\rp, #0]          @ get register contents
ARM_BE8(        rev     \rv, \rv )
                and     \rv, \rv, #0xffffff00   @ strip revision bits [7:0]

                /* Chip specific detection starts here */
20:             checkuart(\rp, \rv, 0x33900000, 3390)
21:             checkuart(\rp, \rv, 0x07211600, 72116)
22:             checkuart(\rp, \rv, 0x72160000, 7216)
23:             checkuart(\rp, \rv, 0x07216400, 72164)
24:             checkuart(\rp, \rv, 0x07216500, 72165)
25:             checkuart(\rp, \rv, 0x72500000, 7250)
26:             checkuart(\rp, \rv, 0x72550000, 7255)
27:             checkuart(\rp, \rv, 0x72600000, 7260)
28:             checkuart(\rp, \rv, 0x72680000, 7268)
29:             checkuart(\rp, \rv, 0x72710000, 7271)
30:             checkuart(\rp, \rv, 0x72780000, 7278)
31:             checkuart(\rp, \rv, 0x73640000, 7364)
32:             checkuart(\rp, \rv, 0x73660000, 7366)
33:             checkuart(\rp, \rv, 0x07416500, 74165)
34:             checkuart(\rp, \rv, 0x07437100, 74371)
35:             checkuart(\rp, \rv, 0x74390000, 7439)
36:             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
ARM_BE8(        rev     \rd, \rd )
                str     \rd, \rx
                .endm

                .macro  load, rd, rx:vararg
                ldr     \rd, \rx
ARM_BE8(        rev     \rd, \rd )
                .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  waituarttxrdy,rd,rx
                .endm

                .macro  waituartcts,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