1 /*
2  * Copyright (c) 2021-2023, 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  *  ======== LRF.c ========
34  */
35 
36 #include <stdint.h>
37 #include <stdlib.h>
38 
39 #include <ti/drivers/rcl/RCL_Command.h>
40 #include <ti/drivers/rcl/RCL_Debug.h>
41 #include <ti/drivers/rcl/LRF.h>
42 #include <ti/log/Log.h>
43 
44 // #define LRF_DEBUG_TRACE
45 
LRF_loadImage(const LRF_TOPsmImage * image,uint32_t destinationAddress)46 LRF_SetupResult LRF_loadImage(const LRF_TOPsmImage *image, uint32_t destinationAddress)
47 {
48     LRF_SetupResult result;
49 
50     if (image == NULL)
51     {
52         /* OK, don't load image */
53         result = SetupResult_Ok;
54     }
55     else
56     {
57         const uint32_t *topsmSourcePointer = image->image;
58         uint32_t *ram = (uint32_t *) destinationAddress;
59         uint32_t length = image->imageLen;
60 
61         if (length > (TOPSM_RAM_SZ / sizeof(uint32_t)))
62         {
63             /* Image too long */
64             result = SetupResult_ErrorImageLen;
65         }
66         else
67         {
68             uint32_t i = 0;
69             /* Check if the image is 128-bit aligned, and if not, read out 32-bit word(s) */
70             while ((((uintptr_t) topsmSourcePointer) & 0x0F) != 0)
71             {
72                 *ram++ = *topsmSourcePointer++;
73                 i++;
74             }
75             /* Load most of the image using aligned 128-bit reads */
76 #ifdef DeviceFamily_CC27XX
77             /* We don't need to use HWREG_READ_LRF every time, as the loop only writes to RAM without registers inbetween, but we should protect the first write */
78             ASM_4_NOPS();
79 #endif //DeviceFamily_CC27XX
80             while (i < length - 3)
81             {
82 #ifdef NO_INLINE_ASM
83                 struct quadword {
84                     uint32_t word[4];
85                 };
86                 *((struct quadword *) ram) = *((const struct quadword *) topsmSourcePointer);
87                 topsmSourcePointer += 4;
88                 ram += 4;
89 #else
90                 __asm(
91                     "LDMIA %0!, {r4, r5, r6, r7} \n"
92                     "STMIA %1!, {r4, r5, r6, r7} \n"
93                     : "+r" (topsmSourcePointer),
94                       "+r" (ram) :
95                     : "r4", "r5", "r6", "r7"
96                 );
97 #endif
98                 i += 4;
99             }
100 
101             /* If one or more 32-bit word is left, read it here */
102             while (i < length)
103             {
104                 *ram++ = *topsmSourcePointer++;
105                 i++;
106             }
107             result = SetupResult_Ok;
108         }
109     }
110     return result;
111 }
112 
LRF_initSettingsState(LRF_ApplySettingsState * state,LRF_ApplySettingsBase includeBase,uint16_t phyFeatures)113 void LRF_initSettingsState(LRF_ApplySettingsState *state,
114                            LRF_ApplySettingsBase   includeBase,
115                            uint16_t                phyFeatures)
116 {
117     LRF_resetSettingsState(state);
118     state->includeBase = includeBase;
119     state->phyFeatures = phyFeatures;
120 }
121 
LRF_applySettings(LRF_ConfigWord * config,LRF_ApplySettingsState * state,int32_t bufferAvailWords)122 LRF_SetupResult LRF_applySettings(LRF_ConfigWord         *config,
123                                   LRF_ApplySettingsState *state,
124                                   int32_t                 bufferAvailWords)
125 {
126 #ifdef BUFFER_SPLIT_SUPPORT
127     uint32_t totalLength = state->totalLength;
128 #else
129     (void)bufferAvailWords;
130 #endif
131     uint32_t segmentLength;
132     uint32_t regionLength;
133     LRF_RegionOperation operation = LRF_RegionOperation_Invalid;
134     uintptr_t address = 0;
135 
136     /* If settings is NULL, ignore the entry */
137     if (config == NULL)
138     {
139         return SetupResult_Ok;
140     }
141 
142     /* Use 32-bit pointer to read entries to ensure compailer doesn't insert
143        16-bit reads toward (possible) flash */
144     uint32_t *curEntry = &config->value32;
145 
146     /* Initialize state if starting fresh */
147 #ifdef BUFFER_SPLIT_SUPPORT
148     if (totalLength == 0)
149     {
150         if (bufferAvailWords < 2)
151         {
152             return SetupResult_ErrorElemLen;
153         }
154         LRF_ConfigWord curWord;
155         curWord.value32 = *curEntry;
156         totalLength = curWord.segment.length;    /* Total length is at least segment */
157 
158         segmentLength = 0; /* Expect region header next */
159         regionLength = 0;  /* Read segment next */
160         if (curWord.segment.compoundSegment != 0)
161         {
162             if (totalLength > MAX_REG_CONFIG_LEN || totalLength == 0)
163             {
164                 /* Too long or non-existent entry */
165                 return SetupResult_ErrorConfigLen;
166 
167             }
168 
169 #ifdef LRF_DEBUG_TRACE
170             Log_printf(RclCoreShort, Log_INFO, "New compound configration, length is %d", totalLength);
171 #endif
172 
173             /* Get subsegment length from next word */
174             curEntry++;
175             bufferAvailWords--; /* Decrement available words */
176         }
177         else
178         {
179             totalLength += 1; /* Simulate a compound header */
180 #ifdef LRF_DEBUG_TRACE
181             Log_printf(RclCoreShort, Log_INFO, "New configration, length is %d", totalLength);
182 #endif
183         }
184 
185         address = 0;
186         operation = LRF_RegionOperation_Invalid;
187 
188     }
189     else
190     {
191         segmentLength = state->segmentLength;
192         regionLength  = state->regionLength;
193         operation     = state->operation;
194         address       = state->address;
195 
196         totalLength -= segmentLength;
197         /* Check if we have words left to skip from last round */
198         if (operation == LRF_RegionOperation_Skip)
199         {
200             bufferAvailWords -= regionLength;
201             curEntry += regionLength;
202             if (bufferAvailWords < 0)
203             {
204                 /* Still more words to skip */
205                 segmentLength = -bufferAvailWords;       /* Number of words left of segment */
206                 /* Add unprocessed part of segment back */
207                 totalLength += segmentLength;
208                 state->regionLength = -bufferAvailWords; /* Signal number of words to skip */
209                 state->segmentLength = segmentLength;
210                 state->totalLength = totalLength;
211                 return SetupResult_Ok_Partial;
212             }
213             else
214             {
215                 /* Start new segment */
216                 segmentLength = 0;
217                 operation = LRF_RegionOperation_Invalid;
218             }
219         }
220 #ifdef LRF_DEBUG_TRACE
221         Log_printf(RclCoreShort, Log_INFO, "Resuming, totalLength:%d, segmentLength:%d address:0x%04X", totalLength, segmentLength, address & 0xffff);
222 #endif
223     }
224 #endif
225 
226     /* While entire segment not parsed, go on. Can abort in the middle if error or
227      * out of data */
228 #ifdef BUFFER_SPLIT_SUPPORT
229     while (totalLength + segmentLength > 0)
230 #endif
231     {
232 #ifdef BUFFER_SPLIT_SUPPORT
233         if (segmentLength == 0)
234 #endif
235         {
236             /* If segment length is 0, process new segment  */
237             LRF_ConfigWord curWord;
238             curWord.value32 = *curEntry++;
239             uint16_t featureMask = curWord.segment.featureMask;
240             if ((curWord.segment.invertedFeatureMask == 0 &&
241                 ((featureMask != 0 && (featureMask & state->phyFeatures) == 0) ||
242                     (featureMask == 0 && !state->includeBase))) ||
243                 (curWord.segment.invertedFeatureMask != 0 && (featureMask != (featureMask & ~state->phyFeatures))))
244             {
245                 /* We skip it */
246 #ifdef LRF_DEBUG_TRACE
247                 Log_printf(RclCoreShort, Log_INFO, "Skipping segment length %1d because invertedFeatureMask = %1d, phyFeatures is 0x%04X and segment's featureMask is 0x%04X", curWord.segment.length, curWord.segment.invertedFeatureMask, state->phyFeatures, featureMask);
248 #endif
249 #ifdef BUFFER_SPLIT_SUPPORT
250                 uint32_t skipSegmentLength = curWord.segment.length;
251                 bufferAvailWords -= skipSegmentLength + 1;
252                 totalLength -= skipSegmentLength + 1;
253 
254                 if (bufferAvailWords < 0)
255                 {
256                     segmentLength = -bufferAvailWords; /* Signal number of words to skip */
257                     regionLength = segmentLength;
258                     operation = LRF_RegionOperation_Skip; /* Skip when resuming */
259                     bufferAvailWords = 0;
260                 }
261                 else
262                 {
263                     curEntry += skipSegmentLength;
264                     segmentLength = 0;
265                 }
266 #else
267                 segmentLength = 0;
268                 return SetupResult_Ok;
269 #endif
270             }
271             else
272             {
273                 segmentLength = curWord.segment.length;
274 #ifdef LRF_DEBUG_TRACE
275                 Log_printf(RclCoreShort, Log_INFO, "New segment, segmentLength:%d", segmentLength);
276 #endif
277 
278 #ifdef BUFFER_SPLIT_SUPPORT
279                 if (segmentLength == 0 || segmentLength >= totalLength)
280                 {
281                     return SetupResult_ErrorConfigLen;
282                 }
283                 bufferAvailWords--;
284                 totalLength -= segmentLength + 1;
285 #else
286                 if (segmentLength == 0 || segmentLength >= MAX_REG_CONFIG_LEN)
287                 {
288                     return SetupResult_ErrorConfigLen;
289                 }
290 #endif
291                 regionLength = 0;  /* Read segment next */
292             }
293         }
294         while (segmentLength > 0)
295         {
296 #ifdef BUFFER_SPLIT_SUPPORT
297             if (bufferAvailWords == 0)
298             {
299                 /* Add unprocessed part of segment back */
300                 totalLength += segmentLength;
301                 state->totalLength = totalLength;
302                 state->segmentLength = segmentLength;
303                 state->regionLength = regionLength;
304                 state->operation = operation;
305                 state->address = address;
306 
307                 return SetupResult_Ok_Partial;
308             }
309 #endif
310             /* If regionLength is 0 we are expecting a region header */
311             if (regionLength == 0)
312             {
313                 LRF_ConfigWord curWord;
314                 curWord.value32 = *curEntry++;
315                 regionLength = curWord.region.lengthMinus1 + 1;
316                 operation    = (LRF_RegionOperation) curWord.region.type;
317                 uint32_t regionStart  = curWord.region.startAddress;
318 
319                 /* Accounting. Parsed a region header, so consume+increment word and
320                  * parsed count */
321                 segmentLength--;
322 #ifdef BUFFER_SPLIT_SUPPORT
323                 bufferAvailWords--;
324 #endif
325                 /* Find correct region base address */
326                 if (operation >= SW_Region_Clear && operation != HW_Write_16bit_masked)
327                 {
328                     if (operation >= Par_Region_Clear)
329                     {
330                         address = ((uintptr_t) &swParamList) + regionStart;
331                         uint32_t regionActualLength = (operation == Par_Reference_32bit) ? 1 : regionLength;
332                         if ((regionStart + (regionActualLength * sizeof(uint32_t))) > swParamListSz)
333                         {
334                             return SetupResult_ErrorParRange;
335                         }
336                     }
337                     else
338                     {
339                         address = PBE_RAM_BASE_ADDR + regionStart;
340                     }
341                 }
342                 else
343                 {
344                     address  = LRF_BASE_ADDR + regionStart;
345                 }
346 #ifdef LRF_DEBUG_TRACE
347                 Log_printf(RclCoreShort, Log_INFO, "New region, regionLength:%d address:0x%04X, operation:%d", regionLength, address & 0xffff, operation);
348 #endif
349             }
350 
351             /* Shuffle the data as requested */
352             uint32_t numWords;
353             switch (operation)
354             {
355                 case HW_Region_Clear:
356                 case Par_Region_Clear:
357                     {
358                         if ((address & 0x03) != 0)
359                         {
360                             return SetupResult_ErrorElemAddrAlign;
361                         }
362                         volatile uint32_t *clear32 = (uint32_t *) address;
363                         for (uint32_t i = 0; i < regionLength; i++)
364                         {
365 #ifdef DeviceFamily_CC27XX
366                             HWREG_WRITE_LRF(clear32++) = 0;
367 #else
368                             *clear32++ = 0;
369 #endif //DeviceFamily_CC27XX
370                         }
371                         regionLength = 0;
372                         numWords = 0;
373                     }
374                     break;
375 
376                 case SW_Region_Clear:
377                     {
378                         if ((address & 0x01) != 0)
379                         {
380                             return SetupResult_ErrorElemAddrAlign;
381                         }
382                         volatile uint16_t *clear16 = (uint16_t *) address;
383                         for (uint32_t i = 0; i < regionLength; i++)
384                         {
385 #ifdef DeviceFamily_CC27XX
386                             HWREGH_WRITE_LRF(clear16++) = 0;
387 #else
388                             *clear16++ = 0;
389 #endif //DeviceFamily_CC27XX
390                         }
391                         regionLength = 0;
392                         numWords = 0;
393                     }
394                     break;
395 
396                 case HW_Write_16bit:
397                 case SW_Write_16bit:
398                     /* Two output words per input words. If number of input
399                         word is odd, last half-word is taken separately */
400                     if ((address & 0x01) != 0)
401                     {
402                         return SetupResult_ErrorElemAddrAlign;
403                     }
404                     numWords = regionLength / 2;
405                     break;
406 
407                 case HW_Write_16bit_masked:
408                     if ((address & 0x01) != 0)
409                     {
410                         return SetupResult_ErrorElemAddrAlign;
411                     }
412                     numWords = regionLength;
413                     break;
414 
415                 case Par_Reference_32bit:
416                 case HW_Write_32bit:
417                 case SW_Write_32bit:
418                 case Par_Write_32bit:
419                 case HW_Write_16bit_sparse:
420                 case SW_Write_16bit_sparse:
421                     if ((address & 0x03) != 0)
422                     {
423                         return SetupResult_ErrorElemAddrAlign;
424                     }
425                     numWords = regionLength;
426                     break;
427 
428                  default:
429                     return SetupResult_ErrorElemType;
430             }
431             if (numWords > segmentLength)
432             {
433                 return SetupResult_ErrorElemLen;
434             }
435 #ifdef BUFFER_SPLIT_SUPPORT
436             if ((int32_t)numWords > bufferAvailWords)
437             {
438                 numWords = bufferAvailWords;
439             }
440 #endif
441             if (numWords > 0)
442             {
443                 /* Write as much as we can */
444                 switch (operation)
445                 {
446                     case HW_Write_16bit:
447                         {
448                             volatile uint32_t *dst32 = (volatile uint32_t *) address;
449                             for (uint32_t i = 0; i < numWords; i++)
450                             {
451                                 LRF_ConfigWord curWord;
452                                 curWord.value32 = *curEntry++;
453 #ifdef LRF_DEBUG_TRACE
454                                 Log_printf(RclCore, Log_INFO1, "HW_Write_16bit: %04X = %08X, ", dst32&0xFFFF, curWord.value32);
455 #endif
456 
457 #ifdef DeviceFamily_CC27XX
458                                 HWREG_WRITE_LRF(dst32++) = curWord.value16[0];
459                                 HWREG_WRITE_LRF(dst32++) = curWord.value16[1];
460 #else
461                                 *dst32++ = curWord.value16[0];
462                                 *dst32++ = curWord.value16[1];
463 #endif //DeviceFamily_CC27XX
464                             }
465                             regionLength -= 2 * numWords;
466                             address = (uintptr_t) dst32;
467                         }
468                         break;
469 
470                     case HW_Write_16bit_masked:
471                         {
472                             volatile uint32_t *dst32 = (volatile uint32_t *) address;
473                             for (uint32_t i = 0; i < numWords; i++)
474                             {
475                                 LRF_ConfigWord curWord;
476                                 curWord.value32 = *curEntry++;
477 #ifdef LRF_DEBUG_TRACE
478                                 Log_printf(RclCoreShort, Log_INFO1, "HW_Write_16bit_Masked: %04X: mask %04X value %04X, ",
479                                     dst32&0xFFFF, curWord.masked.mask16, curWord.masked.value16);
480 #endif
481                                 /* On full setup, do not apply mask, as the register is assumed to start at 0 */
482                                 if (state->includeBase)
483                                 {
484 #ifdef DeviceFamily_CC27XX
485                                     HWREG_WRITE_LRF(dst32++) = curWord.masked.value16;
486 #else
487                                     *dst32++ = curWord.masked.value16;
488 #endif //DeviceFamily_CC27XX
489                                 }
490                                 else
491                                 {
492                                     /* The type is intended for 16-bit registers with 32-bit aperture */
493                                     /* If used on a true 32-bit register, the 16 most significant bits will not be changed */
494 #ifdef DeviceFamily_CC27XX
495                                     uint32_t oldValue = HWREG_READ_LRF(dst32);
496                                     HWREG_WRITE_LRF(dst32++) = (oldValue & ~curWord.masked.mask16) | curWord.masked.value16;
497 #else
498                                     uint32_t oldValue = *dst32;
499                                     *dst32++ = (oldValue & ~curWord.masked.mask16) | curWord.masked.value16;
500 #endif //DeviceFamily_CC27XX
501                                 }
502                             }
503                             regionLength -= numWords;
504                             address = (uintptr_t) dst32;
505                         }
506                         break;
507 
508                     case SW_Write_16bit:
509                         {
510                             volatile uint16_t *dst16 = (volatile uint16_t *) address;
511                             for (uint32_t i = 0; i < numWords; i++)
512                             {
513                                 LRF_ConfigWord curWord;
514                                 curWord.value32 = *curEntry++;
515 #ifdef LRF_DEBUG_TRACE
516                                 Log_printf(RclCore, Log_INFO1, "SW_Write_16bit: %04X = %08X, ", dst16&0xFFFF, curWord.value32);
517 #endif
518 
519 #ifdef DeviceFamily_CC27XX
520                                 HWREGH_WRITE_LRF(dst16++) = curWord.value16[0];
521                                 HWREGH_WRITE_LRF(dst16++) = curWord.value16[1];
522 #else
523                                 *dst16++ = curWord.value16[0];
524                                 *dst16++ = curWord.value16[1];
525 #endif //DeviceFamily_CC27XX
526                             }
527                             regionLength -= 2 * numWords;
528                             address = (uintptr_t) dst16;
529                         }
530                         break;
531 
532                     case HW_Write_32bit:
533                     case SW_Write_32bit:
534                     case Par_Write_32bit:
535                         {
536                             volatile uint32_t *dst32 = (volatile uint32_t *) address;
537                             for (uint32_t i = 0; i < numWords; i++)
538                             {
539 #ifdef LRF_DEBUG_TRACE
540                                 switch(operation)
541                                 {
542                                     case HW_Write_32bit:
543                                         Log_printf(RclCore, Log_INFO1, "HW_Write_32bit: %04X = %08X", dst32&0xffff, *curEntry);
544                                         break;
545                                     case SW_Write_32bit:
546                                         Log_printf(RclCore, Log_INFO1, "SW_Write_32bit: %04X = %08X", dst32&0xffff, *curEntry);
547                                         break;
548                                     case Par_Write_32bit:
549                                         Log_printf(RclCore, Log_INFO1, "Par_Write_32bit: %04X = %08X", dst32&0xffff, *curEntry);
550                                         break;
551                                     default:
552                                         break;
553                                 }
554 #endif
555 #ifdef DeviceFamily_CC27XX
556                                 HWREG_WRITE_LRF(dst32++) = *curEntry++;
557 #else
558                                 *dst32++ = *curEntry++;
559 #endif //DeviceFamily_CC27XX
560                             }
561                             regionLength -= numWords;
562                             address = (uintptr_t) dst32;
563                         }
564                         break;
565 
566                     case Par_Reference_32bit:
567                         {
568 #ifdef BUFFER_SPLIT_SUPPORT
569                             /* Embedded constants must be contiguous */
570                             if ((int32_t)regionLength > bufferAvailWords)
571                             {
572                                 return SetupResult_ErrorParRange;
573                             }
574 #endif
575                             volatile uint32_t **dst32 = (volatile uint32_t **) address;
576                             *dst32 = curEntry;
577                             regionLength -= numWords;
578                             curEntry += numWords;
579 #ifdef LRF_DEBUG_TRACE
580                             Log_printf(RclCore, Log_INFO1, "Par_Reference_32bit: %04X = %08X", address, *dst32);
581 #endif
582                         }
583                         break;
584 
585                     case HW_Write_16bit_sparse:
586                         for (uint32_t i = 0; i < numWords; i++)
587                         {
588                             LRF_ConfigWord curWord;
589                             curWord.value32 = *curEntry++;
590                             uint32_t curAddress = curWord.sparse.address;
591                             if ((curAddress & 3) == 0)
592                             {
593                                 /* Word aligned access to hardware */
594                                 uint32_t *dst32 = (uint32_t *)(address + curAddress);
595 #ifdef DeviceFamily_CC27XX
596                                 HWREG_WRITE_LRF(dst32) = curWord.sparse.value16;
597 #else
598                                 *dst32          = curWord.sparse.value16;
599 #endif //DeviceFamily_CC27XX
600                             }
601                             else if ((curAddress & 1) == 0)
602                             {
603                                 /* Halfword aligned */
604                                 uint16_t *dst16 = (uint16_t *)(address + curAddress);
605 #ifdef DeviceFamily_CC27XX
606                                 HWREGH_WRITE_LRF(dst16) = curWord.sparse.value16;
607 #else
608                                 *dst16          = curWord.sparse.value16;
609 #endif //DeviceFamily_CC27XX
610                             }
611                             else
612                             {
613                                 return SetupResult_ErrorElemAddrAlign;
614                             }
615 #ifdef LRF_DEBUG_TRACE
616                             Log_printf(RclCoreShort, Log_INFO, "HW_Write_16bit_sparse: 0x%04X = 0x%04X", curAddress, curWord.sparse.value16);
617 #endif
618                         }
619                         regionLength -= numWords;
620                         break;
621 
622                     case SW_Write_16bit_sparse:
623                         for (uint32_t i = 0; i < numWords; i++)
624                         {
625                             LRF_ConfigWord curWord;
626                             curWord.value32 = *curEntry++;
627                             if ((curWord.sparse.address & 1) == 0)
628                             {
629                                 /* Word aligned 16 bit access  */
630                                 uint16_t *dst16 = (uint16_t *)(address + curWord.sparse.address);
631 #ifdef DeviceFamily_CC27XX
632                                 HWREGH_WRITE_LRF(dst16) = curWord.sparse.value16;
633 #else
634                                 *dst16          = curWord.sparse.value16;
635 #endif
636                             }
637                             else
638                             {
639                                 return SetupResult_ErrorElemAddrAlign;
640                             }
641 #ifdef LRF_DEBUG_TRACE
642                             Log_printf(RclCoreShort, Log_INFO, "SW_Write_16bit_sparse: 0x%04X = 0x%04X", curWord.sparse.address, curWord.sparse.value16);
643 #endif
644                         }
645                         regionLength -= numWords;
646                         break;
647 
648                     default:
649                         break;
650                 }
651 #ifdef BUFFER_SPLIT_SUPPORT
652                 bufferAvailWords -= numWords;
653 #endif
654                 segmentLength -= numWords;
655             }
656             /* Write straggler for 16-bit */
657             if (regionLength == 1 &&
658 #ifdef BUFFER_SPLIT_SUPPORT
659                 bufferAvailWords > 0 &&
660 #endif
661                 (operation == HW_Write_16bit || operation == SW_Write_16bit))
662             {
663                 if (segmentLength < 1)
664                 {
665                     return SetupResult_ErrorElemLen;
666                 }
667                 if (operation == SW_Write_16bit)
668                 {
669                     volatile uint16_t *dst16 = (volatile uint16_t *) address;
670                     LRF_ConfigWord curWord;
671                     curWord.value32 = *curEntry++;
672 #ifdef DeviceFamily_CC27XX
673                     HWREGH_WRITE_LRF(dst16) = curWord.value16[0];
674 #else
675                     *dst16 = curWord.value16[0];
676 #endif //DeviceFamily_CC27XX
677 #ifdef LRF_DEBUG_TRACE
678                     Log_printf(RclCoreShort, Log_INFO, "SW_Write_16bit: 0x%04X = 0x%04X, ", dst16&0xFFFF, curWord.value16[0]);
679 #endif
680                 }
681                 else
682                 {
683                     volatile uint32_t *dst32 = (volatile uint32_t *) address;
684                     LRF_ConfigWord curWord;
685                     curWord.value32 = *curEntry++;
686 #ifdef DeviceFamily_CC27XX
687                     HWREG_WRITE_LRF(dst32) = curWord.value16[0];
688 #else
689                     *dst32 = curWord.value16[0];
690 #endif //DeviceFamily_CC27XX
691 #ifdef LRF_DEBUG_TRACE
692                     Log_printf(RclCoreShort, Log_INFO, "HW_Write_16bit: 0x%04X = 0x%04X, ", dst32&0xFFFF, curWord.value16[0]);
693 #endif
694                 }
695                 regionLength -= 1;
696 #ifdef BUFFER_SPLIT_SUPPORT
697                 bufferAvailWords--;
698 #endif
699                 segmentLength--;
700             }
701         }
702         /* Done with this segment and its header */
703 #ifdef BUFFER_SPLIT_SUPPORT
704         if (bufferAvailWords == 0 && totalLength > 0)
705         {
706             state->totalLength = totalLength;
707             state->segmentLength = 0;
708             state->regionLength = 0;
709             state->operation = operation;
710 
711             return SetupResult_Ok_Partial;
712         }
713 #endif
714     }
715 
716 #ifdef BUFFER_SPLIT_SUPPORT
717     RCL_Debug_assert(totalLength == 0);
718 
719     state->totalLength = 0;
720 #endif
721 
722     return SetupResult_Ok;
723 }
724 
LRF_TxPowerTable_findValue(const LRF_TxPowerTable * table,LRF_TxPowerTable_Index powerLevel)725 LRF_TxPowerTable_Entry LRF_TxPowerTable_findValue(const LRF_TxPowerTable *table, LRF_TxPowerTable_Index powerLevel)
726 {
727     if (powerLevel.rawValue == LRF_TxPower_Use_Raw.rawValue)
728     {
729         /* Handle special input argument - return raw tx power setting if supported,
730            invalid value otherwise. */
731         return LRF_getRawTxPower();
732     }
733     else if (table != NULL && table->numEntries > 0 && powerLevel.rawValue <= LRF_TxPower_Use_Max.rawValue)
734     {
735         if (powerLevel.rawValue == LRF_TxPower_Use_Min.rawValue)
736         {
737             /* Handle special input argument - return lowest possible tx power. */
738             Log_printf(RclCore, Log_INFO, "Tx table search: lowest possible");
739             return table->powerTable[0];
740         }
741         else if (powerLevel.rawValue == LRF_TxPower_Use_Max.rawValue)
742         {
743             /* Handle special input argument - return highest possible tx power. */
744             Log_printf(RclCore, Log_INFO, "Tx table search: highest possible");
745             return table->powerTable[table->numEntries - 1];
746         }
747         else if (table->powerTable[0].power.rawValue > powerLevel.rawValue)
748         {
749             /* If the first entry is already larger, then the requested
750             power level is invalid. */
751             Log_printf(RclCore, Log_INFO, "Tx table search: %d too low", powerLevel.rawValue);
752             return LRF_TxPowerEntry_INVALID_VALUE;
753         }
754         else
755         {
756             for (size_t i = 1; i < table->numEntries; i++)
757             {
758                 /* Search for the first entry higher than target power level. */
759                 if (table->powerTable[i].power.rawValue > powerLevel.rawValue)
760                 {
761                     /* Return last entry that was not larger than target power level. */
762                     return table->powerTable[i - 1];
763                 }
764             }
765             if (table->powerTable[table->numEntries - 1].power.rawValue == powerLevel.rawValue)
766             {
767                 /* Return highest value if it matches the requested power level. */
768                 return table->powerTable[table->numEntries - 1];
769             }
770             else
771             {
772                 /* If no entries are larger than target power level, then the requested
773                 power level is invalid. */
774                 Log_printf(RclCore, Log_INFO, "Tx table search: %d too high", powerLevel.rawValue);
775                 return LRF_TxPowerEntry_INVALID_VALUE;
776             }
777         }
778     }
779     else
780     {
781         /* Return invalid value. This covers LRF_TxPower_Use_None. */
782         return LRF_TxPowerEntry_INVALID_VALUE;
783     }
784 }
785