aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/arm/vexpress.txt68
-rw-r--r--drivers/mfd/Kconfig6
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/vexpress-config.c277
-rw-r--r--include/linux/vexpress.h85
5 files changed, 436 insertions, 1 deletions
diff --git a/Documentation/devicetree/bindings/arm/vexpress.txt b/Documentation/devicetree/bindings/arm/vexpress.txt
index ec8b50cbb2e8..5d9996b9eabf 100644
--- a/Documentation/devicetree/bindings/arm/vexpress.txt
+++ b/Documentation/devicetree/bindings/arm/vexpress.txt
@@ -11,6 +11,10 @@ the motherboard file using a /include/ directive. As the motherboard
11can be initialized in one of two different configurations ("memory 11can be initialized in one of two different configurations ("memory
12maps"), care must be taken to include the correct one. 12maps"), care must be taken to include the correct one.
13 13
14
15Root node
16---------
17
14Required properties in the root node: 18Required properties in the root node:
15- compatible value: 19- compatible value:
16 compatible = "arm,vexpress,<model>", "arm,vexpress"; 20 compatible = "arm,vexpress,<model>", "arm,vexpress";
@@ -45,6 +49,10 @@ Optional properties in the root node:
45 - Coretile Express A9x4 (V2P-CA9) HBI-0225: 49 - Coretile Express A9x4 (V2P-CA9) HBI-0225:
46 arm,hbi = <0x225>; 50 arm,hbi = <0x225>;
47 51
52
53CPU nodes
54---------
55
48Top-level standard "cpus" node is required. It must contain a node 56Top-level standard "cpus" node is required. It must contain a node
49with device_type = "cpu" property for every available core, eg.: 57with device_type = "cpu" property for every available core, eg.:
50 58
@@ -59,6 +67,52 @@ with device_type = "cpu" property for every available core, eg.:
59 }; 67 };
60 }; 68 };
61 69
70
71Configuration infrastructure
72----------------------------
73
74The platform has an elaborated configuration system, consisting of
75microcontrollers residing on the mother- and daughterboards known
76as Motherboard/Daughterboard Configuration Controller (MCC and DCC).
77The controllers are responsible for the platform initialization
78(reset generation, flash programming, FPGA bitfiles loading etc.)
79but also control clock generators, voltage regulators, gather
80environmental data like temperature, power consumption etc. Even
81the video output switch (FPGA) is controlled that way.
82
83Nodes describing devices controlled by this infrastructure should
84point at the bridge device node:
85- bridge phandle:
86 arm,vexpress,config-bridge = <phandle>;
87This property can be also defined in a parent node (eg. for a DCC)
88and is effective for all children.
89
90
91Platform topology
92-----------------
93
94As Versatile Express can be configured in number of physically
95different setups, the device tree should describe platform topology.
96Root node and main motherboard node must define the following
97property, describing physical location of the children nodes:
98- site number:
99 arm,vexpress,site = <number>;
100 where 0 means motherboard, 1 or 2 are daugtherboard sites,
101 0xf means "master" site (site containing main CPU tile)
102- when daughterboards are stacked on one site, their position
103 in the stack be be described with:
104 arm,vexpress,position = <number>;
105- when describing tiles consisting more than one DCC, its number
106 can be described with:
107 arm,vexpress,dcc = <number>;
108
109Any of the numbers above defaults to zero if not defined in
110the node or any of its parent.
111
112
113Motherboard
114-----------
115
62The motherboard description file provides a single "motherboard" node 116The motherboard description file provides a single "motherboard" node
63using 2 address cells corresponding to the Static Memory Bus used 117using 2 address cells corresponding to the Static Memory Bus used
64between the motherboard and the tile. The first cell defines the Chip 118between the motherboard and the tile. The first cell defines the Chip
@@ -96,13 +150,16 @@ The tile description must define "ranges", "interrupt-map-mask" and
96"interrupt-map" properties to translate the motherboard's address 150"interrupt-map" properties to translate the motherboard's address
97and interrupt space into one used by the tile's processor. 151and interrupt space into one used by the tile's processor.
98 152
99Abbreviated example: 153
154Example of a VE tile description (simplified)
155---------------------------------------------
100 156
101/dts-v1/; 157/dts-v1/;
102 158
103/ { 159/ {
104 model = "V2P-CA5s"; 160 model = "V2P-CA5s";
105 arm,hbi = <0x225>; 161 arm,hbi = <0x225>;
162 arm,vexpress,site = <0xf>;
106 compatible = "arm,vexpress-v2p-ca5s", "arm,vexpress"; 163 compatible = "arm,vexpress-v2p-ca5s", "arm,vexpress";
107 interrupt-parent = <&gic>; 164 interrupt-parent = <&gic>;
108 #address-cells = <1>; 165 #address-cells = <1>;
@@ -134,6 +191,15 @@ Abbreviated example:
134 <0x2c000100 0x100>; 191 <0x2c000100 0x100>;
135 }; 192 };
136 193
194 dcc {
195 compatible = "simple-bus";
196 arm,vexpress,config-bridge = <&v2m_sysreg>;
197
198 osc@0 {
199 compatible = "arm,vexpress-osc";
200 };
201 };
202
137 motherboard { 203 motherboard {
138 /* CS0 is visible at 0x08000000 */ 204 /* CS0 is visible at 0x08000000 */
139 ranges = <0 0 0x08000000 0x04000000>; 205 ranges = <0 0 0x08000000 0x04000000>;
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index acab3ef8a310..637bcdf8ce77 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1070,3 +1070,9 @@ config MCP_UCB1200_TS
1070 depends on MCP_UCB1200 && INPUT 1070 depends on MCP_UCB1200 && INPUT
1071 1071
1072endmenu 1072endmenu
1073
1074config VEXPRESS_CONFIG
1075 bool
1076 help
1077 Platform configuration infrastructure for the ARM Ltd.
1078 Versatile Express.
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index d8ccb630ddb0..e807164f68da 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -138,3 +138,4 @@ obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
138obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o 138obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o
139obj-$(CONFIG_MFD_SYSCON) += syscon.o 139obj-$(CONFIG_MFD_SYSCON) += syscon.o
140obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o 140obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o
141obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o
diff --git a/drivers/mfd/vexpress-config.c b/drivers/mfd/vexpress-config.c
new file mode 100644
index 000000000000..fae15d880758
--- /dev/null
+++ b/drivers/mfd/vexpress-config.c
@@ -0,0 +1,277 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License version 2 as
4 * published by the Free Software Foundation.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
10 *
11 * Copyright (C) 2012 ARM Limited
12 */
13
14#define pr_fmt(fmt) "vexpress-config: " fmt
15
16#include <linux/bitops.h>
17#include <linux/completion.h>
18#include <linux/export.h>
19#include <linux/init.h>
20#include <linux/list.h>
21#include <linux/of.h>
22#include <linux/of_device.h>
23#include <linux/slab.h>
24#include <linux/string.h>
25#include <linux/vexpress.h>
26
27
28#define VEXPRESS_CONFIG_MAX_BRIDGES 2
29
30struct vexpress_config_bridge {
31 struct device_node *node;
32 struct vexpress_config_bridge_info *info;
33 struct list_head transactions;
34 spinlock_t transactions_lock;
35} vexpress_config_bridges[VEXPRESS_CONFIG_MAX_BRIDGES];
36
37static DECLARE_BITMAP(vexpress_config_bridges_map,
38 ARRAY_SIZE(vexpress_config_bridges));
39static DEFINE_MUTEX(vexpress_config_bridges_mutex);
40
41struct vexpress_config_bridge *vexpress_config_bridge_register(
42 struct device_node *node,
43 struct vexpress_config_bridge_info *info)
44{
45 struct vexpress_config_bridge *bridge;
46 int i;
47
48 pr_debug("Registering bridge '%s'\n", info->name);
49
50 mutex_lock(&vexpress_config_bridges_mutex);
51 i = find_first_zero_bit(vexpress_config_bridges_map,
52 ARRAY_SIZE(vexpress_config_bridges));
53 if (i >= ARRAY_SIZE(vexpress_config_bridges)) {
54 pr_err("Can't register more bridges!\n");
55 mutex_unlock(&vexpress_config_bridges_mutex);
56 return NULL;
57 }
58 __set_bit(i, vexpress_config_bridges_map);
59 bridge = &vexpress_config_bridges[i];
60
61 bridge->node = node;
62 bridge->info = info;
63 INIT_LIST_HEAD(&bridge->transactions);
64 spin_lock_init(&bridge->transactions_lock);
65
66 mutex_unlock(&vexpress_config_bridges_mutex);
67
68 return bridge;
69}
70
71void vexpress_config_bridge_unregister(struct vexpress_config_bridge *bridge)
72{
73 struct vexpress_config_bridge __bridge = *bridge;
74 int i;
75
76 mutex_lock(&vexpress_config_bridges_mutex);
77 for (i = 0; i < ARRAY_SIZE(vexpress_config_bridges); i++)
78 if (&vexpress_config_bridges[i] == bridge)
79 __clear_bit(i, vexpress_config_bridges_map);
80 mutex_unlock(&vexpress_config_bridges_mutex);
81
82 WARN_ON(!list_empty(&__bridge.transactions));
83 while (!list_empty(&__bridge.transactions))
84 cpu_relax();
85}
86
87
88struct vexpress_config_func {
89 struct vexpress_config_bridge *bridge;
90 void *func;
91};
92
93struct vexpress_config_func *__vexpress_config_func_get(struct device *dev,
94 struct device_node *node)
95{
96 struct device_node *bridge_node;
97 struct vexpress_config_func *func;
98 int i;
99
100 if (WARN_ON(dev && node && dev->of_node != node))
101 return NULL;
102 if (dev && !node)
103 node = dev->of_node;
104
105 func = kzalloc(sizeof(*func), GFP_KERNEL);
106 if (!func)
107 return NULL;
108
109 bridge_node = of_node_get(node);
110 while (bridge_node) {
111 const __be32 *prop = of_get_property(bridge_node,
112 "arm,vexpress,config-bridge", NULL);
113
114 if (prop) {
115 bridge_node = of_find_node_by_phandle(
116 be32_to_cpup(prop));
117 break;
118 }
119
120 bridge_node = of_get_next_parent(bridge_node);
121 }
122
123 mutex_lock(&vexpress_config_bridges_mutex);
124 for (i = 0; i < ARRAY_SIZE(vexpress_config_bridges); i++) {
125 struct vexpress_config_bridge *bridge =
126 &vexpress_config_bridges[i];
127
128 if (test_bit(i, vexpress_config_bridges_map) &&
129 bridge->node == bridge_node) {
130 func->bridge = bridge;
131 func->func = bridge->info->func_get(dev, node);
132 break;
133 }
134 }
135 mutex_unlock(&vexpress_config_bridges_mutex);
136
137 if (!func->func) {
138 of_node_put(node);
139 kfree(func);
140 return NULL;
141 }
142
143 return func;
144}
145
146void vexpress_config_func_put(struct vexpress_config_func *func)
147{
148 func->bridge->info->func_put(func->func);
149 of_node_put(func->bridge->node);
150 kfree(func);
151}
152
153
154struct vexpress_config_trans {
155 struct vexpress_config_func *func;
156 int offset;
157 bool write;
158 u32 *data;
159 int status;
160 struct completion completion;
161 struct list_head list;
162};
163
164static void vexpress_config_dump_trans(const char *what,
165 struct vexpress_config_trans *trans)
166{
167 pr_debug("%s %s trans %p func 0x%p offset %d data 0x%x status %d\n",
168 what, trans->write ? "write" : "read", trans,
169 trans->func->func, trans->offset,
170 trans->data ? *trans->data : 0, trans->status);
171}
172
173static int vexpress_config_schedule(struct vexpress_config_trans *trans)
174{
175 int status;
176 struct vexpress_config_bridge *bridge = trans->func->bridge;
177 unsigned long flags;
178
179 init_completion(&trans->completion);
180 trans->status = -EFAULT;
181
182 spin_lock_irqsave(&bridge->transactions_lock, flags);
183
184 vexpress_config_dump_trans("Executing", trans);
185
186 if (list_empty(&bridge->transactions))
187 status = bridge->info->func_exec(trans->func->func,
188 trans->offset, trans->write, trans->data);
189 else
190 status = VEXPRESS_CONFIG_STATUS_WAIT;
191
192 switch (status) {
193 case VEXPRESS_CONFIG_STATUS_DONE:
194 vexpress_config_dump_trans("Finished", trans);
195 trans->status = status;
196 break;
197 case VEXPRESS_CONFIG_STATUS_WAIT:
198 list_add_tail(&trans->list, &bridge->transactions);
199 break;
200 }
201
202 spin_unlock_irqrestore(&bridge->transactions_lock, flags);
203
204 return status;
205}
206
207void vexpress_config_complete(struct vexpress_config_bridge *bridge,
208 int status)
209{
210 struct vexpress_config_trans *trans;
211 unsigned long flags;
212
213 spin_lock_irqsave(&bridge->transactions_lock, flags);
214
215 trans = list_first_entry(&bridge->transactions,
216 struct vexpress_config_trans, list);
217 vexpress_config_dump_trans("Completed", trans);
218
219 trans->status = status;
220 list_del(&trans->list);
221
222 if (!list_empty(&bridge->transactions)) {
223 vexpress_config_dump_trans("Pending", trans);
224
225 bridge->info->func_exec(trans->func->func, trans->offset,
226 trans->write, trans->data);
227 }
228 spin_unlock_irqrestore(&bridge->transactions_lock, flags);
229
230 complete(&trans->completion);
231}
232
233int vexpress_config_wait(struct vexpress_config_trans *trans)
234{
235 wait_for_completion(&trans->completion);
236
237 return trans->status;
238}
239
240
241int vexpress_config_read(struct vexpress_config_func *func, int offset,
242 u32 *data)
243{
244 struct vexpress_config_trans trans = {
245 .func = func,
246 .offset = offset,
247 .write = false,
248 .data = data,
249 .status = 0,
250 };
251 int status = vexpress_config_schedule(&trans);
252
253 if (status == VEXPRESS_CONFIG_STATUS_WAIT)
254 status = vexpress_config_wait(&trans);
255
256 return status;
257}
258EXPORT_SYMBOL(vexpress_config_read);
259
260int vexpress_config_write(struct vexpress_config_func *func, int offset,
261 u32 data)
262{
263 struct vexpress_config_trans trans = {
264 .func = func,
265 .offset = offset,
266 .write = true,
267 .data = &data,
268 .status = 0,
269 };
270 int status = vexpress_config_schedule(&trans);
271
272 if (status == VEXPRESS_CONFIG_STATUS_WAIT)
273 status = vexpress_config_wait(&trans);
274
275 return status;
276}
277EXPORT_SYMBOL(vexpress_config_write);
diff --git a/include/linux/vexpress.h b/include/linux/vexpress.h
new file mode 100644
index 000000000000..c2d877a7b691
--- /dev/null
+++ b/include/linux/vexpress.h
@@ -0,0 +1,85 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License version 2 as
4 * published by the Free Software Foundation.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
10 *
11 * Copyright (C) 2012 ARM Limited
12 */
13
14#ifndef _LINUX_VEXPRESS_H
15#define _LINUX_VEXPRESS_H
16
17#include <linux/device.h>
18
19#define VEXPRESS_SITE_MB 0
20#define VEXPRESS_SITE_DB1 1
21#define VEXPRESS_SITE_DB2 2
22#define VEXPRESS_SITE_MASTER 0xf
23
24#define VEXPRESS_CONFIG_STATUS_DONE 0
25#define VEXPRESS_CONFIG_STATUS_WAIT 1
26
27/* Config bridge API */
28
29/**
30 * struct vexpress_config_bridge_info - description of the platform
31 * configuration infrastructure bridge.
32 *
33 * @name: Bridge name
34 *
35 * @func_get: Obtains pointer to a configuration function for a given
36 * device or a Device Tree node, to be used with @func_put
37 * and @func_exec. The node pointer should take precedence
38 * over device pointer when both are passed.
39 *
40 * @func_put: Tells the bridge that the function will not be used any
41 * more, so all allocated resources can be released.
42 *
43 * @func_exec: Executes a configuration function read or write operation.
44 * The offset selects a 32 bit word of the value accessed.
45 * Must return VEXPRESS_CONFIG_STATUS_DONE when operation
46 * is finished immediately, VEXPRESS_CONFIG_STATUS_WAIT when
47 * will be completed in some time or negative value in case
48 * of error.
49 */
50struct vexpress_config_bridge_info {
51 const char *name;
52 void *(*func_get)(struct device *dev, struct device_node *node);
53 void (*func_put)(void *func);
54 int (*func_exec)(void *func, int offset, bool write, u32 *data);
55};
56
57struct vexpress_config_bridge;
58
59struct vexpress_config_bridge *vexpress_config_bridge_register(
60 struct device_node *node,
61 struct vexpress_config_bridge_info *info);
62void vexpress_config_bridge_unregister(struct vexpress_config_bridge *bridge);
63
64void vexpress_config_complete(struct vexpress_config_bridge *bridge,
65 int status);
66
67/* Config function API */
68
69struct vexpress_config_func;
70
71struct vexpress_config_func *__vexpress_config_func_get(struct device *dev,
72 struct device_node *node);
73#define vexpress_config_func_get_by_dev(dev) \
74 __vexpress_config_func_get(dev, NULL)
75#define vexpress_config_func_get_by_node(node) \
76 __vexpress_config_func_get(NULL, node)
77void vexpress_config_func_put(struct vexpress_config_func *func);
78
79/* Both may sleep! */
80int vexpress_config_read(struct vexpress_config_func *func, int offset,
81 u32 *data);
82int vexpress_config_write(struct vexpress_config_func *func, int offset,
83 u32 data);
84
85#endif