xref: /netbsd-src/sys/arch/amiga/dev/wdc_buddha.c (revision 23e63c4b5cecc703250c97faac1ad970f4954821)
1*23e63c4bSthorpej /*	$NetBSD: wdc_buddha.c,v 1.11 2023/12/20 00:40:42 thorpej Exp $	*/
24c7c6343Sis 
34c7c6343Sis /*-
44c7c6343Sis  * Copyright (c) 2000 The NetBSD Foundation, Inc.
54c7c6343Sis  * All rights reserved.
64c7c6343Sis  *
74c7c6343Sis  * This code is derived from software contributed to The NetBSD Foundation
84c7c6343Sis  * by Michael L. Hitch and Ignatios Souvatzis.
94c7c6343Sis  *
104c7c6343Sis  * Redistribution and use in source and binary forms, with or without
114c7c6343Sis  * modification, are permitted provided that the following conditions
124c7c6343Sis  * are met:
134c7c6343Sis  * 1. Redistributions of source code must retain the above copyright
144c7c6343Sis  *    notice, this list of conditions and the following disclaimer.
154c7c6343Sis  * 2. Redistributions in binary form must reproduce the above copyright
164c7c6343Sis  *    notice, this list of conditions and the following disclaimer in the
174c7c6343Sis  *    documentation and/or other materials provided with the distribution.
184c7c6343Sis  *
194c7c6343Sis  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
204c7c6343Sis  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
214c7c6343Sis  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
224c7c6343Sis  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
234c7c6343Sis  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
244c7c6343Sis  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
254c7c6343Sis  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
264c7c6343Sis  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
274c7c6343Sis  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
284c7c6343Sis  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
294c7c6343Sis  * POSSIBILITY OF SUCH DAMAGE.
304c7c6343Sis  */
314c7c6343Sis 
324c7c6343Sis #include <sys/types.h>
334c7c6343Sis #include <sys/param.h>
344c7c6343Sis #include <sys/systm.h>
354c7c6343Sis #include <sys/device.h>
363a45360bSdyoung #include <sys/bus.h>
374c7c6343Sis 
384c7c6343Sis #include <machine/cpu.h>
394c7c6343Sis #include <machine/intr.h>
404c7c6343Sis #include <machine/bswap.h>
414c7c6343Sis 
424c7c6343Sis #include <amiga/amiga/cia.h>
434c7c6343Sis #include <amiga/amiga/custom.h>
444c7c6343Sis #include <amiga/amiga/device.h>
454c7c6343Sis #include <amiga/dev/zbusvar.h>
464c7c6343Sis 
474c7c6343Sis #include <dev/ata/atavar.h>
484c7c6343Sis #include <dev/ic/wdcvar.h>
494c7c6343Sis 
504c7c6343Sis #define BUDDHA_MAX_CHANNELS 3
514c7c6343Sis 
524c7c6343Sis struct wdc_buddha_softc {
534c7c6343Sis 	struct wdc_softc sc_wdcdev;
544c7c6343Sis 	struct ata_channel *wdc_chanarray[BUDDHA_MAX_CHANNELS];
554c7c6343Sis 	struct ata_channel channels[BUDDHA_MAX_CHANNELS];
564c7c6343Sis 	struct bus_space_tag sc_iot;
574c7c6343Sis 	struct isr sc_isr;
584c7c6343Sis 	volatile char *ba;
594c7c6343Sis };
604c7c6343Sis 
617aa6248cScube int	wdc_buddha_probe(device_t, cfdata_t, void *);
627aa6248cScube void	wdc_buddha_attach(device_t, device_t, void *);
634c7c6343Sis int	wdc_buddha_intr(void *);
644c7c6343Sis 
657aa6248cScube CFATTACH_DECL_NEW(wdc_buddha, sizeof(struct wdc_buddha_softc),
664c7c6343Sis     wdc_buddha_probe, wdc_buddha_attach, NULL, NULL);
674c7c6343Sis 
684c7c6343Sis int
wdc_buddha_probe(device_t parent,cfdata_t cfp,void * aux)697aa6248cScube wdc_buddha_probe(device_t parent, cfdata_t cfp, void *aux)
704c7c6343Sis {
714c7c6343Sis 	struct zbus_args *zap;
724c7c6343Sis 
734c7c6343Sis 	zap = aux;
744c7c6343Sis 
754c7c6343Sis 	if (zap->manid != 4626)
764c7c6343Sis 		return 0;
774c7c6343Sis 
784c7c6343Sis 	if ((zap->prodid != 0) &&	/* Buddha */
794c7c6343Sis 	    (zap->prodid != 42))	/* Catweasel */
804c7c6343Sis 		return 0;
814c7c6343Sis 
824c7c6343Sis 	return 1;
834c7c6343Sis }
844c7c6343Sis 
854c7c6343Sis void
wdc_buddha_attach(device_t parent,device_t self,void * aux)867aa6248cScube wdc_buddha_attach(device_t parent, device_t self, void *aux)
874c7c6343Sis {
884c7c6343Sis 	struct wdc_buddha_softc *sc;
894c7c6343Sis 	struct zbus_args *zap;
904c7c6343Sis 	int nchannels;
914c7c6343Sis 	int ch;
924c7c6343Sis 
937aa6248cScube 	sc = device_private(self);
947aa6248cScube 	sc->sc_wdcdev.sc_atac.atac_dev = self;
954c7c6343Sis 	zap = aux;
964c7c6343Sis 
974c7c6343Sis 	sc->ba = zap->va;
984c7c6343Sis 
994c7c6343Sis 	sc->sc_iot.base = (bus_addr_t)sc->ba;
1004c7c6343Sis 	sc->sc_iot.absm = &amiga_bus_stride_4swap;
1014c7c6343Sis 
1024c7c6343Sis 	nchannels = 2;
1034c7c6343Sis 	if (zap->prodid == 42) {
1047aa6248cScube 		aprint_normal(": Catweasel Z2\n");
1054c7c6343Sis 		nchannels = 3;
1064c7c6343Sis 	} else if (zap->serno == 0)
1077aa6248cScube 		aprint_normal(": Buddha\n");
1084c7c6343Sis 	else
1097aa6248cScube 		aprint_normal(": Buddha Flash\n");
1104c7c6343Sis 
1114c7c6343Sis 	/* XXX pio mode setting not implemented yet. */
1124c7c6343Sis 	sc->sc_wdcdev.sc_atac.atac_cap = ATAC_CAP_DATA16;
1134c7c6343Sis 	sc->sc_wdcdev.sc_atac.atac_pio_cap = 0;
1144c7c6343Sis 	sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
1154c7c6343Sis 	sc->sc_wdcdev.sc_atac.atac_nchannels = nchannels;
1169edd4d81Sbouyer 	sc->sc_wdcdev.wdc_maxdrives = 2;
1174c7c6343Sis 
1184c7c6343Sis 	wdc_allocate_regs(&sc->sc_wdcdev);
1194c7c6343Sis 
1204c7c6343Sis 	for (ch = 0; ch < nchannels; ch++) {
1214c7c6343Sis 		struct ata_channel *cp;
1224c7c6343Sis 		struct wdc_regs *wdr;
1234c7c6343Sis 		int i;
1244c7c6343Sis 
1254c7c6343Sis 		cp = &sc->channels[ch];
1264c7c6343Sis 		sc->wdc_chanarray[ch] = cp;
1274c7c6343Sis 
1284c7c6343Sis 		cp->ch_channel = ch;
1294c7c6343Sis 		cp->ch_atac = &sc->sc_wdcdev.sc_atac;
1304c7c6343Sis 
1314c7c6343Sis 		/*
1324c7c6343Sis 		 * XXX According to the Buddha docs, we should use a method
1334c7c6343Sis 		 * array that adds 0x40 to the address for byte accesses, to
1344c7c6343Sis 		 * get the slow timing for command accesses, and the 0x00
1354c7c6343Sis 		 * offset for the word (fast) accesses. This will be
1364c7c6343Sis 		 * reconsidered when implementing setting the timing.
1374c7c6343Sis 		 *
1384c7c6343Sis 		 * XXX We also could consider to abuse the 32bit capability, or
1394c7c6343Sis 		 * 32bit accesses to the words (which will read in two words)
1404c7c6343Sis 		 * for better performance.
1414c7c6343Sis 		 *		-is
1424c7c6343Sis 		 */
1434c7c6343Sis 		wdr = CHAN_TO_WDC_REGS(cp);
1444c7c6343Sis 
1454c7c6343Sis 		wdr->cmd_iot = &sc->sc_iot;
1464c7c6343Sis 		if (bus_space_map(wdr->cmd_iot, 0x210+ch*0x80, 8, 0,
1474c7c6343Sis 		    &wdr->cmd_baseioh)) {
1487aa6248cScube 			aprint_error_dev(self, "couldn't map cmd registers\n");
1494c7c6343Sis 			return;
1504c7c6343Sis 		}
1514c7c6343Sis 
1524c7c6343Sis 		wdr->ctl_iot = &sc->sc_iot;
1534c7c6343Sis 		if (bus_space_map(wdr->ctl_iot, 0x250+ch*0x80, 2, 0,
1544c7c6343Sis 		    &wdr->ctl_ioh)) {
1554c7c6343Sis 			bus_space_unmap(wdr->cmd_iot, wdr->cmd_baseioh, 8);
1567aa6248cScube 			aprint_error_dev(self, "couldn't map ctl registers\n");
1574c7c6343Sis 			return;
1584c7c6343Sis 		}
1594c7c6343Sis 
1604c7c6343Sis 		for (i = 0; i < WDC_NREG; i++) {
1614c7c6343Sis 			if (bus_space_subregion(wdr->cmd_iot, wdr->cmd_baseioh,
1624c7c6343Sis 			    i, i == 0 ? 4 : 1, &wdr->cmd_iohs[i]) != 0) {
1637aa6248cScube 				aprint_error_dev(self,
1647aa6248cScube 				    "couldn't subregion cmd regs\n");
1654c7c6343Sis 				return;
1664c7c6343Sis 			}
1674c7c6343Sis 		}
1684c7c6343Sis 
16926cf6855Sjdolecek 		wdc_init_shadow_regs(wdr);
1704c7c6343Sis 		wdcattach(cp);
1714c7c6343Sis 	}
1724c7c6343Sis 
1734c7c6343Sis 	sc->sc_isr.isr_intr = wdc_buddha_intr;
1744c7c6343Sis 	sc->sc_isr.isr_arg = sc;
1754c7c6343Sis 	sc->sc_isr.isr_ipl = 2;
1764c7c6343Sis 	add_isr (&sc->sc_isr);
1774c7c6343Sis 	sc->ba[0xfc0] = 0;	/* enable interrupts */
1784c7c6343Sis }
1794c7c6343Sis 
1804c7c6343Sis int
wdc_buddha_intr(void * arg)1814c7c6343Sis wdc_buddha_intr(void *arg)
1824c7c6343Sis {
1834c7c6343Sis 	struct wdc_buddha_softc *sc = (struct wdc_buddha_softc *)arg;
1844c7c6343Sis 	int nchannels, i, ret;
1854c7c6343Sis 	volatile char *p;
1864c7c6343Sis 
1874c7c6343Sis 	ret = 0;
1884c7c6343Sis 	nchannels = sc->sc_wdcdev.sc_atac.atac_nchannels;
1894c7c6343Sis 	p = sc->ba;
1904c7c6343Sis 
1914c7c6343Sis 	for (i=0; i<nchannels; i++) {
1924c7c6343Sis 		if (p[0xf00 + 0x40*i] & 0x80) {
1934c7c6343Sis 			wdcintr(&sc->channels[i]);
1944c7c6343Sis 			ret = 1;
1954c7c6343Sis 		}
1964c7c6343Sis 	}
1974c7c6343Sis 
1984c7c6343Sis 	return ret;
1994c7c6343Sis }
200