1 /* $NetBSD: psc.c,v 1.11 2019/07/23 15:19:07 rin Exp $ */ 2 3 /*- 4 * Copyright (c) 1997 David Huang <khym (at) 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.11 2019/07/23 15:19:07 rin 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 static int stop_read_psc_dma(int, int, uint32_t *); 55 static int stop_write_psc_dma(int, int, uint32_t *); 56 57 void (*psc3_ihandler)(void *) = psc_lev3_noint; 58 void *psc3_iarg; 59 60 int (*psc4_itab[4])(void *) = { 61 psc_lev4_noint, /* 0 */ 62 psc_lev4_noint, /* 1 */ 63 psc_lev4_noint, /* 2 */ 64 psc_lev4_noint /* 3 */ 65 }; 66 67 void *psc4_iarg[4] = { 68 (void *)0, (void *)1, (void *)2, (void *)3 69 }; 70 71 void (*psc5_itab[2])(void *) = { 72 psc_lev5_noint, /* 0 */ 73 psc_lev5_noint /* 1 */ 74 }; 75 76 void *psc5_iarg[2] = { 77 (void *)0, (void *)1 78 }; 79 80 void (*psc6_itab[3])(void *) = { 81 psc_lev6_noint, /* 0 */ 82 psc_lev6_noint, /* 1 */ 83 psc_lev6_noint /* 2 */ 84 }; 85 86 void *psc6_iarg[3] = { 87 (void *)0, (void *)1, (void *)2 88 }; 89 90 /* 91 * Make excessively sure that all PSC DMA is shut down. 92 */ 93 void 94 psc_kill_dma(void) 95 { 96 int i; 97 98 for (i = 0; i < 9; i++) { 99 psc_reg2(PSC_CTLBASE + (i << 4)) = 0x8800; 100 psc_reg2(PSC_CTLBASE + (i << 4)) = 0x1000; 101 psc_reg2(PSC_CMDBASE + (i << 5)) = 0x1100; 102 psc_reg2(PSC_CMDBASE + (i << 5) + PSC_SET1) = 0x1100; 103 } 104 } 105 106 /* 107 * Setup the interrupt vectors and disable most of the PSC interrupts 108 */ 109 void 110 psc_init(void) 111 { 112 int s, i; 113 114 /* 115 * Only Quadra AVs have a PSC. 116 */ 117 if (current_mac_model->class == MACH_CLASSAV) { 118 s = splhigh(); 119 psc_kill_dma(); 120 intr_establish(psc_lev3_intr, NULL, 3); 121 intr_establish(psc_lev4_intr, NULL, 4); 122 intr_establish(psc_lev5_intr, NULL, 5); 123 intr_establish(psc_lev6_intr, NULL, 6); 124 for (i = 3; i < 7; i++) { 125 /* Clear any flags */ 126 psc_reg1(PSC_ISR_BASE + 0x10 * i) = 0x0F; 127 /* Clear any interrupt enable */ 128 psc_reg1(PSC_IER_BASE + 0x10 * i) = 0x0F; 129 } 130 psc_reg1(PSC_LEV4_IER) = 0x86; /* enable SCC */ 131 splx(s); 132 } 133 } 134 135 int 136 add_psc_lev3_intr(void (*handler)(void *), void *arg) 137 { 138 int s; 139 140 s = splhigh(); 141 142 psc3_ihandler = handler; 143 psc3_iarg = arg; 144 145 splx(s); 146 147 return 1; 148 } 149 150 int 151 remove_psc_lev3_intr(void) 152 { 153 return add_psc_lev3_intr(psc_lev3_noint, (void *)0); 154 } 155 156 int 157 psc_lev3_intr(void *arg) 158 { 159 u_int8_t intbits; 160 161 while ((intbits = psc_reg1(PSC_LEV3_ISR)) != psc_reg1(PSC_LEV3_ISR)) 162 ; 163 intbits &= 0x1 & psc_reg1(PSC_LEV3_IER); 164 165 if (intbits) 166 psc3_ihandler(psc3_iarg); 167 168 return 0; 169 } 170 171 static void 172 psc_lev3_noint(void *arg) 173 { 174 printf("psc_lev3_noint\n"); 175 } 176 177 int 178 psc_lev4_intr(void *arg) 179 { 180 u_int8_t intbits, bitnum; 181 u_int mask; 182 183 while ((intbits = psc_reg1(PSC_LEV4_ISR)) != psc_reg1(PSC_LEV4_ISR)) 184 ; 185 intbits &= 0xf & psc_reg1(PSC_LEV4_IER); 186 187 mask = 1; 188 bitnum = 0; 189 do { 190 if (intbits & mask) 191 psc4_itab[bitnum](psc4_iarg[bitnum]); 192 mask <<= 1; 193 } while (intbits >= mask && ++bitnum); 194 195 return 0; 196 } 197 198 int 199 add_psc_lev4_intr(int dev, int (*handler)(void *), void *arg) 200 { 201 int s; 202 203 if ((dev < 0) || (dev > 3)) 204 return 0; 205 206 s = splhigh(); 207 208 psc4_itab[dev] = handler; 209 psc4_iarg[dev] = arg; 210 211 splx(s); 212 213 return 1; 214 } 215 216 int 217 remove_psc_lev4_intr(int dev) 218 { 219 return add_psc_lev4_intr(dev, psc_lev4_noint, (void *)dev); 220 } 221 222 int 223 psc_lev4_noint(void *arg) 224 { 225 printf("psc_lev4_noint: device %d\n", (int)arg); 226 return 0; 227 } 228 229 int 230 psc_lev5_intr(void *arg) 231 { 232 u_int8_t intbits, bitnum; 233 u_int mask; 234 235 while ((intbits = psc_reg1(PSC_LEV5_ISR)) != psc_reg1(PSC_LEV5_ISR)) 236 ; 237 intbits &= 0x3 & psc_reg1(PSC_LEV5_IER); 238 239 mask = 1; 240 bitnum = 0; 241 do { 242 if (intbits & mask) 243 psc5_itab[bitnum](psc5_iarg[bitnum]); 244 mask <<= 1; 245 } while (intbits >= mask && ++bitnum); 246 247 return 0; 248 } 249 250 int 251 add_psc_lev5_intr(int dev, void (*handler)(void *), void *arg) 252 { 253 int s; 254 255 if ((dev < 0) || (dev > 1)) 256 return 0; 257 258 s = splhigh(); 259 260 psc5_itab[dev] = handler; 261 psc5_iarg[dev] = arg; 262 263 splx(s); 264 265 return 1; 266 } 267 268 int 269 remove_psc_lev5_intr(int dev) 270 { 271 return add_psc_lev5_intr(dev, psc_lev5_noint, (void *)dev); 272 } 273 274 void 275 psc_lev5_noint(void *arg) 276 { 277 printf("psc_lev5_noint: device %d\n", (int)arg); 278 } 279 280 int 281 psc_lev6_intr(void *arg) 282 { 283 u_int8_t intbits, bitnum; 284 u_int mask; 285 286 while ((intbits = psc_reg1(PSC_LEV6_ISR)) != psc_reg1(PSC_LEV6_ISR)) 287 ; 288 intbits &= 0x7 & psc_reg1(PSC_LEV6_IER); 289 290 mask = 1; 291 bitnum = 0; 292 do { 293 if (intbits & mask) 294 psc6_itab[bitnum](psc6_iarg[bitnum]); 295 mask <<= 1; 296 } while (intbits >= mask && ++bitnum); 297 298 return 0; 299 } 300 301 int 302 add_psc_lev6_intr(int dev, void (*handler)(void *), void *arg) 303 { 304 int s; 305 306 if ((dev < 0) || (dev > 2)) 307 return 0; 308 309 s = splhigh(); 310 311 psc6_itab[dev] = handler; 312 psc6_iarg[dev] = arg; 313 314 splx(s); 315 316 return 1; 317 } 318 319 int 320 remove_psc_lev6_intr(int dev) 321 { 322 return add_psc_lev6_intr(dev, psc_lev6_noint, (void *)dev); 323 } 324 325 void 326 psc_lev6_noint(void *arg) 327 { 328 printf("psc_lev6_noint: device %d\n", (int)arg); 329 } 330 331 /* 332 * DMA Control routines for esp(4). 333 * XXX Need to be merged with DMA engine of mc(4). 334 */ 335 336 int 337 start_psc_dma(int channel, int *rset, bus_addr_t addr, uint32_t len, int datain) 338 { 339 int chan_ctrl, rset_addr, rset_len, rset_cmd, s; 340 341 s = splhigh(); 342 343 chan_ctrl = PSC_CTLBASE + (channel << 4); 344 345 pause_psc_dma(channel); 346 347 *rset = (psc_reg2(chan_ctrl) & 1) << 4; 348 349 rset_addr = PSC_ADDRBASE + (0x20 * channel) + *rset; 350 rset_len = rset_addr + 4; 351 rset_cmd = rset_addr + 8; 352 353 (void)psc_reg2(rset_cmd); 354 psc_reg4(rset_len) = len; 355 psc_reg4(rset_addr) = addr; 356 357 if (datain) 358 psc_reg2(rset_cmd) = 0x8200; 359 else 360 psc_reg2(rset_cmd) = 0x200; 361 362 psc_reg2(rset_cmd) = 0x100; 363 psc_reg2(rset_cmd) = 0x8800; 364 psc_reg2(chan_ctrl) = 0x400; 365 366 splx(s); 367 368 return 0; 369 } 370 371 int 372 pause_psc_dma(int channel) 373 { 374 int chan_ctrl, s; 375 376 s = splhigh(); 377 378 chan_ctrl = PSC_CTLBASE + (channel << 4); 379 380 psc_reg2(chan_ctrl) = 0x8400; 381 382 while (!(psc_reg2(chan_ctrl) & 0x4000)) 383 continue; 384 385 splx(s); 386 387 return 0; 388 } 389 390 int 391 wait_psc_dma(int channel, int rset, uint32_t *residual) 392 { 393 int rset_addr, rset_len, rset_cmd, s; 394 395 s = splhigh(); 396 397 rset_addr = PSC_ADDRBASE + (0x20 * channel) + rset; 398 rset_len = rset_addr + 4; 399 rset_cmd = rset_addr + 8; 400 401 while (!(psc_reg2(rset_cmd) & 0x100)) 402 continue; 403 404 while (psc_reg2(rset_cmd) & 0x800) 405 continue; 406 407 *residual = psc_reg4(rset_len); 408 409 splx(s); 410 411 if (*residual) 412 return -1; 413 else 414 return 0; 415 } 416 417 int 418 stop_psc_dma(int channel, int rset, uint32_t *residual, int datain) 419 { 420 int rval, s; 421 422 s = splhigh(); 423 424 if (datain) 425 rval = stop_read_psc_dma(channel, rset, residual); 426 else 427 rval = stop_write_psc_dma(channel, rset, residual); 428 429 splx(s); 430 431 return rval; 432 } 433 434 static int 435 stop_read_psc_dma(int channel, int rset, uint32_t *residual) 436 { 437 int chan_ctrl, rset_addr, rset_len, rset_cmd; 438 439 chan_ctrl = PSC_CTLBASE + (channel << 4); 440 rset_addr = PSC_ADDRBASE + (0x20 * channel) + rset; 441 rset_len = rset_addr + 4; 442 rset_cmd = rset_addr + 8; 443 444 if (psc_reg2(rset_cmd) & 0x400) { 445 *residual = 0; 446 return 0; 447 } 448 449 psc_reg2(chan_ctrl) = 0x8200; 450 451 while (psc_reg2(chan_ctrl) & 0x200) 452 continue; 453 454 pause_psc_dma(channel); 455 456 *residual = psc_reg4(rset_len); 457 if (*residual == 0) 458 return 0; 459 460 do { 461 psc_reg4(rset_len) = 0; 462 } while (psc_reg4(rset_len)); 463 464 return 0; 465 } 466 467 static int 468 stop_write_psc_dma(int channel, int rset, uint32_t *residual) 469 { 470 int chan_ctrl, rset_addr, rset_len, rset_cmd; 471 472 rset_addr = PSC_ADDRBASE + (0x20 * channel) + rset; 473 rset_cmd = rset_addr + 8; 474 475 if (psc_reg2(rset_cmd) & 0x400) { 476 *residual = 0; 477 return 0; 478 } 479 480 chan_ctrl = PSC_CTLBASE + (channel << 4); 481 rset_len = rset_addr + 4; 482 483 pause_psc_dma(channel); 484 485 *residual = psc_reg4(rset_len); 486 487 psc_reg2(chan_ctrl) = 0x8800; 488 489 return 0; 490 } 491