xref: /openbmc/linux/drivers/block/swim_asm.S (revision 8852ecd97488249ca7fe2c0d3eb44cae95886881)
1*8852ecd9SLaurent Vivier/*
2*8852ecd9SLaurent Vivier * low-level functions for the SWIM floppy controller
3*8852ecd9SLaurent Vivier *
4*8852ecd9SLaurent Vivier * needs assembly language because is very timing dependent
5*8852ecd9SLaurent Vivier * this controller exists only on macintosh 680x0 based
6*8852ecd9SLaurent Vivier *
7*8852ecd9SLaurent Vivier * Copyright (C) 2004,2008 Laurent Vivier <Laurent@lvivier.info>
8*8852ecd9SLaurent Vivier *
9*8852ecd9SLaurent Vivier * based on Alastair Bridgewater SWIM analysis, 2001
10*8852ecd9SLaurent Vivier * based on netBSD IWM driver (c) 1997, 1998 Hauke Fath.
11*8852ecd9SLaurent Vivier *
12*8852ecd9SLaurent Vivier * This program is free software; you can redistribute it and/or
13*8852ecd9SLaurent Vivier * modify it under the terms of the GNU General Public License
14*8852ecd9SLaurent Vivier * as published by the Free Software Foundation; either version
15*8852ecd9SLaurent Vivier * 2 of the License, or (at your option) any later version.
16*8852ecd9SLaurent Vivier *
17*8852ecd9SLaurent Vivier * 2004-08-21 (lv) - Initial implementation
18*8852ecd9SLaurent Vivier * 2008-11-05 (lv) - add get_swim_mode
19*8852ecd9SLaurent Vivier */
20*8852ecd9SLaurent Vivier
21*8852ecd9SLaurent Vivier	.equ	write_data,	0x0000
22*8852ecd9SLaurent Vivier	.equ	write_mark,	0x0200
23*8852ecd9SLaurent Vivier	.equ	write_CRC,	0x0400
24*8852ecd9SLaurent Vivier	.equ	write_parameter,0x0600
25*8852ecd9SLaurent Vivier	.equ	write_phase,	0x0800
26*8852ecd9SLaurent Vivier	.equ	write_setup,	0x0a00
27*8852ecd9SLaurent Vivier	.equ	write_mode0,	0x0c00
28*8852ecd9SLaurent Vivier	.equ	write_mode1,	0x0e00
29*8852ecd9SLaurent Vivier	.equ	read_data,	0x1000
30*8852ecd9SLaurent Vivier	.equ	read_mark,	0x1200
31*8852ecd9SLaurent Vivier	.equ	read_error,	0x1400
32*8852ecd9SLaurent Vivier	.equ	read_parameter,	0x1600
33*8852ecd9SLaurent Vivier	.equ	read_phase,	0x1800
34*8852ecd9SLaurent Vivier	.equ	read_setup,	0x1a00
35*8852ecd9SLaurent Vivier	.equ	read_status,	0x1c00
36*8852ecd9SLaurent Vivier	.equ	read_handshake,	0x1e00
37*8852ecd9SLaurent Vivier
38*8852ecd9SLaurent Vivier	.equ	o_side, 0
39*8852ecd9SLaurent Vivier	.equ	o_track, 1
40*8852ecd9SLaurent Vivier	.equ	o_sector, 2
41*8852ecd9SLaurent Vivier	.equ	o_size, 3
42*8852ecd9SLaurent Vivier	.equ	o_crc0, 4
43*8852ecd9SLaurent Vivier	.equ	o_crc1, 5
44*8852ecd9SLaurent Vivier
45*8852ecd9SLaurent Vivier	.equ	seek_time, 30000
46*8852ecd9SLaurent Vivier	.equ	max_retry, 40
47*8852ecd9SLaurent Vivier	.equ	sector_size, 512
48*8852ecd9SLaurent Vivier
49*8852ecd9SLaurent Vivier	.global swim_read_sector_header
50*8852ecd9SLaurent Vivierswim_read_sector_header:
51*8852ecd9SLaurent Vivier	link	%a6, #0
52*8852ecd9SLaurent Vivier	moveml	%d1-%d5/%a0-%a4,%sp@-
53*8852ecd9SLaurent Vivier	movel	%a6@(0x0c), %a4
54*8852ecd9SLaurent Vivier	bsr	mfm_read_addrmark
55*8852ecd9SLaurent Vivier	moveml	%sp@+, %d1-%d5/%a0-%a4
56*8852ecd9SLaurent Vivier	unlk	%a6
57*8852ecd9SLaurent Vivier	rts
58*8852ecd9SLaurent Vivier
59*8852ecd9SLaurent Viviersector_address_mark:
60*8852ecd9SLaurent Vivier	.byte	0xa1, 0xa1, 0xa1, 0xfe
61*8852ecd9SLaurent Viviersector_data_mark:
62*8852ecd9SLaurent Vivier	.byte	0xa1, 0xa1, 0xa1, 0xfb
63*8852ecd9SLaurent Vivier
64*8852ecd9SLaurent Viviermfm_read_addrmark:
65*8852ecd9SLaurent Vivier	movel	%a6@(0x08), %a3
66*8852ecd9SLaurent Vivier	lea	%a3@(read_handshake), %a2
67*8852ecd9SLaurent Vivier	lea	%a3@(read_mark), %a3
68*8852ecd9SLaurent Vivier	moveq	#-1, %d0
69*8852ecd9SLaurent Vivier	movew	#seek_time, %d2
70*8852ecd9SLaurent Vivier
71*8852ecd9SLaurent Vivierwait_header_init:
72*8852ecd9SLaurent Vivier	tstb	%a3@(read_error - read_mark)
73*8852ecd9SLaurent Vivier	moveb	#0x18, %a3@(write_mode0 - read_mark)
74*8852ecd9SLaurent Vivier	moveb	#0x01, %a3@(write_mode1 - read_mark)
75*8852ecd9SLaurent Vivier	moveb	#0x01, %a3@(write_mode0 - read_mark)
76*8852ecd9SLaurent Vivier	tstb	%a3@(read_error - read_mark)
77*8852ecd9SLaurent Vivier	moveb	#0x08, %a3@(write_mode1 - read_mark)
78*8852ecd9SLaurent Vivier
79*8852ecd9SLaurent Vivier	lea	sector_address_mark, %a0
80*8852ecd9SLaurent Vivier	moveq	#3, %d1
81*8852ecd9SLaurent Vivier
82*8852ecd9SLaurent Vivierwait_addr_mark_byte:
83*8852ecd9SLaurent Vivier
84*8852ecd9SLaurent Vivier	tstb	%a2@
85*8852ecd9SLaurent Vivier	dbmi	%d2, wait_addr_mark_byte
86*8852ecd9SLaurent Vivier	bpl	header_exit
87*8852ecd9SLaurent Vivier
88*8852ecd9SLaurent Vivier	moveb	%a3@, %d3
89*8852ecd9SLaurent Vivier	cmpb	%a0@+, %d3
90*8852ecd9SLaurent Vivier	dbne	%d1, wait_addr_mark_byte
91*8852ecd9SLaurent Vivier	bne	wait_header_init
92*8852ecd9SLaurent Vivier
93*8852ecd9SLaurent Vivier	moveq	#max_retry, %d2
94*8852ecd9SLaurent Vivier
95*8852ecd9SLaurent Vivieramark0:	tstb	%a2@
96*8852ecd9SLaurent Vivier	dbmi	%d2, amark0
97*8852ecd9SLaurent Vivier	bpl	signal_nonyb
98*8852ecd9SLaurent Vivier
99*8852ecd9SLaurent Vivier	moveb	%a3@, %a4@(o_track)
100*8852ecd9SLaurent Vivier
101*8852ecd9SLaurent Vivier	moveq	#max_retry, %d2
102*8852ecd9SLaurent Vivier
103*8852ecd9SLaurent Vivieramark1:	tstb	%a2@
104*8852ecd9SLaurent Vivier	dbmi	%d2, amark1
105*8852ecd9SLaurent Vivier	bpl	signal_nonyb
106*8852ecd9SLaurent Vivier
107*8852ecd9SLaurent Vivier	moveb	%a3@, %a4@(o_side)
108*8852ecd9SLaurent Vivier
109*8852ecd9SLaurent Vivier	moveq	#max_retry, %d2
110*8852ecd9SLaurent Vivier
111*8852ecd9SLaurent Vivieramark2:	tstb	%a2@
112*8852ecd9SLaurent Vivier	dbmi	%d2, amark2
113*8852ecd9SLaurent Vivier	bpl	signal_nonyb
114*8852ecd9SLaurent Vivier
115*8852ecd9SLaurent Vivier	moveb	%a3@, %a4@(o_sector)
116*8852ecd9SLaurent Vivier
117*8852ecd9SLaurent Vivier	moveq	#max_retry, %d2
118*8852ecd9SLaurent Vivier
119*8852ecd9SLaurent Vivieramark3:	tstb	%a2@
120*8852ecd9SLaurent Vivier	dbmi	%d2, amark3
121*8852ecd9SLaurent Vivier	bpl	signal_nonyb
122*8852ecd9SLaurent Vivier
123*8852ecd9SLaurent Vivier	moveb	%a3@, %a4@(o_size)
124*8852ecd9SLaurent Vivier
125*8852ecd9SLaurent Vivier	moveq	#max_retry, %d2
126*8852ecd9SLaurent Vivier
127*8852ecd9SLaurent Viviercrc0:	tstb	%a2@
128*8852ecd9SLaurent Vivier	dbmi	%d2, crc0
129*8852ecd9SLaurent Vivier	bpl	signal_nonyb
130*8852ecd9SLaurent Vivier
131*8852ecd9SLaurent Vivier	moveb	%a3@, %a4@(o_crc0)
132*8852ecd9SLaurent Vivier
133*8852ecd9SLaurent Vivier	moveq	#max_retry, %d2
134*8852ecd9SLaurent Vivier
135*8852ecd9SLaurent Viviercrc1:	tstb	%a2@
136*8852ecd9SLaurent Vivier	dbmi	%d2, crc1
137*8852ecd9SLaurent Vivier	bpl	signal_nonyb
138*8852ecd9SLaurent Vivier
139*8852ecd9SLaurent Vivier	moveb	%a3@, %a4@(o_crc1)
140*8852ecd9SLaurent Vivier
141*8852ecd9SLaurent Vivier	tstb	%a3@(read_error - read_mark)
142*8852ecd9SLaurent Vivier
143*8852ecd9SLaurent Vivierheader_exit:
144*8852ecd9SLaurent Vivier	moveq	#0, %d0
145*8852ecd9SLaurent Vivier	moveb	#0x18, %a3@(write_mode0 - read_mark)
146*8852ecd9SLaurent Vivier	rts
147*8852ecd9SLaurent Viviersignal_nonyb:
148*8852ecd9SLaurent Vivier	moveq	#-1, %d0
149*8852ecd9SLaurent Vivier	moveb	#0x18, %a3@(write_mode0 - read_mark)
150*8852ecd9SLaurent Vivier	rts
151*8852ecd9SLaurent Vivier
152*8852ecd9SLaurent Vivier	.global swim_read_sector_data
153*8852ecd9SLaurent Vivierswim_read_sector_data:
154*8852ecd9SLaurent Vivier	link	%a6, #0
155*8852ecd9SLaurent Vivier	moveml	%d1-%d5/%a0-%a5,%sp@-
156*8852ecd9SLaurent Vivier	movel	%a6@(0x0c), %a4
157*8852ecd9SLaurent Vivier	bsr	mfm_read_data
158*8852ecd9SLaurent Vivier	moveml	%sp@+, %d1-%d5/%a0-%a5
159*8852ecd9SLaurent Vivier	unlk	%a6
160*8852ecd9SLaurent Vivier	rts
161*8852ecd9SLaurent Vivier
162*8852ecd9SLaurent Viviermfm_read_data:
163*8852ecd9SLaurent Vivier	movel	%a6@(0x08), %a3
164*8852ecd9SLaurent Vivier	lea	%a3@(read_handshake), %a2
165*8852ecd9SLaurent Vivier	lea	%a3@(read_data), %a5
166*8852ecd9SLaurent Vivier	lea	%a3@(read_mark), %a3
167*8852ecd9SLaurent Vivier	movew	#seek_time, %d2
168*8852ecd9SLaurent Vivier
169*8852ecd9SLaurent Vivierwait_data_init:
170*8852ecd9SLaurent Vivier	tstb	%a3@(read_error - read_mark)
171*8852ecd9SLaurent Vivier	moveb	#0x18, %a3@(write_mode0 - read_mark)
172*8852ecd9SLaurent Vivier	moveb	#0x01, %a3@(write_mode1 - read_mark)
173*8852ecd9SLaurent Vivier	moveb	#0x01, %a3@(write_mode0 - read_mark)
174*8852ecd9SLaurent Vivier	tstb	%a3@(read_error - read_mark)
175*8852ecd9SLaurent Vivier	moveb	#0x08, %a3@(write_mode1 - read_mark)
176*8852ecd9SLaurent Vivier
177*8852ecd9SLaurent Vivier	lea	sector_data_mark, %a0
178*8852ecd9SLaurent Vivier	moveq	#3, %d1
179*8852ecd9SLaurent Vivier
180*8852ecd9SLaurent Vivier	/* wait data address mark */
181*8852ecd9SLaurent Vivier
182*8852ecd9SLaurent Vivierwait_data_mark_byte:
183*8852ecd9SLaurent Vivier
184*8852ecd9SLaurent Vivier	tstb	%a2@
185*8852ecd9SLaurent Vivier	dbmi	%d2, wait_data_mark_byte
186*8852ecd9SLaurent Vivier	bpl	data_exit
187*8852ecd9SLaurent Vivier
188*8852ecd9SLaurent Vivier	moveb	%a3@, %d3
189*8852ecd9SLaurent Vivier	cmpb	%a0@+, %d3
190*8852ecd9SLaurent Vivier	dbne	%d1, wait_data_mark_byte
191*8852ecd9SLaurent Vivier	bne	wait_data_init
192*8852ecd9SLaurent Vivier
193*8852ecd9SLaurent Vivier	/* read data */
194*8852ecd9SLaurent Vivier
195*8852ecd9SLaurent Vivier	tstb	%a3@(read_error - read_mark)
196*8852ecd9SLaurent Vivier
197*8852ecd9SLaurent Vivier	movel	#sector_size-1, %d4		/* sector size */
198*8852ecd9SLaurent Vivierread_new_data:
199*8852ecd9SLaurent Vivier	movew	#max_retry, %d2
200*8852ecd9SLaurent Vivierread_data_loop:
201*8852ecd9SLaurent Vivier	moveb	%a2@, %d5
202*8852ecd9SLaurent Vivier	andb	#0xc0, %d5
203*8852ecd9SLaurent Vivier	dbne	%d2, read_data_loop
204*8852ecd9SLaurent Vivier	beq	data_exit
205*8852ecd9SLaurent Vivier	moveb	%a5@, %a4@+
206*8852ecd9SLaurent Vivier	andb	#0x40, %d5
207*8852ecd9SLaurent Vivier	dbne	%d4, read_new_data
208*8852ecd9SLaurent Vivier	beq	exit_loop
209*8852ecd9SLaurent Vivier	moveb	%a5@, %a4@+
210*8852ecd9SLaurent Vivier	dbra	%d4, read_new_data
211*8852ecd9SLaurent Vivierexit_loop:
212*8852ecd9SLaurent Vivier
213*8852ecd9SLaurent Vivier	/* read CRC */
214*8852ecd9SLaurent Vivier
215*8852ecd9SLaurent Vivier	movew	#max_retry, %d2
216*8852ecd9SLaurent Vivierdata_crc0:
217*8852ecd9SLaurent Vivier
218*8852ecd9SLaurent Vivier	tstb	%a2@
219*8852ecd9SLaurent Vivier	dbmi	%d2, data_crc0
220*8852ecd9SLaurent Vivier	bpl	data_exit
221*8852ecd9SLaurent Vivier
222*8852ecd9SLaurent Vivier	moveb	%a3@, %d5
223*8852ecd9SLaurent Vivier
224*8852ecd9SLaurent Vivier	moveq	#max_retry, %d2
225*8852ecd9SLaurent Vivier
226*8852ecd9SLaurent Vivierdata_crc1:
227*8852ecd9SLaurent Vivier
228*8852ecd9SLaurent Vivier	tstb	%a2@
229*8852ecd9SLaurent Vivier	dbmi	%d2, data_crc1
230*8852ecd9SLaurent Vivier	bpl	data_exit
231*8852ecd9SLaurent Vivier
232*8852ecd9SLaurent Vivier	moveb	%a3@, %d5
233*8852ecd9SLaurent Vivier
234*8852ecd9SLaurent Vivier	tstb	%a3@(read_error - read_mark)
235*8852ecd9SLaurent Vivier
236*8852ecd9SLaurent Vivier	moveb	#0x18, %a3@(write_mode0 - read_mark)
237*8852ecd9SLaurent Vivier
238*8852ecd9SLaurent Vivier	/* return number of bytes read */
239*8852ecd9SLaurent Vivier
240*8852ecd9SLaurent Vivier	movel	#sector_size, %d0
241*8852ecd9SLaurent Vivier	addw	#1, %d4
242*8852ecd9SLaurent Vivier	subl	%d4, %d0
243*8852ecd9SLaurent Vivier	rts
244*8852ecd9SLaurent Vivierdata_exit:
245*8852ecd9SLaurent Vivier	moveb	#0x18, %a3@(write_mode0 - read_mark)
246*8852ecd9SLaurent Vivier	moveq	#-1, %d0
247*8852ecd9SLaurent Vivier	rts
248