return 0;
}
+/**
+ * Get region cell size specification
+ *
+ * @v fdt Device tree
+ * @v offset Starting (parent) node offset
+ * @v regs Region cell size specification to fill in
+ *
+ * Note that #address-cells and #size-cells are defined on the
+ * immediate parent node, rather than on the node with the "reg"
+ * property itself.
+ */
+void fdt_reg_cells ( struct fdt *fdt, unsigned int offset,
+ struct fdt_reg_cells *regs ) {
+ int rc;
+
+ /* Read #address-cells, if present */
+ if ( ( rc = fdt_u32 ( fdt, offset, "#address-cells",
+ ®s->address_cells ) ) != 0 ) {
+ regs->address_cells = FDT_DEFAULT_ADDRESS_CELLS;
+ }
+
+ /* Read #size-cells, if present */
+ if ( ( rc = fdt_u32 ( fdt, offset, "#size-cells",
+ ®s->size_cells ) ) != 0 ) {
+ regs->size_cells = FDT_DEFAULT_SIZE_CELLS;
+ }
+
+ /* Calculate stride */
+ regs->stride = ( regs->address_cells + regs->size_cells );
+}
+
+/**
+ * Get number of regions
+ *
+ * @v fdt Device tree
+ * @v offset Starting node offset
+ * @v regs Region cell size specification
+ * @ret count Number of regions, or negative error
+ */
+int fdt_reg_count ( struct fdt *fdt, unsigned int offset,
+ struct fdt_reg_cells *regs ) {
+ struct fdt_descriptor desc;
+ const uint32_t *cell;
+ unsigned int count;
+ int rc;
+
+ /* Find property */
+ if ( ( rc = fdt_property ( fdt, offset, "reg", &desc ) ) != 0 )
+ return rc;
+
+ /* Determine number of regions */
+ count = ( desc.len / ( regs->stride * sizeof ( *cell ) ) );
+ return count;
+}
+
+/**
+ * Get region address
+ *
+ * @v fdt Device tree
+ * @v offset Starting node offset
+ * @v regs Region cell size specification
+ * @v index Region index
+ * @v address Region starting address to fill in
+ * @ret rc Return status code
+ */
+int fdt_reg_address ( struct fdt *fdt, unsigned int offset,
+ struct fdt_reg_cells *regs, unsigned int index,
+ uint64_t *address ) {
+ unsigned int cell = ( index * regs->stride );
+ int rc;
+
+ /* Read relevant portion of region array */
+ if ( ( rc = fdt_cells ( fdt, offset, "reg", cell, regs->address_cells,
+ address ) ) != 0 ) {
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Get region size
+ *
+ * @v fdt Device tree
+ * @v offset Starting node offset
+ * @v regs Region cell size specification
+ * @v index Region index
+ * @v size Region size to fill in
+ * @ret rc Return status code
+ */
+int fdt_reg_size ( struct fdt *fdt, unsigned int offset,
+ struct fdt_reg_cells *regs, unsigned int index,
+ uint64_t *size ) {
+ unsigned int cell = ( ( index * regs->stride ) + regs->address_cells );
+ int rc;
+
+ /* Read relevant portion of region array */
+ if ( ( rc = fdt_cells ( fdt, offset, "reg", cell, regs->size_cells,
+ size ) ) != 0 ) {
+ return rc;
+ }
+
+ return 0;
+}
+
/**
* Get MAC address from property
*
unsigned int index, size_t len ) {
struct dt_device *parent =
container_of ( dt->dev.parent, struct dt_device, dev );
+ struct fdt_reg_cells *regs = &parent->regs;
uint64_t address;
uint64_t size;
- unsigned int cell;
void *io_addr;
int rc;
/* Read address */
- cell = ( index * ( parent->address_cells + parent->size_cells ) );
- if ( ( rc = fdt_cells ( &sysfdt, offset, "reg", cell,
- parent->address_cells, &address ) ) != 0 ) {
+ if ( ( rc = fdt_reg_address ( &sysfdt, offset, regs, index,
+ &address ) ) != 0 ) {
DBGC ( dt, "DT %s could not read region %d address: %s\n",
dt->path, index, strerror ( rc ) );
return NULL;
}
- cell += parent->address_cells;
/* Read size (or assume sufficient, if tree specifies no sizes) */
size = len;
- if ( parent->size_cells &&
- ( rc = fdt_cells ( &sysfdt, offset, "reg", cell,
- parent->size_cells, &size ) ) != 0 ) {
+ if ( regs->size_cells &&
+ ( ( rc = fdt_reg_size ( &sysfdt, offset, regs, index,
+ &size ) ) != 0 ) ) {
DBGC ( dt, "DT %s could not read region %d size: %s\n",
dt->path, index, strerror ( rc ) );
return NULL;
list_add_tail ( &dt->dev.siblings, &dt->dev.parent->children );
/* Read #address-cells and #size-cells, if present */
- if ( ( rc = fdt_u32 ( &sysfdt, offset, "#address-cells",
- &dt->address_cells ) ) != 0 ) {
- dt->address_cells = DT_DEFAULT_ADDRESS_CELLS;
- }
- if ( ( rc = fdt_u32 ( &sysfdt, offset, "#size-cells",
- &dt->size_cells ) ) != 0 ) {
- dt->size_cells = DT_DEFAULT_SIZE_CELLS;
- }
+ fdt_reg_cells ( &sysfdt, offset, &dt->regs );
/* Probe device */
if ( ( rc = dt_probe ( dt, offset ) ) != 0 )
#include <ipxe/device.h>
#include <ipxe/dma.h>
+#include <ipxe/fdt.h>
/** A devicetree device */
struct dt_device {
/** Driver-private data */
void *priv;
- /** Number of address cells for child devices */
- uint32_t address_cells;
- /** Number of size cells for child devices */
- uint32_t size_cells;
+ /** Register cell size specification */
+ struct fdt_reg_cells regs;
};
-/** Default number of address cells, if not specified */
-#define DT_DEFAULT_ADDRESS_CELLS 2
-
-/** Default number of size cells, if not specified */
-#define DT_DEFAULT_SIZE_CELLS 1
-
/** A devicetree driver */
struct dt_driver {
/** Driver name */
int depth;
};
+/** A device tree region cell size specification */
+struct fdt_reg_cells {
+ /** Number of address cells */
+ uint32_t address_cells;
+ /** Number of size cells */
+ uint32_t size_cells;
+ /** Number of address cells plus number of size cells */
+ unsigned int stride;
+};
+
+/** Default number of address cells, if not specified */
+#define FDT_DEFAULT_ADDRESS_CELLS 2
+
+/** Default number of size cells, if not specified */
+#define FDT_DEFAULT_SIZE_CELLS 1
+
extern struct image_tag fdt_image __image_tag;
extern struct fdt sysfdt;
uint64_t *value );
extern int fdt_u32 ( struct fdt *fdt, unsigned int offset, const char *name,
uint32_t *value );
+extern void fdt_reg_cells ( struct fdt *fdt, unsigned int offset,
+ struct fdt_reg_cells *regs );
+extern int fdt_reg_count ( struct fdt *fdt, unsigned int offset,
+ struct fdt_reg_cells *regs );
+extern int fdt_reg_address ( struct fdt *fdt, unsigned int offset,
+ struct fdt_reg_cells *regs, unsigned int index,
+ uint64_t *address );
+extern int fdt_reg_size ( struct fdt *fdt, unsigned int offset,
+ struct fdt_reg_cells *regs, unsigned int index,
+ uint64_t *size );
extern int fdt_mac ( struct fdt *fdt, unsigned int offset,
struct net_device *netdev );
extern int fdt_parse ( struct fdt *fdt, struct fdt_header *hdr,