mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
212 lines
4.9 KiB
212 lines
4.9 KiB
/* SPDX-License-Identifier: GPL-2.0-or-later */ |
|
/* |
|
* Copyright (C) 2015 Imagination Technologies |
|
* Author: Paul Burton <paul.burton@mips.com> |
|
*/ |
|
|
|
#include <asm/addrspace.h> |
|
#include <asm/asm.h> |
|
#include <asm/asm-offsets.h> |
|
#include <asm/mipsregs.h> |
|
#include <asm/regdef.h> |
|
#include <linux/serial_reg.h> |
|
|
|
#define UART_TX_OFS (UART_TX << CONFIG_MIPS_CPS_NS16550_SHIFT) |
|
#define UART_LSR_OFS (UART_LSR << CONFIG_MIPS_CPS_NS16550_SHIFT) |
|
|
|
#if CONFIG_MIPS_CPS_NS16550_WIDTH == 1 |
|
# define UART_L lb |
|
# define UART_S sb |
|
#elif CONFIG_MIPS_CPS_NS16550_WIDTH == 2 |
|
# define UART_L lh |
|
# define UART_S sh |
|
#elif CONFIG_MIPS_CPS_NS16550_WIDTH == 4 |
|
# define UART_L lw |
|
# define UART_S sw |
|
#else |
|
# define UART_L lb |
|
# define UART_S sb |
|
#endif |
|
|
|
/** |
|
* _mips_cps_putc() - write a character to the UART |
|
* @a0: ASCII character to write |
|
* @t9: UART base address |
|
*/ |
|
LEAF(_mips_cps_putc) |
|
1: UART_L t0, UART_LSR_OFS(t9) |
|
andi t0, t0, UART_LSR_TEMT |
|
beqz t0, 1b |
|
UART_S a0, UART_TX_OFS(t9) |
|
jr ra |
|
END(_mips_cps_putc) |
|
|
|
/** |
|
* _mips_cps_puts() - write a string to the UART |
|
* @a0: pointer to NULL-terminated ASCII string |
|
* @t9: UART base address |
|
* |
|
* Write a null-terminated ASCII string to the UART. |
|
*/ |
|
NESTED(_mips_cps_puts, 0, ra) |
|
move s7, ra |
|
move s6, a0 |
|
|
|
1: lb a0, 0(s6) |
|
beqz a0, 2f |
|
jal _mips_cps_putc |
|
PTR_ADDIU s6, s6, 1 |
|
b 1b |
|
|
|
2: jr s7 |
|
END(_mips_cps_puts) |
|
|
|
/** |
|
* _mips_cps_putx4 - write a 4b hex value to the UART |
|
* @a0: the 4b value to write to the UART |
|
* @t9: UART base address |
|
* |
|
* Write a single hexadecimal character to the UART. |
|
*/ |
|
NESTED(_mips_cps_putx4, 0, ra) |
|
andi a0, a0, 0xf |
|
li t0, '0' |
|
blt a0, 10, 1f |
|
li t0, 'a' |
|
addiu a0, a0, -10 |
|
1: addu a0, a0, t0 |
|
b _mips_cps_putc |
|
END(_mips_cps_putx4) |
|
|
|
/** |
|
* _mips_cps_putx8 - write an 8b hex value to the UART |
|
* @a0: the 8b value to write to the UART |
|
* @t9: UART base address |
|
* |
|
* Write an 8 bit value (ie. 2 hexadecimal characters) to the UART. |
|
*/ |
|
NESTED(_mips_cps_putx8, 0, ra) |
|
move s3, ra |
|
move s2, a0 |
|
srl a0, a0, 4 |
|
jal _mips_cps_putx4 |
|
move a0, s2 |
|
move ra, s3 |
|
b _mips_cps_putx4 |
|
END(_mips_cps_putx8) |
|
|
|
/** |
|
* _mips_cps_putx16 - write a 16b hex value to the UART |
|
* @a0: the 16b value to write to the UART |
|
* @t9: UART base address |
|
* |
|
* Write a 16 bit value (ie. 4 hexadecimal characters) to the UART. |
|
*/ |
|
NESTED(_mips_cps_putx16, 0, ra) |
|
move s5, ra |
|
move s4, a0 |
|
srl a0, a0, 8 |
|
jal _mips_cps_putx8 |
|
move a0, s4 |
|
move ra, s5 |
|
b _mips_cps_putx8 |
|
END(_mips_cps_putx16) |
|
|
|
/** |
|
* _mips_cps_putx32 - write a 32b hex value to the UART |
|
* @a0: the 32b value to write to the UART |
|
* @t9: UART base address |
|
* |
|
* Write a 32 bit value (ie. 8 hexadecimal characters) to the UART. |
|
*/ |
|
NESTED(_mips_cps_putx32, 0, ra) |
|
move s7, ra |
|
move s6, a0 |
|
srl a0, a0, 16 |
|
jal _mips_cps_putx16 |
|
move a0, s6 |
|
move ra, s7 |
|
b _mips_cps_putx16 |
|
END(_mips_cps_putx32) |
|
|
|
#ifdef CONFIG_64BIT |
|
|
|
/** |
|
* _mips_cps_putx64 - write a 64b hex value to the UART |
|
* @a0: the 64b value to write to the UART |
|
* @t9: UART base address |
|
* |
|
* Write a 64 bit value (ie. 16 hexadecimal characters) to the UART. |
|
*/ |
|
NESTED(_mips_cps_putx64, 0, ra) |
|
move sp, ra |
|
move s8, a0 |
|
dsrl32 a0, a0, 0 |
|
jal _mips_cps_putx32 |
|
move a0, s8 |
|
move ra, sp |
|
b _mips_cps_putx32 |
|
END(_mips_cps_putx64) |
|
|
|
#define _mips_cps_putxlong _mips_cps_putx64 |
|
|
|
#else /* !CONFIG_64BIT */ |
|
|
|
#define _mips_cps_putxlong _mips_cps_putx32 |
|
|
|
#endif /* !CONFIG_64BIT */ |
|
|
|
/** |
|
* mips_cps_bev_dump() - dump relevant exception state to UART |
|
* @a0: pointer to NULL-terminated ASCII string naming the exception |
|
* |
|
* Write information that may be useful in debugging an exception to the |
|
* UART configured by CONFIG_MIPS_CPS_NS16550_*. As this BEV exception |
|
* will only be run if something goes horribly wrong very early during |
|
* the bringup of a core and it is very likely to be unsafe to perform |
|
* memory accesses at that point (cache state indeterminate, EVA may not |
|
* be configured, coherence may be disabled) let alone have a stack, |
|
* this is all written in assembly using only registers & unmapped |
|
* uncached access to the UART registers. |
|
*/ |
|
LEAF(mips_cps_bev_dump) |
|
move s0, ra |
|
move s1, a0 |
|
|
|
li t9, CKSEG1ADDR(CONFIG_MIPS_CPS_NS16550_BASE) |
|
|
|
PTR_LA a0, str_newline |
|
jal _mips_cps_puts |
|
PTR_LA a0, str_bev |
|
jal _mips_cps_puts |
|
move a0, s1 |
|
jal _mips_cps_puts |
|
PTR_LA a0, str_newline |
|
jal _mips_cps_puts |
|
PTR_LA a0, str_newline |
|
jal _mips_cps_puts |
|
|
|
#define DUMP_COP0_REG(reg, name, sz, _mfc0) \ |
|
PTR_LA a0, 8f; \ |
|
jal _mips_cps_puts; \ |
|
_mfc0 a0, reg; \ |
|
jal _mips_cps_putx##sz; \ |
|
PTR_LA a0, str_newline; \ |
|
jal _mips_cps_puts; \ |
|
TEXT(name) |
|
|
|
DUMP_COP0_REG(CP0_CAUSE, "Cause: 0x", 32, mfc0) |
|
DUMP_COP0_REG(CP0_STATUS, "Status: 0x", 32, mfc0) |
|
DUMP_COP0_REG(CP0_EBASE, "EBase: 0x", long, MFC0) |
|
DUMP_COP0_REG(CP0_BADVADDR, "BadVAddr: 0x", long, MFC0) |
|
DUMP_COP0_REG(CP0_BADINSTR, "BadInstr: 0x", 32, mfc0) |
|
|
|
PTR_LA a0, str_newline |
|
jal _mips_cps_puts |
|
jr s0 |
|
END(mips_cps_bev_dump) |
|
|
|
.pushsection .data |
|
str_bev: .asciiz "BEV Exception: " |
|
str_newline: .asciiz "\r\n" |
|
.popsection
|
|
|