1 /* $NetBSD: psc.c,v 1.10 2005/12/11 12:18:03 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1997 David Huang <khym@azeotrope.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 */ 27 28 /* 29 * This handles registration/unregistration of PSC (Peripheral 30 * Subsystem Controller) interrupts. The PSC is used only on the 31 * Centris/Quadra 660av and the Quadra 840av. 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: psc.c,v 1.10 2005/12/11 12:18:03 christos Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 40 #include <machine/bus.h> 41 #include <machine/cpu.h> 42 #include <machine/psc.h> 43 44 static void psc_kill_dma(void); 45 int psc_lev3_intr(void *); 46 static void psc_lev3_noint(void *); 47 int psc_lev4_intr(void *); 48 static int psc_lev4_noint(void *); 49 int psc_lev5_intr(void *); 50 static void psc_lev5_noint(void *); 51 int psc_lev6_intr(void *); 52 static void psc_lev6_noint(void *); 53 54 void (*psc3_ihandler)(void *) = psc_lev3_noint; 55 void *psc3_iarg; 56 57 int (*psc4_itab[4])(void *) = { 58 psc_lev4_noint, /* 0 */ 59 psc_lev4_noint, /* 1 */ 60 psc_lev4_noint, /* 2 */ 61 psc_lev4_noint /* 3 */ 62 }; 63 64 void *psc4_iarg[4] = { 65 (void *)0, (void *)1, (void *)2, (void *)3 66 }; 67 68 void (*psc5_itab[2])(void *) = { 69 psc_lev5_noint, /* 0 */ 70 psc_lev5_noint /* 1 */ 71 }; 72 73 void *psc5_iarg[2] = { 74 (void *)0, (void *)1 75 }; 76 77 void (*psc6_itab[3])(void *) = { 78 psc_lev6_noint, /* 0 */ 79 psc_lev6_noint, /* 1 */ 80 psc_lev6_noint /* 2 */ 81 }; 82 83 void *psc6_iarg[3] = { 84 (void *)0, (void *)1, (void *)2 85 }; 86 87 /* 88 * Make excessively sure that all PSC DMA is shut down. 89 */ 90 void 91 psc_kill_dma(void) 92 { 93 int i; 94 95 for (i = 0; i < 9; i++) { 96 psc_reg2(PSC_CTLBASE + (i << 4)) = 0x8800; 97 psc_reg2(PSC_CTLBASE + (i << 4)) = 0x1000; 98 psc_reg2(PSC_CMDBASE + (i << 5)) = 0x1100; 99 psc_reg2(PSC_CMDBASE + (i << 5) + PSC_SET1) = 0x1100; 100 } 101 } 102 103 /* 104 * Setup the interrupt vectors and disable most of the PSC interrupts 105 */ 106 void 107 psc_init(void) 108 { 109 int s, i; 110 111 /* 112 * Only Quadra AVs have a PSC. 113 */ 114 if (current_mac_model->class == MACH_CLASSAV) { 115 s = splhigh(); 116 psc_kill_dma(); 117 intr_establish(psc_lev3_intr, NULL, 3); 118 intr_establish(psc_lev4_intr, NULL, 4); 119 intr_establish(psc_lev5_intr, NULL, 5); 120 intr_establish(psc_lev6_intr, NULL, 6); 121 for (i = 3; i < 7; i++) { 122 /* Clear any flags */ 123 psc_reg1(PSC_ISR_BASE + 0x10 * i) = 0x0F; 124 /* Clear any interrupt enable */ 125 psc_reg1(PSC_IER_BASE + 0x10 * i) = 0x0F; 126 } 127 psc_reg1(PSC_LEV4_IER) = 0x86; /* enable SCC */ 128 splx(s); 129 } 130 } 131 132 int 133 add_psc_lev3_intr(void (*handler)(void *), void *arg) 134 { 135 int s; 136 137 s = splhigh(); 138 139 psc3_ihandler = handler; 140 psc3_iarg = arg; 141 142 splx(s); 143 144 return 1; 145 } 146 147 int 148 remove_psc_lev3_intr(void) 149 { 150 return add_psc_lev3_intr(psc_lev3_noint, (void *)0); 151 } 152 153 int 154 psc_lev3_intr(void *arg) 155 { 156 u_int8_t intbits; 157 158 while ((intbits = psc_reg1(PSC_LEV3_ISR)) != psc_reg1(PSC_LEV3_ISR)) 159 ; 160 intbits &= 0x1 & psc_reg1(PSC_LEV3_IER); 161 162 if (intbits) 163 psc3_ihandler(psc3_iarg); 164 165 return 0; 166 } 167 168 static void 169 psc_lev3_noint(void *arg) 170 { 171 printf("psc_lev3_noint\n"); 172 } 173 174 int 175 psc_lev4_intr(void *arg) 176 { 177 u_int8_t intbits, bitnum; 178 u_int mask; 179 180 while ((intbits = psc_reg1(PSC_LEV4_ISR)) != psc_reg1(PSC_LEV4_ISR)) 181 ; 182 intbits &= 0xf & psc_reg1(PSC_LEV4_IER); 183 184 mask = 1; 185 bitnum = 0; 186 do { 187 if (intbits & mask) 188 psc4_itab[bitnum](psc4_iarg[bitnum]); 189 mask <<= 1; 190 } while (intbits >= mask && ++bitnum); 191 192 return 0; 193 } 194 195 int 196 add_psc_lev4_intr(int dev, int (*handler)(void *), void *arg) 197 { 198 int s; 199 200 if ((dev < 0) || (dev > 3)) 201 return 0; 202 203 s = splhigh(); 204 205 psc4_itab[dev] = handler; 206 psc4_iarg[dev] = arg; 207 208 splx(s); 209 210 return 1; 211 } 212 213 int 214 remove_psc_lev4_intr(int dev) 215 { 216 return add_psc_lev4_intr(dev, psc_lev4_noint, (void *)dev); 217 } 218 219 int 220 psc_lev4_noint(void *arg) 221 { 222 printf("psc_lev4_noint: device %d\n", (int)arg); 223 return 0; 224 } 225 226 int 227 psc_lev5_intr(void *arg) 228 { 229 u_int8_t intbits, bitnum; 230 u_int mask; 231 232 while ((intbits = psc_reg1(PSC_LEV5_ISR)) != psc_reg1(PSC_LEV5_ISR)) 233 ; 234 intbits &= 0x3 & psc_reg1(PSC_LEV5_IER); 235 236 mask = 1; 237 bitnum = 0; 238 do { 239 if (intbits & mask) 240 psc5_itab[bitnum](psc5_iarg[bitnum]); 241 mask <<= 1; 242 } while (intbits >= mask && ++bitnum); 243 244 return 0; 245 } 246 247 int 248 add_psc_lev5_intr(int dev, void (*handler)(void *), void *arg) 249 { 250 int s; 251 252 if ((dev < 0) || (dev > 1)) 253 return 0; 254 255 s = splhigh(); 256 257 psc5_itab[dev] = handler; 258 psc5_iarg[dev] = arg; 259 260 splx(s); 261 262 return 1; 263 } 264 265 int 266 remove_psc_lev5_intr(int dev) 267 { 268 return add_psc_lev5_intr(dev, psc_lev5_noint, (void *)dev); 269 } 270 271 void 272 psc_lev5_noint(void *arg) 273 { 274 printf("psc_lev5_noint: device %d\n", (int)arg); 275 } 276 277 int 278 psc_lev6_intr(void *arg) 279 { 280 u_int8_t intbits, bitnum; 281 u_int mask; 282 283 while ((intbits = psc_reg1(PSC_LEV6_ISR)) != psc_reg1(PSC_LEV6_ISR)) 284 ; 285 intbits &= 0x7 & psc_reg1(PSC_LEV6_IER); 286 287 mask = 1; 288 bitnum = 0; 289 do { 290 if (intbits & mask) 291 psc6_itab[bitnum](psc6_iarg[bitnum]); 292 mask <<= 1; 293 } while (intbits >= mask && ++bitnum); 294 295 return 0; 296 } 297 298 int 299 add_psc_lev6_intr(int dev, void (*handler)(void *), void *arg) 300 { 301 int s; 302 303 if ((dev < 0) || (dev > 2)) 304 return 0; 305 306 s = splhigh(); 307 308 psc6_itab[dev] = handler; 309 psc6_iarg[dev] = arg; 310 311 splx(s); 312 313 return 1; 314 } 315 316 int 317 remove_psc_lev6_intr(int dev) 318 { 319 return add_psc_lev6_intr(dev, psc_lev6_noint, (void *)dev); 320 } 321 322 void 323 psc_lev6_noint(void *arg) 324 { 325 printf("psc_lev6_noint: device %d\n", (int)arg); 326 } 327