1 /*
2 * @ : Copyright (c) 2021 Phytium Information Technology, Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0.
5 *
6 * @Date: 2021-04-07 09:53:07
7 * @LastEditTime: 2021-05-25 10:51:35
8 * @Description: This files is for generic timer functions
9 *
10 * @Modify History:
11 * Ver Who Date Changes
12 * ----- ------ -------- --------------------------------------
13 */
14
15 #include "ft_status.h"
16 #include "ft_types.h"
17 #include "ft_generic_timer.h"
18 #include "ft_printf.h"
19 #include "ft_assert.h"
20 #include "ft_aarch32_asm.h"
21 #include "ft_cpu.h"
22
23 #define GENERICTIMER_ASM(x) __asm__ volatile(x)
24 #define USEVIRTUAL 0
25 #define USE_ISRNUM GEN_TIMER_PHYSICAL_NOSECURE_IRQN
26
27 static volatile u32 _TickCnt;
28 static volatile u32 _Tickms;
29
30 typedef struct ft_Generictimer
31 {
32 u64 Frequency;
33 u64 MaxCount;
34 u64 TicksPerUs;
35 u32 Isr_PeriodMsec;
36 u32 Isr_PeriodCnt; //<! 中断周期填充值
37 u8 UseVirtual;
38 u8 InitFlg; //<! 初始化标志,1 is 完成初始化,0 is 尚未初始化
39 u8 Isr_IsEnable; //<! 1 is init , 2 is open, 0 is close
40 Ft_GenericTimer_Isr_Callback Callback;
41 } ft_Generictimer_handler_t;
42
43 ft_Generictimer_handler_t Ft_GenericTimer_Handler = {0};
44
45 /**
46 * @name: GenericTimer_WriteReg
47 * @msg:
48 * @in IsVirtual{u8}: 1 使用 虚拟计数器,0 使用物理计数器
49 * @in reg{u32}: 需要写入寄存器类型, GEN_TIMER_REG_CTL ,GEN_TIMER_REG_TVAL 。
50 * @in val{u32}: 需要写入参数 GEN_TIMER_CTRL_ENABLE GEN_TIMER_CTRL_IMASK GEN_TIMER_CTRL_ISTATUS
51 * @return {*}
52 */
GenericTimer_WriteReg(FT_IN u8 IsVirtual,FT_IN u32 reg,FT_IN u32 val)53 __STATIC_INLINE void GenericTimer_WriteReg(FT_IN u8 IsVirtual, FT_IN u32 reg, FT_IN u32 val)
54 {
55 if (IsVirtual)
56 {
57 if (reg == GEN_TIMER_REG_CTL)
58 {
59 arm_aarch32_cnthv_ctl_set(val);
60 }
61 else
62 {
63 arm_aarch32_cnthv_tval_set(val);
64 }
65 }
66 else
67 {
68 if (reg == GEN_TIMER_REG_CTL)
69 {
70 arm_aarch32_cntp_ctl_set(val);
71 }
72 else
73 {
74 arm_aarch32_cntp_tval_set(val);
75 }
76 }
77
78 GENERICTIMER_ASM("ISB");
79 }
80
81 /**
82 * @name: GenericTimer_ReadReg
83 * @msg: 读取GenericTimer 寄存器参数。
84 * @in IsVirtual{u8}: 1 使用 虚拟计数器,0 使用物理计数器
85 * @in reg{u32}: 需要写入寄存器类型, GEN_TIMER_REG_CTL ,GEN_TIMER_REG_TVAL 。
86 * @return {u32} 读取寄存器参数
87 */
GenericTimer_ReadReg(FT_IN u8 IsVirtual,FT_IN u32 reg)88 __STATIC_INLINE u32 GenericTimer_ReadReg(FT_IN u8 IsVirtual, FT_IN u32 reg)
89 {
90 u32 val = 0;
91
92 if (IsVirtual)
93 {
94 if (reg == GEN_TIMER_REG_CTL)
95 {
96 val = arm_aarch32_cnthv_ctl_get();
97 }
98 else
99 {
100 val = arm_aarch32_cnthv_tval_get();
101 }
102 }
103 else
104 {
105 if (reg == GEN_TIMER_REG_CTL)
106 {
107 val = arm_aarch32_cntp_ctl_get();
108 }
109 else
110 {
111 val = arm_aarch32_cntp_ctl_get();
112 }
113 }
114
115 return val;
116 }
117
118 /**
119 * @name: GenericTimer_GetTimerCnt
120 * @msg: 获取定时器定时器计数值。
121 * @in IsVirtual{u8}: 1 使用 虚拟计数器,0 使用物理计数器
122 * @return {u64} timer count value.
123 */
GenericTimer_GetTimerCnt(FT_IN u8 IsVirtual)124 __STATIC_INLINE u64 GenericTimer_GetTimerCnt(FT_IN u8 IsVirtual)
125 {
126
127 GENERICTIMER_ASM("ISB");
128
129 if (IsVirtual)
130 {
131 return arm_aarch32_cntvct_get();
132 }
133 else
134 {
135 return arm_aarch32_cntpct_get();
136 }
137 }
138
139 /**
140 * @name: Ft_GenericTimer_UsDelay
141 * @msg: 使用定时器进行us级别延时
142 * @in param{u32}: DelayUs 需要延时的us
143 * @param {u32} DelayUs
144 */
Ft_GenericTimer_UsDelay(FT_IN u32 DelayUs)145 int32_t Ft_GenericTimer_UsDelay(FT_IN u32 DelayUs)
146 {
147 register volatile u64 oldVal;
148 register volatile u64 newVal;
149 register volatile u64 decElapsed = 0;
150 register volatile u64 totalDelta;
151
152 int loopcount = 0;
153
154 if (Ft_GenericTimer_Handler.InitFlg == 0)
155 {
156 return FST_FAILURE;
157 }
158
159 if (DelayUs == 0)
160 {
161 return FST_FAILURE;
162 }
163
164 if (Ft_GenericTimer_Handler.TicksPerUs != 48)
165 {
166 //Ft_printf("ticksPerUs-%d should be 48 for this board, please check it!\r\n", Ft_GenericTimer_Handler.TicksPerUs);
167 }
168
169 totalDelta = Ft_GenericTimer_Handler.TicksPerUs * (u64)DelayUs;
170 oldVal = GenericTimer_GetTimerCnt(Ft_GenericTimer_Handler.UseVirtual);
171
172 while (decElapsed < totalDelta)
173 {
174 loopcount++;
175 newVal = GenericTimer_GetTimerCnt(Ft_GenericTimer_Handler.UseVirtual);
176
177 if (newVal == oldVal)
178 {
179 continue;
180 }
181
182 /* no rollover. count down... */
183
184 if (newVal < oldVal)
185 {
186 decElapsed += (oldVal - newVal);
187 }
188 /* rollover */
189 else
190 {
191 decElapsed += ((Ft_GenericTimer_Handler.MaxCount - oldVal) + newVal);
192 }
193
194 oldVal = newVal;
195 }
196
197 return FST_SUCCESS;
198 }
199
200 /**
201 * @name: Ft_GenericTimer_IsrSet
202 * @msg: 配置与控制 GenericTimer 中断参数
203 * @in param{u32}: HzRate 设置需要中断频率,输入参数应该小于等于 1000。
204 * @in param{u32}: Cmd 1 使能中断,0关闭中断。
205 * @return {int32_t}: 设置是否成功
206 */
Ft_GenericTimer_IsrSet(FT_IN u32 HzRate,FT_IN u32 Cmd)207 int32_t Ft_GenericTimer_IsrSet(FT_IN u32 HzRate, FT_IN u32 Cmd)
208 {
209
210 Ft_assertNonvoid(HzRate <= 1000);
211 Ft_assertNonvoid(Ft_GenericTimer_Handler.InitFlg != 0);
212
213 if (Cmd == 1)
214 {
215 if (Ft_GenericTimer_Handler.Isr_IsEnable == 2)
216 {
217 //<! turn off isr
218 GenericTimer_WriteReg(Ft_GenericTimer_Handler.UseVirtual, GEN_TIMER_REG_CTL,
219 GEN_TIMER_CTRL_IMASK);
220 }
221
222 Ft_GenericTimer_Handler.Isr_IsEnable = 1;
223 Ft_GenericTimer_Handler.Isr_PeriodCnt = Ft_GenericTimer_Handler.Frequency / HzRate;
224 Ft_GenericTimer_Handler.Isr_PeriodMsec = 1000 / HzRate;
225 /* update the timer value register with maxTimerCount */
226 GenericTimer_WriteReg(Ft_GenericTimer_Handler.UseVirtual, GEN_TIMER_REG_TVAL,
227 Ft_GenericTimer_Handler.Isr_PeriodCnt);
228
229 /* set up the timer control register */
230 GenericTimer_WriteReg(Ft_GenericTimer_Handler.UseVirtual, GEN_TIMER_REG_CTL,
231 GEN_TIMER_CTRL_ENABLE);
232 }
233 else if (Cmd == 0)
234 {
235 Ft_GenericTimer_Handler.Isr_IsEnable = 0;
236 Ft_GenericTimer_Handler.Isr_PeriodCnt = Ft_GenericTimer_Handler.Frequency / HzRate;
237 //<! turn off isr
238 GenericTimer_WriteReg(Ft_GenericTimer_Handler.UseVirtual, GEN_TIMER_REG_CTL,
239 GEN_TIMER_CTRL_IMASK);
240 }
241 else
242 {
243 return FST_FAILURE;
244 }
245 return FST_SUCCESS;
246 }
247
248 /**
249 * @name: Ft_GenericTimer_IrqHandler
250 * @msg: 中断函数
251 * @in param{void *}: param 用户定义变量。
252 */
Ft_GenericTimer_IrqHandler(void * param)253 void Ft_GenericTimer_IrqHandler(void *param)
254 {
255 /* update the timer value register with maxTimerCount */
256 GenericTimer_WriteReg(Ft_GenericTimer_Handler.UseVirtual, GEN_TIMER_REG_TVAL,
257 Ft_GenericTimer_Handler.Isr_PeriodCnt);
258
259 /* set up the timer control register */
260 GenericTimer_WriteReg(Ft_GenericTimer_Handler.UseVirtual, GEN_TIMER_REG_CTL,
261 GEN_TIMER_CTRL_ENABLE);
262
263 if (Ft_GenericTimer_Handler.Callback)
264 {
265 Ft_GenericTimer_Handler.Callback(param);
266 }
267
268 _TickCnt++;
269
270 _Tickms += Ft_GenericTimer_Handler.Isr_PeriodMsec;
271 }
272
Ft_GenericTimer_Debug(void)273 void Ft_GenericTimer_Debug(void)
274 {
275 Ft_printf("GenericTimer_ReadReg %x \r\n", GenericTimer_ReadReg(Ft_GenericTimer_Handler.UseVirtual, GEN_TIMER_REG_CTL));
276 }
277
278 /**
279 * @name: Ft_GenericTimer_GetTick
280 * @msg: 获取中断计数次数
281 * @return {u32} _TickCnt
282 */
Ft_GenericTimer_GetTick(void)283 u32 Ft_GenericTimer_GetTick(void)
284 {
285 return _TickCnt;
286 }
287
288 /**
289 * @name: Ft_GenericTimer_Msec
290 * @msg: 获取中断ms级别计数
291 * @return {u32}
292 */
Ft_GenericTimer_Msec(void)293 u32 Ft_GenericTimer_Msec(void)
294 {
295 return _Tickms;
296 }
297
298 /**
299 * @name: Ft_GenericTimer_Init
300 * @msg: GenericTimer 初始化
301 * @in param { u8} UseVirtual 1 使用 虚拟时钟,0使用真实时钟。
302 * @in param { Ft_GenericTimer_Isr_Callback} 中断回调函数。
303 * @return {*}
304 */
Ft_GenericTimer_Init(FT_IN u8 UseVirtual,FT_IN Ft_GenericTimer_Isr_Callback Callback)305 void Ft_GenericTimer_Init(FT_IN u8 UseVirtual, FT_IN Ft_GenericTimer_Isr_Callback Callback)
306 {
307 Ft_GenericTimer_Handler.Frequency = arm_aarch32_cntfrq_get();
308
309 Ft_GenericTimer_Handler.TicksPerUs = Ft_GenericTimer_Handler.Frequency / 1000000;
310
311 Ft_GenericTimer_Handler.MaxCount = 0xffffffffffffffffull;
312 Ft_GenericTimer_Handler.Callback = Callback;
313 Ft_GenericTimer_Handler.UseVirtual = UseVirtual;
314 Ft_GenericTimer_Handler.InitFlg = 1;
315 Ft_GenericTimer_Handler.Isr_IsEnable = 0;
316 _Tickms = 0;
317 _TickCnt = 0;
318
319 //<! 开启时钟
320 /* update the timer value register with maxTimerCount */
321 GenericTimer_WriteReg(Ft_GenericTimer_Handler.UseVirtual, GEN_TIMER_REG_TVAL,
322 Ft_GenericTimer_Handler.MaxCount);
323
324 /* set up the timer control register */
325 GenericTimer_WriteReg(Ft_GenericTimer_Handler.UseVirtual, GEN_TIMER_REG_CTL,
326 GEN_TIMER_CTRL_ENABLE);
327 }
328