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