1/* SPDX-License-Identifier: GPL-2.0-or-later */ 2/* 3 * Copyright (C) 2015 Imagination Technologies 4 * Author: Paul Burton <paul.burton@mips.com> 5 */ 6 7#include <asm/addrspace.h> 8#include <asm/asm.h> 9#include <asm/asm-offsets.h> 10#include <asm/mipsregs.h> 11#include <asm/regdef.h> 12#include <linux/serial_reg.h> 13 14#define UART_TX_OFS (UART_TX << CONFIG_MIPS_CPS_NS16550_SHIFT) 15#define UART_LSR_OFS (UART_LSR << CONFIG_MIPS_CPS_NS16550_SHIFT) 16 17/** 18 * _mips_cps_putc() - write a character to the UART 19 * @a0: ASCII character to write 20 * @t9: UART base address 21 */ 22LEAF(_mips_cps_putc) 231: lw t0, UART_LSR_OFS(t9) 24 andi t0, t0, UART_LSR_TEMT 25 beqz t0, 1b 26 sb a0, UART_TX_OFS(t9) 27 jr ra 28 END(_mips_cps_putc) 29 30/** 31 * _mips_cps_puts() - write a string to the UART 32 * @a0: pointer to NULL-terminated ASCII string 33 * @t9: UART base address 34 * 35 * Write a null-terminated ASCII string to the UART. 36 */ 37NESTED(_mips_cps_puts, 0, ra) 38 move s7, ra 39 move s6, a0 40 411: lb a0, 0(s6) 42 beqz a0, 2f 43 jal _mips_cps_putc 44 PTR_ADDIU s6, s6, 1 45 b 1b 46 472: jr s7 48 END(_mips_cps_puts) 49 50/** 51 * _mips_cps_putx4 - write a 4b hex value to the UART 52 * @a0: the 4b value to write to the UART 53 * @t9: UART base address 54 * 55 * Write a single hexadecimal character to the UART. 56 */ 57NESTED(_mips_cps_putx4, 0, ra) 58 andi a0, a0, 0xf 59 li t0, '0' 60 blt a0, 10, 1f 61 li t0, 'a' 62 addiu a0, a0, -10 631: addu a0, a0, t0 64 b _mips_cps_putc 65 END(_mips_cps_putx4) 66 67/** 68 * _mips_cps_putx8 - write an 8b hex value to the UART 69 * @a0: the 8b value to write to the UART 70 * @t9: UART base address 71 * 72 * Write an 8 bit value (ie. 2 hexadecimal characters) to the UART. 73 */ 74NESTED(_mips_cps_putx8, 0, ra) 75 move s3, ra 76 move s2, a0 77 srl a0, a0, 4 78 jal _mips_cps_putx4 79 move a0, s2 80 move ra, s3 81 b _mips_cps_putx4 82 END(_mips_cps_putx8) 83 84/** 85 * _mips_cps_putx16 - write a 16b hex value to the UART 86 * @a0: the 16b value to write to the UART 87 * @t9: UART base address 88 * 89 * Write a 16 bit value (ie. 4 hexadecimal characters) to the UART. 90 */ 91NESTED(_mips_cps_putx16, 0, ra) 92 move s5, ra 93 move s4, a0 94 srl a0, a0, 8 95 jal _mips_cps_putx8 96 move a0, s4 97 move ra, s5 98 b _mips_cps_putx8 99 END(_mips_cps_putx16) 100 101/** 102 * _mips_cps_putx32 - write a 32b hex value to the UART 103 * @a0: the 32b value to write to the UART 104 * @t9: UART base address 105 * 106 * Write a 32 bit value (ie. 8 hexadecimal characters) to the UART. 107 */ 108NESTED(_mips_cps_putx32, 0, ra) 109 move s7, ra 110 move s6, a0 111 srl a0, a0, 16 112 jal _mips_cps_putx16 113 move a0, s6 114 move ra, s7 115 b _mips_cps_putx16 116 END(_mips_cps_putx32) 117 118#ifdef CONFIG_64BIT 119 120/** 121 * _mips_cps_putx64 - write a 64b hex value to the UART 122 * @a0: the 64b value to write to the UART 123 * @t9: UART base address 124 * 125 * Write a 64 bit value (ie. 16 hexadecimal characters) to the UART. 126 */ 127NESTED(_mips_cps_putx64, 0, ra) 128 move sp, ra 129 move s8, a0 130 dsrl32 a0, a0, 0 131 jal _mips_cps_putx32 132 move a0, s8 133 move ra, sp 134 b _mips_cps_putx32 135 END(_mips_cps_putx64) 136 137#define _mips_cps_putxlong _mips_cps_putx64 138 139#else /* !CONFIG_64BIT */ 140 141#define _mips_cps_putxlong _mips_cps_putx32 142 143#endif /* !CONFIG_64BIT */ 144 145/** 146 * mips_cps_bev_dump() - dump relevant exception state to UART 147 * @a0: pointer to NULL-terminated ASCII string naming the exception 148 * 149 * Write information that may be useful in debugging an exception to the 150 * UART configured by CONFIG_MIPS_CPS_NS16550_*. As this BEV exception 151 * will only be run if something goes horribly wrong very early during 152 * the bringup of a core and it is very likely to be unsafe to perform 153 * memory accesses at that point (cache state indeterminate, EVA may not 154 * be configured, coherence may be disabled) let alone have a stack, 155 * this is all written in assembly using only registers & unmapped 156 * uncached access to the UART registers. 157 */ 158LEAF(mips_cps_bev_dump) 159 move s0, ra 160 move s1, a0 161 162 li t9, CKSEG1ADDR(CONFIG_MIPS_CPS_NS16550_BASE) 163 164 PTR_LA a0, str_newline 165 jal _mips_cps_puts 166 PTR_LA a0, str_bev 167 jal _mips_cps_puts 168 move a0, s1 169 jal _mips_cps_puts 170 PTR_LA a0, str_newline 171 jal _mips_cps_puts 172 PTR_LA a0, str_newline 173 jal _mips_cps_puts 174 175#define DUMP_COP0_REG(reg, name, sz, _mfc0) \ 176 PTR_LA a0, 8f; \ 177 jal _mips_cps_puts; \ 178 _mfc0 a0, reg; \ 179 jal _mips_cps_putx##sz; \ 180 PTR_LA a0, str_newline; \ 181 jal _mips_cps_puts; \ 182 TEXT(name) 183 184 DUMP_COP0_REG(CP0_CAUSE, "Cause: 0x", 32, mfc0) 185 DUMP_COP0_REG(CP0_STATUS, "Status: 0x", 32, mfc0) 186 DUMP_COP0_REG(CP0_EBASE, "EBase: 0x", long, MFC0) 187 DUMP_COP0_REG(CP0_BADVADDR, "BadVAddr: 0x", long, MFC0) 188 DUMP_COP0_REG(CP0_BADINSTR, "BadInstr: 0x", 32, mfc0) 189 190 PTR_LA a0, str_newline 191 jal _mips_cps_puts 192 jr s0 193 END(mips_cps_bev_dump) 194 195.pushsection .data 196str_bev: .asciiz "BEV Exception: " 197str_newline: .asciiz "\r\n" 198.popsection 199