diff mbox

[U-Boot] fdt: add new fdt address parsing functions

Message ID 1438896662-27510-1-git-send-email-swarren@wwwdotorg.org
State Accepted
Delegated to: Simon Glass
Headers show

Commit Message

Stephen Warren Aug. 6, 2015, 9:31 p.m. UTC
From: Stephen Warren <swarren@nvidia.com>

fdtdec_get_addr_size() hard-codes the number of cells used to represent
an address or size in DT. This is incorrect in many cases depending on
the DT binding for a particular node or property (e.g. it is incorrect
for the "reg" property). In most cases, DT parsing code must use the
properties #address-cells and #size-cells to parse addres properties.

This change splits up the implementation of fdtdec_get_addr_size() so
that the core logic can be used for both hard-coded and non-hard-coded
cases. Various wrapper functions are implemented that support cases
where hard-coded cell counts should or should not be used, and where
the client does and doesn't know the parent node ID that contains the
properties #address-cells and #size-cells.

dev_get_addr() is updated to use the new functions.

Core functionality in fdtdec_get_addr_size_fixed() is widely tested via
fdtdec_get_addr_size(). I tested fdtdec_get_addr_size_auto_noparent() and
dev_get_addr() by manually modifying the Tegra I2C driver to invoke them.

Much of the core implementation of fdtdec_get_addr_size_fixed(),
fdtdec_get_addr_size_auto_parent(), and
fdtdec_get_addr_size_auto_noparent() comes from Thierry Reding's
previous commit "fdt: Fix fdtdec_get_addr_size() for 64-bit".

Based-on-work-by: Thierry Reding <treding@nvidia.com>
Cc: Thierry Reding <treding@nvidia.com>
Cc: Simon Glass <sjg@chromium.org>
Cc: Michal Suchanek <hramrach@gmail.com>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
---
For patch context, this patch relies on Thierry's "fdt: Fix
fdtdec_get_addr_size() for 64-bit" having been reverted.
---
 drivers/core/device.c |   5 ++-
 include/fdtdec.h      | 111 +++++++++++++++++++++++++++++++++++++++++++----
 lib/fdtdec.c          | 116 +++++++++++++++++++++++++++++++++++++++++---------
 3 files changed, 202 insertions(+), 30 deletions(-)

Comments

Stephen Warren Aug. 6, 2015, 9:35 p.m. UTC | #1
On 08/06/2015 03:31 PM, Stephen Warren wrote:
> fdtdec_get_addr_size() hard-codes the number of cells used to represent
> an address or size in DT. This is incorrect in many cases depending on
> the DT binding for a particular node or property (e.g. it is incorrect
> for the "reg" property). In most cases, DT parsing code must use the
> properties #address-cells and #size-cells to parse addres properties.
>
> This change splits up the implementation of fdtdec_get_addr_size() so
> that the core logic can be used for both hard-coded and non-hard-coded
> cases. Various wrapper functions are implemented that support cases
> where hard-coded cell counts should or should not be used, and where
> the client does and doesn't know the parent node ID that contains the
> properties #address-cells and #size-cells.

> diff --git a/lib/fdtdec.c b/lib/fdtdec.c
> index 95b59b586ff0..3afec045e9bd 100644
> --- a/lib/fdtdec.c
> +++ b/lib/fdtdec.c
> @@ -1,3 +1,5 @@
> +#define DEBUG
> +
>   /*

Uggh. That part will of course have to be dropped, but I'll hold off 
resending in case there are any other comments.
Simon Glass Aug. 9, 2015, 3:07 p.m. UTC | #2
Hi Stephen,

On 6 August 2015 at 15:31, Stephen Warren <swarren@wwwdotorg.org> wrote:
> From: Stephen Warren <swarren@nvidia.com>
>
> fdtdec_get_addr_size() hard-codes the number of cells used to represent
> an address or size in DT. This is incorrect in many cases depending on
> the DT binding for a particular node or property (e.g. it is incorrect
> for the "reg" property). In most cases, DT parsing code must use the
> properties #address-cells and #size-cells to parse addres properties.
>
> This change splits up the implementation of fdtdec_get_addr_size() so
> that the core logic can be used for both hard-coded and non-hard-coded
> cases. Various wrapper functions are implemented that support cases
> where hard-coded cell counts should or should not be used, and where
> the client does and doesn't know the parent node ID that contains the
> properties #address-cells and #size-cells.
>
> dev_get_addr() is updated to use the new functions.
>
> Core functionality in fdtdec_get_addr_size_fixed() is widely tested via
> fdtdec_get_addr_size(). I tested fdtdec_get_addr_size_auto_noparent() and
> dev_get_addr() by manually modifying the Tegra I2C driver to invoke them.
>
> Much of the core implementation of fdtdec_get_addr_size_fixed(),
> fdtdec_get_addr_size_auto_parent(), and
> fdtdec_get_addr_size_auto_noparent() comes from Thierry Reding's
> previous commit "fdt: Fix fdtdec_get_addr_size() for 64-bit".
>
> Based-on-work-by: Thierry Reding <treding@nvidia.com>
> Cc: Thierry Reding <treding@nvidia.com>
> Cc: Simon Glass <sjg@chromium.org>
> Cc: Michal Suchanek <hramrach@gmail.com>
> Signed-off-by: Stephen Warren <swarren@nvidia.com>
> ---
> For patch context, this patch relies on Thierry's "fdt: Fix
> fdtdec_get_addr_size() for 64-bit" having been reverted.
> ---
>  drivers/core/device.c |   5 ++-
>  include/fdtdec.h      | 111 +++++++++++++++++++++++++++++++++++++++++++----
>  lib/fdtdec.c          | 116 +++++++++++++++++++++++++++++++++++++++++---------
>  3 files changed, 202 insertions(+), 30 deletions(-)

Acked-by: Simon Glass <sjg@chromium.org>

This looks perfect to me, and covers all cases. Thank you for resolving this.

Re SPL I'll be getting back to that before long and taking another
look at code size. If anything needs tweaking in dev_get_addr() I'll
send a patch then.

I'll wait to see if there are other comments and apply this to the fdt
tree early next week.

Regards,
Simon
Mugunthan V N Sept. 7, 2015, 8:22 a.m. UTC | #3
On Friday 07 August 2015 03:01 AM, Stephen Warren wrote:
> From: Stephen Warren <swarren@nvidia.com>
> 
> fdtdec_get_addr_size() hard-codes the number of cells used to represent
> an address or size in DT. This is incorrect in many cases depending on
> the DT binding for a particular node or property (e.g. it is incorrect
> for the "reg" property). In most cases, DT parsing code must use the
> properties #address-cells and #size-cells to parse addres properties.
> 
> This change splits up the implementation of fdtdec_get_addr_size() so
> that the core logic can be used for both hard-coded and non-hard-coded
> cases. Various wrapper functions are implemented that support cases
> where hard-coded cell counts should or should not be used, and where
> the client does and doesn't know the parent node ID that contains the
> properties #address-cells and #size-cells.
> 
> dev_get_addr() is updated to use the new functions.
> 
> Core functionality in fdtdec_get_addr_size_fixed() is widely tested via
> fdtdec_get_addr_size(). I tested fdtdec_get_addr_size_auto_noparent() and
> dev_get_addr() by manually modifying the Tegra I2C driver to invoke them.
> 
> Much of the core implementation of fdtdec_get_addr_size_fixed(),
> fdtdec_get_addr_size_auto_parent(), and
> fdtdec_get_addr_size_auto_noparent() comes from Thierry Reding's
> previous commit "fdt: Fix fdtdec_get_addr_size() for 64-bit".

Tested this patch for cpsw ethernet dt migration to getting cpsw address
space. Also dropped *#define DEBUG* in lib/fdtdev.c file.

Tested-by: Mugunthan V N <mugunthanvnm@ti.com>

Regards
Mugunthan V N
Simon Glass Sept. 9, 2015, 6:08 p.m. UTC | #4
Hi,

On Monday, 7 September 2015, Mugunthan V N <mugunthanvnm@ti.com> wrote:
>
> On Friday 07 August 2015 03:01 AM, Stephen Warren wrote:
> > From: Stephen Warren <swarren@nvidia.com>
> >
> > fdtdec_get_addr_size() hard-codes the number of cells used to represent
> > an address or size in DT. This is incorrect in many cases depending on
> > the DT binding for a particular node or property (e.g. it is incorrect
> > for the "reg" property). In most cases, DT parsing code must use the
> > properties #address-cells and #size-cells to parse addres properties.
> >
> > This change splits up the implementation of fdtdec_get_addr_size() so
> > that the core logic can be used for both hard-coded and non-hard-coded
> > cases. Various wrapper functions are implemented that support cases
> > where hard-coded cell counts should or should not be used, and where
> > the client does and doesn't know the parent node ID that contains the
> > properties #address-cells and #size-cells.
> >
> > dev_get_addr() is updated to use the new functions.
> >
> > Core functionality in fdtdec_get_addr_size_fixed() is widely tested via
> > fdtdec_get_addr_size(). I tested fdtdec_get_addr_size_auto_noparent() and
> > dev_get_addr() by manually modifying the Tegra I2C driver to invoke them.
> >
> > Much of the core implementation of fdtdec_get_addr_size_fixed(),
> > fdtdec_get_addr_size_auto_parent(), and
> > fdtdec_get_addr_size_auto_noparent() comes from Thierry Reding's
> > previous commit "fdt: Fix fdtdec_get_addr_size() for 64-bit".
>
> Tested this patch for cpsw ethernet dt migration to getting cpsw address
> space. Also dropped *#define DEBUG* in lib/fdtdev.c file.
>
> Tested-by: Mugunthan V N <mugunthanvnm@ti.com>
>
Thanks for testing this. I would like to apply this - are there any
other comments?

Regards,
Simon
Mugunthan V N Sept. 11, 2015, 10:54 a.m. UTC | #5
On Wednesday 09 September 2015 11:38 PM, Simon Glass wrote:
> Hi,
> 
> On Monday, 7 September 2015, Mugunthan V N <mugunthanvnm@ti.com> wrote:
>>
>> On Friday 07 August 2015 03:01 AM, Stephen Warren wrote:
>>> From: Stephen Warren <swarren@nvidia.com>
>>>
>>> fdtdec_get_addr_size() hard-codes the number of cells used to represent
>>> an address or size in DT. This is incorrect in many cases depending on
>>> the DT binding for a particular node or property (e.g. it is incorrect
>>> for the "reg" property). In most cases, DT parsing code must use the
>>> properties #address-cells and #size-cells to parse addres properties.
>>>
>>> This change splits up the implementation of fdtdec_get_addr_size() so
>>> that the core logic can be used for both hard-coded and non-hard-coded
>>> cases. Various wrapper functions are implemented that support cases
>>> where hard-coded cell counts should or should not be used, and where
>>> the client does and doesn't know the parent node ID that contains the
>>> properties #address-cells and #size-cells.
>>>
>>> dev_get_addr() is updated to use the new functions.
>>>
>>> Core functionality in fdtdec_get_addr_size_fixed() is widely tested via
>>> fdtdec_get_addr_size(). I tested fdtdec_get_addr_size_auto_noparent() and
>>> dev_get_addr() by manually modifying the Tegra I2C driver to invoke them.
>>>
>>> Much of the core implementation of fdtdec_get_addr_size_fixed(),
>>> fdtdec_get_addr_size_auto_parent(), and
>>> fdtdec_get_addr_size_auto_noparent() comes from Thierry Reding's
>>> previous commit "fdt: Fix fdtdec_get_addr_size() for 64-bit".
>>
>> Tested this patch for cpsw ethernet dt migration to getting cpsw address
>> space. Also dropped *#define DEBUG* in lib/fdtdev.c file.
>>
>> Tested-by: Mugunthan V N <mugunthanvnm@ti.com>
>>
> Thanks for testing this. I would like to apply this - are there any
> other comments?
> 

There is no other comments apart from removing #define DEBUG

Regards
Mugunthan V N
Mugunthan V N Sept. 15, 2015, 7:55 a.m. UTC | #6
On Friday 11 September 2015 04:24 PM, Mugunthan V N wrote:
> On Wednesday 09 September 2015 11:38 PM, Simon Glass wrote:
>> Hi,
>>
>> On Monday, 7 September 2015, Mugunthan V N <mugunthanvnm@ti.com> wrote:
>>>
>>> On Friday 07 August 2015 03:01 AM, Stephen Warren wrote:
>>>> From: Stephen Warren <swarren@nvidia.com>
>>>>
>>>> fdtdec_get_addr_size() hard-codes the number of cells used to represent
>>>> an address or size in DT. This is incorrect in many cases depending on
>>>> the DT binding for a particular node or property (e.g. it is incorrect
>>>> for the "reg" property). In most cases, DT parsing code must use the
>>>> properties #address-cells and #size-cells to parse addres properties.
>>>>
>>>> This change splits up the implementation of fdtdec_get_addr_size() so
>>>> that the core logic can be used for both hard-coded and non-hard-coded
>>>> cases. Various wrapper functions are implemented that support cases
>>>> where hard-coded cell counts should or should not be used, and where
>>>> the client does and doesn't know the parent node ID that contains the
>>>> properties #address-cells and #size-cells.
>>>>
>>>> dev_get_addr() is updated to use the new functions.
>>>>
>>>> Core functionality in fdtdec_get_addr_size_fixed() is widely tested via
>>>> fdtdec_get_addr_size(). I tested fdtdec_get_addr_size_auto_noparent() and
>>>> dev_get_addr() by manually modifying the Tegra I2C driver to invoke them.
>>>>
>>>> Much of the core implementation of fdtdec_get_addr_size_fixed(),
>>>> fdtdec_get_addr_size_auto_parent(), and
>>>> fdtdec_get_addr_size_auto_noparent() comes from Thierry Reding's
>>>> previous commit "fdt: Fix fdtdec_get_addr_size() for 64-bit".
>>>
>>> Tested this patch for cpsw ethernet dt migration to getting cpsw address
>>> space. Also dropped *#define DEBUG* in lib/fdtdev.c file.
>>>
>>> Tested-by: Mugunthan V N <mugunthanvnm@ti.com>
>>>
>> Thanks for testing this. I would like to apply this - are there any
>> other comments?
>>
> 
> There is no other comments apart from removing #define DEBUG
> 

Simon

Are you applying this patch?

Regards
Mugunthan V N
Simon Glass Sept. 15, 2015, 7:17 p.m. UTC | #7
On 15 September 2015 at 01:55, Mugunthan V N <mugunthanvnm@ti.com> wrote:
> On Friday 11 September 2015 04:24 PM, Mugunthan V N wrote:
>> On Wednesday 09 September 2015 11:38 PM, Simon Glass wrote:
>>> Hi,
>>>
>>> On Monday, 7 September 2015, Mugunthan V N <mugunthanvnm@ti.com> wrote:
>>>>
>>>> On Friday 07 August 2015 03:01 AM, Stephen Warren wrote:
>>>>> From: Stephen Warren <swarren@nvidia.com>
>>>>>
>>>>> fdtdec_get_addr_size() hard-codes the number of cells used to represent
>>>>> an address or size in DT. This is incorrect in many cases depending on
>>>>> the DT binding for a particular node or property (e.g. it is incorrect
>>>>> for the "reg" property). In most cases, DT parsing code must use the
>>>>> properties #address-cells and #size-cells to parse addres properties.
>>>>>
>>>>> This change splits up the implementation of fdtdec_get_addr_size() so
>>>>> that the core logic can be used for both hard-coded and non-hard-coded
>>>>> cases. Various wrapper functions are implemented that support cases
>>>>> where hard-coded cell counts should or should not be used, and where
>>>>> the client does and doesn't know the parent node ID that contains the
>>>>> properties #address-cells and #size-cells.
>>>>>
>>>>> dev_get_addr() is updated to use the new functions.
>>>>>
>>>>> Core functionality in fdtdec_get_addr_size_fixed() is widely tested via
>>>>> fdtdec_get_addr_size(). I tested fdtdec_get_addr_size_auto_noparent() and
>>>>> dev_get_addr() by manually modifying the Tegra I2C driver to invoke them.
>>>>>
>>>>> Much of the core implementation of fdtdec_get_addr_size_fixed(),
>>>>> fdtdec_get_addr_size_auto_parent(), and
>>>>> fdtdec_get_addr_size_auto_noparent() comes from Thierry Reding's
>>>>> previous commit "fdt: Fix fdtdec_get_addr_size() for 64-bit".
>>>>
>>>> Tested this patch for cpsw ethernet dt migration to getting cpsw address
>>>> space. Also dropped *#define DEBUG* in lib/fdtdev.c file.
>>>>
>>>> Tested-by: Mugunthan V N <mugunthanvnm@ti.com>
>>>>
>>> Thanks for testing this. I would like to apply this - are there any
>>> other comments?
>>>
>>
>> There is no other comments apart from removing #define DEBUG
>>
>
> Simon
>
> Are you applying this patch?

Applied to u-boot-fdt.
diff mbox

Patch

diff --git a/drivers/core/device.c b/drivers/core/device.c
index 51b1b44e5b0a..917dd85551d3 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -555,7 +555,10 @@  const char *dev_get_uclass_name(struct udevice *dev)
 #ifdef CONFIG_OF_CONTROL
 fdt_addr_t dev_get_addr(struct udevice *dev)
 {
-	return fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
+	return fdtdec_get_addr_size_auto_parent(gd->fdt_blob,
+						dev->parent->of_offset,
+						dev->of_offset, "reg",
+						0, NULL);
 }
 #else
 fdt_addr_t dev_get_addr(struct udevice *dev)
diff --git a/include/fdtdec.h b/include/fdtdec.h
index 4b3f8d13c356..04fe16bf15d2 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -308,10 +308,90 @@  int fdtdec_next_compatible(const void *blob, int node,
 int fdtdec_next_compatible_subnode(const void *blob, int node,
 		enum fdt_compat_id id, int *depthp);
 
-/**
- * Look up an address property in a node and return it as an address.
- * The property must hold either one address with no trailing data or
- * one address with a length. This is only tested on 32-bit machines.
+/*
+ * Look up an address property in a node and return the parsed address, and
+ * optionally the parsed size.
+ *
+ * This variant assumes a known and fixed number of cells are used to
+ * represent the address and size.
+ *
+ * You probably don't want to use this function directly except to parse
+ * non-standard properties, and never to parse the "reg" property. Instead,
+ * use one of the "auto" variants below, which automatically honor the
+ * #address-cells and #size-cells properties in the parent node.
+ *
+ * @param blob	FDT blob
+ * @param node	node to examine
+ * @param prop_name	name of property to find
+ * @param index	which address to retrieve from a list of addresses. Often 0.
+ * @param na	the number of cells used to represent an address
+ * @param ns	the number of cells used to represent a size
+ * @param sizep	a pointer to store the size into. Use NULL if not required
+ * @return address, if found, or FDT_ADDR_T_NONE if not
+ */
+fdt_addr_t fdtdec_get_addr_size_fixed(const void *blob, int node,
+		const char *prop_name, int index, int na, int ns,
+		fdt_size_t *sizep);
+
+/*
+ * Look up an address property in a node and return the parsed address, and
+ * optionally the parsed size.
+ *
+ * This variant automatically determines the number of cells used to represent
+ * the address and size by parsing the provided parent node's #address-cells
+ * and #size-cells properties.
+ *
+ * @param blob	FDT blob
+ * @param parent	parent node of @node
+ * @param node	node to examine
+ * @param prop_name	name of property to find
+ * @param index	which address to retrieve from a list of addresses. Often 0.
+ * @param sizep	a pointer to store the size into. Use NULL if not required
+ * @return address, if found, or FDT_ADDR_T_NONE if not
+ */
+fdt_addr_t fdtdec_get_addr_size_auto_parent(const void *blob, int parent,
+		int node, const char *prop_name, int index, fdt_size_t *sizep);
+
+/*
+ * Look up an address property in a node and return the parsed address, and
+ * optionally the parsed size.
+ *
+ * This variant automatically determines the number of cells used to represent
+ * the address and size by parsing the parent node's #address-cells
+ * and #size-cells properties. The parent node is automatically found.
+ *
+ * The automatic parent lookup implemented by this function is slow.
+ * Consequently, fdtdec_get_addr_size_auto_parent() should be used where
+ * possible.
+ *
+ * @param blob	FDT blob
+ * @param parent	parent node of @node
+ * @param node	node to examine
+ * @param prop_name	name of property to find
+ * @param index	which address to retrieve from a list of addresses. Often 0.
+ * @param sizep	a pointer to store the size into. Use NULL if not required
+ * @return address, if found, or FDT_ADDR_T_NONE if not
+ */
+fdt_addr_t fdtdec_get_addr_size_auto_noparent(const void *blob, int node,
+		const char *prop_name, int index, fdt_size_t *sizep);
+
+/*
+ * Look up an address property in a node and return the parsed address.
+ *
+ * This variant hard-codes the number of cells used to represent the address
+ * and size based on sizeof(fdt_addr_t) and sizeof(fdt_size_t). It also
+ * always returns the first address value in the property (index 0).
+ *
+ * Use of this function is not recommended due to the hard-coding of cell
+ * counts. There is no programmatic validation that these hard-coded values
+ * actually match the device tree content in any way at all. This assumption
+ * can be satisfied by manually ensuring CONFIG_PHYS_64BIT is appropriately
+ * set in the U-Boot build and exercising strict control over DT content to
+ * ensure use of matching #address-cells/#size-cells properties. However, this
+ * approach is error-prone; those familiar with DT will not expect the
+ * assumption to exist, and could easily invalidate it. If the assumption is
+ * invalidated, this function will not report the issue, and debugging will
+ * be required. Instead, use fdtdec_get_addr_size_auto_parent().
  *
  * @param blob	FDT blob
  * @param node	node to examine
@@ -321,14 +401,29 @@  int fdtdec_next_compatible_subnode(const void *blob, int node,
 fdt_addr_t fdtdec_get_addr(const void *blob, int node,
 		const char *prop_name);
 
-/**
- * Look up an address property in a node and return it as an address.
- * The property must hold one address with a length. This is only tested
- * on 32-bit machines.
+/*
+ * Look up an address property in a node and return the parsed address, and
+ * optionally the parsed size.
+ *
+ * This variant hard-codes the number of cells used to represent the address
+ * and size based on sizeof(fdt_addr_t) and sizeof(fdt_size_t). It also
+ * always returns the first address value in the property (index 0).
+ *
+ * Use of this function is not recommended due to the hard-coding of cell
+ * counts. There is no programmatic validation that these hard-coded values
+ * actually match the device tree content in any way at all. This assumption
+ * can be satisfied by manually ensuring CONFIG_PHYS_64BIT is appropriately
+ * set in the U-Boot build and exercising strict control over DT content to
+ * ensure use of matching #address-cells/#size-cells properties. However, this
+ * approach is error-prone; those familiar with DT will not expect the
+ * assumption to exist, and could easily invalidate it. If the assumption is
+ * invalidated, this function will not report the issue, and debugging will
+ * be required. Instead, use fdtdec_get_addr_size_auto_parent().
  *
  * @param blob	FDT blob
  * @param node	node to examine
  * @param prop_name	name of property to find
+ * @param sizep	a pointer to store the size into. Use NULL if not required
  * @return address, if found, or FDT_ADDR_T_NONE if not
  */
 fdt_addr_t fdtdec_get_addr_size(const void *blob, int node,
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 95b59b586ff0..3afec045e9bd 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -1,3 +1,5 @@ 
+#define DEBUG
+
 /*
  * Copyright (c) 2011 The Chromium OS Authors.
  * SPDX-License-Identifier:	GPL-2.0+
@@ -87,32 +89,104 @@  const char *fdtdec_get_compatible(enum fdt_compat_id id)
 	return compat_names[id];
 }
 
-fdt_addr_t fdtdec_get_addr_size(const void *blob, int node,
-		const char *prop_name, fdt_size_t *sizep)
+fdt_addr_t fdtdec_get_addr_size_fixed(const void *blob, int node,
+		const char *prop_name, int index, int na, int ns,
+		fdt_size_t *sizep)
 {
-	const fdt_addr_t *cell;
+	const fdt32_t *prop, *prop_end;
+	const fdt32_t *prop_addr, *prop_size, *prop_after_size;
 	int len;
+	fdt_addr_t addr;
 
 	debug("%s: %s: ", __func__, prop_name);
-	cell = fdt_getprop(blob, node, prop_name, &len);
-	if (cell && ((!sizep && len == sizeof(fdt_addr_t)) ||
-		     len == sizeof(fdt_addr_t) * 2)) {
-		fdt_addr_t addr = fdt_addr_to_cpu(*cell);
-		if (sizep) {
-			const fdt_size_t *size;
-
-			size = (fdt_size_t *)((char *)cell +
-					sizeof(fdt_addr_t));
-			*sizep = fdt_size_to_cpu(*size);
-			debug("addr=%08lx, size=%llx\n",
-			      (ulong)addr, (u64)*sizep);
-		} else {
-			debug("%08lx\n", (ulong)addr);
-		}
-		return addr;
+
+	if (na > (sizeof(fdt_addr_t) / sizeof(fdt32_t))) {
+		debug("(na too large for fdt_addr_t type)\n");
+		return FDT_ADDR_T_NONE;
 	}
-	debug("(not found)\n");
-	return FDT_ADDR_T_NONE;
+
+	if (ns > (sizeof(fdt_size_t) / sizeof(fdt32_t))) {
+		debug("(ns too large for fdt_size_t type)\n");
+		return FDT_ADDR_T_NONE;
+	}
+
+	prop = fdt_getprop(blob, node, prop_name, &len);
+	if (!prop) {
+		debug("(not found)\n");
+		return FDT_ADDR_T_NONE;
+	}
+	prop_end = prop + (len / sizeof(*prop));
+
+	prop_addr = prop + (index * (na + ns));
+	prop_size = prop_addr + na;
+	prop_after_size = prop_size + ns;
+	if (prop_after_size > prop_end) {
+		debug("(not enough data: expected >= %d cells, got %d cells)\n",
+		      (u32)(prop_after_size - prop), ((u32)(prop_end - prop)));
+		return FDT_ADDR_T_NONE;
+	}
+
+	addr = fdtdec_get_number(prop_addr, na);
+
+	if (sizep) {
+		*sizep = fdtdec_get_number(prop_size, ns);
+		debug("addr=%08llx, size=%llx\n", (u64)addr, (u64)*sizep);
+	} else {
+		debug("addr=%08llx\n", (u64)addr);
+	}
+
+	return addr;
+}
+
+fdt_addr_t fdtdec_get_addr_size_auto_parent(const void *blob, int parent,
+		int node, const char *prop_name, int index, fdt_size_t *sizep)
+{
+	int na, ns;
+
+	debug("%s: ", __func__);
+
+	na = fdt_address_cells(blob, parent);
+	if (na < 1) {
+		debug("(bad #address-cells)\n");
+		return FDT_ADDR_T_NONE;
+	}
+
+	ns = fdt_size_cells(blob, parent);
+	if (ns < 1) {
+		debug("(bad #size-cells)\n");
+		return FDT_ADDR_T_NONE;
+	}
+
+	debug("na=%d, ns=%d, ", na, ns);
+
+	return fdtdec_get_addr_size_fixed(blob, node, prop_name, index, na,
+					  ns, sizep);
+}
+
+fdt_addr_t fdtdec_get_addr_size_auto_noparent(const void *blob, int node,
+		const char *prop_name, int index, fdt_size_t *sizep)
+{
+	int parent;
+
+	debug("%s: ", __func__);
+
+	parent = fdt_parent_offset(blob, node);
+	if (parent < 0) {
+		debug("(no parent found)\n");
+		return FDT_ADDR_T_NONE;
+	}
+
+	return fdtdec_get_addr_size_auto_parent(blob, parent, node, prop_name,
+						index, sizep);
+}
+
+fdt_addr_t fdtdec_get_addr_size(const void *blob, int node,
+		const char *prop_name, fdt_size_t *sizep)
+{
+	return fdtdec_get_addr_size_fixed(blob, node, prop_name, 0,
+					  sizeof(fdt_addr_t) / sizeof(fdt32_t),
+					  sizeof(fdt_size_t) / sizeof(fdt32_t),
+					  sizep);
 }
 
 fdt_addr_t fdtdec_get_addr(const void *blob, int node,