xref: /kernel/linux/linux-6.6/drivers/of/address.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#define pr_fmt(fmt)	"OF: " fmt
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/device.h>
562306a36Sopenharmony_ci#include <linux/fwnode.h>
662306a36Sopenharmony_ci#include <linux/io.h>
762306a36Sopenharmony_ci#include <linux/ioport.h>
862306a36Sopenharmony_ci#include <linux/logic_pio.h>
962306a36Sopenharmony_ci#include <linux/module.h>
1062306a36Sopenharmony_ci#include <linux/of_address.h>
1162306a36Sopenharmony_ci#include <linux/pci.h>
1262306a36Sopenharmony_ci#include <linux/pci_regs.h>
1362306a36Sopenharmony_ci#include <linux/sizes.h>
1462306a36Sopenharmony_ci#include <linux/slab.h>
1562306a36Sopenharmony_ci#include <linux/string.h>
1662306a36Sopenharmony_ci#include <linux/dma-direct.h> /* for bus_dma_region */
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include "of_private.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/* Max address size we deal with */
2162306a36Sopenharmony_ci#define OF_MAX_ADDR_CELLS	4
2262306a36Sopenharmony_ci#define OF_CHECK_ADDR_COUNT(na)	((na) > 0 && (na) <= OF_MAX_ADDR_CELLS)
2362306a36Sopenharmony_ci#define OF_CHECK_COUNTS(na, ns)	(OF_CHECK_ADDR_COUNT(na) && (ns) > 0)
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/* Debug utility */
2662306a36Sopenharmony_ci#ifdef DEBUG
2762306a36Sopenharmony_cistatic void of_dump_addr(const char *s, const __be32 *addr, int na)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	pr_debug("%s", s);
3062306a36Sopenharmony_ci	while (na--)
3162306a36Sopenharmony_ci		pr_cont(" %08x", be32_to_cpu(*(addr++)));
3262306a36Sopenharmony_ci	pr_cont("\n");
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci#else
3562306a36Sopenharmony_cistatic void of_dump_addr(const char *s, const __be32 *addr, int na) { }
3662306a36Sopenharmony_ci#endif
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci/* Callbacks for bus specific translators */
3962306a36Sopenharmony_cistruct of_bus {
4062306a36Sopenharmony_ci	const char	*name;
4162306a36Sopenharmony_ci	const char	*addresses;
4262306a36Sopenharmony_ci	int		(*match)(struct device_node *parent);
4362306a36Sopenharmony_ci	void		(*count_cells)(struct device_node *child,
4462306a36Sopenharmony_ci				       int *addrc, int *sizec);
4562306a36Sopenharmony_ci	u64		(*map)(__be32 *addr, const __be32 *range,
4662306a36Sopenharmony_ci				int na, int ns, int pna);
4762306a36Sopenharmony_ci	int		(*translate)(__be32 *addr, u64 offset, int na);
4862306a36Sopenharmony_ci	bool	has_flags;
4962306a36Sopenharmony_ci	unsigned int	(*get_flags)(const __be32 *addr);
5062306a36Sopenharmony_ci};
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci/*
5362306a36Sopenharmony_ci * Default translator (generic bus)
5462306a36Sopenharmony_ci */
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic void of_bus_default_count_cells(struct device_node *dev,
5762306a36Sopenharmony_ci				       int *addrc, int *sizec)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	if (addrc)
6062306a36Sopenharmony_ci		*addrc = of_n_addr_cells(dev);
6162306a36Sopenharmony_ci	if (sizec)
6262306a36Sopenharmony_ci		*sizec = of_n_size_cells(dev);
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic u64 of_bus_default_map(__be32 *addr, const __be32 *range,
6662306a36Sopenharmony_ci		int na, int ns, int pna)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	u64 cp, s, da;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	cp = of_read_number(range, na);
7162306a36Sopenharmony_ci	s  = of_read_number(range + na + pna, ns);
7262306a36Sopenharmony_ci	da = of_read_number(addr, na);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	pr_debug("default map, cp=%llx, s=%llx, da=%llx\n", cp, s, da);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	if (da < cp || da >= (cp + s))
7762306a36Sopenharmony_ci		return OF_BAD_ADDR;
7862306a36Sopenharmony_ci	return da - cp;
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic int of_bus_default_translate(__be32 *addr, u64 offset, int na)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	u64 a = of_read_number(addr, na);
8462306a36Sopenharmony_ci	memset(addr, 0, na * 4);
8562306a36Sopenharmony_ci	a += offset;
8662306a36Sopenharmony_ci	if (na > 1)
8762306a36Sopenharmony_ci		addr[na - 2] = cpu_to_be32(a >> 32);
8862306a36Sopenharmony_ci	addr[na - 1] = cpu_to_be32(a & 0xffffffffu);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	return 0;
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic unsigned int of_bus_default_flags_get_flags(const __be32 *addr)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	return of_read_number(addr, 1);
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic unsigned int of_bus_default_get_flags(const __be32 *addr)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	return IORESOURCE_MEM;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic u64 of_bus_default_flags_map(__be32 *addr, const __be32 *range, int na,
10462306a36Sopenharmony_ci				    int ns, int pna)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	u64 cp, s, da;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	/* Check that flags match */
10962306a36Sopenharmony_ci	if (*addr != *range)
11062306a36Sopenharmony_ci		return OF_BAD_ADDR;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	/* Read address values, skipping high cell */
11362306a36Sopenharmony_ci	cp = of_read_number(range + 1, na - 1);
11462306a36Sopenharmony_ci	s  = of_read_number(range + na + pna, ns);
11562306a36Sopenharmony_ci	da = of_read_number(addr + 1, na - 1);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	pr_debug("default flags map, cp=%llx, s=%llx, da=%llx\n", cp, s, da);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	if (da < cp || da >= (cp + s))
12062306a36Sopenharmony_ci		return OF_BAD_ADDR;
12162306a36Sopenharmony_ci	return da - cp;
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic int of_bus_default_flags_translate(__be32 *addr, u64 offset, int na)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	/* Keep "flags" part (high cell) in translated address */
12762306a36Sopenharmony_ci	return of_bus_default_translate(addr + 1, offset, na - 1);
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci#ifdef CONFIG_PCI
13162306a36Sopenharmony_cistatic unsigned int of_bus_pci_get_flags(const __be32 *addr)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	unsigned int flags = 0;
13462306a36Sopenharmony_ci	u32 w = be32_to_cpup(addr);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	if (!IS_ENABLED(CONFIG_PCI))
13762306a36Sopenharmony_ci		return 0;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	switch((w >> 24) & 0x03) {
14062306a36Sopenharmony_ci	case 0x01:
14162306a36Sopenharmony_ci		flags |= IORESOURCE_IO;
14262306a36Sopenharmony_ci		break;
14362306a36Sopenharmony_ci	case 0x02: /* 32 bits */
14462306a36Sopenharmony_ci		flags |= IORESOURCE_MEM;
14562306a36Sopenharmony_ci		break;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	case 0x03: /* 64 bits */
14862306a36Sopenharmony_ci		flags |= IORESOURCE_MEM | IORESOURCE_MEM_64;
14962306a36Sopenharmony_ci		break;
15062306a36Sopenharmony_ci	}
15162306a36Sopenharmony_ci	if (w & 0x40000000)
15262306a36Sopenharmony_ci		flags |= IORESOURCE_PREFETCH;
15362306a36Sopenharmony_ci	return flags;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci/*
15762306a36Sopenharmony_ci * PCI bus specific translator
15862306a36Sopenharmony_ci */
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic bool of_node_is_pcie(struct device_node *np)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	bool is_pcie = of_node_name_eq(np, "pcie");
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	if (is_pcie)
16562306a36Sopenharmony_ci		pr_warn_once("%pOF: Missing device_type\n", np);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	return is_pcie;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic int of_bus_pci_match(struct device_node *np)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	/*
17362306a36Sopenharmony_ci 	 * "pciex" is PCI Express
17462306a36Sopenharmony_ci	 * "vci" is for the /chaos bridge on 1st-gen PCI powermacs
17562306a36Sopenharmony_ci	 * "ht" is hypertransport
17662306a36Sopenharmony_ci	 *
17762306a36Sopenharmony_ci	 * If none of the device_type match, and that the node name is
17862306a36Sopenharmony_ci	 * "pcie", accept the device as PCI (with a warning).
17962306a36Sopenharmony_ci	 */
18062306a36Sopenharmony_ci	return of_node_is_type(np, "pci") || of_node_is_type(np, "pciex") ||
18162306a36Sopenharmony_ci		of_node_is_type(np, "vci") || of_node_is_type(np, "ht") ||
18262306a36Sopenharmony_ci		of_node_is_pcie(np);
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic void of_bus_pci_count_cells(struct device_node *np,
18662306a36Sopenharmony_ci				   int *addrc, int *sizec)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	if (addrc)
18962306a36Sopenharmony_ci		*addrc = 3;
19062306a36Sopenharmony_ci	if (sizec)
19162306a36Sopenharmony_ci		*sizec = 2;
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cistatic u64 of_bus_pci_map(__be32 *addr, const __be32 *range, int na, int ns,
19562306a36Sopenharmony_ci		int pna)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	u64 cp, s, da;
19862306a36Sopenharmony_ci	unsigned int af, rf;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	af = of_bus_pci_get_flags(addr);
20162306a36Sopenharmony_ci	rf = of_bus_pci_get_flags(range);
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	/* Check address type match */
20462306a36Sopenharmony_ci	if ((af ^ rf) & (IORESOURCE_MEM | IORESOURCE_IO))
20562306a36Sopenharmony_ci		return OF_BAD_ADDR;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	/* Read address values, skipping high cell */
20862306a36Sopenharmony_ci	cp = of_read_number(range + 1, na - 1);
20962306a36Sopenharmony_ci	s  = of_read_number(range + na + pna, ns);
21062306a36Sopenharmony_ci	da = of_read_number(addr + 1, na - 1);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	pr_debug("PCI map, cp=%llx, s=%llx, da=%llx\n", cp, s, da);
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	if (da < cp || da >= (cp + s))
21562306a36Sopenharmony_ci		return OF_BAD_ADDR;
21662306a36Sopenharmony_ci	return da - cp;
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic int of_bus_pci_translate(__be32 *addr, u64 offset, int na)
22062306a36Sopenharmony_ci{
22162306a36Sopenharmony_ci	return of_bus_default_translate(addr + 1, offset, na - 1);
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ci#endif /* CONFIG_PCI */
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci/*
22662306a36Sopenharmony_ci * of_pci_range_to_resource - Create a resource from an of_pci_range
22762306a36Sopenharmony_ci * @range:	the PCI range that describes the resource
22862306a36Sopenharmony_ci * @np:		device node where the range belongs to
22962306a36Sopenharmony_ci * @res:	pointer to a valid resource that will be updated to
23062306a36Sopenharmony_ci *              reflect the values contained in the range.
23162306a36Sopenharmony_ci *
23262306a36Sopenharmony_ci * Returns -EINVAL if the range cannot be converted to resource.
23362306a36Sopenharmony_ci *
23462306a36Sopenharmony_ci * Note that if the range is an IO range, the resource will be converted
23562306a36Sopenharmony_ci * using pci_address_to_pio() which can fail if it is called too early or
23662306a36Sopenharmony_ci * if the range cannot be matched to any host bridge IO space (our case here).
23762306a36Sopenharmony_ci * To guard against that we try to register the IO range first.
23862306a36Sopenharmony_ci * If that fails we know that pci_address_to_pio() will do too.
23962306a36Sopenharmony_ci */
24062306a36Sopenharmony_ciint of_pci_range_to_resource(struct of_pci_range *range,
24162306a36Sopenharmony_ci			     struct device_node *np, struct resource *res)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci	int err;
24462306a36Sopenharmony_ci	res->flags = range->flags;
24562306a36Sopenharmony_ci	res->parent = res->child = res->sibling = NULL;
24662306a36Sopenharmony_ci	res->name = np->full_name;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	if (res->flags & IORESOURCE_IO) {
24962306a36Sopenharmony_ci		unsigned long port;
25062306a36Sopenharmony_ci		err = pci_register_io_range(&np->fwnode, range->cpu_addr,
25162306a36Sopenharmony_ci				range->size);
25262306a36Sopenharmony_ci		if (err)
25362306a36Sopenharmony_ci			goto invalid_range;
25462306a36Sopenharmony_ci		port = pci_address_to_pio(range->cpu_addr);
25562306a36Sopenharmony_ci		if (port == (unsigned long)-1) {
25662306a36Sopenharmony_ci			err = -EINVAL;
25762306a36Sopenharmony_ci			goto invalid_range;
25862306a36Sopenharmony_ci		}
25962306a36Sopenharmony_ci		res->start = port;
26062306a36Sopenharmony_ci	} else {
26162306a36Sopenharmony_ci		if ((sizeof(resource_size_t) < 8) &&
26262306a36Sopenharmony_ci		    upper_32_bits(range->cpu_addr)) {
26362306a36Sopenharmony_ci			err = -EINVAL;
26462306a36Sopenharmony_ci			goto invalid_range;
26562306a36Sopenharmony_ci		}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci		res->start = range->cpu_addr;
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci	res->end = res->start + range->size - 1;
27062306a36Sopenharmony_ci	return 0;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ciinvalid_range:
27362306a36Sopenharmony_ci	res->start = (resource_size_t)OF_BAD_ADDR;
27462306a36Sopenharmony_ci	res->end = (resource_size_t)OF_BAD_ADDR;
27562306a36Sopenharmony_ci	return err;
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ciEXPORT_SYMBOL(of_pci_range_to_resource);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci/*
28062306a36Sopenharmony_ci * of_range_to_resource - Create a resource from a ranges entry
28162306a36Sopenharmony_ci * @np:		device node where the range belongs to
28262306a36Sopenharmony_ci * @index:	the 'ranges' index to convert to a resource
28362306a36Sopenharmony_ci * @res:	pointer to a valid resource that will be updated to
28462306a36Sopenharmony_ci *              reflect the values contained in the range.
28562306a36Sopenharmony_ci *
28662306a36Sopenharmony_ci * Returns ENOENT if the entry is not found or EINVAL if the range cannot be
28762306a36Sopenharmony_ci * converted to resource.
28862306a36Sopenharmony_ci */
28962306a36Sopenharmony_ciint of_range_to_resource(struct device_node *np, int index, struct resource *res)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	int ret, i = 0;
29262306a36Sopenharmony_ci	struct of_range_parser parser;
29362306a36Sopenharmony_ci	struct of_range range;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	ret = of_range_parser_init(&parser, np);
29662306a36Sopenharmony_ci	if (ret)
29762306a36Sopenharmony_ci		return ret;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	for_each_of_range(&parser, &range)
30062306a36Sopenharmony_ci		if (i++ == index)
30162306a36Sopenharmony_ci			return of_pci_range_to_resource(&range, np, res);
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	return -ENOENT;
30462306a36Sopenharmony_ci}
30562306a36Sopenharmony_ciEXPORT_SYMBOL(of_range_to_resource);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci/*
30862306a36Sopenharmony_ci * ISA bus specific translator
30962306a36Sopenharmony_ci */
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic int of_bus_isa_match(struct device_node *np)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	return of_node_name_eq(np, "isa");
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_cistatic void of_bus_isa_count_cells(struct device_node *child,
31762306a36Sopenharmony_ci				   int *addrc, int *sizec)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	if (addrc)
32062306a36Sopenharmony_ci		*addrc = 2;
32162306a36Sopenharmony_ci	if (sizec)
32262306a36Sopenharmony_ci		*sizec = 1;
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistatic u64 of_bus_isa_map(__be32 *addr, const __be32 *range, int na, int ns,
32662306a36Sopenharmony_ci		int pna)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	u64 cp, s, da;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	/* Check address type match */
33162306a36Sopenharmony_ci	if ((addr[0] ^ range[0]) & cpu_to_be32(1))
33262306a36Sopenharmony_ci		return OF_BAD_ADDR;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	/* Read address values, skipping high cell */
33562306a36Sopenharmony_ci	cp = of_read_number(range + 1, na - 1);
33662306a36Sopenharmony_ci	s  = of_read_number(range + na + pna, ns);
33762306a36Sopenharmony_ci	da = of_read_number(addr + 1, na - 1);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	pr_debug("ISA map, cp=%llx, s=%llx, da=%llx\n", cp, s, da);
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	if (da < cp || da >= (cp + s))
34262306a36Sopenharmony_ci		return OF_BAD_ADDR;
34362306a36Sopenharmony_ci	return da - cp;
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cistatic int of_bus_isa_translate(__be32 *addr, u64 offset, int na)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	return of_bus_default_translate(addr + 1, offset, na - 1);
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_cistatic unsigned int of_bus_isa_get_flags(const __be32 *addr)
35262306a36Sopenharmony_ci{
35362306a36Sopenharmony_ci	unsigned int flags = 0;
35462306a36Sopenharmony_ci	u32 w = be32_to_cpup(addr);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	if (w & 1)
35762306a36Sopenharmony_ci		flags |= IORESOURCE_IO;
35862306a36Sopenharmony_ci	else
35962306a36Sopenharmony_ci		flags |= IORESOURCE_MEM;
36062306a36Sopenharmony_ci	return flags;
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_cistatic int of_bus_default_flags_match(struct device_node *np)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	return of_bus_n_addr_cells(np) == 3;
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci/*
36962306a36Sopenharmony_ci * Array of bus specific translators
37062306a36Sopenharmony_ci */
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic struct of_bus of_busses[] = {
37362306a36Sopenharmony_ci#ifdef CONFIG_PCI
37462306a36Sopenharmony_ci	/* PCI */
37562306a36Sopenharmony_ci	{
37662306a36Sopenharmony_ci		.name = "pci",
37762306a36Sopenharmony_ci		.addresses = "assigned-addresses",
37862306a36Sopenharmony_ci		.match = of_bus_pci_match,
37962306a36Sopenharmony_ci		.count_cells = of_bus_pci_count_cells,
38062306a36Sopenharmony_ci		.map = of_bus_pci_map,
38162306a36Sopenharmony_ci		.translate = of_bus_pci_translate,
38262306a36Sopenharmony_ci		.has_flags = true,
38362306a36Sopenharmony_ci		.get_flags = of_bus_pci_get_flags,
38462306a36Sopenharmony_ci	},
38562306a36Sopenharmony_ci#endif /* CONFIG_PCI */
38662306a36Sopenharmony_ci	/* ISA */
38762306a36Sopenharmony_ci	{
38862306a36Sopenharmony_ci		.name = "isa",
38962306a36Sopenharmony_ci		.addresses = "reg",
39062306a36Sopenharmony_ci		.match = of_bus_isa_match,
39162306a36Sopenharmony_ci		.count_cells = of_bus_isa_count_cells,
39262306a36Sopenharmony_ci		.map = of_bus_isa_map,
39362306a36Sopenharmony_ci		.translate = of_bus_isa_translate,
39462306a36Sopenharmony_ci		.has_flags = true,
39562306a36Sopenharmony_ci		.get_flags = of_bus_isa_get_flags,
39662306a36Sopenharmony_ci	},
39762306a36Sopenharmony_ci	/* Default with flags cell */
39862306a36Sopenharmony_ci	{
39962306a36Sopenharmony_ci		.name = "default-flags",
40062306a36Sopenharmony_ci		.addresses = "reg",
40162306a36Sopenharmony_ci		.match = of_bus_default_flags_match,
40262306a36Sopenharmony_ci		.count_cells = of_bus_default_count_cells,
40362306a36Sopenharmony_ci		.map = of_bus_default_flags_map,
40462306a36Sopenharmony_ci		.translate = of_bus_default_flags_translate,
40562306a36Sopenharmony_ci		.has_flags = true,
40662306a36Sopenharmony_ci		.get_flags = of_bus_default_flags_get_flags,
40762306a36Sopenharmony_ci	},
40862306a36Sopenharmony_ci	/* Default */
40962306a36Sopenharmony_ci	{
41062306a36Sopenharmony_ci		.name = "default",
41162306a36Sopenharmony_ci		.addresses = "reg",
41262306a36Sopenharmony_ci		.match = NULL,
41362306a36Sopenharmony_ci		.count_cells = of_bus_default_count_cells,
41462306a36Sopenharmony_ci		.map = of_bus_default_map,
41562306a36Sopenharmony_ci		.translate = of_bus_default_translate,
41662306a36Sopenharmony_ci		.get_flags = of_bus_default_get_flags,
41762306a36Sopenharmony_ci	},
41862306a36Sopenharmony_ci};
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic struct of_bus *of_match_bus(struct device_node *np)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	int i;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(of_busses); i++)
42562306a36Sopenharmony_ci		if (!of_busses[i].match || of_busses[i].match(np))
42662306a36Sopenharmony_ci			return &of_busses[i];
42762306a36Sopenharmony_ci	BUG();
42862306a36Sopenharmony_ci	return NULL;
42962306a36Sopenharmony_ci}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_cistatic int of_empty_ranges_quirk(struct device_node *np)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_PPC)) {
43462306a36Sopenharmony_ci		/* To save cycles, we cache the result for global "Mac" setting */
43562306a36Sopenharmony_ci		static int quirk_state = -1;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci		/* PA-SEMI sdc DT bug */
43862306a36Sopenharmony_ci		if (of_device_is_compatible(np, "1682m-sdc"))
43962306a36Sopenharmony_ci			return true;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci		/* Make quirk cached */
44262306a36Sopenharmony_ci		if (quirk_state < 0)
44362306a36Sopenharmony_ci			quirk_state =
44462306a36Sopenharmony_ci				of_machine_is_compatible("Power Macintosh") ||
44562306a36Sopenharmony_ci				of_machine_is_compatible("MacRISC");
44662306a36Sopenharmony_ci		return quirk_state;
44762306a36Sopenharmony_ci	}
44862306a36Sopenharmony_ci	return false;
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_cistatic int of_translate_one(struct device_node *parent, struct of_bus *bus,
45262306a36Sopenharmony_ci			    struct of_bus *pbus, __be32 *addr,
45362306a36Sopenharmony_ci			    int na, int ns, int pna, const char *rprop)
45462306a36Sopenharmony_ci{
45562306a36Sopenharmony_ci	const __be32 *ranges;
45662306a36Sopenharmony_ci	unsigned int rlen;
45762306a36Sopenharmony_ci	int rone;
45862306a36Sopenharmony_ci	u64 offset = OF_BAD_ADDR;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	/*
46162306a36Sopenharmony_ci	 * Normally, an absence of a "ranges" property means we are
46262306a36Sopenharmony_ci	 * crossing a non-translatable boundary, and thus the addresses
46362306a36Sopenharmony_ci	 * below the current cannot be converted to CPU physical ones.
46462306a36Sopenharmony_ci	 * Unfortunately, while this is very clear in the spec, it's not
46562306a36Sopenharmony_ci	 * what Apple understood, and they do have things like /uni-n or
46662306a36Sopenharmony_ci	 * /ht nodes with no "ranges" property and a lot of perfectly
46762306a36Sopenharmony_ci	 * useable mapped devices below them. Thus we treat the absence of
46862306a36Sopenharmony_ci	 * "ranges" as equivalent to an empty "ranges" property which means
46962306a36Sopenharmony_ci	 * a 1:1 translation at that level. It's up to the caller not to try
47062306a36Sopenharmony_ci	 * to translate addresses that aren't supposed to be translated in
47162306a36Sopenharmony_ci	 * the first place. --BenH.
47262306a36Sopenharmony_ci	 *
47362306a36Sopenharmony_ci	 * As far as we know, this damage only exists on Apple machines, so
47462306a36Sopenharmony_ci	 * This code is only enabled on powerpc. --gcl
47562306a36Sopenharmony_ci	 *
47662306a36Sopenharmony_ci	 * This quirk also applies for 'dma-ranges' which frequently exist in
47762306a36Sopenharmony_ci	 * child nodes without 'dma-ranges' in the parent nodes. --RobH
47862306a36Sopenharmony_ci	 */
47962306a36Sopenharmony_ci	ranges = of_get_property(parent, rprop, &rlen);
48062306a36Sopenharmony_ci	if (ranges == NULL && !of_empty_ranges_quirk(parent) &&
48162306a36Sopenharmony_ci	    strcmp(rprop, "dma-ranges")) {
48262306a36Sopenharmony_ci		pr_debug("no ranges; cannot translate\n");
48362306a36Sopenharmony_ci		return 1;
48462306a36Sopenharmony_ci	}
48562306a36Sopenharmony_ci	if (ranges == NULL || rlen == 0) {
48662306a36Sopenharmony_ci		offset = of_read_number(addr, na);
48762306a36Sopenharmony_ci		memset(addr, 0, pna * 4);
48862306a36Sopenharmony_ci		pr_debug("empty ranges; 1:1 translation\n");
48962306a36Sopenharmony_ci		goto finish;
49062306a36Sopenharmony_ci	}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	pr_debug("walking ranges...\n");
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	/* Now walk through the ranges */
49562306a36Sopenharmony_ci	rlen /= 4;
49662306a36Sopenharmony_ci	rone = na + pna + ns;
49762306a36Sopenharmony_ci	for (; rlen >= rone; rlen -= rone, ranges += rone) {
49862306a36Sopenharmony_ci		offset = bus->map(addr, ranges, na, ns, pna);
49962306a36Sopenharmony_ci		if (offset != OF_BAD_ADDR)
50062306a36Sopenharmony_ci			break;
50162306a36Sopenharmony_ci	}
50262306a36Sopenharmony_ci	if (offset == OF_BAD_ADDR) {
50362306a36Sopenharmony_ci		pr_debug("not found !\n");
50462306a36Sopenharmony_ci		return 1;
50562306a36Sopenharmony_ci	}
50662306a36Sopenharmony_ci	memcpy(addr, ranges + na, 4 * pna);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci finish:
50962306a36Sopenharmony_ci	of_dump_addr("parent translation for:", addr, pna);
51062306a36Sopenharmony_ci	pr_debug("with offset: %llx\n", offset);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	/* Translate it into parent bus space */
51362306a36Sopenharmony_ci	return pbus->translate(addr, offset, pna);
51462306a36Sopenharmony_ci}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci/*
51762306a36Sopenharmony_ci * Translate an address from the device-tree into a CPU physical address,
51862306a36Sopenharmony_ci * this walks up the tree and applies the various bus mappings on the
51962306a36Sopenharmony_ci * way.
52062306a36Sopenharmony_ci *
52162306a36Sopenharmony_ci * Note: We consider that crossing any level with #size-cells == 0 to mean
52262306a36Sopenharmony_ci * that translation is impossible (that is we are not dealing with a value
52362306a36Sopenharmony_ci * that can be mapped to a cpu physical address). This is not really specified
52462306a36Sopenharmony_ci * that way, but this is traditionally the way IBM at least do things
52562306a36Sopenharmony_ci *
52662306a36Sopenharmony_ci * Whenever the translation fails, the *host pointer will be set to the
52762306a36Sopenharmony_ci * device that had registered logical PIO mapping, and the return code is
52862306a36Sopenharmony_ci * relative to that node.
52962306a36Sopenharmony_ci */
53062306a36Sopenharmony_cistatic u64 __of_translate_address(struct device_node *dev,
53162306a36Sopenharmony_ci				  struct device_node *(*get_parent)(const struct device_node *),
53262306a36Sopenharmony_ci				  const __be32 *in_addr, const char *rprop,
53362306a36Sopenharmony_ci				  struct device_node **host)
53462306a36Sopenharmony_ci{
53562306a36Sopenharmony_ci	struct device_node *parent = NULL;
53662306a36Sopenharmony_ci	struct of_bus *bus, *pbus;
53762306a36Sopenharmony_ci	__be32 addr[OF_MAX_ADDR_CELLS];
53862306a36Sopenharmony_ci	int na, ns, pna, pns;
53962306a36Sopenharmony_ci	u64 result = OF_BAD_ADDR;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	pr_debug("** translation for device %pOF **\n", dev);
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	/* Increase refcount at current level */
54462306a36Sopenharmony_ci	of_node_get(dev);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	*host = NULL;
54762306a36Sopenharmony_ci	/* Get parent & match bus type */
54862306a36Sopenharmony_ci	parent = get_parent(dev);
54962306a36Sopenharmony_ci	if (parent == NULL)
55062306a36Sopenharmony_ci		goto bail;
55162306a36Sopenharmony_ci	bus = of_match_bus(parent);
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	/* Count address cells & copy address locally */
55462306a36Sopenharmony_ci	bus->count_cells(dev, &na, &ns);
55562306a36Sopenharmony_ci	if (!OF_CHECK_COUNTS(na, ns)) {
55662306a36Sopenharmony_ci		pr_debug("Bad cell count for %pOF\n", dev);
55762306a36Sopenharmony_ci		goto bail;
55862306a36Sopenharmony_ci	}
55962306a36Sopenharmony_ci	memcpy(addr, in_addr, na * 4);
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	pr_debug("bus is %s (na=%d, ns=%d) on %pOF\n",
56262306a36Sopenharmony_ci	    bus->name, na, ns, parent);
56362306a36Sopenharmony_ci	of_dump_addr("translating address:", addr, na);
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	/* Translate */
56662306a36Sopenharmony_ci	for (;;) {
56762306a36Sopenharmony_ci		struct logic_pio_hwaddr *iorange;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci		/* Switch to parent bus */
57062306a36Sopenharmony_ci		of_node_put(dev);
57162306a36Sopenharmony_ci		dev = parent;
57262306a36Sopenharmony_ci		parent = get_parent(dev);
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci		/* If root, we have finished */
57562306a36Sopenharmony_ci		if (parent == NULL) {
57662306a36Sopenharmony_ci			pr_debug("reached root node\n");
57762306a36Sopenharmony_ci			result = of_read_number(addr, na);
57862306a36Sopenharmony_ci			break;
57962306a36Sopenharmony_ci		}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci		/*
58262306a36Sopenharmony_ci		 * For indirectIO device which has no ranges property, get
58362306a36Sopenharmony_ci		 * the address from reg directly.
58462306a36Sopenharmony_ci		 */
58562306a36Sopenharmony_ci		iorange = find_io_range_by_fwnode(&dev->fwnode);
58662306a36Sopenharmony_ci		if (iorange && (iorange->flags != LOGIC_PIO_CPU_MMIO)) {
58762306a36Sopenharmony_ci			result = of_read_number(addr + 1, na - 1);
58862306a36Sopenharmony_ci			pr_debug("indirectIO matched(%pOF) 0x%llx\n",
58962306a36Sopenharmony_ci				 dev, result);
59062306a36Sopenharmony_ci			*host = of_node_get(dev);
59162306a36Sopenharmony_ci			break;
59262306a36Sopenharmony_ci		}
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci		/* Get new parent bus and counts */
59562306a36Sopenharmony_ci		pbus = of_match_bus(parent);
59662306a36Sopenharmony_ci		pbus->count_cells(dev, &pna, &pns);
59762306a36Sopenharmony_ci		if (!OF_CHECK_COUNTS(pna, pns)) {
59862306a36Sopenharmony_ci			pr_err("Bad cell count for %pOF\n", dev);
59962306a36Sopenharmony_ci			break;
60062306a36Sopenharmony_ci		}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci		pr_debug("parent bus is %s (na=%d, ns=%d) on %pOF\n",
60362306a36Sopenharmony_ci		    pbus->name, pna, pns, parent);
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci		/* Apply bus translation */
60662306a36Sopenharmony_ci		if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop))
60762306a36Sopenharmony_ci			break;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci		/* Complete the move up one level */
61062306a36Sopenharmony_ci		na = pna;
61162306a36Sopenharmony_ci		ns = pns;
61262306a36Sopenharmony_ci		bus = pbus;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci		of_dump_addr("one level translation:", addr, na);
61562306a36Sopenharmony_ci	}
61662306a36Sopenharmony_ci bail:
61762306a36Sopenharmony_ci	of_node_put(parent);
61862306a36Sopenharmony_ci	of_node_put(dev);
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	return result;
62162306a36Sopenharmony_ci}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ciu64 of_translate_address(struct device_node *dev, const __be32 *in_addr)
62462306a36Sopenharmony_ci{
62562306a36Sopenharmony_ci	struct device_node *host;
62662306a36Sopenharmony_ci	u64 ret;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	ret = __of_translate_address(dev, of_get_parent,
62962306a36Sopenharmony_ci				     in_addr, "ranges", &host);
63062306a36Sopenharmony_ci	if (host) {
63162306a36Sopenharmony_ci		of_node_put(host);
63262306a36Sopenharmony_ci		return OF_BAD_ADDR;
63362306a36Sopenharmony_ci	}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	return ret;
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ciEXPORT_SYMBOL(of_translate_address);
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci#ifdef CONFIG_HAS_DMA
64062306a36Sopenharmony_cistruct device_node *__of_get_dma_parent(const struct device_node *np)
64162306a36Sopenharmony_ci{
64262306a36Sopenharmony_ci	struct of_phandle_args args;
64362306a36Sopenharmony_ci	int ret, index;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	index = of_property_match_string(np, "interconnect-names", "dma-mem");
64662306a36Sopenharmony_ci	if (index < 0)
64762306a36Sopenharmony_ci		return of_get_parent(np);
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	ret = of_parse_phandle_with_args(np, "interconnects",
65062306a36Sopenharmony_ci					 "#interconnect-cells",
65162306a36Sopenharmony_ci					 index, &args);
65262306a36Sopenharmony_ci	if (ret < 0)
65362306a36Sopenharmony_ci		return of_get_parent(np);
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	return of_node_get(args.np);
65662306a36Sopenharmony_ci}
65762306a36Sopenharmony_ci#endif
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_cistatic struct device_node *of_get_next_dma_parent(struct device_node *np)
66062306a36Sopenharmony_ci{
66162306a36Sopenharmony_ci	struct device_node *parent;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	parent = __of_get_dma_parent(np);
66462306a36Sopenharmony_ci	of_node_put(np);
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	return parent;
66762306a36Sopenharmony_ci}
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ciu64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr)
67062306a36Sopenharmony_ci{
67162306a36Sopenharmony_ci	struct device_node *host;
67262306a36Sopenharmony_ci	u64 ret;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	ret = __of_translate_address(dev, __of_get_dma_parent,
67562306a36Sopenharmony_ci				     in_addr, "dma-ranges", &host);
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	if (host) {
67862306a36Sopenharmony_ci		of_node_put(host);
67962306a36Sopenharmony_ci		return OF_BAD_ADDR;
68062306a36Sopenharmony_ci	}
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	return ret;
68362306a36Sopenharmony_ci}
68462306a36Sopenharmony_ciEXPORT_SYMBOL(of_translate_dma_address);
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci/**
68762306a36Sopenharmony_ci * of_translate_dma_region - Translate device tree address and size tuple
68862306a36Sopenharmony_ci * @dev: device tree node for which to translate
68962306a36Sopenharmony_ci * @prop: pointer into array of cells
69062306a36Sopenharmony_ci * @start: return value for the start of the DMA range
69162306a36Sopenharmony_ci * @length: return value for the length of the DMA range
69262306a36Sopenharmony_ci *
69362306a36Sopenharmony_ci * Returns a pointer to the cell immediately following the translated DMA region.
69462306a36Sopenharmony_ci */
69562306a36Sopenharmony_ciconst __be32 *of_translate_dma_region(struct device_node *dev, const __be32 *prop,
69662306a36Sopenharmony_ci				      phys_addr_t *start, size_t *length)
69762306a36Sopenharmony_ci{
69862306a36Sopenharmony_ci	struct device_node *parent;
69962306a36Sopenharmony_ci	u64 address, size;
70062306a36Sopenharmony_ci	int na, ns;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	parent = __of_get_dma_parent(dev);
70362306a36Sopenharmony_ci	if (!parent)
70462306a36Sopenharmony_ci		return NULL;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	na = of_bus_n_addr_cells(parent);
70762306a36Sopenharmony_ci	ns = of_bus_n_size_cells(parent);
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	of_node_put(parent);
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	address = of_translate_dma_address(dev, prop);
71262306a36Sopenharmony_ci	if (address == OF_BAD_ADDR)
71362306a36Sopenharmony_ci		return NULL;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	size = of_read_number(prop + na, ns);
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	if (start)
71862306a36Sopenharmony_ci		*start = address;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	if (length)
72162306a36Sopenharmony_ci		*length = size;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	return prop + na + ns;
72462306a36Sopenharmony_ci}
72562306a36Sopenharmony_ciEXPORT_SYMBOL(of_translate_dma_region);
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ciconst __be32 *__of_get_address(struct device_node *dev, int index, int bar_no,
72862306a36Sopenharmony_ci			       u64 *size, unsigned int *flags)
72962306a36Sopenharmony_ci{
73062306a36Sopenharmony_ci	const __be32 *prop;
73162306a36Sopenharmony_ci	unsigned int psize;
73262306a36Sopenharmony_ci	struct device_node *parent;
73362306a36Sopenharmony_ci	struct of_bus *bus;
73462306a36Sopenharmony_ci	int onesize, i, na, ns;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	/* Get parent & match bus type */
73762306a36Sopenharmony_ci	parent = of_get_parent(dev);
73862306a36Sopenharmony_ci	if (parent == NULL)
73962306a36Sopenharmony_ci		return NULL;
74062306a36Sopenharmony_ci	bus = of_match_bus(parent);
74162306a36Sopenharmony_ci	if (strcmp(bus->name, "pci") && (bar_no >= 0)) {
74262306a36Sopenharmony_ci		of_node_put(parent);
74362306a36Sopenharmony_ci		return NULL;
74462306a36Sopenharmony_ci	}
74562306a36Sopenharmony_ci	bus->count_cells(dev, &na, &ns);
74662306a36Sopenharmony_ci	of_node_put(parent);
74762306a36Sopenharmony_ci	if (!OF_CHECK_ADDR_COUNT(na))
74862306a36Sopenharmony_ci		return NULL;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	/* Get "reg" or "assigned-addresses" property */
75162306a36Sopenharmony_ci	prop = of_get_property(dev, bus->addresses, &psize);
75262306a36Sopenharmony_ci	if (prop == NULL)
75362306a36Sopenharmony_ci		return NULL;
75462306a36Sopenharmony_ci	psize /= 4;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	onesize = na + ns;
75762306a36Sopenharmony_ci	for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) {
75862306a36Sopenharmony_ci		u32 val = be32_to_cpu(prop[0]);
75962306a36Sopenharmony_ci		/* PCI bus matches on BAR number instead of index */
76062306a36Sopenharmony_ci		if (((bar_no >= 0) && ((val & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0))) ||
76162306a36Sopenharmony_ci		    ((index >= 0) && (i == index))) {
76262306a36Sopenharmony_ci			if (size)
76362306a36Sopenharmony_ci				*size = of_read_number(prop + na, ns);
76462306a36Sopenharmony_ci			if (flags)
76562306a36Sopenharmony_ci				*flags = bus->get_flags(prop);
76662306a36Sopenharmony_ci			return prop;
76762306a36Sopenharmony_ci		}
76862306a36Sopenharmony_ci	}
76962306a36Sopenharmony_ci	return NULL;
77062306a36Sopenharmony_ci}
77162306a36Sopenharmony_ciEXPORT_SYMBOL(__of_get_address);
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci/**
77462306a36Sopenharmony_ci * of_property_read_reg - Retrieve the specified "reg" entry index without translating
77562306a36Sopenharmony_ci * @np: device tree node for which to retrieve "reg" from
77662306a36Sopenharmony_ci * @idx: "reg" entry index to read
77762306a36Sopenharmony_ci * @addr: return value for the untranslated address
77862306a36Sopenharmony_ci * @size: return value for the entry size
77962306a36Sopenharmony_ci *
78062306a36Sopenharmony_ci * Returns -EINVAL if "reg" is not found. Returns 0 on success with addr and
78162306a36Sopenharmony_ci * size values filled in.
78262306a36Sopenharmony_ci */
78362306a36Sopenharmony_ciint of_property_read_reg(struct device_node *np, int idx, u64 *addr, u64 *size)
78462306a36Sopenharmony_ci{
78562306a36Sopenharmony_ci	const __be32 *prop = of_get_address(np, idx, size, NULL);
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	if (!prop)
78862306a36Sopenharmony_ci		return -EINVAL;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	*addr = of_read_number(prop, of_n_addr_cells(np));
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	return 0;
79362306a36Sopenharmony_ci}
79462306a36Sopenharmony_ciEXPORT_SYMBOL(of_property_read_reg);
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_cistatic int parser_init(struct of_pci_range_parser *parser,
79762306a36Sopenharmony_ci			struct device_node *node, const char *name)
79862306a36Sopenharmony_ci{
79962306a36Sopenharmony_ci	int rlen;
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	parser->node = node;
80262306a36Sopenharmony_ci	parser->pna = of_n_addr_cells(node);
80362306a36Sopenharmony_ci	parser->na = of_bus_n_addr_cells(node);
80462306a36Sopenharmony_ci	parser->ns = of_bus_n_size_cells(node);
80562306a36Sopenharmony_ci	parser->dma = !strcmp(name, "dma-ranges");
80662306a36Sopenharmony_ci	parser->bus = of_match_bus(node);
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	parser->range = of_get_property(node, name, &rlen);
80962306a36Sopenharmony_ci	if (parser->range == NULL)
81062306a36Sopenharmony_ci		return -ENOENT;
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	parser->end = parser->range + rlen / sizeof(__be32);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	return 0;
81562306a36Sopenharmony_ci}
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ciint of_pci_range_parser_init(struct of_pci_range_parser *parser,
81862306a36Sopenharmony_ci				struct device_node *node)
81962306a36Sopenharmony_ci{
82062306a36Sopenharmony_ci	return parser_init(parser, node, "ranges");
82162306a36Sopenharmony_ci}
82262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_pci_range_parser_init);
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ciint of_pci_dma_range_parser_init(struct of_pci_range_parser *parser,
82562306a36Sopenharmony_ci				struct device_node *node)
82662306a36Sopenharmony_ci{
82762306a36Sopenharmony_ci	return parser_init(parser, node, "dma-ranges");
82862306a36Sopenharmony_ci}
82962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_pci_dma_range_parser_init);
83062306a36Sopenharmony_ci#define of_dma_range_parser_init of_pci_dma_range_parser_init
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_cistruct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
83362306a36Sopenharmony_ci						struct of_pci_range *range)
83462306a36Sopenharmony_ci{
83562306a36Sopenharmony_ci	int na = parser->na;
83662306a36Sopenharmony_ci	int ns = parser->ns;
83762306a36Sopenharmony_ci	int np = parser->pna + na + ns;
83862306a36Sopenharmony_ci	int busflag_na = 0;
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	if (!range)
84162306a36Sopenharmony_ci		return NULL;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	if (!parser->range || parser->range + np > parser->end)
84462306a36Sopenharmony_ci		return NULL;
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	range->flags = parser->bus->get_flags(parser->range);
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	/* A extra cell for resource flags */
84962306a36Sopenharmony_ci	if (parser->bus->has_flags)
85062306a36Sopenharmony_ci		busflag_na = 1;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	range->bus_addr = of_read_number(parser->range + busflag_na, na - busflag_na);
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	if (parser->dma)
85562306a36Sopenharmony_ci		range->cpu_addr = of_translate_dma_address(parser->node,
85662306a36Sopenharmony_ci				parser->range + na);
85762306a36Sopenharmony_ci	else
85862306a36Sopenharmony_ci		range->cpu_addr = of_translate_address(parser->node,
85962306a36Sopenharmony_ci				parser->range + na);
86062306a36Sopenharmony_ci	range->size = of_read_number(parser->range + parser->pna + na, ns);
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	parser->range += np;
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	/* Now consume following elements while they are contiguous */
86562306a36Sopenharmony_ci	while (parser->range + np <= parser->end) {
86662306a36Sopenharmony_ci		u32 flags = 0;
86762306a36Sopenharmony_ci		u64 bus_addr, cpu_addr, size;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci		flags = parser->bus->get_flags(parser->range);
87062306a36Sopenharmony_ci		bus_addr = of_read_number(parser->range + busflag_na, na - busflag_na);
87162306a36Sopenharmony_ci		if (parser->dma)
87262306a36Sopenharmony_ci			cpu_addr = of_translate_dma_address(parser->node,
87362306a36Sopenharmony_ci					parser->range + na);
87462306a36Sopenharmony_ci		else
87562306a36Sopenharmony_ci			cpu_addr = of_translate_address(parser->node,
87662306a36Sopenharmony_ci					parser->range + na);
87762306a36Sopenharmony_ci		size = of_read_number(parser->range + parser->pna + na, ns);
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci		if (flags != range->flags)
88062306a36Sopenharmony_ci			break;
88162306a36Sopenharmony_ci		if (bus_addr != range->bus_addr + range->size ||
88262306a36Sopenharmony_ci		    cpu_addr != range->cpu_addr + range->size)
88362306a36Sopenharmony_ci			break;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci		range->size += size;
88662306a36Sopenharmony_ci		parser->range += np;
88762306a36Sopenharmony_ci	}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	return range;
89062306a36Sopenharmony_ci}
89162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_pci_range_parser_one);
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_cistatic u64 of_translate_ioport(struct device_node *dev, const __be32 *in_addr,
89462306a36Sopenharmony_ci			u64 size)
89562306a36Sopenharmony_ci{
89662306a36Sopenharmony_ci	u64 taddr;
89762306a36Sopenharmony_ci	unsigned long port;
89862306a36Sopenharmony_ci	struct device_node *host;
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	taddr = __of_translate_address(dev, of_get_parent,
90162306a36Sopenharmony_ci				       in_addr, "ranges", &host);
90262306a36Sopenharmony_ci	if (host) {
90362306a36Sopenharmony_ci		/* host-specific port access */
90462306a36Sopenharmony_ci		port = logic_pio_trans_hwaddr(&host->fwnode, taddr, size);
90562306a36Sopenharmony_ci		of_node_put(host);
90662306a36Sopenharmony_ci	} else {
90762306a36Sopenharmony_ci		/* memory-mapped I/O range */
90862306a36Sopenharmony_ci		port = pci_address_to_pio(taddr);
90962306a36Sopenharmony_ci	}
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	if (port == (unsigned long)-1)
91262306a36Sopenharmony_ci		return OF_BAD_ADDR;
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	return port;
91562306a36Sopenharmony_ci}
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci#ifdef CONFIG_HAS_DMA
91862306a36Sopenharmony_ci/**
91962306a36Sopenharmony_ci * of_dma_get_range - Get DMA range info and put it into a map array
92062306a36Sopenharmony_ci * @np:		device node to get DMA range info
92162306a36Sopenharmony_ci * @map:	dma range structure to return
92262306a36Sopenharmony_ci *
92362306a36Sopenharmony_ci * Look in bottom up direction for the first "dma-ranges" property
92462306a36Sopenharmony_ci * and parse it.  Put the information into a DMA offset map array.
92562306a36Sopenharmony_ci *
92662306a36Sopenharmony_ci * dma-ranges format:
92762306a36Sopenharmony_ci *	DMA addr (dma_addr)	: naddr cells
92862306a36Sopenharmony_ci *	CPU addr (phys_addr_t)	: pna cells
92962306a36Sopenharmony_ci *	size			: nsize cells
93062306a36Sopenharmony_ci *
93162306a36Sopenharmony_ci * It returns -ENODEV if "dma-ranges" property was not found for this
93262306a36Sopenharmony_ci * device in the DT.
93362306a36Sopenharmony_ci */
93462306a36Sopenharmony_ciint of_dma_get_range(struct device_node *np, const struct bus_dma_region **map)
93562306a36Sopenharmony_ci{
93662306a36Sopenharmony_ci	struct device_node *node = of_node_get(np);
93762306a36Sopenharmony_ci	const __be32 *ranges = NULL;
93862306a36Sopenharmony_ci	bool found_dma_ranges = false;
93962306a36Sopenharmony_ci	struct of_range_parser parser;
94062306a36Sopenharmony_ci	struct of_range range;
94162306a36Sopenharmony_ci	struct bus_dma_region *r;
94262306a36Sopenharmony_ci	int len, num_ranges = 0;
94362306a36Sopenharmony_ci	int ret = 0;
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	while (node) {
94662306a36Sopenharmony_ci		ranges = of_get_property(node, "dma-ranges", &len);
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci		/* Ignore empty ranges, they imply no translation required */
94962306a36Sopenharmony_ci		if (ranges && len > 0)
95062306a36Sopenharmony_ci			break;
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci		/* Once we find 'dma-ranges', then a missing one is an error */
95362306a36Sopenharmony_ci		if (found_dma_ranges && !ranges) {
95462306a36Sopenharmony_ci			ret = -ENODEV;
95562306a36Sopenharmony_ci			goto out;
95662306a36Sopenharmony_ci		}
95762306a36Sopenharmony_ci		found_dma_ranges = true;
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci		node = of_get_next_dma_parent(node);
96062306a36Sopenharmony_ci	}
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	if (!node || !ranges) {
96362306a36Sopenharmony_ci		pr_debug("no dma-ranges found for node(%pOF)\n", np);
96462306a36Sopenharmony_ci		ret = -ENODEV;
96562306a36Sopenharmony_ci		goto out;
96662306a36Sopenharmony_ci	}
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	of_dma_range_parser_init(&parser, node);
96962306a36Sopenharmony_ci	for_each_of_range(&parser, &range) {
97062306a36Sopenharmony_ci		if (range.cpu_addr == OF_BAD_ADDR) {
97162306a36Sopenharmony_ci			pr_err("translation of DMA address(%llx) to CPU address failed node(%pOF)\n",
97262306a36Sopenharmony_ci			       range.bus_addr, node);
97362306a36Sopenharmony_ci			continue;
97462306a36Sopenharmony_ci		}
97562306a36Sopenharmony_ci		num_ranges++;
97662306a36Sopenharmony_ci	}
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	if (!num_ranges) {
97962306a36Sopenharmony_ci		ret = -EINVAL;
98062306a36Sopenharmony_ci		goto out;
98162306a36Sopenharmony_ci	}
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	r = kcalloc(num_ranges + 1, sizeof(*r), GFP_KERNEL);
98462306a36Sopenharmony_ci	if (!r) {
98562306a36Sopenharmony_ci		ret = -ENOMEM;
98662306a36Sopenharmony_ci		goto out;
98762306a36Sopenharmony_ci	}
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	/*
99062306a36Sopenharmony_ci	 * Record all info in the generic DMA ranges array for struct device,
99162306a36Sopenharmony_ci	 * returning an error if we don't find any parsable ranges.
99262306a36Sopenharmony_ci	 */
99362306a36Sopenharmony_ci	*map = r;
99462306a36Sopenharmony_ci	of_dma_range_parser_init(&parser, node);
99562306a36Sopenharmony_ci	for_each_of_range(&parser, &range) {
99662306a36Sopenharmony_ci		pr_debug("dma_addr(%llx) cpu_addr(%llx) size(%llx)\n",
99762306a36Sopenharmony_ci			 range.bus_addr, range.cpu_addr, range.size);
99862306a36Sopenharmony_ci		if (range.cpu_addr == OF_BAD_ADDR)
99962306a36Sopenharmony_ci			continue;
100062306a36Sopenharmony_ci		r->cpu_start = range.cpu_addr;
100162306a36Sopenharmony_ci		r->dma_start = range.bus_addr;
100262306a36Sopenharmony_ci		r->size = range.size;
100362306a36Sopenharmony_ci		r->offset = range.cpu_addr - range.bus_addr;
100462306a36Sopenharmony_ci		r++;
100562306a36Sopenharmony_ci	}
100662306a36Sopenharmony_ciout:
100762306a36Sopenharmony_ci	of_node_put(node);
100862306a36Sopenharmony_ci	return ret;
100962306a36Sopenharmony_ci}
101062306a36Sopenharmony_ci#endif /* CONFIG_HAS_DMA */
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci/**
101362306a36Sopenharmony_ci * of_dma_get_max_cpu_address - Gets highest CPU address suitable for DMA
101462306a36Sopenharmony_ci * @np: The node to start searching from or NULL to start from the root
101562306a36Sopenharmony_ci *
101662306a36Sopenharmony_ci * Gets the highest CPU physical address that is addressable by all DMA masters
101762306a36Sopenharmony_ci * in the sub-tree pointed by np, or the whole tree if NULL is passed. If no
101862306a36Sopenharmony_ci * DMA constrained device is found, it returns PHYS_ADDR_MAX.
101962306a36Sopenharmony_ci */
102062306a36Sopenharmony_ciphys_addr_t __init of_dma_get_max_cpu_address(struct device_node *np)
102162306a36Sopenharmony_ci{
102262306a36Sopenharmony_ci	phys_addr_t max_cpu_addr = PHYS_ADDR_MAX;
102362306a36Sopenharmony_ci	struct of_range_parser parser;
102462306a36Sopenharmony_ci	phys_addr_t subtree_max_addr;
102562306a36Sopenharmony_ci	struct device_node *child;
102662306a36Sopenharmony_ci	struct of_range range;
102762306a36Sopenharmony_ci	const __be32 *ranges;
102862306a36Sopenharmony_ci	u64 cpu_end = 0;
102962306a36Sopenharmony_ci	int len;
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	if (!np)
103262306a36Sopenharmony_ci		np = of_root;
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	ranges = of_get_property(np, "dma-ranges", &len);
103562306a36Sopenharmony_ci	if (ranges && len) {
103662306a36Sopenharmony_ci		of_dma_range_parser_init(&parser, np);
103762306a36Sopenharmony_ci		for_each_of_range(&parser, &range)
103862306a36Sopenharmony_ci			if (range.cpu_addr + range.size > cpu_end)
103962306a36Sopenharmony_ci				cpu_end = range.cpu_addr + range.size - 1;
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci		if (max_cpu_addr > cpu_end)
104262306a36Sopenharmony_ci			max_cpu_addr = cpu_end;
104362306a36Sopenharmony_ci	}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	for_each_available_child_of_node(np, child) {
104662306a36Sopenharmony_ci		subtree_max_addr = of_dma_get_max_cpu_address(child);
104762306a36Sopenharmony_ci		if (max_cpu_addr > subtree_max_addr)
104862306a36Sopenharmony_ci			max_cpu_addr = subtree_max_addr;
104962306a36Sopenharmony_ci	}
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	return max_cpu_addr;
105262306a36Sopenharmony_ci}
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci/**
105562306a36Sopenharmony_ci * of_dma_is_coherent - Check if device is coherent
105662306a36Sopenharmony_ci * @np:	device node
105762306a36Sopenharmony_ci *
105862306a36Sopenharmony_ci * It returns true if "dma-coherent" property was found
105962306a36Sopenharmony_ci * for this device in the DT, or if DMA is coherent by
106062306a36Sopenharmony_ci * default for OF devices on the current platform and no
106162306a36Sopenharmony_ci * "dma-noncoherent" property was found for this device.
106262306a36Sopenharmony_ci */
106362306a36Sopenharmony_cibool of_dma_is_coherent(struct device_node *np)
106462306a36Sopenharmony_ci{
106562306a36Sopenharmony_ci	struct device_node *node;
106662306a36Sopenharmony_ci	bool is_coherent = dma_default_coherent;
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	node = of_node_get(np);
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	while (node) {
107162306a36Sopenharmony_ci		if (of_property_read_bool(node, "dma-coherent")) {
107262306a36Sopenharmony_ci			is_coherent = true;
107362306a36Sopenharmony_ci			break;
107462306a36Sopenharmony_ci		}
107562306a36Sopenharmony_ci		if (of_property_read_bool(node, "dma-noncoherent")) {
107662306a36Sopenharmony_ci			is_coherent = false;
107762306a36Sopenharmony_ci			break;
107862306a36Sopenharmony_ci		}
107962306a36Sopenharmony_ci		node = of_get_next_dma_parent(node);
108062306a36Sopenharmony_ci	}
108162306a36Sopenharmony_ci	of_node_put(node);
108262306a36Sopenharmony_ci	return is_coherent;
108362306a36Sopenharmony_ci}
108462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_dma_is_coherent);
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci/**
108762306a36Sopenharmony_ci * of_mmio_is_nonposted - Check if device uses non-posted MMIO
108862306a36Sopenharmony_ci * @np:	device node
108962306a36Sopenharmony_ci *
109062306a36Sopenharmony_ci * Returns true if the "nonposted-mmio" property was found for
109162306a36Sopenharmony_ci * the device's bus.
109262306a36Sopenharmony_ci *
109362306a36Sopenharmony_ci * This is currently only enabled on builds that support Apple ARM devices, as
109462306a36Sopenharmony_ci * an optimization.
109562306a36Sopenharmony_ci */
109662306a36Sopenharmony_cistatic bool of_mmio_is_nonposted(struct device_node *np)
109762306a36Sopenharmony_ci{
109862306a36Sopenharmony_ci	struct device_node *parent;
109962306a36Sopenharmony_ci	bool nonposted;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	if (!IS_ENABLED(CONFIG_ARCH_APPLE))
110262306a36Sopenharmony_ci		return false;
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	parent = of_get_parent(np);
110562306a36Sopenharmony_ci	if (!parent)
110662306a36Sopenharmony_ci		return false;
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	nonposted = of_property_read_bool(parent, "nonposted-mmio");
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	of_node_put(parent);
111162306a36Sopenharmony_ci	return nonposted;
111262306a36Sopenharmony_ci}
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_cistatic int __of_address_to_resource(struct device_node *dev, int index, int bar_no,
111562306a36Sopenharmony_ci		struct resource *r)
111662306a36Sopenharmony_ci{
111762306a36Sopenharmony_ci	u64 taddr;
111862306a36Sopenharmony_ci	const __be32	*addrp;
111962306a36Sopenharmony_ci	u64		size;
112062306a36Sopenharmony_ci	unsigned int	flags;
112162306a36Sopenharmony_ci	const char	*name = NULL;
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	addrp = __of_get_address(dev, index, bar_no, &size, &flags);
112462306a36Sopenharmony_ci	if (addrp == NULL)
112562306a36Sopenharmony_ci		return -EINVAL;
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	/* Get optional "reg-names" property to add a name to a resource */
112862306a36Sopenharmony_ci	if (index >= 0)
112962306a36Sopenharmony_ci		of_property_read_string_index(dev, "reg-names",	index, &name);
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	if (flags & IORESOURCE_MEM)
113262306a36Sopenharmony_ci		taddr = of_translate_address(dev, addrp);
113362306a36Sopenharmony_ci	else if (flags & IORESOURCE_IO)
113462306a36Sopenharmony_ci		taddr = of_translate_ioport(dev, addrp, size);
113562306a36Sopenharmony_ci	else
113662306a36Sopenharmony_ci		return -EINVAL;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	if (taddr == OF_BAD_ADDR)
113962306a36Sopenharmony_ci		return -EINVAL;
114062306a36Sopenharmony_ci	memset(r, 0, sizeof(struct resource));
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	if (of_mmio_is_nonposted(dev))
114362306a36Sopenharmony_ci		flags |= IORESOURCE_MEM_NONPOSTED;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	r->start = taddr;
114662306a36Sopenharmony_ci	r->end = taddr + size - 1;
114762306a36Sopenharmony_ci	r->flags = flags;
114862306a36Sopenharmony_ci	r->name = name ? name : dev->full_name;
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	return 0;
115162306a36Sopenharmony_ci}
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci/**
115462306a36Sopenharmony_ci * of_address_to_resource - Translate device tree address and return as resource
115562306a36Sopenharmony_ci * @dev:	Caller's Device Node
115662306a36Sopenharmony_ci * @index:	Index into the array
115762306a36Sopenharmony_ci * @r:		Pointer to resource array
115862306a36Sopenharmony_ci *
115962306a36Sopenharmony_ci * Returns -EINVAL if the range cannot be converted to resource.
116062306a36Sopenharmony_ci *
116162306a36Sopenharmony_ci * Note that if your address is a PIO address, the conversion will fail if
116262306a36Sopenharmony_ci * the physical address can't be internally converted to an IO token with
116362306a36Sopenharmony_ci * pci_address_to_pio(), that is because it's either called too early or it
116462306a36Sopenharmony_ci * can't be matched to any host bridge IO space
116562306a36Sopenharmony_ci */
116662306a36Sopenharmony_ciint of_address_to_resource(struct device_node *dev, int index,
116762306a36Sopenharmony_ci			   struct resource *r)
116862306a36Sopenharmony_ci{
116962306a36Sopenharmony_ci	return __of_address_to_resource(dev, index, -1, r);
117062306a36Sopenharmony_ci}
117162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_address_to_resource);
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ciint of_pci_address_to_resource(struct device_node *dev, int bar,
117462306a36Sopenharmony_ci			       struct resource *r)
117562306a36Sopenharmony_ci{
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	if (!IS_ENABLED(CONFIG_PCI))
117862306a36Sopenharmony_ci		return -ENOSYS;
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	return __of_address_to_resource(dev, -1, bar, r);
118162306a36Sopenharmony_ci}
118262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_pci_address_to_resource);
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci/**
118562306a36Sopenharmony_ci * of_iomap - Maps the memory mapped IO for a given device_node
118662306a36Sopenharmony_ci * @np:		the device whose io range will be mapped
118762306a36Sopenharmony_ci * @index:	index of the io range
118862306a36Sopenharmony_ci *
118962306a36Sopenharmony_ci * Returns a pointer to the mapped memory
119062306a36Sopenharmony_ci */
119162306a36Sopenharmony_civoid __iomem *of_iomap(struct device_node *np, int index)
119262306a36Sopenharmony_ci{
119362306a36Sopenharmony_ci	struct resource res;
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	if (of_address_to_resource(np, index, &res))
119662306a36Sopenharmony_ci		return NULL;
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	if (res.flags & IORESOURCE_MEM_NONPOSTED)
119962306a36Sopenharmony_ci		return ioremap_np(res.start, resource_size(&res));
120062306a36Sopenharmony_ci	else
120162306a36Sopenharmony_ci		return ioremap(res.start, resource_size(&res));
120262306a36Sopenharmony_ci}
120362306a36Sopenharmony_ciEXPORT_SYMBOL(of_iomap);
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci/*
120662306a36Sopenharmony_ci * of_io_request_and_map - Requests a resource and maps the memory mapped IO
120762306a36Sopenharmony_ci *			   for a given device_node
120862306a36Sopenharmony_ci * @device:	the device whose io range will be mapped
120962306a36Sopenharmony_ci * @index:	index of the io range
121062306a36Sopenharmony_ci * @name:	name "override" for the memory region request or NULL
121162306a36Sopenharmony_ci *
121262306a36Sopenharmony_ci * Returns a pointer to the requested and mapped memory or an ERR_PTR() encoded
121362306a36Sopenharmony_ci * error code on failure. Usage example:
121462306a36Sopenharmony_ci *
121562306a36Sopenharmony_ci *	base = of_io_request_and_map(node, 0, "foo");
121662306a36Sopenharmony_ci *	if (IS_ERR(base))
121762306a36Sopenharmony_ci *		return PTR_ERR(base);
121862306a36Sopenharmony_ci */
121962306a36Sopenharmony_civoid __iomem *of_io_request_and_map(struct device_node *np, int index,
122062306a36Sopenharmony_ci				    const char *name)
122162306a36Sopenharmony_ci{
122262306a36Sopenharmony_ci	struct resource res;
122362306a36Sopenharmony_ci	void __iomem *mem;
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	if (of_address_to_resource(np, index, &res))
122662306a36Sopenharmony_ci		return IOMEM_ERR_PTR(-EINVAL);
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	if (!name)
122962306a36Sopenharmony_ci		name = res.name;
123062306a36Sopenharmony_ci	if (!request_mem_region(res.start, resource_size(&res), name))
123162306a36Sopenharmony_ci		return IOMEM_ERR_PTR(-EBUSY);
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	if (res.flags & IORESOURCE_MEM_NONPOSTED)
123462306a36Sopenharmony_ci		mem = ioremap_np(res.start, resource_size(&res));
123562306a36Sopenharmony_ci	else
123662306a36Sopenharmony_ci		mem = ioremap(res.start, resource_size(&res));
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	if (!mem) {
123962306a36Sopenharmony_ci		release_mem_region(res.start, resource_size(&res));
124062306a36Sopenharmony_ci		return IOMEM_ERR_PTR(-ENOMEM);
124162306a36Sopenharmony_ci	}
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	return mem;
124462306a36Sopenharmony_ci}
124562306a36Sopenharmony_ciEXPORT_SYMBOL(of_io_request_and_map);
1246