xref: /netbsd-src/sys/arch/amiga/dev/wdc_xsurf.c (revision 62fb61315509e9ffde7dc87c1c0c06fdfbccdb38)
1 /*      $NetBSD: wdc_xsurf.c,v 1.6 2017/10/20 07:06:06 jdolecek Exp $ */
2 
3 /*-
4  * Copyright (c) 2012 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Radoslaw Kujawa.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /* Driver for IDE controller present on X-Surf. */
33 
34 #include <sys/cdefs.h>
35 
36 #include <sys/systm.h>
37 #include <sys/types.h>
38 #include <sys/device.h>
39 #include <sys/bus.h>
40 #include <sys/conf.h>
41 #include <sys/kmem.h>
42 
43 #include <machine/cpu.h>
44 
45 #include <amiga/amiga/device.h>
46 
47 #include <dev/ata/atavar.h>
48 #include <dev/ic/wdcvar.h>
49 
50 #include <amiga/dev/zbusvar.h>
51 #include <amiga/dev/xsurfvar.h>
52 
53 #define WDC_XSURF_CHANNELS	2
54 #define WDC_XSURF_CHANSIZE	0x30
55 #define WDC_XSURF_CHANOFF	0x2000
56 
57 #define WDC_XSURF_ISR_OFF	0x7E
58 #define WDC_XSURF_ISR_HIGH	0x80
59 
60 #define WDC_XSURF_OFF_DATA	0x0
61 #define WDC_XSURF_OFF_ERROR	0x6
62 #define WDC_XSURF_OFF_SECCNT	0xA
63 #define WDC_XSURF_OFF_SECTOR	0xE
64 #define WDC_XSURF_OFF_CYL_LO	0x12
65 #define WDC_XSURF_OFF_CYL_HI	0x16
66 #define WDC_XSURF_OFF_SDH	0x1A
67 #define WDC_XSURF_OFF_COMMAND	0x1E
68 
69 struct wdc_xsurf_port {
70 	struct ata_channel	channel;
71 	struct wdc_regs		wdr;
72 };
73 
74 struct wdc_xsurf_softc {
75 	struct wdc_softc 	sc_wdcdev;
76 	struct ata_channel 	*sc_chanarray[WDC_XSURF_CHANNELS];
77 	struct wdc_xsurf_port	sc_ports[WDC_XSURF_CHANNELS];
78 
79 	struct bus_space_tag	sc_bst;
80 	bus_space_tag_t		sc_cmdt;
81 	bus_space_handle_t	sc_isrh;
82 
83 	struct isr		sc_isr;
84 };
85 
86 static int	wdc_xsurf_match(device_t, cfdata_t, void *);
87 static void	wdc_xsurf_attach(device_t, device_t, void *);
88 void		wdc_xsurf_attach_channel(struct wdc_xsurf_softc *, int);
89 void		wdc_xsurf_map_channel(struct wdc_xsurf_softc *, int);
90 int		wdc_xsurf_intr(void *arg);
91 
92 CFATTACH_DECL_NEW(wdc_xsurf, sizeof(struct wdc_xsurf_softc),
93     wdc_xsurf_match, wdc_xsurf_attach, NULL, NULL);
94 
95 static const unsigned int wdc_xsurf_wdr_offsets[] = {
96     WDC_XSURF_OFF_DATA, WDC_XSURF_OFF_ERROR, WDC_XSURF_OFF_SECCNT,
97     WDC_XSURF_OFF_SECTOR, WDC_XSURF_OFF_CYL_LO, WDC_XSURF_OFF_CYL_HI,
98     WDC_XSURF_OFF_SDH, WDC_XSURF_OFF_COMMAND
99 };
100 
101 static int
wdc_xsurf_match(device_t parent,cfdata_t cf,void * aux)102 wdc_xsurf_match(device_t parent, cfdata_t cf, void *aux)
103 {
104 	struct xsurfbus_attach_args *xsb_aa = aux;
105 
106 	if (strcmp(xsb_aa->xaa_name, "wdc_xsurf") != 0)
107 		return 0;
108 
109 	return 1;
110 }
111 
112 static void
wdc_xsurf_attach(device_t parent,device_t self,void * aux)113 wdc_xsurf_attach(device_t parent, device_t self, void *aux)
114 {
115 	struct wdc_xsurf_softc *sc;
116 	struct xsurfbus_attach_args *xsb_aa;
117 	int i;
118 
119 	aprint_normal("\n");
120 	aprint_naive("\n");
121 	xsb_aa = aux;
122 	sc = device_private(self);
123 
124 	sc->sc_bst.base = xsb_aa->xaa_base;
125 	sc->sc_bst.absm = &amiga_bus_stride_1swap;
126 	sc->sc_cmdt = &sc->sc_bst;
127 
128 	sc->sc_wdcdev.sc_atac.atac_pio_cap = 0;
129 	sc->sc_wdcdev.sc_atac.atac_nchannels = WDC_XSURF_CHANNELS;
130 	sc->sc_wdcdev.sc_atac.atac_dev = self;
131 	sc->sc_wdcdev.sc_atac.atac_channels = sc->sc_chanarray;
132 	sc->sc_wdcdev.sc_atac.atac_cap = ATAC_CAP_DATA16;
133 	sc->sc_wdcdev.wdc_maxdrives = 2;
134 	/* this controller has no aux control registers */
135 	sc->sc_wdcdev.cap = WDC_CAPABILITY_NO_AUXCTL;
136 
137 	/* attach the channels */
138 	wdc_allocate_regs(&sc->sc_wdcdev);
139 	for (i = 0; i < WDC_XSURF_CHANNELS; i++) {
140 		wdc_xsurf_attach_channel(sc, i);
141 	}
142 
143 	/* map interrupt status register */
144 	bus_space_map(sc->sc_cmdt, WDC_XSURF_ISR_OFF,
145 	    1, 0, &sc->sc_isrh);
146 
147 	/* attach interrupt */
148 	sc->sc_isr.isr_intr = wdc_xsurf_intr;
149 	sc->sc_isr.isr_arg = sc;
150 	sc->sc_isr.isr_ipl = 2;
151 	add_isr(&sc->sc_isr);
152 }
153 
154 void
wdc_xsurf_attach_channel(struct wdc_xsurf_softc * sc,int chnum)155 wdc_xsurf_attach_channel(struct wdc_xsurf_softc *sc, int chnum)
156 {
157 #ifdef WDC_XSURF_DEBUG
158 	device_t self;
159 
160 	self = sc->sc_wdcdev.sc_atac.atac_dev;
161 #endif /* WDC_XSURF_DEBUG */
162 
163 	sc->sc_chanarray[chnum] = &sc->sc_ports[chnum].channel;
164 	memset(&sc->sc_ports[chnum],0,sizeof(struct wdc_xsurf_port));
165 	sc->sc_ports[chnum].channel.ch_channel = chnum;
166 	sc->sc_ports[chnum].channel.ch_atac = &sc->sc_wdcdev.sc_atac;
167 
168 	wdc_xsurf_map_channel(sc, chnum);
169 
170 	wdc_init_shadow_regs(CHAN_TO_WDC_REGS(&sc->sc_ports[chnum].channel));
171 	wdcattach(&sc->sc_ports[chnum].channel);
172 
173 #ifdef WDC_XSURF_DEBUG
174 	aprint_normal_dev(self, "done init for channel %d\n", chnum);
175 #endif /* WDC_XSURF_DEBUG */
176 }
177 
178 void
wdc_xsurf_map_channel(struct wdc_xsurf_softc * sc,int chnum)179 wdc_xsurf_map_channel(struct wdc_xsurf_softc *sc, int chnum)
180 {
181 	struct wdc_regs *wdr;
182 	int i;
183 
184 	wdr = CHAN_TO_WDC_REGS(&sc->sc_ports[chnum].channel);
185 
186 	/* map the registers */
187 	wdr->cmd_iot = sc->sc_cmdt;
188 	bus_space_map(sc->sc_cmdt, chnum * WDC_XSURF_CHANOFF,
189 	    WDC_XSURF_CHANSIZE, 0, &wdr->cmd_baseioh);
190 
191 	for (i = 0; i < WDC_NREG; i++)
192 		bus_space_subregion(wdr->cmd_iot, wdr->cmd_baseioh,
193 		    wdc_xsurf_wdr_offsets[i], i == 0 ? 2 : 1,
194 		    &wdr->cmd_iohs[i]);
195 }
196 
197 int
wdc_xsurf_intr(void * arg)198 wdc_xsurf_intr(void *arg)
199 {
200 	struct wdc_xsurf_softc *sc;
201 	uint8_t intreq;
202 	int r1, r2;
203 
204 	sc  = (struct wdc_xsurf_softc *)arg;
205 	r1 = r2 = 0;
206 
207 	intreq = bus_space_read_1(sc->sc_cmdt, sc->sc_isrh, 0);
208 	bus_space_write_1(sc->sc_cmdt, sc->sc_isrh, 0, 0); /* pull A11 down */
209 
210 	/* only one register for both channels... :/ */
211 	if (intreq & WDC_XSURF_ISR_HIGH) {
212 		r1 = wdcintr(&sc->sc_ports[0].channel);
213 		r2 = wdcintr(&sc->sc_ports[1].channel);
214 	}
215 
216 	return r1 | r2;
217 }
218