diff options
author | Ezequiel Garcia <ezequiel.garcia@free-electrons.com> | 2013-07-26 09:17:46 -0400 |
---|---|---|
committer | Jason Cooper <jason@lakedaemon.net> | 2013-08-06 10:10:29 -0400 |
commit | bb24cab39c7b6971db88d9a72d8d661b9ee887ea (patch) | |
tree | 19773ce6db923f2277acf6961f46aa4039c0b379 /drivers/bus | |
parent | 6839cfa82f99fd098ea486e7f9df78344c8e091f (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.c | 127 |
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 | |||
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 | |||
905 | int __init mvebu_mbus_dt_init(void) | 1026 | int __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 |