1*f7f76b85SAndrew Jones #ifndef _DEVICETREE_H_ 2*f7f76b85SAndrew Jones #define _DEVICETREE_H_ 3*f7f76b85SAndrew Jones /* 4*f7f76b85SAndrew Jones * devicetree builds on libfdt to implement abstractions and accessors 5*f7f76b85SAndrew Jones * for Linux required device tree content. The accessors provided are 6*f7f76b85SAndrew Jones * common across architectures. See section III of the kernel doc 7*f7f76b85SAndrew Jones * Documentation/devicetree/booting-without-of.txt 8*f7f76b85SAndrew Jones * 9*f7f76b85SAndrew Jones * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com> 10*f7f76b85SAndrew Jones * 11*f7f76b85SAndrew Jones * This work is licensed under the terms of the GNU LGPL, version 2. 12*f7f76b85SAndrew Jones */ 13*f7f76b85SAndrew Jones #include "libcflat.h" 14*f7f76b85SAndrew Jones #include "libfdt/libfdt.h" 15*f7f76b85SAndrew Jones 16*f7f76b85SAndrew Jones /********************************************************************** 17*f7f76b85SAndrew Jones * devicetree init and libfdt helpers 18*f7f76b85SAndrew Jones **********************************************************************/ 19*f7f76b85SAndrew Jones 20*f7f76b85SAndrew Jones /* dt_init initializes devicetree with a pointer to an fdt, @fdt_ptr */ 21*f7f76b85SAndrew Jones extern int dt_init(const void *fdt_ptr); 22*f7f76b85SAndrew Jones 23*f7f76b85SAndrew Jones /* get the fdt pointer that devicetree is using */ 24*f7f76b85SAndrew Jones extern const void *dt_fdt(void); 25*f7f76b85SAndrew Jones 26*f7f76b85SAndrew Jones /* check for an initialized, valid devicetree */ 27*f7f76b85SAndrew Jones extern bool dt_available(void); 28*f7f76b85SAndrew Jones 29*f7f76b85SAndrew Jones /* traverse child nodes */ 30*f7f76b85SAndrew Jones #define dt_for_each_subnode(n, s) \ 31*f7f76b85SAndrew Jones for (s = fdt_first_subnode(dt_fdt(), n); \ 32*f7f76b85SAndrew Jones s != -FDT_ERR_NOTFOUND; \ 33*f7f76b85SAndrew Jones s = fdt_next_subnode(dt_fdt(), s)) 34*f7f76b85SAndrew Jones 35*f7f76b85SAndrew Jones /********************************************************************** 36*f7f76b85SAndrew Jones * Abstractions for required node types and properties 37*f7f76b85SAndrew Jones **********************************************************************/ 38*f7f76b85SAndrew Jones 39*f7f76b85SAndrew Jones struct dt_device { 40*f7f76b85SAndrew Jones int fdtnode; 41*f7f76b85SAndrew Jones const struct dt_bus *bus; 42*f7f76b85SAndrew Jones 43*f7f76b85SAndrew Jones /* 44*f7f76b85SAndrew Jones * info is a pointer to device specific data, which may be 45*f7f76b85SAndrew Jones * used by the bus match() and translate() functions 46*f7f76b85SAndrew Jones */ 47*f7f76b85SAndrew Jones void *info; 48*f7f76b85SAndrew Jones }; 49*f7f76b85SAndrew Jones 50*f7f76b85SAndrew Jones struct dt_bus { 51*f7f76b85SAndrew Jones /* 52*f7f76b85SAndrew Jones * match a device @dev to an fdt node @fdtnode 53*f7f76b85SAndrew Jones * returns 54*f7f76b85SAndrew Jones * - a positive value on match 55*f7f76b85SAndrew Jones * - zero on no match 56*f7f76b85SAndrew Jones * - a negative FDT_ERR_* value on failure 57*f7f76b85SAndrew Jones */ 58*f7f76b85SAndrew Jones int (*match)(const struct dt_device *dev, int fdtnode); 59*f7f76b85SAndrew Jones 60*f7f76b85SAndrew Jones /* 61*f7f76b85SAndrew Jones * translate the @regidx'th "address size" tuple of 62*f7f76b85SAndrew Jones * @dev's fdt node's "reg" property, and store the result 63*f7f76b85SAndrew Jones * in @reg, a bus specific structure 64*f7f76b85SAndrew Jones * returns 65*f7f76b85SAndrew Jones * - zero on success 66*f7f76b85SAndrew Jones * - a negative FDT_ERR_* value on failure 67*f7f76b85SAndrew Jones */ 68*f7f76b85SAndrew Jones int (*translate)(const struct dt_device *dev, int regidx, void *reg); 69*f7f76b85SAndrew Jones 70*f7f76b85SAndrew Jones /* the bus #address-cells and #size-cells properties */ 71*f7f76b85SAndrew Jones u32 nr_address_cells, nr_size_cells; 72*f7f76b85SAndrew Jones }; 73*f7f76b85SAndrew Jones 74*f7f76b85SAndrew Jones /* dt_bus_match_any matches any fdt node, i.e. it always returns true */ 75*f7f76b85SAndrew Jones extern int dt_bus_match_any(const struct dt_device *dev, int fdtnode); 76*f7f76b85SAndrew Jones 77*f7f76b85SAndrew Jones /* the processor bus (pbus) address type and register tuple */ 78*f7f76b85SAndrew Jones typedef u64 dt_pbus_addr_t; 79*f7f76b85SAndrew Jones struct dt_pbus_reg { 80*f7f76b85SAndrew Jones dt_pbus_addr_t addr; 81*f7f76b85SAndrew Jones dt_pbus_addr_t size; 82*f7f76b85SAndrew Jones }; 83*f7f76b85SAndrew Jones 84*f7f76b85SAndrew Jones static inline dt_pbus_addr_t dt_pbus_read_cells(u32 nr_cells, u32 *cells) 85*f7f76b85SAndrew Jones { 86*f7f76b85SAndrew Jones switch (nr_cells) { 87*f7f76b85SAndrew Jones case 1: return cells[0]; 88*f7f76b85SAndrew Jones case 2: return ((u64)cells[0] << 32) | cells[1]; 89*f7f76b85SAndrew Jones } 90*f7f76b85SAndrew Jones return (~0ULL); 91*f7f76b85SAndrew Jones } 92*f7f76b85SAndrew Jones 93*f7f76b85SAndrew Jones /* 94*f7f76b85SAndrew Jones * dt_pbus_translate translates device node regs for the 95*f7f76b85SAndrew Jones * processor bus using the root node's #address-cells and 96*f7f76b85SAndrew Jones * #size-cells and dt_pbus_read_cells() 97*f7f76b85SAndrew Jones * returns 98*f7f76b85SAndrew Jones * - zero on success 99*f7f76b85SAndrew Jones * - a negative FDT_ERR_* value on failure 100*f7f76b85SAndrew Jones */ 101*f7f76b85SAndrew Jones extern int dt_pbus_translate(const struct dt_device *dev, int regidx, 102*f7f76b85SAndrew Jones void *reg); 103*f7f76b85SAndrew Jones 104*f7f76b85SAndrew Jones /* 105*f7f76b85SAndrew Jones * dt_pbus_translate_node is the same as dt_pbus_translate but 106*f7f76b85SAndrew Jones * operates on an fdt node instead of a dt_device 107*f7f76b85SAndrew Jones */ 108*f7f76b85SAndrew Jones extern int dt_pbus_translate_node(int fdtnode, int regidx, 109*f7f76b85SAndrew Jones struct dt_pbus_reg *reg); 110*f7f76b85SAndrew Jones 111*f7f76b85SAndrew Jones /* 112*f7f76b85SAndrew Jones * dt_pbus_get_base is an alias for 113*f7f76b85SAndrew Jones * dt_pbus_translate(dev, 0, base) 114*f7f76b85SAndrew Jones * returns 115*f7f76b85SAndrew Jones * - zero on success 116*f7f76b85SAndrew Jones * - a negative FDT_ERR_* value on failure 117*f7f76b85SAndrew Jones */ 118*f7f76b85SAndrew Jones static inline int dt_pbus_get_base(const struct dt_device *dev, 119*f7f76b85SAndrew Jones struct dt_pbus_reg *base) 120*f7f76b85SAndrew Jones { 121*f7f76b85SAndrew Jones return dt_pbus_translate(dev, 0, base); 122*f7f76b85SAndrew Jones } 123*f7f76b85SAndrew Jones 124*f7f76b85SAndrew Jones /* 125*f7f76b85SAndrew Jones * dt_bus_init_defaults initializes @bus with 126*f7f76b85SAndrew Jones * match <- dt_bus_match_any 127*f7f76b85SAndrew Jones * translate <- dt_pbus_translate 128*f7f76b85SAndrew Jones * nr_address_cells <- #address-cells of the root node 129*f7f76b85SAndrew Jones * nr_size_cells <- #size-cells of the root node 130*f7f76b85SAndrew Jones */ 131*f7f76b85SAndrew Jones extern void dt_bus_init_defaults(struct dt_bus *bus); 132*f7f76b85SAndrew Jones 133*f7f76b85SAndrew Jones /* 134*f7f76b85SAndrew Jones * dt_device_init initializes a dt_device with the given parameters 135*f7f76b85SAndrew Jones */ 136*f7f76b85SAndrew Jones extern void dt_device_init(struct dt_device *dev, const struct dt_bus *bus, 137*f7f76b85SAndrew Jones void *info); 138*f7f76b85SAndrew Jones 139*f7f76b85SAndrew Jones static inline void dt_device_bind_node(struct dt_device *dev, int fdtnode) 140*f7f76b85SAndrew Jones { 141*f7f76b85SAndrew Jones dev->fdtnode = fdtnode; 142*f7f76b85SAndrew Jones } 143*f7f76b85SAndrew Jones 144*f7f76b85SAndrew Jones /* 145*f7f76b85SAndrew Jones * dt_device_find_compatible finds a @compatible node 146*f7f76b85SAndrew Jones * returns 147*f7f76b85SAndrew Jones * - node (>= 0) on success 148*f7f76b85SAndrew Jones * - a negative FDT_ERR_* value on failure 149*f7f76b85SAndrew Jones */ 150*f7f76b85SAndrew Jones extern int dt_device_find_compatible(const struct dt_device *dev, 151*f7f76b85SAndrew Jones const char *compatible); 152*f7f76b85SAndrew Jones 153*f7f76b85SAndrew Jones /* 154*f7f76b85SAndrew Jones * dt_pbus_get_base_compatible simply bundles many functions into one. 155*f7f76b85SAndrew Jones * It finds the first @compatible fdt node, then translates the 0th reg 156*f7f76b85SAndrew Jones * tuple (the base) using the processor bus translation, and finally it 157*f7f76b85SAndrew Jones * stores that result in @base. 158*f7f76b85SAndrew Jones * returns 159*f7f76b85SAndrew Jones * - zero on success 160*f7f76b85SAndrew Jones * - a negative FDT_ERR_* value on failure 161*f7f76b85SAndrew Jones */ 162*f7f76b85SAndrew Jones extern int dt_pbus_get_base_compatible(const char *compatible, 163*f7f76b85SAndrew Jones struct dt_pbus_reg *base); 164*f7f76b85SAndrew Jones 165*f7f76b85SAndrew Jones /********************************************************************** 166*f7f76b85SAndrew Jones * Low-level accessors for required node types and properties 167*f7f76b85SAndrew Jones **********************************************************************/ 168*f7f76b85SAndrew Jones 169*f7f76b85SAndrew Jones /* 170*f7f76b85SAndrew Jones * dt_get_nr_cells sets @nr_address_cells and @nr_size_cells to the 171*f7f76b85SAndrew Jones * #address-cells and #size-cells properties of @fdtnode 172*f7f76b85SAndrew Jones * returns 173*f7f76b85SAndrew Jones * - zero on success 174*f7f76b85SAndrew Jones * - a negative FDT_ERR_* value on failure 175*f7f76b85SAndrew Jones */ 176*f7f76b85SAndrew Jones extern int dt_get_nr_cells(int fdtnode, u32 *nr_address_cells, 177*f7f76b85SAndrew Jones u32 *nr_size_cells); 178*f7f76b85SAndrew Jones 179*f7f76b85SAndrew Jones /* dt_reg is a structure for "raw" reg tuples */ 180*f7f76b85SAndrew Jones #define MAX_ADDRESS_CELLS 4 181*f7f76b85SAndrew Jones #define MAX_SIZE_CELLS 4 182*f7f76b85SAndrew Jones struct dt_reg { 183*f7f76b85SAndrew Jones u32 nr_address_cells, nr_size_cells; 184*f7f76b85SAndrew Jones u32 address_cells[MAX_ADDRESS_CELLS]; 185*f7f76b85SAndrew Jones u32 size_cells[MAX_SIZE_CELLS]; 186*f7f76b85SAndrew Jones }; 187*f7f76b85SAndrew Jones 188*f7f76b85SAndrew Jones /* 189*f7f76b85SAndrew Jones * dt_reg_init initialize a dt_reg struct to zero and sets 190*f7f76b85SAndrew Jones * nr_address_cells and nr_size_cells to @nr_address_cells and 191*f7f76b85SAndrew Jones * @nr_size_cells respectively. 192*f7f76b85SAndrew Jones */ 193*f7f76b85SAndrew Jones extern void dt_reg_init(struct dt_reg *reg, u32 nr_address_cells, 194*f7f76b85SAndrew Jones u32 nr_size_cells); 195*f7f76b85SAndrew Jones 196*f7f76b85SAndrew Jones /* 197*f7f76b85SAndrew Jones * dt_get_reg gets the @regidx'th reg tuple of @fdtnode's reg property 198*f7f76b85SAndrew Jones * and stores it in @reg. @reg must be initialized. 199*f7f76b85SAndrew Jones * returns 200*f7f76b85SAndrew Jones * - zero on success 201*f7f76b85SAndrew Jones * - a negative FDT_ERR_* value on failure 202*f7f76b85SAndrew Jones */ 203*f7f76b85SAndrew Jones extern int dt_get_reg(int fdtnode, int regidx, struct dt_reg *reg); 204*f7f76b85SAndrew Jones 205*f7f76b85SAndrew Jones /********************************************************************** 206*f7f76b85SAndrew Jones * High-level accessors for required node types and properties 207*f7f76b85SAndrew Jones **********************************************************************/ 208*f7f76b85SAndrew Jones 209*f7f76b85SAndrew Jones /* 210*f7f76b85SAndrew Jones * dt_get_bootargs gets a pointer to /chosen/bootargs 211*f7f76b85SAndrew Jones * returns 212*f7f76b85SAndrew Jones * - zero on success 213*f7f76b85SAndrew Jones * - a negative FDT_ERR_* value on failure 214*f7f76b85SAndrew Jones */ 215*f7f76b85SAndrew Jones extern int dt_get_bootargs(const char **bootargs); 216*f7f76b85SAndrew Jones 217*f7f76b85SAndrew Jones /* 218*f7f76b85SAndrew Jones * dt_get_memory_params gets the memory parameters from the /memory node(s) 219*f7f76b85SAndrew Jones * storing each memory region ("address size" tuple) in consecutive entries 220*f7f76b85SAndrew Jones * of @regs, up to @nr_regs 221*f7f76b85SAndrew Jones * returns 222*f7f76b85SAndrew Jones * - number of memory regions found on success 223*f7f76b85SAndrew Jones * - a negative FDT_ERR_* value on failure 224*f7f76b85SAndrew Jones */ 225*f7f76b85SAndrew Jones extern int dt_get_memory_params(struct dt_pbus_reg *regs, int nr_regs); 226*f7f76b85SAndrew Jones 227*f7f76b85SAndrew Jones /* 228*f7f76b85SAndrew Jones * dt_for_each_cpu_node runs @func on each cpu node in the /cpus node 229*f7f76b85SAndrew Jones * passing it its fdt node, its reg property value, and @info 230*f7f76b85SAndrew Jones * - zero on success 231*f7f76b85SAndrew Jones * - a negative FDT_ERR_* value on failure 232*f7f76b85SAndrew Jones */ 233*f7f76b85SAndrew Jones extern int dt_for_each_cpu_node(void (*func)(int fdtnode, u32 regval, 234*f7f76b85SAndrew Jones void *info), void *info); 235*f7f76b85SAndrew Jones 236*f7f76b85SAndrew Jones #endif /* _DEVICETREE_H_ */ 237