1 /*
2  * Copyright 2022-2023 NXP
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <math.h>
8 #include "fsl_netc_timer.h"
9 
10 #define NETC_TIMER_GLOBAL_BASE_OFFSET          (0x10000U) /*!< The Timer global register base address offset. */
11 #define NETC_TIMER_EXT_TRIG_FIFO_THRESHOLD_MAX (15U)
12 
13 /*!
14  * @brief Set the MSIX entry table
15  *
16  * This function is to set entry table in specified MSIX Table memory.
17  *
18  * @param handle  The Timer handle.
19  * @param config  The Timer configuration.
20  * @return status_t
21  */
NETC_TimerMSIXSetEntryTable(netc_timer_handle_t * handle,const netc_timer_config_t * config)22 static status_t NETC_TimerMSIXSetEntryTable(netc_timer_handle_t *handle, const netc_timer_config_t *config)
23 {
24     uint32_t *msixTable  = (uint32_t *)(uintptr_t)handle->hw.msixTable;
25     uint32_t *entryTable = (uint32_t *)(uintptr_t)config->msixEntry;
26     uint8_t msixNum;
27 
28     msixNum = (uint8_t)((handle->hw.base->TMR_CAPR & ENETC_PF_TMR_TMR_CAPR_NUM_MSIX_MASK) >>
29                         ENETC_PF_TMR_TMR_CAPR_NUM_MSIX_SHIFT) +
30               1U;
31 
32     /* Entry > 0, enable MSIX. */
33     if (config->entryNum != 0U)
34     {
35         if (config->entryNum > msixNum)
36         {
37             return kStatus_InvalidArgument;
38         }
39 
40         /* Use 32-bit access to set MSIX table. */
41         msixTable[0] = entryTable[0];
42         msixTable[1] = entryTable[1];
43         msixTable[2] = entryTable[2];
44         msixTable[3] = entryTable[3];
45 
46         /* Enable MSIX. */
47         handle->hw.func->PCI_CFC_MSIX_MSG_CTL = ENETC_PCI_TYPE0_PCI_CFC_MSIX_MSG_CTL_MSIX_EN_MASK;
48     }
49     else
50     {
51         /* Disable MSIX. */
52         handle->hw.func->PCI_CFC_MSIX_MSG_CTL = ENETC_PCI_TYPE0_PCI_CFC_MSIX_MSG_CTL_FUNC_MASK_MASK;
53     }
54 
55     return kStatus_Success;
56 }
57 
NETC_TimerInitHandle(netc_timer_handle_t * handle)58 void NETC_TimerInitHandle(netc_timer_handle_t *handle)
59 {
60     /* Initialize the handle. */
61     handle->hw.func      = TMR_PCI_HDR_TYPE0;
62     handle->hw.base      = TMR0_BASE;
63     handle->hw.global    = (ENETC_GLOBAL_Type *)(TMR0_BASE_BASE + NETC_TIMER_GLOBAL_BASE_OFFSET);
64     handle->hw.msixTable = (netc_msix_entry_t *)(FSL_FEATURE_NETC_MSIX_TABLE_BASE);
65 }
66 
NETC_TimerInit(netc_timer_handle_t * handle,const netc_timer_config_t * config)67 status_t NETC_TimerInit(netc_timer_handle_t *handle, const netc_timer_config_t *config)
68 {
69     status_t result = kStatus_Success;
70     uint32_t period = NETC_NANOSECOND_ONE_SECOND / config->refClkHz;
71 
72     /* Initialize the handle. */
73     NETC_TimerInitHandle(handle);
74     handle->entryNum     = config->entryNum;
75     handle->timerFreq    = config->refClkHz;
76 
77     /* Reset this function */
78     handle->hw.func->PCI_CFC_PCIE_DEV_CTL |= ENETC_PCI_TYPE0_PCI_CFC_PCIE_DEV_CTL_INIT_FLR_MASK;
79     while ((handle->hw.func->PCI_CFC_PCIE_DEV_CTL & ENETC_PCI_TYPE0_PCI_CFC_PCIE_DEV_CTL_INIT_FLR_MASK) != 0U)
80     {
81     }
82 
83     /* Enable master bus and memory access for PCIe and MSI-X. */
84     handle->hw.func->PCI_CFH_CMD |=
85         ENETC_PCI_TYPE0_PCI_CFH_CMD_MEM_ACCESS_MASK | ENETC_PCI_TYPE0_PCI_CFH_CMD_BUS_MASTER_EN_MASK;
86 
87     result = NETC_TimerMSIXSetEntryTable(handle, config);
88     if (result != kStatus_Success)
89     {
90         return result;
91     }
92 
93     handle->hw.base->TMR_CTRL =
94         ENETC_PF_TMR_TMR_CTRL_TCLK_PERIOD(period) | ENETC_PF_TMR_TMR_CTRL_COPH(config->clkOutputPhase) |
95         ENETC_PF_TMR_TMR_CTRL_CIPH(config->clkInputPhase) | ENETC_PF_TMR_TMR_CTRL_TE(config->enableTimer) |
96         ENETC_PF_TMR_TMR_CTRL_COMP_MODE(config->atomicMode) | ENETC_PF_TMR_TMR_CTRL_CK_SEL(config->clockSelect);
97 
98     NETC_TimerAdjustFreq(handle, config->defaultPpb);
99 
100     handle->hw.base->TMR_CNT_L = 0;
101     handle->hw.base->TMR_CNT_H = 0;
102 
103     return kStatus_Success;
104 }
105 
NETC_TimerDeinit(netc_timer_handle_t * handle)106 void NETC_TimerDeinit(netc_timer_handle_t *handle)
107 {
108     /* Disable the 1588 timer. */
109     NETC_TimerEnable(handle, false);
110 
111     /* Disable master bus and memory access for PCIe and MSI-X. */
112     TMR_PCI_HDR_TYPE0->PCI_CFH_CMD &=
113         (uint16_t)(~(ENETC_PCI_TYPE0_PCI_CFH_CMD_MEM_ACCESS_MASK | ENETC_PCI_TYPE0_PCI_CFH_CMD_BUS_MASTER_EN_MASK));
114 
115     (void)memset(handle, 0, sizeof(netc_timer_handle_t));
116 }
117 
NETC_TimerEnable(netc_timer_handle_t * handle,bool enable)118 void NETC_TimerEnable(netc_timer_handle_t *handle, bool enable)
119 {
120     if (enable)
121     {
122         handle->hw.base->TMR_CTRL |= ENETC_PF_TMR_TMR_CTRL_TE_MASK;
123     }
124     else
125     {
126         handle->hw.base->TMR_CTRL &= ~ENETC_PF_TMR_TMR_CTRL_TE_MASK;
127     }
128 }
129 
NETC_TimerConfigureAlarm(netc_timer_handle_t * handle,netc_timer_alarm_index_t alarmId,const netc_timer_alarm_t * alarm)130 void NETC_TimerConfigureAlarm(netc_timer_handle_t *handle,
131                               netc_timer_alarm_index_t alarmId,
132                               const netc_timer_alarm_t *alarm)
133 {
134     uint32_t control;
135 
136     control = handle->hw.base->TMR_CTRL;
137     control &=
138         (alarmId == kNETC_TimerAlarm1) ? (~ENETC_PF_TMR_TMR_CTRL_ALM1P_MASK) : (~ENETC_PF_TMR_TMR_CTRL_ALM2P_MASK);
139     control |= (alarmId == kNETC_TimerAlarm1) ? (ENETC_PF_TMR_TMR_CTRL_ALM1P(alarm->polarity)) :
140                                                 ENETC_PF_TMR_TMR_CTRL_ALM2P(alarm->polarity);
141     handle->hw.base->TMR_CTRL = control;
142 
143     control = handle->hw.base->TMR_ALARM_CTRL;
144     control &= (alarmId == kNETC_TimerAlarm1) ?
145                    (~(ENETC_PF_TMR_TMR_ALARM_CTRL_PG1_MASK | ENETC_PF_TMR_TMR_ALARM_CTRL_ALARM1_PW_MASK)) :
146                    (~(ENETC_PF_TMR_TMR_ALARM_CTRL_PG2_MASK | ENETC_PF_TMR_TMR_ALARM_CTRL_ALARM2_PW_MASK));
147     control |= (alarmId == kNETC_TimerAlarm1) ? (ENETC_PF_TMR_TMR_ALARM_CTRL_PG1(alarm->pulseGenSync) |
148                                                  ENETC_PF_TMR_TMR_ALARM_CTRL_ALARM1_PW(alarm->pulseWidth)) :
149                                                 (ENETC_PF_TMR_TMR_ALARM_CTRL_PG2(alarm->pulseGenSync) |
150                                                  ENETC_PF_TMR_TMR_ALARM_CTRL_ALARM2_PW(alarm->pulseWidth));
151     handle->hw.base->TMR_ALARM_CTRL = control;
152 
153     /* Alarm interrupt mask configuration. */
154     control = handle->hw.base->TMR_TEMASK;
155     control &= (alarmId == kNETC_TimerAlarm1) ? (~ENETC_PF_TMR_TMR_TEMASK_ALM1EN_MASK) :
156                                                 (~ENETC_PF_TMR_TMR_TEMASK_ALM2EN_MASK);
157     control |= (alarmId == kNETC_TimerAlarm1) ? ENETC_PF_TMR_TMR_TEMASK_ALM1EN(alarm->enableInterrupt) :
158                                                 ENETC_PF_TMR_TMR_TEMASK_ALM2EN(alarm->enableInterrupt);
159     handle->hw.base->TMR_TEMASK = control;
160 }
161 
NETC_TimerStartAlarm(netc_timer_handle_t * handle,netc_timer_alarm_index_t alarmId,uint64_t nanosecond)162 void NETC_TimerStartAlarm(netc_timer_handle_t *handle, netc_timer_alarm_index_t alarmId, uint64_t nanosecond)
163 {
164     if (alarmId == kNETC_TimerAlarm1)
165     {
166         handle->hw.base->TMR_ALARMM[0].TMR_ALARM_L = (uint32_t)nanosecond;
167         handle->hw.base->TMR_ALARMM[0].TMR_ALARM_H = (uint32_t)(nanosecond >> 32U);
168     }
169     else
170     {
171         handle->hw.base->TMR_ALARMM[1].TMR_ALARM_L = (uint32_t)nanosecond;
172         handle->hw.base->TMR_ALARMM[1].TMR_ALARM_H = (uint32_t)(nanosecond >> 32U);
173     }
174 }
175 
NETC_TimerStopAlarm(netc_timer_handle_t * handle,netc_timer_alarm_index_t alarmId)176 void NETC_TimerStopAlarm(netc_timer_handle_t *handle, netc_timer_alarm_index_t alarmId)
177 {
178     if (alarmId == kNETC_TimerAlarm1)
179     {
180         handle->hw.base->TMR_ALARMM[0].TMR_ALARM_L = 0;
181     }
182     else
183     {
184         handle->hw.base->TMR_ALARMM[1].TMR_ALARM_L = 0;
185     }
186 }
187 
NETC_TimerConfigureFIPER(netc_timer_handle_t * handle,const netc_timer_fiper_config_t * config)188 void NETC_TimerConfigureFIPER(netc_timer_handle_t *handle, const netc_timer_fiper_config_t *config)
189 {
190     assert((config->prescale % 2U) == 0U);
191 
192     handle->hw.base->TMR_CTRL &=
193         ~(ENETC_PF_TMR_TMR_CTRL_FS_MASK | ENETC_PF_TMR_TMR_CTRL_PP1L_MASK | ENETC_PF_TMR_TMR_CTRL_PP2L_MASK);
194     handle->hw.base->TMR_CTRL |= ENETC_PF_TMR_TMR_CTRL_FS(config->startCondition) |
195                                  ENETC_PF_TMR_TMR_CTRL_PP1L(config->fiper1Loopback) |
196                                  ENETC_PF_TMR_TMR_CTRL_PP2L(config->fiper1Loopback);
197     handle->hw.base->TMR_PRSC = config->prescale;
198 }
199 
NETC_TimerStartFIPER(netc_timer_handle_t * handle,netc_timer_fiper_index_t fiperId,const netc_timer_fiper_t * fiper)200 void NETC_TimerStartFIPER(netc_timer_handle_t *handle,
201                           netc_timer_fiper_index_t fiperId,
202                           const netc_timer_fiper_t *fiper)
203 {
204     uint32_t control;
205     uint32_t clear;
206 
207     if (fiperId == kNETC_TimerFiper1)
208     {
209         /* Disbale the FIPER first */
210         handle->hw.base->TMR_FIPER_CTRL |= ENETC_PF_TMR_TMR_FIPER_CTRL_FIPER1_DIS_MASK;
211 
212         handle->hw.base->TMR_TEMASK &= ~ENETC_PF_TMR_TMR_TEMASK_PP1EN_MASK;
213         handle->hw.base->TMR_TEMASK |= ENETC_PF_TMR_TMR_TEMASK_PP1EN(fiper->enableInterrupt);
214         clear   = ENETC_PF_TMR_TMR_FIPER_CTRL_FIPER1_PW_MASK | ENETC_PF_TMR_TMR_FIPER_CTRL_PG1_MASK;
215         control = ENETC_PF_TMR_TMR_FIPER_CTRL_FIPER1_PW(fiper->pulseWidth) |
216                   ENETC_PF_TMR_TMR_FIPER_CTRL_PG1(fiper->pulseGenSync);
217     }
218     else if (fiperId == kNETC_TimerFiper2)
219     {
220         /* Disbale the FIPER first */
221         handle->hw.base->TMR_FIPER_CTRL |= ENETC_PF_TMR_TMR_FIPER_CTRL_FIPER2_DIS_MASK;
222 
223         handle->hw.base->TMR_TEMASK &= ~ENETC_PF_TMR_TMR_TEMASK_PP2EN_MASK;
224         handle->hw.base->TMR_TEMASK |= ENETC_PF_TMR_TMR_TEMASK_PP2EN(fiper->enableInterrupt);
225         clear   = ENETC_PF_TMR_TMR_FIPER_CTRL_FIPER2_PW_MASK | ENETC_PF_TMR_TMR_FIPER_CTRL_PG2_MASK;
226         control = ENETC_PF_TMR_TMR_FIPER_CTRL_FIPER2_PW(fiper->pulseWidth) |
227                   ENETC_PF_TMR_TMR_FIPER_CTRL_PG2(fiper->pulseGenSync);
228     }
229     else
230     {
231         /* Disbale the FIPER first */
232         handle->hw.base->TMR_FIPER_CTRL |= ENETC_PF_TMR_TMR_FIPER_CTRL_FIPER3_DIS_MASK;
233 
234         handle->hw.base->TMR_TEMASK &= ~ENETC_PF_TMR_TMR_TEMASK_PP3EN_MASK;
235         handle->hw.base->TMR_TEMASK |= ENETC_PF_TMR_TMR_TEMASK_PP3EN(fiper->enableInterrupt);
236         clear   = ENETC_PF_TMR_TMR_FIPER_CTRL_FIPER3_PW_MASK | ENETC_PF_TMR_TMR_FIPER_CTRL_PG3_MASK;
237         control = ENETC_PF_TMR_TMR_FIPER_CTRL_FIPER3_PW(fiper->pulseWidth) |
238                   ENETC_PF_TMR_TMR_FIPER_CTRL_PG3(fiper->pulseGenSync);
239     }
240 
241     handle->hw.base->TMR_FIPER[fiperId] = fiper->pulsePeriod;
242     handle->hw.base->TMR_FIPER_CTRL &= ~clear;
243     handle->hw.base->TMR_FIPER_CTRL |= control;
244 
245     handle->hw.base->TMR_FIPER_CTRL &=
246         ~((uint32_t)ENETC_PF_TMR_TMR_FIPER_CTRL_FIPER1_DIS_MASK << ((uint32_t)fiperId * 8U));
247 }
248 
NETC_TimerStopFIPER(netc_timer_handle_t * handle,netc_timer_fiper_index_t fiperId)249 void NETC_TimerStopFIPER(netc_timer_handle_t *handle, netc_timer_fiper_index_t fiperId)
250 {
251     handle->hw.base->TMR_FIPER_CTRL |=
252         ((uint32_t)ENETC_PF_TMR_TMR_FIPER_CTRL_FIPER1_DIS_MASK << ((uint32_t)fiperId * 8U));
253 }
254 
NETC_TimerSetTsFifoThreshold(netc_timer_handle_t * handle,uint8_t threshold)255 status_t NETC_TimerSetTsFifoThreshold(netc_timer_handle_t *handle, uint8_t threshold)
256 {
257     status_t result = kStatus_Fail;
258 
259     if (threshold <= NETC_TIMER_EXT_TRIG_FIFO_THRESHOLD_MAX)
260     {
261         handle->hw.base->TMR_ECTRL = threshold;
262         result                     = kStatus_Success;
263     }
264 
265     return result;
266 }
267 
NETC_TimerConfigureExtPulseTrig(netc_timer_handle_t * handle,netc_timer_exttrig_index_t extTrigId,const netc_timer_ext_trig_t * extTrig)268 void NETC_TimerConfigureExtPulseTrig(netc_timer_handle_t *handle,
269                                      netc_timer_exttrig_index_t extTrigId,
270                                      const netc_timer_ext_trig_t *extTrig)
271 {
272     uint32_t control;
273     uint32_t clear;
274 
275     clear   = (extTrigId == kNETC_TimerExtTrig1) ? ENETC_PF_TMR_TMR_CTRL_ETEP1_MASK : ENETC_PF_TMR_TMR_CTRL_ETEP2_MASK;
276     control = (extTrigId == kNETC_TimerExtTrig1) ? ENETC_PF_TMR_TMR_CTRL_ETEP1(extTrig->polarity) :
277                                                    ENETC_PF_TMR_TMR_CTRL_ETEP2(extTrig->polarity);
278     handle->hw.base->TMR_CTRL &= ~clear;
279     handle->hw.base->TMR_CTRL |= control;
280 
281     clear = (extTrigId == kNETC_TimerExtTrig1) ?
282                 (ENETC_PF_TMR_TMR_TEMASK_ETS1EN_MASK | ENETC_PF_TMR_TMR_TEMASK_ETS1_THREN_MASK |
283                  ENETC_PF_TMR_TMR_TEMASK_ETS1_OVEN_MASK) :
284                 (ENETC_PF_TMR_TMR_TEMASK_ETS2EN_MASK | ENETC_PF_TMR_TMR_TEMASK_ETS2_THREN_MASK |
285                  ENETC_PF_TMR_TMR_TEMASK_ETS2_OVEN_MASK);
286     control = (extTrigId == kNETC_TimerExtTrig1) ?
287                   (ENETC_PF_TMR_TMR_TEMASK_ETS1EN(extTrig->enableTsAvailInterrupt) |
288                    ENETC_PF_TMR_TMR_TEMASK_ETS1_THREN(extTrig->enableFifoThresholdHitInterrupt) |
289                    ENETC_PF_TMR_TMR_TEMASK_ETS1_OVEN(extTrig->enableFifoOverflowInterrupt)) :
290                   (ENETC_PF_TMR_TMR_TEMASK_ETS2EN(extTrig->enableTsAvailInterrupt) |
291                    ENETC_PF_TMR_TMR_TEMASK_ETS2_THREN(extTrig->enableFifoThresholdHitInterrupt) |
292                    ENETC_PF_TMR_TMR_TEMASK_ETS2_OVEN(extTrig->enableFifoOverflowInterrupt));
293     handle->hw.base->TMR_TEMASK &= ~clear;
294     handle->hw.base->TMR_TEMASK |= control;
295 }
296 
297 /*!
298  * @brief Check the timestamp available status in FIFO
299  *
300  * @param base NETC timer peripheral base address.
301  * @param tsFifo The FIFO number to read timestamp out.
302  * @return True: FIFO is empty, False: FIFO is not empty
303  */
NETC_TimerCheckTsFifoEmpty(netc_timer_handle_t * handle,netc_timer_exttrig_index_t extTrigId)304 static bool NETC_TimerCheckTsFifoEmpty(netc_timer_handle_t *handle, netc_timer_exttrig_index_t extTrigId)
305 {
306     return ((handle->hw.base->TMR_STAT & (ENETC_PF_TMR_TMR_STAT_ETS1_VLD_MASK << (uint32_t)extTrigId)) == 0U);
307 }
308 
NETC_TimerReadExtPulseCaptureTime(netc_timer_handle_t * handle,netc_timer_exttrig_index_t extTrigId,uint64_t * nanosecond)309 status_t NETC_TimerReadExtPulseCaptureTime(netc_timer_handle_t *handle,
310                                            netc_timer_exttrig_index_t extTrigId,
311                                            uint64_t *nanosecond)
312 {
313     status_t result = kStatus_Fail;
314     uint32_t timeLow, timeHigh;
315 
316     if (!NETC_TimerCheckTsFifoEmpty(handle, extTrigId))
317     {
318         if (extTrigId == kNETC_TimerExtTrig1)
319         {
320             timeLow  = handle->hw.base->TMR_ETTSN[0].TMR_ETTS_L;
321             timeHigh = handle->hw.base->TMR_ETTSN[0].TMR_ETTS_H;
322         }
323         else
324         {
325             timeLow  = handle->hw.base->TMR_ETTSN[1].TMR_ETTS_L;
326             timeHigh  = handle->hw.base->TMR_ETTSN[1].TMR_ETTS_H;
327         }
328         *nanosecond = ((uint64_t)timeHigh << 32U) + timeLow;
329         result      = kStatus_Success;
330     }
331     return result;
332 }
333 
__NETC_TimerGetCurrentTime(ENETC_PF_TMR_Type * base,uint64_t * nanosecond)334 static void __NETC_TimerGetCurrentTime(ENETC_PF_TMR_Type *base, uint64_t *nanosecond)
335 {
336     uint32_t timeLow, timeHigh[2];
337 
338     timeHigh[0] = base->TMR_CUR_TIME_H;
339     do {
340         timeHigh[1] = timeHigh[0];
341         timeLow     = base->TMR_CUR_TIME_L;
342         timeHigh[0] = base->TMR_CUR_TIME_H;
343     } while (timeHigh[0] != timeHigh[1]);
344 
345     *nanosecond = ((uint64_t)timeHigh[0] << 32U) + timeLow;
346 }
347 
NETC_TimerGetTime(ENETC_PF_TMR_Type * base,uint64_t * nanosecond)348 void NETC_TimerGetTime(ENETC_PF_TMR_Type *base, uint64_t *nanosecond)
349 {
350     if ((base->TMR_CTRL & ENETC_PF_TMR_TMR_CTRL_TE_MASK) != 0U) {
351         __NETC_TimerGetCurrentTime(base, nanosecond);
352     } else {
353         uint32_t timeLow, timeHigh[2];
354 
355         timeHigh[0] = base->TMR_DEF_CNT_H;
356         do {
357             timeHigh[1] = timeHigh[0];
358             timeLow     = base->TMR_DEF_CNT_L;
359             timeHigh[0] = base->TMR_DEF_CNT_H;
360         } while (timeHigh[0] != timeHigh[1]);
361 
362         *nanosecond = ((uint64_t)timeHigh[0] << 32U) + timeLow;
363     }
364 }
365 
NETC_TimerGetCurrentTime(netc_timer_handle_t * handle,uint64_t * nanosecond)366 void NETC_TimerGetCurrentTime(netc_timer_handle_t *handle, uint64_t *nanosecond)
367 {
368     __NETC_TimerGetCurrentTime(handle->hw.base, nanosecond);
369 }
370 
NETC_TimerGetFreeRunningTime(netc_timer_handle_t * handle,uint64_t * nanosecond)371 void NETC_TimerGetFreeRunningTime(netc_timer_handle_t *handle, uint64_t *nanosecond)
372 {
373     uint32_t timeLow, timeHigh[2];
374 
375     timeHigh[0] = handle->hw.base->TMR_FRT_H;
376     do {
377         timeHigh[1] = timeHigh[0];
378         timeLow     = handle->hw.base->TMR_FRT_L;
379         timeHigh[0] = handle->hw.base->TMR_FRT_H;
380     } while (timeHigh[0] != timeHigh[1]);
381 
382     *nanosecond = ((uint64_t)timeHigh[0] << 32U) + timeLow;
383 }
384 
NETC_TimerAddOffset(netc_timer_handle_t * handle,int64_t nanosecond)385 void NETC_TimerAddOffset(netc_timer_handle_t *handle, int64_t nanosecond)
386 {
387     uint64_t offset;
388 
389     if (nanosecond >= 0)
390     {
391         offset = (uint64_t)nanosecond;
392     }
393     else
394     {
395         offset = UINT64_MAX - (uint64_t)(-nanosecond);
396     }
397 
398     /* Calculate a new offset value based on the current one. */
399     offset += ((uint64_t)handle->hw.base->TMROFF_H << 32U) + handle->hw.base->TMROFF_L;
400     /* Update the latest offset. */
401     handle->hw.base->TMROFF_L = (uint32_t)offset;
402     handle->hw.base->TMROFF_H = (uint32_t)(offset >> 32U);
403 }
404 
NETC_TimerAdjustFreq(netc_timer_handle_t * handle,int32_t ppb)405 void NETC_TimerAdjustFreq(netc_timer_handle_t *handle, int32_t ppb)
406 {
407     int64_t offset = 1000000000LL + ppb;
408     uint64_t addend;
409 
410     /* period (in ns) is given by: 10^9 / freq */
411     /* ppb is applied to period: period' = period * (1 + ppb / 10^9) */
412     /* addend is the fractional part of the period (in ns) scaled by 2^32, */
413     /* which is equivalent to scaling period by 2^32, and then taking the lower 32bits */
414     /* addend' = 10^9 / freq * (1 + ppp / 10^9) * 2^32 = (2^32 * (10^9 + ppb)) / freq */
415     addend = (((uint64_t)1ULL << 32) * (uint64_t)offset) / handle->timerFreq;
416 
417     handle->hw.base->TMR_ADD = (uint32_t)addend;
418 }
419 
NETC_TimerGetFrtSrtTime(netc_timer_handle_t * handle,uint64_t * frt,uint64_t * srt)420 void NETC_TimerGetFrtSrtTime(netc_timer_handle_t *handle, uint64_t *frt, uint64_t *srt)
421 {
422     uint32_t tsLow, tsHigh;
423 
424     /* Read TMR_FRT_L captures all 64b of FRT_H/L and 64b of SRT_H/L for an atomic read of all 4 registers. */
425     tsLow  = handle->hw.base->TMR_FRT_L;
426     tsHigh = handle->hw.base->TMR_FRT_H;
427     *frt   = ((uint64_t)tsHigh << 32U) + tsLow;
428 
429     tsLow  = handle->hw.base->TMR_SRT_L;
430     tsHigh = handle->hw.base->TMR_SRT_H;
431     *srt   = ((uint64_t)tsHigh << 32U) + tsLow;
432 }
433 
NETC_TimerMsixSetGlobalMask(netc_timer_handle_t * handle,bool mask)434 status_t NETC_TimerMsixSetGlobalMask(netc_timer_handle_t *handle, bool mask)
435 {
436     if (mask)
437     {
438         handle->hw.func->PCI_CFC_MSIX_MSG_CTL |= ENETC_PCI_TYPE0_PCI_CFC_MSIX_MSG_CTL_FUNC_MASK_MASK;
439     }
440     else
441     {
442         handle->hw.func->PCI_CFC_MSIX_MSG_CTL &= ~(uint16_t)ENETC_VF_PCI_TYPE0_PCI_CFC_MSIX_MSG_CTL_FUNC_MASK_MASK;
443     }
444 
445     return kStatus_Success;
446 }
447 
NETC_TimerMsixSetEntryMask(netc_timer_handle_t * handle,uint8_t entryIdx,bool mask)448 status_t NETC_TimerMsixSetEntryMask(netc_timer_handle_t *handle, uint8_t entryIdx, bool mask)
449 {
450     status_t result;
451 
452     if (entryIdx < handle->entryNum)
453     {
454         handle->hw.msixTable[entryIdx].control = (uint32_t)mask;
455         result                                 = kStatus_Success;
456     }
457     else
458     {
459         result = kStatus_Fail;
460     }
461 
462     return result;
463 }
464 
NETC_TimerMsixGetPendingStatus(netc_timer_handle_t * handle,uint8_t pbaIdx,uint64_t * status)465 status_t NETC_TimerMsixGetPendingStatus(netc_timer_handle_t *handle, uint8_t pbaIdx, uint64_t *status)
466 {
467     status_t result = kStatus_Success;
468     bool funcEnable;
469 
470     if (handle->entryNum == 0U)
471     {
472         return kStatus_Fail;
473     }
474 
475     /* Check MSIX enable status. */
476     funcEnable = ((handle->hw.func->PCI_CFC_MSIX_MSG_CTL & ENETC_PCI_TYPE0_PCI_CFC_MSIX_MSG_CTL_MSIX_EN_MASK) != 0U);
477 
478     if (funcEnable)
479     {
480         if (pbaIdx <= ((handle->entryNum - 1U) / 64U))
481         {
482             *status = *(uint64_t *)((uintptr_t)handle->hw.msixTable + NETC_MSIX_TABLE_PBA_OFFSET + 8U * pbaIdx);
483             result  = kStatus_Success;
484         }
485         else
486         {
487             result = kStatus_InvalidArgument;
488         }
489     }
490     else
491     {
492         *status = 0;
493         result  = kStatus_Fail;
494     }
495 
496     return result;
497 }
498