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