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