diff options
| -rw-r--r-- | drivers/core/device.c | 17 | ||||
| -rw-r--r-- | drivers/core/simple-bus.c | 30 | ||||
| -rw-r--r-- | include/dm/device-internal.h | 12 | 
3 files changed, 53 insertions, 6 deletions
| diff --git a/drivers/core/device.c b/drivers/core/device.c index 51b1b44e5b0..d65717ddc7e 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -552,17 +552,22 @@ const char *dev_get_uclass_name(struct udevice *dev)  	return dev->uclass->uc_drv->name;  } -#ifdef CONFIG_OF_CONTROL  fdt_addr_t dev_get_addr(struct udevice *dev)  { -	return fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg"); -} +#ifdef CONFIG_OF_CONTROL +	fdt_addr_t addr; + +	addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg"); +	if (addr != FDT_ADDR_T_NONE) { +		if (device_get_uclass_id(dev->parent) == UCLASS_SIMPLE_BUS) +			addr = simple_bus_translate(dev->parent, addr); +	} + +	return addr;  #else -fdt_addr_t dev_get_addr(struct udevice *dev) -{  	return FDT_ADDR_T_NONE; -}  #endif +}  bool device_has_children(struct udevice *dev)  { diff --git a/drivers/core/simple-bus.c b/drivers/core/simple-bus.c index 3ea4d8230bd..913c3ccc70b 100644 --- a/drivers/core/simple-bus.c +++ b/drivers/core/simple-bus.c @@ -10,8 +10,37 @@  DECLARE_GLOBAL_DATA_PTR; +struct simple_bus_plat { +	u32 base; +	u32 size; +	u32 target; +}; + +fdt_addr_t simple_bus_translate(struct udevice *dev, fdt_addr_t addr) +{ +	struct simple_bus_plat *plat = dev_get_uclass_platdata(dev); + +	if (addr >= plat->base && addr < plat->base + plat->size) +		addr = (addr - plat->base) + plat->target; + +	return addr; +} +  static int simple_bus_post_bind(struct udevice *dev)  { +	u32 cell[3]; +	int ret; + +	ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "ranges", +				   cell, ARRAY_SIZE(cell)); +	if (!ret) { +		struct simple_bus_plat *plat = dev_get_uclass_platdata(dev); + +		plat->base = cell[0]; +		plat->target = cell[1]; +		plat->size = cell[2]; +	} +  	return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);  } @@ -19,6 +48,7 @@ UCLASS_DRIVER(simple_bus) = {  	.id		= UCLASS_SIMPLE_BUS,  	.name		= "simple_bus",  	.post_bind	= simple_bus_post_bind, +	.per_device_platdata_auto_alloc_size = sizeof(struct simple_bus_plat),  };  static const struct udevice_id generic_simple_bus_ids[] = { diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h index 402304f19ef..1a9ba01b3b8 100644 --- a/include/dm/device-internal.h +++ b/include/dm/device-internal.h @@ -139,6 +139,18 @@ void device_free(struct udevice *dev);  static inline void device_free(struct udevice *dev) {}  #endif +/** + * simple_bus_translate() - translate a bus address to a system address + * + * This handles the 'ranges' property in a simple bus. It translates the + * device address @addr to a system address using this property. + * + * @dev:	Simple bus device (parent of target device) + * @addr:	Address to translate + * @return new address + */ +fdt_addr_t simple_bus_translate(struct udevice *dev, fdt_addr_t addr); +  /* Cast away any volatile pointer */  #define DM_ROOT_NON_CONST		(((gd_t *)gd)->dm_root)  #define DM_UCLASS_ROOT_NON_CONST	(((gd_t *)gd)->uclass_root) | 
