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> 38239274Sgonzo#include <sys/limits.h> 39208747Sraj 40208747Sraj#include <machine/fdt.h> 41208747Sraj#include <machine/resource.h> 42208747Sraj 43208747Sraj#include <dev/fdt/fdt_common.h> 44208747Sraj#include <dev/ofw/ofw_bus.h> 45208747Sraj#include <dev/ofw/ofw_bus_subr.h> 46208747Sraj#include <dev/ofw/openfirm.h> 47208747Sraj 48208747Sraj#include "ofw_bus_if.h" 49208747Sraj 50208747Sraj#ifdef DEBUG 51208747Sraj#define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 52208747Sraj printf(fmt,##args); } while (0) 53208747Sraj#else 54208747Sraj#define debugf(fmt, args...) 55208747Sraj#endif 56208747Sraj 57208747Sraj#define FDT_COMPAT_LEN 255 58208747Sraj#define FDT_TYPE_LEN 64 59208747Sraj 60208747Sraj#define FDT_REG_CELLS 4 61208747Sraj 62208747Srajvm_paddr_t fdt_immr_pa; 63208747Srajvm_offset_t fdt_immr_va; 64208747Srajvm_offset_t fdt_immr_size; 65208747Sraj 66257457Sbrooksstruct fdt_ic_list fdt_ic_list_head = SLIST_HEAD_INITIALIZER(fdt_ic_list_head); 67257457Sbrooks 68208747Srajint 69239274Sgonzofdt_get_range(phandle_t node, int range_id, u_long *base, u_long *size) 70208747Sraj{ 71208747Sraj pcell_t ranges[6], *rangesptr; 72208747Sraj pcell_t addr_cells, size_cells, par_addr_cells; 73208747Sraj int len, tuple_size, tuples; 74208747Sraj 75208747Sraj if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0) 76208747Sraj return (ENXIO); 77208747Sraj /* 78208747Sraj * Process 'ranges' property. 79208747Sraj */ 80208747Sraj par_addr_cells = fdt_parent_addr_cells(node); 81208747Sraj if (par_addr_cells > 2) 82208747Sraj return (ERANGE); 83208747Sraj 84208747Sraj len = OF_getproplen(node, "ranges"); 85208747Sraj if (len > sizeof(ranges)) 86208747Sraj return (ENOMEM); 87239274Sgonzo if (len == 0) { 88239274Sgonzo *base = 0; 89239274Sgonzo *size = ULONG_MAX; 90239274Sgonzo return (0); 91239274Sgonzo } 92208747Sraj 93239274Sgonzo if (!(range_id < len)) 94239274Sgonzo return (ERANGE); 95239274Sgonzo 96208747Sraj if (OF_getprop(node, "ranges", ranges, sizeof(ranges)) <= 0) 97208747Sraj return (EINVAL); 98208747Sraj 99208747Sraj tuple_size = sizeof(pcell_t) * (addr_cells + par_addr_cells + 100208747Sraj size_cells); 101208747Sraj tuples = len / tuple_size; 102208747Sraj 103208747Sraj if (fdt_ranges_verify(ranges, tuples, par_addr_cells, 104208747Sraj addr_cells, size_cells)) { 105208747Sraj return (ERANGE); 106208747Sraj } 107239274Sgonzo *base = 0; 108239274Sgonzo *size = 0; 109239274Sgonzo rangesptr = &ranges[range_id]; 110208747Sraj 111239274Sgonzo *base = fdt_data_get((void *)rangesptr, addr_cells); 112208747Sraj rangesptr += addr_cells; 113239274Sgonzo *base += fdt_data_get((void *)rangesptr, par_addr_cells); 114208747Sraj rangesptr += par_addr_cells; 115239274Sgonzo *size = fdt_data_get((void *)rangesptr, size_cells); 116239274Sgonzo return (0); 117239274Sgonzo} 118208747Sraj 119239274Sgonzoint 120239274Sgonzofdt_immr_addr(vm_offset_t immr_va) 121239274Sgonzo{ 122239274Sgonzo phandle_t node; 123239274Sgonzo u_long base, size; 124239274Sgonzo int r; 125208747Sraj 126239274Sgonzo /* 127239274Sgonzo * Try to access the SOC node directly i.e. through /aliases/. 128239274Sgonzo */ 129239274Sgonzo if ((node = OF_finddevice("soc")) != 0) 130239274Sgonzo if (fdt_is_compatible_strict(node, "simple-bus")) 131239274Sgonzo goto moveon; 132239274Sgonzo /* 133239274Sgonzo * Find the node the long way. 134239274Sgonzo */ 135239274Sgonzo if ((node = OF_finddevice("/")) == 0) 136239274Sgonzo return (ENXIO); 137239274Sgonzo 138239274Sgonzo if ((node = fdt_find_compatible(node, "simple-bus", 1)) == 0) 139239274Sgonzo return (ENXIO); 140239274Sgonzo 141239274Sgonzomoveon: 142239274Sgonzo if ((r = fdt_get_range(node, 0, &base, &size)) == 0) { 143239274Sgonzo fdt_immr_pa = base; 144239274Sgonzo fdt_immr_va = immr_va; 145239274Sgonzo fdt_immr_size = size; 146239274Sgonzo } 147239274Sgonzo 148239274Sgonzo return (r); 149208747Sraj} 150208747Sraj 151208747Sraj/* 152208747Sraj * This routine is an early-usage version of the ofw_bus_is_compatible() when 153208747Sraj * the ofw_bus I/F is not available (like early console routines and similar). 154208747Sraj * Note the buffer has to be on the stack since malloc() is usually not 155208747Sraj * available in such cases either. 156208747Sraj */ 157208747Srajint 158208747Srajfdt_is_compatible(phandle_t node, const char *compatstr) 159208747Sraj{ 160208747Sraj char buf[FDT_COMPAT_LEN]; 161208747Sraj char *compat; 162208747Sraj int len, onelen, l, rv; 163208747Sraj 164208747Sraj if ((len = OF_getproplen(node, "compatible")) <= 0) 165208747Sraj return (0); 166208747Sraj 167208747Sraj compat = (char *)&buf; 168208747Sraj bzero(compat, FDT_COMPAT_LEN); 169208747Sraj 170208747Sraj if (OF_getprop(node, "compatible", compat, FDT_COMPAT_LEN) < 0) 171208747Sraj return (0); 172208747Sraj 173208747Sraj onelen = strlen(compatstr); 174208747Sraj rv = 0; 175208747Sraj while (len > 0) { 176208747Sraj if (strncasecmp(compat, compatstr, onelen) == 0) { 177208747Sraj /* Found it. */ 178208747Sraj rv = 1; 179208747Sraj break; 180208747Sraj } 181208747Sraj /* Slide to the next sub-string. */ 182208747Sraj l = strlen(compat) + 1; 183208747Sraj compat += l; 184208747Sraj len -= l; 185208747Sraj } 186208747Sraj 187208747Sraj return (rv); 188208747Sraj} 189208747Sraj 190208747Srajint 191208747Srajfdt_is_compatible_strict(phandle_t node, const char *compatible) 192208747Sraj{ 193208747Sraj char compat[FDT_COMPAT_LEN]; 194208747Sraj 195208747Sraj if (OF_getproplen(node, "compatible") <= 0) 196208747Sraj return (0); 197208747Sraj 198208747Sraj if (OF_getprop(node, "compatible", compat, FDT_COMPAT_LEN) < 0) 199208747Sraj return (0); 200208747Sraj 201208747Sraj if (strncasecmp(compat, compatible, FDT_COMPAT_LEN) == 0) 202208747Sraj /* This fits. */ 203208747Sraj return (1); 204208747Sraj 205208747Sraj return (0); 206208747Sraj} 207208747Sraj 208208747Srajphandle_t 209208747Srajfdt_find_compatible(phandle_t start, const char *compat, int strict) 210208747Sraj{ 211208747Sraj phandle_t child; 212208747Sraj 213208747Sraj /* 214208747Sraj * Traverse all children of 'start' node, and find first with 215208747Sraj * matching 'compatible' property. 216208747Sraj */ 217208747Sraj for (child = OF_child(start); child != 0; child = OF_peer(child)) 218208747Sraj if (fdt_is_compatible(child, compat)) { 219208747Sraj if (strict) 220208747Sraj if (!fdt_is_compatible_strict(child, compat)) 221208747Sraj continue; 222208747Sraj return (child); 223208747Sraj } 224208747Sraj return (0); 225208747Sraj} 226208747Sraj 227208747Srajint 228208747Srajfdt_is_enabled(phandle_t node) 229208747Sraj{ 230208747Sraj char *stat; 231208747Sraj int ena, len; 232208747Sraj 233208747Sraj len = OF_getprop_alloc(node, "status", sizeof(char), 234208747Sraj (void **)&stat); 235208747Sraj 236208747Sraj if (len <= 0) 237208747Sraj /* It is OK if no 'status' property. */ 238208747Sraj return (1); 239208747Sraj 240208747Sraj /* Anything other than 'okay' means disabled. */ 241208747Sraj ena = 0; 242208747Sraj if (strncmp((char *)stat, "okay", len) == 0) 243208747Sraj ena = 1; 244208747Sraj 245208747Sraj free(stat, M_OFWPROP); 246208747Sraj return (ena); 247208747Sraj} 248208747Sraj 249208747Srajint 250208747Srajfdt_is_type(phandle_t node, const char *typestr) 251208747Sraj{ 252208747Sraj char type[FDT_TYPE_LEN]; 253208747Sraj 254208747Sraj if (OF_getproplen(node, "device_type") <= 0) 255208747Sraj return (0); 256208747Sraj 257208747Sraj if (OF_getprop(node, "device_type", type, FDT_TYPE_LEN) < 0) 258208747Sraj return (0); 259208747Sraj 260208747Sraj if (strncasecmp(type, typestr, FDT_TYPE_LEN) == 0) 261208747Sraj /* This fits. */ 262208747Sraj return (1); 263208747Sraj 264208747Sraj return (0); 265208747Sraj} 266208747Sraj 267208747Srajint 268208747Srajfdt_parent_addr_cells(phandle_t node) 269208747Sraj{ 270208747Sraj pcell_t addr_cells; 271208747Sraj 272208747Sraj /* Find out #address-cells of the superior bus. */ 273208747Sraj if (OF_searchprop(OF_parent(node), "#address-cells", &addr_cells, 274208747Sraj sizeof(addr_cells)) <= 0) 275208747Sraj addr_cells = 2; 276208747Sraj 277208747Sraj return ((int)fdt32_to_cpu(addr_cells)); 278208747Sraj} 279208747Sraj 280208747Srajint 281208747Srajfdt_data_verify(void *data, int cells) 282208747Sraj{ 283208747Sraj uint64_t d64; 284208747Sraj 285208747Sraj if (cells > 1) { 286208747Sraj d64 = fdt64_to_cpu(*((uint64_t *)data)); 287208747Sraj if (((d64 >> 32) & 0xffffffffull) != 0 || cells > 2) 288208747Sraj return (ERANGE); 289208747Sraj } 290208747Sraj 291208747Sraj return (0); 292208747Sraj} 293208747Sraj 294208747Srajint 295208747Srajfdt_pm_is_enabled(phandle_t node) 296208747Sraj{ 297208747Sraj int ret; 298208747Sraj 299208747Sraj ret = 1; 300208747Sraj 301208747Sraj#if defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY) 302208747Sraj ret = fdt_pm(node); 303208747Sraj#endif 304208747Sraj return (ret); 305208747Sraj} 306208747Sraj 307208747Sraju_long 308208747Srajfdt_data_get(void *data, int cells) 309208747Sraj{ 310208747Sraj 311208747Sraj if (cells == 1) 312208747Sraj return (fdt32_to_cpu(*((uint32_t *)data))); 313208747Sraj 314208747Sraj return (fdt64_to_cpu(*((uint64_t *)data))); 315208747Sraj} 316208747Sraj 317208747Srajint 318208747Srajfdt_addrsize_cells(phandle_t node, int *addr_cells, int *size_cells) 319208747Sraj{ 320208747Sraj pcell_t cell; 321208747Sraj int cell_size; 322208747Sraj 323208747Sraj /* 324208747Sraj * Retrieve #{address,size}-cells. 325208747Sraj */ 326208747Sraj cell_size = sizeof(cell); 327208747Sraj if (OF_getprop(node, "#address-cells", &cell, cell_size) < cell_size) 328208747Sraj cell = 2; 329208747Sraj *addr_cells = fdt32_to_cpu((int)cell); 330208747Sraj 331208747Sraj if (OF_getprop(node, "#size-cells", &cell, cell_size) < cell_size) 332208747Sraj cell = 1; 333208747Sraj *size_cells = fdt32_to_cpu((int)cell); 334208747Sraj 335208747Sraj if (*addr_cells > 3 || *size_cells > 2) 336208747Sraj return (ERANGE); 337208747Sraj return (0); 338208747Sraj} 339208747Sraj 340208747Srajint 341208747Srajfdt_ranges_verify(pcell_t *ranges, int tuples, int par_addr_cells, 342208747Sraj int this_addr_cells, int this_size_cells) 343208747Sraj{ 344208747Sraj int i, rv, ulsz; 345208747Sraj 346208747Sraj if (par_addr_cells > 2 || this_addr_cells > 2 || this_size_cells > 2) 347208747Sraj return (ERANGE); 348208747Sraj 349208747Sraj /* 350208747Sraj * This is the max size the resource manager can handle for addresses 351208747Sraj * and sizes. 352208747Sraj */ 353208747Sraj ulsz = sizeof(u_long); 354208747Sraj if (par_addr_cells <= ulsz && this_addr_cells <= ulsz && 355208747Sraj this_size_cells <= ulsz) 356208747Sraj /* We can handle everything */ 357208747Sraj return (0); 358208747Sraj 359208747Sraj rv = 0; 360208747Sraj for (i = 0; i < tuples; i++) { 361208747Sraj 362208747Sraj if (fdt_data_verify((void *)ranges, par_addr_cells)) 363208747Sraj goto err; 364208747Sraj ranges += par_addr_cells; 365208747Sraj 366208747Sraj if (fdt_data_verify((void *)ranges, this_addr_cells)) 367208747Sraj goto err; 368208747Sraj ranges += this_addr_cells; 369208747Sraj 370208747Sraj if (fdt_data_verify((void *)ranges, this_size_cells)) 371208747Sraj goto err; 372208747Sraj ranges += this_size_cells; 373208747Sraj } 374208747Sraj 375208747Sraj return (0); 376208747Sraj 377208747Srajerr: 378208747Sraj debugf("using address range >%d-bit not supported\n", ulsz * 8); 379208747Sraj return (ERANGE); 380208747Sraj} 381208747Sraj 382208747Srajint 383208747Srajfdt_data_to_res(pcell_t *data, int addr_cells, int size_cells, u_long *start, 384208747Sraj u_long *count) 385208747Sraj{ 386208747Sraj 387208747Sraj /* Address portion. */ 388208747Sraj if (fdt_data_verify((void *)data, addr_cells)) 389208747Sraj return (ERANGE); 390208747Sraj 391208747Sraj *start = fdt_data_get((void *)data, addr_cells); 392208747Sraj data += addr_cells; 393208747Sraj 394208747Sraj /* Size portion. */ 395208747Sraj if (fdt_data_verify((void *)data, size_cells)) 396208747Sraj return (ERANGE); 397208747Sraj 398208747Sraj *count = fdt_data_get((void *)data, size_cells); 399208747Sraj return (0); 400208747Sraj} 401208747Sraj 402208747Srajint 403208747Srajfdt_regsize(phandle_t node, u_long *base, u_long *size) 404208747Sraj{ 405208747Sraj pcell_t reg[4]; 406208747Sraj int addr_cells, len, size_cells; 407208747Sraj 408208747Sraj if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells)) 409208747Sraj return (ENXIO); 410208747Sraj 411208747Sraj if ((sizeof(pcell_t) * (addr_cells + size_cells)) > sizeof(reg)) 412208747Sraj return (ENOMEM); 413208747Sraj 414208747Sraj len = OF_getprop(node, "reg", ®, sizeof(reg)); 415208747Sraj if (len <= 0) 416208747Sraj return (EINVAL); 417208747Sraj 418208747Sraj *base = fdt_data_get(®[0], addr_cells); 419208747Sraj *size = fdt_data_get(®[addr_cells], size_cells); 420208747Sraj return (0); 421208747Sraj} 422208747Sraj 423208747Srajint 424239274Sgonzofdt_reg_to_rl(phandle_t node, struct resource_list *rl) 425208747Sraj{ 426248509Sray u_long end, count, start; 427208747Sraj pcell_t *reg, *regptr; 428208747Sraj pcell_t addr_cells, size_cells; 429208747Sraj int tuple_size, tuples; 430208747Sraj int i, rv; 431239274Sgonzo long busaddr, bussize; 432208747Sraj 433208747Sraj if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells) != 0) 434208747Sraj return (ENXIO); 435240484Sgber if (fdt_get_range(OF_parent(node), 0, &busaddr, &bussize)) { 436240484Sgber busaddr = 0; 437240484Sgber bussize = 0; 438240484Sgber } 439208747Sraj 440208747Sraj tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); 441208747Sraj tuples = OF_getprop_alloc(node, "reg", tuple_size, (void **)®); 442208747Sraj debugf("addr_cells = %d, size_cells = %d\n", addr_cells, size_cells); 443208747Sraj debugf("tuples = %d, tuple size = %d\n", tuples, tuple_size); 444208747Sraj if (tuples <= 0) 445208747Sraj /* No 'reg' property in this node. */ 446208747Sraj return (0); 447208747Sraj 448208747Sraj regptr = reg; 449208747Sraj for (i = 0; i < tuples; i++) { 450208747Sraj 451248509Sray rv = fdt_data_to_res(reg, addr_cells, size_cells, &start, 452248509Sray &count); 453208747Sraj if (rv != 0) { 454208747Sraj resource_list_free(rl); 455208747Sraj goto out; 456208747Sraj } 457208747Sraj reg += addr_cells + size_cells; 458208747Sraj 459208747Sraj /* Calculate address range relative to base. */ 460239274Sgonzo start += busaddr; 461248467Sray end = start + count - 1; 462208747Sraj 463248467Sray debugf("reg addr start = %lx, end = %lx, count = %lx\n", start, 464208747Sraj end, count); 465208747Sraj 466248467Sray resource_list_add(rl, SYS_RES_MEMORY, i, start, end, 467208747Sraj count); 468208747Sraj } 469208747Sraj rv = 0; 470208747Sraj 471208747Srajout: 472208747Sraj free(regptr, M_OFWPROP); 473208747Sraj return (rv); 474208747Sraj} 475208747Sraj 476208747Srajint 477208747Srajfdt_intr_decode(phandle_t intr_parent, pcell_t *intr, int *interrupt, 478208747Sraj int *trig, int *pol) 479208747Sraj{ 480208747Sraj fdt_pic_decode_t intr_decode; 481208747Sraj int i, rv; 482208747Sraj 483208747Sraj for (i = 0; fdt_pic_table[i] != NULL; i++) { 484208747Sraj 485208747Sraj /* XXX check if pic_handle has interrupt-controller prop? */ 486208747Sraj 487208747Sraj intr_decode = fdt_pic_table[i]; 488208747Sraj rv = intr_decode(intr_parent, intr, interrupt, trig, pol); 489208747Sraj 490208747Sraj if (rv == 0) 491208747Sraj /* This was recognized as our PIC and decoded. */ 492208747Sraj return (0); 493208747Sraj } 494208747Sraj 495208747Sraj return (ENXIO); 496208747Sraj} 497208747Sraj 498208747Srajint 499208747Srajfdt_intr_to_rl(phandle_t node, struct resource_list *rl, 500208747Sraj struct fdt_sense_level *intr_sl) 501208747Sraj{ 502208747Sraj phandle_t intr_par; 503208747Sraj ihandle_t iph; 504208747Sraj pcell_t *intr; 505208747Sraj pcell_t intr_cells; 506208747Sraj int interrupt, trig, pol; 507218073Smarcel int i, intr_num, irq, rv; 508208747Sraj 509208747Sraj if (OF_getproplen(node, "interrupts") <= 0) 510208747Sraj /* Node does not have 'interrupts' property. */ 511208747Sraj return (0); 512208747Sraj 513208747Sraj /* 514208747Sraj * Find #interrupt-cells of the interrupt domain. 515208747Sraj */ 516208747Sraj if (OF_getprop(node, "interrupt-parent", &iph, sizeof(iph)) <= 0) { 517208747Sraj debugf("no intr-parent phandle\n"); 518208747Sraj intr_par = OF_parent(node); 519208747Sraj } else { 520208747Sraj iph = fdt32_to_cpu(iph); 521208747Sraj intr_par = OF_instance_to_package(iph); 522208747Sraj } 523208747Sraj 524208747Sraj if (OF_getprop(intr_par, "#interrupt-cells", &intr_cells, 525208747Sraj sizeof(intr_cells)) <= 0) { 526208747Sraj debugf("no intr-cells defined, defaulting to 1\n"); 527208747Sraj intr_cells = 1; 528208747Sraj } 529239689Sgonzo else 530239689Sgonzo intr_cells = fdt32_to_cpu(intr_cells); 531208747Sraj 532208747Sraj intr_num = OF_getprop_alloc(node, "interrupts", 533208747Sraj intr_cells * sizeof(pcell_t), (void **)&intr); 534208747Sraj if (intr_num <= 0 || intr_num > DI_MAX_INTR_NUM) 535208747Sraj return (ERANGE); 536208747Sraj 537208747Sraj rv = 0; 538208747Sraj for (i = 0; i < intr_num; i++) { 539208747Sraj 540208747Sraj interrupt = -1; 541208747Sraj trig = pol = 0; 542208747Sraj 543208747Sraj if (fdt_intr_decode(intr_par, &intr[i * intr_cells], 544208747Sraj &interrupt, &trig, &pol) != 0) { 545208747Sraj rv = ENXIO; 546208747Sraj goto out; 547208747Sraj } 548208747Sraj 549208747Sraj if (interrupt < 0) { 550208747Sraj rv = ERANGE; 551208747Sraj goto out; 552208747Sraj } 553208747Sraj 554208747Sraj debugf("decoded intr = %d, trig = %d, pol = %d\n", interrupt, 555208747Sraj trig, pol); 556208747Sraj 557209905Sraj intr_sl[i].trig = trig; 558209905Sraj intr_sl[i].pol = pol; 559208747Sraj 560218073Smarcel irq = FDT_MAP_IRQ(intr_par, interrupt); 561218073Smarcel resource_list_add(rl, SYS_RES_IRQ, i, irq, irq, 1); 562208747Sraj } 563208747Sraj 564208747Srajout: 565208747Sraj free(intr, M_OFWPROP); 566208747Sraj return (rv); 567208747Sraj} 568208747Sraj 569208747Srajint 570232518Srajfdt_get_phyaddr(phandle_t node, device_t dev, int *phy_addr, void **phy_sc) 571208747Sraj{ 572208747Sraj phandle_t phy_node; 573208747Sraj ihandle_t phy_ihandle; 574208747Sraj pcell_t phy_handle, phy_reg; 575232518Sraj uint32_t i; 576232518Sraj device_t parent, child; 577208747Sraj 578208747Sraj if (OF_getprop(node, "phy-handle", (void *)&phy_handle, 579208747Sraj sizeof(phy_handle)) <= 0) 580208747Sraj return (ENXIO); 581208747Sraj 582208747Sraj phy_ihandle = (ihandle_t)phy_handle; 583208747Sraj phy_ihandle = fdt32_to_cpu(phy_ihandle); 584208747Sraj phy_node = OF_instance_to_package(phy_ihandle); 585208747Sraj 586208747Sraj if (OF_getprop(phy_node, "reg", (void *)&phy_reg, 587208747Sraj sizeof(phy_reg)) <= 0) 588208747Sraj return (ENXIO); 589208747Sraj 590208747Sraj *phy_addr = fdt32_to_cpu(phy_reg); 591232518Sraj 592232518Sraj /* 593232518Sraj * Search for softc used to communicate with phy. 594232518Sraj */ 595232518Sraj 596232518Sraj /* 597232518Sraj * Step 1: Search for ancestor of the phy-node with a "phy-handle" 598232518Sraj * property set. 599232518Sraj */ 600232518Sraj phy_node = OF_parent(phy_node); 601232518Sraj while (phy_node != 0) { 602232518Sraj if (OF_getprop(phy_node, "phy-handle", (void *)&phy_handle, 603232518Sraj sizeof(phy_handle)) > 0) 604232518Sraj break; 605232518Sraj phy_node = OF_parent(phy_node); 606232518Sraj } 607232518Sraj if (phy_node == 0) 608232518Sraj return (ENXIO); 609232518Sraj 610232518Sraj /* 611232518Sraj * Step 2: For each device with the same parent and name as ours 612232518Sraj * compare its node with the one found in step 1, ancestor of phy 613232518Sraj * node (stored in phy_node). 614232518Sraj */ 615232518Sraj parent = device_get_parent(dev); 616232518Sraj i = 0; 617232518Sraj child = device_find_child(parent, device_get_name(dev), i); 618232518Sraj while (child != NULL) { 619232518Sraj if (ofw_bus_get_node(child) == phy_node) 620232518Sraj break; 621232518Sraj i++; 622232518Sraj child = device_find_child(parent, device_get_name(dev), i); 623232518Sraj } 624232518Sraj if (child == NULL) 625232518Sraj return (ENXIO); 626232518Sraj 627232518Sraj /* 628232518Sraj * Use softc of the device found. 629232518Sraj */ 630232518Sraj *phy_sc = (void *)device_get_softc(child); 631232518Sraj 632208747Sraj return (0); 633208747Sraj} 634208747Sraj 635208747Srajint 636243690Sgonzofdt_get_reserved_regions(struct mem_region *mr, int *mrcnt) 637243690Sgonzo{ 638243690Sgonzo pcell_t reserve[FDT_REG_CELLS * FDT_MEM_REGIONS]; 639243690Sgonzo pcell_t *reservep; 640243690Sgonzo phandle_t memory, root; 641243690Sgonzo uint32_t memory_size; 642243690Sgonzo int addr_cells, size_cells; 643243690Sgonzo int i, max_size, res_len, rv, tuple_size, tuples; 644243690Sgonzo 645243690Sgonzo max_size = sizeof(reserve); 646243690Sgonzo root = OF_finddevice("/"); 647243690Sgonzo memory = OF_finddevice("/memory"); 648243690Sgonzo if (memory == -1) { 649243690Sgonzo rv = ENXIO; 650243690Sgonzo goto out; 651243690Sgonzo } 652243690Sgonzo 653243690Sgonzo if ((rv = fdt_addrsize_cells(OF_parent(memory), &addr_cells, 654243690Sgonzo &size_cells)) != 0) 655243690Sgonzo goto out; 656243690Sgonzo 657243690Sgonzo if (addr_cells > 2) { 658243690Sgonzo rv = ERANGE; 659243690Sgonzo goto out; 660243690Sgonzo } 661243690Sgonzo 662243690Sgonzo tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); 663243690Sgonzo 664243690Sgonzo res_len = OF_getproplen(root, "memreserve"); 665243690Sgonzo if (res_len <= 0 || res_len > sizeof(reserve)) { 666243690Sgonzo rv = ERANGE; 667243690Sgonzo goto out; 668243690Sgonzo } 669243690Sgonzo 670243690Sgonzo if (OF_getprop(root, "memreserve", reserve, res_len) <= 0) { 671243690Sgonzo rv = ENXIO; 672243690Sgonzo goto out; 673243690Sgonzo } 674243690Sgonzo 675243690Sgonzo memory_size = 0; 676243690Sgonzo tuples = res_len / tuple_size; 677243690Sgonzo reservep = (pcell_t *)&reserve; 678243690Sgonzo for (i = 0; i < tuples; i++) { 679243690Sgonzo 680243690Sgonzo rv = fdt_data_to_res(reservep, addr_cells, size_cells, 681243690Sgonzo (u_long *)&mr[i].mr_start, (u_long *)&mr[i].mr_size); 682243690Sgonzo 683243690Sgonzo if (rv != 0) 684243690Sgonzo goto out; 685243690Sgonzo 686243690Sgonzo reservep += addr_cells + size_cells; 687243690Sgonzo } 688243690Sgonzo 689243690Sgonzo *mrcnt = i; 690243690Sgonzo rv = 0; 691243690Sgonzoout: 692243690Sgonzo return (rv); 693243690Sgonzo} 694243690Sgonzo 695243690Sgonzoint 696208747Srajfdt_get_mem_regions(struct mem_region *mr, int *mrcnt, uint32_t *memsize) 697208747Sraj{ 698208747Sraj pcell_t reg[FDT_REG_CELLS * FDT_MEM_REGIONS]; 699208747Sraj pcell_t *regp; 700208747Sraj phandle_t memory; 701208747Sraj uint32_t memory_size; 702208747Sraj int addr_cells, size_cells; 703208747Sraj int i, max_size, reg_len, rv, tuple_size, tuples; 704208747Sraj 705208747Sraj max_size = sizeof(reg); 706208747Sraj memory = OF_finddevice("/memory"); 707228201Sjchandra if (memory == -1) { 708208747Sraj rv = ENXIO; 709208747Sraj goto out; 710208747Sraj } 711208747Sraj 712208747Sraj if ((rv = fdt_addrsize_cells(OF_parent(memory), &addr_cells, 713208747Sraj &size_cells)) != 0) 714208747Sraj goto out; 715208747Sraj 716208747Sraj if (addr_cells > 2) { 717208747Sraj rv = ERANGE; 718208747Sraj goto out; 719208747Sraj } 720208747Sraj 721208747Sraj tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); 722208747Sraj reg_len = OF_getproplen(memory, "reg"); 723208747Sraj if (reg_len <= 0 || reg_len > sizeof(reg)) { 724208747Sraj rv = ERANGE; 725208747Sraj goto out; 726208747Sraj } 727208747Sraj 728208747Sraj if (OF_getprop(memory, "reg", reg, reg_len) <= 0) { 729208747Sraj rv = ENXIO; 730208747Sraj goto out; 731208747Sraj } 732208747Sraj 733208747Sraj memory_size = 0; 734208747Sraj tuples = reg_len / tuple_size; 735208747Sraj regp = (pcell_t *)® 736208747Sraj for (i = 0; i < tuples; i++) { 737208747Sraj 738208747Sraj rv = fdt_data_to_res(regp, addr_cells, size_cells, 739208747Sraj (u_long *)&mr[i].mr_start, (u_long *)&mr[i].mr_size); 740208747Sraj 741208747Sraj if (rv != 0) 742208747Sraj goto out; 743208747Sraj 744208747Sraj regp += addr_cells + size_cells; 745208747Sraj memory_size += mr[i].mr_size; 746208747Sraj } 747208747Sraj 748208747Sraj if (memory_size == 0) { 749208747Sraj rv = ERANGE; 750208747Sraj goto out; 751208747Sraj } 752208747Sraj 753208747Sraj *mrcnt = i; 754208747Sraj *memsize = memory_size; 755208747Sraj rv = 0; 756208747Srajout: 757208747Sraj return (rv); 758208747Sraj} 759240485Sgber 760240485Sgberint 761240485Sgberfdt_get_unit(device_t dev) 762240485Sgber{ 763240485Sgber const char * name; 764240485Sgber 765240485Sgber name = ofw_bus_get_name(dev); 766240485Sgber name = strchr(name, '@') + 1; 767240485Sgber 768240485Sgber return (strtol(name,NULL,0)); 769240485Sgber} 770