Back to home page

LXR

 
 

    


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

0001 /*
0002  * Use the last periodic interval timer (PIT3) as the system clock.
0003  */
0004 
0005 /*
0006  * Copyright (c) 2005 Eric Norum <eric@norum.ca>
0007  *
0008  * COPYRIGHT (c) 2005.
0009  * On-Line Applications Research Corporation (OAR).
0010  *
0011  * The license and distribution terms for this file may be
0012  * found in the file LICENSE in this distribution or at
0013  * http://www.rtems.org/license/LICENSE.
0014  */
0015 
0016 #include <rtems.h>
0017 #include <rtems/timecounter.h>
0018 #include <bsp.h>
0019 #include <mcf5282/mcf5282.h>
0020 
0021 /*
0022  * CPU load counters
0023  * Place in static RAM so updates don't hit the SDRAM
0024  */
0025 #define IDLE_COUNTER    __SRAMBASE.idle_counter
0026 #define FILTERED_IDLE   __SRAMBASE.filtered_idle
0027 #define MAX_IDLE_COUNT  __SRAMBASE.max_idle_count
0028 #define PITC_PER_TICK   __SRAMBASE.pitc_per_tick
0029 #define NSEC_PER_PITC   __SRAMBASE.nsec_per_pitc
0030 #define FILTER_SHIFT    6
0031 
0032 /*
0033  * Use INTC0 base
0034  */
0035 #define CLOCK_VECTOR (64+58)
0036 
0037 static rtems_timecounter_simple uC5282_tc;
0038 
0039 static uint32_t uC5282_tc_get(rtems_timecounter_simple *tc)
0040 {
0041   return MCF5282_PIT3_PCNTR;
0042 }
0043 
0044 static bool uC5282_tc_is_pending(rtems_timecounter_simple *tc)
0045 {
0046   return (MCF5282_PIT3_PCSR & MCF5282_PIT_PCSR_PIF) != 0;
0047 }
0048 
0049 static uint32_t uC5282_tc_get_timecount(struct timecounter *tc)
0050 {
0051   return rtems_timecounter_simple_downcounter_get(
0052     tc,
0053     uC5282_tc_get,
0054     uC5282_tc_is_pending
0055   );
0056 }
0057 
0058 static void uC5282_tc_at_tick(rtems_timecounter_simple *tc)
0059 {
0060   unsigned idle = IDLE_COUNTER;
0061   IDLE_COUNTER = 0;
0062   if (idle > MAX_IDLE_COUNT)
0063     MAX_IDLE_COUNT = idle;
0064   FILTERED_IDLE = idle + FILTERED_IDLE - (FILTERED_IDLE>>FILTER_SHIFT);
0065   MCF5282_PIT3_PCSR |= MCF5282_PIT_PCSR_PIF;
0066 }
0067 
0068 static void uC5282_tc_tick(void)
0069 {
0070   rtems_timecounter_simple_downcounter_tick(
0071     &uC5282_tc,
0072     uC5282_tc_get,
0073     uC5282_tc_at_tick
0074   );
0075 }
0076 
0077 /*
0078  * Attach clock interrupt handler
0079  */
0080 #define Clock_driver_support_install_isr( _new ) \
0081     set_vector(_new, CLOCK_VECTOR, 1)
0082 
0083 /*
0084  * Set up the clock hardware
0085  *
0086  * f_pit = f_clk / 2^(preScaleCode+1) / N  = 1/(us_per_tick/us_per_s)
0087  *
0088  * N = f_clk / 2^(preScaleCode+1) * us_per_tick / us_per_s
0089  *
0090  * ns_per_pit_clk = ns_per_s / (f_clk / 2^(preScaleCode+1))
0091  *                = ns_per_s * 2^(preScaleCode+1) / f_clk;
0092  */
0093 #define Clock_driver_support_initialize_hardware()                       \
0094     do {                                                                 \
0095         unsigned long long N;                                            \
0096         int level;                                                       \
0097         int preScaleCode = 0;                                            \
0098         N  = bsp_get_CPU_clock_speed();                                  \
0099         N *= rtems_configuration_get_microseconds_per_tick();            \
0100         N /= 2*1000000; /* min_prescale * us_per_s */                    \
0101         while ( N > 0x10000 ) {                                          \
0102             preScaleCode++;                                              \
0103             N >>= 1;                                                     \
0104         }                                                                \
0105         PITC_PER_TICK  = N;                                              \
0106         N  = 2000000000ULL << preScaleCode;                              \
0107         N /= bsp_get_CPU_clock_speed();                                  \
0108         NSEC_PER_PITC  = N;                                              \
0109         IDLE_COUNTER   = 0;                                              \
0110         FILTERED_IDLE  = 0;                                              \
0111         MAX_IDLE_COUNT = 0;                                              \
0112         bsp_allocate_interrupt(PIT3_IRQ_LEVEL, PIT3_IRQ_PRIORITY);       \
0113         MCF5282_INTC0_ICR58 = MCF5282_INTC_ICR_IL(PIT3_IRQ_LEVEL) |      \
0114                               MCF5282_INTC_ICR_IP(PIT3_IRQ_PRIORITY);    \
0115         rtems_interrupt_disable( level );                                \
0116         MCF5282_INTC0_IMRH &= ~MCF5282_INTC_IMRH_INT58;                  \
0117         MCF5282_PIT3_PCSR &= ~MCF5282_PIT_PCSR_EN;                       \
0118         rtems_interrupt_enable( level );                                 \
0119         MCF5282_PIT3_PCSR = MCF5282_PIT_PCSR_PRE(preScaleCode) |         \
0120                             MCF5282_PIT_PCSR_OVW |                       \
0121                             MCF5282_PIT_PCSR_PIE |                       \
0122                             MCF5282_PIT_PCSR_RLD;                        \
0123         MCF5282_PIT3_PMR = PITC_PER_TICK - 1;                            \
0124         MCF5282_PIT3_PCSR = MCF5282_PIT_PCSR_PRE(preScaleCode) |         \
0125                             MCF5282_PIT_PCSR_PIE |                       \
0126                             MCF5282_PIT_PCSR_RLD |                       \
0127                             MCF5282_PIT_PCSR_EN;                         \
0128          rtems_timecounter_simple_install( \
0129            &uC5282_tc, \
0130            bsp_get_CPU_clock_speed() >> (preScaleCode + 1), \
0131            PITC_PER_TICK, \
0132            uC5282_tc_get_timecount \
0133          ); \
0134     } while (0)
0135 
0136 /*
0137  * Provide our own version of the idle task
0138  */
0139 void * bsp_idle_thread(uintptr_t ignored)
0140 {
0141   /* Atomic increment */
0142   for(;;)
0143     __asm__ volatile ("addq.l #1,%0"::"m"(IDLE_COUNTER));
0144 }
0145 
0146 int bsp_cpu_load_percentage(void)
0147 {
0148     return MAX_IDLE_COUNT ?
0149            (100 - ((100 * (FILTERED_IDLE >> FILTER_SHIFT)) / MAX_IDLE_COUNT)) :
0150            0;
0151 }
0152 
0153 #define Clock_driver_timecounter_tick(arg) uC5282_tc_tick()
0154 
0155 #include "../../../shared/dev/clock/clockimpl.h"