/* * Device Tree * * Copyright (C) 2012 Citrix Systems, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #ifndef __XEN_DEVICE_TREE_H__ #define __XEN_DEVICE_TREE_H__ #include #include #include #include #include #define DEVICE_TREE_MAX_DEPTH 16 #define NR_MEM_BANKS 8 #define MOD_XEN 0 #define MOD_FDT 1 #define MOD_KERNEL 2 #define MOD_INITRD 3 #define NR_MODULES 4 #define MOD_DISCARD_FIRST MOD_FDT struct membank { paddr_t start; paddr_t size; }; struct dt_mem_info { int nr_banks; struct membank bank[NR_MEM_BANKS]; }; struct dt_mb_module { paddr_t start; paddr_t size; char cmdline[1024]; }; struct dt_module_info { int nr_mods; /* Module 0 is Xen itself, followed by the provided modules-proper */ struct dt_mb_module module[NR_MODULES]; }; struct dt_early_info { struct dt_mem_info mem; struct dt_module_info modules; }; /* * Struct used for matching a device */ struct dt_device_match { const char *path; const char *type; const char *compatible; }; #define DT_MATCH_PATH(p) { .path = p } #define DT_MATCH_TYPE(typ) { .type = typ } #define DT_MATCH_COMPATIBLE(compat) { .compatible = compat } typedef u32 dt_phandle; /** * dt_property - describe a property for a device * @name: name of the property * @length: size of the value * @value: pointer to data contained in the property * @next: pointer to the next property of a specific node */ struct dt_property { const char *name; u32 length; void *value; struct dt_property *next; }; /** * dt_device_node - describe a node in the device tree * @name: name of the node * @type: type of the node (ie: memory, cpu, ...) * @full_name: full name, it's composed of all the ascendant name separate by / * @used_by: who owns the node? (ie: xen, dom0...) * @properties: list of properties for the node * @child: pointer to the first child * @sibling: pointer to the next sibling * @allnext: pointer to the next in list of all nodes */ struct dt_device_node { const char *name; const char *type; dt_phandle phandle; char *full_name; domid_t used_by; /* By default it's used by dom0 */ struct dt_property *properties; struct dt_device_node *parent; struct dt_device_node *child; struct dt_device_node *sibling; struct dt_device_node *next; /* TODO: Remove it. Only use to know the last children */ struct dt_device_node *allnext; }; /** * IRQ line type. * * DT_IRQ_TYPE_NONE - default, unspecified type * DT_IRQ_TYPE_EDGE_RISING - rising edge triggered * DT_IRQ_TYPE_EDGE_FALLING - falling edge triggered * DT_IRQ_TYPE_EDGE_BOTH - rising and falling edge triggered * DT_IRQ_TYPE_LEVEL_HIGH - high level triggered * DT_IRQ_TYPE_LEVEL_LOW - low level triggered * DT_IRQ_TYPE_LEVEL_MASK - Mask to filter out the level bits * DT_IRQ_TYPE_SENSE_MASK - Mask for all the above bits */ #define DT_IRQ_TYPE_NONE 0x00000000 #define DT_IRQ_TYPE_EDGE_RISING 0x00000001 #define DT_IRQ_TYPE_EDGE_FALLING 0x00000002 #define DT_IRQ_TYPE_EDGE_BOTH \ (DT_IRQ_TYPE_EDGE_FALLING | DT_IRQ_TYPE_EDGE_RISING) #define DT_IRQ_TYPE_LEVEL_HIGH 0x00000004 #define DT_IRQ_TYPE_LEVEL_LOW 0x00000008 #define DT_IRQ_TYPE_LEVEL_MASK \ (DT_IRQ_TYPE_LEVEL_LOW | DT_IRQ_TYPE_LEVEL_HIGH) #define DT_IRQ_TYPE_SENSE_MASK 0x0000000f /** * dt_irq - describe an IRQ in the device tree * @irq: IRQ number * @type: IRQ type (see DT_IRQ_TYPE_*) * * This structure is returned when an interrupt is mapped. */ struct dt_irq { unsigned int irq; unsigned int type; }; /* If type == DT_IRQ_TYPE_NONE, assume we use level triggered */ static inline bool_t dt_irq_is_level_triggered(const struct dt_irq *irq) { unsigned int type = irq->type; return (type & DT_IRQ_TYPE_LEVEL_MASK) || (type == DT_IRQ_TYPE_NONE); } /** * dt_raw_irq - container for device_node/irq_specifier for an irq controller * @controller: pointer to interrupt controller deivce tree node * @size: size of interrupt specifier * @specifier: array of cells @size long specifying the specific interrupt * * This structure is returned when an interrupt is mapped but not translated. */ #define DT_MAX_IRQ_SPEC 4 /* We handle specifiers of at most 4 cells */ struct dt_raw_irq { const struct dt_device_node *controller; u32 size; u32 specifier[DT_MAX_IRQ_SPEC]; }; #define dt_irq(irq) ((irq)->irq) #define dt_irq_flags(irq) ((irq)->flags) typedef int (*device_tree_node_func)(const void *fdt, int node, const char *name, int depth, u32 address_cells, u32 size_cells, void *data); extern struct dt_early_info early_info; extern const void *device_tree_flattened; size_t __init device_tree_early_init(const void *fdt, paddr_t paddr); const char __init *device_tree_bootargs(const void *fdt); void __init device_tree_dump(const void *fdt); /** * dt_unflatten_host_device_tree - Unflatten the host device tree * * Create a hierarchical device tree for the host DTB to be able * to retrieve parents. */ void __init dt_unflatten_host_device_tree(void); /** * IRQ translation callback * TODO: For the moment we assume that we only have ONE * interrupt-controller. */ typedef int (*dt_irq_xlate_func)(const u32 *intspec, unsigned int intsize, unsigned int *out_hwirq, unsigned int *out_type); extern dt_irq_xlate_func dt_irq_xlate; /** * Host device tree * DO NOT modify it! */ extern struct dt_device_node *dt_host; /** * Primary interrupt controller * Exynos SOC has an interrupt combiner, interrupt has no physical * meaning when it's not connected to the primary controller. * We will only map interrupt whose parent controller is * dt_interrupt_controller. It should always be a GIC. * TODO: Handle multiple GIC */ extern const struct dt_device_node *dt_interrupt_controller; /** * Find the interrupt controller * For the moment we handle only one interrupt controller: the first * one without parent which is compatible with the string "compat". * * If found, return the interrupt controller device node. */ struct dt_device_node * __init dt_find_interrupt_controller(const struct dt_device_match *matches); #define dt_prop_cmp(s1, s2) strcmp((s1), (s2)) #define dt_node_cmp(s1, s2) strcasecmp((s1), (s2)) #define dt_compat_cmp(s1, s2) strcasecmp((s1), (s2)) /* Default #address and #size cells */ #define DT_ROOT_NODE_ADDR_CELLS_DEFAULT 2 #define DT_ROOT_NODE_SIZE_CELLS_DEFAULT 1 #define dt_for_each_property_node(dn, pp) \ for ( pp = dn->properties; pp != NULL; pp = pp->next ) #define dt_for_each_device_node(dt, dn) \ for ( dn = dt; dn != NULL; dn = dn->allnext ) #define dt_for_each_child_node(dt, dn) \ for ( dn = dt->child; dn != NULL; dn = dn->sibling ) /* Helper to read a big number; size is in cells (not bytes) */ static inline u64 dt_read_number(const __be32 *cell, int size) { u64 r = 0; while ( size-- ) r = (r << 32) | be32_to_cpu(*(cell++)); return r; } /* Helper to convert a number of cells in bytes */ static inline int dt_cells_to_size(int size) { return (size * sizeof (u32)); } static inline u64 dt_next_cell(int s, const __be32 **cellp) { const __be32 *p = *cellp; *cellp = p + s; return dt_read_number(p, s); } static inline const char *dt_node_full_name(const struct dt_device_node *np) { return (np && np->full_name) ? np->full_name : ""; } static inline const char *dt_node_name(const struct dt_device_node *np) { return (np && np->name) ? np->name : ""; } static inline bool_t dt_node_name_is_equal(const struct dt_device_node *np, const char *name) { return !dt_node_cmp(np->name, name); } static inline bool_t dt_node_path_is_equal(const struct dt_device_node *np, const char *path) { return !dt_node_cmp(np->full_name, path); } static inline bool_t dt_device_type_is_equal(const struct dt_device_node *device, const char *type) { return !dt_node_cmp(device->type, type); } static inline void dt_device_set_used_by(struct dt_device_node *device, domid_t used_by) { /* TODO: children must inherit to the used_by thing */ device->used_by = used_by; } static inline domid_t dt_device_used_by(const struct dt_device_node *device) { return device->used_by; } static inline bool_t dt_property_name_is_equal(const struct dt_property *pp, const char *name) { return !dt_prop_cmp(pp->name, name); } /** * dt_find_compatible_node - Find a node based on type and one of the * tokens in its "compatible" property * @from: The node to start searching from or NULL, the node * you pass will not be searched, only the next one * will; typically, you pass what the previous call * returned. * @type: The type string to match "device_type" or NULL to ignore * @compatible: The string to match to one of the tokens in the device * "compatible" list. * * Returns a node pointer. */ struct dt_device_node *dt_find_compatible_node(struct dt_device_node *from, const char *type, const char *compatible); /** * Find a property with a given name for a given node * and return the value. */ const void *dt_get_property(const struct dt_device_node *np, const char *name, u32 *lenp); /** * dt_property_read_u32 - Helper to read a u32 property. * @np: node to get the value * @name: name of the property * @out_value: pointer to return value * * Return true if get the desired value. */ bool_t dt_property_read_u32(const struct dt_device_node *np, const char *name, u32 *out_value); /** * dt_property_read_u64 - Helper to read a u64 property. * @np: node to get the value * @name: name of the property * @out_value: pointer to return value * * Return true if get the desired value. */ bool_t dt_property_read_u64(const struct dt_device_node *np, const char *name, u64 *out_value); /** * dt_property_read_string - Find and read a string from a property * @np: Device node from which the property value is to be read * @propname: Name of the property to be searched * @out_string: Pointer to null terminated return string, modified only * if return value if 0. * * Search for a property in a device tree node and retrieve a null * terminated string value (pointer to data, not a copy). Returns 0 on * success, -EINVAL if the property does not exist, -ENODATA if property * doest not have value, and -EILSEQ if the string is not * null-terminated with the length of the property data. * * The out_string pointer is modified only if a valid string can be decoded. */ int dt_property_read_string(const struct dt_device_node *np, const char *propname, const char **out_string); /** * Checks if the given "compat" string matches one of the strings in * the device's "compatible" property */ bool_t dt_device_is_compatible(const struct dt_device_node *device, const char *compat); /** * dt_machine_is_compatible - Test root of device tree for a given compatible value * @compat: compatible string to look for in root node's compatible property. * * Returns true if the root node has the given value in its * compatible property. */ bool_t dt_machine_is_compatible(const char *compat); /** * dt_find_node_by_name - Find a node by its "name" property * @from: The node to start searching from or NULL, the node * you pass will not be searched, only the next one * will; typically, you pass what the previous call * returned. of_node_put() will be called on it * @name: The name string to match against * * Returns a node pointer with refcount incremented, use * of_node_put() on it when done. */ struct dt_device_node *dt_find_node_by_name(struct dt_device_node *node, const char *name); /** * dt_find_node_by_type - Find a node by its "type" property */ struct dt_device_node *dt_find_node_by_type(struct dt_device_node *from, const char *type); /** * df_find_node_by_alias - Find a node matching an alias * @alias: The alias to match * * Returns a node pointer. */ struct dt_device_node *dt_find_node_by_alias(const char *alias); /** * dt_find_node_by_path - Find a node matching a full DT path * @path: The full path to match * * Returns a node pointer. */ struct dt_device_node *dt_find_node_by_path(const char *path); /** * dt_get_parent - Get a node's parent if any * @node: Node to get parent * * Returns a node pointer. */ const struct dt_device_node *dt_get_parent(const struct dt_device_node *node); /** * dt_device_get_address - Resolve an address for a device * @device: the device whose address is to be resolved * @index: index of the address to resolve * @addr: address filled by this function * @size: size filled by this function * * This function resolves an address, walking the tree, for a give * device-tree node. It returns 0 on success. */ int dt_device_get_address(const struct dt_device_node *dev, int index, u64 *addr, u64 *size); /** * dt_number_of_irq - Get the number of IRQ for a device * @device: the device whose number of interrupt is to be retrieved * * Return the number of irq for this device or 0 if there is no * interrupt or an error occurred. */ unsigned int dt_number_of_irq(const struct dt_device_node *device); /** * dt_number_of_address - Get the number of addresses for a device * @device: the device whose number of address is to be retrieved * * Return the number of address for this device or 0 if there is no * address or an error occurred. */ unsigned int dt_number_of_address(const struct dt_device_node *device); /** * dt_device_get_irq - Resolve an interrupt for a device * @device: the device whose interrupt is to be resolved * @index: index of the interrupt to resolve * @out_irq: structure dt_irq filled by this function * * This function resolves an interrupt, walking the tree, for a given * device-tree node. It's the high level pendant to dt_device_get_raw_irq(). */ int dt_device_get_irq(const struct dt_device_node *device, int index, struct dt_irq *irq); /** * dt_device_get_raw_irq - Resolve an interrupt for a device without translation * @device: the device whose interrupt is to be resolved * @index: index of the interrupt to resolve * @out_irq: structure dt_raw_irq filled by this function * * This function resolves an interrupt for a device, no translation is * made. dt_irq_translate can be called after. */ int dt_device_get_raw_irq(const struct dt_device_node *device, int index, struct dt_raw_irq *irq); /** * dt_irq_translate - Translate an irq * @raw: IRQ to translate (raw format) * @out_irq: structure dt_irq filled by this function */ int dt_irq_translate(const struct dt_raw_irq *raw, struct dt_irq *out_irq); /** * dt_n_size_cells - Helper to retrieve the number of cell for the size * @np: node to get the value * * This function retrieves for a give device-tree node the number of * cell for the size field. */ int dt_n_size_cells(const struct dt_device_node *np); /** * dt_n_addr_cells - Helper to retrieve the number of cell for the address * @np: node to get the value * * This function retrieves for a give device-tree node the number of * cell for the address field. */ int dt_n_addr_cells(const struct dt_device_node *np); /** * dt_device_is_available - Check if a device is available for use * * @device: Node to check for availability * * Returns true if the status property is absent or set to "okay" or "ok", * false otherwise. */ bool_t dt_device_is_available(const struct dt_device_node *device); /** * dt_match_node - Tell if a device_node has a matching of dt_device_match * @matches: array of dt_device_match structures to search in * @node: the dt_device_node structure to match against * * Returns true if the device node match one of dt_device_match. */ bool_t dt_match_node(const struct dt_device_match *matches, const struct dt_device_node *node); /** * dt_find_matching_node - Find a node based on an dt_device_match match table * @from: The node to start searching from or NULL, the node you pass * will not be searched, only the next one will; typically, you pass * what the returned call returned * @matches: array of dt_device_match structures to search in * * Returns a node pointer. */ struct dt_device_node * dt_find_matching_node(struct dt_device_node *from, const struct dt_device_match *matches); /** * dt_set_cell - Write a value into a series of cells * * @cellp: Pointer to cells * @size: number of cells to write the value * @value: number to write * * Write a value into a series of cells and update cellp to point to the * cell just after. */ void dt_set_cell(__be32 **cellp, int size, u64 val); /** * dt_set_range - Write range into a series of cells * * @cellp: Pointer to cells * @np: Node which contains the encoding for the address and the size * @address: Start of range * @size: Size of the range * * Write a range into a series of cells and update cellp to point to the * cell just after. */ void dt_set_range(__be32 **cellp, const struct dt_device_node *np, u64 address, u64 size); /** * dt_get_range - Read a range (address/size) from a series of cells * * @cellp: Pointer to cells * @np Node which contains the encoding for the addresss and the size * @address: Address filled by this function * @size: Size filled by this function * * WARNING: This function should not be used to decode an address * This function reads a range (address/size) from a series of cells and * update cellp to point to the cell just after. */ void dt_get_range(const __be32 **cellp, const struct dt_device_node *np, u64 *address, u64 *size); #endif /* __XEN_DEVICE_TREE_H */ /* * Local variables: * mode: C * c-file-style: "BSD" * c-basic-offset: 4 * indent-tabs-mode: nil * End: */