diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/codecs/wm_adsp.c | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index ffc89fab96fb..990403b162fe 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c | |||
@@ -350,6 +350,141 @@ out: | |||
350 | return ret; | 350 | return ret; |
351 | } | 351 | } |
352 | 352 | ||
353 | static int wm_adsp_setup_algs(struct wm_adsp *dsp) | ||
354 | { | ||
355 | struct regmap *regmap = dsp->regmap; | ||
356 | struct wmfw_adsp1_id_hdr adsp1_id; | ||
357 | struct wmfw_adsp2_id_hdr adsp2_id; | ||
358 | struct wmfw_adsp1_alg_hdr *adsp1_alg; | ||
359 | struct wmfw_adsp2_alg_hdr *adsp2_alg; | ||
360 | void *alg; | ||
361 | const struct wm_adsp_region *mem; | ||
362 | unsigned int pos, term; | ||
363 | size_t algs; | ||
364 | __be32 val; | ||
365 | int i, ret; | ||
366 | |||
367 | switch (dsp->type) { | ||
368 | case WMFW_ADSP1: | ||
369 | mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM); | ||
370 | break; | ||
371 | case WMFW_ADSP2: | ||
372 | mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM); | ||
373 | break; | ||
374 | default: | ||
375 | mem = NULL; | ||
376 | break; | ||
377 | } | ||
378 | |||
379 | if (mem == NULL) { | ||
380 | BUG_ON(mem != NULL); | ||
381 | return -EINVAL; | ||
382 | } | ||
383 | |||
384 | switch (dsp->type) { | ||
385 | case WMFW_ADSP1: | ||
386 | ret = regmap_raw_read(regmap, mem->base, &adsp1_id, | ||
387 | sizeof(adsp1_id)); | ||
388 | if (ret != 0) { | ||
389 | adsp_err(dsp, "Failed to read algorithm info: %d\n", | ||
390 | ret); | ||
391 | return ret; | ||
392 | } | ||
393 | |||
394 | algs = be32_to_cpu(adsp1_id.algs); | ||
395 | adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", | ||
396 | be32_to_cpu(adsp1_id.fw.id), | ||
397 | (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16, | ||
398 | (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8, | ||
399 | be32_to_cpu(adsp1_id.fw.ver) & 0xff, | ||
400 | algs); | ||
401 | |||
402 | pos = sizeof(adsp1_id) / 2; | ||
403 | term = pos + ((sizeof(*adsp1_alg) * algs) / 2); | ||
404 | break; | ||
405 | |||
406 | case WMFW_ADSP2: | ||
407 | ret = regmap_raw_read(regmap, mem->base, &adsp2_id, | ||
408 | sizeof(adsp2_id)); | ||
409 | if (ret != 0) { | ||
410 | adsp_err(dsp, "Failed to read algorithm info: %d\n", | ||
411 | ret); | ||
412 | return ret; | ||
413 | } | ||
414 | |||
415 | algs = be32_to_cpu(adsp2_id.algs); | ||
416 | adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", | ||
417 | be32_to_cpu(adsp2_id.fw.id), | ||
418 | (be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16, | ||
419 | (be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8, | ||
420 | be32_to_cpu(adsp2_id.fw.ver) & 0xff, | ||
421 | algs); | ||
422 | |||
423 | pos = sizeof(adsp2_id) / 2; | ||
424 | term = pos + ((sizeof(*adsp2_alg) * algs) / 2); | ||
425 | break; | ||
426 | |||
427 | default: | ||
428 | BUG_ON(NULL == "Unknown DSP type"); | ||
429 | return -EINVAL; | ||
430 | } | ||
431 | |||
432 | if (algs == 0) { | ||
433 | adsp_err(dsp, "No algorithms\n"); | ||
434 | return -EINVAL; | ||
435 | } | ||
436 | |||
437 | /* Read the terminator first to validate the length */ | ||
438 | ret = regmap_raw_read(regmap, mem->base + term, &val, sizeof(val)); | ||
439 | if (ret != 0) { | ||
440 | adsp_err(dsp, "Failed to read algorithm list end: %d\n", | ||
441 | ret); | ||
442 | return ret; | ||
443 | } | ||
444 | |||
445 | if (be32_to_cpu(val) != 0xbedead) | ||
446 | adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n", | ||
447 | term, be32_to_cpu(val)); | ||
448 | |||
449 | alg = kzalloc((term - pos) * 2, GFP_KERNEL); | ||
450 | if (!alg) | ||
451 | return -ENOMEM; | ||
452 | |||
453 | ret = regmap_raw_read(regmap, mem->base + pos, alg, (term - pos) * 2); | ||
454 | if (ret != 0) { | ||
455 | adsp_err(dsp, "Failed to read algorithm list: %d\n", | ||
456 | ret); | ||
457 | goto out; | ||
458 | } | ||
459 | |||
460 | adsp1_alg = alg; | ||
461 | adsp2_alg = alg; | ||
462 | |||
463 | for (i = 0; i < algs; i++) { | ||
464 | switch (dsp->type) { | ||
465 | case WMFW_ADSP1: | ||
466 | adsp_info(dsp, "%d: ID %x v%d.%d.%d\n", | ||
467 | i, be32_to_cpu(adsp1_alg[i].alg.id), | ||
468 | (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16, | ||
469 | (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8, | ||
470 | be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff); | ||
471 | break; | ||
472 | |||
473 | case WMFW_ADSP2: | ||
474 | adsp_info(dsp, "%d: ID %x v%d.%d.%d\n", | ||
475 | i, be32_to_cpu(adsp2_alg[i].alg.id), | ||
476 | (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16, | ||
477 | (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8, | ||
478 | be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff); | ||
479 | break; | ||
480 | } | ||
481 | } | ||
482 | |||
483 | out: | ||
484 | kfree(alg); | ||
485 | return ret; | ||
486 | } | ||
487 | |||
353 | static int wm_adsp_load_coeff(struct wm_adsp *dsp) | 488 | static int wm_adsp_load_coeff(struct wm_adsp *dsp) |
354 | { | 489 | { |
355 | struct regmap *regmap = dsp->regmap; | 490 | struct regmap *regmap = dsp->regmap; |
@@ -468,6 +603,10 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, | |||
468 | if (ret != 0) | 603 | if (ret != 0) |
469 | goto err; | 604 | goto err; |
470 | 605 | ||
606 | ret = wm_adsp_setup_algs(dsp); | ||
607 | if (ret != 0) | ||
608 | goto err; | ||
609 | |||
471 | ret = wm_adsp_load_coeff(dsp); | 610 | ret = wm_adsp_load_coeff(dsp); |
472 | if (ret != 0) | 611 | if (ret != 0) |
473 | goto err; | 612 | goto err; |
@@ -604,6 +743,10 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
604 | if (ret != 0) | 743 | if (ret != 0) |
605 | goto err; | 744 | goto err; |
606 | 745 | ||
746 | ret = wm_adsp_setup_algs(dsp); | ||
747 | if (ret != 0) | ||
748 | goto err; | ||
749 | |||
607 | ret = wm_adsp_load_coeff(dsp); | 750 | ret = wm_adsp_load_coeff(dsp); |
608 | if (ret != 0) | 751 | if (ret != 0) |
609 | goto err; | 752 | goto err; |