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