1 /*
2  * Copyright (c) 2021-2024, 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  *  ======== LRFCC23X0.c ========
34  */
35 
36 #include <stdint.h>
37 #include <stdlib.h>
38 
39 #include <ti/drivers/rcl/LRF.h>
40 #include <ti/drivers/rcl/RCL_Scheduler.h>
41 #include <ti/drivers/rcl/RCL_Command.h>
42 #include <ti/log/Log.h>
43 #include <ti/drivers/dpl/HwiP.h>
44 
45 #include <ti/devices/DeviceFamily.h>
46 #include DeviceFamily_constructPath(inc/hw_lrfddbell.h)
47 #include DeviceFamily_constructPath(inc/hw_lrfdpbe.h)
48 #include DeviceFamily_constructPath(inc/hw_lrfdmdm.h)
49 #include DeviceFamily_constructPath(inc/hw_lrfdmdm32.h)
50 #include DeviceFamily_constructPath(inc/hw_lrfdrfe.h)
51 #include DeviceFamily_constructPath(inc/hw_lrfdrfe32.h)
52 #include DeviceFamily_constructPath(inc/pbe_common_ram_regs.h)
53 #include DeviceFamily_constructPath(inc/rfe_common_ram_regs.h)
54 
55 
56 static uint32_t LRF_findPllMBase(uint32_t frequency);
57 static uint32_t countLeadingZeros(uint16_t value);
58 static uint32_t LRF_findCalM(uint32_t frequency, uint32_t prediv);
59 static uint32_t LRF_findFoff(int32_t frequencyOffset, uint32_t invSynthFreq);
60 static void LRF_programShape(const LRF_TxShape *txShape, uint32_t deviation, uint32_t invSynthFreq);
61 static uint32_t LRF_findLog2Bde1(uint32_t demmisc3);
62 static uint32_t LRF_programPQ(uint32_t pllMBase);
63 static void LRF_programCMixN(int32_t rxIntFrequency, uint32_t invSynthFreq);
64 static void LRF_applyTrim(const LRF_TrimDef *trimDef, const LRF_SwConfig *swConfig);
65 static void LRF_updateTrim(const LRF_TrimDef *trimDef, const LRF_SwConfig *swConfig);
66 static void LRF_setTrimCommon(const LRF_TrimDef *trimDef, const LRF_SwConfig *swConfig);
67 static void LRF_setTemperatureTrim(const LRF_TrimDef *trimDef);
68 static void LRF_temperatureCompensateTrim(const LRF_TrimDef *trimDef);
69 static uint32_t LRF_findExtTrim1TrimAdjustment(uint32_t temperatureDiff, uint32_t tempThreshFactor, uint32_t maxAdjustment);
70 static int32_t LRF_findExtTrim0TrimAdjustment(int32_t temperature, int32_t tempCompFactor, int32_t offset);
71 static uint32_t LRF_scaleFreqWithHFXTOffset(uint32_t frequency);
72 static void LRF_writeFifoPtr(uint32_t value, uintptr_t regAddr);
73 static void LRF_writeFifoPtrs(uint32_t value, uintptr_t regAddr0, uintptr_t regAddr1);
74 
75 uint32_t swParamList[sizeof(LRF_SwParam)/sizeof(uint32_t)];
76 const size_t swParamListSz = sizeof(LRF_SwParam);
77 
78 static struct {
79     const LRF_TOPsmImage   *pbeLoaded;
80     const LRF_TOPsmImage   *mceLoaded;
81     const LRF_TOPsmImage   *rfeLoaded;
82     uint16_t                phyFeatures;
83     LRF_TxPowerTable_Entry  currentTxPower;
84     LRF_TxPowerTable_Entry  rawTxPower;
85 } lrfPhyState = {0};
86 
87 /* Required time from enabling refsys to synth programming */
88 #define LRF_REFSYS_ENABLE_TIME RCL_SCHEDULER_SYSTIM_US(30)
89 
90 /* Status to tell if the RX FIFO is already in a deallocated state (SRP and RP being the same) */
91 static bool rxFifoDeallocated = true;
92 
LRF_setupRadio(const LRF_Config * lrfConfig,uint16_t phyFeatures,LRF_RadioState lrfState)93 LRF_SetupResult LRF_setupRadio(const LRF_Config *lrfConfig, uint16_t phyFeatures, LRF_RadioState lrfState)
94 {
95     enum {
96         trimNoUpdate,
97         trimPartialUpdate,
98         trimFullUpdate
99     } trimUpdate = trimNoUpdate;
100     LRF_SetupResult result = SetupResult_Ok;
101 
102     if (lrfPhyState.pbeLoaded != lrfConfig->pbeImage || lrfState < RadioState_ImagesLoaded)
103     {
104         result = LRF_loadImage(lrfConfig->pbeImage, LRFD_PBERAM_BASE);
105         lrfPhyState.pbeLoaded = lrfConfig->pbeImage;
106     }
107     if ((result == SetupResult_Ok) &&
108         (lrfPhyState.mceLoaded != lrfConfig->mceImage || lrfState < RadioState_ImagesLoaded))
109     {
110         result = LRF_loadImage(lrfConfig->mceImage, LRFD_MCERAM_BASE);
111         lrfPhyState.mceLoaded = lrfConfig->mceImage;
112     }
113     if ((result == SetupResult_Ok) &&
114         (lrfPhyState.rfeLoaded != lrfConfig->rfeImage || lrfState < RadioState_ImagesLoaded))
115     {
116         result = LRF_loadImage(lrfConfig->rfeImage, LRFD_RFERAM_BASE);
117         lrfPhyState.rfeLoaded = lrfConfig->rfeImage;
118     }
119 
120     if ((result == SetupResult_Ok) && (lrfConfig->regConfigList != NULL))
121     {
122         LRF_ApplySettingsBase includeBase;
123 
124         if (lrfState < RadioState_Configured)
125         {
126             includeBase = LRF_ApplySettings_IncludeBase;
127             Log_printf(RclCore, Log_VERBOSE, "Performing full setup");
128             trimUpdate = trimFullUpdate;
129         }
130         else
131         {
132             includeBase = LRF_ApplySettings_NoBase;
133             if (phyFeatures != lrfPhyState.phyFeatures)
134             {
135                 Log_printf(RclCore, Log_VERBOSE, "Changing PHY features");
136                 trimUpdate = trimPartialUpdate;
137             }
138         }
139         if (includeBase == LRF_ApplySettings_IncludeBase || phyFeatures != lrfPhyState.phyFeatures)
140         {
141             LRF_ApplySettingsState settingsState;
142             /* Initialize setup state */
143             lrfPhyState.phyFeatures = phyFeatures;
144             LRF_initSettingsState(&settingsState, includeBase, phyFeatures);
145             for (uint32_t i = 0; i < lrfConfig->regConfigList->numEntries; i++)
146             {
147                 LRF_ConfigWord *config = lrfConfig->regConfigList->entries[i];
148 
149                 result = LRF_applySettings(config, &settingsState, LRF_SETTINGS_BUFFER_UNLIMITED);
150 
151                 if (result != SetupResult_Ok)
152                 {
153                     break;
154                 }
155             }
156         }
157         /* Invalidate RSSI value to cover the case in which no RX has run before. */
158         HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_RSSI) = LRF_RSSI_INVALID;
159         /* Set PBE to writing FIFO commands to FCMD */
160         HWREGH_WRITE_LRF(LRFD_BUFRAM_BASE + PBE_COMMON_RAM_O_FIFOCMDADD) = ((LRFDPBE_BASE + LRFDPBE_O_FCMD) & 0x0FFF) >> 2;
161     }
162 
163     if (result == SetupResult_Ok)
164     {
165         LRF_SwParam *swParam = (LRF_SwParam *) swParamList;
166 
167         if (swParam->swConfig == NULL)
168         {
169             result = SetupResult_ErrorSwConfig;
170         }
171         else
172         {
173             if (trimUpdate == trimFullUpdate)
174             {
175                 LRF_applyTrim(swParam->trimDef, swParam->swConfig);
176             }
177             else if (trimUpdate == trimPartialUpdate)
178             {
179                 LRF_updateTrim(swParam->trimDef, swParam->swConfig);
180             }
181             else
182             {
183                 LRF_setTemperatureTrim(swParam->trimDef);
184             }
185         }
186     }
187     return result;
188 }
189 
LRF_imagesNeedUpdate(const LRF_Config * lrfConfig)190 bool LRF_imagesNeedUpdate(const LRF_Config *lrfConfig)
191 {
192     return ((lrfPhyState.pbeLoaded != lrfConfig->pbeImage && lrfConfig->pbeImage != NULL) ||
193             (lrfPhyState.mceLoaded != lrfConfig->mceImage && lrfConfig->mceImage != NULL) ||
194             (lrfPhyState.rfeLoaded != lrfConfig->rfeImage && lrfConfig->rfeImage != NULL));
195 }
196 
LRF_applyTrim(const LRF_TrimDef * trimDef,const LRF_SwConfig * swConfig)197 static void LRF_applyTrim(const LRF_TrimDef *trimDef, const LRF_SwConfig *swConfig)
198 {
199 
200     if (trimDef != NULL)
201     {
202 #ifdef DeviceFamily_CC27XX
203         if (trimDef->revision >= LRF_TRIM_VERSION_CORRECT_AMOUNT_OF_PA_TRIMS_CC27XX)
204         {
205             HWREGH_WRITE_LRF(LRFD_RFERAM_BASE + RFE_COMMON_RAM_O_PATRIM01) = trimDef->trim0.pa2trim01;
206             HWREGH_WRITE_LRF(LRFD_RFERAM_BASE + RFE_COMMON_RAM_O_PATRIM23) = trimDef->trim4.pa2trim23;
207         }
208         else
209         {
210             /* Workaround: Write trim0.pa2trim01 to all trim fields for revisions where all trim fields are not available in apptrims */
211             uint16_t paTrim = trimDef->trim0.pa2trim01;
212             HWREGH_WRITE_LRF(LRFD_RFERAM_BASE + RFE_COMMON_RAM_O_PATRIM01) = (paTrim << RFE_COMMON_RAM_PATRIM01_VAL1_S) | (paTrim << RFE_COMMON_RAM_PATRIM01_VAL0_S);
213             HWREGH_WRITE_LRF(LRFD_RFERAM_BASE + RFE_COMMON_RAM_O_PATRIM23) = (paTrim << RFE_COMMON_RAM_PATRIM23_VAL3_S) | (paTrim << RFE_COMMON_RAM_PATRIM23_VAL2_S);
214         }
215 #else
216         HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_PA0)        = HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_PA0) | trimDef->trim0.pa0;
217 #endif
218         HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_ATSTREFH)   = HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_ATSTREFH) | trimDef->trim0.atstRefH;
219 
220         HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_LNA)        = HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_LNA) | trimDef->trim1.lna;
221         HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_IFAMPRFLDO) = HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_IFAMPRFLDO) | trimDef->trim1.ifampRfLdo;
222 
223 #ifdef DeviceFamily_CC27XX
224         /* DCOLDO0 Workaround: DCOLDO0:FIRSTTRIM is hardcoded to 8U and DCOLDO0:SECONDTRIM is increased by 10 for CC27XX state B devices (see: RCL-616)
225          * ASSUMPTION: AppTrims revision on CC27XX state C devices is not smaller than 7
226          */
227         if (trimDef->revision >= LRF_TRIM_VERSION_STATE_C_TRIM_WORKAROUND_CC27XX)
228         {
229             HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_DCOLDO0) = HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_DCOLDO0) | trimDef->trim2.dcoLdo0;
230         }
231         else
232         {
233             uint32_t trimDcoldo0Val = trimDef->trim2.dcoLdo0;
234             uint32_t secondTrimVal = (trimDcoldo0Val & LRFDRFE_DCOLDO0_SECONDTRIM_M) >> LRFDRFE_DCOLDO0_SECONDTRIM_S;
235 
236             /* Invert bit 3 and 5 to decode the SECONDTRIM value */
237             uint32_t secondTrimValDecoded = secondTrimVal ^ LRF_TRIM_DCOLDO0_SECONDTRIM_CODED_BITS_MASK_STATE_B_DCOLDO_WORKAROUND_CC27XX;
238             uint32_t newSecondTrimVal = secondTrimValDecoded + LRF_TRIM_DCOLDO0_SECONDTRIM_INC_STATE_B_DCOLDO_WORKAROUND_CC27XX;
239 
240             /* DCOLDO0[13:8]SECONDTRIM is saturated at 63U */
241             if (newSecondTrimVal > LRF_TRIM_DCOLDO0_SECONDTRIM_MAX_STATE_B_DCOLDO_WORKAROUND_CC27XX)
242             {
243                 newSecondTrimVal = LRF_TRIM_DCOLDO0_SECONDTRIM_MAX_STATE_B_DCOLDO_WORKAROUND_CC27XX;
244             }
245 
246             /* Invert bit 3 and 5 to encode the SECONDTRIM value */
247             uint32_t newSecondTrimValCoded = newSecondTrimVal ^ LRF_TRIM_DCOLDO0_SECONDTRIM_CODED_BITS_MASK_STATE_B_DCOLDO_WORKAROUND_CC27XX;
248 
249             /* Hardcode the FIRSTTRIM to 8U */
250             trimDcoldo0Val = (trimDcoldo0Val & ~LRFDRFE_DCOLDO0_FIRSTTRIM_M) | (LRF_TRIM_DCOLDO0_FIRSTTRIM_VALUE_STATE_B_DCOLDO_WORKAROUND_CC27XX << LRFDRFE_DCOLDO0_FIRSTTRIM_S);
251 
252             trimDcoldo0Val = (trimDcoldo0Val & ~LRFDRFE_DCOLDO0_SECONDTRIM_M) | (newSecondTrimValCoded << LRFDRFE_DCOLDO0_SECONDTRIM_S);
253             HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_DCOLDO0) = HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_DCOLDO0) | trimDcoldo0Val;
254         }
255 #else
256         HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_DCOLDO0)    = HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_DCOLDO0) | trimDef->trim2.dcoLdo0;
257 #endif
258         HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_IFADCALDO)  = HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_IFADCALDO) | trimDef->trim2.ifadcAldo;
259         HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_IFADCDLDO)  = HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_IFADCDLDO) | trimDef->trim2.ifadcDldo;
260 
261         /* DEMIQMC0 has no fields not to be trimmed */
262         HWREG_WRITE_LRF(LRFDMDM_BASE + LRFDMDM_O_DEMIQMC0)   =  trimDef->trim4.demIQMC0;
263 
264         /* Write trim to shadow registers */
265         HWREGH_WRITE_LRF(LRFD_RFERAM_BASE + RFE_COMMON_RAM_O_IFAMPRFLDODEFAULT) = HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_IFAMPRFLDO) & LRFDRFE_IFAMPRFLDO_TRIM_M;
266 
267         LRF_setTrimCommon(trimDef, swConfig);
268         LRF_temperatureCompensateTrim(trimDef);
269     }
270 }
271 
LRF_updateTrim(const LRF_TrimDef * trimDef,const LRF_SwConfig * swConfig)272 static void LRF_updateTrim(const LRF_TrimDef *trimDef, const LRF_SwConfig *swConfig)
273 {
274     if (trimDef != NULL)
275     {
276         /* Remove trim fields from registers with BW variations */
277         HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_IFADCQUANT)    = HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_IFADCQUANT) & (~(LRFDRFE_IFADCQUANT_QUANTTHR_M));
278         HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_IFADC0)        = HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_IFADC0) & (~(LRFDRFE_IFADC0_AAFCAP_M | LRFDRFE_IFADC0_INT2ADJ_M | LRFDRFE_IFADC0_DITHEREN_M | LRFDRFE_IFADC0_DITHERTRIM_M));
279         HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_IFADC1)        = HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_IFADC1) & (~(LRFDRFE_IFADC1_TRIM_M | LRFDRFE_IFADC1_NRZ_M));
280         HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_IFADCLF)       = 0; /* All fields are trimmed so everything needs to be cleared */
281         HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_IFAMPRFLDO)    = HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_IFAMPRFLDO) & (~LRFDRFE_IFAMPRFLDO_AAFCAP_M);
282 
283         LRF_setTrimCommon(trimDef, swConfig);
284         LRF_setTemperatureTrim(trimDef);
285     }
286 }
287 
LRF_setTrimCommon(const LRF_TrimDef * trimDef,const LRF_SwConfig * swConfig)288 static void LRF_setTrimCommon(const LRF_TrimDef *trimDef, const LRF_SwConfig *swConfig)
289 {
290     uint8_t bwIndex = 0;
291     uint8_t bwIndexDither = 0;
292     uint8_t revision = trimDef->revision;
293     if (revision >= LRF_TRIM_MIN_VERSION_FULL_FEATURES)
294     {
295         bwIndex = swConfig->bwIndex;
296         bwIndexDither = swConfig->bwIndexDither;
297     }
298     HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_IFADCQUANT) = HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_IFADCQUANT) | trimDef->trimVariant[bwIndex].ifadcQuant;
299     HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_IFADC0)     = HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_IFADC0) | trimDef->trimVariant[bwIndex].ifadc0;
300     HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_IFADC1)     = HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_IFADC1) | trimDef->trimVariant[bwIndex].ifadc1;
301     HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_IFADCLF)    = HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_IFADCLF) | trimDef->trimVariant[bwIndex].ifadclf;
302 
303     if (revision >= LRF_TRIM_MIN_VERSION_FULL_FEATURES)
304     {
305         /* Set AAFCAP according to BW */
306         HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_IFAMPRFLDO) = HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_IFAMPRFLDO) | trimDef->trim4.ifamprfldo[bwIndex];
307 
308         if (bwIndexDither != bwIndex)
309         {
310             /* Use different setting of dither settings compared to the rest of the IFADC0 register. */
311             HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_IFADC0) = (HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_IFADC0) & ~(LRFDRFE_IFADC0_DITHEREN_M | LRFDRFE_IFADC0_DITHERTRIM_M)) |
312                 (trimDef->trimVariant[bwIndexDither].ifadc0 & (LRFDRFE_IFADC0_DITHEREN_M | LRFDRFE_IFADC0_DITHERTRIM_M));
313         }
314     }
315 }
316 
LRF_setTemperatureTrim(const LRF_TrimDef * trimDef)317 static void LRF_setTemperatureTrim(const LRF_TrimDef *trimDef)
318 {
319     if (trimDef != NULL)
320     {
321         /* Remove trim fields from registers with temperature compensation */
322         HWREGH_WRITE_LRF(LRFD_RFERAM_BASE + RFE_COMMON_RAM_O_DIVLDOF) = HWREGH_READ_LRF(LRFD_RFERAM_BASE + RFE_COMMON_RAM_O_DIVLDOF) & (~RFE_COMMON_RAM_DIVLDOF_VOUTTRIM_M);
323         HWREGH_WRITE_LRF(LRFD_RFERAM_BASE + RFE_COMMON_RAM_O_DIVLDOI) = HWREGH_READ_LRF(LRFD_RFERAM_BASE + RFE_COMMON_RAM_O_DIVLDOI) & (~RFE_COMMON_RAM_DIVLDOI_VOUTTRIM_M);
324         HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_TDCLDO)              = HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_TDCLDO) & (~LRFDRFE_TDCLDO_VOUTTRIM_M);
325         HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_DCO)                 = HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_DCO) & (~LRFDRFE_DCO_TAILRESTRIM_M);
326 
327         LRF_temperatureCompensateTrim(trimDef);
328     }
329 }
330 
331 /* Number of shifts in temperature compensation for fields in lrfdrfeExtTrim1 */
332 #define LRF_EXTTRIM1_TEMPERATURE_SCALE_EXP 4U
333 /* Adjustment per step of DIVLDO at lowest temperature */
334 #define LRF_DIVLDO_LOW_TEMP_ADJ_FACTOR 10U
335 /* Adjustment per step of DIVLDO at highest temperature */
336 #define LRF_DIVLDO_HIGH_TEMP_ADJ_FACTOR 10U
337 /* Adjustment per step of TDCLDO at lowest temperature */
338 #define LRF_TDCLDO_LOW_TEMP_ADJ_FACTOR 10U
339 /* Adjustment per step of TDCLDO at highest temperature */
340 #define LRF_TDCLDO_HIGH_TEMP_ADJ_FACTOR 10U
341 /* Adjustment per step of RTRIM at lowest temperature */
342 #define LRF_RTRIM_LOW_TEMP_ADJ_FACTOR 1U
343 /* Adjustment per step of RTRIM at highest temperature */
344 #define LRF_RTRIM_HIGH_TEMP_ADJ_FACTOR 1U
345 /* Maximum allowed value (saturation value) for RTRIM, except if RTRIM value in FCFG is above this level */
346 #define LRF_DEFAULT_RTRIM_MAX 12U
347 
348 /* Number of shifts in temperature compensation for fields in lrfdrfeExtTrim0 */
349 #define LRF_EXTTRIM0_TEMPERATURE_SCALE_EXP 7
350 
351 /* Lowest temperature supported */
352 #define LRF_TEMPERATURE_MIN (-40)
353 /* Highest temperature supported */
354 #define LRF_TEMPERATURE_MAX 125
355 /* Nominal temperature for offset definitions */
356 #define LRF_TEMPERATURE_NOM 25
357 
358 /* Bit masks and positions in SPARE0 and SPARE1 */
359 /* RFE_SPARE0: Fast AGC only */
360 #define RFE_SPARE0_LOW_GAIN_BM  0x000F
361 #define RFE_SPARE0_LOW_GAIN     0
362 #define RFE_SPARE0_HIGH_GAIN_BM 0x00F0
363 #define RFE_SPARE0_HIGH_GAIN    4
364 /* RFE_SPARE1: Fast AGC: Threshold. Standard AGC: Magnitude */
365 /* These fields have the same position in the register */
366 #define RFE_SPARE1_AGC_VALUE_BM 0x000FF
367 #define RFE_SPARE1_AGC_VALUE    0
368 
LRF_temperatureCompensateTrim(const LRF_TrimDef * trimDef)369 static void LRF_temperatureCompensateTrim(const LRF_TrimDef *trimDef)
370 {
371     uint32_t divLdoTempOffset = 0;
372     uint32_t tdcLdoTempOffset = 0;
373     uint32_t rtrimTempOffset = 0;
374     int32_t rssiTempOffset = 0;
375     int32_t agcValOffset = 0;
376     int32_t agcHighGainOffset = 0;
377     int32_t agcLowGainOffset = 0;
378 
379     if (trimDef->revision >= LRF_TRIM_MIN_VERSION_FULL_FEATURES)
380     {
381         int32_t temperature = hal_get_temperature();
382 
383         LRF_Trim_tempLdoRtrim tempLdoRtrim = trimDef->trim3.fields.lrfdrfeExtTrim1.tempLdoRtrim;
384 
385         int32_t tempThreshLow = LRF_TEMPERATURE_MIN + tempLdoRtrim.tThrl * (1 << LRF_EXTTRIM1_TEMPERATURE_SCALE_EXP);
386         int32_t tempThreshHigh = LRF_TEMPERATURE_MAX - tempLdoRtrim.tThrh * (1 << LRF_EXTTRIM1_TEMPERATURE_SCALE_EXP);
387 
388         /* Adjust values for extreme temperatures */
389         if (temperature < tempThreshLow)
390         {
391             uint32_t temperatureDiff = tempThreshLow - temperature;
392             divLdoTempOffset = LRF_findExtTrim1TrimAdjustment(temperatureDiff, tempLdoRtrim.tThrl,
393                 LRF_DIVLDO_LOW_TEMP_ADJ_FACTOR * tempLdoRtrim.divLdoMinOffset);
394             tdcLdoTempOffset = LRF_findExtTrim1TrimAdjustment(temperatureDiff, tempLdoRtrim.tThrl,
395                 LRF_TDCLDO_LOW_TEMP_ADJ_FACTOR * tempLdoRtrim.tdcLdoMinOffset);
396             rtrimTempOffset = LRF_findExtTrim1TrimAdjustment(temperatureDiff, tempLdoRtrim.tThrl,
397                 LRF_RTRIM_LOW_TEMP_ADJ_FACTOR * tempLdoRtrim.rtrimMinOffset);
398         }
399         else if (temperature > tempThreshHigh)
400         {
401             uint32_t temperatureDiff = temperature - tempThreshHigh;
402             divLdoTempOffset = LRF_findExtTrim1TrimAdjustment(temperatureDiff, tempLdoRtrim.tThrh,
403                 LRF_DIVLDO_HIGH_TEMP_ADJ_FACTOR * tempLdoRtrim.divLdoMaxOffset);
404             tdcLdoTempOffset = LRF_findExtTrim1TrimAdjustment(temperatureDiff, tempLdoRtrim.tThrh,
405                 LRF_TDCLDO_HIGH_TEMP_ADJ_FACTOR * tempLdoRtrim.tdcLdoMaxOffset);
406             rtrimTempOffset = LRF_findExtTrim1TrimAdjustment(temperatureDiff, tempLdoRtrim.tThrh,
407                 LRF_RTRIM_HIGH_TEMP_ADJ_FACTOR * tempLdoRtrim.rtrimMaxOffset);
408         }
409 
410         rssiTempOffset = LRF_findExtTrim0TrimAdjustment(temperature, trimDef->trim3.fields.lrfdrfeExtTrim0.rssiTcomp, 0);
411 
412         if (((HWREGH_READ_LRF(LRFD_RFERAM_BASE + RFE_COMMON_RAM_O_AGCINFO) & RFE_COMMON_RAM_AGCINFO_MODE_M) >> RFE_COMMON_RAM_AGCINFO_MODE_S) == (RFE_COMMON_RAM_AGCINFO_MODE_FAST >> RFE_COMMON_RAM_AGCINFO_MODE_S))
413         {
414             /* Fast AGC */
415             agcValOffset =LRF_findExtTrim0TrimAdjustment(temperature, trimDef->trim3.fields.lrfdrfeExtTrim0.agcThrTcomp,
416                                                          trimDef->trim3.fields.lrfdrfeExtTrim0.agcThrOffset);
417             agcHighGainOffset = trimDef->trim3.fields.lrfdrfeExtTrim0.highGainOffset;
418             agcLowGainOffset = trimDef->trim3.fields.lrfdrfeExtTrim0.lowGainOffset;
419         }
420         else
421         {
422             /* Standard AGC */
423             agcValOffset = LRF_findExtTrim0TrimAdjustment(temperature, trimDef->trim3.fields.lrfdrfeExtTrim0.magnTcomp,
424                                                           trimDef->trim3.fields.lrfdrfeExtTrim0.magnOffset);
425         }
426     }
427 
428     uint32_t divLdoVoutTrim = trimDef->trim1.fields.divLdo.voutTrim;
429 
430     /* Most significant bit is inverted */
431     divLdoVoutTrim ^= 0x40;
432 
433     divLdoVoutTrim += divLdoTempOffset;
434 
435     /* Saturate at maximum value */
436     if (divLdoVoutTrim > (LRFDRFE_DIVLDO_VOUTTRIM_ONES >> LRFDRFE_DIVLDO_VOUTTRIM_S))
437     {
438         divLdoVoutTrim = (LRFDRFE_DIVLDO_VOUTTRIM_ONES >> LRFDRFE_DIVLDO_VOUTTRIM_S);
439     }
440     /* Write back with most signigicant bit inverted back */
441     HWREGH_WRITE_LRF(LRFD_RFERAM_BASE + RFE_COMMON_RAM_O_DIVLDOF) = HWREGH_READ_LRF(LRFD_RFERAM_BASE + RFE_COMMON_RAM_O_DIVLDOF) | ((divLdoVoutTrim ^ 0x40) << RFE_COMMON_RAM_DIVLDOF_VOUTTRIM_S);
442 
443     /* Add offset to initial value */
444     divLdoVoutTrim += HWREGH_READ_LRF(LRFD_RFERAM_BASE + RFE_COMMON_RAM_O_DIVLDOIOFF);
445 
446     /* Saturate at maximum value */
447     if (divLdoVoutTrim > (LRFDRFE_DIVLDO_VOUTTRIM_ONES >> LRFDRFE_DIVLDO_VOUTTRIM_S))
448     {
449         divLdoVoutTrim = (LRFDRFE_DIVLDO_VOUTTRIM_ONES >> LRFDRFE_DIVLDO_VOUTTRIM_S);
450     }
451     /* Write back with most signigicant bit inverted back */
452     HWREGH_WRITE_LRF(LRFD_RFERAM_BASE + RFE_COMMON_RAM_O_DIVLDOI) = HWREGH_READ_LRF(LRFD_RFERAM_BASE + RFE_COMMON_RAM_O_DIVLDOI) | ((divLdoVoutTrim ^ 0x40) << RFE_COMMON_RAM_DIVLDOI_VOUTTRIM_S);
453 
454     uint32_t tdcLdoVoutTrim = trimDef->trim1.fields.tdcLdo.voutTrim;
455 
456     if (tdcLdoTempOffset > 0)
457     {
458         /* Most significant bit is inverted */
459         tdcLdoVoutTrim ^= 0x40;
460 
461         tdcLdoVoutTrim += tdcLdoTempOffset;
462 
463         /* Saturate at maximum value */
464         if (tdcLdoVoutTrim > (LRFDRFE_TDCLDO_VOUTTRIM_ONES >> LRFDRFE_DIVLDO_VOUTTRIM_S))
465         {
466             tdcLdoVoutTrim = (LRFDRFE_TDCLDO_VOUTTRIM_ONES >> LRFDRFE_DIVLDO_VOUTTRIM_S);
467         }
468 
469         /* Invert back */
470         tdcLdoVoutTrim ^= 0x40;
471     }
472     /* Write back */
473     HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_TDCLDO) = HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_TDCLDO) | (tdcLdoVoutTrim << LRFDRFE_TDCLDO_VOUTTRIM_S);
474 
475 #ifdef DeviceFamily_CC27XX
476     /* RTRIM Workaround: hardcode the RTRIM to 10U rather than read it from FCFG for CC27XX state B devices (see: RCL-591)
477      * ASSUMPTION: AppTrims revision on CC27XX state C devices is not smaller than 7
478      */
479     uint32_t rtrim;
480     if (trimDef->revision >= LRF_TRIM_VERSION_STATE_C_TRIM_WORKAROUND_CC27XX)
481     {
482         rtrim = trimDef->trim2.fields.dco.tailresTrim;
483     }
484     else
485     {
486         rtrim = LRF_TRIM_RTRIM_VALUE_STATE_B_RTRIM_WORKAROUND_CC27XX;
487     }
488 #else
489     uint32_t rtrim = trimDef->trim2.fields.dco.tailresTrim;
490 #endif
491     /* Temperature compensation and PHY offset can only be applied if the value is not above the saturation level */
492     /* If RTRIM from FCFG is above this, always use that level */
493     if (rtrim < LRF_DEFAULT_RTRIM_MAX)
494     {
495         /* Add offset from temperature compensation */
496         rtrim += rtrimTempOffset;
497 
498         /* Add offset from PHY */
499         rtrim += HWREGH_READ_LRF(LRFD_RFERAM_BASE + RFE_COMMON_RAM_O_RTRIMOFF);
500 
501         /* Saturate */
502         if (rtrim > LRF_DEFAULT_RTRIM_MAX)
503         {
504             rtrim = LRF_DEFAULT_RTRIM_MAX;
505         }
506     }
507 
508     /* Ensure it is not smaller than minimum from PHY */
509     uint32_t minRtrim = HWREGH_READ_LRF(LRFD_RFERAM_BASE + RFE_COMMON_RAM_O_RTRIMMIN);
510     if (rtrim < minRtrim)
511     {
512         rtrim = minRtrim;
513     }
514 
515     /* Write into register */
516     HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_DCO) = HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_DCO) | (rtrim << LRFDRFE_DCO_TAILRESTRIM_S);
517 
518     /* Get RSSI offset from FCFG */
519     int32_t rssiOffset = trimDef->trim4.rssiOffset;
520 
521 #if defined(DeviceFamily_CC23X0R5) || defined(DeviceFamily_CC23X0R22) || defined(DeviceFamily_CC2340R53)
522     /* RCL-335: Some devices (State D) have an error in the programmed RSSI offset */
523     if (trimDef->revision == LRF_TRIM_VERSION_RSSIOFFSET_ISSUE_CC23X0R5)
524     {
525         if (rssiOffset <= LRF_TRIM_LIMIT_RSSIOFFSET_ISSUE_CC23X0R5)
526         {
527             rssiOffset += LRF_TRIM_CORRECTION_RSSIOFFSET_ISSUE_CC23X0R5;
528         }
529     }
530 #endif
531 
532     /* Apply temperature compensation */
533     rssiOffset += rssiTempOffset;
534 
535     /* Apply PHY specific offset */
536     rssiOffset += HWREGH_READ_LRF(LRFD_RFERAM_BASE + RFE_COMMON_RAM_O_PHYRSSIOFFSET);
537 
538     /* Store in HW register */
539     HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_RSSIOFFSET) = rssiOffset;
540 
541     if (((HWREGH_READ_LRF(LRFD_RFERAM_BASE + RFE_COMMON_RAM_O_AGCINFO) & RFE_COMMON_RAM_AGCINFO_MODE_M) >> RFE_COMMON_RAM_AGCINFO_MODE_S) == (RFE_COMMON_RAM_AGCINFO_MODE_FAST >> RFE_COMMON_RAM_AGCINFO_MODE_S))
542     {
543         uint32_t spare0Val = HWREGH_READ_LRF(LRFD_RFERAM_BASE + RFE_COMMON_RAM_O_SPARE0SHADOW);
544         if (agcHighGainOffset != 0 || agcLowGainOffset != 0)
545         {
546             int32_t lowGain = (spare0Val & RFE_SPARE0_LOW_GAIN_BM) >> RFE_SPARE0_LOW_GAIN;
547             int32_t highGain = (spare0Val & RFE_SPARE0_HIGH_GAIN_BM) >> RFE_SPARE0_HIGH_GAIN;
548             if (agcLowGainOffset != 0)
549             {
550                 lowGain += agcLowGainOffset;
551                 if (lowGain < 0)
552                 {
553                     lowGain = 0;
554                 }
555                 if (lowGain > (RFE_SPARE0_LOW_GAIN_BM >> RFE_SPARE0_LOW_GAIN))
556                 {
557                     lowGain = (RFE_SPARE0_LOW_GAIN_BM >> RFE_SPARE0_LOW_GAIN);
558                 }
559             }
560             if (agcHighGainOffset != 0)
561             {
562                 highGain += agcHighGainOffset;
563                 if (highGain < 0)
564                 {
565                     highGain = 0;
566                 }
567                 if (highGain > (RFE_SPARE0_HIGH_GAIN_BM >> RFE_SPARE0_HIGH_GAIN))
568                 {
569                     highGain = (RFE_SPARE0_HIGH_GAIN_BM >> RFE_SPARE0_HIGH_GAIN);
570                 }
571             }
572             spare0Val = (spare0Val & ~(RFE_SPARE0_LOW_GAIN_BM | RFE_SPARE0_HIGH_GAIN_BM)) |
573                 (lowGain << RFE_SPARE0_LOW_GAIN) | (highGain << RFE_SPARE0_HIGH_GAIN);
574         }
575         HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_SPARE0) = spare0Val;
576     }
577 
578     uint32_t spare1Val = HWREGH_READ_LRF(LRFD_RFERAM_BASE + RFE_COMMON_RAM_O_SPARE1SHADOW);
579     if (agcValOffset != 0)
580     {
581         int32_t agcVal = (spare1Val & RFE_SPARE1_AGC_VALUE_BM) >> RFE_SPARE1_AGC_VALUE;
582         agcVal += agcValOffset;
583         if (agcVal < 0)
584         {
585             agcVal = 0;
586         }
587         if (agcVal > (RFE_SPARE1_AGC_VALUE_BM >> RFE_SPARE1_AGC_VALUE))
588         {
589             agcVal = (RFE_SPARE1_AGC_VALUE_BM >> RFE_SPARE1_AGC_VALUE);
590         }
591         spare1Val = (spare1Val & ~RFE_SPARE1_AGC_VALUE_BM) | (agcVal << RFE_SPARE1_AGC_VALUE);
592     }
593     HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_SPARE1) = spare1Val;
594 }
595 
596 /* Represent 1/3 with the approximation LRF_ONE_THIRD_MANTISSA * 2^(-LRF_ONE_THIRD_NEG_EXP) */
597 #define LRF_ONE_THIRD_MANTISSA 21845U /* (round(1/3 * 2^16)) */
598 #define LRF_ONE_THIRD_NEG_EXP  16
599 /* Calculate temperature compensation for the fields in lrfdrfeExtTrim1 */
600 /* temperatureDiff: absolute difference from calculated temperature threshold */
601 /* tempThreshFactor: Temperature Threshold field as defined in the trim spec:
602    The temperature threshold is given by (125 - tempThreshFactor * 2^k) for high temperatures and
603    (-40C + tempThreshFactor * 2^k) for low temperatures, where k = LRF_EXTTRIM1_TEMPERATURE_SCALE_EXP. */
604 /* maxAdjustment: The adjustment to apply at the extreme temperature */
605 /* Return: Adjustment to add to value */
LRF_findExtTrim1TrimAdjustment(uint32_t temperatureDiff,uint32_t tempThreshFactor,uint32_t maxAdjustment)606 static uint32_t LRF_findExtTrim1TrimAdjustment(uint32_t temperatureDiff, uint32_t tempThreshFactor, uint32_t maxAdjustment)
607 {
608     uint32_t adjustment;
609     /* Calculate adjustment = round((temperatureDiff * maxAdjustment) / (tempThreshFactor * 2^LRF_EXTTRIM1_TEMPERATURE_SCALE_EXP)) */
610     switch (tempThreshFactor)
611     {
612         case 0:
613         default:
614             /* tempThreshFactor = 0:
615                No temperatures will be in the range for adjustment */
616             adjustment = 0;
617             break;
618         case 1:
619             /* tempThreshFactor = 1:
620                adjustment = round((temperatureDiff * maxAdjustment) / (1 * 2^LRF_EXTTRIM1_TEMPERATURE_SCALE_EXP)) */
621             adjustment = ((temperatureDiff * maxAdjustment) + (1 << (LRF_EXTTRIM1_TEMPERATURE_SCALE_EXP - 1))) >> LRF_EXTTRIM1_TEMPERATURE_SCALE_EXP;
622             break;
623         case 2:
624             /* tempThreshFactor = 2:
625                adjustment = round((temperatureDiff * maxAdjustment) / (2 * 2^LRF_EXTTRIM1_TEMPERATURE_SCALE_EXP)) */
626             adjustment = ((temperatureDiff * maxAdjustment) + (1 << LRF_EXTTRIM1_TEMPERATURE_SCALE_EXP)) >> (LRF_EXTTRIM1_TEMPERATURE_SCALE_EXP + 1);
627             break;
628         case 3:
629             /* tempThreshFactor = 3:
630                adjustment = round((temperatureDiff * maxAdjustment) / (3 * 2^LRF_EXTTRIM1_TEMPERATURE_SCALE_EXP))
631                Use approximation with multiplication to avoid performing division */
632             adjustment = ((temperatureDiff * maxAdjustment * LRF_ONE_THIRD_MANTISSA) + (1 << (LRF_EXTTRIM1_TEMPERATURE_SCALE_EXP + LRF_ONE_THIRD_NEG_EXP - 1)))
633                 >> (LRF_EXTTRIM1_TEMPERATURE_SCALE_EXP + LRF_ONE_THIRD_NEG_EXP);
634             break;
635     }
636     return adjustment;
637 }
638 
639 /* Calculate temperature compensation for the fields in lrfdrfeExtTrim0 */
640 /* temperature: temperature (degrees C) */
641 /* tempCompFactor: Temperature compensation coefficient used to find offset from the formula ((temperature - 25) * tempCompFactor) / 128 */
642 /* offset: Absolute offset to apply independent of temperature  */
643 /* Return: Adjustment to add to value */
LRF_findExtTrim0TrimAdjustment(int32_t temperature,int32_t tempCompFactor,int32_t offset)644 static int32_t LRF_findExtTrim0TrimAdjustment(int32_t temperature, int32_t tempCompFactor, int32_t offset)
645 {
646     return (((temperature - LRF_TEMPERATURE_NOM) * tempCompFactor) >> LRF_EXTTRIM0_TEMPERATURE_SCALE_EXP) + offset;
647 }
648 
LRF_enable(void)649 void LRF_enable(void)
650 {
651     /* Set MSGBOX register to 0 */
652     HWREGH_WRITE_LRF(LRFD_BUFRAM_BASE + PBE_COMMON_RAM_O_MSGBOX) = 0;
653 
654     /* Initialize and enable PBE TOPsm and FIFO */
655     HWREG_WRITE_LRF(LRFDPBE_BASE + LRFDPBE_O_INIT)   = ((1 << LRFDPBE_INIT_MDMF_S)   |
656                                                        (1 << LRFDPBE_INIT_TOPSM_S));
657     HWREG_WRITE_LRF(LRFDPBE_BASE + LRFDPBE_O_ENABLE) = ((1 << LRFDPBE_ENABLE_MDMF_S) |
658                                                        (1 << LRFDPBE_ENABLE_TOPSM_S));
659 
660     /* Initialize and enable MCE TOPsm and FIFO */
661     HWREG_WRITE_LRF(LRFDMDM_BASE + LRFDMDM_O_INIT)   = ((1 << LRFDMDM_INIT_TXRXFIFO_S)  |
662                                                        (1 << LRFDMDM_INIT_TOPSM_S));
663     HWREG_WRITE_LRF(LRFDMDM_BASE + LRFDMDM_O_ENABLE) = ((1 << LRFDMDM_ENABLE_TXRXFIFO_S)|
664                                                        (1 << LRFDMDM_ENABLE_TOPSM_S));
665 
666     /* Initialize and enable RFE TOPsm */
667     HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_INIT)   = (1 << LRFDRFE_INIT_TOPSM_S);
668     HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_ENABLE) = (1 << LRFDRFE_ENABLE_TOPSM_S);
669 }
670 
LRF_disable(void)671 void LRF_disable(void)
672 {
673     /* Request PBE powerdown */
674     HWREG_WRITE_LRF(LRFDPBE_BASE + LRFDPBE_O_PDREQ) = LRFDPBE_PDREQ_TOPSMPDREQ_M;
675     /* Disable all PBE modules */
676     HWREG_WRITE_LRF(LRFDPBE_BASE + LRFDPBE_O_ENABLE) = 0;
677     /* Stop powerdown request */
678     HWREG_WRITE_LRF(LRFDPBE_BASE + LRFDPBE_O_PDREQ) = 0;
679 
680     /* Request MCE powerdown */
681     HWREG_WRITE_LRF(LRFDMDM_BASE + LRFDMDM_O_PDREQ) = LRFDMDM_PDREQ_TOPSMPDREQ_M;
682     /* Disable all MDM modules */
683     HWREG_WRITE_LRF(LRFDMDM_BASE + LRFDMDM_O_ENABLE) = 0;
684     /* Stop powerdown request */
685     HWREG_WRITE_LRF(LRFDMDM_BASE + LRFDMDM_O_PDREQ) = 0;
686 
687     /* Request RFE powerdown */
688     HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_PDREQ) = LRFDRFE_PDREQ_TOPSMPDREQ_M;
689     /* Disable all RFE modules */
690     HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_ENABLE) = 0;
691     /* Stop powerdown request */
692     HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_PDREQ) = 0;
693 }
694 
LRF_waitForTopsmReady(void)695 void LRF_waitForTopsmReady(void)
696 {
697     /* Make sure PBE is finished booting */
698     /* This poll should be quick as long as the TOPsms have been reset and enabled */
699     while (HWREGH_READ_LRF(LRFD_BUFRAM_BASE + PBE_COMMON_RAM_O_MSGBOX) == 0)
700     {
701     }
702 }
703 
LRF_prepareRxFifo(void)704 uint32_t LRF_prepareRxFifo(void)
705 {
706     uint32_t fifoSize;
707     /* Reset RXFIFO. NOTE: Only allowed while PBE is not running, ref. RCL-367 */
708     HWREG_WRITE_LRF(LRFDPBE_BASE + LRFDPBE_O_FCMD) = (LRFDPBE_FCMD_DATA_RXFIFO_RESET >> LRFDPBE_FCMD_DATA_S);
709     /* Set up RXFIFO without auto commit or deallocate */
710     HWREG_WRITE_LRF(LRFDPBE_BASE + LRFDPBE_O_FCFG0) = HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_FCFG0) & (~(LRFDPBE_FCFG0_RXADEAL_M | LRFDPBE_FCFG0_RXACOM_M));
711     /* Read writable bytes, which is the FIFO size */
712     fifoSize = HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_RXFWRITABLE);
713     /* Write SRP to 0. This sets no available space for writing; to be updated
714        by calling LRF_setRxFifoEffSz().
715        This write can be done without protection since PBE is not allowed to be
716        running here, ref RCL-367 */
717     HWREG_WRITE_LRF(LRFDPBE_BASE + LRFDPBE_O_RXFSRP) = 0;
718     rxFifoDeallocated = false;
719 
720     return fifoSize;
721 }
722 
LRF_prepareTxFifo(void)723 uint32_t LRF_prepareTxFifo(void)
724 {
725     /* Reset RXFIFO. NOTE: Only allowed while PBE is not running, ref. RCL-367 */
726     HWREG_WRITE_LRF(LRFDPBE_BASE + LRFDPBE_O_FCMD) = (LRFDPBE_FCMD_DATA_TXFIFO_RESET >> LRFDPBE_FCMD_DATA_S);
727     /* Set up TXFIFO with auto commit, without auto deallocate */
728     uint32_t fcfg0 = HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_FCFG0);
729     fcfg0 &= ~LRFDPBE_FCFG0_TXADEAL_M;
730     fcfg0 |=  LRFDPBE_FCFG0_TXACOM_M;
731     HWREG_WRITE_LRF(LRFDPBE_BASE + LRFDPBE_O_FCFG0) = fcfg0;
732     /* Return writable bytes, which is the FIFO size */
733     return HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_TXFWRITABLE);
734 }
735 
LRF_peekRxFifo(int32_t offset)736 uint32_t LRF_peekRxFifo(int32_t offset)
737 {
738     int32_t index = HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_RXFRP) + offset;
739     int32_t fifosz = ((HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_FCFG4) & LRFDPBE_FCFG4_RXSIZE_M) >> LRFDPBE_FCFG4_RXSIZE_S) << 2;
740     if (index >= fifosz)
741     {
742         index -= fifosz;
743     }
744 
745     return HWREG_READ_LRF(LRFD_BUFRAM_BASE + (HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_FCFG3) << 2) + index);
746 }
747 
LRF_peekTxFifo(int32_t offset)748 uint32_t LRF_peekTxFifo(int32_t offset)
749 {
750     int32_t index = HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_TXFRP) + offset;
751     int32_t fifosz = ((HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_FCFG2) & LRFDPBE_FCFG2_TXSIZE_M) >> LRFDPBE_FCFG2_TXSIZE_S) << 2;
752     if (index >= fifosz)
753     {
754         index -= fifosz;
755     }
756     return HWREG_READ_LRF(LRFD_BUFRAM_BASE + (HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_FCFG1) << 2) + index);
757 }
758 
LRF_getTxFifoWrAddr(int32_t offset)759 uint8_t *LRF_getTxFifoWrAddr(int32_t offset)
760 {
761     int32_t index = HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_TXFWP) + offset;
762     return (uint8_t *) (TXF_UNWRAPPED_BASE_ADDR + (HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_FCFG1) << 2) + index);
763 }
764 
765 /* Use the workaround of RCL-367 to write the FIFO pointer register with
766  * address regAddr to the given value. This allows PBE to protect against
767  * writing FCMD at the same time */
LRF_writeFifoPtr(uint32_t value,uintptr_t regAddr)768 static void LRF_writeFifoPtr(uint32_t value, uintptr_t regAddr)
769 {
770     /* Run in protected region to avoid unnecessary delays */
771     uintptr_t key = HwiP_disable();
772     /* Direct PBE to write FIFO commands to FSTAT register to make them ignored */
773     HWREGH_WRITE_LRF(LRFD_BUFRAM_BASE + PBE_COMMON_RAM_O_FIFOCMDADD) = ((LRFDPBE_BASE + LRFDPBE_O_FSTAT) & 0x0FFF) >> 2;
774     /* Wait a little so that PBE has time to finish any pending command writes */
775     /* Do the wait by dummy reads of FIFOCMDADD */
776     (void) HWREGH_READ_LRF(LRFD_BUFRAM_BASE + PBE_COMMON_RAM_O_FIFOCMDADD);
777     (void) HWREGH_READ_LRF(LRFD_BUFRAM_BASE + PBE_COMMON_RAM_O_FIFOCMDADD);
778     /* Write to specified register */
779     HWREG_WRITE_LRF(regAddr) = value;
780     /* Set PBE back to writing FIFO commands to FCMD */
781     HWREGH_WRITE_LRF(LRFD_BUFRAM_BASE + PBE_COMMON_RAM_O_FIFOCMDADD) = ((LRFDPBE_BASE + LRFDPBE_O_FCMD) & 0x0FFF) >> 2;
782 
783     HwiP_restore(key);
784 }
785 
786 /* Use the workaround of RCL-367 to write both FIFO pointer registers with
787  * addresses regAddr0 and regAddr1 to the given value. This allows PBE to
788  * protect against writing FCMD at the same time */
LRF_writeFifoPtrs(uint32_t value,uintptr_t regAddr0,uintptr_t regAddr1)789 static void LRF_writeFifoPtrs(uint32_t value, uintptr_t regAddr0, uintptr_t regAddr1)
790 {
791     /* Run in protected region to avoid unnecessary delays */
792     uintptr_t key = HwiP_disable();
793     /* Direct PBE to write FIFO commands to FSTAT register to make them ignored */
794     HWREGH_WRITE_LRF(LRFD_BUFRAM_BASE + PBE_COMMON_RAM_O_FIFOCMDADD) = ((LRFDPBE_BASE + LRFDPBE_O_FSTAT) & 0x0FFF) >> 2;
795     /* Wait a little so that PBE has time to finish any pending command writes */
796     /* Do the wait by dummy reads of FIFOCMDADD */
797     (void) HWREGH_READ_LRF(LRFD_BUFRAM_BASE + PBE_COMMON_RAM_O_FIFOCMDADD);
798     (void) HWREGH_READ_LRF(LRFD_BUFRAM_BASE + PBE_COMMON_RAM_O_FIFOCMDADD);
799     /* Write to specified registers */
800     HWREG_WRITE_LRF(regAddr0) = value;
801     HWREG_WRITE_LRF(regAddr1) = value;
802     /* Set PBE back to writing FIFO commands to FCMD */
803     HWREGH_WRITE_LRF(LRFD_BUFRAM_BASE + PBE_COMMON_RAM_O_FIFOCMDADD) = ((LRFDPBE_BASE + LRFDPBE_O_FCMD) & 0x0FFF) >> 2;
804 
805 
806     HwiP_restore(key);
807 }
808 
LRF_skipTxFifoWords(uint32_t wordLength)809 void LRF_skipTxFifoWords(uint32_t wordLength)
810 {
811     int32_t index = HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_TXFRP) + (wordLength * 4);
812     int32_t fifosz = ((HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_FCFG2) & LRFDPBE_FCFG2_TXSIZE_M) >> LRFDPBE_FCFG2_TXSIZE_S) << 2;
813     if (index >= fifosz)
814     {
815         index -= fifosz;
816     }
817     LRF_writeFifoPtr(index, (LRFDPBE_BASE + LRFDPBE_O_TXFRP));
818 }
819 
LRF_discardRxFifoWords(uint32_t wordLength)820 void LRF_discardRxFifoWords(uint32_t wordLength)
821 {
822     int32_t index = HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_RXFRP) + (wordLength * 4);
823     int32_t fifosz = ((HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_FCFG4) & LRFDPBE_FCFG4_RXSIZE_M) >> LRFDPBE_FCFG4_RXSIZE_S) << 2;
824     if (index >= fifosz)
825     {
826         index -= fifosz;
827     }
828     /* Write updated pointer to rp and srp */
829     LRF_writeFifoPtrs(index, (LRFDPBE_BASE + LRFDPBE_O_RXFRP), (LRFDPBE_BASE + LRFDPBE_O_RXFSRP));
830     /* RX FIFO is now deallocated */
831     rxFifoDeallocated = true;
832 }
833 
LRF_readRxFifoWords(uint32_t * data32,uint32_t wordLength)834 void LRF_readRxFifoWords(uint32_t *data32, uint32_t wordLength)
835 {
836     /* Due to RCL-367, the packet is read from memory, and the read pointer is updated afterwards */
837     /* Pointer to unwrapped FIFO RAM representation */
838     uint32_t fifoStart = ((HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_FCFG3) & LRFDPBE_FCFG3_RXSTRT_M) >> LRFDPBE_FCFG3_RXSTRT_S) << 2;
839     uint32_t readPointer = HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_RXFRP) & ~0x0003;
840     volatile uint32_t *fifoReadPtr = (volatile uint32_t *) (RXF_UNWRAPPED_BASE_ADDR + fifoStart + readPointer);
841 
842     /* [RCL-515 WORKAROUND]: Protect the first memory write on BLE High PG1.x due to the hardware bugs */
843 #ifdef DeviceFamily_CC27XX
844     ASM_4_NOPS();
845 #endif //DeviceFamily_CC27XX
846     for (uint32_t i = 0; i < wordLength; i++) {
847         *data32++ = *fifoReadPtr++;
848     }
849     /* Update read pointer */
850     int32_t index = readPointer + (wordLength * 4);
851     int32_t fifosz = ((HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_FCFG4) & LRFDPBE_FCFG4_RXSIZE_M) >> LRFDPBE_FCFG4_RXSIZE_S) << 2;
852     if (index >= fifosz)
853     {
854         index -= fifosz;
855     }
856     LRF_writeFifoPtr(index, (LRFDPBE_BASE + LRFDPBE_O_RXFRP));
857     /* RP was moved, so RX FIFO is not deallocated */
858     rxFifoDeallocated = false;
859 }
860 
LRF_writeTxFifoWords(const uint32_t * data32,uint32_t wordLength)861 void LRF_writeTxFifoWords(const uint32_t *data32, uint32_t wordLength)
862 {
863     /* Due to RCL-367, the packet is written to memory, and the write pointer is updated afterwards */
864     /* Pointer to unwrapped FIFO RAM representation */
865     uint32_t fifoStart = ((HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_FCFG1) & LRFDPBE_FCFG1_TXSTRT_M) >> LRFDPBE_FCFG1_TXSTRT_S) << 2;
866     uint32_t writePointer = HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_TXFWP) & ~0x0003;
867     volatile uint32_t *fifoWritePtr = (volatile uint32_t *) (TXF_UNWRAPPED_BASE_ADDR + fifoStart + writePointer);
868 
869     /* [RCL-515 WORKAROUND]: Protect the first memory write on BLE High PG1.x due to the hardware bugs */
870 #ifdef DeviceFamily_CC27XX
871     ASM_4_NOPS();
872 #endif //DeviceFamily_CC27XX
873     for (uint32_t i = 0; i < wordLength; i++) {
874         *fifoWritePtr++ = *data32++;
875     }
876     /* Update write pointer */
877     int32_t index = writePointer + (wordLength * 4);
878     int32_t fifosz = ((HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_FCFG2) & LRFDPBE_FCFG2_TXSIZE_M) >> LRFDPBE_FCFG2_TXSIZE_S) << 2;
879     if (index >= fifosz)
880     {
881         index -= fifosz;
882     }
883     LRF_writeFifoPtr(index, (LRFDPBE_BASE + LRFDPBE_O_TXFWP));
884 }
885 
LRF_setRxFifoEffSz(uint32_t maxSz)886 void LRF_setRxFifoEffSz(uint32_t maxSz)
887 {
888     uint32_t fifoSz = ((HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_FCFG4) & LRFDPBE_FCFG4_RXSIZE_M) >> LRFDPBE_FCFG4_RXSIZE_S) << 2;
889     if (maxSz >= fifoSz)
890     {
891         /* Deallocate RX FIFO to get no additional FIFO restriction */
892         /* Due to RCL-367, the operation is done with a FIFO pointer register write */
893         if (!rxFifoDeallocated)
894         {
895             /* We should not do this write if the FIFO was already deallocated, as it would move the SRP one full round */
896             LRF_writeFifoPtr(HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_RXFRP), (LRFDPBE_BASE + LRFDPBE_O_RXFSRP));
897             rxFifoDeallocated = true;
898         }
899     }
900     else {
901         uint32_t newSrp;
902         /* A limit of 0 can't be achieved through manipulating SRP. For all practical purposes, a limit of 1 has the same effect. */
903         if (maxSz == 0)
904         {
905             maxSz = 1;
906         }
907 
908         newSrp = HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_RXFRP) + maxSz;
909         if (newSrp >= fifoSz)
910         {
911             newSrp -= fifoSz;
912         }
913         /* The new SRP value will always be a write forward in the FIFO */
914         /* Do not write if the value is the same as before, as this will be
915             interpreted by the FIFO HW as going a full round forward */
916 
917         if (HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_RXFSRP) != newSrp)
918         {
919             LRF_writeFifoPtr(newSrp, (LRFDPBE_BASE + LRFDPBE_O_RXFSRP));
920             /* SRP is now different from RP, so RX FIFO is not deallocated */
921             rxFifoDeallocated = false;
922         }
923     }
924 }
925 
926 /* (FXTALINVL + (FXTALINVH << 16)) = round(2^67/48e6) */
927 #define FXTALINVL 0x00001E52U
928 #define FXTALINVH 0x02CBD3F0U
929 /* (fXtalInv.word[0] + (fXtalInv.word[1] << 16)) = round(2^67/fXtal), where fXtal is clock frequency in Hz */
930 /* Only 16 bits are used of word[0] */
931 LRF_DoubleWord fXtalInv =
932 {
933     .word = {FXTALINVL, FXTALINVH},
934 };
935 /* Calculate PLLM base, that is PLLM assuming an FREF corresponding to the crystal frequency */
936 /* This can be used to find true PLLM by multiplying with prediv */
LRF_findPllMBase(uint32_t frequency)937 static uint32_t LRF_findPllMBase(uint32_t frequency)
938 {
939     /* 2^51 / fxtal */
940     uint32_t frefInv = fXtalInv.word[1];
941 
942     uint32_t pllMBase;
943     /* Find pllMBase = frequency / fxtal, encoded as <12.18u> */
944     /* First, find pllMBase = frequency / fxtal * 2^(51-32) */
945     pllMBase = (frefInv >> 16) * (frequency >> 16);
946     uint32_t tmpPllMBase;
947     tmpPllMBase = ((frefInv >> 16) * (frequency & 0xFFFFU)) >> 1;
948     tmpPllMBase += ((frefInv & 0xFFFFU) * (frequency >> 16)) >> 1;
949     tmpPllMBase += (1U << 14);
950     tmpPllMBase >>= 15;
951     pllMBase += tmpPllMBase;
952 
953     /* Divide by 2 with rounding to get pllMBase = frequency / fxtal * 2^18 */
954     pllMBase += 1;
955     pllMBase >>= 1;
956 
957     return pllMBase;
958 }
959 
countLeadingZeros(uint16_t value)960 static uint32_t countLeadingZeros(uint16_t value)
961 {
962    int numZeros = 0;
963    if (value >= 0x0100) {
964       value >>= 8;
965    }
966    else {
967       numZeros += 8;
968    }
969    if (value >= 0x10) {
970       value >>= 4;
971    }
972    else {
973       numZeros += 4;
974    }
975    if (value >= 0x04) {
976       value >>= 2;
977    }
978    else {
979       numZeros += 2;
980    }
981    if (value >= 0x02) {
982        /* No need to shift down value since this is the last step */
983    }
984    else {
985       numZeros += 1;
986    }
987    return numZeros;
988 }
989 
LRF_findCalM(uint32_t frequency,uint32_t prediv)990 static uint32_t LRF_findCalM(uint32_t frequency, uint32_t prediv)
991 {
992     /* Find 2^47 / fref = 2^47 * prediv / fxtal */
993     uint32_t frefInv = (fXtalInv.word[1] >> 4) * prediv;
994     /* Round to 2^31 * prediv / fxtal */
995     frefInv += 1 << 15;
996     frefInv >>= 16;
997 
998     uint32_t calM;
999     /* Find calM = frequency / fref (no fractional bits) */
1000     /* First, find calM = frequency / fref * 2^(31-15)) */
1001     calM = frefInv * ((frequency + (1 << 14)) >> 15);
1002 
1003     /* Divide by 2^16 with rounding to get calM = frequency / fref */
1004     calM += 1 << 15;
1005     calM >>= 16;
1006 
1007     return calM;
1008 }
1009 
1010 /* invSynthFreq = 2^47 / synthFrequency */
LRF_findFoff(int32_t frequencyOffset,uint32_t invSynthFreq)1011 static uint32_t LRF_findFoff(int32_t frequencyOffset, uint32_t invSynthFreq)
1012 {
1013     uint32_t absFrequencyOffset;
1014     int32_t fOffRes;
1015     if (frequencyOffset == 0)
1016     {
1017         return 0;
1018     }
1019     else {
1020         if (frequencyOffset < 0)
1021         {
1022             absFrequencyOffset = -frequencyOffset;
1023         }
1024         else
1025         {
1026             absFrequencyOffset = frequencyOffset;
1027         }
1028         /* Calculate 2^41 * abs(frequencyOffset) / synthFrequency */
1029         absFrequencyOffset = (absFrequencyOffset + (1U << 5)) >> 6;
1030         absFrequencyOffset *= invSynthFreq;
1031         /* Round to 2^21 * abs(frequencyOffset) / synthFrequency */
1032         absFrequencyOffset = (absFrequencyOffset + (1U << 19)) >> 20;
1033         /* Re-intruduce sign */
1034         if (frequencyOffset < 0)
1035         {
1036             fOffRes = -absFrequencyOffset;
1037         }
1038         else
1039         {
1040             fOffRes = absFrequencyOffset;
1041         }
1042 
1043         return (((uint32_t)fOffRes) & LRFDRFE_MOD1_FOFF_M);
1044     }
1045 }
1046 
1047 #define NUM_TX_FILTER_TAPS 24
1048 /* deviation in Hz */
1049 /* invSynthFreq = 2^51 / synthFrequency */
LRF_programShape(const LRF_TxShape * txShape,uint32_t deviation,uint32_t invSynthFreq)1050 static void LRF_programShape(const LRF_TxShape *txShape, uint32_t deviation, uint32_t invSynthFreq)
1051 {
1052     /* If txShape is NULL, do not program shape, but instead leave the values programmed as part of setup */
1053     if (txShape != NULL)
1054     {
1055         union {
1056             uint8_t  b[NUM_TX_FILTER_TAPS];
1057             uint32_t w[NUM_TX_FILTER_TAPS/4];
1058         } filterCoeff;
1059         /* Find deviation * 2^29/fs * 2^10 */
1060         uint32_t deviationFactor1 = ((deviation >> 12) * invSynthFreq) +
1061             (((deviation & 0x0FFFU) * invSynthFreq) >> 12);
1062         /* Find deviation * 2^29/fs * scale / 2^16 */
1063         uint32_t scale = txShape->scale;
1064         uint32_t deviationFactor2 = ((((deviationFactor1 >> 15) * scale) >> 1) +
1065                                      (((deviationFactor1 & 0x7FFF) * scale) >> 16) + (1 << 4)) >> 5;
1066         /* Find shapeGain and scaling */
1067         int32_t shapeGain = 8 - countLeadingZeros(deviationFactor2 >> 11);
1068         if (shapeGain < 0)
1069         {
1070             shapeGain = 0;
1071         }
1072         uint32_t startCoeff = NUM_TX_FILTER_TAPS - txShape->numCoeff;
1073         for (uint32_t i = 0; i < startCoeff; i++)
1074         {
1075             filterCoeff.b[i] = 0;
1076         }
1077         for (uint32_t i = 0; i < NUM_TX_FILTER_TAPS - startCoeff; i++)
1078         {
1079             filterCoeff.b[i + startCoeff] =
1080                 ((deviationFactor2 * txShape->coeff[i]) + (1 << (18 + shapeGain))) >> (19 + shapeGain);
1081         }
1082 
1083         /* [RCL-515 WORKAROUND]: Protect the first memory write on BLE High PG1.x due to the hardware bugs */
1084 #ifdef DeviceFamily_CC27XX
1085         ASM_4_NOPS();
1086 #endif //DeviceFamily_CC27XX
1087         for (int i = 0; i <  NUM_TX_FILTER_TAPS / 4; i++)
1088         {
1089             *((unsigned long*) (LRFDRFE32_BASE + LRFDRFE32_O_DTX1_DTX0) + i) = filterCoeff.w[i];
1090         }
1091         if (shapeGain > 3)
1092         {
1093             /* TODO: Scale by adjusting the symbol mapping */
1094             shapeGain = 3;
1095         }
1096         HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_MOD0) = (HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_MOD0) & ~LRFDRFE_MOD0_SHPGAIN_M) | (shapeGain << LRFDRFE_MOD0_SHPGAIN_S);
1097     }
1098 }
1099 
LRF_findLog2Bde1(uint32_t demmisc3)1100 static uint32_t LRF_findLog2Bde1(uint32_t demmisc3)
1101 {
1102     uint32_t log2Bde1;
1103     if ((demmisc3 & LRFDMDM_DEMMISC3_BDE1FILTMODE_M) != 0)
1104     {
1105         log2Bde1 = 0;
1106     }
1107     else
1108     {
1109         log2Bde1 = (demmisc3 & LRFDMDM_DEMMISC3_BDE1NUMSTAGES_M) >> LRFDMDM_DEMMISC3_BDE1NUMSTAGES_S;
1110     }
1111     return log2Bde1;
1112 }
1113 
1114 /* Calculate P as rateWord * bde1 * bde2 * pdifDecim * 9 * 2^4
1115    Calculate Q as pllMBase * pre
1116    Normalize Q to 28 bits and do the same normalization to P */
1117 /* Multiplication factor from P formula */
1118 #define P_FACTOR 9
1119 /* Shift from P formula */
1120 #define P_SHIFT 4
1121 /* Right shift of PLL M to allow 32-bit calculation */
1122 #define Q_MAGN_SHIFT 6
1123 /* Number of bits in P and Q */
1124 #define FRAC_NUM_BITS 28
1125 /* Number of extra bits in an uint32_t compared to the P and Q HW registers */
1126 #define FRAC_EXTRA_BITS (32 - FRAC_NUM_BITS)
LRF_programPQ(uint32_t pllMBase)1127 static uint32_t LRF_programPQ(uint32_t pllMBase)
1128 {
1129     bool roundingError = false;
1130     uint32_t rateWord = (HWREG_READ_LRF(LRFDMDM_BASE + LRFDMDM_O_BAUD) << 5);
1131     rateWord |= ((HWREG_READ_LRF(LRFDMDM_BASE + LRFDMDM_O_BAUDPRE) & LRFDMDM_BAUDPRE_EXTRATEWORD_M) >> LRFDMDM_BAUDPRE_EXTRATEWORD_S);
1132     uint32_t pre = (HWREG_READ_LRF(LRFDMDM_BASE + LRFDMDM_O_BAUDPRE) & LRFDMDM_BAUDPRE_PRESCALER_M);
1133     uint32_t demmisc3 = HWREG_READ_LRF(LRFDMDM_BASE + LRFDMDM_O_DEMMISC3);
1134     uint32_t log2Bde1 = LRF_findLog2Bde1(demmisc3);
1135 
1136     uint32_t bde2 = (demmisc3 & LRFDMDM_DEMMISC3_BDE2DECRATIO_M) >> LRFDMDM_DEMMISC3_BDE2DECRATIO_S;
1137     uint32_t log2PdifDecim = (demmisc3 & LRFDMDM_DEMMISC3_PDIFDECIM_M) >> LRFDMDM_DEMMISC3_PDIFDECIM_S;
1138     int32_t leftShiftP;
1139 
1140     leftShiftP = log2Bde1 + log2PdifDecim + P_SHIFT;
1141 
1142     uint32_t demFracP = rateWord * bde2;
1143     if (demFracP > (uint32_t)((1ULL << 32) / P_FACTOR))
1144     {
1145         if ((demFracP & 1) != 0)
1146         {
1147             roundingError = true;
1148         }
1149         demFracP >>= 1;
1150         leftShiftP -= 1;
1151     }
1152     demFracP *= P_FACTOR;
1153 
1154     /* Preliminary calculation to find scaling factor - round PLLM upwards to ensure no overflow
1155        in final calculation */
1156     uint32_t demFracQ = ((pllMBase + ((1 << Q_MAGN_SHIFT) - 1)) >> Q_MAGN_SHIFT) * pre;
1157     uint32_t num0Q = countLeadingZeros(demFracQ >> 16);
1158 
1159     int32_t pllMShift = Q_MAGN_SHIFT + FRAC_EXTRA_BITS - num0Q;
1160     uint32_t pllMBaseRounded;
1161     if (pllMShift <= 0)
1162     {
1163         pllMBaseRounded = pllMBase;
1164         demFracQ = pllMBase * pre;
1165         int32_t leftShiftQ = -pllMShift;
1166         leftShiftP += leftShiftQ;
1167         /* leftShiftQ is sure to be positive since pllMShift <= 0 */
1168         demFracQ <<= leftShiftQ;
1169     }
1170     else
1171     {
1172         /* Scale PLLM to allow Q to fit */
1173         pllMBaseRounded = (pllMBase + (1U << (pllMShift - 1))) >> pllMShift;
1174         demFracQ = pllMBaseRounded * pre;
1175         /* Multiply PLLM back (rounding is now applied) */
1176         pllMBaseRounded <<= pllMShift;
1177         leftShiftP -= pllMShift;
1178     }
1179 
1180     if (leftShiftP >= 0)
1181     {
1182         demFracP <<= leftShiftP;
1183     }
1184     else
1185     {
1186         /* Check if right shift of P introduces rounding error */
1187         if ((demFracP & ((1 << -leftShiftP) - 1)) != 0)
1188         {
1189             roundingError = true;
1190         }
1191         demFracP >>= -leftShiftP;
1192     }
1193 
1194     if (demFracP >= demFracQ)
1195     {
1196         Log_printf(RclCore, Log_ERROR, "Error: resampler fraction greater than 1; demodulator will not work");
1197     }
1198     if (roundingError)
1199     {
1200         Log_printf(RclCore, Log_WARNING, "Rounding error in fractional resampler");
1201     }
1202     if (pllMBaseRounded != pllMBase)
1203     {
1204         Log_printf(RclCore, Log_INFO, "PLLM base rounded from %08X to %08X to fit in fractional resampler", pllMBase, pllMBaseRounded);
1205     }
1206 
1207 #ifdef DeviceFamily_CC27XX
1208     /* Check if shadow register for downsampler coefficient P is in use */
1209     if ((HWREG_READ_LRF(LRFDMDM_BASE + LRFDMDM_O_BAUDCOMP) & LRFDMDM_BAUDCOMP_FRAC_SHADOW) != 0)
1210     {
1211         /* Write downsampler coefficient P to shadow registers for new Rx operations to restore */
1212         HWREG_WRITE_LRF(LRFDMDM_BASE + LRFDMDM_O_DEMCOHR3) = demFracP & 0x0000FFFFU;
1213         HWREG_WRITE_LRF(LRFDMDM_BASE + LRFDMDM_O_DEMCOHR4) = demFracP >> 16;
1214     }
1215 #endif /* DeviceFamily_CC27XX */
1216 
1217     HWREG_WRITE_LRF(LRFDMDM32_BASE + LRFDMDM32_O_DEMFRAC1_DEMFRAC0) = demFracP;
1218     HWREG_WRITE_LRF(LRFDMDM32_BASE + LRFDMDM32_O_DEMFRAC3_DEMFRAC2) = demFracQ;
1219 
1220     return pllMBaseRounded;
1221 }
1222 
1223 /* invSynthFreq = 2^47 / synthFrequency */
LRF_programCMixN(int32_t rxIntFrequency,uint32_t invSynthFreq)1224 static void LRF_programCMixN(int32_t rxIntFrequency, uint32_t invSynthFreq)
1225 {
1226     /* Calculate n = f_if/f_pll*24*12*bde1*1024
1227                    = f_if/f_pll * 2^(15 + log2Bde1) * 9 */
1228     uint32_t absRxIntFrequency;
1229     if (rxIntFrequency < 0)
1230     {
1231         absRxIntFrequency = -rxIntFrequency;
1232     }
1233     else
1234     {
1235         absRxIntFrequency = rxIntFrequency;
1236     }
1237 
1238     absRxIntFrequency = (absRxIntFrequency + (1 << 5)) >> 6;
1239     /* Find 2^41 * abs(rxIntFrequency) / synthFrequency */
1240     uint32_t cMixN = absRxIntFrequency * invSynthFreq;
1241     /* Find 2^37 * abs(rxIntFrequency) / synthFrequency * 9 */
1242     cMixN = ((cMixN + (1 << 3)) >> 4) * 9;
1243 
1244     /* Find 2^(15 + log2Bde1) * abs(rxIntFrequency) / synthFrequency * 9 */
1245     uint32_t rightShift = (37 - 15) - LRF_findLog2Bde1(HWREG_READ_LRF(LRFDMDM_BASE + LRFDMDM_O_DEMMISC3));
1246     cMixN = (cMixN + (1 << (rightShift - 1))) >> rightShift;
1247 
1248     int32_t signedCMixN;
1249     /* Use inverse sign */
1250     if (rxIntFrequency > 0)
1251     {
1252         signedCMixN = -cMixN;
1253     }
1254     else
1255     {
1256         signedCMixN = cMixN;
1257     }
1258 #ifdef DeviceFamily_CC27XX
1259         /* Workaround (RCL-489): Invert RX frequency programmed to account for swapped I and Q signals in CC27xx PG1.0
1260          * TODO: May be swapped back for later PGs
1261          */
1262     signedCMixN = -signedCMixN;
1263 #endif
1264 
1265     cMixN = (uint32_t)(signedCMixN & LRFDMDM_DEMMISC0_CMIXN_M);
1266     HWREG_WRITE_LRF(LRFDMDM_BASE + LRFDMDM_O_DEMMISC0) = cMixN;
1267     HWREG_WRITE_LRF(LRFDMDM_BASE + LRFDMDM_O_SPARE3) = cMixN;
1268 }
1269 
LRF_programFrequency(uint32_t frequency,bool tx)1270 void LRF_programFrequency(uint32_t frequency, bool tx)
1271 {
1272     uint32_t synthFrequency;
1273     LRF_SwParam *swParam = (LRF_SwParam *) swParamList;
1274     const LRF_SwConfig *swConfig = swParam->swConfig;
1275 
1276     /* Find frequency corrected for IF. Normally, the result will be the same for tx and rx, and
1277        that is a prerequisite for switching without recalibration. */
1278     if (tx)
1279     {
1280         synthFrequency = frequency - swConfig->txFrequencyOffset;
1281     }
1282     else
1283     {
1284         synthFrequency = frequency - swConfig->rxFrequencyOffset
1285             - swConfig->rxIntFrequency;
1286     }
1287 
1288     /* Compensate desired frequency for temperature-dependent offset in HFXT, if any */
1289     uint32_t synthFrequencyCompensated = LRF_scaleFreqWithHFXTOffset(synthFrequency);
1290 
1291     /* Frequency divided by 2^16, rounded */
1292     uint32_t frequencyDiv2_16 = (synthFrequency + (1 << 15)) >> 16;
1293 
1294     /* Start calculating 2^47/frequency (approximated as 2^31/(synthFrequency/2^16)) */
1295     HWREG_WRITE_LRF(LRFDRFE32_BASE + LRFDRFE32_O_DIVIDEND) = 1U << 31;
1296     HWREG_WRITE_LRF(LRFDRFE32_BASE + LRFDRFE32_O_DIVISOR) = frequencyDiv2_16;
1297 
1298     /* Write approximate freuency to RFE */
1299     HWREGH_WRITE_LRF(LRFD_RFERAM_BASE + RFE_COMMON_RAM_O_K5) = frequencyDiv2_16;
1300 
1301     /* Find setting for coarse and mid calibration */
1302     uint32_t precalSetting = HWREG_READ_LRF(LRFDRFE32_BASE + LRFDRFE32_O_PRE3_PRE2);
1303     uint32_t coarsePrecal = (precalSetting & LRFDRFE32_PRE3_PRE2_CRSCALDIV_M) >> LRFDRFE32_PRE3_PRE2_CRSCALDIV_S;
1304     uint32_t midPrecal = (precalSetting &
1305                           (LRFDRFE32_PRE3_PRE2_MIDCALDIVMSB_M | LRFDRFE32_PRE3_PRE2_MIDCALDIVLSB_M))
1306         >> LRFDRFE_PRE2_MIDCALDIVLSB_S;
1307 
1308     uint32_t calMCoarse = LRF_findCalM(synthFrequency, coarsePrecal);
1309     uint32_t calMMid;
1310     if (coarsePrecal == midPrecal)
1311     {
1312         calMMid = calMCoarse;
1313     }
1314     else
1315     {
1316         calMMid = LRF_findCalM(synthFrequency, midPrecal);
1317     }
1318     HWREG_WRITE_LRF(LRFDRFE32_BASE + LRFDRFE32_O_CALMMID_CALMCRS) = (calMCoarse << LRFDRFE32_CALMMID_CALMCRS_CALMCRS_VAL_S) |
1319         (calMMid << LRFDRFE32_CALMMID_CALMCRS_CALMMID_VAL_S);
1320 
1321     precalSetting = HWREG_READ_LRF(LRFDRFE32_BASE + LRFDRFE32_O_PRE1_PRE0);
1322 
1323     uint32_t precal0 = (precalSetting & LRFDRFE32_PRE1_PRE0_PLLDIV0_M) >> LRFDRFE32_PRE1_PRE0_PLLDIV0_S;
1324     uint32_t precal1 = (precalSetting & LRFDRFE32_PRE1_PRE0_PLLDIV1_M) >> LRFDRFE32_PRE1_PRE0_PLLDIV1_S;
1325 
1326     uint32_t pllMBase = LRF_findPllMBase(synthFrequency);
1327     pllMBase =  LRF_programPQ(pllMBase);
1328 
1329     uint32_t pllMBaseCompensated;
1330     if (synthFrequencyCompensated == synthFrequency)
1331     {
1332         pllMBaseCompensated = pllMBase;
1333     }
1334     else
1335     {
1336         pllMBaseCompensated = LRF_findPllMBase(synthFrequencyCompensated);
1337     }
1338 
1339     HWREG_WRITE_LRF(LRFDRFE32_BASE + LRFDRFE32_O_PLLM0) = ((pllMBaseCompensated * precal0) << LRFDRFE32_PLLM0_VAL_S);
1340     HWREG_WRITE_LRF(LRFDRFE32_BASE + LRFDRFE32_O_PLLM1) = ((pllMBaseCompensated * precal1) << LRFDRFE32_PLLM1_VAL_S);
1341 
1342     /* Read out division result to find invSynthFreq */
1343     while ((HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_DIVSTA) & LRFDRFE_DIVSTA_STAT_M) != 0)
1344     {
1345     }
1346     uint32_t invSynthFreq = HWREG_READ_LRF(LRFDRFE32_BASE + LRFDRFE32_O_QUOTIENT);
1347 
1348     /* Calculate intermediate frequencies */
1349     HWREGH_WRITE_LRF(LRFD_RFERAM_BASE + RFE_COMMON_RAM_O_RXIF) = LRF_findFoff(swConfig->rxFrequencyOffset, invSynthFreq);
1350     HWREGH_WRITE_LRF(LRFD_RFERAM_BASE + RFE_COMMON_RAM_O_TXIF) = LRF_findFoff(swConfig->txFrequencyOffset, invSynthFreq);
1351 
1352     /* Calculate CMIXN */
1353     LRF_programCMixN(swConfig->rxIntFrequency, invSynthFreq);
1354 
1355     LRF_programShape(swConfig->txShape, swConfig->modFrequencyDeviation,
1356                      invSynthFreq << 4);
1357 }
1358 
LRF_enableSynthRefsys(void)1359 uint32_t LRF_enableSynthRefsys(void)
1360 {
1361     uint32_t earliestStartTime;
1362 
1363     /* Enable REFSYS if not already done. If it is enabled now, we need to make sure that start
1364        time is late enough */
1365     uint32_t atstref = HWREG_READ_LRF(LRFDRFE32_BASE + LRFDRFE32_O_ATSTREF);
1366     if ((atstref & LRFDRFE32_ATSTREF_BIAS_M) == 0)
1367     {
1368         /* Bias not already enabled - enable it now */
1369         HWREG_WRITE_LRF(LRFDRFE32_BASE + LRFDRFE32_O_ATSTREF) = atstref | LRFDRFE32_ATSTREF_BIAS_M;
1370         /* Set earliest start time of synth to some later time */
1371         earliestStartTime = LRF_REFSYS_ENABLE_TIME;
1372     }
1373     else
1374     {
1375         /* No restriction on start time */
1376         earliestStartTime = 0;
1377     }
1378     /* Add current time */
1379     earliestStartTime += RCL_Scheduler_getCurrentTime();
1380 
1381     return earliestStartTime;
1382 }
1383 
LRF_disableSynthRefsys(void)1384 void LRF_disableSynthRefsys(void)
1385 {
1386     HWREG_WRITE_LRF(LRFDRFE32_BASE + LRFDRFE32_O_ATSTREF) = HWREG_READ_LRF(LRFDRFE32_BASE + LRFDRFE32_O_ATSTREF) & (~LRFDRFE32_ATSTREF_BIAS_M);
1387 }
1388 
LRF_rclEnableRadioClocks(void)1389 void LRF_rclEnableRadioClocks(void)
1390 {
1391     LRF_setRclClockEnable(LRFDDBELL_CLKCTL_BUFRAM_M |
1392                           LRFDDBELL_CLKCTL_DSBRAM_M |
1393                           LRFDDBELL_CLKCTL_RFERAM_M |
1394                           LRFDDBELL_CLKCTL_MCERAM_M |
1395                           LRFDDBELL_CLKCTL_PBERAM_M |
1396                           LRFDDBELL_CLKCTL_RFE_M |
1397                           LRFDDBELL_CLKCTL_MDM_M |
1398                           LRFDDBELL_CLKCTL_PBE_M);
1399 }
1400 
LRF_rclDisableRadioClocks(void)1401 void LRF_rclDisableRadioClocks(void)
1402 {
1403     LRF_clearRclClockEnable(LRFDDBELL_CLKCTL_BUFRAM_M |
1404                             LRFDDBELL_CLKCTL_DSBRAM_M |
1405                             LRFDDBELL_CLKCTL_RFERAM_M |
1406                             LRFDDBELL_CLKCTL_MCERAM_M |
1407                             LRFDDBELL_CLKCTL_PBERAM_M |
1408                             LRFDDBELL_CLKCTL_RFE_M |
1409                             LRFDDBELL_CLKCTL_MDM_M |
1410                             LRFDDBELL_CLKCTL_PBE_M);
1411 }
1412 
LRF_readRssi(void)1413 int8_t LRF_readRssi(void)
1414 {
1415     return (int8_t)(HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_RSSI) & LRFDRFE_RSSI_VAL_M);
1416 }
1417 
LRF_setRawTxPower(uint32_t value,uint32_t temperatureCoefficient)1418 void LRF_setRawTxPower(uint32_t value, uint32_t temperatureCoefficient)
1419 {
1420     lrfPhyState.rawTxPower.value.rawValue = value;
1421     lrfPhyState.rawTxPower.tempCoeff = temperatureCoefficient;
1422     lrfPhyState.rawTxPower.power = LRF_TxPower_Use_Raw;
1423 }
1424 
LRF_getRawTxPower(void)1425 LRF_TxPowerTable_Entry LRF_getRawTxPower(void)
1426 {
1427     if (lrfPhyState.rawTxPower.power.rawValue == LRF_TxPower_Use_Raw.rawValue)
1428     {
1429         /* Raw TX power has been set */
1430         return lrfPhyState.rawTxPower;
1431     }
1432     else
1433     {
1434         /* Error: Raw TX power was never set */
1435         return LRF_TxPowerEntry_INVALID_VALUE;
1436     }
1437 }
1438 
1439 /* Avoid IB = 0 as it effectively turns the PA off */
1440 #define RFE_PA0_IB_MIN_USED 1
1441 
LRF_programTemperatureCompensatedTxPower(void)1442 void LRF_programTemperatureCompensatedTxPower(void)
1443 {
1444     LRF_TxPowerTable_Entry txPowerEntry = lrfPhyState.currentTxPower;
1445     uint8_t tempCoeff = txPowerEntry.tempCoeff;
1446     if (tempCoeff != 0)
1447     {
1448         int32_t ib = txPowerEntry.value.ib;
1449         int32_t temperature = hal_get_temperature();
1450         /* Linear adjustment of IB field as a function of temperature, scaled
1451          * by the coefficient for the given setting */
1452         ib += ((temperature - LRF_TXPOWER_REFERENCE_TEMPERATURE) * (int32_t) tempCoeff)
1453             / LRF_TXPOWER_TEMPERATURE_SCALING;
1454         /* Saturate IB */
1455         if (ib < (int32_t) RFE_PA0_IB_MIN_USED)
1456         {
1457             ib = RFE_PA0_IB_MIN_USED;
1458         }
1459 #ifdef DeviceFamily_CC27XX
1460         /* TODO: See RCL-444. Use LRFDRFE_PA1_IB_MAX for CC27XX. */
1461         if (ib > (int32_t) (LRFDRFE_PA1_IB_MAX >> LRFDRFE_PA1_IB_S))
1462         {
1463             ib = LRFDRFE_PA1_IB_MAX >> LRFDRFE_PA1_IB_S;
1464         }
1465 #else
1466         if (ib > (int32_t) (LRFDRFE_PA0_IB_MAX >> LRFDRFE_PA0_IB_S))
1467         {
1468             ib = LRFDRFE_PA0_IB_MAX >> LRFDRFE_PA0_IB_S;
1469         }
1470 #endif
1471         txPowerEntry.value.ib = ib;
1472     }
1473     /* Program into RFE shadow register for PA power */
1474     HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_SPARE5) = txPowerEntry.value.rawValue;
1475 }
1476 
LRF_programTxPower(LRF_TxPowerTable_Index powerLevel)1477 LRF_TxPowerResult LRF_programTxPower(LRF_TxPowerTable_Index powerLevel)
1478 {
1479     if (powerLevel.rawValue != LRF_TxPower_None.rawValue)
1480     {
1481         LRF_SwParam *swParam = (LRF_SwParam *) swParamList;
1482         LRF_TxPowerTable_Entry txPowerEntry = LRF_TxPowerTable_findValue(swParam->txPowerTable, powerLevel);
1483         if (txPowerEntry.value.rawValue != LRF_TxPowerTable_INVALID_VALUE.rawValue)
1484         {
1485             lrfPhyState.currentTxPower = txPowerEntry;
1486             LRF_programTemperatureCompensatedTxPower();
1487         }
1488         else
1489         {
1490             return TxPowerResult_Error;
1491         }
1492     }
1493     return TxPowerResult_Ok;
1494 }
1495 
LRF_scaleFreqWithHFXTOffset(uint32_t frequency)1496 static uint32_t LRF_scaleFreqWithHFXTOffset(uint32_t frequency)
1497 {
1498     /* Get HFXT ratio from HFTRACKCTL register. This will have been
1499      * updated by the power driver if compensation is enabled and the temperature has drifted beyond the threshold.
1500      */
1501     uint32_t ratio = hal_get_hfxt_ratio();
1502 
1503     /* If temperature compensation is disabled, or temperature has not drifted,
1504      * the ratio will have its reset-value of 0x400000. In this case, do not perform scaling of input frequency
1505      * to save computational cost.
1506      * Rationale:
1507      * ratio = 24 MHz / (2 * HFXT_freq) * 2^24 ==> HFXT_freq = 24 MHz / ratio * 2^23
1508      * (ref: CKMD.HFTRACKCTL.RATIO register description)
1509      * Nominal HFXT frequency is 48 MHz
1510      *
1511      * frequency_out = frequency_in * HFXT_nominal_freq / HFXT_freq
1512      *               = frequency_in * 48 MHz / (24 MHz / ratio * 2^23)
1513      * frequency_out = frequency_in * ratio * 2^-22
1514      *
1515      * The method below is a computationally cost-effective way to calculate the scaled result.
1516      * Instead of performing 64-bit multiplication and shifting, the multiplier and multiplicand are divided into
1517      * half-words which are multiplied, added, and shifted appropriately.
1518      */
1519     if (ratio != hal_get_hfxt_ratio_default())
1520     {
1521         uint32_t ah = frequency >> 16;      /* Multiplier high half-word */
1522         uint32_t al = frequency & 0xFFFF;   /* Multiplier low half-word */
1523 
1524         uint32_t bh = ratio >> 16;          /* Multiplicand high half-word */
1525         uint32_t bl = ratio & 0xFFFF;       /* Multiplicand low half-word */
1526 
1527         /* Perform standard long multiplication where each "digit" is a half-word
1528          * https://en.wikipedia.org/wiki/Multiplication_algorithm
1529          * The rounding error will be maximum 1 Hz in this calculation.
1530          * frequency * ratio >> 22 = [ah al] * [bh bl] >> 22
1531          * [ah al] * [bh bl] >> 22 = ([bl * al] + (([bl * ah] + [bh * al]) << 16) + ([bh * ah]) << 32) >> 22
1532          *                         = (([bl * ah] + [bh * al]) >> 6) + ([bh * ah]) << 10)
1533          */
1534         frequency = ((bl*ah + bh*al + ((bl*al) >> 16)) >> 6) + ((bh*ah) << 10);
1535     }
1536 
1537     return frequency;
1538 }
1539