xref: /netbsd-src/sys/arch/amiga/dev/wdc_xsurf.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1 /*      $NetBSD: wdc_xsurf.c,v 1.2 2012/11/21 22:37:03 rkujawa 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 ata_queue	queue;
72 	struct wdc_regs		wdr;
73 };
74 
75 struct wdc_xsurf_softc {
76 	device_t		sc_dev;
77 
78 	struct wdc_softc 	sc_wdcdev;
79 	struct ata_channel 	*sc_chanarray[WDC_XSURF_CHANNELS];
80 	struct wdc_xsurf_port	sc_ports[WDC_XSURF_CHANNELS];
81 
82 	struct bus_space_tag	sc_bst;
83 	bus_space_tag_t		sc_cmdt;
84 	bus_space_handle_t	sc_isrh;
85 
86 	struct isr		sc_isr;
87 };
88 
89 static int	wdc_xsurf_match(device_t, cfdata_t, void *);
90 static void	wdc_xsurf_attach(device_t, device_t, void *);
91 void		wdc_xsurf_attach_channel(struct wdc_xsurf_softc *, int);
92 void		wdc_xsurf_map_channel(struct wdc_xsurf_softc *, int);
93 int		wdc_xsurf_intr(void *arg);
94 
95 CFATTACH_DECL_NEW(wdc_xsurf, sizeof(struct wdc_softc),
96     wdc_xsurf_match, wdc_xsurf_attach, NULL, NULL);
97 
98 static const unsigned int wdc_xsurf_wdr_offsets[] = {
99     WDC_XSURF_OFF_DATA, WDC_XSURF_OFF_ERROR, WDC_XSURF_OFF_SECCNT,
100     WDC_XSURF_OFF_SECTOR, WDC_XSURF_OFF_CYL_LO, WDC_XSURF_OFF_CYL_HI,
101     WDC_XSURF_OFF_SDH, WDC_XSURF_OFF_COMMAND
102 };
103 
104 static int
105 wdc_xsurf_match(device_t parent, cfdata_t cf, void *aux)
106 {
107 	struct xsurfbus_attach_args *xsb_aa = aux;
108 
109 	if (strcmp(xsb_aa->xaa_name, "wdc_xsurf") != 0)
110 		return 0;
111 
112 	return 1;
113 }
114 
115 static void
116 wdc_xsurf_attach(device_t parent, device_t self, void *aux)
117 {
118 	struct wdc_xsurf_softc *sc;
119 	struct xsurfbus_attach_args *xsb_aa;
120 	int i;
121 
122 	aprint_normal("\n");
123 	aprint_naive("\n");
124 	xsb_aa = aux;
125 	sc = device_private(self);
126 	sc->sc_dev = self;
127 
128 	sc->sc_bst.base = xsb_aa->xaa_base;
129 	sc->sc_bst.absm = &amiga_bus_stride_1swap;
130 	sc->sc_cmdt = &sc->sc_bst;
131 
132 	sc->sc_wdcdev.sc_atac.atac_pio_cap = 0;
133 	sc->sc_wdcdev.sc_atac.atac_nchannels = WDC_XSURF_CHANNELS;
134 	sc->sc_wdcdev.sc_atac.atac_dev = self;
135 	sc->sc_wdcdev.sc_atac.atac_channels = sc->sc_chanarray;
136 	sc->sc_wdcdev.sc_atac.atac_cap = ATAC_CAP_DATA16;
137 	sc->sc_wdcdev.wdc_maxdrives = 2;
138 	/* this controller has no aux control registers */
139 	sc->sc_wdcdev.cap = WDC_CAPABILITY_NO_AUXCTL;
140 
141 	/* attach the channels */
142 	wdc_allocate_regs(&sc->sc_wdcdev);
143 	for (i = 0; i < WDC_XSURF_CHANNELS; i++) {
144 		wdc_xsurf_attach_channel(sc, i);
145 	}
146 
147 	/* map interrupt status register */
148 	bus_space_map(sc->sc_cmdt, WDC_XSURF_ISR_OFF,
149 	    1, 0, &sc->sc_isrh);
150 
151 	/* attach interrupt */
152 	sc->sc_isr.isr_intr = wdc_xsurf_intr;
153 	sc->sc_isr.isr_arg = sc;
154 	sc->sc_isr.isr_ipl = 2;
155 	add_isr(&sc->sc_isr);
156 }
157 
158 void
159 wdc_xsurf_attach_channel(struct wdc_xsurf_softc *sc, int chnum)
160 {
161 	sc->sc_chanarray[chnum] = &sc->sc_ports[chnum].channel;
162 	memset(&sc->sc_ports[chnum],0,sizeof(struct wdc_xsurf_port));
163 	sc->sc_ports[chnum].channel.ch_channel = chnum;
164 	sc->sc_ports[chnum].channel.ch_atac = &sc->sc_wdcdev.sc_atac;
165 	sc->sc_ports[chnum].channel.ch_queue = &sc->sc_ports[chnum].queue;
166 
167 	wdc_xsurf_map_channel(sc, chnum);
168 
169 	wdc_init_shadow_regs(&sc->sc_ports[chnum].channel);
170 	wdcattach(&sc->sc_ports[chnum].channel);
171 
172 #ifdef WDC_XSURF_DEBUG
173 	aprint_normal_dev(sc->sc_dev, "done init for channel %d\n", chnum);
174 #endif /* WDC_XSURF_DEBUG */
175 }
176 
177 void
178 wdc_xsurf_map_channel(struct wdc_xsurf_softc *sc, int chnum)
179 {
180 	struct wdc_regs *wdr;
181 	int i;
182 
183 	wdr = CHAN_TO_WDC_REGS(&sc->sc_ports[chnum].channel);
184 
185 	/* map the registers */
186 	wdr->cmd_iot = sc->sc_cmdt;
187 	bus_space_map(sc->sc_cmdt, chnum * WDC_XSURF_CHANOFF,
188 	    WDC_XSURF_CHANSIZE, 0, &wdr->cmd_baseioh);
189 
190 	for (i = 0; i < WDC_NREG; i++)
191 		bus_space_subregion(wdr->cmd_iot, wdr->cmd_baseioh,
192 		    wdc_xsurf_wdr_offsets[i], i == 0 ? 2 : 1,
193 		    &wdr->cmd_iohs[i]);
194 }
195 
196 int
197 wdc_xsurf_intr(void *arg)
198 {
199 	struct wdc_xsurf_softc *sc;
200 	uint8_t intreq;
201 	int r1, r2;
202 
203 	sc  = (struct wdc_xsurf_softc *)arg;
204 	r1 = r2 = 0;
205 
206 	intreq = bus_space_read_1(sc->sc_cmdt, sc->sc_isrh, 0);
207 	bus_space_write_1(sc->sc_cmdt, sc->sc_isrh, 0, 0); /* pull A11 down */
208 
209 	/* only one register for both channels... :/ */
210 	if (intreq & WDC_XSURF_ISR_HIGH) {
211 		r1 = wdcintr(&sc->sc_ports[0].channel);
212 		r2 = wdcintr(&sc->sc_ports[1].channel);
213 	}
214 
215 	return r1 | r2;
216 }
217