1 /*
2 * Copyright (c) 2015-2020, Texas Instruments Incorporated
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of Texas Instruments Incorporated nor the names of
17 * its contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <ti/drivers/dpl/ClockP.h>
34 #include <ti/drivers/dpl/DebugP.h>
35 #include <ti/drivers/dpl/HwiP.h>
36 #include <ti/drivers/dpl/SemaphoreP.h>
37 #include <ti/drivers/dpl/SwiP.h>
38
39 #include <ti/drivers/Power.h>
40 #include <ti/drivers/power/PowerCC26X2.h>
41 #include <ti/drivers/Temperature.h>
42 #include <ti/drivers/rf/RF.h>
43 #include <ti/drivers/utils/List.h>
44
45 #include <ti/devices/DeviceFamily.h>
46 #include DeviceFamily_constructPath(inc/hw_memmap.h)
47 #include DeviceFamily_constructPath(inc/hw_ints.h)
48 #include DeviceFamily_constructPath(inc/hw_types.h)
49 #include DeviceFamily_constructPath(inc/hw_rfc_rat.h)
50 #include DeviceFamily_constructPath(inc/hw_rfc_dbell.h)
51 #include DeviceFamily_constructPath(driverlib/rfc.h)
52 #include DeviceFamily_constructPath(driverlib/sys_ctrl.h)
53 #include DeviceFamily_constructPath(driverlib/ioc.h)
54 #include DeviceFamily_constructPath(driverlib/aon_ioc.h)
55 #include DeviceFamily_constructPath(driverlib/rf_mailbox.h)
56 #include DeviceFamily_constructPath(driverlib/adi.h)
57 #include DeviceFamily_constructPath(driverlib/aon_rtc.h)
58 #include DeviceFamily_constructPath(driverlib/chipinfo.h)
59 #include DeviceFamily_constructPath(driverlib/osc.h)
60 #include DeviceFamily_constructPath(driverlib/ccfgread.h)
61
62 #if defined(__IAR_SYSTEMS_ICC__)
63 #pragma diag_remark=Pa082
64 #endif
65
66 #if defined(RF_SINGLEMODE)
67 #error "An incompatible symbol (RF_SINGLEMODE) is defined in the project. \
68 To build with this driver, remove the RF_SINGLEMODE token definition."
69 #endif
70
71 /*-------------- Typedefs, structures & defines ---------------*/
72
73 /* Definition of internal state-machine events. */
74 typedef enum RF_FsmEvent_ {
75 RF_FsmEventLastCommandDone = (1UL << 1), /* Indicates that a radio command is finished. */
76 RF_FsmEventWakeup = (1UL << 2), /* Used to initiate the power up sequence of the RF core. */
77 RF_FsmEventPowerDown = (1UL << 3), /* Used to initiate the power down sequence of the RF core. */
78 RF_FsmEventInitChangePhy = (1UL << 10), /* Used to initiate the PHY change sequence. */
79 RF_FsmEventFinishChangePhy = (1UL << 11), /* Used to finalize the PHY change sequence. */
80 RF_FsmEventCpeInt = (1UL << 14), /* Generated during command execution. */
81 RF_FsmEventPowerStep = (1UL << 29), /* Generated during the power up sequence of RF core. */
82 RF_FsmEventRunScheduler = (1UL << 30) /* Used to invoke the scheduler again to check for conflicts. */
83 } RF_FsmEvent;
84
85 /* Definition of states of RF core. */
86 typedef enum RF_CoreStatus_ {
87 RF_CoreStatusIdle = 0, /* The RF core is OFF. */
88 RF_CoreStatusPoweringUp = 1, /* The RF core is being powered up. */
89 RF_CoreStatusActive = 2, /* The RF core is ON. */
90 RF_CoreStatusPoweringDown = 3, /* The RF core is being powered down. */
91 RF_CoreStatusPhySwitching = 4 /* The RF core is being reconfigured. */
92 } RF_CoreStatus;
93
94 /* Definition of internal power constraints. Note that the physical RAT channels in the RF core are
95 not a one-to-one map to the constraint values here. */
96 typedef enum RF_PowerConstraintSrc_ {
97 RF_PowerConstraintNone = 0,
98 RF_PowerConstraintRatCh0 = (1U << 0), /* Indicates that the Channel 0 of RAT timer is running. */
99 RF_PowerConstraintRatCh1 = (1U << 1), /* Indicates that the Channel 1 of RAT timer is running. */
100 RF_PowerConstraintRatCh2 = (1U << 2), /* Indicates that the Channel 2 of RAT timer is running. */
101 RF_PowerConstraintCmdQ = (1U << 3), /* Indicates that the RF core executing a radio command. */
102 RF_PowerConstraintDisallow = (1U << 7) /* Disable automatic power management. */
103 } RF_PowerConstraintSrc;
104
105 /* Definition of internal Radio Timer (RAT) modes. */
106 typedef enum RF_RatMode_ {
107 RF_RatModeUndefined = 0, /* Indicates that the RAT channel is not configured. */
108 RF_RatModeCompare = 1, /* Indicates that the RAT channel is configured to compare mode. */
109 RF_RatModeCapture = 2 /* Indicates that the RAT channel is configured to capture mode. */
110 } RF_RatMode;
111
112 /* Definition of internal Radio Timer (RAT) states. */
113 typedef enum RF_RatStatus_ {
114 RF_RatStatusIdle = 0, /* Indicates that the RAT channel is not used. */
115 RF_RatStatusPending = 1, /* Indicates that the RAT channel is configured, but the RAT timer is not running (i.e. RF core is OFF). */
116 RF_RatStatusRunning = 2 /* Indicates that the RAT channel is configured, and the RAT timer is running. */
117 } RF_RatStatus;
118
119 /* Definition of internal status codes of command shceduling. */
120 typedef enum RF_ScheduleCmdStatus_ {
121 RF_ScheduleCmdSuccess = 0, /* Schedule command success. */
122 RF_ScheduleCmdAllocError = 1, /* Schedule command allocation error (such as queue is full). */
123 RF_ScheduleCmdSchError = 2 /* SChedule command scheduler error (timing or priority conflict). */
124 } RF_ScheduleCmdStatus;
125
126 /*-------------- Macros ---------------*/
127
128 /* Zephyr already defines these, so undefining them */
129 #ifdef MAX
130 #undef MAX
131 #endif
132 #ifdef MIN
133 #undef MIN
134 #endif
135
136 #define ABS(x) (((x) < 0) ? -(x) : (x))
137 #define MAX(x,y) (((x) > (y)) ? (x) : (y))
138 #define MIN(x,y) (((x) < (y)) ? (x) : (y))
139 #define UDIFF(x,y) (((y) > (x)) ? ((y) - (x)) : ((~0) + (y) - (x) + (1)))
140 #define ADD(x,y) ((x > ((~0) - (y))) ? (~0) : ((x) + (y)))
141
142 /*-------------- Defines ---------------*/
143
144 /* Max # of RF driver clients */
145 #define N_MAX_CLIENTS 2
146 /* 8 RF_Cmds in pool */
147 #define N_CMD_POOL 8
148 /* Modulus mask used for RF_CmdHandle calculations */
149 #define N_CMD_MODMASK 0xFFF
150
151 /*-------------- Internal RF constants ---------------*/
152
153 #define RF_CMD0 0x0607
154 #define RF_BOOT0 0xE0000011
155 #define RF_BOOT1 0x00000080
156 /* Accessible RF Core interrupts mask MSB 32 bits : RFHW int, LSB 32 bits : RF CPE int */
157 #define RF_INTERNAL_IFG_MASK 0xFFFFFFDF60001000
158 #define RF_TERMINATION_EVENT_MASK (RF_EventLastCmdDone | RF_EventLastFGCmdDone | RF_EventCmdAborted | RF_EventCmdStopped | RF_EventCmdCancelled)
159 #define RF_CMD_FG_CMD_FLAG (1 << 4)
160 #define RF_CMD_ALLOC_FLAG (1 << 7)
161 #define RF_CMD_TERMINATED (DONE_OK | ERROR_PAST_START)
162 #define RF_HW_INT_RAT_CH_MASK (RFC_DBELL_RFHWIFG_RATCH7 | RFC_DBELL_RFHWIFG_RATCH6 | RFC_DBELL_RFHWIFG_RATCH5)
163 #define RF_RAT_CH_CNT 3
164 #define RF_HW_INT_CPE_MASK RFC_DBELL_RFHWIFG_MDMSOFT
165 #define RF_CPE0_INT_MASK 0xFFFFFFFF
166 /* Default value for power up duration (in us) used before first power cycle */
167 #define RF_DEFAULT_POWER_UP_TIME 2500
168 /* Default minimum power up duration (in us) */
169 #define RF_DEFAULT_MIN_POWER_UP_TIME 300
170 /* Default power-up margin (in us) to account for wake-up sequence outside the RF power state machine */
171 #define RF_DEFAULT_POWER_UP_MARGIN 314
172 /* Default phy-switching margin (in us) to account for overhead of processing time on the system MCU. */
173 #define RF_DEFAULT_PHY_SWITCHING_MARGIN 314
174 /* Default power down duration in us */
175 #define RF_DEFAULT_POWER_DOWN_TIME 1000
176 #define RF_MAX_CHAIN_CMD_LEN 8
177 /* RAT channel (0-4) are used by RF Core. Only 5,6,7 are available for application */
178 #define RF_RAT_CH_LOWEST 5
179 #define RF_SEND_RAT_STOP_RATIO 7
180 #define RF_RTC_CONV_TO_US_SHIFT 12
181 #define RF_SHIFT_4_BITS 4
182 #define RF_SHIFT_8_BITS 8
183 #define RF_SHIFT_16_BITS 16
184 #define RF_SHIFT_32_BITS 32
185 #define RF_RTC_TICK_INC (0x100000000LL/32768)
186 #define RF_SCALE_RTC_TO_4MHZ 4000000
187 #define RF_NUM_RAT_TICKS_IN_1_US 4
188 /* (3/4)th of a full RAT cycle, in us */
189 #define RF_DISPATCH_MAX_TIME_US (UINT32_MAX / RF_NUM_RAT_TICKS_IN_1_US * 3 / 4)
190 /* (1/4)th of a full RAT cycle, in us */
191 #define RF_DISPATCH_MAX_TIME_WRAPAROUND_US (int32_t)(RF_DISPATCH_MAX_TIME_US - UINT32_MAX / RF_NUM_RAT_TICKS_IN_1_US)
192 #define RF_DISPATCH_INFINIT_TIME (UINT32_MAX)
193 #define RF_XOSC_HF_SWITCH_CHECK_PERIOD_US 50
194 #define RF_DEFAULT_AVAILRATCH_VAL 0x7
195 #define RF_ABORT_FLUSH_ALL 0x2
196 #define RF_CMDSTA_REG_VAL_MASK 0xFF
197 #define RF_RAT_CAPTURE_REPEAT_MODE 0x10000000
198 #define RF_RAT_INTERRUPT_BASE_INDEX 0x01
199 #define RF_RAT_ERROR_BASE_INDEX 0x10
200 #define RF_RAT_COMPENSATION_TIME_US 25
201 #define RF_PHY_SWITCHING_MODE 1
202 #define RF_PHY_BOOTUP_MODE 0
203 #define RF_SCH_CMD_TIMING_INSERT 0x4
204 #define RF_REQ_ACCESS_MAX_DUR_US 1000000
205 /* Additional analog config time for setup command */
206 #define RF_ANALOG_CFG_TIME_US 96
207 /* Update analog configuration in setup */
208 #define RF_SETUP_ANALOGCFG_UPDATE 0
209 /* Don't update analog configuration in setup */
210 #define RF_SETUP_ANALOGCFG_NOUPDATE 0x2D
211 #define RF_SCH_CMD_STARTTIME_NOW 0
212 #define RF_SCH_CMD_ENDTIME_IGNORE 0
213 #define RF_DEFAULT_PHY_SWITCHING_TIME 500
214 #define RF_RADIOFREECB_PREEMPT_FLAG 0x1
215 #define RF_RADIOFREECB_REQACCESS_FLAG 0x2
216 #define RF_RADIOFREECB_CMDREJECT_FLAG 0x4
217 #define RF_DEFAULT_RAT_RTC_ERR_TOL_IN_US 5
218 /* Approx for 1e6 / 500. XTAL drift is 500 ppm */
219 #define RF_DEFAULT_COMB_XTAL_DRIFT_BITS_SHIFT 11
220 /* Window (in us) to decide if wakeup was from RF power up clock */
221 #define RF_WAKEUP_DETECTION_WINDOW_IN_US 300
222 /* Ieee context mask and background value */
223 #define RF_IEEE_ID_MASK 0xFC00
224 #define RF_IEEE_FG_CMD 0x2C00
225 /* Defines for to mask High-PA overrides. */
226 #define RF_TX20_ENABLED 0xFFFF
227 #define RF_TX20_PATYPE_ADDRESS 0x21000345
228 #define RF_TX20_PATYPE_MASK 0x04
229 #define RF_TX20_GAIN_ADDRESS 0x2100034C
230 #define RF_TX20_GAIN_MASK 0x003FFFFF
231 #define RF_TX20_PATTERN TX20_POWER_OVERRIDE(0)
232 #define RF_TXSTD_PATTERN TX_STD_POWER_OVERRIDE(0)
233 #define RF_TX_OVERRIDE_MASK 0x000003FF
234 #define RF_TX_OVERRIDE_SHIFT 10
235 #define RF_TX_OVERRIDE_INVALID_OFFSET 0xFF
236 /* Defines for update of the HPOSC override */
237 #define RF_HPOSC_OVERRIDE_PATTERN HPOSC_OVERRIDE(0)
238 #define RF_HPOSC_OVERRIDE_MASK 0xFFFF
239 /* Common defines for override handling*/
240 #define RF_OVERRIDE_SEARCH_DEPTH 80
241 /* Define for HPOSC temperature limits */
242 #define RF_TEMP_LIMIT_3_DEGREES_CELSIUS 0x3
243
244 /*-------------- Structures and definitions ---------------*/
245
246 /* FSM typedef. */
247 typedef void (*RF_FsmStateFxn)(RF_Object*, RF_FsmEvent const);
248
249 /* Rat channel configuration. */
250 typedef struct RF_RatChannel_s RF_RatChannel;
251
252 /* Rat channel configuration. */
253 struct RF_RatChannel_s {
254 RF_Handle pClient; /* Pointer to client owning the channel. NULL means the channel is free. */
255 RF_RatCallback pCb; /* Callback pointer of the channel. */
256 RF_RatMode mode; /* Mode of this RAT channel: RF_RatModeCompare, etc. */
257 RF_RatHandle handle; /* Channel number: 0,1,2. */
258 RF_RatStatus status; /* Status of the channel: RF_RatStatusIdle, RF_RatStatusPending, RF_RatStatusRunning */
259 uint64_t chCmd; /* Generic storage for the command structure itself. */
260 uint32_t ioCmd; /* Raw binary to be sent to the CM0 to set up the GPOs. This is optional. */
261 };
262
263 /* Rat module configuration. */
264 typedef struct RF_RatModule_s RF_RatModule;
265
266 /* Rat module configuration. */
267 struct RF_RatModule_s {
268 RF_RatChannel channel[RF_RAT_CH_CNT]; /* Container of channel configurations. */
269 uint8_t availableRatChannels; /* Storage of available RAT channels read from the RF core. */
270 uint8_t volatile pendingInt; /* Pending interrupt flags to be served. */
271 uint8_t numActiveChannels; /* Counter of active channels. This is used to compensate the
272 overhead of programming the channels.*/
273 };
274
275 /* RF core configuration. */
276 typedef struct RF_CoreState_s RF_CoreState;
277
278 /* RF core configuration. */
279 struct RF_CoreState_s
280 {
281 RF_CoreStatus volatile status;
282 RF_FsmStateFxn fxn;
283 uint32_t activeTimeUs;
284 bool init;
285 bool manualXoscHfSelect;
286 };
287
288 /* RAT synchronization. */
289 typedef union RF_RatSyncCmd_u RF_RatSyncCmd;
290
291 /* RAT synchronization. */
292 union RF_RatSyncCmd_u
293 {
294 rfc_CMD_SYNC_START_RAT_t start;
295 rfc_CMD_SYNC_STOP_RAT_t stop;
296 };
297
298 /* Reconfigure the PA settings. */
299 typedef union RF_ConfigurePaCmd_u RF_ConfigurePaCmd;
300
301 /* Reconfigure the PA settings. */
302 union RF_ConfigurePaCmd_u {
303 rfc_CMD_SET_TX_POWER_t tuneTxPower;
304 rfc_CMD_SET_TX20_POWER_t tuneTx20Power;
305 rfc_CMD_CHANGE_PA_t changePa;
306 };
307
308 /* Command queue. */
309 typedef struct RF_CmdQ_s RF_CmdQ;
310
311 /* Command queue. */
312 struct RF_CmdQ_s{
313 List_List pPend; /* List of pending commands to be dispatched. */
314 List_List pDone; /* List of executed commands to be served. */
315 RF_Cmd* volatile pCurrCmdBg; /* Currently running command. */
316 RF_Cmd* volatile pCurrCmdFg; /* Currently running foreground command. */
317 RF_Cmd* volatile pCurrCmdCb; /* Command which callback to be invoked. */
318 RF_CmdHandle volatile nSeqPost; /* Sequence # for previously posted command. */
319 RF_CmdHandle volatile nSeqDone; /* Sequence # for last done command. */
320 };
321
322 /* RF scheduler. */
323 typedef struct RF_Sch_s RF_Sch_t;
324
325 /* RF scheduler. */
326 struct RF_Sch_s {
327 RF_Handle clientHnd[N_MAX_CLIENTS]; /* Client handle for each registered client. */
328 RF_AccessParams accReq[N_MAX_CLIENTS]; /* Input parameters from any RF_requestAccess API calls. */
329 RF_Handle clientHndRadioFreeCb; /* Client handle for the radio callback. */
330 uint8_t issueRadioFreeCbFlags; /* Indicate if driver needs to issue RF_EventRadioFree callback {0:pre-emption, 1:requestAccess running, 2: reject command}. */
331 uint8_t cmdInsertFlags; /* Indicate if the command was inserted based on timing information. */
332 };
333
334 /*-------------- RTOS objects ---------------*/
335
336 /* RF core software interrupts */
337 static SwiP_Struct RF_swiFsmObj;
338 static void RF_swiFsm(uintptr_t a, uintptr_t b);
339
340 /* RF core hardware interrupts */
341 static HwiP_Struct RF_hwiCpe0Obj;
342 static void RF_hwiCpe0Active(uintptr_t a);
343 static void RF_hwiCpe0PowerFsm(uintptr_t a);
344
345 /* RF core HW software interrupts */
346 static SwiP_Struct RF_swiHwObj;
347 static void RF_swiHw(uintptr_t a, uintptr_t b);
348
349 /* RF core HW hardware interrupts */
350 static HwiP_Struct RF_hwiHwObj;
351 static void RF_hwiHw(uintptr_t a);
352
353 /* Clock used for triggering power-up sequences */
354 static ClockP_Struct RF_clkPowerUpObj;
355 static void RF_clkPowerUp(uintptr_t a);
356
357 /* Common inactivity timeout clock callback */
358 static ClockP_Struct RF_clkInactivityObj;
359 static void RF_clkInactivityCallback(uintptr_t a);
360
361 /* Common request access timeout clock callback */
362 static void RF_clkReqAccess(uintptr_t a);
363
364
365 /*-------------- Static structures ---------------*/
366
367 /* Default RF parameters structure */
368 static const RF_Params RF_defaultParams = {
369 .nInactivityTimeout = SemaphoreP_WAIT_FOREVER,
370 .nPowerUpDuration = 0,
371 .pPowerCb = NULL,
372 .pErrCb = NULL,
373 .nPowerUpDurationMargin = RF_DEFAULT_POWER_UP_MARGIN,
374 .nPhySwitchingDurationMargin = RF_DEFAULT_PHY_SWITCHING_MARGIN,
375 .pClientEventCb = NULL,
376 .nClientEventMask = 0,
377 .nID = 0,
378 };
379
380 /*-------------- Global variables ---------------*/
381
382 /* RF_Cmd container pool. Containers with extra information about RF commands. */
383 static RF_Cmd RF_cmdPool[N_CMD_POOL];
384
385 /* Command queue top level structure. It contains pointers to the different queues. */
386 static RF_CmdQ RF_cmdQ;
387
388 /* Static object used to subscribe from early notification in the power driver */
389 static Power_NotifyObj RF_wakeupNotifyObj;
390
391 /* Power constraints set by the RF driver */
392 static volatile uint8_t RF_powerConstraint;
393
394 /* Pointer to current radio client (indicates also whether the radio is powered) */
395 static RF_Object* RF_currClient;
396
397 /* Current state of the RF core. */
398 static RF_CoreState RF_core;
399
400 /* Static container of a direct/immediate commands */
401 static RF_RatModule RF_ratModule;
402
403 /* Commands used to synchronize the RTC and the RAT timer. */
404 static volatile RF_RatSyncCmd RF_ratSyncCmd;
405
406 /* Top level structure of the shceduler unit. */
407 static RF_Sch_t RF_Sch;
408
409 /* Variables used for powerUpDuration, phySwitchingTime and RAT sync time calculation. */
410 static uint32_t RF_rtcTimestampA; /* RTC timer value power-up and active time calculation. */
411 static uint32_t RF_rtcBeginSequence; /* RTC timer value for switching time calculation. */
412 static uint32_t RF_errTolValInUs; /* max allowed error between RAT/RTC drift to enable resync at power-down (in us). */
413
414 /* Counter of radio clients */
415 static uint8_t RF_numClients;
416
417 /* Current HPOSC frequency offset */
418 static int32_t RF_currentHposcFreqOffset;
419
420 /* Temperature notify object used by HPOSC device */
421 static Temperature_NotifyObj RF_hposcRfCompNotifyObj;
422
423 /* Common system-level temperature based synth compensation */
424 static void (*pfnUpdateHposcOverride)(uint32_t *pRegOverride) = NULL;
425 static int_fast16_t (*pfnTemperatureUnregisterNotify)(Temperature_NotifyObj *notifyObject) = NULL;
426
427 /*-------------- Externs ---------------*/
428
429 /* Hardware attribute structure populated in board file. */
430 extern const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs;
431
432 /* Software policy set in the board file and implements the distributed scheduling algorithm. */
433 __attribute__((weak)) RFCC26XX_SchedulerPolicy RFCC26XX_schedulerPolicy = {
434 .submitHook = RF_defaultSubmitPolicy,
435 .executeHook = RF_defaultExecutionPolicy
436 };
437
438 /*-------------- Booleans ---------------*/
439
440 /* variable to indicate with the FLASH is disable during the power up */
441 static bool bDisableFlashInIdleConstraint;
442
443 /*-------------- State machine functions ---------------*/
444
445 /* FSM state functions */
446 static void RF_fsmPowerUpState(RF_Object *pObj, RF_FsmEvent e);
447 static void RF_fsmSetupState(RF_Object *pObj, RF_FsmEvent e);
448 static void RF_fsmActiveState(RF_Object *pObj, RF_FsmEvent e);
449 static void RF_fsmXOSCState(RF_Object *pObj, RF_FsmEvent e);
450
451 /*-------------- Helper functions ---------------*/
452
453 /* Command queue handling */
454 static RF_Cmd* RF_queueEnd(RF_Handle h, List_List* pHead);
455
456 /* Command handling*/
457 static bool RF_isClientOwner(RF_Handle h, RF_Cmd* pCmd);
458 static RF_Cmd* RF_cmdAlloc(void);
459 static RF_Cmd* RF_cmdGet(RF_Handle h, RF_CmdHandle ch, uint8_t mask);
460 static void RF_cmdStoreEvents(RF_Cmd* pCmd, RF_EventMask events);
461 static bool RF_cmdDispatchTime(uint32_t* dispatchTimeClockTicks, bool conflict, RF_Cmd** pAbsCmd);
462 static RF_Stat RF_abortCmd(RF_Handle h, RF_CmdHandle ch, bool graceful, bool flush, bool preempt);
463 static bool RF_checkCmdFsError(void);
464 static void RF_cacheFsCmd(RF_Cmd* pCmd);
465 static uint32_t RF_discardPendCmd(RF_Handle h, RF_Cmd* pCmd, bool bFlushAll, bool bPreempt);
466
467 /* Scheduler */
468 static void RF_issueRadioFreeCb(uint8_t src);
469 static bool RF_verifyGap(RF_Cmd* newCmd, RF_Cmd* prevCmd, RF_Cmd* nextCmd);
470 static RF_ScheduleStatus RF_howToSchedule(RF_Cmd* newCmd, RF_Cmd* pCmdBg, RF_Cmd* pCmdFg, List_List* pPendQueue, List_List* pDoneQueue, RF_Cmd** pInsertLocation);
471
472 /* RAT module */
473 static RF_RatChannel* RF_ratGetChannel(uint8_t ch);
474 static RF_RatChannel* RF_ratAllocChannel(RF_RatHandle ratChannel);
475 static uint32_t RF_ratGetChannelValue(RF_RatHandle ratHandle);
476 static uint32_t RF_ratGetValue(void);
477 static void RF_ratGenerateChCmd(RF_RatChannel* ratCh, void* ratConfig);
478 static void RF_ratGenerateIoCmd(RF_RatChannel* ratCh, RF_RatConfigOutput* ioConfig);
479 static RF_RatHandle RF_ratSetupChannel(RF_Handle ratClient, RF_RatMode ratMode, RF_RatCallback ratCallback, RF_RatHandle ratChannel, void* ratConfig, RF_RatConfigOutput* ioConfig);
480 static void RF_ratRestartChannels(void);
481 static RF_Stat RF_ratArmChannel(RF_RatChannel* ratCh);
482 static void RF_ratFreeChannel(RF_RatChannel* ratCh);
483 static void RF_ratSuspendChannels(void);
484 static bool RF_ratReleaseChannels(void);
485 static bool RF_ratDispatchTime(uint32_t* dispatchTimeClockTicks);
486 static bool RF_ratIsRunning(void);
487
488 /* Time management */
489 static uint32_t RF_calculateDeltaTimeUs(uint32_t absTime, uint32_t nTotalPowerUpDuration);
490 static bool RF_calculateDispatchTime(uint32_t* dispatchTimeClockTicks);
491 static void RF_dispatchNextEvent(void);
492 static void RF_dispatchNextCmd(void);
493 static void RF_restartClockTimeout(ClockP_Handle clock, uint32_t timeout);
494
495 /* Power management */
496 static void RF_corePowerDown(void);
497 void RF_powerConstraintRelease(RF_PowerConstraintSrc src);
498 void RF_powerConstraintSet(RF_PowerConstraintSrc src);
499 RF_PowerConstraintSrc RF_powerConstraintGet(RF_PowerConstraintSrc src);
500 static void RF_setInactivityTimeout(void);
501
502 /* Others */
503 static void RF_init(void);
504 static void RF_defaultCallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e);
505 static RF_Stat RF_runDirectImmediateCmd(RF_Handle h, uint32_t pCmd, uint32_t* rawStatus);
506 static RF_Stat RF_executeDirectImmediateCmd(uint32_t pCmd, uint32_t* rawStatus);
507 static void RF_invokeGlobalCallback(RF_GlobalEvent event, void* arg);
508 static void RF_dbellSubmitCmdAsync(uint32_t rawCmd);
509 static void RF_dbellSyncOnAck(void);
510 static bool RF_isRadioSetup(RF_Op* pOp);
511 static void RF_initRadioSetup(RF_Handle handle);
512 static void RF_radioOpDoneCb(void);
513 static RF_Op* RF_findEndOfChain(RF_Op* pOp);
514 static void RF_applyRfCorePatch(bool mode);
515 static bool RF_isStateTransitionAllowed(void);
516
517 /* PA management */
518 static RF_Stat RF_updatePaConfiguration(RF_RadioSetup* radioSetup, RF_TxPowerTable_Value newValue, RF_ConfigurePaCmd* configurePaCmd);
519 static void RF_extractPaConfiguration(RF_Handle handle);
520 static bool RF_decodeOverridePointers(RF_RadioSetup* radioSetup, uint16_t** pTxPower, uint32_t** pRegOverride, uint32_t** pRegOverrideTxStd, uint32_t** pRegOverrideTx20);
521 static void RF_attachOverrides(uint32_t* baseOverride, uint32_t* newOverride);
522 static void RF_detachOverrides(uint32_t* baseOverride, uint32_t* newOverride);
523
524 /* HPOSC management */
525 static void RF_updateHpOscOverride(uint32_t *pRegOverride);
526 static void RF_hposcRfCompensateFxn(int16_t currentTemperature,
527 int16_t thresholdTemperature,
528 uintptr_t clientArg,
529 Temperature_NotifyObj *notifyObject);
530
531 /*-------------- Command queue internal functions ---------------*/
532
533 /*
534 * Compares the client of a command.
535 *
536 * Input: h - Client to check against.
537 * pCmd - Command to check.
538 * Return: true - If the client owns the command.
539 * false - Otherwise.
540 */
RF_isClientOwner(RF_Handle h,RF_Cmd * pCmd)541 static bool RF_isClientOwner(RF_Handle h, RF_Cmd* pCmd)
542 {
543 if (pCmd && (pCmd->pClient == h))
544 {
545 return(true);
546 }
547 else
548 {
549 return(false);
550 }
551 }
552
553 /*
554 * Search last entry in simple queue for particular client.
555 *
556 * Input: h - Client handle.
557 * list - List to search within.
558 * Return: RF_Cmd if found any
559 */
RF_queueEnd(RF_Handle h,List_List * list)560 static RF_Cmd* RF_queueEnd(RF_Handle h, List_List* list)
561 {
562 /* Enter critical section */
563 uint32_t key = HwiP_disable();
564
565 /* Local variables */
566 List_Elem* pTail = NULL;
567 List_Elem* pHead = List_head(list);
568
569 /* Start at the head of queue */
570 while (pHead)
571 {
572 if (RF_isClientOwner(h, (RF_Cmd*)pHead))
573 {
574 pTail = pHead;
575 }
576
577 pHead = List_next(pHead);
578 }
579
580 /* Exit critical section */
581 HwiP_restore(key);
582
583 /* Return with the last entry belongs to the client */
584 return((RF_Cmd*)pTail);
585 }
586
587 /*
588 * Allocate a command buffer from the command pool.
589 *
590 * Input: none
591 * Return: RF command
592 */
RF_cmdAlloc(void)593 static RF_Cmd* RF_cmdAlloc(void)
594 {
595 uint32_t i;
596 for (i = 0; i < N_CMD_POOL; i++)
597 {
598 /* Find the first available entry in the command pool */
599 if (!(RF_cmdPool[i].flags & RF_CMD_ALLOC_FLAG))
600 {
601 return(&RF_cmdPool[i]);
602 }
603 }
604 return(NULL);
605 }
606
607 /*
608 * Search command in the command pool.
609 *
610 * Input: h - Handle to the client which the command should belong to.
611 * ch - Handle to the command to search for.
612 * mask - Optional mask of flags to compare to.
613 * Return: RF command
614 */
RF_cmdGet(RF_Handle h,RF_CmdHandle ch,uint8_t mask)615 static RF_Cmd* RF_cmdGet(RF_Handle h, RF_CmdHandle ch, uint8_t mask)
616 {
617 uint32_t i;
618 for (i = 0; i < N_CMD_POOL; i++)
619 {
620 /* Find the allocated command pool entry corresponding to ch */
621 if (RF_cmdPool[i].ch == ch)
622 {
623 if (RF_isClientOwner(h, &RF_cmdPool[i]))
624 {
625 /* If a mask is provided, check the flags too */
626 if (!mask || (RF_cmdPool[i].flags & mask))
627 {
628 return(&RF_cmdPool[i]);
629 }
630 }
631 }
632 }
633 return(NULL);
634 }
635
636 /*
637 * Atomic storage of radio events happened during the execution of a command.
638 *
639 * Input: pCmd - Command the events belogn to.
640 * events - The radio events to be store within the context of the command.
641 * Return: none
642 */
RF_cmdStoreEvents(RF_Cmd * pCmd,RF_EventMask events)643 static void RF_cmdStoreEvents(RF_Cmd* pCmd, RF_EventMask events)
644 {
645 /* Enter critical section. */
646 uint32_t key = HwiP_disable();
647
648 /* Store the events within the context of the command. */
649 if (pCmd)
650 {
651 /* The field rfifg store the events for the next callback.
652 The field pastifg accumulates the events in case an
653 RF_pendCmd() API call happens. */
654 pCmd->rfifg |= events;
655 pCmd->pastifg |= events;
656 }
657
658 /* Exit critical section. */
659 HwiP_restore(key);
660 }
661
662 /*
663 * Reconfigure and restart a particular clock object.
664 *
665 * Input: clockObj - A pointer to a clock object.
666 * timeoutClockTicks - The timeout to be set in unit of clock ticks.
667 * Return: none
668 */
RF_restartClockTimeout(ClockP_Handle clockHandle,uint32_t timeoutClockTicks)669 static void RF_restartClockTimeout(ClockP_Handle clockHandle, uint32_t timeoutClockTicks)
670 {
671 /* Ceil the value at minimum 1 clock tick. */
672 timeoutClockTicks = MAX(timeoutClockTicks, 1);
673
674 /* Reprogram the clock object. */
675 ClockP_setTimeout(clockHandle, timeoutClockTicks);
676 ClockP_start(clockHandle);
677 }
678
679 /*
680 * Calculate the delta time to an RF event including the overhead of powering up
681 * and down.
682 *
683 * Input: abstime - The timestamp the event will need to happen.
684 * nTotalPowerUpDuration - The duration we need to compensate with.
685 * Return: deltaTime - The time left until the RF core need to be trigged.
686 */
RF_calculateDeltaTimeUs(uint32_t absTime,uint32_t nTotalPowerUpDuration)687 static uint32_t RF_calculateDeltaTimeUs(uint32_t absTime, uint32_t nTotalPowerUpDuration)
688 {
689 /* Local variables. */
690 uint32_t deltaTimeUs;
691
692 /* Read the timestamp to calculate difference from. */
693 uint32_t currentTime = RF_getCurrentTime();
694
695 /* Calculate the difference with the current timestamp. */
696 deltaTimeUs = UDIFF(currentTime, absTime);
697 deltaTimeUs /= RF_NUM_RAT_TICKS_IN_1_US;
698
699 /* Check if delta time is greater than (powerup duration + power down duration) for a
700 power cycle, and is less than 3/4 of a RAT cycle (~17 minutes) */
701 if ((deltaTimeUs > (int32_t)(nTotalPowerUpDuration + RF_DEFAULT_POWER_DOWN_TIME)) &&
702 (deltaTimeUs <= RF_DISPATCH_MAX_TIME_US))
703 {
704 /* Dispatch command in the future */
705 return(MAX((deltaTimeUs - nTotalPowerUpDuration), 1));
706 }
707 else
708 {
709 /* Dispatch immediately */
710 return(0);
711 }
712 }
713
714 /*
715 * Calculate the wakeup time of next command in the queue.
716 *
717 * Input: dispatchTimeClockTicks - Location where the calculated time is being stored.
718 * conflict - true: compare to the first command which have TRIG_ABSTIME trigger type.
719 * false: compare to the first command in the queue
720 * pAbsCmd - Pointer to the first command which has an absolute start time.
721 * Return: validTime - Indicates if the returned time is valid.
722 */
RF_cmdDispatchTime(uint32_t * dispatchTimeClockTicks,bool conflict,RF_Cmd ** pAbsCmd)723 static bool RF_cmdDispatchTime(uint32_t* dispatchTimeClockTicks, bool conflict, RF_Cmd** pAbsCmd)
724 {
725 /* By default, there is no command in the queue. */
726 RF_Cmd* pCmd = NULL;
727 bool validTime = false;
728
729 /* The input argument determines which command to use as a reference. This is to be able to
730 reuse the calculation for both power management and conflict resolution. */
731 if (conflict == true)
732 {
733 /* Start from the beginning of queue. */
734 RF_Cmd* pTempCmd = (RF_Cmd*)List_head(&RF_cmdQ.pPend);
735
736 /* Walk the queue and find the first command contains an absolute start time. */
737 while (pTempCmd)
738 {
739 /* Finish the search upon the first match. This assumes that commands with
740 absolute start times are in order. */
741 if (pTempCmd->pOp->startTrigger.triggerType == TRIG_ABSTIME)
742 {
743 pCmd = pTempCmd;
744 break;
745 }
746 else
747 {
748 /* Continue the search if no match. */
749 pTempCmd = (RF_Cmd*)List_next((List_Elem*)pTempCmd);
750 }
751 }
752 }
753 else
754 {
755 /* The next command in the queue independently of its type determines the timing. */
756 pCmd = (RF_Cmd*)List_head(&RF_cmdQ.pPend);
757 }
758
759 /* Only recognizes TRIG_ABSTIME triggers, everything else gets dispatched immediately. */
760 if (pCmd)
761 {
762 /* If there is at least one pending command, we can calculate a legit dispatch time. */
763 validTime = true;
764
765 /* Return with the command which we calculate the remained time against. */
766 if (pAbsCmd)
767 {
768 *pAbsCmd = pCmd;
769 }
770
771 /* If the start trigger is absolute, we can calculate the time difference. */
772 if (pCmd->pOp->startTrigger.triggerType == TRIG_ABSTIME)
773 {
774 uint32_t nTotalDuration = 0;
775
776 /* Calculate the sum of overhead it takes to start up and configure the RF core. */
777 if (conflict == true)
778 {
779 nTotalDuration = pCmd->pClient->clientConfig.nPhySwitchingDuration
780 + pCmd->pClient->clientConfig.nPhySwitchingDurationMargin;
781 }
782 else
783 {
784 nTotalDuration = pCmd->pClient->clientConfig.nPowerUpDuration
785 + pCmd->pClient->clientConfig.nPowerUpDurationMargin
786 + (RF_RAT_COMPENSATION_TIME_US * RF_ratModule.numActiveChannels);
787 }
788
789 /* Calculate the remained time until this absolute event. The calculation takes
790 into account the minimum power cycle time. */
791 *dispatchTimeClockTicks = RF_calculateDeltaTimeUs(pCmd->startTime, nTotalDuration);
792
793 /* Scale the value to clock ticks*/
794 *dispatchTimeClockTicks /= ClockP_getSystemTickPeriod();
795 }
796 else
797 {
798 /* Dispatch immediately. */
799 *dispatchTimeClockTicks = 0;
800 }
801 }
802 else
803 {
804 /* This value will not be used. */
805 *dispatchTimeClockTicks = 0;
806 }
807
808 /* If the returned timestamp represents a valid dispatch time, return with true. */
809 return(validTime);
810 }
811
812 /*
813 * Determines if the RAT timer is running (clock is not gated) or not.
814 * This is used to determine if any RAT related command can be execured.
815 *
816 * Input: none
817 * Return: PWMCLK_EN_RAT - RAT timer is running.
818 * 0 - RAT timer is not running.
819 */
RF_ratIsRunning(void)820 static bool RF_ratIsRunning(void)
821 {
822 /* Assume by default that the RAT is not available. */
823 bool status = false;
824
825 /* If the RF core power domain is ON, read the clock of the RAT. */
826 if (HWREG(PRCM_BASE + PRCM_O_PDSTAT0) & PRCM_PDSTAT0_RFC_ON)
827 {
828 status = (bool)(HWREG(RFC_PWR_BASE + RFC_PWR_O_PWMCLKEN) & RFC_PWR_PWMCLKEN_RAT_M);
829 }
830
831 /* Return with the status of RAT. */
832 return(status);
833 }
834
835 /*
836 * Allocate a RAT channel from the three slots available
837 * for the user.
838 *
839 * Input: ratChannel - Pointer to a user provided RF_RatHandle.
840 * Return: RF_RatChannel* - Pointer to the allocated channel if success.
841 * NULL - If failure.
842 */
RF_ratAllocChannel(RF_RatHandle ratChannel)843 static RF_RatChannel* RF_ratAllocChannel(RF_RatHandle ratChannel)
844 {
845 /* Walk the RAT channel indexes. */
846 uint32_t i;
847 for (i = 0; i < RF_RAT_CH_CNT; i++)
848 {
849 /* Calculate the bit representing this channel within the available channels. */
850 uint32_t bitMask = (1 << i);
851
852 /* Verify that no one is using this channel (from outside the scope of RF driver). */
853 if (RF_ratModule.availableRatChannels & bitMask)
854 {
855 /* Mask the possible channels if a user handle is provided, otherwise find the
856 the first available channel. */
857 if ((ratChannel == RF_RatChannelAny) || (ratChannel == i))
858 {
859 /* Decode the fields of a channel. */
860 RF_RatChannel* ratCh = RF_ratGetChannel(i);
861
862 /* If an available channel is found. */
863 if (ratCh && (ratCh->status == RF_RatStatusIdle))
864 {
865 /* Mark the channel as occupied. */
866 RF_ratModule.availableRatChannels &= ~bitMask;
867
868 /* Put the channel into pending state. */
869 ratCh->status = RF_RatStatusPending;
870 ratCh->handle = i;
871
872 /* Increment the counter of active channels. This is used to compensate the
873 power up time with the overhead of programming these channels. */
874 RF_ratModule.numActiveChannels += 1;
875
876 /* Return with a pointer to the channel. */
877 return(ratCh);
878 }
879 }
880 }
881 }
882
883 /* Return with an invalid channel pointer in case of error. */
884 return(NULL);
885 }
886
887 /*
888 * Free a given RAT channel.
889 *
890 * Input: ratCh - Pointer to a RAT channel in RF_ratModule.
891 * Return: none
892 */
RF_ratFreeChannel(RF_RatChannel * ratCh)893 static void RF_ratFreeChannel(RF_RatChannel* ratCh)
894 {
895 /* Enter critical section */
896 uint32_t key = HwiP_disable();
897
898 /* If a valid pointer is provided */
899 if (ratCh && ratCh->status)
900 {
901 /* Precalculate the contraint ID of this channel. */
902 RF_PowerConstraintSrc powerConstraint = (RF_PowerConstraintSrc)(1 << ratCh->handle);
903
904 /* If the RF core power domain is ON. */
905 if (RF_ratIsRunning())
906 {
907 /* Calculate the channel index based on the handle. */
908 uint32_t ratChIntFlag = (1 << (RFC_DBELL_RFHWIFG_RATCH5_BITN + ratCh->handle));
909
910 /* Disable the RAT channel interrupt source. */
911 RFCHwIntDisable(ratChIntFlag);
912 RFCHwIntClear(ratChIntFlag);
913 }
914
915 /* Reset the status of the channel. */
916 ratCh->status = RF_RatStatusIdle;
917 ratCh->mode = RF_RatModeUndefined;
918 ratCh->pClient = NULL;
919 ratCh->pCb = NULL;
920 ratCh->chCmd = 0;
921 ratCh->ioCmd = 0;
922
923 /* Mark the channel as available. */
924 RF_ratModule.availableRatChannels |= (1 << ratCh->handle);
925
926 /* Decrement the counter of active channels. To avoid underflow, check its value first. */
927 if (RF_ratModule.numActiveChannels)
928 {
929 RF_ratModule.numActiveChannels -= 1;
930 }
931
932 /* Notify the state machine that the RF core can be possibly powered down. */
933 RF_powerConstraintRelease(powerConstraint);
934 }
935
936 /* Exit critical section */
937 HwiP_restore(key);
938 }
939
940 /*
941 * Returns with a pointer to a RAT channel based on it's handle.
942 *
943 * Input: ch - Channel handle.
944 * Return: ratCh - Pointer to a RAT channel in RF_ratModule.
945 */
RF_ratGetChannel(uint8_t ch)946 static RF_RatChannel* RF_ratGetChannel(uint8_t ch)
947 {
948 /* Convert a valid index into a pointer of a RAT channel configuration. */
949 if (ch < RF_RAT_CH_CNT)
950 {
951 return((RF_RatChannel*)&RF_ratModule.channel[ch]);
952 }
953
954 /* Return with NULL in case of invalid input argument. */
955 return(NULL);
956 }
957
958 /*
959 * Suspend the running channels and potentially initiate a power down.
960 *
961 * Input: none
962 * Return: true - All RAT channel is suspended.
963 * false - Otherwise.
964 */
RF_ratReleaseChannels(void)965 static bool RF_ratReleaseChannels(void)
966 {
967 /* Only try to release the RAT channels if there is no other dependencies set. */
968 if (!RF_powerConstraintGet(RF_PowerConstraintCmdQ) &&
969 !RF_powerConstraintGet(RF_PowerConstraintDisallow))
970 {
971 /* Calculate if there is enough time to power down and up. */
972 uint32_t dispatchTimeClockTicks;
973 bool validTime = RF_calculateDispatchTime(&dispatchTimeClockTicks);
974
975 /* If the next event is sufficiently far into the future. */
976 if (!validTime || (validTime && dispatchTimeClockTicks))
977 {
978 /* Avoid powering down the radio if there are callbacks to be served. The
979 SWI will try to access the RAT timer, which need to be powered. */
980 if (RF_ratModule.pendingInt == 0U)
981 {
982 /* Suspend all RAT channels. */
983 RF_ratSuspendChannels();
984
985 /* RAT channels were suspended. */
986 return(true);
987 }
988 }
989 }
990
991 /* RAT channels were not suspended. */
992 return(false);
993 }
994
995 /*
996 * Calculate the timeout of closest RAT event.
997 *
998 * Input: dispatchTimeClockTicks - Location where the calculated time is being stored.
999 * Return: validTime - Indicates if the returned time is valid.
1000 */
RF_ratDispatchTime(uint32_t * dispatchTimeClockTicks)1001 static bool RF_ratDispatchTime(uint32_t* dispatchTimeClockTicks)
1002 {
1003 /* By default, there is no RAT running. */
1004 bool validTime = false;
1005
1006 /* Initialize the return value. */
1007 *dispatchTimeClockTicks = RF_DISPATCH_INFINIT_TIME;
1008
1009 /* Iterate through the RAT containers and calculate the remained time until
1010 the closest RAT event. */
1011 uint32_t i;
1012 for(i = 0; i < RF_RAT_CH_CNT; i++)
1013 {
1014 /* Use a local pointer to have easier access to member fields. */
1015 RF_RatChannel* ratCh = RF_ratGetChannel(i);
1016
1017 /* If the channel is either in PENDING or RUNNING state, meaning it is in use. */
1018 if (ratCh && ratCh->status)
1019 {
1020 /* There is at least one active channel, we can calculate a legit timestamp. */
1021 validTime = true;
1022
1023 /* If there is at least one channel in Capture mode, we need to power
1024 up immediately. */
1025 if (ratCh->mode == RF_RatModeCapture)
1026 {
1027 /* Use immediate timeout orcing the RF core to be powered up. */
1028 *dispatchTimeClockTicks = 0;
1029
1030 /* No point to look to the other RAT channels.*/
1031 break;
1032 }
1033 else
1034 {
1035 /* Decode the compareTime field. */
1036 rfc_CMD_SET_RAT_CMP_t* cmd = (rfc_CMD_SET_RAT_CMP_t *)&ratCh->chCmd;
1037 uint32_t compareTime = cmd->compareTime;
1038
1039 /* Calculate the remained time until this RAT event. The calculation takes
1040 into account the minimum power cycle time. */
1041 uint32_t deltaTimeUs = RF_calculateDeltaTimeUs(compareTime,
1042 RF_currClient->clientConfig.nPowerUpDuration +
1043 RF_currClient->clientConfig.nPowerUpDurationMargin +
1044 (RF_RAT_COMPENSATION_TIME_US * RF_ratModule.numActiveChannels));
1045
1046 /* Scale the value to clock ticks. */
1047 uint32_t deltaTimeClockTicks = deltaTimeUs / ClockP_getSystemTickPeriod();
1048
1049 /* If this is the closest RAT event, update the timer. */
1050 if (deltaTimeClockTicks < (*dispatchTimeClockTicks))
1051 {
1052 *dispatchTimeClockTicks = deltaTimeClockTicks;
1053 }
1054 }
1055 }
1056 }
1057
1058 /* Return with true if the dispatchTime represents a valid timestamp. */
1059 return(validTime);
1060 }
1061
1062 /*
1063 * Arms a given RAT channel. The mode of the channel will define which mode
1064 * it is being configured to. The cmd variable contains the raw word to be
1065 * sent to the RF core.
1066 *
1067 * Input: ratCh - Pointer to a RAT channel.
1068 * Return: status - Status code based on the response of RF core.
1069 *
1070 */
RF_ratArmChannel(RF_RatChannel * ratCh)1071 static RF_Stat RF_ratArmChannel(RF_RatChannel* ratCh)
1072 {
1073 /* Local variable */
1074 RF_Stat status = RF_StatError;
1075
1076 /* Only those channels can be programmed which are in pending state. */
1077 if (ratCh && (ratCh->status == RF_RatStatusPending))
1078 {
1079 /* Calculate the channel interrupt flag on the handle. */
1080 uint32_t ratChIntFlag = (1 << (RFC_DBELL_RFHWIFG_RATCH5_BITN + ratCh->handle));
1081
1082 /* Clear and enable the interrupt source for that particular channel. */
1083 RFCHwIntClear(ratChIntFlag);
1084 RFCHwIntEnable(ratChIntFlag);
1085
1086 /* Set the power constraint on this channel to keep the RF core ON. */
1087 RF_powerConstraintSet((RF_PowerConstraintSrc)(1 << ratCh->handle));
1088
1089 /* Send the command to the RF core. */
1090 status = RF_executeDirectImmediateCmd((uint32_t)&ratCh->chCmd, NULL);
1091
1092 /* If the channel configuration is succesfull. */
1093 if (status == RF_StatCmdDoneSuccess)
1094 {
1095 /* Send the IO command to the RF core if there is any configured. */
1096 if (ratCh->ioCmd)
1097 {
1098 status = RF_executeDirectImmediateCmd((uint32_t)ratCh->ioCmd, NULL);
1099 }
1100
1101 /* If both the channel and io configuration is succesfull. */
1102 if (status == RF_StatCmdDoneSuccess)
1103 {
1104 ratCh->status = RF_RatStatusRunning;
1105 }
1106 }
1107 }
1108
1109 /* Return with the status code. */
1110 return(status);
1111 }
1112
1113 /*
1114 * Restarts any RAT channels which are in pending state at the moment of
1115 * invoking this method. This is used to automatically restore the rat module
1116 * right after the RF core is powered up. This is essential for power management.
1117 *
1118 * Input: none
1119 * Return: none
1120 *
1121 */
RF_ratRestartChannels(void)1122 static void RF_ratRestartChannels(void)
1123 {
1124 /* Iterate through the RAT containers and restore the channels
1125 which were in running state before we entered Standby mode. */
1126 uint32_t i;
1127 for(i = 0; i < RF_RAT_CH_CNT; i++)
1128 {
1129 /* Convert the index to a pointer. */
1130 RF_RatChannel* ratCh = RF_ratGetChannel(i);
1131
1132 /* If the channel is in pending state, program it. */
1133 if (ratCh && (ratCh->status == RF_RatStatusPending))
1134 {
1135 /* Try to program the RAT channel. */
1136 RF_Stat status = RF_ratArmChannel(ratCh);
1137
1138 /* Execute error handling if programming fails, i.e. due to past timestamp.
1139 This is done in SWI context. */
1140 if (status != RF_StatCmdDoneSuccess)
1141 {
1142 /* Mark the event as an error by setting also a shadow bit. */
1143 RF_ratModule.pendingInt |= ((RF_RAT_INTERRUPT_BASE_INDEX | RF_RAT_ERROR_BASE_INDEX) << ratCh->handle);
1144
1145 /* Post the SWI handler to serve the callback. */
1146 SwiP_or(&RF_swiHwObj, 0);
1147 }
1148 }
1149 }
1150 }
1151
1152 /*
1153 * Suspends any RAT channel which are in RUNNING state.
1154 * This is used to force all RAT channels into pending state allowing the power
1155 * management to power off the RF core power domain and resynchronize the RAT channels
1156 * on next power up.
1157 *
1158 * Input: none
1159 * Return: none
1160 */
RF_ratSuspendChannels(void)1161 static void RF_ratSuspendChannels(void)
1162 {
1163 /* Iterate through the RAT containers and suspend the active channels. */
1164 uint32_t i;
1165 for(i = 0; i < RF_RAT_CH_CNT; i++)
1166 {
1167 /* Set a pointer to the channel. */
1168 RF_RatChannel* ratCh = RF_ratGetChannel(i);
1169
1170 /* Only actively running channles can be suspended. */
1171 if (ratCh && ratCh->status)
1172 {
1173 /* Set the status to be suspended. */
1174 ratCh->status = RF_RatStatusPending;
1175
1176 /* Clear the power constraint of this channel */
1177 RF_powerConstraintRelease((RF_PowerConstraintSrc)(1 << ratCh->handle));
1178 }
1179 }
1180 }
1181
1182 /*
1183 * Read the counter value from the RAT timer.
1184 *
1185 * Input: none
1186 * Return: time - The value found in the RATCNT running register.
1187 */
RF_ratGetValue(void)1188 static uint32_t RF_ratGetValue(void)
1189 {
1190 return(HWREG(RFC_RAT_BASE + RFC_RAT_O_RATCNT));
1191 }
1192
1193 /*
1194 * Read the channel value from the RAT timer.
1195 *
1196 * Input: ratHandle - The handle to the channel.
1197 * Return: timeout - The value found in the RATCHxVAL register.
1198 */
RF_ratGetChannelValue(RF_RatHandle ratHandle)1199 static uint32_t RF_ratGetChannelValue(RF_RatHandle ratHandle)
1200 {
1201 /* Read the channel value. */
1202 return(HWREG(RFC_RAT_BASE + RFC_RAT_O_RATCH5VAL + ratHandle * sizeof(uint32_t)));
1203 }
1204
1205 /*
1206 * Generate a command which can be used to configure a RAT channel into COMPARE mode.
1207 *
1208 * Input: ratCh - Pointer to the channel.
1209 * ratConfig - Configuration structure holding the channel setup.
1210 * Return: none
1211 */
RF_ratGenerateChCmd(RF_RatChannel * ratCh,void * ratConfig)1212 static void RF_ratGenerateChCmd(RF_RatChannel* ratCh, void* ratConfig)
1213 {
1214 /* Generate a command based on the mode. */
1215 if (ratCh->mode == RF_RatModeCompare)
1216 {
1217 /* Local pointer to cast the configuration to the proper type. */
1218 RF_RatConfigCompare* ratCompareConfig = (RF_RatConfigCompare*) ratConfig;
1219
1220 /* Point a pointer to the generic command field within the channels context. */
1221 rfc_CMD_SET_RAT_CMP_t* pCmd = (rfc_CMD_SET_RAT_CMP_t*)&ratCh->chCmd;
1222
1223 /* Populate the command structure properly. */
1224 pCmd->commandNo = CMD_SET_RAT_CMP; /* Instruct the RF core to use COMPARE mode. */
1225 pCmd->ratCh = RF_RAT_CH_LOWEST + ratCh->handle; /* Encode the selected channel number. */
1226 pCmd->compareTime = ratCompareConfig->timeout; /* Select the compare timeout. */
1227 }
1228 else if (ratCh->mode == RF_RatModeCapture)
1229 {
1230 /* Local pointer to cast the configuration to the proper type. */
1231 RF_RatConfigCapture* ratCaptureConfig = (RF_RatConfigCapture*) ratConfig;
1232
1233 /* Point a pointer to the generic command field within the channels context. */
1234 rfc_CMD_SET_RAT_CPT_t* pCmd = (rfc_CMD_SET_RAT_CPT_t*)&ratCh->chCmd;
1235
1236 /* Calculate the direct command to be sent to the RF core.*/
1237 pCmd->commandNo = CMD_SET_RAT_CPT; /* Instruct the RF core to use CAPTURE mode. */
1238 pCmd->config.ratCh = RF_RAT_CH_LOWEST + ratCh->handle; /* Encode the selected channel number. */
1239 pCmd->config.inputSrc = ratCaptureConfig->source; /* Select the source to be captured. */
1240 pCmd->config.inputMode = ratCaptureConfig->captureMode; /* Select the mode of capture: raising, falling, etc*/
1241 pCmd->config.bRepeated = ratCaptureConfig->repeat; /* Select if we should re-arm the channel after a capture event. */
1242 }
1243 }
1244
1245 /*
1246 * Generate a command which can be used to configure an IO for a particular RAT channel.
1247 *
1248 * Input: ratCh - Pointer to the channel.
1249 * ioConfig - Configuration channel for the IO.
1250 * Return: cmdToDoorbell - Return with the command structure. It is casted to uint32_t as it is
1251 * stored in a generic variable.
1252 */
RF_ratGenerateIoCmd(RF_RatChannel * ratCh,RF_RatConfigOutput * ioConfig)1253 static void RF_ratGenerateIoCmd(RF_RatChannel* ratCh, RF_RatConfigOutput* ioConfig)
1254 {
1255 /* Local variable. */
1256 uint32_t cmdToDoorbell = 0;
1257
1258 /* If there is an IO configuration. */
1259 if (ioConfig)
1260 {
1261 cmdToDoorbell |= ioConfig->select << 2;
1262 cmdToDoorbell |= ioConfig->mode << 5;
1263 cmdToDoorbell |= (uint32_t)(RF_RAT_CH_LOWEST + ratCh->handle) << 8;
1264
1265 cmdToDoorbell = (uint32_t)CMDR_DIR_CMD_2BYTE(CMD_SET_RAT_OUTPUT, cmdToDoorbell);
1266 }
1267
1268 /* Return with the raw command to be sent to the doorbell. */
1269 ratCh->ioCmd = cmdToDoorbell;
1270 }
1271
1272 /*
1273 * Wrapper function to setup a RAT channel into the selected mode.
1274 *
1275 * Input: ratClient - Handle previously returned by RF_open().
1276 * ratMode - Identifies the mode the channel is being set up: RF_RatModeCompare or RF_RatModeCapture.
1277 * ratCallback - Callback function to be registered to the RAT channel.
1278 * ratChannel - Preferred channel to be allocated. If RF_RatChannelAny is provided, allocatethe first available channel.
1279 * ratConfig - Configuration structure holding the setup of the particulare channel.
1280 * ioConfig - Configuration strucutre of the assosiated GPO setup.
1281 * Return: ratHandle - RF_RatHandle to the allocated channel. If allocation fails, RF_ALLOC_ERROR is returned.
1282 */
RF_ratSetupChannel(RF_Handle ratClient,RF_RatMode ratMode,RF_RatCallback ratCallback,RF_RatHandle ratChannel,void * ratConfig,RF_RatConfigOutput * ioConfig)1283 static RF_RatHandle RF_ratSetupChannel(RF_Handle ratClient, RF_RatMode ratMode, RF_RatCallback ratCallback, RF_RatHandle ratChannel, void* ratConfig, RF_RatConfigOutput* ioConfig)
1284 {
1285 /* Return with an error. Either we couldn't allocate any RAT
1286 channel, or the RAT module declined our configuration. */
1287 RF_RatHandle ratHandle = (RF_RatHandle)RF_ALLOC_ERROR;
1288
1289 /* Enter critical section */
1290 uint32_t key = HwiP_disable();
1291
1292 /* Find and allocate a RAT channel (if any is available) */
1293 RF_RatChannel* ratCh = RF_ratAllocChannel(ratChannel);
1294
1295 /* If we could allocate a RAT channel */
1296 if (ratCh)
1297 {
1298 /* Populate the container. Use the default "do nothing" callback
1299 if no user callback is provided and generate the command based
1300 on the mode of the channel. */
1301 ratCh->pClient = ratClient;
1302 ratCh->mode = ratMode;
1303 ratCh->pCb = (RF_RatCallback)RF_defaultCallback;
1304 RF_ratGenerateChCmd(ratCh, ratConfig);
1305 RF_ratGenerateIoCmd(ratCh, ioConfig);
1306
1307 /* If there is a user callback provided, override the default callback. */
1308 if (ratCallback)
1309 {
1310 ratCh->pCb = ratCallback;
1311 }
1312
1313 /* Decide which PHY should be used upon first start up. */
1314 if (RF_currClient == NULL)
1315 {
1316 RF_currClient = ratCh->pClient;
1317 }
1318
1319 /* Calculate the RAT/RTC timestamp to be used to wake the RF core. */
1320 RF_dispatchNextEvent();
1321
1322 /* Return with the handle upon success. */
1323 ratHandle = (RF_RatHandle)ratCh->handle;
1324 }
1325
1326 /* Exit critical section. */
1327 HwiP_restore(key);
1328
1329 /* Return with either an error OR a handle to a RAT channel. */
1330 return(ratHandle);
1331 }
1332
1333 /*
1334 * Poll the RFACKIFG and clear the flag afterwards. This is used during the power up sequence
1335 * of the RF core where interlaying processing is implemented.
1336 *
1337 * Input: none
1338 * Return: none
1339 */
RF_dbellSyncOnAck(void)1340 static void RF_dbellSyncOnAck(void)
1341 {
1342 while (!HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFACKIFG));
1343 HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFACKIFG) = 0;
1344 }
1345
1346 /*
1347 * Submit a command to the doorbell without blocking command execution. This is used during the
1348 * power up sequence where the system CPU can continue with processing data while the RF core
1349 * executes the submitted command.
1350 *
1351 * Input: rawCmd - The raw command to be written to the doorbell. This can be a pointer or a
1352 * a direct/immediate command.
1353 * Return: none
1354 */
RF_dbellSubmitCmdAsync(uint32_t rawCmd)1355 static void RF_dbellSubmitCmdAsync(uint32_t rawCmd)
1356 {
1357 HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFACKIFG) = 0;
1358 HWREG(RFC_DBELL_BASE + RFC_DBELL_O_CMDR) = rawCmd;
1359 }
1360
1361 /*
1362 * Wake up notification callback from the power driver. If the callback is from RF wakeup
1363 * set constraint to let RF Driver control the XOSC switching else do nothing in the
1364 * callback.
1365 *
1366 * Input: eventType - The type of event when the notification is invoked
1367 * eventArg - Not used.
1368 * clientArg - Not used.
1369 * Return: Power_NOTIFYDONE
1370 */
RF_wakeupNotification(uint8_t eventType,uint32_t * eventArg,uint32_t * clientArg)1371 static uint8_t RF_wakeupNotification(uint8_t eventType, uint32_t *eventArg, uint32_t *clientArg)
1372 {
1373 /* Check if the callback is for wakeup from standby and if power up clock is running */
1374 if ((eventType == PowerCC26XX_AWAKE_STANDBY) && (ClockP_isActive(&RF_clkPowerUpObj)))
1375 {
1376 /* Calculate time (in us) until next trigger (assume next trigger is max ~70 min away) */
1377 uint32_t timeInUsUntilNextTrig = ClockP_getSystemTickPeriod() * ClockP_getTimeout(&RF_clkPowerUpObj);
1378
1379 /* Check if the next trig time is close enough to the actual power up */
1380 if (timeInUsUntilNextTrig < RF_WAKEUP_DETECTION_WINDOW_IN_US)
1381 {
1382 /* Stop power up clock */
1383 ClockP_stop(&RF_clkPowerUpObj);
1384
1385 /* Setup RF Driver to do the XOSC_HF switching */
1386 Power_setConstraint(PowerCC26XX_SWITCH_XOSC_HF_MANUALLY);
1387
1388 /* Set variable to indicate RF Driver will do the XOSC_HF switching */
1389 RF_core.manualXoscHfSelect = true;
1390
1391 /* Start the RF Core power up */
1392 SwiP_or(&RF_swiFsmObj, RF_FsmEventWakeup);
1393 }
1394 }
1395
1396 return(Power_NOTIFYDONE);
1397 }
1398
1399 /*-------------- Scheduler internal functions --------------------------------*/
1400
1401 /*
1402 * Issue RF_EventRadioFree callback to the client. The callback is issued -
1403 * 1. After pre-emption is complete
1404 * 2. Dedicated request access period expires or released
1405 * 3. command reject because of other high priority command running
1406 *
1407 * Input: src - Flag indicating the source of callback request.
1408 * Return: none
1409 */
RF_issueRadioFreeCb(uint8_t src)1410 static void RF_issueRadioFreeCb(uint8_t src)
1411 {
1412 /* Enter critical section*/
1413 uint32_t key = HwiP_disable();
1414
1415 /* Clear the reason why the callback is being invoked */
1416 RF_Sch.issueRadioFreeCbFlags &= ~src;
1417
1418 /* Local variable */
1419 bool isReqAccessActive = false;
1420
1421 /* If any of the clients has active request access, indicate it */
1422 if (RF_Sch.clientHnd[0])
1423 {
1424 isReqAccessActive |= ClockP_isActive(&RF_Sch.clientHnd[0]->state.clkReqAccess);
1425 }
1426 if (RF_Sch.clientHnd[1])
1427 {
1428 isReqAccessActive |= ClockP_isActive(&RF_Sch.clientHnd[1]->state.clkReqAccess);
1429 }
1430
1431 /* If we cleared all the potential sources and there is no request access*/
1432 if ((RF_Sch.issueRadioFreeCbFlags == 0) && !isReqAccessActive)
1433 {
1434 /* If a valid client handle is provided through the global pointer */
1435 if (RF_Sch.clientHndRadioFreeCb && (RF_Sch.clientHndRadioFreeCb->clientConfig.nClientEventMask & RF_ClientEventRadioFree))
1436 {
1437 /* Get a pointer to the client event callback */
1438 RF_ClientCallback pClientEventCb = (RF_ClientCallback)RF_Sch.clientHndRadioFreeCb->clientConfig.pClientEventCb;
1439
1440 /* Exit critical section */
1441 HwiP_restore(key);
1442
1443 /* Invoek the client event callback */
1444 pClientEventCb(RF_Sch.clientHndRadioFreeCb, RF_ClientEventRadioFree, NULL);
1445
1446 /* Clear the client pointer in any case */
1447 RF_Sch.clientHndRadioFreeCb = NULL;
1448 }
1449 else
1450 {
1451 /* Exit critical section */
1452 HwiP_restore(key);
1453 }
1454 }
1455 else
1456 {
1457 /* Exit critical section */
1458 HwiP_restore(key);
1459 }
1460 }
1461
1462 /*
1463 * Decode how much time it will take to switch protocol/phy configuration.
1464 *
1465 * Input: prevCmd - The command switching from.
1466 * nextCmd - The command switching to.
1467 * Return: switchingTime - The time it takes to switch the PHY.
1468 */
RF_getSwitchingTimeInUs(RF_Cmd * prevCmd,RF_Cmd * nextCmd)1469 static int32_t RF_getSwitchingTimeInUs(RF_Cmd* prevCmd, RF_Cmd* nextCmd)
1470 {
1471 int32_t switchingTime = 0;
1472
1473 /* If otherCmd and newCmd are from different client then there is a switching time
1474 related to moving between the two commands. */
1475 if (prevCmd->pClient != nextCmd->pClient)
1476 {
1477 switchingTime = nextCmd->pClient->clientConfig.nPhySwitchingDuration;
1478 }
1479
1480 /* Return the switching time related to moving between the two clients. */
1481 return(switchingTime);
1482 }
1483
1484 /*
1485 * Check if new request can inserted between the previous and next command in the
1486 * current queue.
1487 *
1488 * Input: newCmd - RF_Cmd pointer for the new command request
1489 * prevCmd - RF_Cmd pointer for the previous cmd in the queue
1490 * nextCmd - RF_Cmd pointer for the next cmd in the queue
1491 * Return: true - If command can be inserted in the queue else
1492 * false - Otherwise.
1493 */
RF_verifyGap(RF_Cmd * newCmd,RF_Cmd * prevCmd,RF_Cmd * nextCmd)1494 static bool RF_verifyGap(RF_Cmd* newCmd, RF_Cmd* prevCmd, RF_Cmd* nextCmd)
1495 {
1496 /* Initialize local variables. */
1497 bool insertNewCmdAfterPrev = prevCmd ? false : true;
1498 bool insertNewCmdBeforeNext = nextCmd ? false : true;
1499 int32_t deltaInUs = 0;
1500
1501 /* Step 1 - The newCmd must have an endTime in order to be placed anywhere
1502 else than the end. Or if there are no commands behind. */
1503 if ((newCmd) && (insertNewCmdBeforeNext || (newCmd->endType != RF_EndNotSpecified)))
1504 {
1505 /* If there is a prevCmd and it have an endTime, we could potentially
1506 put the new command behind it. */
1507 if ((prevCmd) && (prevCmd->endType != RF_EndNotSpecified))
1508 {
1509 /* Take the start time of the command located later in the timeline. */
1510 deltaInUs = (int32_t)RF_convertRatTicksToUs(newCmd->startTime);
1511
1512 /* Substract the time earlier in the timeline. The result is the gap in between. */
1513 deltaInUs -= (int32_t)RF_convertRatTicksToUs(prevCmd->endTime);
1514
1515 /* Substract the switching time needed to move between prevCmd and newCmd. */
1516 deltaInUs -= RF_getSwitchingTimeInUs(prevCmd, newCmd);
1517
1518 /* Handle timer overflow with the assumption that the difference between the startTime
1519 and endTime is less than ~8 min. */
1520 if ((deltaInUs < ((int32_t)RF_DISPATCH_MAX_TIME_WRAPAROUND_US)) || (deltaInUs > 0))
1521 {
1522 /* Allow insertion if startTime has wrapped around or no wrap around and we can insert the command */
1523 insertNewCmdAfterPrev = true;
1524 }
1525 }
1526
1527 /* If there is a nextCmd, and it has an aboslute startTime, we could potentially put the new command in front of it.
1528 If we already have evaluated that we can't be behind the prevCmd, there is no need to evalue this. */
1529 if ((insertNewCmdAfterPrev) && (nextCmd) && (nextCmd->pOp->startTrigger.triggerType == TRIG_ABSTIME))
1530 {
1531 /* Take the start time of the command located later in the timeline. */
1532 deltaInUs = (int32_t)RF_convertRatTicksToUs(nextCmd->startTime);
1533
1534 /* Substract the time earlier in the timeline. The result is the gap in between. */
1535 deltaInUs -= (int32_t)RF_convertRatTicksToUs(newCmd->endTime);
1536
1537 /* Substract the switching time needed to move between newCmd and nextCmd. */
1538 deltaInUs -= RF_getSwitchingTimeInUs(newCmd, nextCmd);
1539
1540 /* Handle timer overflow with the assumption that the difference between the startTime
1541 and endTime is less than ~8 min. */
1542 if ((deltaInUs < ((int32_t)RF_DISPATCH_MAX_TIME_WRAPAROUND_US)) || (deltaInUs > 0))
1543 {
1544 /* Allow insertion if startTime has wrapped around or no wrap around and we can insert the command. */
1545 insertNewCmdBeforeNext = true;
1546 }
1547 }
1548 }
1549
1550 /* Return with true if the command can be inserted into the queue (both before or after criteria met). */
1551 return(insertNewCmdBeforeNext & insertNewCmdAfterPrev);
1552 }
1553
1554 /*
1555 * Check what scheduling strategy that can be used to schedule the requesting command.
1556 *
1557 * Input: newCmd - Points to the newly submitted radio command,
1558 * pCmdBg - Points to the active background command (if any).
1559 * pCmdFg - Points to the active foreground command (if any).
1560 * pPendQueue - Points to the queue holding the commands to be executed.
1561 * pDoneQueue - Points to the queue holding the commands which has been exeuted.
1562 * pInsertLocation - Reference to command which the newCmd shall be inserted behind.
1563 *
1564 * Return: RF_ScheduleStatus - Returning status containing the scheduling decision.
1565 */
RF_howToSchedule(RF_Cmd * newCmd,RF_Cmd * pCmdBg,RF_Cmd * pCmdFg,List_List * pPendQueue,List_List * pDoneQueue,RF_Cmd ** pInsertLocation)1566 static RF_ScheduleStatus RF_howToSchedule(RF_Cmd* newCmd, RF_Cmd* pCmdBg, RF_Cmd* pCmdFg, List_List* pPendQueue, List_List* pDoneQueue, RF_Cmd** pInsertLocation)
1567 {
1568 /* By default, reject any new request. */
1569 volatile RF_ScheduleStatus status = RF_ScheduleStatusError;
1570
1571 /* Typecast the arguments to RF commands. */
1572 RF_Cmd* pHead = (RF_Cmd*)List_head(pPendQueue);
1573
1574 /* Load list head as the start point of the iterator. */
1575 RF_Cmd* it = pHead;
1576
1577 /* Step 1 - Check if new command can be inserted based on the timing information
1578 at the top of the pending queue. */
1579 if (RF_verifyGap(newCmd, pCmdBg, pHead))
1580 {
1581 /* Indicate that the command was put on the top of the queue.ss */
1582 status = RF_ScheduleStatusTop;
1583 }
1584
1585 /* Step 2 - Check if new command can be inserted based on the timing information
1586 in the middle/end of the pending queue. This require the new command
1587 to have an ABSOLUTE startTrigger type. */
1588 if ((status == RF_ScheduleStatusError) && (newCmd->pOp->startTrigger.triggerType == TRIG_ABSTIME))
1589 {
1590 /* Walk the queue.*/
1591 while (it)
1592 {
1593 /* Check if we can insert the new command in between. */
1594 if (RF_verifyGap(newCmd, it, (RF_Cmd*)List_next((List_Elem*)it)))
1595 {
1596 /* Set the return value that the new command should be
1597 inserted in between it and it->pNext. */
1598 status = RF_ScheduleStatusMiddle;
1599 break;
1600 }
1601 else
1602 {
1603 it = (RF_Cmd*)List_next((List_Elem*)it);
1604 }
1605 }
1606 }
1607
1608 /* Step 3 - If step 1) or 2) fails, reject or append the command to the end of the queue
1609 based on the allowDelay argument of RF_scheduleCmd() API call. */
1610 if ((status == RF_ScheduleStatusError) && (newCmd->allowDelay))
1611 {
1612 status = RF_ScheduleStatusTail;
1613 }
1614
1615 /* Set pInsertLocation to mark where to insert the new command. */
1616 *pInsertLocation = it;
1617
1618 /* Return with the scheduling method. */
1619 return(status);
1620 }
1621
1622 /**
1623 * Sorts and adds command to the RF driver internal command queue.
1624 *
1625 * Input: pCmdNew - Pointer to the command to be submitted.
1626 * pCmdBg - Running background command.
1627 * pCmdFg - Running foreground command.
1628 * pPendQueue - Pointer to the head structure of pend queue.
1629 * pDoneQueue - Pointer to the head structure of done queue.
1630 * Return: RF_ScheduleStatus - Identifies the success or failure of enquing.
1631 */
RF_defaultSubmitPolicy(RF_Cmd * pCmdNew,RF_Cmd * pCmdBg,RF_Cmd * pCmdFg,List_List * pPendQueue,List_List * pDoneQueue)1632 RF_ScheduleStatus RF_defaultSubmitPolicy(RF_Cmd* pCmdNew, RF_Cmd* pCmdBg, RF_Cmd* pCmdFg, List_List* pPendQueue, List_List* pDoneQueue)
1633 {
1634 /* Local pointer to a command which will be used if insertition
1635 is selected as a method. */
1636 RF_Cmd* pInsertLocation = NULL;
1637
1638 /* Check the method how the new command should be scheduled. */
1639 RF_ScheduleStatus status = RF_howToSchedule(pCmdNew, pCmdBg, pCmdFg, pPendQueue, pDoneQueue, &pInsertLocation);
1640
1641 /* Step 1 - If the new command is placed to the top of the pend queue. */
1642 if (status == RF_ScheduleStatusTop)
1643 {
1644 /* Insert command at the beginning of the queue */
1645 List_putHead(pPendQueue, (List_Elem*)pCmdNew);
1646 }
1647
1648 /* Step 2 - If the new command is inserted behind a particular command. */
1649 if (status == RF_ScheduleStatusMiddle)
1650 {
1651 /* Insert command between pInsertLocation and pInsertLocation->pNext. */
1652 if (List_next((List_Elem*)pInsertLocation))
1653 {
1654 /* Insert command before pInsertLocation->next. */
1655 List_insert(pPendQueue, (List_Elem*)pCmdNew, List_next((List_Elem*)pInsertLocation));
1656 }
1657 else
1658 {
1659 /* Append command to the end of the queue (if next does not exist). */
1660 List_put(pPendQueue, (List_Elem*)pCmdNew);
1661 }
1662 }
1663
1664 /* Step 3 - Append command to the end of the queue. */
1665 if (status == RF_ScheduleStatusTail)
1666 {
1667 List_put(pPendQueue, (List_Elem*)pCmdNew);
1668 }
1669
1670 /* Return command with the method we used to schedule the command.
1671 Might be RF_ScheduleStatusError if none of the above rules applied. */
1672 return(status);
1673 }
1674
1675 /**
1676 * Sorts and adds command to the RF driver internal command queue.
1677 *
1678 * Input: pCmdBg - Running background command.
1679 * pCmdFg - Running foreground command.
1680 * pPendQueue - Pointer to the head structure of pend queue.
1681 * pDoneQueue - Pointer to the head structure of done queue.
1682 * bConflict - Whether the incoming command conflicts with ongoing activity.
1683 * conflictCmd - Pointer to the command that conflicts with ongoing.
1684 * Return: RF_ScheduleStatus - Identifies the success or failure of enquing.
1685 */
RF_defaultExecutionPolicy(RF_Cmd * pCmdBg,RF_Cmd * pCmdFg,List_List * pPendQueue,List_List * pDoneQueue,bool bConflict,RF_Cmd * conflictCmd)1686 RF_ExecuteAction RF_defaultExecutionPolicy(RF_Cmd* pCmdBg, RF_Cmd* pCmdFg, List_List* pPendQueue, List_List* pDoneQueue, bool bConflict, RF_Cmd* conflictCmd)
1687 {
1688 return(RF_ExecuteActionNone);
1689 }
1690
1691 /*
1692 * Execute RF power down sequence.
1693 *
1694 * Input: none
1695 * Return: none
1696 */
RF_corePowerDown(void)1697 static void RF_corePowerDown(void)
1698 {
1699 /* Local variables to calculate active time in current window. */
1700 uint32_t deltaTimeInUs = 0;
1701
1702 /* Disable all CPE and HW interrupts as we are about to power down the core.
1703 Clearing is not important as content will be lost anyway. */
1704 RFCCpeIntDisable(~0);
1705 RFCHwIntDisable(~0);
1706
1707 /* Remap HWI to the startup function (preparing for next wake up) */
1708 HwiP_setFunc(&RF_hwiCpe0Obj, RF_hwiCpe0PowerFsm, (uintptr_t)NULL);
1709
1710 /* Take wake up timestamp and the current timestamp */
1711 uint32_t rtcTimestampB = (uint32_t) AONRTCCurrent64BitValueGet();
1712
1713 /* Find the radio core active delta time since the last power up. */
1714 deltaTimeInUs = UDIFF(RF_rtcTimestampA, rtcTimestampB);
1715 deltaTimeInUs >>= RF_RTC_CONV_TO_US_SHIFT;
1716
1717 /* Accumulate the delta time with the previous active time windows. Avoid overflow. */
1718 RF_core.activeTimeUs = ADD(RF_core.activeTimeUs, deltaTimeInUs);
1719
1720 /* Decide whether to send the CMD_SYNC_STOP_RAT command. If this is first power down (.init) or active time (activeTimeInUs)
1721 is longer than the time that can cause maximum allowed error between RAT and RTC clocks. Yielding will automatically fulfill
1722 the latter. */
1723 if (!(RF_core.init) ||
1724 (RF_core.activeTimeUs > (RF_errTolValInUs << RF_DEFAULT_COMB_XTAL_DRIFT_BITS_SHIFT)))
1725 {
1726 /* Stop and synchronize the RAT if it is running */
1727 if (RF_ratIsRunning())
1728 {
1729 /* Setup RAT_SYNC command to follow powerdown. */
1730 RF_ratSyncCmd.stop.commandNo = CMD_SYNC_STOP_RAT;
1731 RF_ratSyncCmd.stop.status = IDLE;
1732 RF_ratSyncCmd.stop.condition.rule = COND_NEVER;
1733 RF_ratSyncCmd.stop.startTrigger.triggerType = TRIG_NOW;
1734 RF_ratSyncCmd.stop.pNextOp = NULL;
1735
1736 /* Send RAT Stop command and synchronously wait until it run. */
1737 RF_dbellSubmitCmdAsync((uint32_t)&RF_ratSyncCmd.stop);
1738 while (!(RF_ratSyncCmd.stop.status & RF_CMD_TERMINATED));
1739 }
1740
1741 /* The RF core is now initialized and RAT is synchronized. */
1742 RF_core.init = true;
1743 RF_core.activeTimeUs = 0;
1744 }
1745
1746 /* Turn off Synth */
1747 RFCSynthPowerDown();
1748
1749 /* Turn off the RF core by gating its clock. This is a quick way to have it shut off. */
1750 RFCClockDisable();
1751 }
1752
1753 /*-------------- Power constraints internal functions ------------------------*/
1754
1755 /*
1756 * Set RF power constraints.
1757 *
1758 * Input: src - RF_PowerConstraintSrc (Source: Queue or RAT)
1759 * Return: none
1760 */
RF_powerConstraintSet(RF_PowerConstraintSrc src)1761 void RF_powerConstraintSet(RF_PowerConstraintSrc src)
1762 {
1763 /* Enter critical section */
1764 uint32_t key = HwiP_disable();
1765
1766 /* Set constraint based on source */
1767 RF_powerConstraint |= src;
1768
1769 /* Exit critical section */
1770 HwiP_restore(key);
1771 }
1772
1773 /*
1774 * Release RF power constraints.
1775 *
1776 * Input: src - RF_PowerConstraintSrc (Source: Queue or RAT)
1777 * Return: none
1778 */
RF_powerConstraintRelease(RF_PowerConstraintSrc src)1779 void RF_powerConstraintRelease(RF_PowerConstraintSrc src)
1780 {
1781 /* Enter critical section. */
1782 uint32_t key = HwiP_disable();
1783
1784 /* Release this constraint. */
1785 RF_powerConstraint &= ~src;
1786
1787 /* Check if all constraints are clear. */
1788 if (!(RF_powerConstraint & RF_PowerConstraintCmdQ))
1789 {
1790 /* Initiate power down if the above criterion is met.
1791 The RAT timer though might will prevent us to proceed. */
1792 SwiP_or(&RF_swiFsmObj, RF_FsmEventPowerDown);
1793 }
1794
1795 /* Exit critical section. */
1796 HwiP_restore(key);
1797 }
1798
1799 /*
1800 * Get RF power constraints.
1801 *
1802 * Input: src - Mask of constraints we requesting
1803 * Return: Bitwise-OR of the power constraints set and the input argument
1804 */
RF_powerConstraintGet(RF_PowerConstraintSrc src)1805 RF_PowerConstraintSrc RF_powerConstraintGet(RF_PowerConstraintSrc src)
1806 {
1807 /* Set constraint based on source */
1808 return((RF_PowerConstraintSrc)(RF_powerConstraint & (uint8_t)src));
1809 }
1810
1811 /*
1812 * It calculates and returns the closest RF event in time if any.
1813 *
1814 * Calling context: Hwi, Swi
1815 *
1816 * Input: dispatchTime - pointer to a container where the calculated time can be returned
1817 * Return: ticks - If command is far away in future.
1818 * 0 - If command is too close and should be scheduled now.
1819 */
RF_calculateDispatchTime(uint32_t * dispatchTimeClockTicks)1820 static bool RF_calculateDispatchTime(uint32_t* dispatchTimeClockTicks)
1821 {
1822 /* Local variables. */
1823 uint32_t deltaTimeCmdClockTicks;
1824 uint32_t deltaTimeRatClockTicks;
1825
1826 /* Initialize return value. */
1827 *dispatchTimeClockTicks = 0;
1828
1829 /* Calculate the timestamp of the next command in the command queue. */
1830 bool validCmdTime = RF_cmdDispatchTime(&deltaTimeCmdClockTicks, false, NULL);
1831
1832 /* If any of the RAT timers expire before the command should be dispatched,
1833 reprogram the power up clock to the RAT event instead. */
1834 bool validRatTime = RF_ratDispatchTime(&deltaTimeRatClockTicks);
1835
1836 if (validCmdTime && validRatTime)
1837 {
1838 /* Determine if command execution or RAT event comes first. */
1839 *dispatchTimeClockTicks = MIN(deltaTimeCmdClockTicks, deltaTimeRatClockTicks);
1840 }
1841 else if (validCmdTime)
1842 {
1843 /* Command queue determines the next event. */
1844 *dispatchTimeClockTicks = deltaTimeCmdClockTicks;
1845 }
1846 else if (validRatTime)
1847 {
1848 /* RAT timer determines the next event. */
1849 *dispatchTimeClockTicks = deltaTimeRatClockTicks;
1850 }
1851
1852 /* If any of them valid, return with true indicating a valid dispatch time. */
1853 return(validCmdTime || validRatTime);
1854 }
1855
1856 /*
1857 * Dispatch the closest event generated either by a command or the RAT timer.
1858 * If the RF core is powered, it triggs the HWI to execute the dispatcher.
1859 * If the RF core is not powered, it decides if it should be powered ON immediately, or
1860 * the execution can be deferred to a later timestamp. In the latter case, the RTC is used to keep
1861 * track of proper timing.
1862 *
1863 * Input: none
1864 * Return: status - Status of the command execution.
1865 *
1866 */
RF_dispatchNextEvent(void)1867 static void RF_dispatchNextEvent(void)
1868 {
1869 if (RF_core.status == RF_CoreStatusActive)
1870 {
1871 /* Kick the HWI to dispatch the next pending event. */
1872 HwiP_post(INT_RFC_CPE_0);
1873 }
1874 else if ((RF_core.status == RF_CoreStatusPoweringUp) ||
1875 (RF_core.status == RF_CoreStatusPhySwitching))
1876 {
1877 /* Do nothing. We will dispatch the next event at the end
1878 of power-up/phy-switching sequence naturally. */
1879 }
1880 else
1881 {
1882 /* Enter critical section. */
1883 uint32_t key = HwiP_disable();
1884
1885 /* Calculate dispatch time. */
1886 uint32_t dispatchTimeClockTicks;
1887 bool validTime = RF_calculateDispatchTime(&dispatchTimeClockTicks);
1888
1889 if (validTime)
1890 {
1891 /* Decide whether the command should be dispatched. */
1892 if (dispatchTimeClockTicks)
1893 {
1894 /* Dispatch command in the future. */
1895 RF_restartClockTimeout(&RF_clkPowerUpObj, dispatchTimeClockTicks);
1896 }
1897 else
1898 {
1899 /* Dispatch the event immediately. Clock is not needed anymore. */
1900 ClockP_stop(&RF_clkPowerUpObj);
1901
1902 /* Initiate powering up the RF core. */
1903 SwiP_or(&RF_swiFsmObj, RF_FsmEventWakeup);
1904 }
1905 }
1906 else
1907 {
1908 /* There is no event to be dispatched. */
1909 ClockP_stop(&RF_clkPowerUpObj);
1910 }
1911
1912 /* Exit critical section. */
1913 HwiP_restore(key);
1914 }
1915 }
1916
1917 /*
1918 * Update the cached FS command within the client's context.
1919 *
1920 * Calling context: Hwi, Swi
1921 *
1922 * Input: pCmd - Pointer to radio operation command.
1923 * Return: none
1924 */
RF_cacheFsCmd(RF_Cmd * pCmd)1925 static void RF_cacheFsCmd(RF_Cmd* pCmd)
1926 {
1927 /* Upper limit of the number of operations in a chain */
1928 uint8_t nCmdChainMax = RF_MAX_CHAIN_CMD_LEN;
1929
1930 /* Traverse the chain */
1931 RF_Op* pOp = pCmd->pOp;
1932 while (pOp && nCmdChainMax)
1933 {
1934 /* If the operation is a CMD_FS or CMD_FS_OFF */
1935 if ((pOp->commandNo == CMD_FS) || (pOp->commandNo == CMD_FS_OFF))
1936 {
1937 /* Create a copy of the first CMD_FS command (or CMD_FS_OFF) for later power up */
1938 memcpy(&pCmd->pClient->state.mode_state.cmdFs, pOp, sizeof(pCmd->pClient->state.mode_state.cmdFs));
1939 break;
1940 }
1941
1942 /* Step the chain */
1943 pOp = pOp->pNextOp;
1944
1945 /* Avoid infinit loop (in case of closed loops) */
1946 --nCmdChainMax;
1947 }
1948 }
1949
1950 /*
1951 * Find the last radio operation within a chain.
1952 *
1953 * Calling context: Task, Hwi, Swi
1954 *
1955 * Input: pOp - Pointer to the first radio operation.
1956 * Return: RF_Op* - Pointer to the last radio operation.
1957 */
RF_findEndOfChain(RF_Op * pOp)1958 static RF_Op* RF_findEndOfChain(RF_Op* pOp)
1959 {
1960 /* Upper limit of the number of operations in a chain. */
1961 uint8_t nCmdChainMax = RF_MAX_CHAIN_CMD_LEN;
1962
1963 /* Traverse the chain. */
1964 while (pOp->pNextOp && nCmdChainMax)
1965 {
1966 /* Step the chain. */
1967 pOp = pOp->pNextOp;
1968
1969 /* Avoid infinit loop (in case of closed loops). */
1970 --nCmdChainMax;
1971 }
1972
1973 /* Return with the last radio operation. */
1974 return(pOp);
1975 }
1976
1977 /*
1978 * Verify if the given command is a setup command.
1979 *
1980 * Calling context: Hwi, Swi
1981 *
1982 * Input: pOp - Pointer to radio operation.
1983 * Return: true - The given command is a setup command.
1984 * false - The given command is not a setup command.
1985 */
RF_isRadioSetup(RF_Op * pOp)1986 static bool RF_isRadioSetup(RF_Op* pOp)
1987 {
1988 /* Verify the command ID against the known setup commands. */
1989 switch(pOp->commandNo)
1990 {
1991 case (CMD_RADIO_SETUP):
1992 case (CMD_BLE5_RADIO_SETUP):
1993 case (CMD_PROP_RADIO_SETUP):
1994 case (CMD_PROP_RADIO_DIV_SETUP):
1995 /* The given radio operation is indead a setup command. */
1996 return(true);
1997 default:
1998 /* Do nothing. */
1999 return(false);
2000 }
2001 }
2002
2003 /*
2004 * Ensure that the setup command is properly initialized.
2005 *
2006 * Input: handle - Pointer to the client.
2007 * Return: None
2008 */
RF_initRadioSetup(RF_Handle handle)2009 static void RF_initRadioSetup(RF_Handle handle)
2010 {
2011 /* Local variables. */
2012 uint16_t* pTxPower = NULL;
2013 uint32_t* pRegOverride = NULL;
2014 uint32_t* pRegOverrideTxStd = NULL;
2015 uint32_t* pRegOverrideTx20 = NULL;
2016 bool tx20FeatureAvailable = false;
2017 bool update = handle->clientConfig.bUpdateSetup;
2018
2019 /* Decode the setup command. */
2020 RF_RadioSetup* radioSetup = handle->clientConfig.pRadioSetup;
2021 radioSetup->common.status = IDLE;
2022
2023 /* Adjust the setup command if needed. */
2024 switch (radioSetup->common.commandNo)
2025 {
2026 case (CMD_RADIO_SETUP):
2027 case (CMD_BLE5_RADIO_SETUP):
2028 /* Configure that the frequency synthetizer should be powered up */
2029 radioSetup->common.config.bNoFsPowerUp = 0;
2030
2031 /* If requested, also change the analog configuration during power up */
2032 if (update)
2033 {
2034 radioSetup->common.config.analogCfgMode = RF_SETUP_ANALOGCFG_UPDATE;
2035 }
2036 else
2037 {
2038 radioSetup->common.config.analogCfgMode = RF_SETUP_ANALOGCFG_NOUPDATE;
2039 }
2040 break;
2041
2042 case (CMD_PROP_RADIO_SETUP):
2043 case (CMD_PROP_RADIO_DIV_SETUP):
2044 /* Configure that the frequency synthetizer should be powered ON */
2045 radioSetup->prop.config.bNoFsPowerUp = 0;
2046
2047 /* If requested, also change the analog configuration during power up */
2048 if (update)
2049 {
2050 radioSetup->prop.config.analogCfgMode = RF_SETUP_ANALOGCFG_UPDATE;
2051 }
2052 else
2053 {
2054 radioSetup->prop.config.analogCfgMode = RF_SETUP_ANALOGCFG_NOUPDATE;
2055 }
2056 break;
2057 default:
2058 break;
2059 }
2060
2061 /* Clear the update request flag as it was handled by now. */
2062 handle->clientConfig.bUpdateSetup = false;
2063
2064 /* Decode if High Gain PA is available. */
2065 tx20FeatureAvailable = RF_decodeOverridePointers(radioSetup, &pTxPower, &pRegOverride, &pRegOverrideTxStd, &pRegOverrideTx20);
2066
2067 /* Ensure that overrides are in sync with the selected PA. */
2068 if (tx20FeatureAvailable && (*pTxPower == RF_TX20_ENABLED))
2069 {
2070 /* Attach the High Gain overrides. It does nothing if the extra overrides are NULL. */
2071 RF_attachOverrides(pRegOverride, pRegOverrideTx20);
2072 }
2073 else
2074 {
2075 /* Detach the High Gain overrides. It does nothing if it is not present. */
2076 RF_detachOverrides(pRegOverride, pRegOverrideTx20);
2077 }
2078
2079 /* Perform Software Temperature Controlled Crystal Oscillator compensation (SW TCXO), if enabled */
2080 if(pfnUpdateHposcOverride != NULL)
2081 {
2082 pfnUpdateHposcOverride(pRegOverride);
2083 }
2084 }
2085
2086 /*
2087 * Submit the pending command to the RF Core.
2088 *
2089 * Input: none
2090 * Return: none
2091 */
RF_dispatchNextCmd(void)2092 static void RF_dispatchNextCmd(void)
2093 {
2094 bool doDispatchNow = false;
2095 RF_Cmd* pConflictCmd = NULL;
2096 RF_Cmd* pNextCmd = (RF_Cmd*)List_head(&RF_cmdQ.pPend);
2097 bool validTime = false;
2098 uint32_t dispatchTimeClockTicks = 0;
2099
2100 /* Decide whether to schedule the next command or not. */
2101 if (pNextCmd)
2102 {
2103 /* Either no commands are active, and we will execute */
2104 if (NULL == RF_cmdQ.pCurrCmdFg && NULL == RF_cmdQ.pCurrCmdBg)
2105 {
2106 doDispatchNow = true;
2107 }
2108 /* Or the current client wants to execute in the foreground on top of a background command */
2109 else if (RF_cmdQ.pCurrCmdBg
2110 && (RF_cmdQ.pCurrCmdBg->pClient == pNextCmd->pClient)
2111 && (pNextCmd->flags & RF_CMD_FG_CMD_FLAG))
2112 {
2113 /* Try to execute the foreground command. */
2114 doDispatchNow = true;
2115
2116 /* Be sure that the background command is started within the RF core.
2117 This is to avoid race condition. */
2118 while ((RF_cmdQ.pCurrCmdBg->pOp->status == IDLE) ||
2119 (RF_cmdQ.pCurrCmdBg->pOp->status == PENDING));
2120 }
2121 /* Or there is conflict. */
2122 else
2123 {
2124 /* By default let current command finish. */
2125 doDispatchNow = false;
2126 }
2127 }
2128 else
2129 {
2130 /* There is nothing to do, serve the last callbacks. */
2131 SwiP_or(&RF_swiFsmObj, RF_FsmEventLastCommandDone);
2132 }
2133
2134 /*
2135 * Calculate the timestamp of the next command in the command queue.
2136 * `conflict` parameter (here opposite of doDistpatch) implicitly used to determine margin needed to execute incoming command.
2137 */
2138 if (pNextCmd && (validTime = RF_cmdDispatchTime(&dispatchTimeClockTicks, !doDispatchNow, &pConflictCmd)))
2139 {
2140 /* If there is a conflict, but there is time left */
2141 if (!doDispatchNow && dispatchTimeClockTicks > 0)
2142 {
2143 /* The conflict is in the future, and might resolve naturally.
2144 Revisit the issue again before the execution should start. */
2145 RF_restartClockTimeout(&RF_clkPowerUpObj, dispatchTimeClockTicks);
2146
2147 /* Set pNext to NULL to avoid calling the hook until we revisit. */
2148 pNextCmd = NULL;
2149 }
2150 }
2151
2152 /* Invoke the registered hook to get a final decision if there is still one to be made */
2153 if(pNextCmd && RFCC26XX_schedulerPolicy.executeHook && validTime && (0 == dispatchTimeClockTicks))
2154 {
2155 /* Invoke the conflit hook to determine what action we shall take. */
2156 RF_ExecuteAction action =
2157 RFCC26XX_schedulerPolicy.executeHook(RF_cmdQ.pCurrCmdBg,
2158 RF_cmdQ.pCurrCmdFg,
2159 &RF_cmdQ.pPend,
2160 &RF_cmdQ.pDone,
2161 !doDispatchNow,
2162 pConflictCmd);
2163
2164 switch (action)
2165 {
2166 case RF_ExecuteActionAbortOngoing:
2167 {
2168 RF_abortCmd(RF_cmdQ.pCurrCmdBg->pClient, RF_cmdQ.pCurrCmdBg->ch, false, true, true);
2169 /* Do not dispatch now, wait for abort to complete, then reschedule */
2170 doDispatchNow = false;
2171 }
2172 break;
2173
2174 case RF_ExecuteActionRejectIncoming:
2175 {
2176 RF_Cmd *abortCmd = pConflictCmd ? pConflictCmd : pNextCmd;
2177 RF_abortCmd(abortCmd->pClient, abortCmd->ch, false, false, true);
2178 /* Do not dispatch now, wait for abort to complete, then reschedule */
2179 doDispatchNow = false;
2180 }
2181 break;
2182
2183 case RF_ExecuteActionNone:
2184 default:
2185 {
2186 /*
2187 * Ignore command if conflict, and pick it up after current finishes.
2188 * If no conflict, dispatch.
2189 */
2190 ;
2191 }
2192 break;
2193 }
2194 }
2195
2196 /* We need to evaluate and handle the next command. Check pointer for static analysis. */
2197 if (doDispatchNow && pNextCmd)
2198 {
2199 if (pNextCmd->pClient != RF_currClient)
2200 {
2201 /* We need to change radio client, signal to FSM. */
2202 SwiP_or(&RF_swiFsmObj, RF_FsmEventInitChangePhy);
2203 }
2204 else
2205 {
2206 /* Dispatch command in the future */
2207 if (validTime && dispatchTimeClockTicks && !RF_cmdQ.pCurrCmdBg && !RF_cmdQ.pCurrCmdFg)
2208 {
2209 /* Command sufficiently far into future that it shouldn't be dispatched yet
2210 Release RF power constraint and potentially power down radio */
2211 RF_powerConstraintRelease(RF_PowerConstraintCmdQ);
2212 }
2213 else
2214 {
2215 /* Set power constraint on the command queue, since there is now a running command. */
2216 RF_powerConstraintSet(RF_PowerConstraintCmdQ);
2217
2218 /* Move the command from the pending queue to the current command. */
2219 if (pNextCmd->flags & RF_CMD_FG_CMD_FLAG)
2220 {
2221 RF_cmdQ.pCurrCmdFg = (RF_Cmd*)List_get(&RF_cmdQ.pPend);
2222 }
2223 else
2224 {
2225 RF_cmdQ.pCurrCmdBg = (RF_Cmd*)List_get(&RF_cmdQ.pPend);
2226 }
2227
2228 /* Clear and enable the requested interrupt sources of the command. */
2229 RFCCpeIntClear((uint32_t) (pNextCmd->bmEvent));
2230 RFCCpeIntEnable((uint32_t)(pNextCmd->bmEvent));
2231 RFCHwIntClear((uint32_t) (pNextCmd->bmEvent >> RF_SHIFT_32_BITS));
2232 RFCHwIntEnable((uint32_t) (pNextCmd->bmEvent >> RF_SHIFT_32_BITS));
2233
2234 /* Decode the radio operation itself. */
2235 RF_Op* pOp = (RF_Op*)pNextCmd->pOp;
2236
2237 /* Invoke global callback to indicate start of command chain */
2238 RF_invokeGlobalCallback(RF_GlobalEventCmdStart, (void*)pNextCmd);
2239
2240 /* Send the radio operation to the RF core. */
2241 RFCDoorbellSendTo((uint32_t)pOp);
2242
2243 /* If the command is a new setup command, notify the board file. */
2244 if (RF_isRadioSetup(pOp))
2245 {
2246 /* Invoke the global callback if the setup command changed. This is needed to
2247 adjust the front-end configuration according to the new PHY. */
2248 RF_invokeGlobalCallback(RF_GlobalEventRadioSetup, (void*)pOp);
2249 }
2250
2251 /* Check the pending queue for any foreground command (IEEE 15.4 mode) */
2252 SwiP_or(&RF_swiFsmObj, RF_FsmEventRunScheduler);
2253 }
2254 }
2255 }
2256 }
2257
2258 /*
2259 * Check if there was an error with the synth while running CMD_FS
2260 * error callback is not issued in this function.
2261 *
2262 * Input: none
2263 * Return: true - If there was an error.
2264 * false - If there was no error.
2265 */
RF_checkCmdFsError(void)2266 static bool RF_checkCmdFsError(void)
2267 {
2268 /* Take the handle of the current client */
2269 RF_Handle pObj = RF_currClient;
2270
2271 /* Find the FS command stored in the context of the client */
2272 RF_Op *tmp1 = (RF_Op*)&pObj->clientConfig.pRadioSetup->prop;
2273 while (tmp1->pNextOp && tmp1->pNextOp != (RF_Op*)&pObj->state.mode_state.cmdFs)
2274 {
2275 tmp1 = tmp1->pNextOp;
2276 }
2277
2278 /* Evaluate if the FS command succeeded */
2279 if ((tmp1->condition.rule == COND_ALWAYS) &&
2280 (pObj->state.mode_state.cmdFs.status == ERROR_SYNTH_PROG))
2281 {
2282 /* CMD_FS completed with error so return true */
2283 return(true);
2284 }
2285 else
2286 {
2287 /* There is no synth error so return false */
2288 return(false);
2289 }
2290 }
2291
2292 /*
2293 * RF HW ISR when radio is active.
2294 *
2295 * Input: a - Not used.
2296 * Return: none
2297 */
RF_hwiHw(uintptr_t a)2298 static void RF_hwiHw(uintptr_t a)
2299 {
2300 /* Prepare a direct command */
2301 RF_Cmd* pCmd = RF_cmdQ.pCurrCmdBg;
2302
2303 /* Read and clear the interrupt flags */
2304 uint32_t rfchwifg = RFCHwIntGetAndClear(RF_HW_INT_CPE_MASK | RF_HW_INT_RAT_CH_MASK);
2305 uint32_t rfchwien = HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFHWIEN) & RF_HW_INT_CPE_MASK;
2306 uint32_t rathwien = HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFHWIEN) & RF_HW_INT_RAT_CH_MASK;
2307
2308 if (rfchwifg & rfchwien)
2309 {
2310 /* Post SWI_FSM if MODEM_SOFT event occured and the interrupt was enabled */
2311 if (pCmd)
2312 {
2313 /* Store the command which callback need to be served */
2314 RF_cmdQ.pCurrCmdCb = pCmd;
2315
2316 /* Decode the event numeber. */
2317 RF_EventMask events = ((RF_EventMask)(rfchwifg & rfchwien) << RF_SHIFT_32_BITS);
2318
2319 /* Store the events within the context of the command for the callback. */
2320 RF_cmdStoreEvents(pCmd, events);
2321
2322 /* Trig the state machine to handle this event */
2323 SwiP_or(&RF_swiFsmObj, RF_FsmEventCpeInt);
2324 }
2325 }
2326
2327 /* Post the SWI_HW if any RAT channel event occured */
2328 if (rfchwifg & rathwien)
2329 {
2330 /* Store the channel which cause the interrupt */
2331 RF_ratModule.pendingInt |= (rfchwifg & rathwien) >> RFC_DBELL_RFHWIFG_RATCH5_BITN;
2332
2333 /* Post the swi to handle its callback */
2334 SwiP_or(&RF_swiHwObj, 0);
2335 }
2336 }
2337
2338 /*
2339 * Software interrupt handler which servers Radio Timer (RAT) related events.
2340 *
2341 * Input: a - Generic argument. Not used.
2342 * b - Generic argument. Not used.
2343 * Return: none
2344 */
RF_swiHw(uintptr_t a,uintptr_t b)2345 static void RF_swiHw(uintptr_t a, uintptr_t b)
2346 {
2347 /* Local variable */
2348 bool error = false;
2349
2350 /* If the interrupt was trigged due to one of the RAT channels. */
2351 if (RF_ratModule.pendingInt)
2352 {
2353 /* Process lower channel first and allow multiple interrupt flags to be processed sequentially. */
2354 uint32_t i;
2355 for(i = 0; i < RF_RAT_CH_CNT; i++)
2356 {
2357 if (RF_ratModule.pendingInt & (RF_RAT_INTERRUPT_BASE_INDEX << i))
2358 {
2359 /* If there is also a bit indicating that the interrupt is due to an error. */
2360 if (RF_ratModule.pendingInt & (RF_RAT_ERROR_BASE_INDEX << i))
2361 {
2362 error = true;
2363 }
2364
2365 /* Enter critical section. */
2366 uint32_t key= HwiP_disable();
2367
2368 /* Atomic read-modify-write instruction of the interrupt flags.
2369 Knowing that this is the only place when such a flag can be cleared, it is safe to only guard this
2370 operation. Additional flags (which have been raised in the meantime) will be reserved and served in the
2371 next iteration. */
2372 RF_ratModule.pendingInt &= ~((RF_RAT_INTERRUPT_BASE_INDEX | RF_RAT_ERROR_BASE_INDEX) << i);
2373
2374 /* Exit critical section. */
2375 HwiP_restore(key);
2376
2377 /* Convert the channel index to a pointer of rat configuration. */
2378 RF_RatChannel* ratCh = RF_ratGetChannel(i);
2379
2380 /* Serve the interrupt if it is from an active channel. This is to avoid decoding function
2381 pointers from invalid containers due to fantom interrupts. */
2382 if (ratCh && ratCh->status)
2383 {
2384 /* Read the channel counter from the RAT timer. In capture mode this is the captured value,
2385 in compare mode this is the compare timestamp.*/
2386 uint32_t compareCaptureValue = RF_ratGetChannelValue(ratCh->handle);
2387
2388 /* Temporarily store the callback handler and the channel offset.
2389 This is necessary in order to be able to free and reallocate the
2390 same channel within the context of the callback itself. */
2391 RF_Handle ratClient = (RF_Handle) ratCh->pClient;
2392 RF_RatHandle ratHandle = (RF_CmdHandle) ratCh->handle;
2393 RF_RatCallback ratCallback = (RF_RatCallback) ratCh->pCb;
2394
2395 /* Only free the channel if it is NOT in repeated capture mode, or an error occured. */
2396 if (error || !(ratCh->mode == RF_RatModeCapture) || !(ratCh->chCmd & RF_RAT_CAPTURE_REPEAT_MODE))
2397 {
2398 /* Free RAT channel. If this is the last channel, it might delay with 1 LF edge to
2399 calculate the next wake up event. */
2400 RF_ratFreeChannel(ratCh);
2401 }
2402
2403 /* Serve the user callback with Error or Compare/Capture Event. */
2404 if (error)
2405 {
2406 ratCallback(ratClient, ratHandle, RF_EventError, 0);
2407 }
2408 else
2409 {
2410 ratCallback(ratClient, ratHandle, RF_EventRatCh, compareCaptureValue);
2411 }
2412 }
2413
2414 /* Only serve one channel at a time. */
2415 break;
2416 }
2417 }
2418 }
2419
2420 /* Repost the SWI again if multiple interrupt flags are still set. */
2421 if (RF_ratModule.pendingInt)
2422 {
2423 SwiP_or(&RF_swiHwObj, 0);
2424 }
2425 }
2426
2427 /*
2428 * RF CPE0 ISR when radio is active. Assume that all IRQs relevant to command
2429 * dispatcher are mapped here. Furthermore, assume that there is no need for
2430 * critical sections here (i.e. that this ISR has higher priority than
2431 * any HWI calling a RF API function or that HWIs can't call the RF API).
2432 *
2433 * Input: a - Not used.
2434 * Return: none
2435 */
RF_hwiCpe0Active(uintptr_t a)2436 static void RF_hwiCpe0Active(uintptr_t a)
2437 {
2438 /* Local variables. */
2439 RF_Cmd* volatile* ppActiveCmd = NULL;
2440 RF_Cmd* volatile* activeCmd[2] = {&RF_cmdQ.pCurrCmdBg, &RF_cmdQ.pCurrCmdFg};
2441 uint32_t rfcpeifgMask = 0;
2442 uint32_t rfcpeifg = 0;
2443 uint32_t nextEvent = 0;
2444
2445 /* Handle PA switching. */
2446 if (RFCCpeIntGetAndClear(RF_EventPaChanged))
2447 {
2448 /* The PA was changed during a chain of radio operation. We need to extract the current configuration
2449 and propagate it back to the setup command. This is to reserve the change after power cycle. */
2450 RF_extractPaConfiguration(RF_currClient);
2451
2452 /* Invoke the board file to reconfigure the external front-end configuration. */
2453 RF_invokeGlobalCallback(RF_GlobalEventRadioSetup, (void*) RF_currClient->clientConfig.pRadioSetup);
2454 }
2455
2456 /* Iterate through the possible active commands. */
2457 uint32_t i;
2458 for(i = 0; i < sizeof(activeCmd)/sizeof(uint32_t); i++)
2459 {
2460 /* Decode the active command. */
2461 ppActiveCmd = activeCmd[i];
2462
2463 /* If there was a command running (handles both foreground and background context). */
2464 if (*ppActiveCmd)
2465 {
2466 /* Decode the events the active command subscribed to. */
2467 rfcpeifgMask = (*ppActiveCmd)->bmEvent;
2468
2469 /* Read the interrupt flags which belong to the active command (including the mandatory termination events). */
2470 rfcpeifg = RFCCpeIntGetAndClear(rfcpeifgMask);
2471
2472 /* Save the events happened and to be passed to the callback. */
2473 RF_cmdStoreEvents((*ppActiveCmd), rfcpeifg);
2474
2475 /* Look for termination events. */
2476 if (rfcpeifg & (RFC_DBELL_RFCPEIFG_LAST_FG_COMMAND_DONE_M | RFC_DBELL_RFCPEIFG_LAST_COMMAND_DONE_M))
2477 {
2478 /* Disable interrupt sources which were subsribed by the command. Since the LAST_CMD_DONE is
2479 is shared with the state machine, it cannot be disabled. */
2480 RFCCpeIntDisable((uint32_t)((*ppActiveCmd)->bmEvent & ~(RFC_DBELL_RFCPEIFG_LAST_COMMAND_DONE_M | RFC_DBELL_RFCPEIEN_IRQ14_M)));
2481 RFCHwIntDisable((uint32_t) ((*ppActiveCmd)->bmEvent >> RF_SHIFT_32_BITS));
2482
2483 /* Invoke global callback to indicate end of command chain */
2484 RF_invokeGlobalCallback(RF_GlobalEventCmdStop, (void*)(*ppActiveCmd));
2485
2486 /* Move active command to done queue. */
2487 List_put(&RF_cmdQ.pDone, (List_Elem*)(*ppActiveCmd));
2488
2489 /* Retire the command, it is not running anymore. */
2490 (*ppActiveCmd) = NULL;
2491
2492 /* We will invoke the callback and deallocate the command. */
2493 nextEvent |= RF_FsmEventLastCommandDone;
2494 }
2495 else if (rfcpeifg)
2496 {
2497 /* The interrupt is just an ordinary event without termination. */
2498 RF_cmdQ.pCurrCmdCb = (*ppActiveCmd);
2499
2500 /* We will just invoke the callback. */
2501 nextEvent |= RF_FsmEventCpeInt;
2502 }
2503 }
2504 }
2505
2506 /* Post SWI to handle registered callbacks if there is any. */
2507 if (nextEvent)
2508 {
2509 SwiP_or(&RF_swiFsmObj, nextEvent);
2510 }
2511
2512 /* Restart pending rat channels. */
2513 RF_ratRestartChannels();
2514
2515 /* Dispatch the next pending command if exists. */
2516 RF_dispatchNextCmd();
2517 }
2518
2519 /*
2520 * Temperature limit notification function.
2521 */
RF_hposcRfCompensateFxn(int16_t currentTemperature,int16_t thresholdTemperature,uintptr_t clientArg,Temperature_NotifyObj * NotifyObj)2522 static void RF_hposcRfCompensateFxn(int16_t currentTemperature,
2523 int16_t thresholdTemperature,
2524 uintptr_t clientArg,
2525 Temperature_NotifyObj *NotifyObj)
2526 {
2527 int32_t relFreqOffset;
2528 int16_t relFreqOffsetConverted;
2529 int_fast16_t status;
2530
2531 /* Check if HPOSC frequency offset has changed */
2532 relFreqOffset = OSC_HPOSCRelativeFrequencyOffsetGet(currentTemperature);
2533 if (relFreqOffset != RF_currentHposcFreqOffset)
2534 {
2535 /* Frequency offset has changed. Compensation is required */
2536 RF_currentHposcFreqOffset = relFreqOffset;
2537 relFreqOffsetConverted = OSC_HPOSCRelativeFrequencyOffsetToRFCoreFormatConvert(relFreqOffset);
2538
2539 /* Check if radio is powered */
2540 if ((RF_core.status == RF_CoreStatusActive) || (RF_core.status == RF_CoreStatusPhySwitching))
2541 {
2542 /* Radio is powered. Check if any actively running command */
2543 if (RF_cmdQ.pCurrCmdBg || RF_cmdQ.pCurrCmdFg)
2544 {
2545 /* Command is running. Abort command and assure that both RF_EventCmdAborted and RF_EventCmdPreemptrf events are set */
2546 RF_abortCmd(RF_cmdQ.pCurrCmdBg->pClient, RF_cmdQ.pCurrCmdBg->ch, false, false, true);
2547 }
2548
2549 /* Update RFCore with the HPOSC frequency offset */
2550 RF_runDirectImmediateCmd(RF_currClient, CMDR_DIR_CMD_2BYTE(CMD_UPDATE_HPOSC_FREQ, relFreqOffsetConverted), NULL);
2551 }
2552 }
2553
2554 /* Register the notification again with updated thresholds */
2555 status = Temperature_registerNotifyRange(NotifyObj,
2556 currentTemperature + RF_TEMP_LIMIT_3_DEGREES_CELSIUS,
2557 currentTemperature - RF_TEMP_LIMIT_3_DEGREES_CELSIUS,
2558 RF_hposcRfCompensateFxn,
2559 (uintptr_t)NULL);
2560
2561 if (status != Temperature_STATUS_SUCCESS) {
2562 while(1);
2563 }
2564 }
2565
2566 /*
2567 * Clock callback due to inactivity timeout.
2568 *
2569 * Input: pObj - Not used.
2570 * Return: none
2571 */
RF_clkInactivityCallback(uintptr_t a)2572 static void RF_clkInactivityCallback(uintptr_t a)
2573 {
2574 /* If there are no pending commands in the queue */
2575 if (RF_cmdQ.nSeqPost == RF_cmdQ.nSeqDone)
2576 {
2577 /* Release the constraint on the command queue and if nothing prevents, power down the radio */
2578 RF_powerConstraintRelease(RF_PowerConstraintCmdQ);
2579 }
2580 }
2581
2582 /*
2583 * Clock callback due to request access timeout.
2584 *
2585 * Input: a - Not used.
2586 * Return: none
2587 */
RF_clkReqAccess(uintptr_t a)2588 static void RF_clkReqAccess(uintptr_t a)
2589 {
2590 RF_issueRadioFreeCb(RF_RADIOFREECB_REQACCESS_FLAG |
2591 RF_RADIOFREECB_PREEMPT_FLAG |
2592 RF_RADIOFREECB_CMDREJECT_FLAG);
2593 }
2594
2595 /*
2596 * Callback used to post semaphore for runCmd() and pendCmd().
2597 *
2598 * Input: h - Handle to the client.
2599 * ch - Handle to the command which callback to be invoked.
2600 * e - Events causing the function call.
2601 * Return: none
2602 */
RF_syncCb(RF_Handle h,RF_CmdHandle ch,RF_EventMask e)2603 static void RF_syncCb(RF_Handle h, RF_CmdHandle ch, RF_EventMask e)
2604 {
2605 /* Local variables */
2606 RF_Cmd* pCmd;
2607
2608 /* If there is a user callback provided. */
2609 if (h->state.pCbSync)
2610 {
2611 /* Invoke the user callback with the events fired. */
2612 ((RF_Callback)h->state.pCbSync)(h, ch, e);
2613 }
2614
2615 /* Mask the possible causes of releasing the semaphore */
2616 RF_EventMask maskedEvents = (e & h->state.eventSync);
2617
2618 /* Release the semaphore on any of the reasons: last command done,
2619 subscribed event happened, last FG command is done in IEEE mode */
2620 if (maskedEvents)
2621 {
2622 /* Find the command. We do it here within the SWI context. */
2623 pCmd = RF_cmdGet(h, ch, RF_CMD_ALLOC_FLAG);
2624
2625 /* Store the events in the context of the client */
2626 h->state.unpendCause = maskedEvents;
2627
2628 /* Find the command. We do it here within the SWI context. */
2629 if (pCmd)
2630 {
2631 /* Clear the handled past events so it is possible to pend again */
2632 pCmd->pastifg &= ~h->state.unpendCause;
2633
2634 /* Exhange the callback function: use the user callback from this point */
2635 pCmd->pCb = (RF_Callback)h->state.pCbSync;
2636 }
2637
2638 /* Clear temporary storage of user callback (it was restored and served at this point) */
2639 h->state.pCbSync = NULL;
2640
2641 /* Post the semaphore to release the RF_pendCmd() */
2642 SemaphoreP_post(&h->state.semSync);
2643 }
2644 }
2645
2646 /*
2647 * Invoke the global callback registered through the RFCC26XX_hwAttrs.
2648 *
2649 * Input: e - Events causing the function call.
2650 * Return: none
2651 */
RF_invokeGlobalCallback(RF_GlobalEvent event,void * arg)2652 static void RF_invokeGlobalCallback(RF_GlobalEvent event, void* arg)
2653 {
2654 /* Decode the global callback and it's mask from the board file. */
2655 RF_GlobalCallback callback = RFCC26XX_hwAttrs.globalCallback;
2656 RF_GlobalEventMask eventMask = RFCC26XX_hwAttrs.globalEventMask;
2657
2658 /* If the board has subscribed to this event, invoke the callback. */
2659 if (callback && (eventMask & event))
2660 {
2661 callback(RF_currClient, event, arg);
2662 }
2663 }
2664
2665 /*
2666 * Default callback function.
2667 *
2668 * Input: h - Handle to the client.
2669 * ch - Handle to the command which callback to be invoked.
2670 * e - Events causing the function call.
2671 * Return: none
2672 */
RF_defaultCallback(RF_Handle h,RF_CmdHandle ch,RF_EventMask e)2673 static void RF_defaultCallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e)
2674 {
2675 /* Do nothing */;
2676 }
2677
2678 /*-------------- RF powerup/powerdown FSM functions ---------------*/
2679
2680 /*
2681 * The SWI handler for FSM events.
2682 *
2683 * Input: a0 - Not used.
2684 * a1 - Not used.
2685 * Return: none
2686 */
RF_swiFsm(uintptr_t a0,uintptr_t a1)2687 static void RF_swiFsm(uintptr_t a0, uintptr_t a1)
2688 {
2689 RF_core.fxn(RF_currClient, (RF_FsmEvent)SwiP_getTrigger());
2690 }
2691
2692 /*
2693 * Clock callback called upon powerup.
2694 *
2695 * Input: a - Not used.
2696 * Return: none
2697 */
RF_clkPowerUp(uintptr_t a)2698 static void RF_clkPowerUp(uintptr_t a)
2699 {
2700 if (RF_core.fxn == RF_fsmActiveState)
2701 {
2702 /* Dispatch the next RF core event. */
2703 RF_dispatchNextEvent();
2704 }
2705 else
2706 {
2707 /* Trigger FSM SWI to start the wake up sequence of the radio.
2708 This is important when we poll the XOSC_HF. */
2709 SwiP_or(&RF_swiFsmObj, RF_FsmEventWakeup);
2710 }
2711 }
2712
2713 /*
2714 * RF CPE0 ISR during FSM powerup/powerdown.
2715 *
2716 * Input: a0 - Not used.
2717 * Return: none
2718 */
RF_hwiCpe0PowerFsm(uintptr_t a0)2719 static void RF_hwiCpe0PowerFsm(uintptr_t a0)
2720 {
2721 /* Read all IRQ flags in doorbell and then clear them */
2722 uint32_t rfcpeifg = RFCCpeIntGetAndClear(RF_CPE0_INT_MASK);
2723
2724 /* If the radio is active */
2725 if (RF_core.fxn == RF_fsmActiveState)
2726 {
2727 /* Change HWI handler to the correct one */
2728 HwiP_setFunc(&RF_hwiCpe0Obj, RF_hwiCpe0Active, (uintptr_t)NULL);
2729
2730 /* Mark radio and client as being active */
2731 RF_core.status = RF_CoreStatusActive;
2732
2733 /* No synth error */
2734 if (!RF_checkCmdFsError())
2735 {
2736 /* Restart pending rat channels. */
2737 RF_ratRestartChannels();
2738
2739 /* Dispatch the next command */
2740 RF_dispatchNextCmd();
2741 }
2742 }
2743
2744 /* Handle special events as boot, etc */
2745 if (rfcpeifg & (RFC_DBELL_RFCPEIFG_BOOT_DONE_M | RFC_DBELL_RFCPEIFG_LAST_COMMAND_DONE_M))
2746 {
2747 SwiP_or(&RF_swiFsmObj, RF_FsmEventPowerStep);
2748 }
2749 }
2750
2751 /*
2752 * RF CPE0 ISR during Change PHY switching.
2753 *
2754 * Input: a0 - Not used.
2755 * Return: none
2756 */
RF_hwiCpe0ChangePhy(uintptr_t a0)2757 static void RF_hwiCpe0ChangePhy(uintptr_t a0)
2758 {
2759 /* Clear all IRQ flags in doorbell and then clear them */
2760 uint32_t rfcpeifg = RFCCpeIntGetAndClear(RF_CPE0_INT_MASK);
2761
2762 if (rfcpeifg & IRQ_LAST_COMMAND_DONE)
2763 {
2764 /* Proceed to the second phase of the phy switching process */
2765 SwiP_or(&RF_swiFsmObj, RF_FsmEventFinishChangePhy);
2766 }
2767 }
2768
2769 /*-------------- Power management state functions ---------------*/
2770 /*
2771 * Handles RF Core patching for CPE, MCE, RFE (if required) in setup state during power-up.
2772 *
2773 * Input: mode - RF_PHY_BOOTUP_MODE: First boot of the RF core.
2774 * - RF_PHY_SWITCHING_MODE: Switching between two phys.
2775 * Return: none
2776 */
RF_applyRfCorePatch(bool mode)2777 static void RF_applyRfCorePatch(bool mode)
2778 {
2779 /* Local reference to the patches. */
2780 void (*cpePatchFxn)(void) = RF_currClient->clientConfig.pRfMode->cpePatchFxn;
2781 void (*mcePatchFxn)(void) = RF_currClient->clientConfig.pRfMode->mcePatchFxn;
2782 void (*rfePatchFxn)(void) = RF_currClient->clientConfig.pRfMode->rfePatchFxn;
2783
2784 if (mode == RF_PHY_SWITCHING_MODE)
2785 {
2786 /* If patches are provided, enable RFE and MCE clocks. */
2787 if ((mcePatchFxn != NULL) || (rfePatchFxn != NULL))
2788 {
2789 RF_dbellSubmitCmdAsync((uint32_t)CMDR_DIR_CMD_2BYTE(RF_CMD0, RFC_PWR_PWMCLKEN_MDMRAM | RFC_PWR_PWMCLKEN_RFERAM));
2790 }
2791
2792 /* Clear the previous patch. */
2793 if (cpePatchFxn != NULL)
2794 {
2795 RFCCpePatchReset();
2796 }
2797 }
2798
2799 /* Load the patches if relevant for this phy. */
2800 if (cpePatchFxn != NULL)
2801 {
2802 if (mode == RF_PHY_BOOTUP_MODE)
2803 {
2804 cpePatchFxn();
2805 }
2806 }
2807
2808 if ((mcePatchFxn != NULL) || (rfePatchFxn != NULL))
2809 {
2810 /* Wait for clocks to be turned ON */
2811 RF_dbellSyncOnAck();
2812
2813 /* Patch MCE if relevant */
2814 if (mcePatchFxn != NULL)
2815 {
2816 mcePatchFxn();
2817 }
2818
2819 /* Patch RFE if relevant */
2820 if (rfePatchFxn != NULL)
2821 {
2822 rfePatchFxn();
2823 }
2824
2825 /* Turn off additional clocks */
2826 RFCDoorbellSendTo(CMDR_DIR_CMD_2BYTE(RF_CMD0, 0));
2827 }
2828 }
2829
2830 /*
2831 * Arms the inactivity timer and hence postpones the decision whether
2832 * power management shall take place or not.
2833 *
2834 * Input: none
2835 * Return: none
2836 */
RF_setInactivityTimeout(void)2837 static void RF_setInactivityTimeout(void)
2838 {
2839 /* Local variables to be used to find the correct timeout value. */
2840 uint32_t inactivityTimeUsA = 0;
2841 uint32_t inactivityTimeUsB = 0;
2842 RF_Handle handleA = RF_Sch.clientHnd[0];
2843 RF_Handle handleB = RF_Sch.clientHnd[1];
2844
2845 /* Issue radio free callback after pre-emption if required */
2846 uint8_t tmp = RF_RADIOFREECB_PREEMPT_FLAG | RF_RADIOFREECB_CMDREJECT_FLAG;
2847
2848 /* If the radio was yielded, add the flag */
2849 if (RF_currClient->state.bYielded)
2850 {
2851 tmp |= RF_RADIOFREECB_REQACCESS_FLAG;
2852 }
2853
2854 /* Call the radio free callback */
2855 RF_issueRadioFreeCb(tmp);
2856
2857 if (handleA)
2858 {
2859 if (handleA->state.bYielded == false)
2860 {
2861 inactivityTimeUsA = handleA->clientConfig.nInactivityTimeout;
2862 }
2863 handleA->state.bYielded = false;
2864 }
2865
2866 if (handleB)
2867 {
2868 if (handleB->state.bYielded == false)
2869 {
2870 inactivityTimeUsB = handleB->clientConfig.nInactivityTimeout;
2871 }
2872 handleB->state.bYielded = false;
2873 }
2874
2875 /* Set the inactivity time to the max between the two clients */
2876 uint32_t inactivityTimeUs = MAX(inactivityTimeUsA, inactivityTimeUsB);
2877
2878 /* If immediate power down is reuqested */
2879 if (inactivityTimeUs == SemaphoreP_NO_WAIT)
2880 {
2881 /* We can powerdown immediately */
2882 RF_clkInactivityCallback((uintptr_t)NULL);
2883 }
2884 else if (inactivityTimeUs != SemaphoreP_WAIT_FOREVER)
2885 {
2886 /* Reprogram and start inactivity timer */
2887 RF_restartClockTimeout(&RF_clkInactivityObj, inactivityTimeUs/ClockP_getSystemTickPeriod());
2888 }
2889 }
2890
2891
2892 /*
2893 * Handle callback to client for RF_EventLastCmdDone and issue radio free callback if required.
2894 *
2895 * Input: none
2896 * Return: none
2897 */
RF_radioOpDoneCb(void)2898 static void RF_radioOpDoneCb(void)
2899 {
2900 /* Serve the first entry in the done queue */
2901 RF_Cmd* pCmd = (RF_Cmd*)List_head(&RF_cmdQ.pDone);
2902
2903 /* Radio command done */
2904 if (pCmd)
2905 {
2906 /* Update implicit radio state (chained FS command if any) */
2907 RF_cacheFsCmd(pCmd);
2908
2909 /* Read and clear the events */
2910 RF_EventMask events = pCmd->rfifg;
2911 pCmd->rfifg = 0;
2912
2913 /* Issue callback, free container and dequeue */
2914 if (pCmd->pCb)
2915 {
2916 /* If any of the cancel events are set, mask out the other events. */
2917 RF_EventMask abortMask = (RF_EventCmdCancelled
2918 | RF_EventCmdAborted
2919 | RF_EventCmdStopped
2920 | RF_EventCmdPreempted);
2921
2922 /* Mask out the other events if any of the above is set. */
2923 if (events & abortMask)
2924 {
2925 RF_EventMask nonTerminatingEvents = events & ~(abortMask | RF_EventCmdDone | RF_EventLastCmdDone |
2926 RF_EventLastFGCmdDone | RF_EventFGCmdDone);
2927 if (nonTerminatingEvents)
2928 {
2929 /* Invoke the user callback with any pending non-terminating events, since bare abort will follow */
2930 pCmd->pCb(pCmd->pClient, pCmd->ch, nonTerminatingEvents);
2931 }
2932
2933 /* Mask out the other events if any of the above is set. */
2934 events &= abortMask;
2935 }
2936
2937 /* Invoke the user callback */
2938 pCmd->pCb(pCmd->pClient, pCmd->ch, events);
2939 }
2940
2941 /* Enter critical section */
2942 uint32_t key = HwiP_disable();
2943
2944 /* Update num of radio command done */
2945 RF_cmdQ.nSeqDone = (RF_cmdQ.nSeqDone+1) & N_CMD_MODMASK;
2946
2947 /* Commmand completed reset command flags */
2948 pCmd->flags = 0;
2949
2950 /* Invalidate the command handle. This is to avoid having duplicate
2951 handles in the pool. */
2952 pCmd->ch = RF_SCHEDULE_CMD_ERROR;
2953
2954 /* Command completed, free command queue container */
2955 List_get(&RF_cmdQ.pDone);
2956
2957 /* Exit critical section */
2958 HwiP_restore(key);
2959
2960 /* Check if there are any more pending commands */
2961 if (RF_cmdQ.nSeqDone == RF_cmdQ.nSeqPost)
2962 {
2963 RF_setInactivityTimeout();
2964 }
2965 }
2966 }
2967
2968 /*
2969 * Verify if reconiguring or powering down the radio is allowed.
2970 *
2971 * Input: none
2972 * Return: none
2973 */
RF_isStateTransitionAllowed(void)2974 static bool RF_isStateTransitionAllowed(void)
2975 {
2976 /* Local variable. */
2977 bool status = false;
2978
2979 /* If we are not performing RF core state changes. */
2980 if (RF_core.status == RF_CoreStatusActive)
2981 {
2982 if(RF_cmdQ.pCurrCmdBg == NULL &&
2983 RF_cmdQ.pCurrCmdFg == NULL)
2984 {
2985 status = true;
2986 }
2987 }
2988
2989 /* Return with the decision. */
2990 return(status);
2991 }
2992
2993 /*
2994 * RF state machine function during power up state.
2995 *
2996 * Input: pObj - Pointer to RF object.
2997 * e - State machine event.
2998 * Return: none
2999 */
RF_fsmPowerUpState(RF_Object * pObj,RF_FsmEvent e)3000 static void RF_fsmPowerUpState(RF_Object *pObj, RF_FsmEvent e)
3001 {
3002 /* Note: pObj is NULL in this state */
3003 if (e & RF_FsmEventLastCommandDone)
3004 {
3005 /* Invoke the user provided callback function */
3006 RF_radioOpDoneCb();
3007
3008 /* Retrig the SWI if there are more commands in the done queue. */
3009 if (List_head(&RF_cmdQ.pDone))
3010 {
3011 /* Trigger self if there are more commands in callback queue */
3012 SwiP_or(&RF_swiFsmObj, (e | RF_FsmEventLastCommandDone));
3013 }
3014 else
3015 {
3016 /* We've handled this event now */
3017 e &= ~RF_FsmEventLastCommandDone;
3018
3019 /* Schedule the next event based on the state of the command queue
3020 and the RAT module. */
3021 RF_dispatchNextEvent();
3022 }
3023 }
3024 else if (e & RF_FsmEventWakeup)
3025 {
3026 /* Notify the power driver that FLASH is needed in IDLE */
3027 bDisableFlashInIdleConstraint = true;
3028 Power_setConstraint(PowerCC26XX_NEED_FLASH_IN_IDLE);
3029
3030 /* Store the current RTC tick for nPowerUpDuration calculation */
3031 RF_rtcTimestampA = AONRTCCurrent64BitValueGet();
3032
3033 /* Set current client from first command in command queue */
3034 RF_Cmd* pNextCmd = (RF_Cmd*)List_head(&RF_cmdQ.pPend);
3035 if (pNextCmd)
3036 {
3037 RF_Object* pNextClient = pNextCmd->pClient;
3038
3039 /* If the next command belongs to another client, initiate PHY switching */
3040 if ((RF_currClient) && (RF_currClient != pNextClient))
3041 {
3042 /* Invoke the client switch callback if it was provided */
3043 if (pNextClient->clientConfig.nClientEventMask & RF_ClientEventSwitchClientEntered)
3044 {
3045 RF_ClientCallback pClientEventCb = (RF_ClientCallback)pNextClient->clientConfig.pClientEventCb;
3046 pClientEventCb(pNextClient, RF_ClientEventSwitchClientEntered, NULL);
3047 }
3048
3049 /* Due to client switching, update the analogCfg field of setup command. */
3050 pNextClient->clientConfig.bUpdateSetup = true;
3051 }
3052
3053 /* Set the current client to be the next client */
3054 RF_currClient = pNextClient;
3055 }
3056
3057 /* Set the RF mode in the PRCM register (RF_open already verified that it is valid) */
3058 HWREG(PRCM_BASE + PRCM_O_RFCMODESEL) = RF_currClient->clientConfig.pRfMode->rfMode;
3059
3060 /* Notiy the power driver that Standby is not allowed and RF core need to be powered */
3061 Power_setConstraint(PowerCC26XX_DISALLOW_STANDBY);
3062 Power_setDependency(PowerCC26XX_DOMAIN_RFCORE);
3063
3064 /* Indicate that the power-up sequence is being started */
3065 RF_core.status = RF_CoreStatusPoweringUp;
3066
3067 /* If the configuration on board level requires to set the dependency every time. */
3068 if (RFCC26XX_hwAttrs.xoscHfAlwaysNeeded == false)
3069 {
3070 Power_setDependency(PowerCC26XX_XOSC_HF);
3071 }
3072
3073 /* If there are RFE and MCE patches, turn on their clocks */
3074 if ((RF_currClient->clientConfig.pRfMode->mcePatchFxn != NULL) ||
3075 (RF_currClient->clientConfig.pRfMode->rfePatchFxn != NULL))
3076 {
3077 RF_dbellSubmitCmdAsync((uint32_t)CMDR_DIR_CMD_2BYTE(RF_CMD0, RFC_PWR_PWMCLKEN_MDMRAM | RFC_PWR_PWMCLKEN_RFERAM));
3078 }
3079
3080 /* Turn on the clock to the RF core. Registers can be accessed afterwards. */
3081 RFCClockEnable();
3082
3083 /* Reconfigure the CPE interrupt lines to a start up value on a controlled way. */
3084 RFCCpeIntDisable(RF_CPE0_INT_MASK);
3085 RFCCpe0IntSelect(RF_CPE0_INT_MASK);
3086
3087 /* Enable some of the interrupt sources. */
3088 RFCCpeIntEnable(RFC_DBELL_RFCPEIEN_BOOT_DONE_M
3089 | RFC_DBELL_RFCPEIEN_LAST_COMMAND_DONE_M
3090 | RFC_DBELL_RFCPEIEN_IRQ14_M);
3091
3092 /* Set the next state. */
3093 RF_core.fxn = RF_fsmSetupState;
3094
3095 /* Enable interrupts: continue when boot is done */
3096 HwiP_enableInterrupt(INT_RFC_HW_COMB);
3097 HwiP_enableInterrupt(INT_RFC_CPE_0);
3098 }
3099 }
3100
3101 /*
3102 * RF state machine function during setup state.
3103 *
3104 * Input: pObj - Pointer to RF object.
3105 * e - State machine event.
3106 * Return: none
3107 */
RF_fsmSetupState(RF_Object * pObj,RF_FsmEvent e)3108 static void RF_fsmSetupState(RF_Object *pObj, RF_FsmEvent e)
3109 {
3110 if (e & RF_FsmEventPowerStep)
3111 {
3112 /* Apply RF Core patches (if required) */
3113 RF_applyRfCorePatch(RF_PHY_BOOTUP_MODE);
3114
3115 /* Initialize system bus request */
3116 RF_dbellSubmitCmdAsync((uint32_t)CMDR_DIR_CMD_1BYTE(CMD_BUS_REQUEST, 1));
3117
3118 /* Configure the RAT_SYNC command which will follow SETUP command */
3119 RF_ratSyncCmd.start.commandNo = CMD_SYNC_START_RAT;
3120 RF_ratSyncCmd.start.status = IDLE;
3121 RF_ratSyncCmd.start.startTrigger.triggerType = TRIG_NOW;
3122 RF_ratSyncCmd.start.pNextOp = NULL;
3123 RF_ratSyncCmd.start.condition.rule = COND_NEVER;
3124
3125 /* Init the content of setup command. */
3126 RF_initRadioSetup(pObj);
3127
3128 /* Configure the SETUP command. */
3129 RF_RadioSetup* pRadioSetup = pObj->clientConfig.pRadioSetup;
3130
3131 /* Search for specific commands in the command chain. */
3132 RF_Op* tmp = (RF_Op*)&pRadioSetup->prop;
3133 while ((tmp->pNextOp) && (tmp->pNextOp->commandNo != CMD_SYNC_START_RAT) &&
3134 (tmp->pNextOp->commandNo != CMD_FS) &&
3135 (tmp->pNextOp->commandNo != CMD_FS_OFF))
3136 {
3137 /* Trace to the end of chain */
3138 tmp = tmp->pNextOp;
3139 }
3140
3141 /* Add the CMD_RAT_SYNC to the end of chain */
3142 tmp->pNextOp = (RF_Op*)&RF_ratSyncCmd.start;
3143 tmp->condition.rule = COND_ALWAYS;
3144
3145 /* Setup FS command to follow SETUP command */
3146 RF_Cmd* pCmdFirstPend = (RF_Cmd*)List_head(&RF_cmdQ.pPend);
3147 if (pCmdFirstPend && ((pCmdFirstPend->pOp->commandNo == CMD_FS) || (pCmdFirstPend->pOp->commandNo == CMD_FS_OFF)))
3148 {
3149 /* First command is FS command so no need to chain an implicit FS command -> Reset nRtc1 */
3150 RF_rtcTimestampA = 0;
3151 }
3152 else
3153 {
3154 if (pObj->state.mode_state.cmdFs.commandNo)
3155 {
3156 /* Chain in the implicit FS command */
3157 rfc_CMD_FS_t* pOpFs = &pObj->state.mode_state.cmdFs;
3158 pOpFs->status = IDLE;
3159 pOpFs->pNextOp = NULL;
3160 pOpFs->startTrigger.triggerType = TRIG_NOW;
3161 pOpFs->condition.rule = COND_NEVER;
3162 RF_ratSyncCmd.start.pNextOp = (RF_Op*)pOpFs;
3163 RF_ratSyncCmd.start.condition.rule = COND_ALWAYS;
3164 }
3165 }
3166
3167 /* Make sure system bus request is done by now */
3168 RF_dbellSyncOnAck();
3169
3170 /* Set the next state. */
3171 RF_core.fxn = RF_fsmActiveState;
3172
3173 /* Run the XOSC_HF switching if the pre-notify function setup the power
3174 constraint PowerCC26XX_SWITCH_XOSC_HF_MANUALLY */
3175 if (RF_core.manualXoscHfSelect)
3176 {
3177 /* Wait until the XOSC_HF is stable */
3178 while (!PowerCC26XX_isStableXOSC_HF());
3179
3180 /* Invoke the XOSC_HF switching */
3181 PowerCC26XX_switchXOSC_HF();
3182 }
3183 else if (OSCClockSourceGet(OSC_SRC_CLK_HF) != OSC_XOSC_HF)
3184 {
3185 /* If the XOSC_HF is not ready yet, only execute the first hal of the chain*/
3186 tmp->condition.rule = COND_NEVER;
3187
3188 /* Next state: RF_fsmXOSCState (polling XOSC_HF)*/
3189 RF_core.fxn = RF_fsmXOSCState;
3190 }
3191
3192 /* Send the setup chain to the RF core */
3193 RF_dbellSubmitCmdAsync((uint32_t)pRadioSetup);
3194
3195 /* Invoke the global callback. */
3196 RF_invokeGlobalCallback(RF_GlobalEventRadioSetup, (void*)pRadioSetup);
3197 }
3198 }
3199
3200 /*
3201 * RF state machine function during XOSC state.
3202 *
3203 * Input: pObj - Pointer to RF object.
3204 * e - State machine event.
3205 * Return: none
3206 */
RF_fsmXOSCState(RF_Object * pObj,RF_FsmEvent e)3207 static void RF_fsmXOSCState(RF_Object *pObj, RF_FsmEvent e)
3208 {
3209 if ((e & RF_FsmEventPowerStep) || (e & RF_FsmEventWakeup))
3210 {
3211 /* If XOSC_HF is now ready */
3212 if (OSCClockSourceGet(OSC_SRC_CLK_HF) == OSC_XOSC_HF)
3213 {
3214 /* Next state: RF_fsmActiveState */
3215 RF_core.fxn = RF_fsmActiveState;
3216
3217 /* Continue with the CMD_RAT_SYNC and the rest of the chain. */
3218 RF_dbellSubmitCmdAsync((uint32_t)&RF_ratSyncCmd.start);
3219 }
3220 else
3221 {
3222 /* Clock source not yet switched to XOSC_HF: schedule new polling */
3223 RF_restartClockTimeout(&RF_clkPowerUpObj, RF_XOSC_HF_SWITCH_CHECK_PERIOD_US/ClockP_getSystemTickPeriod());
3224 }
3225 }
3226 }
3227
3228 /*
3229 * RF state machine function during active state.
3230 *
3231 * Input: pObj - Pointer to RF object.
3232 * e - State machine event.
3233 * Return: none
3234 */
RF_fsmActiveState(RF_Object * pObj,RF_FsmEvent e)3235 static void RF_fsmActiveState(RF_Object *pObj, RF_FsmEvent e)
3236 {
3237 volatile RF_Cmd* pCmd;
3238 uint32_t rtcValTmp1;
3239 uint32_t rtcValTmp2;
3240 RF_EventMask events;
3241 bool transitionAllowed;
3242 uint32_t key;
3243
3244 if (e & RF_FsmEventCpeInt)
3245 {
3246 /* Enter critical section */
3247 key = HwiP_disable();
3248
3249 /* Dereference the command which requested the callback*/
3250 pCmd = (RF_Cmd*)RF_cmdQ.pCurrCmdCb;
3251
3252 /* If this is due to other event than LastCmdDone */
3253 if (pCmd && !(pCmd->rfifg & RF_TERMINATION_EVENT_MASK))
3254 {
3255 /* Temporarily store the reason of callback */
3256 events = pCmd->rfifg;
3257
3258 /* Clear the events which are handled here */
3259 pCmd->rfifg &= (~events);
3260
3261 /* Exit critical section */
3262 HwiP_restore(key);
3263
3264 /* Invoke the user callback if it is provided */
3265 if (pCmd->pCb && events)
3266 {
3267 pCmd->pCb(pCmd->pClient, pCmd->ch, events);
3268 }
3269 }
3270 else
3271 {
3272 /* Exit critical section */
3273 HwiP_restore(key);
3274 }
3275
3276 /* We've handled this event now */
3277 e &= ~RF_FsmEventCpeInt;
3278 }
3279 /* Coming from powerup states */
3280 else if (e & RF_FsmEventPowerStep)
3281 {
3282 /* RF core boot process is now finished */
3283 HWREG(PRCM_BASE + PRCM_O_RFCBITS) |= RF_BOOT1;
3284
3285 /* Release the constraint on the FLASH in IDLE */
3286 if (bDisableFlashInIdleConstraint)
3287 {
3288 Power_releaseConstraint(PowerCC26XX_NEED_FLASH_IN_IDLE);
3289 bDisableFlashInIdleConstraint = false;
3290 }
3291
3292 /* Enter critical section */
3293 key = HwiP_disable();
3294
3295 /* Update power up duration if coming from the clkPowerUpFxn. Skip the calcualtion
3296 if coming from boot, since the LF clock is derived from RCOSC_HF without calibration. */
3297 if ((OSCClockSourceGet(OSC_SRC_CLK_LF) != OSC_RCOSC_HF)
3298 && pObj->clientConfig.bMeasurePowerUpDuration
3299 && RF_rtcTimestampA)
3300 {
3301 /* Temporary storage to be able to compare the new value to the old measurement */
3302 uint32_t prevPowerUpDuration = pObj->clientConfig.nPowerUpDuration;
3303
3304 /* Take wake up timestamp and the current timestamp */
3305 rtcValTmp1 = (uint32_t) RF_rtcTimestampA;
3306 rtcValTmp2 = (uint32_t) AONRTCCurrent64BitValueGet();
3307
3308 /* Calculate the difference of the timestamps and convert it to us units */
3309 pObj->clientConfig.nPowerUpDuration = UDIFF(rtcValTmp1, rtcValTmp2);
3310 pObj->clientConfig.nPowerUpDuration >>= RF_RTC_CONV_TO_US_SHIFT;
3311
3312 /* Low pass filter on power up durations less than in the previous cycle */
3313 if (prevPowerUpDuration > pObj->clientConfig.nPowerUpDuration)
3314 {
3315 /* Expect that the values are small and the calculation can be done in 32 bits */
3316 pObj->clientConfig.nPowerUpDuration = (prevPowerUpDuration + pObj->clientConfig.nPowerUpDuration)/2;
3317 }
3318
3319 /* Power up duration should be within certain upper and lower bounds */
3320 if ((pObj->clientConfig.nPowerUpDuration > RF_DEFAULT_POWER_UP_TIME) ||
3321 (pObj->clientConfig.nPowerUpDuration < RF_DEFAULT_MIN_POWER_UP_TIME))
3322 {
3323 pObj->clientConfig.nPowerUpDuration = RF_DEFAULT_POWER_UP_TIME;
3324 }
3325 }
3326
3327 /* Exit critical section */
3328 HwiP_restore(key);
3329
3330 /* Check the status of the CMD_FS, if it was sent (chained) to the setup command.
3331 If it failed, return an error callback to the client.
3332 The client can either resend the CMD_FS or ignore the error as per Errata on PG2.1 */
3333 if (RF_checkCmdFsError())
3334 {
3335 /* Invoke the error callback: deault is do nothing */
3336 RF_Callback pErrCb = (RF_Callback)pObj->clientConfig.pErrCb;
3337 pErrCb(pObj, RF_ERROR_CMDFS_SYNTH_PROG, RF_EventError);
3338
3339 /* Check if there is pending command */
3340 if (List_head(&RF_cmdQ.pPend))
3341 {
3342 /* Make sure the next pending command gets dispatched by issuing CPE0 IRQ */
3343 RF_dispatchNextEvent();
3344 }
3345 else
3346 {
3347 /* No pending command */
3348 e |= RF_FsmEventLastCommandDone;
3349 }
3350 }
3351
3352 /* Issue power up callback: the RF core is active */
3353 RF_Callback pPowerCb = (RF_Callback)pObj->clientConfig.pPowerCb;
3354 pPowerCb(pObj, 0, RF_EventPowerUp);
3355
3356 /* We've handled this event now */
3357 e &= ~RF_FsmEventPowerStep;
3358 }
3359 else if (e & RF_FsmEventLastCommandDone)
3360 {
3361 /* Issue radio operation done callback */
3362 RF_radioOpDoneCb();
3363
3364 /* Take the next command in the done queue if any left */
3365 if (List_empty(&RF_cmdQ.pDone))
3366 {
3367 /* We've handled this event now */
3368 e &= ~RF_FsmEventLastCommandDone;
3369 }
3370 }
3371 else if (e & RF_FsmEventInitChangePhy)
3372 {
3373 /* Enter critical section */
3374 key = HwiP_disable();
3375
3376 /* We only continue with phy switching if the RF core is still available.
3377 This check is important since the queues might have changed in the meantime
3378 of servicing the SWI. */
3379 transitionAllowed = RF_isStateTransitionAllowed();
3380
3381 /* Take the next command from the pend queue */
3382 RF_Cmd* pNextCmd = (RF_Cmd*)List_head(&RF_cmdQ.pPend);
3383
3384 if ((transitionAllowed == true) && (pNextCmd != NULL))
3385 {
3386 /* Indicate that we are changing phy on the RF core. */
3387 RF_core.status = RF_CoreStatusPhySwitching;
3388
3389 /* Change HWI handler while switching the phy */
3390 HwiP_setFunc(&RF_hwiCpe0Obj, RF_hwiCpe0ChangePhy, (uintptr_t)NULL);
3391
3392 /* Exit critical section */
3393 HwiP_restore(key);
3394
3395 /* Stop inactivity clock of the current client if running */
3396 ClockP_stop(&RF_clkInactivityObj);
3397
3398 /* Store the timestamp or measurement of the switching time */
3399 RF_rtcBeginSequence = AONRTCCurrent64BitValueGet();
3400
3401 /* Notify the power driver that FLASH is needed in IDLE */
3402 bDisableFlashInIdleConstraint = true;
3403 Power_setConstraint(PowerCC26XX_NEED_FLASH_IN_IDLE);
3404
3405 /* Switch the current client to the commands client */
3406 RF_currClient = pNextCmd->pClient;
3407
3408 /* Do client switch callback if provided */
3409 if (RF_currClient->clientConfig.nClientEventMask & RF_ClientEventSwitchClientEntered)
3410 {
3411 RF_ClientCallback pClientEventCb = (RF_ClientCallback)RF_currClient->clientConfig.pClientEventCb;
3412 pClientEventCb(RF_currClient, RF_ClientEventSwitchClientEntered, NULL);
3413 }
3414
3415 /* Apply the new RF Core patch */
3416 RF_applyRfCorePatch(RF_PHY_SWITCHING_MODE);
3417
3418 /* Ensure that the analog domain is updated. */
3419 RF_currClient->clientConfig.bUpdateSetup = true;
3420
3421 /* Ensure that the overrides are correct. */
3422 RF_initRadioSetup(RF_currClient);
3423
3424 /* Configure the SETUP command */
3425 RF_RadioSetup* pRadioSetup = RF_currClient->clientConfig.pRadioSetup;
3426
3427 /* Walk the chain and search or specific commands */
3428 RF_Op* tmp = (RF_Op*)&pRadioSetup->prop;
3429 while ((tmp->pNextOp) && (tmp->pNextOp->commandNo != CMD_SYNC_START_RAT) &&
3430 (tmp->pNextOp->commandNo != CMD_FS) &&
3431 (tmp->pNextOp->commandNo != CMD_FS_OFF))
3432 {
3433 tmp = tmp->pNextOp;
3434 }
3435
3436 /* Clear any of the found specific command */
3437 tmp->pNextOp = NULL;
3438 tmp->condition.rule = COND_NEVER;
3439
3440 /* Setup FS command to follow SETUP command */
3441 RF_Op* pOpFirstPend = pNextCmd->pOp;
3442 if ((pOpFirstPend->commandNo == CMD_FS) || (pOpFirstPend->commandNo == CMD_FS_OFF))
3443 {
3444 /* First command is FS command so no need to chain an implicit FS command -> reset nRtc2 */
3445 RF_rtcBeginSequence = 0;
3446 }
3447 else
3448 {
3449 if (RF_currClient->state.mode_state.cmdFs.commandNo)
3450 {
3451 /* Chain in the implicit FS command */
3452 rfc_CMD_FS_t* pOpFs = &RF_currClient->state.mode_state.cmdFs;
3453 pOpFs->status = IDLE;
3454 pOpFs->pNextOp = NULL;
3455 pOpFs->startTrigger.triggerType = TRIG_NOW;
3456 pOpFs->condition.rule = COND_NEVER;
3457 tmp->pNextOp = (RF_Op*)pOpFs;
3458 tmp->condition.rule = COND_ALWAYS;
3459 }
3460 }
3461
3462 /* Send the command chain */
3463 RF_dbellSubmitCmdAsync((uint32_t)pRadioSetup);
3464
3465 /* Invoke the global callback. */
3466 RF_invokeGlobalCallback(RF_GlobalEventRadioSetup, (void*)pRadioSetup);
3467 }
3468 else
3469 {
3470 /* Exit critical section */
3471 HwiP_restore(key);
3472 }
3473
3474 /* We've handled this event now */
3475 e &= ~RF_FsmEventInitChangePhy;
3476 }
3477 else if (e & RF_FsmEventFinishChangePhy)
3478 {
3479 /* Release the constraint on the FLASH in IDLE */
3480 if (bDisableFlashInIdleConstraint)
3481 {
3482 Power_releaseConstraint(PowerCC26XX_NEED_FLASH_IN_IDLE);
3483 bDisableFlashInIdleConstraint = false;
3484 }
3485
3486 /* Check the status of the CMD_FS, if it was sent (chained) to the setup command.
3487 If it failed, invoke the error callback of the client.
3488 The client can either resend the CMD_FS or ignore the error. */
3489 if (RF_checkCmdFsError())
3490 {
3491 RF_Callback pErrCb = (RF_Callback)RF_currClient->clientConfig.pErrCb;
3492 pErrCb(RF_currClient, RF_ERROR_CMDFS_SYNTH_PROG, RF_EventError);
3493 }
3494
3495 /* Only compute PHY switching time if rtcValTmp1 is not zero (was initialized) */
3496 if (RF_rtcBeginSequence)
3497 {
3498 /* Record the timestamp for switching time measurement. */
3499 rtcValTmp2 = (uint32_t) AONRTCCurrent64BitValueGet();
3500
3501 /* Calculate how long it took to reconfigure the radio to a new phy. */
3502 RF_currClient->clientConfig.nPhySwitchingDuration = UDIFF(RF_rtcBeginSequence, rtcValTmp2);
3503 RF_currClient->clientConfig.nPhySwitchingDuration >>= RF_RTC_CONV_TO_US_SHIFT;
3504
3505 /* Reset RF_rtcBeginSequence value at the end of phy switching sequence. */
3506 RF_rtcBeginSequence = 0;
3507 }
3508
3509 /* Change HWI handler */
3510 HwiP_setFunc(&RF_hwiCpe0Obj, RF_hwiCpe0Active, (uintptr_t)NULL);
3511
3512 /* Mark radio and client as being active */
3513 RF_core.status = RF_CoreStatusActive;
3514
3515 /* Serve the callbacks if the queue was rearranged while PHY switching was performed. */
3516 if (List_head(&RF_cmdQ.pDone))
3517 {
3518 SwiP_or(&RF_swiFsmObj, RF_FsmEventLastCommandDone);
3519 }
3520
3521 /* Run the scheduler again. */
3522 RF_dispatchNextEvent();
3523
3524 /* We have handled this event now */
3525 e &= ~RF_FsmEventFinishChangePhy;
3526 }
3527 else if (e & RF_FsmEventPowerDown)
3528 {
3529 /* Enter critical section. */
3530 key = HwiP_disable();
3531
3532 /* Verify if the decision has not been reverted in the meantime. */
3533 transitionAllowed = RF_isStateTransitionAllowed();
3534
3535 /* If possible, put the running RAT channels into pending state allowing to
3536 power down the RF core. */
3537 if (transitionAllowed)
3538 {
3539 transitionAllowed = RF_ratReleaseChannels();
3540 }
3541
3542 /* If there is nothing prevent us to power down, proceed. */
3543 if (transitionAllowed)
3544 {
3545 /* Indicate that the RF core is being powered down from now */
3546 RF_core.status = RF_CoreStatusPoweringDown;
3547
3548 /* Stop inactivity timer. */
3549 ClockP_stop(&RF_clkInactivityObj);
3550
3551 /* Exit ritical setion. */
3552 HwiP_restore(key);
3553
3554 /* Execute power down sequence of the RF core */
3555 RF_corePowerDown();
3556
3557 /* Invoke the global callback. At this point the clock of RF core is OFF, but the
3558 power domain is still powered (hence the doorbell signals are still active.
3559 We do the callback here to save some power. */
3560 RF_invokeGlobalCallback(RF_GlobalEventRadioPowerDown, NULL);
3561
3562 /* Notify the power driver that Standby mode is allowed and the RF core can be powered down. */
3563 Power_releaseConstraint(PowerCC26XX_DISALLOW_STANDBY);
3564 Power_releaseDependency(PowerCC26XX_DOMAIN_RFCORE);
3565
3566 /* Closing all handles */
3567 if (!RF_numClients)
3568 {
3569 /* Release the semaphore to be sure no one is pending on it */
3570 SemaphoreP_post(&RF_currClient->state.semSync);
3571 }
3572
3573 /* If there is no specific client request or the XOSC, release the dependency */
3574 if (RFCC26XX_hwAttrs.xoscHfAlwaysNeeded == false)
3575 {
3576 Power_releaseDependency(PowerCC26XX_XOSC_HF);
3577 }
3578
3579 /* Release constraint of switching XOSC_HF from the RF driver itself */
3580 if (RF_core.manualXoscHfSelect)
3581 {
3582 RF_core.manualXoscHfSelect = false;
3583 Power_releaseConstraint(PowerCC26XX_SWITCH_XOSC_HF_MANUALLY);
3584 }
3585
3586 /* Next state: RF_fsmPowerUpState */
3587 RF_core.fxn = RF_fsmPowerUpState;
3588
3589 /* Indicate that the RF core is now powered down */
3590 RF_core.status = RF_CoreStatusIdle;
3591
3592 /* Issue radio available callback if RF_yield was called with no
3593 pending commands in the queue */
3594 uint8_t tmp = RF_RADIOFREECB_REQACCESS_FLAG;
3595 if (RF_cmdQ.nSeqDone == RF_cmdQ.nSeqPost)
3596 {
3597 tmp |= RF_RADIOFREECB_PREEMPT_FLAG | RF_RADIOFREECB_CMDREJECT_FLAG;
3598 }
3599 RF_issueRadioFreeCb(tmp);
3600 }
3601 else
3602 {
3603 /* Exit ritical setion. */
3604 HwiP_restore(key);
3605 }
3606
3607 /* Reschedule the next event based on the state of the command queue
3608 and the RAT module. We do it here as future commands need to work even if
3609 power management is disabled manually. */
3610 RF_dispatchNextEvent();
3611
3612 /* We've handled this event now */
3613 e &= ~RF_FsmEventPowerDown;
3614 }
3615 else if (e & RF_FsmEventRunScheduler)
3616 {
3617 /* Run the scheduler again. */
3618 RF_dispatchNextEvent();
3619
3620 /* We've handled this event now */
3621 e &= ~RF_FsmEventRunScheduler;
3622 }
3623
3624 /* Call self again if there are outstanding events to be processed */
3625 if (e)
3626 {
3627 /* Trig the SWI with the remained/unhandled events */
3628 SwiP_or(&RF_swiFsmObj, e);
3629 }
3630 }
3631
3632 /*-------------- Initialization & helper functions ---------------*/
3633
3634 /*
3635 * Initialize RF driver.
3636 *
3637 * Input: none
3638 * Return: none
3639 */
RF_init(void)3640 static void RF_init(void)
3641 {
3642 union {
3643 HwiP_Params hp;
3644 SwiP_Params sp;
3645 } params;
3646
3647 /* Power init */
3648 Power_init();
3649
3650 /* Enable output RTC clock for Radio Timer Synchronization */
3651 HWREG(AON_RTC_BASE + AON_RTC_O_CTL) |= AON_RTC_CTL_RTC_UPD_EN_M;
3652
3653 /* Set the automatic bus request */
3654 HWREG(PRCM_BASE + PRCM_O_RFCBITS) = RF_BOOT0;
3655
3656 /* Initialize SWI used by the RF driver. */
3657 SwiP_Params_init(¶ms.sp);
3658 params.sp.priority = RFCC26XX_hwAttrs.swiPriority;
3659 SwiP_construct(&RF_swiFsmObj, RF_swiFsm, ¶ms.sp);
3660 SwiP_construct(&RF_swiHwObj, RF_swiHw, ¶ms.sp);
3661
3662 /* Initialize HWI used by the RF driver. */
3663 HwiP_Params_init(¶ms.hp);
3664 params.hp.priority = RFCC26XX_hwAttrs.hwiPriority;
3665 HwiP_construct(&RF_hwiCpe0Obj, INT_RFC_CPE_0, RF_hwiCpe0PowerFsm, ¶ms.hp);
3666 HwiP_construct(&RF_hwiHwObj, INT_RFC_HW_COMB, RF_hwiHw, ¶ms.hp);
3667
3668 /* Initialize clock object used as power-up trigger */
3669 ClockP_construct(&RF_clkPowerUpObj, &RF_clkPowerUp, 0, NULL);
3670 ClockP_construct(&RF_clkInactivityObj, &RF_clkInactivityCallback, 0, NULL);
3671
3672 /* If TCXO is selected in CCFG, the RF Driver must not be allowed to control
3673 the XOSC switching by subscribing to wakeup notification from the Power driver. */
3674 if (CCFGRead_XOSC_FREQ() != CCFGREAD_XOSC_FREQ_TCXO)
3675 {
3676 /* Subscribe to wakeup notification from the Power driver */
3677 Power_registerNotify(&RF_wakeupNotifyObj, /* Object to register */
3678 PowerCC26XX_AWAKE_STANDBY, /* Event the notification to be invoked upon */
3679 (Power_NotifyFxn) RF_wakeupNotification, /* Function to be invoked */
3680 (uintptr_t) NULL); /* Parameters */
3681 }
3682
3683 /* Set the XOSC_HF dependency if the HW attributes say so. This will ensure
3684 that the XOSC_HF is turned on by the power driver as soon as possible when
3685 coming out of standby. */
3686 if (RFCC26XX_hwAttrs.xoscHfAlwaysNeeded == true)
3687 {
3688 Power_setDependency(PowerCC26XX_XOSC_HF);
3689 }
3690
3691 /* Initialized the queues. */
3692 List_clearList(&RF_cmdQ.pDone);
3693 List_clearList(&RF_cmdQ.pPend);
3694
3695 /* Initialize global variables */
3696 RF_core.status = RF_CoreStatusIdle;
3697 RF_core.init = false;
3698 RF_core.activeTimeUs = 0;
3699 RF_core.manualXoscHfSelect = false;
3700 RF_ratModule.availableRatChannels = RF_DEFAULT_AVAILRATCH_VAL;
3701 RF_rtcTimestampA = 0;
3702 RF_rtcBeginSequence = 0;
3703 RF_errTolValInUs = RF_DEFAULT_RAT_RTC_ERR_TOL_IN_US;
3704 RF_powerConstraint = 0;
3705
3706 /* Set FSM state to power up */
3707 RF_core.fxn = RF_fsmPowerUpState;
3708
3709 /* Invoke the board file init function. */
3710 RF_invokeGlobalCallback(RF_GlobalEventInit, NULL);
3711 }
3712
3713 /*
3714 * Trace through the pending queue and flush the command(s).
3715 *
3716 * Input: h - Handle to the client calling this function.
3717 * pCmd - Pointer to the command where the cancelling should start with.
3718 * bFlushAll - Decides weather one or more commands should be aborted.
3719 * Return: Number of commands was terminated.
3720 */
RF_discardPendCmd(RF_Handle h,RF_Cmd * pCmd,bool bFlushAll,bool bPreempt)3721 static uint32_t RF_discardPendCmd(RF_Handle h, RF_Cmd* pCmd, bool bFlushAll, bool bPreempt)
3722 {
3723 /* Local variables, start from the head of queue. */
3724 uint32_t numDiscardedCmd = 0;
3725 RF_Cmd* pElem = (RF_Cmd*)List_head(&RF_cmdQ.pPend);
3726
3727 /* Find the first command to be cancelled. */
3728 while (pElem && (pElem != pCmd))
3729 {
3730 pElem = (RF_Cmd*)List_next((List_Elem*)pElem);
3731 }
3732
3733 /* If we found the command to be cancelled. */
3734 while (pElem)
3735 {
3736 /* Temporarly store the next element, since we will need
3737 to continue from there. */
3738 RF_Cmd* pNextElem = (RF_Cmd*)List_next((List_Elem*)pElem);
3739
3740 if (RF_isClientOwner(h, pElem))
3741 {
3742 /* Mark the command that it was cancelled. */
3743 RF_cmdStoreEvents(pElem, RF_EventCmdCancelled);
3744
3745 if (bPreempt)
3746 {
3747 /* Mark the command as being preempted. */
3748 RF_cmdStoreEvents(pElem, RF_EventCmdPreempted);
3749
3750 /* Subscribe the client for RadioFree callback. */
3751 RF_Sch.clientHndRadioFreeCb = pCmd->pClient;
3752 RF_Sch.issueRadioFreeCbFlags |= RF_RADIOFREECB_PREEMPT_FLAG;
3753 }
3754
3755 /* Remove the command from the pend queue and place it to
3756 the done queue. */
3757 List_remove(&RF_cmdQ.pPend, (List_Elem*)pElem);
3758 List_put(&RF_cmdQ.pDone, (List_Elem*)pElem);
3759
3760 /* Increment the counter of cancelled commands. */
3761 numDiscardedCmd += 1;
3762 }
3763
3764 /* Break the loop if only single cancel was requested.
3765 Step the queue otherwise. */
3766 if (bFlushAll)
3767 {
3768 pElem = pNextElem;
3769 }
3770 else
3771 {
3772 break;
3773 }
3774 }
3775
3776 /* Return with the number of cancelled commands. */
3777 return(numDiscardedCmd);
3778 }
3779
3780 /*
3781 * Process cancel commands. It is used by RF_cancelCmd, RF_flushCmd API.
3782 *
3783 * Input: h - Handle to the client calling this function.
3784 * ch - Handle to the command where the cancelling should start with.
3785 * graceful - true: stop the command
3786 * false: abort the command
3787 * flush - true: flush all commands of this client
3788 * false: only cancel the given command
3789 * preempt - mark the command as the reason of aborting is preemption
3790 * Return: status
3791 */
RF_abortCmd(RF_Handle h,RF_CmdHandle ch,bool graceful,bool flush,bool preempt)3792 static RF_Stat RF_abortCmd(RF_Handle h, RF_CmdHandle ch, bool graceful, bool flush, bool preempt)
3793 {
3794 /* Assert */
3795 DebugP_assert(h != NULL);
3796
3797 /* Initialize local variables */
3798 RF_Cmd* pCmd = NULL;
3799 RF_Stat status = RF_StatInvalidParamsError;
3800 RF_EventMask event = graceful ? RF_EventCmdStopped : RF_EventCmdAborted;
3801
3802 /* Enter critical section */
3803 uint32_t key = HwiP_disable();
3804
3805 /* Handle FLUSH_ALL request */
3806 if (ch == RF_CMDHANDLE_FLUSH_ALL)
3807 {
3808 /* Start to cancel the commands from the actively running onces if it belongs to this client. */
3809 if (RF_isClientOwner(h, RF_cmdQ.pCurrCmdBg))
3810 {
3811 pCmd = RF_cmdQ.pCurrCmdBg;
3812 }
3813 else if (RF_isClientOwner(h, RF_cmdQ.pCurrCmdFg))
3814 {
3815 pCmd = RF_cmdQ.pCurrCmdFg;
3816 }
3817 else
3818 {
3819 /* Start to walk the pending queue from its head. */
3820 pCmd = (RF_Cmd*)List_head(&RF_cmdQ.pPend);
3821 }
3822 }
3823 else
3824 {
3825 /* Search for the command in the command pool based on its handle. The command can
3826 locate on any of the queues at this point. */
3827 pCmd = RF_cmdGet(h, ch, 0x00);
3828 }
3829
3830 /* If command handle is valid, proceed to cancel. */
3831 if (pCmd)
3832 {
3833 /* If the command is still allocated. */
3834 if (pCmd->flags & RF_CMD_ALLOC_FLAG)
3835 {
3836 /* If the command we want to cancel is actively running. */
3837 if ((pCmd == RF_cmdQ.pCurrCmdBg) || (pCmd == RF_cmdQ.pCurrCmdFg))
3838 {
3839 /* Flag that the command has been aborted. In IEEE 15.4 mode, this means
3840 aborting both the background and foreground commands. */
3841 RF_cmdStoreEvents(RF_cmdQ.pCurrCmdBg, event);
3842 RF_cmdStoreEvents(RF_cmdQ.pCurrCmdFg, event);
3843
3844 /* Decode what method to use to terminate the ongoing radio operation. */
3845 uint32_t directCmd = (graceful) ? CMDR_DIR_CMD(CMD_STOP) : CMDR_DIR_CMD(CMD_ABORT);
3846
3847 /* Send the abort/stop command through the doorbell to the RF core. */
3848 RFCDoorbellSendTo(directCmd);
3849
3850 if (preempt)
3851 {
3852 /* Mark the command as being preempted. */
3853 RF_cmdStoreEvents(RF_cmdQ.pCurrCmdBg, RF_EventCmdPreempted);
3854 RF_cmdStoreEvents(RF_cmdQ.pCurrCmdFg, RF_EventCmdPreempted);
3855
3856 /* Subscribe the client for RadioFree callback. */
3857 RF_Sch.clientHndRadioFreeCb = pCmd->pClient;
3858 RF_Sch.issueRadioFreeCbFlags |= RF_RADIOFREECB_PREEMPT_FLAG;
3859 }
3860
3861 /* Remove all commands from the pend queue belong to this client. Only do it
3862 if it was explicitely requested through the flush argument. */
3863 if (flush)
3864 {
3865 RF_discardPendCmd(h, (RF_Cmd*)List_head(&RF_cmdQ.pPend), flush, preempt);
3866 }
3867
3868 /* Return with success as we cancelled at least the currently running command. */
3869 status = RF_StatSuccess;
3870 }
3871 else
3872 {
3873 /* Remove one/all commands from the pend queue based on the flush argument.
3874 If at least one command is cancelled the operation was succesful. Otherwise,
3875 either the pend queue is empty or pCmd have terminated earlier */
3876 if (RF_discardPendCmd(h, pCmd, flush, preempt))
3877 {
3878 /* Kick the state machine to handle the done queue and re-execute the scheduler.
3879 This is not necessary when the RF is currently performing a power-up. */
3880 if ((RF_core.status != RF_CoreStatusPoweringUp) &&
3881 (RF_core.status != RF_CoreStatusPhySwitching))
3882 {
3883 SwiP_or(&RF_swiFsmObj, (RF_FsmEventLastCommandDone | RF_FsmEventRunScheduler));
3884 }
3885
3886 /* At least one command was cancelled. */
3887 status = RF_StatSuccess;
3888 }
3889 else
3890 {
3891 /* The command is not running and is not in the pend queue. It is located on the
3892 done queue, hence return RF_StatCmdEnded. */
3893 status = RF_StatCmdEnded;
3894 }
3895 }
3896 }
3897 else
3898 { /* If command is still in the pool but it is not allocated anymore, i.e. it was already served. */
3899 status = RF_StatCmdEnded;
3900 }
3901 }
3902
3903 /* Exit critical section */
3904 HwiP_restore(key);
3905
3906 /* Return with the result:
3907 - RF_StatSuccess if at least one command was cancelled.
3908 - RF_StatCmdEnded, when the command already finished (in the Done Q, but not deallocated yet).
3909 - RF_StatInvalidParamsError otherwise. */
3910 return(status);
3911 }
3912
3913 /*
3914 * Execute a direct or immediate command in the RF Core if possible.
3915 *
3916 * Input: pCmd - Pointer to the command which shall be sent to the RF core.
3917 * rawStatus - Return address of the raw status byte read from the CMDSTA register.
3918 * Return: The return value interprets and converts the result of command execution to and RF_Stat value.
3919 * RF_StatCmdDoneSuccess - If the command was sent and accepted by the RF core.
3920 * RF_StatCmdDoneError - Command was rejected by the RF core.
3921 * RF_StatRadioInactiveError - The RF core is OFF.
3922 */
RF_executeDirectImmediateCmd(uint32_t pCmd,uint32_t * rawStatus)3923 static RF_Stat RF_executeDirectImmediateCmd(uint32_t pCmd, uint32_t* rawStatus)
3924 {
3925 /* If the RF core is ON, we can send the command */
3926 if (RF_core.status == RF_CoreStatusActive)
3927 {
3928 /* Submit the command to the doorbell */
3929 uint32_t localStatus = RFCDoorbellSendTo(pCmd);
3930
3931 /* Pass the rawStatus to the callee if possible. */
3932 if (rawStatus)
3933 {
3934 *rawStatus = localStatus;
3935 }
3936
3937 /* Check the return value of the RF core through the CMDSTA register within the doorbell */
3938 if ((localStatus & RF_CMDSTA_REG_VAL_MASK) == CMDSTA_Done)
3939 {
3940 /* The command was accepted */
3941 return(RF_StatCmdDoneSuccess);
3942 }
3943 else
3944 {
3945 /* The command was rejected */
3946 return(RF_StatCmdDoneError);
3947 }
3948 }
3949 else
3950 {
3951 /* The RF core is not capable of receiving the command */
3952 return(RF_StatRadioInactiveError);
3953 }
3954 }
3955
3956 /*
3957 * Send a direct or immediate command to the RF core. The command is rejected
3958 * if the RF core is configured to a different PHY (client).
3959 *
3960 * Input: h - Handle to the client calling this function.
3961 * pCmd - Pointer to the command which shall be sent to the RF core.
3962 * rawStatus - Return address of raw status byte read from CMDSTA register.
3963 * Return: RF_StatCmdDoneSuccess - If the command was sent and accepted by the RF core.
3964 * RF_StatCmdDoneError - Command was rejected by the RF core.
3965 * RF_StatInvalidParamsError - Client do not have the right to send commands now.
3966 * RF_StatRadioInactiveError - The RF core is OFF.
3967 */
RF_runDirectImmediateCmd(RF_Handle h,uint32_t pCmd,uint32_t * rawStatus)3968 static RF_Stat RF_runDirectImmediateCmd(RF_Handle h, uint32_t pCmd, uint32_t* rawStatus)
3969 {
3970 /* Local variable. */
3971 RF_Stat status;
3972
3973 /* Enter critical section */
3974 uint32_t key = HwiP_disable();
3975
3976 /* Only the current client is allowed to send direct commands */
3977 if (h != RF_currClient)
3978 {
3979 /* Return with an error code it is a different client */
3980 status = RF_StatInvalidParamsError;
3981 }
3982 else
3983 {
3984 /* Execute the direct or immediate command. */
3985 status = RF_executeDirectImmediateCmd(pCmd, rawStatus);
3986 }
3987
3988 /* Exit critical section. */
3989 HwiP_restore(key);
3990
3991 /* Return with the status information about the success of command execution. */
3992 return(status);
3993 }
3994
3995 /*
3996 * Helper function to find the first override representing a High PA value (CC13x2P devices).
3997 *
3998 * Input: pOverride - Pointer to an override list to be searched.
3999 * overridePattern - Pattern o override to search for.
4000 * currentValue - Reference where the current value can be returned.
4001 * Return: paOffset - Offset of the High PA override.
4002 * RF_TX_OVERRIDE_INVALID_OFFSET - No override was found in the list.
4003 */
RF_getPAOverrideOffsetAndValue(uint32_t * pOverride,uint32_t overridePattern,uint32_t * currentValue)4004 static uint8_t RF_getPAOverrideOffsetAndValue(uint32_t* pOverride, uint32_t overridePattern, uint32_t* currentValue)
4005 {
4006 /* Search for the particular override. */
4007 uint8_t paOffset = RFCOverrideSearch(pOverride, overridePattern, RF_TX_OVERRIDE_MASK, RF_OVERRIDE_SEARCH_DEPTH);
4008
4009 /* If the override was found. */
4010 if (currentValue)
4011 {
4012 *currentValue = pOverride[paOffset] >> RF_TX_OVERRIDE_SHIFT;
4013 }
4014
4015 /* Return with an invalid value. */
4016 return(paOffset);
4017 }
4018
4019 /*
4020 * Helper function to find and replace the first override representing a High PA value.
4021 *
4022 * Input: pOverride - Pointer to an override list to be searched.
4023 * overridePattern - Mask of override type to searh for.
4024 * newValue - The new raw value the PA to be set to.
4025 * Return: paOffset - Offset of the High PA override.
4026 * RF_TX_OVERRIDE_INVALID_OFFSET - No override was found in the list. Hence nothing to replace.
4027 */
RF_searchAndReplacePAOverride(uint32_t * pOverride,uint32_t overridePattern,uint32_t newValue)4028 static uint8_t RF_searchAndReplacePAOverride(uint32_t* pOverride, uint32_t overridePattern, uint32_t newValue)
4029 {
4030 /* Search for the particular override. */
4031 uint8_t paOffset = RF_getPAOverrideOffsetAndValue(pOverride, overridePattern, NULL);
4032
4033 /* If the override was found. */
4034 if (paOffset != RF_TX_OVERRIDE_INVALID_OFFSET)
4035 {
4036 if (overridePattern == RF_TX20_PATTERN)
4037 {
4038 /* Replace the high PA gain with the new value. */
4039 pOverride[paOffset] = TX20_POWER_OVERRIDE(newValue);
4040 }
4041 else
4042 {
4043 /* Replace the default PA gain with the new value. */
4044 pOverride[paOffset] = TX_STD_POWER_OVERRIDE(newValue);
4045 }
4046 }
4047
4048 /* Return with the offset of the PA override. */
4049 return(paOffset);
4050 }
4051
4052 /*
4053 * Appends the PA specific override list to the end of given overrides.
4054 *
4055 * Input: baseOverride - Override list to append the applicable segment to.
4056 * newOverride - Override segment to be appended.
4057 * Return: none
4058 */
RF_attachOverrides(uint32_t * baseOverride,uint32_t * newOverride)4059 static void RF_attachOverrides(uint32_t* baseOverride, uint32_t* newOverride)
4060 {
4061 if (newOverride != NULL)
4062 {
4063 /* Search for the attached override list. */
4064 uint32_t maskOverride = NEW_OVERRIDE_SEGMENT(newOverride);
4065
4066 /* Search for the end of the base override list. We also look for new segment vectors. */
4067 while ((*baseOverride != END_OVERRIDE) && (*baseOverride != maskOverride))
4068 {
4069 baseOverride++;
4070 }
4071
4072 /* Append the second override list. */
4073 *baseOverride = maskOverride;
4074 }
4075 }
4076
4077 /*
4078 * Terminate the override list at the first match of a jump to the given newOverride.
4079 * The function assumes that there are no other jump vectors before.
4080 *
4081 * Input: baseOverride - Override list to append the applicable segment to.
4082 * newOverride - Override segment to be appended.
4083 * Return: none
4084 */
RF_detachOverrides(uint32_t * baseOverride,uint32_t * newOverride)4085 static void RF_detachOverrides(uint32_t* baseOverride, uint32_t* newOverride)
4086 {
4087 if (newOverride != NULL)
4088 {
4089 /* Search for the attached override list. */
4090 uint32_t maskOverride = NEW_OVERRIDE_SEGMENT(newOverride);
4091
4092 /* Search for the end of the base override list. We also look for new segment vectors. */
4093 while ((*baseOverride != END_OVERRIDE) && (*baseOverride != maskOverride))
4094 {
4095 baseOverride++;
4096 }
4097
4098 /* Append the second override list if exists. */
4099 *baseOverride = END_OVERRIDE;
4100 }
4101 }
4102
4103 /*
4104 * Decode all the override pointers according to the type of the setup command.
4105 *
4106 * Input: radioSetup - Pointer to the setup command to be evaluated.
4107 * Return: tx20FeatureAvailable - true if the High Gain PA is available.
4108 * pTxPower - Pointer to the txPower field of setup command.
4109 * pRegOverride - Pointer to the base override list.
4110 * pRegOverrideTxStd - Pointer to the Default PA override list.
4111 * pRegOverrideTx20 - Pointer to the High PA override list.
4112 */
RF_decodeOverridePointers(RF_RadioSetup * radioSetup,uint16_t ** pTxPower,uint32_t ** pRegOverride,uint32_t ** pRegOverrideTxStd,uint32_t ** pRegOverrideTx20)4113 static bool RF_decodeOverridePointers(RF_RadioSetup* radioSetup, uint16_t** pTxPower, uint32_t** pRegOverride, uint32_t** pRegOverrideTxStd, uint32_t** pRegOverrideTx20)
4114 {
4115 /* Decode if High Gain PA is even available. */
4116 bool tx20FeatureAvailable = (ChipInfo_GetChipType() == CHIP_TYPE_CC1352P) || (ChipInfo_GetChipType() == CHIP_TYPE_CC1352P7) ||
4117 (ChipInfo_GetChipType() == CHIP_TYPE_CC2652P);
4118
4119 /* Only decode the offset of those fields which exist on this device. */
4120 if (tx20FeatureAvailable)
4121 {
4122 /* Local variables. */
4123 uint8_t loDivider;
4124 uint8_t frontEndMode;
4125 uint8_t index;
4126
4127 /* Decode the offset of txPower field and all the override pointers
4128 available on the CC1352P/CC2652P devices. */
4129 switch (radioSetup->commandId.commandNo)
4130 {
4131 case (CMD_RADIO_SETUP):
4132 *pTxPower = &radioSetup->common_pa.txPower;
4133 *pRegOverride = radioSetup->common_pa.pRegOverride;
4134 *pRegOverrideTxStd = radioSetup->common_pa.pRegOverrideTxStd;
4135 *pRegOverrideTx20 = radioSetup->common_pa.pRegOverrideTx20;
4136
4137 /* Input to recalculation of overrides. */
4138 loDivider = radioSetup->common_pa.loDivider;
4139 frontEndMode = radioSetup->common_pa.config.frontEndMode;
4140
4141 break;
4142 case (CMD_BLE5_RADIO_SETUP):
4143 *pTxPower = &radioSetup->ble5_pa.txPower;
4144 *pRegOverride = radioSetup->ble5_pa.pRegOverrideCommon;
4145 *pRegOverrideTxStd = radioSetup->ble5_pa.pRegOverrideTxStd;
4146 *pRegOverrideTx20 = radioSetup->ble5_pa.pRegOverrideTx20;
4147
4148 /* Input to recalculation of overrides. */
4149 loDivider = radioSetup->ble5_pa.loDivider;
4150 frontEndMode = radioSetup->ble5_pa.config.frontEndMode;
4151
4152 break;
4153 case (CMD_PROP_RADIO_SETUP):
4154 *pTxPower = &radioSetup->prop_pa.txPower;
4155 *pRegOverride = radioSetup->prop_pa.pRegOverride;
4156 *pRegOverrideTxStd = radioSetup->prop_pa.pRegOverrideTxStd;
4157 *pRegOverrideTx20 = radioSetup->prop_pa.pRegOverrideTx20;
4158
4159 /* Input to recalculation of overrides. */
4160 loDivider = 0;
4161 frontEndMode = radioSetup->prop_pa.config.frontEndMode;
4162 break;
4163 default:
4164 *pTxPower = &radioSetup->prop_div_pa.txPower;
4165 *pRegOverride = radioSetup->prop_div_pa.pRegOverride;
4166 *pRegOverrideTxStd = radioSetup->prop_div_pa.pRegOverrideTxStd;
4167 *pRegOverrideTx20 = radioSetup->prop_div_pa.pRegOverrideTx20;
4168
4169 /* Input to recalculation of overrides. */
4170 loDivider = radioSetup->prop_div_pa.loDivider;
4171 frontEndMode = radioSetup->prop_div_pa.config.frontEndMode;
4172 break;
4173 }
4174
4175 /* Modify the divider and front-end specific override. This is to keep the override
4176 list and the setup command in sync, even if the setup command was changed runtime
4177 due to the changing stack configuration. */
4178 if (*pRegOverrideTxStd)
4179 {
4180 index = RFCOverrideSearch(*pRegOverrideTxStd, RFC_FE_OVERRIDE_ADDRESS, RFC_FE_OVERRIDE_MASK, RFC_MAX_SEARCH_DEPTH);
4181
4182 if (index < RFC_MAX_SEARCH_DEPTH)
4183 {
4184 (*pRegOverrideTxStd)[index] = RFCAnaDivTxOverride(loDivider, frontEndMode);
4185 }
4186 }
4187
4188 if (*pRegOverrideTx20)
4189 {
4190 index = RFCOverrideSearch(*pRegOverrideTx20, RFC_FE_OVERRIDE_ADDRESS, RFC_FE_OVERRIDE_MASK, RFC_MAX_SEARCH_DEPTH);
4191
4192 if (index < RFC_MAX_SEARCH_DEPTH)
4193 {
4194 (*pRegOverrideTx20)[index] = RFCAnaDivTxOverride(loDivider, RFC_FE_MODE_ESCAPE_VALUE);
4195 }
4196 }
4197 }
4198 else
4199 {
4200 /* Decode the offset of txPower field and the only relevant override pointer
4201 available on all other devices. */
4202 switch (radioSetup->commandId.commandNo)
4203 {
4204 case (CMD_RADIO_SETUP):
4205 *pTxPower = &radioSetup->common.txPower;
4206 *pRegOverride = radioSetup->common.pRegOverride;
4207 break;
4208 case (CMD_BLE5_RADIO_SETUP):
4209 *pTxPower = &radioSetup->ble5.txPower;
4210 *pRegOverride = radioSetup->ble5.pRegOverrideCommon;
4211 break;
4212 case (CMD_PROP_RADIO_SETUP):
4213 *pTxPower = &radioSetup->prop.txPower;
4214 *pRegOverride = radioSetup->prop.pRegOverride;
4215 break;
4216 default:
4217 *pTxPower = &radioSetup->prop_div.txPower;
4218 *pRegOverride = radioSetup->prop_div.pRegOverride;
4219 break;
4220 }
4221
4222 /* Force the value of non-existing pointers to be NULL. */
4223 *pRegOverrideTxStd = NULL;
4224 *pRegOverrideTx20 = NULL;
4225 }
4226
4227 /* Return if the High Gain PA feature is available or not. */
4228 return (tx20FeatureAvailable);
4229 }
4230
4231 /*
4232 * In case the PA configuration changes during the execution of a chain, this function
4233 * propagates the change back to the setup command. This is to reserve the change even
4234 * after a power cycle
4235 *
4236 * Input: handle - Radio handle the change should be stored within
4237 * Return: none
4238 */
RF_extractPaConfiguration(RF_Handle handle)4239 static void RF_extractPaConfiguration(RF_Handle handle)
4240 {
4241 /* Local variable to store the return value of function call. It is not used here. */
4242 RF_ConfigurePaCmd configurePaCmd;
4243
4244 /* Retrieve the PA configuration from the RF core itself. */
4245 RF_TxPowerTable_Value value;
4246 value.rawValue = RFCGetPaGain();
4247 value.paType = (RF_TxPowerTable_PAType) RFCGetPaType();
4248
4249 /* Update the setup command with the new settings. The change is now permanent
4250 and will be kept even if the RF core is powered off. */
4251 RF_updatePaConfiguration(handle->clientConfig.pRadioSetup, value, &configurePaCmd);
4252 }
4253
4254 /*
4255 * Helper function to find the HPOSC_OVERRIDE in provided override list and modify the HPOSC frequency offset.
4256 *
4257 * Input: pRegOverride - Pointer to override list.
4258 * Return: None
4259 */
RF_updateHpOscOverride(uint32_t * pRegOverride)4260 static void RF_updateHpOscOverride(uint32_t *pRegOverride)
4261 {
4262 /* Local variables. */
4263 int32_t tempDegC;
4264 int32_t relFreqOffset;
4265 int16_t relFreqOffsetConverted;
4266
4267 /* Find override for HPOSC frequency offset. */
4268 if (pRegOverride)
4269 {
4270 uint8_t index;
4271 index = RFCOverrideSearch(pRegOverride, RF_HPOSC_OVERRIDE_PATTERN, RF_HPOSC_OVERRIDE_MASK, RF_OVERRIDE_SEARCH_DEPTH);
4272
4273 if (index < RF_OVERRIDE_SEARCH_DEPTH)
4274 {
4275 /* Get temperature dependent HPOSC frequency offset */
4276 tempDegC = Temperature_getTemperature();
4277 relFreqOffset = OSC_HPOSCRelativeFrequencyOffsetGet(tempDegC);
4278 RF_currentHposcFreqOffset = relFreqOffset;
4279 relFreqOffsetConverted = OSC_HPOSCRelativeFrequencyOffsetToRFCoreFormatConvert(relFreqOffset);
4280
4281 /* Update override with the HPOSC frequency offset */
4282 pRegOverride[index] = HPOSC_OVERRIDE(relFreqOffsetConverted);
4283 }
4284 }
4285 else
4286 {
4287 /* Hange here if HPOSC_OVERRIDE override is not available. */
4288 while(1);
4289 }
4290 }
4291
4292 /*
4293 * Helper function to find and modify the PA selection and gain of the provided setup command.
4294 *
4295 * Input: radioSetup - Setup command belong to the client.
4296 * newValue - The new value the PA to be set to.
4297 * configurePaCmd - The immediate command to be used to apply the changes if the RF core is active.
4298 * Return: RF_StatSuccess - The setup command was reconfigured.
4299 * Otherwise - An error occured.
4300 */
RF_updatePaConfiguration(RF_RadioSetup * radioSetup,RF_TxPowerTable_Value newValue,RF_ConfigurePaCmd * configurePaCmd)4301 static RF_Stat RF_updatePaConfiguration(RF_RadioSetup* radioSetup, RF_TxPowerTable_Value newValue, RF_ConfigurePaCmd* configurePaCmd)
4302 {
4303 /* Set the default return value to indicate success. */
4304 RF_Stat status = RF_StatSuccess;
4305
4306 /* Local variables. */
4307 uint16_t* pTxPower = NULL;
4308 uint32_t* pRegOverride = NULL;
4309 uint32_t* pRegOverrideTxStd = NULL;
4310 uint32_t* pRegOverrideTx20 = NULL;
4311
4312 /* Decode if High Gain PA is available. */
4313 bool tx20FeatureAvailable = RF_decodeOverridePointers(radioSetup, &pTxPower, &pRegOverride, &pRegOverrideTxStd, &pRegOverrideTx20);
4314
4315 /* The new value requires the deault PA. */
4316 if (newValue.paType == RF_TxPowerTable_DefaultPA)
4317 {
4318 /* On CC1352P/CC2652P devices with the correct override lists. */
4319 if (tx20FeatureAvailable && pRegOverrideTxStd && pRegOverrideTx20)
4320 {
4321 /* Store the new value in the setup command. */
4322 *pTxPower = (uint16_t) newValue.rawValue;
4323
4324 /* Ensure that the gain within the overrides are also updated. */
4325 RF_searchAndReplacePAOverride(pRegOverrideTxStd, RF_TXSTD_PATTERN, newValue.rawValue);
4326
4327 /* Detach the High Gain overrides. It does nothing if the overrides are not attached. */
4328 RF_detachOverrides(pRegOverride, pRegOverrideTx20);
4329
4330 /* Return with the immediate command in the argument. */
4331 configurePaCmd->changePa.commandNo = CMD_CHANGE_PA;
4332 configurePaCmd->changePa.pRegOverride = pRegOverrideTxStd;
4333 }
4334 else if (tx20FeatureAvailable)
4335 {
4336 /* Limited backward compatibility on CC1352P/CC2652P devices without the
4337 proper override lists. Only gain tuning on the Default PA is available. */
4338 if (*pTxPower != RF_TX20_ENABLED)
4339 {
4340 /* Store the new value in the setup command. */
4341 *pTxPower = (uint16_t) newValue.rawValue;
4342
4343 /* Use the dedicated command to tune the gain */
4344 configurePaCmd->tuneTxPower.commandNo = CMD_SET_TX_POWER;
4345 configurePaCmd->tuneTxPower.txPower = newValue.rawValue;
4346 }
4347 else
4348 {
4349 /* PA swithing is not allowed due to the missing overrides. */
4350 status = RF_StatInvalidParamsError;
4351 }
4352 }
4353 else
4354 {
4355 /* On any other devices, just accept the new gain. */
4356 *pTxPower = (uint16_t) newValue.rawValue;
4357
4358 /* Use the dedicated command to tune the gain. */
4359 configurePaCmd->tuneTxPower.commandNo = CMD_SET_TX_POWER;
4360 configurePaCmd->tuneTxPower.txPower = newValue.rawValue;
4361 }
4362 }
4363 else
4364 {
4365 /* On CC1352P/CC2652P devices with the correct override lists. */
4366 if (tx20FeatureAvailable && pRegOverrideTxStd && pRegOverrideTx20)
4367 {
4368 /* If the High Gain PA is available store the escape value in the setup
4369 command and update the overrides. */
4370 *pTxPower = (uint16_t) RF_TX20_ENABLED;
4371
4372 /* Change the gain to the new value. */
4373 RF_searchAndReplacePAOverride(pRegOverrideTx20, RF_TX20_PATTERN, newValue.rawValue);
4374
4375 /* Attach the High Gain overrides. */
4376 RF_attachOverrides(pRegOverride, pRegOverrideTx20);
4377
4378 /* Return with the command argument to be used. */
4379 configurePaCmd->changePa.commandNo = CMD_CHANGE_PA;
4380 configurePaCmd->changePa.pRegOverride = pRegOverrideTx20;
4381 }
4382 else if (tx20FeatureAvailable)
4383 {
4384 /* Limited backward compatibility on CC1352P/CC2652P devices without the
4385 proper override lists. Only gain tuning on the High PA is available
4386 if the gain override is present within the base override list.*/
4387 if (RF_searchAndReplacePAOverride(pRegOverride, RF_TX20_PATTERN, newValue.rawValue) == RF_TX_OVERRIDE_INVALID_OFFSET)
4388 {
4389 /* Cannot use the high gain PA without a proper override list
4390 that contains at least a placeholder gain entry. */
4391 status = RF_StatInvalidParamsError;
4392 }
4393 else
4394 {
4395 /* If updating the override list with the gain value was succesful,
4396 set the escape value in the setup command. */
4397 *pTxPower = (uint16_t) RF_TX20_ENABLED;
4398
4399 /* Use the dedicated command to tune the gain. */
4400 configurePaCmd->tuneTx20Power.commandNo = CMD_SET_TX20_POWER;
4401 configurePaCmd->tuneTx20Power.tx20Power = newValue.rawValue;
4402 }
4403 }
4404 else
4405 {
4406 /* Do not accept any high gain PA values on devices which do not support it. */
4407 status = RF_StatInvalidParamsError;
4408 }
4409 }
4410
4411 /* Return with the status. */
4412 return(status);
4413 }
4414
4415 /*-------------- API functions ---------------*/
4416 /*
4417 * ======== RF_open ========
4418 * Open an RF handle
4419 */
RF_open(RF_Object * pObj,RF_Mode * pRfMode,RF_RadioSetup * pRadioSetup,RF_Params * params)4420 RF_Handle RF_open(RF_Object *pObj, RF_Mode* pRfMode, RF_RadioSetup* pRadioSetup, RF_Params *params)
4421 {
4422 /* Assert */
4423 DebugP_assert(pObj != NULL);
4424
4425 /* Read available RF modes from the PRCM register */
4426 uint32_t availableRfModes = HWREG(PRCM_BASE + PRCM_O_RFCMODEHWOPT);
4427
4428 /* Verify that the provided configuration is supported by this device.
4429 Reject any request which is not compliant. */
4430 if (pRfMode && pRadioSetup && (availableRfModes & (1 << pRfMode->rfMode)))
4431 {
4432 /* Trim the override list; The implementation of RFCOverrideUpdate is device specific */
4433 RFCOverrideUpdate((RF_Op*)pRadioSetup, NULL);
4434
4435 /* Register the setup command to the client */
4436 pObj->clientConfig.pRadioSetup = pRadioSetup;
4437
4438 /* Register the mode to the client */
4439 pObj->clientConfig.pRfMode = pRfMode;
4440 }
4441 else
4442 {
4443 /* Return with null if the device do not support the requested configuration */
4444 return(NULL);
4445 }
4446
4447 /* Enter critical section */
4448 uint32_t key = HwiP_disable();
4449
4450 /* Check whether RF driver is accepting more clients */
4451 if (RF_numClients < N_MAX_CLIENTS)
4452 {
4453 /* Initialize shared objects on first client opening */
4454 if (RF_numClients == 0) RF_init();
4455
4456 /* Save the new RF_Handle */
4457 RF_Sch.clientHnd[RF_numClients++] = pObj;
4458
4459 /* Exit critical section */
4460 HwiP_restore(key);
4461
4462 /* Populate default RF parameters if not provided */
4463 RF_Params rfParams;
4464 if (params == NULL)
4465 {
4466 RF_Params_init(&rfParams);
4467 params = &rfParams;
4468 }
4469
4470 /* Initialize RF_Object configuration */
4471 pObj->clientConfig.nInactivityTimeout = params->nInactivityTimeout;
4472 pObj->clientConfig.nPhySwitchingDuration = RF_DEFAULT_PHY_SWITCHING_TIME;
4473 pObj->clientConfig.nClientEventMask = params->nClientEventMask;
4474 pObj->clientConfig.nPowerUpDurationMargin = params->nPowerUpDurationMargin;
4475 pObj->clientConfig.bUpdateSetup = true;
4476 pObj->clientConfig.nID = params->nID;
4477
4478 /* Decide if automatic adjustment should be used. */
4479 if (params->nPowerUpDuration)
4480 {
4481 pObj->clientConfig.nPowerUpDuration = params->nPowerUpDuration;
4482 pObj->clientConfig.bMeasurePowerUpDuration = false;
4483 }
4484 else
4485 {
4486 pObj->clientConfig.nPowerUpDuration = RF_DEFAULT_POWER_UP_TIME;
4487 pObj->clientConfig.bMeasurePowerUpDuration = true;
4488 }
4489
4490 /* Set all the callbacks to the default (do nothing) callback */
4491 pObj->clientConfig.pErrCb = (void*) RF_defaultCallback;
4492 pObj->clientConfig.pClientEventCb = (void*) RF_defaultCallback;
4493 pObj->clientConfig.pPowerCb = (void*) RF_defaultCallback;
4494
4495 /* If a user specified callback is provided, overwrite the default */
4496 if (params->pErrCb)
4497 {
4498 pObj->clientConfig.pErrCb = (void *)params->pErrCb;
4499 }
4500 if (params->pClientEventCb)
4501 {
4502 pObj->clientConfig.pClientEventCb = (void *)params->pClientEventCb;
4503 }
4504 if (params->pPowerCb)
4505 {
4506 pObj->clientConfig.pPowerCb = (void *)params->pPowerCb;
4507 }
4508
4509 /* Initialize client state & variables to zero */
4510 memset((void*)&pObj->state, 0, sizeof(pObj->state));
4511
4512 /* Initialize client specific semaphore object */
4513 SemaphoreP_constructBinary(&pObj->state.semSync, 0);
4514
4515 /* Initialize client specific clock objects */
4516 ClockP_construct(&pObj->state.clkReqAccess, RF_clkReqAccess, 0, NULL);
4517
4518 /* Return with the RF handle. */
4519 return(pObj);
4520 }
4521 else
4522 {
4523 /* Exit critical section */
4524 HwiP_restore(key);
4525
4526 /* Return with null if no more clients are accepted */
4527 return(NULL);
4528 }
4529 }
4530
4531 /*
4532 * ======== RF_close ========
4533 * Close an RF handle
4534 */
RF_close(RF_Handle h)4535 void RF_close(RF_Handle h)
4536 {
4537 /* Assert */
4538 DebugP_assert(h != NULL);
4539
4540 /* If there is at least one active client */
4541 if (RF_numClients)
4542 {
4543 /* Wait for all issued commands to finish before freeing the resources */
4544 if (RF_cmdQ.nSeqPost != RF_cmdQ.nSeqDone)
4545 {
4546 /* There are commands which not even dispatched yet. */
4547 RF_Cmd* pCmd = RF_queueEnd(h, &RF_cmdQ.pPend);
4548
4549 /* There is no pending commmand, determine if there are items on the
4550 other queues. */
4551 if (!pCmd)
4552 {
4553 /* If the client is executing a command running. */
4554 if (RF_isClientOwner(h, RF_cmdQ.pCurrCmdBg))
4555 {
4556 /* The currentlty running command is the last. */
4557 pCmd = RF_cmdQ.pCurrCmdBg;
4558 }
4559 else
4560 {
4561 /* All commands has been dispatched, some just need to be served. This also
4562 can return with NULL if nothing to be done. */
4563 pCmd = RF_queueEnd(h, &RF_cmdQ.pDone);
4564 }
4565 }
4566
4567 /* Pend until the running command terminates */
4568 if (pCmd)
4569 {
4570 RF_pendCmd(h, pCmd->ch, RF_TERMINATION_EVENT_MASK);
4571 }
4572 }
4573
4574 /* Enter critical section */
4575 uint32_t key = HwiP_disable();
4576
4577 /* Clear the RF_sch client handle */
4578 if (h == RF_Sch.clientHnd[0])
4579 {
4580 RF_Sch.clientHnd[0] = NULL;
4581 }
4582 else
4583 {
4584 RF_Sch.clientHnd[1] = NULL;
4585 }
4586
4587 /* Check whether this is the last client */
4588 if (--RF_numClients == 0)
4589 {
4590 /* If this is the last client, set it to be the active client */
4591 RF_currClient = h;
4592
4593 if (RF_core.status == RF_CoreStatusActive)
4594 {
4595 /* Release the constraint on the RF resources */
4596 RF_powerConstraintRelease(RF_PowerConstraintCmdQ);
4597
4598 /* Exit critical section */
4599 HwiP_restore(key);
4600
4601 /* Wait until the radio is powered down (outside critical section) */
4602 SemaphoreP_pend(&h->state.semSync, SemaphoreP_WAIT_FOREVER);
4603
4604 /* Enter critical section */
4605 key = HwiP_disable();
4606 }
4607
4608 /* Unregister shared RTOS objects initalized during RF_init by the first client */
4609 SwiP_destruct(&RF_swiFsmObj);
4610 HwiP_destruct(&RF_hwiCpe0Obj);
4611 SwiP_destruct(&RF_swiHwObj);
4612 HwiP_destruct(&RF_hwiHwObj);
4613 ClockP_destruct(&RF_clkPowerUpObj);
4614 ClockP_destruct(&RF_clkInactivityObj);
4615
4616 /* Unregister temperature notify object if SW TCXO functionality is enabled. */
4617 if(pfnTemperatureUnregisterNotify != NULL)
4618 {
4619 pfnTemperatureUnregisterNotify(&RF_hposcRfCompNotifyObj);
4620 }
4621
4622 /* Unregister the wakeup notify callback */
4623 Power_unregisterNotify(&RF_wakeupNotifyObj);
4624
4625 /* Release XOSC_HF dependency if it was set on board level. */
4626 if (RFCC26XX_hwAttrs.xoscHfAlwaysNeeded == true)
4627 {
4628 Power_releaseDependency(PowerCC26XX_XOSC_HF);
4629 }
4630 }
4631
4632 /* If we're the current RF client, stop being it */
4633 if (RF_currClient == h)
4634 {
4635 RF_currClient = NULL;
4636 }
4637
4638 /* Exit critical section */
4639 HwiP_restore(key);
4640
4641 /* Unregister client specific RTOS objects (these are not shared between clients) */
4642 SemaphoreP_destruct(&h->state.semSync);
4643 ClockP_destruct(&h->state.clkReqAccess);
4644 }
4645 }
4646
4647 /*
4648 * ======== RF_getCurrentTime ========
4649 * Get current time in RAT ticks
4650 */
RF_getCurrentTime(void)4651 uint32_t RF_getCurrentTime(void)
4652 {
4653 /* Local variable */
4654 uint64_t nCurrentTime = 0;
4655
4656 /* Enter critical section */
4657 uint32_t key = HwiP_disable();
4658
4659 /* If radio is active, read the RAT */
4660 if ((RF_core.status == RF_CoreStatusActive) || (RF_core.status == RF_CoreStatusPhySwitching))
4661 {
4662 /* Read the RAT timer through register access */
4663 nCurrentTime = RF_ratGetValue();
4664
4665 /* Exit critical section */
4666 HwiP_restore(key);
4667 }
4668 else
4669 {
4670 /* Exit critical section */
4671 HwiP_restore(key);
4672
4673 /* The radio is inactive, read the RTC instead */
4674 nCurrentTime = AONRTCCurrent64BitValueGet();
4675
4676 /* Conservatively assume that we are just about to increment the RTC
4677 Scale with the 4 MHz that the RAT is running
4678 Add the RAT offset for RTC==0 */
4679 nCurrentTime += RF_RTC_TICK_INC;
4680 nCurrentTime *= RF_SCALE_RTC_TO_4MHZ;
4681 nCurrentTime += ((uint64_t)RF_ratSyncCmd.start.rat0) << RF_SHIFT_32_BITS;
4682 nCurrentTime >>= RF_SHIFT_32_BITS;
4683 }
4684
4685 /* Return with the current value */
4686 return((uint32_t) nCurrentTime);
4687 }
4688
4689 /*
4690 * ======== RF_postCmd ========
4691 * Post radio command
4692 */
RF_postCmd(RF_Handle h,RF_Op * pOp,RF_Priority ePri,RF_Callback pCb,RF_EventMask bmEvent)4693 RF_CmdHandle RF_postCmd(RF_Handle h, RF_Op* pOp, RF_Priority ePri, RF_Callback pCb, RF_EventMask bmEvent)
4694 {
4695 /* Assert */
4696 DebugP_assert(h != NULL);
4697 DebugP_assert(pOp != NULL);
4698
4699 /* Local pointer to a radio commands */
4700 RF_CmdHandle cmdHandle = (RF_CmdHandle)RF_ALLOC_ERROR;
4701
4702 /* Enter critical section */
4703 uint32_t key = HwiP_disable();
4704
4705 /* Try to allocate container */
4706 RF_Cmd* pCmd = RF_cmdAlloc();
4707
4708 /* If allocation succeeded */
4709 if (pCmd)
4710 {
4711 /* Stop inactivity clock if running */
4712 ClockP_stop(&RF_clkInactivityObj);
4713
4714 /* Increment the sequence number and mask the value */
4715 RF_cmdQ.nSeqPost = (RF_cmdQ.nSeqPost + 1) & N_CMD_MODMASK;
4716
4717 /* Populate container with reset values */
4718 pCmd->pOp = pOp;
4719 pCmd->ePri = ePri;
4720 pCmd->pCb = pCb;
4721 pCmd->ch = RF_cmdQ.nSeqPost;
4722 pCmd->pClient = h;
4723 pCmd->bmEvent = (bmEvent | RFC_DBELL_RFCPEIFG_LAST_COMMAND_DONE_M) & ~RF_INTERNAL_IFG_MASK;
4724 pCmd->pastifg = 0;
4725 pCmd->flags = RF_CMD_ALLOC_FLAG;
4726 pCmd->endTime = 0;
4727 pCmd->endType = RF_EndNotSpecified;
4728 pCmd->startTime = 0;
4729 pCmd->startType = RF_StartNotSpecified;
4730 pCmd->allowDelay = RF_AllowDelayAny;
4731 pCmd->duration = 0;
4732 pCmd->activityInfo = 0;
4733 pCmd->coexPriority = RF_PriorityCoexDefault;
4734 pCmd->coexRequest = RF_RequestCoexDefault;
4735
4736 /* Update start time if absolute start time present in radio operation. */
4737 if (pOp->startTrigger.triggerType == TRIG_ABSTIME)
4738 {
4739 pCmd->startType = RF_StartAbs;
4740 pCmd->startTime = pOp->startTime;
4741 }
4742
4743 /* Cancel ongoing yielding */
4744 h->state.bYielded = false;
4745
4746 /* Submit to pending command to the queue. */
4747 List_put(&RF_cmdQ.pPend, (List_Elem*)pCmd);
4748
4749 /* Trigger dispatcher if the timings need to be reconsidered. */
4750 if (List_head(&RF_cmdQ.pPend) == (List_Elem*)pCmd)
4751 {
4752 RF_dispatchNextEvent();
4753 }
4754
4755 /* Return with the command handle as success */
4756 cmdHandle = pCmd->ch;
4757 }
4758
4759 /* Exit critical section */
4760 HwiP_restore(key);
4761
4762 /* Return with an error code */
4763 return(cmdHandle);
4764 }
4765
4766 /*
4767 * ==================== RF_ScheduleCmdParams_init ============================
4768 * Initialize the parameter structure to be used with RF_scheduleCmd().
4769 */
RF_ScheduleCmdParams_init(RF_ScheduleCmdParams * pSchParams)4770 void RF_ScheduleCmdParams_init(RF_ScheduleCmdParams *pSchParams)
4771 {
4772 /* Assert */
4773 DebugP_assert(pSchParams != NULL);
4774
4775 /* Set the configuration to use the default values. */
4776 pSchParams->startTime = 0;
4777 pSchParams->startType = RF_StartNotSpecified;
4778 pSchParams->allowDelay = RF_AllowDelayAny;
4779 pSchParams->endTime = 0;
4780 pSchParams->endType = RF_EndNotSpecified;
4781 pSchParams->duration = 0;
4782 pSchParams->activityInfo = 0;
4783 pSchParams->coexPriority = RF_PriorityCoexDefault;
4784 pSchParams->coexRequest = RF_RequestCoexDefault;
4785 }
4786
4787 /*
4788 * ==================== RF_scheduleCmd ============================
4789 * Process request to schedule new command from a particular client
4790 */
RF_scheduleCmd(RF_Handle h,RF_Op * pOp,RF_ScheduleCmdParams * pSchParams,RF_Callback pCb,RF_EventMask bmEvent)4791 RF_CmdHandle RF_scheduleCmd(RF_Handle h, RF_Op* pOp, RF_ScheduleCmdParams *pSchParams, RF_Callback pCb, RF_EventMask bmEvent)
4792 {
4793 /* Local variable declaration. */
4794 RF_Cmd* pCmd;
4795 RF_Handle h2;
4796 RF_ScheduleStatus status;
4797
4798 /* Assert. */
4799 DebugP_assert(h != NULL);
4800 DebugP_assert(pOp != NULL);
4801
4802 /* Local pointer to a radio commands. */
4803 RF_CmdHandle cmdHandle = (RF_CmdHandle)RF_ALLOC_ERROR;
4804
4805 /* Enter critical section. */
4806 uint32_t key = HwiP_disable();
4807
4808 /* Assign h2 to client that is not issuing the new command.
4809 The client h is issuing the new command. */
4810 if (h == RF_Sch.clientHnd[0])
4811 {
4812 h2 = RF_Sch.clientHnd[1];
4813 }
4814 else
4815 {
4816 h2 = RF_Sch.clientHnd[0];
4817 }
4818
4819 /* If client h2 already has, reject any new commands from h. */
4820 if (h2 && (ClockP_isActive(&h2->state.clkReqAccess)))
4821 {
4822 /* Set the status value to schedule_error if we could not allocate space. */
4823 cmdHandle = (RF_CmdHandle) RF_ScheduleStatusError;
4824
4825 /* Store the reason and the handle why the callback is being invoked. */
4826 RF_Sch.issueRadioFreeCbFlags |= RF_RADIOFREECB_CMDREJECT_FLAG;
4827 RF_Sch.clientHndRadioFreeCb = h;
4828 }
4829 else
4830 {
4831 /* Check if command queue has free entries and allocate RF_Op* container
4832 if command queue is full reject the command. */
4833 pCmd = RF_cmdAlloc();
4834
4835 /* If allocation was successful. */
4836 if (pCmd)
4837 {
4838 /* Stop inactivity clock if running. */
4839 ClockP_stop(&RF_clkInactivityObj);
4840
4841 /* Increment the sequence number and mask the value. */
4842 RF_cmdQ.nSeqPost = (RF_cmdQ.nSeqPost + 1) & N_CMD_MODMASK;
4843
4844 /* Cache meta-data. */
4845 pCmd->pOp = pOp;
4846 pCmd->ePri = RF_PriorityNormal;
4847 pCmd->pCb = pCb;
4848 pCmd->ch = RF_cmdQ.nSeqPost;
4849 pCmd->pClient = h;
4850 pCmd->bmEvent = bmEvent & ~RF_INTERNAL_IFG_MASK;
4851 pCmd->flags = 0;
4852 pCmd->pastifg = 0;
4853 pCmd->endTime = pSchParams->endTime;
4854 pCmd->endType = pSchParams->endType;
4855 pCmd->startTime = pSchParams->startTime;
4856 pCmd->startType = pSchParams->startType;
4857 pCmd->allowDelay = pSchParams->allowDelay;
4858 pCmd->duration = pSchParams->duration;
4859 pCmd->activityInfo = pSchParams->activityInfo;
4860 pCmd->coexPriority = pSchParams->coexPriority;
4861 pCmd->coexRequest = pSchParams->coexRequest;
4862
4863 /* Update the default endTime based on the scheduling parameters. */
4864 if (pSchParams->endType == RF_EndNotSpecified)
4865 {
4866 if (pSchParams->endTime != 0)
4867 {
4868 pCmd->endType = RF_EndAbs;
4869 }
4870 }
4871
4872 /* Update the default startTime based on the command parameters. */
4873 if (pSchParams->startType == RF_StartNotSpecified)
4874 {
4875 if (pOp->startTrigger.triggerType == TRIG_ABSTIME)
4876 {
4877 pCmd->startType = RF_StartAbs;
4878 pCmd->startTime = pOp->startTime;
4879 }
4880 }
4881
4882 /* Find the last radio operation within the chain. */
4883 RF_Op* pEndOfChain = RF_findEndOfChain(pOp);
4884
4885 /* Mark the context of the command based on it's ID and subscribe it
4886 to the expected termination event. */
4887 if ((pEndOfChain->commandNo & RF_IEEE_ID_MASK) == RF_IEEE_FG_CMD)
4888 {
4889 pCmd->flags |= RF_CMD_FG_CMD_FLAG;
4890 pCmd->bmEvent |= RFC_DBELL_RFCPEIFG_LAST_FG_COMMAND_DONE_M;
4891 }
4892 else
4893 {
4894 pCmd->bmEvent |= RFC_DBELL_RFCPEIFG_LAST_COMMAND_DONE_M;
4895 }
4896
4897 /* Cancel the radio free callback if new command is from the same client. */
4898 if ((RF_Sch.clientHndRadioFreeCb == h) &&
4899 (RF_Sch.issueRadioFreeCbFlags & RF_RADIOFREECB_PREEMPT_FLAG))
4900 {
4901 RF_Sch.issueRadioFreeCbFlags &= ~RF_RADIOFREECB_PREEMPT_FLAG;
4902 }
4903
4904 /* Invoke the submit policy which shall identify where exactly the new command is being
4905 inserted based on the application level prioritization table. */
4906 if (RFCC26XX_schedulerPolicy.submitHook == NULL)
4907 {
4908 status = RF_ScheduleStatusError;
4909 }
4910 else
4911 {
4912 /* Execute the scheduling logic and queue management. */
4913 status = RFCC26XX_schedulerPolicy.submitHook(pCmd,
4914 RF_cmdQ.pCurrCmdBg,
4915 RF_cmdQ.pCurrCmdFg,
4916 &RF_cmdQ.pPend,
4917 &RF_cmdQ.pDone);
4918
4919 /* In case of rescheduling (re-entering the same command), the assigned handle will
4920 not match and the counter need to be corrected. */
4921 if ((status != RF_ScheduleStatusError) && (RF_cmdQ.nSeqPost != pCmd->ch))
4922 {
4923 /* Decrement the sequence number and mask the value. */
4924 RF_cmdQ.nSeqPost = (RF_cmdQ.nSeqPost - 1) & N_CMD_MODMASK;
4925 }
4926 }
4927
4928 /* Command was rejected. Either there was no slot available, or the timing did not fit. */
4929 if ((status == RF_ALLOC_ERROR) || (status == RF_ScheduleStatusError))
4930 {
4931 /* Decrement the sequence number and mask the value. */
4932 RF_cmdQ.nSeqPost = (RF_cmdQ.nSeqPost - 1) & N_CMD_MODMASK;
4933
4934 /* Store the reason and the handle why the callback is being invoked. */
4935 RF_Sch.issueRadioFreeCbFlags |= RF_RADIOFREECB_CMDREJECT_FLAG;
4936 RF_Sch.clientHndRadioFreeCb = h;
4937
4938 /* Ensure that the error code reflects the reason of rejection. */
4939 cmdHandle = (RF_CmdHandle) status;
4940 }
4941 else
4942 {
4943 /* Command was inserted. Return with the valid handle. */
4944 cmdHandle = pCmd->ch;
4945
4946 /* Mark the command as being allocated. */
4947 pCmd->flags |= RF_CMD_ALLOC_FLAG;
4948
4949 /* Cancel previous yielding. */
4950 h->state.bYielded = false;
4951
4952 /* Trigger dispatcher if the timings need to be reconsidered. */
4953 if ((List_head(&RF_cmdQ.pPend) == (List_Elem*)pCmd) ||
4954 (pCmd->pOp->startTrigger.triggerType == TRIG_ABSTIME))
4955 {
4956 RF_dispatchNextEvent();
4957 }
4958 }
4959 }
4960 }
4961
4962 /* Exit critical section. */
4963 HwiP_restore(key);
4964
4965 /* Return with the command handle. */
4966 return(cmdHandle);
4967 }
4968
4969 /*
4970 * ======== RF_pendCmd ========
4971 * Pend on radio command
4972 */
RF_pendCmd(RF_Handle h,RF_CmdHandle ch,RF_EventMask bmEvent)4973 RF_EventMask RF_pendCmd(RF_Handle h, RF_CmdHandle ch, RF_EventMask bmEvent)
4974 {
4975 /* Assert */
4976 DebugP_assert(h != NULL);
4977
4978 /* If the command handle is invalid (i.e. RF_ALLOC_ERROR) */
4979 if (ch < 0)
4980 {
4981 /* Return with zero means the command was rejected earlier */
4982 return(0);
4983 }
4984
4985 /* Enter critical section */
4986 uint32_t key = SwiP_disable();
4987
4988 /* Find the command based on its handle in the command pool */
4989 RF_Cmd* pCmd = RF_cmdGet(h, ch, RF_CMD_ALLOC_FLAG);
4990
4991 /* If the command was already disposed */
4992 if (!pCmd || !(pCmd->flags & RF_CMD_ALLOC_FLAG))
4993 {
4994 /* Exit critical section */
4995 SwiP_restore(key);
4996
4997 /* Return with last command done event */
4998 return(RF_EventLastCmdDone);
4999 }
5000
5001 /* Expand the pend mask to accept RF_EventLastCmdDone and RF_EventLastFGCmdDone events even if it is not given explicitely */
5002 bmEvent = (bmEvent | RF_TERMINATION_EVENT_MASK);
5003
5004 /* If the command is being executed, but the event we pending on has already happend (i.e. in a chain),
5005 return the past events */
5006 if (pCmd->pastifg & bmEvent)
5007 {
5008 /* Exit critical section */
5009 SwiP_restore(key);
5010
5011 /* Store the cause of returning */
5012 h->state.unpendCause = pCmd->pastifg & bmEvent;
5013
5014 /* Clear the handled past events so it is possible to pend again */
5015 pCmd->pastifg &= ~h->state.unpendCause;
5016
5017 /* Return with the events */
5018 return(h->state.unpendCause);
5019 }
5020
5021 /* Command has still not finished, override user callback with one that calls the user callback then posts to semaphore */
5022 if (pCmd->pCb != RF_syncCb)
5023 {
5024 /* Temporarily store the callback function */
5025 h->state.pCbSync = (void*)pCmd->pCb;
5026
5027 /* Exhange the callback function: this will invoke the user callback and post to the semaphore if needed */
5028 pCmd->pCb = RF_syncCb;
5029 }
5030
5031 /* Store the event subscriptions in the clients context. This can only be one of the already enabled
5032 interrupt sources by RF_postCmd (including RF_EventLastCmdDone) */
5033 h->state.eventSync = bmEvent;
5034
5035 /* Exit critical section */
5036 SwiP_restore(key);
5037
5038 /* Wait for semaphore */
5039 SemaphoreP_pend(&h->state.semSync, SemaphoreP_WAIT_FOREVER);
5040
5041 /* Return the events that resulted in releasing the RF_pend() call */
5042 return(h->state.unpendCause);
5043 }
5044
5045 /*
5046 * ======== RF_runCmd ========
5047 * Run to completion a posted command
5048 */
RF_runCmd(RF_Handle h,RF_Op * pOp,RF_Priority ePri,RF_Callback pCb,RF_EventMask bmEvent)5049 RF_EventMask RF_runCmd(RF_Handle h, RF_Op* pOp, RF_Priority ePri, RF_Callback pCb, RF_EventMask bmEvent)
5050 {
5051 /* Assert */
5052 DebugP_assert(h != NULL);
5053
5054 /* Post the requested command */
5055 RF_CmdHandle ch = RF_postCmd(h, pOp, ePri, pCb, bmEvent);
5056
5057 /* If the command was accepted, pend until one of the special events occur */
5058 return(RF_pendCmd(h, ch, RF_TERMINATION_EVENT_MASK));
5059 }
5060
5061 /*
5062 * ======== RF_runScheduleCmd ========
5063 * Run to completion a scheduled command
5064 */
RF_runScheduleCmd(RF_Handle h,RF_Op * pOp,RF_ScheduleCmdParams * pSchParams,RF_Callback pCb,RF_EventMask bmEvent)5065 RF_EventMask RF_runScheduleCmd(RF_Handle h, RF_Op* pOp, RF_ScheduleCmdParams *pSchParams, RF_Callback pCb, RF_EventMask bmEvent)
5066 {
5067 /* Assert */
5068 DebugP_assert(h != NULL);
5069
5070 /* Post the requested command */
5071 RF_CmdHandle ch = RF_scheduleCmd(h, pOp, pSchParams, pCb, bmEvent);
5072
5073 /* If the command was accepted, pend until one of the special events occur */
5074 return(RF_pendCmd(h, ch, RF_TERMINATION_EVENT_MASK));
5075 }
5076
5077 /*
5078 * ======== RF_yieldCmd ========
5079 * Release client access
5080 */
RF_yield(RF_Handle h)5081 void RF_yield(RF_Handle h)
5082 {
5083 /* Assert */
5084 DebugP_assert(h != NULL);
5085
5086 /* Enter critical section */
5087 uint32_t key = HwiP_disable();
5088
5089 /* Request the synchronization of RTC and RAT at next power down. This is trigged
5090 by ceiling the active time to the maximum value. */
5091 RF_core.activeTimeUs = UINT32_MAX;
5092
5093 /* Stop ongoing request access and issue callback if the radio is off */
5094 ClockP_stop((&h->state.clkReqAccess));
5095
5096 /* If all commands are done */
5097 if (RF_cmdQ.nSeqDone == RF_cmdQ.nSeqPost)
5098 {
5099 if ((RF_core.status != RF_CoreStatusActive) && RF_Sch.issueRadioFreeCbFlags)
5100 {
5101 /* Exit critical section. */
5102 HwiP_restore(key);
5103
5104 /* Invoke the radio free callback provided by the user. */
5105 RF_issueRadioFreeCb(RF_RADIOFREECB_REQACCESS_FLAG |
5106 RF_RADIOFREECB_PREEMPT_FLAG |
5107 RF_RADIOFREECB_CMDREJECT_FLAG);
5108
5109 /* Enter critical section. */
5110 key = HwiP_disable();
5111 }
5112 }
5113
5114 /* If the radioFreeCb did not post new commands. */
5115 if (RF_cmdQ.nSeqDone == RF_cmdQ.nSeqPost)
5116 {
5117 /* All commands are done. Stop inactivity timer. */
5118 ClockP_stop(&RF_clkInactivityObj);
5119
5120 /* Potentially power down the RF core. */
5121 RF_powerConstraintRelease(RF_PowerConstraintCmdQ);
5122 }
5123 else
5124 {
5125 /* There are still client commands that haven't finished.
5126 Set flag to indicate immediate powerdown when last command is done. */
5127 h->state.bYielded = true;
5128 }
5129
5130 /* Exit critical section */
5131 HwiP_restore(key);
5132 }
5133
5134 /*
5135 * ======== RF_cancelCmd ========
5136 * Cancel single radio command
5137 */
RF_cancelCmd(RF_Handle h,RF_CmdHandle ch,uint8_t mode)5138 RF_Stat RF_cancelCmd(RF_Handle h, RF_CmdHandle ch, uint8_t mode)
5139 {
5140 /* Assert */
5141 DebugP_assert(h != NULL);
5142
5143 /* Decode what method to be used for terminating the commands. */
5144 bool graceful = (bool)(mode & RF_ABORT_GRACEFULLY);
5145 bool flush = (bool)(mode & RF_ABORT_FLUSH_ALL);
5146 bool preempt = (bool)(mode & RF_ABORT_PREEMPTION);
5147
5148 /* Invoke the aborting process with the input arguments on a single command */
5149 return(RF_abortCmd(h, ch, graceful, flush, preempt));
5150 }
5151
5152 /*
5153 * ======== RF_flushCmd ========
5154 * Cancel multiple radio commands from a client
5155 */
RF_flushCmd(RF_Handle h,RF_CmdHandle ch,uint8_t mode)5156 RF_Stat RF_flushCmd(RF_Handle h, RF_CmdHandle ch, uint8_t mode)
5157 {
5158 /* Assert */
5159 DebugP_assert(h != NULL);
5160
5161 /* Decode what method to be used for terminating the commands. */
5162 bool graceful = (bool)(mode & RF_ABORT_GRACEFULLY);
5163 bool flush = true;
5164 bool preempt = (bool)(mode & RF_ABORT_PREEMPTION);
5165
5166 /* Abort multiple radio commands implicitly */
5167 return(RF_abortCmd(h, ch, graceful, flush, preempt));
5168 }
5169
5170 /*
5171 * ======== RF_Params_init ========
5172 * Initialize the RF_params to default value
5173 */
RF_Params_init(RF_Params * params)5174 void RF_Params_init(RF_Params *params)
5175 {
5176 /* Assert */
5177 DebugP_assert(params != NULL);
5178
5179 /* Assign default values for RF_params */
5180 *params = RF_defaultParams;
5181 }
5182
5183 /*
5184 * ======== RF_runImmediateCmd ========
5185 * Run immediate command
5186 */
RF_runImmediateCmd(RF_Handle h,uint32_t * pCmd)5187 RF_Stat RF_runImmediateCmd(RF_Handle h, uint32_t* pCmd)
5188 {
5189 /* Assert */
5190 DebugP_assert(h != NULL);
5191
5192 /* Submit the command to the RF core */
5193 return(RF_runDirectImmediateCmd(h, (uint32_t)pCmd, NULL));
5194 }
5195
5196 /*
5197 * ======== RF_runDirectCmd ========
5198 * Run direct command
5199 */
RF_runDirectCmd(RF_Handle h,uint32_t cmd)5200 RF_Stat RF_runDirectCmd(RF_Handle h, uint32_t cmd)
5201 {
5202 /* Assert */
5203 DebugP_assert(h != NULL);
5204
5205 /* Submit the command to the RF core */
5206 return(RF_runDirectImmediateCmd(h, cmd, NULL));
5207 }
5208
5209 /*
5210 * ======== RF_getRssi ========
5211 * Get RSSI value
5212 */
RF_getRssi(RF_Handle h)5213 int8_t RF_getRssi(RF_Handle h)
5214 {
5215 /* Assert */
5216 DebugP_assert(h != NULL);
5217
5218 /* Local variable. */
5219 uint32_t rawRssi;
5220
5221 /* Read the RSSI value if possible. */
5222 RF_Stat status = RF_runDirectImmediateCmd(h, CMDR_DIR_CMD(CMD_GET_RSSI), &rawRssi);
5223
5224 /* Decode the RSSI value if possible. */
5225 if (status == RF_StatCmdDoneSuccess)
5226 {
5227 return((int8_t)((rawRssi >> RF_SHIFT_16_BITS) & RF_CMDSTA_REG_VAL_MASK));
5228 }
5229 else
5230 {
5231 return((int8_t)RF_GET_RSSI_ERROR_VAL);
5232 }
5233 }
5234
5235 /*
5236 * ======== RF_getInfo ========
5237 * Get RF driver info
5238 */
RF_getInfo(RF_Handle h,RF_InfoType type,RF_InfoVal * pValue)5239 RF_Stat RF_getInfo(RF_Handle h, RF_InfoType type, RF_InfoVal *pValue)
5240 {
5241 /* Prepare the default status value */
5242 RF_Stat status = RF_StatSuccess;
5243
5244 /* Enter critical section */
5245 uint32_t key = HwiP_disable();
5246
5247 /* Serve the different flavor of requests */
5248 switch (type)
5249 {
5250 case RF_GET_CURR_CMD:
5251 /* Get the handle of the currently running command. It can be conerted
5252 to a pointer through the RF_getCmdOp() API. */
5253 if (RF_cmdQ.pCurrCmdBg)
5254 {
5255 pValue->ch = RF_cmdQ.pCurrCmdBg->ch;
5256 }
5257 else
5258 {
5259 status = RF_StatError;
5260 }
5261 break;
5262
5263 case RF_GET_AVAIL_RAT_CH:
5264 /* Get available user channels within the RAT timer.
5265 These channels can be allocated and used by the application. */
5266 pValue->availRatCh = RF_ratModule.availableRatChannels;
5267 break;
5268
5269 case RF_GET_RADIO_STATE:
5270 /* Get current radio state */
5271 pValue->bRadioState = (RF_core.status == RF_CoreStatusActive) ? true : false;
5272 break;
5273
5274 case RF_GET_CLIENT_LIST:
5275 /* Copy the client pointer list ([0] -> client 1, [1] -> client 2) */
5276 pValue->pClientList[0] = RF_Sch.clientHnd[0];
5277 pValue->pClientList[1] = RF_Sch.clientHnd[1];
5278 break;
5279
5280 case RF_GET_CLIENT_SWITCHING_TIME:
5281 /* Copy the phy switching times to the RF_InfoVal structure */
5282 pValue->phySwitchingTimeInUs[0] = RF_Sch.clientHnd[0] ? RF_Sch.clientHnd[0]->clientConfig.nPhySwitchingDuration : 0;
5283 pValue->phySwitchingTimeInUs[1] = RF_Sch.clientHnd[1] ? RF_Sch.clientHnd[1]->clientConfig.nPhySwitchingDuration : 0;
5284 break;
5285
5286 default:
5287 status = RF_StatInvalidParamsError;
5288 break;
5289 }
5290
5291 /* Exit critical section */
5292 HwiP_restore(key);
5293
5294 /* Return with a status code */
5295 return(status);
5296 }
5297
5298 /*
5299 * ======== RF_getCmdOp ========
5300 * Get RF command
5301 */
RF_getCmdOp(RF_Handle h,RF_CmdHandle ch)5302 RF_Op* RF_getCmdOp(RF_Handle h, RF_CmdHandle ch)
5303 {
5304 /* Assert */
5305 DebugP_assert(h != NULL);
5306
5307 /* Find the command in the command pool based on its handle */
5308 RF_Cmd* pCmd = RF_cmdGet(h, ch, RF_CMD_ALLOC_FLAG);
5309
5310 /* If the command is found */
5311 if (pCmd)
5312 {
5313 /* Return with the first operation in the command */
5314 return(pCmd->pOp);
5315 }
5316 else
5317 {
5318 /* Return with null in case of error */
5319 return(NULL);
5320 }
5321 }
5322
5323 /*
5324 * ======== RF_RatConfigCompare_init ========
5325 * Initialize RAT compare configuration
5326 */
RF_RatConfigCompare_init(RF_RatConfigCompare * channelConfig)5327 void RF_RatConfigCompare_init(RF_RatConfigCompare* channelConfig)
5328 {
5329 /* Assert */
5330 DebugP_assert(channelConfig != NULL);
5331
5332 /* Set the values to default. */
5333 memset((void*)channelConfig, 0, sizeof(RF_RatConfigCompare));
5334
5335 /* Set the default allocation method to use any channel. */
5336 channelConfig->channel = RF_RatChannelAny;
5337 }
5338
5339 /*
5340 * ======== RF_RatConfigCapture_init ========
5341 * Initialize RAT capture configuration
5342 */
RF_RatConfigCapture_init(RF_RatConfigCapture * channelConfig)5343 void RF_RatConfigCapture_init(RF_RatConfigCapture* channelConfig)
5344 {
5345 /* Assert */
5346 DebugP_assert(channelConfig != NULL);
5347
5348 /* Set the values to default. */
5349 memset((void*)channelConfig, 0, sizeof(RF_RatConfigCapture));
5350
5351 /* Set the default allocation method to use any channel. */
5352 channelConfig->channel = RF_RatChannelAny;
5353 }
5354
5355 /*
5356 * ======== RF_RatConfigOutput_init ========
5357 * Initialize RAT IO configuration
5358 */
RF_RatConfigOutput_init(RF_RatConfigOutput * ioConfig)5359 void RF_RatConfigOutput_init(RF_RatConfigOutput* ioConfig)
5360 {
5361 /* Assert */
5362 DebugP_assert(ioConfig != NULL);
5363
5364 /* Set the values to default. */
5365 memset((void*)ioConfig, 0, sizeof(RF_RatConfigOutput));
5366 }
5367
5368 /*
5369 * ======== RF_ratCompare ========
5370 * Set RAT compare
5371 */
RF_ratCompare(RF_Handle rfHandle,RF_RatConfigCompare * channelConfig,RF_RatConfigOutput * ioConfig)5372 RF_RatHandle RF_ratCompare(RF_Handle rfHandle, RF_RatConfigCompare* channelConfig, RF_RatConfigOutput* ioConfig)
5373 {
5374 /* Assert */
5375 DebugP_assert(h != NULL);
5376
5377 /* Configure the RAT channel into COMPARE mode. */
5378 return(RF_ratSetupChannel(rfHandle, RF_RatModeCompare, channelConfig->callback, channelConfig->channel, (void*) channelConfig, ioConfig));
5379 }
5380
5381 /*
5382 * ======== RF_ratCapture ========
5383 * Set RAT capture
5384 */
RF_ratCapture(RF_Handle rfHandle,RF_RatConfigCapture * channelConfig,RF_RatConfigOutput * ioConfig)5385 RF_RatHandle RF_ratCapture(RF_Handle rfHandle, RF_RatConfigCapture* channelConfig, RF_RatConfigOutput* ioConfig)
5386 {
5387 /* Assert */
5388 DebugP_assert(h != NULL);
5389
5390 /* Configure the RAT channel into CAPTURE mode. */
5391 return(RF_ratSetupChannel(rfHandle, RF_RatModeCapture, channelConfig->callback, channelConfig->channel, (void*) channelConfig, ioConfig));
5392 }
5393
5394 /*
5395 * ======== RF_ratDisableChannel ========
5396 * Disable RAT channel
5397 */
RF_ratDisableChannel(RF_Handle h,RF_RatHandle ratHandle)5398 RF_Stat RF_ratDisableChannel(RF_Handle h, RF_RatHandle ratHandle)
5399 {
5400 /* Assert */
5401 DebugP_assert(h != NULL);
5402
5403 /* Default return value */
5404 RF_Stat status = RF_StatError;
5405
5406 /* Enter critical section. */
5407 uint32_t key = HwiP_disable();
5408
5409 /* Find the pointer to the RAT channel configuration. */
5410 RF_RatChannel* ratCh = RF_ratGetChannel(ratHandle);
5411
5412 /* If the provided handler is valid. */
5413 if (ratCh && ratCh->status && (ratCh->pClient == h))
5414 {
5415 /* If the RF core is active, abort the RAT event. */
5416 if (RF_core.status == RF_CoreStatusActive)
5417 {
5418 /* Calculate the configuration field of command (the channel we disable). */
5419 uint16_t config = (uint16_t)(RF_RAT_CH_LOWEST + ratCh->handle) << RF_SHIFT_8_BITS;
5420
5421 /* Disable the channel within the RF core.
5422 It has been checked that RAT channel to be disabled is owned by the input handle h.
5423 Call the function that executes the disabling with RF_currClient as input argument in
5424 instead of h in order to force the function to accept the disable request. This is
5425 required in the case where the client that will disable a RAT channel is not the same
5426 client as currently controlling the radio.
5427 */
5428 status = RF_runDirectImmediateCmd(RF_currClient, ((uint32_t)CMDR_DIR_CMD_2BYTE(CMD_DISABLE_RAT_CH, config)), NULL);
5429
5430 /* Free the container for further use. We do it after the direct command to be sure it is not powered down.
5431 This will implicitely schedule the next event and run the power management accordingly. */
5432 RF_ratFreeChannel(ratCh);
5433 }
5434 else
5435 {
5436 /* Set status to be successful. */
5437 status = RF_StatCmdDoneSuccess;
5438
5439 /* Free the container for further use. If possible, power down the radio. */
5440 RF_ratFreeChannel(ratCh);
5441
5442 /* Recalculate the next wakeup event if the radio was off. */
5443 RF_dispatchNextEvent();
5444 }
5445 }
5446
5447 /* Exit critical section. */
5448 HwiP_restore(key);
5449
5450 /* Return with the status code */
5451 return(status);
5452 }
5453
5454 /*
5455 * ======== RF_control ========
5456 * RF control
5457 */
RF_control(RF_Handle h,int8_t ctrl,void * args)5458 RF_Stat RF_control(RF_Handle h, int8_t ctrl, void *args)
5459 {
5460 /* Assert */
5461 DebugP_assert(h != NULL);
5462
5463 /* Prepare the return value for worst case scenario */
5464 RF_Stat status = RF_StatSuccess;
5465
5466 /* Enter critical section */
5467 uint32_t key = HwiP_disable();
5468
5469 /* Serve the different requests */
5470 switch (ctrl)
5471 {
5472 case RF_CTRL_SET_INACTIVITY_TIMEOUT:
5473 /* Update the inactivity timeout of the client.
5474 This can be used if the value given at RF_open
5475 need to be updated */
5476 h->clientConfig.nInactivityTimeout = *(uint32_t *)args;
5477 break;
5478
5479 case RF_CTRL_UPDATE_SETUP_CMD:
5480 /* Enable a special boot process which can be controlled
5481 through the config field of the radio setup command.
5482 This will influence only the next power up sequence
5483 and will be reset automatically afterwards. The special
5484 power up process will require longer power up time, hence
5485 the nPowerUpDuration need to be increased */
5486 h->clientConfig.bUpdateSetup = true;
5487 h->clientConfig.nPowerUpDuration += RF_ANALOG_CFG_TIME_US;
5488 break;
5489
5490 case RF_CTRL_SET_POWERUP_DURATION_MARGIN:
5491 /* Configure the margin which is added to the measured
5492 nPowerUpDuration. This can ensure that the commands
5493 are executed on time, depending on the load of the
5494 cpu */
5495 h->clientConfig.nPowerUpDurationMargin = *(uint32_t *)args;
5496 break;
5497
5498 case RF_CTRL_SET_PHYSWITCHING_DURATION_MARGIN:
5499 /* Configure the margin which is added to the measured
5500 nPowerUpDuration. This can ensure that the commands
5501 are executed on time, depending on the load of the
5502 cpu */
5503 h->clientConfig.nPhySwitchingDurationMargin = *(uint32_t *)args;
5504 break;
5505
5506 case RF_CTRL_SET_RAT_RTC_ERR_TOL_VAL:
5507 /* Configure the tolerance value which is used to determine
5508 the period when the RAT need to be syncronized to the RTC
5509 due to the frequency offset */
5510 RF_errTolValInUs = *(uint32_t*)args;
5511 break;
5512
5513 case RF_CTRL_SET_POWER_MGMT:
5514 /* The RF drivers power management can be enabled/disabled by
5515 directly setting the power constraints from the application.
5516 It is important that the order of actions align. */
5517 if (*(uint32_t*)args == 0)
5518 {
5519 RF_powerConstraintSet(RF_PowerConstraintDisallow);
5520 }
5521 else if (*(uint32_t*)args == 1)
5522 {
5523 RF_powerConstraintRelease(RF_PowerConstraintDisallow);
5524 }
5525 else
5526 {
5527 status = RF_StatInvalidParamsError;
5528 }
5529 break;
5530
5531 case RF_CTRL_SET_HWI_PRIORITY:
5532 /* Changing priorities during run-time has constraints.
5533 To not mess up with the RF driver, we require the RF
5534 driver to be inactive. */
5535 if (RF_core.status || (List_head(&RF_cmdQ.pPend)))
5536 {
5537 status = RF_StatBusyError;
5538 }
5539 else
5540 {
5541 HwiP_setPriority(INT_RFC_CPE_0, *(uint32_t *)args);
5542 HwiP_setPriority(INT_RFC_HW_COMB, *(uint32_t *)args);
5543 }
5544 break;
5545
5546 case RF_CTRL_SET_SWI_PRIORITY:
5547 /* Changing priorities during run-time has constraints.
5548 To not mess up with the RF driver, we require the RF
5549 driver to be inactive. */
5550 if (RF_core.status || (List_head(&RF_cmdQ.pPend)))
5551 {
5552 status = RF_StatBusyError;
5553 }
5554 else
5555 {
5556 SwiP_setPriority(&RF_swiFsmObj, *(uint32_t *)args);
5557 SwiP_setPriority(&RF_swiHwObj, *(uint32_t *)args);
5558 }
5559 break;
5560
5561 case RF_CTRL_SET_AVAILABLE_RAT_CHANNELS_MASK:
5562 /* Mask the available RAT channels manually. This can be used when
5563 a particular RAT channel is used through oridnary radio operations
5564 instead of the dedicated RAT APIs. */
5565 RF_ratModule.availableRatChannels = *(uint8_t *)args;
5566 break;
5567
5568 case RF_CTRL_COEX_CONTROL:
5569 /* Pass this request on to the dynamically generated board file
5570 event handler */
5571 RF_invokeGlobalCallback(RF_GlobalEventCoexControl, args);
5572 break;
5573
5574 default:
5575 /* Request can not be served */
5576 status = RF_StatInvalidParamsError;
5577 break;
5578 }
5579
5580 /* Exit critical section */
5581 HwiP_restore(key);
5582
5583 /* Return with the status code */
5584 return(status);
5585 }
5586
5587 /*
5588 * ======== RF_requestAccess ========
5589 * RF request access
5590 */
RF_requestAccess(RF_Handle h,RF_AccessParams * pParams)5591 RF_Stat RF_requestAccess(RF_Handle h, RF_AccessParams *pParams)
5592 {
5593 /* Assert. */
5594 DebugP_assert(h != NULL);
5595 DebugP_assert(pParams != NULL);
5596
5597 /* By default, the status is set to busy. */
5598 RF_Stat status = RF_StatBusyError;
5599
5600 /* Convert the requested duration to us. */
5601 uint32_t durationInUs = RF_convertRatTicksToUs(pParams->duration);
5602
5603 /* Check if the requested period is within the acceptable range. */
5604 if (durationInUs > RF_REQ_ACCESS_MAX_DUR_US)
5605 {
5606 /* Reject the request if not. */
5607 status = RF_StatInvalidParamsError;
5608 }
5609
5610 /* Enter critical section. */
5611 uint32_t key = HwiP_disable();
5612
5613 /* Determine the ID of the requesting client. */
5614 uint8_t clientIdx = 0;
5615 if (h == RF_Sch.clientHnd[1])
5616 {
5617 clientIdx = 1;
5618 }
5619
5620 /* Get handle to the other client. */
5621 RF_Handle h2 = RF_Sch.clientHnd[clientIdx ^ 0x1];
5622
5623 /* Check if the radio is free and if request can be served.
5624 If possible update the RF_Sch structure and start the timer (RTC)
5625 for the request access duration, else, return RF_StatBusyError. */
5626 if (!(h && ClockP_isActive(&h->state.clkReqAccess)) &&
5627 !(h2 && ClockP_isActive(&h2->state.clkReqAccess)))
5628 {
5629 /* Update the scheduler. */
5630 RF_Sch.accReq[clientIdx].duration = pParams->duration;
5631 RF_Sch.accReq[clientIdx].priority = pParams->priority;
5632
5633 /* Start timeout of the request. */
5634 RF_restartClockTimeout(&h->state.clkReqAccess, durationInUs/ClockP_getSystemTickPeriod());
5635
5636 /* Set status to success after the access was granted. */
5637 status = RF_StatSuccess;
5638 }
5639 else
5640 {
5641 /* In case the request can not be served, prepare for a notification
5642 callback when the radio becomes available. */
5643 RF_Sch.issueRadioFreeCbFlags |= RF_RADIOFREECB_REQACCESS_FLAG;
5644 RF_Sch.clientHndRadioFreeCb = h;
5645 }
5646
5647 /* Exit critical section. */
5648 HwiP_restore(key);
5649
5650 /* Return the status. */
5651 return(status);
5652 }
5653
5654 /*
5655 * ======== RF_setTxPower ========
5656 * Set the TX power of the client
5657 */
RF_setTxPower(RF_Handle handle,RF_TxPowerTable_Value value)5658 RF_Stat RF_setTxPower(RF_Handle handle, RF_TxPowerTable_Value value)
5659 {
5660 /* Local variable stores the return value. */
5661 RF_Stat status;
5662
5663 /* Placeholder of the command to be used to update the PA configuration within the RF core immediately. */
5664 RF_ConfigurePaCmd configurePaCmd;
5665
5666 /* Update the setup command to make the changes permanent. */
5667 status = RF_updatePaConfiguration(handle->clientConfig.pRadioSetup, value, &configurePaCmd);
5668
5669 /* If we managed to decode and cache the changes in the setup command. */
5670 if (status == RF_StatSuccess)
5671 {
5672 /* Execute the necessary command to apply the changes. It only takes effect if the RF core
5673 is active and we configure the current client. The IO configuration can be re-evaluated when
5674 the RF core issues the PA_CHANGED interrupt. */
5675 RF_runDirectImmediateCmd(handle, (uint32_t)&configurePaCmd, NULL);
5676 }
5677
5678 /* Return with the status. */
5679 return(status);
5680 }
5681
5682 /*
5683 * ======== RF_getTxPower ========
5684 * Get the current TX power value
5685 */
RF_getTxPower(RF_Handle handle)5686 RF_TxPowerTable_Value RF_getTxPower(RF_Handle handle)
5687 {
5688 /* Default return value. */
5689 RF_TxPowerTable_Value value = { .rawValue = RF_TxPowerTable_INVALID_VALUE,
5690 .paType = RF_TxPowerTable_DefaultPA};
5691
5692 /* Local variables. */
5693 uint16_t* pTxPower = NULL;
5694 uint32_t* pRegOverride = NULL;
5695 uint32_t* pRegOverrideTxStd = NULL;
5696 uint32_t* pRegOverrideTx20 = NULL;
5697
5698 /* Decode if High Gain PA is available. */
5699 bool tx20FeatureAvailable = RF_decodeOverridePointers(handle->clientConfig.pRadioSetup, &pTxPower, &pRegOverride, &pRegOverrideTxStd, &pRegOverrideTx20);
5700
5701 /* Continue the search for the poper value if the High PA is used. */
5702 if (*pTxPower == RF_TX20_ENABLED)
5703 {
5704 /* Local variable. */
5705 uint32_t rawValue;
5706
5707 /* Returning the High Gain PA gain is only possible if the P device is in use. */
5708 if (tx20FeatureAvailable && pRegOverrideTxStd && pRegOverrideTx20)
5709 {
5710 if (RF_getPAOverrideOffsetAndValue(pRegOverrideTx20, RF_TX20_PATTERN, &rawValue) != RF_TX_OVERRIDE_INVALID_OFFSET)
5711 {
5712 /* Return the value found in the gain related list. */
5713 value.rawValue = rawValue;
5714 value.paType = RF_TxPowerTable_HighPA;
5715 }
5716 }
5717 else if (tx20FeatureAvailable)
5718 {
5719 if (RF_getPAOverrideOffsetAndValue(pRegOverride, RF_TX20_PATTERN, &rawValue) != RF_TX_OVERRIDE_INVALID_OFFSET)
5720 {
5721 /* As a backup option, parse the common list too. This is or backward compatibility
5722 and new software shall not rely on this feature. */
5723 value.rawValue = rawValue;
5724 value.paType = RF_TxPowerTable_HighPA;
5725 }
5726 }
5727 }
5728 else
5729 {
5730 /* The value in the .txPower field represents the output power.*/
5731 value.rawValue = *pTxPower;
5732 }
5733
5734 /* Return with the decoded value. */
5735 return(value);
5736 }
5737
5738 /*
5739 * ======== RF_TxPowerTable_findPowerLevel ========
5740 * Retrieves a power level in dBm for a given power configuration value.
5741 */
RF_TxPowerTable_findPowerLevel(RF_TxPowerTable_Entry table[],RF_TxPowerTable_Value value)5742 int8_t RF_TxPowerTable_findPowerLevel(RF_TxPowerTable_Entry table[], RF_TxPowerTable_Value value)
5743 {
5744 /* Iterate through the power table. We do not verify against nullptr. */
5745 uint32_t i;
5746 for (i=0; (table[i].power != RF_TxPowerTable_INVALID_DBM) &&
5747 (table[i].value.rawValue != RF_TxPowerTable_INVALID_VALUE); i++)
5748 {
5749 if (((uint32_t)table[i].value.paType == (uint32_t)value.paType) &&
5750 ((uint32_t)table[i].value.rawValue == (uint32_t)value.rawValue))
5751 {
5752 /* Break the loop on the first entry which satisfies
5753 the lower-or-equal criterion toward the input argument. */
5754 break;
5755 }
5756 }
5757
5758 /* Return with the power level in dBm or with the
5759 termination value RF_TxPowerTable_INVALID_DBM. */
5760 return(table[i].power);
5761 }
5762
5763 /*
5764 * ======== RF_TxPowerTable_findValue ========
5765 * Retrieves a power configuration value for a given power level in dBm.
5766 */
RF_TxPowerTable_findValue(RF_TxPowerTable_Entry table[],int8_t powerLevel)5767 RF_TxPowerTable_Value RF_TxPowerTable_findValue(RF_TxPowerTable_Entry table[], int8_t powerLevel)
5768 {
5769 /* Local variable stores an invalid value. */
5770 RF_TxPowerTable_Value invalidValue = { .rawValue = RF_TxPowerTable_INVALID_VALUE,
5771 .paType = RF_TxPowerTable_DefaultPA };
5772
5773 /* Handle special input argument. */
5774 if (powerLevel == RF_TxPowerTable_MIN_DBM)
5775 {
5776 return(table[0].value);
5777 }
5778 else
5779 {
5780 /* Iterate through the power table. We do not verify against nullptr. */
5781 uint32_t i;
5782 for (i=0; ((int8_t)table[i].power != (int8_t)RF_TxPowerTable_INVALID_DBM) &&
5783 ((uint32_t)table[i].value.rawValue != (uint32_t)RF_TxPowerTable_INVALID_VALUE); i++)
5784 {
5785 if (table[i].power > powerLevel)
5786 {
5787 /* Break the loop on the first entry which satisfies
5788 the lower-or-equal criterion toward the input argument. */
5789 break;
5790 }
5791 }
5792
5793 if (i == 0)
5794 {
5795 /* If the first entry is already larger, then the requested
5796 power level is invalid. */
5797 return(invalidValue);
5798 }
5799 else
5800 {
5801 /* Return with a valid RF_TxPowerTable_Value or with the
5802 maximum value in the table. */
5803 return(table[i-1].value);
5804 }
5805 }
5806 }
5807
5808 /*
5809 * ======== RF_enableHPOSCTemperatureCompensation ========
5810 * Initializes the temperature compensation monitoring (SW TCXO)
5811 * This function enables RF synthesizer temperature compensation
5812 * It is intended for use on the SIP or BAW devices where compensation
5813 * coefficients are available inside the chip.
5814 *
5815 * The name of the function is a misnomer, as it does not only apply to
5816 * HPOSC (BAW) configuration, but will generically enable SW TCXO.
5817 */
RF_enableHPOSCTemperatureCompensation(void)5818 void RF_enableHPOSCTemperatureCompensation(void)
5819 {
5820 int_fast16_t status;
5821
5822 Temperature_init();
5823
5824 int16_t currentTemperature = Temperature_getTemperature();
5825
5826 status = Temperature_registerNotifyRange(&RF_hposcRfCompNotifyObj,
5827 currentTemperature + RF_TEMP_LIMIT_3_DEGREES_CELSIUS,
5828 currentTemperature - RF_TEMP_LIMIT_3_DEGREES_CELSIUS,
5829 RF_hposcRfCompensateFxn,
5830 (uintptr_t)NULL);
5831
5832 pfnUpdateHposcOverride = &RF_updateHpOscOverride;
5833 pfnTemperatureUnregisterNotify = &Temperature_unregisterNotify;
5834
5835 if (status != Temperature_STATUS_SUCCESS)
5836 {
5837 while(1);
5838 }
5839 }
5840