aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2015-06-02 16:06:04 -0400
committerMark Brown <broonie@kernel.org>2015-06-02 16:06:04 -0400
commitb601b58785d1440236a4180b1e3ec7bc7c1e5664 (patch)
tree71b873b01ea1353ecb82bf4c8da43d8a3b18c636
parentc38a1ffbf54f4d1c40a476a2a9ddc9177f493b78 (diff)
parent10337b070d3ba7696c8e746bd1f94870c01153ec (diff)
Merge branch 'topic/adsp' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into asoc-arizona
-rw-r--r--sound/soc/codecs/wm_adsp.c1159
-rw-r--r--sound/soc/codecs/wm_adsp.h6
-rw-r--r--sound/soc/codecs/wmfw.h44
3 files changed, 763 insertions, 446 deletions
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index d01c2095452f..477390ad9c6d 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -121,6 +121,11 @@
121#define ADSP2_WDMA_CONFIG_2 0x31 121#define ADSP2_WDMA_CONFIG_2 0x31
122#define ADSP2_RDMA_CONFIG_1 0x34 122#define ADSP2_RDMA_CONFIG_1 0x34
123 123
124#define ADSP2_SCRATCH0 0x40
125#define ADSP2_SCRATCH1 0x41
126#define ADSP2_SCRATCH2 0x42
127#define ADSP2_SCRATCH3 0x43
128
124/* 129/*
125 * ADSP2 Control 130 * ADSP2 Control
126 */ 131 */
@@ -229,16 +234,18 @@ struct wm_coeff_ctl_ops {
229 234
230struct wm_coeff_ctl { 235struct wm_coeff_ctl {
231 const char *name; 236 const char *name;
232 struct wm_adsp_alg_region region; 237 const char *fw_name;
238 struct wm_adsp_alg_region alg_region;
233 struct wm_coeff_ctl_ops ops; 239 struct wm_coeff_ctl_ops ops;
234 struct wm_adsp *adsp; 240 struct wm_adsp *dsp;
235 void *private;
236 unsigned int enabled:1; 241 unsigned int enabled:1;
237 struct list_head list; 242 struct list_head list;
238 void *cache; 243 void *cache;
244 unsigned int offset;
239 size_t len; 245 size_t len;
240 unsigned int set:1; 246 unsigned int set:1;
241 struct snd_kcontrol *kcontrol; 247 struct snd_kcontrol *kcontrol;
248 unsigned int flags;
242}; 249};
243 250
244static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol, 251static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
@@ -246,9 +253,9 @@ static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
246{ 253{
247 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); 254 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
248 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 255 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
249 struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec); 256 struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
250 257
251 ucontrol->value.integer.value[0] = adsp[e->shift_l].fw; 258 ucontrol->value.integer.value[0] = dsp[e->shift_l].fw;
252 259
253 return 0; 260 return 0;
254} 261}
@@ -258,18 +265,18 @@ static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
258{ 265{
259 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); 266 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
260 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 267 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
261 struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec); 268 struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
262 269
263 if (ucontrol->value.integer.value[0] == adsp[e->shift_l].fw) 270 if (ucontrol->value.integer.value[0] == dsp[e->shift_l].fw)
264 return 0; 271 return 0;
265 272
266 if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW) 273 if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW)
267 return -EINVAL; 274 return -EINVAL;
268 275
269 if (adsp[e->shift_l].running) 276 if (dsp[e->shift_l].running)
270 return -EBUSY; 277 return -EBUSY;
271 278
272 adsp[e->shift_l].fw = ucontrol->value.integer.value[0]; 279 dsp[e->shift_l].fw = ucontrol->value.integer.value[0];
273 280
274 return 0; 281 return 0;
275} 282}
@@ -340,28 +347,47 @@ static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
340 return NULL; 347 return NULL;
341} 348}
342 349
343static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *region, 350static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *mem,
344 unsigned int offset) 351 unsigned int offset)
345{ 352{
346 if (WARN_ON(!region)) 353 if (WARN_ON(!mem))
347 return offset; 354 return offset;
348 switch (region->type) { 355 switch (mem->type) {
349 case WMFW_ADSP1_PM: 356 case WMFW_ADSP1_PM:
350 return region->base + (offset * 3); 357 return mem->base + (offset * 3);
351 case WMFW_ADSP1_DM: 358 case WMFW_ADSP1_DM:
352 return region->base + (offset * 2); 359 return mem->base + (offset * 2);
353 case WMFW_ADSP2_XM: 360 case WMFW_ADSP2_XM:
354 return region->base + (offset * 2); 361 return mem->base + (offset * 2);
355 case WMFW_ADSP2_YM: 362 case WMFW_ADSP2_YM:
356 return region->base + (offset * 2); 363 return mem->base + (offset * 2);
357 case WMFW_ADSP1_ZM: 364 case WMFW_ADSP1_ZM:
358 return region->base + (offset * 2); 365 return mem->base + (offset * 2);
359 default: 366 default:
360 WARN(1, "Unknown memory region type"); 367 WARN(1, "Unknown memory region type");
361 return offset; 368 return offset;
362 } 369 }
363} 370}
364 371
372static void wm_adsp2_show_fw_status(struct wm_adsp *dsp)
373{
374 u16 scratch[4];
375 int ret;
376
377 ret = regmap_raw_read(dsp->regmap, dsp->base + ADSP2_SCRATCH0,
378 scratch, sizeof(scratch));
379 if (ret) {
380 adsp_err(dsp, "Failed to read SCRATCH regs: %d\n", ret);
381 return;
382 }
383
384 adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
385 be16_to_cpu(scratch[0]),
386 be16_to_cpu(scratch[1]),
387 be16_to_cpu(scratch[2]),
388 be16_to_cpu(scratch[3]));
389}
390
365static int wm_coeff_info(struct snd_kcontrol *kcontrol, 391static int wm_coeff_info(struct snd_kcontrol *kcontrol,
366 struct snd_ctl_elem_info *uinfo) 392 struct snd_ctl_elem_info *uinfo)
367{ 393{
@@ -372,40 +398,39 @@ static int wm_coeff_info(struct snd_kcontrol *kcontrol,
372 return 0; 398 return 0;
373} 399}
374 400
375static int wm_coeff_write_control(struct snd_kcontrol *kcontrol, 401static int wm_coeff_write_control(struct wm_coeff_ctl *ctl,
376 const void *buf, size_t len) 402 const void *buf, size_t len)
377{ 403{
378 struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; 404 struct wm_adsp_alg_region *alg_region = &ctl->alg_region;
379 struct wm_adsp_alg_region *region = &ctl->region;
380 const struct wm_adsp_region *mem; 405 const struct wm_adsp_region *mem;
381 struct wm_adsp *adsp = ctl->adsp; 406 struct wm_adsp *dsp = ctl->dsp;
382 void *scratch; 407 void *scratch;
383 int ret; 408 int ret;
384 unsigned int reg; 409 unsigned int reg;
385 410
386 mem = wm_adsp_find_region(adsp, region->type); 411 mem = wm_adsp_find_region(dsp, alg_region->type);
387 if (!mem) { 412 if (!mem) {
388 adsp_err(adsp, "No base for region %x\n", 413 adsp_err(dsp, "No base for region %x\n",
389 region->type); 414 alg_region->type);
390 return -EINVAL; 415 return -EINVAL;
391 } 416 }
392 417
393 reg = ctl->region.base; 418 reg = ctl->alg_region.base + ctl->offset;
394 reg = wm_adsp_region_to_reg(mem, reg); 419 reg = wm_adsp_region_to_reg(mem, reg);
395 420
396 scratch = kmemdup(buf, ctl->len, GFP_KERNEL | GFP_DMA); 421 scratch = kmemdup(buf, ctl->len, GFP_KERNEL | GFP_DMA);
397 if (!scratch) 422 if (!scratch)
398 return -ENOMEM; 423 return -ENOMEM;
399 424
400 ret = regmap_raw_write(adsp->regmap, reg, scratch, 425 ret = regmap_raw_write(dsp->regmap, reg, scratch,
401 ctl->len); 426 ctl->len);
402 if (ret) { 427 if (ret) {
403 adsp_err(adsp, "Failed to write %zu bytes to %x: %d\n", 428 adsp_err(dsp, "Failed to write %zu bytes to %x: %d\n",
404 ctl->len, reg, ret); 429 ctl->len, reg, ret);
405 kfree(scratch); 430 kfree(scratch);
406 return ret; 431 return ret;
407 } 432 }
408 adsp_dbg(adsp, "Wrote %zu bytes to %x\n", ctl->len, reg); 433 adsp_dbg(dsp, "Wrote %zu bytes to %x\n", ctl->len, reg);
409 434
410 kfree(scratch); 435 kfree(scratch);
411 436
@@ -424,42 +449,41 @@ static int wm_coeff_put(struct snd_kcontrol *kcontrol,
424 if (!ctl->enabled) 449 if (!ctl->enabled)
425 return 0; 450 return 0;
426 451
427 return wm_coeff_write_control(kcontrol, p, ctl->len); 452 return wm_coeff_write_control(ctl, p, ctl->len);
428} 453}
429 454
430static int wm_coeff_read_control(struct snd_kcontrol *kcontrol, 455static int wm_coeff_read_control(struct wm_coeff_ctl *ctl,
431 void *buf, size_t len) 456 void *buf, size_t len)
432{ 457{
433 struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; 458 struct wm_adsp_alg_region *alg_region = &ctl->alg_region;
434 struct wm_adsp_alg_region *region = &ctl->region;
435 const struct wm_adsp_region *mem; 459 const struct wm_adsp_region *mem;
436 struct wm_adsp *adsp = ctl->adsp; 460 struct wm_adsp *dsp = ctl->dsp;
437 void *scratch; 461 void *scratch;
438 int ret; 462 int ret;
439 unsigned int reg; 463 unsigned int reg;
440 464
441 mem = wm_adsp_find_region(adsp, region->type); 465 mem = wm_adsp_find_region(dsp, alg_region->type);
442 if (!mem) { 466 if (!mem) {
443 adsp_err(adsp, "No base for region %x\n", 467 adsp_err(dsp, "No base for region %x\n",
444 region->type); 468 alg_region->type);
445 return -EINVAL; 469 return -EINVAL;
446 } 470 }
447 471
448 reg = ctl->region.base; 472 reg = ctl->alg_region.base + ctl->offset;
449 reg = wm_adsp_region_to_reg(mem, reg); 473 reg = wm_adsp_region_to_reg(mem, reg);
450 474
451 scratch = kmalloc(ctl->len, GFP_KERNEL | GFP_DMA); 475 scratch = kmalloc(ctl->len, GFP_KERNEL | GFP_DMA);
452 if (!scratch) 476 if (!scratch)
453 return -ENOMEM; 477 return -ENOMEM;
454 478
455 ret = regmap_raw_read(adsp->regmap, reg, scratch, ctl->len); 479 ret = regmap_raw_read(dsp->regmap, reg, scratch, ctl->len);
456 if (ret) { 480 if (ret) {
457 adsp_err(adsp, "Failed to read %zu bytes from %x: %d\n", 481 adsp_err(dsp, "Failed to read %zu bytes from %x: %d\n",
458 ctl->len, reg, ret); 482 ctl->len, reg, ret);
459 kfree(scratch); 483 kfree(scratch);
460 return ret; 484 return ret;
461 } 485 }
462 adsp_dbg(adsp, "Read %zu bytes from %x\n", ctl->len, reg); 486 adsp_dbg(dsp, "Read %zu bytes from %x\n", ctl->len, reg);
463 487
464 memcpy(buf, scratch, ctl->len); 488 memcpy(buf, scratch, ctl->len);
465 kfree(scratch); 489 kfree(scratch);
@@ -473,17 +497,25 @@ static int wm_coeff_get(struct snd_kcontrol *kcontrol,
473 struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; 497 struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
474 char *p = ucontrol->value.bytes.data; 498 char *p = ucontrol->value.bytes.data;
475 499
500 if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
501 if (ctl->enabled)
502 return wm_coeff_read_control(ctl, p, ctl->len);
503 else
504 return -EPERM;
505 }
506
476 memcpy(p, ctl->cache, ctl->len); 507 memcpy(p, ctl->cache, ctl->len);
508
477 return 0; 509 return 0;
478} 510}
479 511
480struct wmfw_ctl_work { 512struct wmfw_ctl_work {
481 struct wm_adsp *adsp; 513 struct wm_adsp *dsp;
482 struct wm_coeff_ctl *ctl; 514 struct wm_coeff_ctl *ctl;
483 struct work_struct work; 515 struct work_struct work;
484}; 516};
485 517
486static int wmfw_add_ctl(struct wm_adsp *adsp, struct wm_coeff_ctl *ctl) 518static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
487{ 519{
488 struct snd_kcontrol_new *kcontrol; 520 struct snd_kcontrol_new *kcontrol;
489 int ret; 521 int ret;
@@ -502,17 +534,25 @@ static int wmfw_add_ctl(struct wm_adsp *adsp, struct wm_coeff_ctl *ctl)
502 kcontrol->put = wm_coeff_put; 534 kcontrol->put = wm_coeff_put;
503 kcontrol->private_value = (unsigned long)ctl; 535 kcontrol->private_value = (unsigned long)ctl;
504 536
505 ret = snd_soc_add_card_controls(adsp->card, 537 if (ctl->flags) {
538 if (ctl->flags & WMFW_CTL_FLAG_WRITEABLE)
539 kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
540 if (ctl->flags & WMFW_CTL_FLAG_READABLE)
541 kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_READ;
542 if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
543 kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_VOLATILE;
544 }
545
546 ret = snd_soc_add_card_controls(dsp->card,
506 kcontrol, 1); 547 kcontrol, 1);
507 if (ret < 0) 548 if (ret < 0)
508 goto err_kcontrol; 549 goto err_kcontrol;
509 550
510 kfree(kcontrol); 551 kfree(kcontrol);
511 552
512 ctl->kcontrol = snd_soc_card_get_kcontrol(adsp->card, 553 ctl->kcontrol = snd_soc_card_get_kcontrol(dsp->card,
513 ctl->name); 554 ctl->name);
514 555
515 list_add(&ctl->list, &adsp->ctl_list);
516 return 0; 556 return 0;
517 557
518err_kcontrol: 558err_kcontrol:
@@ -520,6 +560,358 @@ err_kcontrol:
520 return ret; 560 return ret;
521} 561}
522 562
563static int wm_coeff_init_control_caches(struct wm_adsp *dsp)
564{
565 struct wm_coeff_ctl *ctl;
566 int ret;
567
568 list_for_each_entry(ctl, &dsp->ctl_list, list) {
569 if (!ctl->enabled || ctl->set)
570 continue;
571 if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
572 continue;
573
574 ret = wm_coeff_read_control(ctl,
575 ctl->cache,
576 ctl->len);
577 if (ret < 0)
578 return ret;
579 }
580
581 return 0;
582}
583
584static int wm_coeff_sync_controls(struct wm_adsp *dsp)
585{
586 struct wm_coeff_ctl *ctl;
587 int ret;
588
589 list_for_each_entry(ctl, &dsp->ctl_list, list) {
590 if (!ctl->enabled)
591 continue;
592 if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) {
593 ret = wm_coeff_write_control(ctl,
594 ctl->cache,
595 ctl->len);
596 if (ret < 0)
597 return ret;
598 }
599 }
600
601 return 0;
602}
603
604static void wm_adsp_ctl_work(struct work_struct *work)
605{
606 struct wmfw_ctl_work *ctl_work = container_of(work,
607 struct wmfw_ctl_work,
608 work);
609
610 wmfw_add_ctl(ctl_work->dsp, ctl_work->ctl);
611 kfree(ctl_work);
612}
613
614static int wm_adsp_create_control(struct wm_adsp *dsp,
615 const struct wm_adsp_alg_region *alg_region,
616 unsigned int offset, unsigned int len,
617 const char *subname, unsigned int subname_len,
618 unsigned int flags)
619{
620 struct wm_coeff_ctl *ctl;
621 struct wmfw_ctl_work *ctl_work;
622 char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
623 char *region_name;
624 int ret;
625
626 if (flags & WMFW_CTL_FLAG_SYS)
627 return 0;
628
629 switch (alg_region->type) {
630 case WMFW_ADSP1_PM:
631 region_name = "PM";
632 break;
633 case WMFW_ADSP1_DM:
634 region_name = "DM";
635 break;
636 case WMFW_ADSP2_XM:
637 region_name = "XM";
638 break;
639 case WMFW_ADSP2_YM:
640 region_name = "YM";
641 break;
642 case WMFW_ADSP1_ZM:
643 region_name = "ZM";
644 break;
645 default:
646 adsp_err(dsp, "Unknown region type: %d\n", alg_region->type);
647 return -EINVAL;
648 }
649
650 switch (dsp->fw_ver) {
651 case 0:
652 case 1:
653 snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "DSP%d %s %x",
654 dsp->num, region_name, alg_region->alg);
655 break;
656 default:
657 ret = snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
658 "DSP%d%c %.12s %x", dsp->num, *region_name,
659 wm_adsp_fw_text[dsp->fw], alg_region->alg);
660
661 /* Truncate the subname from the start if it is too long */
662 if (subname) {
663 int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2;
664 int skip = 0;
665
666 if (subname_len > avail)
667 skip = subname_len - avail;
668
669 snprintf(name + ret,
670 SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret, " %.*s",
671 subname_len - skip, subname + skip);
672 }
673 break;
674 }
675
676 list_for_each_entry(ctl, &dsp->ctl_list,
677 list) {
678 if (!strcmp(ctl->name, name)) {
679 if (!ctl->enabled)
680 ctl->enabled = 1;
681 return 0;
682 }
683 }
684
685 ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
686 if (!ctl)
687 return -ENOMEM;
688 ctl->fw_name = wm_adsp_fw_text[dsp->fw];
689 ctl->alg_region = *alg_region;
690 ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL);
691 if (!ctl->name) {
692 ret = -ENOMEM;
693 goto err_ctl;
694 }
695 ctl->enabled = 1;
696 ctl->set = 0;
697 ctl->ops.xget = wm_coeff_get;
698 ctl->ops.xput = wm_coeff_put;
699 ctl->dsp = dsp;
700
701 ctl->flags = flags;
702 ctl->offset = offset;
703 if (len > 512) {
704 adsp_warn(dsp, "Truncating control %s from %d\n",
705 ctl->name, len);
706 len = 512;
707 }
708 ctl->len = len;
709 ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
710 if (!ctl->cache) {
711 ret = -ENOMEM;
712 goto err_ctl_name;
713 }
714
715 list_add(&ctl->list, &dsp->ctl_list);
716
717 ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL);
718 if (!ctl_work) {
719 ret = -ENOMEM;
720 goto err_ctl_cache;
721 }
722
723 ctl_work->dsp = dsp;
724 ctl_work->ctl = ctl;
725 INIT_WORK(&ctl_work->work, wm_adsp_ctl_work);
726 schedule_work(&ctl_work->work);
727
728 return 0;
729
730err_ctl_cache:
731 kfree(ctl->cache);
732err_ctl_name:
733 kfree(ctl->name);
734err_ctl:
735 kfree(ctl);
736
737 return ret;
738}
739
740struct wm_coeff_parsed_alg {
741 int id;
742 const u8 *name;
743 int name_len;
744 int ncoeff;
745};
746
747struct wm_coeff_parsed_coeff {
748 int offset;
749 int mem_type;
750 const u8 *name;
751 int name_len;
752 int ctl_type;
753 int flags;
754 int len;
755};
756
757static int wm_coeff_parse_string(int bytes, const u8 **pos, const u8 **str)
758{
759 int length;
760
761 switch (bytes) {
762 case 1:
763 length = **pos;
764 break;
765 case 2:
766 length = le16_to_cpu(*((__le16 *)*pos));
767 break;
768 default:
769 return 0;
770 }
771
772 if (str)
773 *str = *pos + bytes;
774
775 *pos += ((length + bytes) + 3) & ~0x03;
776
777 return length;
778}
779
780static int wm_coeff_parse_int(int bytes, const u8 **pos)
781{
782 int val = 0;
783
784 switch (bytes) {
785 case 2:
786 val = le16_to_cpu(*((__le16 *)*pos));
787 break;
788 case 4:
789 val = le32_to_cpu(*((__le32 *)*pos));
790 break;
791 default:
792 break;
793 }
794
795 *pos += bytes;
796
797 return val;
798}
799
800static inline void wm_coeff_parse_alg(struct wm_adsp *dsp, const u8 **data,
801 struct wm_coeff_parsed_alg *blk)
802{
803 const struct wmfw_adsp_alg_data *raw;
804
805 switch (dsp->fw_ver) {
806 case 0:
807 case 1:
808 raw = (const struct wmfw_adsp_alg_data *)*data;
809 *data = raw->data;
810
811 blk->id = le32_to_cpu(raw->id);
812 blk->name = raw->name;
813 blk->name_len = strlen(raw->name);
814 blk->ncoeff = le32_to_cpu(raw->ncoeff);
815 break;
816 default:
817 blk->id = wm_coeff_parse_int(sizeof(raw->id), data);
818 blk->name_len = wm_coeff_parse_string(sizeof(u8), data,
819 &blk->name);
820 wm_coeff_parse_string(sizeof(u16), data, NULL);
821 blk->ncoeff = wm_coeff_parse_int(sizeof(raw->ncoeff), data);
822 break;
823 }
824
825 adsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id);
826 adsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name);
827 adsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff);
828}
829
830static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data,
831 struct wm_coeff_parsed_coeff *blk)
832{
833 const struct wmfw_adsp_coeff_data *raw;
834 const u8 *tmp;
835 int length;
836
837 switch (dsp->fw_ver) {
838 case 0:
839 case 1:
840 raw = (const struct wmfw_adsp_coeff_data *)*data;
841 *data = *data + sizeof(raw->hdr) + le32_to_cpu(raw->hdr.size);
842
843 blk->offset = le16_to_cpu(raw->hdr.offset);
844 blk->mem_type = le16_to_cpu(raw->hdr.type);
845 blk->name = raw->name;
846 blk->name_len = strlen(raw->name);
847 blk->ctl_type = le16_to_cpu(raw->ctl_type);
848 blk->flags = le16_to_cpu(raw->flags);
849 blk->len = le32_to_cpu(raw->len);
850 break;
851 default:
852 tmp = *data;
853 blk->offset = wm_coeff_parse_int(sizeof(raw->hdr.offset), &tmp);
854 blk->mem_type = wm_coeff_parse_int(sizeof(raw->hdr.type), &tmp);
855 length = wm_coeff_parse_int(sizeof(raw->hdr.size), &tmp);
856 blk->name_len = wm_coeff_parse_string(sizeof(u8), &tmp,
857 &blk->name);
858 wm_coeff_parse_string(sizeof(u8), &tmp, NULL);
859 wm_coeff_parse_string(sizeof(u16), &tmp, NULL);
860 blk->ctl_type = wm_coeff_parse_int(sizeof(raw->ctl_type), &tmp);
861 blk->flags = wm_coeff_parse_int(sizeof(raw->flags), &tmp);
862 blk->len = wm_coeff_parse_int(sizeof(raw->len), &tmp);
863
864 *data = *data + sizeof(raw->hdr) + length;
865 break;
866 }
867
868 adsp_dbg(dsp, "\tCoefficient type: %#x\n", blk->mem_type);
869 adsp_dbg(dsp, "\tCoefficient offset: %#x\n", blk->offset);
870 adsp_dbg(dsp, "\tCoefficient name: %.*s\n", blk->name_len, blk->name);
871 adsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags);
872 adsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type);
873 adsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len);
874}
875
876static int wm_adsp_parse_coeff(struct wm_adsp *dsp,
877 const struct wmfw_region *region)
878{
879 struct wm_adsp_alg_region alg_region = {};
880 struct wm_coeff_parsed_alg alg_blk;
881 struct wm_coeff_parsed_coeff coeff_blk;
882 const u8 *data = region->data;
883 int i, ret;
884
885 wm_coeff_parse_alg(dsp, &data, &alg_blk);
886 for (i = 0; i < alg_blk.ncoeff; i++) {
887 wm_coeff_parse_coeff(dsp, &data, &coeff_blk);
888
889 switch (coeff_blk.ctl_type) {
890 case SNDRV_CTL_ELEM_TYPE_BYTES:
891 break;
892 default:
893 adsp_err(dsp, "Unknown control type: %d\n",
894 coeff_blk.ctl_type);
895 return -EINVAL;
896 }
897
898 alg_region.type = coeff_blk.mem_type;
899 alg_region.alg = alg_blk.id;
900
901 ret = wm_adsp_create_control(dsp, &alg_region,
902 coeff_blk.offset,
903 coeff_blk.len,
904 coeff_blk.name,
905 coeff_blk.name_len,
906 coeff_blk.flags);
907 if (ret < 0)
908 adsp_err(dsp, "Failed to create control: %.*s, %d\n",
909 coeff_blk.name_len, coeff_blk.name, ret);
910 }
911
912 return 0;
913}
914
523static int wm_adsp_load(struct wm_adsp *dsp) 915static int wm_adsp_load(struct wm_adsp *dsp)
524{ 916{
525 LIST_HEAD(buf_list); 917 LIST_HEAD(buf_list);
@@ -568,12 +960,22 @@ static int wm_adsp_load(struct wm_adsp *dsp)
568 goto out_fw; 960 goto out_fw;
569 } 961 }
570 962
571 if (header->ver != 0) { 963 switch (header->ver) {
964 case 0:
965 adsp_warn(dsp, "%s: Depreciated file format %d\n",
966 file, header->ver);
967 break;
968 case 1:
969 case 2:
970 break;
971 default:
572 adsp_err(dsp, "%s: unknown file format %d\n", 972 adsp_err(dsp, "%s: unknown file format %d\n",
573 file, header->ver); 973 file, header->ver);
574 goto out_fw; 974 goto out_fw;
575 } 975 }
976
576 adsp_info(dsp, "Firmware version: %d\n", header->ver); 977 adsp_info(dsp, "Firmware version: %d\n", header->ver);
978 dsp->fw_ver = header->ver;
577 979
578 if (header->core != dsp->type) { 980 if (header->core != dsp->type) {
579 adsp_err(dsp, "%s: invalid core %d != %d\n", 981 adsp_err(dsp, "%s: invalid core %d != %d\n",
@@ -638,6 +1040,12 @@ static int wm_adsp_load(struct wm_adsp *dsp)
638 text = kzalloc(le32_to_cpu(region->len) + 1, 1040 text = kzalloc(le32_to_cpu(region->len) + 1,
639 GFP_KERNEL); 1041 GFP_KERNEL);
640 break; 1042 break;
1043 case WMFW_ALGORITHM_DATA:
1044 region_name = "Algorithm";
1045 ret = wm_adsp_parse_coeff(dsp, region);
1046 if (ret != 0)
1047 goto out_fw;
1048 break;
641 case WMFW_INFO_TEXT: 1049 case WMFW_INFO_TEXT:
642 region_name = "Information"; 1050 region_name = "Information";
643 text = kzalloc(le32_to_cpu(region->len) + 1, 1051 text = kzalloc(le32_to_cpu(region->len) + 1,
@@ -730,444 +1138,316 @@ out:
730 return ret; 1138 return ret;
731} 1139}
732 1140
733static int wm_coeff_init_control_caches(struct wm_adsp *adsp) 1141static void wm_adsp_ctl_fixup_base(struct wm_adsp *dsp,
1142 const struct wm_adsp_alg_region *alg_region)
734{ 1143{
735 struct wm_coeff_ctl *ctl; 1144 struct wm_coeff_ctl *ctl;
736 int ret;
737 1145
738 list_for_each_entry(ctl, &adsp->ctl_list, list) { 1146 list_for_each_entry(ctl, &dsp->ctl_list, list) {
739 if (!ctl->enabled || ctl->set) 1147 if (ctl->fw_name == wm_adsp_fw_text[dsp->fw] &&
740 continue; 1148 alg_region->alg == ctl->alg_region.alg &&
741 ret = wm_coeff_read_control(ctl->kcontrol, 1149 alg_region->type == ctl->alg_region.type) {
742 ctl->cache, 1150 ctl->alg_region.base = alg_region->base;
743 ctl->len); 1151 }
744 if (ret < 0)
745 return ret;
746 } 1152 }
747
748 return 0;
749} 1153}
750 1154
751static int wm_coeff_sync_controls(struct wm_adsp *adsp) 1155static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
1156 unsigned int pos, unsigned int len)
752{ 1157{
753 struct wm_coeff_ctl *ctl; 1158 void *alg;
754 int ret; 1159 int ret;
1160 __be32 val;
755 1161
756 list_for_each_entry(ctl, &adsp->ctl_list, list) { 1162 if (n_algs == 0) {
757 if (!ctl->enabled) 1163 adsp_err(dsp, "No algorithms\n");
758 continue; 1164 return ERR_PTR(-EINVAL);
759 if (ctl->set) {
760 ret = wm_coeff_write_control(ctl->kcontrol,
761 ctl->cache,
762 ctl->len);
763 if (ret < 0)
764 return ret;
765 }
766 } 1165 }
767 1166
768 return 0; 1167 if (n_algs > 1024) {
769} 1168 adsp_err(dsp, "Algorithm count %zx excessive\n", n_algs);
770 1169 return ERR_PTR(-EINVAL);
771static void wm_adsp_ctl_work(struct work_struct *work) 1170 }
772{
773 struct wmfw_ctl_work *ctl_work = container_of(work,
774 struct wmfw_ctl_work,
775 work);
776
777 wmfw_add_ctl(ctl_work->adsp, ctl_work->ctl);
778 kfree(ctl_work);
779}
780
781static int wm_adsp_create_control(struct wm_adsp *dsp,
782 const struct wm_adsp_alg_region *region)
783
784{
785 struct wm_coeff_ctl *ctl;
786 struct wmfw_ctl_work *ctl_work;
787 char *name;
788 char *region_name;
789 int ret;
790
791 name = kmalloc(PAGE_SIZE, GFP_KERNEL);
792 if (!name)
793 return -ENOMEM;
794 1171
795 switch (region->type) { 1172 /* Read the terminator first to validate the length */
796 case WMFW_ADSP1_PM: 1173 ret = regmap_raw_read(dsp->regmap, pos + len, &val, sizeof(val));
797 region_name = "PM"; 1174 if (ret != 0) {
798 break; 1175 adsp_err(dsp, "Failed to read algorithm list end: %d\n",
799 case WMFW_ADSP1_DM: 1176 ret);
800 region_name = "DM"; 1177 return ERR_PTR(ret);
801 break;
802 case WMFW_ADSP2_XM:
803 region_name = "XM";
804 break;
805 case WMFW_ADSP2_YM:
806 region_name = "YM";
807 break;
808 case WMFW_ADSP1_ZM:
809 region_name = "ZM";
810 break;
811 default:
812 ret = -EINVAL;
813 goto err_name;
814 } 1178 }
815 1179
816 snprintf(name, PAGE_SIZE, "DSP%d %s %x", 1180 if (be32_to_cpu(val) != 0xbedead)
817 dsp->num, region_name, region->alg); 1181 adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n",
1182 pos + len, be32_to_cpu(val));
818 1183
819 list_for_each_entry(ctl, &dsp->ctl_list, 1184 alg = kzalloc(len * 2, GFP_KERNEL | GFP_DMA);
820 list) { 1185 if (!alg)
821 if (!strcmp(ctl->name, name)) { 1186 return ERR_PTR(-ENOMEM);
822 if (!ctl->enabled)
823 ctl->enabled = 1;
824 goto found;
825 }
826 }
827 1187
828 ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); 1188 ret = regmap_raw_read(dsp->regmap, pos, alg, len * 2);
829 if (!ctl) { 1189 if (ret != 0) {
830 ret = -ENOMEM; 1190 adsp_err(dsp, "Failed to read algorithm list: %d\n",
831 goto err_name; 1191 ret);
832 } 1192 kfree(alg);
833 ctl->region = *region; 1193 return ERR_PTR(ret);
834 ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL);
835 if (!ctl->name) {
836 ret = -ENOMEM;
837 goto err_ctl;
838 } 1194 }
839 ctl->enabled = 1;
840 ctl->set = 0;
841 ctl->ops.xget = wm_coeff_get;
842 ctl->ops.xput = wm_coeff_put;
843 ctl->adsp = dsp;
844 1195
845 ctl->len = region->len; 1196 return alg;
846 ctl->cache = kzalloc(ctl->len, GFP_KERNEL); 1197}
847 if (!ctl->cache) {
848 ret = -ENOMEM;
849 goto err_ctl_name;
850 }
851 1198
852 ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL); 1199static struct wm_adsp_alg_region *wm_adsp_create_region(struct wm_adsp *dsp,
853 if (!ctl_work) { 1200 int type, __be32 id,
854 ret = -ENOMEM; 1201 __be32 base)
855 goto err_ctl_cache; 1202{
856 } 1203 struct wm_adsp_alg_region *alg_region;
857 1204
858 ctl_work->adsp = dsp; 1205 alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL);
859 ctl_work->ctl = ctl; 1206 if (!alg_region)
860 INIT_WORK(&ctl_work->work, wm_adsp_ctl_work); 1207 return ERR_PTR(-ENOMEM);
861 schedule_work(&ctl_work->work);
862 1208
863found: 1209 alg_region->type = type;
864 kfree(name); 1210 alg_region->alg = be32_to_cpu(id);
1211 alg_region->base = be32_to_cpu(base);
865 1212
866 return 0; 1213 list_add_tail(&alg_region->list, &dsp->alg_regions);
867 1214
868err_ctl_cache: 1215 if (dsp->fw_ver > 0)
869 kfree(ctl->cache); 1216 wm_adsp_ctl_fixup_base(dsp, alg_region);
870err_ctl_name: 1217
871 kfree(ctl->name); 1218 return alg_region;
872err_ctl:
873 kfree(ctl);
874err_name:
875 kfree(name);
876 return ret;
877} 1219}
878 1220
879static int wm_adsp_setup_algs(struct wm_adsp *dsp) 1221static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
880{ 1222{
881 struct regmap *regmap = dsp->regmap;
882 struct wmfw_adsp1_id_hdr adsp1_id; 1223 struct wmfw_adsp1_id_hdr adsp1_id;
883 struct wmfw_adsp2_id_hdr adsp2_id;
884 struct wmfw_adsp1_alg_hdr *adsp1_alg; 1224 struct wmfw_adsp1_alg_hdr *adsp1_alg;
885 struct wmfw_adsp2_alg_hdr *adsp2_alg; 1225 struct wm_adsp_alg_region *alg_region;
886 void *alg, *buf;
887 struct wm_adsp_alg_region *region;
888 const struct wm_adsp_region *mem; 1226 const struct wm_adsp_region *mem;
889 unsigned int pos, term; 1227 unsigned int pos, len;
890 size_t algs, buf_size; 1228 size_t n_algs;
891 __be32 val;
892 int i, ret; 1229 int i, ret;
893 1230
894 switch (dsp->type) { 1231 mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM);
895 case WMFW_ADSP1:
896 mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM);
897 break;
898 case WMFW_ADSP2:
899 mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
900 break;
901 default:
902 mem = NULL;
903 break;
904 }
905
906 if (WARN_ON(!mem)) 1232 if (WARN_ON(!mem))
907 return -EINVAL; 1233 return -EINVAL;
908 1234
909 switch (dsp->type) { 1235 ret = regmap_raw_read(dsp->regmap, mem->base, &adsp1_id,
910 case WMFW_ADSP1: 1236 sizeof(adsp1_id));
911 ret = regmap_raw_read(regmap, mem->base, &adsp1_id,
912 sizeof(adsp1_id));
913 if (ret != 0) {
914 adsp_err(dsp, "Failed to read algorithm info: %d\n",
915 ret);
916 return ret;
917 }
918
919 buf = &adsp1_id;
920 buf_size = sizeof(adsp1_id);
921
922 algs = be32_to_cpu(adsp1_id.algs);
923 dsp->fw_id = be32_to_cpu(adsp1_id.fw.id);
924 adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
925 dsp->fw_id,
926 (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16,
927 (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8,
928 be32_to_cpu(adsp1_id.fw.ver) & 0xff,
929 algs);
930
931 region = kzalloc(sizeof(*region), GFP_KERNEL);
932 if (!region)
933 return -ENOMEM;
934 region->type = WMFW_ADSP1_ZM;
935 region->alg = be32_to_cpu(adsp1_id.fw.id);
936 region->base = be32_to_cpu(adsp1_id.zm);
937 list_add_tail(&region->list, &dsp->alg_regions);
938
939 region = kzalloc(sizeof(*region), GFP_KERNEL);
940 if (!region)
941 return -ENOMEM;
942 region->type = WMFW_ADSP1_DM;
943 region->alg = be32_to_cpu(adsp1_id.fw.id);
944 region->base = be32_to_cpu(adsp1_id.dm);
945 list_add_tail(&region->list, &dsp->alg_regions);
946
947 pos = sizeof(adsp1_id) / 2;
948 term = pos + ((sizeof(*adsp1_alg) * algs) / 2);
949 break;
950
951 case WMFW_ADSP2:
952 ret = regmap_raw_read(regmap, mem->base, &adsp2_id,
953 sizeof(adsp2_id));
954 if (ret != 0) {
955 adsp_err(dsp, "Failed to read algorithm info: %d\n",
956 ret);
957 return ret;
958 }
959
960 buf = &adsp2_id;
961 buf_size = sizeof(adsp2_id);
962
963 algs = be32_to_cpu(adsp2_id.algs);
964 dsp->fw_id = be32_to_cpu(adsp2_id.fw.id);
965 adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
966 dsp->fw_id,
967 (be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16,
968 (be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8,
969 be32_to_cpu(adsp2_id.fw.ver) & 0xff,
970 algs);
971
972 region = kzalloc(sizeof(*region), GFP_KERNEL);
973 if (!region)
974 return -ENOMEM;
975 region->type = WMFW_ADSP2_XM;
976 region->alg = be32_to_cpu(adsp2_id.fw.id);
977 region->base = be32_to_cpu(adsp2_id.xm);
978 list_add_tail(&region->list, &dsp->alg_regions);
979
980 region = kzalloc(sizeof(*region), GFP_KERNEL);
981 if (!region)
982 return -ENOMEM;
983 region->type = WMFW_ADSP2_YM;
984 region->alg = be32_to_cpu(adsp2_id.fw.id);
985 region->base = be32_to_cpu(adsp2_id.ym);
986 list_add_tail(&region->list, &dsp->alg_regions);
987
988 region = kzalloc(sizeof(*region), GFP_KERNEL);
989 if (!region)
990 return -ENOMEM;
991 region->type = WMFW_ADSP2_ZM;
992 region->alg = be32_to_cpu(adsp2_id.fw.id);
993 region->base = be32_to_cpu(adsp2_id.zm);
994 list_add_tail(&region->list, &dsp->alg_regions);
995
996 pos = sizeof(adsp2_id) / 2;
997 term = pos + ((sizeof(*adsp2_alg) * algs) / 2);
998 break;
999
1000 default:
1001 WARN(1, "Unknown DSP type");
1002 return -EINVAL;
1003 }
1004
1005 if (algs == 0) {
1006 adsp_err(dsp, "No algorithms\n");
1007 return -EINVAL;
1008 }
1009
1010 if (algs > 1024) {
1011 adsp_err(dsp, "Algorithm count %zx excessive\n", algs);
1012 print_hex_dump_bytes(dev_name(dsp->dev), DUMP_PREFIX_OFFSET,
1013 buf, buf_size);
1014 return -EINVAL;
1015 }
1016
1017 /* Read the terminator first to validate the length */
1018 ret = regmap_raw_read(regmap, mem->base + term, &val, sizeof(val));
1019 if (ret != 0) { 1237 if (ret != 0) {
1020 adsp_err(dsp, "Failed to read algorithm list end: %d\n", 1238 adsp_err(dsp, "Failed to read algorithm info: %d\n",
1021 ret); 1239 ret);
1022 return ret; 1240 return ret;
1023 } 1241 }
1024 1242
1025 if (be32_to_cpu(val) != 0xbedead) 1243 n_algs = be32_to_cpu(adsp1_id.n_algs);
1026 adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n", 1244 dsp->fw_id = be32_to_cpu(adsp1_id.fw.id);
1027 term, be32_to_cpu(val)); 1245 adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
1028 1246 dsp->fw_id,
1029 alg = kzalloc((term - pos) * 2, GFP_KERNEL | GFP_DMA); 1247 (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16,
1030 if (!alg) 1248 (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8,
1031 return -ENOMEM; 1249 be32_to_cpu(adsp1_id.fw.ver) & 0xff,
1032 1250 n_algs);
1033 ret = regmap_raw_read(regmap, mem->base + pos, alg, (term - pos) * 2); 1251
1034 if (ret != 0) { 1252 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM,
1035 adsp_err(dsp, "Failed to read algorithm list: %d\n", 1253 adsp1_id.fw.id, adsp1_id.zm);
1036 ret); 1254 if (IS_ERR(alg_region))
1037 goto out; 1255 return PTR_ERR(alg_region);
1038 } 1256
1039 1257 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM,
1040 adsp1_alg = alg; 1258 adsp1_id.fw.id, adsp1_id.dm);
1041 adsp2_alg = alg; 1259 if (IS_ERR(alg_region))
1042 1260 return PTR_ERR(alg_region);
1043 for (i = 0; i < algs; i++) { 1261
1044 switch (dsp->type) { 1262 pos = sizeof(adsp1_id) / 2;
1045 case WMFW_ADSP1: 1263 len = (sizeof(*adsp1_alg) * n_algs) / 2;
1046 adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n", 1264
1047 i, be32_to_cpu(adsp1_alg[i].alg.id), 1265 adsp1_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len);
1048 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16, 1266 if (IS_ERR(adsp1_alg))
1049 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8, 1267 return PTR_ERR(adsp1_alg);
1050 be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff, 1268
1051 be32_to_cpu(adsp1_alg[i].dm), 1269 for (i = 0; i < n_algs; i++) {
1052 be32_to_cpu(adsp1_alg[i].zm)); 1270 adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
1053 1271 i, be32_to_cpu(adsp1_alg[i].alg.id),
1054 region = kzalloc(sizeof(*region), GFP_KERNEL); 1272 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16,
1055 if (!region) { 1273 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8,
1056 ret = -ENOMEM; 1274 be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff,
1057 goto out; 1275 be32_to_cpu(adsp1_alg[i].dm),
1058 } 1276 be32_to_cpu(adsp1_alg[i].zm));
1059 region->type = WMFW_ADSP1_DM; 1277
1060 region->alg = be32_to_cpu(adsp1_alg[i].alg.id); 1278 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM,
1061 region->base = be32_to_cpu(adsp1_alg[i].dm); 1279 adsp1_alg[i].alg.id,
1062 region->len = 0; 1280 adsp1_alg[i].dm);
1063 list_add_tail(&region->list, &dsp->alg_regions); 1281 if (IS_ERR(alg_region)) {
1064 if (i + 1 < algs) { 1282 ret = PTR_ERR(alg_region);
1065 region->len = be32_to_cpu(adsp1_alg[i + 1].dm); 1283 goto out;
1066 region->len -= be32_to_cpu(adsp1_alg[i].dm); 1284 }
1067 region->len *= 4; 1285 if (dsp->fw_ver == 0) {
1068 wm_adsp_create_control(dsp, region); 1286 if (i + 1 < n_algs) {
1287 len = be32_to_cpu(adsp1_alg[i + 1].dm);
1288 len -= be32_to_cpu(adsp1_alg[i].dm);
1289 len *= 4;
1290 wm_adsp_create_control(dsp, alg_region, 0,
1291 len, NULL, 0, 0);
1069 } else { 1292 } else {
1070 adsp_warn(dsp, "Missing length info for region DM with ID %x\n", 1293 adsp_warn(dsp, "Missing length info for region DM with ID %x\n",
1071 be32_to_cpu(adsp1_alg[i].alg.id)); 1294 be32_to_cpu(adsp1_alg[i].alg.id));
1072 } 1295 }
1296 }
1073 1297
1074 region = kzalloc(sizeof(*region), GFP_KERNEL); 1298 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM,
1075 if (!region) { 1299 adsp1_alg[i].alg.id,
1076 ret = -ENOMEM; 1300 adsp1_alg[i].zm);
1077 goto out; 1301 if (IS_ERR(alg_region)) {
1078 } 1302 ret = PTR_ERR(alg_region);
1079 region->type = WMFW_ADSP1_ZM; 1303 goto out;
1080 region->alg = be32_to_cpu(adsp1_alg[i].alg.id); 1304 }
1081 region->base = be32_to_cpu(adsp1_alg[i].zm); 1305 if (dsp->fw_ver == 0) {
1082 region->len = 0; 1306 if (i + 1 < n_algs) {
1083 list_add_tail(&region->list, &dsp->alg_regions); 1307 len = be32_to_cpu(adsp1_alg[i + 1].zm);
1084 if (i + 1 < algs) { 1308 len -= be32_to_cpu(adsp1_alg[i].zm);
1085 region->len = be32_to_cpu(adsp1_alg[i + 1].zm); 1309 len *= 4;
1086 region->len -= be32_to_cpu(adsp1_alg[i].zm); 1310 wm_adsp_create_control(dsp, alg_region, 0,
1087 region->len *= 4; 1311 len, NULL, 0, 0);
1088 wm_adsp_create_control(dsp, region);
1089 } else { 1312 } else {
1090 adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", 1313 adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
1091 be32_to_cpu(adsp1_alg[i].alg.id)); 1314 be32_to_cpu(adsp1_alg[i].alg.id));
1092 } 1315 }
1093 break; 1316 }
1317 }
1094 1318
1095 case WMFW_ADSP2: 1319out:
1096 adsp_info(dsp, 1320 kfree(adsp1_alg);
1097 "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n", 1321 return ret;
1098 i, be32_to_cpu(adsp2_alg[i].alg.id), 1322}
1099 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16, 1323
1100 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8, 1324static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
1101 be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff, 1325{
1102 be32_to_cpu(adsp2_alg[i].xm), 1326 struct wmfw_adsp2_id_hdr adsp2_id;
1103 be32_to_cpu(adsp2_alg[i].ym), 1327 struct wmfw_adsp2_alg_hdr *adsp2_alg;
1104 be32_to_cpu(adsp2_alg[i].zm)); 1328 struct wm_adsp_alg_region *alg_region;
1105 1329 const struct wm_adsp_region *mem;
1106 region = kzalloc(sizeof(*region), GFP_KERNEL); 1330 unsigned int pos, len;
1107 if (!region) { 1331 size_t n_algs;
1108 ret = -ENOMEM; 1332 int i, ret;
1109 goto out; 1333
1110 } 1334 mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
1111 region->type = WMFW_ADSP2_XM; 1335 if (WARN_ON(!mem))
1112 region->alg = be32_to_cpu(adsp2_alg[i].alg.id); 1336 return -EINVAL;
1113 region->base = be32_to_cpu(adsp2_alg[i].xm); 1337
1114 region->len = 0; 1338 ret = regmap_raw_read(dsp->regmap, mem->base, &adsp2_id,
1115 list_add_tail(&region->list, &dsp->alg_regions); 1339 sizeof(adsp2_id));
1116 if (i + 1 < algs) { 1340 if (ret != 0) {
1117 region->len = be32_to_cpu(adsp2_alg[i + 1].xm); 1341 adsp_err(dsp, "Failed to read algorithm info: %d\n",
1118 region->len -= be32_to_cpu(adsp2_alg[i].xm); 1342 ret);
1119 region->len *= 4; 1343 return ret;
1120 wm_adsp_create_control(dsp, region); 1344 }
1345
1346 n_algs = be32_to_cpu(adsp2_id.n_algs);
1347 dsp->fw_id = be32_to_cpu(adsp2_id.fw.id);
1348 adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
1349 dsp->fw_id,
1350 (be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16,
1351 (be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8,
1352 be32_to_cpu(adsp2_id.fw.ver) & 0xff,
1353 n_algs);
1354
1355 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM,
1356 adsp2_id.fw.id, adsp2_id.xm);
1357 if (IS_ERR(alg_region))
1358 return PTR_ERR(alg_region);
1359
1360 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM,
1361 adsp2_id.fw.id, adsp2_id.ym);
1362 if (IS_ERR(alg_region))
1363 return PTR_ERR(alg_region);
1364
1365 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM,
1366 adsp2_id.fw.id, adsp2_id.zm);
1367 if (IS_ERR(alg_region))
1368 return PTR_ERR(alg_region);
1369
1370 pos = sizeof(adsp2_id) / 2;
1371 len = (sizeof(*adsp2_alg) * n_algs) / 2;
1372
1373 adsp2_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len);
1374 if (IS_ERR(adsp2_alg))
1375 return PTR_ERR(adsp2_alg);
1376
1377 for (i = 0; i < n_algs; i++) {
1378 adsp_info(dsp,
1379 "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
1380 i, be32_to_cpu(adsp2_alg[i].alg.id),
1381 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
1382 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
1383 be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
1384 be32_to_cpu(adsp2_alg[i].xm),
1385 be32_to_cpu(adsp2_alg[i].ym),
1386 be32_to_cpu(adsp2_alg[i].zm));
1387
1388 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM,
1389 adsp2_alg[i].alg.id,
1390 adsp2_alg[i].xm);
1391 if (IS_ERR(alg_region)) {
1392 ret = PTR_ERR(alg_region);
1393 goto out;
1394 }
1395 if (dsp->fw_ver == 0) {
1396 if (i + 1 < n_algs) {
1397 len = be32_to_cpu(adsp2_alg[i + 1].xm);
1398 len -= be32_to_cpu(adsp2_alg[i].xm);
1399 len *= 4;
1400 wm_adsp_create_control(dsp, alg_region, 0,
1401 len, NULL, 0, 0);
1121 } else { 1402 } else {
1122 adsp_warn(dsp, "Missing length info for region XM with ID %x\n", 1403 adsp_warn(dsp, "Missing length info for region XM with ID %x\n",
1123 be32_to_cpu(adsp2_alg[i].alg.id)); 1404 be32_to_cpu(adsp2_alg[i].alg.id));
1124 } 1405 }
1406 }
1125 1407
1126 region = kzalloc(sizeof(*region), GFP_KERNEL); 1408 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM,
1127 if (!region) { 1409 adsp2_alg[i].alg.id,
1128 ret = -ENOMEM; 1410 adsp2_alg[i].ym);
1129 goto out; 1411 if (IS_ERR(alg_region)) {
1130 } 1412 ret = PTR_ERR(alg_region);
1131 region->type = WMFW_ADSP2_YM; 1413 goto out;
1132 region->alg = be32_to_cpu(adsp2_alg[i].alg.id); 1414 }
1133 region->base = be32_to_cpu(adsp2_alg[i].ym); 1415 if (dsp->fw_ver == 0) {
1134 region->len = 0; 1416 if (i + 1 < n_algs) {
1135 list_add_tail(&region->list, &dsp->alg_regions); 1417 len = be32_to_cpu(adsp2_alg[i + 1].ym);
1136 if (i + 1 < algs) { 1418 len -= be32_to_cpu(adsp2_alg[i].ym);
1137 region->len = be32_to_cpu(adsp2_alg[i + 1].ym); 1419 len *= 4;
1138 region->len -= be32_to_cpu(adsp2_alg[i].ym); 1420 wm_adsp_create_control(dsp, alg_region, 0,
1139 region->len *= 4; 1421 len, NULL, 0, 0);
1140 wm_adsp_create_control(dsp, region);
1141 } else { 1422 } else {
1142 adsp_warn(dsp, "Missing length info for region YM with ID %x\n", 1423 adsp_warn(dsp, "Missing length info for region YM with ID %x\n",
1143 be32_to_cpu(adsp2_alg[i].alg.id)); 1424 be32_to_cpu(adsp2_alg[i].alg.id));
1144 } 1425 }
1426 }
1145 1427
1146 region = kzalloc(sizeof(*region), GFP_KERNEL); 1428 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM,
1147 if (!region) { 1429 adsp2_alg[i].alg.id,
1148 ret = -ENOMEM; 1430 adsp2_alg[i].zm);
1149 goto out; 1431 if (IS_ERR(alg_region)) {
1150 } 1432 ret = PTR_ERR(alg_region);
1151 region->type = WMFW_ADSP2_ZM; 1433 goto out;
1152 region->alg = be32_to_cpu(adsp2_alg[i].alg.id); 1434 }
1153 region->base = be32_to_cpu(adsp2_alg[i].zm); 1435 if (dsp->fw_ver == 0) {
1154 region->len = 0; 1436 if (i + 1 < n_algs) {
1155 list_add_tail(&region->list, &dsp->alg_regions); 1437 len = be32_to_cpu(adsp2_alg[i + 1].zm);
1156 if (i + 1 < algs) { 1438 len -= be32_to_cpu(adsp2_alg[i].zm);
1157 region->len = be32_to_cpu(adsp2_alg[i + 1].zm); 1439 len *= 4;
1158 region->len -= be32_to_cpu(adsp2_alg[i].zm); 1440 wm_adsp_create_control(dsp, alg_region, 0,
1159 region->len *= 4; 1441 len, NULL, 0, 0);
1160 wm_adsp_create_control(dsp, region);
1161 } else { 1442 } else {
1162 adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", 1443 adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
1163 be32_to_cpu(adsp2_alg[i].alg.id)); 1444 be32_to_cpu(adsp2_alg[i].alg.id));
1164 } 1445 }
1165 break;
1166 } 1446 }
1167 } 1447 }
1168 1448
1169out: 1449out:
1170 kfree(alg); 1450 kfree(adsp2_alg);
1171 return ret; 1451 return ret;
1172} 1452}
1173 1453
@@ -1354,9 +1634,9 @@ out:
1354 return ret; 1634 return ret;
1355} 1635}
1356 1636
1357int wm_adsp1_init(struct wm_adsp *adsp) 1637int wm_adsp1_init(struct wm_adsp *dsp)
1358{ 1638{
1359 INIT_LIST_HEAD(&adsp->alg_regions); 1639 INIT_LIST_HEAD(&dsp->alg_regions);
1360 1640
1361 return 0; 1641 return 0;
1362} 1642}
@@ -1410,7 +1690,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
1410 if (ret != 0) 1690 if (ret != 0)
1411 goto err; 1691 goto err;
1412 1692
1413 ret = wm_adsp_setup_algs(dsp); 1693 ret = wm_adsp1_setup_algs(dsp);
1414 if (ret != 0) 1694 if (ret != 0)
1415 goto err; 1695 goto err;
1416 1696
@@ -1568,7 +1848,7 @@ static void wm_adsp2_boot_work(struct work_struct *work)
1568 if (ret != 0) 1848 if (ret != 0)
1569 goto err; 1849 goto err;
1570 1850
1571 ret = wm_adsp_setup_algs(dsp); 1851 ret = wm_adsp2_setup_algs(dsp);
1572 if (ret != 0) 1852 if (ret != 0)
1573 goto err; 1853 goto err;
1574 1854
@@ -1642,6 +1922,9 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
1642 break; 1922 break;
1643 1923
1644 case SND_SOC_DAPM_PRE_PMD: 1924 case SND_SOC_DAPM_PRE_PMD:
1925 /* Log firmware state, it can be useful for analysis */
1926 wm_adsp2_show_fw_status(dsp);
1927
1645 dsp->running = false; 1928 dsp->running = false;
1646 1929
1647 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 1930 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
@@ -1694,7 +1977,7 @@ err:
1694} 1977}
1695EXPORT_SYMBOL_GPL(wm_adsp2_event); 1978EXPORT_SYMBOL_GPL(wm_adsp2_event);
1696 1979
1697int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs) 1980int wm_adsp2_init(struct wm_adsp *dsp, bool dvfs)
1698{ 1981{
1699 int ret; 1982 int ret;
1700 1983
@@ -1702,40 +1985,40 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs)
1702 * Disable the DSP memory by default when in reset for a small 1985 * Disable the DSP memory by default when in reset for a small
1703 * power saving. 1986 * power saving.
1704 */ 1987 */
1705 ret = regmap_update_bits(adsp->regmap, adsp->base + ADSP2_CONTROL, 1988 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
1706 ADSP2_MEM_ENA, 0); 1989 ADSP2_MEM_ENA, 0);
1707 if (ret != 0) { 1990 if (ret != 0) {
1708 adsp_err(adsp, "Failed to clear memory retention: %d\n", ret); 1991 adsp_err(dsp, "Failed to clear memory retention: %d\n", ret);
1709 return ret; 1992 return ret;
1710 } 1993 }
1711 1994
1712 INIT_LIST_HEAD(&adsp->alg_regions); 1995 INIT_LIST_HEAD(&dsp->alg_regions);
1713 INIT_LIST_HEAD(&adsp->ctl_list); 1996 INIT_LIST_HEAD(&dsp->ctl_list);
1714 INIT_WORK(&adsp->boot_work, wm_adsp2_boot_work); 1997 INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work);
1715 1998
1716 if (dvfs) { 1999 if (dvfs) {
1717 adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD"); 2000 dsp->dvfs = devm_regulator_get(dsp->dev, "DCVDD");
1718 if (IS_ERR(adsp->dvfs)) { 2001 if (IS_ERR(dsp->dvfs)) {
1719 ret = PTR_ERR(adsp->dvfs); 2002 ret = PTR_ERR(dsp->dvfs);
1720 adsp_err(adsp, "Failed to get DCVDD: %d\n", ret); 2003 adsp_err(dsp, "Failed to get DCVDD: %d\n", ret);
1721 return ret; 2004 return ret;
1722 } 2005 }
1723 2006
1724 ret = regulator_enable(adsp->dvfs); 2007 ret = regulator_enable(dsp->dvfs);
1725 if (ret != 0) { 2008 if (ret != 0) {
1726 adsp_err(adsp, "Failed to enable DCVDD: %d\n", ret); 2009 adsp_err(dsp, "Failed to enable DCVDD: %d\n", ret);
1727 return ret; 2010 return ret;
1728 } 2011 }
1729 2012
1730 ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000); 2013 ret = regulator_set_voltage(dsp->dvfs, 1200000, 1800000);
1731 if (ret != 0) { 2014 if (ret != 0) {
1732 adsp_err(adsp, "Failed to initialise DVFS: %d\n", ret); 2015 adsp_err(dsp, "Failed to initialise DVFS: %d\n", ret);
1733 return ret; 2016 return ret;
1734 } 2017 }
1735 2018
1736 ret = regulator_disable(adsp->dvfs); 2019 ret = regulator_disable(dsp->dvfs);
1737 if (ret != 0) { 2020 if (ret != 0) {
1738 adsp_err(adsp, "Failed to disable DCVDD: %d\n", ret); 2021 adsp_err(dsp, "Failed to disable DCVDD: %d\n", ret);
1739 return ret; 2022 return ret;
1740 } 2023 }
1741 } 2024 }
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
index a4f6b64deb61..4fe066745377 100644
--- a/sound/soc/codecs/wm_adsp.h
+++ b/sound/soc/codecs/wm_adsp.h
@@ -30,7 +30,6 @@ struct wm_adsp_alg_region {
30 unsigned int alg; 30 unsigned int alg;
31 int type; 31 int type;
32 unsigned int base; 32 unsigned int base;
33 size_t len;
34}; 33};
35 34
36struct wm_adsp { 35struct wm_adsp {
@@ -54,6 +53,7 @@ struct wm_adsp {
54 int num_mems; 53 int num_mems;
55 54
56 int fw; 55 int fw;
56 int fw_ver;
57 bool running; 57 bool running;
58 58
59 struct regulator *dvfs; 59 struct regulator *dvfs;
@@ -78,8 +78,8 @@ struct wm_adsp {
78extern const struct snd_kcontrol_new wm_adsp1_fw_controls[]; 78extern const struct snd_kcontrol_new wm_adsp1_fw_controls[];
79extern const struct snd_kcontrol_new wm_adsp2_fw_controls[]; 79extern const struct snd_kcontrol_new wm_adsp2_fw_controls[];
80 80
81int wm_adsp1_init(struct wm_adsp *adsp); 81int wm_adsp1_init(struct wm_adsp *dsp);
82int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs); 82int wm_adsp2_init(struct wm_adsp *dsp, bool dvfs);
83int wm_adsp1_event(struct snd_soc_dapm_widget *w, 83int wm_adsp1_event(struct snd_soc_dapm_widget *w,
84 struct snd_kcontrol *kcontrol, int event); 84 struct snd_kcontrol *kcontrol, int event);
85int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, 85int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
diff --git a/sound/soc/codecs/wmfw.h b/sound/soc/codecs/wmfw.h
index ef163360a745..7613d60d62ea 100644
--- a/sound/soc/codecs/wmfw.h
+++ b/sound/soc/codecs/wmfw.h
@@ -15,6 +15,17 @@
15 15
16#include <linux/types.h> 16#include <linux/types.h>
17 17
18#define WMFW_MAX_ALG_NAME 256
19#define WMFW_MAX_ALG_DESCR_NAME 256
20
21#define WMFW_MAX_COEFF_NAME 256
22#define WMFW_MAX_COEFF_DESCR_NAME 256
23
24#define WMFW_CTL_FLAG_SYS 0x8000
25#define WMFW_CTL_FLAG_VOLATILE 0x0004
26#define WMFW_CTL_FLAG_WRITEABLE 0x0002
27#define WMFW_CTL_FLAG_READABLE 0x0001
28
18struct wmfw_header { 29struct wmfw_header {
19 char magic[4]; 30 char magic[4];
20 __le32 len; 31 __le32 len;
@@ -61,7 +72,7 @@ struct wmfw_adsp1_id_hdr {
61 struct wmfw_id_hdr fw; 72 struct wmfw_id_hdr fw;
62 __be32 zm; 73 __be32 zm;
63 __be32 dm; 74 __be32 dm;
64 __be32 algs; 75 __be32 n_algs;
65} __packed; 76} __packed;
66 77
67struct wmfw_adsp2_id_hdr { 78struct wmfw_adsp2_id_hdr {
@@ -69,7 +80,7 @@ struct wmfw_adsp2_id_hdr {
69 __be32 zm; 80 __be32 zm;
70 __be32 xm; 81 __be32 xm;
71 __be32 ym; 82 __be32 ym;
72 __be32 algs; 83 __be32 n_algs;
73} __packed; 84} __packed;
74 85
75struct wmfw_alg_hdr { 86struct wmfw_alg_hdr {
@@ -90,6 +101,28 @@ struct wmfw_adsp2_alg_hdr {
90 __be32 ym; 101 __be32 ym;
91} __packed; 102} __packed;
92 103
104struct wmfw_adsp_alg_data {
105 __le32 id;
106 u8 name[WMFW_MAX_ALG_NAME];
107 u8 descr[WMFW_MAX_ALG_DESCR_NAME];
108 __le32 ncoeff;
109 u8 data[];
110} __packed;
111
112struct wmfw_adsp_coeff_data {
113 struct {
114 __le16 offset;
115 __le16 type;
116 __le32 size;
117 } hdr;
118 u8 name[WMFW_MAX_COEFF_NAME];
119 u8 descr[WMFW_MAX_COEFF_DESCR_NAME];
120 __le16 ctl_type;
121 __le16 flags;
122 __le32 len;
123 u8 data[];
124} __packed;
125
93struct wmfw_coeff_hdr { 126struct wmfw_coeff_hdr {
94 u8 magic[4]; 127 u8 magic[4];
95 __le32 len; 128 __le32 len;
@@ -117,9 +150,10 @@ struct wmfw_coeff_item {
117#define WMFW_ADSP1 1 150#define WMFW_ADSP1 1
118#define WMFW_ADSP2 2 151#define WMFW_ADSP2 2
119 152
120#define WMFW_ABSOLUTE 0xf0 153#define WMFW_ABSOLUTE 0xf0
121#define WMFW_NAME_TEXT 0xfe 154#define WMFW_ALGORITHM_DATA 0xf2
122#define WMFW_INFO_TEXT 0xff 155#define WMFW_NAME_TEXT 0xfe
156#define WMFW_INFO_TEXT 0xff
123 157
124#define WMFW_ADSP1_PM 2 158#define WMFW_ADSP1_PM 2
125#define WMFW_ADSP1_DM 3 159#define WMFW_ADSP1_DM 3