Back to home page

LXR

 
 

    


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

0001 /*
0002  * This file contains the generic RTEMS clock driver the Hitachi SH 7750
0003  */
0004 
0005 /*
0006  * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
0007  * Author: Victor V. Vengerov <vvv@oktet.ru>
0008  *
0009  *  COPYRIGHT (c) 2001
0010  *  On-Line Applications Research Corporation (OAR).
0011  *
0012  *  The license and distribution terms for this file may be
0013  *  found in the file LICENSE in this distribution or at
0014  *  http://www.rtems.org/license/LICENSE.
0015  */
0016 
0017 #include <rtems.h>
0018 
0019 #include <stdlib.h>
0020 
0021 #include <rtems/clockdrv.h>
0022 #include <rtems/score/sh_io.h>
0023 #include <rtems/score/sh.h>
0024 #include <rtems/score/ispsh7750.h>
0025 #include <rtems/score/iosh7750.h>
0026 
0027 static void Clock_exit( void );
0028 
0029 extern uint32_t bsp_clicks_per_second;
0030 
0031 #ifndef CLOCKPRIO
0032 #define CLOCKPRIO 10
0033 #endif
0034 
0035 /* Clock timer prescaler division ratio */
0036 #define CLOCK_PRESCALER 4
0037 #define TCR0_TPSC       SH7750_TCR_TPSC_DIV4
0038 
0039 /*
0040  *  The interrupt vector number associated with the clock tick device
0041  *  driver.
0042  */
0043 #define CLOCK_VECTOR SH7750_EVT_TO_NUM(SH7750_EVT_TUNI0)
0044 
0045 /*
0046  *  Clock_driver_ticks is a monotonically increasing counter of the
0047  *  number of clock ticks since the driver was initialized.
0048  */
0049 volatile uint32_t   Clock_driver_ticks;
0050 
0051 static rtems_isr Clock_isr( rtems_vector_number vector );
0052 
0053 /*
0054  *  The previous ISR on this clock tick interrupt vector.
0055  */
0056 rtems_isr_entry  Old_ticker;
0057 
0058 /*
0059  *  Isr Handler
0060  */
0061 
0062 /*
0063  * Clock_isr
0064  *
0065  * Clock interrupt handling routine.
0066  */
0067 static rtems_isr Clock_isr(rtems_vector_number vector)
0068 {
0069   uint16_t   tcr;
0070 
0071   /* reset the timer underflow flag */
0072   tcr = read16(SH7750_TCR0);
0073   write16(tcr & ~SH7750_TCR_UNF, SH7750_TCR0);
0074 
0075   /* Increment the clock interrupt counter */
0076   Clock_driver_ticks++ ;
0077 
0078   /* Invoke rtems clock service routine */
0079     rtems_clock_tick();
0080 }
0081 
0082 /*
0083  * Install_clock
0084  *
0085  * Install a clock tick handler and reprograms the chip.  This
0086  * is used to initially establish the clock tick.
0087  *
0088  * SIDE EFFECTS:
0089  *     Establish clock interrupt handler, configure Timer 0 hardware
0090  */
0091 static void Install_clock(rtems_isr_entry clock_isr)
0092 {
0093   int cpudiv = 1; /* CPU frequency divider */
0094   int tidiv = 1;  /* Timer input frequency divider */
0095   uint32_t   timer_divider; /* Calculated Timer Divider value */
0096   uint8_t   temp8;
0097   uint16_t   temp16;
0098 
0099   /*
0100    *  Initialize the clock tick device driver variables
0101    */
0102 
0103   Clock_driver_ticks = 0;
0104 
0105   /* Get CPU frequency divider from clock unit */
0106   switch (read16(SH7750_FRQCR) & SH7750_FRQCR_IFC) {
0107     case SH7750_FRQCR_IFCDIV1:
0108       cpudiv = 1;
0109       break;
0110 
0111     case SH7750_FRQCR_IFCDIV2:
0112       cpudiv = 2;
0113       break;
0114 
0115     case SH7750_FRQCR_IFCDIV3:
0116       cpudiv = 3;
0117       break;
0118 
0119     case SH7750_FRQCR_IFCDIV4:
0120       cpudiv = 4;
0121       break;
0122 
0123     case SH7750_FRQCR_IFCDIV6:
0124       cpudiv = 6;
0125       break;
0126 
0127     case SH7750_FRQCR_IFCDIV8:
0128       cpudiv = 8;
0129       break;
0130 
0131       default:
0132         rtems_fatal_error_occurred( RTEMS_NOT_CONFIGURED);
0133   }
0134 
0135   /* Get peripheral module frequency divider from clock unit */
0136   switch (read16(SH7750_FRQCR) & SH7750_FRQCR_PFC) {
0137     case SH7750_FRQCR_PFCDIV2:
0138       tidiv = 2 * CLOCK_PRESCALER;
0139       break;
0140 
0141     case SH7750_FRQCR_PFCDIV3:
0142       tidiv = 3 * CLOCK_PRESCALER;
0143       break;
0144 
0145     case SH7750_FRQCR_PFCDIV4:
0146       tidiv = 4 * CLOCK_PRESCALER;
0147       break;
0148 
0149     case SH7750_FRQCR_PFCDIV6:
0150       tidiv = 6 * CLOCK_PRESCALER;
0151       break;
0152 
0153     case SH7750_FRQCR_PFCDIV8:
0154       tidiv = 8 * CLOCK_PRESCALER;
0155       break;
0156 
0157     default:
0158       rtems_fatal_error_occurred( RTEMS_NOT_CONFIGURED);
0159   }
0160   timer_divider =
0161       (bsp_clicks_per_second * cpudiv / (tidiv*1000000)) *
0162       rtems_configuration_get_microseconds_per_tick();
0163 
0164   /*
0165    *  Hardware specific initialization
0166    */
0167 
0168   /* Stop the Timer 0 */
0169   temp8 = read8(SH7750_TSTR);
0170   temp8 &= ~SH7750_TSTR_STR0;
0171   write8(temp8, SH7750_TSTR);
0172 
0173   /* Establish interrupt handler */
0174   rtems_interrupt_catch( Clock_isr, CLOCK_VECTOR, &Old_ticker );
0175 
0176   /* Reset counter */
0177   write32(timer_divider, SH7750_TCNT0);
0178 
0179   /* Load divider */
0180   write32(timer_divider, SH7750_TCOR0);
0181 
0182   write16(
0183       SH7750_TCR_UNIE |        /* Enable Underflow Interrupt */
0184       SH7750_TCR_CKEG_RAISE |  /* Count on rising edge */
0185       TCR0_TPSC,               /* Timer prescaler ratio */
0186       SH7750_TCR0);
0187 
0188   /* Set clock interrupt priority */
0189   temp16 = read16(SH7750_IPRA);
0190   temp16 = (temp16 & ~SH7750_IPRA_TMU0) | (CLOCKPRIO << SH7750_IPRA_TMU0_S);
0191   write16(temp16, SH7750_IPRA);
0192 
0193   /* Start the Timer 0 */
0194   temp8 = read8(SH7750_TSTR);
0195   temp8 |= SH7750_TSTR_STR0;
0196   write8(temp8, SH7750_TSTR);
0197 
0198   /*
0199    *  Schedule the clock cleanup routine to execute if the application exits.
0200    */
0201   atexit( Clock_exit );
0202 }
0203 
0204 /*
0205  * Clock_exit
0206  *
0207  * Clean up before the application exits
0208  *
0209  * SIDE EFFECTS:
0210  *     Stop Timer 0 counting, set timer 0 interrupt priority level to 0.
0211  */
0212 void
0213 Clock_exit(void)
0214 {
0215   uint8_t   temp8 = 0;
0216   uint16_t   temp16 = 0;
0217 
0218   /* turn off the timer interrupts */
0219   /* Stop the Timer 0 */
0220   temp8 = read8(SH7750_TSTR);
0221   temp8 &= ~SH7750_TSTR_STR0;
0222   write8(temp8, SH7750_TSTR);
0223 
0224   /* Lower timer interrupt priority to 0 */
0225   temp16 = read16(SH7750_IPRA);
0226   temp16 = (temp16 & ~SH7750_IPRA_TMU0) | (0 << SH7750_IPRA_TMU0_S);
0227   write16(temp16, SH7750_IPRA);
0228 
0229   /* old vector shall not be installed */
0230 }
0231 
0232 void _Clock_Initialize( void )
0233 {
0234     Install_clock( Clock_isr );
0235 }