GNU Linux-libre 4.19.286-gnu1
[releases.git] / arch / mips / kernel / cps-vec-ns16550.S
1 /*
2  * Copyright (C) 2015 Imagination Technologies
3  * Author: Paul Burton <paul.burton@mips.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