* @ret rc Return status code
*/
static int fdt_enter ( struct fdt *fdt, unsigned int offset,
- struct fdt_descriptor *desc ) {
+ struct fdt_descriptor *desc ) {
int rc;
/* Find begin node token */
}
}
+/**
+ * Find node relative depth
+ *
+ * @v fdt Device tree
+ * @v offset Starting node offset
+ * @v target Target node offset
+ * @ret depth Depth, or negative error
+ */
+static int fdt_depth ( struct fdt *fdt, unsigned int offset,
+ unsigned int target ) {
+ struct fdt_descriptor desc;
+ int depth;
+ int rc;
+
+ /* Enter node */
+ if ( ( rc = fdt_enter ( fdt, offset, &desc ) ) != 0 )
+ return rc;
+
+ /* Find target node */
+ for ( depth = 0 ; depth >= 0 ; depth += desc.depth ) {
+
+ /* Describe token */
+ if ( ( rc = fdt_next ( fdt, &desc ) ) != 0 ) {
+ DBGC ( fdt, "FDT +%#04x has malformed node: %s\n",
+ offset, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Check for target node */
+ if ( desc.offset == target ) {
+ DBGC2 ( fdt, "FDT +%#04x has descendant node +%#04x "
+ "at depth +%d\n", offset, target, depth );
+ return depth;
+ }
+ }
+
+ DBGC ( fdt, "FDT +#%04x has no descendant node +%#04x\n",
+ offset, target );
+ return -ENOENT;
+}
+
+/**
+ * Find parent node
+ *
+ * @v fdt Device tree
+ * @v offset Starting node offset
+ * @v parent Parent node offset to fill in
+ * @ret rc Return status code
+ */
+int fdt_parent ( struct fdt *fdt, unsigned int offset, unsigned int *parent ) {
+ struct fdt_descriptor desc;
+ int pdepth;
+ int depth;
+ int rc;
+
+ /* Find depth from root of tree */
+ depth = fdt_depth ( fdt, 0, offset );
+ if ( depth < 0 ) {
+ rc = depth;
+ return rc;
+ }
+ pdepth = ( depth - 1 );
+
+ /* Enter root node */
+ if ( ( rc = fdt_enter ( fdt, 0, &desc ) ) != 0 )
+ return rc;
+ *parent = desc.offset;
+
+ /* Find parent node */
+ for ( depth = 0 ; depth >= 0 ; depth += desc.depth ) {
+
+ /* Describe token */
+ if ( ( rc = fdt_next ( fdt, &desc ) ) != 0 ) {
+ DBGC ( fdt, "FDT +%#04x has malformed node: %s\n",
+ offset, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Record possible parent node */
+ if ( ( depth == pdepth ) && desc.name && ( ! desc.data ) )
+ *parent = desc.offset;
+
+ /* Check for target node */
+ if ( desc.offset == offset ) {
+ DBGC2 ( fdt, "FDT +%#04x has parent node at +%#04x\n",
+ offset, *parent );
+ return 0;
+ }
+ }
+
+ DBGC ( fdt, "FDT +#%04x has no parent node\n", offset );
+ return -ENOENT;
+}
+
/**
* Find child node
*
ok ( strcmp ( desc.data, "memory" ) == 0 );
ok ( desc.depth == 0 );
+ /* Verify parent lookup */
+ ok ( fdt_path ( &fdt, "/soc/ethernet@10090000/ethernet-phy@0",
+ &offset ) == 0 );
+ ok ( fdt_parent ( &fdt, offset, &offset ) == 0 );
+ ok ( fdt_describe ( &fdt, offset, &desc ) == 0 );
+ ok ( strcmp ( desc.name, "ethernet@10090000" ) == 0 );
+ ok ( fdt_parent ( &fdt, offset, &offset ) == 0 );
+ ok ( fdt_describe ( &fdt, offset, &desc ) == 0 );
+ ok ( strcmp ( desc.name, "soc" ) == 0 );
+ ok ( fdt_parent ( &fdt, offset, &offset ) == 0 );
+ ok ( offset == 0 );
+
/* Verify device tree creation */
image = image_memory ( "test.dtb", sifive_u, sizeof ( sifive_u ) );
ok ( image != NULL );