Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:01

0001 /**
0002  *  @file
0003  *  @brief Timer driver for the Hitachi SH 7750
0004  */
0005 
0006 /*
0007  *  Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
0008  *  Author: Victor V. Vengerov <vvv@oktet.ru>
0009  *
0010  *  COPYRIGHT (c) 1998.
0011  *  On-Line Applications Research Corporation (OAR).
0012  *
0013  *  The license and distribution terms for this file may be
0014  *  found in the file LICENSE in this distribution or at
0015  *  http://www.rtems.org/license/LICENSE.
0016  */
0017 
0018 #include <rtems.h>
0019 #include <rtems/btimer.h>
0020 
0021 #include <rtems/score/sh_io.h>
0022 #include <rtems/score/iosh7750.h>
0023 
0024 extern uint32_t bsp_clicks_per_second;
0025 
0026 #ifndef TIMER_PRIO
0027 #define TIMER_PRIO 15
0028 #endif
0029 
0030 /* Timer prescaler division ratio */
0031 #define TIMER_PRESCALER 4
0032 #define TCR1_TPSC       SH7750_TCR_TPSC_DIV4
0033 
0034 #define TIMER_VECTOR SH7750_EVT_TO_NUM(SH7750_EVT_TUNI1)
0035 
0036 extern rtems_isr timerisr(void);
0037 
0038 static uint32_t   Timer_interrupts;
0039 
0040 /* Counter should be divided to this value to obtain time in microseconds */
0041 static uint32_t   microseconds_divider;
0042 
0043 /* Interrupt period in microseconds */
0044 static uint32_t   microseconds_per_int;
0045 
0046 bool benchmark_timer_find_average_overhead;
0047 
0048 /* benchmark_timer_initialize --
0049  *     Initialize Timer 1 to operate as a RTEMS benchmark timer:
0050  *        - determine timer clock frequency
0051  *        - install timer interrupt handler
0052  *        - configure the Timer 1 hardware
0053  *        - start the timer
0054  *
0055  * PARAMETERS:
0056  *     none
0057  *
0058  * RETURNS:
0059  *     none
0060  */
0061 void
0062 benchmark_timer_initialize(void)
0063 {
0064     uint8_t               temp8;
0065     uint16_t              temp16;
0066     rtems_interrupt_level level;
0067     rtems_isr            *ignored;
0068     int                   cpudiv = 1;
0069     int                   tidiv = 1;
0070 
0071     Timer_interrupts  = 0;
0072     rtems_interrupt_disable(level);
0073 
0074     /* Get CPU frequency divider from clock unit */
0075     switch (read16(SH7750_FRQCR) & SH7750_FRQCR_IFC)
0076     {
0077         case SH7750_FRQCR_IFCDIV1:
0078             cpudiv = 1;
0079             break;
0080 
0081         case SH7750_FRQCR_IFCDIV2:
0082             cpudiv = 2;
0083             break;
0084 
0085         case SH7750_FRQCR_IFCDIV3:
0086             cpudiv = 3;
0087             break;
0088 
0089         case SH7750_FRQCR_IFCDIV4:
0090             cpudiv = 4;
0091             break;
0092 
0093         case SH7750_FRQCR_IFCDIV6:
0094             cpudiv = 6;
0095             break;
0096 
0097         case SH7750_FRQCR_IFCDIV8:
0098             cpudiv = 8;
0099             break;
0100 
0101         default:
0102             rtems_fatal_error_occurred( RTEMS_NOT_CONFIGURED);
0103     }
0104 
0105     /* Get peripheral module frequency divider from clock unit */
0106     switch (read16(SH7750_FRQCR) & SH7750_FRQCR_PFC)
0107     {
0108         case SH7750_FRQCR_PFCDIV2:
0109             tidiv = 2 * TIMER_PRESCALER;
0110             break;
0111 
0112         case SH7750_FRQCR_PFCDIV3:
0113             tidiv = 3 * TIMER_PRESCALER;
0114             break;
0115 
0116         case SH7750_FRQCR_PFCDIV4:
0117             tidiv = 4 * TIMER_PRESCALER;
0118             break;
0119 
0120         case SH7750_FRQCR_PFCDIV6:
0121             tidiv = 6 * TIMER_PRESCALER;
0122             break;
0123 
0124         case SH7750_FRQCR_PFCDIV8:
0125             tidiv = 8 * TIMER_PRESCALER;
0126             break;
0127 
0128         default:
0129             rtems_fatal_error_occurred( RTEMS_NOT_CONFIGURED);
0130     }
0131 
0132     microseconds_divider = bsp_clicks_per_second * cpudiv / (tidiv * 1000000);
0133     microseconds_per_int = 0xFFFFFFFF / microseconds_divider;
0134 
0135     /*
0136      *  Hardware specific initialization
0137      */
0138 
0139     /* Stop the Timer 0 */
0140     temp8 = read8(SH7750_TSTR);
0141     temp8 &= ~SH7750_TSTR_STR1;
0142     write8(temp8, SH7750_TSTR);
0143 
0144     /* Establish interrupt handler */
0145     _CPU_ISR_install_raw_handler( TIMER_VECTOR, timerisr, &ignored );
0146 
0147     /* Reset timer constant and counter */
0148     write32(0xFFFFFFFF, SH7750_TCOR1);
0149     write32(0xFFFFFFFF, SH7750_TCNT1);
0150 
0151     /* Select timer mode */
0152     write16(
0153         SH7750_TCR_UNIE |        /* Enable Underflow Interrupt */
0154         SH7750_TCR_CKEG_RAISE |  /* Count on rising edge */
0155         TCR1_TPSC,               /* Timer prescaler ratio */
0156         SH7750_TCR1);
0157 
0158     /* Set timer interrupt priority */
0159     temp16 = read16(SH7750_IPRA);
0160     temp16 = (temp16 & ~SH7750_IPRA_TMU1) | (TIMER_PRIO << SH7750_IPRA_TMU1_S);
0161     write16(temp16, SH7750_IPRA);
0162 
0163 
0164     rtems_interrupt_enable(level);
0165 
0166     /* Start the Timer 1 */
0167     temp8 = read8(SH7750_TSTR);
0168     temp8 |= SH7750_TSTR_STR1;
0169     write8(temp8, SH7750_TSTR);
0170 
0171 }
0172 
0173 /*
0174  *  The following controls the behavior of benchmark_timer_read().
0175  *
0176  *  AVG_OVERHEAD is the overhead for starting and stopping the timer.  It
0177  *  is usually deducted from the number returned.
0178  *
0179  *  LEAST_VALID is the lowest number this routine should trust.  Numbers
0180  *  below this are "noise" and zero is returned.
0181  */
0182 
0183 #define AVG_OVERHEAD      0  /* It typically takes X.X microseconds */
0184                              /* (Y countdowns) to start/stop the timer. */
0185                              /* This value is in microseconds. */
0186 #define LEAST_VALID       0 /* 20 */ /* Don't trust a clicks value lower than this */
0187 
0188 /* benchmark_timer_read --
0189  *     Read timer value in microsecond units since timer start.
0190  *
0191  * PARAMETERS:
0192  *     none
0193  *
0194  * RETURNS:
0195  *     number of microseconds since timer has been started
0196  */
0197 benchmark_timer_t
0198 benchmark_timer_read(void)
0199 {
0200     uint32_t              clicks;
0201     uint32_t              ints;
0202     uint32_t              total;
0203     rtems_interrupt_level level;
0204     uint32_t              tcr;
0205 
0206 
0207     rtems_interrupt_disable(level);
0208 
0209     clicks = 0xFFFFFFFF - read32(SH7750_TCNT1);
0210     tcr = read32(SH7750_TCR1);
0211     ints = Timer_interrupts;
0212 
0213     rtems_interrupt_enable(level);
0214 
0215     /* Handle the case when timer overflowed but interrupt was not processed */
0216     if ((clicks > 0xFF000000) && ((tcr & SH7750_TCR_UNF) != 0))
0217     {
0218         ints++;
0219     }
0220 
0221     total = microseconds_per_int * ints + (clicks / microseconds_divider);
0222 
0223     if ( benchmark_timer_find_average_overhead )
0224         return total;          /* in microsecond units */
0225     else
0226     {
0227         if ( total < LEAST_VALID )
0228             return 0;            /* below timer resolution */
0229         /*
0230          *  Somehow convert total into microseconds
0231          */
0232         return (total - AVG_OVERHEAD) ;
0233     }
0234 }
0235 
0236 /* benchmark_timer_disable_subtracting_average_overhead --
0237  *     This routine is invoked by the "Check Timer" (tmck) test in the
0238  *     RTEMS Timing Test Suite. It makes the benchmark_timer_read routine not
0239  *     subtract the overhead required to initialize and read the benchmark
0240  *     timer.
0241  *
0242  * PARAMETERS:
0243  *     find_flag - boolean flag, true if overhead must not be subtracted.
0244  *
0245  * RETURNS:
0246  *     none
0247  */
0248 void
0249 benchmark_timer_disable_subtracting_average_overhead(bool find_flag)
0250 {
0251     benchmark_timer_find_average_overhead = find_flag;
0252 }
0253 
0254 /* timerisr --
0255  *     Timer interrupt handler routine. This function invoked on timer
0256  *     underflow event; once per 2^32 clocks. It should reset the timer
0257  *     event and increment timer interrupts counter.
0258  */
0259 void
0260 timerisr(void)
0261 {
0262   uint8_t   temp8;
0263 
0264   /* reset the flags of the status register */
0265   temp8 = read8(SH7750_TCR1) & ~SH7750_TCR_UNF;
0266   write8(temp8, SH7750_TCR1);
0267 
0268   Timer_interrupts += 1;
0269 }