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