Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bb24cab3 authored by Ezequiel Garcia's avatar Ezequiel Garcia Committed by Jason Cooper
Browse files

bus: mvebu-mbus: Add static window allocation to the DT binding



This patch adds static window allocation to the device tree binding.
Each first-child of the mbus-compatible node, with a suitable 'ranges'
property, declaring an address translation, will trigger an address
decoding window allocation.

Signed-off-by: default avatarEzequiel Garcia <ezequiel.garcia@free-electrons.com>
Tested-by: default avatarAndrew Lunn <andrew@lunn.ch>
Tested-by: default avatarSebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Signed-off-by: default avatarJason Cooper <jason@lakedaemon.net>
parent 6839cfa8
Loading
Loading
Loading
Loading
+126 −1
Original line number Original line Diff line number Diff line
@@ -902,6 +902,127 @@ int __init mvebu_mbus_init(const char *soc, phys_addr_t mbuswins_phys_base,
}
}


#ifdef CONFIG_OF
#ifdef CONFIG_OF
/*
 * The window IDs in the ranges DT property have the following format:
 *  - bits 28 to 31: MBus custom field
 *  - bits 24 to 27: window target ID
 *  - bits 16 to 23: window attribute ID
 *  - bits  0 to 15: unused
 */
#define CUSTOM(id) (((id) & 0xF0000000) >> 24)
#define TARGET(id) (((id) & 0x0F000000) >> 24)
#define ATTR(id)   (((id) & 0x00FF0000) >> 16)

static int __init mbus_dt_setup_win(struct mvebu_mbus_state *mbus,
				    u32 base, u32 size,
				    u8 target, u8 attr)
{
	const struct mvebu_mbus_mapping *map = mbus->soc->map;
	const char *name;
	int i;

	/* Search for a suitable window in the existing mappings */
	for (i = 0; map[i].name; i++)
		if (map[i].target == target &&
		    map[i].attr == (attr & map[i].attrmask))
			break;

	name = map[i].name;
	if (!name) {
		pr_err("window 0x%x:0x%x is unknown, skipping\n",
		       target, attr);
		return -EINVAL;
	}

	if (!mvebu_mbus_window_conflicts(mbus, base, size, target, attr)) {
		pr_err("cannot add window '%s', conflicts with another window\n",
		       name);
		return -EBUSY;
	}

	if (mvebu_mbus_alloc_window(mbus, base, size, MVEBU_MBUS_NO_REMAP,
				    target, attr)) {
		pr_err("cannot add window '%s', too many windows\n",
		       name);
		return -ENOMEM;
	}
	return 0;
}

static int __init
mbus_parse_ranges(struct device_node *node,
		  int *addr_cells, int *c_addr_cells, int *c_size_cells,
		  int *cell_count, const __be32 **ranges_start,
		  const __be32 **ranges_end)
{
	const __be32 *prop;
	int ranges_len, tuple_len;

	/* Allow a node with no 'ranges' property */
	*ranges_start = of_get_property(node, "ranges", &ranges_len);
	if (*ranges_start == NULL) {
		*addr_cells = *c_addr_cells = *c_size_cells = *cell_count = 0;
		*ranges_start = *ranges_end = NULL;
		return 0;
	}
	*ranges_end = *ranges_start + ranges_len / sizeof(__be32);

	*addr_cells = of_n_addr_cells(node);

	prop = of_get_property(node, "#address-cells", NULL);
	*c_addr_cells = be32_to_cpup(prop);

	prop = of_get_property(node, "#size-cells", NULL);
	*c_size_cells = be32_to_cpup(prop);

	*cell_count = *addr_cells + *c_addr_cells + *c_size_cells;
	tuple_len = (*cell_count) * sizeof(__be32);

	if (ranges_len % tuple_len) {
		pr_warn("malformed ranges entry '%s'\n", node->name);
		return -EINVAL;
	}
	return 0;
}

static int __init mbus_dt_setup(struct mvebu_mbus_state *mbus,
				struct device_node *np)
{
	int addr_cells, c_addr_cells, c_size_cells;
	int i, ret, cell_count;
	const __be32 *r, *ranges_start, *ranges_end;

	ret = mbus_parse_ranges(np, &addr_cells, &c_addr_cells,
				&c_size_cells, &cell_count,
				&ranges_start, &ranges_end);
	if (ret < 0)
		return ret;

	for (i = 0, r = ranges_start; r < ranges_end; r += cell_count, i++) {
		u32 windowid, base, size;
		u8 target, attr;

		/*
		 * An entry with a non-zero custom field do not
		 * correspond to a static window, so skip it.
		 */
		windowid = of_read_number(r, 1);
		if (CUSTOM(windowid))
			continue;

		target = TARGET(windowid);
		attr = ATTR(windowid);

		base = of_read_number(r + c_addr_cells, addr_cells);
		size = of_read_number(r + c_addr_cells + addr_cells,
				      c_size_cells);
		ret = mbus_dt_setup_win(mbus, base, size, target, attr);
		if (ret < 0)
			return ret;
	}
	return 0;
}

int __init mvebu_mbus_dt_init(void)
int __init mvebu_mbus_dt_init(void)
{
{
	struct resource mbuswins_res, sdramwins_res;
	struct resource mbuswins_res, sdramwins_res;
@@ -946,6 +1067,10 @@ int __init mvebu_mbus_dt_init(void)
				     resource_size(&mbuswins_res),
				     resource_size(&mbuswins_res),
				     sdramwins_res.start,
				     sdramwins_res.start,
				     resource_size(&sdramwins_res));
				     resource_size(&sdramwins_res));
	if (ret)
		return ret;
		return ret;

	/* Setup statically declared windows in the DT */
	return mbus_dt_setup(&mbus_state, np);
}
}
#endif
#endif