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