1 1.35 thorpej /* $NetBSD: ofisa.c,v 1.35 2022/01/22 11:49:17 thorpej Exp $ */ 2 1.1 cgd 3 1.1 cgd /* 4 1.1 cgd * Copyright 1997, 1998 5 1.1 cgd * Digital Equipment Corporation. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * This software is furnished under license and may be used and 8 1.1 cgd * copied only in accordance with the following terms and conditions. 9 1.1 cgd * Subject to these conditions, you may download, copy, install, 10 1.1 cgd * use, modify and distribute this software in source and/or binary 11 1.1 cgd * form. No title or ownership is transferred hereby. 12 1.1 cgd * 13 1.1 cgd * 1) Any source code used, modified or distributed must reproduce 14 1.1 cgd * and retain this copyright notice and list of conditions as 15 1.1 cgd * they appear in the source file. 16 1.1 cgd * 17 1.1 cgd * 2) No right is granted to use any trade name, trademark, or logo of 18 1.1 cgd * Digital Equipment Corporation. Neither the "Digital Equipment 19 1.1 cgd * Corporation" name nor any trademark or logo of Digital Equipment 20 1.1 cgd * Corporation may be used to endorse or promote products derived 21 1.1 cgd * from this software without the prior written permission of 22 1.1 cgd * Digital Equipment Corporation. 23 1.1 cgd * 24 1.1 cgd * 3) This software is provided "AS-IS" and any express or implied 25 1.1 cgd * warranties, including but not limited to, any implied warranties 26 1.1 cgd * of merchantability, fitness for a particular purpose, or 27 1.1 cgd * non-infringement are disclaimed. In no event shall DIGITAL be 28 1.1 cgd * liable for any damages whatsoever, and in particular, DIGITAL 29 1.1 cgd * shall not be liable for special, indirect, consequential, or 30 1.1 cgd * incidental damages or damages for lost profits, loss of 31 1.1 cgd * revenue or loss of use, whether such damages arise in contract, 32 1.1 cgd * negligence, tort, under statute, in equity, at law or otherwise, 33 1.1 cgd * even if advised of the possibility of such damage. 34 1.1 cgd */ 35 1.8 lukem 36 1.8 lukem #include <sys/cdefs.h> 37 1.35 thorpej __KERNEL_RCSID(0, "$NetBSD: ofisa.c,v 1.35 2022/01/22 11:49:17 thorpej Exp $"); 38 1.1 cgd 39 1.1 cgd #include <sys/param.h> 40 1.1 cgd #include <sys/systm.h> 41 1.1 cgd #include <sys/device.h> 42 1.1 cgd #include <sys/malloc.h> 43 1.18 ad #include <sys/bus.h> 44 1.18 ad #include <sys/intr.h> 45 1.1 cgd 46 1.1 cgd #include <dev/ofw/openfirm.h> 47 1.1 cgd #include <dev/isa/isavar.h> 48 1.1 cgd #include <dev/ofisa/ofisavar.h> 49 1.1 cgd 50 1.5 thorpej #include "isadma.h" 51 1.5 thorpej 52 1.1 cgd #define OFW_MAX_STACK_BUF_SIZE 256 53 1.1 cgd 54 1.23 cegger static int ofisamatch(device_t, cfdata_t, void *); 55 1.23 cegger static void ofisaattach(device_t, device_t, void *); 56 1.1 cgd 57 1.33 thorpej static int ofisa_subclass_match(device_t, cfdata_t, void *); 58 1.33 thorpej 59 1.24 matt CFATTACH_DECL_NEW(ofisa, 0, 60 1.12 thorpej ofisamatch, ofisaattach, NULL, NULL); 61 1.1 cgd 62 1.33 thorpej CFATTACH_DECL_NEW(ofisa_subclass, 0, 63 1.33 thorpej ofisa_subclass_match, ofisaattach, NULL, NULL); 64 1.33 thorpej 65 1.2 cgd extern struct cfdriver ofisa_cd; 66 1.1 cgd 67 1.33 thorpej int 68 1.19 dsl ofisaprint(void *aux, const char *pnp) 69 1.1 cgd { 70 1.2 cgd struct ofbus_attach_args *oba = aux; 71 1.1 cgd char name[64]; 72 1.1 cgd 73 1.2 cgd (void)of_packagename(oba->oba_phandle, name, sizeof name); 74 1.1 cgd if (pnp) 75 1.13 thorpej aprint_normal("%s at %s", name, pnp); 76 1.1 cgd else 77 1.13 thorpej aprint_normal(" (%s)", name); 78 1.1 cgd return UNCONF; 79 1.1 cgd } 80 1.1 cgd 81 1.27 thorpej static const struct device_compatible_entry compat_data[] = { 82 1.27 thorpej { .compat = "pnpPNP,a00" }, 83 1.29 thorpej DEVICE_COMPAT_EOL 84 1.27 thorpej }; 85 1.27 thorpej 86 1.1 cgd int 87 1.23 cegger ofisamatch(device_t parent, cfdata_t cf, void *aux) 88 1.1 cgd { 89 1.2 cgd struct ofbus_attach_args *oba = aux; 90 1.27 thorpej int rv; 91 1.1 cgd 92 1.30 thorpej rv = of_compatible_match(oba->oba_phandle, compat_data) ? 5 : 0; 93 1.1 cgd #ifdef _OFISA_MD_MATCH 94 1.1 cgd if (!rv) 95 1.1 cgd rv = ofisa_md_match(parent, cf, aux); 96 1.1 cgd #endif 97 1.1 cgd 98 1.1 cgd return (rv); 99 1.1 cgd } 100 1.1 cgd 101 1.33 thorpej int 102 1.33 thorpej ofisa_subclass_match(device_t parent, cfdata_t cf, void *aux) 103 1.33 thorpej { 104 1.33 thorpej /* We're attaching "ofisa" to something that knows what it's doing. */ 105 1.33 thorpej return 5; 106 1.33 thorpej } 107 1.33 thorpej 108 1.1 cgd void 109 1.23 cegger ofisaattach(device_t parent, device_t self, void *aux) 110 1.1 cgd { 111 1.2 cgd struct ofbus_attach_args *oba = aux; 112 1.1 cgd struct isabus_attach_args iba; 113 1.1 cgd struct ofisa_attach_args aa; 114 1.1 cgd int child; 115 1.1 cgd 116 1.2 cgd if (ofisa_get_isabus_data(oba->oba_phandle, &iba) < 0) { 117 1.1 cgd printf(": couldn't get essential bus data\n"); 118 1.1 cgd return; 119 1.1 cgd } 120 1.1 cgd 121 1.1 cgd printf("\n"); 122 1.3 thorpej 123 1.5 thorpej #if NISADMA > 0 124 1.3 thorpej /* 125 1.3 thorpej * Initialize our DMA state. 126 1.3 thorpej */ 127 1.3 thorpej isa_dmainit(iba.iba_ic, iba.iba_iot, iba.iba_dmat, self); 128 1.5 thorpej #endif 129 1.1 cgd 130 1.35 thorpej devhandle_t selfh = device_handle(self); 131 1.2 cgd for (child = OF_child(oba->oba_phandle); child; 132 1.1 cgd child = OF_peer(child)) { 133 1.2 cgd if (ofisa_ignore_child(oba->oba_phandle, child)) 134 1.1 cgd continue; 135 1.1 cgd 136 1.21 cegger memset(&aa, 0, sizeof aa); 137 1.1 cgd 138 1.32 thorpej aa.oba.oba_busname = "ofisa"; 139 1.2 cgd aa.oba.oba_phandle = child; 140 1.1 cgd aa.iot = iba.iba_iot; 141 1.1 cgd aa.memt = iba.iba_memt; 142 1.1 cgd aa.dmat = iba.iba_dmat; 143 1.1 cgd aa.ic = iba.iba_ic; 144 1.1 cgd 145 1.31 thorpej config_found(self, &aa, ofisaprint, 146 1.35 thorpej CFARGS(.devhandle = devhandle_from_of(selfh, child))); 147 1.1 cgd } 148 1.1 cgd } 149 1.1 cgd 150 1.1 cgd int 151 1.19 dsl ofisa_reg_count(int phandle) 152 1.1 cgd { 153 1.1 cgd int len; 154 1.1 cgd 155 1.1 cgd len = OF_getproplen(phandle, "reg"); 156 1.1 cgd 157 1.7 wiz /* nonexistent or obviously malformed "reg" property */ 158 1.1 cgd if (len < 0 || (len % 12) != 0) 159 1.1 cgd return (-1); 160 1.1 cgd return (len / 12); 161 1.1 cgd } 162 1.1 cgd 163 1.1 cgd int 164 1.19 dsl ofisa_reg_get(int phandle, struct ofisa_reg_desc *descp, int ndescs) 165 1.1 cgd { 166 1.25 christos char *buf, *bp, small[OFW_MAX_STACK_BUF_SIZE]; 167 1.25 christos int i, proplen, rv; 168 1.1 cgd 169 1.1 cgd i = ofisa_reg_count(phandle); 170 1.1 cgd if (i < 0) 171 1.1 cgd return (-1); 172 1.6 thorpej proplen = i * 12; 173 1.26 riastrad ndescs = uimin(ndescs, i); 174 1.1 cgd 175 1.1 cgd i = ndescs * 12; 176 1.1 cgd if (i > OFW_MAX_STACK_BUF_SIZE) { 177 1.1 cgd buf = malloc(i, M_TEMP, M_WAITOK); 178 1.1 cgd } else { 179 1.25 christos buf = small; 180 1.1 cgd } 181 1.1 cgd 182 1.6 thorpej if (OF_getprop(phandle, "reg", buf, i) != proplen) { 183 1.1 cgd rv = -1; 184 1.1 cgd goto out; 185 1.1 cgd } 186 1.1 cgd 187 1.1 cgd for (i = 0, bp = buf; i < ndescs; i++, bp += 12) { 188 1.1 cgd if (of_decode_int(&bp[0]) & 1) 189 1.1 cgd descp[i].type = OFISA_REG_TYPE_IO; 190 1.1 cgd else 191 1.1 cgd descp[i].type = OFISA_REG_TYPE_MEM; 192 1.1 cgd descp[i].addr = of_decode_int(&bp[4]); 193 1.1 cgd descp[i].len = of_decode_int(&bp[8]); 194 1.1 cgd } 195 1.1 cgd rv = i; /* number of descriptors processed (== ndescs) */ 196 1.1 cgd 197 1.1 cgd out: 198 1.25 christos if (buf != small) 199 1.1 cgd free(buf, M_TEMP); 200 1.1 cgd return (rv); 201 1.1 cgd } 202 1.1 cgd 203 1.1 cgd void 204 1.19 dsl ofisa_reg_print(struct ofisa_reg_desc *descp, int ndescs) 205 1.1 cgd { 206 1.1 cgd int i; 207 1.1 cgd 208 1.1 cgd if (ndescs == 0) { 209 1.1 cgd printf("none"); 210 1.1 cgd return; 211 1.1 cgd } 212 1.1 cgd 213 1.1 cgd for (i = 0; i < ndescs; i++) { 214 1.1 cgd printf("%s%s 0x%lx/%ld", i ? ", " : "", 215 1.1 cgd descp[i].type == OFISA_REG_TYPE_IO ? "io" : "mem", 216 1.1 cgd (long)descp[i].addr, (long)descp[i].len); 217 1.1 cgd } 218 1.1 cgd } 219 1.1 cgd 220 1.1 cgd int 221 1.19 dsl ofisa_intr_count(int phandle) 222 1.1 cgd { 223 1.1 cgd int len; 224 1.1 cgd 225 1.1 cgd len = OF_getproplen(phandle, "interrupts"); 226 1.1 cgd 227 1.7 wiz /* nonexistent or obviously malformed "reg" property */ 228 1.1 cgd if (len < 0 || (len % 8) != 0) 229 1.1 cgd return (-1); 230 1.1 cgd return (len / 8); 231 1.1 cgd } 232 1.1 cgd 233 1.1 cgd int 234 1.19 dsl ofisa_intr_get(int phandle, struct ofisa_intr_desc *descp, int ndescs) 235 1.1 cgd { 236 1.25 christos char *buf, *bp, small[OFW_MAX_STACK_BUF_SIZE]; 237 1.25 christos int i, proplen, rv; 238 1.1 cgd 239 1.1 cgd i = ofisa_intr_count(phandle); 240 1.1 cgd if (i < 0) 241 1.1 cgd return (-1); 242 1.6 thorpej proplen = i * 8; 243 1.26 riastrad ndescs = uimin(ndescs, i); 244 1.1 cgd 245 1.1 cgd i = ndescs * 8; 246 1.1 cgd if (i > OFW_MAX_STACK_BUF_SIZE) { 247 1.1 cgd buf = malloc(i, M_TEMP, M_WAITOK); 248 1.1 cgd } else { 249 1.25 christos buf = small; 250 1.1 cgd } 251 1.1 cgd 252 1.6 thorpej if (OF_getprop(phandle, "interrupts", buf, i) != proplen) { 253 1.1 cgd rv = -1; 254 1.1 cgd goto out; 255 1.1 cgd } 256 1.1 cgd 257 1.1 cgd for (i = 0, bp = buf; i < ndescs; i++, bp += 8) { 258 1.1 cgd descp[i].irq = of_decode_int(&bp[0]); 259 1.1 cgd switch (of_decode_int(&bp[4])) { 260 1.1 cgd case 0: 261 1.1 cgd case 1: 262 1.1 cgd descp[i].share = IST_LEVEL; 263 1.1 cgd break; 264 1.1 cgd case 2: 265 1.1 cgd case 3: 266 1.1 cgd descp[i].share = IST_EDGE; 267 1.1 cgd break; 268 1.1 cgd #ifdef DIAGNOSTIC 269 1.1 cgd default: 270 1.1 cgd /* Dunno what to do, so fail. */ 271 1.17 matt printf("ofisa_intr_get: unknown interrupt type %d\n", 272 1.1 cgd of_decode_int(&bp[4])); 273 1.1 cgd rv = -1; 274 1.1 cgd goto out; 275 1.1 cgd #endif 276 1.1 cgd } 277 1.1 cgd } 278 1.1 cgd rv = i; /* number of descriptors processed (== ndescs) */ 279 1.1 cgd 280 1.1 cgd out: 281 1.25 christos if (buf != small) 282 1.1 cgd free(buf, M_TEMP); 283 1.1 cgd return (rv); 284 1.1 cgd } 285 1.1 cgd 286 1.1 cgd void 287 1.19 dsl ofisa_intr_print(struct ofisa_intr_desc *descp, int ndescs) 288 1.1 cgd { 289 1.1 cgd int i; 290 1.1 cgd 291 1.1 cgd if (ndescs == 0) { 292 1.1 cgd printf("none"); 293 1.1 cgd return; 294 1.1 cgd } 295 1.1 cgd 296 1.1 cgd for (i = 0; i < ndescs; i++) { 297 1.1 cgd printf("%s%d (%s)", i ? ", " : "", descp[i].irq, 298 1.1 cgd descp[i].share == IST_LEVEL ? "level" : "edge"); 299 1.6 thorpej } 300 1.6 thorpej } 301 1.6 thorpej 302 1.6 thorpej int 303 1.19 dsl ofisa_dma_count(int phandle) 304 1.6 thorpej { 305 1.6 thorpej int len; 306 1.6 thorpej 307 1.6 thorpej len = OF_getproplen(phandle, "dma"); 308 1.6 thorpej 309 1.7 wiz /* nonexistent or obviously malformed "reg" property */ 310 1.6 thorpej if (len < 0 || (len % 20) != 0) 311 1.6 thorpej return (-1); 312 1.6 thorpej return (len / 20); 313 1.6 thorpej } 314 1.6 thorpej 315 1.6 thorpej int 316 1.19 dsl ofisa_dma_get(int phandle, struct ofisa_dma_desc *descp, int ndescs) 317 1.6 thorpej { 318 1.25 christos char *buf, *bp, small[OFW_MAX_STACK_BUF_SIZE]; 319 1.25 christos int i, proplen, rv; 320 1.6 thorpej 321 1.6 thorpej i = ofisa_dma_count(phandle); 322 1.6 thorpej if (i < 0) 323 1.6 thorpej return (-1); 324 1.6 thorpej proplen = i * 20; 325 1.26 riastrad ndescs = uimin(ndescs, i); 326 1.6 thorpej 327 1.6 thorpej i = ndescs * 20; 328 1.6 thorpej if (i > OFW_MAX_STACK_BUF_SIZE) { 329 1.6 thorpej buf = malloc(i, M_TEMP, M_WAITOK); 330 1.6 thorpej } else { 331 1.25 christos buf = small; 332 1.6 thorpej } 333 1.6 thorpej 334 1.6 thorpej if (OF_getprop(phandle, "dma", buf, i) != proplen) { 335 1.6 thorpej rv = -1; 336 1.6 thorpej goto out; 337 1.6 thorpej } 338 1.6 thorpej 339 1.6 thorpej for (i = 0, bp = buf; i < ndescs; i++, bp += 20) { 340 1.6 thorpej descp[i].drq = of_decode_int(&bp[0]); 341 1.6 thorpej descp[i].mode = of_decode_int(&bp[4]); 342 1.6 thorpej descp[i].width = of_decode_int(&bp[8]); 343 1.6 thorpej descp[i].countwidth = of_decode_int(&bp[12]); 344 1.6 thorpej descp[i].busmaster = of_decode_int(&bp[16]); 345 1.6 thorpej } 346 1.6 thorpej rv = i; /* number of descriptors processed (== ndescs) */ 347 1.6 thorpej 348 1.6 thorpej out: 349 1.25 christos if (buf != small) 350 1.6 thorpej free(buf, M_TEMP); 351 1.6 thorpej return (rv); 352 1.6 thorpej } 353 1.6 thorpej 354 1.6 thorpej void 355 1.19 dsl ofisa_dma_print(struct ofisa_dma_desc *descp, int ndescs) 356 1.6 thorpej { 357 1.6 thorpej char unkmode[16]; 358 1.6 thorpej const char *modestr; 359 1.6 thorpej int i; 360 1.6 thorpej 361 1.6 thorpej if (ndescs == 0) { 362 1.6 thorpej printf("none"); 363 1.6 thorpej return; 364 1.6 thorpej } 365 1.6 thorpej 366 1.6 thorpej for (i = 0; i < ndescs; i++) { 367 1.6 thorpej switch (descp[i].mode) { 368 1.6 thorpej case OFISA_DMA_MODE_COMPAT: 369 1.6 thorpej modestr = "compat"; 370 1.6 thorpej break; 371 1.6 thorpej case OFISA_DMA_MODE_A: 372 1.6 thorpej modestr = "A"; 373 1.6 thorpej break; 374 1.6 thorpej case OFISA_DMA_MODE_B: 375 1.6 thorpej modestr = "B"; 376 1.6 thorpej break; 377 1.6 thorpej case OFISA_DMA_MODE_F: 378 1.6 thorpej modestr = "F"; 379 1.6 thorpej break; 380 1.6 thorpej case OFISA_DMA_MODE_C: 381 1.6 thorpej modestr = "C"; 382 1.6 thorpej break; 383 1.6 thorpej default: 384 1.14 itojun snprintf(unkmode, sizeof(unkmode), "??? (%d)", 385 1.14 itojun descp[i].mode); 386 1.6 thorpej modestr = unkmode; 387 1.6 thorpej break; 388 1.6 thorpej } 389 1.6 thorpej 390 1.6 thorpej printf("%s%d %s mode %d-bit (%d-bit count)%s", i ? ", " : "", 391 1.6 thorpej descp[i].drq, modestr, descp[i].width, 392 1.6 thorpej descp[i].countwidth, 393 1.6 thorpej descp[i].busmaster ? " busmaster" : ""); 394 1.6 thorpej 395 1.1 cgd } 396 1.1 cgd } 397 1.25 christos 398 1.25 christos void 399 1.25 christos ofisa_print_model(device_t self, int phandle) 400 1.25 christos { 401 1.25 christos char *model, small[OFW_MAX_STACK_BUF_SIZE]; 402 1.25 christos int n = OF_getproplen(phandle, "model"); 403 1.25 christos 404 1.25 christos if (n <= 0) 405 1.25 christos return; 406 1.25 christos 407 1.25 christos if (n > OFW_MAX_STACK_BUF_SIZE) { 408 1.25 christos model = malloc(n, M_TEMP, M_WAITOK); 409 1.25 christos } else { 410 1.25 christos model = small; 411 1.25 christos } 412 1.25 christos 413 1.25 christos if (OF_getprop(phandle, "model", model, n) != n) 414 1.25 christos goto out; 415 1.25 christos 416 1.25 christos aprint_normal(": %s\n", model); 417 1.25 christos if (self) 418 1.25 christos aprint_normal_dev(self, ""); 419 1.25 christos out: 420 1.25 christos if (model != small) 421 1.25 christos free(model, M_TEMP); 422 1.25 christos } 423