Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
ifr_radio.c
00001 /* 00002 * Copyright (c) 2015, Freescale Semiconductor, Inc. 00003 * Copyright 2016-2017 NXP 00004 * 00005 * Redistribution and use in source and binary forms, with or without modification, 00006 * are permitted provided that the following conditions are met: 00007 * 00008 * o Redistributions of source code must retain the above copyright notice, this list 00009 * of conditions and the following disclaimer. 00010 * 00011 * o Redistributions in binary form must reproduce the above copyright notice, this 00012 * list of conditions and the following disclaimer in the documentation and/or 00013 * other materials provided with the distribution. 00014 * 00015 * o Neither the name of Freescale Semiconductor, Inc. nor the names of its 00016 * contributors may be used to endorse or promote products derived from this 00017 * software without specific prior written permission. 00018 * 00019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 00020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 00023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 00026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00029 */ 00030 00031 #include "fsl_device_registers.h" 00032 #include "fsl_xcvr.h " 00033 #include "ifr_radio.h " 00034 #include "EmbeddedTypes.h " 00035 #include "platform/arm_hal_interrupt.h" 00036 /******************************************************************************* 00037 * Definitions 00038 ******************************************************************************/ 00039 #define IFR_RAM (0) 00040 00041 #if RADIO_IS_GEN_3P0 00042 #define RDINDX (0x41U) 00043 #define K3_BASE_INDEX (0x11U) /* Based for read index */ 00044 #else 00045 #define RDRSRC (0x03U) 00046 #define KW4x_512_BASE (0x20000U) 00047 #define KW4x_256_BASE (0x10000U) 00048 #endif /* RADIO_IS_GEN_3P0 */ 00049 00050 #if RADIO_IS_GEN_2P1 00051 #define FTFA (FTFE) 00052 #endif /* RADIO_IS_GEN_2P1 */ 00053 00054 /******************************************************************************* 00055 * Prototypes 00056 ******************************************************************************/ 00057 uint32_t read_another_ifr_word(void); 00058 uint32_t read_first_ifr_word(uint32_t read_addr); 00059 00060 #if RADIO_IS_GEN_3P0 00061 uint64_t read_index_ifr(uint32_t read_addr); 00062 #else 00063 /*! ********************************************************************************* 00064 * @brief Reads a location in block 1 IFR for use by the radio. 00065 * 00066 * This function handles reading IFR data from flash memory for trim loading. 00067 * 00068 * @param read_addr the address in the IFR to be read. 00069 * 00070 * @details This function wraps both the Gen2 read_resource command and the Gen2.1 and Gen3 read_index 00071 ***********************************************************************************/ 00072 #if RADIO_IS_GEN_2P1 00073 uint64_t read_resource_ifr(uint32_t read_addr); 00074 #else 00075 uint32_t read_resource_ifr(uint32_t read_addr); 00076 #endif /* RADIO_IS_GEN_2P1 */ 00077 #endif /* RADIO_IS_GEN_3P0 */ 00078 00079 void store_sw_trim(IFR_SW_TRIM_TBL_ENTRY_T * sw_trim_tbl, uint16_t num_entries, uint32_t addr, uint32_t data); 00080 00081 /******************************************************************************* 00082 * Variables 00083 ******************************************************************************/ 00084 static uint32_t ifr_read_addr; 00085 00086 #if RADIO_IS_GEN_3P0 00087 static uint64_t packed_data_long; /* Storage for 2 32 bit values to be read by read_index */ 00088 static uint8_t num_words_avail; /* Number of 32 bit words available in packed_data_long storage */ 00089 const uint32_t BLOCK_1_IFR[]= 00090 { 00091 /* Revised fallback table which should work with untrimmed parts */ 00092 0xABCDFFFEU, /* Version #FFFE indicates default trim values */ 00093 00094 /* Trim table is empty for Gen3 by default */ 00095 00096 /* No TRIM_STATUS in SW fallback array. */ 00097 0xFEED0E0FU /* End of File */ 00098 }; 00099 #else 00100 #if RADIO_IS_GEN_2P0 00101 const uint32_t BLOCK_1_IFR[]= 00102 { 00103 /* Revised fallback table which should work with untrimmed parts */ 00104 0xABCDFFFEU, /* Version #FFFE indicates default trim values */ 00105 00106 0x4005912CU, /* RSIM_ANA_TRIM address */ 00107 0x784B0000U, /* RSIM_ANA_TRIM default value */ 00108 00109 /* No TRIM_STATUS in SW fallback array. */ 00110 0xFEED0E0FU /* End of File */ 00111 }; 00112 #else 00113 static uint64_t packed_data_long; /* Storage for 2 32 bit values to be read by read_index */ 00114 static uint8_t num_words_avail; /* Number of 32 bit words available in packed_data_long storage */ 00115 const uint32_t BLOCK_1_IFR[]= 00116 { 00117 /* Revised fallback table which should work with untrimmed parts */ 00118 0xABCDFFFEU, /* Version #FFFE indicates default trim values */ 00119 00120 0x4005912CU, /* RSIM_ANA_TRIM address */ 00121 0x784B0000U, /* RSIM_ANA_TRIM default value */ 00122 00123 /* No TRIM_STATUS in SW fallback array. */ 00124 0xFEED0E0FU /* End of File */ 00125 }; 00126 #endif /* RADIO_IS_GEN_2P0 */ 00127 #endif /* RADIO_IS_GEN_3P0 */ 00128 00129 /******************************************************************************* 00130 * Code 00131 ******************************************************************************/ 00132 00133 /*! ********************************************************************************* 00134 * \brief Read command for reading the first 32bit word from IFR, encapsulates different 00135 * flash IFR read mechanisms for multiple generations of SOC 00136 * 00137 * \param read_addr flash address 00138 * 00139 * \return 8 bytes of packed data containing radio trims only 00140 * 00141 ***********************************************************************************/ 00142 uint32_t read_first_ifr_word(uint32_t read_addr) 00143 { 00144 ifr_read_addr = read_addr; 00145 return read_another_ifr_word(); 00146 } 00147 00148 /*! ********************************************************************************* 00149 * \brief Read command for reading additional 32bit words from IFR. Encapsulates multiple IFR read mechanisms. 00150 * 00151 * \param read_addr flash address 00152 * 00153 * \return 8 bytes of packed data containing radio trims only 00154 * 00155 * \remarks PRE-CONDITIONS: 00156 * The function read_first_ifr_word() must have been called so that the ifr_read_addr variable is setup prior to use. 00157 * 00158 ***********************************************************************************/ 00159 uint32_t read_another_ifr_word(void) 00160 { 00161 uint32_t packed_data; 00162 00163 #if (RADIO_IS_GEN_3P0 || RADIO_IS_GEN_2P1) 00164 /* Using some static storage and alternating reads to read_index_ifr to replace read_resource_ifr */ 00165 if (num_words_avail == 0) 00166 { 00167 #if RADIO_IS_GEN_3P0 00168 packed_data_long = read_index_ifr(ifr_read_addr); 00169 #else /* Use 64 bit return version of read_resource */ 00170 packed_data_long = read_resource_ifr(ifr_read_addr); 00171 #endif /* RADIO_IS_GEN_3P0 */ 00172 00173 num_words_avail = 2; 00174 ifr_read_addr++; /* Read index addresses increment by 1 */ 00175 } 00176 00177 packed_data = (uint32_t)(packed_data_long & 0xFFFFFFFF); 00178 packed_data_long = packed_data_long >> 32; 00179 num_words_avail--; 00180 #else 00181 packed_data = read_resource_ifr(ifr_read_addr); 00182 ifr_read_addr += 4; /* Read resource addresses increment by 4 */ 00183 #endif /* (RADIO_IS_GEN_3P0 || RADIO_IS_GEN_2P1) */ 00184 00185 return packed_data; 00186 } 00187 00188 #if RADIO_IS_GEN_3P0 00189 /*! ********************************************************************************* 00190 * \brief Read command for reading from IFR using RDINDEX command 00191 * 00192 * \param read_addr flash address 00193 * 00194 * \return 8 bytes of packed data containing radio trims only 00195 * 00196 ***********************************************************************************/ 00197 uint64_t read_index_ifr(uint32_t read_addr) 00198 { 00199 uint8_t rdindex = read_addr; 00200 uint64_t read_data; 00201 uint8_t i; 00202 00203 while ((FTFE_FSTAT_CCIF_MASK & FTFE->FSTAT) == 0); /* Wait till CCIF=1 to make sure not interrupting a prior operation */ 00204 00205 if ((FTFE->FSTAT & FTFE_FSTAT_ACCERR_MASK) == FTFE_FSTAT_ACCERR_MASK ) 00206 { 00207 FTFE->FSTAT = (1 << FTFE_FSTAT_ACCERR_SHIFT); /* Write 1 to ACCEER to clear errors */ 00208 } 00209 00210 FTFE->FCCOB[0] = RDINDX; 00211 FTFE->FCCOB[1] = rdindex; 00212 00213 platform_enter_critical(); 00214 FTFE->FSTAT = FTFE_FSTAT_CCIF_MASK; 00215 while((FTFE_FSTAT_CCIF_MASK & FTFE->FSTAT) == 0); /* Wait till CCIF=1 */ 00216 platform_exit_critical(); 00217 00218 /* Pack read data back into 64 bit type */ 00219 read_data = FTFE->FCCOB[11]; /* MSB goes in first, will be shifted left sequentially */ 00220 for (i = 10; i > 3; i--) 00221 { 00222 read_data = read_data << 8; 00223 read_data |= FTFE->FCCOB[i]; 00224 } 00225 00226 return read_data; 00227 } 00228 #else 00229 00230 /*! ********************************************************************************* 00231 * \brief Read command for reading from IFR 00232 * 00233 * \param read_addr flash address 00234 * 00235 * \return packed data containing radio trims only 00236 * 00237 ***********************************************************************************/ 00238 #if RADIO_IS_GEN_2P0 00239 uint32_t read_resource_ifr(uint32_t read_addr) 00240 { 00241 00242 uint32_t packed_data; 00243 uint8_t flash_addr23_16, flash_addr15_8, flash_addr7_0; 00244 uint32_t read_data31_24, read_data23_16, read_data15_8, read_data7_0; 00245 00246 flash_addr23_16 = (uint8_t)((read_addr & 0xFF0000) >> 16); 00247 flash_addr15_8 = (uint8_t)((read_addr & 0x00FF00) >> 8); 00248 flash_addr7_0 = (uint8_t)(read_addr & 0xFF); 00249 00250 while ((FTFA_FSTAT_CCIF_MASK & FTFA->FSTAT) == 0); /* Wait till CCIF=1 */ 00251 00252 if ((FTFA->FSTAT & FTFA_FSTAT_ACCERR_MASK) == FTFA_FSTAT_ACCERR_MASK ) 00253 { 00254 FTFA->FSTAT = (1<<FTFA_FSTAT_ACCERR_SHIFT); /* Write 1 to ACCEER to clear errors */ 00255 } 00256 00257 FTFA->FCCOB0 = RDRSRC; 00258 FTFA->FCCOB1 = flash_addr23_16; 00259 FTFA->FCCOB2 = flash_addr15_8; 00260 FTFA->FCCOB3 = flash_addr7_0; 00261 FTFA->FCCOB8 = 0x00; 00262 00263 platform_enter_critical(); 00264 FTFA->FSTAT = FTFA_FSTAT_CCIF_MASK; 00265 while ((FTFA_FSTAT_CCIF_MASK & FTFA->FSTAT) == 0); /* Wait till CCIF=1 */ 00266 platform_exit_critical(); 00267 00268 /* Start reading */ 00269 read_data31_24 = FTFA->FCCOB4; /* FTFA->FCCOB[4] */ 00270 read_data23_16 = FTFA->FCCOB5; /* FTFA->FCCOB[5] */ 00271 read_data15_8 = FTFA->FCCOB6; /* FTFA->FCCOB[6] */ 00272 read_data7_0 = FTFA->FCCOB7; /* FTFA->FCCOB[7] */ 00273 00274 packed_data = (read_data31_24 << 24) | (read_data23_16 << 16) | (read_data15_8 << 8) | (read_data7_0 << 0); 00275 00276 return packed_data; 00277 } 00278 #else 00279 uint64_t read_resource_ifr(uint32_t read_addr) 00280 { 00281 00282 uint64_t packed_data; 00283 uint8_t flash_addr23_16, flash_addr15_8, flash_addr7_0; 00284 uint8_t read_data[8]; 00285 uint64_t temp_64; 00286 uint8_t i; 00287 00288 flash_addr23_16 = (uint8_t)((read_addr & 0xFF0000) >> 16); 00289 flash_addr15_8 = (uint8_t)((read_addr & 0x00FF00) >> 8); 00290 flash_addr7_0 = (uint8_t)(read_addr & 0xFF); 00291 while((FTFE_FSTAT_CCIF_MASK & FTFE->FSTAT) == 0); /* Wait till CCIF=1 */ 00292 00293 if ((FTFE->FSTAT & FTFE_FSTAT_ACCERR_MASK) == FTFE_FSTAT_ACCERR_MASK ) 00294 { 00295 FTFE->FSTAT = (1<<FTFE_FSTAT_ACCERR_SHIFT); /* Write 1 to ACCEER to clear errors */ 00296 } 00297 00298 FTFE->FCCOB0 = RDRSRC; 00299 FTFE->FCCOB1 = flash_addr23_16; 00300 FTFE->FCCOB2 = flash_addr15_8; 00301 FTFE->FCCOB3 = flash_addr7_0; 00302 FTFE->FCCOB4 = 0x00; 00303 00304 platform_enter_critical(); 00305 FTFE->FSTAT = FTFE_FSTAT_CCIF_MASK; 00306 while ((FTFE_FSTAT_CCIF_MASK & FTFE->FSTAT) == 0); /* Wait till CCIF=1 */ 00307 platform_exit_critical(); 00308 00309 /* Start reading */ 00310 read_data[7] = FTFE->FCCOB4; 00311 read_data[6] = FTFE->FCCOB5; 00312 read_data[5] = FTFE->FCCOB6; 00313 read_data[4] = FTFE->FCCOB7; 00314 read_data[3] = FTFE->FCCOB8; 00315 read_data[2] = FTFE->FCCOB9; 00316 read_data[1] = FTFE->FCCOBA; 00317 read_data[0] = FTFE->FCCOBB; 00318 00319 packed_data = 0; 00320 for (i = 0; i < 8; i++) 00321 { 00322 temp_64 = read_data[i]; 00323 packed_data |= temp_64 << (i * 8); 00324 } 00325 00326 return packed_data; 00327 } 00328 00329 #endif /* RADIO_IS_GEN_2P0 */ 00330 #endif /* RADIO_IS_GEN_3P0 */ 00331 00332 /*! ********************************************************************************* 00333 * \brief Store a SW trim value in the table passed in from calling function. 00334 * 00335 * \param sw_trim_tbl pointer to the software trim table to hold SW trim values 00336 * \param num_entries the number of entries in the SW trim table 00337 * \param addr the software trim ID 00338 * \param data the value of the software trim 00339 * 00340 ***********************************************************************************/ 00341 void store_sw_trim(IFR_SW_TRIM_TBL_ENTRY_T * sw_trim_tbl, uint16_t num_entries, uint32_t addr, uint32_t data) 00342 { 00343 uint16_t i; 00344 00345 if (sw_trim_tbl != NULL) 00346 { 00347 for (i = 0; i < num_entries; i++) 00348 { 00349 if (addr == sw_trim_tbl[i].trim_id) 00350 { 00351 sw_trim_tbl[i].trim_value = data; 00352 sw_trim_tbl[i].valid = 1; 00353 break; /* Don't need to scan the array any further... */ 00354 } 00355 } 00356 } 00357 } 00358 00359 /*! ********************************************************************************* 00360 * \brief Process block 1 IFR data. 00361 * 00362 * \param sw_trim_tbl pointer to the software trim table to hold SW trim values 00363 * \param num_entries the number of entries in the SW trim table 00364 * 00365 * \remarks 00366 * Uses a IFR v2 formatted default array if the IFR is blank or corrupted. 00367 * Stores SW trim values to an array passed into this function. 00368 * 00369 ***********************************************************************************/ 00370 void handle_ifr(IFR_SW_TRIM_TBL_ENTRY_T * sw_trim_tbl, uint16_t num_entries) 00371 { 00372 uint32_t dest_addr; 00373 uint32_t read_addr; 00374 uint32_t dest_data; 00375 uint32_t packed_data; 00376 uint32_t *ifr_ptr; 00377 00378 #if RADIO_IS_GEN_3P0 00379 num_words_avail = 0; /* Prep for handling 64 bit words from flash */ 00380 #endif /* RADIO_IS_GEN_3P0 */ 00381 00382 #if RADIO_IS_GEN_3P0 00383 read_addr = K3_BASE_INDEX; 00384 #else 00385 #ifdef CPU_MKW41Z256VHT4 00386 read_addr = KW4x_256_BASE; 00387 #else 00388 read_addr = KW4x_512_BASE; 00389 #endif /* CPU_MKW41Z256VHT4 */ 00390 #endif /* RADIO_IS_GEN_3P0 */ 00391 00392 /* Read first entry in IFR table */ 00393 packed_data = read_first_ifr_word(read_addr); 00394 if ((packed_data&~IFR_VERSION_MASK) == IFR_VERSION_HDR) 00395 { 00396 /* Valid header was found, process real IFR data */ 00397 XCVR_MISC->OVERWRITE_VER = (packed_data & IFR_VERSION_MASK); 00398 store_sw_trim(sw_trim_tbl, num_entries, 0xABCD, (packed_data & IFR_VERSION_MASK)); /* Place IFR version # in SW trim array*/ 00399 packed_data = read_another_ifr_word(); 00400 00401 while (packed_data !=IFR_EOF_SYMBOL) 00402 { 00403 if (IS_A_SW_ID(packed_data)) /* SW Trim case (non_reg writes) */ 00404 { 00405 dest_addr = packed_data; 00406 packed_data = read_another_ifr_word(); 00407 dest_data = packed_data; 00408 /* Place SW trim in array for driver SW to use */ 00409 store_sw_trim(sw_trim_tbl, num_entries, dest_addr, dest_data); 00410 } 00411 else 00412 { 00413 if (IS_VALID_REG_ADDR(packed_data)) /* Valid register write address */ 00414 { 00415 dest_addr = packed_data; 00416 packed_data = read_another_ifr_word(); 00417 dest_data = packed_data; 00418 *(uint32_t *)(dest_addr) = dest_data; 00419 } 00420 else 00421 { /* Invalid address case */ 00422 00423 } 00424 } 00425 00426 packed_data=read_another_ifr_word(); 00427 } 00428 } 00429 else 00430 { 00431 /* Valid header is not present, use blind IFR trim table */ 00432 ifr_ptr = (void *)BLOCK_1_IFR; 00433 packed_data = *ifr_ptr; 00434 XCVR_MISC->OVERWRITE_VER = (packed_data & IFR_VERSION_MASK); 00435 store_sw_trim(sw_trim_tbl, num_entries, 0xABCD, (packed_data & IFR_VERSION_MASK)); /* Place IFR version # in SW trim array */ 00436 ifr_ptr++; 00437 packed_data= *ifr_ptr; 00438 00439 while (packed_data != IFR_EOF_SYMBOL) 00440 { 00441 if (IS_A_SW_ID(packed_data)) 00442 { 00443 /* SW Trim case (non_reg writes) */ 00444 dest_addr = packed_data; 00445 ifr_ptr++; 00446 packed_data = *(ifr_ptr); 00447 dest_data = packed_data; 00448 /* Place SW trim in array for driver SW to use */ 00449 store_sw_trim(sw_trim_tbl, num_entries, dest_addr, dest_data); 00450 } 00451 else 00452 { 00453 dest_addr = packed_data; 00454 ifr_ptr++; 00455 packed_data = *ifr_ptr; 00456 dest_data = packed_data; 00457 00458 /* Valid register write address */ 00459 if (IS_VALID_REG_ADDR(dest_addr)) 00460 { 00461 *(uint32_t *)(dest_addr) = dest_data; 00462 } 00463 else 00464 { 00465 /* Invalid address case */ 00466 } 00467 } 00468 00469 ifr_ptr++; 00470 packed_data= *ifr_ptr; 00471 } 00472 } 00473 } 00474 00475 #if RADIO_IS_GEN_3P0 00476 00477 #else 00478 uint32_t handle_ifr_die_id(void) 00479 { 00480 uint32_t id_x, id_y; 00481 uint32_t id; 00482 00483 id = read_resource_ifr(0x90); 00484 id_x = id & 0x00FF0000; 00485 id_y = id & 0x000000FF; 00486 00487 return (id_x | id_y); 00488 } 00489 00490 uint32_t handle_ifr_die_kw_type(void) 00491 { 00492 uint32_t zb, ble; 00493 00494 zb = read_resource_ifr(0x80) & 0x8000; 00495 ble= read_resource_ifr(0x88) & 0x100000; 00496 00497 return (zb | ble); 00498 } 00499 00500 #endif /* RADIO_IS_GEN_3P0 */ 00501 00502 /*! ********************************************************************************* 00503 * \brief Dumps block 1 IFR data to an array. 00504 * 00505 * \param dump_tbl pointer to the table to hold the dumped IFR values 00506 * \param num_entries the number of entries to dump 00507 * 00508 * \remarks 00509 * Starts at the first address in IFR and dumps sequential entries. 00510 * 00511 ***********************************************************************************/ 00512 void dump_ifr(uint32_t * dump_tbl, uint8_t num_entries) 00513 { 00514 #if RADIO_IS_GEN_3P0 00515 uint32_t ifr_address = 0x20000; 00516 #else 00517 uint32_t ifr_address = 0x20000; 00518 #endif /* RADIO_IS_GEN_3P0 */ 00519 uint32_t * dump_ptr = dump_tbl; 00520 uint8_t i; 00521 00522 *dump_ptr = read_first_ifr_word(ifr_address); 00523 dump_ptr++; 00524 00525 for (i = 0; i < num_entries - 1; i++) 00526 { 00527 *dump_ptr = read_another_ifr_word(); 00528 dump_ptr++; 00529 } 00530 } 00531
Generated on Wed Jul 13 2022 07:46:57 by
1.7.2