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