251 lines
7.4 KiB
C
251 lines
7.4 KiB
C
#ifndef _DEVICETREE_H_
|
|
#define _DEVICETREE_H_
|
|
/*
|
|
* devicetree builds on libfdt to implement abstractions and accessors
|
|
* for Linux required device tree content. The accessors provided are
|
|
* common across architectures. See section III of the kernel doc
|
|
* Documentation/devicetree/booting-without-of.txt
|
|
*
|
|
* Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com>
|
|
*
|
|
* This work is licensed under the terms of the GNU LGPL, version 2.
|
|
*/
|
|
#include "libcflat.h"
|
|
#include "libfdt/libfdt.h"
|
|
|
|
/**********************************************************************
|
|
* devicetree init and libfdt helpers
|
|
**********************************************************************/
|
|
|
|
/* dt_init initializes devicetree with a pointer to an fdt, @fdt_ptr */
|
|
extern int dt_init(const void *fdt_ptr);
|
|
|
|
/* get the fdt pointer that devicetree is using */
|
|
extern const void *dt_fdt(void);
|
|
|
|
/* check for an initialized, valid devicetree */
|
|
extern bool dt_available(void);
|
|
|
|
/* traverse child nodes */
|
|
#define dt_for_each_subnode(n, s) \
|
|
for (s = fdt_first_subnode(dt_fdt(), n); \
|
|
s != -FDT_ERR_NOTFOUND; \
|
|
s = fdt_next_subnode(dt_fdt(), s))
|
|
|
|
/**********************************************************************
|
|
* Abstractions for required node types and properties
|
|
**********************************************************************/
|
|
|
|
struct dt_device {
|
|
int fdtnode;
|
|
const struct dt_bus *bus;
|
|
|
|
/*
|
|
* info is a pointer to device specific data, which may be
|
|
* used by the bus match() and translate() functions
|
|
*/
|
|
void *info;
|
|
};
|
|
|
|
struct dt_bus {
|
|
/*
|
|
* match a device @dev to an fdt node @fdtnode
|
|
* returns
|
|
* - a positive value on match
|
|
* - zero on no match
|
|
* - a negative FDT_ERR_* value on failure
|
|
*/
|
|
int (*match)(const struct dt_device *dev, int fdtnode);
|
|
|
|
/*
|
|
* translate the @regidx'th "address size" tuple of
|
|
* @dev's fdt node's "reg" property, and store the result
|
|
* in @reg, a bus specific structure
|
|
* returns
|
|
* - zero on success
|
|
* - a negative FDT_ERR_* value on failure
|
|
*/
|
|
int (*translate)(const struct dt_device *dev, int regidx, void *reg);
|
|
};
|
|
|
|
/* dt_bus_match_any matches any fdt node, i.e. it always returns true */
|
|
extern int dt_bus_match_any(const struct dt_device *dev, int fdtnode);
|
|
|
|
/* the processor bus (pbus) address type and register tuple */
|
|
typedef u64 dt_pbus_addr_t;
|
|
struct dt_pbus_reg {
|
|
dt_pbus_addr_t addr;
|
|
dt_pbus_addr_t size;
|
|
};
|
|
|
|
static inline dt_pbus_addr_t dt_pbus_read_cells(u32 nr_cells, u32 *cells)
|
|
{
|
|
switch (nr_cells) {
|
|
case 1: return cells[0];
|
|
case 2: return ((u64)cells[0] << 32) | cells[1];
|
|
}
|
|
return (~0ULL);
|
|
}
|
|
|
|
/*
|
|
* dt_pbus_translate translates device node regs for the
|
|
* processor bus using the parent node's #address-cells
|
|
* and #size-cells and dt_pbus_read_cells()
|
|
* returns
|
|
* - zero on success
|
|
* - a negative FDT_ERR_* value on failure
|
|
*/
|
|
extern int dt_pbus_translate(const struct dt_device *dev, int regidx,
|
|
void *reg);
|
|
|
|
/*
|
|
* dt_pbus_translate_node is the same as dt_pbus_translate but
|
|
* operates on an fdt node instead of a dt_device
|
|
*/
|
|
extern int dt_pbus_translate_node(int fdtnode, int regidx,
|
|
struct dt_pbus_reg *reg);
|
|
|
|
/*
|
|
* dt_pbus_get_base is an alias for
|
|
* dt_pbus_translate(dev, 0, base)
|
|
* returns
|
|
* - zero on success
|
|
* - a negative FDT_ERR_* value on failure
|
|
*/
|
|
static inline int dt_pbus_get_base(const struct dt_device *dev,
|
|
struct dt_pbus_reg *base)
|
|
{
|
|
return dt_pbus_translate(dev, 0, base);
|
|
}
|
|
|
|
/*
|
|
* dt_bus_init_defaults initializes @bus with
|
|
* match <- dt_bus_match_any
|
|
* translate <- dt_pbus_translate
|
|
*/
|
|
extern void dt_bus_init_defaults(struct dt_bus *bus);
|
|
|
|
/*
|
|
* dt_device_init initializes a dt_device with the given parameters
|
|
*/
|
|
extern void dt_device_init(struct dt_device *dev, const struct dt_bus *bus,
|
|
void *info);
|
|
|
|
static inline void dt_device_bind_node(struct dt_device *dev, int fdtnode)
|
|
{
|
|
dev->fdtnode = fdtnode;
|
|
}
|
|
|
|
/*
|
|
* dt_device_find_compatible finds a @compatible node
|
|
* returns
|
|
* - node (>= 0) on success
|
|
* - a negative FDT_ERR_* value on failure
|
|
*/
|
|
extern int dt_device_find_compatible(const struct dt_device *dev,
|
|
const char *compatible);
|
|
|
|
/*
|
|
* dt_pbus_get_base_compatible simply bundles many functions into one.
|
|
* It finds the first @compatible fdt node, then translates the 0th reg
|
|
* tuple (the base) using the processor bus translation, and finally it
|
|
* stores that result in @base.
|
|
* returns
|
|
* - zero on success
|
|
* - a negative FDT_ERR_* value on failure
|
|
*/
|
|
extern int dt_pbus_get_base_compatible(const char *compatible,
|
|
struct dt_pbus_reg *base);
|
|
|
|
/**********************************************************************
|
|
* Low-level accessors for required node types and properties
|
|
**********************************************************************/
|
|
|
|
/*
|
|
* dt_get_nr_cells sets @nr_address_cells and @nr_size_cells to the
|
|
* #address-cells and #size-cells properties of @fdtnode
|
|
* returns
|
|
* - zero on success
|
|
* - a negative FDT_ERR_* value on failure
|
|
*/
|
|
extern int dt_get_nr_cells(int fdtnode, u32 *nr_address_cells,
|
|
u32 *nr_size_cells);
|
|
|
|
/* dt_reg is a structure for "raw" reg tuples */
|
|
#define MAX_ADDRESS_CELLS 4
|
|
#define MAX_SIZE_CELLS 4
|
|
struct dt_reg {
|
|
u32 nr_address_cells, nr_size_cells;
|
|
u32 address_cells[MAX_ADDRESS_CELLS];
|
|
u32 size_cells[MAX_SIZE_CELLS];
|
|
};
|
|
|
|
/*
|
|
* dt_reg_init initialize a dt_reg struct to zero and sets
|
|
* nr_address_cells and nr_size_cells to @nr_address_cells and
|
|
* @nr_size_cells respectively.
|
|
*/
|
|
extern void dt_reg_init(struct dt_reg *reg, u32 nr_address_cells,
|
|
u32 nr_size_cells);
|
|
|
|
/*
|
|
* dt_get_reg gets the @regidx'th reg tuple of @fdtnode's reg property
|
|
* and stores it in @reg. @reg must be initialized.
|
|
* returns
|
|
* - zero on success
|
|
* - a negative FDT_ERR_* value on failure
|
|
*/
|
|
extern int dt_get_reg(int fdtnode, int regidx, struct dt_reg *reg);
|
|
|
|
/**********************************************************************
|
|
* High-level accessors for required node types and properties
|
|
**********************************************************************/
|
|
|
|
/*
|
|
* dt_get_bootargs gets the string pointer from /chosen/bootargs
|
|
* returns
|
|
* - zero on success
|
|
* - a negative FDT_ERR_* value on failure, and @bootargs
|
|
* will be set to NULL
|
|
*/
|
|
extern int dt_get_bootargs(const char **bootargs);
|
|
|
|
/*
|
|
* dt_get_default_console_node gets the node of the path stored in
|
|
* /chosen/stdout-path (or the deprecated /chosen/linux,stdout-path)
|
|
* returns
|
|
* - the node (>= 0) on success
|
|
* - a negative FDT_ERR_* value on failure
|
|
*/
|
|
extern int dt_get_default_console_node(void);
|
|
|
|
/*
|
|
* dt_get_initrd gets the physical address of the initrd and its
|
|
* size from /chosen
|
|
* returns
|
|
* - zero on success
|
|
* - a negative FDT_ERR_* value on failure, and @initrd will be
|
|
* set to NULL and @size set to zero
|
|
*/
|
|
extern int dt_get_initrd(const char **initrd, u32 *size);
|
|
|
|
/*
|
|
* dt_get_memory_params gets the memory parameters from the /memory node(s)
|
|
* storing each memory region ("address size" tuple) in consecutive entries
|
|
* of @regs, up to @nr_regs
|
|
* returns
|
|
* - number of memory regions found on success
|
|
* - a negative FDT_ERR_* value on failure
|
|
*/
|
|
extern int dt_get_memory_params(struct dt_pbus_reg *regs, int nr_regs);
|
|
|
|
/*
|
|
* dt_for_each_cpu_node runs @func on each cpu node in the /cpus node
|
|
* passing it its fdt node, its reg property value, and @info
|
|
* - zero on success
|
|
* - a negative FDT_ERR_* value on failure
|
|
*/
|
|
extern int dt_for_each_cpu_node(void (*func)(int fdtnode, u64 regval,
|
|
void *info), void *info);
|
|
|
|
#endif /* _DEVICETREE_H_ */
|