aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/bus
diff options
context:
space:
mode:
authorEzequiel Garcia <ezequiel.garcia@free-electrons.com>2013-07-26 09:17:46 -0400
committerJason Cooper <jason@lakedaemon.net>2013-08-06 10:10:29 -0400
commitbb24cab39c7b6971db88d9a72d8d661b9ee887ea (patch)
tree19773ce6db923f2277acf6961f46aa4039c0b379 /drivers/bus
parent6839cfa82f99fd098ea486e7f9df78344c8e091f (diff)
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>
Diffstat (limited to 'drivers/bus')
-rw-r--r--drivers/bus/mvebu-mbus.c127
1 files changed, 126 insertions, 1 deletions
diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c
index 44a07c4ee4ea..78b8c0436f0b 100644
--- a/drivers/bus/mvebu-mbus.c
+++ b/drivers/bus/mvebu-mbus.c
@@ -902,6 +902,127 @@ int __init mvebu_mbus_init(const char *soc, phys_addr_t mbuswins_phys_base,
902} 902}
903 903
904#ifdef CONFIG_OF 904#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
916static 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
952static int __init
953mbus_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
988static 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
905int __init mvebu_mbus_dt_init(void) 1026int __init mvebu_mbus_dt_init(void)
906{ 1027{
907 struct resource mbuswins_res, sdramwins_res; 1028 struct resource mbuswins_res, sdramwins_res;
@@ -946,6 +1067,10 @@ int __init mvebu_mbus_dt_init(void)
946 resource_size(&mbuswins_res), 1067 resource_size(&mbuswins_res),
947 sdramwins_res.start, 1068 sdramwins_res.start,
948 resource_size(&sdramwins_res)); 1069 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);
950} 1075}
951#endif 1076#endif