diff options
Diffstat (limited to 'sound/soc/intel')
| -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 |
45 files changed, 1350 insertions, 695 deletions
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 | } |
