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