1 /* $NetBSD: simide.c,v 1.33 2023/12/20 06:13:59 thorpej Exp $ */ 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 */ 41 42 #include <sys/cdefs.h> 43 __KERNEL_RCSID(0, "$NetBSD: simide.c,v 1.33 2023/12/20 06:13:59 thorpej Exp $"); 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/conf.h> 48 #include <sys/device.h> 49 #include <sys/bus.h> 50 51 #include <machine/intr.h> 52 #include <machine/io.h> 53 #include <acorn32/podulebus/podulebus.h> 54 #include <acorn32/podulebus/simidereg.h> 55 56 #include <dev/ata/atavar.h> 57 #include <dev/ic/wdcreg.h> 58 #include <dev/ic/wdcvar.h> 59 #include <dev/podulebus/podules.h> 60 61 62 /* 63 * Simtec IDE podule device. 64 * 65 * This probes and attaches the top level Simtec IDE device to the podulebus. 66 * It then configures any children of the Simtec IDE device. 67 * The attach args specify whether it is configuring the primary or 68 * secondary channel. 69 * The children are expected to be wdc devices using simide attachments. 70 */ 71 72 /* 73 * Simtec IDE card softc structure. 74 * 75 * Contains the device node, podule information and global information 76 * required by the driver such as the card version and the interrupt mask. 77 */ 78 79 struct simide_softc { 80 struct wdc_softc sc_wdcdev; /* common wdc definitions */ 81 struct ata_channel *sc_chanarray[2]; /* channels definition */ 82 podule_t *sc_podule; /* Our podule info */ 83 int sc_podule_number; /* Our podule number */ 84 int sc_ctl_reg; /* Global ctl reg */ 85 int sc_version; /* Card version */ 86 bus_space_tag_t sc_ctliot; /* Bus tag */ 87 bus_space_handle_t sc_ctlioh; /* control handle */ 88 struct bus_space sc_tag; /* custom tag */ 89 struct simide_channel { 90 struct ata_channel sc_channel; /* generic part */ 91 irqhandler_t sc_ih; /* interrupt handler */ 92 int sc_irqmask; /* IRQ mask for this channel */ 93 } simide_channels[2]; 94 struct wdc_regs sc_wdc_regs[2]; 95 }; 96 97 int simide_probe (device_t, cfdata_t, void *); 98 void simide_attach (device_t, device_t, void *); 99 void simide_shutdown (void *arg); 100 int simide_intr (void *arg); 101 102 CFATTACH_DECL_NEW(simide, sizeof(struct simide_softc), 103 simide_probe, simide_attach, NULL, NULL); 104 105 106 /* 107 * Define prototypes for custom bus space functions. 108 */ 109 110 bs_rm_2_proto(simide); 111 bs_wm_2_proto(simide); 112 113 /* 114 * Create an array of address structures. These define the addresses and 115 * masks needed for the different channels. 116 * 117 * index = channel 118 */ 119 120 struct { 121 u_int drive_registers; 122 u_int aux_register; 123 u_int irq_mask; 124 } simide_info[] = { 125 { PRIMARY_DRIVE_REGISTERS_POFFSET, PRIMARY_AUX_REGISTER_POFFSET, 126 CONTROL_PRIMARY_IRQ }, 127 { SECONDARY_DRIVE_REGISTERS_POFFSET, SECONDARY_AUX_REGISTER_POFFSET, 128 CONTROL_SECONDARY_IRQ } 129 }; 130 131 /* 132 * Card probe function 133 * 134 * Just match the manufacturer and podule ID's 135 */ 136 137 int 138 simide_probe(device_t parent, cfdata_t cf, void *aux) 139 { 140 struct podule_attach_args *pa = (void *)aux; 141 142 return (pa->pa_product == PODULE_SIMTEC_IDE); 143 } 144 145 /* 146 * Card attach function 147 * 148 * Identify the card version and configure any children. 149 * Install a shutdown handler to kill interrupts on shutdown 150 */ 151 152 void 153 simide_attach(device_t parent, device_t self, void *aux) 154 { 155 struct simide_softc *sc = device_private(self); 156 struct podule_attach_args *pa = (void *)aux; 157 int status; 158 u_int iobase; 159 int channel, i; 160 struct simide_channel *scp; 161 struct ata_channel *cp; 162 struct wdc_regs *wdr; 163 irqhandler_t *ihp; 164 165 /* Note the podule number and validate */ 166 if (pa->pa_podule_number == -1) 167 panic("Podule has disappeared !"); 168 169 sc->sc_wdcdev.sc_atac.atac_dev = self; 170 sc->sc_podule_number = pa->pa_podule_number; 171 sc->sc_podule = pa->pa_podule; 172 podules[sc->sc_podule_number].attached = 1; 173 174 sc->sc_wdcdev.regs = sc->sc_wdc_regs; 175 176 /* 177 * Ok we need our own bus tag as the register spacing 178 * is not the default. 179 * 180 * For the podulebus the bus tag cookie is the shift 181 * to apply to registers 182 * So duplicate the bus space tag and change the 183 * cookie. 184 * 185 * Also while we are at it replace the default 186 * read/write multiple short functions with 187 * optimised versions 188 */ 189 190 sc->sc_tag = *pa->pa_iot; 191 sc->sc_tag.bs_cookie = (void *) DRIVE_REGISTER_SPACING_SHIFT; 192 sc->sc_tag.bs_rm_2 = simide_bs_rm_2; 193 sc->sc_tag.bs_wm_2 = simide_bs_wm_2; 194 sc->sc_ctliot = pa->pa_iot; 195 196 /* Obtain bus space handles for all the control registers */ 197 if (bus_space_map(sc->sc_ctliot, pa->pa_podule->mod_base + 198 CONTROL_REGISTERS_POFFSET, CONTROL_REGISTER_SPACE, 0, 199 &sc->sc_ctlioh)) 200 panic("%s: Cannot map control registers", device_xname(self)); 201 202 /* Install a clean up handler to make sure IRQ's are disabled */ 203 if (shutdownhook_establish(simide_shutdown, (void *)sc) == NULL) 204 panic("%s: Cannot install shutdown handler", 205 device_xname(self)); 206 207 /* Set the interrupt info for this podule */ 208 sc->sc_podule->irq_addr = pa->pa_podule->mod_base 209 + CONTROL_REGISTERS_POFFSET + (CONTROL_REGISTER_OFFSET << 2); 210 sc->sc_podule->irq_mask = STATUS_IRQ; 211 212 sc->sc_ctl_reg = 0; 213 214 status = bus_space_read_1(sc->sc_ctliot, sc->sc_ctlioh, 215 STATUS_REGISTER_OFFSET); 216 217 aprint_normal(":"); 218 /* If any of the bits in STATUS_FAULT are zero then we have a fault. */ 219 if ((status & STATUS_FAULT) != STATUS_FAULT) 220 aprint_normal(" card/cable fault (%02x) -", status); 221 222 if (!(status & STATUS_RESET)) 223 aprint_normal(" (reset)"); 224 if (!(status & STATUS_ADDR_TEST)) 225 aprint_normal(" (addr)"); 226 if (!(status & STATUS_CS_TEST)) 227 aprint_normal(" (cs)"); 228 if (!(status & STATUS_RW_TEST)) 229 aprint_normal(" (rw)"); 230 231 aprint_normal("\n"); 232 233 /* Perhaps we should just abort at this point. */ 234 /* if ((status & STATUS_FAULT) != STATUS_FAULT) 235 return;*/ 236 237 /* 238 * Enable IDE, Obey IORDY and disabled slow mode 239 */ 240 sc->sc_ctl_reg |= CONTROL_IDE_ENABLE | CONTROL_IORDY 241 | CONTROL_SLOW_MODE_OFF; 242 bus_space_write_1(sc->sc_ctliot, sc->sc_ctlioh, 243 CONTROL_REGISTER_OFFSET, sc->sc_ctl_reg); 244 245 /* Fill in wdc and channel infos */ 246 sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DATA16; 247 sc->sc_wdcdev.sc_atac.atac_pio_cap = 0; 248 sc->sc_wdcdev.sc_atac.atac_channels = sc->sc_chanarray; 249 sc->sc_wdcdev.sc_atac.atac_nchannels = 2; 250 sc->sc_wdcdev.wdc_maxdrives = 2; 251 for (channel = 0 ; channel < 2; channel++) { 252 scp = &sc->simide_channels[channel]; 253 sc->sc_chanarray[channel] = &scp->sc_channel; 254 cp = &scp->sc_channel; 255 wdr = &sc->sc_wdc_regs[channel]; 256 257 cp->ch_channel = channel; 258 cp->ch_atac = &sc->sc_wdcdev.sc_atac; 259 wdr->cmd_iot = wdr->ctl_iot = &sc->sc_tag; 260 iobase = pa->pa_podule->mod_base; 261 if (bus_space_map(wdr->cmd_iot, iobase + 262 simide_info[channel].drive_registers, 263 DRIVE_REGISTERS_SPACE, 0, &wdr->cmd_baseioh)) 264 continue; 265 for (i = 0; i < WDC_NREG; i++) { 266 if (bus_space_subregion(wdr->cmd_iot, wdr->cmd_baseioh, 267 i, i == 0 ? 4 : 1, &wdr->cmd_iohs[i]) != 0) { 268 bus_space_unmap(wdr->cmd_iot, wdr->cmd_baseioh, 269 DRIVE_REGISTERS_SPACE); 270 continue; 271 } 272 } 273 wdc_init_shadow_regs(wdr); 274 if (bus_space_map(wdr->ctl_iot, iobase + 275 simide_info[channel].aux_register, 4, 0, &wdr->ctl_ioh)) { 276 bus_space_unmap(wdr->cmd_iot, wdr->cmd_baseioh, 277 DRIVE_REGISTERS_SPACE); 278 continue; 279 } 280 /* Disable interrupts and clear any pending interrupts */ 281 scp->sc_irqmask = simide_info[channel].irq_mask; 282 sc->sc_ctl_reg &= ~scp->sc_irqmask; 283 bus_space_write_1(sc->sc_ctliot, sc->sc_ctlioh, 284 CONTROL_REGISTER_OFFSET, sc->sc_ctl_reg); 285 ihp = &scp->sc_ih; 286 ihp->ih_func = simide_intr; 287 ihp->ih_arg = scp; 288 ihp->ih_level = IPL_BIO; 289 ihp->ih_name = "simide"; 290 ihp->ih_maskaddr = pa->pa_podule->irq_addr; 291 ihp->ih_maskbits = scp->sc_irqmask; 292 if (irq_claim(sc->sc_podule->interrupt, ihp)) 293 panic("%s: Cannot claim interrupt %d", 294 device_xname(self), sc->sc_podule->interrupt); 295 /* clear any pending interrupts and enable interrupts */ 296 sc->sc_ctl_reg |= scp->sc_irqmask; 297 bus_space_write_1(sc->sc_ctliot, sc->sc_ctlioh, 298 CONTROL_REGISTER_OFFSET, sc->sc_ctl_reg); 299 wdcattach(cp); 300 } 301 } 302 303 /* 304 * Card shutdown function 305 * 306 * Called via do_shutdown_hooks() during kernel shutdown. 307 * Clear the cards's interrupt mask to stop any podule interrupts. 308 */ 309 310 void 311 simide_shutdown(void *arg) 312 { 313 struct simide_softc *sc = arg; 314 315 sc->sc_ctl_reg &= (CONTROL_PRIMARY_IRQ | CONTROL_SECONDARY_IRQ); 316 317 /* Disable card interrupts */ 318 bus_space_write_1(sc->sc_ctliot, sc->sc_ctlioh, 319 CONTROL_REGISTER_OFFSET, sc->sc_ctl_reg); 320 } 321 322 /* 323 * Podule interrupt handler 324 * 325 * If the interrupt was from our card pass it on to the wdc interrupt handler 326 */ 327 int 328 simide_intr(void *arg) 329 { 330 struct simide_channel *scp = arg; 331 irqhandler_t *ihp = &scp->sc_ih; 332 volatile u_char *intraddr = (volatile u_char *)ihp->ih_maskaddr; 333 334 /* XXX - not bus space yet - should really be handled by podulebus */ 335 if ((*intraddr) & ihp->ih_maskbits) 336 wdcintr(&scp->sc_channel); 337 338 return(0); 339 } 340