1 /*!
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * All rights reserved.
4 *
5 * \file ifr_mkw40z4_radio.c
6 * MKW40Z4 Radio IFR pack/unpack function.
7 *
8 * Redistribution and use in source and binary forms, with or without modification,
9 * are permitted provided that the following conditions are met:
10 *
11 * o Redistributions of source code must retain the above copyright notice, this list
12 * of conditions and the following disclaimer.
13 *
14 * o Redistributions in binary form must reproduce the above copyright notice, this
15 * list of conditions and the following disclaimer in the documentation and/or
16 * other materials provided with the distribution.
17 *
18 * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
19 * contributors may be used to endorse or promote products derived from this
20 * software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
26 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
29 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /*! *********************************************************************************
35 *************************************************************************************
36 * Include
37 *************************************************************************************
38 ********************************************************************************** */
39 #include "EmbeddedTypes.h"
40 #include "ifr_mkw40z4_radio.h"
41 #include "MKW40Z4.h"
42 #include "KW4xXcvrDrv.h"
43 #include "fsl_device_registers.h"
44 #include "fsl_os_abstraction.h"
45
46 /*! *********************************************************************************
47 *************************************************************************************
48 * Private macros
49 *************************************************************************************
50 ********************************************************************************** */
51 #define IFR_RAM (0)
52
53 #define mem32(x) (*(volatile uint32_t *)(x))
54
55 /*! *********************************************************************************
56 *************************************************************************************
57 * Public memory declarations
58 *************************************************************************************
59 ********************************************************************************** */
60 const uint32_t BLOCK_1_IFR[]=
61 {
62 0xABCDFFFE, /* Version #FFFE indicates default trim values */
63 0x4005C47C, /* IQMC_DC_GAIN_ADJ id */
64 0x00000400, /* IQMC_DC_GAIN_ADJ default value */
65 0x4005C050, /* XCVR_IQMC_CAL id */
66 0x00000400, /* IQMC_PHASE_ADJ=0x000 and IQMC_GAIN_ADJ=0x400 (default value) */
67 0x4005C43C, /* XCVR_BGAP_CTRL id */
68 0x00000087, /* XCVR_BGAP_CTRL=0x08 */
69 0x00000002, /* ZB_FILT_TRIM id */
70 0x00440000, /* ZB_FILT_TRIM = BBF_CAP_TUNE<3:0>=0x3, BBF_RES_TUNE2<3:0>=0x3, TZA_CAP_TUNE<3:0>=0x3 */
71 0x00000003, /* BLE_FILT_TRIM id */
72 0x00640004, /* BLE_FILT_TRIM = BBF_CAP_TUNE<3:0>=0x3, BBF_RES_TUNE2<3:0>=0x6, TZA_CAP_TUNE<3:0>=0x3 */
73 0x4005C024, /* BBF_DCOC_STEP */
74 0x00000147,
75 0x4005C028, /* BBF_DCOC_STEP_RCP */
76 0x00000322,
77 0x4005C110, /* TZA_DCOC_STEP & STEP_RCP */
78 0x005C0B21,
79 0x4005C114,
80 0x008D0743,
81 0x4005C118,
82 0x00D304DA,
83 0x4005C11C,
84 0x0136034E,
85 0x4005C120,
86 0x01C30245,
87 0x4005C124,
88 0x02890194,
89 0x4005C128,
90 0x03A3011A,
91 0x4005C12C,
92 0x053000C5,
93 0x4005C130,
94 0x0761008B,
95 0x4005C134,
96 0x0A790062,
97 0x4005C138,
98 0x0ED70045,
99 /* No TRIM_STATUS in SW fallback array. */
100 0xFEED0E0F /* End of File */
101 };
102
103 /*! *********************************************************************************
104 *************************************************************************************
105 * Private prototypes
106 *************************************************************************************
107 ********************************************************************************** */
108 void store_sw_trim(IFR_SW_TRIM_TBL_ENTRY_T * sw_trim_tbl, uint16_t num_entries, uint32_t addr, uint32_t data);
109
110 /*! *********************************************************************************
111 *************************************************************************************
112 * Public functions
113 *************************************************************************************
114 ********************************************************************************** */
115
116 /*! *********************************************************************************
117 * \brief Read Resource IFR
118 *
119 * Read command for reading from IFR
120 *
121 * \param[in] read_addr flash address
122 *
123 * \return Packed data containing radio trims only.
124 *
125 ********************************************************************************** */
read_resource_ifr(uint32_t read_addr)126 uint32_t read_resource_ifr(uint32_t read_addr)
127 {
128 uint32_t packed_data;
129 uint8_t flash_addr23_16,flash_addr15_8,flash_addr7_0;
130 uint8_t read_data31_24,read_data23_16,read_data15_8,read_data7_0;
131
132 flash_addr23_16 = (uint8_t)((read_addr & 0xFF0000)>>16);
133 flash_addr15_8 = (uint8_t)((read_addr & 0x00FF00)>>8);
134 flash_addr7_0 = (uint8_t)(read_addr & 0xFF);
135
136 #if SILICON
137 while((FTFA_FSTAT_CCIF_MASK & FTFA->FSTAT)==0); /* Wait till CCIF=1 */
138 #endif /* SILICON */
139
140 if ((FTFA->FSTAT & FTFA_FSTAT_ACCERR_MASK)== FTFA_FSTAT_ACCERR_MASK )
141 {
142 FTFA->FSTAT = (1<<FTFA_FSTAT_ACCERR_SHIFT); /* Write 1 to ACCEER to clear errors */
143 }
144
145 FTFA_WR_FCCOB0(FTFA,RDRSRC);
146 FTFA_WR_FCCOB1(FTFA,flash_addr23_16);
147 FTFA_WR_FCCOB2(FTFA,flash_addr15_8);
148 FTFA_WR_FCCOB3(FTFA,flash_addr7_0);
149 FTFA_WR_FCCOB8(FTFA,0);
150
151 /* Disable Interrupts */
152 OSA_InterruptDisable();
153
154 FTFA->FSTAT = FTFA_FSTAT_CCIF_MASK;
155 while((FTFA_FSTAT_CCIF_MASK & FTFA->FSTAT)==0); /* Wait till CCIF=1 */
156
157 /* Enable Interrupts */
158 OSA_InterruptEnable();
159
160 /* Start reading */
161 read_data31_24 = FTFA->FCCOB4;
162 read_data23_16 = FTFA->FCCOB5;
163 read_data15_8 = FTFA->FCCOB6;
164 read_data7_0 = FTFA->FCCOB7;
165
166 packed_data = (read_data31_24<<24)|(read_data23_16<<16)|(read_data15_8<<8)|(read_data7_0<<0);
167
168 return packed_data;
169 }
170
read_resource(uint16_t resource_id)171 uint32_t read_resource(uint16_t resource_id)
172 {
173 uint32_t ifr_addr;
174
175 /* Return the test arrays of packed bits */
176 switch (resource_id)
177 {
178 case 0x84:
179 #if IFR_RAM
180 return 0x4370; /* TZA_CAP_TUNE=0b0100; BBF_CAP_TUNE=4�b0011; BBF_RES_TUNE2=4�b0111 */
181 #else
182 ifr_addr = read_resource_ifr(0x84);
183 return ifr_addr;
184 #endif
185 break;
186 case 0x98:
187 #if IFR_RAM
188 return 0x40000000; /* IQMC_GAIN)ADJ=0b10000000000 */
189 #else
190 ifr_addr = read_resource_ifr(0x98);
191 return ifr_addr;
192 #endif
193 break;
194 case 0x9C:
195 #if IFR_RAM
196 return 0x37000000; /* BGAP_V Trim = 0b0011 & BGAP_I Trim=0b0111 */
197 #else
198 ifr_addr = read_resource_ifr(0x9C);
199 return ifr_addr;
200 #endif
201 case 0x90:
202 ifr_addr = read_resource_ifr(0x90);
203 return ifr_addr;
204
205 case 0x80:
206 ifr_addr = read_resource_ifr(0x80);
207 return ifr_addr;
208
209 case 0x88:
210 ifr_addr = read_resource_ifr(0x88);
211 return ifr_addr;
212
213 break;
214 default:
215 return 0x12345678;
216 break;
217 }
218 }
219
220 /*! *********************************************************************************
221 * \brief Store a SW trim value in the table passed in from calling function.
222 *
223 * \param[in] sw_trim_tbl pointer to the software trim table to hold SW trim values
224 * \param[in] num_entries the number of entries in the SW trim table
225 * \param[in] addr the software trim ID
226 * \param[in] data the value of the software trim
227 *
228 * \return None.
229 *
230 ********************************************************************************** */
store_sw_trim(IFR_SW_TRIM_TBL_ENTRY_T * sw_trim_tbl,uint16_t num_entries,uint32_t addr,uint32_t data)231 void store_sw_trim(IFR_SW_TRIM_TBL_ENTRY_T * sw_trim_tbl, uint16_t num_entries, uint32_t addr, uint32_t data)
232 {
233 uint16_t i;
234 if (sw_trim_tbl != NULL)
235 {
236 for (i=0;i<num_entries;i++)
237 {
238 if (addr == sw_trim_tbl[i].trim_id)
239 {
240 sw_trim_tbl[i].trim_value = data;
241 sw_trim_tbl[i].valid = TRUE;
242 break;
243 }
244 }
245 }
246 }
247
248 /*! *********************************************************************************
249 * \brief Process block 1 IFR data.
250 *
251 * \param[in] sw_trim_tbl pointer to the software trim table to hold SW trim values
252 * \param[in] num_entries the number of entries in the SW trim table
253 * \param[in] addr the software trim ID
254 * \param[in] data the value of the software trim
255 *
256 * \return None.
257 *
258 * \remarks Uses a IFR v2 formatted default array if the IFR is blank or corrupted.
259 * Stores SW trim values to an array passed into this function.
260 *
261 ********************************************************************************** */
handle_ifr(IFR_SW_TRIM_TBL_ENTRY_T * sw_trim_tbl,uint16_t num_entries)262 void handle_ifr(IFR_SW_TRIM_TBL_ENTRY_T * sw_trim_tbl, uint16_t num_entries)
263 {
264 uint32_t read_addr = 0x20000;
265 uint32_t dest_addr, dest_data, packed_data;
266 uint32_t *ifr_ptr;
267
268 /* Read first entry in IFR table */
269 packed_data=read_resource_ifr(read_addr);
270 read_addr+=4;
271 if ((packed_data&~IFR_VERSION_MASK)==IFR_VERSION_HDR)
272 {
273 /* Valid header was found, process real IFR data */
274 XCVR_OVERWRITE_VER = (uint32_t)(packed_data & IFR_VERSION_MASK);
275 store_sw_trim(sw_trim_tbl, num_entries, 0xABCD, (packed_data & IFR_VERSION_MASK)); /* Place IFR version # in SW trim array */
276 packed_data = read_resource_ifr(read_addr);
277 while (packed_data !=IFR_EOF_SYMBOL)
278 {
279 if(IS_A_SW_ID(packed_data)) /* SW Trim case (non_reg writes) */
280 {
281 dest_addr = packed_data;
282 read_addr+=4;
283 packed_data = read_resource_ifr(read_addr);
284 dest_data = packed_data;
285 /* Place SW trim in array for driver SW to use */
286 store_sw_trim(sw_trim_tbl, num_entries, dest_addr, dest_data);
287 }
288 else
289 {
290 if (IS_VALID_REG_ADDR(packed_data)) /* Valid register write address */
291 {
292 dest_addr = packed_data;
293 read_addr+=4;
294 packed_data = read_resource_ifr(read_addr);
295 dest_data = packed_data;
296 mem32(dest_addr) = dest_data;
297 }
298 else
299 {
300 /* Invalid address case */
301 }
302 }
303 read_addr+=4;
304 packed_data=read_resource_ifr(read_addr);
305 }
306 }
307 else
308 {
309 /* Valid header is not present, use blind IFR trim table */
310 ifr_ptr = (uint32_t*) BLOCK_1_IFR;
311 packed_data = *ifr_ptr;
312 XCVR_OVERWRITE_VER = (uint32_t)(packed_data & IFR_VERSION_MASK);
313 store_sw_trim(sw_trim_tbl, num_entries, 0xABCD, (packed_data & IFR_VERSION_MASK)); /* Place IFR version # in SW trim array */
314 ifr_ptr++;
315 packed_data= *ifr_ptr;
316 while(packed_data!=IFR_EOF_SYMBOL)
317 {
318 if(IS_A_SW_ID(packed_data)) /* SW Trim case (non_reg writes) */
319 {
320 dest_addr = packed_data;
321 ifr_ptr++;
322 packed_data = *(ifr_ptr);
323 dest_data = packed_data;
324 /* Place SW trim in array for driver SW to use */
325 store_sw_trim(sw_trim_tbl, num_entries, dest_addr, dest_data);
326 }
327 else
328 {
329 dest_addr = packed_data;
330 ifr_ptr++;
331 packed_data = *ifr_ptr;
332 dest_data = packed_data;
333 if (IS_VALID_REG_ADDR(dest_addr)) /* Valid register write address */
334 {
335 mem32(dest_addr)=dest_data;
336 }
337 else
338 {
339 /* Invalid address case */
340 }
341 }
342 ifr_ptr++;
343 packed_data= *ifr_ptr;
344 }
345 }
346 }
347
handle_ifr_die_id(void)348 uint32_t handle_ifr_die_id(void)
349 {
350 uint32_t id_x,id_y;
351 uint32_t id;
352
353 id = read_resource_ifr(0x90);
354 id_x = id&0x00FF0000;
355 id_y = id&0x000000FF;
356 return (id_x|id_y);
357 }
358
handle_ifr_die_kw_type(void)359 uint32_t handle_ifr_die_kw_type(void)
360 {
361 uint32_t zb,ble;
362
363 zb = read_resource_ifr(0x80)&0x8000;
364 ble= read_resource_ifr(0x88)&0x100000;
365
366 return (zb|ble);
367 }
368
369 /*! *********************************************************************************
370 * \brief Dumps block 1 IFR data to an array.
371 *
372 * \param[in] dump_tbl pointer to the table to hold the dumped IFR values
373 * \param[in] num_entries the number of entries to dump
374 *
375 * \return None.
376 *
377 * \remarks Starts at the first address in IFR and dumps sequential entries.
378 *
379 ********************************************************************************** */
dump_ifr(uint32_t * dump_tbl,uint8_t num_entries)380 void dump_ifr(uint32_t * dump_tbl, uint8_t num_entries)
381 {
382 uint32_t ifr_address = 0x20000;
383 uint32_t * dump_ptr = dump_tbl;
384 uint8_t i;
385
386 for (i=0;i<num_entries;i++)
387 {
388 *dump_ptr = read_resource_ifr(ifr_address);
389 dump_ptr++;
390 ifr_address += 4;
391 }
392 }
393