1 /* $NetBSD: pcc.c,v 1.28 2007/12/03 15:33:58 ad 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/cdefs.h> 74 __KERNEL_RCSID(0, "$NetBSD: pcc.c,v 1.28 2007/12/03 15:33:58 ad Exp $"); 75 76 #include <sys/param.h> 77 #include <sys/kernel.h> 78 #include <sys/systm.h> 79 #include <sys/device.h> 80 #include <sys/kcore.h> 81 82 #include <machine/cpu.h> 83 #include <machine/bus.h> 84 85 #include <mvme68k/dev/mainbus.h> 86 #include <mvme68k/dev/pccreg.h> 87 #include <mvme68k/dev/pccvar.h> 88 89 /* 90 * Autoconfiguration stuff for the PCC chip on mvme147 91 */ 92 93 void pccattach __P((struct device *, struct device *, void *)); 94 int pccmatch __P((struct device *, struct cfdata *, void *)); 95 int pccprint __P((void *, const char *)); 96 97 CFATTACH_DECL(pcc, sizeof(struct pcc_softc), 98 pccmatch, pccattach, NULL, NULL); 99 100 extern struct cfdriver pcc_cd; 101 static int pccintr __P((void *)); 102 static int pccsoftintr __P((void *)); 103 #ifdef notyet 104 static void pccsoftintrassert __P((void)); 105 #endif 106 107 /* 108 * Structure used to describe a device for autoconfiguration purposes. 109 */ 110 struct pcc_device { 111 const char *pcc_name; /* name of device (e.g. "clock") */ 112 bus_addr_t pcc_offset; /* offset from PCC base */ 113 }; 114 115 /* 116 * Devices that live on the PCC, attached in this order. 117 */ 118 static const struct pcc_device pcc_devices[] = { 119 {"clock", 0}, 120 {"zsc", PCC_ZS0_OFF}, 121 {"zsc", PCC_ZS1_OFF}, 122 {"le", PCC_LE_OFF}, 123 {"wdsc", PCC_WDSC_OFF}, 124 {"lpt", PCC_LPT_OFF}, 125 {"vmepcc", PCC_VME_OFF}, 126 {NULL, 0}, 127 }; 128 129 static int pcc_vec2intctrl[] = { 130 PCCREG_ACFAIL_INTR_CTRL,/* PCCV_ACFAIL */ 131 PCCREG_BUSERR_INTR_CTRL,/* PCCV_BERR */ 132 PCCREG_ABORT_INTR_CTRL, /* PCCV_ABORT */ 133 PCCREG_SERIAL_INTR_CTRL,/* PCCV_ZS */ 134 PCCREG_LANCE_INTR_CTRL, /* PCCV_LE */ 135 PCCREG_SCSI_INTR_CTRL, /* PCCV_SCSI */ 136 PCCREG_DMA_INTR_CTRL, /* PCCV_DMA */ 137 PCCREG_PRNT_INTR_CTRL, /* PCCV_PRINTER */ 138 PCCREG_TMR1_INTR_CTRL, /* PCCV_TIMER1 */ 139 PCCREG_TMR2_INTR_CTRL, /* PCCV_TIMER2 */ 140 PCCREG_SOFT1_INTR_CTRL, /* PCCV_SOFT1 */ 141 PCCREG_SOFT2_INTR_CTRL /* PCCV_SOFT2 */ 142 }; 143 144 extern phys_ram_seg_t mem_clusters[]; 145 struct pcc_softc *sys_pcc; 146 147 /* The base address of the MVME147 from the VMEbus */ 148 bus_addr_t pcc_slave_base_addr; 149 150 151 /* ARGSUSED */ 152 int 153 pccmatch(parent, cf, args) 154 struct device *parent; 155 struct cfdata *cf; 156 void *args; 157 { 158 struct mainbus_attach_args *ma; 159 160 ma = args; 161 162 /* Only attach one PCC. */ 163 if (sys_pcc) 164 return (0); 165 166 return (strcmp(ma->ma_name, pcc_cd.cd_name) == 0); 167 } 168 169 /* ARGSUSED */ 170 void 171 pccattach(parent, self, args) 172 struct device *parent; 173 struct device *self; 174 void *args; 175 { 176 struct mainbus_attach_args *ma; 177 struct pcc_attach_args npa; 178 struct pcc_softc *sc; 179 u_int8_t reg; 180 int i; 181 182 ma = args; 183 sc = sys_pcc = (struct pcc_softc *) self; 184 185 /* Get a handle to the PCC's registers. */ 186 sc->sc_bust = ma->ma_bust; 187 bus_space_map(sc->sc_bust, ma->ma_offset, PCCREG_SIZE, 0, &sc->sc_bush); 188 189 /* Tell the chip the base interrupt vector */ 190 pcc_reg_write(sc, PCCREG_VECTOR_BASE, PCC_VECBASE); 191 192 printf(": Peripheral Channel Controller, " 193 "rev %d, vecbase 0x%x\n", pcc_reg_read(sc, PCCREG_REVISION), 194 pcc_reg_read(sc, PCCREG_VECTOR_BASE)); 195 196 evcnt_attach_dynamic(&sc->sc_evcnt, EVCNT_TYPE_INTR, 197 isrlink_evcnt(7), "nmi", "abort sw"); 198 199 /* Hook up interrupt handler for abort button, and enable it */ 200 pccintr_establish(PCCV_ABORT, pccintr, 7, NULL, &sc->sc_evcnt); 201 pcc_reg_write(sc, PCCREG_ABORT_INTR_CTRL, 202 PCC_ABORT_IEN | PCC_ABORT_ACK); 203 204 /* 205 * Install a handler for Software Interrupt 1 206 * and arrange to schedule soft interrupts on demand. 207 */ 208 pccintr_establish(PCCV_SOFT1, pccsoftintr, 1, sc, &sc->sc_evcnt); 209 #ifdef notyet 210 _softintr_chipset_assert = pccsoftintrassert; 211 #endif 212 213 /* Make sure the global interrupt line is hot. */ 214 reg = pcc_reg_read(sc, PCCREG_GENERAL_CONTROL) | PCC_GENCR_IEN; 215 pcc_reg_write(sc, PCCREG_GENERAL_CONTROL, reg); 216 217 /* 218 * Calculate the board's VMEbus slave base address, for the 219 * benefit of the VMEchip driver. 220 * (Weird that this register is in the PCC ...) 221 */ 222 reg = pcc_reg_read(sc, PCCREG_SLAVE_BASE_ADDR) & PCC_SLAVE_BASE_MASK; 223 pcc_slave_base_addr = (bus_addr_t)reg * mem_clusters[0].size; 224 225 /* 226 * Attach configured children. 227 */ 228 npa._pa_base = ma->ma_offset; 229 for (i = 0; pcc_devices[i].pcc_name != NULL; ++i) { 230 /* 231 * Note that IPL is filled in by match function. 232 */ 233 npa.pa_name = pcc_devices[i].pcc_name; 234 npa.pa_ipl = -1; 235 npa.pa_dmat = ma->ma_dmat; 236 npa.pa_bust = ma->ma_bust; 237 npa.pa_offset = pcc_devices[i].pcc_offset + ma->ma_offset; 238 239 /* Attach the device if configured. */ 240 (void) config_found(self, &npa, pccprint); 241 } 242 } 243 244 int 245 pccprint(aux, cp) 246 void *aux; 247 const char *cp; 248 { 249 struct pcc_attach_args *pa; 250 251 pa = aux; 252 253 if (cp) 254 aprint_normal("%s at %s", pa->pa_name, cp); 255 256 aprint_normal(" offset 0x%lx", pa->pa_offset - pa->_pa_base); 257 if (pa->pa_ipl != -1) 258 aprint_normal(" ipl %d", pa->pa_ipl); 259 260 return (UNCONF); 261 } 262 263 /* 264 * pccintr_establish: establish pcc interrupt 265 */ 266 void 267 pccintr_establish(pccvec, hand, lvl, arg, evcnt) 268 int pccvec; 269 int (*hand) __P((void *)), lvl; 270 void *arg; 271 struct evcnt *evcnt; 272 { 273 274 #ifdef DEBUG 275 if (pccvec < 0 || pccvec >= PCC_NVEC) { 276 printf("pcc: illegal vector offset: 0x%x\n", pccvec); 277 panic("pccintr_establish"); 278 } 279 if (lvl < 1 || lvl > 7) { 280 printf("pcc: illegal interrupt level: %d\n", lvl); 281 panic("pccintr_establish"); 282 } 283 #endif 284 285 isrlink_vectored(hand, arg, lvl, pccvec + PCC_VECBASE, evcnt); 286 } 287 288 void 289 pccintr_disestablish(pccvec) 290 int pccvec; 291 { 292 293 #ifdef DEBUG 294 if (pccvec < 0 || pccvec >= PCC_NVEC) { 295 printf("pcc: illegal vector offset: 0x%x\n", pccvec); 296 panic("pccintr_disestablish"); 297 } 298 #endif 299 300 /* Disable the interrupt */ 301 pcc_reg_write(sys_pcc, pcc_vec2intctrl[pccvec], PCC_ICLEAR); 302 isrunlink_vectored(pccvec + PCC_VECBASE); 303 } 304 305 /* 306 * Handle NMI from abort switch. 307 */ 308 static int 309 pccintr(frame) 310 void *frame; 311 { 312 313 /* XXX wait until button pops out */ 314 pcc_reg_write(sys_pcc, PCCREG_ABORT_INTR_CTRL, 315 PCC_ABORT_IEN | PCC_ABORT_ACK); 316 317 return (nmihand(frame)); 318 } 319 320 #ifdef notyet 321 static void 322 pccsoftintrassert(void) 323 { 324 325 /* Request a software interrupt at ipl 1 */ 326 pcc_reg_write(sys_pcc, PCCREG_SOFT1_INTR_CTRL, 1 | PCC_IENABLE); 327 } 328 #endif 329 330 /* 331 * Handle PCC soft interrupt #1 332 */ 333 static int 334 pccsoftintr(arg) 335 void *arg; 336 { 337 struct pcc_softc *sc = arg; 338 339 /* Clear the interrupt */ 340 pcc_reg_write(sc, PCCREG_SOFT1_INTR_CTRL, 0); 341 342 #ifdef notyet 343 /* Call the soft interrupt dispatcher */ 344 softintr_dispatch(); 345 #endif 346 347 return (1); 348 } 349