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