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