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 | |