Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:52

0001 /* Driver for discovery timers and watchdog */
0002 
0003 /* 
0004  * Acknowledgements:
0005  * Valuable information was obtained from the following drivers
0006  *   netbsd: (C) Allegro Networks Inc; Wasabi Systems Inc.
0007  *   linux:  (C) MontaVista, Software, Inc; Mark A. Greer.
0008  *   rtems:  (C) Brookhaven National Laboratory; K. Feng
0009  * but this implementation is original work by the author.
0010  */
0011 
0012 /* 
0013  * Authorship
0014  * ----------
0015  * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was
0016  *     created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
0017  *      Stanford Linear Accelerator Center, Stanford University.
0018  * 
0019  * Acknowledgement of sponsorship
0020  * ------------------------------
0021  * The 'beatnik' BSP was produced by
0022  *     the Stanford Linear Accelerator Center, Stanford University,
0023  *      under Contract DE-AC03-76SFO0515 with the Department of Energy.
0024  * 
0025  * Government disclaimer of liability
0026  * ----------------------------------
0027  * Neither the United States nor the United States Department of Energy,
0028  * nor any of their employees, makes any warranty, express or implied, or
0029  * assumes any legal liability or responsibility for the accuracy,
0030  * completeness, or usefulness of any data, apparatus, product, or process
0031  * disclosed, or represents that its use would not infringe privately owned
0032  * rights.
0033  * 
0034  * Stanford disclaimer of liability
0035  * --------------------------------
0036  * Stanford University makes no representations or warranties, express or
0037  * implied, nor assumes any liability for the use of this software.
0038  * 
0039  * Stanford disclaimer of copyright
0040  * --------------------------------
0041  * Stanford University, owner of the copyright, hereby disclaims its
0042  * copyright and all other rights in this software.  Hence, anyone may
0043  * freely use it for any purpose without restriction.  
0044  * 
0045  * Maintenance of notices
0046  * ----------------------
0047  * In the interest of clarity regarding the origin and status of this
0048  * SLAC software, this and all the preceding Stanford University notices
0049  * are to remain affixed to any copy or derivative of this software made
0050  * or distributed by the recipient and are to be affixed to any copy of
0051  * software made or distributed by the recipient that contains a copy or
0052  * derivative of this software.
0053  * 
0054  * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
0055  */ 
0056 
0057 #include <rtems.h>
0058 #include <bsp/gtreg.h>
0059 #include <libcpu/io.h>
0060 #include <bsp.h>
0061 #include <bsp/irq.h>
0062 #include <rtems/bspIo.h>
0063 
0064 #include <stdint.h>
0065 
0066 #include <bsp/gt_timer.h>
0067 
0068 #define DEBUG
0069 
0070 static inline uint32_t gt_rd(uint32_t off)
0071 {
0072   return in_le32( (volatile uint32_t *)(BSP_MV64x60_BASE+off) );
0073 }
0074 
0075 static inline void gt_wr(uint32_t off, uint32_t val)
0076 {
0077   out_le32( (volatile uint32_t *)(BSP_MV64x60_BASE+off), val);
0078 }
0079 
0080 static inline uint32_t gt_timer_bitmod(uint32_t off, uint32_t clr, uint32_t set)
0081 {
0082   unsigned  flags;
0083   uint32_t  rval;
0084 
0085   rtems_interrupt_disable(flags);
0086     rval = gt_rd( off );
0087     gt_wr( off, (rval & ~clr) | set );
0088   rtems_interrupt_enable(flags);
0089   return rval;
0090 }
0091 
0092 #define GT_TIMER_MAX      3
0093 #define TIMER_ARGCHECK(t)  do { if ((t)>GT_TIMER_MAX) return -1; } while (0)
0094 
0095 static struct {
0096   void (*isr)(void *);
0097   void  *arg;
0098 } gt_timer_isrs[GT_TIMER_MAX+1] = {{0},};
0099 
0100 uint32_t BSP_timer_read(uint32_t timer)
0101 {
0102   TIMER_ARGCHECK(timer);
0103   return gt_rd(GT_TIMER_0 + (timer<<2));
0104 }
0105 
0106 int
0107 BSP_timer_start(uint32_t timer, uint32_t period)
0108 {
0109   TIMER_ARGCHECK(timer);
0110   gt_wr(GT_TIMER_0 + (timer<<2), period);
0111   return 0;
0112 }
0113 
0114 int
0115 BSP_timer_stop(uint32_t timer)
0116 {
0117   TIMER_ARGCHECK(timer);
0118   /* disable, clear period, re-enable */
0119   gt_timer_bitmod(GT_TIMER_0_3_Ctl, GT_TIMER_0_Ctl_Enb << (timer<<3), 0);
0120   gt_wr(GT_TIMER_0 + (timer<<2), 0);
0121   gt_timer_bitmod(GT_TIMER_0_3_Ctl, 0, GT_TIMER_0_Ctl_Enb << (timer<<3));
0122   return 0;
0123 }
0124 
0125 int
0126 BSP_timer_setup(uint32_t timer, void (*isr)(void *arg), void *arg, int reload)
0127 {
0128   TIMER_ARGCHECK(timer);
0129   if ( isr && gt_timer_isrs[timer].isr )
0130     return -1;
0131 
0132   BSP_timer_stop(timer);
0133   /* mask and clear */
0134   gt_timer_bitmod(GT_TIMER_0_3_Intr_Msk, GT_TIMER_0_Intr<<timer, 0);
0135   gt_timer_bitmod(GT_TIMER_0_3_Intr_Cse, GT_TIMER_0_Intr<<timer, 0);
0136 
0137   /* set reload bit */
0138   if ( reload )
0139     gt_timer_bitmod(GT_TIMER_0_3_Ctl, 0, GT_TIMER_0_Ctl_Rld << (timer<<3));
0140   else
0141     gt_timer_bitmod(GT_TIMER_0_3_Ctl, GT_TIMER_0_Ctl_Rld << (timer<<3), 0);
0142 
0143   asm volatile("":::"memory");
0144 
0145   if ( isr ) {
0146     gt_timer_isrs[timer].isr = isr;
0147     gt_timer_isrs[timer].arg = arg;
0148     asm volatile("":::"memory");
0149     gt_timer_bitmod(GT_TIMER_0_3_Intr_Msk, 0, GT_TIMER_0_Intr<<timer);
0150   } else {
0151     gt_timer_isrs[timer].isr = 0;
0152     gt_timer_isrs[timer].arg = 0;
0153   }
0154   return 0;
0155 }
0156 
0157 static void
0158 gt_timer_hdl(rtems_irq_hdl_param arg)
0159 {
0160   int       iarg = (int)arg;
0161   int       timer;
0162   uint32_t  bit;
0163 
0164   for ( ; iarg; iarg >>= 4 ) {
0165     timer = (iarg & 0xf)-1;
0166     bit   = GT_TIMER_0_Intr<<timer;
0167     if ( gt_timer_bitmod(GT_TIMER_0_3_Intr_Cse, bit, 0) & bit ) {
0168       /* cause was set */
0169       if ( ! gt_timer_isrs[timer].isr ) {
0170         printk("gt_timer: warning; no ISR connected but and IRQ happened (timer # %i)\n", timer);
0171         /* mask */
0172         gt_timer_bitmod(GT_TIMER_0_3_Intr_Msk, bit, 0);
0173       } else {
0174         gt_timer_isrs[timer].isr(gt_timer_isrs[timer].arg);
0175       }
0176     }
0177   }
0178 }
0179 
0180 int
0181 BSP_timers_initialize(void)
0182 {
0183   rtems_irq_connect_data xx = {0};
0184   int                    i, ainc, arg;
0185 
0186   xx.hdl    = gt_timer_hdl;
0187   xx.on     = 0;
0188   xx.off    = 0;
0189   xx.isOn   = 0;
0190 
0191   switch (BSP_getDiscoveryVersion(0)) {
0192     case MV_64360:
0193       i    = 3;
0194       ainc = 1;
0195       arg  = 4;
0196       break;
0197     default:
0198       i    = 1;
0199       ainc = 0x0202;
0200       arg  = 0x0403;
0201       break;
0202   }
0203 
0204   for ( ; i>=0; i--, arg-=ainc ) {
0205     xx.name   = BSP_IRQ_TIME0_1 + i;
0206     xx.handle = (rtems_irq_hdl_param)arg;
0207     if ( !BSP_install_rtems_irq_handler(&xx) )
0208       return -1;
0209   }
0210 
0211   return 0;
0212 }
0213 
0214 #ifdef DEBUG_MODULAR
0215 static int
0216 BSP_timers_uninstall(void)
0217 {
0218   rtems_irq_connect_data xx = {0};
0219   int                    i;
0220 
0221   xx.hdl    = gt_timer_hdl;
0222   xx.on     = 0;
0223   xx.off    = 0;
0224   xx.isOn   = 0;
0225 
0226   for ( i=0; i<= GT_TIMER_MAX; i++ ) {
0227     if ( BSP_timer_setup(i, 0, 0, 0) )
0228       return -1;
0229   }
0230 
0231   switch (BSP_getDiscoveryVersion(0)) {
0232     case MV_64360:
0233       i = 3;
0234       break;
0235     default:
0236       i = 1;
0237       break;
0238   }
0239 
0240   for ( ; i >= 0; i-- ) {
0241     xx.name  = BSP_IRQ_TIME0_1 + i;
0242     BSP_get_current_rtems_irq_handler(&xx);
0243     if ( !BSP_remove_rtems_irq_handler(&xx) )
0244       return -1;
0245   }
0246 
0247   return 0;
0248 }
0249 #endif
0250 
0251 uint32_t
0252 BSP_timer_clock_get(uint32_t timer)
0253 {
0254   return BSP_bus_frequency;
0255 }
0256 
0257 int BSP_timer_instances(void)
0258 {
0259   return GT_TIMER_MAX + 1;
0260 }
0261 
0262 /* On a 64260A we can't read the status (on/off), apparently
0263  * so we maintain it locally and assume the firmware has
0264  * not enabled the dog initially...
0265  */
0266 static uint32_t wdog_on = 0x00ffffff;
0267 
0268 static uint32_t rd_wdcnf(void)
0269 {
0270   uint32_t cnf = gt_rd(GT_WDOG_Config);
0271 
0272   /* BSD driver says that on the 64260A we always
0273    * read 0xffffffff so we have to maintain the
0274    * status locally (and hope we get the initial
0275    * value right).
0276    */
0277   if ( ~0 == cnf )
0278     cnf = wdog_on;
0279   return cnf;
0280 }
0281 
0282 /* change on/off state assume caller has IRQs disabled */
0283 static void dog_toggle(uint32_t ctl)
0284 {
0285   ctl &= ~( GT_WDOG_Config_Ctl1a | GT_WDOG_Config_Ctl1b \
0286           | GT_WDOG_Config_Ctl2a | GT_WDOG_Config_Ctl2b);
0287   gt_wr(GT_WDOG_Config, ctl | GT_WDOG_Config_Ctl1a);
0288   gt_wr(GT_WDOG_Config, ctl | GT_WDOG_Config_Ctl1b);
0289 }
0290 
0291 static void dog_pet(uint32_t ctl)
0292 {
0293   ctl &= ~( GT_WDOG_Config_Ctl1a | GT_WDOG_Config_Ctl1b \
0294           | GT_WDOG_Config_Ctl2a | GT_WDOG_Config_Ctl2b);
0295   gt_wr(GT_WDOG_Config, ctl | GT_WDOG_Config_Ctl2a);
0296   gt_wr(GT_WDOG_Config, ctl | GT_WDOG_Config_Ctl2b);
0297 }
0298 
0299 
0300 /* Enable watchdog and set a timeout (in us)
0301  * a timeout of 0xffffffff selects the old/existing
0302  * timeout.
0303  *
0304  * RETURNS 0 on success
0305  */
0306 int
0307 BSP_watchdog_enable(uint32_t timeout_us)
0308 {
0309   unsigned long long x = timeout_us;
0310   unsigned flags;
0311   uint32_t ctl;
0312 
0313   x *= BSP_bus_frequency;
0314   x /= 256;     /* there seems to be a prescaler */
0315     x /= 1000000; /* us/s                          */
0316 
0317   if ( x > (1<<24)-1 )
0318     x = (1<<24)-1;
0319 
0320   if ( 0xffffffff != timeout_us )
0321     timeout_us = x;
0322 
0323   rtems_interrupt_disable(flags);
0324 
0325   ctl = rd_wdcnf();
0326 
0327   /* if enabled, disable first */
0328   if ( GT_WDOG_Config_Enb & ctl ) {
0329     dog_toggle(ctl);
0330   }
0331   if ( 0xffffffff == timeout_us ) {
0332     timeout_us = ctl & ((1<<24)-1);
0333     dog_toggle(ctl);
0334     dog_pet(ctl);
0335   } else {
0336     gt_wr(GT_WDOG_Config, timeout_us | GT_WDOG_Config_Ctl1a);
0337     gt_wr(GT_WDOG_Config, timeout_us | GT_WDOG_Config_Ctl1b);
0338   }
0339 
0340   wdog_on = GT_WDOG_Config_Enb | timeout_us;
0341 
0342   rtems_interrupt_enable(flags);
0343   return 0;
0344 }
0345 
0346 /* Disable watchdog
0347  * RETURNS 0 on success
0348  */
0349 int BSP_watchdog_disable(void)
0350 {
0351 unsigned long flags;
0352 uint32_t      ctl;
0353 
0354   rtems_interrupt_disable(flags);
0355 
0356   ctl = rd_wdcnf();
0357 
0358   if ( (GT_WDOG_Config_Enb & ctl) ) {
0359     dog_toggle(ctl);
0360     wdog_on = ctl & ~(GT_WDOG_Config_Enb);
0361   }
0362 
0363   rtems_interrupt_enable(flags);
0364   return 0;
0365 }
0366 
0367 /* Check status -- unfortunately there seems to be no way
0368  * to read the running value...
0369  *
0370  * RETURNS nonzero if enabled/running, zero if disabled/stopped
0371  */
0372 int BSP_watchdog_status(void)
0373 {
0374   uint32_t ctl = rd_wdcnf();
0375 
0376   /* report also the current period */
0377   return GT_WDOG_Config_Enb & ctl ? ctl : 0;
0378 }
0379 
0380 /* Pet the watchdog (rearm to configured timeout)
0381  * RETURNS: 0 on success, nonzero on failure (watchdog
0382  * currently not running).
0383  */
0384 int BSP_watchdog_pet(void)
0385 {
0386   unsigned long flags;
0387 
0388   if ( !wdog_on )
0389     return -1;
0390   rtems_interrupt_disable(flags);
0391     dog_pet(rd_wdcnf());
0392   rtems_interrupt_enable(flags);
0393   return 0;
0394 }
0395 
0396 
0397 #ifdef DEBUG_MODULAR
0398 int
0399 _cexpModuleFinalize(void *unused)
0400 {
0401   BSP_watchdog_disable();
0402   return BSP_timers_uninstall();
0403 }
0404 
0405 void
0406 _cexpModuleInitialize(void *unused)
0407 {
0408   BSP_timers_initialize();
0409 }
0410 #endif