1/*
2 * Mini SCLP driver.
3 *
4 * Copyright IBM Corp. 2004, 2009
5 *
6 *   Author(s):	Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>,
7 *		Heiko Carstens <heiko.carstens@de.ibm.com>,
8 *
9 */
10
11#include <linux/linkage.h>
12#include <asm/irq.h>
13
14LC_EXT_NEW_PSW		= 0x58			# addr of ext int handler
15LC_EXT_NEW_PSW_64	= 0x1b0			# addr of ext int handler 64 bit
16LC_EXT_INT_PARAM	= 0x80			# addr of ext int parameter
17LC_EXT_INT_CODE		= 0x86			# addr of ext int code
18LC_AR_MODE_ID		= 0xa3
19
20#
21# Subroutine which waits synchronously until either an external interruption
22# or a timeout occurs.
23#
24# Parameters:
25#   R2	= 0 for no timeout, non-zero for timeout in (approximated) seconds
26#
27# Returns:
28#   R2	= 0 on interrupt, 2 on timeout
29#   R3	= external interruption parameter if R2=0
30#
31
32_sclp_wait_int:
33	stm	%r6,%r15,24(%r15)		# save registers
34	basr	%r13,0				# get base register
35.LbaseS1:
36	ahi	%r15,-96			# create stack frame
37	la	%r8,LC_EXT_NEW_PSW		# register int handler
38	la	%r9,.LextpswS1-.LbaseS1(%r13)
39	tm	LC_AR_MODE_ID,1
40	jno	.Lesa1
41	la	%r8,LC_EXT_NEW_PSW_64		# register int handler 64 bit
42	la	%r9,.LextpswS1_64-.LbaseS1(%r13)
43.Lesa1:
44	mvc	.LoldpswS1-.LbaseS1(16,%r13),0(%r8)
45	mvc	0(16,%r8),0(%r9)
46	epsw	%r6,%r7				# set current addressing mode
47	nill	%r6,0x1				# in new psw (31 or 64 bit mode)
48	nilh	%r7,0x8000
49	stm	%r6,%r7,0(%r8)
50	lhi	%r6,0x0200			# cr mask for ext int (cr0.54)
51	ltr	%r2,%r2
52	jz	.LsetctS1
53	ahi	%r6,0x0800			# cr mask for clock int (cr0.52)
54	stck	.LtimeS1-.LbaseS1(%r13)		# initiate timeout
55	al	%r2,.LtimeS1-.LbaseS1(%r13)
56	st	%r2,.LtimeS1-.LbaseS1(%r13)
57	sckc	.LtimeS1-.LbaseS1(%r13)
58
59.LsetctS1:
60	stctl	%c0,%c0,.LctlS1-.LbaseS1(%r13)	# enable required interrupts
61	l	%r0,.LctlS1-.LbaseS1(%r13)
62	lhi	%r1,~(0x200 | 0x800)		# clear old values
63	nr	%r1,%r0
64	or	%r1,%r6				# set new value
65	st	%r1,.LctlS1-.LbaseS1(%r13)
66	lctl	%c0,%c0,.LctlS1-.LbaseS1(%r13)
67	st	%r0,.LctlS1-.LbaseS1(%r13)
68	lhi	%r2,2				# return code for timeout
69.LloopS1:
70	lpsw	.LwaitpswS1-.LbaseS1(%r13)	# wait until interrupt
71.LwaitS1:
72	lh	%r7,LC_EXT_INT_CODE
73	chi	%r7,EXT_IRQ_CLK_COMP		# timeout?
74	je	.LtimeoutS1
75	chi	%r7,EXT_IRQ_SERVICE_SIG		# service int?
76	jne	.LloopS1
77	sr	%r2,%r2
78	l	%r3,LC_EXT_INT_PARAM
79.LtimeoutS1:
80	lctl	%c0,%c0,.LctlS1-.LbaseS1(%r13)	# restore interrupt setting
81	# restore old handler
82	mvc	0(16,%r8),.LoldpswS1-.LbaseS1(%r13)
83	lm	%r6,%r15,120(%r15)		# restore registers
84	br	%r14				# return to caller
85
86	.align	8
87.LoldpswS1:
88	.long	0, 0, 0, 0			# old ext int PSW
89.LextpswS1:
90	.long	0x00080000, 0x80000000+.LwaitS1	# PSW to handle ext int
91.LextpswS1_64:
92	.quad	0, .LwaitS1			# PSW to handle ext int, 64 bit
93.LwaitpswS1:
94	.long	0x010a0000, 0x00000000+.LloopS1	# PSW to wait for ext int
95.LtimeS1:
96	.quad	0				# current time
97.LctlS1:
98	.long	0				# CT0 contents
99
100#
101# Subroutine to synchronously issue a service call.
102#
103# Parameters:
104#   R2	= command word
105#   R3	= sccb address
106#
107# Returns:
108#   R2	= 0 on success, 1 on failure
109#   R3	= sccb response code if R2 = 0
110#
111
112_sclp_servc:
113	stm	%r6,%r15,24(%r15)		# save registers
114	ahi	%r15,-96			# create stack frame
115	lr	%r6,%r2				# save command word
116	lr	%r7,%r3				# save sccb address
117.LretryS2:
118	lhi	%r2,1				# error return code
119	.insn	rre,0xb2200000,%r6,%r7		# servc
120	brc	1,.LendS2			# exit if not operational
121	brc	8,.LnotbusyS2			# go on if not busy
122	sr	%r2,%r2				# wait until no longer busy
123	bras	%r14,_sclp_wait_int
124	j	.LretryS2			# retry
125.LnotbusyS2:
126	sr	%r2,%r2				# wait until result
127	bras	%r14,_sclp_wait_int
128	sr	%r2,%r2
129	lh	%r3,6(%r7)
130.LendS2:
131	lm	%r6,%r15,120(%r15)		# restore registers
132	br	%r14
133
134#
135# Subroutine to set up the SCLP interface.
136#
137# Parameters:
138#   R2	= 0 to activate, non-zero to deactivate
139#
140# Returns:
141#   R2	= 0 on success, non-zero on failure
142#
143
144_sclp_setup:
145	stm	%r6,%r15,24(%r15)		# save registers
146	ahi	%r15,-96			# create stack frame
147	basr	%r13,0				# get base register
148.LbaseS3:
149	l	%r6,.LsccbS0-.LbaseS3(%r13)	# prepare init mask sccb
150	mvc	0(.LinitendS3-.LinitsccbS3,%r6),.LinitsccbS3-.LbaseS3(%r13)
151	ltr	%r2,%r2				# initialization?
152	jz	.LdoinitS3			# go ahead
153	# clear masks
154	xc	.LinitmaskS3-.LinitsccbS3(8,%r6),.LinitmaskS3-.LinitsccbS3(%r6)
155.LdoinitS3:
156	l	%r2,.LwritemaskS3-.LbaseS3(%r13)# get command word
157	lr	%r3,%r6				# get sccb address
158	bras	%r14,_sclp_servc		# issue service call
159	ltr	%r2,%r2				# servc successful?
160	jnz	.LerrorS3
161	chi	%r3,0x20			# write mask successful?
162	jne	.LerrorS3
163	# check masks
164	la	%r2,.LinitmaskS3-.LinitsccbS3(%r6)
165	l	%r1,0(%r2)			# receive mask ok?
166	n	%r1,12(%r2)
167	cl	%r1,0(%r2)
168	jne	.LerrorS3
169	l	%r1,4(%r2)			# send mask ok?
170	n	%r1,8(%r2)
171	cl	%r1,4(%r2)
172	sr	%r2,%r2
173	je	.LendS3
174.LerrorS3:
175	lhi	%r2,1				# error return code
176.LendS3:
177	lm	%r6,%r15,120(%r15)		# restore registers
178	br	%r14
179.LwritemaskS3:
180	.long	0x00780005			# SCLP command for write mask
181.LinitsccbS3:
182	.word	.LinitendS3-.LinitsccbS3
183	.byte	0,0,0,0
184	.word	0
185	.word	0
186	.word	4
187.LinitmaskS3:
188	.long	0x80000000
189	.long	0x40000000
190	.long	0
191	.long	0
192.LinitendS3:
193
194#
195# Subroutine which prints a given text to the SCLP console.
196#
197# Parameters:
198#   R2	= address of nil-terminated ASCII text
199#
200# Returns:
201#   R2	= 0 on success, 1 on failure
202#
203
204_sclp_print:
205	stm	%r6,%r15,24(%r15)		# save registers
206	ahi	%r15,-96			# create stack frame
207	basr	%r13,0				# get base register
208.LbaseS4:
209	l	%r8,.LsccbS0-.LbaseS4(%r13)	# prepare write data sccb
210	mvc	0(.LmtoS4-.LwritesccbS4,%r8),.LwritesccbS4-.LbaseS4(%r13)
211	la	%r7,.LmtoS4-.LwritesccbS4(%r8)	# current mto addr
212	sr	%r0,%r0
213	l	%r10,.Lascebc-.LbaseS4(%r13)	# address of translation table
214.LinitmtoS4:
215	# initialize mto
216	mvc	0(.LmtoendS4-.LmtoS4,%r7),.LmtoS4-.LbaseS4(%r13)
217	lhi	%r6,.LmtoendS4-.LmtoS4		# current mto length
218.LloopS4:
219	ic	%r0,0(%r2)			# get character
220	ahi	%r2,1
221	ltr	%r0,%r0				# end of string?
222	jz	.LfinalizemtoS4
223	chi	%r0,0x0a			# end of line (NL)?
224	jz	.LfinalizemtoS4
225	stc	%r0,0(%r6,%r7)			# copy to mto
226	la	%r11,0(%r6,%r7)
227	tr	0(1,%r11),0(%r10)		# translate to EBCDIC
228	ahi	%r6,1
229	j	.LloopS4
230.LfinalizemtoS4:
231	sth	%r6,0(%r7)			# update mto length
232	lh	%r9,.LmdbS4-.LwritesccbS4(%r8)	# update mdb length
233	ar	%r9,%r6
234	sth	%r9,.LmdbS4-.LwritesccbS4(%r8)
235	lh	%r9,.LevbufS4-.LwritesccbS4(%r8)# update evbuf length
236	ar	%r9,%r6
237	sth	%r9,.LevbufS4-.LwritesccbS4(%r8)
238	lh	%r9,0(%r8)			# update sccb length
239	ar	%r9,%r6
240	sth	%r9,0(%r8)
241	ar	%r7,%r6				# update current mto address
242	ltr	%r0,%r0				# more characters?
243	jnz	.LinitmtoS4
244	l	%r2,.LwritedataS4-.LbaseS4(%r13)# write data
245	lr	%r3,%r8
246	bras	%r14,_sclp_servc
247	ltr	%r2,%r2				# servc successful?
248	jnz	.LendS4
249	chi	%r3,0x20			# write data successful?
250	je	.LendS4
251	lhi	%r2,1				# error return code
252.LendS4:
253	lm	%r6,%r15,120(%r15)		# restore registers
254	br	%r14
255
256#
257# Function which prints a given text to the SCLP console.
258#
259# Parameters:
260#   R2	= address of nil-terminated ASCII text
261#
262# Returns:
263#   R2	= 0 on success, 1 on failure
264#
265
266ENTRY(_sclp_print_early)
267	stm	%r6,%r15,24(%r15)		# save registers
268	ahi	%r15,-96			# create stack frame
269	tm	LC_AR_MODE_ID,1
270	jno	.Lesa2
271	ahi	%r15,-80
272	stmh	%r6,%r15,96(%r15)		# store upper register halves
273	basr	%r13,0
274	lmh	%r0,%r15,.Lzeroes-.(%r13)	# clear upper register halves
275.Lesa2:
276	lr	%r10,%r2			# save string pointer
277	lhi	%r2,0
278	bras	%r14,_sclp_setup		# enable console
279	ltr	%r2,%r2
280	jnz	.LendS5
281	lr	%r2,%r10
282	bras	%r14,_sclp_print		# print string
283	ltr	%r2,%r2
284	jnz	.LendS5
285	lhi	%r2,1
286	bras	%r14,_sclp_setup		# disable console
287.LendS5:
288	tm	LC_AR_MODE_ID,1
289	jno	.Lesa3
290	lgfr	%r2,%r2				# sign extend return value
291	lmh	%r6,%r15,96(%r15)		# restore upper register halves
292	ahi	%r15,80
293.Lesa3:
294	lm	%r6,%r15,120(%r15)		# restore registers
295	br	%r14
296.Lzeroes:
297	.fill	64,4,0
298
299.LwritedataS4:
300	.long	0x00760005			# SCLP command for write data
301.LwritesccbS4:
302	# sccb
303	.word	.LmtoS4-.LwritesccbS4
304	.byte	0
305	.byte	0,0,0
306	.word	0
307
308	# evbuf
309.LevbufS4:
310	.word	.LmtoS4-.LevbufS4
311	.byte	0x02
312	.byte	0
313	.word	0
314
315.LmdbS4:
316	# mdb
317	.word	.LmtoS4-.LmdbS4
318	.word	1
319	.long	0xd4c4c240
320	.long	1
321
322	# go
323.LgoS4:
324	.word	.LmtoS4-.LgoS4
325	.word	1
326	.long	0
327	.byte	0,0,0,0,0,0,0,0
328	.byte	0,0,0
329	.byte	0
330	.byte	0,0,0,0,0,0,0
331	.byte	0
332	.word	0
333	.byte	0,0,0,0,0,0,0,0,0,0
334	.byte	0,0,0,0,0,0,0,0
335	.byte	0,0,0,0,0,0,0,0
336
337.LmtoS4:
338	.word	.LmtoendS4-.LmtoS4
339	.word	4
340	.word	0x1000
341	.byte	0
342	.byte	0,0,0
343.LmtoendS4:
344
345	# Global constants
346.LsccbS0:
347	.long	_sclp_work_area
348.Lascebc:
349	.long	_ascebc
350
351.section .data,"aw",@progbits
352	.balign 4096
353_sclp_work_area:
354	.fill	4096
355.previous
356