Igor Stepura / kw41z-rf-driver Featured
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ifr_radio.c Source File

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