xref: /netbsd-src/sys/arch/amiga/dev/wdc_acafh.c (revision 23e63c4b5cecc703250c97faac1ad970f4954821)
1*23e63c4bSthorpej /*	$NetBSD: wdc_acafh.c,v 1.7 2023/12/20 00:40:42 thorpej Exp $ */
2f7bd7656Srkujawa 
3f7bd7656Srkujawa /*-
4f7bd7656Srkujawa  * Copyright (c) 2000, 2003, 2013 The NetBSD Foundation, Inc.
5f7bd7656Srkujawa  * All rights reserved.
6f7bd7656Srkujawa  *
7f7bd7656Srkujawa  * This code is derived from software contributed to The NetBSD Foundation
8f7bd7656Srkujawa  * by Radoslaw Kujawa.
9f7bd7656Srkujawa  *
10f7bd7656Srkujawa  * This code is derived from software contributed to The NetBSD Foundation
11f7bd7656Srkujawa  * by Michael L. Hitch.
12f7bd7656Srkujawa  *
13f7bd7656Srkujawa  * Redistribution and use in source and binary forms, with or without
14f7bd7656Srkujawa  * modification, are permitted provided that the following conditions
15f7bd7656Srkujawa  * are met:
16f7bd7656Srkujawa  * 1. Redistributions of source code must retain the above copyright
17f7bd7656Srkujawa  *    notice, this list of conditions and the following disclaimer.
18f7bd7656Srkujawa  * 2. Redistributions in binary form must reproduce the above copyright
19f7bd7656Srkujawa  *    notice, this list of conditions and the following disclaimer in the
20f7bd7656Srkujawa  *    documentation and/or other materials provided with the distribution.
21f7bd7656Srkujawa  *
22f7bd7656Srkujawa  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23f7bd7656Srkujawa  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24f7bd7656Srkujawa  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25f7bd7656Srkujawa  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26f7bd7656Srkujawa  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27f7bd7656Srkujawa  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28f7bd7656Srkujawa  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29f7bd7656Srkujawa  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30f7bd7656Srkujawa  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31f7bd7656Srkujawa  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32f7bd7656Srkujawa  * POSSIBILITY OF SUCH DAMAGE.
33f7bd7656Srkujawa  */
34f7bd7656Srkujawa 
357598b3c2Srkujawa /*
367598b3c2Srkujawa  * ACA500 CF (IDE) controller driver.
377598b3c2Srkujawa  *
387598b3c2Srkujawa  * The hardware emulates original A600/A1200 Gayle interface. However, it has
397598b3c2Srkujawa  * two channels, second channel placed instead of ctl registers (so software
407598b3c2Srkujawa  * reset of the bus is not possible, duh). There are no slave devices.
417598b3c2Srkujawa  */
427598b3c2Srkujawa 
43f7bd7656Srkujawa #include <sys/cdefs.h>
44*23e63c4bSthorpej __KERNEL_RCSID(0, "$NetBSD: wdc_acafh.c,v 1.7 2023/12/20 00:40:42 thorpej Exp $");
45f7bd7656Srkujawa 
46f7bd7656Srkujawa #include <sys/types.h>
47f7bd7656Srkujawa #include <sys/param.h>
48f7bd7656Srkujawa #include <sys/systm.h>
49f7bd7656Srkujawa #include <sys/device.h>
50f7bd7656Srkujawa #include <sys/bus.h>
51f7bd7656Srkujawa 
52f7bd7656Srkujawa #include <machine/cpu.h>
53f7bd7656Srkujawa #include <machine/intr.h>
54f7bd7656Srkujawa #include <sys/bswap.h>
55f7bd7656Srkujawa 
56f7bd7656Srkujawa #include <amiga/amiga/cia.h>
57f7bd7656Srkujawa #include <amiga/amiga/custom.h>
58f7bd7656Srkujawa #include <amiga/amiga/device.h>
59f7bd7656Srkujawa #include <amiga/amiga/gayle.h>
60f7bd7656Srkujawa #include <amiga/dev/zbusvar.h>
61f7bd7656Srkujawa #include <amiga/dev/acafhvar.h>
627598b3c2Srkujawa #include <amiga/dev/acafhreg.h>
63f7bd7656Srkujawa 
64f7bd7656Srkujawa #include <dev/ata/atavar.h>
65f7bd7656Srkujawa #include <dev/ic/wdcvar.h>
66f7bd7656Srkujawa 
677598b3c2Srkujawa #define WDC_ACAFH_SLOTS 2
687598b3c2Srkujawa 
697598b3c2Srkujawa struct wdc_acafh_slot {
707598b3c2Srkujawa 	struct ata_channel	channel;
717598b3c2Srkujawa 	struct wdc_regs		wdr;
727598b3c2Srkujawa };
737598b3c2Srkujawa 
74f7bd7656Srkujawa struct wdc_acafh_softc {
75f7bd7656Srkujawa 	struct wdc_softc	sc_wdcdev;
767598b3c2Srkujawa 	struct ata_channel	*sc_chanlist[WDC_ACAFH_SLOTS];
777598b3c2Srkujawa 	struct wdc_acafh_slot	sc_slots[WDC_ACAFH_SLOTS];
787598b3c2Srkujawa 
79f7bd7656Srkujawa 	struct isr		sc_isr;
807598b3c2Srkujawa 
81f7bd7656Srkujawa 	struct bus_space_tag	cmd_iot;
827598b3c2Srkujawa 
83f7bd7656Srkujawa 	struct acafh_softc	*aca_sc;
84f7bd7656Srkujawa };
85f7bd7656Srkujawa 
86f7bd7656Srkujawa int		wdc_acafh_match(device_t, cfdata_t, void *);
87f7bd7656Srkujawa void		wdc_acafh_attach(device_t, device_t, void *);
88f7bd7656Srkujawa int		wdc_acafh_intr(void *);
897598b3c2Srkujawa static void	wdc_acafh_attach_channel(struct wdc_acafh_softc *, int);
907598b3c2Srkujawa static void	wdc_acafh_map_channel(struct wdc_acafh_softc *, int);
91f7bd7656Srkujawa 
92f7bd7656Srkujawa CFATTACH_DECL_NEW(wdc_acafh, sizeof(struct wdc_acafh_softc),
93f7bd7656Srkujawa     wdc_acafh_match, wdc_acafh_attach, NULL, NULL);
94f7bd7656Srkujawa 
95f7bd7656Srkujawa int
wdc_acafh_match(device_t parent,cfdata_t cfp,void * aux)96f7bd7656Srkujawa wdc_acafh_match(device_t parent, cfdata_t cfp, void *aux)
97f7bd7656Srkujawa {
98f7bd7656Srkujawa 	struct acafhbus_attach_args *aap = aux;
99f7bd7656Srkujawa 
100f7bd7656Srkujawa 	if (strcmp(aap->aaa_name, "wdc_acafh") != 0)
101f7bd7656Srkujawa 		return(0);
102f7bd7656Srkujawa 	return 1;
103f7bd7656Srkujawa }
104f7bd7656Srkujawa 
105f7bd7656Srkujawa void
wdc_acafh_attach(device_t parent,device_t self,void * aux)106f7bd7656Srkujawa wdc_acafh_attach(device_t parent, device_t self, void *aux)
107f7bd7656Srkujawa {
108f7bd7656Srkujawa 	struct wdc_acafh_softc *sc = device_private(self);
109f7bd7656Srkujawa 	int i;
110f7bd7656Srkujawa 
1117598b3c2Srkujawa 	aprint_normal(": ACA500 CompactFlash interface\n");
112f7bd7656Srkujawa 	sc->aca_sc = device_private(parent);
113f7bd7656Srkujawa 
114f7bd7656Srkujawa 	gayle_init();
115f7bd7656Srkujawa 
1167598b3c2Srkujawa 	/* XXX: take addr from attach args? */
1177598b3c2Srkujawa 	sc->cmd_iot.base = (u_long) ztwomap(GAYLE_IDE_BASE + 2);
1187598b3c2Srkujawa 	sc->cmd_iot.absm = &amiga_bus_stride_4swap;
119f7bd7656Srkujawa 
1207598b3c2Srkujawa 	sc->sc_wdcdev.sc_atac.atac_dev = self;
1217598b3c2Srkujawa 	sc->sc_wdcdev.sc_atac.atac_cap = ATAC_CAP_DATA16;
1227598b3c2Srkujawa 	sc->sc_wdcdev.sc_atac.atac_pio_cap = 0;
1237598b3c2Srkujawa 	sc->sc_wdcdev.sc_atac.atac_channels = sc->sc_chanlist;
1247598b3c2Srkujawa 	sc->sc_wdcdev.sc_atac.atac_nchannels = WDC_ACAFH_SLOTS;
1257598b3c2Srkujawa 	sc->sc_wdcdev.wdc_maxdrives = 2;
1267598b3c2Srkujawa 	sc->sc_wdcdev.cap = WDC_CAPABILITY_NO_AUXCTL;
1277598b3c2Srkujawa 
1287598b3c2Srkujawa 	wdc_allocate_regs(&sc->sc_wdcdev);
1297598b3c2Srkujawa 	for (i = 0; i < WDC_ACAFH_SLOTS; i++) {
1307598b3c2Srkujawa 		wdc_acafh_attach_channel(sc, i);
1317598b3c2Srkujawa 	}
1327598b3c2Srkujawa 
1337598b3c2Srkujawa 	sc->sc_isr.isr_intr = wdc_acafh_intr;
1347598b3c2Srkujawa 	sc->sc_isr.isr_arg = sc;
1357598b3c2Srkujawa 	sc->sc_isr.isr_ipl = 2;
1367598b3c2Srkujawa 	add_isr (&sc->sc_isr);
1377598b3c2Srkujawa 
138d8300310Srkujawa 	gayle_intr_enable_set(GAYLE_INT_IDE);
1397598b3c2Srkujawa 
1407598b3c2Srkujawa }
1417598b3c2Srkujawa 
1427598b3c2Srkujawa void
wdc_acafh_attach_channel(struct wdc_acafh_softc * sc,int chnum)1437598b3c2Srkujawa wdc_acafh_attach_channel(struct wdc_acafh_softc *sc, int chnum)
1447598b3c2Srkujawa {
145bc473197Sphx #ifdef WDC_ACAFH_DEBUG
146bc473197Sphx 	device_t self;
147bc473197Sphx 
148bc473197Sphx 	self = sc->sc_wdcdev.sc_atac.atac_dev;
149bc473197Sphx #endif /* WDC_ACAFH_DEBUG */
150bc473197Sphx 
1517598b3c2Srkujawa 	sc->sc_chanlist[chnum] = &sc->sc_slots[chnum].channel;
1527598b3c2Srkujawa 	memset(&sc->sc_slots[chnum],0,sizeof(struct wdc_acafh_slot));
1537598b3c2Srkujawa 	sc->sc_slots[chnum].channel.ch_channel = chnum;
1547598b3c2Srkujawa 	sc->sc_slots[chnum].channel.ch_atac = &sc->sc_wdcdev.sc_atac;
1557598b3c2Srkujawa 
1567598b3c2Srkujawa 	wdc_acafh_map_channel(sc, chnum);
1577598b3c2Srkujawa 
15826cf6855Sjdolecek 	wdc_init_shadow_regs(CHAN_TO_WDC_REGS(&sc->sc_slots[chnum].channel));
1597598b3c2Srkujawa 	wdcattach(&sc->sc_slots[chnum].channel);
1607598b3c2Srkujawa 
1617598b3c2Srkujawa #ifdef WDC_ACAFH_DEBUG
162bc473197Sphx 	aprint_normal_dev(self, "done init for channel %d\n", chnum);
1637598b3c2Srkujawa #endif /* WDC_ACAFH_DEBUG */
1647598b3c2Srkujawa }
1657598b3c2Srkujawa 
1667598b3c2Srkujawa void
wdc_acafh_map_channel(struct wdc_acafh_softc * sc,int chnum)1677598b3c2Srkujawa wdc_acafh_map_channel(struct wdc_acafh_softc *sc, int chnum)
1687598b3c2Srkujawa {
1697598b3c2Srkujawa 	struct wdc_regs *wdr;
1707598b3c2Srkujawa 	bus_addr_t off;
171bc473197Sphx 	device_t self;
172bc473197Sphx 	int i;
173bc473197Sphx 
174bc473197Sphx 	self = sc->sc_wdcdev.sc_atac.atac_dev;
1757598b3c2Srkujawa 
1767598b3c2Srkujawa 	wdr = CHAN_TO_WDC_REGS(&sc->sc_slots[chnum].channel);
1777598b3c2Srkujawa 	wdr->cmd_iot = &sc->cmd_iot;
1787598b3c2Srkujawa 
1797598b3c2Srkujawa 	if (chnum == 0)
1807598b3c2Srkujawa 		off = 0;
1817598b3c2Srkujawa 	else
1827598b3c2Srkujawa 		off = 0x400;
1837598b3c2Srkujawa 
1847598b3c2Srkujawa 	if (bus_space_map(wdr->cmd_iot, off, 0x40, 0,
185f7bd7656Srkujawa 			  &wdr->cmd_baseioh)) {
186bc473197Sphx 		aprint_error_dev(self, "couldn't map regs\n");
187f7bd7656Srkujawa 		return;
188f7bd7656Srkujawa 	}
189f7bd7656Srkujawa 
190f7bd7656Srkujawa 	for (i = 0; i < WDC_NREG; i++) {
191f7bd7656Srkujawa 		if (bus_space_subregion(wdr->cmd_iot,
192f7bd7656Srkujawa 		    wdr->cmd_baseioh, i, i == 0 ? 4 : 1,
193f7bd7656Srkujawa 		    &wdr->cmd_iohs[i]) != 0) {
194f7bd7656Srkujawa 
195f7bd7656Srkujawa 			bus_space_unmap(wdr->cmd_iot,
196f7bd7656Srkujawa 			    wdr->cmd_baseioh, 0x40);
197bc473197Sphx 			aprint_error_dev(self, "couldn't map regs\n");
198f7bd7656Srkujawa 			return;
199f7bd7656Srkujawa 		}
200f7bd7656Srkujawa 	}
201f7bd7656Srkujawa 
202f7bd7656Srkujawa }
203f7bd7656Srkujawa 
204f7bd7656Srkujawa int
wdc_acafh_intr(void * arg)205f7bd7656Srkujawa wdc_acafh_intr(void *arg)
206f7bd7656Srkujawa {
207d8300310Srkujawa 	struct wdc_acafh_softc *sc;
208d8300310Srkujawa 	uint8_t intreq;
209d8300310Srkujawa 	int ret;
210d8300310Srkujawa 
211d8300310Srkujawa 	sc = (struct wdc_acafh_softc *) arg;
212d8300310Srkujawa 	intreq = gayle_intr_status();
213d8300310Srkujawa 	ret = 0;
214f7bd7656Srkujawa 
215f7bd7656Srkujawa 	if (intreq & GAYLE_INT_IDE) {
2167598b3c2Srkujawa 		if (acafh_cf_intr_status(sc->aca_sc, 1) == 1) {
2177598b3c2Srkujawa 			ret = wdcintr(&sc->sc_slots[1].channel);
2187598b3c2Srkujawa 		}
2197598b3c2Srkujawa 		if (acafh_cf_intr_status(sc->aca_sc, 0) == 1) {
2207598b3c2Srkujawa 			ret = wdcintr(&sc->sc_slots[0].channel);
2217598b3c2Srkujawa 		}
222d8300310Srkujawa 		gayle_intr_ack(0x7C | (intreq & GAYLE_INT_IDEACK));
223f7bd7656Srkujawa 	}
224f7bd7656Srkujawa 
225f7bd7656Srkujawa 	return ret;
226f7bd7656Srkujawa }
227f7bd7656Srkujawa 
228