1139825Simp/*- 277957Sbenno * Copyright (C) 1996 Wolfgang Solfrank. 377957Sbenno * Copyright (C) 1996 TooLs GmbH. 477957Sbenno * All rights reserved. 577957Sbenno * 677957Sbenno * Redistribution and use in source and binary forms, with or without 777957Sbenno * modification, are permitted provided that the following conditions 877957Sbenno * are met: 977957Sbenno * 1. Redistributions of source code must retain the above copyright 1077957Sbenno * notice, this list of conditions and the following disclaimer. 1177957Sbenno * 2. Redistributions in binary form must reproduce the above copyright 1277957Sbenno * notice, this list of conditions and the following disclaimer in the 1377957Sbenno * documentation and/or other materials provided with the distribution. 1477957Sbenno * 3. All advertising materials mentioning features or use of this software 1577957Sbenno * must display the following acknowledgement: 1677957Sbenno * This product includes software developed by TooLs GmbH. 1777957Sbenno * 4. The name of TooLs GmbH may not be used to endorse or promote products 1877957Sbenno * derived from this software without specific prior written permission. 1977957Sbenno * 2077957Sbenno * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 2177957Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2277957Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2377957Sbenno * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2477957Sbenno * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 2577957Sbenno * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 2677957Sbenno * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 2777957Sbenno * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 2877957Sbenno * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 2977957Sbenno * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3077957Sbenno * 3177957Sbenno * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $ 3277957Sbenno */ 3377957Sbenno 34113038Sobrien#include <sys/cdefs.h> 35113038Sobrien__FBSDID("$FreeBSD$"); 3677957Sbenno 3777957Sbenno#include <sys/param.h> 3877957Sbenno#include <sys/bus.h> 3977957Sbenno#include <sys/systm.h> 4077957Sbenno#include <sys/conf.h> 4177957Sbenno#include <sys/disk.h> 4277957Sbenno#include <sys/fcntl.h> 4377957Sbenno#include <sys/malloc.h> 44208364Snwhitehorn#include <sys/smp.h> 4577957Sbenno#include <sys/stat.h> 4677957Sbenno 4799665Sbenno#include <net/ethernet.h> 4899665Sbenno 4977957Sbenno#include <dev/ofw/openfirm.h> 50165151Smarcel#include <dev/ofw/ofw_pci.h> 51183882Snwhitehorn#include <dev/ofw/ofw_bus.h> 5277957Sbenno 5390643Sbenno#include <vm/vm.h> 5490643Sbenno#include <vm/vm_param.h> 5590643Sbenno#include <vm/vm_page.h> 5690643Sbenno 57160714Smarcel#include <machine/bus.h> 58199886Snwhitehorn#include <machine/cpu.h> 59160714Smarcel#include <machine/md_var.h> 60192067Snwhitehorn#include <machine/platform.h> 6199030Sbenno#include <machine/ofw_machdep.h> 62259235Sandreast#include <machine/trap.h> 6377957Sbenno 64259235Sandreast#ifdef AIM 65151891Sgrehanextern register_t ofmsr[5]; 66222613Snwhitehornextern void *openfirmware_entry; 67186347Snwhitehornstatic void *fdt; 68186347Snwhitehornint ofw_real_mode; 69259235Sandreastextern char save_trap_init[0x2f00]; /* EXC_LAST */ 70259235Sandreastchar save_trap_of[0x2f00]; /* EXC_LAST */ 7177957Sbenno 72222667Snwhitehornint ofwcall(void *); 73186347Snwhitehornstatic int openfirmware(void *args); 74186347Snwhitehorn 75259235Sandreast__inline void 76259235Sandreastofw_save_trap_vec(char *save_trap_vec) 77259235Sandreast{ 78266020Sian if (!ofw_real_mode) 79259235Sandreast return; 80259235Sandreast 81259235Sandreast bcopy((void *)EXC_RST, save_trap_vec, EXC_LAST - EXC_RST); 82259235Sandreast} 83259235Sandreast 84259235Sandreaststatic __inline void 85259235Sandreastofw_restore_trap_vec(char *restore_trap_vec) 86259235Sandreast{ 87266020Sian if (!ofw_real_mode) 88259235Sandreast return; 89259235Sandreast 90259235Sandreast bcopy(restore_trap_vec, (void *)EXC_RST, EXC_LAST - EXC_RST); 91259235Sandreast __syncicache(EXC_RSVD, EXC_LAST - EXC_RSVD); 92259235Sandreast} 93259235Sandreast 9477957Sbenno/* 95151891Sgrehan * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback. 96151891Sgrehan */ 97151891Sgrehanregister_t ofw_sprg0_save; 98151891Sgrehan 99151891Sgrehanstatic __inline void 100151891Sgrehanofw_sprg_prepare(void) 101151891Sgrehan{ 102266020Sian if (ofw_real_mode) 103259235Sandreast return; 104259235Sandreast 105151891Sgrehan /* 106151891Sgrehan * Assume that interrupt are disabled at this point, or 107151891Sgrehan * SPRG1-3 could be trashed 108151891Sgrehan */ 109151891Sgrehan __asm __volatile("mfsprg0 %0\n\t" 110151891Sgrehan "mtsprg0 %1\n\t" 111151891Sgrehan "mtsprg1 %2\n\t" 112151891Sgrehan "mtsprg2 %3\n\t" 113151891Sgrehan "mtsprg3 %4\n\t" 114151891Sgrehan : "=&r"(ofw_sprg0_save) 115151891Sgrehan : "r"(ofmsr[1]), 116151891Sgrehan "r"(ofmsr[2]), 117151891Sgrehan "r"(ofmsr[3]), 118151891Sgrehan "r"(ofmsr[4])); 119151891Sgrehan} 120151891Sgrehan 121151891Sgrehanstatic __inline void 122151891Sgrehanofw_sprg_restore(void) 123151891Sgrehan{ 124266020Sian#if 0 125266020Sian if (ofw_real_mode) 126259235Sandreast return; 127266020Sian#endif 128259235Sandreast 129151891Sgrehan /* 130151891Sgrehan * Note that SPRG1-3 contents are irrelevant. They are scratch 131151891Sgrehan * registers used in the early portion of trap handling when 132151891Sgrehan * interrupts are disabled. 133151891Sgrehan * 134151891Sgrehan * PCPU data cannot be used until this routine is called ! 135151891Sgrehan */ 136151891Sgrehan __asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save)); 137151891Sgrehan} 138259235Sandreast#endif 139151891Sgrehan 140123370Sgrehanstatic int 141209975Snwhitehornparse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output) 14277957Sbenno{ 143209975Snwhitehorn cell_t address_cells, size_cells; 144222667Snwhitehorn cell_t OFmem[4 * PHYS_AVAIL_SZ]; 145209975Snwhitehorn int sz, i, j; 146209975Snwhitehorn int apple_hack_mode; 147190681Snwhitehorn phandle_t phandle; 148190681Snwhitehorn 149209975Snwhitehorn sz = 0; 150209975Snwhitehorn apple_hack_mode = 0; 151190681Snwhitehorn 152190681Snwhitehorn /* 153190681Snwhitehorn * Get #address-cells from root node, defaulting to 1 if it cannot 154190681Snwhitehorn * be found. 155190681Snwhitehorn */ 156190681Snwhitehorn phandle = OF_finddevice("/"); 157190681Snwhitehorn if (OF_getprop(phandle, "#address-cells", &address_cells, 158230398Snwhitehorn sizeof(address_cells)) < (ssize_t)sizeof(address_cells)) 159190681Snwhitehorn address_cells = 1; 160209975Snwhitehorn if (OF_getprop(phandle, "#size-cells", &size_cells, 161230398Snwhitehorn sizeof(size_cells)) < (ssize_t)sizeof(size_cells)) 162209975Snwhitehorn size_cells = 1; 163209975Snwhitehorn 164209975Snwhitehorn /* 16577957Sbenno * Get memory. 16677957Sbenno */ 167222667Snwhitehorn if (node == -1 || (sz = OF_getprop(node, prop, 168222667Snwhitehorn OFmem, sizeof(OFmem))) <= 0) 169209975Snwhitehorn panic("Physical memory map not found"); 170190681Snwhitehorn 171209975Snwhitehorn i = 0; 172209975Snwhitehorn j = 0; 173209975Snwhitehorn while (i < sz/sizeof(cell_t)) { 174209975Snwhitehorn #ifndef __powerpc64__ 175209975Snwhitehorn /* On 32-bit PPC, ignore regions starting above 4 GB */ 176209975Snwhitehorn if (address_cells > 1 && OFmem[i] > 0) { 177209975Snwhitehorn i += address_cells + size_cells; 178209975Snwhitehorn continue; 179190681Snwhitehorn } 180209975Snwhitehorn #endif 181190681Snwhitehorn 182209975Snwhitehorn output[j].mr_start = OFmem[i++]; 183209975Snwhitehorn if (address_cells == 2) { 184209975Snwhitehorn #ifdef __powerpc64__ 185209975Snwhitehorn output[j].mr_start <<= 32; 186209975Snwhitehorn #endif 187209975Snwhitehorn output[j].mr_start += OFmem[i++]; 188190681Snwhitehorn } 189209975Snwhitehorn 190209975Snwhitehorn output[j].mr_size = OFmem[i++]; 191209975Snwhitehorn if (size_cells == 2) { 192209975Snwhitehorn #ifdef __powerpc64__ 193209975Snwhitehorn output[j].mr_size <<= 32; 194209975Snwhitehorn #endif 195209975Snwhitehorn output[j].mr_size += OFmem[i++]; 196209975Snwhitehorn } 197190681Snwhitehorn 198209975Snwhitehorn #ifndef __powerpc64__ 199209975Snwhitehorn /* 200209975Snwhitehorn * Check for memory regions extending above 32-bit 201209975Snwhitehorn * memory space, and restrict them to stay there. 202209975Snwhitehorn */ 203209975Snwhitehorn if (((uint64_t)output[j].mr_start + 204209975Snwhitehorn (uint64_t)output[j].mr_size) > 205209975Snwhitehorn BUS_SPACE_MAXADDR_32BIT) { 206209975Snwhitehorn output[j].mr_size = BUS_SPACE_MAXADDR_32BIT - 207209975Snwhitehorn output[j].mr_start; 208209975Snwhitehorn } 209209975Snwhitehorn #endif 210190681Snwhitehorn 211209975Snwhitehorn j++; 212209975Snwhitehorn } 213209975Snwhitehorn sz = j*sizeof(output[0]); 214209975Snwhitehorn 215209975Snwhitehorn return (sz); 216209975Snwhitehorn} 217209975Snwhitehorn 218209975Snwhitehorn/* 219209975Snwhitehorn * This is called during powerpc_init, before the system is really initialized. 220209975Snwhitehorn * It shall provide the total and the available regions of RAM. 221209975Snwhitehorn * Both lists must have a zero-size entry as terminator. 222209975Snwhitehorn * The available regions need not take the kernel into account, but needs 223209975Snwhitehorn * to provide space for two additional entry beyond the terminating one. 224209975Snwhitehorn */ 225209975Snwhitehornvoid 226266020Sianofw_mem_regions(struct mem_region *memp, int *memsz, 227266020Sian struct mem_region *availp, int *availsz) 228209975Snwhitehorn{ 229209975Snwhitehorn phandle_t phandle; 230266020Sian int asz, msz; 231266020Sian int res; 232222667Snwhitehorn char name[31]; 233209975Snwhitehorn 234209975Snwhitehorn asz = msz = 0; 235209975Snwhitehorn 236209975Snwhitehorn /* 237222667Snwhitehorn * Get memory from all the /memory nodes. 238209975Snwhitehorn */ 239222667Snwhitehorn for (phandle = OF_child(OF_peer(0)); phandle != 0; 240222667Snwhitehorn phandle = OF_peer(phandle)) { 241222667Snwhitehorn if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0) 242222667Snwhitehorn continue; 243222667Snwhitehorn if (strncmp(name, "memory", sizeof(name)) != 0) 244222667Snwhitehorn continue; 245209975Snwhitehorn 246266020Sian res = parse_ofw_memory(phandle, "reg", &memp[msz]); 247222667Snwhitehorn msz += res/sizeof(struct mem_region); 248222667Snwhitehorn if (OF_getproplen(phandle, "available") >= 0) 249222667Snwhitehorn res = parse_ofw_memory(phandle, "available", 250266020Sian &availp[asz]); 251222667Snwhitehorn else 252266020Sian res = parse_ofw_memory(phandle, "reg", &availp[asz]); 253222667Snwhitehorn asz += res/sizeof(struct mem_region); 254222667Snwhitehorn } 255209975Snwhitehorn 256222667Snwhitehorn *memsz = msz; 257266020Sian *availsz = asz; 25877957Sbenno} 25977957Sbenno 260259235Sandreast#ifdef AIM 26177957Sbennovoid 262186347SnwhitehornOF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *)) 26377957Sbenno{ 264186347Snwhitehorn if (ofmsr[0] & PSL_DR) 265186347Snwhitehorn ofw_real_mode = 0; 266186347Snwhitehorn else 267186347Snwhitehorn ofw_real_mode = 1; 26877957Sbenno 269186347Snwhitehorn fdt = fdt_ptr; 270215067Snwhitehorn 271215067Snwhitehorn #ifdef FDT_DTB_STATIC 272215067Snwhitehorn /* Check for a statically included blob */ 273215067Snwhitehorn if (fdt == NULL) 274215067Snwhitehorn fdt = &fdt_static_dtb; 275215067Snwhitehorn #endif 27677957Sbenno} 27777957Sbenno 278186347Snwhitehornboolean_t 279186347SnwhitehornOF_bootstrap() 280186347Snwhitehorn{ 281186347Snwhitehorn boolean_t status = FALSE; 282186347Snwhitehorn 283222613Snwhitehorn if (openfirmware_entry != NULL) { 284209975Snwhitehorn if (ofw_real_mode) { 285186347Snwhitehorn status = OF_install(OFW_STD_REAL, 0); 286209975Snwhitehorn } else { 287209975Snwhitehorn #ifdef __powerpc64__ 288209975Snwhitehorn status = OF_install(OFW_STD_32BIT, 0); 289209975Snwhitehorn #else 290186347Snwhitehorn status = OF_install(OFW_STD_DIRECT, 0); 291209975Snwhitehorn #endif 292209975Snwhitehorn } 293186347Snwhitehorn 294186347Snwhitehorn if (status != TRUE) 295186347Snwhitehorn return status; 296186347Snwhitehorn 297186347Snwhitehorn OF_init(openfirmware); 298215067Snwhitehorn } else if (fdt != NULL) { 299186347Snwhitehorn status = OF_install(OFW_FDT, 0); 300186347Snwhitehorn 301186347Snwhitehorn if (status != TRUE) 302186347Snwhitehorn return status; 303186347Snwhitehorn 304186347Snwhitehorn OF_init(fdt); 305186347Snwhitehorn } 306186347Snwhitehorn 307186347Snwhitehorn return (status); 308186347Snwhitehorn} 309186347Snwhitehorn 310255910Snwhitehornvoid 311208172Snwhitehornofw_quiesce(void) 312208172Snwhitehorn{ 313208172Snwhitehorn struct { 314208172Snwhitehorn cell_t name; 315208172Snwhitehorn cell_t nargs; 316208172Snwhitehorn cell_t nreturns; 317208172Snwhitehorn } args; 318208172Snwhitehorn 319255910Snwhitehorn KASSERT(!pmap_bootstrapped, ("Cannot call ofw_quiesce after VM is up")); 320208172Snwhitehorn 321255910Snwhitehorn args.name = (cell_t)(uintptr_t)"quiesce"; 322255910Snwhitehorn args.nargs = 0; 323255910Snwhitehorn args.nreturns = 0; 324255910Snwhitehorn openfirmware(&args); 325208172Snwhitehorn} 326208172Snwhitehorn 327186347Snwhitehornstatic int 328208364Snwhitehornopenfirmware_core(void *args) 32977957Sbenno{ 330209975Snwhitehorn int result; 331209975Snwhitehorn register_t oldmsr; 33277957Sbenno 333209975Snwhitehorn /* 334209975Snwhitehorn * Turn off exceptions - we really don't want to end up 335215163Snwhitehorn * anywhere unexpected with PCPU set to something strange 336215163Snwhitehorn * or the stack pointer wrong. 337209975Snwhitehorn */ 338209975Snwhitehorn oldmsr = intr_disable(); 33977957Sbenno 340151891Sgrehan ofw_sprg_prepare(); 341151891Sgrehan 342259235Sandreast /* Save trap vectors */ 343259235Sandreast ofw_save_trap_vec(save_trap_of); 344259235Sandreast 345259235Sandreast /* Restore initially saved trap vectors */ 346259235Sandreast ofw_restore_trap_vec(save_trap_init); 347259235Sandreast 348215163Snwhitehorn#if defined(AIM) && !defined(__powerpc64__) 349215163Snwhitehorn /* 350215163Snwhitehorn * Clear battable[] translations 351215163Snwhitehorn */ 352215163Snwhitehorn if (!(cpu_features & PPC_FEATURE_64)) 353215163Snwhitehorn __asm __volatile("mtdbatu 2, %0\n" 354215163Snwhitehorn "mtdbatu 3, %0" : : "r" (0)); 355215163Snwhitehorn isync(); 356215163Snwhitehorn#endif 357209975Snwhitehorn 358219428Snwhitehorn result = ofwcall(args); 359259235Sandreast 360259235Sandreast /* Restore trap vecotrs */ 361259235Sandreast ofw_restore_trap_vec(save_trap_of); 362259235Sandreast 363151891Sgrehan ofw_sprg_restore(); 364151891Sgrehan 365209975Snwhitehorn intr_restore(oldmsr); 36677957Sbenno 367208364Snwhitehorn return (result); 368208364Snwhitehorn} 369208364Snwhitehorn 370208364Snwhitehorn#ifdef SMP 371208364Snwhitehornstruct ofw_rv_args { 372208364Snwhitehorn void *args; 373208364Snwhitehorn int retval; 374208364Snwhitehorn volatile int in_progress; 375208364Snwhitehorn}; 376208364Snwhitehorn 377208364Snwhitehornstatic void 378208364Snwhitehornofw_rendezvous_dispatch(void *xargs) 379208364Snwhitehorn{ 380208364Snwhitehorn struct ofw_rv_args *rv_args = xargs; 381208364Snwhitehorn 382208364Snwhitehorn /* NOTE: Interrupts are disabled here */ 383208364Snwhitehorn 384208364Snwhitehorn if (PCPU_GET(cpuid) == 0) { 385208364Snwhitehorn /* 386208364Snwhitehorn * Execute all OF calls on CPU 0 387208364Snwhitehorn */ 388208364Snwhitehorn rv_args->retval = openfirmware_core(rv_args->args); 389208364Snwhitehorn rv_args->in_progress = 0; 390208364Snwhitehorn } else { 391208364Snwhitehorn /* 392208364Snwhitehorn * Spin with interrupts off on other CPUs while OF has 393208364Snwhitehorn * control of the machine. 394208364Snwhitehorn */ 395208364Snwhitehorn while (rv_args->in_progress) 396208364Snwhitehorn cpu_spinwait(); 397208364Snwhitehorn } 398208364Snwhitehorn} 399208364Snwhitehorn#endif 400208364Snwhitehorn 401208364Snwhitehornstatic int 402208364Snwhitehornopenfirmware(void *args) 403208364Snwhitehorn{ 404208364Snwhitehorn int result; 405208364Snwhitehorn #ifdef SMP 406208364Snwhitehorn struct ofw_rv_args rv_args; 407208364Snwhitehorn 408208364Snwhitehorn rv_args.args = args; 409208364Snwhitehorn rv_args.in_progress = 1; 410208364Snwhitehorn smp_rendezvous(smp_no_rendevous_barrier, ofw_rendezvous_dispatch, 411208364Snwhitehorn smp_no_rendevous_barrier, &rv_args); 412208364Snwhitehorn result = rv_args.retval; 413208364Snwhitehorn #else 414208364Snwhitehorn result = openfirmware_core(args); 415208364Snwhitehorn #endif 416208364Snwhitehorn 41777957Sbenno return (result); 41877957Sbenno} 41977957Sbenno 42077957Sbennovoid 421212054SnwhitehornOF_reboot() 422123353Sgallatin{ 423212054Snwhitehorn struct { 424212054Snwhitehorn cell_t name; 425212054Snwhitehorn cell_t nargs; 426212054Snwhitehorn cell_t nreturns; 427212054Snwhitehorn cell_t arg; 428212054Snwhitehorn } args; 429123353Sgallatin 430212054Snwhitehorn args.name = (cell_t)(uintptr_t)"interpret"; 431212054Snwhitehorn args.nargs = 1; 432212054Snwhitehorn args.nreturns = 0; 433212054Snwhitehorn args.arg = (cell_t)(uintptr_t)"reset-all"; 434212054Snwhitehorn openfirmware_core(&args); /* Don't do rendezvous! */ 435123353Sgallatin 436123353Sgallatin for (;;); /* just in case */ 437123353Sgallatin} 438123353Sgallatin 439259235Sandreast#endif /* AIM */ 440259235Sandreast 441123353Sgallatinvoid 44299665SbennoOF_getetheraddr(device_t dev, u_char *addr) 44399665Sbenno{ 44499665Sbenno phandle_t node; 44599665Sbenno 446183882Snwhitehorn node = ofw_bus_get_node(dev); 44799665Sbenno OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN); 44899665Sbenno} 449133855Sssouhlal 450160714Smarcel/* 451165151Smarcel * Return a bus handle and bus tag that corresponds to the register 452165151Smarcel * numbered regno for the device referenced by the package handle 453165151Smarcel * dev. This function is intended to be used by console drivers in 454165151Smarcel * early boot only. It works by mapping the address of the device's 455165151Smarcel * register in the address space of its parent and recursively walk 456165151Smarcel * the device tree upward this way. 457160714Smarcel */ 458165151Smarcelstatic void 459165151SmarcelOF_get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip) 460165151Smarcel{ 461259235Sandreast char type[64]; 462165151Smarcel uint32_t addr, size; 463165151Smarcel int pci, res; 464165151Smarcel 465165151Smarcel res = OF_getprop(node, "#address-cells", &addr, sizeof(addr)); 466165151Smarcel if (res == -1) 467165151Smarcel addr = 2; 468165151Smarcel res = OF_getprop(node, "#size-cells", &size, sizeof(size)); 469165151Smarcel if (res == -1) 470165151Smarcel size = 1; 471165151Smarcel pci = 0; 472165151Smarcel if (addr == 3 && size == 2) { 473259235Sandreast res = OF_getprop(node, "device_type", type, sizeof(type)); 474165151Smarcel if (res != -1) { 475259235Sandreast type[sizeof(type) - 1] = '\0'; 476259235Sandreast pci = (strcmp(type, "pci") == 0) ? 1 : 0; 477165151Smarcel } 478165151Smarcel } 479165151Smarcel if (addrp != NULL) 480165151Smarcel *addrp = addr; 481165151Smarcel if (sizep != NULL) 482165151Smarcel *sizep = size; 483165151Smarcel if (pcip != NULL) 484165151Smarcel *pcip = pci; 485165151Smarcel} 486165151Smarcel 487133855Sssouhlalint 488165151SmarcelOF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag, 489160714Smarcel bus_space_handle_t *handle) 490160714Smarcel{ 491165151Smarcel uint32_t cell[32]; 492165151Smarcel bus_addr_t addr, raddr, baddr; 493165151Smarcel bus_size_t size, rsize; 494165151Smarcel uint32_t c, nbridge, naddr, nsize; 495165151Smarcel phandle_t bridge, parent; 496255904Snwhitehorn u_int spc, rspc, prefetch; 497165151Smarcel int pci, pcib, res; 498160714Smarcel 499165151Smarcel /* Sanity checking. */ 500165151Smarcel if (dev == 0) 501165151Smarcel return (EINVAL); 502165151Smarcel bridge = OF_parent(dev); 503165151Smarcel if (bridge == 0) 504165151Smarcel return (EINVAL); 505165151Smarcel if (regno < 0) 506165151Smarcel return (EINVAL); 507165151Smarcel if (tag == NULL || handle == NULL) 508165151Smarcel return (EINVAL); 509165151Smarcel 510259235Sandreast /* Assume big-endian unless we find a PCI device */ 511259235Sandreast *tag = &bs_be_tag; 512259235Sandreast 513165151Smarcel /* Get the requested register. */ 514165151Smarcel OF_get_addr_props(bridge, &naddr, &nsize, &pci); 515259235Sandreast if (pci) 516259235Sandreast *tag = &bs_le_tag; 517165151Smarcel res = OF_getprop(dev, (pci) ? "assigned-addresses" : "reg", 518165151Smarcel cell, sizeof(cell)); 519165151Smarcel if (res == -1) 520165151Smarcel return (ENXIO); 521165151Smarcel if (res % sizeof(cell[0])) 522165151Smarcel return (ENXIO); 523165151Smarcel res /= sizeof(cell[0]); 524165151Smarcel regno *= naddr + nsize; 525165151Smarcel if (regno + naddr + nsize > res) 526165151Smarcel return (EINVAL); 527165151Smarcel spc = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK : ~0; 528255904Snwhitehorn prefetch = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_PREFETCHABLE : 0; 529165151Smarcel addr = 0; 530165151Smarcel for (c = 0; c < naddr; c++) 531165151Smarcel addr = ((uint64_t)addr << 32) | cell[regno++]; 532165151Smarcel size = 0; 533165151Smarcel for (c = 0; c < nsize; c++) 534165151Smarcel size = ((uint64_t)size << 32) | cell[regno++]; 535165151Smarcel 536165151Smarcel /* 537165151Smarcel * Map the address range in the bridge's decoding window as given 538165151Smarcel * by the "ranges" property. If a node doesn't have such property 539165151Smarcel * then no mapping is done. 540165151Smarcel */ 541165151Smarcel parent = OF_parent(bridge); 542165151Smarcel while (parent != 0) { 543165151Smarcel OF_get_addr_props(parent, &nbridge, NULL, &pcib); 544259235Sandreast if (pcib) 545259235Sandreast *tag = &bs_le_tag; 546165151Smarcel res = OF_getprop(bridge, "ranges", cell, sizeof(cell)); 547165151Smarcel if (res == -1) 548165151Smarcel goto next; 549165151Smarcel if (res % sizeof(cell[0])) 550165151Smarcel return (ENXIO); 551165151Smarcel res /= sizeof(cell[0]); 552165151Smarcel regno = 0; 553165151Smarcel while (regno < res) { 554165151Smarcel rspc = (pci) 555165151Smarcel ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK 556165151Smarcel : ~0; 557165151Smarcel if (rspc != spc) { 558165151Smarcel regno += naddr + nbridge + nsize; 559165151Smarcel continue; 560165151Smarcel } 561165151Smarcel raddr = 0; 562165151Smarcel for (c = 0; c < naddr; c++) 563165151Smarcel raddr = ((uint64_t)raddr << 32) | cell[regno++]; 564165151Smarcel rspc = (pcib) 565165151Smarcel ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK 566165151Smarcel : ~0; 567165151Smarcel baddr = 0; 568165151Smarcel for (c = 0; c < nbridge; c++) 569165151Smarcel baddr = ((uint64_t)baddr << 32) | cell[regno++]; 570165151Smarcel rsize = 0; 571165151Smarcel for (c = 0; c < nsize; c++) 572165151Smarcel rsize = ((uint64_t)rsize << 32) | cell[regno++]; 573165151Smarcel if (addr < raddr || addr >= raddr + rsize) 574165151Smarcel continue; 575165151Smarcel addr = addr - raddr + baddr; 576165151Smarcel if (rspc != ~0) 577165151Smarcel spc = rspc; 578165151Smarcel } 579165151Smarcel 580165151Smarcel next: 581165151Smarcel bridge = parent; 582165151Smarcel parent = OF_parent(bridge); 583165151Smarcel OF_get_addr_props(bridge, &naddr, &nsize, &pci); 584165151Smarcel } 585165151Smarcel 586255904Snwhitehorn return (bus_space_map(*tag, addr, size, 587255904Snwhitehorn prefetch ? BUS_SPACE_MAP_PREFETCHABLE : 0, handle)); 588160714Smarcel} 589160714Smarcel 590