Skip to content

Commit bb24cab

Browse files
ezequielgarciaJason Cooper
authored andcommitted
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: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> Tested-by: Andrew Lunn <andrew@lunn.ch> Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> Signed-off-by: Jason Cooper <jason@lakedaemon.net>
1 parent 6839cfa commit bb24cab

File tree

1 file changed

+126
-1
lines changed

1 file changed

+126
-1
lines changed

drivers/bus/mvebu-mbus.c

Lines changed: 126 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,127 @@ int __init mvebu_mbus_init(const char *soc, phys_addr_t mbuswins_phys_base,
902902
}
903903

904904
#ifdef CONFIG_OF
905+
/*
906+
* The window IDs in the ranges DT property have the following format:
907+
* - bits 28 to 31: MBus custom field
908+
* - bits 24 to 27: window target ID
909+
* - bits 16 to 23: window attribute ID
910+
* - bits 0 to 15: unused
911+
*/
912+
#define CUSTOM(id) (((id) & 0xF0000000) >> 24)
913+
#define TARGET(id) (((id) & 0x0F000000) >> 24)
914+
#define ATTR(id) (((id) & 0x00FF0000) >> 16)
915+
916+
static int __init mbus_dt_setup_win(struct mvebu_mbus_state *mbus,
917+
u32 base, u32 size,
918+
u8 target, u8 attr)
919+
{
920+
const struct mvebu_mbus_mapping *map = mbus->soc->map;
921+
const char *name;
922+
int i;
923+
924+
/* Search for a suitable window in the existing mappings */
925+
for (i = 0; map[i].name; i++)
926+
if (map[i].target == target &&
927+
map[i].attr == (attr & map[i].attrmask))
928+
break;
929+
930+
name = map[i].name;
931+
if (!name) {
932+
pr_err("window 0x%x:0x%x is unknown, skipping\n",
933+
target, attr);
934+
return -EINVAL;
935+
}
936+
937+
if (!mvebu_mbus_window_conflicts(mbus, base, size, target, attr)) {
938+
pr_err("cannot add window '%s', conflicts with another window\n",
939+
name);
940+
return -EBUSY;
941+
}
942+
943+
if (mvebu_mbus_alloc_window(mbus, base, size, MVEBU_MBUS_NO_REMAP,
944+
target, attr)) {
945+
pr_err("cannot add window '%s', too many windows\n",
946+
name);
947+
return -ENOMEM;
948+
}
949+
return 0;
950+
}
951+
952+
static int __init
953+
mbus_parse_ranges(struct device_node *node,
954+
int *addr_cells, int *c_addr_cells, int *c_size_cells,
955+
int *cell_count, const __be32 **ranges_start,
956+
const __be32 **ranges_end)
957+
{
958+
const __be32 *prop;
959+
int ranges_len, tuple_len;
960+
961+
/* Allow a node with no 'ranges' property */
962+
*ranges_start = of_get_property(node, "ranges", &ranges_len);
963+
if (*ranges_start == NULL) {
964+
*addr_cells = *c_addr_cells = *c_size_cells = *cell_count = 0;
965+
*ranges_start = *ranges_end = NULL;
966+
return 0;
967+
}
968+
*ranges_end = *ranges_start + ranges_len / sizeof(__be32);
969+
970+
*addr_cells = of_n_addr_cells(node);
971+
972+
prop = of_get_property(node, "#address-cells", NULL);
973+
*c_addr_cells = be32_to_cpup(prop);
974+
975+
prop = of_get_property(node, "#size-cells", NULL);
976+
*c_size_cells = be32_to_cpup(prop);
977+
978+
*cell_count = *addr_cells + *c_addr_cells + *c_size_cells;
979+
tuple_len = (*cell_count) * sizeof(__be32);
980+
981+
if (ranges_len % tuple_len) {
982+
pr_warn("malformed ranges entry '%s'\n", node->name);
983+
return -EINVAL;
984+
}
985+
return 0;
986+
}
987+
988+
static int __init mbus_dt_setup(struct mvebu_mbus_state *mbus,
989+
struct device_node *np)
990+
{
991+
int addr_cells, c_addr_cells, c_size_cells;
992+
int i, ret, cell_count;
993+
const __be32 *r, *ranges_start, *ranges_end;
994+
995+
ret = mbus_parse_ranges(np, &addr_cells, &c_addr_cells,
996+
&c_size_cells, &cell_count,
997+
&ranges_start, &ranges_end);
998+
if (ret < 0)
999+
return ret;
1000+
1001+
for (i = 0, r = ranges_start; r < ranges_end; r += cell_count, i++) {
1002+
u32 windowid, base, size;
1003+
u8 target, attr;
1004+
1005+
/*
1006+
* An entry with a non-zero custom field do not
1007+
* correspond to a static window, so skip it.
1008+
*/
1009+
windowid = of_read_number(r, 1);
1010+
if (CUSTOM(windowid))
1011+
continue;
1012+
1013+
target = TARGET(windowid);
1014+
attr = ATTR(windowid);
1015+
1016+
base = of_read_number(r + c_addr_cells, addr_cells);
1017+
size = of_read_number(r + c_addr_cells + addr_cells,
1018+
c_size_cells);
1019+
ret = mbus_dt_setup_win(mbus, base, size, target, attr);
1020+
if (ret < 0)
1021+
return ret;
1022+
}
1023+
return 0;
1024+
}
1025+
9051026
int __init mvebu_mbus_dt_init(void)
9061027
{
9071028
struct resource mbuswins_res, sdramwins_res;
@@ -946,6 +1067,10 @@ int __init mvebu_mbus_dt_init(void)
9461067
resource_size(&mbuswins_res),
9471068
sdramwins_res.start,
9481069
resource_size(&sdramwins_res));
949-
return ret;
1070+
if (ret)
1071+
return ret;
1072+
1073+
/* Setup statically declared windows in the DT */
1074+
return mbus_dt_setup(&mbus_state, np);
9501075
}
9511076
#endif

0 commit comments

Comments
 (0)