| /* | |
| * Copyright (C) 2015 Imagination Technologies | |
| * Author: Paul Burton <paul.burton@mips.com> | |
| * | |
| * 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; either version 2 of the License, or (at your | |
| * option) any later version. | |
| */ | |
| #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) | |
| /** | |
| * _mips_cps_putc() - write a character to the UART | |
| * @a0: ASCII character to write | |
| * @t9: UART base address | |
| */ | |
| LEAF(_mips_cps_putc) | |
| 1: lw t0, UART_LSR_OFS(t9) | |
| andi t0, t0, UART_LSR_TEMT | |
| beqz t0, 1b | |
| sb 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 |