source: rtems/c/src/lib/libbsp/powerpc/beatnik/marvell/gt_timer.c @ 3964329

Last change on this file since 3964329 was 3964329, checked in by Chris Johns <chrisj@…>, on Jan 4, 2018 at 7:57:18 AM

bsp/beatnik: Use public include path

Update #3254.

  • Property mode set to 100644
File size: 9.7 KB
Line 
1/* Driver for discovery timers and watchdog */
2
3/*
4 * Acknowledgements:
5 * Valuable information was obtained from the following drivers
6 *   netbsd: (C) Allegro Networks Inc; Wasabi Systems Inc.
7 *   linux:  (C) MontaVista, Software, Inc; Mark A. Greer.
8 *   rtems:  (C) Brookhaven National Laboratory; K. Feng
9 * but this implementation is original work by the author.
10 */
11
12/*
13 * Authorship
14 * ----------
15 * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was
16 *     created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
17 *      Stanford Linear Accelerator Center, Stanford University.
18 *
19 * Acknowledgement of sponsorship
20 * ------------------------------
21 * The 'beatnik' BSP was produced by
22 *     the Stanford Linear Accelerator Center, Stanford University,
23 *      under Contract DE-AC03-76SFO0515 with the Department of Energy.
24 *
25 * Government disclaimer of liability
26 * ----------------------------------
27 * Neither the United States nor the United States Department of Energy,
28 * nor any of their employees, makes any warranty, express or implied, or
29 * assumes any legal liability or responsibility for the accuracy,
30 * completeness, or usefulness of any data, apparatus, product, or process
31 * disclosed, or represents that its use would not infringe privately owned
32 * rights.
33 *
34 * Stanford disclaimer of liability
35 * --------------------------------
36 * Stanford University makes no representations or warranties, express or
37 * implied, nor assumes any liability for the use of this software.
38 *
39 * Stanford disclaimer of copyright
40 * --------------------------------
41 * Stanford University, owner of the copyright, hereby disclaims its
42 * copyright and all other rights in this software.  Hence, anyone may
43 * freely use it for any purpose without restriction. 
44 *
45 * Maintenance of notices
46 * ----------------------
47 * In the interest of clarity regarding the origin and status of this
48 * SLAC software, this and all the preceding Stanford University notices
49 * are to remain affixed to any copy or derivative of this software made
50 * or distributed by the recipient and are to be affixed to any copy of
51 * software made or distributed by the recipient that contains a copy or
52 * derivative of this software.
53 *
54 * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
55 */ 
56
57#include <rtems.h>
58#include <bsp/gtreg.h>
59#include <libcpu/io.h>
60#include <bsp.h>
61#include <bsp/irq.h>
62#include <rtems/bspIo.h>
63
64#include <stdint.h>
65
66#include <bsp/gt_timer.h>
67
68#define DEBUG
69
70static inline uint32_t gt_rd(uint32_t off)
71{
72  return in_le32( (volatile uint32_t *)(BSP_MV64x60_BASE+off) );
73}
74
75static inline void gt_wr(uint32_t off, uint32_t val)
76{
77  out_le32( (volatile uint32_t *)(BSP_MV64x60_BASE+off), val);
78}
79
80static inline uint32_t gt_timer_bitmod(uint32_t off, uint32_t clr, uint32_t set)
81{
82  unsigned  flags;
83  uint32_t  rval;
84
85  rtems_interrupt_disable(flags);
86    rval = gt_rd( off );
87    gt_wr( off, (rval & ~clr) | set );
88  rtems_interrupt_enable(flags);
89  return rval;
90}
91
92#define GT_TIMER_MAX      3
93#define TIMER_ARGCHECK(t)  do { if ((t)>GT_TIMER_MAX) return -1; } while (0)
94
95static struct {
96  void (*isr)(void *);
97  void  *arg;
98} gt_timer_isrs[GT_TIMER_MAX+1] = {{0},};
99
100uint32_t BSP_timer_read(uint32_t timer)
101{
102  TIMER_ARGCHECK(timer);
103  return gt_rd(GT_TIMER_0 + (timer<<2));
104}
105
106int
107BSP_timer_start(uint32_t timer, uint32_t period)
108{
109  TIMER_ARGCHECK(timer);
110  gt_wr(GT_TIMER_0 + (timer<<2), period);
111  return 0;
112}
113
114int
115BSP_timer_stop(uint32_t timer)
116{
117  TIMER_ARGCHECK(timer);
118  /* disable, clear period, re-enable */
119  gt_timer_bitmod(GT_TIMER_0_3_Ctl, GT_TIMER_0_Ctl_Enb << (timer<<3), 0);
120  gt_wr(GT_TIMER_0 + (timer<<2), 0);
121  gt_timer_bitmod(GT_TIMER_0_3_Ctl, 0, GT_TIMER_0_Ctl_Enb << (timer<<3));
122  return 0;
123}
124
125int
126BSP_timer_setup(uint32_t timer, void (*isr)(void *arg), void *arg, int reload)
127{
128  TIMER_ARGCHECK(timer);
129  if ( isr && gt_timer_isrs[timer].isr )
130    return -1;
131
132  BSP_timer_stop(timer);
133  /* mask and clear */
134  gt_timer_bitmod(GT_TIMER_0_3_Intr_Msk, GT_TIMER_0_Intr<<timer, 0);
135  gt_timer_bitmod(GT_TIMER_0_3_Intr_Cse, GT_TIMER_0_Intr<<timer, 0);
136
137  /* set reload bit */
138  if ( reload )
139    gt_timer_bitmod(GT_TIMER_0_3_Ctl, 0, GT_TIMER_0_Ctl_Rld << (timer<<3));
140  else
141    gt_timer_bitmod(GT_TIMER_0_3_Ctl, GT_TIMER_0_Ctl_Rld << (timer<<3), 0);
142
143  asm volatile("":::"memory");
144
145  if ( isr ) {
146    gt_timer_isrs[timer].isr = isr;
147    gt_timer_isrs[timer].arg = arg;
148    asm volatile("":::"memory");
149    gt_timer_bitmod(GT_TIMER_0_3_Intr_Msk, 0, GT_TIMER_0_Intr<<timer);
150  } else {
151    gt_timer_isrs[timer].isr = 0;
152    gt_timer_isrs[timer].arg = 0;
153  }
154  return 0;
155}
156
157static void
158gt_timer_hdl(rtems_irq_hdl_param arg)
159{
160  int       iarg = (int)arg;
161  int       timer;
162  uint32_t  bit;
163
164  for ( ; iarg; iarg >>= 4 ) {
165    timer = (iarg & 0xf)-1;
166    bit   = GT_TIMER_0_Intr<<timer;
167    if ( gt_timer_bitmod(GT_TIMER_0_3_Intr_Cse, bit, 0) & bit ) {
168      /* cause was set */
169      if ( ! gt_timer_isrs[timer].isr ) {
170        printk("gt_timer: warning; no ISR connected but and IRQ happened (timer # %i)\n", timer);
171        /* mask */
172        gt_timer_bitmod(GT_TIMER_0_3_Intr_Msk, bit, 0);
173      } else {
174        gt_timer_isrs[timer].isr(gt_timer_isrs[timer].arg);
175      }
176    }
177  }
178}
179
180int
181BSP_timers_initialize(void)
182{
183  rtems_irq_connect_data xx = {0};
184  int                    i, ainc, arg;
185
186  xx.hdl    = gt_timer_hdl;
187  xx.on     = 0;
188  xx.off    = 0;
189  xx.isOn   = 0;
190
191  switch (BSP_getDiscoveryVersion(0)) {
192    case MV_64360:
193      i    = 3;
194      ainc = 1;
195      arg  = 4;
196      break;
197    default:
198      i    = 1;
199      ainc = 0x0202;
200      arg  = 0x0403;
201      break;
202  }
203
204  for ( ; i>=0; i--, arg-=ainc ) {
205    xx.name   = BSP_IRQ_TIME0_1 + i;
206    xx.handle = (rtems_irq_hdl_param)arg;
207    if ( !BSP_install_rtems_irq_handler(&xx) )
208      return -1;
209  }
210
211  return 0;
212}
213
214#ifdef DEBUG_MODULAR
215static int
216BSP_timers_uninstall(void)
217{
218  rtems_irq_connect_data xx = {0};
219  int                    i;
220
221  xx.hdl    = gt_timer_hdl;
222  xx.on     = 0;
223  xx.off    = 0;
224  xx.isOn   = 0;
225
226  for ( i=0; i<= GT_TIMER_MAX; i++ ) {
227    if ( BSP_timer_setup(i, 0, 0, 0) )
228      return -1;
229  }
230
231  switch (BSP_getDiscoveryVersion(0)) {
232    case MV_64360:
233      i = 3;
234      break;
235    default:
236      i = 1;
237      break;
238  }
239
240  for ( ; i >= 0; i-- ) {
241    xx.name  = BSP_IRQ_TIME0_1 + i;
242    BSP_get_current_rtems_irq_handler(&xx);
243    if ( !BSP_remove_rtems_irq_handler(&xx) )
244      return -1;
245  }
246
247  return 0;
248}
249#endif
250
251uint32_t
252BSP_timer_clock_get(uint32_t timer)
253{
254  return BSP_bus_frequency;
255}
256
257int BSP_timer_instances(void)
258{
259  return GT_TIMER_MAX + 1;
260}
261
262/* On a 64260A we can't read the status (on/off), apparently
263 * so we maintain it locally and assume the firmware has
264 * not enabled the dog initially...
265 */
266static uint32_t wdog_on = 0x00ffffff;
267
268static uint32_t rd_wdcnf(void)
269{
270  uint32_t cnf = gt_rd(GT_WDOG_Config);
271
272  /* BSD driver says that on the 64260A we always
273   * read 0xffffffff so we have to maintain the
274   * status locally (and hope we get the initial
275   * value right).
276   */
277  if ( ~0 == cnf )
278    cnf = wdog_on;
279  return cnf;
280}
281
282/* change on/off state assume caller has IRQs disabled */
283static void dog_toggle(uint32_t ctl)
284{
285  ctl &= ~( GT_WDOG_Config_Ctl1a | GT_WDOG_Config_Ctl1b \
286          | GT_WDOG_Config_Ctl2a | GT_WDOG_Config_Ctl2b);
287  gt_wr(GT_WDOG_Config, ctl | GT_WDOG_Config_Ctl1a);
288  gt_wr(GT_WDOG_Config, ctl | GT_WDOG_Config_Ctl1b);
289}
290
291static void dog_pet(uint32_t ctl)
292{
293  ctl &= ~( GT_WDOG_Config_Ctl1a | GT_WDOG_Config_Ctl1b \
294          | GT_WDOG_Config_Ctl2a | GT_WDOG_Config_Ctl2b);
295  gt_wr(GT_WDOG_Config, ctl | GT_WDOG_Config_Ctl2a);
296  gt_wr(GT_WDOG_Config, ctl | GT_WDOG_Config_Ctl2b);
297}
298
299
300/* Enable watchdog and set a timeout (in us)
301 * a timeout of 0xffffffff selects the old/existing
302 * timeout.
303 *
304 * RETURNS 0 on success
305 */
306int
307BSP_watchdog_enable(uint32_t timeout_us)
308{
309  unsigned long long x = timeout_us;
310  unsigned flags;
311  uint32_t ctl;
312
313  x *= BSP_bus_frequency;
314  x /= 256;     /* there seems to be a prescaler */
315    x /= 1000000; /* us/s                          */
316
317  if ( x > (1<<24)-1 )
318    x = (1<<24)-1;
319
320  if ( 0xffffffff != timeout_us )
321    timeout_us = x;
322
323  rtems_interrupt_disable(flags);
324
325  ctl = rd_wdcnf();
326
327  /* if enabled, disable first */
328  if ( GT_WDOG_Config_Enb & ctl ) {
329    dog_toggle(ctl);
330  }
331  if ( 0xffffffff == timeout_us ) {
332    timeout_us = ctl & ((1<<24)-1);
333    dog_toggle(ctl);
334    dog_pet(ctl);
335  } else {
336    gt_wr(GT_WDOG_Config, timeout_us | GT_WDOG_Config_Ctl1a);
337    gt_wr(GT_WDOG_Config, timeout_us | GT_WDOG_Config_Ctl1b);
338  }
339
340  wdog_on = GT_WDOG_Config_Enb | timeout_us;
341
342  rtems_interrupt_enable(flags);
343  return 0;
344}
345
346/* Disable watchdog
347 * RETURNS 0 on success
348 */
349int BSP_watchdog_disable(void)
350{
351unsigned long flags;
352uint32_t      ctl;
353
354  rtems_interrupt_disable(flags);
355
356  ctl = rd_wdcnf();
357
358  if ( (GT_WDOG_Config_Enb & ctl) ) {
359    dog_toggle(ctl);
360    wdog_on = ctl & ~(GT_WDOG_Config_Enb);
361  }
362
363  rtems_interrupt_enable(flags);
364  return 0;
365}
366
367/* Check status -- unfortunately there seems to be no way
368 * to read the running value...
369 *
370 * RETURNS nonzero if enabled/running, zero if disabled/stopped
371 */
372int BSP_watchdog_status(void)
373{
374  uint32_t ctl = rd_wdcnf();
375
376  /* report also the current period */
377  return GT_WDOG_Config_Enb & ctl ? ctl : 0;
378}
379
380/* Pet the watchdog (rearm to configured timeout)
381 * RETURNS: 0 on success, nonzero on failure (watchdog
382 * currently not running).
383 */
384int BSP_watchdog_pet(void)
385{
386  unsigned long flags;
387
388  if ( !wdog_on )
389    return -1;
390  rtems_interrupt_disable(flags);
391    dog_pet(rd_wdcnf());
392  rtems_interrupt_enable(flags);
393  return 0;
394}
395
396
397#ifdef DEBUG_MODULAR
398int
399_cexpModuleFinalize(void *unused)
400{
401  BSP_watchdog_disable();
402  return BSP_timers_uninstall();
403}
404
405void
406_cexpModuleInitialize(void *unused)
407{
408  BSP_timers_initialize();
409}
410#endif
Note: See TracBrowser for help on using the repository browser.