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