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