1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2017 NXP
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * o Redistributions of source code must retain the above copyright notice, this list
9 * of conditions and the following disclaimer.
10 *
11 * o Redistributions in binary form must reproduce the above copyright notice, this
12 * list of conditions and the following disclaimer in the documentation and/or
13 * other materials provided with the distribution.
14 *
15 * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "fsl_device_registers.h"
32 #include "fsl_xcvr.h"
33 #include "ifr_radio.h"
34 #include "fsl_os_abstraction.h"
35 /*******************************************************************************
36 * Definitions
37 ******************************************************************************/
38 #define IFR_RAM (0)
39
40 #if RADIO_IS_GEN_3P0
41 #define RDINDX (0x41U)
42 #define K3_BASE_INDEX (0x11U) /* Based for read index */
43 #else
44 #define RDRSRC (0x03U)
45 #define KW4x_512_BASE (0x20000U)
46 #define KW4x_256_BASE (0x10000U)
47 #endif /* RADIO_IS_GEN_3P0 */
48
49 #if RADIO_IS_GEN_2P1
50 #define FTFA (FTFE)
51 #endif /* RADIO_IS_GEN_2P1 */
52
53 /*******************************************************************************
54 * Prototypes
55 ******************************************************************************/
56 uint32_t read_another_ifr_word(void);
57 uint32_t read_first_ifr_word(uint32_t read_addr);
58
59 #if RADIO_IS_GEN_3P0
60 uint64_t read_index_ifr(uint32_t read_addr);
61 #else
62 /*! *********************************************************************************
63 * @brief Reads a location in block 1 IFR for use by the radio.
64 *
65 * This function handles reading IFR data from flash memory for trim loading.
66 *
67 * @param read_addr the address in the IFR to be read.
68 *
69 * @details This function wraps both the Gen2 read_resource command and the Gen2.1 and Gen3 read_index
70 ***********************************************************************************/
71 #if RADIO_IS_GEN_2P1
72 uint64_t read_resource_ifr(uint32_t read_addr);
73 #else
74 uint32_t read_resource_ifr(uint32_t read_addr);
75 #endif /* RADIO_IS_GEN_2P1 */
76 #endif /* RADIO_IS_GEN_3P0 */
77
78 void store_sw_trim(IFR_SW_TRIM_TBL_ENTRY_T * sw_trim_tbl, uint16_t num_entries, uint32_t addr, uint32_t data);
79
80 /*******************************************************************************
81 * Variables
82 ******************************************************************************/
83 static uint32_t ifr_read_addr;
84
85 #if RADIO_IS_GEN_3P0
86 static uint64_t packed_data_long; /* Storage for 2 32 bit values to be read by read_index */
87 static uint8_t num_words_avail; /* Number of 32 bit words available in packed_data_long storage */
88 const uint32_t BLOCK_1_IFR[]=
89 {
90 /* Revised fallback table which should work with untrimmed parts */
91 0xABCDFFFEU, /* Version #FFFE indicates default trim values */
92
93 /* Trim table is empty for Gen3 by default */
94
95 /* No TRIM_STATUS in SW fallback array. */
96 0xFEED0E0FU /* End of File */
97 };
98 #else
99 #if RADIO_IS_GEN_2P0
100 const uint32_t BLOCK_1_IFR[]=
101 {
102 /* Revised fallback table which should work with untrimmed parts */
103 0xABCDFFFEU, /* Version #FFFE indicates default trim values */
104
105 0x4005912CU, /* RSIM_ANA_TRIM address */
106 0x784B0000U, /* RSIM_ANA_TRIM default value */
107
108 /* No TRIM_STATUS in SW fallback array. */
109 0xFEED0E0FU /* End of File */
110 };
111 #else
112 static uint64_t packed_data_long; /* Storage for 2 32 bit values to be read by read_index */
113 static uint8_t num_words_avail; /* Number of 32 bit words available in packed_data_long storage */
114 const uint32_t BLOCK_1_IFR[]=
115 {
116 /* Revised fallback table which should work with untrimmed parts */
117 0xABCDFFFEU, /* Version #FFFE indicates default trim values */
118
119 0x4005912CU, /* RSIM_ANA_TRIM address */
120 0x784B0000U, /* RSIM_ANA_TRIM default value */
121
122 /* No TRIM_STATUS in SW fallback array. */
123 0xFEED0E0FU /* End of File */
124 };
125 #endif /* RADIO_IS_GEN_2P0 */
126 #endif /* RADIO_IS_GEN_3P0 */
127
128 /*******************************************************************************
129 * Code
130 ******************************************************************************/
131
132 /*! *********************************************************************************
133 * \brief Read command for reading the first 32bit word from IFR, encapsulates different
134 * flash IFR read mechanisms for multiple generations of SOC
135 *
136 * \param read_addr flash address
137 *
138 * \return 8 bytes of packed data containing radio trims only
139 *
140 ***********************************************************************************/
read_first_ifr_word(uint32_t read_addr)141 uint32_t read_first_ifr_word(uint32_t read_addr)
142 {
143 ifr_read_addr = read_addr;
144 return read_another_ifr_word();
145 }
146
147 /*! *********************************************************************************
148 * \brief Read command for reading additional 32bit words from IFR. Encapsulates multiple IFR read mechanisms.
149 *
150 * \param read_addr flash address
151 *
152 * \return 8 bytes of packed data containing radio trims only
153 *
154 * \remarks PRE-CONDITIONS:
155 * The function read_first_ifr_word() must have been called so that the ifr_read_addr variable is setup prior to use.
156 *
157 ***********************************************************************************/
read_another_ifr_word(void)158 uint32_t read_another_ifr_word(void)
159 {
160 uint32_t packed_data;
161
162 #if (RADIO_IS_GEN_3P0 || RADIO_IS_GEN_2P1)
163 /* Using some static storage and alternating reads to read_index_ifr to replace read_resource_ifr */
164 if (num_words_avail == 0)
165 {
166 #if RADIO_IS_GEN_3P0
167 packed_data_long = read_index_ifr(ifr_read_addr);
168 #else /* Use 64 bit return version of read_resource */
169 packed_data_long = read_resource_ifr(ifr_read_addr);
170 #endif /* RADIO_IS_GEN_3P0 */
171
172 num_words_avail = 2;
173 ifr_read_addr++; /* Read index addresses increment by 1 */
174 }
175
176 packed_data = (uint32_t)(packed_data_long & 0xFFFFFFFF);
177 packed_data_long = packed_data_long >> 32;
178 num_words_avail--;
179 #else
180 packed_data = read_resource_ifr(ifr_read_addr);
181 ifr_read_addr += 4; /* Read resource addresses increment by 4 */
182 #endif /* (RADIO_IS_GEN_3P0 || RADIO_IS_GEN_2P1) */
183
184 return packed_data;
185 }
186
187 #if RADIO_IS_GEN_3P0
188 /*! *********************************************************************************
189 * \brief Read command for reading from IFR using RDINDEX command
190 *
191 * \param read_addr flash address
192 *
193 * \return 8 bytes of packed data containing radio trims only
194 *
195 ***********************************************************************************/
read_index_ifr(uint32_t read_addr)196 uint64_t read_index_ifr(uint32_t read_addr)
197 {
198 uint8_t rdindex = read_addr;
199 uint64_t read_data;
200 uint8_t i;
201
202 while ((FTFE_FSTAT_CCIF_MASK & FTFE->FSTAT) == 0); /* Wait till CCIF=1 to make sure not interrupting a prior operation */
203
204 if ((FTFE->FSTAT & FTFE_FSTAT_ACCERR_MASK) == FTFE_FSTAT_ACCERR_MASK )
205 {
206 FTFE->FSTAT = (1 << FTFE_FSTAT_ACCERR_SHIFT); /* Write 1 to ACCEER to clear errors */
207 }
208
209 FTFE->FCCOB[0] = RDINDX;
210 FTFE->FCCOB[1] = rdindex;
211
212 OSA_InterrupDisable();
213 FTFE->FSTAT = FTFE_FSTAT_CCIF_MASK;
214 while((FTFE_FSTAT_CCIF_MASK & FTFE->FSTAT) == 0); /* Wait till CCIF=1 */
215 OSA_InterruptEnable();
216
217 /* Pack read data back into 64 bit type */
218 read_data = FTFE->FCCOB[11]; /* MSB goes in first, will be shifted left sequentially */
219 for (i = 10; i > 3; i--)
220 {
221 read_data = read_data << 8;
222 read_data |= FTFE->FCCOB[i];
223 }
224
225 return read_data;
226 }
227 #else
228
229 /*! *********************************************************************************
230 * \brief Read command for reading from IFR
231 *
232 * \param read_addr flash address
233 *
234 * \return packed data containing radio trims only
235 *
236 ***********************************************************************************/
237 #if RADIO_IS_GEN_2P0
read_resource_ifr(uint32_t read_addr)238 uint32_t read_resource_ifr(uint32_t read_addr)
239 {
240
241 uint32_t packed_data;
242 uint8_t flash_addr23_16, flash_addr15_8, flash_addr7_0;
243 uint32_t read_data31_24, read_data23_16, read_data15_8, read_data7_0;
244
245 flash_addr23_16 = (uint8_t)((read_addr & 0xFF0000) >> 16);
246 flash_addr15_8 = (uint8_t)((read_addr & 0x00FF00) >> 8);
247 flash_addr7_0 = (uint8_t)(read_addr & 0xFF);
248
249 while ((FTFA_FSTAT_CCIF_MASK & FTFA->FSTAT) == 0); /* Wait till CCIF=1 */
250
251 if ((FTFA->FSTAT & FTFA_FSTAT_ACCERR_MASK) == FTFA_FSTAT_ACCERR_MASK )
252 {
253 FTFA->FSTAT = (1<<FTFA_FSTAT_ACCERR_SHIFT); /* Write 1 to ACCEER to clear errors */
254 }
255
256 FTFA->FCCOB0 = RDRSRC;
257 FTFA->FCCOB1 = flash_addr23_16;
258 FTFA->FCCOB2 = flash_addr15_8;
259 FTFA->FCCOB3 = flash_addr7_0;
260 FTFA->FCCOB8 = 0x00;
261
262 OSA_InterruptDisable();
263 FTFA->FSTAT = FTFA_FSTAT_CCIF_MASK;
264 while ((FTFA_FSTAT_CCIF_MASK & FTFA->FSTAT) == 0); /* Wait till CCIF=1 */
265 OSA_InterruptEnable();
266
267 /* Start reading */
268 read_data31_24 = FTFA->FCCOB4; /* FTFA->FCCOB[4] */
269 read_data23_16 = FTFA->FCCOB5; /* FTFA->FCCOB[5] */
270 read_data15_8 = FTFA->FCCOB6; /* FTFA->FCCOB[6] */
271 read_data7_0 = FTFA->FCCOB7; /* FTFA->FCCOB[7] */
272
273 packed_data = (read_data31_24 << 24) | (read_data23_16 << 16) | (read_data15_8 << 8) | (read_data7_0 << 0);
274
275 return packed_data;
276 }
277 #else
read_resource_ifr(uint32_t read_addr)278 uint64_t read_resource_ifr(uint32_t read_addr)
279 {
280
281 uint64_t packed_data;
282 uint8_t flash_addr23_16, flash_addr15_8, flash_addr7_0;
283 uint8_t read_data[8];
284 uint64_t temp_64;
285 uint8_t i;
286
287 flash_addr23_16 = (uint8_t)((read_addr & 0xFF0000) >> 16);
288 flash_addr15_8 = (uint8_t)((read_addr & 0x00FF00) >> 8);
289 flash_addr7_0 = (uint8_t)(read_addr & 0xFF);
290 while((FTFE_FSTAT_CCIF_MASK & FTFE->FSTAT) == 0); /* Wait till CCIF=1 */
291
292 if ((FTFE->FSTAT & FTFE_FSTAT_ACCERR_MASK) == FTFE_FSTAT_ACCERR_MASK )
293 {
294 FTFE->FSTAT = (1<<FTFE_FSTAT_ACCERR_SHIFT); /* Write 1 to ACCEER to clear errors */
295 }
296
297 FTFE->FCCOB0 = RDRSRC;
298 FTFE->FCCOB1 = flash_addr23_16;
299 FTFE->FCCOB2 = flash_addr15_8;
300 FTFE->FCCOB3 = flash_addr7_0;
301 FTFE->FCCOB4 = 0x00;
302
303 OSA_InterruptDisable();
304 FTFE->FSTAT = FTFE_FSTAT_CCIF_MASK;
305 while ((FTFE_FSTAT_CCIF_MASK & FTFE->FSTAT) == 0); /* Wait till CCIF=1 */
306 OSA_InterruptEnable();
307
308 /* Start reading */
309 read_data[7] = FTFE->FCCOB4;
310 read_data[6] = FTFE->FCCOB5;
311 read_data[5] = FTFE->FCCOB6;
312 read_data[4] = FTFE->FCCOB7;
313 read_data[3] = FTFE->FCCOB8;
314 read_data[2] = FTFE->FCCOB9;
315 read_data[1] = FTFE->FCCOBA;
316 read_data[0] = FTFE->FCCOBB;
317
318 packed_data = 0;
319 for (i = 0; i < 8; i++)
320 {
321 temp_64 = read_data[i];
322 packed_data |= temp_64 << (i * 8);
323 }
324
325 return packed_data;
326 }
327
328 #endif /* RADIO_IS_GEN_2P0 */
329 #endif /* RADIO_IS_GEN_3P0 */
330
331 /*! *********************************************************************************
332 * \brief Store a SW trim value in the table passed in from calling function.
333 *
334 * \param sw_trim_tbl pointer to the software trim table to hold SW trim values
335 * \param num_entries the number of entries in the SW trim table
336 * \param addr the software trim ID
337 * \param data the value of the software trim
338 *
339 ***********************************************************************************/
store_sw_trim(IFR_SW_TRIM_TBL_ENTRY_T * sw_trim_tbl,uint16_t num_entries,uint32_t addr,uint32_t data)340 void store_sw_trim(IFR_SW_TRIM_TBL_ENTRY_T * sw_trim_tbl, uint16_t num_entries, uint32_t addr, uint32_t data)
341 {
342 uint16_t i;
343
344 if (sw_trim_tbl != NULL)
345 {
346 for (i = 0; i < num_entries; i++)
347 {
348 if (addr == sw_trim_tbl[i].trim_id)
349 {
350 sw_trim_tbl[i].trim_value = data;
351 sw_trim_tbl[i].valid = 1;
352 break; /* Don't need to scan the array any further... */
353 }
354 }
355 }
356 }
357
358 /*! *********************************************************************************
359 * \brief Process block 1 IFR data.
360 *
361 * \param sw_trim_tbl pointer to the software trim table to hold SW trim values
362 * \param num_entries the number of entries in the SW trim table
363 *
364 * \remarks
365 * Uses a IFR v2 formatted default array if the IFR is blank or corrupted.
366 * Stores SW trim values to an array passed into this function.
367 *
368 ***********************************************************************************/
handle_ifr(IFR_SW_TRIM_TBL_ENTRY_T * sw_trim_tbl,uint16_t num_entries)369 void handle_ifr(IFR_SW_TRIM_TBL_ENTRY_T * sw_trim_tbl, uint16_t num_entries)
370 {
371 uint32_t dest_addr;
372 uint32_t read_addr;
373 uint32_t dest_data;
374 uint32_t packed_data;
375 uint32_t *ifr_ptr;
376
377 #if RADIO_IS_GEN_3P0
378 num_words_avail = 0; /* Prep for handling 64 bit words from flash */
379 #endif /* RADIO_IS_GEN_3P0 */
380
381 #if RADIO_IS_GEN_3P0
382 read_addr = K3_BASE_INDEX;
383 #else
384 #ifdef CPU_MKW41Z256VHT4
385 read_addr = KW4x_256_BASE;
386 #else
387 read_addr = KW4x_512_BASE;
388 #endif /* CPU_MKW41Z256VHT4 */
389 #endif /* RADIO_IS_GEN_3P0 */
390
391 /* Read first entry in IFR table */
392 packed_data = read_first_ifr_word(read_addr);
393 if ((packed_data&~IFR_VERSION_MASK) == IFR_VERSION_HDR)
394 {
395 /* Valid header was found, process real IFR data */
396 XCVR_MISC->OVERWRITE_VER = (packed_data & IFR_VERSION_MASK);
397 store_sw_trim(sw_trim_tbl, num_entries, 0xABCD, (packed_data & IFR_VERSION_MASK)); /* Place IFR version # in SW trim array*/
398 packed_data = read_another_ifr_word();
399
400 while (packed_data !=IFR_EOF_SYMBOL)
401 {
402 if (IS_A_SW_ID(packed_data)) /* SW Trim case (non_reg writes) */
403 {
404 dest_addr = packed_data;
405 packed_data = read_another_ifr_word();
406 dest_data = packed_data;
407 /* Place SW trim in array for driver SW to use */
408 store_sw_trim(sw_trim_tbl, num_entries, dest_addr, dest_data);
409 }
410 else
411 {
412 if (IS_VALID_REG_ADDR(packed_data)) /* Valid register write address */
413 {
414 dest_addr = packed_data;
415 packed_data = read_another_ifr_word();
416 dest_data = packed_data;
417 *(uint32_t *)(dest_addr) = dest_data;
418 }
419 else
420 { /* Invalid address case */
421
422 }
423 }
424
425 packed_data=read_another_ifr_word();
426 }
427 }
428 else
429 {
430 /* Valid header is not present, use blind IFR trim table */
431 ifr_ptr = (void *)BLOCK_1_IFR;
432 packed_data = *ifr_ptr;
433 XCVR_MISC->OVERWRITE_VER = (packed_data & IFR_VERSION_MASK);
434 store_sw_trim(sw_trim_tbl, num_entries, 0xABCD, (packed_data & IFR_VERSION_MASK)); /* Place IFR version # in SW trim array */
435 ifr_ptr++;
436 packed_data= *ifr_ptr;
437
438 while (packed_data != IFR_EOF_SYMBOL)
439 {
440 if (IS_A_SW_ID(packed_data))
441 {
442 /* SW Trim case (non_reg writes) */
443 dest_addr = packed_data;
444 ifr_ptr++;
445 packed_data = *(ifr_ptr);
446 dest_data = packed_data;
447 /* Place SW trim in array for driver SW to use */
448 store_sw_trim(sw_trim_tbl, num_entries, dest_addr, dest_data);
449 }
450 else
451 {
452 dest_addr = packed_data;
453 ifr_ptr++;
454 packed_data = *ifr_ptr;
455 dest_data = packed_data;
456
457 /* Valid register write address */
458 if (IS_VALID_REG_ADDR(dest_addr))
459 {
460 *(uint32_t *)(dest_addr) = dest_data;
461 }
462 else
463 {
464 /* Invalid address case */
465 }
466 }
467
468 ifr_ptr++;
469 packed_data= *ifr_ptr;
470 }
471 }
472 }
473
474 #if RADIO_IS_GEN_3P0
475
476 #else
handle_ifr_die_id(void)477 uint32_t handle_ifr_die_id(void)
478 {
479 uint32_t id_x, id_y;
480 uint32_t id;
481
482 id = read_resource_ifr(0x90);
483 id_x = id & 0x00FF0000;
484 id_y = id & 0x000000FF;
485
486 return (id_x | id_y);
487 }
488
handle_ifr_die_kw_type(void)489 uint32_t handle_ifr_die_kw_type(void)
490 {
491 uint32_t zb, ble;
492
493 zb = read_resource_ifr(0x80) & 0x8000;
494 ble= read_resource_ifr(0x88) & 0x100000;
495
496 return (zb | ble);
497 }
498
499 #endif /* RADIO_IS_GEN_3P0 */
500
501 /*! *********************************************************************************
502 * \brief Dumps block 1 IFR data to an array.
503 *
504 * \param dump_tbl pointer to the table to hold the dumped IFR values
505 * \param num_entries the number of entries to dump
506 *
507 * \remarks
508 * Starts at the first address in IFR and dumps sequential entries.
509 *
510 ***********************************************************************************/
dump_ifr(uint32_t * dump_tbl,uint8_t num_entries)511 void dump_ifr(uint32_t * dump_tbl, uint8_t num_entries)
512 {
513 #if RADIO_IS_GEN_3P0
514 uint32_t ifr_address = 0x20000;
515 #else
516 uint32_t ifr_address = 0x20000;
517 #endif /* RADIO_IS_GEN_3P0 */
518 uint32_t * dump_ptr = dump_tbl;
519 uint8_t i;
520
521 *dump_ptr = read_first_ifr_word(ifr_address);
522 dump_ptr++;
523
524 for (i = 0; i < num_entries - 1; i++)
525 {
526 *dump_ptr = read_another_ifr_word();
527 dump_ptr++;
528 }
529 }
530
531