forked from nuttx/nuttx-update
drivers/devicetree: Add a set of commonly used FDT utilities.
This commit is contained in:
parent
297b3b0209
commit
c4dbabb1bb
4 changed files with 254 additions and 7 deletions
|
@ -70,7 +70,7 @@ static void register_virtio_devices_from_fdt(const void *fdt)
|
|||
break;
|
||||
}
|
||||
|
||||
addr = fdt_get_reg_base(fdt, offset);
|
||||
addr = fdt_get_reg_base(fdt, offset, 0);
|
||||
irqnum = fdt_get_irq(fdt, offset, 1, QEMU_SPI_IRQ_BASE);
|
||||
if (addr > 0 && irqnum >= 0)
|
||||
{
|
||||
|
|
|
@ -70,7 +70,7 @@ static void register_virtio_devices_from_fdt(const void *fdt)
|
|||
break;
|
||||
}
|
||||
|
||||
addr = fdt_get_reg_base(fdt, offset);
|
||||
addr = fdt_get_reg_base(fdt, offset, 0);
|
||||
irqnum = fdt_get_irq(fdt, offset, 1, QEMU_SPI_IRQ_BASE);
|
||||
if (addr > 0 && irqnum >= 0)
|
||||
{
|
||||
|
|
|
@ -122,15 +122,41 @@ uintptr_t fdt_ld_by_cells(FAR const void *value, int cells)
|
|||
}
|
||||
}
|
||||
|
||||
uintptr_t fdt_get_reg_base(FAR const void *fdt, int offset)
|
||||
uintptr_t fdt_get_reg_base_by_name(FAR const void *fdt, int offset,
|
||||
const char *reg_name)
|
||||
{
|
||||
uintptr_t addr = 0;
|
||||
|
||||
int reg_index
|
||||
= fdt_stringlist_search(fdt, offset, "reg-names", reg_name);
|
||||
if (reg_index < 0)
|
||||
{
|
||||
return addr;
|
||||
}
|
||||
|
||||
return fdt_get_reg_base(fdt, offset, reg_index);
|
||||
}
|
||||
|
||||
uintptr_t fdt_get_reg_base(FAR const void *fdt, int offset, int index)
|
||||
{
|
||||
FAR const void *reg;
|
||||
uintptr_t addr = 0;
|
||||
int reg_length;
|
||||
|
||||
reg = fdt_getprop(fdt, offset, "reg", NULL);
|
||||
/* Register cells contain a tuple of two values */
|
||||
|
||||
index *= 2;
|
||||
|
||||
reg = fdt_getprop(fdt, offset, "reg", ®_length);
|
||||
if (reg != NULL)
|
||||
{
|
||||
addr = fdt_ld_by_cells(reg, fdt_get_parent_address_cells(fdt, offset));
|
||||
if ((index * sizeof(uintptr_t)) > reg_length)
|
||||
{
|
||||
return addr;
|
||||
}
|
||||
|
||||
addr = fdt_ld_by_cells(reg + index * sizeof(uintptr_t),
|
||||
fdt_get_parent_address_cells(fdt, offset));
|
||||
}
|
||||
|
||||
return addr;
|
||||
|
@ -152,6 +178,115 @@ uintptr_t fdt_get_reg_size(FAR const void *fdt, int offset)
|
|||
|
||||
uintptr_t fdt_get_reg_base_by_path(FAR const void *fdt, FAR const char *path)
|
||||
{
|
||||
return fdt_get_reg_base(fdt, fdt_path_offset(fdt, path));
|
||||
return fdt_get_reg_base(fdt, fdt_path_offset(fdt, path), 0);
|
||||
}
|
||||
|
||||
bool fdt_device_is_available(FAR const void *fdt, int node)
|
||||
{
|
||||
const char *status = fdt_getprop(fdt, node, "status", NULL);
|
||||
if (!status)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!strcmp(status, "ok") || !strcmp(status, "okay"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *fdt_get_node_label(FAR const void *fdt, int node)
|
||||
{
|
||||
int symbols_offset;
|
||||
int property_offset;
|
||||
int ret;
|
||||
const char *property_name;
|
||||
const char *label_name;
|
||||
char path_buffer[CONFIG_PATH_MAX] =
|
||||
{
|
||||
0
|
||||
};
|
||||
|
||||
symbols_offset = fdt_path_offset(fdt, "/__symbols__");
|
||||
if (symbols_offset < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = fdt_get_path(fdt, node, path_buffer, sizeof(path_buffer));
|
||||
if (ret < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fdt_for_each_property_offset(property_offset, fdt, symbols_offset)
|
||||
{
|
||||
property_name = fdt_getprop_by_offset(
|
||||
fdt, property_offset, &label_name, NULL);
|
||||
|
||||
/* The symbols section is a list of parameters in the format
|
||||
* label_name = node_path. So the value of each property needs to be
|
||||
* checked with the full path found earlier.
|
||||
*
|
||||
*/
|
||||
|
||||
if (!strncmp(property_name, path_buffer, sizeof(path_buffer)))
|
||||
{
|
||||
return label_name;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uintptr_t fdt_get_clock_frequency(FAR const void *fdt, int offset)
|
||||
{
|
||||
const void *pv;
|
||||
uintptr_t clock_frequency = 0;
|
||||
|
||||
pv = fdt_getprop(fdt, offset, "clock-frequency", NULL);
|
||||
if (!pv)
|
||||
{
|
||||
return clock_frequency;
|
||||
}
|
||||
|
||||
clock_frequency = fdt_ld_by_cells(pv,
|
||||
fdt_get_parent_address_cells(fdt,
|
||||
offset));
|
||||
|
||||
return clock_frequency;
|
||||
}
|
||||
|
||||
uintptr_t fdt_get_clock_frequency_from_clocks(FAR const void *fdt,
|
||||
int offset,
|
||||
int index)
|
||||
{
|
||||
const fdt32_t *pv;
|
||||
fdt32_t clk_phandle;
|
||||
int pv_offset;
|
||||
uintptr_t clock_frequency = 0;
|
||||
int clk_length;
|
||||
|
||||
pv = fdt_getprop(fdt, offset, "clocks", &clk_length);
|
||||
if (!pv)
|
||||
{
|
||||
return clock_frequency;
|
||||
}
|
||||
|
||||
if ((index * sizeof(fdt32_t)) > clk_length)
|
||||
{
|
||||
return clock_frequency;
|
||||
}
|
||||
|
||||
clk_phandle = fdt32_ld(pv + index);
|
||||
|
||||
pv_offset = fdt_node_offset_by_phandle(fdt, clk_phandle);
|
||||
if (pv_offset < 0)
|
||||
{
|
||||
return clock_frequency;
|
||||
}
|
||||
|
||||
return fdt_get_clock_frequency(fdt, pv_offset);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <nuttx/compiler.h>
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -186,6 +187,31 @@ int fdt_get_parent_size_cells(FAR const void *fdt, int offset);
|
|||
|
||||
uintptr_t fdt_ld_by_cells(FAR const void *value, int cells);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: fdt_get_reg_base_by_name
|
||||
*
|
||||
* Description:
|
||||
* Get the value of the "reg" property by its offset in the "reg-names"
|
||||
* property
|
||||
*
|
||||
* Input Parameters:
|
||||
* fdt - The pointer to the raw FDT.
|
||||
* offset - The offset to the node.
|
||||
* reg_name - The name of the register
|
||||
*
|
||||
* Returned Value:
|
||||
* The register address determined by its name. Returns 0 if:
|
||||
* - The reg-names property doesn't exist.
|
||||
* - The reg property doesn't exits.
|
||||
* - The reg-names property doesn't contain the "reg_name".
|
||||
* - The offset combined with the size is larger than the width of the
|
||||
* "reg" field
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uintptr_t fdt_get_reg_base_by_name(FAR const void *fdt, int offset,
|
||||
const char *reg_name);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: fdt_get_reg_base
|
||||
*
|
||||
|
@ -195,13 +221,14 @@ uintptr_t fdt_ld_by_cells(FAR const void *value, int cells);
|
|||
* Input Parameters:
|
||||
* fdt - The pointer to the raw FDT.
|
||||
* offset - The offset of the node
|
||||
* index - The index of the register in the reg field.
|
||||
*
|
||||
* Return:
|
||||
* The base address of the register space
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uintptr_t fdt_get_reg_base(FAR const void *fdt, int offset);
|
||||
uintptr_t fdt_get_reg_base(FAR const void *fdt, int offset, int index);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: fdt_get_reg_size
|
||||
|
@ -238,4 +265,89 @@ uintptr_t fdt_get_reg_size(FAR const void *fdt, int offset);
|
|||
uintptr_t fdt_get_reg_base_by_path(FAR const void *fdt,
|
||||
FAR const char *path);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: fdt_device_is_available
|
||||
*
|
||||
* Description:
|
||||
* Test if node contains the "status" property with field set to okay or
|
||||
* ok.
|
||||
*
|
||||
* Input Parameters:
|
||||
* fdt - The pointer to the raw FDT.
|
||||
* offset - The offset to the node to query.
|
||||
*
|
||||
* Returned Value:
|
||||
* true: The node contains the status propertry, and is set to okay or
|
||||
* ok.
|
||||
* false: The node contains the status propertry, but it is set to
|
||||
* something other than ok or okay.
|
||||
* Always returns true if the node doesn't contain a status property.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
bool fdt_device_is_available(FAR const void * fdt, int offset);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: fdt_get_node_label
|
||||
*
|
||||
* Description:
|
||||
* Get the label for a given node. The device tree must be compiled with
|
||||
* the -@ option in order for the symbol table to be generated.
|
||||
*
|
||||
* Input Parameters:
|
||||
* fdt - The pointer to the raw FDT.
|
||||
* offset - The offset to the node to query.
|
||||
*
|
||||
* Returned Value:
|
||||
* Node label if found. NULL is returned if no label if found for the given
|
||||
* node.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
const char *fdt_get_node_label(FAR const void *fdt, int offset);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: fdt_get_clock_frequency
|
||||
*
|
||||
* Description:
|
||||
* Get the value of the "clock-frequency" value for the given node.
|
||||
*
|
||||
* Input Parameters:
|
||||
* fdt - The pointer to the raw FDT.
|
||||
* offset - The offset to the node to query.
|
||||
*
|
||||
* Returned Value:
|
||||
* The value of the clock-frequency property of the node. Zero is
|
||||
* returned if the node doesn't contain a clock-frequency property.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uintptr_t fdt_get_clock_frequency(FAR const void *fdt, int offset);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: fdt_get_clock_frequency_from_clocks
|
||||
*
|
||||
* Description:
|
||||
* Get the "clock-frequency" property for the given node, using the phandle
|
||||
* specified in the "clocks" property
|
||||
*
|
||||
* Input Parameters:
|
||||
* fdt - The pointer to the raw FDT.
|
||||
* node - The offset to the node to query.
|
||||
* offset - The offset of the phandle in the clocks property
|
||||
*
|
||||
* Returned Value:
|
||||
* The value of the clock-frequency property of the node, following the
|
||||
* specified phandle in the "clocks"' property. Returns 0 if:
|
||||
* - The node doesn't have a "clocks" property
|
||||
* - The offset given is larger than the length of the "clocks" property
|
||||
* - The phandle specified by the "clocks" property doesn't contain a
|
||||
* "clock-frequency" property.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uintptr_t fdt_get_clock_frequency_from_clocks(FAR const void *fdt,
|
||||
int offset,
|
||||
int index);
|
||||
|
||||
#endif /* __INCLUDE_NUTTX_FDT_H */
|
||||
|
|
Loading…
Reference in a new issue