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