18791Sjkh/* SPDX-License-Identifier: GPL-2.0-or-later */ 28791Sjkh/* 38791Sjkh * Copyright (C) 2015 Imagination Technologies 48791Sjkh * Author: Paul Burton <paul.burton@mips.com> 58791Sjkh */ 68791Sjkh 78837Sjkh#include <asm/addrspace.h> 88791Sjkh#include <asm/asm.h> 98791Sjkh#include <asm/asm-offsets.h> 108791Sjkh#include <asm/mipsregs.h> 118791Sjkh#include <asm/regdef.h> 128791Sjkh#include <linux/serial_reg.h> 138791Sjkh 148791Sjkh#define UART_TX_OFS (UART_TX << CONFIG_MIPS_CPS_NS16550_SHIFT) 158791Sjkh#define UART_LSR_OFS (UART_LSR << CONFIG_MIPS_CPS_NS16550_SHIFT) 168791Sjkh 178791Sjkh#if CONFIG_MIPS_CPS_NS16550_WIDTH == 1 188791Sjkh# define UART_L lb 198791Sjkh# define UART_S sb 208791Sjkh#elif CONFIG_MIPS_CPS_NS16550_WIDTH == 2 218791Sjkh# define UART_L lh 228791Sjkh# define UART_S sh 238791Sjkh#elif CONFIG_MIPS_CPS_NS16550_WIDTH == 4 248791Sjkh# define UART_L lw 258791Sjkh# define UART_S sw 268791Sjkh#else 278791Sjkh# define UART_L lb 288791Sjkh# define UART_S sb 298791Sjkh#endif 308791Sjkh 318791Sjkh/** 328791Sjkh * _mips_cps_putc() - write a character to the UART 338791Sjkh * @a0: ASCII character to write 348791Sjkh * @t9: UART base address 358791Sjkh */ 368791SjkhLEAF(_mips_cps_putc) 378791Sjkh1: UART_L t0, UART_LSR_OFS(t9) 388791Sjkh andi t0, t0, UART_LSR_TEMT 398791Sjkh beqz t0, 1b 408791Sjkh UART_S a0, UART_TX_OFS(t9) 418791Sjkh jr ra 428791Sjkh END(_mips_cps_putc) 438791Sjkh 448791Sjkh/** 458791Sjkh * _mips_cps_puts() - write a string to the UART 468803Sjkh * @a0: pointer to NULL-terminated ASCII string 478791Sjkh * @t9: UART base address 488791Sjkh * 498810Sjkh * Write a null-terminated ASCII string to the UART. 508837Sjkh */ 518791SjkhNESTED(_mips_cps_puts, 0, ra) 528791Sjkh move s7, ra 538810Sjkh move s6, a0 548791Sjkh 558791Sjkh1: lb a0, 0(s6) 568791Sjkh beqz a0, 2f 578791Sjkh jal _mips_cps_putc 588791Sjkh PTR_ADDIU s6, s6, 1 598791Sjkh b 1b 608791Sjkh 618791Sjkh2: jr s7 628791Sjkh END(_mips_cps_puts) 638791Sjkh 648791Sjkh/** 658791Sjkh * _mips_cps_putx4 - write a 4b hex value to the UART 668810Sjkh * @a0: the 4b value to write to the UART 678810Sjkh * @t9: UART base address 688810Sjkh * 698810Sjkh * Write a single hexadecimal character to the UART. 708810Sjkh */ 718791SjkhNESTED(_mips_cps_putx4, 0, ra) 728837Sjkh andi a0, a0, 0xf 738837Sjkh li t0, '0' 748837Sjkh blt a0, 10, 1f 758837Sjkh li t0, 'a' 768837Sjkh addiu a0, a0, -10 778837Sjkh1: addu a0, a0, t0 788837Sjkh b _mips_cps_putc 798837Sjkh END(_mips_cps_putx4) 808837Sjkh 818837Sjkh/** 828837Sjkh * _mips_cps_putx8 - write an 8b hex value to the UART 838837Sjkh * @a0: the 8b value to write to the UART 848837Sjkh * @t9: UART base address 858837Sjkh * 868837Sjkh * Write an 8 bit value (ie. 2 hexadecimal characters) to the UART. 878837Sjkh */ 888791SjkhNESTED(_mips_cps_putx8, 0, ra) 898791Sjkh move s3, ra 908791Sjkh move s2, a0 918791Sjkh srl a0, a0, 4 928791Sjkh jal _mips_cps_putx4 938791Sjkh move a0, s2 948791Sjkh move ra, s3 958791Sjkh b _mips_cps_putx4 968791Sjkh END(_mips_cps_putx8) 978791Sjkh 988791Sjkh/** 998791Sjkh * _mips_cps_putx16 - write a 16b hex value to the UART 1008791Sjkh * @a0: the 16b value to write to the UART 1018791Sjkh * @t9: UART base address 1028791Sjkh * 1038791Sjkh * Write a 16 bit value (ie. 4 hexadecimal characters) to the UART. 1048791Sjkh */ 1058791SjkhNESTED(_mips_cps_putx16, 0, ra) 1068791Sjkh move s5, ra 1078791Sjkh move s4, a0 1088791Sjkh srl a0, a0, 8 1098791Sjkh jal _mips_cps_putx8 1108791Sjkh move a0, s4 1118791Sjkh move ra, s5 1128791Sjkh b _mips_cps_putx8 1138791Sjkh END(_mips_cps_putx16) 1148791Sjkh 1158791Sjkh/** 1168791Sjkh * _mips_cps_putx32 - write a 32b hex value to the UART 1178791Sjkh * @a0: the 32b value to write to the UART 1188791Sjkh * @t9: UART base address 1198791Sjkh * 1208791Sjkh * Write a 32 bit value (ie. 8 hexadecimal characters) to the UART. 1218791Sjkh */ 1228791SjkhNESTED(_mips_cps_putx32, 0, ra) 1238810Sjkh move s7, ra 1248810Sjkh move s6, a0 1258791Sjkh srl a0, a0, 16 1268791Sjkh jal _mips_cps_putx16 1278791Sjkh move a0, s6 1288791Sjkh move ra, s7 1298791Sjkh b _mips_cps_putx16 1308791Sjkh END(_mips_cps_putx32) 1318791Sjkh 1328791Sjkh#ifdef CONFIG_64BIT 1338791Sjkh 1348791Sjkh/** 1358810Sjkh * _mips_cps_putx64 - write a 64b hex value to the UART 1368810Sjkh * @a0: the 64b value to write to the UART 1378810Sjkh * @t9: UART base address 1388810Sjkh * 1398791Sjkh * Write a 64 bit value (ie. 16 hexadecimal characters) to the UART. 1408810Sjkh */ 1418791SjkhNESTED(_mips_cps_putx64, 0, ra) 1428810Sjkh move sp, ra 1438810Sjkh move s8, a0 1448810Sjkh dsrl32 a0, a0, 0 1458810Sjkh jal _mips_cps_putx32 1468810Sjkh move a0, s8 1478810Sjkh move ra, sp 1488810Sjkh b _mips_cps_putx32 1498810Sjkh END(_mips_cps_putx64) 1508810Sjkh 1518791Sjkh#define _mips_cps_putxlong _mips_cps_putx64 1528810Sjkh 1538810Sjkh#else /* !CONFIG_64BIT */ 1548810Sjkh 1558810Sjkh#define _mips_cps_putxlong _mips_cps_putx32 1568810Sjkh 1578828Sjkh#endif /* !CONFIG_64BIT */ 1588810Sjkh 1598810Sjkh/** 1608810Sjkh * mips_cps_bev_dump() - dump relevant exception state to UART 1618810Sjkh * @a0: pointer to NULL-terminated ASCII string naming the exception 1628810Sjkh * 1638810Sjkh * Write information that may be useful in debugging an exception to the 1648810Sjkh * UART configured by CONFIG_MIPS_CPS_NS16550_*. As this BEV exception 1658810Sjkh * will only be run if something goes horribly wrong very early during 1668810Sjkh * the bringup of a core and it is very likely to be unsafe to perform 1678810Sjkh * memory accesses at that point (cache state indeterminate, EVA may not 1688828Sjkh * be configured, coherence may be disabled) let alone have a stack, 1698828Sjkh * this is all written in assembly using only registers & unmapped 1708828Sjkh * uncached access to the UART registers. 1718828Sjkh */ 1728828SjkhLEAF(mips_cps_bev_dump) 1738828Sjkh move s0, ra 1748828Sjkh move s1, a0 1758828Sjkh 1768828Sjkh li t9, CKSEG1ADDR(CONFIG_MIPS_CPS_NS16550_BASE) 1778828Sjkh 1788810Sjkh PTR_LA a0, str_newline 1798810Sjkh jal _mips_cps_puts 1808810Sjkh PTR_LA a0, str_bev 1818810Sjkh jal _mips_cps_puts 1828810Sjkh move a0, s1 1838810Sjkh jal _mips_cps_puts 1848810Sjkh PTR_LA a0, str_newline 1858810Sjkh jal _mips_cps_puts 1868810Sjkh PTR_LA a0, str_newline 1878810Sjkh jal _mips_cps_puts 1888810Sjkh 1898810Sjkh#define DUMP_COP0_REG(reg, name, sz, _mfc0) \ 1908810Sjkh PTR_LA a0, 8f; \ 1918810Sjkh jal _mips_cps_puts; \ 1928810Sjkh _mfc0 a0, reg; \ 1938810Sjkh jal _mips_cps_putx##sz; \ 1948810Sjkh PTR_LA a0, str_newline; \ 1958810Sjkh jal _mips_cps_puts; \ 1968810Sjkh TEXT(name) 1978810Sjkh 1988810Sjkh DUMP_COP0_REG(CP0_CAUSE, "Cause: 0x", 32, mfc0) 1998810Sjkh DUMP_COP0_REG(CP0_STATUS, "Status: 0x", 32, mfc0) 2008810Sjkh DUMP_COP0_REG(CP0_EBASE, "EBase: 0x", long, MFC0) 2018810Sjkh DUMP_COP0_REG(CP0_BADVADDR, "BadVAddr: 0x", long, MFC0) 2028810Sjkh DUMP_COP0_REG(CP0_BADINSTR, "BadInstr: 0x", 32, mfc0) 2038810Sjkh 2048810Sjkh PTR_LA a0, str_newline 2058810Sjkh jal _mips_cps_puts 2068810Sjkh jr s0 2078810Sjkh END(mips_cps_bev_dump) 2088810Sjkh 2098810Sjkh.pushsection .data 2108810Sjkhstr_bev: .asciiz "BEV Exception: " 2118810Sjkhstr_newline: .asciiz "\r\n" 2128810Sjkh.popsection 213