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