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