1 /* $NetBSD: pcc.c,v 1.22 2002/10/02 05:28:14 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe and Steve C. Woodford. 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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * Copyright (c) 1995 Charles D. Cranor 41 * All rights reserved. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. All advertising materials mentioning features or use of this software 52 * must display the following acknowledgement: 53 * This product includes software developed by Charles D. Cranor. 54 * 4. The name of the author may not be used to endorse or promote products 55 * derived from this software without specific prior written permission. 56 * 57 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 58 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 59 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 60 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 61 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 62 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 63 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 64 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 65 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 66 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 67 */ 68 69 /* 70 * peripheral channel controller 71 */ 72 73 #include <sys/param.h> 74 #include <sys/kernel.h> 75 #include <sys/systm.h> 76 #include <sys/device.h> 77 #include <sys/kcore.h> 78 79 #include <machine/cpu.h> 80 #include <machine/bus.h> 81 82 #include <mvme68k/dev/mainbus.h> 83 #include <mvme68k/dev/pccreg.h> 84 #include <mvme68k/dev/pccvar.h> 85 86 /* 87 * Autoconfiguration stuff for the PCC chip on mvme147 88 */ 89 90 void pccattach __P((struct device *, struct device *, void *)); 91 int pccmatch __P((struct device *, struct cfdata *, void *)); 92 int pccprint __P((void *, const char *)); 93 94 CFATTACH_DECL(pcc, sizeof(struct pcc_softc), 95 pccmatch, pccattach, NULL, NULL); 96 97 extern struct cfdriver pcc_cd; 98 static int pccintr __P((void *)); 99 static int pccsoftintr __P((void *)); 100 static void pccsoftintrassert __P((void)); 101 102 /* 103 * Structure used to describe a device for autoconfiguration purposes. 104 */ 105 struct pcc_device { 106 char *pcc_name; /* name of device (e.g. "clock") */ 107 bus_addr_t pcc_offset; /* offset from PCC base */ 108 }; 109 110 /* 111 * Devices that live on the PCC, attached in this order. 112 */ 113 static struct pcc_device pcc_devices[] = { 114 {"clock", 0}, 115 {"zsc", PCC_ZS0_OFF}, 116 {"zsc", PCC_ZS1_OFF}, 117 {"le", PCC_LE_OFF}, 118 {"wdsc", PCC_WDSC_OFF}, 119 {"lpt", PCC_LPT_OFF}, 120 {"vmepcc", PCC_VME_OFF}, 121 {NULL, 0}, 122 }; 123 124 static int pcc_vec2intctrl[] = { 125 PCCREG_ACFAIL_INTR_CTRL,/* PCCV_ACFAIL */ 126 PCCREG_BUSERR_INTR_CTRL,/* PCCV_BERR */ 127 PCCREG_ABORT_INTR_CTRL, /* PCCV_ABORT */ 128 PCCREG_SERIAL_INTR_CTRL,/* PCCV_ZS */ 129 PCCREG_LANCE_INTR_CTRL, /* PCCV_LE */ 130 PCCREG_SCSI_INTR_CTRL, /* PCCV_SCSI */ 131 PCCREG_DMA_INTR_CTRL, /* PCCV_DMA */ 132 PCCREG_PRNT_INTR_CTRL, /* PCCV_PRINTER */ 133 PCCREG_TMR1_INTR_CTRL, /* PCCV_TIMER1 */ 134 PCCREG_TMR2_INTR_CTRL, /* PCCV_TIMER2 */ 135 PCCREG_SOFT1_INTR_CTRL, /* PCCV_SOFT1 */ 136 PCCREG_SOFT2_INTR_CTRL /* PCCV_SOFT2 */ 137 }; 138 139 extern phys_ram_seg_t mem_clusters[]; 140 struct pcc_softc *sys_pcc; 141 142 /* The base address of the MVME147 from the VMEbus */ 143 bus_addr_t pcc_slave_base_addr; 144 145 146 /* ARGSUSED */ 147 int 148 pccmatch(parent, cf, args) 149 struct device *parent; 150 struct cfdata *cf; 151 void *args; 152 { 153 struct mainbus_attach_args *ma; 154 155 ma = args; 156 157 /* Only attach one PCC. */ 158 if (sys_pcc) 159 return (0); 160 161 return (strcmp(ma->ma_name, pcc_cd.cd_name) == 0); 162 } 163 164 /* ARGSUSED */ 165 void 166 pccattach(parent, self, args) 167 struct device *parent; 168 struct device *self; 169 void *args; 170 { 171 struct mainbus_attach_args *ma; 172 struct pcc_attach_args npa; 173 struct pcc_softc *sc; 174 u_int8_t reg; 175 int i; 176 177 ma = args; 178 sc = sys_pcc = (struct pcc_softc *) self; 179 180 /* Get a handle to the PCC's registers. */ 181 sc->sc_bust = ma->ma_bust; 182 bus_space_map(sc->sc_bust, ma->ma_offset, PCCREG_SIZE, 0, &sc->sc_bush); 183 184 /* Tell the chip the base interrupt vector */ 185 pcc_reg_write(sc, PCCREG_VECTOR_BASE, PCC_VECBASE); 186 187 printf(": Peripheral Channel Controller, " 188 "rev %d, vecbase 0x%x\n", pcc_reg_read(sc, PCCREG_REVISION), 189 pcc_reg_read(sc, PCCREG_VECTOR_BASE)); 190 191 evcnt_attach_dynamic(&sc->sc_evcnt, EVCNT_TYPE_INTR, 192 isrlink_evcnt(7), "nmi", "abort sw"); 193 194 /* Hook up interrupt handler for abort button, and enable it */ 195 pccintr_establish(PCCV_ABORT, pccintr, 7, NULL, &sc->sc_evcnt); 196 pcc_reg_write(sc, PCCREG_ABORT_INTR_CTRL, 197 PCC_ABORT_IEN | PCC_ABORT_ACK); 198 199 /* 200 * Install a handler for Software Interrupt 1 201 * and arrange to schedule soft interrupts on demand. 202 */ 203 pccintr_establish(PCCV_SOFT1, pccsoftintr, 1, sc, &sc->sc_evcnt); 204 _softintr_chipset_assert = pccsoftintrassert; 205 206 /* Make sure the global interrupt line is hot. */ 207 reg = pcc_reg_read(sc, PCCREG_GENERAL_CONTROL) | PCC_GENCR_IEN; 208 pcc_reg_write(sc, PCCREG_GENERAL_CONTROL, reg); 209 210 /* 211 * Calculate the board's VMEbus slave base address, for the 212 * benefit of the VMEchip driver. 213 * (Weird that this register is in the PCC ...) 214 */ 215 reg = pcc_reg_read(sc, PCCREG_SLAVE_BASE_ADDR) & PCC_SLAVE_BASE_MASK; 216 pcc_slave_base_addr = (bus_addr_t)reg * mem_clusters[0].size; 217 218 /* 219 * Attach configured children. 220 */ 221 npa._pa_base = ma->ma_offset; 222 for (i = 0; pcc_devices[i].pcc_name != NULL; ++i) { 223 /* 224 * Note that IPL is filled in by match function. 225 */ 226 npa.pa_name = pcc_devices[i].pcc_name; 227 npa.pa_ipl = -1; 228 npa.pa_dmat = ma->ma_dmat; 229 npa.pa_bust = ma->ma_bust; 230 npa.pa_offset = pcc_devices[i].pcc_offset + ma->ma_offset; 231 232 /* Attach the device if configured. */ 233 (void) config_found(self, &npa, pccprint); 234 } 235 } 236 237 int 238 pccprint(aux, cp) 239 void *aux; 240 const char *cp; 241 { 242 struct pcc_attach_args *pa; 243 244 pa = aux; 245 246 if (cp) 247 printf("%s at %s", pa->pa_name, cp); 248 249 printf(" offset 0x%lx", pa->pa_offset - pa->_pa_base); 250 if (pa->pa_ipl != -1) 251 printf(" ipl %d", pa->pa_ipl); 252 253 return (UNCONF); 254 } 255 256 /* 257 * pccintr_establish: establish pcc interrupt 258 */ 259 void 260 pccintr_establish(pccvec, hand, lvl, arg, evcnt) 261 int pccvec; 262 int (*hand) __P((void *)), lvl; 263 void *arg; 264 struct evcnt *evcnt; 265 { 266 267 #ifdef DEBUG 268 if (pccvec < 0 || pccvec >= PCC_NVEC) { 269 printf("pcc: illegal vector offset: 0x%x\n", pccvec); 270 panic("pccintr_establish"); 271 } 272 if (lvl < 1 || lvl > 7) { 273 printf("pcc: illegal interrupt level: %d\n", lvl); 274 panic("pccintr_establish"); 275 } 276 #endif 277 278 isrlink_vectored(hand, arg, lvl, pccvec + PCC_VECBASE, evcnt); 279 } 280 281 void 282 pccintr_disestablish(pccvec) 283 int pccvec; 284 { 285 286 #ifdef DEBUG 287 if (pccvec < 0 || pccvec >= PCC_NVEC) { 288 printf("pcc: illegal vector offset: 0x%x\n", pccvec); 289 panic("pccintr_disestablish"); 290 } 291 #endif 292 293 /* Disable the interrupt */ 294 pcc_reg_write(sys_pcc, pcc_vec2intctrl[pccvec], PCC_ICLEAR); 295 isrunlink_vectored(pccvec + PCC_VECBASE); 296 } 297 298 /* 299 * Handle NMI from abort switch. 300 */ 301 static int 302 pccintr(frame) 303 void *frame; 304 { 305 306 /* XXX wait until button pops out */ 307 pcc_reg_write(sys_pcc, PCCREG_ABORT_INTR_CTRL, 308 PCC_ABORT_IEN | PCC_ABORT_ACK); 309 310 return (nmihand(frame)); 311 } 312 313 static void 314 pccsoftintrassert(void) 315 { 316 317 /* Request a software interrupt at ipl 1 */ 318 pcc_reg_write(sys_pcc, PCCREG_SOFT1_INTR_CTRL, 1 | PCC_IENABLE); 319 } 320 321 /* 322 * Handle PCC soft interupt #1 323 */ 324 static int 325 pccsoftintr(arg) 326 void *arg; 327 { 328 struct pcc_softc *sc = arg; 329 330 /* Clear the interrupt */ 331 pcc_reg_write(sc, PCCREG_SOFT1_INTR_CTRL, 0); 332 333 /* Call the soft interrupt dispatcher */ 334 softintr_dispatch(); 335 336 return (1); 337 } 338