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