1 /**************************************************************************//**
2  * @file     os_tick_gtim.c
3  * @brief    CMSIS OS Tick implementation for Generic Timer
4  * @version  V1.0.1
5  * @date     24. November 2017
6  ******************************************************************************/
7 /*
8  * Copyright (c) 2017 ARM Limited. All rights reserved.
9  *
10  * SPDX-License-Identifier: Apache-2.0
11  *
12  * Licensed under the Apache License, Version 2.0 (the License); you may
13  * not use this file except in compliance with the License.
14  * You may obtain a copy of the License at
15  *
16  * www.apache.org/licenses/LICENSE-2.0
17  *
18  * Unless required by applicable law or agreed to in writing, software
19  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
20  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21  * See the License for the specific language governing permissions and
22  * limitations under the License.
23  */
24 
25 #include "os_tick.h"
26 #include "irq_ctrl.h"
27 
28 #include "RTE_Components.h"
29 #include CMSIS_device_header
30 
31 #ifndef GTIM_IRQ_PRIORITY
32 #define GTIM_IRQ_PRIORITY           0xFFU
33 #endif
34 
35 #ifndef GTIM_IRQ_NUM
36 #define GTIM_IRQ_NUM                SecurePhyTimer_IRQn
37 #endif
38 
39 // Timer interrupt pending flag
40 static uint8_t GTIM_PendIRQ;
41 
42 // Timer tick frequency
43 static uint32_t GTIM_Clock;
44 
45 // Timer load value
46 static uint32_t GTIM_Load;
47 
48 // Setup OS Tick.
OS_Tick_Setup(uint32_t freq,IRQHandler_t handler)49 int32_t OS_Tick_Setup (uint32_t freq, IRQHandler_t handler) {
50   uint32_t prio, bits;
51 
52   if (freq == 0U) {
53     return (-1);
54   }
55 
56   GTIM_PendIRQ = 0U;
57 
58   // Get timer clock
59 #ifdef SCTR_BASE
60   GTIM_Clock = *(uint32_t*)(SCTR_BASE+0x20);
61 #else
62   // FVP REFCLK CNTControl 100MHz
63   GTIM_Clock = 100000000UL;
64 #endif
65 
66   PL1_SetCounterFrequency(GTIM_Clock);
67 
68   // Calculate load value
69   GTIM_Load = (GTIM_Clock / freq) - 1U;
70 
71   // Disable Generic Timer and set load value
72   PL1_SetControl(0U);
73   PL1_SetLoadValue(GTIM_Load);
74 
75   // Disable corresponding IRQ
76   IRQ_Disable(GTIM_IRQ_NUM);
77   IRQ_ClearPending(GTIM_IRQ_NUM);
78 
79   // Determine number of implemented priority bits
80   IRQ_SetPriority(GTIM_IRQ_NUM, 0xFFU);
81 
82   prio = IRQ_GetPriority(GTIM_IRQ_NUM);
83 
84   // At least bits [7:4] must be implemented
85   if ((prio & 0xF0U) == 0U) {
86     return (-1);
87   }
88 
89   for (bits = 0; bits < 4; bits++) {
90     if ((prio & 0x01) != 0) {
91       break;
92     }
93     prio >>= 1;
94   }
95 
96   // Adjust configured priority to the number of implemented priority bits
97   prio = (GTIM_IRQ_PRIORITY << bits) & 0xFFUL;
98 
99   // Set Private Timer interrupt priority
100   IRQ_SetPriority(GTIM_IRQ_NUM, prio-1U);
101 
102   // Set edge-triggered IRQ
103   IRQ_SetMode(GTIM_IRQ_NUM, IRQ_MODE_TRIG_EDGE);
104 
105   // Register tick interrupt handler function
106   IRQ_SetHandler(GTIM_IRQ_NUM, handler);
107 
108   // Enable corresponding interrupt
109   IRQ_Enable(GTIM_IRQ_NUM);
110 
111   // Enable system counter and timer control
112 #ifdef SCTR_BASE
113   *(uint32_t*)SCTR_BASE |= 3U;
114 #endif
115 
116   // Enable timer control
117   PL1_SetControl(1U);
118 
119   return (0);
120 }
121 
122 /// Enable OS Tick.
OS_Tick_Enable(void)123 void OS_Tick_Enable (void) {
124   uint32_t ctrl;
125 
126   // Set pending interrupt if flag set
127   if (GTIM_PendIRQ != 0U) {
128     GTIM_PendIRQ = 0U;
129     IRQ_SetPending (GTIM_IRQ_NUM);
130   }
131 
132   // Start the Private Timer
133   ctrl = PL1_GetControl();
134   // Set bit: Timer enable
135   ctrl |= 1U;
136   PL1_SetControl(ctrl);
137 }
138 
139 /// Disable OS Tick.
OS_Tick_Disable(void)140 void OS_Tick_Disable (void) {
141   uint32_t ctrl;
142 
143   // Stop the Private Timer
144   ctrl = PL1_GetControl();
145   // Clear bit: Timer enable
146   ctrl &= ~1U;
147   PL1_SetControl(ctrl);
148 
149   // Remember pending interrupt flag
150   if (IRQ_GetPending(GTIM_IRQ_NUM) != 0) {
151     IRQ_ClearPending(GTIM_IRQ_NUM);
152     GTIM_PendIRQ = 1U;
153   }
154 }
155 
156 // Acknowledge OS Tick IRQ.
OS_Tick_AcknowledgeIRQ(void)157 void OS_Tick_AcknowledgeIRQ (void) {
158   IRQ_ClearPending (GTIM_IRQ_NUM);
159   PL1_SetLoadValue(GTIM_Load);
160 }
161 
162 // Get OS Tick IRQ number.
OS_Tick_GetIRQn(void)163 int32_t  OS_Tick_GetIRQn (void) {
164   return (GTIM_IRQ_NUM);
165 }
166 
167 // Get OS Tick clock.
OS_Tick_GetClock(void)168 uint32_t OS_Tick_GetClock (void) {
169   return (GTIM_Clock);
170 }
171 
172 // Get OS Tick interval.
OS_Tick_GetInterval(void)173 uint32_t OS_Tick_GetInterval (void) {
174   return (GTIM_Load + 1U);
175 }
176 
177 // Get OS Tick count value.
OS_Tick_GetCount(void)178 uint32_t OS_Tick_GetCount (void) {
179   return (GTIM_Load - PL1_GetCurrentValue());
180 }
181 
182 // Get OS Tick overflow status.
OS_Tick_GetOverflow(void)183 uint32_t OS_Tick_GetOverflow (void) {
184   CNTP_CTL_Type cntp_ctl;
185   cntp_ctl.w = PL1_GetControl();
186   return (cntp_ctl.b.ISTATUS);
187 }
188