1208747Sraj/*- 2208747Sraj * Copyright (c) 2009-2010 The FreeBSD Foundation 3208747Sraj * All rights reserved. 4208747Sraj * 5208747Sraj * This software was developed by Semihalf under sponsorship from 6208747Sraj * the FreeBSD Foundation. 7208747Sraj * 8208747Sraj * Redistribution and use in source and binary forms, with or without 9208747Sraj * modification, are permitted provided that the following conditions 10208747Sraj * are met: 11208747Sraj * 1. Redistributions of source code must retain the above copyright 12208747Sraj * notice, this list of conditions and the following disclaimer. 13208747Sraj * 2. Redistributions in binary form must reproduce the above copyright 14208747Sraj * notice, this list of conditions and the following disclaimer in the 15208747Sraj * documentation and/or other materials provided with the distribution. 16208747Sraj * 17208747Sraj * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18208747Sraj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19208747Sraj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20208747Sraj * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21208747Sraj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22208747Sraj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23208747Sraj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24208747Sraj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25208747Sraj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26208747Sraj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27208747Sraj * SUCH DAMAGE. 28208747Sraj */ 29208747Sraj 30208747Sraj#include <sys/cdefs.h> 31208747Sraj__FBSDID("$FreeBSD$"); 32208747Sraj 33208747Sraj#include <sys/param.h> 34208747Sraj#include <sys/systm.h> 35208747Sraj#include <sys/kernel.h> 36208747Sraj#include <sys/module.h> 37208747Sraj#include <sys/bus.h> 38208747Sraj 39208747Sraj#include <machine/fdt.h> 40208747Sraj#include <machine/resource.h> 41208747Sraj 42208747Sraj#include <dev/fdt/fdt_common.h> 43208747Sraj#include <dev/ofw/ofw_bus.h> 44208747Sraj#include <dev/ofw/ofw_bus_subr.h> 45208747Sraj#include <dev/ofw/openfirm.h> 46208747Sraj 47208747Sraj#include "ofw_bus_if.h" 48208747Sraj 49208747Sraj#ifdef DEBUG 50208747Sraj#define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 51208747Sraj printf(fmt,##args); } while (0) 52208747Sraj#else 53208747Sraj#define debugf(fmt, args...) 54208747Sraj#endif 55208747Sraj 56208747Sraj#define FDT_COMPAT_LEN 255 57208747Sraj#define FDT_TYPE_LEN 64 58208747Sraj 59208747Sraj#define FDT_REG_CELLS 4 60208747Sraj 61208747Srajvm_paddr_t fdt_immr_pa; 62208747Srajvm_offset_t fdt_immr_va; 63208747Srajvm_offset_t fdt_immr_size; 64208747Sraj 65208747Srajint 66210247Srajfdt_immr_addr(vm_offset_t immr_va) 67208747Sraj{ 68208747Sraj pcell_t ranges[6], *rangesptr; 69208747Sraj phandle_t node; 70208747Sraj u_long base, size; 71208747Sraj pcell_t addr_cells, size_cells, par_addr_cells; 72208747Sraj int len, tuple_size, tuples; 73208747Sraj 74208747Sraj /* 75208747Sraj * Try to access the SOC node directly i.e. through /aliases/. 76208747Sraj */ 77208747Sraj if ((node = OF_finddevice("soc")) != 0) 78208747Sraj if (fdt_is_compatible_strict(node, "simple-bus")) 79208747Sraj goto moveon; 80208747Sraj /* 81208747Sraj * Find the node the long way. 82208747Sraj */ 83208747Sraj if ((node = OF_finddevice("/")) == 0) 84208747Sraj return (ENXIO); 85208747Sraj 86208747Sraj if ((node = fdt_find_compatible(node, "simple-bus", 1)) == 0) 87208747Sraj return (ENXIO); 88208747Sraj 89208747Srajmoveon: 90208747Sraj if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0) 91208747Sraj return (ENXIO); 92208747Sraj /* 93208747Sraj * Process 'ranges' property. 94208747Sraj */ 95208747Sraj par_addr_cells = fdt_parent_addr_cells(node); 96208747Sraj if (par_addr_cells > 2) 97208747Sraj return (ERANGE); 98208747Sraj 99208747Sraj len = OF_getproplen(node, "ranges"); 100208747Sraj if (len > sizeof(ranges)) 101208747Sraj return (ENOMEM); 102208747Sraj 103208747Sraj if (OF_getprop(node, "ranges", ranges, sizeof(ranges)) <= 0) 104208747Sraj return (EINVAL); 105208747Sraj 106208747Sraj tuple_size = sizeof(pcell_t) * (addr_cells + par_addr_cells + 107208747Sraj size_cells); 108208747Sraj tuples = len / tuple_size; 109208747Sraj 110208747Sraj if (fdt_ranges_verify(ranges, tuples, par_addr_cells, 111208747Sraj addr_cells, size_cells)) { 112208747Sraj return (ERANGE); 113208747Sraj } 114208747Sraj base = 0; 115208747Sraj size = 0; 116208747Sraj rangesptr = &ranges[0]; 117208747Sraj 118208747Sraj base = fdt_data_get((void *)rangesptr, addr_cells); 119208747Sraj rangesptr += addr_cells; 120208747Sraj base += fdt_data_get((void *)rangesptr, par_addr_cells); 121208747Sraj rangesptr += par_addr_cells; 122208747Sraj size = fdt_data_get((void *)rangesptr, size_cells); 123208747Sraj 124208747Sraj fdt_immr_pa = base; 125210247Sraj fdt_immr_va = immr_va; 126208747Sraj fdt_immr_size = size; 127208747Sraj 128208747Sraj return (0); 129208747Sraj} 130208747Sraj 131208747Sraj/* 132208747Sraj * This routine is an early-usage version of the ofw_bus_is_compatible() when 133208747Sraj * the ofw_bus I/F is not available (like early console routines and similar). 134208747Sraj * Note the buffer has to be on the stack since malloc() is usually not 135208747Sraj * available in such cases either. 136208747Sraj */ 137208747Srajint 138208747Srajfdt_is_compatible(phandle_t node, const char *compatstr) 139208747Sraj{ 140208747Sraj char buf[FDT_COMPAT_LEN]; 141208747Sraj char *compat; 142208747Sraj int len, onelen, l, rv; 143208747Sraj 144208747Sraj if ((len = OF_getproplen(node, "compatible")) <= 0) 145208747Sraj return (0); 146208747Sraj 147208747Sraj compat = (char *)&buf; 148208747Sraj bzero(compat, FDT_COMPAT_LEN); 149208747Sraj 150208747Sraj if (OF_getprop(node, "compatible", compat, FDT_COMPAT_LEN) < 0) 151208747Sraj return (0); 152208747Sraj 153208747Sraj onelen = strlen(compatstr); 154208747Sraj rv = 0; 155208747Sraj while (len > 0) { 156208747Sraj if (strncasecmp(compat, compatstr, onelen) == 0) { 157208747Sraj /* Found it. */ 158208747Sraj rv = 1; 159208747Sraj break; 160208747Sraj } 161208747Sraj /* Slide to the next sub-string. */ 162208747Sraj l = strlen(compat) + 1; 163208747Sraj compat += l; 164208747Sraj len -= l; 165208747Sraj } 166208747Sraj 167208747Sraj return (rv); 168208747Sraj} 169208747Sraj 170208747Srajint 171208747Srajfdt_is_compatible_strict(phandle_t node, const char *compatible) 172208747Sraj{ 173208747Sraj char compat[FDT_COMPAT_LEN]; 174208747Sraj 175208747Sraj if (OF_getproplen(node, "compatible") <= 0) 176208747Sraj return (0); 177208747Sraj 178208747Sraj if (OF_getprop(node, "compatible", compat, FDT_COMPAT_LEN) < 0) 179208747Sraj return (0); 180208747Sraj 181208747Sraj if (strncasecmp(compat, compatible, FDT_COMPAT_LEN) == 0) 182208747Sraj /* This fits. */ 183208747Sraj return (1); 184208747Sraj 185208747Sraj return (0); 186208747Sraj} 187208747Sraj 188208747Srajphandle_t 189208747Srajfdt_find_compatible(phandle_t start, const char *compat, int strict) 190208747Sraj{ 191208747Sraj phandle_t child; 192208747Sraj 193208747Sraj /* 194208747Sraj * Traverse all children of 'start' node, and find first with 195208747Sraj * matching 'compatible' property. 196208747Sraj */ 197208747Sraj for (child = OF_child(start); child != 0; child = OF_peer(child)) 198208747Sraj if (fdt_is_compatible(child, compat)) { 199208747Sraj if (strict) 200208747Sraj if (!fdt_is_compatible_strict(child, compat)) 201208747Sraj continue; 202208747Sraj return (child); 203208747Sraj } 204208747Sraj return (0); 205208747Sraj} 206208747Sraj 207208747Srajint 208208747Srajfdt_is_enabled(phandle_t node) 209208747Sraj{ 210208747Sraj char *stat; 211208747Sraj int ena, len; 212208747Sraj 213208747Sraj len = OF_getprop_alloc(node, "status", sizeof(char), 214208747Sraj (void **)&stat); 215208747Sraj 216208747Sraj if (len <= 0) 217208747Sraj /* It is OK if no 'status' property. */ 218208747Sraj return (1); 219208747Sraj 220208747Sraj /* Anything other than 'okay' means disabled. */ 221208747Sraj ena = 0; 222208747Sraj if (strncmp((char *)stat, "okay", len) == 0) 223208747Sraj ena = 1; 224208747Sraj 225208747Sraj free(stat, M_OFWPROP); 226208747Sraj return (ena); 227208747Sraj} 228208747Sraj 229208747Srajint 230208747Srajfdt_is_type(phandle_t node, const char *typestr) 231208747Sraj{ 232208747Sraj char type[FDT_TYPE_LEN]; 233208747Sraj 234208747Sraj if (OF_getproplen(node, "device_type") <= 0) 235208747Sraj return (0); 236208747Sraj 237208747Sraj if (OF_getprop(node, "device_type", type, FDT_TYPE_LEN) < 0) 238208747Sraj return (0); 239208747Sraj 240208747Sraj if (strncasecmp(type, typestr, FDT_TYPE_LEN) == 0) 241208747Sraj /* This fits. */ 242208747Sraj return (1); 243208747Sraj 244208747Sraj return (0); 245208747Sraj} 246208747Sraj 247208747Srajint 248208747Srajfdt_parent_addr_cells(phandle_t node) 249208747Sraj{ 250208747Sraj pcell_t addr_cells; 251208747Sraj 252208747Sraj /* Find out #address-cells of the superior bus. */ 253208747Sraj if (OF_searchprop(OF_parent(node), "#address-cells", &addr_cells, 254208747Sraj sizeof(addr_cells)) <= 0) 255208747Sraj addr_cells = 2; 256208747Sraj 257208747Sraj return ((int)fdt32_to_cpu(addr_cells)); 258208747Sraj} 259208747Sraj 260208747Srajint 261208747Srajfdt_data_verify(void *data, int cells) 262208747Sraj{ 263208747Sraj uint64_t d64; 264208747Sraj 265208747Sraj if (cells > 1) { 266208747Sraj d64 = fdt64_to_cpu(*((uint64_t *)data)); 267208747Sraj if (((d64 >> 32) & 0xffffffffull) != 0 || cells > 2) 268208747Sraj return (ERANGE); 269208747Sraj } 270208747Sraj 271208747Sraj return (0); 272208747Sraj} 273208747Sraj 274208747Srajint 275208747Srajfdt_pm_is_enabled(phandle_t node) 276208747Sraj{ 277208747Sraj int ret; 278208747Sraj 279208747Sraj ret = 1; 280208747Sraj 281208747Sraj#if defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY) 282208747Sraj ret = fdt_pm(node); 283208747Sraj#endif 284208747Sraj return (ret); 285208747Sraj} 286208747Sraj 287208747Sraju_long 288208747Srajfdt_data_get(void *data, int cells) 289208747Sraj{ 290208747Sraj 291208747Sraj if (cells == 1) 292208747Sraj return (fdt32_to_cpu(*((uint32_t *)data))); 293208747Sraj 294208747Sraj return (fdt64_to_cpu(*((uint64_t *)data))); 295208747Sraj} 296208747Sraj 297208747Srajint 298208747Srajfdt_addrsize_cells(phandle_t node, int *addr_cells, int *size_cells) 299208747Sraj{ 300208747Sraj pcell_t cell; 301208747Sraj int cell_size; 302208747Sraj 303208747Sraj /* 304208747Sraj * Retrieve #{address,size}-cells. 305208747Sraj */ 306208747Sraj cell_size = sizeof(cell); 307208747Sraj if (OF_getprop(node, "#address-cells", &cell, cell_size) < cell_size) 308208747Sraj cell = 2; 309208747Sraj *addr_cells = fdt32_to_cpu((int)cell); 310208747Sraj 311208747Sraj if (OF_getprop(node, "#size-cells", &cell, cell_size) < cell_size) 312208747Sraj cell = 1; 313208747Sraj *size_cells = fdt32_to_cpu((int)cell); 314208747Sraj 315208747Sraj if (*addr_cells > 3 || *size_cells > 2) 316208747Sraj return (ERANGE); 317208747Sraj return (0); 318208747Sraj} 319208747Sraj 320208747Srajint 321208747Srajfdt_ranges_verify(pcell_t *ranges, int tuples, int par_addr_cells, 322208747Sraj int this_addr_cells, int this_size_cells) 323208747Sraj{ 324208747Sraj int i, rv, ulsz; 325208747Sraj 326208747Sraj if (par_addr_cells > 2 || this_addr_cells > 2 || this_size_cells > 2) 327208747Sraj return (ERANGE); 328208747Sraj 329208747Sraj /* 330208747Sraj * This is the max size the resource manager can handle for addresses 331208747Sraj * and sizes. 332208747Sraj */ 333208747Sraj ulsz = sizeof(u_long); 334208747Sraj if (par_addr_cells <= ulsz && this_addr_cells <= ulsz && 335208747Sraj this_size_cells <= ulsz) 336208747Sraj /* We can handle everything */ 337208747Sraj return (0); 338208747Sraj 339208747Sraj rv = 0; 340208747Sraj for (i = 0; i < tuples; i++) { 341208747Sraj 342208747Sraj if (fdt_data_verify((void *)ranges, par_addr_cells)) 343208747Sraj goto err; 344208747Sraj ranges += par_addr_cells; 345208747Sraj 346208747Sraj if (fdt_data_verify((void *)ranges, this_addr_cells)) 347208747Sraj goto err; 348208747Sraj ranges += this_addr_cells; 349208747Sraj 350208747Sraj if (fdt_data_verify((void *)ranges, this_size_cells)) 351208747Sraj goto err; 352208747Sraj ranges += this_size_cells; 353208747Sraj } 354208747Sraj 355208747Sraj return (0); 356208747Sraj 357208747Srajerr: 358208747Sraj debugf("using address range >%d-bit not supported\n", ulsz * 8); 359208747Sraj return (ERANGE); 360208747Sraj} 361208747Sraj 362208747Srajint 363208747Srajfdt_data_to_res(pcell_t *data, int addr_cells, int size_cells, u_long *start, 364208747Sraj u_long *count) 365208747Sraj{ 366208747Sraj 367208747Sraj /* Address portion. */ 368208747Sraj if (fdt_data_verify((void *)data, addr_cells)) 369208747Sraj return (ERANGE); 370208747Sraj 371208747Sraj *start = fdt_data_get((void *)data, addr_cells); 372208747Sraj data += addr_cells; 373208747Sraj 374208747Sraj /* Size portion. */ 375208747Sraj if (fdt_data_verify((void *)data, size_cells)) 376208747Sraj return (ERANGE); 377208747Sraj 378208747Sraj *count = fdt_data_get((void *)data, size_cells); 379208747Sraj return (0); 380208747Sraj} 381208747Sraj 382208747Srajint 383208747Srajfdt_regsize(phandle_t node, u_long *base, u_long *size) 384208747Sraj{ 385208747Sraj pcell_t reg[4]; 386208747Sraj int addr_cells, len, size_cells; 387208747Sraj 388208747Sraj if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells)) 389208747Sraj return (ENXIO); 390208747Sraj 391208747Sraj if ((sizeof(pcell_t) * (addr_cells + size_cells)) > sizeof(reg)) 392208747Sraj return (ENOMEM); 393208747Sraj 394208747Sraj len = OF_getprop(node, "reg", ®, sizeof(reg)); 395208747Sraj if (len <= 0) 396208747Sraj return (EINVAL); 397208747Sraj 398208747Sraj *base = fdt_data_get(®[0], addr_cells); 399208747Sraj *size = fdt_data_get(®[addr_cells], size_cells); 400208747Sraj return (0); 401208747Sraj} 402208747Sraj 403208747Srajint 404208747Srajfdt_reg_to_rl(phandle_t node, struct resource_list *rl, u_long base) 405208747Sraj{ 406208747Sraj u_long start, end, count; 407208747Sraj pcell_t *reg, *regptr; 408208747Sraj pcell_t addr_cells, size_cells; 409208747Sraj int tuple_size, tuples; 410208747Sraj int i, rv; 411208747Sraj 412208747Sraj if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells) != 0) 413208747Sraj return (ENXIO); 414208747Sraj 415208747Sraj tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); 416208747Sraj tuples = OF_getprop_alloc(node, "reg", tuple_size, (void **)®); 417208747Sraj debugf("addr_cells = %d, size_cells = %d\n", addr_cells, size_cells); 418208747Sraj debugf("tuples = %d, tuple size = %d\n", tuples, tuple_size); 419208747Sraj if (tuples <= 0) 420208747Sraj /* No 'reg' property in this node. */ 421208747Sraj return (0); 422208747Sraj 423208747Sraj regptr = reg; 424208747Sraj for (i = 0; i < tuples; i++) { 425208747Sraj 426208747Sraj rv = fdt_data_to_res(reg, addr_cells, size_cells, &start, 427208747Sraj &count); 428208747Sraj if (rv != 0) { 429208747Sraj resource_list_free(rl); 430208747Sraj goto out; 431208747Sraj } 432208747Sraj reg += addr_cells + size_cells; 433208747Sraj 434208747Sraj /* Calculate address range relative to base. */ 435208747Sraj start &= 0x000ffffful; 436208747Sraj start = base + start; 437208747Sraj end = start + count - 1; 438208747Sraj 439208747Sraj debugf("reg addr start = %lx, end = %lx, count = %lx\n", start, 440208747Sraj end, count); 441208747Sraj 442208747Sraj resource_list_add(rl, SYS_RES_MEMORY, i, start, end, 443208747Sraj count); 444208747Sraj } 445208747Sraj rv = 0; 446208747Sraj 447208747Srajout: 448208747Sraj free(regptr, M_OFWPROP); 449208747Sraj return (rv); 450208747Sraj} 451208747Sraj 452208747Srajint 453208747Srajfdt_intr_decode(phandle_t intr_parent, pcell_t *intr, int *interrupt, 454208747Sraj int *trig, int *pol) 455208747Sraj{ 456208747Sraj fdt_pic_decode_t intr_decode; 457208747Sraj int i, rv; 458208747Sraj 459208747Sraj for (i = 0; fdt_pic_table[i] != NULL; i++) { 460208747Sraj 461208747Sraj /* XXX check if pic_handle has interrupt-controller prop? */ 462208747Sraj 463208747Sraj intr_decode = fdt_pic_table[i]; 464208747Sraj rv = intr_decode(intr_parent, intr, interrupt, trig, pol); 465208747Sraj 466208747Sraj if (rv == 0) 467208747Sraj /* This was recognized as our PIC and decoded. */ 468208747Sraj return (0); 469208747Sraj } 470208747Sraj 471208747Sraj return (ENXIO); 472208747Sraj} 473208747Sraj 474208747Srajint 475208747Srajfdt_intr_to_rl(phandle_t node, struct resource_list *rl, 476208747Sraj struct fdt_sense_level *intr_sl) 477208747Sraj{ 478208747Sraj phandle_t intr_par; 479208747Sraj ihandle_t iph; 480208747Sraj pcell_t *intr; 481208747Sraj pcell_t intr_cells; 482208747Sraj int interrupt, trig, pol; 483218073Smarcel int i, intr_num, irq, rv; 484208747Sraj 485208747Sraj if (OF_getproplen(node, "interrupts") <= 0) 486208747Sraj /* Node does not have 'interrupts' property. */ 487208747Sraj return (0); 488208747Sraj 489208747Sraj /* 490208747Sraj * Find #interrupt-cells of the interrupt domain. 491208747Sraj */ 492208747Sraj if (OF_getprop(node, "interrupt-parent", &iph, sizeof(iph)) <= 0) { 493208747Sraj debugf("no intr-parent phandle\n"); 494208747Sraj intr_par = OF_parent(node); 495208747Sraj } else { 496208747Sraj iph = fdt32_to_cpu(iph); 497208747Sraj intr_par = OF_instance_to_package(iph); 498208747Sraj } 499208747Sraj 500208747Sraj if (OF_getprop(intr_par, "#interrupt-cells", &intr_cells, 501208747Sraj sizeof(intr_cells)) <= 0) { 502208747Sraj debugf("no intr-cells defined, defaulting to 1\n"); 503208747Sraj intr_cells = 1; 504208747Sraj } 505208747Sraj intr_cells = fdt32_to_cpu(intr_cells); 506208747Sraj 507208747Sraj intr_num = OF_getprop_alloc(node, "interrupts", 508208747Sraj intr_cells * sizeof(pcell_t), (void **)&intr); 509208747Sraj if (intr_num <= 0 || intr_num > DI_MAX_INTR_NUM) 510208747Sraj return (ERANGE); 511208747Sraj 512208747Sraj rv = 0; 513208747Sraj for (i = 0; i < intr_num; i++) { 514208747Sraj 515208747Sraj interrupt = -1; 516208747Sraj trig = pol = 0; 517208747Sraj 518208747Sraj if (fdt_intr_decode(intr_par, &intr[i * intr_cells], 519208747Sraj &interrupt, &trig, &pol) != 0) { 520208747Sraj rv = ENXIO; 521208747Sraj goto out; 522208747Sraj } 523208747Sraj 524208747Sraj if (interrupt < 0) { 525208747Sraj rv = ERANGE; 526208747Sraj goto out; 527208747Sraj } 528208747Sraj 529208747Sraj debugf("decoded intr = %d, trig = %d, pol = %d\n", interrupt, 530208747Sraj trig, pol); 531208747Sraj 532209905Sraj intr_sl[i].trig = trig; 533209905Sraj intr_sl[i].pol = pol; 534208747Sraj 535218073Smarcel irq = FDT_MAP_IRQ(intr_par, interrupt); 536218073Smarcel resource_list_add(rl, SYS_RES_IRQ, i, irq, irq, 1); 537208747Sraj } 538208747Sraj 539208747Srajout: 540208747Sraj free(intr, M_OFWPROP); 541208747Sraj return (rv); 542208747Sraj} 543208747Sraj 544208747Srajint 545233015Srajfdt_get_phyaddr(phandle_t node, device_t dev, int *phy_addr, void **phy_sc) 546208747Sraj{ 547208747Sraj phandle_t phy_node; 548208747Sraj ihandle_t phy_ihandle; 549208747Sraj pcell_t phy_handle, phy_reg; 550233015Sraj uint32_t i; 551233015Sraj device_t parent, child; 552208747Sraj 553208747Sraj if (OF_getprop(node, "phy-handle", (void *)&phy_handle, 554208747Sraj sizeof(phy_handle)) <= 0) 555208747Sraj return (ENXIO); 556208747Sraj 557208747Sraj phy_ihandle = (ihandle_t)phy_handle; 558208747Sraj phy_ihandle = fdt32_to_cpu(phy_ihandle); 559208747Sraj phy_node = OF_instance_to_package(phy_ihandle); 560208747Sraj 561208747Sraj if (OF_getprop(phy_node, "reg", (void *)&phy_reg, 562208747Sraj sizeof(phy_reg)) <= 0) 563208747Sraj return (ENXIO); 564208747Sraj 565208747Sraj *phy_addr = fdt32_to_cpu(phy_reg); 566233015Sraj 567233015Sraj /* 568233015Sraj * Search for softc used to communicate with phy. 569233015Sraj */ 570233015Sraj 571233015Sraj /* 572233015Sraj * Step 1: Search for ancestor of the phy-node with a "phy-handle" 573233015Sraj * property set. 574233015Sraj */ 575233015Sraj phy_node = OF_parent(phy_node); 576233015Sraj while (phy_node != 0) { 577233015Sraj if (OF_getprop(phy_node, "phy-handle", (void *)&phy_handle, 578233015Sraj sizeof(phy_handle)) > 0) 579233015Sraj break; 580233015Sraj phy_node = OF_parent(phy_node); 581233015Sraj } 582233015Sraj if (phy_node == 0) 583233015Sraj return (ENXIO); 584233015Sraj 585233015Sraj /* 586233015Sraj * Step 2: For each device with the same parent and name as ours 587233015Sraj * compare its node with the one found in step 1, ancestor of phy 588233015Sraj * node (stored in phy_node). 589233015Sraj */ 590233015Sraj parent = device_get_parent(dev); 591233015Sraj i = 0; 592233015Sraj child = device_find_child(parent, device_get_name(dev), i); 593233015Sraj while (child != NULL) { 594233015Sraj if (ofw_bus_get_node(child) == phy_node) 595233015Sraj break; 596233015Sraj i++; 597233015Sraj child = device_find_child(parent, device_get_name(dev), i); 598233015Sraj } 599233015Sraj if (child == NULL) 600233015Sraj return (ENXIO); 601233015Sraj 602233015Sraj /* 603233015Sraj * Use softc of the device found. 604233015Sraj */ 605233015Sraj *phy_sc = (void *)device_get_softc(child); 606233015Sraj 607208747Sraj return (0); 608208747Sraj} 609208747Sraj 610208747Srajint 611208747Srajfdt_get_mem_regions(struct mem_region *mr, int *mrcnt, uint32_t *memsize) 612208747Sraj{ 613208747Sraj pcell_t reg[FDT_REG_CELLS * FDT_MEM_REGIONS]; 614208747Sraj pcell_t *regp; 615208747Sraj phandle_t memory; 616208747Sraj uint32_t memory_size; 617208747Sraj int addr_cells, size_cells; 618208747Sraj int i, max_size, reg_len, rv, tuple_size, tuples; 619208747Sraj 620208747Sraj max_size = sizeof(reg); 621208747Sraj memory = OF_finddevice("/memory"); 622208747Sraj if (memory <= 0) { 623208747Sraj rv = ENXIO; 624208747Sraj goto out; 625208747Sraj } 626208747Sraj 627208747Sraj if ((rv = fdt_addrsize_cells(OF_parent(memory), &addr_cells, 628208747Sraj &size_cells)) != 0) 629208747Sraj goto out; 630208747Sraj 631208747Sraj if (addr_cells > 2) { 632208747Sraj rv = ERANGE; 633208747Sraj goto out; 634208747Sraj } 635208747Sraj 636208747Sraj tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); 637208747Sraj reg_len = OF_getproplen(memory, "reg"); 638208747Sraj if (reg_len <= 0 || reg_len > sizeof(reg)) { 639208747Sraj rv = ERANGE; 640208747Sraj goto out; 641208747Sraj } 642208747Sraj 643208747Sraj if (OF_getprop(memory, "reg", reg, reg_len) <= 0) { 644208747Sraj rv = ENXIO; 645208747Sraj goto out; 646208747Sraj } 647208747Sraj 648208747Sraj memory_size = 0; 649208747Sraj tuples = reg_len / tuple_size; 650208747Sraj regp = (pcell_t *)® 651208747Sraj for (i = 0; i < tuples; i++) { 652208747Sraj 653208747Sraj rv = fdt_data_to_res(regp, addr_cells, size_cells, 654208747Sraj (u_long *)&mr[i].mr_start, (u_long *)&mr[i].mr_size); 655208747Sraj 656208747Sraj if (rv != 0) 657208747Sraj goto out; 658208747Sraj 659208747Sraj regp += addr_cells + size_cells; 660208747Sraj memory_size += mr[i].mr_size; 661208747Sraj } 662208747Sraj 663208747Sraj if (memory_size == 0) { 664208747Sraj rv = ERANGE; 665208747Sraj goto out; 666208747Sraj } 667208747Sraj 668208747Sraj *mrcnt = i; 669208747Sraj *memsize = memory_size; 670208747Sraj rv = 0; 671208747Srajout: 672208747Sraj return (rv); 673208747Sraj} 674