d9e783a48126a2e01dba52bbebee7bff44f0e691
[openwrt.git] / target / linux / mvebu / patches-3.10 / 0045-bus-mvebu-mbus-Add-static-window-allocation-to-the-D.patch
1 From ece28a7e105cedb5a9ebd2553aa41d965fb83b64 Mon Sep 17 00:00:00 2001
2 From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
3 Date: Tue, 28 May 2013 07:58:31 -0300
4 Subject: [PATCH 045/203] bus: mvebu-mbus: Add static window allocation to the
5  DT binding
6
7 This patch adds static window allocation to the device tree binding.
8 Each first-child of the mbus-compatible node, with a suitable 'ranges'
9 property, declaring an address translation, will trigger an address
10 decoding window allocation.
11
12 Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
13 Tested-by: Andrew Lunn <andrew@lunn.ch>
14 Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
15 ---
16  drivers/bus/mvebu-mbus.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++-
17  1 file changed, 126 insertions(+), 1 deletion(-)
18
19 --- a/drivers/bus/mvebu-mbus.c
20 +++ b/drivers/bus/mvebu-mbus.c
21 @@ -902,6 +902,127 @@ int __init mvebu_mbus_init(const char *s
22  }
23  
24  #ifdef CONFIG_OF
25 +/*
26 + * The window IDs in the ranges DT property have the following format:
27 + *  - bits 28 to 31: MBus custom field
28 + *  - bits 24 to 27: window target ID
29 + *  - bits 16 to 23: window attribute ID
30 + *  - bits  0 to 15: unused
31 + */
32 +#define CUSTOM(id) (((id) & 0xF0000000) >> 24)
33 +#define TARGET(id) (((id) & 0x0F000000) >> 24)
34 +#define ATTR(id)   (((id) & 0x00FF0000) >> 16)
35 +
36 +static int __init mbus_dt_setup_win(struct mvebu_mbus_state *mbus,
37 +                                   u32 base, u32 size,
38 +                                   u8 target, u8 attr)
39 +{
40 +       const struct mvebu_mbus_mapping *map = mbus->soc->map;
41 +       const char *name;
42 +       int i;
43 +
44 +       /* Search for a suitable window in the existing mappings */
45 +       for (i = 0; map[i].name; i++)
46 +               if (map[i].target == target &&
47 +                   map[i].attr == (attr & map[i].attrmask))
48 +                       break;
49 +
50 +       name = map[i].name;
51 +       if (!name) {
52 +               pr_err("window 0x%x:0x%x is unknown, skipping\n",
53 +                      target, attr);
54 +               return -EINVAL;
55 +       }
56 +
57 +       if (!mvebu_mbus_window_conflicts(mbus, base, size, target, attr)) {
58 +               pr_err("cannot add window '%s', conflicts with another window\n",
59 +                      name);
60 +               return -EBUSY;
61 +       }
62 +
63 +       if (mvebu_mbus_alloc_window(mbus, base, size, MVEBU_MBUS_NO_REMAP,
64 +                                   target, attr)) {
65 +               pr_err("cannot add window '%s', too many windows\n",
66 +                      name);
67 +               return -ENOMEM;
68 +       }
69 +       return 0;
70 +}
71 +
72 +static int __init
73 +mbus_parse_ranges(struct device_node *node,
74 +                 int *addr_cells, int *c_addr_cells, int *c_size_cells,
75 +                 int *cell_count, const __be32 **ranges_start,
76 +                 const __be32 **ranges_end)
77 +{
78 +       const __be32 *prop;
79 +       int ranges_len, tuple_len;
80 +
81 +       /* Allow a node with no 'ranges' property */
82 +       *ranges_start = of_get_property(node, "ranges", &ranges_len);
83 +       if (*ranges_start == NULL) {
84 +               *addr_cells = *c_addr_cells = *c_size_cells = *cell_count = 0;
85 +               *ranges_start = *ranges_end = NULL;
86 +               return 0;
87 +       }
88 +       *ranges_end = *ranges_start + ranges_len / sizeof(__be32);
89 +
90 +       *addr_cells = of_n_addr_cells(node);
91 +
92 +       prop = of_get_property(node, "#address-cells", NULL);
93 +       *c_addr_cells = be32_to_cpup(prop);
94 +
95 +       prop = of_get_property(node, "#size-cells", NULL);
96 +       *c_size_cells = be32_to_cpup(prop);
97 +
98 +       *cell_count = *addr_cells + *c_addr_cells + *c_size_cells;
99 +       tuple_len = (*cell_count) * sizeof(__be32);
100 +
101 +       if (ranges_len % tuple_len) {
102 +               pr_warn("malformed ranges entry '%s'\n", node->name);
103 +               return -EINVAL;
104 +       }
105 +       return 0;
106 +}
107 +
108 +static int __init mbus_dt_setup(struct mvebu_mbus_state *mbus,
109 +                               struct device_node *np)
110 +{
111 +       int addr_cells, c_addr_cells, c_size_cells;
112 +       int i, ret, cell_count;
113 +       const __be32 *r, *ranges_start, *ranges_end;
114 +
115 +       ret = mbus_parse_ranges(np, &addr_cells, &c_addr_cells,
116 +                               &c_size_cells, &cell_count,
117 +                               &ranges_start, &ranges_end);
118 +       if (ret < 0)
119 +               return ret;
120 +
121 +       for (i = 0, r = ranges_start; r < ranges_end; r += cell_count, i++) {
122 +               u32 windowid, base, size;
123 +               u8 target, attr;
124 +
125 +               /*
126 +                * An entry with a non-zero custom field do not
127 +                * correspond to a static window, so skip it.
128 +                */
129 +               windowid = of_read_number(r, 1);
130 +               if (CUSTOM(windowid))
131 +                       continue;
132 +
133 +               target = TARGET(windowid);
134 +               attr = ATTR(windowid);
135 +
136 +               base = of_read_number(r + c_addr_cells, addr_cells);
137 +               size = of_read_number(r + c_addr_cells + addr_cells,
138 +                                     c_size_cells);
139 +               ret = mbus_dt_setup_win(mbus, base, size, target, attr);
140 +               if (ret < 0)
141 +                       return ret;
142 +       }
143 +       return 0;
144 +}
145 +
146  int __init mvebu_mbus_dt_init(void)
147  {
148         struct resource mbuswins_res, sdramwins_res;
149 @@ -946,6 +1067,10 @@ int __init mvebu_mbus_dt_init(void)
150                                      resource_size(&mbuswins_res),
151                                      sdramwins_res.start,
152                                      resource_size(&sdramwins_res));
153 -       return ret;
154 +       if (ret)
155 +               return ret;
156 +
157 +       /* Setup statically declared windows in the DT */
158 +       return mbus_dt_setup(&mbus_state, np);
159  }
160  #endif