1 /*
2  * Copyright (c) 2023-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  *  ======== adc_noise.c ========
34  */
35 
36 #include <stdint.h>
37 #include <stdlib.h>
38 #include <string.h>
39 
40 #include <ti/drivers/rcl/RCL_Command.h>
41 #include <ti/drivers/rcl/RCL_Types.h>
42 #include <ti/drivers/rcl/RCL_Scheduler.h>
43 
44 #include <ti/drivers/rcl/commands/adc_noise.h>
45 
46 #include <ti/log/Log.h>
47 
48 #include <ti/devices/DeviceFamily.h>
49 #include DeviceFamily_constructPath(inc/hw_lrfdrfe.h)
50 #include DeviceFamily_constructPath(inc/hw_lrfdrfe32.h)
51 #include DeviceFamily_constructPath(inc/rfe_common_ram_regs.h)
52 #include DeviceFamily_constructPath(inc/hw_lrfds2r.h)
53 #include DeviceFamily_constructPath(inc/hw_lrfdmdm.h)
54 #include DeviceFamily_constructPath(inc/hw_lrfddbell.h)
55 
56 /* Storage location of S2R samples */
57 #define ADC_NOISE_SAMPLE_MEM (PBE_RAM_BASE_ADDR)
58 #define ADC_NOISE_SAMPLE_PTR ((uint32_t *)ADC_NOISE_SAMPLE_MEM)
59 /* Start-address of PBE RAM in S2R address-space */
60 #ifdef DeviceFamily_CC23X0R2
61 #define ADC_NOISE_SAMPLE_MEM_S2R_START 1024
62 #else
63 #define ADC_NOISE_SAMPLE_MEM_S2R_START 2048
64 #endif
65 
66 struct
67 {
68     uint8_t synthRefsys:1;
69     uint8_t powerUp:1;
70     uint8_t s2rConversion:1;
71 } adcNoiseHandlerState;
72 
73 static void RCL_Handler_Adc_Noise_configureS2R(uint32_t numWords);
74 static void RCL_Handler_Adc_Noise_powerUp(void);
75 static void RCL_Handler_Adc_Noise_powerDown(void);
76 
77 /*
78  *  ======== RCL_Handler_ADC_Noise_getNoise ========
79  */
RCL_Handler_ADC_Noise_getNoise(RCL_Command * cmd,LRF_Events lrfEvents,RCL_Events rclEventsIn)80 RCL_Events RCL_Handler_ADC_Noise_getNoise(RCL_Command *cmd, LRF_Events lrfEvents, RCL_Events rclEventsIn)
81 {
82     RCL_CmdAdcNoiseGet *adcCmd = (RCL_CmdAdcNoiseGet *)cmd;
83     RCL_Events rclEvents = {.value = 0};
84 
85     if (rclEventsIn.setup != 0)
86     {
87         uint32_t earliestStartTime;
88         RCL_CommandStatus startTimeStatus;
89 
90         /* Verify that length is greater than 0, and does not exceed maximum.
91          * A length of 0 is not handled by the S2R module, so abort here.
92          */
93         if ((adcCmd->numWords == 0) || (adcCmd->numWords > RCL_ADC_NOISE_MAX_NUM_WORDS))
94         {
95             cmd->status = RCL_CommandStatus_Error_Param;
96             rclEvents.lastCmdDone = 1;
97             return rclEvents;
98         }
99 
100         /* Start by enabling refsys */
101         earliestStartTime = LRF_enableSynthRefsys();
102 
103         /* Schedule new command start-time to wait for refsys */
104         startTimeStatus = RCL_Scheduler_setStartStopTimeEarliestStart(cmd, earliestStartTime);
105 
106         if (startTimeStatus >= RCL_CommandStatus_Finished)
107         {
108             cmd->status = startTimeStatus;
109             rclEvents.lastCmdDone = 1;
110             LRF_disableSynthRefsys();
111         }
112         else
113         {
114             /* Initialise handler state */
115             adcNoiseHandlerState.powerUp = 0;
116             adcNoiseHandlerState.s2rConversion = 0;
117 
118             /* Indicate that command has been accepted and is active */
119             cmd->status = RCL_CommandStatus_Active;
120             /* Update handler state */
121             adcNoiseHandlerState.synthRefsys = 1;
122         }
123     }
124 
125     if (cmd->status == RCL_CommandStatus_Active)
126     {
127         if (rclEventsIn.timerStart != 0)
128         {
129             if (adcNoiseHandlerState.synthRefsys != 0)
130             {
131                 /* Power up hardware */
132                 RCL_Handler_Adc_Noise_powerUp();
133 
134                 /* Configure S2R */
135                 RCL_Handler_Adc_Noise_configureS2R(adcCmd->numWords);
136 
137                 Log_printf(RclCore, Log_VERBOSE, "RFE powered up. Configured S2R for %d words, buffer: 0x%x", adcCmd->numWords, adcCmd->output);
138 
139                 adcNoiseHandlerState.synthRefsys = 0;
140                 adcNoiseHandlerState.powerUp = 1;
141                 rclEvents.cmdStarted = 1;
142             }
143 
144             if (adcNoiseHandlerState.s2rConversion != 0)
145             {
146                 /* Make sure S2R is complete */
147                 while (HWREG_READ_LRF(LRFDS2R_BASE + LRFDS2R_O_STAT) & LRFDS2R_STAT_RUNNING_M);
148 
149                 /* Power down hardware */
150                 RCL_Handler_Adc_Noise_powerDown();
151 
152                 if (adcCmd->output == NULL)
153                 {
154                     /* Update output pointer if it was NULL */
155                     adcCmd->output = ADC_NOISE_SAMPLE_PTR;
156                 }
157                 else
158                 {
159                     /* Copy data from ADC_NOISE_SAMPLE_MEM to output buffer */
160                     memcpy(adcCmd->output, ADC_NOISE_SAMPLE_PTR, adcCmd->numWords * sizeof(uint32_t));
161                     /* Clear data from LRF RAM */
162                     memset(ADC_NOISE_SAMPLE_PTR, 0, adcCmd->numWords * sizeof(uint32_t));
163                 }
164 
165                 /* Command is complete */
166                 adcNoiseHandlerState.s2rConversion = 0;
167                 cmd->status = RCL_CommandStatus_Finished;
168                 rclEvents.lastCmdDone = 1;
169             }
170         }
171 
172         if (lrfEvents.rfedone != 0)
173         {
174             /* Hardware is powered up - proceed to start collecting samples */
175             if (adcNoiseHandlerState.powerUp != 0)
176             {
177                 RCL_CommandStatus startTimeStatus;
178 
179                 /* Clear messagebox */
180                 HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_MSGBOX) = 0;
181                 /* Start RX */
182                 HWREG_WRITE_LRF(LRFDPBE_BASE + LRFDPBE_O_RFEAPI) = 3;
183                 /* Wait until RX is up and running */
184                 while ((HWREG_READ_LRF(LRFDMDM_BASE + LRFDMDM_O_RFECMDIN) & 0x08) == 0);
185 
186                 /* Disable LNA and mixer clocks to reduce impact of any signal received on the antenna */
187                 HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_LNA) = HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_LNA) & (~LRFDRFE_LNA_EN_M);
188                 HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_DIVCTL) = HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_DIVCTL) & (~(LRFDRFE_DIVCTL_RXPH90DIV_M | LRFDRFE_DIVCTL_RXPH0DIV_M));
189 
190                 /* Initialize and enable ADC digital interface */
191                 HWREG_WRITE_LRF(LRFDMDM_BASE + LRFDMDM_O_INIT) = (LRFDMDM_INIT_ADCDIG_RESET);
192                 HWREG_WRITE_LRF(LRFDMDM_BASE + LRFDMDM_O_ENABLE) = (LRFDMDM_ENABLE_ADCDIG_EN);
193 
194                 /* Trigger one shot capture */
195                 HWREG_WRITE_LRF(LRFDS2R_BASE + LRFDS2R_O_TRIG) = LRFDS2R_TRIG_TRIG_ARM;
196 
197                 /* Wait for S2R to complete by setting new handler start time.
198                  * ADC sampling frequency is ~11.5 MSamples/s, or 3 words / 260 ns.
199                  * We wait for (words / 3) * 250 ns, as there is no need to sleep for too long.
200                  * The handler will poll for the last few us before reading out the samples
201                  */
202                 startTimeStatus = RCL_Scheduler_setNewStartAbsTime(RCL_Scheduler_getCurrentTime() + adcCmd->numWords / 3, true);
203 
204                 if (startTimeStatus >= RCL_CommandStatus_Finished)
205                 {
206                     cmd->status = startTimeStatus;
207                     rclEvents.lastCmdDone = 1;
208                     RCL_Handler_Adc_Noise_powerDown();
209                 }
210                 else
211                 {
212                     adcNoiseHandlerState.s2rConversion = 1;
213                 }
214 
215                 adcNoiseHandlerState.powerUp = 0;
216             }
217         }
218     }
219 
220     return rclEvents;
221 }
222 
223 /*
224  *  ======== RCL_Handler_Adc_Noise_configureS2R ========
225  */
RCL_Handler_Adc_Noise_configureS2R(uint32_t numWords)226 static void RCL_Handler_Adc_Noise_configureS2R(uint32_t numWords)
227 {
228     /* Enable S2R module */
229     LRF_setRclClockEnable(LRFDDBELL_CLKCTL_S2R_M);
230 
231     /* Configure S2R */
232     HWREG_WRITE_LRF(LRFDMDM_BASE + LRFDMDM_O_ADCDIGCONF) = (1 << LRFDMDM_ADCDIGCONF_QBRANCHEN_S) | (1 << LRFDMDM_ADCDIGCONF_IBRANCHEN_S);
233 
234     /* Setup Sample capture, use PBE RAM for storing samples */
235     HWREG_WRITE_LRF(LRFDS2R_BASE + LRFDS2R_O_CFG) = ((LRFDS2R_CFG_TRIGMODE_ONESHOT) |
236                                                     (LRFDS2R_CFG_SEL_ADCDIG) |
237                                                     (LRFDS2R_CFG_CTL_EN));
238 
239     /* Set start-address of where to store samples */
240     HWREG_WRITE_LRF(LRFDS2R_BASE + LRFDS2R_O_START) = ADC_NOISE_SAMPLE_MEM_S2R_START;
241     /* Set stop-address */
242     HWREG_WRITE_LRF(LRFDS2R_BASE + LRFDS2R_O_STOP) = ADC_NOISE_SAMPLE_MEM_S2R_START + numWords - 1;
243 }
244 
245 /*
246  *  ======== RCL_Handler_Adc_Noise_powerUp ========
247  */
RCL_Handler_Adc_Noise_powerUp(void)248 static void RCL_Handler_Adc_Noise_powerUp(void)
249 {
250     /* Write precomputed frequency words, based on frequency: 2440000000 */
251     HWREGH_WRITE_LRF(LRFD_RFERAM_BASE + RFE_COMMON_RAM_O_K5) = 0x9160;
252     HWREG_WRITE_LRF(LRFDRFE32_BASE + LRFDRFE32_O_CALMMID_CALMCRS) = 0x098604C4;
253     HWREG_WRITE_LRF(LRFDRFE32_BASE + LRFDRFE32_O_PLLM0) = 0x130E0000;
254     HWREG_WRITE_LRF(LRFDRFE32_BASE + LRFDRFE32_O_PLLM1) = 0x163B0000;
255     HWREGH_WRITE_LRF(LRFD_RFERAM_BASE + RFE_COMMON_RAM_O_RXIF) = 0;
256 
257     /* Initialize and enable RFE TOPsm */
258     HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_INIT) = (1 << LRFDRFE_INIT_TOPSM_S);
259     HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_ENABLE) = (1 << LRFDRFE_ENABLE_TOPSM_S);
260 
261     /* Wait for boot done */
262     while(HWREG_READ_LRF(LRFDRFE_BASE + LRFDRFE_O_MSGBOX) != 4);
263 
264     /* Clear message box */
265     HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_MSGBOX) = 0;
266     /* Calibrate PLL */
267     HWREG_WRITE_LRF(LRFDPBE_BASE + LRFDPBE_O_RFEAPI) = 4;
268 
269     /* Enable RFEDONE interrupt */
270     LRF_enableHwInterrupt(LRFDDBELL_IMASK0_RFEDONE_M);
271 }
272 
273 /*
274  *  ======== RCL_Handler_Adc_Noise_powerDown ========
275  */
RCL_Handler_Adc_Noise_powerDown(void)276 static void RCL_Handler_Adc_Noise_powerDown(void)
277 {
278     /* Disable RFEDONE interrupt */
279     LRF_disableHwInterrupt(LRFDDBELL_IMASK0_RFEDONE_M);
280 
281     /* Clear message box */
282     HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_MSGBOX) = 0;
283     /* Stop Radio */
284     HWREG_WRITE_LRF(LRFDPBE_BASE + LRFDPBE_O_RFEAPI) = 1;
285 
286     /* Wait until radio stops */
287     while (HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_RFEMSGBOX) == 0);
288 
289     /* Clear message box */
290     HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_MSGBOX) = 0;
291     /* Stop PLL */
292     HWREG_WRITE_LRF(LRFDPBE_BASE + LRFDPBE_O_RFEAPI) = 5;
293 
294     /* Wait until radio stops */
295     while (HWREG_READ_LRF(LRFDPBE_BASE + LRFDPBE_O_RFEMSGBOX) == 0);
296 
297     /* Disable S2R module */
298     HWREG_WRITE_LRF(LRFDS2R_BASE + LRFDS2R_O_CFG) = 0;
299     /* Initialize/Reset (needed for safe shut down of ADCDIG) */
300     HWREG_WRITE_LRF(LRFDMDM_BASE + LRFDMDM_O_INIT) = 0xFFFF;
301     /* Stop modem */
302     HWREG_WRITE_LRF(LRFDMDM_BASE + LRFDMDM_O_ENABLE) = 0;
303 
304     /* Request RFE powerdown */
305     HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_PDREQ) = LRFDRFE_PDREQ_TOPSMPDREQ_M;
306     /* Disable all RFE modules */
307     HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_ENABLE) = 0;
308     /* Stop powerdown request */
309     HWREG_WRITE_LRF(LRFDRFE_BASE + LRFDRFE_O_PDREQ) = 0;
310 
311     /* Disable S2R module */
312     LRF_clearRclClockEnable(LRFDDBELL_CLKCTL_S2R_M);
313 
314     /* Disable refsys */
315     LRF_disableSynthRefsys();
316 }
317