xref: /openbmc/linux/arch/mips/kernel/cps-vec-ns16550.S (revision 4b4193256c8d3bc3a5397b5cd9494c2ad386317d)
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  */
36 LEAF(_mips_cps_putc)
37 1:	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  */
51 NESTED(_mips_cps_puts, 0, ra)
52 	move		s7, ra
53 	move		s6, a0
54 
55 1:	lb		a0, 0(s6)
56 	beqz		a0, 2f
57 	jal		_mips_cps_putc
58 	PTR_ADDIU	s6, s6, 1
59 	b		1b
60 
61 2:	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  */
71 NESTED(_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
77 1:	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  */
88 NESTED(_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  */
105 NESTED(_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  */
122 NESTED(_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  */
141 NESTED(_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  */
172 LEAF(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
210 str_bev: .asciiz "BEV Exception: "
211 str_newline: .asciiz "\r\n"
212 .popsection
213