| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 | // SPDX-License-Identifier: GPL-2.0+/* * Device addresses * * Copyright (c) 2017 Google, Inc * * (C) Copyright 2012 * Pavel Herrmann <morpheus.ibis@gmail.com> */#include <common.h>#include <dm.h>#include <fdt_support.h>#include <asm/io.h>#include <dm/device-internal.h>DECLARE_GLOBAL_DATA_PTR;fdt_addr_t devfdt_get_addr_index(struct udevice *dev, int index){#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)	fdt_addr_t addr;	if (CONFIG_IS_ENABLED(OF_TRANSLATE)) {		const fdt32_t *reg;		int len = 0;		int na, ns;		na = fdt_address_cells(gd->fdt_blob,				       dev_of_offset(dev->parent));		if (na < 1) {			debug("bad #address-cells\n");			return FDT_ADDR_T_NONE;		}		ns = fdt_size_cells(gd->fdt_blob, dev_of_offset(dev->parent));		if (ns < 0) {			debug("bad #size-cells\n");			return FDT_ADDR_T_NONE;		}		reg = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "reg",				  &len);		if (!reg || (len <= (index * sizeof(fdt32_t) * (na + ns)))) {			debug("Req index out of range\n");			return FDT_ADDR_T_NONE;		}		reg += index * (na + ns);		if (ns) {			/*			 * Use the full-fledged translate function for complex			 * bus setups.			 */			addr = fdt_translate_address((void *)gd->fdt_blob,						     dev_of_offset(dev), reg);		} else {			/* Non translatable if #size-cells == 0 */			addr = fdt_read_number(reg, na);		}	} else {		/*		 * Use the "simple" translate function for less complex		 * bus setups.		 */		addr = fdtdec_get_addr_size_auto_parent(gd->fdt_blob,				dev_of_offset(dev->parent), dev_of_offset(dev),				"reg", index, NULL, false);		if (CONFIG_IS_ENABLED(SIMPLE_BUS) && addr != FDT_ADDR_T_NONE) {			if (device_get_uclass_id(dev->parent) ==			    UCLASS_SIMPLE_BUS)				addr = simple_bus_translate(dev->parent, addr);		}	}	/*	 * Some platforms need a special address translation. Those	 * platforms (e.g. mvebu in SPL) can configure a translation	 * offset in the DM by calling dm_set_translation_offset() that	 * will get added to all addresses returned by devfdt_get_addr().	 */	addr += dm_get_translation_offset();	return addr;#else	return FDT_ADDR_T_NONE;#endif}fdt_addr_t devfdt_get_addr_size_index(struct udevice *dev, int index,				   fdt_size_t *size){#if CONFIG_IS_ENABLED(OF_CONTROL)	/*	 * Only get the size in this first call. We'll get the addr in the	 * next call to the exisiting dev_get_xxx function which handles	 * all config options.	 */	fdtdec_get_addr_size_auto_noparent(gd->fdt_blob, dev_of_offset(dev),					   "reg", index, size, false);	/*	 * Get the base address via the existing function which handles	 * all Kconfig cases	 */	return devfdt_get_addr_index(dev, index);#else	return FDT_ADDR_T_NONE;#endif}fdt_addr_t devfdt_get_addr_name(struct udevice *dev, const char *name){#if CONFIG_IS_ENABLED(OF_CONTROL)	int index;	index = fdt_stringlist_search(gd->fdt_blob, dev_of_offset(dev),				      "reg-names", name);	if (index < 0)		return index;	return devfdt_get_addr_index(dev, index);#else	return FDT_ADDR_T_NONE;#endif}fdt_addr_t devfdt_get_addr(struct udevice *dev){	return devfdt_get_addr_index(dev, 0);}void *devfdt_get_addr_ptr(struct udevice *dev){	return (void *)(uintptr_t)devfdt_get_addr_index(dev, 0);}void *devfdt_remap_addr_index(struct udevice *dev, int index){	fdt_addr_t addr = devfdt_get_addr(dev);	if (addr == FDT_ADDR_T_NONE)		return NULL;	return map_physmem(addr, 0, MAP_NOCACHE);}void *devfdt_remap_addr(struct udevice *dev){	return devfdt_remap_addr_index(dev, 0);}void *devfdt_map_physmem(struct udevice *dev, unsigned long size){	fdt_addr_t addr = devfdt_get_addr(dev);	if (addr == FDT_ADDR_T_NONE)		return NULL;	return map_physmem(addr, size, MAP_NOCACHE);}
 |