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