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