[41c9282] | 1 | /* |
---|
| 2 | * Clock Tick Device Driver |
---|
| 3 | * |
---|
| 4 | * This routine initializes LEON timer 1 which used for the clock tick. |
---|
| 5 | * |
---|
| 6 | * The tick frequency is directly programmed to the configured number of |
---|
| 7 | * microseconds per tick. |
---|
| 8 | * |
---|
[29d1fce] | 9 | * COPYRIGHT (c) 1989-2006. |
---|
[41c9282] | 10 | * On-Line Applications Research Corporation (OAR). |
---|
| 11 | * |
---|
| 12 | * Modified for LEON3 BSP. |
---|
| 13 | * COPYRIGHT (c) 2004. |
---|
| 14 | * Gaisler Research. |
---|
| 15 | * |
---|
| 16 | * The license and distribution terms for this file may be |
---|
| 17 | * found in the file LICENSE in this distribution or at |
---|
[c499856] | 18 | * http://www.rtems.org/license/LICENSE. |
---|
[41c9282] | 19 | */ |
---|
| 20 | |
---|
| 21 | #include <bsp.h> |
---|
[29d1fce] | 22 | #include <bspopts.h> |
---|
[a387e944] | 23 | #include <bsp/fatal.h> |
---|
| 24 | #include <rtems/rtems/intr.h> |
---|
[1f7cfbe3] | 25 | #include <ambapp.h> |
---|
[234ecedd] | 26 | #include <rtems/score/profiling.h> |
---|
[29d1fce] | 27 | |
---|
| 28 | #if SIMSPARC_FAST_IDLE==1 |
---|
[d473dc0] | 29 | #define CLOCK_DRIVER_USE_FAST_IDLE 1 |
---|
[29d1fce] | 30 | #endif |
---|
[41c9282] | 31 | |
---|
| 32 | /* |
---|
| 33 | * The Real Time Clock Counter Timer uses this trap type. |
---|
| 34 | */ |
---|
| 35 | |
---|
[226d48d8] | 36 | volatile struct gptimer_regs *LEON3_Timer_Regs = 0; |
---|
[41c9282] | 37 | static int clkirq; |
---|
| 38 | |
---|
[234ecedd] | 39 | static void leon3_clock_profiling_interrupt_delay(void) |
---|
| 40 | { |
---|
| 41 | #ifdef RTEMS_PROFILING |
---|
| 42 | /* |
---|
| 43 | * We need a small state machine to ignore the first clock interrupt, since |
---|
| 44 | * it contains the sequential system initialization time. Do the timestamp |
---|
| 45 | * initialization on the fly. |
---|
| 46 | */ |
---|
| 47 | static int state = 1; |
---|
| 48 | |
---|
| 49 | volatile struct irqmp_timestamp_regs *irqmp_ts = |
---|
| 50 | &LEON3_IrqCtrl_Regs->timestamp[0]; |
---|
| 51 | unsigned int s1_s2 = (1U << 25) | (1U << 26); |
---|
| 52 | |
---|
| 53 | if (state == 0) { |
---|
| 54 | unsigned int first = irqmp_ts->assertion; |
---|
| 55 | unsigned int second = irqmp_ts->counter; |
---|
| 56 | |
---|
| 57 | irqmp_ts->control |= s1_s2; |
---|
| 58 | |
---|
| 59 | _Profiling_Update_max_interrupt_delay(_Per_CPU_Get(), second - first); |
---|
| 60 | } else if (state == 1 && leon3_irqmp_has_timestamp(irqmp_ts)) { |
---|
| 61 | unsigned int ks = 1U << 5; |
---|
| 62 | |
---|
| 63 | state = 0; |
---|
| 64 | |
---|
| 65 | irqmp_ts->control = ks | s1_s2 | (unsigned int) clkirq; |
---|
| 66 | } else if (state == 1) { |
---|
| 67 | state = 2; |
---|
| 68 | } |
---|
| 69 | #endif |
---|
| 70 | } |
---|
| 71 | |
---|
| 72 | #define Clock_driver_support_at_tick() \ |
---|
| 73 | do { \ |
---|
| 74 | leon3_clock_profiling_interrupt_delay(); \ |
---|
| 75 | } while (0) |
---|
[29d1fce] | 76 | |
---|
[7f3c6ce] | 77 | #if defined(RTEMS_MULTIPROCESSING) |
---|
| 78 | #define Adjust_clkirq_for_node() \ |
---|
| 79 | do { \ |
---|
| 80 | if (rtems_configuration_get_user_multiprocessing_table() != NULL) { \ |
---|
| 81 | clkirq += LEON3_Cpu_Index; \ |
---|
| 82 | } \ |
---|
| 83 | } while(0) |
---|
| 84 | #else |
---|
[4fa6be9] | 85 | #define Adjust_clkirq_for_node() do { clkirq += LEON3_CLOCK_INDEX; } while(0) |
---|
[7f3c6ce] | 86 | #endif |
---|
| 87 | |
---|
[29d1fce] | 88 | #define Clock_driver_support_find_timer() \ |
---|
[921bb59] | 89 | do { \ |
---|
[1f7cfbe3] | 90 | struct ambapp_dev *adev; \ |
---|
[29d1fce] | 91 | \ |
---|
[1f7cfbe3] | 92 | /* Find first LEON3 GP Timer */ \ |
---|
| 93 | adev = (void *)ambapp_for_each(&ambapp_plb, (OPTIONS_ALL|OPTIONS_APB_SLVS),\ |
---|
| 94 | VENDOR_GAISLER, GAISLER_GPTIMER, ambapp_find_by_idx, NULL); \ |
---|
| 95 | if (adev) { \ |
---|
[30a8915] | 96 | /* Found APB GPTIMER Timer */ \ |
---|
[226d48d8] | 97 | LEON3_Timer_Regs = (volatile struct gptimer_regs *) \ |
---|
[1f7cfbe3] | 98 | DEV_TO_APB(adev)->start; \ |
---|
[226d48d8] | 99 | clkirq = (LEON3_Timer_Regs->cfg & 0xf8) >> 3; \ |
---|
[921bb59] | 100 | \ |
---|
[7f3c6ce] | 101 | Adjust_clkirq_for_node(); \ |
---|
[29d1fce] | 102 | } \ |
---|
| 103 | } while (0) |
---|
| 104 | |
---|
| 105 | #define Clock_driver_support_install_isr( _new, _old ) \ |
---|
| 106 | do { \ |
---|
[a387e944] | 107 | (_old) = NULL; \ |
---|
| 108 | bsp_clock_handler_install(_new); \ |
---|
[29d1fce] | 109 | } while(0) |
---|
| 110 | |
---|
[a387e944] | 111 | static void bsp_clock_handler_install(rtems_isr *new) |
---|
| 112 | { |
---|
| 113 | rtems_status_code sc; |
---|
| 114 | |
---|
| 115 | sc = rtems_interrupt_handler_install( |
---|
| 116 | clkirq, |
---|
| 117 | "Clock", |
---|
| 118 | RTEMS_INTERRUPT_UNIQUE, |
---|
| 119 | new, |
---|
| 120 | NULL |
---|
| 121 | ); |
---|
| 122 | if (sc != RTEMS_SUCCESSFUL) { |
---|
| 123 | rtems_fatal(RTEMS_FATAL_SOURCE_BSP, LEON3_FATAL_CLOCK_INITIALIZATION); |
---|
| 124 | } |
---|
| 125 | } |
---|
| 126 | |
---|
[29d1fce] | 127 | #define Clock_driver_support_initialize_hardware() \ |
---|
| 128 | do { \ |
---|
| 129 | LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].reload = \ |
---|
[12bd47e] | 130 | rtems_configuration_get_microseconds_per_tick() - 1; \ |
---|
[29d1fce] | 131 | \ |
---|
[226d48d8] | 132 | LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].ctrl = \ |
---|
[3a3869c4] | 133 | GPTIMER_TIMER_CTRL_EN | GPTIMER_TIMER_CTRL_RS | \ |
---|
| 134 | GPTIMER_TIMER_CTRL_LD | GPTIMER_TIMER_CTRL_IE; \ |
---|
[29d1fce] | 135 | } while (0) |
---|
| 136 | |
---|
| 137 | #define Clock_driver_support_shutdown_hardware() \ |
---|
| 138 | do { \ |
---|
| 139 | LEON_Mask_interrupt(LEON_TRAP_TYPE(clkirq)); \ |
---|
[226d48d8] | 140 | LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].ctrl = 0; \ |
---|
[29d1fce] | 141 | } while (0) |
---|
| 142 | |
---|
[876af7a] | 143 | static uint32_t bsp_clock_nanoseconds_since_last_tick(void) |
---|
[0e58c4f] | 144 | { |
---|
| 145 | uint32_t clicks; |
---|
[b3559ee9] | 146 | uint32_t usecs; |
---|
| 147 | |
---|
[0e58c4f] | 148 | if ( !LEON3_Timer_Regs ) |
---|
| 149 | return 0; |
---|
| 150 | |
---|
[4fa6be9] | 151 | clicks = LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].value; |
---|
[0e58c4f] | 152 | |
---|
[b3559ee9] | 153 | if ( LEON_Is_interrupt_pending( clkirq ) ) { |
---|
[4fa6be9] | 154 | clicks = LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].value; |
---|
[b3559ee9] | 155 | usecs = (2*rtems_configuration_get_microseconds_per_tick() - clicks); |
---|
| 156 | } else { |
---|
| 157 | usecs = (rtems_configuration_get_microseconds_per_tick() - clicks); |
---|
| 158 | } |
---|
| 159 | return usecs * 1000; |
---|
[0e58c4f] | 160 | } |
---|
| 161 | |
---|
[b3559ee9] | 162 | #define Clock_driver_nanoseconds_since_last_tick \ |
---|
| 163 | bsp_clock_nanoseconds_since_last_tick |
---|
[0e58c4f] | 164 | |
---|
[8ce272b] | 165 | #include "../../../shared/clockdrv_shell.h" |
---|