File indexing completed on 2025-05-11 08:23:58
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
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
0049
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
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
0090 Clock_driver_ticks += 1;
0091
0092
0093 msr = ppc_external_exceptions_enable();
0094
0095
0096 ppc_clock_tick();
0097
0098
0099 ppc_external_exceptions_disable( msr);
0100
0101
0102 next += delta;
0103
0104
0105 now = ppc_time_base();
0106
0107
0108 dec = next - now;
0109 } while (dec > delta);
0110
0111
0112 ppc_set_decrementer_register( dec);
0113
0114
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
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
0144 PPC_SET_SPECIAL_PURPOSE_REGISTER( BOOKE_TSR, BOOKE_TSR_DIS);
0145
0146
0147 Clock_driver_ticks += 1;
0148
0149
0150 msr = ppc_external_exceptions_enable();
0151
0152
0153 ppc_clock_tick();
0154
0155
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
0166 PPC_SET_SPECIAL_PURPOSE_REGISTER(PPC405_TSR, BOOKE_TSR_DIS);
0167
0168
0169 Clock_driver_ticks += 1;
0170
0171
0172 msr = ppc_external_exceptions_enable();
0173
0174
0175 ppc_clock_tick();
0176
0177
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
0191
0192 ppc_clock_tick = rtems_timecounter_tick;
0193
0194 if (ppc_cpu_is_bookE() != PPC_BOOKE_405) {
0195
0196 ppc_clock_decrementer_value = interval - 1;
0197
0198
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
0205 PPC_SET_SPECIAL_PURPOSE_REGISTER( BOOKE_DECAR, ppc_clock_decrementer_value);
0206
0207
0208 ppc_exc_set_handler( ASM_BOOKE_DEC_VECTOR, ppc_clock_exception_handler_booke);
0209
0210
0211 PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS( BOOKE_TCR, BOOKE_TCR_DIE | BOOKE_TCR_ARE);
0212 } else {
0213
0214 ++ppc_clock_decrementer_value;
0215
0216
0217 ppc_clock_next_time_base = ppc_time_base() + ppc_clock_decrementer_value;
0218
0219
0220 ppc_exc_set_handler( ASM_DEC_VECTOR, ppc_clock_exception_handler_first);
0221 }
0222
0223
0224 ppc_set_decrementer_register( ppc_clock_decrementer_value);
0225 } else {
0226
0227 ppc_clock_decrementer_value = interval;
0228
0229
0230 ppc_exc_set_handler(ASM_BOOKE_DEC_VECTOR, ppc_clock_exception_handler_ppc405);
0231
0232
0233 PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS(PPC405_TCR, BOOKE_TCR_DIE | BOOKE_TCR_ARE);
0234
0235
0236 PPC_SET_SPECIAL_PURPOSE_REGISTER(PPC405_PIT, interval);
0237 }
0238
0239
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 }