1 1.39 thorpej /* $NetBSD: tc_3000_300.c,v 1.39 2021/05/07 16:58:34 thorpej Exp $ */ 2 1.1 cgd 3 1.1 cgd /* 4 1.6 cgd * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University. 5 1.1 cgd * All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Author: Chris G. Demetriou 8 1.32 matt * 9 1.1 cgd * Permission to use, copy, modify and distribute this software and 10 1.1 cgd * its documentation is hereby granted, provided that both the copyright 11 1.1 cgd * notice and this permission notice appear in all copies of the 12 1.1 cgd * software, derivative works or modified versions, and any portions 13 1.1 cgd * thereof, and that both notices appear in supporting documentation. 14 1.32 matt * 15 1.32 matt * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 16 1.32 matt * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 17 1.1 cgd * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 18 1.32 matt * 19 1.1 cgd * Carnegie Mellon requests users of this software to return to 20 1.1 cgd * 21 1.1 cgd * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU 22 1.1 cgd * School of Computer Science 23 1.1 cgd * Carnegie Mellon University 24 1.1 cgd * Pittsburgh PA 15213-3890 25 1.1 cgd * 26 1.1 cgd * any improvements or extensions that they make and grant Carnegie the 27 1.1 cgd * rights to redistribute these changes. 28 1.1 cgd */ 29 1.13 cgd 30 1.14 cgd #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 31 1.14 cgd 32 1.39 thorpej __KERNEL_RCSID(0, "$NetBSD: tc_3000_300.c,v 1.39 2021/05/07 16:58:34 thorpej Exp $"); 33 1.1 cgd 34 1.1 cgd #include <sys/param.h> 35 1.9 cgd #include <sys/systm.h> 36 1.1 cgd #include <sys/device.h> 37 1.38 thorpej #include <sys/kmem.h> 38 1.37 thorpej #include <sys/cpu.h> 39 1.1 cgd 40 1.1 cgd #include <machine/autoconf.h> 41 1.1 cgd #include <machine/pte.h> 42 1.1 cgd 43 1.4 cgd #include <dev/tc/tcvar.h> 44 1.21 nisimura #include <dev/tc/ioasicreg.h> 45 1.4 cgd #include <alpha/tc/tc_conf.h> 46 1.1 cgd #include <alpha/tc/tc_3000_300.h> 47 1.17 briggs 48 1.19 drochner #include "wsdisplay.h" 49 1.17 briggs #include "sfb.h" 50 1.17 briggs 51 1.17 briggs #if NSFB > 0 52 1.28 dsl extern int sfb_cnattach(tc_addr_t); 53 1.17 briggs #endif 54 1.1 cgd 55 1.39 thorpej static int tc_3000_300_intrnull(void *); 56 1.4 cgd 57 1.4 cgd #define C(x) ((void *)(u_long)x) 58 1.9 cgd #define KV(x) (ALPHA_PHYS_TO_K0SEG(x)) 59 1.1 cgd 60 1.5 cgd /* 61 1.5 cgd * We have to read and modify the IOASIC registers directly, because 62 1.5 cgd * the TC option slot interrupt request and mask bits are stored there, 63 1.5 cgd * and the ioasic code isn't initted when we need to frob some interrupt 64 1.5 cgd * bits. 65 1.5 cgd */ 66 1.5 cgd #define DEC_3000_300_IOASIC_ADDR KV(0x1a0000000) 67 1.5 cgd 68 1.39 thorpej const struct tc_slotdesc tc_3000_300_slots[] = { 69 1.4 cgd { KV(0x100000000), C(TC_3000_300_DEV_OPT0), }, /* 0 - opt slot 0 */ 70 1.4 cgd { KV(0x120000000), C(TC_3000_300_DEV_OPT1), }, /* 1 - opt slot 1 */ 71 1.22 nisimura { KV(0x140000000), C(TC_3000_300_DEV_BOGUS), }, /* 2 - unused */ 72 1.22 nisimura { KV(0x160000000), C(TC_3000_300_DEV_BOGUS), }, /* 3 - unused */ 73 1.22 nisimura { KV(0x180000000), C(TC_3000_300_DEV_BOGUS), }, /* 4 - TCDS ASIC */ 74 1.22 nisimura { KV(0x1a0000000), C(TC_3000_300_DEV_BOGUS), }, /* 5 - IOCTL ASIC */ 75 1.22 nisimura { KV(0x1c0000000), C(TC_3000_300_DEV_BOGUS), }, /* 6 - CXTurbo */ 76 1.1 cgd }; 77 1.39 thorpej const int tc_3000_300_nslots = __arraycount(tc_3000_300_slots); 78 1.1 cgd 79 1.39 thorpej const struct tc_builtin tc_3000_300_builtins[] = { 80 1.22 nisimura { "PMAGB-BA", 6, 0x02000000, C(TC_3000_300_DEV_CXTURBO), }, 81 1.22 nisimura { "FLAMG-IO", 5, 0x00000000, C(TC_3000_300_DEV_IOASIC), }, 82 1.22 nisimura { "PMAZ-DS ", 4, 0x00000000, C(TC_3000_300_DEV_TCDS), }, 83 1.1 cgd }; 84 1.39 thorpej const int tc_3000_300_nbuiltins = __arraycount(tc_3000_300_builtins); 85 1.1 cgd 86 1.39 thorpej static struct tcintr { 87 1.28 dsl int (*tci_func)(void *); 88 1.4 cgd void *tci_arg; 89 1.25 thorpej struct evcnt tci_evcnt; 90 1.4 cgd } tc_3000_300_intr[TC_3000_300_NCOOKIES]; 91 1.4 cgd 92 1.1 cgd void 93 1.32 matt tc_3000_300_intr_setup(void) 94 1.1 cgd { 95 1.32 matt volatile uint32_t *imskp; 96 1.25 thorpej char *cp; 97 1.4 cgd u_long i; 98 1.1 cgd 99 1.4 cgd /* 100 1.5 cgd * Disable all interrupts that we can (can't disable builtins). 101 1.4 cgd */ 102 1.32 matt imskp = (volatile uint32_t *)(DEC_3000_300_IOASIC_ADDR + IOASIC_IMSK); 103 1.5 cgd *imskp &= ~(IOASIC_INTR_300_OPT0 | IOASIC_INTR_300_OPT1); 104 1.4 cgd 105 1.4 cgd /* 106 1.4 cgd * Set up interrupt handlers. 107 1.4 cgd */ 108 1.4 cgd for (i = 0; i < TC_3000_300_NCOOKIES; i++) { 109 1.32 matt tc_3000_300_intr[i].tci_func = tc_3000_300_intrnull; 110 1.32 matt tc_3000_300_intr[i].tci_arg = (void *)i; 111 1.25 thorpej 112 1.38 thorpej cp = kmem_asprintf("slot %lu", i); 113 1.25 thorpej evcnt_attach_dynamic(&tc_3000_300_intr[i].tci_evcnt, 114 1.25 thorpej EVCNT_TYPE_INTR, NULL, "tc", cp); 115 1.2 cgd } 116 1.24 cgd } 117 1.24 cgd 118 1.24 cgd const struct evcnt * 119 1.31 matt tc_3000_300_intr_evcnt(device_t tcadev, void *cookie) 120 1.24 cgd { 121 1.25 thorpej u_long dev = (u_long)cookie; 122 1.25 thorpej 123 1.25 thorpej #ifdef DIAGNOSTIC 124 1.25 thorpej /* XXX bounds-check cookie. */ 125 1.25 thorpej #endif 126 1.24 cgd 127 1.25 thorpej return (&tc_3000_300_intr[dev].tci_evcnt); 128 1.1 cgd } 129 1.1 cgd 130 1.1 cgd void 131 1.31 matt tc_3000_300_intr_establish(device_t tcadev, void *cookie, tc_intrlevel_t level, int (*func)(void *), void *arg) 132 1.1 cgd { 133 1.32 matt volatile uint32_t *imskp; 134 1.4 cgd u_long dev = (u_long)cookie; 135 1.1 cgd 136 1.1 cgd #ifdef DIAGNOSTIC 137 1.4 cgd /* XXX bounds-check cookie. */ 138 1.1 cgd #endif 139 1.1 cgd 140 1.4 cgd if (tc_3000_300_intr[dev].tci_func != tc_3000_300_intrnull) 141 1.18 thorpej panic("tc_3000_300_intr_establish: cookie %lu twice", dev); 142 1.1 cgd 143 1.37 thorpej const int s = splhigh(); 144 1.37 thorpej 145 1.37 thorpej /* All TC systems are uniprocessors. */ 146 1.37 thorpej KASSERT(CPU_IS_PRIMARY(curcpu())); 147 1.37 thorpej KASSERT(ncpu == 1); 148 1.37 thorpej curcpu()->ci_nintrhand++; 149 1.37 thorpej 150 1.4 cgd tc_3000_300_intr[dev].tci_func = func; 151 1.4 cgd tc_3000_300_intr[dev].tci_arg = arg; 152 1.1 cgd 153 1.37 thorpej splx(s); 154 1.37 thorpej 155 1.32 matt imskp = (volatile uint32_t *)(DEC_3000_300_IOASIC_ADDR + IOASIC_IMSK); 156 1.4 cgd switch (dev) { 157 1.4 cgd case TC_3000_300_DEV_OPT0: 158 1.5 cgd *imskp |= IOASIC_INTR_300_OPT0; 159 1.4 cgd break; 160 1.4 cgd case TC_3000_300_DEV_OPT1: 161 1.5 cgd *imskp |= IOASIC_INTR_300_OPT1; 162 1.4 cgd break; 163 1.4 cgd default: 164 1.4 cgd /* interrupts for builtins always enabled */ 165 1.4 cgd break; 166 1.4 cgd } 167 1.1 cgd } 168 1.1 cgd 169 1.1 cgd void 170 1.31 matt tc_3000_300_intr_disestablish(device_t tcadev, void *cookie) 171 1.1 cgd { 172 1.32 matt volatile uint32_t *imskp; 173 1.4 cgd u_long dev = (u_long)cookie; 174 1.1 cgd 175 1.1 cgd #ifdef DIAGNOSTIC 176 1.4 cgd /* XXX bounds-check cookie. */ 177 1.1 cgd #endif 178 1.1 cgd 179 1.4 cgd if (tc_3000_300_intr[dev].tci_func == tc_3000_300_intrnull) 180 1.18 thorpej panic("tc_3000_300_intr_disestablish: cookie %lu bad intr", 181 1.1 cgd dev); 182 1.1 cgd 183 1.32 matt imskp = (volatile uint32_t *)(DEC_3000_300_IOASIC_ADDR + IOASIC_IMSK); 184 1.4 cgd switch (dev) { 185 1.4 cgd case TC_3000_300_DEV_OPT0: 186 1.5 cgd *imskp &= ~IOASIC_INTR_300_OPT0; 187 1.4 cgd break; 188 1.4 cgd case TC_3000_300_DEV_OPT1: 189 1.5 cgd *imskp &= ~IOASIC_INTR_300_OPT1; 190 1.4 cgd break; 191 1.4 cgd default: 192 1.4 cgd /* interrupts for builtins always enabled */ 193 1.4 cgd break; 194 1.4 cgd } 195 1.1 cgd 196 1.37 thorpej const int s = splhigh(); 197 1.37 thorpej 198 1.37 thorpej curcpu()->ci_nintrhand--; 199 1.37 thorpej 200 1.4 cgd tc_3000_300_intr[dev].tci_func = tc_3000_300_intrnull; 201 1.4 cgd tc_3000_300_intr[dev].tci_arg = (void *)dev; 202 1.37 thorpej 203 1.37 thorpej splx(s); 204 1.4 cgd } 205 1.4 cgd 206 1.39 thorpej static int 207 1.29 dsl tc_3000_300_intrnull(void *val) 208 1.4 cgd { 209 1.4 cgd 210 1.27 provos panic("tc_3000_300_intrnull: uncaught TC intr for cookie %ld", 211 1.4 cgd (u_long)val); 212 1.1 cgd } 213 1.1 cgd 214 1.1 cgd void 215 1.29 dsl tc_3000_300_iointr(void *arg, unsigned long vec) 216 1.1 cgd { 217 1.32 matt uint32_t tcir, ioasicir, ioasicimr; 218 1.9 cgd int ifound; 219 1.1 cgd 220 1.36 thorpej KERNEL_LOCK(1, NULL); 221 1.36 thorpej 222 1.1 cgd #ifdef DIAGNOSTIC 223 1.1 cgd int s; 224 1.1 cgd if (vec != 0x800) 225 1.10 cgd panic("INVALID ASSUMPTION: vec 0x%lx, not 0x800", vec); 226 1.1 cgd s = splhigh(); 227 1.35 thorpej if (s != ALPHA_PSL_IPL_IO_HI) 228 1.9 cgd panic("INVALID ASSUMPTION: IPL %d, not %d", s, 229 1.35 thorpej ALPHA_PSL_IPL_IO_HI); 230 1.1 cgd splx(s); 231 1.1 cgd #endif 232 1.1 cgd 233 1.1 cgd do { 234 1.4 cgd tc_syncbus(); 235 1.2 cgd 236 1.2 cgd /* find out what interrupts/errors occurred */ 237 1.32 matt tcir = *(volatile uint32_t *)TC_3000_300_IR; 238 1.32 matt ioasicir = *(volatile uint32_t *) 239 1.21 nisimura (DEC_3000_300_IOASIC_ADDR + IOASIC_INTR); 240 1.32 matt ioasicimr = *(volatile uint32_t *) 241 1.21 nisimura (DEC_3000_300_IOASIC_ADDR + IOASIC_IMSK); 242 1.4 cgd tc_mb(); 243 1.2 cgd 244 1.7 cgd /* Ignore interrupts that aren't enabled out. */ 245 1.7 cgd ioasicir &= ioasicimr; 246 1.7 cgd 247 1.2 cgd /* clear the interrupts/errors we found. */ 248 1.32 matt *(volatile uint32_t *)TC_3000_300_IR = tcir; 249 1.4 cgd /* XXX can't clear TC option slot interrupts here? */ 250 1.4 cgd tc_wmb(); 251 1.1 cgd 252 1.1 cgd ifound = 0; 253 1.8 cgd 254 1.25 thorpej #define INCRINTRCNT(slot) tc_3000_300_intr[slot].tci_evcnt.ev_count++ 255 1.8 cgd 256 1.4 cgd #define CHECKINTR(slot, flag) \ 257 1.8 cgd if (flag) { \ 258 1.1 cgd ifound = 1; \ 259 1.8 cgd INCRINTRCNT(slot); \ 260 1.4 cgd (*tc_3000_300_intr[slot].tci_func) \ 261 1.4 cgd (tc_3000_300_intr[slot].tci_arg); \ 262 1.1 cgd } 263 1.1 cgd /* Do them in order of priority; highest slot # first. */ 264 1.5 cgd CHECKINTR(TC_3000_300_DEV_CXTURBO, 265 1.5 cgd tcir & TC_3000_300_IR_CXTURBO); 266 1.8 cgd CHECKINTR(TC_3000_300_DEV_IOASIC, 267 1.8 cgd (tcir & TC_3000_300_IR_IOASIC) && 268 1.8 cgd (ioasicir & ~(IOASIC_INTR_300_OPT1|IOASIC_INTR_300_OPT0))); 269 1.5 cgd CHECKINTR(TC_3000_300_DEV_TCDS, tcir & TC_3000_300_IR_TCDS); 270 1.5 cgd CHECKINTR(TC_3000_300_DEV_OPT1, 271 1.7 cgd ioasicir & IOASIC_INTR_300_OPT1); 272 1.7 cgd CHECKINTR(TC_3000_300_DEV_OPT0, 273 1.5 cgd ioasicir & IOASIC_INTR_300_OPT0); 274 1.1 cgd #undef CHECKINTR 275 1.1 cgd 276 1.1 cgd #ifdef DIAGNOSTIC 277 1.1 cgd #define PRINTINTR(msg, bits) \ 278 1.5 cgd if (tcir & bits) \ 279 1.12 christos printf(msg); 280 1.1 cgd PRINTINTR("BCache tag parity error\n", 281 1.1 cgd TC_3000_300_IR_BCTAGPARITY); 282 1.1 cgd PRINTINTR("TC overrun error\n", TC_3000_300_IR_TCOVERRUN); 283 1.1 cgd PRINTINTR("TC I/O timeout\n", TC_3000_300_IR_TCTIMEOUT); 284 1.1 cgd PRINTINTR("Bcache parity error\n", 285 1.1 cgd TC_3000_300_IR_BCACHEPARITY); 286 1.1 cgd PRINTINTR("Memory parity error\n", TC_3000_300_IR_MEMPARITY); 287 1.1 cgd #undef PRINTINTR 288 1.1 cgd #endif 289 1.1 cgd } while (ifound); 290 1.36 thorpej 291 1.36 thorpej KERNEL_UNLOCK_ONE(NULL); 292 1.16 briggs } 293 1.16 briggs 294 1.19 drochner #if NWSDISPLAY > 0 295 1.16 briggs /* 296 1.16 briggs * tc_3000_300_fb_cnattach -- 297 1.16 briggs * Attempt to map the CTB output device to a slot and attach the 298 1.16 briggs * framebuffer as the output side of the console. 299 1.16 briggs */ 300 1.16 briggs int 301 1.32 matt tc_3000_300_fb_cnattach(uint64_t turbo_slot) 302 1.16 briggs { 303 1.32 matt uint32_t output_slot; 304 1.16 briggs 305 1.16 briggs output_slot = turbo_slot & 0xffffffff; 306 1.16 briggs 307 1.16 briggs if (output_slot >= tc_3000_300_nslots) { 308 1.20 drochner return EINVAL; 309 1.16 briggs } 310 1.16 briggs 311 1.16 briggs if (output_slot == 0) { 312 1.17 briggs #if NSFB > 0 313 1.16 briggs sfb_cnattach(KV(0x1c0000000) + 0x02000000); 314 1.20 drochner return 0; 315 1.17 briggs #else 316 1.20 drochner return ENXIO; 317 1.17 briggs #endif 318 1.16 briggs } 319 1.16 briggs 320 1.16 briggs return tc_fb_cnattach(tc_3000_300_slots[output_slot-1].tcs_addr); 321 1.1 cgd } 322 1.19 drochner #endif /* NWSDISPLAY */ 323