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