Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSBSPsPowerPCShared
0007  *
0008  * @brief Source file for a clock driver.
0009  */
0010 
0011 /*
0012  * Copyright (C) 2008, 2015 embedded brains GmbH & Co. KG
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #include <rtems.h>
0037 #include <rtems/clockdrv.h>
0038 #include <rtems/timecounter.h>
0039 
0040 #include <libcpu/powerpc-utility.h>
0041 #include <bsp/vectors.h>
0042 
0043 #define RTEMS_STATUS_CHECKS_USE_PRINTK
0044 
0045 #include <rtems/status-checks.h>
0046 
0047 /*
0048  * This variable must be defined in the BSP and valid before clock driver
0049  * initialization.
0050  */
0051 extern uint32_t bsp_time_base_frequency;
0052 
0053 #define PPC405_PIT 0x3db
0054 
0055 #define PPC_CLOCK_DECREMENTER_MAX UINT32_MAX
0056 
0057 volatile uint32_t Clock_driver_ticks = 0;
0058 
0059 static uint32_t ppc_clock_decrementer_value = PPC_CLOCK_DECREMENTER_MAX;
0060 
0061 static uint32_t ppc_clock_next_time_base;
0062 
0063 static struct timecounter ppc_tc;
0064 
0065 static uint32_t ppc_get_timecount(struct timecounter *tc)
0066 {
0067   return ppc_time_base();
0068 }
0069 
0070 static void ppc_clock_no_tick(void)
0071 {
0072   /* Do nothing */
0073 }
0074 
0075 static void (*ppc_clock_tick)(void) = ppc_clock_no_tick;
0076 
0077 static int ppc_clock_exception_handler(
0078   BSP_Exception_frame *frame,
0079   unsigned number
0080 )
0081 {
0082   uint32_t delta = ppc_clock_decrementer_value;
0083   uint32_t next = ppc_clock_next_time_base;
0084   uint32_t dec = 0;
0085   uint32_t now = 0;
0086   uint32_t msr = 0;
0087 
0088   do {
0089     /* Increment clock ticks */
0090     Clock_driver_ticks += 1;
0091 
0092     /* Enable external exceptions */
0093     msr = ppc_external_exceptions_enable();
0094 
0095     /* Call clock ticker  */
0096     ppc_clock_tick();
0097 
0098     /* Restore machine state */
0099     ppc_external_exceptions_disable( msr);
0100 
0101     /* Next time base */
0102     next += delta;
0103 
0104     /* Current time */
0105     now = ppc_time_base();
0106 
0107     /* New decrementer value */
0108     dec = next - now;
0109   } while (dec > delta);
0110 
0111   /* Set decrementer */
0112   ppc_set_decrementer_register( dec);
0113 
0114   /* Expected next time base */
0115   ppc_clock_next_time_base = next;
0116 
0117   return 0;
0118 }
0119 
0120 static int ppc_clock_exception_handler_first(
0121   BSP_Exception_frame *frame,
0122   unsigned number
0123 )
0124 {
0125   /* We have to clear the first pending decrementer exception this way */
0126 
0127   if (ppc_decrementer_register() >= 0x80000000) {
0128     ppc_clock_exception_handler( frame, number);
0129   }
0130 
0131   ppc_exc_set_handler( ASM_DEC_VECTOR, ppc_clock_exception_handler);
0132 
0133   return 0;
0134 }
0135 
0136 static int ppc_clock_exception_handler_booke(
0137   BSP_Exception_frame *frame,
0138   unsigned number
0139 )
0140 {
0141   uint32_t msr;
0142 
0143   /* Acknowledge decrementer request */
0144   PPC_SET_SPECIAL_PURPOSE_REGISTER( BOOKE_TSR, BOOKE_TSR_DIS);
0145 
0146   /* Increment clock ticks */
0147   Clock_driver_ticks += 1;
0148 
0149   /* Enable external exceptions */
0150   msr = ppc_external_exceptions_enable();
0151 
0152   /* Call clock ticker  */
0153   ppc_clock_tick();
0154 
0155   /* Restore machine state */
0156   ppc_external_exceptions_disable( msr);
0157 
0158   return 0;
0159 }
0160 
0161 static int ppc_clock_exception_handler_ppc405(BSP_Exception_frame *frame, unsigned number)
0162 {
0163   uint32_t msr;
0164 
0165   /* Acknowledge PIT request */
0166   PPC_SET_SPECIAL_PURPOSE_REGISTER(PPC405_TSR, BOOKE_TSR_DIS);
0167 
0168   /* Increment clock ticks */
0169   Clock_driver_ticks += 1;
0170 
0171   /* Enable external exceptions */
0172   msr = ppc_external_exceptions_enable();
0173 
0174   /* Call clock ticker  */
0175   ppc_clock_tick();
0176 
0177   /* Restore machine state */
0178   ppc_external_exceptions_disable(msr);
0179 
0180   return 0;
0181 }
0182 
0183 void _Clock_Initialize( void )
0184 {
0185   uint64_t frequency = bsp_time_base_frequency;
0186   uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick();
0187   uint32_t interval = (uint32_t) ((frequency * us_per_tick) / 1000000);
0188 
0189   /*
0190    * Set default ticker.
0191    */
0192   ppc_clock_tick = rtems_timecounter_tick;
0193 
0194   if (ppc_cpu_is_bookE() != PPC_BOOKE_405) {
0195     /* Decrementer value */
0196     ppc_clock_decrementer_value = interval - 1;
0197 
0198     /* Check decrementer value */
0199     if (ppc_clock_decrementer_value == 0) {
0200       ppc_clock_decrementer_value = PPC_CLOCK_DECREMENTER_MAX;
0201       RTEMS_SYSLOG_ERROR( "decrementer value would be zero, will be set to maximum value instead\n");
0202     }
0203     if (ppc_cpu_is_bookE()) {
0204       /* Set decrementer auto-reload value */
0205       PPC_SET_SPECIAL_PURPOSE_REGISTER( BOOKE_DECAR, ppc_clock_decrementer_value);
0206 
0207       /* Install exception handler */
0208       ppc_exc_set_handler( ASM_BOOKE_DEC_VECTOR, ppc_clock_exception_handler_booke);
0209 
0210       /* Enable decrementer and auto-reload */
0211       PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS( BOOKE_TCR, BOOKE_TCR_DIE | BOOKE_TCR_ARE);
0212     } else {
0213       /* Here the decrementer value is actually the interval */
0214       ++ppc_clock_decrementer_value;
0215 
0216       /* Initialize next time base */
0217       ppc_clock_next_time_base = ppc_time_base() + ppc_clock_decrementer_value;
0218 
0219       /* Install exception handler */
0220       ppc_exc_set_handler( ASM_DEC_VECTOR, ppc_clock_exception_handler_first);
0221     }
0222 
0223     /* Set the decrementer value */
0224     ppc_set_decrementer_register( ppc_clock_decrementer_value);
0225   } else {
0226     /* PIT interval value */
0227     ppc_clock_decrementer_value = interval;
0228 
0229     /* Install exception handler */
0230     ppc_exc_set_handler(ASM_BOOKE_DEC_VECTOR, ppc_clock_exception_handler_ppc405);
0231 
0232     /* Enable PIT and auto-reload */
0233     PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS(PPC405_TCR, BOOKE_TCR_DIE | BOOKE_TCR_ARE);
0234 
0235     /* Set PIT auto-reload and initial value */
0236     PPC_SET_SPECIAL_PURPOSE_REGISTER(PPC405_PIT, interval);
0237   }
0238 
0239   /* Install timecounter */
0240   ppc_tc.tc_get_timecount = ppc_get_timecount;
0241   ppc_tc.tc_counter_mask = 0xffffffff;
0242   ppc_tc.tc_frequency = frequency;
0243   ppc_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
0244   rtems_timecounter_install(&ppc_tc);
0245 }