1 /* $OpenBSD: mainbus.c,v 1.32 2024/11/18 05:32:39 jsg Exp $ */ 2 /* 3 * Copyright (c) 2016 Patrick Wildt <patrick@blueri.se> 4 * Copyright (c) 2017 Mark Kettenis <kettenis@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/kernel.h> 22 #include <sys/device.h> 23 #include <sys/malloc.h> 24 25 #include <machine/fdt.h> 26 #include <dev/ofw/openfirm.h> 27 #include <dev/ofw/fdt.h> 28 #include <dev/ofw/ofw_misc.h> 29 #include <dev/ofw/ofw_thermal.h> 30 31 int mainbus_match(struct device *, void *, void *); 32 void mainbus_attach(struct device *, struct device *, void *); 33 34 void mainbus_attach_node(struct device *, int, cfmatch_t); 35 int mainbus_match_status(struct device *, void *, void *); 36 void mainbus_attach_cpus(struct device *, cfmatch_t); 37 int mainbus_match_primary(struct device *, void *, void *); 38 int mainbus_match_secondary(struct device *, void *, void *); 39 void mainbus_attach_psci(struct device *); 40 void mainbus_attach_efi(struct device *); 41 void mainbus_attach_apm(struct device *); 42 void mainbus_attach_framebuffer(struct device *); 43 void mainbus_attach_firmware(struct device *); 44 void mainbus_attach_resvmem(struct device *); 45 46 struct mainbus_softc { 47 struct device sc_dev; 48 int sc_node; 49 bus_space_tag_t sc_iot; 50 bus_dma_tag_t sc_dmat; 51 int sc_acells; 52 int sc_scells; 53 int *sc_ranges; 54 int sc_rangeslen; 55 int sc_early; 56 int sc_early_nodes[64]; 57 }; 58 59 const struct cfattach mainbus_ca = { 60 sizeof(struct mainbus_softc), mainbus_match, mainbus_attach 61 }; 62 63 struct cfdriver mainbus_cd = { 64 NULL, "mainbus", DV_DULL 65 }; 66 67 struct machine_bus_dma_tag mainbus_dma_tag = { 68 NULL, 69 0, 70 _dmamap_create, 71 _dmamap_destroy, 72 _dmamap_load, 73 _dmamap_load_mbuf, 74 _dmamap_load_uio, 75 _dmamap_load_raw, 76 _dmamap_load_buffer, 77 _dmamap_unload, 78 _dmamap_sync, 79 _dmamem_alloc, 80 _dmamem_alloc_range, 81 _dmamem_free, 82 _dmamem_map, 83 _dmamem_unmap, 84 _dmamem_mmap, 85 }; 86 87 /* 88 * Mainbus takes care of FDT and non-FDT machines, so we 89 * always attach. 90 */ 91 int 92 mainbus_match(struct device *parent, void *cfdata, void *aux) 93 { 94 return (1); 95 } 96 97 void agtimer_init(void); 98 99 void 100 mainbus_attach(struct device *parent, struct device *self, void *aux) 101 { 102 struct mainbus_softc *sc = (struct mainbus_softc *)self; 103 char prop[128]; 104 int node, len; 105 106 arm_intr_init_fdt(); 107 agtimer_init(); 108 109 sc->sc_node = OF_peer(0); 110 sc->sc_iot = &arm64_bs_tag; 111 sc->sc_dmat = &mainbus_dma_tag; 112 sc->sc_acells = OF_getpropint(OF_peer(0), "#address-cells", 1); 113 sc->sc_scells = OF_getpropint(OF_peer(0), "#size-cells", 1); 114 115 len = OF_getprop(sc->sc_node, "model", prop, sizeof(prop)); 116 if (len > 0) { 117 printf(": %s\n", prop); 118 hw_prod = malloc(len, M_DEVBUF, M_NOWAIT); 119 if (hw_prod) 120 strlcpy(hw_prod, prop, len); 121 } else 122 printf(": unknown model\n"); 123 124 len = OF_getprop(sc->sc_node, "serial-number", prop, sizeof(prop)); 125 if (len > 0) { 126 hw_serial = malloc(len, M_DEVBUF, M_NOWAIT); 127 if (hw_serial) 128 strlcpy(hw_serial, prop, len); 129 } 130 131 mainbus_attach_psci(self); 132 mainbus_attach_efi(self); 133 134 /* Attach primary CPU first. */ 135 mainbus_attach_cpus(self, mainbus_match_primary); 136 137 /* Attach secondary CPUs. */ 138 mainbus_attach_cpus(self, mainbus_match_secondary); 139 140 mainbus_attach_firmware(self); 141 mainbus_attach_resvmem(self); 142 143 sc->sc_rangeslen = OF_getproplen(OF_peer(0), "ranges"); 144 if (sc->sc_rangeslen > 0 && !(sc->sc_rangeslen % sizeof(uint32_t))) { 145 sc->sc_ranges = malloc(sc->sc_rangeslen, M_TEMP, M_WAITOK); 146 OF_getpropintarray(OF_peer(0), "ranges", sc->sc_ranges, 147 sc->sc_rangeslen); 148 } 149 150 mainbus_attach_apm(self); 151 152 /* Scan the whole tree. */ 153 for (sc->sc_early = 2; sc->sc_early >= 0; sc->sc_early--) { 154 for (node = OF_child(sc->sc_node); node; node = OF_peer(node)) 155 mainbus_attach_node(self, node, NULL); 156 } 157 sc->sc_early = 0; 158 159 /* 160 * Delay attaching the framebuffer to give other drivers a 161 * chance to claim it. 162 */ 163 config_mountroot(self, mainbus_attach_framebuffer); 164 165 thermal_init(); 166 } 167 168 int 169 mainbus_print(void *aux, const char *pnp) 170 { 171 struct fdt_attach_args *fa = aux; 172 char buf[32]; 173 174 if (!pnp) 175 return (QUIET); 176 177 if (OF_getprop(fa->fa_node, "status", buf, sizeof(buf)) > 0 && 178 strcmp(buf, "disabled") == 0) 179 return (QUIET); 180 181 if (OF_getprop(fa->fa_node, "name", buf, sizeof(buf)) > 0) { 182 buf[sizeof(buf) - 1] = 0; 183 if (strcmp(buf, "aliases") == 0 || 184 strcmp(buf, "chosen") == 0 || 185 strcmp(buf, "cpus") == 0 || 186 strcmp(buf, "memory") == 0 || 187 strcmp(buf, "reserved-memory") == 0 || 188 strcmp(buf, "thermal-zones") == 0 || 189 strncmp(buf, "__", 2) == 0) 190 return (QUIET); 191 printf("\"%s\"", buf); 192 } else 193 printf("node %u", fa->fa_node); 194 195 printf(" at %s", pnp); 196 197 return (UNCONF); 198 } 199 200 /* 201 * Look for a driver that wants to be attached to this node. 202 */ 203 void 204 mainbus_attach_node(struct device *self, int node, cfmatch_t submatch) 205 { 206 struct mainbus_softc *sc = (struct mainbus_softc *)self; 207 struct fdt_attach_args fa; 208 int i, len, line; 209 uint32_t *cell, *reg; 210 struct device *child; 211 cfprint_t print = NULL; 212 213 /* Skip if already attached early. */ 214 for (i = 0; i < nitems(sc->sc_early_nodes); i++) { 215 if (sc->sc_early_nodes[i] == node) 216 return; 217 if (sc->sc_early_nodes[i] == 0) 218 break; 219 } 220 221 memset(&fa, 0, sizeof(fa)); 222 fa.fa_name = ""; 223 fa.fa_node = node; 224 fa.fa_iot = sc->sc_iot; 225 fa.fa_dmat = sc->sc_dmat; 226 fa.fa_acells = sc->sc_acells; 227 fa.fa_scells = sc->sc_scells; 228 229 len = OF_getproplen(node, "reg"); 230 line = (sc->sc_acells + sc->sc_scells) * sizeof(uint32_t); 231 if (len > 0 && (len % line) == 0) { 232 reg = malloc(len, M_TEMP, M_WAITOK); 233 OF_getpropintarray(node, "reg", reg, len); 234 235 fa.fa_reg = malloc((len / line) * sizeof(struct fdt_reg), 236 M_DEVBUF, M_WAITOK); 237 fa.fa_nreg = (len / line); 238 239 for (i = 0, cell = reg; i < len / line; i++) { 240 if (sc->sc_acells >= 1) 241 fa.fa_reg[i].addr = cell[0]; 242 if (sc->sc_acells == 2) { 243 fa.fa_reg[i].addr <<= 32; 244 fa.fa_reg[i].addr |= cell[1]; 245 } 246 cell += sc->sc_acells; 247 if (sc->sc_scells >= 1) 248 fa.fa_reg[i].size = cell[0]; 249 if (sc->sc_scells == 2) { 250 fa.fa_reg[i].size <<= 32; 251 fa.fa_reg[i].size |= cell[1]; 252 } 253 cell += sc->sc_scells; 254 } 255 256 free(reg, M_TEMP, len); 257 } 258 259 len = OF_getproplen(node, "interrupts"); 260 if (len > 0 && (len % sizeof(uint32_t)) == 0) { 261 fa.fa_intr = malloc(len, M_DEVBUF, M_WAITOK); 262 fa.fa_nintr = len / sizeof(uint32_t); 263 264 OF_getpropintarray(node, "interrupts", fa.fa_intr, len); 265 } 266 267 if (OF_getproplen(node, "dma-coherent") >= 0) { 268 fa.fa_dmat = malloc(sizeof(*sc->sc_dmat), 269 M_DEVBUF, M_WAITOK | M_ZERO); 270 memcpy(fa.fa_dmat, sc->sc_dmat, sizeof(*sc->sc_dmat)); 271 fa.fa_dmat->_flags |= BUS_DMA_COHERENT; 272 } 273 274 fa.fa_dmat = iommu_device_map(fa.fa_node, fa.fa_dmat); 275 276 if (submatch == NULL && sc->sc_early == 0) 277 print = mainbus_print; 278 if (submatch == NULL) 279 submatch = mainbus_match_status; 280 281 child = config_found_sm(self, &fa, print, submatch); 282 283 /* Record nodes that we attach early. */ 284 if (child && sc->sc_early) { 285 for (i = 0; i < nitems(sc->sc_early_nodes); i++) { 286 if (sc->sc_early_nodes[i] != 0) 287 continue; 288 sc->sc_early_nodes[i] = node; 289 break; 290 } 291 } 292 293 free(fa.fa_reg, M_DEVBUF, fa.fa_nreg * sizeof(struct fdt_reg)); 294 free(fa.fa_intr, M_DEVBUF, fa.fa_nintr * sizeof(uint32_t)); 295 } 296 297 int 298 mainbus_match_status(struct device *parent, void *match, void *aux) 299 { 300 struct mainbus_softc *sc = (struct mainbus_softc *)parent; 301 struct fdt_attach_args *fa = aux; 302 struct cfdata *cf = match; 303 char buf[32]; 304 305 if (OF_getprop(fa->fa_node, "status", buf, sizeof(buf)) > 0 && 306 strcmp(buf, "disabled") == 0) 307 return 0; 308 309 if (cf->cf_loc[0] == sc->sc_early) 310 return (*cf->cf_attach->ca_match)(parent, match, aux); 311 312 return 0; 313 } 314 315 void 316 mainbus_attach_cpus(struct device *self, cfmatch_t match) 317 { 318 struct mainbus_softc *sc = (struct mainbus_softc *)self; 319 int node = OF_finddevice("/cpus"); 320 int acells, scells; 321 char buf[32]; 322 323 if (node == -1) 324 return; 325 326 acells = sc->sc_acells; 327 scells = sc->sc_scells; 328 sc->sc_acells = OF_getpropint(node, "#address-cells", 2); 329 sc->sc_scells = OF_getpropint(node, "#size-cells", 0); 330 331 ncpusfound = 0; 332 for (node = OF_child(node); node != 0; node = OF_peer(node)) { 333 if (OF_getprop(node, "device_type", buf, sizeof(buf)) > 0 && 334 strcmp(buf, "cpu") == 0) 335 ncpusfound++; 336 337 mainbus_attach_node(self, node, match); 338 } 339 340 sc->sc_acells = acells; 341 sc->sc_scells = scells; 342 } 343 344 int 345 mainbus_match_primary(struct device *parent, void *match, void *aux) 346 { 347 struct fdt_attach_args *fa = aux; 348 struct cfdata *cf = match; 349 uint64_t mpidr = READ_SPECIALREG(mpidr_el1); 350 351 if (fa->fa_nreg < 1 || fa->fa_reg[0].addr != (mpidr & MPIDR_AFF)) 352 return 0; 353 354 return (*cf->cf_attach->ca_match)(parent, match, aux); 355 } 356 357 int 358 mainbus_match_secondary(struct device *parent, void *match, void *aux) 359 { 360 struct fdt_attach_args *fa = aux; 361 struct cfdata *cf = match; 362 uint64_t mpidr = READ_SPECIALREG(mpidr_el1); 363 364 if (fa->fa_nreg < 1 || fa->fa_reg[0].addr == (mpidr & MPIDR_AFF)) 365 return 0; 366 367 return (*cf->cf_attach->ca_match)(parent, match, aux); 368 } 369 370 void 371 mainbus_attach_psci(struct device *self) 372 { 373 struct mainbus_softc *sc = (struct mainbus_softc *)self; 374 int node = OF_finddevice("/psci"); 375 376 if (node == -1) 377 return; 378 379 sc->sc_early = 1; 380 mainbus_attach_node(self, node, NULL); 381 sc->sc_early = 0; 382 } 383 384 void 385 mainbus_attach_efi(struct device *self) 386 { 387 struct mainbus_softc *sc = (struct mainbus_softc *)self; 388 struct fdt_attach_args fa; 389 int node = OF_finddevice("/chosen"); 390 391 if (node == -1 || 392 OF_getproplen(node, "openbsd,uefi-system-table") <= 0) 393 return; 394 395 memset(&fa, 0, sizeof(fa)); 396 fa.fa_name = "efi"; 397 fa.fa_iot = sc->sc_iot; 398 fa.fa_dmat = sc->sc_dmat; 399 config_found(self, &fa, NULL); 400 } 401 402 void 403 mainbus_attach_apm(struct device *self) 404 { 405 struct fdt_attach_args fa; 406 407 memset(&fa, 0, sizeof(fa)); 408 fa.fa_name = "apm"; 409 410 config_found(self, &fa, NULL); 411 } 412 413 void 414 mainbus_attach_framebuffer(struct device *self) 415 { 416 int node = OF_finddevice("/chosen"); 417 418 if (node == -1) 419 return; 420 421 for (node = OF_child(node); node != 0; node = OF_peer(node)) 422 mainbus_attach_node(self, node, NULL); 423 } 424 425 void 426 mainbus_attach_firmware(struct device *self) 427 { 428 int node = OF_finddevice("/firmware"); 429 430 if (node == -1) 431 return; 432 433 for (node = OF_child(node); node != 0; node = OF_peer(node)) 434 mainbus_attach_node(self, node, NULL); 435 } 436 437 void 438 mainbus_attach_resvmem(struct device *self) 439 { 440 int node = OF_finddevice("/reserved-memory"); 441 442 if (node == -1) 443 return; 444 445 for (node = OF_child(node); node != 0; node = OF_peer(node)) 446 mainbus_attach_node(self, node, NULL); 447 } 448