26
26
#include <linux/regmap.h>
27
27
#include <linux/mfd/syscon.h>
28
28
#include <linux/reset.h>
29
+ #include <clocksource/timer-ti-dm.h>
30
+
31
+ #include <linux/platform_data/dmtimer-omap.h>
29
32
30
33
#include "omap_remoteproc.h"
31
34
#include "remoteproc_internal.h"
@@ -57,13 +60,25 @@ struct omap_rproc_mem {
57
60
size_t size ;
58
61
};
59
62
63
+ /**
64
+ * struct omap_rproc_timer - data structure for a timer used by a omap rproc
65
+ * @odt: timer pointer
66
+ * @timer_ops: OMAP dmtimer ops for @odt timer
67
+ */
68
+ struct omap_rproc_timer {
69
+ struct omap_dm_timer * odt ;
70
+ const struct omap_dm_timer_ops * timer_ops ;
71
+ };
72
+
60
73
/**
61
74
* struct omap_rproc - omap remote processor state
62
75
* @mbox: mailbox channel handle
63
76
* @client: mailbox client to request the mailbox channel
64
77
* @boot_data: boot data structure for setting processor boot address
65
78
* @mem: internal memory regions data
66
79
* @num_mems: number of internal memory regions
80
+ * @num_timers: number of rproc timer(s)
81
+ * @timers: timer(s) info used by rproc
67
82
* @rproc: rproc handle
68
83
* @reset: reset handle
69
84
*/
@@ -73,6 +88,8 @@ struct omap_rproc {
73
88
struct omap_rproc_boot_data * boot_data ;
74
89
struct omap_rproc_mem * mem ;
75
90
int num_mems ;
91
+ int num_timers ;
92
+ struct omap_rproc_timer * timers ;
76
93
struct rproc * rproc ;
77
94
struct reset_control * reset ;
78
95
};
@@ -97,6 +114,231 @@ struct omap_rproc_dev_data {
97
114
const struct omap_rproc_mem_data * mems ;
98
115
};
99
116
117
+ /**
118
+ * omap_rproc_request_timer() - request a timer for a remoteproc
119
+ * @dev: device requesting the timer
120
+ * @np: device node pointer to the desired timer
121
+ * @timer: handle to a struct omap_rproc_timer to return the timer handle
122
+ *
123
+ * This helper function is used primarily to request a timer associated with
124
+ * a remoteproc. The returned handle is stored in the .odt field of the
125
+ * @timer structure passed in, and is used to invoke other timer specific
126
+ * ops (like starting a timer either during device initialization or during
127
+ * a resume operation, or for stopping/freeing a timer).
128
+ *
129
+ * Return: 0 on success, otherwise an appropriate failure
130
+ */
131
+ static int omap_rproc_request_timer (struct device * dev , struct device_node * np ,
132
+ struct omap_rproc_timer * timer )
133
+ {
134
+ int ret ;
135
+
136
+ timer -> odt = timer -> timer_ops -> request_by_node (np );
137
+ if (!timer -> odt ) {
138
+ dev_err (dev , "request for timer node %p failed\n" , np );
139
+ return - EBUSY ;
140
+ }
141
+
142
+ ret = timer -> timer_ops -> set_source (timer -> odt , OMAP_TIMER_SRC_SYS_CLK );
143
+ if (ret ) {
144
+ dev_err (dev , "error setting OMAP_TIMER_SRC_SYS_CLK as source for timer node %p\n" ,
145
+ np );
146
+ timer -> timer_ops -> free (timer -> odt );
147
+ return ret ;
148
+ }
149
+
150
+ /* clean counter, remoteproc code will set the value */
151
+ timer -> timer_ops -> set_load (timer -> odt , 0 , 0 );
152
+
153
+ return 0 ;
154
+ }
155
+
156
+ /**
157
+ * omap_rproc_start_timer() - start a timer for a remoteproc
158
+ * @timer: handle to a OMAP rproc timer
159
+ *
160
+ * This helper function is used to start a timer associated with a remoteproc,
161
+ * obtained using the request_timer ops. The helper function needs to be
162
+ * invoked by the driver to start the timer (during device initialization)
163
+ * or to just resume the timer.
164
+ *
165
+ * Return: 0 on success, otherwise a failure as returned by DMTimer ops
166
+ */
167
+ static inline int omap_rproc_start_timer (struct omap_rproc_timer * timer )
168
+ {
169
+ return timer -> timer_ops -> start (timer -> odt );
170
+ }
171
+
172
+ /**
173
+ * omap_rproc_stop_timer() - stop a timer for a remoteproc
174
+ * @timer: handle to a OMAP rproc timer
175
+ *
176
+ * This helper function is used to disable a timer associated with a
177
+ * remoteproc, and needs to be called either during a device shutdown
178
+ * or suspend operation. The separate helper function allows the driver
179
+ * to just stop a timer without having to release the timer during a
180
+ * suspend operation.
181
+ *
182
+ * Return: 0 on success, otherwise a failure as returned by DMTimer ops
183
+ */
184
+ static inline int omap_rproc_stop_timer (struct omap_rproc_timer * timer )
185
+ {
186
+ return timer -> timer_ops -> stop (timer -> odt );
187
+ }
188
+
189
+ /**
190
+ * omap_rproc_release_timer() - release a timer for a remoteproc
191
+ * @timer: handle to a OMAP rproc timer
192
+ *
193
+ * This helper function is used primarily to release a timer associated
194
+ * with a remoteproc. The dmtimer will be available for other clients to
195
+ * use once released.
196
+ *
197
+ * Return: 0 on success, otherwise a failure as returned by DMTimer ops
198
+ */
199
+ static inline int omap_rproc_release_timer (struct omap_rproc_timer * timer )
200
+ {
201
+ return timer -> timer_ops -> free (timer -> odt );
202
+ }
203
+
204
+ /**
205
+ * omap_rproc_enable_timers() - enable the timers for a remoteproc
206
+ * @rproc: handle of a remote processor
207
+ * @configure: boolean flag used to acquire and configure the timer handle
208
+ *
209
+ * This function is used primarily to enable the timers associated with
210
+ * a remoteproc. The configure flag is provided to allow the driver to
211
+ * to either acquire and start a timer (during device initialization) or
212
+ * to just start a timer (during a resume operation).
213
+ *
214
+ * Return: 0 on success, otherwise an appropriate failure
215
+ */
216
+ static int omap_rproc_enable_timers (struct rproc * rproc , bool configure )
217
+ {
218
+ int i ;
219
+ int ret = 0 ;
220
+ struct platform_device * tpdev ;
221
+ struct dmtimer_platform_data * tpdata ;
222
+ const struct omap_dm_timer_ops * timer_ops ;
223
+ struct omap_rproc * oproc = rproc -> priv ;
224
+ struct omap_rproc_timer * timers = oproc -> timers ;
225
+ struct device * dev = rproc -> dev .parent ;
226
+ struct device_node * np = NULL ;
227
+
228
+ if (!oproc -> num_timers )
229
+ return 0 ;
230
+
231
+ if (!configure )
232
+ goto start_timers ;
233
+
234
+ for (i = 0 ; i < oproc -> num_timers ; i ++ ) {
235
+ np = of_parse_phandle (dev -> of_node , "ti,timers" , i );
236
+ if (!np ) {
237
+ ret = - ENXIO ;
238
+ dev_err (dev , "device node lookup for timer at index %d failed: %d\n" ,
239
+ i , ret );
240
+ goto free_timers ;
241
+ }
242
+
243
+ tpdev = of_find_device_by_node (np );
244
+ if (!tpdev ) {
245
+ ret = - ENODEV ;
246
+ dev_err (dev , "could not get timer platform device\n" );
247
+ goto put_node ;
248
+ }
249
+
250
+ tpdata = dev_get_platdata (& tpdev -> dev );
251
+ put_device (& tpdev -> dev );
252
+ if (!tpdata ) {
253
+ ret = - EINVAL ;
254
+ dev_err (dev , "dmtimer pdata structure NULL\n" );
255
+ goto put_node ;
256
+ }
257
+
258
+ timer_ops = tpdata -> timer_ops ;
259
+ if (!timer_ops || !timer_ops -> request_by_node ||
260
+ !timer_ops -> set_source || !timer_ops -> set_load ||
261
+ !timer_ops -> free || !timer_ops -> start ||
262
+ !timer_ops -> stop ) {
263
+ ret = - EINVAL ;
264
+ dev_err (dev , "device does not have required timer ops\n" );
265
+ goto put_node ;
266
+ }
267
+
268
+ timers [i ].timer_ops = timer_ops ;
269
+ ret = omap_rproc_request_timer (dev , np , & timers [i ]);
270
+ if (ret ) {
271
+ dev_err (dev , "request for timer %p failed: %d\n" , np ,
272
+ ret );
273
+ goto put_node ;
274
+ }
275
+ of_node_put (np );
276
+ }
277
+
278
+ start_timers :
279
+ for (i = 0 ; i < oproc -> num_timers ; i ++ ) {
280
+ ret = omap_rproc_start_timer (& timers [i ]);
281
+ if (ret ) {
282
+ dev_err (dev , "start timer %p failed failed: %d\n" , np ,
283
+ ret );
284
+ break ;
285
+ }
286
+ }
287
+ if (ret ) {
288
+ while (i >= 0 ) {
289
+ omap_rproc_stop_timer (& timers [i ]);
290
+ i -- ;
291
+ }
292
+ goto put_node ;
293
+ }
294
+ return 0 ;
295
+
296
+ put_node :
297
+ if (configure )
298
+ of_node_put (np );
299
+ free_timers :
300
+ while (i -- ) {
301
+ omap_rproc_release_timer (& timers [i ]);
302
+ timers [i ].odt = NULL ;
303
+ timers [i ].timer_ops = NULL ;
304
+ }
305
+
306
+ return ret ;
307
+ }
308
+
309
+ /**
310
+ * omap_rproc_disable_timers() - disable the timers for a remoteproc
311
+ * @rproc: handle of a remote processor
312
+ * @configure: boolean flag used to release the timer handle
313
+ *
314
+ * This function is used primarily to disable the timers associated with
315
+ * a remoteproc. The configure flag is provided to allow the driver to
316
+ * to either stop and release a timer (during device shutdown) or to just
317
+ * stop a timer (during a suspend operation).
318
+ *
319
+ * Return: 0 on success or no timers
320
+ */
321
+ static int omap_rproc_disable_timers (struct rproc * rproc , bool configure )
322
+ {
323
+ int i ;
324
+ struct omap_rproc * oproc = rproc -> priv ;
325
+ struct omap_rproc_timer * timers = oproc -> timers ;
326
+
327
+ if (!oproc -> num_timers )
328
+ return 0 ;
329
+
330
+ for (i = 0 ; i < oproc -> num_timers ; i ++ ) {
331
+ omap_rproc_stop_timer (& timers [i ]);
332
+ if (configure ) {
333
+ omap_rproc_release_timer (& timers [i ]);
334
+ timers [i ].odt = NULL ;
335
+ timers [i ].timer_ops = NULL ;
336
+ }
337
+ }
338
+
339
+ return 0 ;
340
+ }
341
+
100
342
/**
101
343
* omap_rproc_mbox_callback() - inbound mailbox message handler
102
344
* @client: mailbox client pointer used for requesting the mailbox channel
@@ -232,14 +474,22 @@ static int omap_rproc_start(struct rproc *rproc)
232
474
goto put_mbox ;
233
475
}
234
476
477
+ ret = omap_rproc_enable_timers (rproc , true);
478
+ if (ret ) {
479
+ dev_err (dev , "omap_rproc_enable_timers failed: %d\n" , ret );
480
+ goto put_mbox ;
481
+ }
482
+
235
483
ret = reset_control_deassert (oproc -> reset );
236
484
if (ret ) {
237
485
dev_err (dev , "reset control deassert failed: %d\n" , ret );
238
- goto put_mbox ;
486
+ goto disable_timers ;
239
487
}
240
488
241
489
return 0 ;
242
490
491
+ disable_timers :
492
+ omap_rproc_disable_timers (rproc , true);
243
493
put_mbox :
244
494
mbox_free_channel (oproc -> mbox );
245
495
return ret ;
@@ -255,6 +505,10 @@ static int omap_rproc_stop(struct rproc *rproc)
255
505
if (ret )
256
506
return ret ;
257
507
508
+ ret = omap_rproc_disable_timers (rproc , true);
509
+ if (ret )
510
+ return ret ;
511
+
258
512
mbox_free_channel (oproc -> mbox );
259
513
260
514
return 0 ;
@@ -482,6 +736,37 @@ static int omap_rproc_of_get_internal_memories(struct platform_device *pdev,
482
736
return 0 ;
483
737
}
484
738
739
+ static int omap_rproc_of_get_timers (struct platform_device * pdev ,
740
+ struct rproc * rproc )
741
+ {
742
+ struct device_node * np = pdev -> dev .of_node ;
743
+ struct omap_rproc * oproc = rproc -> priv ;
744
+ struct device * dev = & pdev -> dev ;
745
+
746
+ /*
747
+ * Timer nodes are directly used in client nodes as phandles, so
748
+ * retrieve the count using appropriate size
749
+ */
750
+ oproc -> num_timers = of_count_phandle_with_args (np , "ti,timers" , NULL );
751
+ if (oproc -> num_timers <= 0 ) {
752
+ dev_dbg (dev , "device does not have timers, status = %d\n" ,
753
+ oproc -> num_timers );
754
+ oproc -> num_timers = 0 ;
755
+ }
756
+
757
+ if (oproc -> num_timers ) {
758
+ oproc -> timers = devm_kcalloc (dev , oproc -> num_timers ,
759
+ sizeof (* oproc -> timers ),
760
+ GFP_KERNEL );
761
+ if (!oproc -> timers )
762
+ return - ENOMEM ;
763
+
764
+ dev_dbg (dev , "device has %d tick timers\n" , oproc -> num_timers );
765
+ }
766
+
767
+ return 0 ;
768
+ }
769
+
485
770
static int omap_rproc_probe (struct platform_device * pdev )
486
771
{
487
772
struct device_node * np = pdev -> dev .of_node ;
@@ -529,6 +814,10 @@ static int omap_rproc_probe(struct platform_device *pdev)
529
814
if (ret )
530
815
goto free_rproc ;
531
816
817
+ ret = omap_rproc_of_get_timers (pdev , rproc );
818
+ if (ret )
819
+ goto free_rproc ;
820
+
532
821
ret = of_reserved_mem_device_init (& pdev -> dev );
533
822
if (ret ) {
534
823
dev_warn (& pdev -> dev , "device does not have specific CMA pool.\n" );
0 commit comments