1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2015
4  * Texas Instruments Incorporated - http://www.ti.com/
5  */
6 #define pr_fmt(fmt) "%s: " fmt, __func__
7 #include <common.h>
8 #include <dm.h>
9 #include <errno.h>
10 #include <log.h>
11 #include <remoteproc.h>
12 #include <asm/io.h>
13 
14 /**
15  * enum sandbox_state - different device states
16  * @sb_booted:	Entry condition, just booted
17  * @sb_init:	Initialized (basic environment is ready)
18  * @sb_reset:	Held in reset (accessible, but not running)
19  * @sb_loaded:	Loaded with image (but not running)
20  * @sb_running:	Processor is running
21  */
22 enum sandbox_state {
23 	sb_booted,
24 	sb_init,
25 	sb_reset,
26 	sb_loaded,
27 	sb_running
28 };
29 
30 /**
31  * struct sandbox_test_devdata - private data per device
32  * @current_state:	device current state
33  */
34 struct sandbox_test_devdata {
35 	enum sandbox_state current_state;
36 };
37 
38 /**
39  * sandbox_dev_move_to_state() - statemachine for our dummy device
40  * @dev:	device to switch state
41  * @next_state:	next proposed state
42  *
43  * This tries to follow the following statemachine:
44  *           Entry
45  *            |
46  *            v
47  *         +-------+
48  *     +---+ init  |
49  *     |   |       | <---------------------+
50  *     |   +-------+                       |
51  *     |                                   |
52  *     |                                   |
53  *     |   +--------+                      |
54  * Load|   |  reset |                      |
55  *     |   |        | <----------+         |
56  *     |   +--------+            |         |
57  *     |        |Load            |         |
58  *     |        |                |         |
59  *     |   +----v----+   reset   |         |
60  *     +-> |         |    (opt)  |         |
61  *         |  Loaded +-----------+         |
62  *         |         |                     |
63  *         +----+----+                     |
64  *              | Start                    |
65  *          +---v-----+        (opt)       |
66  *       +->| Running |        Stop        |
67  * Ping  +- |         +--------------------+
68  * (opt)    +---------+
69  *
70  * (is_running does not change state)
71  *
72  * Return: 0 when valid state transition is seen, else returns -EINVAL
73  */
sandbox_dev_move_to_state(struct udevice * dev,enum sandbox_state next_state)74 static int sandbox_dev_move_to_state(struct udevice *dev,
75 				     enum sandbox_state next_state)
76 {
77 	struct sandbox_test_devdata *ddata = dev_get_priv(dev);
78 
79 	/* No state transition is OK */
80 	if (ddata->current_state == next_state)
81 		return 0;
82 
83 	debug("current_state=%d, next_state=%d\n", ddata->current_state,
84 	      next_state);
85 	switch (ddata->current_state) {
86 	case sb_booted:
87 		if (next_state == sb_init)
88 			goto ok_state;
89 		break;
90 
91 	case sb_init:
92 		if (next_state == sb_reset || next_state == sb_loaded)
93 			goto ok_state;
94 		break;
95 
96 	case sb_reset:
97 		if (next_state == sb_loaded || next_state == sb_init)
98 			goto ok_state;
99 		break;
100 
101 	case sb_loaded:
102 		if (next_state == sb_reset || next_state == sb_init ||
103 		    next_state == sb_running)
104 			goto ok_state;
105 		break;
106 
107 	case sb_running:
108 		if (next_state == sb_reset || next_state == sb_init)
109 			goto ok_state;
110 		break;
111 	};
112 	return -EINVAL;
113 
114 ok_state:
115 	ddata->current_state = next_state;
116 	return 0;
117 }
118 
119 /**
120  * sandbox_testproc_probe() - basic probe function
121  * @dev:	test proc device that is being probed.
122  *
123  * Return: 0 if all went ok, else return appropriate error
124  */
sandbox_testproc_probe(struct udevice * dev)125 static int sandbox_testproc_probe(struct udevice *dev)
126 {
127 	struct dm_rproc_uclass_pdata *uc_pdata;
128 	struct sandbox_test_devdata *ddata;
129 	int ret;
130 
131 	uc_pdata = dev_get_uclass_plat(dev);
132 	ddata = dev_get_priv(dev);
133 	if (!ddata) {
134 		debug("%s: platform private data missing\n", uc_pdata->name);
135 		return -EINVAL;
136 	}
137 	ret = sandbox_dev_move_to_state(dev, sb_booted);
138 	debug("%s: called(%d)\n", uc_pdata->name, ret);
139 
140 	return ret;
141 }
142 
143 /**
144  * sandbox_testproc_init() - Simple initialization function
145  * @dev:	device to operate upon
146  *
147  * Return: 0 if all went ok, else return appropriate error
148  */
sandbox_testproc_init(struct udevice * dev)149 static int sandbox_testproc_init(struct udevice *dev)
150 {
151 	struct dm_rproc_uclass_pdata *uc_pdata;
152 	int ret;
153 
154 	uc_pdata = dev_get_uclass_plat(dev);
155 
156 	ret = sandbox_dev_move_to_state(dev, sb_init);
157 
158 	debug("%s: called(%d)\n", uc_pdata->name, ret);
159 	if (ret)
160 		debug("%s init failed\n", uc_pdata->name);
161 
162 	return ret;
163 }
164 
165 /**
166  * sandbox_testproc_reset() - Reset the remote processor
167  * @dev:	device to operate upon
168  *
169  * Return: 0 if all went ok, else return appropriate error
170  */
sandbox_testproc_reset(struct udevice * dev)171 static int sandbox_testproc_reset(struct udevice *dev)
172 {
173 	struct dm_rproc_uclass_pdata *uc_pdata;
174 	int ret;
175 
176 	uc_pdata = dev_get_uclass_plat(dev);
177 
178 	ret = sandbox_dev_move_to_state(dev, sb_reset);
179 
180 	debug("%s: called(%d)\n", uc_pdata->name, ret);
181 
182 	if (ret)
183 		debug("%s reset failed\n", uc_pdata->name);
184 	return ret;
185 }
186 
187 /**
188  * sandbox_testproc_load() - (replace: short desc)
189  * @dev:	device to operate upon
190  * @addr:	Address of the binary image to load
191  * @size:	Size (in bytes) of the binary image to load
192  *
193  * Return: 0 if all went ok, else return appropriate error
194  */
sandbox_testproc_load(struct udevice * dev,ulong addr,ulong size)195 static int sandbox_testproc_load(struct udevice *dev, ulong addr, ulong size)
196 {
197 	struct dm_rproc_uclass_pdata *uc_pdata;
198 	int ret;
199 
200 	uc_pdata = dev_get_uclass_plat(dev);
201 
202 	ret = sandbox_dev_move_to_state(dev, sb_loaded);
203 
204 	debug("%s: called(%d) Loading to %08lX %lu size\n",
205 	      uc_pdata->name, ret, addr, size);
206 
207 	if (ret)
208 		debug("%s load failed\n", uc_pdata->name);
209 	return ret;
210 }
211 
212 /**
213  * sandbox_testproc_start() - Start the remote processor
214  * @dev:	device to operate upon
215  *
216  * Return: 0 if all went ok, else return appropriate error
217  */
sandbox_testproc_start(struct udevice * dev)218 static int sandbox_testproc_start(struct udevice *dev)
219 {
220 	struct dm_rproc_uclass_pdata *uc_pdata;
221 	int ret;
222 
223 	uc_pdata = dev_get_uclass_plat(dev);
224 
225 	ret = sandbox_dev_move_to_state(dev, sb_running);
226 
227 	debug("%s: called(%d)\n", uc_pdata->name, ret);
228 
229 	if (ret)
230 		debug("%s start failed\n", uc_pdata->name);
231 	return ret;
232 }
233 
234 /**
235  * sandbox_testproc_stop() - Stop the remote processor
236  * @dev:	device to operate upon
237  *
238  * Return: 0 if all went ok, else return appropriate error
239  */
sandbox_testproc_stop(struct udevice * dev)240 static int sandbox_testproc_stop(struct udevice *dev)
241 {
242 	struct dm_rproc_uclass_pdata *uc_pdata;
243 	int ret;
244 
245 	uc_pdata = dev_get_uclass_plat(dev);
246 
247 	ret = sandbox_dev_move_to_state(dev, sb_init);
248 
249 	debug("%s: called(%d)\n", uc_pdata->name, ret);
250 
251 	if (ret)
252 		debug("%s stop failed\n", uc_pdata->name);
253 	return ret;
254 }
255 
256 /**
257  * sandbox_testproc_is_running() - Check if remote processor is running
258  * @dev:	device to operate upon
259  *
260  * Return: 0 if running, 1 if not running
261  */
sandbox_testproc_is_running(struct udevice * dev)262 static int sandbox_testproc_is_running(struct udevice *dev)
263 {
264 	struct dm_rproc_uclass_pdata *uc_pdata;
265 	struct sandbox_test_devdata *ddata;
266 	int ret = 1;
267 
268 	uc_pdata = dev_get_uclass_plat(dev);
269 	ddata = dev_get_priv(dev);
270 
271 	if (ddata->current_state == sb_running)
272 		ret = 0;
273 	debug("%s: called(%d)\n", uc_pdata->name, ret);
274 
275 	return ret;
276 }
277 
278 /**
279  * sandbox_testproc_ping() - Try pinging remote processor
280  * @dev:	device to operate upon
281  *
282  * Return: 0 if running, -EINVAL if not running
283  */
sandbox_testproc_ping(struct udevice * dev)284 static int sandbox_testproc_ping(struct udevice *dev)
285 {
286 	struct dm_rproc_uclass_pdata *uc_pdata;
287 	struct sandbox_test_devdata *ddata;
288 	int ret;
289 
290 	uc_pdata = dev_get_uclass_plat(dev);
291 	ddata = dev_get_priv(dev);
292 
293 	if (ddata->current_state == sb_running)
294 		ret = 0;
295 	else
296 		ret = -EINVAL;
297 
298 	debug("%s: called(%d)\n", uc_pdata->name, ret);
299 	if (ret)
300 		debug("%s: No response.(Not started?)\n", uc_pdata->name);
301 
302 	return ret;
303 }
304 
305 #define SANDBOX_RPROC_DEV_TO_PHY_OFFSET	0x1000
306 /**
307  * sandbox_testproc_device_to_virt() - Convert device address to virtual address
308  * @dev:	device to operate upon
309  * @da:		device address
310  * @size:	Size of the memory region @da is pointing to
311  * @return converted virtual address
312  */
sandbox_testproc_device_to_virt(struct udevice * dev,ulong da,ulong size)313 static void *sandbox_testproc_device_to_virt(struct udevice *dev, ulong da,
314 					     ulong size)
315 {
316 	u64 paddr;
317 
318 	/* Use a simple offset conversion */
319 	paddr = da + SANDBOX_RPROC_DEV_TO_PHY_OFFSET;
320 
321 	return phys_to_virt(paddr);
322 }
323 
324 static const struct dm_rproc_ops sandbox_testproc_ops = {
325 	.init = sandbox_testproc_init,
326 	.reset = sandbox_testproc_reset,
327 	.load = sandbox_testproc_load,
328 	.start = sandbox_testproc_start,
329 	.stop = sandbox_testproc_stop,
330 	.is_running = sandbox_testproc_is_running,
331 	.ping = sandbox_testproc_ping,
332 	.device_to_virt = sandbox_testproc_device_to_virt,
333 };
334 
335 static const struct udevice_id sandbox_ids[] = {
336 	{.compatible = "sandbox,test-processor"},
337 	{}
338 };
339 
340 U_BOOT_DRIVER(sandbox_testproc) = {
341 	.name = "sandbox_test_proc",
342 	.of_match = sandbox_ids,
343 	.id = UCLASS_REMOTEPROC,
344 	.ops = &sandbox_testproc_ops,
345 	.probe = sandbox_testproc_probe,
346 	.priv_auto	= sizeof(struct sandbox_test_devdata),
347 };
348 
349 /* TODO(nm@ti.com): Remove this along with non-DT support */
350 static struct dm_rproc_uclass_pdata proc_3_test = {
351 	.name = "proc_3_legacy",
352 	.mem_type = RPROC_INTERNAL_MEMORY_MAPPED,
353 };
354 
355 U_BOOT_DRVINFO(proc_3_demo) = {
356 	.name = "sandbox_test_proc",
357 	.plat = &proc_3_test,
358 };
359