1/* $NetBSD: tc_3000_500.c,v 1.38 2021/05/07 16:58:34 thorpej Exp $ */ 2 3/* 4 * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University. 5 * All rights reserved. 6 * 7 * Author: Chris G. Demetriou 8 * 9 * Permission to use, copy, modify and distribute this software and 10 * its documentation is hereby granted, provided that both the copyright 11 * notice and this permission notice appear in all copies of the 12 * software, derivative works or modified versions, and any portions 13 * thereof, and that both notices appear in supporting documentation. 14 * 15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 17 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 18 * 19 * Carnegie Mellon requests users of this software to return to 20 * 21 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 22 * School of Computer Science 23 * Carnegie Mellon University 24 * Pittsburgh PA 15213-3890 25 * 26 * any improvements or extensions that they make and grant Carnegie the 27 * rights to redistribute these changes. 28 */ 29 30#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 31 32__KERNEL_RCSID(0, "$NetBSD: tc_3000_500.c,v 1.38 2021/05/07 16:58:34 thorpej Exp $"); 33 34#include <sys/param.h> 35#include <sys/systm.h> 36#include <sys/device.h> 37#include <sys/kmem.h> 38#include <sys/cpu.h> 39 40#include <machine/autoconf.h> 41#include <machine/pte.h> 42#include <machine/rpb.h> 43 44#include <dev/tc/tcvar.h> 45#include <alpha/tc/tc_conf.h> 46#include <alpha/tc/tc_3000_500.h> 47 48#include "wsdisplay.h" 49#include "sfb.h" 50 51#if NSFB > 0 52extern int sfb_cnattach(tc_addr_t); 53#endif 54 55static int tc_3000_500_intrnull(void *); 56 57#define C(x) ((void *)(u_long)x) 58#define KV(x) (ALPHA_PHYS_TO_K0SEG(x)) 59 60const struct tc_slotdesc tc_3000_500_slots[] = { 61 { KV(0x100000000), C(TC_3000_500_DEV_OPT0), }, /* 0 - opt slot 0 */ 62 { KV(0x120000000), C(TC_3000_500_DEV_OPT1), }, /* 1 - opt slot 1 */ 63 { KV(0x140000000), C(TC_3000_500_DEV_OPT2), }, /* 2 - opt slot 2 */ 64 { KV(0x160000000), C(TC_3000_500_DEV_OPT3), }, /* 3 - opt slot 3 */ 65 { KV(0x180000000), C(TC_3000_500_DEV_OPT4), }, /* 4 - opt slot 4 */ 66 { KV(0x1a0000000), C(TC_3000_500_DEV_OPT5), }, /* 5 - opt slot 5 */ 67 { KV(0x1c0000000), C(TC_3000_500_DEV_BOGUS), }, /* 6 - TCDS ASIC */ 68 { KV(0x1e0000000), C(TC_3000_500_DEV_BOGUS), }, /* 7 - IOCTL ASIC */ 69}; 70const int tc_3000_500_nslots = __arraycount(tc_3000_500_slots); 71 72const struct tc_builtin tc_3000_500_graphics_builtins[] = { 73 { "FLAMG-IO", 7, 0x00000000, C(TC_3000_500_DEV_IOASIC), }, 74 { "PMAGB-BA", 7, 0x02000000, C(TC_3000_500_DEV_CXTURBO), }, 75 { "PMAZ-DS ", 6, 0x00000000, C(TC_3000_500_DEV_TCDS), }, 76}; 77const int tc_3000_500_graphics_nbuiltins = 78 __arraycount(tc_3000_500_graphics_builtins); 79 80const struct tc_builtin tc_3000_500_nographics_builtins[] = { 81 { "FLAMG-IO", 7, 0x00000000, C(TC_3000_500_DEV_IOASIC), }, 82 { "PMAZ-DS ", 6, 0x00000000, C(TC_3000_500_DEV_TCDS), }, 83}; 84const int tc_3000_500_nographics_nbuiltins = 85 __arraycount(tc_3000_500_nographics_builtins); 86 87static const uint32_t tc_3000_500_intrbits[TC_3000_500_NCOOKIES] = { 88 TC_3000_500_IR_OPT0, 89 TC_3000_500_IR_OPT1, 90 TC_3000_500_IR_OPT2, 91 TC_3000_500_IR_OPT3, 92 TC_3000_500_IR_OPT4, 93 TC_3000_500_IR_OPT5, 94 TC_3000_500_IR_TCDS, 95 TC_3000_500_IR_IOASIC, 96 TC_3000_500_IR_CXTURBO, 97}; 98 99static struct tcintr { 100 int (*tci_func)(void *); 101 void *tci_arg; 102 struct evcnt tci_evcnt; 103} tc_3000_500_intr[TC_3000_500_NCOOKIES]; 104 105static uint32_t tc_3000_500_imask; /* intrs we want to ignore; mirrors IMR. */ 106 107void 108tc_3000_500_intr_setup(void) 109{ 110 char *cp; 111 u_long i; 112 113 /* 114 * Disable all slot interrupts. Note that this cannot 115 * actually disable CXTurbo, TCDS, and IOASIC interrupts. 116 */ 117 tc_3000_500_imask = *(volatile uint32_t *)TC_3000_500_IMR_READ; 118 for (i = 0; i < TC_3000_500_NCOOKIES; i++) 119 tc_3000_500_imask |= tc_3000_500_intrbits[i]; 120 *(volatile uint32_t *)TC_3000_500_IMR_WRITE = tc_3000_500_imask; 121 tc_mb(); 122 123 /* 124 * Set up interrupt handlers. 125 */ 126 for (i = 0; i < TC_3000_500_NCOOKIES; i++) { 127 tc_3000_500_intr[i].tci_func = tc_3000_500_intrnull; 128 tc_3000_500_intr[i].tci_arg = (void *)i; 129 130 cp = kmem_asprintf("slot %lu", i); 131 evcnt_attach_dynamic(&tc_3000_500_intr[i].tci_evcnt, 132 EVCNT_TYPE_INTR, NULL, "tc", cp); 133 } 134} 135 136const struct evcnt * 137tc_3000_500_intr_evcnt(device_t tcadev, void *cookie) 138{ 139 u_long dev = (u_long)cookie; 140 141#ifdef DIAGNOSTIC 142 /* XXX bounds-check cookie. */ 143#endif 144 145 return (&tc_3000_500_intr[dev].tci_evcnt); 146} 147 148void 149tc_3000_500_intr_establish(device_t tcadev, void *cookie, tc_intrlevel_t level, int (*func)(void *), void *arg) 150{ 151 u_long dev = (u_long)cookie; 152 153#ifdef DIAGNOSTIC 154 /* XXX bounds-check cookie. */ 155#endif 156 157 if (tc_3000_500_intr[dev].tci_func != tc_3000_500_intrnull) 158 panic("tc_3000_500_intr_establish: cookie %lu twice", dev); 159 160 const int s = splhigh(); 161 162 /* All TC systems are uniprocessors. */ 163 KASSERT(CPU_IS_PRIMARY(curcpu())); 164 KASSERT(ncpu == 1); 165 curcpu()->ci_nintrhand++; 166 167 tc_3000_500_intr[dev].tci_func = func; 168 tc_3000_500_intr[dev].tci_arg = arg; 169 170 splx(s); 171 172 tc_3000_500_imask &= ~tc_3000_500_intrbits[dev]; 173 *(volatile uint32_t *)TC_3000_500_IMR_WRITE = tc_3000_500_imask; 174 tc_mb(); 175} 176 177void 178tc_3000_500_intr_disestablish(device_t tcadev, void *cookie) 179{ 180 u_long dev = (u_long)cookie; 181 182#ifdef DIAGNOSTIC 183 /* XXX bounds-check cookie. */ 184#endif 185 186 if (tc_3000_500_intr[dev].tci_func == tc_3000_500_intrnull) 187 panic("tc_3000_500_intr_disestablish: cookie %lu bad intr", 188 dev); 189 190 tc_3000_500_imask |= tc_3000_500_intrbits[dev]; 191 *(volatile uint32_t *)TC_3000_500_IMR_WRITE = tc_3000_500_imask; 192 tc_mb(); 193 194 const int s = splhigh(); 195 196 curcpu()->ci_nintrhand--; 197 198 tc_3000_500_intr[dev].tci_func = tc_3000_500_intrnull; 199 tc_3000_500_intr[dev].tci_arg = (void *)dev; 200 201 splx(s); 202} 203 204static int 205tc_3000_500_intrnull(void *val) 206{ 207 208 panic("tc_3000_500_intrnull: uncaught TC intr for cookie %ld", 209 (u_long)val); 210} 211 212void 213tc_3000_500_iointr(void *arg, unsigned long vec) 214{ 215 uint32_t ir; 216 int ifound; 217 218 KERNEL_LOCK(1, NULL); 219 220#ifdef DIAGNOSTIC 221 int s; 222 if (vec != 0x800) 223 panic("INVALID ASSUMPTION: vec 0x%lx, not 0x800", vec); 224 s = splhigh(); 225 if (s != ALPHA_PSL_IPL_IO_HI) 226 panic("INVALID ASSUMPTION: IPL %d, not %d", s, 227 ALPHA_PSL_IPL_IO_HI); 228 splx(s); 229#endif 230 231 do { 232 tc_syncbus(); 233 ir = *(volatile uint32_t *)TC_3000_500_IR_CLEAR; 234 235 /* Ignore interrupts that we haven't enabled. */ 236 ir &= ~(tc_3000_500_imask & 0x1ff); 237 238 ifound = 0; 239 240#define INCRINTRCNT(slot) tc_3000_500_intr[slot].tci_evcnt.ev_count++ 241 242#define CHECKINTR(slot) \ 243 if (ir & tc_3000_500_intrbits[slot]) { \ 244 ifound = 1; \ 245 INCRINTRCNT(slot); \ 246 (*tc_3000_500_intr[slot].tci_func) \ 247 (tc_3000_500_intr[slot].tci_arg); \ 248 } 249 /* Do them in order of priority; highest slot # first. */ 250 CHECKINTR(TC_3000_500_DEV_CXTURBO); 251 CHECKINTR(TC_3000_500_DEV_IOASIC); 252 CHECKINTR(TC_3000_500_DEV_TCDS); 253 CHECKINTR(TC_3000_500_DEV_OPT5); 254 CHECKINTR(TC_3000_500_DEV_OPT4); 255 CHECKINTR(TC_3000_500_DEV_OPT3); 256 CHECKINTR(TC_3000_500_DEV_OPT2); 257 CHECKINTR(TC_3000_500_DEV_OPT1); 258 CHECKINTR(TC_3000_500_DEV_OPT0); 259#undef CHECKINTR 260 261#ifdef DIAGNOSTIC 262#define PRINTINTR(msg, bits) \ 263 if (ir & bits) \ 264 printf(msg); 265 PRINTINTR("Second error occurred\n", TC_3000_500_IR_ERR2); 266 PRINTINTR("DMA buffer error\n", TC_3000_500_IR_DMABE); 267 PRINTINTR("DMA cross 2K boundary\n", TC_3000_500_IR_DMA2K); 268 PRINTINTR("TC reset in progress\n", TC_3000_500_IR_TCRESET); 269 PRINTINTR("TC parity error\n", TC_3000_500_IR_TCPAR); 270 PRINTINTR("DMA tag error\n", TC_3000_500_IR_DMATAG); 271 PRINTINTR("Single-bit error\n", TC_3000_500_IR_DMASBE); 272 PRINTINTR("Double-bit error\n", TC_3000_500_IR_DMADBE); 273 PRINTINTR("TC I/O timeout\n", TC_3000_500_IR_TCTIMEOUT); 274 PRINTINTR("DMA block too long\n", TC_3000_500_IR_DMABLOCK); 275 PRINTINTR("Invalid I/O address\n", TC_3000_500_IR_IOADDR); 276 PRINTINTR("DMA scatter/gather invalid\n", TC_3000_500_IR_DMASG); 277 PRINTINTR("Scatter/gather parity error\n", 278 TC_3000_500_IR_SGPAR); 279#undef PRINTINTR 280#endif 281 } while (ifound); 282 283 KERNEL_UNLOCK_ONE(NULL); 284} 285 286#if NWSDISPLAY > 0 287/* 288 * tc_3000_500_fb_cnattach -- 289 * Attempt to map the CTB output device to a slot and attach the 290 * framebuffer as the output side of the console. 291 */ 292int 293tc_3000_500_fb_cnattach(uint64_t turbo_slot) 294{ 295 uint32_t output_slot; 296 297 output_slot = turbo_slot & 0xffffffff; 298 299 if (output_slot >= tc_3000_500_nslots) { 300 return EINVAL; 301 } 302 303 if (hwrpb->rpb_variation & SV_GRAPHICS) { 304 if (output_slot == 0) { 305#if NSFB > 0 306 sfb_cnattach(KV(0x1e0000000) + 0x02000000); 307 return 0; 308#else 309 return ENXIO; 310#endif 311 } 312 } else { 313 /* 314 * Slots 0-2 in the tc_3000_500_slots array are only 315 * on the 500 models that also have the CXTurbo 316 * (500/800/900) and a total of 6 TC slots. For the 317 * 400/600/700, slots 0-2 are in table locations 3-5, so 318 * offset the CTB slot by 3 to get the address in our table. 319 */ 320 output_slot += 3; 321 } 322 return tc_fb_cnattach(tc_3000_500_slots[output_slot-1].tcs_addr); 323} 324#endif /* NWSDISPLAY */ 325 326#if 0 327/* 328 * tc_3000_500_ioslot -- 329 * Set the PBS bits for devices on the TC. 330 */ 331void 332tc_3000_500_ioslot(uint32_t slot, uint32_t flags, int set) 333{ 334 volatile uint32_t *iosp; 335 uint32_t ios; 336 int s; 337 338 iosp = (volatile uint32_t *)TC_3000_500_IOSLOT; 339 ios = *iosp; 340 flags <<= (slot * 3); 341 if (set) 342 ios |= flags; 343 else 344 ios &= ~flags; 345 s = splhigh(); 346 *iosp = ios; 347 tc_mb(); 348 splx(s); 349} 350#endif 351