Annotation of src/sys/arch/acorn32/podulebus/simide.c, Revision 1.26.2.1
1.26.2.1! yamt 1: /* $NetBSD: simide.c,v 1.26 2011/07/19 15:59:54 dyoung Exp $ */
1.1 reinoud 2:
3: /*
4: * Copyright (c) 1997-1998 Mark Brinicombe
5: * Copyright (c) 1997-1998 Causality Limited
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by Mark Brinicombe
18: * for the NetBSD Project.
19: * 4. The name of the author may not be used to endorse or promote products
20: * derived from this software without specific prior written permission.
21: *
22: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32: *
33: * Card driver and probe and attach functions to use generic IDE driver
34: * for the Simtec IDE podule
35: */
36:
37: /*
38: * Thanks to Gareth Simpson, Simtec Electronics for providing
39: * the hardware information
40: */
1.8 lukem 41:
42: #include <sys/cdefs.h>
1.26.2.1! yamt 43: __KERNEL_RCSID(0, "$NetBSD: simide.c,v 1.26 2011/07/19 15:59:54 dyoung Exp $");
1.1 reinoud 44:
45: #include <sys/param.h>
46: #include <sys/systm.h>
47: #include <sys/conf.h>
48: #include <sys/device.h>
49: #include <sys/malloc.h>
1.26 dyoung 50: #include <sys/bus.h>
1.1 reinoud 51:
1.2 thorpej 52: #include <machine/intr.h>
1.1 reinoud 53: #include <machine/io.h>
54: #include <acorn32/podulebus/podulebus.h>
55: #include <acorn32/podulebus/simidereg.h>
56:
57: #include <dev/ata/atavar.h>
1.14 bjh21 58: #include <dev/ic/wdcreg.h>
1.1 reinoud 59: #include <dev/ic/wdcvar.h>
60: #include <dev/podulebus/podules.h>
61:
62:
63: /*
64: * Simtec IDE podule device.
65: *
66: * This probes and attaches the top level Simtec IDE device to the podulebus.
67: * It then configures any children of the Simtec IDE device.
68: * The attach args specify whether it is configuring the primary or
69: * secondary channel.
70: * The children are expected to be wdc devices using simide attachments.
71: */
72:
73: /*
74: * Simtec IDE card softc structure.
75: *
76: * Contains the device node, podule information and global information
77: * required by the driver such as the card version and the interrupt mask.
78: */
79:
80: struct simide_softc {
81: struct wdc_softc sc_wdcdev; /* common wdc definitions */
1.20 thorpej 82: struct ata_channel *sc_chanarray[2]; /* channels definition */
1.1 reinoud 83: podule_t *sc_podule; /* Our podule info */
84: int sc_podule_number; /* Our podule number */
85: int sc_ctl_reg; /* Global ctl reg */
86: int sc_version; /* Card version */
87: bus_space_tag_t sc_ctliot; /* Bus tag */
88: bus_space_handle_t sc_ctlioh; /* control handle */
89: struct bus_space sc_tag; /* custom tag */
90: struct simide_channel {
1.20 thorpej 91: struct ata_channel sc_channel; /* generic part */
92: struct ata_queue sc_chqueue; /* channel queue */
1.1 reinoud 93: irqhandler_t sc_ih; /* interrupt handler */
94: int sc_irqmask; /* IRQ mask for this channel */
95: } simide_channels[2];
1.20 thorpej 96: struct wdc_regs sc_wdc_regs[2];
1.1 reinoud 97: };
98:
1.25 cube 99: int simide_probe (device_t, cfdata_t, void *);
100: void simide_attach (device_t, device_t, void *);
101: void simide_shutdown (void *arg);
102: int simide_intr (void *arg);
1.1 reinoud 103:
1.25 cube 104: CFATTACH_DECL_NEW(simide, sizeof(struct simide_softc),
1.7 thorpej 105: simide_probe, simide_attach, NULL, NULL);
1.1 reinoud 106:
107:
108: /*
109: * Define prototypes for custom bus space functions.
110: */
111:
112: bs_rm_2_proto(simide);
113: bs_wm_2_proto(simide);
114:
115: /*
116: * Create an array of address structures. These define the addresses and
117: * masks needed for the different channels.
118: *
119: * index = channel
120: */
121:
122: struct {
123: u_int drive_registers;
124: u_int aux_register;
125: u_int irq_mask;
126: } simide_info[] = {
127: { PRIMARY_DRIVE_REGISTERS_POFFSET, PRIMARY_AUX_REGISTER_POFFSET,
128: CONTROL_PRIMARY_IRQ },
129: { SECONDARY_DRIVE_REGISTERS_POFFSET, SECONDARY_AUX_REGISTER_POFFSET,
130: CONTROL_SECONDARY_IRQ }
131: };
132:
133: /*
134: * Card probe function
135: *
136: * Just match the manufacturer and podule ID's
137: */
138:
139: int
1.25 cube 140: simide_probe(device_t parent, cfdata_t cf, void *aux)
1.1 reinoud 141: {
142: struct podule_attach_args *pa = (void *)aux;
143:
1.3 bjh21 144: return (pa->pa_product == PODULE_SIMTEC_IDE);
1.1 reinoud 145: }
146:
147: /*
148: * Card attach function
149: *
150: * Identify the card version and configure any children.
151: * Install a shutdown handler to kill interrupts on shutdown
152: */
153:
154: void
1.25 cube 155: simide_attach(device_t parent, device_t self, void *aux)
1.1 reinoud 156: {
1.25 cube 157: struct simide_softc *sc = device_private(self);
1.1 reinoud 158: struct podule_attach_args *pa = (void *)aux;
159: int status;
160: u_int iobase;
1.14 bjh21 161: int channel, i;
1.1 reinoud 162: struct simide_channel *scp;
1.20 thorpej 163: struct ata_channel *cp;
164: struct wdc_regs *wdr;
1.1 reinoud 165: irqhandler_t *ihp;
166:
167: /* Note the podule number and validate */
168: if (pa->pa_podule_number == -1)
169: panic("Podule has disappeared !");
170:
1.25 cube 171: sc->sc_wdcdev.sc_atac.atac_dev = self;
1.1 reinoud 172: sc->sc_podule_number = pa->pa_podule_number;
173: sc->sc_podule = pa->pa_podule;
174: podules[sc->sc_podule_number].attached = 1;
175:
1.20 thorpej 176: sc->sc_wdcdev.regs = sc->sc_wdc_regs;
177:
1.1 reinoud 178: /*
179: * Ok we need our own bus tag as the register spacing
180: * is not the default.
181: *
182: * For the podulebus the bus tag cookie is the shift
183: * to apply to registers
184: * So duplicate the bus space tag and change the
185: * cookie.
186: *
187: * Also while we are at it replace the default
188: * read/write mulitple short functions with
189: * optimised versions
190: */
191:
192: sc->sc_tag = *pa->pa_iot;
193: sc->sc_tag.bs_cookie = (void *) DRIVE_REGISTER_SPACING_SHIFT;
194: sc->sc_tag.bs_rm_2 = simide_bs_rm_2;
195: sc->sc_tag.bs_wm_2 = simide_bs_wm_2;
196: sc->sc_ctliot = pa->pa_iot;
197:
198: /* Obtain bus space handles for all the control registers */
199: if (bus_space_map(sc->sc_ctliot, pa->pa_podule->mod_base +
200: CONTROL_REGISTERS_POFFSET, CONTROL_REGISTER_SPACE, 0,
201: &sc->sc_ctlioh))
1.25 cube 202: panic("%s: Cannot map control registers", device_xname(self));
1.1 reinoud 203:
204: /* Install a clean up handler to make sure IRQ's are disabled */
205: if (shutdownhook_establish(simide_shutdown, (void *)sc) == NULL)
1.25 cube 206: panic("%s: Cannot install shutdown handler",
207: device_xname(self));
1.1 reinoud 208:
209: /* Set the interrupt info for this podule */
210: sc->sc_podule->irq_addr = pa->pa_podule->mod_base
211: + CONTROL_REGISTERS_POFFSET + (CONTROL_REGISTER_OFFSET << 2);
212: sc->sc_podule->irq_mask = STATUS_IRQ;
213:
214: sc->sc_ctl_reg = 0;
215:
216: status = bus_space_read_1(sc->sc_ctliot, sc->sc_ctlioh,
217: STATUS_REGISTER_OFFSET);
218:
1.25 cube 219: aprint_normal(":");
1.1 reinoud 220: /* If any of the bits in STATUS_FAULT are zero then we have a fault. */
221: if ((status & STATUS_FAULT) != STATUS_FAULT)
1.25 cube 222: aprint_normal(" card/cable fault (%02x) -", status);
1.1 reinoud 223:
224: if (!(status & STATUS_RESET))
1.25 cube 225: aprint_normal(" (reset)");
1.1 reinoud 226: if (!(status & STATUS_ADDR_TEST))
1.25 cube 227: aprint_normal(" (addr)");
1.1 reinoud 228: if (!(status & STATUS_CS_TEST))
1.25 cube 229: aprint_normal(" (cs)");
1.1 reinoud 230: if (!(status & STATUS_RW_TEST))
1.25 cube 231: aprint_normal(" (rw)");
1.1 reinoud 232:
1.25 cube 233: aprint_normal("\n");
1.1 reinoud 234:
235: /* Perhaps we should just abort at this point. */
236: /* if ((status & STATUS_FAULT) != STATUS_FAULT)
237: return;*/
238:
239: /*
240: * Enable IDE, Obey IORDY and disabled slow mode
241: */
242: sc->sc_ctl_reg |= CONTROL_IDE_ENABLE | CONTROL_IORDY
243: | CONTROL_SLOW_MODE_OFF;
244: bus_space_write_1(sc->sc_ctliot, sc->sc_ctlioh,
245: CONTROL_REGISTER_OFFSET, sc->sc_ctl_reg);
246:
247: /* Fill in wdc and channel infos */
1.21 thorpej 248: sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DATA16;
249: sc->sc_wdcdev.sc_atac.atac_pio_cap = 0;
250: sc->sc_wdcdev.sc_atac.atac_channels = sc->sc_chanarray;
251: sc->sc_wdcdev.sc_atac.atac_nchannels = 2;
1.26.2.1! yamt 252: sc->sc_wdcdev.wdc_maxdrives = 2;
1.1 reinoud 253: for (channel = 0 ; channel < 2; channel++) {
254: scp = &sc->simide_channels[channel];
1.20 thorpej 255: sc->sc_chanarray[channel] = &scp->sc_channel;
256: cp = &scp->sc_channel;
257: wdr = &sc->sc_wdc_regs[channel];
1.1 reinoud 258:
1.18 thorpej 259: cp->ch_channel = channel;
1.21 thorpej 260: cp->ch_atac = &sc->sc_wdcdev.sc_atac;
1.20 thorpej 261: cp->ch_queue = &scp->sc_chqueue;
262: wdr->cmd_iot = wdr->ctl_iot = &sc->sc_tag;
1.1 reinoud 263: iobase = pa->pa_podule->mod_base;
1.20 thorpej 264: if (bus_space_map(wdr->cmd_iot, iobase +
1.1 reinoud 265: simide_info[channel].drive_registers,
1.20 thorpej 266: DRIVE_REGISTERS_SPACE, 0, &wdr->cmd_baseioh))
1.1 reinoud 267: continue;
1.24 bjh21 268: for (i = 0; i < WDC_NREG; i++) {
1.20 thorpej 269: if (bus_space_subregion(wdr->cmd_iot, wdr->cmd_baseioh,
270: i, i == 0 ? 4 : 1, &wdr->cmd_iohs[i]) != 0) {
271: bus_space_unmap(wdr->cmd_iot, wdr->cmd_baseioh,
1.14 bjh21 272: DRIVE_REGISTERS_SPACE);
273: continue;
274: }
275: }
1.19 thorpej 276: wdc_init_shadow_regs(cp);
1.20 thorpej 277: if (bus_space_map(wdr->ctl_iot, iobase +
278: simide_info[channel].aux_register, 4, 0, &wdr->ctl_ioh)) {
279: bus_space_unmap(wdr->cmd_iot, wdr->cmd_baseioh,
1.1 reinoud 280: DRIVE_REGISTERS_SPACE);
281: continue;
282: }
283: /* Disable interrupts and clear any pending interrupts */
284: scp->sc_irqmask = simide_info[channel].irq_mask;
285: sc->sc_ctl_reg &= ~scp->sc_irqmask;
286: bus_space_write_1(sc->sc_ctliot, sc->sc_ctlioh,
287: CONTROL_REGISTER_OFFSET, sc->sc_ctl_reg);
288: ihp = &scp->sc_ih;
289: ihp->ih_func = simide_intr;
290: ihp->ih_arg = scp;
291: ihp->ih_level = IPL_BIO;
292: ihp->ih_name = "simide";
293: ihp->ih_maskaddr = pa->pa_podule->irq_addr;
294: ihp->ih_maskbits = scp->sc_irqmask;
295: if (irq_claim(sc->sc_podule->interrupt, ihp))
1.4 provos 296: panic("%s: Cannot claim interrupt %d",
1.25 cube 297: device_xname(self), sc->sc_podule->interrupt);
1.1 reinoud 298: /* clear any pending interrupts and enable interrupts */
299: sc->sc_ctl_reg |= scp->sc_irqmask;
300: bus_space_write_1(sc->sc_ctliot, sc->sc_ctlioh,
301: CONTROL_REGISTER_OFFSET, sc->sc_ctl_reg);
1.13 he 302: wdcattach(cp);
1.1 reinoud 303: }
304: }
305:
306: /*
307: * Card shutdown function
308: *
309: * Called via do_shutdown_hooks() during kernel shutdown.
310: * Clear the cards's interrupt mask to stop any podule interrupts.
311: */
312:
313: void
1.25 cube 314: simide_shutdown(void *arg)
1.1 reinoud 315: {
316: struct simide_softc *sc = arg;
317:
318: sc->sc_ctl_reg &= (CONTROL_PRIMARY_IRQ | CONTROL_SECONDARY_IRQ);
319:
320: /* Disable card interrupts */
321: bus_space_write_1(sc->sc_ctliot, sc->sc_ctlioh,
322: CONTROL_REGISTER_OFFSET, sc->sc_ctl_reg);
323: }
324:
325: /*
326: * Podule interrupt handler
327: *
328: * If the interrupt was from our card pass it on to the wdc interrupt handler
329: */
330: int
1.25 cube 331: simide_intr(void *arg)
1.1 reinoud 332: {
333: struct simide_channel *scp = arg;
334: irqhandler_t *ihp = &scp->sc_ih;
335: volatile u_char *intraddr = (volatile u_char *)ihp->ih_maskaddr;
336:
337: /* XXX - not bus space yet - should really be handled by podulebus */
338: if ((*intraddr) & ihp->ih_maskbits)
1.20 thorpej 339: wdcintr(&scp->sc_channel);
1.1 reinoud 340:
341: return(0);
342: }
CVSweb <webmaster@jp.NetBSD.org>