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