1 /*
2 * Copyright 2019 NXP
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include "tfa2_dev.h" /* for regwrite */
9 #include "tfa2_container.h"
10
11 static int tfa2_cnt_write_item(struct tfa2_device *tfa, nxpTfaDescPtr_t *dsc);
12 /* write all descripters from the dsc list which type is in the items list */
13 static int tfa2_cnt_write_items_list(struct tfa2_device *tfa,
14 nxpTfaDescPtr_t *dsc_list,
15 int length,
16 nxpTfaDescriptorType_t *items_list);
17
18 /* items that require clock to run */
19 static nxpTfaDescriptorType_t clockdep_items_list[] = {dscFile, dscCmd, dscCfMem, dscProfile, dsc_listend};
20
21 /*
22 dsp mem direct write
23 */
tfa2_cnt_write_dspmem(struct tfa2_device * tfa,nxpTfaDspMem_t * cfmem)24 static int tfa2_cnt_write_dspmem(struct tfa2_device *tfa, nxpTfaDspMem_t *cfmem)
25 {
26 int rc = 0, i;
27 uint16_t address = cfmem->address;
28
29 for (i = 0; i < cfmem->size; i++)
30 {
31 dev_dbg(&tfa->i2c->dev, "dsp mem (%d): 0x%02x=0x%04x\n", cfmem->type, address, cfmem->words[i]);
32 rc = tfa2_i2c_write_cf_mem32(tfa->i2c, address++, (int32_t *)cfmem + offsetof(nxpTfaDspMem_t, words) + i, 1,
33 (enum tfa2_cf_mem)(cfmem->type));
34 if (rc < 0)
35 return rc;
36 }
37
38 return rc;
39 }
40
41 /*
42 * check the container file
43 */
tfa2_load_cnt(void * cnt,int length)44 int tfa2_load_cnt(void *cnt, int length)
45 {
46 nxpTfaContainer_t *cntbuf = (nxpTfaContainer_t *)cnt;
47
48 if (length > TFA_MAX_CNT_LENGTH)
49 {
50 pr_err("incorrect length\n");
51 return -EINVAL;
52 }
53
54 if (HDR(cntbuf->id[0], cntbuf->id[1]) == 0)
55 {
56 pr_err("header is 0\n");
57 return -EINVAL;
58 }
59
60 if ((HDR(cntbuf->id[0], cntbuf->id[1])) != paramsHdr)
61 {
62 pr_err("wrong header type: 0x%02x 0x%02x\n", cntbuf->id[0], cntbuf->id[1]);
63 return -EINVAL;
64 }
65
66 if (cntbuf->size == 0)
67 {
68 pr_err("data size is 0\n");
69 return -EINVAL;
70 }
71
72 /* check CRC */
73 if (tfa2_cnt_crc_check_container(cntbuf))
74 {
75 pr_err("CRC error\n");
76 return -EINVAL;
77 }
78
79 /* check sub version level */
80 if ((cntbuf->subversion[1] != NXPTFA_PM_SUBVERSION) && (cntbuf->subversion[0] != '0'))
81 {
82 pr_err("container sub-version not supported: %c%c\n", cntbuf->subversion[0], cntbuf->subversion[1]);
83 return -EINVAL;
84 }
85
86 return 0;
87 }
88
89 /*
90 * check CRC for container
91 * CRC is calculated over the bytes following the CRC field
92 *
93 * return non zero value on error
94 */
tfa2_cnt_crc_check_container(nxpTfaContainer_t * cont)95 int tfa2_cnt_crc_check_container(nxpTfaContainer_t *cont)
96 {
97 uint8_t *base;
98 size_t size;
99 uint32_t crc;
100
101 base = (uint8_t *)cont + offsetof(nxpTfaContainer_t, CRC) + 4; // ptr to bytes following the CRC field
102 size = (size_t)(cont->size - (base - (uint8_t *)cont)); // nr of bytes following the CRC field
103 crc = ~crc32_le(~0u, base, size);
104
105 return crc != cont->CRC;
106 }
107
tfa2_cnt_check_revid(struct tfa2_device * tfa)108 int tfa2_cnt_check_revid(struct tfa2_device *tfa)
109 {
110 nxpTfaPatch_t *patchfile;
111 nxpTfaDescPtr_t *patchdsc;
112
113 if (!tfa->cnt)
114 return -EINVAL;
115
116 patchdsc = tfa2_cnt_get_dsc(tfa->cnt, dscPatch, tfa->dev_idx);
117 if (!patchdsc) /* no patch for this device */
118 return -ENXIO;
119
120 patchdsc += 2; /* first the filename dsc and filesize, so skip them */
121 patchfile = (nxpTfaPatch_t *)patchdsc;
122
123 return tfa2_check_patch((const uint8_t *)patchfile, patchfile->hdr.size, tfa->rev);
124 }
125
126 /*
127 * return 1 if the item is in the list
128 * list must end with dsc_listend
129 */
hitlist(nxpTfaDescriptorType_t * items,nxpTfaDescriptorType_t item)130 static int hitlist(nxpTfaDescriptorType_t *items, nxpTfaDescriptorType_t item)
131 {
132 nxpTfaDescriptorType_t *list_item = items;
133
134 while (*list_item != dsc_listend && *list_item < dsc_last)
135 {
136 if (*list_item++ == item)
137 return 1;
138 }
139 return 0;
140 }
141
142 /*****************************************************************************/
143 /* cnt getinfo */
144 // int tfa2_cnt_get_init_multi_msg(nxpTfaContainer_t *cnt,
145 // int dev_idx, int profile, char *mmsg, int *length) {
146 //
147 // return 0;
148 //}
149
tfa2_cnt_get_string(nxpTfaContainer_t * cnt,nxpTfaDescPtr_t * dsc)150 char *tfa2_cnt_get_string(nxpTfaContainer_t *cnt, nxpTfaDescPtr_t *dsc)
151 {
152 if (dsc->type != dscString)
153 return NULL;
154
155 return dsc->offset + (char *)cnt;
156 }
157
tfa2_cnt_get_cmd(nxpTfaContainer_t * cnt,int dev,int profidx,int offset,uint8_t ** array,int * length)158 int tfa2_cnt_get_cmd(nxpTfaContainer_t *cnt, int dev, int profidx, int offset, uint8_t **array, int *length)
159 {
160 int i;
161 char *pcnt = (char *)cnt;
162 nxpTfaProfileList_t *prof = tfa2_cnt_get_dev_prof_list(cnt, dev, profidx);
163 nxpTfaDescPtr_t *dsc;
164
165 if (!prof)
166 return -EINVAL;
167
168 /* process the list until the end of the profile */
169 for (i = offset; i < prof->length - 1; i++)
170 {
171 dsc = &prof->list[i];
172 if (dsc->type == dscCmd)
173 {
174 *length = get_unaligned_le16((uint16_t *)(dsc->offset + pcnt));
175 *array = (uint8_t *)(dsc->offset + 2 + pcnt);
176 return i;
177 }
178 }
179
180 return -EINVAL; /* not found */
181 }
182
183 /*
184 * Get the name of the device at a certain index in the container file
185 * return device name
186 */
tfa2_cnt_device_name(nxpTfaContainer_t * cnt,int dev_idx)187 char *tfa2_cnt_device_name(nxpTfaContainer_t *cnt, int dev_idx)
188 {
189 nxpTfaDeviceList_t *dev;
190
191 dev = tfa2_cnt_device(cnt, dev_idx);
192 if (dev == NULL)
193 return NULL;
194
195 return tfa2_cnt_get_string(cnt, &dev->name);
196 }
197 /*
198 * Get the name of the profile at certain index for a device in the container file
199 * return profile name
200 */
tfa2_cnt_profile_name(nxpTfaContainer_t * cnt,int dev_idx,int prof_idx)201 char *tfa2_cnt_profile_name(nxpTfaContainer_t *cnt, int dev_idx, int prof_idx)
202 {
203 nxpTfaProfileList_t *prof = NULL;
204
205 /* the Nth profiles for this device */
206 prof = tfa2_cnt_get_dev_prof_list(cnt, dev_idx, prof_idx);
207
208 /* If the index is out of bound */
209 if (prof == NULL)
210 return NULL;
211
212 return tfa2_cnt_get_string(cnt, &prof->name);
213 }
214 /*
215 * Get the application name from the container file application field
216 * note that the input stringbuffer should be sizeof(application field)+1
217 *
218 */
tfa2_cnt_get_app_name(struct tfa2_device * tfa,char * name)219 int tfa2_cnt_get_app_name(struct tfa2_device *tfa, char *name)
220 {
221 unsigned int i;
222 int len = 0;
223
224 for (i = 0; i < sizeof(tfa->cnt->application); i++)
225 {
226 if (isalnum(tfa->cnt->application[i])) /* copy char if valid */
227 name[len++] = tfa->cnt->application[i];
228 if (tfa->cnt->application[i] == '\0')
229 break;
230 }
231 name[len++] = '\0';
232
233 return len;
234 }
235
236 /*
237 * Dump the contents of the file header
238 */
tfa2_cnt_show_header(nxpTfaHeader_t * hdr)239 void tfa2_cnt_show_header(nxpTfaHeader_t *hdr)
240 {
241 char _id[2];
242
243 pr_debug("File header\n");
244
245 _id[1] = hdr->id >> 8;
246 _id[0] = hdr->id & 0xff;
247 pr_debug("\tid:%.2s version:%.2s subversion:%.2s\n", _id, hdr->version, hdr->subversion);
248 pr_debug("\tsize:%d CRC:0x%08x \n", hdr->size, hdr->CRC);
249 pr_debug("\tcustomer:%.8s application:%.8s type:%.8s\n", hdr->customer, hdr->application,
250 hdr->type); /* TODO fix leading zeroes */
251 }
252
253 /*****************************************************************************/
254 /* cnt infra lookups */
255
256 /*
257 * get the slave for the device if it exists
258 */
tfa2_cnt_get_slave(nxpTfaContainer_t * cnt,int dev_idx)259 int tfa2_cnt_get_slave(nxpTfaContainer_t *cnt, int dev_idx)
260 {
261 nxpTfaDeviceList_t *dev;
262
263 /* Make sure the cnt file is loaded */
264 if (!cnt)
265 return -EINVAL;
266
267 dev = tfa2_cnt_device(cnt, dev_idx);
268 if (!dev)
269 return -EINVAL;
270
271 return dev->dev;
272 }
273
274 /*
275 * return the device list pointer
276 */
tfa2_cnt_device(nxpTfaContainer_t * cnt,int dev_idx)277 nxpTfaDeviceList_t *tfa2_cnt_device(nxpTfaContainer_t *cnt, int dev_idx)
278 {
279 return tfa2_cnt_get_dev_list(cnt, dev_idx);
280 }
281
282 /**
283 * get the 1st of this dsc type from this devicelist
284 */
tfa2_cnt_get_dsc(nxpTfaContainer_t * cnt,nxpTfaDescriptorType_t type,int dev_idx)285 nxpTfaDescPtr_t *tfa2_cnt_get_dsc(nxpTfaContainer_t *cnt, nxpTfaDescriptorType_t type, int dev_idx)
286 {
287 nxpTfaDeviceList_t *dev = tfa2_cnt_get_dev_list(cnt, dev_idx);
288 nxpTfaDescPtr_t *_this;
289 int i;
290
291 if (!dev)
292 {
293 return NULL;
294 }
295 /* process the list until a the type is encountered */
296 for (i = 0; i < dev->length; i++)
297 {
298 if (dev->list[i].type == (uint32_t)type)
299 {
300 _this = (nxpTfaDescPtr_t *)(dev->list[i].offset + (uint8_t *)cnt);
301 return _this;
302 }
303 }
304
305 return NULL;
306 }
307
308 /*
309 * return device list dsc from index
310 */
tfa2_cnt_get_dev_list(nxpTfaContainer_t * cont,int dev_idx)311 nxpTfaDeviceList_t *tfa2_cnt_get_dev_list(nxpTfaContainer_t *cont, int dev_idx)
312 {
313 uint8_t *base = (uint8_t *)cont;
314 nxpTfaDeviceList_t *this_dev;
315
316 if (cont == NULL)
317 return NULL;
318
319 if ((dev_idx < 0) || (dev_idx >= cont->ndev))
320 return NULL;
321
322 if (cont->index[dev_idx].type != dscDevice)
323 return NULL;
324
325 base += cont->index[dev_idx].offset;
326 this_dev = (nxpTfaDeviceList_t *)base;
327
328 if (this_dev->name.type != dscString)
329 {
330 pr_err("fatal corruption: device[%d] has no name\n", dev_idx);
331 return NULL;
332 }
333
334 return this_dev;
335 }
336
337 /*
338 * get the Nth profile for the Nth device
339 */
tfa2_cnt_get_dev_prof_list(nxpTfaContainer_t * cont,int devIdx,int profIdx)340 nxpTfaProfileList_t *tfa2_cnt_get_dev_prof_list(nxpTfaContainer_t *cont, int devIdx, int profIdx)
341 {
342 nxpTfaDeviceList_t *dev;
343 int idx, hit;
344 uint8_t *base = (uint8_t *)cont;
345
346 dev = tfa2_cnt_get_dev_list(cont, devIdx);
347 if (dev)
348 {
349 for (idx = 0, hit = 0; idx < dev->length; idx++)
350 {
351 if (dev->list[idx].type == dscProfile)
352 {
353 if (profIdx == hit++)
354 return (nxpTfaProfileList_t *)(dev->list[idx].offset + base);
355 }
356 }
357 }
358
359 return NULL;
360 }
361
362 /*
363 * get the number of profiles for the Nth device of this tfa
364 */
tfa2_dev_get_dev_nprof(struct tfa2_device * tfa)365 int tfa2_dev_get_dev_nprof(struct tfa2_device *tfa) // TODO call tfa2_cnt_get_dev_nprof
366 {
367 nxpTfaDeviceList_t *dev;
368 int idx, nprof = 0;
369
370 if (tfa->cnt == NULL)
371 return 0;
372
373 if ((tfa->dev_idx < 0) || (tfa->dev_idx >= tfa->cnt->ndev))
374 return 0;
375
376 dev = tfa2_cnt_get_dev_list(tfa->cnt, tfa->dev_idx);
377 if (dev)
378 {
379 for (idx = 0; idx < dev->length; idx++)
380 {
381 if (dev->list[idx].type == dscProfile)
382 {
383 nprof++;
384 }
385 }
386 }
387
388 return nprof;
389 }
390
391 /*
392 * get the number of profiles for the Nth device
393 */
tfa2_cnt_get_dev_nprof(nxpTfaContainer_t * cnt,int dev_idx)394 int tfa2_cnt_get_dev_nprof(nxpTfaContainer_t *cnt, int dev_idx)
395 {
396 nxpTfaDeviceList_t *dev;
397 int idx, nprof = 0;
398
399 if (cnt == NULL)
400 return 0;
401
402 if ((dev_idx < 0) || (dev_idx >= cnt->ndev))
403 return 0;
404
405 dev = tfa2_cnt_get_dev_list(cnt, dev_idx);
406 if (dev)
407 {
408 for (idx = 0; idx < dev->length; idx++)
409 {
410 if (dev->list[idx].type == dscProfile)
411 {
412 nprof++;
413 }
414 }
415 }
416
417 return nprof;
418 }
419
420 /*
421 * get the n-th profilename match for this device
422 */
tfa2_cnt_grep_nth_profile_name(nxpTfaContainer_t * cnt,int dev_idx,int n,const char * string)423 int tfa2_cnt_grep_nth_profile_name(nxpTfaContainer_t *cnt, int dev_idx, int n, const char *string)
424 {
425 int prof, count = 0;
426
427 /* compare string to the profile name in the list of profiles */
428 for (prof = 0; prof < cnt->nprof; prof++)
429 {
430 char *profile = tfa2_cnt_profile_name(cnt, dev_idx, prof);
431 if (profile && strstr(profile, string))
432 {
433 if (n == count++)
434 return prof; // tfa2_cnt_get_dev_prof_list(cnt, dev_idx, prof);
435 }
436 }
437
438 return -EINVAL;
439 }
440 /*
441 * get the 1st profilename match for this device
442 */
tfa2_cnt_grep_profile_name(nxpTfaContainer_t * cnt,int dev_idx,const char * string)443 int tfa2_cnt_grep_profile_name(nxpTfaContainer_t *cnt, int dev_idx, const char *string)
444 {
445 return tfa2_cnt_grep_nth_profile_name(cnt, dev_idx, 0, string);
446 }
447
448 /*
449 * get the index of the 1st item in the list that depends on clock
450 * get the index of the default section marker
451 * if not found return -1
452 */
tfa2_cnt_get_clockdep_idx(struct tfa2_device * tfa,nxpTfaDescPtr_t * dsc_list,int length,int * clockdep_idx,int * default_section_idx)453 int tfa2_cnt_get_clockdep_idx(
454 struct tfa2_device *tfa, nxpTfaDescPtr_t *dsc_list, int length, int *clockdep_idx, int *default_section_idx)
455 {
456 int i;
457
458 if (clockdep_idx == NULL || default_section_idx == NULL || tfa == NULL || dsc_list == NULL)
459 return -EINVAL;
460
461 *clockdep_idx = -1;
462 *default_section_idx = -1;
463
464 /* find the matches in the list */
465 for (i = 0; i < length; i++)
466 {
467 if (*clockdep_idx == -1 && hitlist(clockdep_items_list, (nxpTfaDescriptorType_t)(dsc_list[i].type)))
468 *clockdep_idx = i;
469 if (dsc_list[i].type == dscDefault)
470 {
471 *default_section_idx = i;
472 break; /* clock dep items cannot be in the default section */
473 }
474 }
475
476 return 0;
477 }
478 ///*
479 // * return the index of the default section marker of this profile
480 // * if not found return -1
481 // */
482 // int tfa2_cnt_get_default_idx(struct tfa2_device *tfa, nxpTfaProfileList_t *prof) {
483 // int i;
484 //
485 // /* find a match in the list */
486 // for(i=0;i < prof->length ;i++) {
487 // if ( prof->list[i].type == dscDefault )
488 // return i;
489 // }
490 //
491 // return -1 ;
492 //}
493
494 /*
495 * write the register based on the input address, value and mask
496 * only the part that is masked will be updated
497 */
tfa2_dev_cnt_write_register(struct tfa2_device * tfa,nxpTfaRegpatch_t * reg)498 static int tfa2_dev_cnt_write_register(struct tfa2_device *tfa, nxpTfaRegpatch_t *reg)
499 {
500 int rc;
501 uint16_t value, newvalue;
502
503 if (tfa->verbose)
504 dev_dbg(&tfa->i2c->dev, "register: 0x%02x=0x%04x (msk=0x%04x)\n", reg->address, reg->value, reg->mask);
505
506 rc = tfa2_i2c_read_reg(tfa->i2c, reg->address); /* will report error */
507 if (rc < 0)
508 return rc;
509 value = (uint16_t)rc;
510
511 value &= ~reg->mask;
512 newvalue = reg->value & reg->mask;
513
514 value |= newvalue;
515
516 rc = tfa2_i2c_write_reg(tfa->i2c, reg->address, value);
517
518 return rc;
519 }
520
521 /* write reg and bitfield items in the devicelist
522 * until a clock dependent item is encountered
523 * this is called during called start init
524 */
tfa2_cnt_write_regs_dev(struct tfa2_device * tfa)525 int tfa2_cnt_write_regs_dev(struct tfa2_device *tfa)
526 {
527 int i, rc = 0;
528 nxpTfaDeviceList_t *dev = tfa2_cnt_device(tfa->cnt, tfa->dev_idx);
529 /* write these items until break */
530 nxpTfaDescriptorType_t items_list[] = {dscBitfield, dscRegister, dsc_listend};
531
532 if (!dev)
533 {
534 return -EINVAL;
535 }
536
537 /* process the list until a clock dependent is encountered */
538 for (i = 0; i < dev->length; i++)
539 {
540 if (hitlist(clockdep_items_list, (nxpTfaDescriptorType_t)(dev->list[i].type)))
541 break;
542 if (hitlist(items_list, (nxpTfaDescriptorType_t)(dev->list[i].type)))
543 {
544 rc = tfa2_cnt_write_item(tfa, &dev->list[i]);
545 if (rc < 0)
546 break;
547 }
548 }
549
550 return rc;
551 }
552
553 /* write reg and bitfield items in the profilelist the target */
tfa2_cnt_write_regs_profile(struct tfa2_device * tfa,int prof_idx)554 int tfa2_cnt_write_regs_profile(struct tfa2_device *tfa, int prof_idx)
555 {
556 int i, rc = 0;
557 char *profile = NULL;
558 nxpTfaProfileList_t *prof = tfa2_cnt_get_dev_prof_list(tfa->cnt, tfa->dev_idx, prof_idx);
559 nxpTfaDescriptorType_t items_list[] = {dscBitfield, dscRegister, dsc_listend};
560
561 if (!prof)
562 {
563 return -EINVAL;
564 }
565
566 profile = tfa2_cnt_get_string(tfa->cnt, &prof->name);
567 if (profile == NULL)
568 {
569 dev_dbg(&tfa->i2c->dev, "Invalid profile index given: %d\n", prof_idx);
570 return -EINVAL;
571 }
572 else
573 {
574 dev_dbg(&tfa->i2c->dev, "----- profile: %s (%d) -----\n", profile, prof_idx);
575 }
576
577 /* process the list until the end of the profile or the default section */
578 for (i = 0; i < prof->length - 1; i++)
579 {
580 /* We only want to write the values before the default section when we switch profile */
581 if (prof->list[i].type == dscDefault)
582 break;
583 if (hitlist(items_list, (nxpTfaDescriptorType_t)(prof->list[i].type)))
584 {
585 rc = tfa2_cnt_write_item(tfa, &prof->list[i]);
586 if (rc < 0)
587 break;
588 }
589 }
590 return rc;
591 }
592
tfa2_cnt_write_patch(struct tfa2_device * tfa,nxpTfaPatch_t * patchfile)593 int tfa2_cnt_write_patch(struct tfa2_device *tfa, nxpTfaPatch_t *patchfile)
594 {
595 int rc, size;
596
597 if (tfa->verbose)
598 tfa2_cnt_show_header(&patchfile->hdr);
599
600 size = patchfile->hdr.size - sizeof(nxpTfaPatch_t); // size is total length
601 rc = tfa2_check_patch((const uint8_t *)patchfile, patchfile->hdr.size,
602 tfa->rev); // TODO fix for single patch header type
603 if (rc < 0)
604 return rc;
605
606 rc = tfa2_dev_dsp_patch(tfa, size, (const unsigned char *)patchfile->data);
607
608 return rc;
609 }
610 /*
611 * write the item from the dsc
612 * ignore if not a content item
613 */
tfa2_cnt_write_item(struct tfa2_device * tfa,nxpTfaDescPtr_t * dsc)614 static int tfa2_cnt_write_item(struct tfa2_device *tfa, nxpTfaDescPtr_t *dsc)
615 {
616 int rc = 0;
617 nxpTfaRegpatch_t *reg;
618 nxpTfaBitfield_t *bitf;
619 nxpTfaFileDsc_t *file;
620 void *cnt_offset;
621
622 cnt_offset = dsc->offset + (uint8_t *)tfa->cnt; /* payload offset in cnt */
623
624 switch (dsc->type)
625 {
626 case dscBitfield:
627 bitf = (nxpTfaBitfield_t *)(cnt_offset);
628 rc = tfa2_i2c_write_bf_volatile(tfa->i2c, bitf->field, bitf->value);
629 break;
630 case dscFile:
631 rc = tfa2_cnt_write_file(tfa, (nxpTfaFileDsc_t *)(cnt_offset));
632 break;
633 case dscCmd:
634 rc = tfa2_cnt_write_msg_dsc(tfa, dsc);
635 break;
636 case dscCfMem:
637 rc = tfa2_cnt_write_dspmem(tfa, (nxpTfaDspMem_t *)cnt_offset);
638 break;
639 case dscDefault: /* default listpoint marker */
640 case dscDevice: /* device list */
641 case dscProfile: /* profile list */
642 case dscGroup:
643 case dscMarker:
644 case dscTfaHal:
645 case dscLiveDataString:
646 case dscLiveData:
647 case dscInfoText:
648 case dscInfoFile:
649 case dscFilter:
650 break; /* ignore */
651 case dscString: // ascii: zero terminated string
652 dev_dbg(&tfa->i2c->dev, ";string: %s\n", tfa2_cnt_get_string(tfa->cnt, dsc));
653 break;
654 case dscRegister: // register patch
655 reg = (nxpTfaRegpatch_t *)(cnt_offset);
656 rc = tfa2_dev_cnt_write_register(tfa, reg);
657 // dev_dbg(&tfa->i2c->dev, "$0x%2x=0x%02x,0x%02x\n", reg->address, reg->mask, reg->value);
658 break;
659 // case dscFile: // filename + file contents
660 case dscPatch:
661 file = (nxpTfaFileDsc_t *)(cnt_offset); /* get the payload from the file dsc */
662 rc = tfa2_cnt_write_patch(tfa, (nxpTfaPatch_t *)&file->data); /* data is the patch header */
663 break;
664 default:
665 dev_err(&tfa->i2c->dev, "unsupported list item:%d\n", dsc->type);
666 rc = -EINVAL;
667 }
668
669 return rc;
670 }
671
672 /*
673 * all container originated RPC msgs goes through this
674 *
675 * the cmd_id is monitored here to insert {"SetAlgoParams", 0x48100},
676 {"SetAlgoParamsWithoutReset", 0x48102},
677 {"SetMBDrc", 0x48107},
678 {"SetMBDrcWithoutReset", 0x48108},
679 */
tfa2_cnt_write_msg(struct tfa2_device * tfa,int wlength,char * wbuf)680 int tfa2_cnt_write_msg(struct tfa2_device *tfa, int wlength, char *wbuf)
681 {
682 int rc = 0;
683 uint8_t *cmd_id24 = (uint8_t *)wbuf;
684 int cmd_id = cmd_id24[0] << 16 | cmd_id24[1] << 8 | cmd_id24[2];
685 uint8_t *cmd_lsb = &cmd_id24[2];
686 int coldstarting = tfa2_dev_is_fw_cold(tfa); /* set if FW is cold */
687 char rbuf[3];
688 uint32_t rpc_status;
689
690 /*
691 * select the cmd_id variant based on the init state
692 */
693 switch (cmd_id & 0x7fff)
694 {
695 default:
696 break;
697 case 0x100: /* SetAlgoParams 0x48100*/
698 case 0x102: /* SetAlgoParamsWithoutReset 0x48102*/
699 *cmd_lsb = coldstarting ? 0 : 2; /* if cold cmd_id = coldstart variant */
700 break;
701 case 0x107: /* SetMBDrc 0x48107*/
702 case 0x108: /* SetMBDrcWithoutReset 0x48108*/
703 *cmd_lsb = coldstarting ? 7 : 8; /* if cold cmd_id = coldstart variant */
704 break;
705 }
706
707 if (tfa->verbose)
708 {
709 int cmd_id = cmd_id24[0] << 16 | cmd_id24[1] << 8 | cmd_id24[2];
710 dev_dbg(&tfa->i2c->dev, "Writing cmd=0x%06x,size=%d\n", cmd_id, wlength);
711 }
712
713 rc = tfa2_dsp_execute(tfa, wbuf, wlength, rbuf, 3);
714 if (rc < 0)
715 return rc;
716 rpc_status = (rbuf[0] << 16) | (rbuf[1] << 8) | rbuf[2];
717 if (rpc_status != 0)
718 {
719 dev_err(&tfa->i2c->dev, "%s: rpc_status = 0x%x\n", __func__, rpc_status);
720 return -1;
721 }
722
723 return rc;
724 }
725
726 /* write all patchfiles in the devicelist to the target */
tfa2_cnt_write_patches(struct tfa2_device * tfa)727 int tfa2_cnt_write_patches(struct tfa2_device *tfa)
728 {
729 int rc = 0;
730 nxpTfaDeviceList_t *dev = tfa2_cnt_get_dev_list(tfa->cnt, tfa->dev_idx);
731 int i;
732
733 if (!dev)
734 {
735 return -EINVAL;
736 }
737
738 /* process the list until a patch is encountered and load it */
739 for (i = 0; i < dev->length; i++)
740 {
741 if (dev->list[i].type == dscPatch)
742 {
743 rc = tfa2_cnt_write_item(tfa, &dev->list[i]);
744 }
745 }
746
747 return rc;
748 }
749
tfa2_cnt_write_msg_dsc(struct tfa2_device * tfa,nxpTfaDescPtr_t * dsc)750 int tfa2_cnt_write_msg_dsc(struct tfa2_device *tfa, nxpTfaDescPtr_t *dsc)
751 {
752 char *cnt = (char *)tfa->cnt;
753 int size;
754
755 size = get_unaligned_le16((uint16_t *)(dsc->offset + cnt));
756 return tfa2_cnt_write_msg(tfa, size, dsc->offset + 2 + cnt);
757 }
758
759 /*
760 * write all descripters from the dsc list which type is in the items list
761 */
tfa2_cnt_write_items_list(struct tfa2_device * tfa,nxpTfaDescPtr_t * dsc_list,int length,nxpTfaDescriptorType_t * items_list)762 static int tfa2_cnt_write_items_list(struct tfa2_device *tfa,
763 nxpTfaDescPtr_t *dsc_list,
764 int length,
765 nxpTfaDescriptorType_t *items_list)
766 {
767 int i, rc = 0;
768
769 /* process the list and write all files */
770 for (i = 0; i < length; i++)
771 {
772 if (hitlist(items_list, (nxpTfaDescriptorType_t)(dsc_list[i].type)))
773 {
774 rc = tfa2_cnt_write_item(tfa, &dsc_list[i]);
775 if (rc < 0)
776 break;
777 }
778 }
779
780 return rc;
781 }
782
783 /* write all param files and cfmem from the devicelist to the target */
tfa2_cnt_write_files(struct tfa2_device * tfa)784 int tfa2_cnt_write_files(struct tfa2_device *tfa)
785 {
786 nxpTfaDeviceList_t *dev;
787 nxpTfaDescriptorType_t items_list[] = {dscFile, dscCmd, dscCfMem, dsc_listend};
788
789 dev = tfa2_cnt_device(tfa->cnt, tfa->dev_idx);
790 if (!dev)
791 return -EINVAL;
792
793 /* process the list and write all files */
794 return tfa2_cnt_write_items_list(tfa, dev->list, dev->length, items_list);
795 }
796
797 /* write all param files in the profile list to the target */
tfa2_cnt_write_files_profile(struct tfa2_device * tfa,int prof_idx,int vstep_idx)798 int tfa2_cnt_write_files_profile(struct tfa2_device *tfa, int prof_idx, int vstep_idx)
799 {
800 nxpTfaProfileList_t *prof = tfa2_cnt_get_dev_prof_list(tfa->cnt, tfa->dev_idx, prof_idx);
801 nxpTfaDescriptorType_t items_list[] = {dscFile, dscCmd, dscCfMem, dscPatch, dsc_listend};
802
803 if (!prof)
804 {
805 return -EINVAL;
806 }
807
808 /* process the list and write all files */
809 return tfa2_cnt_write_items_list(tfa, prof->list, prof->length - 1, items_list);
810 }
811
812 /*
813 * write a parameter file to the device
814 * only generic rpc msg and speaker/lsmodel files are supported
815 */
tfa2_cnt_write_file(struct tfa2_device * tfa,nxpTfaFileDsc_t * file)816 int tfa2_cnt_write_file(struct tfa2_device *tfa, nxpTfaFileDsc_t *file)
817 {
818 int rc = 0;
819 nxpTfaHeader_t *hdr = (nxpTfaHeader_t *)file->data;
820 nxpTfaHeaderType_t type;
821 int size;
822
823 if (tfa->verbose)
824 {
825 tfa2_cnt_show_header(hdr);
826 }
827
828 type = (nxpTfaHeaderType_t)hdr->id;
829
830 switch (type)
831 {
832 case msgHdr: /* generic DSP message */
833 case equalizerHdr:
834 size = hdr->size - sizeof(tfa_msg_file_t);
835 rc = tfa2_cnt_write_msg(tfa, size, (char *)((tfa_msg_file_t *)hdr)->data);
836 break;
837 case speakerHdr:
838 /* Remove header and xml_id */
839 size = hdr->size - sizeof(struct nxpTfaSpkHeader) - sizeof(struct nxpTfaFWVer);
840 rc = tfa2_cnt_write_msg(tfa, size,
841 (char *)(((nxpTfaSpeakerFile_t *)hdr)->data + (sizeof(struct nxpTfaFWVer))));
842 break;
843 case infoHdr:
844 /* Ignore */
845 break;
846 case patchHdr:
847 rc = tfa2_cnt_write_patch(tfa, (nxpTfaPatch_t *)&file->data);
848 break;
849
850 default:
851 dev_err(&tfa->i2c->dev, "Header is of unknown type: %c%c (0x%x)\n", type & 0xff, (type >> 8) & 0xff, type);
852 return -EINVAL;
853 }
854
855 return rc;
856 }
857
858 /*
859 * process all items in the profilelist
860 * NOTE an error return during processing will leave the device muted
861 *
862 */
tfa2_cnt_write_profile(struct tfa2_device * tfa,int prof_idx,int vstep_idx)863 int tfa2_cnt_write_profile(struct tfa2_device *tfa, int prof_idx, int vstep_idx)
864 {
865 int i, rc = 0;
866 int previous_prof_idx = tfa2_dev_get_swprofile(tfa);
867 nxpTfaProfileList_t *prof = tfa2_cnt_get_dev_prof_list(tfa->cnt, tfa->dev_idx, prof_idx);
868 nxpTfaProfileList_t *previous_prof = tfa2_cnt_get_dev_prof_list(tfa->cnt, tfa->dev_idx, previous_prof_idx);
869 int in_group;
870 int prof_clockdep_idx, prof_default_section_idx;
871 int previous_clockdep_idx, previous_default_section_idx;
872
873 if (!prof || !previous_prof)
874 {
875 dev_err(&tfa->i2c->dev, "Error trying to get the (previous) swprofile \n");
876 return -EINVAL;
877 }
878
879 /* grouping enabled ? */
880 in_group = prof->group == previous_prof->group && prof->group != 0;
881
882 /* get indexes of relevant points in the profiles:
883 * 1st clock dependent item and default settings marker */
884 rc = tfa2_cnt_get_clockdep_idx(tfa, previous_prof->list, previous_prof->length, &previous_clockdep_idx,
885 &previous_default_section_idx);
886 if (rc < 0)
887 return rc;
888 /* new profile */
889 rc = tfa2_cnt_get_clockdep_idx(tfa, prof->list, prof->length, &prof_clockdep_idx, &prof_default_section_idx);
890 if (rc < 0)
891 return rc;
892
893 dev_dbg(&tfa->i2c->dev, "profile switch device:%s, %s > %s (%s pwdn)\n",
894 tfa2_cnt_device_name(tfa->cnt, tfa->dev_idx),
895 tfa2_cnt_profile_name(tfa->cnt, tfa->dev_idx, previous_prof_idx),
896 tfa2_cnt_profile_name(tfa->cnt, tfa->dev_idx, prof_idx), in_group ? "no" : "with");
897
898 /* We only power cycle when the profiles are not in the same group */
899 if (!in_group)
900 {
901 /* When we switch profile we first power down thePLL */
902 rc = tfa2_dev_set_state(tfa, (enum tfa_state)(TFA_STATE_POWERDOWN | TFA_STATE_MUTE)); /* with mute */
903 if (rc < 0)
904 return rc;
905 }
906
907 if (tfa->verbose)
908 tfa2_show_current_state(tfa);
909
910 /* restore defaults/ non-clock dependent settings from the active (previous) profile */
911 for (i = previous_default_section_idx; i < previous_prof->length - 1; i++)
912 {
913 rc = tfa2_cnt_write_item(tfa, &previous_prof->list[i]);
914 if (rc < 0)
915 return rc;
916 }
917 /* apply all non-clock dependent settings from new profile */
918 for (i = 0; i < prof_clockdep_idx; i++)
919 {
920 rc = tfa2_cnt_write_item(tfa, &prof->list[i]);
921 if (rc < 0)
922 return rc;
923 }
924
925 /* We only power cycle when the profiles are not in the same group */
926 if (!in_group)
927 {
928 /* Leave powerdown state */
929 rc = tfa2_dev_set_state(tfa, TFA_STATE_CLOCK); /* clock will be there on return */
930 if (rc < 0)
931 return rc;
932 /* hook for workaround */
933 tfa2_init_fix_initcf(tfa);
934 }
935
936 /* write everything until end or the default section */
937 for (i = prof_clockdep_idx; i < prof_default_section_idx; i++)
938 {
939 rc = tfa2_cnt_write_item(tfa, &prof->list[i]);
940 if (rc < 0)
941 return rc;
942 }
943
944 return rc;
945 }
946 /*
947 * direct write of all items in the profile
948 */
tfa2_cnt_write_transient_profile(struct tfa2_device * tfa,int prof_idx)949 int tfa2_cnt_write_transient_profile(struct tfa2_device *tfa, int prof_idx)
950 {
951 int i, rc = 0;
952 nxpTfaProfileList_t *prof = tfa2_cnt_get_dev_prof_list(tfa->cnt, tfa->dev_idx, prof_idx);
953 int prof_clockdep_idx, prof_default_section_idx;
954
955 if (!prof)
956 {
957 dev_err(&tfa->i2c->dev, "Error trying to get the (previous) swprofile \n");
958 return -EINVAL;
959 }
960 /* get indexes of relevant points in the profiles:
961 * 1st clock dependent item and default settings marker */
962 rc = tfa2_cnt_get_clockdep_idx(tfa, prof->list, prof->length, &prof_clockdep_idx, &prof_default_section_idx);
963 if (rc < 0)
964 return rc;
965
966 /* write everything until end or the default section */
967 for (i = 0; i < prof_default_section_idx; i++)
968 {
969 rc = tfa2_cnt_write_item(tfa, &prof->list[i]);
970 if (rc < 0)
971 break;
972 }
973
974 return rc;
975 }
976 /*
977 * lookup slave and return device index
978 */
tfa2_cnt_get_idx(struct tfa2_device * tfa)979 int tfa2_cnt_get_idx(struct tfa2_device *tfa)
980 {
981 nxpTfaDeviceList_t *dev = NULL;
982 int i;
983
984 for (i = 0; i < tfa->cnt->ndev; i++)
985 {
986 dev = tfa2_cnt_device(tfa->cnt, i);
987 if (!dev)
988 return -1;
989 if (dev->dev == tfa->slave_address)
990 break;
991 }
992 if (i == tfa->cnt->ndev)
993 return -1;
994
995 return i;
996 }
997