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(&params.sp);
3628     params.sp.priority = RFCC26XX_hwAttrs.swiPriority;
3629     SwiP_construct(&RF_swiFsmObj, RF_swiFsm, &params.sp);
3630     SwiP_construct(&RF_swiHwObj,  RF_swiHw,  &params.sp);
3631 
3632     /* Initialize HWI used by the RF driver. */
3633     HwiP_Params_init(&params.hp);
3634     params.hp.priority = RFCC26XX_hwAttrs.hwiPriority;
3635     HwiP_construct(&RF_hwiCpe0Obj, INT_RFC_CPE_0,   RF_hwiCpe0PowerFsm, &params.hp);
3636     HwiP_construct(&RF_hwiHwObj,   INT_RFC_HW_COMB, RF_hwiHw,           &params.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