xref: /linux/drivers/block/swim_asm.S (revision 2874c5fd)
1*2874c5fdSThomas Gleixner/* SPDX-License-Identifier: GPL-2.0-or-later */
28852ecd9SLaurent Vivier/*
38852ecd9SLaurent Vivier * low-level functions for the SWIM floppy controller
48852ecd9SLaurent Vivier *
58852ecd9SLaurent Vivier * needs assembly language because is very timing dependent
68852ecd9SLaurent Vivier * this controller exists only on macintosh 680x0 based
78852ecd9SLaurent Vivier *
88852ecd9SLaurent Vivier * Copyright (C) 2004,2008 Laurent Vivier <Laurent@lvivier.info>
98852ecd9SLaurent Vivier *
108852ecd9SLaurent Vivier * based on Alastair Bridgewater SWIM analysis, 2001
118852ecd9SLaurent Vivier * based on netBSD IWM driver (c) 1997, 1998 Hauke Fath.
128852ecd9SLaurent Vivier *
138852ecd9SLaurent Vivier * 2004-08-21 (lv) - Initial implementation
148852ecd9SLaurent Vivier * 2008-11-05 (lv) - add get_swim_mode
158852ecd9SLaurent Vivier */
168852ecd9SLaurent Vivier
178852ecd9SLaurent Vivier	.equ	write_data,	0x0000
188852ecd9SLaurent Vivier	.equ	write_mark,	0x0200
198852ecd9SLaurent Vivier	.equ	write_CRC,	0x0400
208852ecd9SLaurent Vivier	.equ	write_parameter,0x0600
218852ecd9SLaurent Vivier	.equ	write_phase,	0x0800
228852ecd9SLaurent Vivier	.equ	write_setup,	0x0a00
238852ecd9SLaurent Vivier	.equ	write_mode0,	0x0c00
248852ecd9SLaurent Vivier	.equ	write_mode1,	0x0e00
258852ecd9SLaurent Vivier	.equ	read_data,	0x1000
268852ecd9SLaurent Vivier	.equ	read_mark,	0x1200
278852ecd9SLaurent Vivier	.equ	read_error,	0x1400
288852ecd9SLaurent Vivier	.equ	read_parameter,	0x1600
298852ecd9SLaurent Vivier	.equ	read_phase,	0x1800
308852ecd9SLaurent Vivier	.equ	read_setup,	0x1a00
318852ecd9SLaurent Vivier	.equ	read_status,	0x1c00
328852ecd9SLaurent Vivier	.equ	read_handshake,	0x1e00
338852ecd9SLaurent Vivier
348852ecd9SLaurent Vivier	.equ	o_side, 0
358852ecd9SLaurent Vivier	.equ	o_track, 1
368852ecd9SLaurent Vivier	.equ	o_sector, 2
378852ecd9SLaurent Vivier	.equ	o_size, 3
388852ecd9SLaurent Vivier	.equ	o_crc0, 4
398852ecd9SLaurent Vivier	.equ	o_crc1, 5
408852ecd9SLaurent Vivier
418852ecd9SLaurent Vivier	.equ	seek_time, 30000
428852ecd9SLaurent Vivier	.equ	max_retry, 40
438852ecd9SLaurent Vivier	.equ	sector_size, 512
448852ecd9SLaurent Vivier
458852ecd9SLaurent Vivier	.global swim_read_sector_header
468852ecd9SLaurent Vivierswim_read_sector_header:
478852ecd9SLaurent Vivier	link	%a6, #0
488852ecd9SLaurent Vivier	moveml	%d1-%d5/%a0-%a4,%sp@-
498852ecd9SLaurent Vivier	movel	%a6@(0x0c), %a4
508852ecd9SLaurent Vivier	bsr	mfm_read_addrmark
518852ecd9SLaurent Vivier	moveml	%sp@+, %d1-%d5/%a0-%a4
528852ecd9SLaurent Vivier	unlk	%a6
538852ecd9SLaurent Vivier	rts
548852ecd9SLaurent Vivier
558852ecd9SLaurent Viviersector_address_mark:
568852ecd9SLaurent Vivier	.byte	0xa1, 0xa1, 0xa1, 0xfe
578852ecd9SLaurent Viviersector_data_mark:
588852ecd9SLaurent Vivier	.byte	0xa1, 0xa1, 0xa1, 0xfb
598852ecd9SLaurent Vivier
608852ecd9SLaurent Viviermfm_read_addrmark:
618852ecd9SLaurent Vivier	movel	%a6@(0x08), %a3
628852ecd9SLaurent Vivier	lea	%a3@(read_handshake), %a2
638852ecd9SLaurent Vivier	lea	%a3@(read_mark), %a3
648852ecd9SLaurent Vivier	moveq	#-1, %d0
658852ecd9SLaurent Vivier	movew	#seek_time, %d2
668852ecd9SLaurent Vivier
678852ecd9SLaurent Vivierwait_header_init:
688852ecd9SLaurent Vivier	tstb	%a3@(read_error - read_mark)
698852ecd9SLaurent Vivier	moveb	#0x18, %a3@(write_mode0 - read_mark)
708852ecd9SLaurent Vivier	moveb	#0x01, %a3@(write_mode1 - read_mark)
718852ecd9SLaurent Vivier	moveb	#0x01, %a3@(write_mode0 - read_mark)
728852ecd9SLaurent Vivier	tstb	%a3@(read_error - read_mark)
738852ecd9SLaurent Vivier	moveb	#0x08, %a3@(write_mode1 - read_mark)
748852ecd9SLaurent Vivier
758852ecd9SLaurent Vivier	lea	sector_address_mark, %a0
768852ecd9SLaurent Vivier	moveq	#3, %d1
778852ecd9SLaurent Vivier
788852ecd9SLaurent Vivierwait_addr_mark_byte:
798852ecd9SLaurent Vivier
808852ecd9SLaurent Vivier	tstb	%a2@
818852ecd9SLaurent Vivier	dbmi	%d2, wait_addr_mark_byte
828852ecd9SLaurent Vivier	bpl	header_exit
838852ecd9SLaurent Vivier
848852ecd9SLaurent Vivier	moveb	%a3@, %d3
858852ecd9SLaurent Vivier	cmpb	%a0@+, %d3
868852ecd9SLaurent Vivier	dbne	%d1, wait_addr_mark_byte
878852ecd9SLaurent Vivier	bne	wait_header_init
888852ecd9SLaurent Vivier
898852ecd9SLaurent Vivier	moveq	#max_retry, %d2
908852ecd9SLaurent Vivier
918852ecd9SLaurent Vivieramark0:	tstb	%a2@
928852ecd9SLaurent Vivier	dbmi	%d2, amark0
938852ecd9SLaurent Vivier	bpl	signal_nonyb
948852ecd9SLaurent Vivier
958852ecd9SLaurent Vivier	moveb	%a3@, %a4@(o_track)
968852ecd9SLaurent Vivier
978852ecd9SLaurent Vivier	moveq	#max_retry, %d2
988852ecd9SLaurent Vivier
998852ecd9SLaurent Vivieramark1:	tstb	%a2@
1008852ecd9SLaurent Vivier	dbmi	%d2, amark1
1018852ecd9SLaurent Vivier	bpl	signal_nonyb
1028852ecd9SLaurent Vivier
1038852ecd9SLaurent Vivier	moveb	%a3@, %a4@(o_side)
1048852ecd9SLaurent Vivier
1058852ecd9SLaurent Vivier	moveq	#max_retry, %d2
1068852ecd9SLaurent Vivier
1078852ecd9SLaurent Vivieramark2:	tstb	%a2@
1088852ecd9SLaurent Vivier	dbmi	%d2, amark2
1098852ecd9SLaurent Vivier	bpl	signal_nonyb
1108852ecd9SLaurent Vivier
1118852ecd9SLaurent Vivier	moveb	%a3@, %a4@(o_sector)
1128852ecd9SLaurent Vivier
1138852ecd9SLaurent Vivier	moveq	#max_retry, %d2
1148852ecd9SLaurent Vivier
1158852ecd9SLaurent Vivieramark3:	tstb	%a2@
1168852ecd9SLaurent Vivier	dbmi	%d2, amark3
1178852ecd9SLaurent Vivier	bpl	signal_nonyb
1188852ecd9SLaurent Vivier
1198852ecd9SLaurent Vivier	moveb	%a3@, %a4@(o_size)
1208852ecd9SLaurent Vivier
1218852ecd9SLaurent Vivier	moveq	#max_retry, %d2
1228852ecd9SLaurent Vivier
1238852ecd9SLaurent Viviercrc0:	tstb	%a2@
1248852ecd9SLaurent Vivier	dbmi	%d2, crc0
1258852ecd9SLaurent Vivier	bpl	signal_nonyb
1268852ecd9SLaurent Vivier
1278852ecd9SLaurent Vivier	moveb	%a3@, %a4@(o_crc0)
1288852ecd9SLaurent Vivier
1298852ecd9SLaurent Vivier	moveq	#max_retry, %d2
1308852ecd9SLaurent Vivier
1318852ecd9SLaurent Viviercrc1:	tstb	%a2@
1328852ecd9SLaurent Vivier	dbmi	%d2, crc1
1338852ecd9SLaurent Vivier	bpl	signal_nonyb
1348852ecd9SLaurent Vivier
1358852ecd9SLaurent Vivier	moveb	%a3@, %a4@(o_crc1)
1368852ecd9SLaurent Vivier
1378852ecd9SLaurent Vivier	tstb	%a3@(read_error - read_mark)
1388852ecd9SLaurent Vivier
1398852ecd9SLaurent Vivierheader_exit:
1408852ecd9SLaurent Vivier	moveq	#0, %d0
1418852ecd9SLaurent Vivier	moveb	#0x18, %a3@(write_mode0 - read_mark)
1428852ecd9SLaurent Vivier	rts
1438852ecd9SLaurent Viviersignal_nonyb:
1448852ecd9SLaurent Vivier	moveq	#-1, %d0
1458852ecd9SLaurent Vivier	moveb	#0x18, %a3@(write_mode0 - read_mark)
1468852ecd9SLaurent Vivier	rts
1478852ecd9SLaurent Vivier
1488852ecd9SLaurent Vivier	.global swim_read_sector_data
1498852ecd9SLaurent Vivierswim_read_sector_data:
1508852ecd9SLaurent Vivier	link	%a6, #0
1518852ecd9SLaurent Vivier	moveml	%d1-%d5/%a0-%a5,%sp@-
1528852ecd9SLaurent Vivier	movel	%a6@(0x0c), %a4
1538852ecd9SLaurent Vivier	bsr	mfm_read_data
1548852ecd9SLaurent Vivier	moveml	%sp@+, %d1-%d5/%a0-%a5
1558852ecd9SLaurent Vivier	unlk	%a6
1568852ecd9SLaurent Vivier	rts
1578852ecd9SLaurent Vivier
1588852ecd9SLaurent Viviermfm_read_data:
1598852ecd9SLaurent Vivier	movel	%a6@(0x08), %a3
1608852ecd9SLaurent Vivier	lea	%a3@(read_handshake), %a2
1618852ecd9SLaurent Vivier	lea	%a3@(read_data), %a5
1628852ecd9SLaurent Vivier	lea	%a3@(read_mark), %a3
1638852ecd9SLaurent Vivier	movew	#seek_time, %d2
1648852ecd9SLaurent Vivier
1658852ecd9SLaurent Vivierwait_data_init:
1668852ecd9SLaurent Vivier	tstb	%a3@(read_error - read_mark)
1678852ecd9SLaurent Vivier	moveb	#0x18, %a3@(write_mode0 - read_mark)
1688852ecd9SLaurent Vivier	moveb	#0x01, %a3@(write_mode1 - read_mark)
1698852ecd9SLaurent Vivier	moveb	#0x01, %a3@(write_mode0 - read_mark)
1708852ecd9SLaurent Vivier	tstb	%a3@(read_error - read_mark)
1718852ecd9SLaurent Vivier	moveb	#0x08, %a3@(write_mode1 - read_mark)
1728852ecd9SLaurent Vivier
1738852ecd9SLaurent Vivier	lea	sector_data_mark, %a0
1748852ecd9SLaurent Vivier	moveq	#3, %d1
1758852ecd9SLaurent Vivier
1768852ecd9SLaurent Vivier	/* wait data address mark */
1778852ecd9SLaurent Vivier
1788852ecd9SLaurent Vivierwait_data_mark_byte:
1798852ecd9SLaurent Vivier
1808852ecd9SLaurent Vivier	tstb	%a2@
1818852ecd9SLaurent Vivier	dbmi	%d2, wait_data_mark_byte
1828852ecd9SLaurent Vivier	bpl	data_exit
1838852ecd9SLaurent Vivier
1848852ecd9SLaurent Vivier	moveb	%a3@, %d3
1858852ecd9SLaurent Vivier	cmpb	%a0@+, %d3
1868852ecd9SLaurent Vivier	dbne	%d1, wait_data_mark_byte
1878852ecd9SLaurent Vivier	bne	wait_data_init
1888852ecd9SLaurent Vivier
1898852ecd9SLaurent Vivier	/* read data */
1908852ecd9SLaurent Vivier
1918852ecd9SLaurent Vivier	tstb	%a3@(read_error - read_mark)
1928852ecd9SLaurent Vivier
1938852ecd9SLaurent Vivier	movel	#sector_size-1, %d4		/* sector size */
1948852ecd9SLaurent Vivierread_new_data:
1958852ecd9SLaurent Vivier	movew	#max_retry, %d2
1968852ecd9SLaurent Vivierread_data_loop:
1978852ecd9SLaurent Vivier	moveb	%a2@, %d5
1988852ecd9SLaurent Vivier	andb	#0xc0, %d5
1998852ecd9SLaurent Vivier	dbne	%d2, read_data_loop
2008852ecd9SLaurent Vivier	beq	data_exit
2018852ecd9SLaurent Vivier	moveb	%a5@, %a4@+
2028852ecd9SLaurent Vivier	andb	#0x40, %d5
2038852ecd9SLaurent Vivier	dbne	%d4, read_new_data
2048852ecd9SLaurent Vivier	beq	exit_loop
2058852ecd9SLaurent Vivier	moveb	%a5@, %a4@+
2068852ecd9SLaurent Vivier	dbra	%d4, read_new_data
2078852ecd9SLaurent Vivierexit_loop:
2088852ecd9SLaurent Vivier
2098852ecd9SLaurent Vivier	/* read CRC */
2108852ecd9SLaurent Vivier
2118852ecd9SLaurent Vivier	movew	#max_retry, %d2
2128852ecd9SLaurent Vivierdata_crc0:
2138852ecd9SLaurent Vivier
2148852ecd9SLaurent Vivier	tstb	%a2@
2158852ecd9SLaurent Vivier	dbmi	%d2, data_crc0
2168852ecd9SLaurent Vivier	bpl	data_exit
2178852ecd9SLaurent Vivier
2188852ecd9SLaurent Vivier	moveb	%a3@, %d5
2198852ecd9SLaurent Vivier
2208852ecd9SLaurent Vivier	moveq	#max_retry, %d2
2218852ecd9SLaurent Vivier
2228852ecd9SLaurent Vivierdata_crc1:
2238852ecd9SLaurent Vivier
2248852ecd9SLaurent Vivier	tstb	%a2@
2258852ecd9SLaurent Vivier	dbmi	%d2, data_crc1
2268852ecd9SLaurent Vivier	bpl	data_exit
2278852ecd9SLaurent Vivier
2288852ecd9SLaurent Vivier	moveb	%a3@, %d5
2298852ecd9SLaurent Vivier
2308852ecd9SLaurent Vivier	tstb	%a3@(read_error - read_mark)
2318852ecd9SLaurent Vivier
2328852ecd9SLaurent Vivier	moveb	#0x18, %a3@(write_mode0 - read_mark)
2338852ecd9SLaurent Vivier
2348852ecd9SLaurent Vivier	/* return number of bytes read */
2358852ecd9SLaurent Vivier
2368852ecd9SLaurent Vivier	movel	#sector_size, %d0
2378852ecd9SLaurent Vivier	addw	#1, %d4
2388852ecd9SLaurent Vivier	subl	%d4, %d0
2398852ecd9SLaurent Vivier	rts
2408852ecd9SLaurent Vivierdata_exit:
2418852ecd9SLaurent Vivier	moveb	#0x18, %a3@(write_mode0 - read_mark)
2428852ecd9SLaurent Vivier	moveq	#-1, %d0
2438852ecd9SLaurent Vivier	rts
244