Home | History | Annotate | Line # | Download | only in fdt
fdt_subr.c revision 1.2
      1 /* $NetBSD: fdt_subr.c,v 1.2 2015/12/16 12:03:44 jmcneill Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2015 Jared D. McNeill <jmcneill (at) invisible.ca>
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: fdt_subr.c,v 1.2 2015/12/16 12:03:44 jmcneill Exp $");
     31 
     32 #include <sys/param.h>
     33 #include <sys/bus.h>
     34 #include <sys/kmem.h>
     35 
     36 #include <libfdt.h>
     37 #include <dev/ofw/openfirm.h>
     38 #include <dev/fdt/fdt_openfirm.h>
     39 #include <dev/fdt/fdtvar.h>
     40 
     41 static int
     42 fdtbus_get_addr_cells(int phandle)
     43 {
     44 	int val, addr_cells, error;
     45 
     46 	const int parent = OF_parent(phandle);
     47 	if (parent == -1)
     48 		return -1;
     49 
     50 	error = OF_getprop(parent, "#address-cells", &val, sizeof(val));
     51 	if (error <= 0) {
     52 		addr_cells = 2;
     53 	} else {
     54 		addr_cells = fdt32_to_cpu(val);
     55 	}
     56 
     57 	return addr_cells;
     58 }
     59 
     60 static int
     61 fdtbus_get_size_cells(int phandle)
     62 {
     63 	int val, size_cells, error;
     64 
     65 	const int parent = OF_parent(phandle);
     66 	if (parent == -1)
     67 		return -1;
     68 
     69 	error = OF_getprop(parent, "#size-cells", &val, sizeof(val));
     70 	if (error <= 0) {
     71 		size_cells = 0;
     72 	} else {
     73 		size_cells = fdt32_to_cpu(val);
     74 	}
     75 
     76 	return size_cells;
     77 }
     78 
     79 int
     80 fdtbus_get_phandle(int phandle, const char *prop)
     81 {
     82 	u_int phandle_ref;
     83 	u_int *buf;
     84 	int len;
     85 
     86 	len = OF_getproplen(phandle, prop);
     87 	if (len < sizeof(phandle_ref))
     88 		return -1;
     89 
     90 	buf = kmem_alloc(len, KM_SLEEP);
     91 
     92 	if (OF_getprop(phandle, prop, buf, len) != len) {
     93 		kmem_free(buf, len);
     94 		return -1;
     95 	}
     96 
     97 	phandle_ref = fdt32_to_cpu(buf[0]);
     98 	kmem_free(buf, len);
     99 
    100 	const void *data = fdt_openfirm_get_data();
    101 	const int off = fdt_node_offset_by_phandle(data, phandle_ref);
    102 	if (off < 0) {
    103 		return -1;
    104 	}
    105 
    106 	return fdt_openfirm_get_phandle(off);
    107 }
    108 
    109 int
    110 fdtbus_get_reg(int phandle, u_int index, bus_addr_t *paddr, bus_size_t *psize)
    111 {
    112 	bus_addr_t addr;
    113 	bus_size_t size;
    114 	uint8_t *buf;
    115 	int len;
    116 
    117 	const int addr_cells = fdtbus_get_addr_cells(phandle);
    118 	const int size_cells = fdtbus_get_size_cells(phandle);
    119 	if (addr_cells == -1 || size_cells == -1)
    120 		return -1;
    121 
    122 	const u_int reglen = size_cells * 4 + addr_cells * 4;
    123 	if (reglen == 0)
    124 		return -1;
    125 
    126 	len = OF_getproplen(phandle, "reg");
    127 	if (len <= 0)
    128 		return -1;
    129 
    130 	const u_int nregs = len / reglen;
    131 
    132 	if (index >= nregs)
    133 		return -1;
    134 
    135 	buf = kmem_alloc(len, KM_SLEEP);
    136 	if (buf == NULL)
    137 		return -1;
    138 
    139 	len = OF_getprop(phandle, "reg", buf, len);
    140 
    141 	switch (addr_cells) {
    142 	case 0:
    143 		addr = 0;
    144 		break;
    145 	case 1:
    146 		addr = be32dec(&buf[index * reglen + 0]);
    147 		break;
    148 	case 2:
    149 		addr = be64dec(&buf[index * reglen + 0]);
    150 		break;
    151 	default:
    152 		panic("fdtbus_get_reg: unsupported addr_cells %d", addr_cells);
    153 	}
    154 
    155 	switch (size_cells) {
    156 	case 0:
    157 		size = 0;
    158 		break;
    159 	case 1:
    160 		size = be32dec(&buf[index * reglen + addr_cells * 4]);
    161 		break;
    162 	case 2:
    163 		size = be64dec(&buf[index * reglen + addr_cells * 4]);
    164 		break;
    165 	default:
    166 		panic("fdtbus_get_reg: unsupported size_cells %d", size_cells);
    167 	}
    168 
    169 	if (paddr)
    170 		*paddr = addr;
    171 	if (psize)
    172 		*psize = size;
    173 
    174 	kmem_free(buf, len);
    175 
    176 	return 0;
    177 }
    178