diff options
author | Mark Brown <broonie@kernel.org> | 2015-04-12 14:48:33 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2015-04-12 14:48:33 -0400 |
commit | aab0bb17ef2440ef5f68dcde5f1a6b32dcdfa9fb (patch) | |
tree | 6e14e997a1424e189d47ec04f4b1e1b8e6d85491 | |
parent | 77b62fa5d23988155132cf7fee44f2c209e3dc4c (diff) | |
parent | a5e5e12bd4ed5cd1123ace4300b5c07230fbf21e (diff) |
Merge remote-tracking branch 'asoc/topic/intel' into asoc-next
-rw-r--r-- | include/sound/rt5670.h | 1 | ||||
-rw-r--r-- | sound/soc/codecs/rt5670.c | 213 | ||||
-rw-r--r-- | sound/soc/codecs/rt5670.h | 7 | ||||
-rw-r--r-- | sound/soc/intel/Makefile | 42 | ||||
-rw-r--r-- | sound/soc/intel/atom/Makefile | 7 | ||||
-rw-r--r-- | sound/soc/intel/atom/sst-atom-controls.c (renamed from sound/soc/intel/sst-atom-controls.c) | 0 | ||||
-rw-r--r-- | sound/soc/intel/atom/sst-atom-controls.h (renamed from sound/soc/intel/sst-atom-controls.h) | 0 | ||||
-rw-r--r-- | sound/soc/intel/atom/sst-mfld-dsp.h (renamed from sound/soc/intel/sst-mfld-dsp.h) | 0 | ||||
-rw-r--r-- | sound/soc/intel/atom/sst-mfld-platform-compress.c (renamed from sound/soc/intel/sst-mfld-platform-compress.c) | 0 | ||||
-rw-r--r-- | sound/soc/intel/atom/sst-mfld-platform-pcm.c (renamed from sound/soc/intel/sst-mfld-platform-pcm.c) | 0 | ||||
-rw-r--r-- | sound/soc/intel/atom/sst-mfld-platform.h (renamed from sound/soc/intel/sst-mfld-platform.h) | 0 | ||||
-rw-r--r-- | sound/soc/intel/atom/sst/Makefile (renamed from sound/soc/intel/sst/Makefile) | 0 | ||||
-rw-r--r-- | sound/soc/intel/atom/sst/sst.c (renamed from sound/soc/intel/sst/sst.c) | 2 | ||||
-rw-r--r-- | sound/soc/intel/atom/sst/sst.h (renamed from sound/soc/intel/sst/sst.h) | 0 | ||||
-rw-r--r-- | sound/soc/intel/atom/sst/sst_acpi.c (renamed from sound/soc/intel/sst/sst_acpi.c) | 2 | ||||
-rw-r--r-- | sound/soc/intel/atom/sst/sst_drv_interface.c (renamed from sound/soc/intel/sst/sst_drv_interface.c) | 4 | ||||
-rw-r--r-- | sound/soc/intel/atom/sst/sst_ipc.c (renamed from sound/soc/intel/sst/sst_ipc.c) | 2 | ||||
-rw-r--r-- | sound/soc/intel/atom/sst/sst_loader.c (renamed from sound/soc/intel/sst/sst_loader.c) | 2 | ||||
-rw-r--r-- | sound/soc/intel/atom/sst/sst_pci.c (renamed from sound/soc/intel/sst/sst_pci.c) | 0 | ||||
-rw-r--r-- | sound/soc/intel/atom/sst/sst_pvt.c (renamed from sound/soc/intel/sst/sst_pvt.c) | 26 | ||||
-rw-r--r-- | sound/soc/intel/atom/sst/sst_stream.c (renamed from sound/soc/intel/sst/sst_stream.c) | 2 | ||||
-rw-r--r-- | sound/soc/intel/baytrail/Makefile | 4 | ||||
-rw-r--r-- | sound/soc/intel/baytrail/sst-baytrail-dsp.c (renamed from sound/soc/intel/sst-baytrail-dsp.c) | 4 | ||||
-rw-r--r-- | sound/soc/intel/baytrail/sst-baytrail-ipc.c (renamed from sound/soc/intel/sst-baytrail-ipc.c) | 364 | ||||
-rw-r--r-- | sound/soc/intel/baytrail/sst-baytrail-ipc.h (renamed from sound/soc/intel/sst-baytrail-ipc.h) | 0 | ||||
-rw-r--r-- | sound/soc/intel/baytrail/sst-baytrail-pcm.c (renamed from sound/soc/intel/sst-baytrail-pcm.c) | 4 | ||||
-rw-r--r-- | sound/soc/intel/boards/Makefile | 15 | ||||
-rw-r--r-- | sound/soc/intel/boards/broadwell.c (renamed from sound/soc/intel/broadwell.c) | 34 | ||||
-rw-r--r-- | sound/soc/intel/boards/byt-max98090.c (renamed from sound/soc/intel/byt-max98090.c) | 2 | ||||
-rw-r--r-- | sound/soc/intel/boards/byt-rt5640.c (renamed from sound/soc/intel/byt-rt5640.c) | 4 | ||||
-rw-r--r-- | sound/soc/intel/boards/bytcr_rt5640.c (renamed from sound/soc/intel/bytcr_dpcm_rt5640.c) | 4 | ||||
-rw-r--r-- | sound/soc/intel/boards/cht_bsw_rt5645.c (renamed from sound/soc/intel/cht_bsw_rt5645.c) | 4 | ||||
-rw-r--r-- | sound/soc/intel/boards/cht_bsw_rt5672.c (renamed from sound/soc/intel/cht_bsw_rt5672.c) | 99 | ||||
-rw-r--r-- | sound/soc/intel/boards/haswell.c (renamed from sound/soc/intel/haswell.c) | 6 | ||||
-rw-r--r-- | sound/soc/intel/boards/mfld_machine.c (renamed from sound/soc/intel/mfld_machine.c) | 0 | ||||
-rw-r--r-- | sound/soc/intel/common/Makefile | 7 | ||||
-rw-r--r-- | sound/soc/intel/common/sst-acpi.c (renamed from sound/soc/intel/sst-acpi.c) | 0 | ||||
-rw-r--r-- | sound/soc/intel/common/sst-dsp-priv.h (renamed from sound/soc/intel/sst-dsp-priv.h) | 13 | ||||
-rw-r--r-- | sound/soc/intel/common/sst-dsp.c (renamed from sound/soc/intel/sst-dsp.c) | 0 | ||||
-rw-r--r-- | sound/soc/intel/common/sst-dsp.h (renamed from sound/soc/intel/sst-dsp.h) | 1 | ||||
-rw-r--r-- | sound/soc/intel/common/sst-firmware.c (renamed from sound/soc/intel/sst-firmware.c) | 6 | ||||
-rw-r--r-- | sound/soc/intel/common/sst-ipc.c | 294 | ||||
-rw-r--r-- | sound/soc/intel/common/sst-ipc.h | 91 | ||||
-rw-r--r-- | sound/soc/intel/haswell/Makefile | 4 | ||||
-rw-r--r-- | sound/soc/intel/haswell/sst-haswell-dsp.c (renamed from sound/soc/intel/sst-haswell-dsp.c) | 9 | ||||
-rw-r--r-- | sound/soc/intel/haswell/sst-haswell-ipc.c (renamed from sound/soc/intel/sst-haswell-ipc.c) | 794 | ||||
-rw-r--r-- | sound/soc/intel/haswell/sst-haswell-ipc.h (renamed from sound/soc/intel/sst-haswell-ipc.h) | 53 | ||||
-rw-r--r-- | sound/soc/intel/haswell/sst-haswell-pcm.c (renamed from sound/soc/intel/sst-haswell-pcm.c) | 140 |
48 files changed, 1554 insertions, 712 deletions
diff --git a/include/sound/rt5670.h b/include/sound/rt5670.h index bd311197a3b5..b7d60510819b 100644 --- a/include/sound/rt5670.h +++ b/include/sound/rt5670.h | |||
@@ -14,6 +14,7 @@ | |||
14 | struct rt5670_platform_data { | 14 | struct rt5670_platform_data { |
15 | int jd_mode; | 15 | int jd_mode; |
16 | bool in2_diff; | 16 | bool in2_diff; |
17 | bool dev_gpio; | ||
17 | 18 | ||
18 | bool dmic_en; | 19 | bool dmic_en; |
19 | unsigned int dmic1_data_pin; | 20 | unsigned int dmic1_data_pin; |
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index fd102613d20d..cc7f84a150a7 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c | |||
@@ -403,6 +403,189 @@ static bool rt5670_readable_register(struct device *dev, unsigned int reg) | |||
403 | } | 403 | } |
404 | } | 404 | } |
405 | 405 | ||
406 | /** | ||
407 | * rt5670_headset_detect - Detect headset. | ||
408 | * @codec: SoC audio codec device. | ||
409 | * @jack_insert: Jack insert or not. | ||
410 | * | ||
411 | * Detect whether is headset or not when jack inserted. | ||
412 | * | ||
413 | * Returns detect status. | ||
414 | */ | ||
415 | |||
416 | static int rt5670_headset_detect(struct snd_soc_codec *codec, int jack_insert) | ||
417 | { | ||
418 | int val; | ||
419 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); | ||
420 | |||
421 | if (jack_insert) { | ||
422 | snd_soc_dapm_force_enable_pin(&codec->dapm, | ||
423 | "Mic Det Power"); | ||
424 | snd_soc_dapm_sync(&codec->dapm); | ||
425 | snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x0); | ||
426 | snd_soc_update_bits(codec, RT5670_CJ_CTRL2, | ||
427 | RT5670_CBJ_DET_MODE | RT5670_CBJ_MN_JD, | ||
428 | RT5670_CBJ_MN_JD); | ||
429 | snd_soc_write(codec, RT5670_GPIO_CTRL2, 0x0004); | ||
430 | snd_soc_update_bits(codec, RT5670_GPIO_CTRL1, | ||
431 | RT5670_GP1_PIN_MASK, RT5670_GP1_PIN_IRQ); | ||
432 | snd_soc_update_bits(codec, RT5670_CJ_CTRL1, | ||
433 | RT5670_CBJ_BST1_EN, RT5670_CBJ_BST1_EN); | ||
434 | snd_soc_write(codec, RT5670_JD_CTRL3, 0x00f0); | ||
435 | snd_soc_update_bits(codec, RT5670_CJ_CTRL2, | ||
436 | RT5670_CBJ_MN_JD, RT5670_CBJ_MN_JD); | ||
437 | snd_soc_update_bits(codec, RT5670_CJ_CTRL2, | ||
438 | RT5670_CBJ_MN_JD, 0); | ||
439 | msleep(300); | ||
440 | val = snd_soc_read(codec, RT5670_CJ_CTRL3) & 0x7; | ||
441 | if (val == 0x1 || val == 0x2) { | ||
442 | rt5670->jack_type = SND_JACK_HEADSET; | ||
443 | /* for push button */ | ||
444 | snd_soc_update_bits(codec, RT5670_INT_IRQ_ST, 0x8, 0x8); | ||
445 | snd_soc_update_bits(codec, RT5670_IL_CMD, 0x40, 0x40); | ||
446 | snd_soc_read(codec, RT5670_IL_CMD); | ||
447 | } else { | ||
448 | snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x4); | ||
449 | rt5670->jack_type = SND_JACK_HEADPHONE; | ||
450 | snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power"); | ||
451 | snd_soc_dapm_sync(&codec->dapm); | ||
452 | } | ||
453 | } else { | ||
454 | snd_soc_update_bits(codec, RT5670_INT_IRQ_ST, 0x8, 0x0); | ||
455 | snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x4); | ||
456 | rt5670->jack_type = 0; | ||
457 | snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power"); | ||
458 | snd_soc_dapm_sync(&codec->dapm); | ||
459 | } | ||
460 | |||
461 | return rt5670->jack_type; | ||
462 | } | ||
463 | |||
464 | void rt5670_jack_suspend(struct snd_soc_codec *codec) | ||
465 | { | ||
466 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); | ||
467 | |||
468 | rt5670->jack_type_saved = rt5670->jack_type; | ||
469 | rt5670_headset_detect(codec, 0); | ||
470 | } | ||
471 | EXPORT_SYMBOL_GPL(rt5670_jack_suspend); | ||
472 | |||
473 | void rt5670_jack_resume(struct snd_soc_codec *codec) | ||
474 | { | ||
475 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); | ||
476 | |||
477 | if (rt5670->jack_type_saved) | ||
478 | rt5670_headset_detect(codec, 1); | ||
479 | } | ||
480 | EXPORT_SYMBOL_GPL(rt5670_jack_resume); | ||
481 | |||
482 | static int rt5670_button_detect(struct snd_soc_codec *codec) | ||
483 | { | ||
484 | int btn_type, val; | ||
485 | |||
486 | val = snd_soc_read(codec, RT5670_IL_CMD); | ||
487 | btn_type = val & 0xff80; | ||
488 | snd_soc_write(codec, RT5670_IL_CMD, val); | ||
489 | if (btn_type != 0) { | ||
490 | msleep(20); | ||
491 | val = snd_soc_read(codec, RT5670_IL_CMD); | ||
492 | snd_soc_write(codec, RT5670_IL_CMD, val); | ||
493 | } | ||
494 | |||
495 | return btn_type; | ||
496 | } | ||
497 | |||
498 | static int rt5670_irq_detection(void *data) | ||
499 | { | ||
500 | struct rt5670_priv *rt5670 = (struct rt5670_priv *)data; | ||
501 | struct snd_soc_jack_gpio *gpio = &rt5670->hp_gpio; | ||
502 | struct snd_soc_jack *jack = rt5670->jack; | ||
503 | int val, btn_type, report = jack->status; | ||
504 | |||
505 | if (rt5670->pdata.jd_mode == 1) /* 2 port */ | ||
506 | val = snd_soc_read(rt5670->codec, RT5670_A_JD_CTRL1) & 0x0070; | ||
507 | else | ||
508 | val = snd_soc_read(rt5670->codec, RT5670_A_JD_CTRL1) & 0x0020; | ||
509 | |||
510 | switch (val) { | ||
511 | /* jack in */ | ||
512 | case 0x30: /* 2 port */ | ||
513 | case 0x0: /* 1 port or 2 port */ | ||
514 | if (rt5670->jack_type == 0) { | ||
515 | report = rt5670_headset_detect(rt5670->codec, 1); | ||
516 | /* for push button and jack out */ | ||
517 | gpio->debounce_time = 25; | ||
518 | break; | ||
519 | } | ||
520 | btn_type = 0; | ||
521 | if (snd_soc_read(rt5670->codec, RT5670_INT_IRQ_ST) & 0x4) { | ||
522 | /* button pressed */ | ||
523 | report = SND_JACK_HEADSET; | ||
524 | btn_type = rt5670_button_detect(rt5670->codec); | ||
525 | switch (btn_type) { | ||
526 | case 0x2000: /* up */ | ||
527 | report |= SND_JACK_BTN_1; | ||
528 | break; | ||
529 | case 0x0400: /* center */ | ||
530 | report |= SND_JACK_BTN_0; | ||
531 | break; | ||
532 | case 0x0080: /* down */ | ||
533 | report |= SND_JACK_BTN_2; | ||
534 | break; | ||
535 | default: | ||
536 | dev_err(rt5670->codec->dev, | ||
537 | "Unexpected button code 0x%04x\n", | ||
538 | btn_type); | ||
539 | break; | ||
540 | } | ||
541 | } | ||
542 | if (btn_type == 0)/* button release */ | ||
543 | report = rt5670->jack_type; | ||
544 | |||
545 | break; | ||
546 | /* jack out */ | ||
547 | case 0x70: /* 2 port */ | ||
548 | case 0x10: /* 2 port */ | ||
549 | case 0x20: /* 1 port */ | ||
550 | report = 0; | ||
551 | snd_soc_update_bits(rt5670->codec, RT5670_INT_IRQ_ST, 0x1, 0x0); | ||
552 | rt5670_headset_detect(rt5670->codec, 0); | ||
553 | gpio->debounce_time = 150; /* for jack in */ | ||
554 | break; | ||
555 | default: | ||
556 | break; | ||
557 | } | ||
558 | |||
559 | return report; | ||
560 | } | ||
561 | |||
562 | int rt5670_set_jack_detect(struct snd_soc_codec *codec, | ||
563 | struct snd_soc_jack *jack) | ||
564 | { | ||
565 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); | ||
566 | int ret; | ||
567 | |||
568 | rt5670->jack = jack; | ||
569 | rt5670->hp_gpio.gpiod_dev = codec->dev; | ||
570 | rt5670->hp_gpio.name = "headphone detect"; | ||
571 | rt5670->hp_gpio.report = SND_JACK_HEADSET | | ||
572 | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2; | ||
573 | rt5670->hp_gpio.debounce_time = 150; | ||
574 | rt5670->hp_gpio.wake = true; | ||
575 | rt5670->hp_gpio.data = (struct rt5670_priv *)rt5670; | ||
576 | rt5670->hp_gpio.jack_status_check = rt5670_irq_detection; | ||
577 | |||
578 | ret = snd_soc_jack_add_gpios(rt5670->jack, 1, | ||
579 | &rt5670->hp_gpio); | ||
580 | if (ret) { | ||
581 | dev_err(codec->dev, "Adding jack GPIO failed\n"); | ||
582 | return ret; | ||
583 | } | ||
584 | |||
585 | return 0; | ||
586 | } | ||
587 | EXPORT_SYMBOL_GPL(rt5670_set_jack_detect); | ||
588 | |||
406 | static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); | 589 | static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); |
407 | static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); | 590 | static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); |
408 | static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); | 591 | static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); |
@@ -517,11 +700,9 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, | |||
517 | struct snd_soc_dapm_widget *sink) | 700 | struct snd_soc_dapm_widget *sink) |
518 | { | 701 | { |
519 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); | 702 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); |
520 | unsigned int val; | 703 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); |
521 | 704 | ||
522 | val = snd_soc_read(codec, RT5670_GLB_CLK); | 705 | if (rt5670->sysclk_src == RT5670_SCLK_S_PLL1) |
523 | val &= RT5670_SCLK_SRC_MASK; | ||
524 | if (val == RT5670_SCLK_SRC_PLL1) | ||
525 | return 1; | 706 | return 1; |
526 | else | 707 | else |
527 | return 0; | 708 | return 0; |
@@ -2271,16 +2452,6 @@ static int rt5670_set_dai_sysclk(struct snd_soc_dai *dai, | |||
2271 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); | 2452 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); |
2272 | unsigned int reg_val = 0; | 2453 | unsigned int reg_val = 0; |
2273 | 2454 | ||
2274 | if (freq == rt5670->sysclk && clk_id == rt5670->sysclk_src) | ||
2275 | return 0; | ||
2276 | |||
2277 | if (rt5670->pdata.jd_mode) { | ||
2278 | if (clk_id == RT5670_SCLK_S_PLL1) | ||
2279 | snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1"); | ||
2280 | else | ||
2281 | snd_soc_dapm_disable_pin(&codec->dapm, "PLL1"); | ||
2282 | snd_soc_dapm_sync(&codec->dapm); | ||
2283 | } | ||
2284 | switch (clk_id) { | 2455 | switch (clk_id) { |
2285 | case RT5670_SCLK_S_MCLK: | 2456 | case RT5670_SCLK_S_MCLK: |
2286 | reg_val |= RT5670_SCLK_SRC_MCLK; | 2457 | reg_val |= RT5670_SCLK_SRC_MCLK; |
@@ -2298,7 +2469,8 @@ static int rt5670_set_dai_sysclk(struct snd_soc_dai *dai, | |||
2298 | snd_soc_update_bits(codec, RT5670_GLB_CLK, | 2469 | snd_soc_update_bits(codec, RT5670_GLB_CLK, |
2299 | RT5670_SCLK_SRC_MASK, reg_val); | 2470 | RT5670_SCLK_SRC_MASK, reg_val); |
2300 | rt5670->sysclk = freq; | 2471 | rt5670->sysclk = freq; |
2301 | rt5670->sysclk_src = clk_id; | 2472 | if (clk_id != RT5670_SCLK_S_RCCLK) |
2473 | rt5670->sysclk_src = clk_id; | ||
2302 | 2474 | ||
2303 | dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); | 2475 | dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); |
2304 | 2476 | ||
@@ -2517,6 +2689,7 @@ static int rt5670_remove(struct snd_soc_codec *codec) | |||
2517 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); | 2689 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); |
2518 | 2690 | ||
2519 | regmap_write(rt5670->regmap, RT5670_RESET, 0); | 2691 | regmap_write(rt5670->regmap, RT5670_RESET, 0); |
2692 | snd_soc_jack_free_gpios(rt5670->jack, 1, &rt5670->hp_gpio); | ||
2520 | return 0; | 2693 | return 0; |
2521 | } | 2694 | } |
2522 | 2695 | ||
@@ -2676,6 +2849,7 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, | |||
2676 | if (dmi_check_system(dmi_platform_intel_braswell)) { | 2849 | if (dmi_check_system(dmi_platform_intel_braswell)) { |
2677 | rt5670->pdata.dmic_en = true; | 2850 | rt5670->pdata.dmic_en = true; |
2678 | rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P; | 2851 | rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P; |
2852 | rt5670->pdata.dev_gpio = true; | ||
2679 | rt5670->pdata.jd_mode = 1; | 2853 | rt5670->pdata.jd_mode = 1; |
2680 | } | 2854 | } |
2681 | 2855 | ||
@@ -2717,12 +2891,17 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, | |||
2717 | regmap_update_bits(rt5670->regmap, RT5670_IN2, | 2891 | regmap_update_bits(rt5670->regmap, RT5670_IN2, |
2718 | RT5670_IN_DF2, RT5670_IN_DF2); | 2892 | RT5670_IN_DF2, RT5670_IN_DF2); |
2719 | 2893 | ||
2720 | if (i2c->irq) { | 2894 | if (rt5670->pdata.dev_gpio) { |
2895 | /* for push button */ | ||
2896 | regmap_write(rt5670->regmap, RT5670_IL_CMD, 0x0000); | ||
2897 | regmap_write(rt5670->regmap, RT5670_IL_CMD2, 0x0010); | ||
2898 | regmap_write(rt5670->regmap, RT5670_IL_CMD3, 0x0014); | ||
2899 | /* for irq */ | ||
2721 | regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL1, | 2900 | regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL1, |
2722 | RT5670_GP1_PIN_MASK, RT5670_GP1_PIN_IRQ); | 2901 | RT5670_GP1_PIN_MASK, RT5670_GP1_PIN_IRQ); |
2723 | regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL2, | 2902 | regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL2, |
2724 | RT5670_GP1_PF_MASK, RT5670_GP1_PF_OUT); | 2903 | RT5670_GP1_PF_MASK, RT5670_GP1_PF_OUT); |
2725 | 2904 | regmap_update_bits(rt5670->regmap, RT5670_DIG_MISC, 0x8, 0x8); | |
2726 | } | 2905 | } |
2727 | 2906 | ||
2728 | if (rt5670->pdata.jd_mode) { | 2907 | if (rt5670->pdata.jd_mode) { |
diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h index 0a67adbcfbc3..dc2b46236c5c 100644 --- a/sound/soc/codecs/rt5670.h +++ b/sound/soc/codecs/rt5670.h | |||
@@ -1988,6 +1988,8 @@ struct rt5670_priv { | |||
1988 | struct snd_soc_codec *codec; | 1988 | struct snd_soc_codec *codec; |
1989 | struct rt5670_platform_data pdata; | 1989 | struct rt5670_platform_data pdata; |
1990 | struct regmap *regmap; | 1990 | struct regmap *regmap; |
1991 | struct snd_soc_jack *jack; | ||
1992 | struct snd_soc_jack_gpio hp_gpio; | ||
1991 | 1993 | ||
1992 | int sysclk; | 1994 | int sysclk; |
1993 | int sysclk_src; | 1995 | int sysclk_src; |
@@ -2002,6 +2004,11 @@ struct rt5670_priv { | |||
2002 | int dsp_sw; /* expected parameter setting */ | 2004 | int dsp_sw; /* expected parameter setting */ |
2003 | int dsp_rate; | 2005 | int dsp_rate; |
2004 | int jack_type; | 2006 | int jack_type; |
2007 | int jack_type_saved; | ||
2005 | }; | 2008 | }; |
2006 | 2009 | ||
2010 | void rt5670_jack_suspend(struct snd_soc_codec *codec); | ||
2011 | void rt5670_jack_resume(struct snd_soc_codec *codec); | ||
2012 | int rt5670_set_jack_detect(struct snd_soc_codec *codec, | ||
2013 | struct snd_soc_jack *jack); | ||
2007 | #endif /* __RT5670_H__ */ | 2014 | #endif /* __RT5670_H__ */ |
diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index a8e53c45c6b6..cd9aee9871a3 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile | |||
@@ -1,42 +1,10 @@ | |||
1 | # Core support | 1 | # Core support |
2 | snd-soc-sst-dsp-objs := sst-dsp.o sst-firmware.o | 2 | obj-$(CONFIG_SND_SOC_INTEL_SST) += common/ |
3 | snd-soc-sst-acpi-objs := sst-acpi.o | ||
4 | |||
5 | snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o \ | ||
6 | sst-mfld-platform-compress.o sst-atom-controls.o | ||
7 | snd-soc-mfld-machine-objs := mfld_machine.o | ||
8 | |||
9 | obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o | ||
10 | obj-$(CONFIG_SND_MFLD_MACHINE) += snd-soc-mfld-machine.o | ||
11 | |||
12 | obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o | ||
13 | obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o | ||
14 | 3 | ||
15 | # Platform Support | 4 | # Platform Support |
16 | snd-soc-sst-haswell-pcm-objs := \ | 5 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/ |
17 | sst-haswell-ipc.o sst-haswell-pcm.o sst-haswell-dsp.o | 6 | obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += baytrail/ |
18 | snd-soc-sst-baytrail-pcm-objs := \ | 7 | obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += atom/ |
19 | sst-baytrail-ipc.o sst-baytrail-pcm.o sst-baytrail-dsp.o | ||
20 | |||
21 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += snd-soc-sst-haswell-pcm.o | ||
22 | obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += snd-soc-sst-baytrail-pcm.o | ||
23 | 8 | ||
24 | # Machine support | 9 | # Machine support |
25 | snd-soc-sst-haswell-objs := haswell.o | 10 | obj-$(CONFIG_SND_SOC_INTEL_SST) += boards/ |
26 | snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o | ||
27 | snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o | ||
28 | snd-soc-sst-broadwell-objs := broadwell.o | ||
29 | snd-soc-sst-bytcr-dpcm-rt5640-objs := bytcr_dpcm_rt5640.o | ||
30 | snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o | ||
31 | snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o | ||
32 | |||
33 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o | ||
34 | obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o | ||
35 | obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o | ||
36 | obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o | ||
37 | obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-dpcm-rt5640.o | ||
38 | obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o | ||
39 | obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o | ||
40 | |||
41 | # DSP driver | ||
42 | obj-$(CONFIG_SND_SST_IPC) += sst/ | ||
diff --git a/sound/soc/intel/atom/Makefile b/sound/soc/intel/atom/Makefile new file mode 100644 index 000000000000..ce8074fa6d66 --- /dev/null +++ b/sound/soc/intel/atom/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o \ | ||
2 | sst-mfld-platform-compress.o sst-atom-controls.o | ||
3 | |||
4 | obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o | ||
5 | |||
6 | # DSP driver | ||
7 | obj-$(CONFIG_SND_SST_IPC) += sst/ | ||
diff --git a/sound/soc/intel/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 90aa5c0476f3..90aa5c0476f3 100644 --- a/sound/soc/intel/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c | |||
diff --git a/sound/soc/intel/sst-atom-controls.h b/sound/soc/intel/atom/sst-atom-controls.h index daecc58f28af..daecc58f28af 100644 --- a/sound/soc/intel/sst-atom-controls.h +++ b/sound/soc/intel/atom/sst-atom-controls.h | |||
diff --git a/sound/soc/intel/sst-mfld-dsp.h b/sound/soc/intel/atom/sst-mfld-dsp.h index 4257263157cd..4257263157cd 100644 --- a/sound/soc/intel/sst-mfld-dsp.h +++ b/sound/soc/intel/atom/sst-mfld-dsp.h | |||
diff --git a/sound/soc/intel/sst-mfld-platform-compress.c b/sound/soc/intel/atom/sst-mfld-platform-compress.c index 395168986462..395168986462 100644 --- a/sound/soc/intel/sst-mfld-platform-compress.c +++ b/sound/soc/intel/atom/sst-mfld-platform-compress.c | |||
diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 2fbaf2c75d17..2fbaf2c75d17 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c | |||
diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/atom/sst-mfld-platform.h index 9094314be2b0..9094314be2b0 100644 --- a/sound/soc/intel/sst-mfld-platform.h +++ b/sound/soc/intel/atom/sst-mfld-platform.h | |||
diff --git a/sound/soc/intel/sst/Makefile b/sound/soc/intel/atom/sst/Makefile index fd21726361b5..fd21726361b5 100644 --- a/sound/soc/intel/sst/Makefile +++ b/sound/soc/intel/atom/sst/Makefile | |||
diff --git a/sound/soc/intel/sst/sst.c b/sound/soc/intel/atom/sst/sst.c index 1a7eeec444b1..96c2e420cce6 100644 --- a/sound/soc/intel/sst/sst.c +++ b/sound/soc/intel/atom/sst/sst.c | |||
@@ -32,7 +32,7 @@ | |||
32 | #include <asm/platform_sst_audio.h> | 32 | #include <asm/platform_sst_audio.h> |
33 | #include "../sst-mfld-platform.h" | 33 | #include "../sst-mfld-platform.h" |
34 | #include "sst.h" | 34 | #include "sst.h" |
35 | #include "../sst-dsp.h" | 35 | #include "../../common/sst-dsp.h" |
36 | 36 | ||
37 | MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>"); | 37 | MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>"); |
38 | MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>"); | 38 | MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>"); |
diff --git a/sound/soc/intel/sst/sst.h b/sound/soc/intel/atom/sst/sst.h index 3f493862e98d..3f493862e98d 100644 --- a/sound/soc/intel/sst/sst.h +++ b/sound/soc/intel/atom/sst/sst.h | |||
diff --git a/sound/soc/intel/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index b536ddd2517d..05f693083911 100644 --- a/sound/soc/intel/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c | |||
@@ -39,7 +39,7 @@ | |||
39 | #include <acpi/actypes.h> | 39 | #include <acpi/actypes.h> |
40 | #include <acpi/acpi_bus.h> | 40 | #include <acpi/acpi_bus.h> |
41 | #include "../sst-mfld-platform.h" | 41 | #include "../sst-mfld-platform.h" |
42 | #include "../sst-dsp.h" | 42 | #include "../../common/sst-dsp.h" |
43 | #include "sst.h" | 43 | #include "sst.h" |
44 | 44 | ||
45 | struct sst_machines { | 45 | struct sst_machines { |
diff --git a/sound/soc/intel/sst/sst_drv_interface.c b/sound/soc/intel/atom/sst/sst_drv_interface.c index f0e4b99b3aeb..7b50a9d17ec1 100644 --- a/sound/soc/intel/sst/sst_drv_interface.c +++ b/sound/soc/intel/atom/sst/sst_drv_interface.c | |||
@@ -32,7 +32,7 @@ | |||
32 | #include <asm/platform_sst_audio.h> | 32 | #include <asm/platform_sst_audio.h> |
33 | #include "../sst-mfld-platform.h" | 33 | #include "../sst-mfld-platform.h" |
34 | #include "sst.h" | 34 | #include "sst.h" |
35 | #include "../sst-dsp.h" | 35 | #include "../../common/sst-dsp.h" |
36 | 36 | ||
37 | 37 | ||
38 | 38 | ||
@@ -381,7 +381,7 @@ static int sst_cdev_tstamp(struct device *dev, unsigned int str_id, | |||
381 | tstamp->copied_total = fw_tstamp.ring_buffer_counter; | 381 | tstamp->copied_total = fw_tstamp.ring_buffer_counter; |
382 | tstamp->pcm_frames = fw_tstamp.frames_decoded; | 382 | tstamp->pcm_frames = fw_tstamp.frames_decoded; |
383 | tstamp->pcm_io_frames = div_u64(fw_tstamp.hardware_counter, | 383 | tstamp->pcm_io_frames = div_u64(fw_tstamp.hardware_counter, |
384 | (u64)((stream->num_ch) * SST_GET_BYTES_PER_SAMPLE(24))); | 384 | (u64)stream->num_ch * SST_GET_BYTES_PER_SAMPLE(24)); |
385 | tstamp->sampling_rate = fw_tstamp.sampling_frequency; | 385 | tstamp->sampling_rate = fw_tstamp.sampling_frequency; |
386 | 386 | ||
387 | dev_dbg(dev, "PCM = %u\n", tstamp->pcm_io_frames); | 387 | dev_dbg(dev, "PCM = %u\n", tstamp->pcm_io_frames); |
diff --git a/sound/soc/intel/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c index 484e60978477..5a278618466c 100644 --- a/sound/soc/intel/sst/sst_ipc.c +++ b/sound/soc/intel/atom/sst/sst_ipc.c | |||
@@ -32,7 +32,7 @@ | |||
32 | #include <asm/platform_sst_audio.h> | 32 | #include <asm/platform_sst_audio.h> |
33 | #include "../sst-mfld-platform.h" | 33 | #include "../sst-mfld-platform.h" |
34 | #include "sst.h" | 34 | #include "sst.h" |
35 | #include "../sst-dsp.h" | 35 | #include "../../common/sst-dsp.h" |
36 | 36 | ||
37 | struct sst_block *sst_create_block(struct intel_sst_drv *ctx, | 37 | struct sst_block *sst_create_block(struct intel_sst_drv *ctx, |
38 | u32 msg_id, u32 drv_id) | 38 | u32 msg_id, u32 drv_id) |
diff --git a/sound/soc/intel/sst/sst_loader.c b/sound/soc/intel/atom/sst/sst_loader.c index e88907ae8b15..33917146d9c4 100644 --- a/sound/soc/intel/sst/sst_loader.c +++ b/sound/soc/intel/atom/sst/sst_loader.c | |||
@@ -37,7 +37,7 @@ | |||
37 | #include <asm/platform_sst_audio.h> | 37 | #include <asm/platform_sst_audio.h> |
38 | #include "../sst-mfld-platform.h" | 38 | #include "../sst-mfld-platform.h" |
39 | #include "sst.h" | 39 | #include "sst.h" |
40 | #include "../sst-dsp.h" | 40 | #include "../../common/sst-dsp.h" |
41 | 41 | ||
42 | void memcpy32_toio(void __iomem *dst, const void *src, int count) | 42 | void memcpy32_toio(void __iomem *dst, const void *src, int count) |
43 | { | 43 | { |
diff --git a/sound/soc/intel/sst/sst_pci.c b/sound/soc/intel/atom/sst/sst_pci.c index 3a0b3bf0af97..3a0b3bf0af97 100644 --- a/sound/soc/intel/sst/sst_pci.c +++ b/sound/soc/intel/atom/sst/sst_pci.c | |||
diff --git a/sound/soc/intel/sst/sst_pvt.c b/sound/soc/intel/atom/sst/sst_pvt.c index 4b7720864492..adb32fefd693 100644 --- a/sound/soc/intel/sst/sst_pvt.c +++ b/sound/soc/intel/atom/sst/sst_pvt.c | |||
@@ -34,7 +34,7 @@ | |||
34 | #include <asm/platform_sst_audio.h> | 34 | #include <asm/platform_sst_audio.h> |
35 | #include "../sst-mfld-platform.h" | 35 | #include "../sst-mfld-platform.h" |
36 | #include "sst.h" | 36 | #include "sst.h" |
37 | #include "../sst-dsp.h" | 37 | #include "../../common/sst-dsp.h" |
38 | 38 | ||
39 | int sst_shim_write(void __iomem *addr, int offset, int value) | 39 | int sst_shim_write(void __iomem *addr, int offset, int value) |
40 | { | 40 | { |
@@ -111,30 +111,6 @@ int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx, | |||
111 | 111 | ||
112 | } | 112 | } |
113 | 113 | ||
114 | unsigned long long read_shim_data(struct intel_sst_drv *sst, int addr) | ||
115 | { | ||
116 | unsigned long long val = 0; | ||
117 | |||
118 | switch (sst->dev_id) { | ||
119 | case SST_MRFLD_PCI_ID: | ||
120 | case SST_BYT_ACPI_ID: | ||
121 | val = sst_shim_read64(sst->shim, addr); | ||
122 | break; | ||
123 | } | ||
124 | return val; | ||
125 | } | ||
126 | |||
127 | void write_shim_data(struct intel_sst_drv *sst, int addr, | ||
128 | unsigned long long data) | ||
129 | { | ||
130 | switch (sst->dev_id) { | ||
131 | case SST_MRFLD_PCI_ID: | ||
132 | case SST_BYT_ACPI_ID: | ||
133 | sst_shim_write64(sst->shim, addr, (u64) data); | ||
134 | break; | ||
135 | } | ||
136 | } | ||
137 | |||
138 | /* | 114 | /* |
139 | * sst_wait_timeout - wait on event for timeout | 115 | * sst_wait_timeout - wait on event for timeout |
140 | * | 116 | * |
diff --git a/sound/soc/intel/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c index dae2a41997aa..a74c64c7053c 100644 --- a/sound/soc/intel/sst/sst_stream.c +++ b/sound/soc/intel/atom/sst/sst_stream.c | |||
@@ -31,7 +31,7 @@ | |||
31 | #include <asm/platform_sst_audio.h> | 31 | #include <asm/platform_sst_audio.h> |
32 | #include "../sst-mfld-platform.h" | 32 | #include "../sst-mfld-platform.h" |
33 | #include "sst.h" | 33 | #include "sst.h" |
34 | #include "../sst-dsp.h" | 34 | #include "../../common/sst-dsp.h" |
35 | 35 | ||
36 | int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params) | 36 | int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params) |
37 | { | 37 | { |
diff --git a/sound/soc/intel/baytrail/Makefile b/sound/soc/intel/baytrail/Makefile new file mode 100644 index 000000000000..488408cadf6d --- /dev/null +++ b/sound/soc/intel/baytrail/Makefile | |||
@@ -0,0 +1,4 @@ | |||
1 | snd-soc-sst-baytrail-pcm-objs := \ | ||
2 | sst-baytrail-ipc.o sst-baytrail-pcm.o sst-baytrail-dsp.o | ||
3 | |||
4 | obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += snd-soc-sst-baytrail-pcm.o | ||
diff --git a/sound/soc/intel/sst-baytrail-dsp.c b/sound/soc/intel/baytrail/sst-baytrail-dsp.c index 5a9e56700f31..01d023cc05dd 100644 --- a/sound/soc/intel/sst-baytrail-dsp.c +++ b/sound/soc/intel/baytrail/sst-baytrail-dsp.c | |||
@@ -22,8 +22,8 @@ | |||
22 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
23 | #include <linux/firmware.h> | 23 | #include <linux/firmware.h> |
24 | 24 | ||
25 | #include "sst-dsp.h" | 25 | #include "../common/sst-dsp.h" |
26 | #include "sst-dsp-priv.h" | 26 | #include "../common/sst-dsp-priv.h" |
27 | #include "sst-baytrail-ipc.h" | 27 | #include "sst-baytrail-ipc.h" |
28 | 28 | ||
29 | #define SST_BYT_FW_SIGNATURE_SIZE 4 | 29 | #define SST_BYT_FW_SIGNATURE_SIZE 4 |
diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/baytrail/sst-baytrail-ipc.c index b4ad98c43e5c..1efb33b36303 100644 --- a/sound/soc/intel/sst-baytrail-ipc.c +++ b/sound/soc/intel/baytrail/sst-baytrail-ipc.c | |||
@@ -29,8 +29,9 @@ | |||
29 | #include <asm/div64.h> | 29 | #include <asm/div64.h> |
30 | 30 | ||
31 | #include "sst-baytrail-ipc.h" | 31 | #include "sst-baytrail-ipc.h" |
32 | #include "sst-dsp.h" | 32 | #include "../common/sst-dsp.h" |
33 | #include "sst-dsp-priv.h" | 33 | #include "../common/sst-dsp-priv.h" |
34 | #include "../common/sst-ipc.h" | ||
34 | 35 | ||
35 | /* IPC message timeout */ | 36 | /* IPC message timeout */ |
36 | #define IPC_TIMEOUT_MSECS 300 | 37 | #define IPC_TIMEOUT_MSECS 300 |
@@ -142,23 +143,6 @@ struct sst_byt_fw_init { | |||
142 | u8 debug_info; | 143 | u8 debug_info; |
143 | } __packed; | 144 | } __packed; |
144 | 145 | ||
145 | /* driver internal IPC message structure */ | ||
146 | struct ipc_message { | ||
147 | struct list_head list; | ||
148 | u64 header; | ||
149 | |||
150 | /* direction wrt host CPU */ | ||
151 | char tx_data[SST_BYT_IPC_MAX_PAYLOAD_SIZE]; | ||
152 | size_t tx_size; | ||
153 | char rx_data[SST_BYT_IPC_MAX_PAYLOAD_SIZE]; | ||
154 | size_t rx_size; | ||
155 | |||
156 | wait_queue_head_t waitq; | ||
157 | bool complete; | ||
158 | bool wait; | ||
159 | int errno; | ||
160 | }; | ||
161 | |||
162 | struct sst_byt_stream; | 146 | struct sst_byt_stream; |
163 | struct sst_byt; | 147 | struct sst_byt; |
164 | 148 | ||
@@ -195,14 +179,7 @@ struct sst_byt { | |||
195 | struct sst_fw *fw; | 179 | struct sst_fw *fw; |
196 | 180 | ||
197 | /* IPC messaging */ | 181 | /* IPC messaging */ |
198 | struct list_head tx_list; | 182 | struct sst_generic_ipc ipc; |
199 | struct list_head rx_list; | ||
200 | struct list_head empty_list; | ||
201 | wait_queue_head_t wait_txq; | ||
202 | struct task_struct *tx_thread; | ||
203 | struct kthread_worker kworker; | ||
204 | struct kthread_work kwork; | ||
205 | struct ipc_message *msg; | ||
206 | }; | 183 | }; |
207 | 184 | ||
208 | static inline u64 sst_byt_header(int msg_id, int data, bool large, int str_id) | 185 | static inline u64 sst_byt_header(int msg_id, int data, bool large, int str_id) |
@@ -246,209 +223,6 @@ static struct sst_byt_stream *sst_byt_get_stream(struct sst_byt *byt, | |||
246 | return NULL; | 223 | return NULL; |
247 | } | 224 | } |
248 | 225 | ||
249 | static void sst_byt_ipc_shim_dbg(struct sst_byt *byt, const char *text) | ||
250 | { | ||
251 | struct sst_dsp *sst = byt->dsp; | ||
252 | u64 isr, ipcd, imrx, ipcx; | ||
253 | |||
254 | ipcx = sst_dsp_shim_read64_unlocked(sst, SST_IPCX); | ||
255 | isr = sst_dsp_shim_read64_unlocked(sst, SST_ISRX); | ||
256 | ipcd = sst_dsp_shim_read64_unlocked(sst, SST_IPCD); | ||
257 | imrx = sst_dsp_shim_read64_unlocked(sst, SST_IMRX); | ||
258 | |||
259 | dev_err(byt->dev, | ||
260 | "ipc: --%s-- ipcx 0x%llx isr 0x%llx ipcd 0x%llx imrx 0x%llx\n", | ||
261 | text, ipcx, isr, ipcd, imrx); | ||
262 | } | ||
263 | |||
264 | /* locks held by caller */ | ||
265 | static struct ipc_message *sst_byt_msg_get_empty(struct sst_byt *byt) | ||
266 | { | ||
267 | struct ipc_message *msg = NULL; | ||
268 | |||
269 | if (!list_empty(&byt->empty_list)) { | ||
270 | msg = list_first_entry(&byt->empty_list, | ||
271 | struct ipc_message, list); | ||
272 | list_del(&msg->list); | ||
273 | } | ||
274 | |||
275 | return msg; | ||
276 | } | ||
277 | |||
278 | static void sst_byt_ipc_tx_msgs(struct kthread_work *work) | ||
279 | { | ||
280 | struct sst_byt *byt = | ||
281 | container_of(work, struct sst_byt, kwork); | ||
282 | struct ipc_message *msg; | ||
283 | u64 ipcx; | ||
284 | unsigned long flags; | ||
285 | |||
286 | spin_lock_irqsave(&byt->dsp->spinlock, flags); | ||
287 | if (list_empty(&byt->tx_list)) { | ||
288 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
289 | return; | ||
290 | } | ||
291 | |||
292 | /* if the DSP is busy we will TX messages after IRQ */ | ||
293 | ipcx = sst_dsp_shim_read64_unlocked(byt->dsp, SST_IPCX); | ||
294 | if (ipcx & SST_BYT_IPCX_BUSY) { | ||
295 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
296 | return; | ||
297 | } | ||
298 | |||
299 | msg = list_first_entry(&byt->tx_list, struct ipc_message, list); | ||
300 | |||
301 | list_move(&msg->list, &byt->rx_list); | ||
302 | |||
303 | /* send the message */ | ||
304 | if (msg->header & IPC_HEADER_LARGE(true)) | ||
305 | sst_dsp_outbox_write(byt->dsp, msg->tx_data, msg->tx_size); | ||
306 | sst_dsp_shim_write64_unlocked(byt->dsp, SST_IPCX, msg->header); | ||
307 | |||
308 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
309 | } | ||
310 | |||
311 | static inline void sst_byt_tx_msg_reply_complete(struct sst_byt *byt, | ||
312 | struct ipc_message *msg) | ||
313 | { | ||
314 | msg->complete = true; | ||
315 | |||
316 | if (!msg->wait) | ||
317 | list_add_tail(&msg->list, &byt->empty_list); | ||
318 | else | ||
319 | wake_up(&msg->waitq); | ||
320 | } | ||
321 | |||
322 | static void sst_byt_drop_all(struct sst_byt *byt) | ||
323 | { | ||
324 | struct ipc_message *msg, *tmp; | ||
325 | unsigned long flags; | ||
326 | |||
327 | /* drop all TX and Rx messages before we stall + reset DSP */ | ||
328 | spin_lock_irqsave(&byt->dsp->spinlock, flags); | ||
329 | list_for_each_entry_safe(msg, tmp, &byt->tx_list, list) { | ||
330 | list_move(&msg->list, &byt->empty_list); | ||
331 | } | ||
332 | |||
333 | list_for_each_entry_safe(msg, tmp, &byt->rx_list, list) { | ||
334 | list_move(&msg->list, &byt->empty_list); | ||
335 | } | ||
336 | |||
337 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
338 | } | ||
339 | |||
340 | static int sst_byt_tx_wait_done(struct sst_byt *byt, struct ipc_message *msg, | ||
341 | void *rx_data) | ||
342 | { | ||
343 | unsigned long flags; | ||
344 | int ret; | ||
345 | |||
346 | /* wait for DSP completion */ | ||
347 | ret = wait_event_timeout(msg->waitq, msg->complete, | ||
348 | msecs_to_jiffies(IPC_TIMEOUT_MSECS)); | ||
349 | |||
350 | spin_lock_irqsave(&byt->dsp->spinlock, flags); | ||
351 | if (ret == 0) { | ||
352 | list_del(&msg->list); | ||
353 | sst_byt_ipc_shim_dbg(byt, "message timeout"); | ||
354 | |||
355 | ret = -ETIMEDOUT; | ||
356 | } else { | ||
357 | |||
358 | /* copy the data returned from DSP */ | ||
359 | if (msg->rx_size) | ||
360 | memcpy(rx_data, msg->rx_data, msg->rx_size); | ||
361 | ret = msg->errno; | ||
362 | } | ||
363 | |||
364 | list_add_tail(&msg->list, &byt->empty_list); | ||
365 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
366 | return ret; | ||
367 | } | ||
368 | |||
369 | static int sst_byt_ipc_tx_message(struct sst_byt *byt, u64 header, | ||
370 | void *tx_data, size_t tx_bytes, | ||
371 | void *rx_data, size_t rx_bytes, int wait) | ||
372 | { | ||
373 | unsigned long flags; | ||
374 | struct ipc_message *msg; | ||
375 | |||
376 | spin_lock_irqsave(&byt->dsp->spinlock, flags); | ||
377 | |||
378 | msg = sst_byt_msg_get_empty(byt); | ||
379 | if (msg == NULL) { | ||
380 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
381 | return -EBUSY; | ||
382 | } | ||
383 | |||
384 | msg->header = header; | ||
385 | msg->tx_size = tx_bytes; | ||
386 | msg->rx_size = rx_bytes; | ||
387 | msg->wait = wait; | ||
388 | msg->errno = 0; | ||
389 | msg->complete = false; | ||
390 | |||
391 | if (tx_bytes) { | ||
392 | /* msg content = lower 32-bit of the header + data */ | ||
393 | *(u32 *)msg->tx_data = (u32)(header & (u32)-1); | ||
394 | memcpy(msg->tx_data + sizeof(u32), tx_data, tx_bytes); | ||
395 | msg->tx_size += sizeof(u32); | ||
396 | } | ||
397 | |||
398 | list_add_tail(&msg->list, &byt->tx_list); | ||
399 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
400 | |||
401 | queue_kthread_work(&byt->kworker, &byt->kwork); | ||
402 | |||
403 | if (wait) | ||
404 | return sst_byt_tx_wait_done(byt, msg, rx_data); | ||
405 | else | ||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | static inline int sst_byt_ipc_tx_msg_wait(struct sst_byt *byt, u64 header, | ||
410 | void *tx_data, size_t tx_bytes, | ||
411 | void *rx_data, size_t rx_bytes) | ||
412 | { | ||
413 | return sst_byt_ipc_tx_message(byt, header, tx_data, tx_bytes, | ||
414 | rx_data, rx_bytes, 1); | ||
415 | } | ||
416 | |||
417 | static inline int sst_byt_ipc_tx_msg_nowait(struct sst_byt *byt, u64 header, | ||
418 | void *tx_data, size_t tx_bytes) | ||
419 | { | ||
420 | return sst_byt_ipc_tx_message(byt, header, tx_data, tx_bytes, | ||
421 | NULL, 0, 0); | ||
422 | } | ||
423 | |||
424 | static struct ipc_message *sst_byt_reply_find_msg(struct sst_byt *byt, | ||
425 | u64 header) | ||
426 | { | ||
427 | struct ipc_message *msg = NULL, *_msg; | ||
428 | u64 mask; | ||
429 | |||
430 | /* match reply to message sent based on msg and stream IDs */ | ||
431 | mask = IPC_HEADER_MSG_ID_MASK | | ||
432 | IPC_HEADER_STR_ID_MASK << IPC_HEADER_STR_ID_SHIFT; | ||
433 | header &= mask; | ||
434 | |||
435 | if (list_empty(&byt->rx_list)) { | ||
436 | dev_err(byt->dev, | ||
437 | "ipc: rx list is empty but received 0x%llx\n", header); | ||
438 | goto out; | ||
439 | } | ||
440 | |||
441 | list_for_each_entry(_msg, &byt->rx_list, list) { | ||
442 | if ((_msg->header & mask) == header) { | ||
443 | msg = _msg; | ||
444 | break; | ||
445 | } | ||
446 | } | ||
447 | |||
448 | out: | ||
449 | return msg; | ||
450 | } | ||
451 | |||
452 | static void sst_byt_stream_update(struct sst_byt *byt, struct ipc_message *msg) | 226 | static void sst_byt_stream_update(struct sst_byt *byt, struct ipc_message *msg) |
453 | { | 227 | { |
454 | struct sst_byt_stream *stream; | 228 | struct sst_byt_stream *stream; |
@@ -477,7 +251,7 @@ static int sst_byt_process_reply(struct sst_byt *byt, u64 header) | |||
477 | { | 251 | { |
478 | struct ipc_message *msg; | 252 | struct ipc_message *msg; |
479 | 253 | ||
480 | msg = sst_byt_reply_find_msg(byt, header); | 254 | msg = sst_ipc_reply_find_msg(&byt->ipc, header); |
481 | if (msg == NULL) | 255 | if (msg == NULL) |
482 | return 1; | 256 | return 1; |
483 | 257 | ||
@@ -491,7 +265,7 @@ static int sst_byt_process_reply(struct sst_byt *byt, u64 header) | |||
491 | 265 | ||
492 | list_del(&msg->list); | 266 | list_del(&msg->list); |
493 | /* wake up */ | 267 | /* wake up */ |
494 | sst_byt_tx_msg_reply_complete(byt, msg); | 268 | sst_ipc_tx_msg_reply_complete(&byt->ipc, msg); |
495 | 269 | ||
496 | return 1; | 270 | return 1; |
497 | } | 271 | } |
@@ -538,6 +312,7 @@ static irqreturn_t sst_byt_irq_thread(int irq, void *context) | |||
538 | { | 312 | { |
539 | struct sst_dsp *sst = (struct sst_dsp *) context; | 313 | struct sst_dsp *sst = (struct sst_dsp *) context; |
540 | struct sst_byt *byt = sst_dsp_get_thread_context(sst); | 314 | struct sst_byt *byt = sst_dsp_get_thread_context(sst); |
315 | struct sst_generic_ipc *ipc = &byt->ipc; | ||
541 | u64 header; | 316 | u64 header; |
542 | unsigned long flags; | 317 | unsigned long flags; |
543 | 318 | ||
@@ -569,7 +344,7 @@ static irqreturn_t sst_byt_irq_thread(int irq, void *context) | |||
569 | spin_unlock_irqrestore(&sst->spinlock, flags); | 344 | spin_unlock_irqrestore(&sst->spinlock, flags); |
570 | 345 | ||
571 | /* continue to send any remaining messages... */ | 346 | /* continue to send any remaining messages... */ |
572 | queue_kthread_work(&byt->kworker, &byt->kwork); | 347 | queue_kthread_work(&ipc->kworker, &ipc->kwork); |
573 | 348 | ||
574 | return IRQ_HANDLED; | 349 | return IRQ_HANDLED; |
575 | } | 350 | } |
@@ -656,7 +431,8 @@ int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream) | |||
656 | header = sst_byt_header(IPC_IA_ALLOC_STREAM, | 431 | header = sst_byt_header(IPC_IA_ALLOC_STREAM, |
657 | sizeof(*str_req) + sizeof(u32), | 432 | sizeof(*str_req) + sizeof(u32), |
658 | true, stream->str_id); | 433 | true, stream->str_id); |
659 | ret = sst_byt_ipc_tx_msg_wait(byt, header, str_req, sizeof(*str_req), | 434 | ret = sst_ipc_tx_message_wait(&byt->ipc, header, str_req, |
435 | sizeof(*str_req), | ||
660 | reply, sizeof(*reply)); | 436 | reply, sizeof(*reply)); |
661 | if (ret < 0) { | 437 | if (ret < 0) { |
662 | dev_err(byt->dev, "ipc: error stream commit failed\n"); | 438 | dev_err(byt->dev, "ipc: error stream commit failed\n"); |
@@ -679,7 +455,7 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream) | |||
679 | goto out; | 455 | goto out; |
680 | 456 | ||
681 | header = sst_byt_header(IPC_IA_FREE_STREAM, 0, false, stream->str_id); | 457 | header = sst_byt_header(IPC_IA_FREE_STREAM, 0, false, stream->str_id); |
682 | ret = sst_byt_ipc_tx_msg_wait(byt, header, NULL, 0, NULL, 0); | 458 | ret = sst_ipc_tx_message_wait(&byt->ipc, header, NULL, 0, NULL, 0); |
683 | if (ret < 0) { | 459 | if (ret < 0) { |
684 | dev_err(byt->dev, "ipc: free stream %d failed\n", | 460 | dev_err(byt->dev, "ipc: free stream %d failed\n", |
685 | stream->str_id); | 461 | stream->str_id); |
@@ -703,9 +479,11 @@ static int sst_byt_stream_operations(struct sst_byt *byt, int type, | |||
703 | 479 | ||
704 | header = sst_byt_header(type, 0, false, stream_id); | 480 | header = sst_byt_header(type, 0, false, stream_id); |
705 | if (wait) | 481 | if (wait) |
706 | return sst_byt_ipc_tx_msg_wait(byt, header, NULL, 0, NULL, 0); | 482 | return sst_ipc_tx_message_wait(&byt->ipc, header, NULL, |
483 | 0, NULL, 0); | ||
707 | else | 484 | else |
708 | return sst_byt_ipc_tx_msg_nowait(byt, header, NULL, 0); | 485 | return sst_ipc_tx_message_nowait(&byt->ipc, header, |
486 | NULL, 0); | ||
709 | } | 487 | } |
710 | 488 | ||
711 | /* stream ALSA trigger operations */ | 489 | /* stream ALSA trigger operations */ |
@@ -725,7 +503,7 @@ int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream, | |||
725 | tx_msg = &start_stream; | 503 | tx_msg = &start_stream; |
726 | size = sizeof(start_stream); | 504 | size = sizeof(start_stream); |
727 | 505 | ||
728 | ret = sst_byt_ipc_tx_msg_nowait(byt, header, tx_msg, size); | 506 | ret = sst_ipc_tx_message_nowait(&byt->ipc, header, tx_msg, size); |
729 | if (ret < 0) | 507 | if (ret < 0) |
730 | dev_err(byt->dev, "ipc: error failed to start stream %d\n", | 508 | dev_err(byt->dev, "ipc: error failed to start stream %d\n", |
731 | stream->str_id); | 509 | stream->str_id); |
@@ -790,23 +568,6 @@ int sst_byt_get_dsp_position(struct sst_byt *byt, | |||
790 | return do_div(fw_tstamp.ring_buffer_counter, buffer_size); | 568 | return do_div(fw_tstamp.ring_buffer_counter, buffer_size); |
791 | } | 569 | } |
792 | 570 | ||
793 | static int msg_empty_list_init(struct sst_byt *byt) | ||
794 | { | ||
795 | struct ipc_message *msg; | ||
796 | int i; | ||
797 | |||
798 | byt->msg = kzalloc(sizeof(*msg) * IPC_EMPTY_LIST_SIZE, GFP_KERNEL); | ||
799 | if (byt->msg == NULL) | ||
800 | return -ENOMEM; | ||
801 | |||
802 | for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { | ||
803 | init_waitqueue_head(&byt->msg[i].waitq); | ||
804 | list_add(&byt->msg[i].list, &byt->empty_list); | ||
805 | } | ||
806 | |||
807 | return 0; | ||
808 | } | ||
809 | |||
810 | struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt) | 571 | struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt) |
811 | { | 572 | { |
812 | return byt->dsp; | 573 | return byt->dsp; |
@@ -823,7 +584,7 @@ int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata) | |||
823 | 584 | ||
824 | dev_dbg(byt->dev, "dsp reset\n"); | 585 | dev_dbg(byt->dev, "dsp reset\n"); |
825 | sst_dsp_reset(byt->dsp); | 586 | sst_dsp_reset(byt->dsp); |
826 | sst_byt_drop_all(byt); | 587 | sst_ipc_drop_all(&byt->ipc); |
827 | dev_dbg(byt->dev, "dsp in reset\n"); | 588 | dev_dbg(byt->dev, "dsp in reset\n"); |
828 | 589 | ||
829 | dev_dbg(byt->dev, "free all blocks and unload fw\n"); | 590 | dev_dbg(byt->dev, "free all blocks and unload fw\n"); |
@@ -876,9 +637,52 @@ int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata) | |||
876 | } | 637 | } |
877 | EXPORT_SYMBOL_GPL(sst_byt_dsp_wait_for_ready); | 638 | EXPORT_SYMBOL_GPL(sst_byt_dsp_wait_for_ready); |
878 | 639 | ||
640 | static void byt_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) | ||
641 | { | ||
642 | if (msg->header & IPC_HEADER_LARGE(true)) | ||
643 | sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size); | ||
644 | |||
645 | sst_dsp_shim_write64_unlocked(ipc->dsp, SST_IPCX, msg->header); | ||
646 | } | ||
647 | |||
648 | static void byt_shim_dbg(struct sst_generic_ipc *ipc, const char *text) | ||
649 | { | ||
650 | struct sst_dsp *sst = ipc->dsp; | ||
651 | u64 isr, ipcd, imrx, ipcx; | ||
652 | |||
653 | ipcx = sst_dsp_shim_read64_unlocked(sst, SST_IPCX); | ||
654 | isr = sst_dsp_shim_read64_unlocked(sst, SST_ISRX); | ||
655 | ipcd = sst_dsp_shim_read64_unlocked(sst, SST_IPCD); | ||
656 | imrx = sst_dsp_shim_read64_unlocked(sst, SST_IMRX); | ||
657 | |||
658 | dev_err(ipc->dev, | ||
659 | "ipc: --%s-- ipcx 0x%llx isr 0x%llx ipcd 0x%llx imrx 0x%llx\n", | ||
660 | text, ipcx, isr, ipcd, imrx); | ||
661 | } | ||
662 | |||
663 | static void byt_tx_data_copy(struct ipc_message *msg, char *tx_data, | ||
664 | size_t tx_size) | ||
665 | { | ||
666 | /* msg content = lower 32-bit of the header + data */ | ||
667 | *(u32 *)msg->tx_data = (u32)(msg->header & (u32)-1); | ||
668 | memcpy(msg->tx_data + sizeof(u32), tx_data, tx_size); | ||
669 | msg->tx_size += sizeof(u32); | ||
670 | } | ||
671 | |||
672 | static u64 byt_reply_msg_match(u64 header, u64 *mask) | ||
673 | { | ||
674 | /* match reply to message sent based on msg and stream IDs */ | ||
675 | *mask = IPC_HEADER_MSG_ID_MASK | | ||
676 | IPC_HEADER_STR_ID_MASK << IPC_HEADER_STR_ID_SHIFT; | ||
677 | header &= *mask; | ||
678 | |||
679 | return header; | ||
680 | } | ||
681 | |||
879 | int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) | 682 | int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) |
880 | { | 683 | { |
881 | struct sst_byt *byt; | 684 | struct sst_byt *byt; |
685 | struct sst_generic_ipc *ipc; | ||
882 | struct sst_fw *byt_sst_fw; | 686 | struct sst_fw *byt_sst_fw; |
883 | struct sst_byt_fw_init init; | 687 | struct sst_byt_fw_init init; |
884 | int err; | 688 | int err; |
@@ -889,39 +693,30 @@ int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
889 | if (byt == NULL) | 693 | if (byt == NULL) |
890 | return -ENOMEM; | 694 | return -ENOMEM; |
891 | 695 | ||
892 | byt->dev = dev; | 696 | ipc = &byt->ipc; |
893 | INIT_LIST_HEAD(&byt->stream_list); | 697 | ipc->dev = dev; |
894 | INIT_LIST_HEAD(&byt->tx_list); | 698 | ipc->ops.tx_msg = byt_tx_msg; |
895 | INIT_LIST_HEAD(&byt->rx_list); | 699 | ipc->ops.shim_dbg = byt_shim_dbg; |
896 | INIT_LIST_HEAD(&byt->empty_list); | 700 | ipc->ops.tx_data_copy = byt_tx_data_copy; |
897 | init_waitqueue_head(&byt->boot_wait); | 701 | ipc->ops.reply_msg_match = byt_reply_msg_match; |
898 | init_waitqueue_head(&byt->wait_txq); | ||
899 | 702 | ||
900 | err = msg_empty_list_init(byt); | 703 | err = sst_ipc_init(ipc); |
901 | if (err < 0) | 704 | if (err != 0) |
902 | return -ENOMEM; | 705 | goto ipc_init_err; |
903 | |||
904 | /* start the IPC message thread */ | ||
905 | init_kthread_worker(&byt->kworker); | ||
906 | byt->tx_thread = kthread_run(kthread_worker_fn, | ||
907 | &byt->kworker, "%s", | ||
908 | dev_name(byt->dev)); | ||
909 | if (IS_ERR(byt->tx_thread)) { | ||
910 | err = PTR_ERR(byt->tx_thread); | ||
911 | dev_err(byt->dev, "error failed to create message TX task\n"); | ||
912 | goto err_free_msg; | ||
913 | } | ||
914 | init_kthread_work(&byt->kwork, sst_byt_ipc_tx_msgs); | ||
915 | 706 | ||
707 | INIT_LIST_HEAD(&byt->stream_list); | ||
708 | init_waitqueue_head(&byt->boot_wait); | ||
916 | byt_dev.thread_context = byt; | 709 | byt_dev.thread_context = byt; |
917 | 710 | ||
918 | /* init SST shim */ | 711 | /* init SST shim */ |
919 | byt->dsp = sst_dsp_new(dev, &byt_dev, pdata); | 712 | byt->dsp = sst_dsp_new(dev, &byt_dev, pdata); |
920 | if (byt->dsp == NULL) { | 713 | if (byt->dsp == NULL) { |
921 | err = -ENODEV; | 714 | err = -ENODEV; |
922 | goto dsp_err; | 715 | goto dsp_new_err; |
923 | } | 716 | } |
924 | 717 | ||
718 | ipc->dsp = byt->dsp; | ||
719 | |||
925 | /* keep the DSP in reset state for base FW loading */ | 720 | /* keep the DSP in reset state for base FW loading */ |
926 | sst_dsp_reset(byt->dsp); | 721 | sst_dsp_reset(byt->dsp); |
927 | 722 | ||
@@ -961,10 +756,10 @@ boot_err: | |||
961 | sst_fw_free(byt_sst_fw); | 756 | sst_fw_free(byt_sst_fw); |
962 | fw_err: | 757 | fw_err: |
963 | sst_dsp_free(byt->dsp); | 758 | sst_dsp_free(byt->dsp); |
964 | dsp_err: | 759 | dsp_new_err: |
965 | kthread_stop(byt->tx_thread); | 760 | sst_ipc_fini(ipc); |
966 | err_free_msg: | 761 | ipc_init_err: |
967 | kfree(byt->msg); | 762 | kfree(byt); |
968 | 763 | ||
969 | return err; | 764 | return err; |
970 | } | 765 | } |
@@ -977,7 +772,6 @@ void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata) | |||
977 | sst_dsp_reset(byt->dsp); | 772 | sst_dsp_reset(byt->dsp); |
978 | sst_fw_free_all(byt->dsp); | 773 | sst_fw_free_all(byt->dsp); |
979 | sst_dsp_free(byt->dsp); | 774 | sst_dsp_free(byt->dsp); |
980 | kthread_stop(byt->tx_thread); | 775 | sst_ipc_fini(&byt->ipc); |
981 | kfree(byt->msg); | ||
982 | } | 776 | } |
983 | EXPORT_SYMBOL_GPL(sst_byt_dsp_free); | 777 | EXPORT_SYMBOL_GPL(sst_byt_dsp_free); |
diff --git a/sound/soc/intel/sst-baytrail-ipc.h b/sound/soc/intel/baytrail/sst-baytrail-ipc.h index 8faff6dcf25d..8faff6dcf25d 100644 --- a/sound/soc/intel/sst-baytrail-ipc.h +++ b/sound/soc/intel/baytrail/sst-baytrail-ipc.h | |||
diff --git a/sound/soc/intel/sst-baytrail-pcm.c b/sound/soc/intel/baytrail/sst-baytrail-pcm.c index 224c49c9f135..79547bec558b 100644 --- a/sound/soc/intel/sst-baytrail-pcm.c +++ b/sound/soc/intel/baytrail/sst-baytrail-pcm.c | |||
@@ -20,8 +20,8 @@ | |||
20 | #include <sound/pcm_params.h> | 20 | #include <sound/pcm_params.h> |
21 | #include <sound/soc.h> | 21 | #include <sound/soc.h> |
22 | #include "sst-baytrail-ipc.h" | 22 | #include "sst-baytrail-ipc.h" |
23 | #include "sst-dsp-priv.h" | 23 | #include "../common/sst-dsp-priv.h" |
24 | #include "sst-dsp.h" | 24 | #include "../common/sst-dsp.h" |
25 | 25 | ||
26 | #define BYT_PCM_COUNT 2 | 26 | #define BYT_PCM_COUNT 2 |
27 | 27 | ||
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile new file mode 100644 index 000000000000..f8237f0044eb --- /dev/null +++ b/sound/soc/intel/boards/Makefile | |||
@@ -0,0 +1,15 @@ | |||
1 | snd-soc-sst-haswell-objs := haswell.o | ||
2 | snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o | ||
3 | snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o | ||
4 | snd-soc-sst-broadwell-objs := broadwell.o | ||
5 | snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o | ||
6 | snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o | ||
7 | snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o | ||
8 | |||
9 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o | ||
10 | obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o | ||
11 | obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o | ||
12 | obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o | ||
13 | obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o | ||
14 | obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o | ||
15 | obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o | ||
diff --git a/sound/soc/intel/broadwell.c b/sound/soc/intel/boards/broadwell.c index fc5542034b9b..8bafaf6ceab1 100644 --- a/sound/soc/intel/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c | |||
@@ -22,10 +22,10 @@ | |||
22 | #include <sound/jack.h> | 22 | #include <sound/jack.h> |
23 | #include <sound/pcm_params.h> | 23 | #include <sound/pcm_params.h> |
24 | 24 | ||
25 | #include "sst-dsp.h" | 25 | #include "../common/sst-dsp.h" |
26 | #include "sst-haswell-ipc.h" | 26 | #include "../haswell/sst-haswell-ipc.h" |
27 | 27 | ||
28 | #include "../codecs/rt286.h" | 28 | #include "../../codecs/rt286.h" |
29 | 29 | ||
30 | static struct snd_soc_jack broadwell_headset; | 30 | static struct snd_soc_jack broadwell_headset; |
31 | /* Headset jack detection DAPM pins */ | 31 | /* Headset jack detection DAPM pins */ |
@@ -219,6 +219,32 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { | |||
219 | }, | 219 | }, |
220 | }; | 220 | }; |
221 | 221 | ||
222 | static int broadwell_suspend(struct snd_soc_card *card){ | ||
223 | struct snd_soc_codec *codec; | ||
224 | |||
225 | list_for_each_entry(codec, &card->codec_dev_list, card_list) { | ||
226 | if (!strcmp(codec->component.name, "i2c-INT343A:00")) { | ||
227 | dev_dbg(codec->dev, "disabling jack detect before going to suspend.\n"); | ||
228 | rt286_mic_detect(codec, NULL); | ||
229 | break; | ||
230 | } | ||
231 | } | ||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | static int broadwell_resume(struct snd_soc_card *card){ | ||
236 | struct snd_soc_codec *codec; | ||
237 | |||
238 | list_for_each_entry(codec, &card->codec_dev_list, card_list) { | ||
239 | if (!strcmp(codec->component.name, "i2c-INT343A:00")) { | ||
240 | dev_dbg(codec->dev, "enabling jack detect for resume.\n"); | ||
241 | rt286_mic_detect(codec, &broadwell_headset); | ||
242 | break; | ||
243 | } | ||
244 | } | ||
245 | return 0; | ||
246 | } | ||
247 | |||
222 | /* broadwell audio machine driver for WPT + RT286S */ | 248 | /* broadwell audio machine driver for WPT + RT286S */ |
223 | static struct snd_soc_card broadwell_rt286 = { | 249 | static struct snd_soc_card broadwell_rt286 = { |
224 | .name = "broadwell-rt286", | 250 | .name = "broadwell-rt286", |
@@ -232,6 +258,8 @@ static struct snd_soc_card broadwell_rt286 = { | |||
232 | .dapm_routes = broadwell_rt286_map, | 258 | .dapm_routes = broadwell_rt286_map, |
233 | .num_dapm_routes = ARRAY_SIZE(broadwell_rt286_map), | 259 | .num_dapm_routes = ARRAY_SIZE(broadwell_rt286_map), |
234 | .fully_routed = true, | 260 | .fully_routed = true, |
261 | .suspend_pre = broadwell_suspend, | ||
262 | .resume_post = broadwell_resume, | ||
235 | }; | 263 | }; |
236 | 264 | ||
237 | static int broadwell_audio_probe(struct platform_device *pdev) | 265 | static int broadwell_audio_probe(struct platform_device *pdev) |
diff --git a/sound/soc/intel/byt-max98090.c b/sound/soc/intel/boards/byt-max98090.c index d8b1f038da1c..7ab8cc9fbfd5 100644 --- a/sound/soc/intel/byt-max98090.c +++ b/sound/soc/intel/boards/byt-max98090.c | |||
@@ -24,7 +24,7 @@ | |||
24 | #include <sound/pcm_params.h> | 24 | #include <sound/pcm_params.h> |
25 | #include <sound/soc.h> | 25 | #include <sound/soc.h> |
26 | #include <sound/jack.h> | 26 | #include <sound/jack.h> |
27 | #include "../codecs/max98090.h" | 27 | #include "../../codecs/max98090.h" |
28 | 28 | ||
29 | struct byt_max98090_private { | 29 | struct byt_max98090_private { |
30 | struct snd_soc_jack jack; | 30 | struct snd_soc_jack jack; |
diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/boards/byt-rt5640.c index 354eaad886e1..ae89b9b966d9 100644 --- a/sound/soc/intel/byt-rt5640.c +++ b/sound/soc/intel/boards/byt-rt5640.c | |||
@@ -23,9 +23,9 @@ | |||
23 | #include <sound/pcm_params.h> | 23 | #include <sound/pcm_params.h> |
24 | #include <sound/soc.h> | 24 | #include <sound/soc.h> |
25 | #include <sound/jack.h> | 25 | #include <sound/jack.h> |
26 | #include "../codecs/rt5640.h" | 26 | #include "../../codecs/rt5640.h" |
27 | 27 | ||
28 | #include "sst-dsp.h" | 28 | #include "../common/sst-dsp.h" |
29 | 29 | ||
30 | static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = { | 30 | static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = { |
31 | SND_SOC_DAPM_HP("Headphone", NULL), | 31 | SND_SOC_DAPM_HP("Headphone", NULL), |
diff --git a/sound/soc/intel/bytcr_dpcm_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 3b262d01c1b3..7f55d59024a8 100644 --- a/sound/soc/intel/bytcr_dpcm_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c | |||
@@ -26,8 +26,8 @@ | |||
26 | #include <sound/pcm.h> | 26 | #include <sound/pcm.h> |
27 | #include <sound/pcm_params.h> | 27 | #include <sound/pcm_params.h> |
28 | #include <sound/soc.h> | 28 | #include <sound/soc.h> |
29 | #include "../codecs/rt5640.h" | 29 | #include "../../codecs/rt5640.h" |
30 | #include "sst-atom-controls.h" | 30 | #include "../atom/sst-atom-controls.h" |
31 | 31 | ||
32 | static const struct snd_soc_dapm_widget byt_dapm_widgets[] = { | 32 | static const struct snd_soc_dapm_widget byt_dapm_widgets[] = { |
33 | SND_SOC_DAPM_HP("Headphone", NULL), | 33 | SND_SOC_DAPM_HP("Headphone", NULL), |
diff --git a/sound/soc/intel/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 012227997ed9..20a28b22e30f 100644 --- a/sound/soc/intel/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c | |||
@@ -27,8 +27,8 @@ | |||
27 | #include <sound/pcm_params.h> | 27 | #include <sound/pcm_params.h> |
28 | #include <sound/soc.h> | 28 | #include <sound/soc.h> |
29 | #include <sound/jack.h> | 29 | #include <sound/jack.h> |
30 | #include "../codecs/rt5645.h" | 30 | #include "../../codecs/rt5645.h" |
31 | #include "sst-atom-controls.h" | 31 | #include "../atom/sst-atom-controls.h" |
32 | 32 | ||
33 | #define CHT_PLAT_CLK_3_HZ 19200000 | 33 | #define CHT_PLAT_CLK_3_HZ 19200000 |
34 | #define CHT_CODEC_DAI "rt5645-aif1" | 34 | #define CHT_CODEC_DAI "rt5645-aif1" |
diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index bc8dcacd5e6a..2c9cc5be439e 100644 --- a/sound/soc/intel/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c | |||
@@ -22,13 +22,28 @@ | |||
22 | #include <sound/pcm.h> | 22 | #include <sound/pcm.h> |
23 | #include <sound/pcm_params.h> | 23 | #include <sound/pcm_params.h> |
24 | #include <sound/soc.h> | 24 | #include <sound/soc.h> |
25 | #include "../codecs/rt5670.h" | 25 | #include <sound/jack.h> |
26 | #include "sst-atom-controls.h" | 26 | #include "../../codecs/rt5670.h" |
27 | #include "../atom/sst-atom-controls.h" | ||
27 | 28 | ||
28 | /* The platform clock #3 outputs 19.2Mhz clock to codec as I2S MCLK */ | 29 | /* The platform clock #3 outputs 19.2Mhz clock to codec as I2S MCLK */ |
29 | #define CHT_PLAT_CLK_3_HZ 19200000 | 30 | #define CHT_PLAT_CLK_3_HZ 19200000 |
30 | #define CHT_CODEC_DAI "rt5670-aif1" | 31 | #define CHT_CODEC_DAI "rt5670-aif1" |
31 | 32 | ||
33 | static struct snd_soc_jack cht_bsw_headset; | ||
34 | |||
35 | /* Headset jack detection DAPM pins */ | ||
36 | static struct snd_soc_jack_pin cht_bsw_headset_pins[] = { | ||
37 | { | ||
38 | .pin = "Headset Mic", | ||
39 | .mask = SND_JACK_MICROPHONE, | ||
40 | }, | ||
41 | { | ||
42 | .pin = "Headphone", | ||
43 | .mask = SND_JACK_HEADPHONE, | ||
44 | }, | ||
45 | }; | ||
46 | |||
32 | static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) | 47 | static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) |
33 | { | 48 | { |
34 | int i; | 49 | int i; |
@@ -50,6 +65,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, | |||
50 | struct snd_soc_dapm_context *dapm = w->dapm; | 65 | struct snd_soc_dapm_context *dapm = w->dapm; |
51 | struct snd_soc_card *card = dapm->card; | 66 | struct snd_soc_card *card = dapm->card; |
52 | struct snd_soc_dai *codec_dai; | 67 | struct snd_soc_dai *codec_dai; |
68 | int ret; | ||
53 | 69 | ||
54 | codec_dai = cht_get_codec_dai(card); | 70 | codec_dai = cht_get_codec_dai(card); |
55 | if (!codec_dai) { | 71 | if (!codec_dai) { |
@@ -57,17 +73,31 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, | |||
57 | return -EIO; | 73 | return -EIO; |
58 | } | 74 | } |
59 | 75 | ||
60 | if (!SND_SOC_DAPM_EVENT_OFF(event)) | 76 | if (SND_SOC_DAPM_EVENT_ON(event)) { |
61 | return 0; | 77 | /* set codec PLL source to the 19.2MHz platform clock (MCLK) */ |
62 | 78 | ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_MCLK, | |
63 | /* Set codec sysclk source to its internal clock because codec PLL will | 79 | CHT_PLAT_CLK_3_HZ, 48000 * 512); |
64 | * be off when idle and MCLK will also be off by ACPI when codec is | 80 | if (ret < 0) { |
65 | * runtime suspended. Codec needs clock for jack detection and button | 81 | dev_err(card->dev, "can't set codec pll: %d\n", ret); |
66 | * press. | 82 | return ret; |
67 | */ | 83 | } |
68 | snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK, | 84 | |
69 | 0, SND_SOC_CLOCK_IN); | 85 | /* set codec sysclk source to PLL */ |
70 | 86 | ret = snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_PLL1, | |
87 | 48000 * 512, SND_SOC_CLOCK_IN); | ||
88 | if (ret < 0) { | ||
89 | dev_err(card->dev, "can't set codec sysclk: %d\n", ret); | ||
90 | return ret; | ||
91 | } | ||
92 | } else { | ||
93 | /* Set codec sysclk source to its internal clock because codec | ||
94 | * PLL will be off when idle and MCLK will also be off by ACPI | ||
95 | * when codec is runtime suspended. Codec needs clock for jack | ||
96 | * detection and button press. | ||
97 | */ | ||
98 | snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK, | ||
99 | 48000 * 512, SND_SOC_CLOCK_IN); | ||
100 | } | ||
71 | return 0; | 101 | return 0; |
72 | } | 102 | } |
73 | 103 | ||
@@ -77,7 +107,8 @@ static const struct snd_soc_dapm_widget cht_dapm_widgets[] = { | |||
77 | SND_SOC_DAPM_MIC("Int Mic", NULL), | 107 | SND_SOC_DAPM_MIC("Int Mic", NULL), |
78 | SND_SOC_DAPM_SPK("Ext Spk", NULL), | 108 | SND_SOC_DAPM_SPK("Ext Spk", NULL), |
79 | SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, | 109 | SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, |
80 | platform_clock_control, SND_SOC_DAPM_POST_PMD), | 110 | platform_clock_control, SND_SOC_DAPM_PRE_PMU | |
111 | SND_SOC_DAPM_POST_PMD), | ||
81 | }; | 112 | }; |
82 | 113 | ||
83 | static const struct snd_soc_dapm_route cht_audio_map[] = { | 114 | static const struct snd_soc_dapm_route cht_audio_map[] = { |
@@ -162,6 +193,15 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) | |||
162 | | RT5670_AD_MONO_L_FILTER | 193 | | RT5670_AD_MONO_L_FILTER |
163 | | RT5670_AD_MONO_R_FILTER, | 194 | | RT5670_AD_MONO_R_FILTER, |
164 | RT5670_CLK_SEL_I2S1_ASRC); | 195 | RT5670_CLK_SEL_I2S1_ASRC); |
196 | |||
197 | ret = snd_soc_card_jack_new(runtime->card, "Headset", | ||
198 | SND_JACK_HEADSET | SND_JACK_BTN_0 | | ||
199 | SND_JACK_BTN_1 | SND_JACK_BTN_2, &cht_bsw_headset, | ||
200 | cht_bsw_headset_pins, ARRAY_SIZE(cht_bsw_headset_pins)); | ||
201 | if (ret) | ||
202 | return ret; | ||
203 | |||
204 | rt5670_set_jack_detect(codec, &cht_bsw_headset); | ||
165 | return 0; | 205 | return 0; |
166 | } | 206 | } |
167 | 207 | ||
@@ -251,6 +291,35 @@ static struct snd_soc_dai_link cht_dailink[] = { | |||
251 | }, | 291 | }, |
252 | }; | 292 | }; |
253 | 293 | ||
294 | static int cht_suspend_pre(struct snd_soc_card *card) | ||
295 | { | ||
296 | struct snd_soc_codec *codec; | ||
297 | |||
298 | list_for_each_entry(codec, &card->codec_dev_list, card_list) { | ||
299 | if (!strcmp(codec->component.name, "i2c-10EC5670:00")) { | ||
300 | dev_dbg(codec->dev, "disabling jack detect before going to suspend.\n"); | ||
301 | rt5670_jack_suspend(codec); | ||
302 | break; | ||
303 | } | ||
304 | } | ||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | static int cht_resume_post(struct snd_soc_card *card) | ||
309 | { | ||
310 | struct snd_soc_codec *codec; | ||
311 | |||
312 | list_for_each_entry(codec, &card->codec_dev_list, card_list) { | ||
313 | if (!strcmp(codec->component.name, "i2c-10EC5670:00")) { | ||
314 | dev_dbg(codec->dev, "enabling jack detect for resume.\n"); | ||
315 | rt5670_jack_resume(codec); | ||
316 | break; | ||
317 | } | ||
318 | } | ||
319 | |||
320 | return 0; | ||
321 | } | ||
322 | |||
254 | /* SoC card */ | 323 | /* SoC card */ |
255 | static struct snd_soc_card snd_soc_card_cht = { | 324 | static struct snd_soc_card snd_soc_card_cht = { |
256 | .name = "cherrytrailcraudio", | 325 | .name = "cherrytrailcraudio", |
@@ -262,6 +331,8 @@ static struct snd_soc_card snd_soc_card_cht = { | |||
262 | .num_dapm_routes = ARRAY_SIZE(cht_audio_map), | 331 | .num_dapm_routes = ARRAY_SIZE(cht_audio_map), |
263 | .controls = cht_mc_controls, | 332 | .controls = cht_mc_controls, |
264 | .num_controls = ARRAY_SIZE(cht_mc_controls), | 333 | .num_controls = ARRAY_SIZE(cht_mc_controls), |
334 | .suspend_pre = cht_suspend_pre, | ||
335 | .resume_post = cht_resume_post, | ||
265 | }; | 336 | }; |
266 | 337 | ||
267 | static int snd_cht_mc_probe(struct platform_device *pdev) | 338 | static int snd_cht_mc_probe(struct platform_device *pdev) |
diff --git a/sound/soc/intel/haswell.c b/sound/soc/intel/boards/haswell.c index 00fddd3f5dfb..22558572cb9c 100644 --- a/sound/soc/intel/haswell.c +++ b/sound/soc/intel/boards/haswell.c | |||
@@ -21,10 +21,10 @@ | |||
21 | #include <sound/soc.h> | 21 | #include <sound/soc.h> |
22 | #include <sound/pcm_params.h> | 22 | #include <sound/pcm_params.h> |
23 | 23 | ||
24 | #include "sst-dsp.h" | 24 | #include "../common/sst-dsp.h" |
25 | #include "sst-haswell-ipc.h" | 25 | #include "../haswell/sst-haswell-ipc.h" |
26 | 26 | ||
27 | #include "../codecs/rt5640.h" | 27 | #include "../../codecs/rt5640.h" |
28 | 28 | ||
29 | /* Haswell ULT platforms have a Headphone and Mic jack */ | 29 | /* Haswell ULT platforms have a Headphone and Mic jack */ |
30 | static const struct snd_soc_dapm_widget haswell_widgets[] = { | 30 | static const struct snd_soc_dapm_widget haswell_widgets[] = { |
diff --git a/sound/soc/intel/mfld_machine.c b/sound/soc/intel/boards/mfld_machine.c index 49c09a0add79..49c09a0add79 100644 --- a/sound/soc/intel/mfld_machine.c +++ b/sound/soc/intel/boards/mfld_machine.c | |||
diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile new file mode 100644 index 000000000000..f24154ca4e98 --- /dev/null +++ b/sound/soc/intel/common/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | snd-soc-sst-dsp-objs := sst-dsp.o sst-firmware.o | ||
2 | snd-soc-sst-acpi-objs := sst-acpi.o | ||
3 | snd-soc-sst-ipc-objs := sst-ipc.o | ||
4 | |||
5 | obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o | ||
6 | obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o | ||
7 | |||
diff --git a/sound/soc/intel/sst-acpi.c b/sound/soc/intel/common/sst-acpi.c index 42f293f9c6e2..42f293f9c6e2 100644 --- a/sound/soc/intel/sst-acpi.c +++ b/sound/soc/intel/common/sst-acpi.c | |||
diff --git a/sound/soc/intel/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h index b9da030e312d..396d54510350 100644 --- a/sound/soc/intel/sst-dsp-priv.h +++ b/sound/soc/intel/common/sst-dsp-priv.h | |||
@@ -173,6 +173,16 @@ struct sst_module_runtime_context { | |||
173 | }; | 173 | }; |
174 | 174 | ||
175 | /* | 175 | /* |
176 | * Audio DSP Module State | ||
177 | */ | ||
178 | enum sst_module_state { | ||
179 | SST_MODULE_STATE_UNLOADED = 0, /* default state */ | ||
180 | SST_MODULE_STATE_LOADED, | ||
181 | SST_MODULE_STATE_INITIALIZED, /* and inactive */ | ||
182 | SST_MODULE_STATE_ACTIVE, | ||
183 | }; | ||
184 | |||
185 | /* | ||
176 | * Audio DSP Generic Module. | 186 | * Audio DSP Generic Module. |
177 | * | 187 | * |
178 | * Each Firmware file can consist of 1..N modules. A module can span multiple | 188 | * Each Firmware file can consist of 1..N modules. A module can span multiple |
@@ -203,6 +213,9 @@ struct sst_module { | |||
203 | struct list_head list; /* DSP list of modules */ | 213 | struct list_head list; /* DSP list of modules */ |
204 | struct list_head list_fw; /* FW list of modules */ | 214 | struct list_head list_fw; /* FW list of modules */ |
205 | struct list_head runtime_list; /* list of runtime module objects*/ | 215 | struct list_head runtime_list; /* list of runtime module objects*/ |
216 | |||
217 | /* state */ | ||
218 | enum sst_module_state state; | ||
206 | }; | 219 | }; |
207 | 220 | ||
208 | /* | 221 | /* |
diff --git a/sound/soc/intel/sst-dsp.c b/sound/soc/intel/common/sst-dsp.c index 64e94212d2d2..64e94212d2d2 100644 --- a/sound/soc/intel/sst-dsp.c +++ b/sound/soc/intel/common/sst-dsp.c | |||
diff --git a/sound/soc/intel/sst-dsp.h b/sound/soc/intel/common/sst-dsp.h index 148d8c589a43..96aeb2556ad4 100644 --- a/sound/soc/intel/sst-dsp.h +++ b/sound/soc/intel/common/sst-dsp.h | |||
@@ -28,7 +28,6 @@ | |||
28 | 28 | ||
29 | /* Supported SST DMA Devices */ | 29 | /* Supported SST DMA Devices */ |
30 | #define SST_DMA_TYPE_DW 1 | 30 | #define SST_DMA_TYPE_DW 1 |
31 | #define SST_DMA_TYPE_MID 2 | ||
32 | 31 | ||
33 | /* autosuspend delay 5s*/ | 32 | /* autosuspend delay 5s*/ |
34 | #define SST_RUNTIME_SUSPEND_DELAY (5 * 1000) | 33 | #define SST_RUNTIME_SUSPEND_DELAY (5 * 1000) |
diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/common/sst-firmware.c index 4a993d16a235..ebcca6dc48d1 100644 --- a/sound/soc/intel/sst-firmware.c +++ b/sound/soc/intel/common/sst-firmware.c | |||
@@ -221,8 +221,6 @@ int sst_dsp_dma_get_channel(struct sst_dsp *dsp, int chan_id) | |||
221 | dma_cap_mask_t mask; | 221 | dma_cap_mask_t mask; |
222 | int ret; | 222 | int ret; |
223 | 223 | ||
224 | /* The Intel MID DMA engine driver needs the slave config set but | ||
225 | * Synopsis DMA engine driver safely ignores the slave config */ | ||
226 | dma_cap_zero(mask); | 224 | dma_cap_zero(mask); |
227 | dma_cap_set(DMA_SLAVE, mask); | 225 | dma_cap_set(DMA_SLAVE, mask); |
228 | dma_cap_set(DMA_MEMCPY, mask); | 226 | dma_cap_set(DMA_MEMCPY, mask); |
@@ -281,9 +279,6 @@ int sst_dma_new(struct sst_dsp *sst) | |||
281 | case SST_DMA_TYPE_DW: | 279 | case SST_DMA_TYPE_DW: |
282 | dma_dev_name = "dw_dmac"; | 280 | dma_dev_name = "dw_dmac"; |
283 | break; | 281 | break; |
284 | case SST_DMA_TYPE_MID: | ||
285 | dma_dev_name = "Intel MID DMA"; | ||
286 | break; | ||
287 | default: | 282 | default: |
288 | dev_err(sst->dev, "error: invalid DMA engine %d\n", | 283 | dev_err(sst->dev, "error: invalid DMA engine %d\n", |
289 | sst->pdata->dma_engine); | 284 | sst->pdata->dma_engine); |
@@ -502,6 +497,7 @@ struct sst_module *sst_module_new(struct sst_fw *sst_fw, | |||
502 | sst_module->scratch_size = template->scratch_size; | 497 | sst_module->scratch_size = template->scratch_size; |
503 | sst_module->persistent_size = template->persistent_size; | 498 | sst_module->persistent_size = template->persistent_size; |
504 | sst_module->entry = template->entry; | 499 | sst_module->entry = template->entry; |
500 | sst_module->state = SST_MODULE_STATE_UNLOADED; | ||
505 | 501 | ||
506 | INIT_LIST_HEAD(&sst_module->block_list); | 502 | INIT_LIST_HEAD(&sst_module->block_list); |
507 | INIT_LIST_HEAD(&sst_module->runtime_list); | 503 | INIT_LIST_HEAD(&sst_module->runtime_list); |
diff --git a/sound/soc/intel/common/sst-ipc.c b/sound/soc/intel/common/sst-ipc.c new file mode 100644 index 000000000000..4b62a553823c --- /dev/null +++ b/sound/soc/intel/common/sst-ipc.c | |||
@@ -0,0 +1,294 @@ | |||
1 | /* | ||
2 | * Intel SST generic IPC Support | ||
3 | * | ||
4 | * Copyright (C) 2015, Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/types.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/list.h> | ||
20 | #include <linux/wait.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/spinlock.h> | ||
23 | #include <linux/device.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/workqueue.h> | ||
26 | #include <linux/sched.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <linux/platform_device.h> | ||
29 | #include <linux/kthread.h> | ||
30 | #include <sound/asound.h> | ||
31 | |||
32 | #include "sst-dsp.h" | ||
33 | #include "sst-dsp-priv.h" | ||
34 | #include "sst-ipc.h" | ||
35 | |||
36 | /* IPC message timeout (msecs) */ | ||
37 | #define IPC_TIMEOUT_MSECS 300 | ||
38 | |||
39 | #define IPC_EMPTY_LIST_SIZE 8 | ||
40 | |||
41 | /* locks held by caller */ | ||
42 | static struct ipc_message *msg_get_empty(struct sst_generic_ipc *ipc) | ||
43 | { | ||
44 | struct ipc_message *msg = NULL; | ||
45 | |||
46 | if (!list_empty(&ipc->empty_list)) { | ||
47 | msg = list_first_entry(&ipc->empty_list, struct ipc_message, | ||
48 | list); | ||
49 | list_del(&msg->list); | ||
50 | } | ||
51 | |||
52 | return msg; | ||
53 | } | ||
54 | |||
55 | static int tx_wait_done(struct sst_generic_ipc *ipc, | ||
56 | struct ipc_message *msg, void *rx_data) | ||
57 | { | ||
58 | unsigned long flags; | ||
59 | int ret; | ||
60 | |||
61 | /* wait for DSP completion (in all cases atm inc pending) */ | ||
62 | ret = wait_event_timeout(msg->waitq, msg->complete, | ||
63 | msecs_to_jiffies(IPC_TIMEOUT_MSECS)); | ||
64 | |||
65 | spin_lock_irqsave(&ipc->dsp->spinlock, flags); | ||
66 | if (ret == 0) { | ||
67 | if (ipc->ops.shim_dbg != NULL) | ||
68 | ipc->ops.shim_dbg(ipc, "message timeout"); | ||
69 | |||
70 | list_del(&msg->list); | ||
71 | ret = -ETIMEDOUT; | ||
72 | } else { | ||
73 | |||
74 | /* copy the data returned from DSP */ | ||
75 | if (msg->rx_size) | ||
76 | memcpy(rx_data, msg->rx_data, msg->rx_size); | ||
77 | ret = msg->errno; | ||
78 | } | ||
79 | |||
80 | list_add_tail(&msg->list, &ipc->empty_list); | ||
81 | spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); | ||
82 | return ret; | ||
83 | } | ||
84 | |||
85 | static int ipc_tx_message(struct sst_generic_ipc *ipc, u64 header, | ||
86 | void *tx_data, size_t tx_bytes, void *rx_data, | ||
87 | size_t rx_bytes, int wait) | ||
88 | { | ||
89 | struct ipc_message *msg; | ||
90 | unsigned long flags; | ||
91 | |||
92 | spin_lock_irqsave(&ipc->dsp->spinlock, flags); | ||
93 | |||
94 | msg = msg_get_empty(ipc); | ||
95 | if (msg == NULL) { | ||
96 | spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); | ||
97 | return -EBUSY; | ||
98 | } | ||
99 | |||
100 | msg->header = header; | ||
101 | msg->tx_size = tx_bytes; | ||
102 | msg->rx_size = rx_bytes; | ||
103 | msg->wait = wait; | ||
104 | msg->errno = 0; | ||
105 | msg->pending = false; | ||
106 | msg->complete = false; | ||
107 | |||
108 | if ((tx_bytes) && (ipc->ops.tx_data_copy != NULL)) | ||
109 | ipc->ops.tx_data_copy(msg, tx_data, tx_bytes); | ||
110 | |||
111 | list_add_tail(&msg->list, &ipc->tx_list); | ||
112 | spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); | ||
113 | |||
114 | queue_kthread_work(&ipc->kworker, &ipc->kwork); | ||
115 | |||
116 | if (wait) | ||
117 | return tx_wait_done(ipc, msg, rx_data); | ||
118 | else | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | static int msg_empty_list_init(struct sst_generic_ipc *ipc) | ||
123 | { | ||
124 | int i; | ||
125 | |||
126 | ipc->msg = kzalloc(sizeof(struct ipc_message) * | ||
127 | IPC_EMPTY_LIST_SIZE, GFP_KERNEL); | ||
128 | if (ipc->msg == NULL) | ||
129 | return -ENOMEM; | ||
130 | |||
131 | for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { | ||
132 | init_waitqueue_head(&ipc->msg[i].waitq); | ||
133 | list_add(&ipc->msg[i].list, &ipc->empty_list); | ||
134 | } | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | static void ipc_tx_msgs(struct kthread_work *work) | ||
140 | { | ||
141 | struct sst_generic_ipc *ipc = | ||
142 | container_of(work, struct sst_generic_ipc, kwork); | ||
143 | struct ipc_message *msg; | ||
144 | unsigned long flags; | ||
145 | u64 ipcx; | ||
146 | |||
147 | spin_lock_irqsave(&ipc->dsp->spinlock, flags); | ||
148 | |||
149 | if (list_empty(&ipc->tx_list) || ipc->pending) { | ||
150 | spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); | ||
151 | return; | ||
152 | } | ||
153 | |||
154 | /* if the DSP is busy, we will TX messages after IRQ. | ||
155 | * also postpone if we are in the middle of procesing completion irq*/ | ||
156 | ipcx = sst_dsp_shim_read_unlocked(ipc->dsp, SST_IPCX); | ||
157 | if (ipcx & (SST_IPCX_BUSY | SST_IPCX_DONE)) { | ||
158 | spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); | ||
159 | return; | ||
160 | } | ||
161 | |||
162 | msg = list_first_entry(&ipc->tx_list, struct ipc_message, list); | ||
163 | list_move(&msg->list, &ipc->rx_list); | ||
164 | |||
165 | if (ipc->ops.tx_msg != NULL) | ||
166 | ipc->ops.tx_msg(ipc, msg); | ||
167 | |||
168 | spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); | ||
169 | } | ||
170 | |||
171 | int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header, | ||
172 | void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes) | ||
173 | { | ||
174 | return ipc_tx_message(ipc, header, tx_data, tx_bytes, | ||
175 | rx_data, rx_bytes, 1); | ||
176 | } | ||
177 | EXPORT_SYMBOL_GPL(sst_ipc_tx_message_wait); | ||
178 | |||
179 | int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, u64 header, | ||
180 | void *tx_data, size_t tx_bytes) | ||
181 | { | ||
182 | return ipc_tx_message(ipc, header, tx_data, tx_bytes, | ||
183 | NULL, 0, 0); | ||
184 | } | ||
185 | EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nowait); | ||
186 | |||
187 | struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc, | ||
188 | u64 header) | ||
189 | { | ||
190 | struct ipc_message *msg; | ||
191 | u64 mask; | ||
192 | |||
193 | if (ipc->ops.reply_msg_match != NULL) | ||
194 | header = ipc->ops.reply_msg_match(header, &mask); | ||
195 | |||
196 | if (list_empty(&ipc->rx_list)) { | ||
197 | dev_err(ipc->dev, "error: rx list empty but received 0x%llx\n", | ||
198 | header); | ||
199 | return NULL; | ||
200 | } | ||
201 | |||
202 | list_for_each_entry(msg, &ipc->rx_list, list) { | ||
203 | if ((msg->header & mask) == header) | ||
204 | return msg; | ||
205 | } | ||
206 | |||
207 | return NULL; | ||
208 | } | ||
209 | EXPORT_SYMBOL_GPL(sst_ipc_reply_find_msg); | ||
210 | |||
211 | /* locks held by caller */ | ||
212 | void sst_ipc_tx_msg_reply_complete(struct sst_generic_ipc *ipc, | ||
213 | struct ipc_message *msg) | ||
214 | { | ||
215 | msg->complete = true; | ||
216 | |||
217 | if (!msg->wait) | ||
218 | list_add_tail(&msg->list, &ipc->empty_list); | ||
219 | else | ||
220 | wake_up(&msg->waitq); | ||
221 | } | ||
222 | EXPORT_SYMBOL_GPL(sst_ipc_tx_msg_reply_complete); | ||
223 | |||
224 | void sst_ipc_drop_all(struct sst_generic_ipc *ipc) | ||
225 | { | ||
226 | struct ipc_message *msg, *tmp; | ||
227 | unsigned long flags; | ||
228 | int tx_drop_cnt = 0, rx_drop_cnt = 0; | ||
229 | |||
230 | /* drop all TX and Rx messages before we stall + reset DSP */ | ||
231 | spin_lock_irqsave(&ipc->dsp->spinlock, flags); | ||
232 | |||
233 | list_for_each_entry_safe(msg, tmp, &ipc->tx_list, list) { | ||
234 | list_move(&msg->list, &ipc->empty_list); | ||
235 | tx_drop_cnt++; | ||
236 | } | ||
237 | |||
238 | list_for_each_entry_safe(msg, tmp, &ipc->rx_list, list) { | ||
239 | list_move(&msg->list, &ipc->empty_list); | ||
240 | rx_drop_cnt++; | ||
241 | } | ||
242 | |||
243 | spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); | ||
244 | |||
245 | if (tx_drop_cnt || rx_drop_cnt) | ||
246 | dev_err(ipc->dev, "dropped IPC msg RX=%d, TX=%d\n", | ||
247 | tx_drop_cnt, rx_drop_cnt); | ||
248 | } | ||
249 | EXPORT_SYMBOL_GPL(sst_ipc_drop_all); | ||
250 | |||
251 | int sst_ipc_init(struct sst_generic_ipc *ipc) | ||
252 | { | ||
253 | int ret; | ||
254 | |||
255 | INIT_LIST_HEAD(&ipc->tx_list); | ||
256 | INIT_LIST_HEAD(&ipc->rx_list); | ||
257 | INIT_LIST_HEAD(&ipc->empty_list); | ||
258 | init_waitqueue_head(&ipc->wait_txq); | ||
259 | |||
260 | ret = msg_empty_list_init(ipc); | ||
261 | if (ret < 0) | ||
262 | return -ENOMEM; | ||
263 | |||
264 | /* start the IPC message thread */ | ||
265 | init_kthread_worker(&ipc->kworker); | ||
266 | ipc->tx_thread = kthread_run(kthread_worker_fn, | ||
267 | &ipc->kworker, "%s", | ||
268 | dev_name(ipc->dev)); | ||
269 | if (IS_ERR(ipc->tx_thread)) { | ||
270 | dev_err(ipc->dev, "error: failed to create message TX task\n"); | ||
271 | ret = PTR_ERR(ipc->tx_thread); | ||
272 | kfree(ipc->msg); | ||
273 | return ret; | ||
274 | } | ||
275 | |||
276 | init_kthread_work(&ipc->kwork, ipc_tx_msgs); | ||
277 | return 0; | ||
278 | } | ||
279 | EXPORT_SYMBOL_GPL(sst_ipc_init); | ||
280 | |||
281 | void sst_ipc_fini(struct sst_generic_ipc *ipc) | ||
282 | { | ||
283 | if (ipc->tx_thread) | ||
284 | kthread_stop(ipc->tx_thread); | ||
285 | |||
286 | if (ipc->msg) | ||
287 | kfree(ipc->msg); | ||
288 | } | ||
289 | EXPORT_SYMBOL_GPL(sst_ipc_fini); | ||
290 | |||
291 | /* Module information */ | ||
292 | MODULE_AUTHOR("Jin Yao"); | ||
293 | MODULE_DESCRIPTION("Intel SST IPC generic"); | ||
294 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/intel/common/sst-ipc.h b/sound/soc/intel/common/sst-ipc.h new file mode 100644 index 000000000000..125ea451a373 --- /dev/null +++ b/sound/soc/intel/common/sst-ipc.h | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * Intel SST generic IPC Support | ||
3 | * | ||
4 | * Copyright (C) 2015, Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #ifndef __SST_GENERIC_IPC_H | ||
18 | #define __SST_GENERIC_IPC_H | ||
19 | |||
20 | #include <linux/types.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/wait.h> | ||
23 | #include <linux/list.h> | ||
24 | #include <linux/workqueue.h> | ||
25 | #include <linux/sched.h> | ||
26 | #include <linux/kthread.h> | ||
27 | |||
28 | #define IPC_MAX_MAILBOX_BYTES 256 | ||
29 | |||
30 | struct ipc_message { | ||
31 | struct list_head list; | ||
32 | u64 header; | ||
33 | |||
34 | /* direction wrt host CPU */ | ||
35 | char tx_data[IPC_MAX_MAILBOX_BYTES]; | ||
36 | size_t tx_size; | ||
37 | char rx_data[IPC_MAX_MAILBOX_BYTES]; | ||
38 | size_t rx_size; | ||
39 | |||
40 | wait_queue_head_t waitq; | ||
41 | bool pending; | ||
42 | bool complete; | ||
43 | bool wait; | ||
44 | int errno; | ||
45 | }; | ||
46 | |||
47 | struct sst_generic_ipc; | ||
48 | |||
49 | struct sst_plat_ipc_ops { | ||
50 | void (*tx_msg)(struct sst_generic_ipc *, struct ipc_message *); | ||
51 | void (*shim_dbg)(struct sst_generic_ipc *, const char *); | ||
52 | void (*tx_data_copy)(struct ipc_message *, char *, size_t); | ||
53 | u64 (*reply_msg_match)(u64 header, u64 *mask); | ||
54 | }; | ||
55 | |||
56 | /* SST generic IPC data */ | ||
57 | struct sst_generic_ipc { | ||
58 | struct device *dev; | ||
59 | struct sst_dsp *dsp; | ||
60 | |||
61 | /* IPC messaging */ | ||
62 | struct list_head tx_list; | ||
63 | struct list_head rx_list; | ||
64 | struct list_head empty_list; | ||
65 | wait_queue_head_t wait_txq; | ||
66 | struct task_struct *tx_thread; | ||
67 | struct kthread_worker kworker; | ||
68 | struct kthread_work kwork; | ||
69 | bool pending; | ||
70 | struct ipc_message *msg; | ||
71 | |||
72 | struct sst_plat_ipc_ops ops; | ||
73 | }; | ||
74 | |||
75 | int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header, | ||
76 | void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes); | ||
77 | |||
78 | int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, u64 header, | ||
79 | void *tx_data, size_t tx_bytes); | ||
80 | |||
81 | struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc, | ||
82 | u64 header); | ||
83 | |||
84 | void sst_ipc_tx_msg_reply_complete(struct sst_generic_ipc *ipc, | ||
85 | struct ipc_message *msg); | ||
86 | |||
87 | void sst_ipc_drop_all(struct sst_generic_ipc *ipc); | ||
88 | int sst_ipc_init(struct sst_generic_ipc *ipc); | ||
89 | void sst_ipc_fini(struct sst_generic_ipc *ipc); | ||
90 | |||
91 | #endif | ||
diff --git a/sound/soc/intel/haswell/Makefile b/sound/soc/intel/haswell/Makefile new file mode 100644 index 000000000000..9c1723112d22 --- /dev/null +++ b/sound/soc/intel/haswell/Makefile | |||
@@ -0,0 +1,4 @@ | |||
1 | snd-soc-sst-haswell-pcm-objs := \ | ||
2 | sst-haswell-ipc.o sst-haswell-pcm.o sst-haswell-dsp.o | ||
3 | |||
4 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += snd-soc-sst-haswell-pcm.o | ||
diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/haswell/sst-haswell-dsp.c index 402b728c0a06..7f94920c8a4d 100644 --- a/sound/soc/intel/sst-haswell-dsp.c +++ b/sound/soc/intel/haswell/sst-haswell-dsp.c | |||
@@ -28,9 +28,9 @@ | |||
28 | #include <linux/firmware.h> | 28 | #include <linux/firmware.h> |
29 | #include <linux/pm_runtime.h> | 29 | #include <linux/pm_runtime.h> |
30 | 30 | ||
31 | #include "sst-dsp.h" | 31 | #include "../common/sst-dsp.h" |
32 | #include "sst-dsp-priv.h" | 32 | #include "../common/sst-dsp-priv.h" |
33 | #include "sst-haswell-ipc.h" | 33 | #include "../haswell/sst-haswell-ipc.h" |
34 | 34 | ||
35 | #include <trace/events/hswadsp.h> | 35 | #include <trace/events/hswadsp.h> |
36 | 36 | ||
@@ -100,6 +100,7 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, | |||
100 | && module->type != SST_HSW_MODULE_PCM | 100 | && module->type != SST_HSW_MODULE_PCM |
101 | && module->type != SST_HSW_MODULE_PCM_REFERENCE | 101 | && module->type != SST_HSW_MODULE_PCM_REFERENCE |
102 | && module->type != SST_HSW_MODULE_PCM_CAPTURE | 102 | && module->type != SST_HSW_MODULE_PCM_CAPTURE |
103 | && module->type != SST_HSW_MODULE_WAVES | ||
103 | && module->type != SST_HSW_MODULE_LPAL) | 104 | && module->type != SST_HSW_MODULE_LPAL) |
104 | return 0; | 105 | return 0; |
105 | 106 | ||
@@ -139,6 +140,7 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, | |||
139 | mod->type = SST_MEM_IRAM; | 140 | mod->type = SST_MEM_IRAM; |
140 | break; | 141 | break; |
141 | case SST_HSW_DRAM: | 142 | case SST_HSW_DRAM: |
143 | case SST_HSW_REGS: | ||
142 | ram = dsp->addr.lpe; | 144 | ram = dsp->addr.lpe; |
143 | mod->offset = block->ram_offset; | 145 | mod->offset = block->ram_offset; |
144 | mod->type = SST_MEM_DRAM; | 146 | mod->type = SST_MEM_DRAM; |
@@ -169,6 +171,7 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, | |||
169 | 171 | ||
170 | block = (void *)block + sizeof(*block) + block->size; | 172 | block = (void *)block + sizeof(*block) + block->size; |
171 | } | 173 | } |
174 | mod->state = SST_MODULE_STATE_LOADED; | ||
172 | 175 | ||
173 | return 0; | 176 | return 0; |
174 | } | 177 | } |
diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c index 863a9ca34b8e..344a1e9bbce5 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/haswell/sst-haswell-ipc.c | |||
@@ -34,8 +34,9 @@ | |||
34 | #include <sound/asound.h> | 34 | #include <sound/asound.h> |
35 | 35 | ||
36 | #include "sst-haswell-ipc.h" | 36 | #include "sst-haswell-ipc.h" |
37 | #include "sst-dsp.h" | 37 | #include "../common/sst-dsp.h" |
38 | #include "sst-dsp-priv.h" | 38 | #include "../common/sst-dsp-priv.h" |
39 | #include "../common/sst-ipc.h" | ||
39 | 40 | ||
40 | /* Global Message - Generic */ | 41 | /* Global Message - Generic */ |
41 | #define IPC_GLB_TYPE_SHIFT 24 | 42 | #define IPC_GLB_TYPE_SHIFT 24 |
@@ -79,6 +80,15 @@ | |||
79 | #define IPC_LOG_ID_MASK (0xf << IPC_LOG_ID_SHIFT) | 80 | #define IPC_LOG_ID_MASK (0xf << IPC_LOG_ID_SHIFT) |
80 | #define IPC_LOG_ID(x) (x << IPC_LOG_ID_SHIFT) | 81 | #define IPC_LOG_ID(x) (x << IPC_LOG_ID_SHIFT) |
81 | 82 | ||
83 | /* Module Message */ | ||
84 | #define IPC_MODULE_OPERATION_SHIFT 20 | ||
85 | #define IPC_MODULE_OPERATION_MASK (0xf << IPC_MODULE_OPERATION_SHIFT) | ||
86 | #define IPC_MODULE_OPERATION(x) (x << IPC_MODULE_OPERATION_SHIFT) | ||
87 | |||
88 | #define IPC_MODULE_ID_SHIFT 16 | ||
89 | #define IPC_MODULE_ID_MASK (0xf << IPC_MODULE_ID_SHIFT) | ||
90 | #define IPC_MODULE_ID(x) (x << IPC_MODULE_ID_SHIFT) | ||
91 | |||
82 | /* IPC message timeout (msecs) */ | 92 | /* IPC message timeout (msecs) */ |
83 | #define IPC_TIMEOUT_MSECS 300 | 93 | #define IPC_TIMEOUT_MSECS 300 |
84 | #define IPC_BOOT_MSECS 200 | 94 | #define IPC_BOOT_MSECS 200 |
@@ -115,6 +125,7 @@ enum ipc_glb_type { | |||
115 | IPC_GLB_ENTER_DX_STATE = 12, | 125 | IPC_GLB_ENTER_DX_STATE = 12, |
116 | IPC_GLB_GET_MIXER_STREAM_INFO = 13, /* Request mixer stream params */ | 126 | IPC_GLB_GET_MIXER_STREAM_INFO = 13, /* Request mixer stream params */ |
117 | IPC_GLB_DEBUG_LOG_MESSAGE = 14, /* Message to or from the debug logger. */ | 127 | IPC_GLB_DEBUG_LOG_MESSAGE = 14, /* Message to or from the debug logger. */ |
128 | IPC_GLB_MODULE_OPERATION = 15, /* Message to loadable fw module */ | ||
118 | IPC_GLB_REQUEST_TRANSFER = 16, /* < Request Transfer for host */ | 129 | IPC_GLB_REQUEST_TRANSFER = 16, /* < Request Transfer for host */ |
119 | IPC_GLB_MAX_IPC_MESSAGE_TYPE = 17, /* Maximum message number */ | 130 | IPC_GLB_MAX_IPC_MESSAGE_TYPE = 17, /* Maximum message number */ |
120 | }; | 131 | }; |
@@ -133,6 +144,16 @@ enum ipc_glb_reply { | |||
133 | IPC_GLB_REPLY_SOURCE_NOT_STARTED = 10, /* Source was not started. */ | 144 | IPC_GLB_REPLY_SOURCE_NOT_STARTED = 10, /* Source was not started. */ |
134 | }; | 145 | }; |
135 | 146 | ||
147 | enum ipc_module_operation { | ||
148 | IPC_MODULE_NOTIFICATION = 0, | ||
149 | IPC_MODULE_ENABLE = 1, | ||
150 | IPC_MODULE_DISABLE = 2, | ||
151 | IPC_MODULE_GET_PARAMETER = 3, | ||
152 | IPC_MODULE_SET_PARAMETER = 4, | ||
153 | IPC_MODULE_GET_INFO = 5, | ||
154 | IPC_MODULE_MAX_MESSAGE | ||
155 | }; | ||
156 | |||
136 | /* Stream Message - Types */ | 157 | /* Stream Message - Types */ |
137 | enum ipc_str_operation { | 158 | enum ipc_str_operation { |
138 | IPC_STR_RESET = 0, | 159 | IPC_STR_RESET = 0, |
@@ -190,23 +211,6 @@ struct sst_hsw_ipc_fw_ready { | |||
190 | u8 fw_info[IPC_MAX_MAILBOX_BYTES - 5 * sizeof(u32)]; | 211 | u8 fw_info[IPC_MAX_MAILBOX_BYTES - 5 * sizeof(u32)]; |
191 | } __attribute__((packed)); | 212 | } __attribute__((packed)); |
192 | 213 | ||
193 | struct ipc_message { | ||
194 | struct list_head list; | ||
195 | u32 header; | ||
196 | |||
197 | /* direction wrt host CPU */ | ||
198 | char tx_data[IPC_MAX_MAILBOX_BYTES]; | ||
199 | size_t tx_size; | ||
200 | char rx_data[IPC_MAX_MAILBOX_BYTES]; | ||
201 | size_t rx_size; | ||
202 | |||
203 | wait_queue_head_t waitq; | ||
204 | bool pending; | ||
205 | bool complete; | ||
206 | bool wait; | ||
207 | int errno; | ||
208 | }; | ||
209 | |||
210 | struct sst_hsw_stream; | 214 | struct sst_hsw_stream; |
211 | struct sst_hsw; | 215 | struct sst_hsw; |
212 | 216 | ||
@@ -305,18 +309,19 @@ struct sst_hsw { | |||
305 | bool shutdown; | 309 | bool shutdown; |
306 | 310 | ||
307 | /* IPC messaging */ | 311 | /* IPC messaging */ |
308 | struct list_head tx_list; | 312 | struct sst_generic_ipc ipc; |
309 | struct list_head rx_list; | ||
310 | struct list_head empty_list; | ||
311 | wait_queue_head_t wait_txq; | ||
312 | struct task_struct *tx_thread; | ||
313 | struct kthread_worker kworker; | ||
314 | struct kthread_work kwork; | ||
315 | bool pending; | ||
316 | struct ipc_message *msg; | ||
317 | 313 | ||
318 | /* FW log stream */ | 314 | /* FW log stream */ |
319 | struct sst_hsw_log_stream log_stream; | 315 | struct sst_hsw_log_stream log_stream; |
316 | |||
317 | /* flags bit field to track module state when resume from RTD3, | ||
318 | * each bit represent state (enabled/disabled) of single module */ | ||
319 | u32 enabled_modules_rtd3; | ||
320 | |||
321 | /* buffer to store parameter lines */ | ||
322 | u32 param_idx_w; /* write index */ | ||
323 | u32 param_idx_r; /* read index */ | ||
324 | u8 param_buf[WAVES_PARAM_LINES][WAVES_PARAM_COUNT]; | ||
320 | }; | 325 | }; |
321 | 326 | ||
322 | #define CREATE_TRACE_POINTS | 327 | #define CREATE_TRACE_POINTS |
@@ -352,6 +357,16 @@ static inline u32 msg_get_notify_reason(u32 msg) | |||
352 | return (msg & IPC_STG_TYPE_MASK) >> IPC_STG_TYPE_SHIFT; | 357 | return (msg & IPC_STG_TYPE_MASK) >> IPC_STG_TYPE_SHIFT; |
353 | } | 358 | } |
354 | 359 | ||
360 | static inline u32 msg_get_module_operation(u32 msg) | ||
361 | { | ||
362 | return (msg & IPC_MODULE_OPERATION_MASK) >> IPC_MODULE_OPERATION_SHIFT; | ||
363 | } | ||
364 | |||
365 | static inline u32 msg_get_module_id(u32 msg) | ||
366 | { | ||
367 | return (msg & IPC_MODULE_ID_MASK) >> IPC_MODULE_ID_SHIFT; | ||
368 | } | ||
369 | |||
355 | u32 create_channel_map(enum sst_hsw_channel_config config) | 370 | u32 create_channel_map(enum sst_hsw_channel_config config) |
356 | { | 371 | { |
357 | switch (config) { | 372 | switch (config) { |
@@ -417,159 +432,6 @@ static struct sst_hsw_stream *get_stream_by_id(struct sst_hsw *hsw, | |||
417 | return NULL; | 432 | return NULL; |
418 | } | 433 | } |
419 | 434 | ||
420 | static void ipc_shim_dbg(struct sst_hsw *hsw, const char *text) | ||
421 | { | ||
422 | struct sst_dsp *sst = hsw->dsp; | ||
423 | u32 isr, ipcd, imrx, ipcx; | ||
424 | |||
425 | ipcx = sst_dsp_shim_read_unlocked(sst, SST_IPCX); | ||
426 | isr = sst_dsp_shim_read_unlocked(sst, SST_ISRX); | ||
427 | ipcd = sst_dsp_shim_read_unlocked(sst, SST_IPCD); | ||
428 | imrx = sst_dsp_shim_read_unlocked(sst, SST_IMRX); | ||
429 | |||
430 | dev_err(hsw->dev, "ipc: --%s-- ipcx 0x%8.8x isr 0x%8.8x ipcd 0x%8.8x imrx 0x%8.8x\n", | ||
431 | text, ipcx, isr, ipcd, imrx); | ||
432 | } | ||
433 | |||
434 | /* locks held by caller */ | ||
435 | static struct ipc_message *msg_get_empty(struct sst_hsw *hsw) | ||
436 | { | ||
437 | struct ipc_message *msg = NULL; | ||
438 | |||
439 | if (!list_empty(&hsw->empty_list)) { | ||
440 | msg = list_first_entry(&hsw->empty_list, struct ipc_message, | ||
441 | list); | ||
442 | list_del(&msg->list); | ||
443 | } | ||
444 | |||
445 | return msg; | ||
446 | } | ||
447 | |||
448 | static void ipc_tx_msgs(struct kthread_work *work) | ||
449 | { | ||
450 | struct sst_hsw *hsw = | ||
451 | container_of(work, struct sst_hsw, kwork); | ||
452 | struct ipc_message *msg; | ||
453 | unsigned long flags; | ||
454 | u32 ipcx; | ||
455 | |||
456 | spin_lock_irqsave(&hsw->dsp->spinlock, flags); | ||
457 | |||
458 | if (list_empty(&hsw->tx_list) || hsw->pending) { | ||
459 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
460 | return; | ||
461 | } | ||
462 | |||
463 | /* if the DSP is busy, we will TX messages after IRQ. | ||
464 | * also postpone if we are in the middle of procesing completion irq*/ | ||
465 | ipcx = sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCX); | ||
466 | if (ipcx & (SST_IPCX_BUSY | SST_IPCX_DONE)) { | ||
467 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
468 | return; | ||
469 | } | ||
470 | |||
471 | msg = list_first_entry(&hsw->tx_list, struct ipc_message, list); | ||
472 | |||
473 | list_move(&msg->list, &hsw->rx_list); | ||
474 | |||
475 | /* send the message */ | ||
476 | sst_dsp_outbox_write(hsw->dsp, msg->tx_data, msg->tx_size); | ||
477 | sst_dsp_ipc_msg_tx(hsw->dsp, msg->header | SST_IPCX_BUSY); | ||
478 | |||
479 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
480 | } | ||
481 | |||
482 | /* locks held by caller */ | ||
483 | static void tx_msg_reply_complete(struct sst_hsw *hsw, struct ipc_message *msg) | ||
484 | { | ||
485 | msg->complete = true; | ||
486 | trace_ipc_reply("completed", msg->header); | ||
487 | |||
488 | if (!msg->wait) | ||
489 | list_add_tail(&msg->list, &hsw->empty_list); | ||
490 | else | ||
491 | wake_up(&msg->waitq); | ||
492 | } | ||
493 | |||
494 | static int tx_wait_done(struct sst_hsw *hsw, struct ipc_message *msg, | ||
495 | void *rx_data) | ||
496 | { | ||
497 | unsigned long flags; | ||
498 | int ret; | ||
499 | |||
500 | /* wait for DSP completion (in all cases atm inc pending) */ | ||
501 | ret = wait_event_timeout(msg->waitq, msg->complete, | ||
502 | msecs_to_jiffies(IPC_TIMEOUT_MSECS)); | ||
503 | |||
504 | spin_lock_irqsave(&hsw->dsp->spinlock, flags); | ||
505 | if (ret == 0) { | ||
506 | ipc_shim_dbg(hsw, "message timeout"); | ||
507 | |||
508 | trace_ipc_error("error message timeout for", msg->header); | ||
509 | list_del(&msg->list); | ||
510 | ret = -ETIMEDOUT; | ||
511 | } else { | ||
512 | |||
513 | /* copy the data returned from DSP */ | ||
514 | if (msg->rx_size) | ||
515 | memcpy(rx_data, msg->rx_data, msg->rx_size); | ||
516 | ret = msg->errno; | ||
517 | } | ||
518 | |||
519 | list_add_tail(&msg->list, &hsw->empty_list); | ||
520 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
521 | return ret; | ||
522 | } | ||
523 | |||
524 | static int ipc_tx_message(struct sst_hsw *hsw, u32 header, void *tx_data, | ||
525 | size_t tx_bytes, void *rx_data, size_t rx_bytes, int wait) | ||
526 | { | ||
527 | struct ipc_message *msg; | ||
528 | unsigned long flags; | ||
529 | |||
530 | spin_lock_irqsave(&hsw->dsp->spinlock, flags); | ||
531 | |||
532 | msg = msg_get_empty(hsw); | ||
533 | if (msg == NULL) { | ||
534 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
535 | return -EBUSY; | ||
536 | } | ||
537 | |||
538 | if (tx_bytes) | ||
539 | memcpy(msg->tx_data, tx_data, tx_bytes); | ||
540 | |||
541 | msg->header = header; | ||
542 | msg->tx_size = tx_bytes; | ||
543 | msg->rx_size = rx_bytes; | ||
544 | msg->wait = wait; | ||
545 | msg->errno = 0; | ||
546 | msg->pending = false; | ||
547 | msg->complete = false; | ||
548 | |||
549 | list_add_tail(&msg->list, &hsw->tx_list); | ||
550 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
551 | |||
552 | queue_kthread_work(&hsw->kworker, &hsw->kwork); | ||
553 | |||
554 | if (wait) | ||
555 | return tx_wait_done(hsw, msg, rx_data); | ||
556 | else | ||
557 | return 0; | ||
558 | } | ||
559 | |||
560 | static inline int ipc_tx_message_wait(struct sst_hsw *hsw, u32 header, | ||
561 | void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes) | ||
562 | { | ||
563 | return ipc_tx_message(hsw, header, tx_data, tx_bytes, rx_data, | ||
564 | rx_bytes, 1); | ||
565 | } | ||
566 | |||
567 | static inline int ipc_tx_message_nowait(struct sst_hsw *hsw, u32 header, | ||
568 | void *tx_data, size_t tx_bytes) | ||
569 | { | ||
570 | return ipc_tx_message(hsw, header, tx_data, tx_bytes, NULL, 0, 0); | ||
571 | } | ||
572 | |||
573 | static void hsw_fw_ready(struct sst_hsw *hsw, u32 header) | 435 | static void hsw_fw_ready(struct sst_hsw *hsw, u32 header) |
574 | { | 436 | { |
575 | struct sst_hsw_ipc_fw_ready fw_ready; | 437 | struct sst_hsw_ipc_fw_ready fw_ready; |
@@ -604,7 +466,7 @@ static void hsw_fw_ready(struct sst_hsw *hsw, u32 header) | |||
604 | /* log the FW version info got from the mailbox here. */ | 466 | /* log the FW version info got from the mailbox here. */ |
605 | memcpy(fw_info, fw_ready.fw_info, fw_ready.fw_info_size); | 467 | memcpy(fw_info, fw_ready.fw_info, fw_ready.fw_info_size); |
606 | pinfo = &fw_info[0]; | 468 | pinfo = &fw_info[0]; |
607 | for (i = 0; i < sizeof(tmp) / sizeof(char *); i++) | 469 | for (i = 0; i < ARRAY_SIZE(tmp); i++) |
608 | tmp[i] = strsep(&pinfo, " "); | 470 | tmp[i] = strsep(&pinfo, " "); |
609 | dev_info(hsw->dev, "FW loaded, mailbox readback FW info: type %s, - " | 471 | dev_info(hsw->dev, "FW loaded, mailbox readback FW info: type %s, - " |
610 | "version: %s.%s, build %s, source commit id: %s\n", | 472 | "version: %s.%s, build %s, source commit id: %s\n", |
@@ -657,27 +519,6 @@ static void hsw_notification_work(struct work_struct *work) | |||
657 | sst_dsp_shim_update_bits(hsw->dsp, SST_IMRX, SST_IMRX_BUSY, 0); | 519 | sst_dsp_shim_update_bits(hsw->dsp, SST_IMRX, SST_IMRX_BUSY, 0); |
658 | } | 520 | } |
659 | 521 | ||
660 | static struct ipc_message *reply_find_msg(struct sst_hsw *hsw, u32 header) | ||
661 | { | ||
662 | struct ipc_message *msg; | ||
663 | |||
664 | /* clear reply bits & status bits */ | ||
665 | header &= ~(IPC_STATUS_MASK | IPC_GLB_REPLY_MASK); | ||
666 | |||
667 | if (list_empty(&hsw->rx_list)) { | ||
668 | dev_err(hsw->dev, "error: rx list empty but received 0x%x\n", | ||
669 | header); | ||
670 | return NULL; | ||
671 | } | ||
672 | |||
673 | list_for_each_entry(msg, &hsw->rx_list, list) { | ||
674 | if (msg->header == header) | ||
675 | return msg; | ||
676 | } | ||
677 | |||
678 | return NULL; | ||
679 | } | ||
680 | |||
681 | static void hsw_stream_update(struct sst_hsw *hsw, struct ipc_message *msg) | 522 | static void hsw_stream_update(struct sst_hsw *hsw, struct ipc_message *msg) |
682 | { | 523 | { |
683 | struct sst_hsw_stream *stream; | 524 | struct sst_hsw_stream *stream; |
@@ -716,7 +557,7 @@ static int hsw_process_reply(struct sst_hsw *hsw, u32 header) | |||
716 | 557 | ||
717 | trace_ipc_reply("processing -->", header); | 558 | trace_ipc_reply("processing -->", header); |
718 | 559 | ||
719 | msg = reply_find_msg(hsw, header); | 560 | msg = sst_ipc_reply_find_msg(&hsw->ipc, header); |
720 | if (msg == NULL) { | 561 | if (msg == NULL) { |
721 | trace_ipc_error("error: can't find message header", header); | 562 | trace_ipc_error("error: can't find message header", header); |
722 | return -EIO; | 563 | return -EIO; |
@@ -727,14 +568,14 @@ static int hsw_process_reply(struct sst_hsw *hsw, u32 header) | |||
727 | case IPC_GLB_REPLY_PENDING: | 568 | case IPC_GLB_REPLY_PENDING: |
728 | trace_ipc_pending_reply("received", header); | 569 | trace_ipc_pending_reply("received", header); |
729 | msg->pending = true; | 570 | msg->pending = true; |
730 | hsw->pending = true; | 571 | hsw->ipc.pending = true; |
731 | return 1; | 572 | return 1; |
732 | case IPC_GLB_REPLY_SUCCESS: | 573 | case IPC_GLB_REPLY_SUCCESS: |
733 | if (msg->pending) { | 574 | if (msg->pending) { |
734 | trace_ipc_pending_reply("completed", header); | 575 | trace_ipc_pending_reply("completed", header); |
735 | sst_dsp_inbox_read(hsw->dsp, msg->rx_data, | 576 | sst_dsp_inbox_read(hsw->dsp, msg->rx_data, |
736 | msg->rx_size); | 577 | msg->rx_size); |
737 | hsw->pending = false; | 578 | hsw->ipc.pending = false; |
738 | } else { | 579 | } else { |
739 | /* copy data from the DSP */ | 580 | /* copy data from the DSP */ |
740 | sst_dsp_outbox_read(hsw->dsp, msg->rx_data, | 581 | sst_dsp_outbox_read(hsw->dsp, msg->rx_data, |
@@ -790,11 +631,36 @@ static int hsw_process_reply(struct sst_hsw *hsw, u32 header) | |||
790 | 631 | ||
791 | /* wake up and return the error if we have waiters on this message ? */ | 632 | /* wake up and return the error if we have waiters on this message ? */ |
792 | list_del(&msg->list); | 633 | list_del(&msg->list); |
793 | tx_msg_reply_complete(hsw, msg); | 634 | sst_ipc_tx_msg_reply_complete(&hsw->ipc, msg); |
794 | 635 | ||
795 | return 1; | 636 | return 1; |
796 | } | 637 | } |
797 | 638 | ||
639 | static int hsw_module_message(struct sst_hsw *hsw, u32 header) | ||
640 | { | ||
641 | u32 operation, module_id; | ||
642 | int handled = 0; | ||
643 | |||
644 | operation = msg_get_module_operation(header); | ||
645 | module_id = msg_get_module_id(header); | ||
646 | dev_dbg(hsw->dev, "received module message header: 0x%8.8x\n", | ||
647 | header); | ||
648 | dev_dbg(hsw->dev, "operation: 0x%8.8x module_id: 0x%8.8x\n", | ||
649 | operation, module_id); | ||
650 | |||
651 | switch (operation) { | ||
652 | case IPC_MODULE_NOTIFICATION: | ||
653 | dev_dbg(hsw->dev, "module notification received"); | ||
654 | handled = 1; | ||
655 | break; | ||
656 | default: | ||
657 | handled = hsw_process_reply(hsw, header); | ||
658 | break; | ||
659 | } | ||
660 | |||
661 | return handled; | ||
662 | } | ||
663 | |||
798 | static int hsw_stream_message(struct sst_hsw *hsw, u32 header) | 664 | static int hsw_stream_message(struct sst_hsw *hsw, u32 header) |
799 | { | 665 | { |
800 | u32 stream_msg, stream_id, stage_type; | 666 | u32 stream_msg, stream_id, stage_type; |
@@ -890,6 +756,9 @@ static int hsw_process_notification(struct sst_hsw *hsw) | |||
890 | case IPC_GLB_DEBUG_LOG_MESSAGE: | 756 | case IPC_GLB_DEBUG_LOG_MESSAGE: |
891 | handled = hsw_log_message(hsw, header); | 757 | handled = hsw_log_message(hsw, header); |
892 | break; | 758 | break; |
759 | case IPC_GLB_MODULE_OPERATION: | ||
760 | handled = hsw_module_message(hsw, header); | ||
761 | break; | ||
893 | default: | 762 | default: |
894 | dev_err(hsw->dev, "error: unexpected type %d hdr 0x%8.8x\n", | 763 | dev_err(hsw->dev, "error: unexpected type %d hdr 0x%8.8x\n", |
895 | type, header); | 764 | type, header); |
@@ -903,6 +772,7 @@ static irqreturn_t hsw_irq_thread(int irq, void *context) | |||
903 | { | 772 | { |
904 | struct sst_dsp *sst = (struct sst_dsp *) context; | 773 | struct sst_dsp *sst = (struct sst_dsp *) context; |
905 | struct sst_hsw *hsw = sst_dsp_get_thread_context(sst); | 774 | struct sst_hsw *hsw = sst_dsp_get_thread_context(sst); |
775 | struct sst_generic_ipc *ipc = &hsw->ipc; | ||
906 | u32 ipcx, ipcd; | 776 | u32 ipcx, ipcd; |
907 | int handled; | 777 | int handled; |
908 | unsigned long flags; | 778 | unsigned long flags; |
@@ -949,7 +819,7 @@ static irqreturn_t hsw_irq_thread(int irq, void *context) | |||
949 | spin_unlock_irqrestore(&sst->spinlock, flags); | 819 | spin_unlock_irqrestore(&sst->spinlock, flags); |
950 | 820 | ||
951 | /* continue to send any remaining messages... */ | 821 | /* continue to send any remaining messages... */ |
952 | queue_kthread_work(&hsw->kworker, &hsw->kwork); | 822 | queue_kthread_work(&ipc->kworker, &ipc->kwork); |
953 | 823 | ||
954 | return IRQ_HANDLED; | 824 | return IRQ_HANDLED; |
955 | } | 825 | } |
@@ -959,7 +829,8 @@ int sst_hsw_fw_get_version(struct sst_hsw *hsw, | |||
959 | { | 829 | { |
960 | int ret; | 830 | int ret; |
961 | 831 | ||
962 | ret = ipc_tx_message_wait(hsw, IPC_GLB_TYPE(IPC_GLB_GET_FW_VERSION), | 832 | ret = sst_ipc_tx_message_wait(&hsw->ipc, |
833 | IPC_GLB_TYPE(IPC_GLB_GET_FW_VERSION), | ||
963 | NULL, 0, version, sizeof(*version)); | 834 | NULL, 0, version, sizeof(*version)); |
964 | if (ret < 0) | 835 | if (ret < 0) |
965 | dev_err(hsw->dev, "error: get version failed\n"); | 836 | dev_err(hsw->dev, "error: get version failed\n"); |
@@ -1023,7 +894,8 @@ int sst_hsw_stream_set_volume(struct sst_hsw *hsw, | |||
1023 | req->channel = channel; | 894 | req->channel = channel; |
1024 | } | 895 | } |
1025 | 896 | ||
1026 | ret = ipc_tx_message_wait(hsw, header, req, sizeof(*req), NULL, 0); | 897 | ret = sst_ipc_tx_message_wait(&hsw->ipc, header, req, |
898 | sizeof(*req), NULL, 0); | ||
1027 | if (ret < 0) { | 899 | if (ret < 0) { |
1028 | dev_err(hsw->dev, "error: set stream volume failed\n"); | 900 | dev_err(hsw->dev, "error: set stream volume failed\n"); |
1029 | return ret; | 901 | return ret; |
@@ -1088,7 +960,8 @@ int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, | |||
1088 | req.curve_type = hsw->curve_type; | 960 | req.curve_type = hsw->curve_type; |
1089 | req.target_volume = volume; | 961 | req.target_volume = volume; |
1090 | 962 | ||
1091 | ret = ipc_tx_message_wait(hsw, header, &req, sizeof(req), NULL, 0); | 963 | ret = sst_ipc_tx_message_wait(&hsw->ipc, header, &req, |
964 | sizeof(req), NULL, 0); | ||
1092 | if (ret < 0) { | 965 | if (ret < 0) { |
1093 | dev_err(hsw->dev, "error: set mixer volume failed\n"); | 966 | dev_err(hsw->dev, "error: set mixer volume failed\n"); |
1094 | return ret; | 967 | return ret; |
@@ -1146,7 +1019,7 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream) | |||
1146 | stream->free_req.stream_id = stream->reply.stream_hw_id; | 1019 | stream->free_req.stream_id = stream->reply.stream_hw_id; |
1147 | header = IPC_GLB_TYPE(IPC_GLB_FREE_STREAM); | 1020 | header = IPC_GLB_TYPE(IPC_GLB_FREE_STREAM); |
1148 | 1021 | ||
1149 | ret = ipc_tx_message_wait(hsw, header, &stream->free_req, | 1022 | ret = sst_ipc_tx_message_wait(&hsw->ipc, header, &stream->free_req, |
1150 | sizeof(stream->free_req), NULL, 0); | 1023 | sizeof(stream->free_req), NULL, 0); |
1151 | if (ret < 0) { | 1024 | if (ret < 0) { |
1152 | dev_err(hsw->dev, "error: free stream %d failed\n", | 1025 | dev_err(hsw->dev, "error: free stream %d failed\n", |
@@ -1338,8 +1211,8 @@ int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream) | |||
1338 | 1211 | ||
1339 | header = IPC_GLB_TYPE(IPC_GLB_ALLOCATE_STREAM); | 1212 | header = IPC_GLB_TYPE(IPC_GLB_ALLOCATE_STREAM); |
1340 | 1213 | ||
1341 | ret = ipc_tx_message_wait(hsw, header, str_req, sizeof(*str_req), | 1214 | ret = sst_ipc_tx_message_wait(&hsw->ipc, header, str_req, |
1342 | reply, sizeof(*reply)); | 1215 | sizeof(*str_req), reply, sizeof(*reply)); |
1343 | if (ret < 0) { | 1216 | if (ret < 0) { |
1344 | dev_err(hsw->dev, "error: stream commit failed\n"); | 1217 | dev_err(hsw->dev, "error: stream commit failed\n"); |
1345 | return ret; | 1218 | return ret; |
@@ -1388,7 +1261,8 @@ int sst_hsw_mixer_get_info(struct sst_hsw *hsw) | |||
1388 | 1261 | ||
1389 | trace_ipc_request("get global mixer info", 0); | 1262 | trace_ipc_request("get global mixer info", 0); |
1390 | 1263 | ||
1391 | ret = ipc_tx_message_wait(hsw, header, NULL, 0, reply, sizeof(*reply)); | 1264 | ret = sst_ipc_tx_message_wait(&hsw->ipc, header, NULL, 0, |
1265 | reply, sizeof(*reply)); | ||
1392 | if (ret < 0) { | 1266 | if (ret < 0) { |
1393 | dev_err(hsw->dev, "error: get stream info failed\n"); | 1267 | dev_err(hsw->dev, "error: get stream info failed\n"); |
1394 | return ret; | 1268 | return ret; |
@@ -1409,9 +1283,10 @@ static int sst_hsw_stream_operations(struct sst_hsw *hsw, int type, | |||
1409 | header |= (stream_id << IPC_STR_ID_SHIFT); | 1283 | header |= (stream_id << IPC_STR_ID_SHIFT); |
1410 | 1284 | ||
1411 | if (wait) | 1285 | if (wait) |
1412 | return ipc_tx_message_wait(hsw, header, NULL, 0, NULL, 0); | 1286 | return sst_ipc_tx_message_wait(&hsw->ipc, header, |
1287 | NULL, 0, NULL, 0); | ||
1413 | else | 1288 | else |
1414 | return ipc_tx_message_nowait(hsw, header, NULL, 0); | 1289 | return sst_ipc_tx_message_nowait(&hsw->ipc, header, NULL, 0); |
1415 | } | 1290 | } |
1416 | 1291 | ||
1417 | /* Stream ALSA trigger operations */ | 1292 | /* Stream ALSA trigger operations */ |
@@ -1538,8 +1413,8 @@ int sst_hsw_device_set_config(struct sst_hsw *hsw, | |||
1538 | 1413 | ||
1539 | header = IPC_GLB_TYPE(IPC_GLB_SET_DEVICE_FORMATS); | 1414 | header = IPC_GLB_TYPE(IPC_GLB_SET_DEVICE_FORMATS); |
1540 | 1415 | ||
1541 | ret = ipc_tx_message_wait(hsw, header, &config, sizeof(config), | 1416 | ret = sst_ipc_tx_message_wait(&hsw->ipc, header, &config, |
1542 | NULL, 0); | 1417 | sizeof(config), NULL, 0); |
1543 | if (ret < 0) | 1418 | if (ret < 0) |
1544 | dev_err(hsw->dev, "error: set device formats failed\n"); | 1419 | dev_err(hsw->dev, "error: set device formats failed\n"); |
1545 | 1420 | ||
@@ -1559,8 +1434,8 @@ int sst_hsw_dx_set_state(struct sst_hsw *hsw, | |||
1559 | 1434 | ||
1560 | trace_ipc_request("PM enter Dx state", state); | 1435 | trace_ipc_request("PM enter Dx state", state); |
1561 | 1436 | ||
1562 | ret = ipc_tx_message_wait(hsw, header, &state_, sizeof(state_), | 1437 | ret = sst_ipc_tx_message_wait(&hsw->ipc, header, &state_, |
1563 | dx, sizeof(*dx)); | 1438 | sizeof(state_), dx, sizeof(*dx)); |
1564 | if (ret < 0) { | 1439 | if (ret < 0) { |
1565 | dev_err(hsw->dev, "ipc: error set dx state %d failed\n", state); | 1440 | dev_err(hsw->dev, "ipc: error set dx state %d failed\n", state); |
1566 | return ret; | 1441 | return ret; |
@@ -1703,32 +1578,6 @@ static int sst_hsw_dx_state_restore(struct sst_hsw *hsw) | |||
1703 | return 0; | 1578 | return 0; |
1704 | } | 1579 | } |
1705 | 1580 | ||
1706 | static void sst_hsw_drop_all(struct sst_hsw *hsw) | ||
1707 | { | ||
1708 | struct ipc_message *msg, *tmp; | ||
1709 | unsigned long flags; | ||
1710 | int tx_drop_cnt = 0, rx_drop_cnt = 0; | ||
1711 | |||
1712 | /* drop all TX and Rx messages before we stall + reset DSP */ | ||
1713 | spin_lock_irqsave(&hsw->dsp->spinlock, flags); | ||
1714 | |||
1715 | list_for_each_entry_safe(msg, tmp, &hsw->tx_list, list) { | ||
1716 | list_move(&msg->list, &hsw->empty_list); | ||
1717 | tx_drop_cnt++; | ||
1718 | } | ||
1719 | |||
1720 | list_for_each_entry_safe(msg, tmp, &hsw->rx_list, list) { | ||
1721 | list_move(&msg->list, &hsw->empty_list); | ||
1722 | rx_drop_cnt++; | ||
1723 | } | ||
1724 | |||
1725 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
1726 | |||
1727 | if (tx_drop_cnt || rx_drop_cnt) | ||
1728 | dev_err(hsw->dev, "dropped IPC msg RX=%d, TX=%d\n", | ||
1729 | tx_drop_cnt, rx_drop_cnt); | ||
1730 | } | ||
1731 | |||
1732 | int sst_hsw_dsp_load(struct sst_hsw *hsw) | 1581 | int sst_hsw_dsp_load(struct sst_hsw *hsw) |
1733 | { | 1582 | { |
1734 | struct sst_dsp *dsp = hsw->dsp; | 1583 | struct sst_dsp *dsp = hsw->dsp; |
@@ -1808,7 +1657,7 @@ int sst_hsw_dsp_runtime_suspend(struct sst_hsw *hsw) | |||
1808 | if (ret < 0) | 1657 | if (ret < 0) |
1809 | return ret; | 1658 | return ret; |
1810 | 1659 | ||
1811 | sst_hsw_drop_all(hsw); | 1660 | sst_ipc_drop_all(&hsw->ipc); |
1812 | 1661 | ||
1813 | return 0; | 1662 | return 0; |
1814 | } | 1663 | } |
@@ -1844,6 +1693,8 @@ int sst_hsw_dsp_runtime_resume(struct sst_hsw *hsw) | |||
1844 | if (ret < 0) | 1693 | if (ret < 0) |
1845 | dev_err(dev, "error: audio DSP boot failure\n"); | 1694 | dev_err(dev, "error: audio DSP boot failure\n"); |
1846 | 1695 | ||
1696 | sst_hsw_init_module_state(hsw); | ||
1697 | |||
1847 | ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete, | 1698 | ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete, |
1848 | msecs_to_jiffies(IPC_BOOT_MSECS)); | 1699 | msecs_to_jiffies(IPC_BOOT_MSECS)); |
1849 | if (ret == 0) { | 1700 | if (ret == 0) { |
@@ -1864,26 +1715,345 @@ int sst_hsw_dsp_runtime_resume(struct sst_hsw *hsw) | |||
1864 | } | 1715 | } |
1865 | #endif | 1716 | #endif |
1866 | 1717 | ||
1867 | static int msg_empty_list_init(struct sst_hsw *hsw) | 1718 | struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw) |
1868 | { | 1719 | { |
1869 | int i; | 1720 | return hsw->dsp; |
1721 | } | ||
1870 | 1722 | ||
1871 | hsw->msg = kzalloc(sizeof(struct ipc_message) * | 1723 | void sst_hsw_init_module_state(struct sst_hsw *hsw) |
1872 | IPC_EMPTY_LIST_SIZE, GFP_KERNEL); | 1724 | { |
1873 | if (hsw->msg == NULL) | 1725 | struct sst_module *module; |
1874 | return -ENOMEM; | 1726 | enum sst_hsw_module_id id; |
1727 | |||
1728 | /* the base fw contains several modules */ | ||
1729 | for (id = SST_HSW_MODULE_BASE_FW; id < SST_HSW_MAX_MODULE_ID; id++) { | ||
1730 | module = sst_module_get_from_id(hsw->dsp, id); | ||
1731 | if (module) { | ||
1732 | /* module waves is active only after being enabled */ | ||
1733 | if (id == SST_HSW_MODULE_WAVES) | ||
1734 | module->state = SST_MODULE_STATE_INITIALIZED; | ||
1735 | else | ||
1736 | module->state = SST_MODULE_STATE_ACTIVE; | ||
1737 | } | ||
1738 | } | ||
1739 | } | ||
1740 | |||
1741 | bool sst_hsw_is_module_loaded(struct sst_hsw *hsw, u32 module_id) | ||
1742 | { | ||
1743 | struct sst_module *module; | ||
1744 | |||
1745 | module = sst_module_get_from_id(hsw->dsp, module_id); | ||
1746 | if (module == NULL || module->state == SST_MODULE_STATE_UNLOADED) | ||
1747 | return false; | ||
1748 | else | ||
1749 | return true; | ||
1750 | } | ||
1751 | |||
1752 | bool sst_hsw_is_module_active(struct sst_hsw *hsw, u32 module_id) | ||
1753 | { | ||
1754 | struct sst_module *module; | ||
1755 | |||
1756 | module = sst_module_get_from_id(hsw->dsp, module_id); | ||
1757 | if (module != NULL && module->state == SST_MODULE_STATE_ACTIVE) | ||
1758 | return true; | ||
1759 | else | ||
1760 | return false; | ||
1761 | } | ||
1875 | 1762 | ||
1876 | for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { | 1763 | void sst_hsw_set_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id) |
1877 | init_waitqueue_head(&hsw->msg[i].waitq); | 1764 | { |
1878 | list_add(&hsw->msg[i].list, &hsw->empty_list); | 1765 | hsw->enabled_modules_rtd3 |= (1 << module_id); |
1766 | } | ||
1767 | |||
1768 | void sst_hsw_set_module_disabled_rtd3(struct sst_hsw *hsw, u32 module_id) | ||
1769 | { | ||
1770 | hsw->enabled_modules_rtd3 &= ~(1 << module_id); | ||
1771 | } | ||
1772 | |||
1773 | bool sst_hsw_is_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id) | ||
1774 | { | ||
1775 | return hsw->enabled_modules_rtd3 & (1 << module_id); | ||
1776 | } | ||
1777 | |||
1778 | void sst_hsw_reset_param_buf(struct sst_hsw *hsw) | ||
1779 | { | ||
1780 | hsw->param_idx_w = 0; | ||
1781 | hsw->param_idx_r = 0; | ||
1782 | memset((void *)hsw->param_buf, 0, sizeof(hsw->param_buf)); | ||
1783 | } | ||
1784 | |||
1785 | int sst_hsw_store_param_line(struct sst_hsw *hsw, u8 *buf) | ||
1786 | { | ||
1787 | /* save line to the first available position of param buffer */ | ||
1788 | if (hsw->param_idx_w > WAVES_PARAM_LINES - 1) { | ||
1789 | dev_warn(hsw->dev, "warning: param buffer overflow!\n"); | ||
1790 | return -EPERM; | ||
1791 | } | ||
1792 | memcpy(hsw->param_buf[hsw->param_idx_w], buf, WAVES_PARAM_COUNT); | ||
1793 | hsw->param_idx_w++; | ||
1794 | return 0; | ||
1795 | } | ||
1796 | |||
1797 | int sst_hsw_load_param_line(struct sst_hsw *hsw, u8 *buf) | ||
1798 | { | ||
1799 | u8 id = 0; | ||
1800 | |||
1801 | /* read the first matching line from param buffer */ | ||
1802 | while (hsw->param_idx_r < WAVES_PARAM_LINES) { | ||
1803 | id = hsw->param_buf[hsw->param_idx_r][0]; | ||
1804 | hsw->param_idx_r++; | ||
1805 | if (buf[0] == id) { | ||
1806 | memcpy(buf, hsw->param_buf[hsw->param_idx_r], | ||
1807 | WAVES_PARAM_COUNT); | ||
1808 | break; | ||
1809 | } | ||
1879 | } | 1810 | } |
1811 | if (hsw->param_idx_r > WAVES_PARAM_LINES - 1) { | ||
1812 | dev_dbg(hsw->dev, "end of buffer, roll to the beginning\n"); | ||
1813 | hsw->param_idx_r = 0; | ||
1814 | return 0; | ||
1815 | } | ||
1816 | return 0; | ||
1817 | } | ||
1818 | |||
1819 | int sst_hsw_launch_param_buf(struct sst_hsw *hsw) | ||
1820 | { | ||
1821 | int ret, idx; | ||
1880 | 1822 | ||
1823 | if (!sst_hsw_is_module_active(hsw, SST_HSW_MODULE_WAVES)) { | ||
1824 | dev_dbg(hsw->dev, "module waves is not active\n"); | ||
1825 | return 0; | ||
1826 | } | ||
1827 | |||
1828 | /* put all param lines to DSP through ipc */ | ||
1829 | for (idx = 0; idx < hsw->param_idx_w; idx++) { | ||
1830 | ret = sst_hsw_module_set_param(hsw, | ||
1831 | SST_HSW_MODULE_WAVES, 0, hsw->param_buf[idx][0], | ||
1832 | WAVES_PARAM_COUNT, hsw->param_buf[idx]); | ||
1833 | if (ret < 0) | ||
1834 | return ret; | ||
1835 | } | ||
1881 | return 0; | 1836 | return 0; |
1882 | } | 1837 | } |
1883 | 1838 | ||
1884 | struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw) | 1839 | int sst_hsw_module_load(struct sst_hsw *hsw, |
1840 | u32 module_id, u32 instance_id, char *name) | ||
1885 | { | 1841 | { |
1886 | return hsw->dsp; | 1842 | int ret = 0; |
1843 | const struct firmware *fw = NULL; | ||
1844 | struct sst_fw *hsw_sst_fw; | ||
1845 | struct sst_module *module; | ||
1846 | struct device *dev = hsw->dev; | ||
1847 | struct sst_dsp *dsp = hsw->dsp; | ||
1848 | |||
1849 | dev_dbg(dev, "sst_hsw_module_load id=%d, name='%s'", module_id, name); | ||
1850 | |||
1851 | module = sst_module_get_from_id(dsp, module_id); | ||
1852 | if (module == NULL) { | ||
1853 | /* loading for the first time */ | ||
1854 | if (module_id == SST_HSW_MODULE_BASE_FW) { | ||
1855 | /* for base module: use fw requested in acpi probe */ | ||
1856 | fw = dsp->pdata->fw; | ||
1857 | if (!fw) { | ||
1858 | dev_err(dev, "request Base fw failed\n"); | ||
1859 | return -ENODEV; | ||
1860 | } | ||
1861 | } else { | ||
1862 | /* try and load any other optional modules if they are | ||
1863 | * available. Use dev_info instead of dev_err in case | ||
1864 | * request firmware failed */ | ||
1865 | ret = request_firmware(&fw, name, dev); | ||
1866 | if (ret) { | ||
1867 | dev_info(dev, "fw image %s not available(%d)\n", | ||
1868 | name, ret); | ||
1869 | return ret; | ||
1870 | } | ||
1871 | } | ||
1872 | hsw_sst_fw = sst_fw_new(dsp, fw, hsw); | ||
1873 | if (hsw_sst_fw == NULL) { | ||
1874 | dev_err(dev, "error: failed to load firmware\n"); | ||
1875 | ret = -ENOMEM; | ||
1876 | goto out; | ||
1877 | } | ||
1878 | module = sst_module_get_from_id(dsp, module_id); | ||
1879 | if (module == NULL) { | ||
1880 | dev_err(dev, "error: no module %d in firmware %s\n", | ||
1881 | module_id, name); | ||
1882 | } | ||
1883 | } else | ||
1884 | dev_info(dev, "module %d (%s) already loaded\n", | ||
1885 | module_id, name); | ||
1886 | out: | ||
1887 | /* release fw, but base fw should be released by acpi driver */ | ||
1888 | if (fw && module_id != SST_HSW_MODULE_BASE_FW) | ||
1889 | release_firmware(fw); | ||
1890 | |||
1891 | return ret; | ||
1892 | } | ||
1893 | |||
1894 | int sst_hsw_module_enable(struct sst_hsw *hsw, | ||
1895 | u32 module_id, u32 instance_id) | ||
1896 | { | ||
1897 | int ret; | ||
1898 | u32 header = 0; | ||
1899 | struct sst_hsw_ipc_module_config config; | ||
1900 | struct sst_module *module; | ||
1901 | struct sst_module_runtime *runtime; | ||
1902 | struct device *dev = hsw->dev; | ||
1903 | struct sst_dsp *dsp = hsw->dsp; | ||
1904 | |||
1905 | if (!sst_hsw_is_module_loaded(hsw, module_id)) { | ||
1906 | dev_dbg(dev, "module %d not loaded\n", module_id); | ||
1907 | return 0; | ||
1908 | } | ||
1909 | |||
1910 | if (sst_hsw_is_module_active(hsw, module_id)) { | ||
1911 | dev_info(dev, "module %d already enabled\n", module_id); | ||
1912 | return 0; | ||
1913 | } | ||
1914 | |||
1915 | module = sst_module_get_from_id(dsp, module_id); | ||
1916 | if (module == NULL) { | ||
1917 | dev_err(dev, "module %d not valid\n", module_id); | ||
1918 | return -ENXIO; | ||
1919 | } | ||
1920 | |||
1921 | runtime = sst_module_runtime_get_from_id(module, module_id); | ||
1922 | if (runtime == NULL) { | ||
1923 | dev_err(dev, "runtime %d not valid", module_id); | ||
1924 | return -ENXIO; | ||
1925 | } | ||
1926 | |||
1927 | header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) | | ||
1928 | IPC_MODULE_OPERATION(IPC_MODULE_ENABLE) | | ||
1929 | IPC_MODULE_ID(module_id); | ||
1930 | dev_dbg(dev, "module enable header: %x\n", header); | ||
1931 | |||
1932 | config.map.module_entries_count = 1; | ||
1933 | config.map.module_entries[0].module_id = module->id; | ||
1934 | config.map.module_entries[0].entry_point = module->entry; | ||
1935 | |||
1936 | config.persistent_mem.offset = | ||
1937 | sst_dsp_get_offset(dsp, | ||
1938 | runtime->persistent_offset, SST_MEM_DRAM); | ||
1939 | config.persistent_mem.size = module->persistent_size; | ||
1940 | |||
1941 | config.scratch_mem.offset = | ||
1942 | sst_dsp_get_offset(dsp, | ||
1943 | dsp->scratch_offset, SST_MEM_DRAM); | ||
1944 | config.scratch_mem.size = module->scratch_size; | ||
1945 | dev_dbg(dev, "mod %d enable p:%d @ %x, s:%d @ %x, ep: %x", | ||
1946 | config.map.module_entries[0].module_id, | ||
1947 | config.persistent_mem.size, | ||
1948 | config.persistent_mem.offset, | ||
1949 | config.scratch_mem.size, config.scratch_mem.offset, | ||
1950 | config.map.module_entries[0].entry_point); | ||
1951 | |||
1952 | ret = sst_ipc_tx_message_wait(&hsw->ipc, header, | ||
1953 | &config, sizeof(config), NULL, 0); | ||
1954 | if (ret < 0) | ||
1955 | dev_err(dev, "ipc: module enable failed - %d\n", ret); | ||
1956 | else | ||
1957 | module->state = SST_MODULE_STATE_ACTIVE; | ||
1958 | |||
1959 | return ret; | ||
1960 | } | ||
1961 | |||
1962 | int sst_hsw_module_disable(struct sst_hsw *hsw, | ||
1963 | u32 module_id, u32 instance_id) | ||
1964 | { | ||
1965 | int ret; | ||
1966 | u32 header; | ||
1967 | struct sst_module *module; | ||
1968 | struct device *dev = hsw->dev; | ||
1969 | struct sst_dsp *dsp = hsw->dsp; | ||
1970 | |||
1971 | if (!sst_hsw_is_module_loaded(hsw, module_id)) { | ||
1972 | dev_dbg(dev, "module %d not loaded\n", module_id); | ||
1973 | return 0; | ||
1974 | } | ||
1975 | |||
1976 | if (!sst_hsw_is_module_active(hsw, module_id)) { | ||
1977 | dev_info(dev, "module %d already disabled\n", module_id); | ||
1978 | return 0; | ||
1979 | } | ||
1980 | |||
1981 | module = sst_module_get_from_id(dsp, module_id); | ||
1982 | if (module == NULL) { | ||
1983 | dev_err(dev, "module %d not valid\n", module_id); | ||
1984 | return -ENXIO; | ||
1985 | } | ||
1986 | |||
1987 | header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) | | ||
1988 | IPC_MODULE_OPERATION(IPC_MODULE_DISABLE) | | ||
1989 | IPC_MODULE_ID(module_id); | ||
1990 | |||
1991 | ret = sst_ipc_tx_message_wait(&hsw->ipc, header, NULL, 0, NULL, 0); | ||
1992 | if (ret < 0) | ||
1993 | dev_err(dev, "module disable failed - %d\n", ret); | ||
1994 | else | ||
1995 | module->state = SST_MODULE_STATE_INITIALIZED; | ||
1996 | |||
1997 | return ret; | ||
1998 | } | ||
1999 | |||
2000 | int sst_hsw_module_set_param(struct sst_hsw *hsw, | ||
2001 | u32 module_id, u32 instance_id, u32 parameter_id, | ||
2002 | u32 param_size, char *param) | ||
2003 | { | ||
2004 | int ret; | ||
2005 | unsigned char *data = NULL; | ||
2006 | u32 header = 0; | ||
2007 | u32 payload_size = 0, transfer_parameter_size = 0; | ||
2008 | dma_addr_t dma_addr = 0; | ||
2009 | struct sst_hsw_transfer_parameter *parameter; | ||
2010 | struct device *dev = hsw->dev; | ||
2011 | |||
2012 | header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) | | ||
2013 | IPC_MODULE_OPERATION(IPC_MODULE_SET_PARAMETER) | | ||
2014 | IPC_MODULE_ID(module_id); | ||
2015 | dev_dbg(dev, "sst_hsw_module_set_param header=%x\n", header); | ||
2016 | |||
2017 | payload_size = param_size + | ||
2018 | sizeof(struct sst_hsw_transfer_parameter) - | ||
2019 | sizeof(struct sst_hsw_transfer_list); | ||
2020 | dev_dbg(dev, "parameter size : %d\n", param_size); | ||
2021 | dev_dbg(dev, "payload size : %d\n", payload_size); | ||
2022 | |||
2023 | if (payload_size <= SST_HSW_IPC_MAX_SHORT_PARAMETER_SIZE) { | ||
2024 | /* short parameter, mailbox can contain data */ | ||
2025 | dev_dbg(dev, "transfer parameter size : %d\n", | ||
2026 | transfer_parameter_size); | ||
2027 | |||
2028 | transfer_parameter_size = ALIGN(payload_size, 4); | ||
2029 | dev_dbg(dev, "transfer parameter aligned size : %d\n", | ||
2030 | transfer_parameter_size); | ||
2031 | |||
2032 | parameter = kzalloc(transfer_parameter_size, GFP_KERNEL); | ||
2033 | if (parameter == NULL) | ||
2034 | return -ENOMEM; | ||
2035 | |||
2036 | memcpy(parameter->data, param, param_size); | ||
2037 | } else { | ||
2038 | dev_warn(dev, "transfer parameter size too large!"); | ||
2039 | return 0; | ||
2040 | } | ||
2041 | |||
2042 | parameter->parameter_id = parameter_id; | ||
2043 | parameter->data_size = param_size; | ||
2044 | |||
2045 | ret = sst_ipc_tx_message_wait(&hsw->ipc, header, | ||
2046 | parameter, transfer_parameter_size , NULL, 0); | ||
2047 | if (ret < 0) | ||
2048 | dev_err(dev, "ipc: module set parameter failed - %d\n", ret); | ||
2049 | |||
2050 | kfree(parameter); | ||
2051 | |||
2052 | if (data) | ||
2053 | dma_free_coherent(hsw->dsp->dma_dev, | ||
2054 | param_size, (void *)data, dma_addr); | ||
2055 | |||
2056 | return ret; | ||
1887 | } | 2057 | } |
1888 | 2058 | ||
1889 | static struct sst_dsp_device hsw_dev = { | 2059 | static struct sst_dsp_device hsw_dev = { |
@@ -1891,10 +2061,48 @@ static struct sst_dsp_device hsw_dev = { | |||
1891 | .ops = &haswell_ops, | 2061 | .ops = &haswell_ops, |
1892 | }; | 2062 | }; |
1893 | 2063 | ||
2064 | static void hsw_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) | ||
2065 | { | ||
2066 | /* send the message */ | ||
2067 | sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size); | ||
2068 | sst_dsp_ipc_msg_tx(ipc->dsp, msg->header); | ||
2069 | } | ||
2070 | |||
2071 | static void hsw_shim_dbg(struct sst_generic_ipc *ipc, const char *text) | ||
2072 | { | ||
2073 | struct sst_dsp *sst = ipc->dsp; | ||
2074 | u32 isr, ipcd, imrx, ipcx; | ||
2075 | |||
2076 | ipcx = sst_dsp_shim_read_unlocked(sst, SST_IPCX); | ||
2077 | isr = sst_dsp_shim_read_unlocked(sst, SST_ISRX); | ||
2078 | ipcd = sst_dsp_shim_read_unlocked(sst, SST_IPCD); | ||
2079 | imrx = sst_dsp_shim_read_unlocked(sst, SST_IMRX); | ||
2080 | |||
2081 | dev_err(ipc->dev, | ||
2082 | "ipc: --%s-- ipcx 0x%8.8x isr 0x%8.8x ipcd 0x%8.8x imrx 0x%8.8x\n", | ||
2083 | text, ipcx, isr, ipcd, imrx); | ||
2084 | } | ||
2085 | |||
2086 | static void hsw_tx_data_copy(struct ipc_message *msg, char *tx_data, | ||
2087 | size_t tx_size) | ||
2088 | { | ||
2089 | memcpy(msg->tx_data, tx_data, tx_size); | ||
2090 | } | ||
2091 | |||
2092 | static u64 hsw_reply_msg_match(u64 header, u64 *mask) | ||
2093 | { | ||
2094 | /* clear reply bits & status bits */ | ||
2095 | header &= ~(IPC_STATUS_MASK | IPC_GLB_REPLY_MASK); | ||
2096 | *mask = (u64)-1; | ||
2097 | |||
2098 | return header; | ||
2099 | } | ||
2100 | |||
1894 | int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) | 2101 | int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) |
1895 | { | 2102 | { |
1896 | struct sst_hsw_ipc_fw_version version; | 2103 | struct sst_hsw_ipc_fw_version version; |
1897 | struct sst_hsw *hsw; | 2104 | struct sst_hsw *hsw; |
2105 | struct sst_generic_ipc *ipc; | ||
1898 | int ret; | 2106 | int ret; |
1899 | 2107 | ||
1900 | dev_dbg(dev, "initialising Audio DSP IPC\n"); | 2108 | dev_dbg(dev, "initialising Audio DSP IPC\n"); |
@@ -1903,39 +2111,30 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
1903 | if (hsw == NULL) | 2111 | if (hsw == NULL) |
1904 | return -ENOMEM; | 2112 | return -ENOMEM; |
1905 | 2113 | ||
1906 | hsw->dev = dev; | 2114 | ipc = &hsw->ipc; |
1907 | INIT_LIST_HEAD(&hsw->stream_list); | 2115 | ipc->dev = dev; |
1908 | INIT_LIST_HEAD(&hsw->tx_list); | 2116 | ipc->ops.tx_msg = hsw_tx_msg; |
1909 | INIT_LIST_HEAD(&hsw->rx_list); | 2117 | ipc->ops.shim_dbg = hsw_shim_dbg; |
1910 | INIT_LIST_HEAD(&hsw->empty_list); | 2118 | ipc->ops.tx_data_copy = hsw_tx_data_copy; |
1911 | init_waitqueue_head(&hsw->boot_wait); | 2119 | ipc->ops.reply_msg_match = hsw_reply_msg_match; |
1912 | init_waitqueue_head(&hsw->wait_txq); | ||
1913 | |||
1914 | ret = msg_empty_list_init(hsw); | ||
1915 | if (ret < 0) | ||
1916 | return -ENOMEM; | ||
1917 | 2120 | ||
1918 | /* start the IPC message thread */ | 2121 | ret = sst_ipc_init(ipc); |
1919 | init_kthread_worker(&hsw->kworker); | 2122 | if (ret != 0) |
1920 | hsw->tx_thread = kthread_run(kthread_worker_fn, | 2123 | goto ipc_init_err; |
1921 | &hsw->kworker, "%s", | ||
1922 | dev_name(hsw->dev)); | ||
1923 | if (IS_ERR(hsw->tx_thread)) { | ||
1924 | ret = PTR_ERR(hsw->tx_thread); | ||
1925 | dev_err(hsw->dev, "error: failed to create message TX task\n"); | ||
1926 | goto err_free_msg; | ||
1927 | } | ||
1928 | init_kthread_work(&hsw->kwork, ipc_tx_msgs); | ||
1929 | 2124 | ||
2125 | INIT_LIST_HEAD(&hsw->stream_list); | ||
2126 | init_waitqueue_head(&hsw->boot_wait); | ||
1930 | hsw_dev.thread_context = hsw; | 2127 | hsw_dev.thread_context = hsw; |
1931 | 2128 | ||
1932 | /* init SST shim */ | 2129 | /* init SST shim */ |
1933 | hsw->dsp = sst_dsp_new(dev, &hsw_dev, pdata); | 2130 | hsw->dsp = sst_dsp_new(dev, &hsw_dev, pdata); |
1934 | if (hsw->dsp == NULL) { | 2131 | if (hsw->dsp == NULL) { |
1935 | ret = -ENODEV; | 2132 | ret = -ENODEV; |
1936 | goto dsp_err; | 2133 | goto dsp_new_err; |
1937 | } | 2134 | } |
1938 | 2135 | ||
2136 | ipc->dsp = hsw->dsp; | ||
2137 | |||
1939 | /* allocate DMA buffer for context storage */ | 2138 | /* allocate DMA buffer for context storage */ |
1940 | hsw->dx_context = dma_alloc_coherent(hsw->dsp->dma_dev, | 2139 | hsw->dx_context = dma_alloc_coherent(hsw->dsp->dma_dev, |
1941 | SST_HSW_DX_CONTEXT_SIZE, &hsw->dx_context_paddr, GFP_KERNEL); | 2140 | SST_HSW_DX_CONTEXT_SIZE, &hsw->dx_context_paddr, GFP_KERNEL); |
@@ -1947,18 +2146,22 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
1947 | /* keep the DSP in reset state for base FW loading */ | 2146 | /* keep the DSP in reset state for base FW loading */ |
1948 | sst_dsp_reset(hsw->dsp); | 2147 | sst_dsp_reset(hsw->dsp); |
1949 | 2148 | ||
1950 | hsw->sst_fw = sst_fw_new(hsw->dsp, pdata->fw, hsw); | 2149 | /* load base module and other modules in base firmware image */ |
1951 | if (hsw->sst_fw == NULL) { | 2150 | ret = sst_hsw_module_load(hsw, SST_HSW_MODULE_BASE_FW, 0, "Base"); |
1952 | ret = -ENODEV; | 2151 | if (ret < 0) |
1953 | dev_err(dev, "error: failed to load firmware\n"); | ||
1954 | goto fw_err; | 2152 | goto fw_err; |
1955 | } | 2153 | |
2154 | /* try to load module waves */ | ||
2155 | sst_hsw_module_load(hsw, SST_HSW_MODULE_WAVES, 0, "intel/IntcPP01.bin"); | ||
1956 | 2156 | ||
1957 | /* allocate scratch mem regions */ | 2157 | /* allocate scratch mem regions */ |
1958 | ret = sst_block_alloc_scratch(hsw->dsp); | 2158 | ret = sst_block_alloc_scratch(hsw->dsp); |
1959 | if (ret < 0) | 2159 | if (ret < 0) |
1960 | goto boot_err; | 2160 | goto boot_err; |
1961 | 2161 | ||
2162 | /* init param buffer */ | ||
2163 | sst_hsw_reset_param_buf(hsw); | ||
2164 | |||
1962 | /* wait for DSP boot completion */ | 2165 | /* wait for DSP boot completion */ |
1963 | sst_dsp_boot(hsw->dsp); | 2166 | sst_dsp_boot(hsw->dsp); |
1964 | ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete, | 2167 | ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete, |
@@ -1971,6 +2174,9 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
1971 | goto boot_err; | 2174 | goto boot_err; |
1972 | } | 2175 | } |
1973 | 2176 | ||
2177 | /* init module state after boot */ | ||
2178 | sst_hsw_init_module_state(hsw); | ||
2179 | |||
1974 | /* get the FW version */ | 2180 | /* get the FW version */ |
1975 | sst_hsw_fw_get_version(hsw, &version); | 2181 | sst_hsw_fw_get_version(hsw, &version); |
1976 | 2182 | ||
@@ -1986,17 +2192,16 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
1986 | 2192 | ||
1987 | boot_err: | 2193 | boot_err: |
1988 | sst_dsp_reset(hsw->dsp); | 2194 | sst_dsp_reset(hsw->dsp); |
1989 | sst_fw_free(hsw->sst_fw); | 2195 | sst_fw_free_all(hsw->dsp); |
1990 | fw_err: | 2196 | fw_err: |
1991 | dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE, | 2197 | dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE, |
1992 | hsw->dx_context, hsw->dx_context_paddr); | 2198 | hsw->dx_context, hsw->dx_context_paddr); |
1993 | dma_err: | 2199 | dma_err: |
1994 | sst_dsp_free(hsw->dsp); | 2200 | sst_dsp_free(hsw->dsp); |
1995 | dsp_err: | 2201 | dsp_new_err: |
1996 | kthread_stop(hsw->tx_thread); | 2202 | sst_ipc_fini(ipc); |
1997 | err_free_msg: | 2203 | ipc_init_err: |
1998 | kfree(hsw->msg); | 2204 | kfree(hsw); |
1999 | |||
2000 | return ret; | 2205 | return ret; |
2001 | } | 2206 | } |
2002 | EXPORT_SYMBOL_GPL(sst_hsw_dsp_init); | 2207 | EXPORT_SYMBOL_GPL(sst_hsw_dsp_init); |
@@ -2010,7 +2215,6 @@ void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata) | |||
2010 | dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE, | 2215 | dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE, |
2011 | hsw->dx_context, hsw->dx_context_paddr); | 2216 | hsw->dx_context, hsw->dx_context_paddr); |
2012 | sst_dsp_free(hsw->dsp); | 2217 | sst_dsp_free(hsw->dsp); |
2013 | kthread_stop(hsw->tx_thread); | 2218 | sst_ipc_fini(&hsw->ipc); |
2014 | kfree(hsw->msg); | ||
2015 | } | 2219 | } |
2016 | EXPORT_SYMBOL_GPL(sst_hsw_dsp_free); | 2220 | EXPORT_SYMBOL_GPL(sst_hsw_dsp_free); |
diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/haswell/sst-haswell-ipc.h index 858096041cb1..06d71aefa1fe 100644 --- a/sound/soc/intel/sst-haswell-ipc.h +++ b/sound/soc/intel/haswell/sst-haswell-ipc.h | |||
@@ -37,6 +37,9 @@ | |||
37 | #define SST_HSW_IPC_MAX_PAYLOAD_SIZE 400 | 37 | #define SST_HSW_IPC_MAX_PAYLOAD_SIZE 400 |
38 | #define SST_HSW_MAX_INFO_SIZE 64 | 38 | #define SST_HSW_MAX_INFO_SIZE 64 |
39 | #define SST_HSW_BUILD_HASH_LENGTH 40 | 39 | #define SST_HSW_BUILD_HASH_LENGTH 40 |
40 | #define SST_HSW_IPC_MAX_SHORT_PARAMETER_SIZE 500 | ||
41 | #define WAVES_PARAM_COUNT 128 | ||
42 | #define WAVES_PARAM_LINES 160 | ||
40 | 43 | ||
41 | struct sst_hsw; | 44 | struct sst_hsw; |
42 | struct sst_hsw_stream; | 45 | struct sst_hsw_stream; |
@@ -187,6 +190,28 @@ enum sst_hsw_performance_action { | |||
187 | SST_HSW_PERF_STOP = 1, | 190 | SST_HSW_PERF_STOP = 1, |
188 | }; | 191 | }; |
189 | 192 | ||
193 | struct sst_hsw_transfer_info { | ||
194 | uint32_t destination; /* destination address */ | ||
195 | uint32_t reverse:1; /* if 1 data flows from destination */ | ||
196 | uint32_t size:31; /* transfer size in bytes.*/ | ||
197 | uint16_t first_page_offset; /* offset to data in the first page. */ | ||
198 | uint8_t packed_pages; /* page addresses. Each occupies 20 bits */ | ||
199 | } __attribute__((packed)); | ||
200 | |||
201 | struct sst_hsw_transfer_list { | ||
202 | uint32_t transfers_count; | ||
203 | struct sst_hsw_transfer_info transfers; | ||
204 | } __attribute__((packed)); | ||
205 | |||
206 | struct sst_hsw_transfer_parameter { | ||
207 | uint32_t parameter_id; | ||
208 | uint32_t data_size; | ||
209 | union { | ||
210 | uint8_t data[1]; | ||
211 | struct sst_hsw_transfer_list transfer_list; | ||
212 | }; | ||
213 | } __attribute__((packed)); | ||
214 | |||
190 | /* SST firmware module info */ | 215 | /* SST firmware module info */ |
191 | struct sst_hsw_module_info { | 216 | struct sst_hsw_module_info { |
192 | u8 name[SST_HSW_MAX_INFO_SIZE]; | 217 | u8 name[SST_HSW_MAX_INFO_SIZE]; |
@@ -215,6 +240,12 @@ struct sst_hsw_fx_enable { | |||
215 | struct sst_hsw_memory_info persistent_mem; | 240 | struct sst_hsw_memory_info persistent_mem; |
216 | } __attribute__((packed)); | 241 | } __attribute__((packed)); |
217 | 242 | ||
243 | struct sst_hsw_ipc_module_config { | ||
244 | struct sst_hsw_module_map map; | ||
245 | struct sst_hsw_memory_info persistent_mem; | ||
246 | struct sst_hsw_memory_info scratch_mem; | ||
247 | } __attribute__((packed)); | ||
248 | |||
218 | struct sst_hsw_get_fx_param { | 249 | struct sst_hsw_get_fx_param { |
219 | u32 parameter_id; | 250 | u32 parameter_id; |
220 | u32 param_size; | 251 | u32 param_size; |
@@ -467,6 +498,28 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata); | |||
467 | void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata); | 498 | void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata); |
468 | struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw); | 499 | struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw); |
469 | 500 | ||
501 | /* fw module function */ | ||
502 | void sst_hsw_init_module_state(struct sst_hsw *hsw); | ||
503 | bool sst_hsw_is_module_loaded(struct sst_hsw *hsw, u32 module_id); | ||
504 | bool sst_hsw_is_module_active(struct sst_hsw *hsw, u32 module_id); | ||
505 | void sst_hsw_set_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id); | ||
506 | void sst_hsw_set_module_disabled_rtd3(struct sst_hsw *hsw, u32 module_id); | ||
507 | bool sst_hsw_is_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id); | ||
508 | void sst_hsw_reset_param_buf(struct sst_hsw *hsw); | ||
509 | int sst_hsw_store_param_line(struct sst_hsw *hsw, u8 *buf); | ||
510 | int sst_hsw_load_param_line(struct sst_hsw *hsw, u8 *buf); | ||
511 | int sst_hsw_launch_param_buf(struct sst_hsw *hsw); | ||
512 | |||
513 | int sst_hsw_module_load(struct sst_hsw *hsw, | ||
514 | u32 module_id, u32 instance_id, char *name); | ||
515 | int sst_hsw_module_enable(struct sst_hsw *hsw, | ||
516 | u32 module_id, u32 instance_id); | ||
517 | int sst_hsw_module_disable(struct sst_hsw *hsw, | ||
518 | u32 module_id, u32 instance_id); | ||
519 | int sst_hsw_module_set_param(struct sst_hsw *hsw, | ||
520 | u32 module_id, u32 instance_id, u32 parameter_id, | ||
521 | u32 param_size, char *param); | ||
522 | |||
470 | /* runtime module management */ | 523 | /* runtime module management */ |
471 | struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw, | 524 | struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw, |
472 | int mod_id, int offset); | 525 | int mod_id, int offset); |
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/haswell/sst-haswell-pcm.c index 7e21e8f85885..23ae0400d6db 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/haswell/sst-haswell-pcm.c | |||
@@ -29,9 +29,9 @@ | |||
29 | #include <sound/tlv.h> | 29 | #include <sound/tlv.h> |
30 | #include <sound/compress_driver.h> | 30 | #include <sound/compress_driver.h> |
31 | 31 | ||
32 | #include "sst-haswell-ipc.h" | 32 | #include "../haswell/sst-haswell-ipc.h" |
33 | #include "sst-dsp-priv.h" | 33 | #include "../common/sst-dsp-priv.h" |
34 | #include "sst-dsp.h" | 34 | #include "../common/sst-dsp.h" |
35 | 35 | ||
36 | #define HSW_PCM_COUNT 6 | 36 | #define HSW_PCM_COUNT 6 |
37 | #define HSW_VOLUME_MAX 0x7FFFFFFF /* 0dB */ | 37 | #define HSW_VOLUME_MAX 0x7FFFFFFF /* 0dB */ |
@@ -137,6 +137,7 @@ struct hsw_priv_data { | |||
137 | struct device *dev; | 137 | struct device *dev; |
138 | enum hsw_pm_state pm_state; | 138 | enum hsw_pm_state pm_state; |
139 | struct snd_soc_card *soc_card; | 139 | struct snd_soc_card *soc_card; |
140 | struct sst_module_runtime *runtime_waves; /* sound effect module */ | ||
140 | 141 | ||
141 | /* page tables */ | 142 | /* page tables */ |
142 | struct snd_dma_buffer dmab[HSW_PCM_COUNT][2]; | 143 | struct snd_dma_buffer dmab[HSW_PCM_COUNT][2]; |
@@ -318,6 +319,93 @@ static int hsw_volume_get(struct snd_kcontrol *kcontrol, | |||
318 | return 0; | 319 | return 0; |
319 | } | 320 | } |
320 | 321 | ||
322 | static int hsw_waves_switch_get(struct snd_kcontrol *kcontrol, | ||
323 | struct snd_ctl_elem_value *ucontrol) | ||
324 | { | ||
325 | struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); | ||
326 | struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); | ||
327 | struct sst_hsw *hsw = pdata->hsw; | ||
328 | enum sst_hsw_module_id id = SST_HSW_MODULE_WAVES; | ||
329 | |||
330 | ucontrol->value.integer.value[0] = | ||
331 | (sst_hsw_is_module_active(hsw, id) || | ||
332 | sst_hsw_is_module_enabled_rtd3(hsw, id)); | ||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | static int hsw_waves_switch_put(struct snd_kcontrol *kcontrol, | ||
337 | struct snd_ctl_elem_value *ucontrol) | ||
338 | { | ||
339 | struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); | ||
340 | struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); | ||
341 | struct sst_hsw *hsw = pdata->hsw; | ||
342 | int ret = 0; | ||
343 | enum sst_hsw_module_id id = SST_HSW_MODULE_WAVES; | ||
344 | bool switch_on = (bool)ucontrol->value.integer.value[0]; | ||
345 | |||
346 | /* if module is in RAM on the DSP, apply user settings to module through | ||
347 | * ipc. If module is not in RAM on the DSP, store user setting for | ||
348 | * track */ | ||
349 | if (sst_hsw_is_module_loaded(hsw, id)) { | ||
350 | if (switch_on == sst_hsw_is_module_active(hsw, id)) | ||
351 | return 0; | ||
352 | |||
353 | if (switch_on) | ||
354 | ret = sst_hsw_module_enable(hsw, id, 0); | ||
355 | else | ||
356 | ret = sst_hsw_module_disable(hsw, id, 0); | ||
357 | } else { | ||
358 | if (switch_on == sst_hsw_is_module_enabled_rtd3(hsw, id)) | ||
359 | return 0; | ||
360 | |||
361 | if (switch_on) | ||
362 | sst_hsw_set_module_enabled_rtd3(hsw, id); | ||
363 | else | ||
364 | sst_hsw_set_module_disabled_rtd3(hsw, id); | ||
365 | } | ||
366 | |||
367 | return ret; | ||
368 | } | ||
369 | |||
370 | static int hsw_waves_param_get(struct snd_kcontrol *kcontrol, | ||
371 | struct snd_ctl_elem_value *ucontrol) | ||
372 | { | ||
373 | struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); | ||
374 | struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); | ||
375 | struct sst_hsw *hsw = pdata->hsw; | ||
376 | |||
377 | /* return a matching line from param buffer */ | ||
378 | return sst_hsw_load_param_line(hsw, ucontrol->value.bytes.data); | ||
379 | } | ||
380 | |||
381 | static int hsw_waves_param_put(struct snd_kcontrol *kcontrol, | ||
382 | struct snd_ctl_elem_value *ucontrol) | ||
383 | { | ||
384 | struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); | ||
385 | struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); | ||
386 | struct sst_hsw *hsw = pdata->hsw; | ||
387 | int ret; | ||
388 | enum sst_hsw_module_id id = SST_HSW_MODULE_WAVES; | ||
389 | int param_id = ucontrol->value.bytes.data[0]; | ||
390 | int param_size = WAVES_PARAM_COUNT; | ||
391 | |||
392 | /* clear param buffer and reset buffer index */ | ||
393 | if (param_id == 0xFF) { | ||
394 | sst_hsw_reset_param_buf(hsw); | ||
395 | return 0; | ||
396 | } | ||
397 | |||
398 | /* store params into buffer */ | ||
399 | ret = sst_hsw_store_param_line(hsw, ucontrol->value.bytes.data); | ||
400 | if (ret < 0) | ||
401 | return ret; | ||
402 | |||
403 | if (sst_hsw_is_module_active(hsw, id)) | ||
404 | ret = sst_hsw_module_set_param(hsw, id, 0, param_id, | ||
405 | param_size, ucontrol->value.bytes.data); | ||
406 | return ret; | ||
407 | } | ||
408 | |||
321 | /* TLV used by both global and stream volumes */ | 409 | /* TLV used by both global and stream volumes */ |
322 | static const DECLARE_TLV_DB_SCALE(hsw_vol_tlv, -9000, 300, 1); | 410 | static const DECLARE_TLV_DB_SCALE(hsw_vol_tlv, -9000, 300, 1); |
323 | 411 | ||
@@ -339,6 +427,12 @@ static const struct snd_kcontrol_new hsw_volume_controls[] = { | |||
339 | SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 4, 0, 8, | 427 | SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 4, 0, 8, |
340 | ARRAY_SIZE(volume_map) - 1, 0, | 428 | ARRAY_SIZE(volume_map) - 1, 0, |
341 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), | 429 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), |
430 | /* enable/disable module waves */ | ||
431 | SOC_SINGLE_BOOL_EXT("Waves Switch", 0, | ||
432 | hsw_waves_switch_get, hsw_waves_switch_put), | ||
433 | /* set parameters to module waves */ | ||
434 | SND_SOC_BYTES_EXT("Waves Set Param", WAVES_PARAM_COUNT, | ||
435 | hsw_waves_param_get, hsw_waves_param_put), | ||
342 | }; | 436 | }; |
343 | 437 | ||
344 | /* Create DMA buffer page table for DSP */ | 438 | /* Create DMA buffer page table for DSP */ |
@@ -807,6 +901,14 @@ static int hsw_pcm_create_modules(struct hsw_priv_data *pdata) | |||
807 | pcm_data->runtime->persistent_offset; | 901 | pcm_data->runtime->persistent_offset; |
808 | } | 902 | } |
809 | 903 | ||
904 | /* create runtime blocks for module waves */ | ||
905 | if (sst_hsw_is_module_loaded(hsw, SST_HSW_MODULE_WAVES)) { | ||
906 | pdata->runtime_waves = sst_hsw_runtime_module_create(hsw, | ||
907 | SST_HSW_MODULE_WAVES, 0); | ||
908 | if (pdata->runtime_waves == NULL) | ||
909 | goto err; | ||
910 | } | ||
911 | |||
810 | return 0; | 912 | return 0; |
811 | 913 | ||
812 | err: | 914 | err: |
@@ -820,14 +922,17 @@ err: | |||
820 | 922 | ||
821 | static void hsw_pcm_free_modules(struct hsw_priv_data *pdata) | 923 | static void hsw_pcm_free_modules(struct hsw_priv_data *pdata) |
822 | { | 924 | { |
925 | struct sst_hsw *hsw = pdata->hsw; | ||
823 | struct hsw_pcm_data *pcm_data; | 926 | struct hsw_pcm_data *pcm_data; |
824 | int i; | 927 | int i; |
825 | 928 | ||
826 | for (i = 0; i < ARRAY_SIZE(mod_map); i++) { | 929 | for (i = 0; i < ARRAY_SIZE(mod_map); i++) { |
827 | pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; | 930 | pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; |
828 | |||
829 | sst_hsw_runtime_module_free(pcm_data->runtime); | 931 | sst_hsw_runtime_module_free(pcm_data->runtime); |
830 | } | 932 | } |
933 | if (sst_hsw_is_module_loaded(hsw, SST_HSW_MODULE_WAVES)) { | ||
934 | sst_hsw_runtime_module_free(pdata->runtime_waves); | ||
935 | } | ||
831 | } | 936 | } |
832 | 937 | ||
833 | static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) | 938 | static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) |
@@ -984,7 +1089,9 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) | |||
984 | } | 1089 | } |
985 | 1090 | ||
986 | /* allocate runtime modules */ | 1091 | /* allocate runtime modules */ |
987 | hsw_pcm_create_modules(priv_data); | 1092 | ret = hsw_pcm_create_modules(priv_data); |
1093 | if (ret < 0) | ||
1094 | goto err; | ||
988 | 1095 | ||
989 | /* enable runtime PM with auto suspend */ | 1096 | /* enable runtime PM with auto suspend */ |
990 | pm_runtime_set_autosuspend_delay(platform->dev, | 1097 | pm_runtime_set_autosuspend_delay(platform->dev, |
@@ -996,7 +1103,7 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) | |||
996 | return 0; | 1103 | return 0; |
997 | 1104 | ||
998 | err: | 1105 | err: |
999 | for (;i >= 0; i--) { | 1106 | for (--i; i >= 0; i--) { |
1000 | if (hsw_dais[i].playback.channels_min) | 1107 | if (hsw_dais[i].playback.channels_min) |
1001 | snd_dma_free_pages(&priv_data->dmab[i][0]); | 1108 | snd_dma_free_pages(&priv_data->dmab[i][0]); |
1002 | if (hsw_dais[i].capture.channels_min) | 1109 | if (hsw_dais[i].capture.channels_min) |
@@ -1101,10 +1208,18 @@ static int hsw_pcm_runtime_suspend(struct device *dev) | |||
1101 | { | 1208 | { |
1102 | struct hsw_priv_data *pdata = dev_get_drvdata(dev); | 1209 | struct hsw_priv_data *pdata = dev_get_drvdata(dev); |
1103 | struct sst_hsw *hsw = pdata->hsw; | 1210 | struct sst_hsw *hsw = pdata->hsw; |
1211 | int ret; | ||
1104 | 1212 | ||
1105 | if (pdata->pm_state >= HSW_PM_STATE_RTD3) | 1213 | if (pdata->pm_state >= HSW_PM_STATE_RTD3) |
1106 | return 0; | 1214 | return 0; |
1107 | 1215 | ||
1216 | /* fw modules will be unloaded on RTD3, set flag to track */ | ||
1217 | if (sst_hsw_is_module_active(hsw, SST_HSW_MODULE_WAVES)) { | ||
1218 | ret = sst_hsw_module_disable(hsw, SST_HSW_MODULE_WAVES, 0); | ||
1219 | if (ret < 0) | ||
1220 | return ret; | ||
1221 | sst_hsw_set_module_enabled_rtd3(hsw, SST_HSW_MODULE_WAVES); | ||
1222 | } | ||
1108 | sst_hsw_dsp_runtime_suspend(hsw); | 1223 | sst_hsw_dsp_runtime_suspend(hsw); |
1109 | sst_hsw_dsp_runtime_sleep(hsw); | 1224 | sst_hsw_dsp_runtime_sleep(hsw); |
1110 | pdata->pm_state = HSW_PM_STATE_RTD3; | 1225 | pdata->pm_state = HSW_PM_STATE_RTD3; |
@@ -1139,6 +1254,19 @@ static int hsw_pcm_runtime_resume(struct device *dev) | |||
1139 | else if (ret == 1) /* no action required */ | 1254 | else if (ret == 1) /* no action required */ |
1140 | return 0; | 1255 | return 0; |
1141 | 1256 | ||
1257 | /* check flag when resume */ | ||
1258 | if (sst_hsw_is_module_enabled_rtd3(hsw, SST_HSW_MODULE_WAVES)) { | ||
1259 | ret = sst_hsw_module_enable(hsw, SST_HSW_MODULE_WAVES, 0); | ||
1260 | if (ret < 0) | ||
1261 | return ret; | ||
1262 | /* put parameters from buffer to dsp */ | ||
1263 | ret = sst_hsw_launch_param_buf(hsw); | ||
1264 | if (ret < 0) | ||
1265 | return ret; | ||
1266 | /* unset flag */ | ||
1267 | sst_hsw_set_module_disabled_rtd3(hsw, SST_HSW_MODULE_WAVES); | ||
1268 | } | ||
1269 | |||
1142 | pdata->pm_state = HSW_PM_STATE_D0; | 1270 | pdata->pm_state = HSW_PM_STATE_D0; |
1143 | return ret; | 1271 | return ret; |
1144 | } | 1272 | } |