xref: /rk3399_rockchip-uboot/drivers/core/of_addr.c (revision 0e00a84cdedf7a1949486746225b35984b351eca)
138d21b41SSimon Glass /*
238d21b41SSimon Glass  * Taken from Linux v4.9 drivers/of/address.c
338d21b41SSimon Glass  *
438d21b41SSimon Glass  * Modified for U-Boot
538d21b41SSimon Glass  * Copyright (c) 2017 Google, Inc
638d21b41SSimon Glass  *
738d21b41SSimon Glass  * SPDX-License-Identifier:	GPL-2.0+
838d21b41SSimon Glass  */
938d21b41SSimon Glass 
1038d21b41SSimon Glass #include <common.h>
11*0e00a84cSMasahiro Yamada #include <linux/libfdt.h>
1238d21b41SSimon Glass #include <dm/of_access.h>
1338d21b41SSimon Glass #include <dm/of_addr.h>
1438d21b41SSimon Glass #include <linux/err.h>
1538d21b41SSimon Glass #include <linux/ioport.h>
1638d21b41SSimon Glass 
1738d21b41SSimon Glass /* Max address size we deal with */
1838d21b41SSimon Glass #define OF_MAX_ADDR_CELLS	4
1938d21b41SSimon Glass #define OF_CHECK_ADDR_COUNT(na)	((na) > 0 && (na) <= OF_MAX_ADDR_CELLS)
2038d21b41SSimon Glass #define OF_CHECK_COUNTS(na, ns)	(OF_CHECK_ADDR_COUNT(na) && (ns) > 0)
2138d21b41SSimon Glass 
2238d21b41SSimon Glass static struct of_bus *of_match_bus(struct device_node *np);
2338d21b41SSimon Glass 
2438d21b41SSimon Glass /* Debug utility */
2538d21b41SSimon Glass #ifdef DEBUG
of_dump_addr(const char * s,const __be32 * addr,int na)2638d21b41SSimon Glass static void of_dump_addr(const char *s, const __be32 *addr, int na)
2738d21b41SSimon Glass {
2838d21b41SSimon Glass 	debug("%s", s);
2938d21b41SSimon Glass 	while (na--)
3038d21b41SSimon Glass 		pr_cont(" %08x", be32_to_cpu(*(addr++)));
3138d21b41SSimon Glass 	pr_cont("\n");
3238d21b41SSimon Glass }
3338d21b41SSimon Glass #else
of_dump_addr(const char * s,const __be32 * addr,int na)3438d21b41SSimon Glass static void of_dump_addr(const char *s, const __be32 *addr, int na) { }
3538d21b41SSimon Glass #endif
3638d21b41SSimon Glass 
3738d21b41SSimon Glass /* Callbacks for bus specific translators */
3838d21b41SSimon Glass struct of_bus {
3938d21b41SSimon Glass 	const char *name;
4038d21b41SSimon Glass 	const char *addresses;
4138d21b41SSimon Glass 	int (*match)(struct device_node *parent);
4238d21b41SSimon Glass 	void (*count_cells)(const struct device_node *child, int *addrc,
4338d21b41SSimon Glass 			    int *sizec);
4438d21b41SSimon Glass 	u64 (*map)(__be32 *addr, const __be32 *range, int na, int ns, int pna);
4538d21b41SSimon Glass 	int (*translate)(__be32 *addr, u64 offset, int na);
4638d21b41SSimon Glass 	unsigned int (*get_flags)(const __be32 *addr);
4738d21b41SSimon Glass };
4838d21b41SSimon Glass 
of_bus_default_count_cells(const struct device_node * np,int * addrc,int * sizec)4938d21b41SSimon Glass static void of_bus_default_count_cells(const struct device_node *np,
5038d21b41SSimon Glass 				       int *addrc, int *sizec)
5138d21b41SSimon Glass {
5238d21b41SSimon Glass 	if (addrc)
5338d21b41SSimon Glass 		*addrc = of_n_addr_cells(np);
5438d21b41SSimon Glass 	if (sizec)
5538d21b41SSimon Glass 		*sizec = of_n_size_cells(np);
5638d21b41SSimon Glass }
5738d21b41SSimon Glass 
of_bus_default_map(__be32 * addr,const __be32 * range,int na,int ns,int pna)5838d21b41SSimon Glass static u64 of_bus_default_map(__be32 *addr, const __be32 *range,
5938d21b41SSimon Glass 		int na, int ns, int pna)
6038d21b41SSimon Glass {
6138d21b41SSimon Glass 	u64 cp, s, da;
6238d21b41SSimon Glass 
6338d21b41SSimon Glass 	cp = of_read_number(range, na);
6438d21b41SSimon Glass 	s  = of_read_number(range + na + pna, ns);
6538d21b41SSimon Glass 	da = of_read_number(addr, na);
6638d21b41SSimon Glass 
6738d21b41SSimon Glass 	debug("default map, cp=%llx, s=%llx, da=%llx\n",
6838d21b41SSimon Glass 	      (unsigned long long)cp, (unsigned long long)s,
6938d21b41SSimon Glass 	      (unsigned long long)da);
7038d21b41SSimon Glass 
7138d21b41SSimon Glass 	if (da < cp || da >= (cp + s))
7238d21b41SSimon Glass 		return OF_BAD_ADDR;
7338d21b41SSimon Glass 	return da - cp;
7438d21b41SSimon Glass }
7538d21b41SSimon Glass 
of_bus_default_translate(__be32 * addr,u64 offset,int na)7638d21b41SSimon Glass static int of_bus_default_translate(__be32 *addr, u64 offset, int na)
7738d21b41SSimon Glass {
7838d21b41SSimon Glass 	u64 a = of_read_number(addr, na);
7938d21b41SSimon Glass 	memset(addr, 0, na * 4);
8038d21b41SSimon Glass 	a += offset;
8138d21b41SSimon Glass 	if (na > 1)
8238d21b41SSimon Glass 		addr[na - 2] = cpu_to_be32(a >> 32);
8338d21b41SSimon Glass 	addr[na - 1] = cpu_to_be32(a & 0xffffffffu);
8438d21b41SSimon Glass 
8538d21b41SSimon Glass 	return 0;
8638d21b41SSimon Glass }
8738d21b41SSimon Glass 
of_bus_default_get_flags(const __be32 * addr)8838d21b41SSimon Glass static unsigned int of_bus_default_get_flags(const __be32 *addr)
8938d21b41SSimon Glass {
9038d21b41SSimon Glass 	return IORESOURCE_MEM;
9138d21b41SSimon Glass }
9238d21b41SSimon Glass 
9338d21b41SSimon Glass /*
9438d21b41SSimon Glass  * Array of bus-specific translators
9538d21b41SSimon Glass  */
9638d21b41SSimon Glass static struct of_bus of_busses[] = {
9738d21b41SSimon Glass 	/* Default */
9838d21b41SSimon Glass 	{
9938d21b41SSimon Glass 		.name = "default",
10038d21b41SSimon Glass 		.addresses = "reg",
10138d21b41SSimon Glass 		.match = NULL,
10238d21b41SSimon Glass 		.count_cells = of_bus_default_count_cells,
10338d21b41SSimon Glass 		.map = of_bus_default_map,
10438d21b41SSimon Glass 		.translate = of_bus_default_translate,
10538d21b41SSimon Glass 		.get_flags = of_bus_default_get_flags,
10638d21b41SSimon Glass 	},
10738d21b41SSimon Glass };
10838d21b41SSimon Glass 
of_match_bus(struct device_node * np)10938d21b41SSimon Glass static struct of_bus *of_match_bus(struct device_node *np)
11038d21b41SSimon Glass {
11138d21b41SSimon Glass 	int i;
11238d21b41SSimon Glass 
11338d21b41SSimon Glass 	for (i = 0; i < ARRAY_SIZE(of_busses); i++)
11438d21b41SSimon Glass 		if (!of_busses[i].match || of_busses[i].match(np))
11538d21b41SSimon Glass 			return &of_busses[i];
11638d21b41SSimon Glass 	BUG();
11738d21b41SSimon Glass 	return NULL;
11838d21b41SSimon Glass }
11938d21b41SSimon Glass 
dev_count_cells(const struct device_node * np,int * nap,int * nsp)12038d21b41SSimon Glass static void dev_count_cells(const struct device_node *np, int *nap, int *nsp)
12138d21b41SSimon Glass {
12238d21b41SSimon Glass 	of_bus_default_count_cells(np, nap, nsp);
12338d21b41SSimon Glass }
12438d21b41SSimon Glass 
of_get_address(const struct device_node * dev,int index,u64 * size,unsigned int * flags)12538d21b41SSimon Glass const __be32 *of_get_address(const struct device_node *dev, int index,
12638d21b41SSimon Glass 			     u64 *size, unsigned int *flags)
12738d21b41SSimon Glass {
12838d21b41SSimon Glass 	const __be32 *prop;
12938d21b41SSimon Glass 	int psize;
13038d21b41SSimon Glass 	struct device_node *parent;
13138d21b41SSimon Glass 	struct of_bus *bus;
13238d21b41SSimon Glass 	int onesize, i, na, ns;
13338d21b41SSimon Glass 
13438d21b41SSimon Glass 	/* Get parent & match bus type */
13538d21b41SSimon Glass 	parent = of_get_parent(dev);
13638d21b41SSimon Glass 	if (parent == NULL)
13738d21b41SSimon Glass 		return NULL;
13838d21b41SSimon Glass 	dev_count_cells(dev, &na, &ns);
13938d21b41SSimon Glass 	bus = of_match_bus(parent);
14038d21b41SSimon Glass 	bus->count_cells(dev, &na, &ns);
14138d21b41SSimon Glass 	of_node_put(parent);
14238d21b41SSimon Glass 	if (!OF_CHECK_ADDR_COUNT(na))
14338d21b41SSimon Glass 		return NULL;
14438d21b41SSimon Glass 
14538d21b41SSimon Glass 	/* Get "reg" or "assigned-addresses" property */
14638d21b41SSimon Glass 	prop = of_get_property(dev, "reg", &psize);
14738d21b41SSimon Glass 	if (prop == NULL)
14838d21b41SSimon Glass 		return NULL;
14938d21b41SSimon Glass 	psize /= 4;
15038d21b41SSimon Glass 
15138d21b41SSimon Glass 	onesize = na + ns;
15238d21b41SSimon Glass 	for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
15338d21b41SSimon Glass 		if (i == index) {
15438d21b41SSimon Glass 			if (size)
15538d21b41SSimon Glass 				*size = of_read_number(prop + na, ns);
15638d21b41SSimon Glass 			if (flags)
15738d21b41SSimon Glass 				*flags = bus->get_flags(prop);
15838d21b41SSimon Glass 			return prop;
15938d21b41SSimon Glass 		}
16038d21b41SSimon Glass 	return NULL;
16138d21b41SSimon Glass }
16238d21b41SSimon Glass EXPORT_SYMBOL(of_get_address);
16338d21b41SSimon Glass 
of_empty_ranges_quirk(const struct device_node * np)16438d21b41SSimon Glass static int of_empty_ranges_quirk(const struct device_node *np)
16538d21b41SSimon Glass {
16638d21b41SSimon Glass 	return false;
16738d21b41SSimon Glass }
16838d21b41SSimon Glass 
of_translate_one(const struct device_node * parent,struct of_bus * bus,struct of_bus * pbus,__be32 * addr,int na,int ns,int pna,const char * rprop)16938d21b41SSimon Glass static int of_translate_one(const struct device_node *parent,
17038d21b41SSimon Glass 			    struct of_bus *bus, struct of_bus *pbus,
17138d21b41SSimon Glass 			    __be32 *addr, int na, int ns, int pna,
17238d21b41SSimon Glass 			    const char *rprop)
17338d21b41SSimon Glass {
17438d21b41SSimon Glass 	const __be32 *ranges;
17538d21b41SSimon Glass 	int rlen;
17638d21b41SSimon Glass 	int rone;
17738d21b41SSimon Glass 	u64 offset = OF_BAD_ADDR;
17838d21b41SSimon Glass 
17938d21b41SSimon Glass 	/*
18038d21b41SSimon Glass 	 * Normally, an absence of a "ranges" property means we are
18138d21b41SSimon Glass 	 * crossing a non-translatable boundary, and thus the addresses
18238d21b41SSimon Glass 	 * below the current cannot be converted to CPU physical ones.
18338d21b41SSimon Glass 	 * Unfortunately, while this is very clear in the spec, it's not
18438d21b41SSimon Glass 	 * what Apple understood, and they do have things like /uni-n or
18538d21b41SSimon Glass 	 * /ht nodes with no "ranges" property and a lot of perfectly
18638d21b41SSimon Glass 	 * useable mapped devices below them. Thus we treat the absence of
18738d21b41SSimon Glass 	 * "ranges" as equivalent to an empty "ranges" property which means
18838d21b41SSimon Glass 	 * a 1:1 translation at that level. It's up to the caller not to try
18938d21b41SSimon Glass 	 * to translate addresses that aren't supposed to be translated in
19038d21b41SSimon Glass 	 * the first place. --BenH.
19138d21b41SSimon Glass 	 *
19238d21b41SSimon Glass 	 * As far as we know, this damage only exists on Apple machines, so
19338d21b41SSimon Glass 	 * This code is only enabled on powerpc. --gcl
19438d21b41SSimon Glass 	 */
19538d21b41SSimon Glass 	ranges = of_get_property(parent, rprop, &rlen);
19638d21b41SSimon Glass 	if (ranges == NULL && !of_empty_ranges_quirk(parent)) {
19738d21b41SSimon Glass 		debug("no ranges; cannot translate\n");
19838d21b41SSimon Glass 		return 1;
19938d21b41SSimon Glass 	}
20038d21b41SSimon Glass 	if (ranges == NULL || rlen == 0) {
20138d21b41SSimon Glass 		offset = of_read_number(addr, na);
20238d21b41SSimon Glass 		memset(addr, 0, pna * 4);
20338d21b41SSimon Glass 		debug("empty ranges; 1:1 translation\n");
20438d21b41SSimon Glass 		goto finish;
20538d21b41SSimon Glass 	}
20638d21b41SSimon Glass 
20738d21b41SSimon Glass 	debug("walking ranges...\n");
20838d21b41SSimon Glass 
20938d21b41SSimon Glass 	/* Now walk through the ranges */
21038d21b41SSimon Glass 	rlen /= 4;
21138d21b41SSimon Glass 	rone = na + pna + ns;
21238d21b41SSimon Glass 	for (; rlen >= rone; rlen -= rone, ranges += rone) {
21338d21b41SSimon Glass 		offset = bus->map(addr, ranges, na, ns, pna);
21438d21b41SSimon Glass 		if (offset != OF_BAD_ADDR)
21538d21b41SSimon Glass 			break;
21638d21b41SSimon Glass 	}
21738d21b41SSimon Glass 	if (offset == OF_BAD_ADDR) {
21838d21b41SSimon Glass 		debug("not found !\n");
21938d21b41SSimon Glass 		return 1;
22038d21b41SSimon Glass 	}
22138d21b41SSimon Glass 	memcpy(addr, ranges + na, 4 * pna);
22238d21b41SSimon Glass 
22338d21b41SSimon Glass  finish:
22438d21b41SSimon Glass 	of_dump_addr("parent translation for:", addr, pna);
22538d21b41SSimon Glass 	debug("with offset: %llx\n", (unsigned long long)offset);
22638d21b41SSimon Glass 
22738d21b41SSimon Glass 	/* Translate it into parent bus space */
22838d21b41SSimon Glass 	return pbus->translate(addr, offset, pna);
22938d21b41SSimon Glass }
23038d21b41SSimon Glass 
23138d21b41SSimon Glass /*
23238d21b41SSimon Glass  * Translate an address from the device-tree into a CPU physical address,
23338d21b41SSimon Glass  * this walks up the tree and applies the various bus mappings on the
23438d21b41SSimon Glass  * way.
23538d21b41SSimon Glass  *
23638d21b41SSimon Glass  * Note: We consider that crossing any level with #size-cells == 0 to mean
23738d21b41SSimon Glass  * that translation is impossible (that is we are not dealing with a value
23838d21b41SSimon Glass  * that can be mapped to a cpu physical address). This is not really specified
23938d21b41SSimon Glass  * that way, but this is traditionally the way IBM at least do things
24038d21b41SSimon Glass  */
__of_translate_address(const struct device_node * dev,const __be32 * in_addr,const char * rprop)24138d21b41SSimon Glass static u64 __of_translate_address(const struct device_node *dev,
24238d21b41SSimon Glass 				  const __be32 *in_addr, const char *rprop)
24338d21b41SSimon Glass {
24438d21b41SSimon Glass 	struct device_node *parent = NULL;
24538d21b41SSimon Glass 	struct of_bus *bus, *pbus;
24638d21b41SSimon Glass 	__be32 addr[OF_MAX_ADDR_CELLS];
24738d21b41SSimon Glass 	int na, ns, pna, pns;
24838d21b41SSimon Glass 	u64 result = OF_BAD_ADDR;
24938d21b41SSimon Glass 
25038d21b41SSimon Glass 	debug("** translation for device %s **\n", of_node_full_name(dev));
25138d21b41SSimon Glass 
25238d21b41SSimon Glass 	/* Increase refcount at current level */
25338d21b41SSimon Glass 	(void)of_node_get(dev);
25438d21b41SSimon Glass 
25538d21b41SSimon Glass 	/* Get parent & match bus type */
25638d21b41SSimon Glass 	parent = of_get_parent(dev);
25738d21b41SSimon Glass 	if (parent == NULL)
25838d21b41SSimon Glass 		goto bail;
25938d21b41SSimon Glass 	bus = of_match_bus(parent);
26038d21b41SSimon Glass 
26138d21b41SSimon Glass 	/* Count address cells & copy address locally */
26238d21b41SSimon Glass 	bus->count_cells(dev, &na, &ns);
26338d21b41SSimon Glass 	if (!OF_CHECK_COUNTS(na, ns)) {
26438d21b41SSimon Glass 		debug("Bad cell count for %s\n", of_node_full_name(dev));
26538d21b41SSimon Glass 		goto bail;
26638d21b41SSimon Glass 	}
26738d21b41SSimon Glass 	memcpy(addr, in_addr, na * 4);
26838d21b41SSimon Glass 
26938d21b41SSimon Glass 	debug("bus is %s (na=%d, ns=%d) on %s\n", bus->name, na, ns,
27038d21b41SSimon Glass 	      of_node_full_name(parent));
27138d21b41SSimon Glass 	of_dump_addr("translating address:", addr, na);
27238d21b41SSimon Glass 
27338d21b41SSimon Glass 	/* Translate */
27438d21b41SSimon Glass 	for (;;) {
27538d21b41SSimon Glass 		/* Switch to parent bus */
27638d21b41SSimon Glass 		of_node_put(dev);
27738d21b41SSimon Glass 		dev = parent;
27838d21b41SSimon Glass 		parent = of_get_parent(dev);
27938d21b41SSimon Glass 
28038d21b41SSimon Glass 		/* If root, we have finished */
28138d21b41SSimon Glass 		if (parent == NULL) {
28238d21b41SSimon Glass 			debug("reached root node\n");
28338d21b41SSimon Glass 			result = of_read_number(addr, na);
28438d21b41SSimon Glass 			break;
28538d21b41SSimon Glass 		}
28638d21b41SSimon Glass 
28738d21b41SSimon Glass 		/* Get new parent bus and counts */
28838d21b41SSimon Glass 		pbus = of_match_bus(parent);
28938d21b41SSimon Glass 		pbus->count_cells(dev, &pna, &pns);
29038d21b41SSimon Glass 		if (!OF_CHECK_COUNTS(pna, pns)) {
29138d21b41SSimon Glass 			debug("Bad cell count for %s\n",
29238d21b41SSimon Glass 			      of_node_full_name(dev));
29338d21b41SSimon Glass 			break;
29438d21b41SSimon Glass 		}
29538d21b41SSimon Glass 
29638d21b41SSimon Glass 		debug("parent bus is %s (na=%d, ns=%d) on %s\n", pbus->name,
29738d21b41SSimon Glass 		      pna, pns, of_node_full_name(parent));
29838d21b41SSimon Glass 
29938d21b41SSimon Glass 		/* Apply bus translation */
30038d21b41SSimon Glass 		if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop))
30138d21b41SSimon Glass 			break;
30238d21b41SSimon Glass 
30338d21b41SSimon Glass 		/* Complete the move up one level */
30438d21b41SSimon Glass 		na = pna;
30538d21b41SSimon Glass 		ns = pns;
30638d21b41SSimon Glass 		bus = pbus;
30738d21b41SSimon Glass 
30838d21b41SSimon Glass 		of_dump_addr("one level translation:", addr, na);
30938d21b41SSimon Glass 	}
31038d21b41SSimon Glass  bail:
31138d21b41SSimon Glass 	of_node_put(parent);
31238d21b41SSimon Glass 	of_node_put(dev);
31338d21b41SSimon Glass 
31438d21b41SSimon Glass 	return result;
31538d21b41SSimon Glass }
31638d21b41SSimon Glass 
of_translate_address(const struct device_node * dev,const __be32 * in_addr)31738d21b41SSimon Glass u64 of_translate_address(const struct device_node *dev, const __be32 *in_addr)
31838d21b41SSimon Glass {
31938d21b41SSimon Glass 	return __of_translate_address(dev, in_addr, "ranges");
32038d21b41SSimon Glass }
32138d21b41SSimon Glass 
32238d21b41SSimon Glass 
__of_address_to_resource(const struct device_node * dev,const __be32 * addrp,u64 size,unsigned int flags,const char * name,struct resource * r)32338d21b41SSimon Glass static int __of_address_to_resource(const struct device_node *dev,
32438d21b41SSimon Glass 		const __be32 *addrp, u64 size, unsigned int flags,
32538d21b41SSimon Glass 		const char *name, struct resource *r)
32638d21b41SSimon Glass {
32738d21b41SSimon Glass 	u64 taddr;
32838d21b41SSimon Glass 
32938d21b41SSimon Glass 	if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)
33038d21b41SSimon Glass 		return -EINVAL;
33138d21b41SSimon Glass 	taddr = of_translate_address(dev, addrp);
33238d21b41SSimon Glass 	if (taddr == OF_BAD_ADDR)
33338d21b41SSimon Glass 		return -EINVAL;
33438d21b41SSimon Glass 	memset(r, 0, sizeof(struct resource));
33538d21b41SSimon Glass 	r->start = taddr;
33638d21b41SSimon Glass 	r->end = taddr + size - 1;
33738d21b41SSimon Glass 	r->flags = flags;
33838d21b41SSimon Glass 	r->name = name ? name : dev->full_name;
33938d21b41SSimon Glass 
34038d21b41SSimon Glass 	return 0;
34138d21b41SSimon Glass }
34238d21b41SSimon Glass 
of_address_to_resource(const struct device_node * dev,int index,struct resource * r)34338d21b41SSimon Glass int of_address_to_resource(const struct device_node *dev, int index,
34438d21b41SSimon Glass 			   struct resource *r)
34538d21b41SSimon Glass {
34638d21b41SSimon Glass 	const __be32	*addrp;
34738d21b41SSimon Glass 	u64		size;
34838d21b41SSimon Glass 	unsigned int	flags;
34938d21b41SSimon Glass 	const char	*name = NULL;
35038d21b41SSimon Glass 
35138d21b41SSimon Glass 	addrp = of_get_address(dev, index, &size, &flags);
35238d21b41SSimon Glass 	if (addrp == NULL)
35338d21b41SSimon Glass 		return -EINVAL;
35438d21b41SSimon Glass 
35538d21b41SSimon Glass 	/* Get optional "reg-names" property to add a name to a resource */
35638d21b41SSimon Glass 	of_property_read_string_index(dev, "reg-names", index, &name);
35738d21b41SSimon Glass 
35838d21b41SSimon Glass 	return __of_address_to_resource(dev, addrp, size, flags, name, r);
35938d21b41SSimon Glass }
360