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