From a31b466f9541048fd00e0d2d282091c5693d79d0 Mon Sep 17 00:00:00 2001 From: Sathyanarayana Nujella Date: Tue, 4 Oct 2016 10:33:20 -0700 Subject: ASoC: Intel: report JACK_LINEOUT event This patch updates Jack type bitmask to include SND_JACK_LINEOUT while creating a new jack, so that LINEOUT events are reported properly. Signed-off-by: Sathyanarayana Nujella Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 6532b8f0ab2f..865a21e557cc 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -130,8 +130,8 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) */ ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, &broxton_headset, - NULL, 0); + SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, + &broxton_headset, NULL, 0); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; -- cgit v1.2.3 From 89c03ddbb9aafe370e7d1ebe07258ae755588bdc Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 17 Oct 2016 23:02:56 +0100 Subject: ASoC: sst-bxt-da7219_max98357a: fix obsoleted initializer for array Smatch reports below warnings: bxt_da7219_max98357a.c:352:9: warning: obsolete array initializer, use C99 syntax An earlier commit cleaned up similar warnings, however, a recent commit 43c02ede76a60de ("ASoC: Intel: Add DMIC channel constraint for bxt machine") re-introduced the older initializer style. So fix this warning to make the code consistent. Signed-off-by: Colin Ian King Reviewed-by: Takashi Sakamoto Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 865a21e557cc..bff80b467262 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -348,7 +348,7 @@ static struct snd_soc_dai_link broxton_dais[] = { .dynamic = 1, .ops = &broxton_refcap_ops, }, - [BXT_DPCM_AUDIO_DMIC_CP] + [BXT_DPCM_AUDIO_DMIC_CP] = { .name = "Bxt Audio DMIC cap", .stream_name = "dmiccap", -- cgit v1.2.3 From d5bc18c148fd3d3ab7cbd3d976f7e27226f74dd8 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 15 Oct 2016 16:55:45 +0200 Subject: ASoC: intel: broadwell: constify snd_soc_ops structures Check for snd_soc_ops structures that are only stored in the ops field of a snd_soc_dai_link structure. This field is declared const, so snd_soc_ops structures that have this property can be declared as const also. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @r disable optional_qualifier@ identifier i; position p; @@ static struct snd_soc_ops i@p = { ... }; @ok1@ identifier r.i; struct snd_soc_dai_link e; position p; @@ e.ops = &i@p; @ok2@ identifier r.i, e; position p; @@ struct snd_soc_dai_link e[] = { ..., { .ops = &i@p, }, ..., }; @bad@ position p != {r.p,ok1.p,ok2.p}; identifier r.i; struct snd_soc_ops e; @@ e@i@p @depends on !bad disable optional_qualifier@ identifier r.i; @@ static +const struct snd_soc_ops i = { ... }; // The effect on the layout of the .o file is shown by the following output of the size command, first before then after the transformation: text data bss dec hex filename 3865 2784 384 7033 1b79 sound/soc/intel/boards/broadwell.o 3929 2720 384 7033 1b79 sound/soc/intel/boards/broadwell.o Signed-off-by: Julia Lawall Acked-by: Jie Yang Signed-off-by: Mark Brown --- sound/soc/intel/boards/broadwell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index 7486a0022fde..5bb64d164877 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -126,7 +126,7 @@ static int broadwell_rt286_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops broadwell_rt286_ops = { +static const struct snd_soc_ops broadwell_rt286_ops = { .hw_params = broadwell_rt286_hw_params, }; -- cgit v1.2.3 From c8eabf821cac120afb78ca251b07cbf520406a7e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 13 Oct 2016 11:55:48 +0300 Subject: ASoC: Intel: Skylake: Fix a shift wrapping bug "*val" is a u64. It definitely looks like we intend to use the high 32 bits as well. Fixes: 700a9a63f9c1 ("ASoC: Intel: Skylake: Add module instance id generation APIs") Signed-off-by: Dan Carpenter Acked-by: Vinod Koul Tested-by: Kranthi G Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst-utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c index 8dc03039b311..ea162fbf68e5 100644 --- a/sound/soc/intel/skylake/skl-sst-utils.c +++ b/sound/soc/intel/skylake/skl-sst-utils.c @@ -179,7 +179,7 @@ static inline int skl_getid_32(struct uuid_module *module, u64 *val, index = ffz(mask_val); pvt_id = index + word1_mask + word2_mask; if (pvt_id <= (max_inst - 1)) { - *val |= 1 << (index + word1_mask); + *val |= 1ULL << (index + word1_mask); return pvt_id; } } -- cgit v1.2.3 From ca590c1c45d1d06f842a82f6a591b94af95952b0 Mon Sep 17 00:00:00 2001 From: Dharageswari R Date: Thu, 6 Oct 2016 08:51:21 +0530 Subject: ASoC: Intel: Skylake: Use DPIB to update position for Playback stream DPIB is read currently from a buffer position in memory (indicated by the registers DPIB[U|L]BASE).Driver reads the position buffer on BDL completion interrupts to report the DMA position. But the BDL completion interrupt only indicates the last DMA transfer of the buffer is completed at the Intel HD Audio subsystem boundary. The periodic DMA Position-in-Buffer writes may be scheduled at the same time or later than the MSI and does not guarantee to reflect the position of the last buffer that was transferred. Whereas DPIB register in HDA space(vendor specific register indicated by SDxDPIB) reflects the actual data that is transferred. Hence update the position based on DPIB for playback. Signed-off-by: Dharageswari R Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 58c728662600..c966b40da180 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1031,10 +1031,24 @@ static snd_pcm_uframes_t skl_platform_pcm_pointer (struct snd_pcm_substream *substream) { struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream); + struct hdac_ext_bus *ebus = get_bus_ctx(substream); unsigned int pos; - /* use the position buffer as default */ - pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream)); + /* + * Use DPIB for Playback stream as the periodic DMA Position-in- + * Buffer Writes may be scheduled at the same time or later than + * the MSI and does not guarantee to reflect the Position of the + * last buffer that was transferred. Whereas DPIB register in + * HAD space reflects the actual data that is transferred. + * Use the position buffer for capture, as DPIB write gets + * completed earlier than the actual data written to the DDR. + */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + pos = readl(ebus->bus.remap_addr + AZX_REG_VS_SDXDPIB_XBASE + + (AZX_REG_VS_SDXDPIB_XINTERVAL * + hdac_stream(hstream)->index)); + else + pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream)); if (pos >= hdac_stream(hstream)->bufsize) pos = 0; -- cgit v1.2.3 From 6a7f5e41128de638fae7522262d18a6ef9cf1096 Mon Sep 17 00:00:00 2001 From: Sebastien Guiriec Date: Fri, 28 Oct 2016 16:32:50 +0200 Subject: ASoC: Intel: atom: Add debug information related to FW version This patch is adding debug information related to SST FW version. Signed-off-by: Sebastien Guiriec Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_ipc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c index bfc889950bb2..7934a0047384 100644 --- a/sound/soc/intel/atom/sst/sst_ipc.c +++ b/sound/soc/intel/atom/sst/sst_ipc.c @@ -236,6 +236,11 @@ static void process_fw_init(struct intel_sst_drv *sst_drv_ctx, retval = init->result; goto ret; } + dev_info(sst_drv_ctx->dev, "FW Version %02x.%02x.%02x.%02x\n", + init->fw_version.type, init->fw_version.major, + init->fw_version.minor, init->fw_version.build); + dev_dbg(sst_drv_ctx->dev, "Build date %s Time %s\n", + init->build_info.date, init->build_info.time); ret: sst_wake_up_block(sst_drv_ctx, retval, FW_DWNL_ID, 0 , NULL, 0); -- cgit v1.2.3 From f999d1fd69ede11012a872cbdba33bd9c9c2e386 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 26 Sep 2016 11:05:28 +0530 Subject: ASoC: Intel: Add check_dsp_lp_on callback on IPC Some controllers support power modes which can't communicate using IPC. So add a callback to check and wake DSP before sending IPC and then put to sleep if it is in these power modes. Signed-off-by: Jayachandran B Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/common/sst-ipc.c | 19 ++++++++++++++++++- sound/soc/intel/common/sst-ipc.h | 1 + 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/common/sst-ipc.c b/sound/soc/intel/common/sst-ipc.c index 6c672ac79cce..45a85190a081 100644 --- a/sound/soc/intel/common/sst-ipc.c +++ b/sound/soc/intel/common/sst-ipc.c @@ -190,8 +190,25 @@ static void ipc_tx_msgs(struct kthread_work *work) int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header, void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes) { - return ipc_tx_message(ipc, header, tx_data, tx_bytes, + int ret; + + /* + * DSP maybe in lower power active state, so + * check if the DSP supports DSP lp On method + * if so invoke that before sending IPC + */ + if (ipc->ops.check_dsp_lp_on) + if (ipc->ops.check_dsp_lp_on(ipc->dsp, true)) + return -EIO; + + ret = ipc_tx_message(ipc, header, tx_data, tx_bytes, rx_data, rx_bytes, 1); + + if (ipc->ops.check_dsp_lp_on) + if (ipc->ops.check_dsp_lp_on(ipc->dsp, false)) + return -EIO; + + return ret; } EXPORT_SYMBOL_GPL(sst_ipc_tx_message_wait); diff --git a/sound/soc/intel/common/sst-ipc.h b/sound/soc/intel/common/sst-ipc.h index ceb7e468a3fa..46871a5dff1d 100644 --- a/sound/soc/intel/common/sst-ipc.h +++ b/sound/soc/intel/common/sst-ipc.h @@ -52,6 +52,7 @@ struct sst_plat_ipc_ops { void (*tx_data_copy)(struct ipc_message *, char *, size_t); u64 (*reply_msg_match)(u64 header, u64 *mask); bool (*is_dsp_busy)(struct sst_dsp *dsp); + int (*check_dsp_lp_on)(struct sst_dsp *dsp, bool state); }; /* SST generic IPC data */ -- cgit v1.2.3 From 80a0df18191ab50eee7da3cd56cecdd55b7ab148 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 3 Nov 2016 17:07:14 +0530 Subject: ASoC: Intel: Add sst_ipc_tx_message_nopm If the DSP is in low power mode, it needs to be woken up by a "wake" IPC to set it into the D0 state before we can send any other IPC command. The call flow is that the driver calls sst_ipc_tx_message_wait() to send any IPC and this call checks if the device is in low power mode and in that case we need to send the wake IPC. So add a new IPC nopm variant which can be called from driver and doesn't check for power state (as we already know that) and avoids circular dependency of again checking power state. Signed-off-by: Jayachandran B Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/common/sst-ipc.c | 8 ++++++++ sound/soc/intel/common/sst-ipc.h | 3 +++ 2 files changed, 11 insertions(+) diff --git a/sound/soc/intel/common/sst-ipc.c b/sound/soc/intel/common/sst-ipc.c index 45a85190a081..2c1b3159ac1a 100644 --- a/sound/soc/intel/common/sst-ipc.c +++ b/sound/soc/intel/common/sst-ipc.c @@ -220,6 +220,14 @@ int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, u64 header, } EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nowait); +int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, u64 header, + void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes) +{ + return ipc_tx_message(ipc, header, tx_data, tx_bytes, + rx_data, rx_bytes, 1); +} +EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nopm); + struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc, u64 header) { diff --git a/sound/soc/intel/common/sst-ipc.h b/sound/soc/intel/common/sst-ipc.h index 46871a5dff1d..f4aab1b3789a 100644 --- a/sound/soc/intel/common/sst-ipc.h +++ b/sound/soc/intel/common/sst-ipc.h @@ -82,6 +82,9 @@ int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header, int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, u64 header, void *tx_data, size_t tx_bytes); +int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, u64 header, + void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes); + struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc, u64 header); -- cgit v1.2.3 From 41b7523f192bdf3804e3e18a61f91244e4a0cb25 Mon Sep 17 00:00:00 2001 From: Pardha Saradhi K Date: Thu, 3 Nov 2016 17:07:15 +0530 Subject: ASoC: Intel: Skylake: Add D0iX IPCs The audio DSP supports intermediate power states between D0 and D3 states. These states are D0i0 and D0i3 states. Collectively we refer these two states as D0iX states. To set or wake up from these states, driver also needs to send an IPC "Set D0iX IPC" before doing anything else. Add support for this new IPC messages. Signed-off-by: Pardha Saradhi K Signed-off-by: Jayachandran B Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst-ipc.c | 43 ++++++++++++++++++++++++++++++++++- sound/soc/intel/skylake/skl-sst-ipc.h | 10 ++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 797cf4053235..087b8d6e7186 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -172,6 +172,17 @@ << IPC_INITIAL_BLOCK_SHIFT) #define IPC_INITIAL_BLOCK_CLEAR ~(IPC_INITIAL_BLOCK_MASK \ << IPC_INITIAL_BLOCK_SHIFT) +/* Set D0ix IPC extension register */ +#define IPC_D0IX_WAKE_SHIFT 0 +#define IPC_D0IX_WAKE_MASK 0x1 +#define IPC_D0IX_WAKE(x) (((x) & IPC_D0IX_WAKE_MASK) \ + << IPC_D0IX_WAKE_SHIFT) + +#define IPC_D0IX_STREAMING_SHIFT 1 +#define IPC_D0IX_STREAMING_MASK 0x1 +#define IPC_D0IX_STREAMING(x) (((x) & IPC_D0IX_STREAMING_MASK) \ + << IPC_D0IX_STREAMING_SHIFT) + enum skl_ipc_msg_target { IPC_FW_GEN_MSG = 0, @@ -258,7 +269,8 @@ enum skl_ipc_module_msg { IPC_MOD_LARGE_CONFIG_SET = 4, IPC_MOD_BIND = 5, IPC_MOD_UNBIND = 6, - IPC_MOD_SET_DX = 7 + IPC_MOD_SET_DX = 7, + IPC_MOD_SET_D0IX = 8 }; static void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data, @@ -931,3 +943,32 @@ int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, return ret; } EXPORT_SYMBOL_GPL(skl_sst_ipc_load_library); + +int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc, struct skl_ipc_d0ix_msg *msg) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + int ret; + + header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(IPC_MOD_SET_D0IX); + header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); + header.primary |= IPC_MOD_ID(msg->module_id); + + header.extension = IPC_D0IX_WAKE(msg->wake); + header.extension |= IPC_D0IX_STREAMING(msg->streaming); + + dev_dbg(ipc->dev, "In %s primary=%x ext=%x\n", __func__, + header.primary, header.extension); + + /* + * Use the nopm IPC here as we dont want it checking for D0iX + */ + ret = sst_ipc_tx_message_nopm(ipc, *ipc_header, NULL, 0, NULL, 0); + if (ret < 0) + dev_err(ipc->dev, "ipc: set d0ix failed, err %d\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(skl_ipc_set_d0ix); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index 0334ed4af031..1ae265d8ee08 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -111,6 +111,13 @@ struct skl_ipc_large_config_msg { u32 param_data_size; }; +struct skl_ipc_d0ix_msg { + u32 module_id; + u32 instance_id; + u8 streaming; + u8 wake; +}; + #define SKL_IPC_BOOT_MSECS 3000 #define SKL_IPC_D3_MASK 0 @@ -155,6 +162,9 @@ int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, u8 dma_id, u8 table_id); +int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc, + struct skl_ipc_d0ix_msg *msg); + void skl_ipc_int_enable(struct sst_dsp *dsp); void skl_ipc_op_int_enable(struct sst_dsp *ctx); void skl_ipc_op_int_disable(struct sst_dsp *ctx); -- cgit v1.2.3 From a26a3f53e3d2bfeb666ca31b5f86c65a1816eb89 Mon Sep 17 00:00:00 2001 From: Pardha Saradhi K Date: Thu, 3 Nov 2016 17:07:16 +0530 Subject: ASoC: Intel: Skylake: Add support for programming D0i3C To set the controller in D0i3 mode, the driver needs to set D0i3C register after DSP is quiesced. Since the D0iX entry/exit is done by IPC, add this as callback so that it can be invoked from IPC module. Signed-off-by: Pardha Saradhi K Signed-off-by: Jayachandran B Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 1 + sound/soc/intel/skylake/skl-sst-ipc.h | 3 +++ sound/soc/intel/skylake/skl.c | 47 +++++++++++++++++++++++++++++++++++ sound/soc/intel/skylake/skl.h | 5 ++++ 4 files changed, 56 insertions(+) diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index c966b40da180..b69e05ec6844 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1211,6 +1211,7 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform) return ret; } skl_populate_modules(skl); + skl->skl_sst->update_d0i3c = skl_update_d0i3c; } pm_runtime_mark_last_busy(platform->dev); pm_runtime_put_autosuspend(platform->dev); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index 1ae265d8ee08..ef2182d21934 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -83,6 +83,9 @@ struct skl_sst { /* tplg manifest */ struct skl_dfw_manifest manifest; + + /* Callback to update D0i3C register */ + void (*update_d0i3c)(struct device *dev, bool enable); }; struct skl_ipc_init_instance_msg { diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 2989c164dafe..b9209af89915 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "../common/sst-acpi.h" #include @@ -109,6 +110,52 @@ static int skl_init_chip(struct hdac_bus *bus, bool full_reset) return ret; } +void skl_update_d0i3c(struct device *dev, bool enable) +{ + struct pci_dev *pci = to_pci_dev(dev); + struct hdac_ext_bus *ebus = pci_get_drvdata(pci); + struct hdac_bus *bus = ebus_to_hbus(ebus); + u8 reg; + int timeout = 50; + + reg = snd_hdac_chip_readb(bus, VS_D0I3C); + /* Do not write to D0I3C until command in progress bit is cleared */ + while ((reg & AZX_REG_VS_D0I3C_CIP) && --timeout) { + udelay(10); + reg = snd_hdac_chip_readb(bus, VS_D0I3C); + } + + /* Highly unlikely. But if it happens, flag error explicitly */ + if (!timeout) { + dev_err(bus->dev, "Before D0I3C update: D0I3C CIP timeout\n"); + return; + } + + if (enable) + reg = reg | AZX_REG_VS_D0I3C_I3; + else + reg = reg & (~AZX_REG_VS_D0I3C_I3); + + snd_hdac_chip_writeb(bus, VS_D0I3C, reg); + + timeout = 50; + /* Wait for cmd in progress to be cleared before exiting the function */ + reg = snd_hdac_chip_readb(bus, VS_D0I3C); + while ((reg & AZX_REG_VS_D0I3C_CIP) && --timeout) { + udelay(10); + reg = snd_hdac_chip_readb(bus, VS_D0I3C); + } + + /* Highly unlikely. But if it happens, flag error explicitly */ + if (!timeout) { + dev_err(bus->dev, "After D0I3C update: D0I3C CIP timeout\n"); + return; + } + + dev_dbg(bus->dev, "D0I3C register = 0x%x\n", + snd_hdac_chip_readb(bus, VS_D0I3C)); +} + /* called from IRQ */ static void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr) { diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 5d4fbb094c48..88ba54ba5f72 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -52,6 +52,9 @@ #define AZX_PGCTL_LSRMD_MASK (1 << 4) #define AZX_PCIREG_CGCTL 0x48 #define AZX_CGCTL_MISCBDCGE_MASK (1 << 6) +/* D0I3C Register fields */ +#define AZX_REG_VS_D0I3C_CIP 0x1 /* Command in progress */ +#define AZX_REG_VS_D0I3C_I3 0x4 /* D0i3 enable */ struct skl_dsp_resource { u32 max_mcps; @@ -125,4 +128,6 @@ int skl_suspend_dsp(struct skl *skl); int skl_resume_dsp(struct skl *skl); void skl_cleanup_resources(struct skl *skl); const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id); +void skl_update_d0i3c(struct device *dev, bool enable); + #endif /* __SOUND_SOC_SKL_H */ -- cgit v1.2.3 From 5bb4cd46ace5f220fbc34370e7fe9ba515ead9f8 Mon Sep 17 00:00:00 2001 From: Jayachandran B Date: Thu, 3 Nov 2016 17:07:17 +0530 Subject: ASoC: Intel: Skylake: Add D0iX callbacks The driver needs two DSP callback, one to set D0i0 (active) and D0i3 (low-power) states. Add these callbacks in dsp ops and implement them for broxton platforms. Signed-off-by: Jayachandran B Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/bxt-sst.c | 140 ++++++++++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-sst-dsp.h | 12 +++ sound/soc/intel/skylake/skl-sst-ipc.h | 19 +++++ 3 files changed, 171 insertions(+) diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c index 1d251d59bcb9..fed818fe2e69 100644 --- a/sound/soc/intel/skylake/bxt-sst.c +++ b/sound/soc/intel/skylake/bxt-sst.c @@ -43,6 +43,9 @@ #define BXT_ADSP_FW_BIN_HDR_OFFSET 0x2000 +/* Delay before scheduling D0i3 entry */ +#define BXT_D0I3_DELAY 5000 + static unsigned int bxt_get_errorcode(struct sst_dsp *ctx) { return sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE); @@ -288,6 +291,141 @@ sst_load_base_firmware_failed: return ret; } +/* + * Decide the D0i3 state that can be targeted based on the usecase + * ref counts and DSP state + * + * Decision Matrix: (X= dont care; state = target state) + * + * DSP state != SKL_DSP_RUNNING ; state = no d0i3 + * + * DSP state == SKL_DSP_RUNNING , the following matrix applies + * non_d0i3 >0; streaming =X; non_streaming =X; state = no d0i3 + * non_d0i3 =X; streaming =0; non_streaming =0; state = no d0i3 + * non_d0i3 =0; streaming >0; non_streaming =X; state = streaming d0i3 + * non_d0i3 =0; streaming =0; non_streaming =X; state = non-streaming d0i3 + */ +static int bxt_d0i3_target_state(struct sst_dsp *ctx) +{ + struct skl_sst *skl = ctx->thread_context; + struct skl_d0i3_data *d0i3 = &skl->d0i3; + + if (skl->cores.state[SKL_DSP_CORE0_ID] != SKL_DSP_RUNNING) + return SKL_DSP_D0I3_NONE; + + if (d0i3->non_d0i3) + return SKL_DSP_D0I3_NONE; + else if (d0i3->streaming) + return SKL_DSP_D0I3_STREAMING; + else if (d0i3->non_streaming) + return SKL_DSP_D0I3_NON_STREAMING; + else + return SKL_DSP_D0I3_NONE; +} + +static void bxt_set_dsp_D0i3(struct work_struct *work) +{ + int ret; + struct skl_ipc_d0ix_msg msg; + struct skl_sst *skl = container_of(work, + struct skl_sst, d0i3.work.work); + struct sst_dsp *ctx = skl->dsp; + struct skl_d0i3_data *d0i3 = &skl->d0i3; + int target_state; + + dev_dbg(ctx->dev, "In %s:\n", __func__); + + /* D0i3 entry allowed only if core 0 alone is running */ + if (skl_dsp_get_enabled_cores(ctx) != SKL_DSP_CORE0_MASK) { + dev_warn(ctx->dev, + "D0i3 allowed when only core0 running:Exit\n"); + return; + } + + target_state = bxt_d0i3_target_state(ctx); + if (target_state == SKL_DSP_D0I3_NONE) + return; + + msg.instance_id = 0; + msg.module_id = 0; + msg.wake = 1; + msg.streaming = 0; + if (target_state == SKL_DSP_D0I3_STREAMING) + msg.streaming = 1; + + ret = skl_ipc_set_d0ix(&skl->ipc, &msg); + + if (ret < 0) { + dev_err(ctx->dev, "Failed to set DSP to D0i3 state\n"); + return; + } + + /* Set Vendor specific register D0I3C.I3 to enable D0i3*/ + if (skl->update_d0i3c) + skl->update_d0i3c(skl->dev, true); + + d0i3->state = target_state; + skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING_D0I3; +} + +static int bxt_schedule_dsp_D0i3(struct sst_dsp *ctx) +{ + struct skl_sst *skl = ctx->thread_context; + struct skl_d0i3_data *d0i3 = &skl->d0i3; + + /* Schedule D0i3 only if the usecase ref counts are appropriate */ + if (bxt_d0i3_target_state(ctx) != SKL_DSP_D0I3_NONE) { + + dev_dbg(ctx->dev, "%s: Schedule D0i3\n", __func__); + + schedule_delayed_work(&d0i3->work, + msecs_to_jiffies(BXT_D0I3_DELAY)); + } + + return 0; +} + +static int bxt_set_dsp_D0i0(struct sst_dsp *ctx) +{ + int ret; + struct skl_ipc_d0ix_msg msg; + struct skl_sst *skl = ctx->thread_context; + + dev_dbg(ctx->dev, "In %s:\n", __func__); + + /* First Cancel any pending attempt to put DSP to D0i3 */ + cancel_delayed_work_sync(&skl->d0i3.work); + + /* If DSP is currently in D0i3, bring it to D0i0 */ + if (skl->cores.state[SKL_DSP_CORE0_ID] != SKL_DSP_RUNNING_D0I3) + return 0; + + dev_dbg(ctx->dev, "Set DSP to D0i0\n"); + + msg.instance_id = 0; + msg.module_id = 0; + msg.streaming = 0; + msg.wake = 0; + + if (skl->d0i3.state == SKL_DSP_D0I3_STREAMING) + msg.streaming = 1; + + /* Clear Vendor specific register D0I3C.I3 to disable D0i3*/ + if (skl->update_d0i3c) + skl->update_d0i3c(skl->dev, false); + + ret = skl_ipc_set_d0ix(&skl->ipc, &msg); + if (ret < 0) { + dev_err(ctx->dev, "Failed to set DSP to D0i0\n"); + return ret; + } + + skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING; + skl->d0i3.state = SKL_DSP_D0I3_NONE; + + return 0; +} + static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) { struct skl_sst *skl = ctx->thread_context; @@ -414,6 +552,8 @@ static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) static struct skl_dsp_fw_ops bxt_fw_ops = { .set_state_D0 = bxt_set_dsp_D0, .set_state_D3 = bxt_set_dsp_D3, + .set_state_D0i3 = bxt_schedule_dsp_D0i3, + .set_state_D0i0 = bxt_set_dsp_D0i0, .load_fw = bxt_load_base_firmware, .get_fw_errcode = bxt_get_errorcode, .load_library = bxt_load_library, diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index b9e71d051fb1..7c272ba0f4b5 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -126,11 +126,21 @@ struct sst_dsp_device; #define SKL_ADSPCS_CPA_SHIFT 24 #define SKL_ADSPCS_CPA_MASK(cm) ((cm) << SKL_ADSPCS_CPA_SHIFT) +/* DSP Core state */ enum skl_dsp_states { SKL_DSP_RUNNING = 1, + /* Running in D0i3 state; can be in streaming or non-streaming D0i3 */ + SKL_DSP_RUNNING_D0I3, /* Running in D0i3 state*/ SKL_DSP_RESET, }; +/* D0i3 substates */ +enum skl_dsp_d0i3_states { + SKL_DSP_D0I3_NONE = -1, /* No D0i3 */ + SKL_DSP_D0I3_NON_STREAMING = 0, + SKL_DSP_D0I3_STREAMING = 1, +}; + struct skl_dsp_fw_ops { int (*load_fw)(struct sst_dsp *ctx); /* FW module parser/loader */ @@ -139,6 +149,8 @@ struct skl_dsp_fw_ops { int (*parse_fw)(struct sst_dsp *ctx); int (*set_state_D0)(struct sst_dsp *ctx, unsigned int core_id); int (*set_state_D3)(struct sst_dsp *ctx, unsigned int core_id); + int (*set_state_D0i3)(struct sst_dsp *ctx); + int (*set_state_D0i0)(struct sst_dsp *ctx); unsigned int (*get_fw_errcode)(struct sst_dsp *ctx); int (*load_mod)(struct sst_dsp *ctx, u16 mod_id, u8 *mod_name); int (*unload_mod)(struct sst_dsp *ctx, u16 mod_id); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index ef2182d21934..a45c42046b64 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -53,6 +53,23 @@ struct skl_dsp_cores { int usage_count[SKL_DSP_CORES_MAX]; }; +/** + * skl_d0i3_data: skl D0i3 counters data struct + * + * @streaming: Count of usecases that can attempt streaming D0i3 + * @non_streaming: Count of usecases that can attempt non-streaming D0i3 + * @non_d0i3: Count of usecases that cannot attempt D0i3 + * @state: current state + * @work: D0i3 worker thread + */ +struct skl_d0i3_data { + int streaming; + int non_streaming; + int non_d0i3; + enum skl_dsp_d0i3_states state; + struct delayed_work work; +}; + struct skl_sst { struct device *dev; struct sst_dsp *dsp; @@ -86,6 +103,8 @@ struct skl_sst { /* Callback to update D0i3C register */ void (*update_d0i3c)(struct device *dev, bool enable); + + struct skl_d0i3_data d0i3; }; struct skl_ipc_init_instance_msg { -- cgit v1.2.3 From 8a0cb2360ddb941e0a2fbe33d400d2985e4f2fff Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 3 Nov 2016 17:07:18 +0530 Subject: ASoC: Intel: Skylake: Add support for LPMode For D0i3, we need to tell DSP to run the pipelines in LP mode. This information is kept in topology and passed to driver as an attribute for pipe. So add a new tuple for lpmode and program the pipe based on value set. Signed-off-by: Jayachandran B Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- include/uapi/sound/snd_sst_tokens.h | 5 ++++- sound/soc/intel/skylake/skl-messages.c | 3 ++- sound/soc/intel/skylake/skl-sst-ipc.c | 9 ++++++++- sound/soc/intel/skylake/skl-sst-ipc.h | 2 +- sound/soc/intel/skylake/skl-topology.c | 5 +++++ sound/soc/intel/skylake/skl-topology.h | 1 + 6 files changed, 21 insertions(+), 4 deletions(-) diff --git a/include/uapi/sound/snd_sst_tokens.h b/include/uapi/sound/snd_sst_tokens.h index 1ee2e943d66a..f4b8b34de519 100644 --- a/include/uapi/sound/snd_sst_tokens.h +++ b/include/uapi/sound/snd_sst_tokens.h @@ -157,6 +157,8 @@ * * %SKL_TKN_STR_LIB_NAME: Specifies the library name * + * %SKL_TKN_U32_PMODE: Specifies the power mode for pipe + * * module_id and loadable flags dont have tokens as these values will be * read from the DSP FW manifest */ @@ -208,7 +210,8 @@ enum SKL_TKNS { SKL_TKN_U32_PROC_DOMAIN, SKL_TKN_U32_LIB_COUNT, SKL_TKN_STR_LIB_NAME, - SKL_TKN_MAX = SKL_TKN_STR_LIB_NAME, + SKL_TKN_U32_PMODE, + SKL_TKN_MAX = SKL_TKN_U32_PMODE, }; #endif diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 805b7f2173f3..87fc647fa04c 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -1042,7 +1042,8 @@ int skl_create_pipeline(struct skl_sst *ctx, struct skl_pipe *pipe) dev_dbg(ctx->dev, "%s: pipe_id = %d\n", __func__, pipe->ppl_id); ret = skl_ipc_create_pipeline(&ctx->ipc, pipe->memory_pages, - pipe->pipe_priority, pipe->ppl_id); + pipe->pipe_priority, pipe->ppl_id, + pipe->lp_mode); if (ret < 0) { dev_err(ctx->dev, "Failed to create pipeline\n"); return ret; diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 087b8d6e7186..734408a34a24 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -81,6 +81,11 @@ #define IPC_INSTANCE_ID(x) (((x) & IPC_INSTANCE_ID_MASK) \ << IPC_INSTANCE_ID_SHIFT) +#define IPC_PPL_LP_MODE_SHIFT 0 +#define IPC_PPL_LP_MODE_MASK 0x1 +#define IPC_PPL_LP_MODE(x) (((x) & IPC_PPL_LP_MODE_MASK) \ + << IPC_PPL_LP_MODE_SHIFT) + /* Set pipeline state message */ #define IPC_PPL_STATE_SHIFT 0 #define IPC_PPL_STATE_MASK 0x1F @@ -559,7 +564,7 @@ void skl_ipc_free(struct sst_generic_ipc *ipc) } int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc, - u16 ppl_mem_size, u8 ppl_type, u8 instance_id) + u16 ppl_mem_size, u8 ppl_type, u8 instance_id, u8 lp_mode) { struct skl_ipc_header header = {0}; u64 *ipc_header = (u64 *)(&header); @@ -572,6 +577,8 @@ int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc, header.primary |= IPC_PPL_TYPE(ppl_type); header.primary |= IPC_PPL_MEM_SIZE(ppl_mem_size); + header.extension = IPC_PPL_LP_MODE(lp_mode); + dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); if (ret < 0) { diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index a45c42046b64..83bf1689f62e 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -148,7 +148,7 @@ struct skl_ipc_d0ix_msg { irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context); int skl_ipc_create_pipeline(struct sst_generic_ipc *sst_ipc, - u16 ppl_mem_size, u8 ppl_type, u8 instance_id); + u16 ppl_mem_size, u8 ppl_type, u8 instance_id, u8 lp_mode); int skl_ipc_delete_pipeline(struct sst_generic_ipc *sst_ipc, u8 instance_id); diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index b5b1934d8550..9a7a008f6689 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -1519,6 +1519,10 @@ static int skl_tplg_fill_pipe_tkn(struct device *dev, pipe->memory_pages = tkn_val; break; + case SKL_TKN_U32_PMODE: + pipe->lp_mode = tkn_val; + break; + default: dev_err(dev, "Token not handled %d\n", tkn); return -EINVAL; @@ -1841,6 +1845,7 @@ static int skl_tplg_get_token(struct device *dev, case SKL_TKN_U32_PIPE_CONN_TYPE: case SKL_TKN_U32_PIPE_PRIORITY: case SKL_TKN_U32_PIPE_MEM_PGS: + case SKL_TKN_U32_PMODE: if (is_pipe_exists) { ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe, tkn_elem->token, tkn_elem->value); diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index a519360f42a6..11fd0a4b6603 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -279,6 +279,7 @@ struct skl_pipe { u8 pipe_priority; u16 conn_type; u32 memory_pages; + u8 lp_mode; struct skl_pipe_params *p_params; enum skl_pipe_state state; struct list_head w_list; -- cgit v1.2.3 From 6bd9dcf339ebb292fa149ee0e52ea3c9d9822553 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 3 Nov 2016 17:07:19 +0530 Subject: ASoC: Intel: Skylake: Add support for specifying D0i3 configuration Not all use cases can support Doi3. Only certain use cases like hot word detection, deep buffering can support D0i3 based on resource requirement. So, pass the D0i3 capability for the FE/BE copier using topology. This will be used to take a decision for D0i3 mode entry/exit. Signed-off-by: Jayachandran B Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- include/uapi/sound/snd_sst_tokens.h | 5 ++++- sound/soc/intel/skylake/skl-topology.c | 4 ++++ sound/soc/intel/skylake/skl-topology.h | 7 +++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/uapi/sound/snd_sst_tokens.h b/include/uapi/sound/snd_sst_tokens.h index f4b8b34de519..93392bedcc58 100644 --- a/include/uapi/sound/snd_sst_tokens.h +++ b/include/uapi/sound/snd_sst_tokens.h @@ -159,6 +159,8 @@ * * %SKL_TKN_U32_PMODE: Specifies the power mode for pipe * + * %SKL_TKL_U32_D0I3_CAPS: Specifies the D0i3 capability for module + * * module_id and loadable flags dont have tokens as these values will be * read from the DSP FW manifest */ @@ -211,7 +213,8 @@ enum SKL_TKNS { SKL_TKN_U32_LIB_COUNT, SKL_TKN_STR_LIB_NAME, SKL_TKN_U32_PMODE, - SKL_TKN_MAX = SKL_TKN_U32_PMODE, + SKL_TKL_U32_D0I3_CAPS, + SKL_TKN_MAX = SKL_TKL_U32_D0I3_CAPS, }; #endif diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 9a7a008f6689..86597d491982 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -1830,6 +1830,10 @@ static int skl_tplg_get_token(struct device *dev, mconfig->converter = tkn_elem->value; break; + case SKL_TKL_U32_D0I3_CAPS: + mconfig->d0i3_caps = tkn_elem->value; + break; + case SKL_TKN_U32_PIPE_ID: ret = skl_tplg_add_pipe(dev, mconfig, skl, tkn_elem); diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 11fd0a4b6603..38809f6d20d6 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -294,6 +294,12 @@ enum skl_module_state { SKL_MODULE_UNLOADED = 4, }; +enum d0i3_capability { + SKL_D0I3_NONE = 0, + SKL_D0I3_STREAMING = 1, + SKL_D0I3_NON_STREAMING = 2, +}; + struct skl_module_cfg { u8 guid[16]; struct skl_module_inst_id id; @@ -320,6 +326,7 @@ struct skl_module_cfg { u32 converter; u32 vbus_id; u32 mem_pages; + enum d0i3_capability d0i3_caps; struct skl_module_pin *m_in_pin; struct skl_module_pin *m_out_pin; enum skl_module_type m_type; -- cgit v1.2.3 From a83e3b4c4454ecdc473cf09aa1c9d1705623c4cc Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 3 Nov 2016 17:07:20 +0530 Subject: ASoC: Intel: Skylake: Add D0i3 mode ref counting For device opened/closed, we check the D0i3 capability for the device and invoke skl_tplg_d0i3_get/put, which counts the use case based on the mode supported. These counters are then used to decide if the device can enter D0i3 mode of streaming or non-streaming or no D0i3. Signed-off-by: Jayachandran B Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/bxt-sst.c | 5 +++++ sound/soc/intel/skylake/skl-pcm.c | 9 ++++++++ sound/soc/intel/skylake/skl-sst-ipc.c | 17 +++++++++++++++ sound/soc/intel/skylake/skl-sst-ipc.h | 2 ++ sound/soc/intel/skylake/skl-topology.c | 38 ++++++++++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-topology.h | 3 +++ 6 files changed, 74 insertions(+) diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c index fed818fe2e69..1f9f33d34000 100644 --- a/sound/soc/intel/skylake/bxt-sst.c +++ b/sound/soc/intel/skylake/bxt-sst.c @@ -610,10 +610,15 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, if (ret) return ret; + /* set the D0i3 check */ + skl->ipc.ops.check_dsp_lp_on = skl_ipc_check_D0i0; + skl->cores.count = 2; skl->boot_complete = false; init_waitqueue_head(&skl->boot_wait); skl->is_first_boot = true; + INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3); + skl->d0i3.state = SKL_DSP_D0I3_NONE; if (dsp) *dsp = skl; diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index b69e05ec6844..84b5101e6ca6 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -144,6 +144,8 @@ static int skl_pcm_open(struct snd_pcm_substream *substream, struct hdac_ext_stream *stream; struct snd_pcm_runtime *runtime = substream->runtime; struct skl_dma_params *dma_params; + struct skl *skl = get_skl_ctx(dai->dev); + struct skl_module_cfg *mconfig; dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); @@ -177,6 +179,9 @@ static int skl_pcm_open(struct snd_pcm_substream *substream, skl_set_suspend_active(substream, dai, true); snd_pcm_set_sync(substream); + mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); + skl_tplg_d0i3_get(skl, mconfig->d0i3_caps); + return 0; } @@ -302,6 +307,7 @@ static void skl_pcm_close(struct snd_pcm_substream *substream, struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); struct skl_dma_params *dma_params = NULL; struct skl *skl = ebus_to_skl(ebus); + struct skl_module_cfg *mconfig; dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); @@ -325,6 +331,9 @@ static void skl_pcm_close(struct snd_pcm_substream *substream, skl->skl_sst->miscbdcg_disabled = false; } + mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); + skl_tplg_d0i3_put(skl, mconfig->d0i3_caps); + kfree(dma_params); } diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 734408a34a24..594623a4b4cd 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -306,6 +306,23 @@ static void skl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) header->primary | SKL_ADSP_REG_HIPCI_BUSY); } +int skl_ipc_check_D0i0(struct sst_dsp *dsp, bool state) +{ + int ret; + + /* check D0i3 support */ + if (!dsp->fw_ops.set_state_D0i0) + return 0; + + /* Attempt D0i0 or D0i3 based on state */ + if (state) + ret = dsp->fw_ops.set_state_D0i0(dsp); + else + ret = dsp->fw_ops.set_state_D0i3(dsp); + + return ret; +} + static struct ipc_message *skl_ipc_reply_get_msg(struct sst_generic_ipc *ipc, u64 ipc_header) { diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index 83bf1689f62e..0568f2e8fc57 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -187,6 +187,8 @@ int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc, struct skl_ipc_d0ix_msg *msg); +int skl_ipc_check_D0i0(struct sst_dsp *dsp, bool state); + void skl_ipc_int_enable(struct sst_dsp *dsp); void skl_ipc_op_int_enable(struct sst_dsp *ctx); void skl_ipc_op_int_disable(struct sst_dsp *ctx); diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 86597d491982..bd313c907b20 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -36,6 +36,44 @@ #define SKL_IN_DIR_BIT_MASK BIT(0) #define SKL_PIN_COUNT_MASK GENMASK(7, 4) +void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps) +{ + struct skl_d0i3_data *d0i3 = &skl->skl_sst->d0i3; + + switch (caps) { + case SKL_D0I3_NONE: + d0i3->non_d0i3++; + break; + + case SKL_D0I3_STREAMING: + d0i3->streaming++; + break; + + case SKL_D0I3_NON_STREAMING: + d0i3->non_streaming++; + break; + } +} + +void skl_tplg_d0i3_put(struct skl *skl, enum d0i3_capability caps) +{ + struct skl_d0i3_data *d0i3 = &skl->skl_sst->d0i3; + + switch (caps) { + case SKL_D0I3_NONE: + d0i3->non_d0i3--; + break; + + case SKL_D0I3_STREAMING: + d0i3->streaming--; + break; + + case SKL_D0I3_NON_STREAMING: + d0i3->non_streaming--; + break; + } +} + /* * SKL DSP driver modelling uses only few DAPM widgets so for rest we will * ignore. This helpers checks if the SKL driver handles this widget type diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 38809f6d20d6..3b962d84bcb8 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -369,6 +369,9 @@ struct skl_module_cfg *skl_tplg_fe_get_cpr_module( int skl_tplg_update_pipe_params(struct device *dev, struct skl_module_cfg *mconfig, struct skl_pipe_params *params); +void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps); +void skl_tplg_d0i3_put(struct skl *skl, enum d0i3_capability caps); + int skl_create_pipeline(struct skl_sst *ctx, struct skl_pipe *pipe); int skl_run_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); -- cgit v1.2.3 From 68d03a3aa2747e1a33231950d2c8369f1cef4244 Mon Sep 17 00:00:00 2001 From: Jayachandran B Date: Thu, 3 Nov 2016 17:07:22 +0530 Subject: ASoC: Intel: Skylake: remove pci device enabling calls on suspend We were invoking pci_disable_device() while going to suspend-to-idle and pci_enable_device() while coming back to active state. Turns out that we do not need these calls as we only need system to be wake capable when in suspend-to-idle state. The wake capability is already done by enable_irq_wake() calls, so remove these unwanted calls in driver. Signed-off-by: Jayachandran B Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index b9209af89915..ed59783e9846 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -290,7 +290,6 @@ static int skl_suspend(struct device *dev) enable_irq_wake(bus->irq); pci_save_state(pci); - pci_disable_device(pci); } else { ret = _skl_suspend(ebus); if (ret < 0) @@ -333,7 +332,6 @@ static int skl_resume(struct device *dev) */ if (skl->supend_active) { pci_restore_state(pci); - ret = pci_enable_device(pci); snd_hdac_ext_bus_link_power_up_all(ebus); disable_irq_wake(bus->irq); /* -- cgit v1.2.3 From 8b4a133c6145a34618c770117b65b33f1aa993aa Mon Sep 17 00:00:00 2001 From: Jayachandran B Date: Thu, 3 Nov 2016 17:07:21 +0530 Subject: ASoC: Intel: Skylake: Flush pending D0i3 request on suspend While going to suspend, if we have any pending D0i3 work scheduled, flush that and force the DSP to goto D0i3 mode before going to suspend. Signed-off-by: Jayachandran B Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 27 +++++++++++++++++++++++++++ sound/soc/intel/skylake/skl.c | 10 ++++++++++ sound/soc/intel/skylake/skl.h | 1 + 3 files changed, 38 insertions(+) diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 87fc647fa04c..4ae021aabc3a 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -294,6 +294,33 @@ int skl_free_dsp(struct skl *skl) return 0; } +/* + * In the case of "suspend_active" i.e, the Audio IP being active + * during system suspend, immediately excecute any pending D0i3 work + * before suspending. This is needed for the IP to work in low power + * mode during system suspend. In the case of normal suspend, cancel + * any pending D0i3 work. + */ +int skl_suspend_late_dsp(struct skl *skl) +{ + struct skl_sst *ctx = skl->skl_sst; + struct delayed_work *dwork; + + if (!ctx) + return 0; + + dwork = &ctx->d0i3.work; + + if (dwork->work.func) { + if (skl->supend_active) + flush_delayed_work(dwork); + else + cancel_delayed_work_sync(dwork); + } + + return 0; +} + int skl_suspend_dsp(struct skl *skl) { struct skl_sst *ctx = skl->skl_sst; diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index ed59783e9846..61a484888cfa 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -228,6 +228,15 @@ static int skl_acquire_irq(struct hdac_ext_bus *ebus, int do_disconnect) return 0; } +static int skl_suspend_late(struct device *dev) +{ + struct pci_dev *pci = to_pci_dev(dev); + struct hdac_ext_bus *ebus = pci_get_drvdata(pci); + struct skl *skl = ebus_to_skl(ebus); + + return skl_suspend_late_dsp(skl); +} + #ifdef CONFIG_PM static int _skl_suspend(struct hdac_ext_bus *ebus) { @@ -390,6 +399,7 @@ static int skl_runtime_resume(struct device *dev) static const struct dev_pm_ops skl_pm = { SET_SYSTEM_SLEEP_PM_OPS(skl_suspend, skl_resume) SET_RUNTIME_PM_OPS(skl_runtime_suspend, skl_runtime_resume, NULL) + .suspend_late = skl_suspend_late, }; /* diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 88ba54ba5f72..4986e3929dd3 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -124,6 +124,7 @@ int skl_get_dmic_geo(struct skl *skl); int skl_nhlt_update_topology_bin(struct skl *skl); int skl_init_dsp(struct skl *skl); int skl_free_dsp(struct skl *skl); +int skl_suspend_late_dsp(struct skl *skl); int skl_suspend_dsp(struct skl *skl); int skl_resume_dsp(struct skl *skl); void skl_cleanup_resources(struct skl *skl); -- cgit v1.2.3 From 3421894765a345c6919b22cdda606c2ba1aab2eb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 12 Nov 2016 18:07:44 -0600 Subject: ASoC: Intel: common: add ACPI package extraction utility Add a new common routine to extract a package exposed by a device indexed with the HID value. The functionality is implemented without assumptions on the package type or structure to allow for reuse. The caller is responsible for defining the name and allocating structures to store the results, ACPICA will complain in case of type mismatches or buffer size issues. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/common/sst-acpi.h | 17 +++++++++- sound/soc/intel/common/sst-match-acpi.c | 57 +++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/common/sst-acpi.h b/sound/soc/intel/common/sst-acpi.h index 012742299dd5..214e000667ae 100644 --- a/sound/soc/intel/common/sst-acpi.h +++ b/sound/soc/intel/common/sst-acpi.h @@ -15,14 +15,29 @@ #include #include -/* translation fron HID to I2C name, needed for DAI codec_name */ +struct sst_acpi_package_context { + char *name; /* package name */ + int length; /* number of elements */ + struct acpi_buffer *format; + struct acpi_buffer *state; + bool data_valid; +}; + #if IS_ENABLED(CONFIG_ACPI) +/* translation fron HID to I2C name, needed for DAI codec_name */ const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]); +bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], + struct sst_acpi_package_context *ctx); #else static inline const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]) { return NULL; } +static inline bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], + struct sst_acpi_package_context *ctx) +{ + return false; +} #endif /* acpi match */ diff --git a/sound/soc/intel/common/sst-match-acpi.c b/sound/soc/intel/common/sst-match-acpi.c index 789843307a49..1070f3ad23e5 100644 --- a/sound/soc/intel/common/sst-match-acpi.c +++ b/sound/soc/intel/common/sst-match-acpi.c @@ -77,5 +77,62 @@ struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines) } EXPORT_SYMBOL_GPL(sst_acpi_find_machine); +static acpi_status sst_acpi_find_package(acpi_handle handle, u32 level, + void *context, void **ret) +{ + struct acpi_device *adev; + acpi_status status = AE_OK; + struct sst_acpi_package_context *pkg_ctx = context; + + pkg_ctx->data_valid = false; + + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; + + if (adev->status.present && adev->status.functional) { + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object *myobj = NULL; + + status = acpi_evaluate_object_typed(handle, pkg_ctx->name, + NULL, &buffer, + ACPI_TYPE_PACKAGE); + if (ACPI_FAILURE(status)) + return AE_OK; + + myobj = buffer.pointer; + if (!myobj || myobj->package.count != pkg_ctx->length) { + kfree(buffer.pointer); + return AE_OK; + } + + status = acpi_extract_package(myobj, + pkg_ctx->format, pkg_ctx->state); + if (ACPI_FAILURE(status)) { + kfree(buffer.pointer); + return AE_OK; + } + + kfree(buffer.pointer); + pkg_ctx->data_valid = true; + return AE_CTRL_TERMINATE; + } + + return AE_OK; +} + +bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], + struct sst_acpi_package_context *ctx) +{ + acpi_status status; + + status = acpi_get_devices(hid, sst_acpi_find_package, ctx, NULL); + + if (ACPI_FAILURE(status) || !ctx->data_valid) + return false; + + return true; +} +EXPORT_SYMBOL_GPL(sst_acpi_find_package_from_hid); + MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Intel Common ACPI Match module"); -- cgit v1.2.3 From 64e84305cb936024a9862c48f61539fdad649a22 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 12 Nov 2016 18:07:45 -0600 Subject: ASoC: Intel: detect audio routing with CHAN package Baytrail-CR devices usually expose information in the DSDT which can be used to auto-detect AIF1/AIF2 connections. The CHAN package contains two integers, the first one describes the AIF number (1: AIF1, 2: AIF2) and the second the MCLK value (ignored in this patch) For example the following information is found in Lenovo 100s: Device (RTEK) { [...] Name (CHAN, Package (0x02) { One, 0x017D7840 }) While on Asus T100TAF the package values are: Name (CHAN, Package (0x02) { 0x02, 0x017D7840 }) This patch relies on the new common routine to extract a package exposed by a device indexed with the HID value. The CHAN package contents are queried from the machine driver and stored in a structure. If this auto-detection fails (missing or bad package in the BIOS), the routing falls back to SSP0-AIF2. Note that quirks may still be needed to support mono speakers or microphone, but this should reduce the number of issues with Baytrail significantly. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5640.c | 53 +++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index bff77a1f27fc..32aeffc352ee 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -689,6 +689,10 @@ static bool is_valleyview(void) return true; } +struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ + u64 aif_value; /* 1: AIF1, 2: AIF2 */ + u64 mclock_value; /* usually 25MHz (0x17d7940), ignored */ +}; static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) { @@ -698,6 +702,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) int i; int dai_index; struct byt_rt5640_private *priv; + bool is_bytcr = false; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC); if (!priv) @@ -734,8 +739,52 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) struct sst_platform_info *p_info = mach->pdata; const struct sst_res_info *res_info = p_info->res_info; - /* TODO: use CHAN package info from BIOS to detect AIF1/AIF2 */ - if (res_info->acpi_ipc_irq_index == 0) { + if (res_info->acpi_ipc_irq_index == 0) + is_bytcr = true; + } + + if (is_bytcr) { + /* + * Baytrail CR platforms may have CHAN package in BIOS, try + * to find relevant routing quirk based as done on Windows + * platforms. We have to read the information directly from the + * BIOS, at this stage the card is not created and the links + * with the codec driver/pdata are non-existent + */ + + struct acpi_chan_package chan_package; + + /* format specified: 2 64-bit integers */ + struct acpi_buffer format = {sizeof("NN"), "NN"}; + struct acpi_buffer state = {0, NULL}; + struct sst_acpi_package_context pkg_ctx; + bool pkg_found = false; + + state.length = sizeof(chan_package); + state.pointer = &chan_package; + + pkg_ctx.name = "CHAN"; + pkg_ctx.length = 2; + pkg_ctx.format = &format; + pkg_ctx.state = &state; + pkg_ctx.data_valid = false; + + pkg_found = sst_acpi_find_package_from_hid(mach->id, &pkg_ctx); + if (pkg_found) { + if (chan_package.aif_value == 1) { + dev_info(&pdev->dev, "BIOS Routing: AIF1 connected\n"); + byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF1; + } else if (chan_package.aif_value == 2) { + dev_info(&pdev->dev, "BIOS Routing: AIF2 connected\n"); + byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF2; + } else { + dev_info(&pdev->dev, "BIOS Routing isn't valid, ignored\n"); + pkg_found = false; + } + } + + if (!pkg_found) { + /* no BIOS indications, assume SSP0-AIF2 connection */ byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF2; } } -- cgit v1.2.3 From bf46241bee7bc3ec28703796f4fbd56085055fca Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 12 Nov 2016 18:07:46 -0600 Subject: ASoC: Intel: bytct_rt5640: change default capture settings Most Baytrail-CR devices use analog differential microphones, modify capture default to avoid DMI quirks. Keep digital mics for all other configurations. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5640.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 32aeffc352ee..f9d73b55d2f7 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -57,9 +57,7 @@ struct byt_rt5640_private { struct clk *mclk; }; -static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP | - BYT_RT5640_DMIC_EN | - BYT_RT5640_MCLK_EN; +static unsigned long byt_rt5640_quirk = BYT_RT5640_MCLK_EN; static void log_quirks(struct device *dev) { @@ -787,6 +785,13 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) /* no BIOS indications, assume SSP0-AIF2 connection */ byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF2; } + + /* change defaults for Baytrail-CR capture */ + byt_rt5640_quirk |= BYT_RT5640_IN1_MAP; + byt_rt5640_quirk |= BYT_RT5640_DIFF_MIC; + } else { + byt_rt5640_quirk |= (BYT_RT5640_DMIC1_MAP | + BYT_RT5640_DMIC_EN); } /* check quirks before creating card */ -- cgit v1.2.3 From 266c618d67dd4a42f798baaab47634018cb1db4b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 15 Nov 2016 21:40:45 +0100 Subject: ASoC: intel: mfld: Make static string arrays 'const 'char * const []' const char * const [] is the preferred type for static string arrays since this states explicitly that the individual entries are not going to be changed. Due to limitations in the ASoC API it was not possible to use it for enum text arrays. Commit 87023ff74b23 ("ASoC: Declare const properly for enum texts") changed this, but most drivers still use 'const char * []' as the type for their enum text arrays. Change these occurrences of 'static * const char * []' to 'static const char * const []'. The conversion was done automatically using the following coccinelle semantic patch: // @disable optional_qualifier@ identifier s; @@ static -const char * +const char * const s[] = ...; // Signed-off-by: Lars-Peter Clausen Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/mfld_machine.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/mfld_machine.c b/sound/soc/intel/boards/mfld_machine.c index 34f46c72a0e2..4e08885f37aa 100644 --- a/sound/soc/intel/boards/mfld_machine.c +++ b/sound/soc/intel/boards/mfld_machine.c @@ -81,9 +81,9 @@ static struct snd_soc_jack_zone mfld_zones[] = { }; /* sound card controls */ -static const char *headset_switch_text[] = {"Earpiece", "Headset"}; +static const char * const headset_switch_text[] = {"Earpiece", "Headset"}; -static const char *lo_text[] = {"Vibra", "Headset", "IHF", "None"}; +static const char * const lo_text[] = {"Vibra", "Headset", "IHF", "None"}; static const struct soc_enum headset_enum = SOC_ENUM_SINGLE_EXT(2, headset_switch_text); -- cgit v1.2.3 From c186fe7401e4234aee6796eda3ad38bd57507899 Mon Sep 17 00:00:00 2001 From: GuruprasadX Pawse Date: Wed, 23 Nov 2016 22:46:26 +0530 Subject: ASoC: Intel: Skylake: Don't use dma I2S config structure in kernel I2S blob config structure can change between DSP copier module versions. We are not modifying these structures anyway and NHLT blobs specify them properly, so use the blob directly to send the dma_control ipc instead of using the predefined I2S blob config structure. Signed-off-by: GuruprasadX Pawse Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 4ae021aabc3a..e79cbcf6e462 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -527,16 +527,14 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx, int skl_dsp_set_dma_control(struct skl_sst *ctx, struct skl_module_cfg *mconfig) { struct skl_dma_control *dma_ctrl; - struct skl_i2s_config_blob config_blob; struct skl_ipc_large_config_msg msg = {0}; int err = 0; /* - * if blob size is same as capablity size, then no dma control - * present so return + * if blob size zero, then return */ - if (mconfig->formats_config.caps_size == sizeof(config_blob)) + if (mconfig->formats_config.caps_size == 0) return 0; msg.large_param_id = DMA_CONTROL_ID; @@ -550,7 +548,7 @@ int skl_dsp_set_dma_control(struct skl_sst *ctx, struct skl_module_cfg *mconfig) dma_ctrl->node_id = skl_get_node_id(ctx, mconfig); /* size in dwords */ - dma_ctrl->config_length = sizeof(config_blob) / 4; + dma_ctrl->config_length = mconfig->formats_config.caps_size / 4; memcpy(dma_ctrl->config_data, mconfig->formats_config.caps, mconfig->formats_config.caps_size); @@ -558,7 +556,6 @@ int skl_dsp_set_dma_control(struct skl_sst *ctx, struct skl_module_cfg *mconfig) err = skl_ipc_set_large_config(&ctx->ipc, &msg, (u32 *)dma_ctrl); kfree(dma_ctrl); - return err; } -- cgit v1.2.3 From 48458cc891232ba6cb0270ba03520f54536d590a Mon Sep 17 00:00:00 2001 From: GuruprasadX Pawse Date: Wed, 23 Nov 2016 22:46:27 +0530 Subject: ASoC: Intel: Skylake: Removed the unused I2S blob structure Now that I2S conflig blob structure is no longer in use, remove it. Signed-off-by: GuruprasadX Pawse Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.h | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 3b962d84bcb8..08d39280b07b 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -113,23 +113,6 @@ struct skl_cpr_gtw_cfg { u32 config_data[1]; } __packed; -struct skl_i2s_config_blob { - u32 gateway_attrib; - u32 tdm_ts_group[8]; - u32 ssc0; - u32 ssc1; - u32 sscto; - u32 sspsp; - u32 sstsa; - u32 ssrsa; - u32 ssc2; - u32 sspsp2; - u32 ssc3; - u32 ssioc; - u32 mdivc; - u32 mdivr; -} __packed; - struct skl_dma_control { u32 node_id; u32 config_length; -- cgit v1.2.3 From 91197a9230e852eeefdb79b1bddc3cd9505d4248 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 28 Nov 2016 16:26:40 +0100 Subject: ASoC: Intel: atom: Make some messages to debug level Intel sst driver spews lots of kernel messages in INFO level; typically, it gives a kernel message at each time it allocates or frees a stream, or at each time when a stream is started or stopped. This will piles up quickly, and it's almost useless for normal users, so let's hide them to KERN_DEBUG level. Signed-off-by: Takashi Iwai Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-atom-controls.c | 2 +- sound/soc/intel/atom/sst/sst_stream.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 0838478c4c3f..c7b3cbf92faf 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -937,7 +937,7 @@ int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable) struct sst_data *drv = snd_soc_dai_get_drvdata(dai); int ssp_id; - dev_info(dai->dev, "Enter: enable=%d port_name=%s\n", enable, id); + dev_dbg(dai->dev, "Enter: enable=%d port_name=%s\n", enable, id); if (strcmp(id, "ssp0-port") == 0) ssp_id = SSP_MODEM; diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c index 4ccc80e5e8cc..51bdeeecb7c8 100644 --- a/sound/soc/intel/atom/sst/sst_stream.c +++ b/sound/soc/intel/atom/sst/sst_stream.c @@ -104,7 +104,7 @@ int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params) sst_init_stream(&sst_drv_ctx->streams[str_id], alloc_param.codec_type, str_id, alloc_param.operation, 0); - dev_info(sst_drv_ctx->dev, "Alloc for str %d pipe %#x\n", + dev_dbg(sst_drv_ctx->dev, "Alloc for str %d pipe %#x\n", str_id, pipe_id); ret = sst_prepare_and_post_msg(sst_drv_ctx, task_id, IPC_CMD, IPC_IA_ALLOC_STREAM_MRFLD, pipe_id, sizeof(alloc_param), @@ -415,7 +415,7 @@ int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) str_info->status = STREAM_UN_INIT; mutex_unlock(&str_info->lock); - dev_info(sst_drv_ctx->dev, "Free for str %d pipe %#x\n", + dev_dbg(sst_drv_ctx->dev, "Free for str %d pipe %#x\n", str_id, str_info->pipe_id); retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, IPC_IA_FREE_STREAM_MRFLD, str_info->pipe_id, 0, -- cgit v1.2.3 From 786e1c37194e8e822eb72a0aed5fa850e07071a0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 28 Nov 2016 16:32:19 +0100 Subject: ASoC: intel: Replace kthread with work The usage pattern of kthread worker in Intel SST drivers can be replaced gracefully with the normal workqueue, which is more light- weight and easier to manage in general. Let's do it. While in the replacement, move the schedule_work() call inside the spinlock for excluding the race, too. Signed-off-by: Takashi Iwai Acked-by: Vinod Koul Tested-by: Subhransu S. Prusty Signed-off-by: Mark Brown --- sound/soc/intel/baytrail/sst-baytrail-ipc.c | 3 +- sound/soc/intel/common/sst-ipc.c | 58 ++++++++++------------------- sound/soc/intel/common/sst-ipc.h | 4 +- sound/soc/intel/haswell/sst-haswell-ipc.c | 3 +- sound/soc/intel/skylake/skl-sst-cldma.c | 1 - sound/soc/intel/skylake/skl-sst-ipc.c | 2 +- sound/soc/intel/skylake/skl-sst-ipc.h | 1 - 7 files changed, 24 insertions(+), 48 deletions(-) diff --git a/sound/soc/intel/baytrail/sst-baytrail-ipc.c b/sound/soc/intel/baytrail/sst-baytrail-ipc.c index 7ab14ce65a73..260447da32b8 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-ipc.c +++ b/sound/soc/intel/baytrail/sst-baytrail-ipc.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -338,7 +337,7 @@ static irqreturn_t sst_byt_irq_thread(int irq, void *context) spin_unlock_irqrestore(&sst->spinlock, flags); /* continue to send any remaining messages... */ - kthread_queue_work(&ipc->kworker, &ipc->kwork); + schedule_work(&ipc->kwork); return IRQ_HANDLED; } diff --git a/sound/soc/intel/common/sst-ipc.c b/sound/soc/intel/common/sst-ipc.c index 2c1b3159ac1a..62f3a8e0ec87 100644 --- a/sound/soc/intel/common/sst-ipc.c +++ b/sound/soc/intel/common/sst-ipc.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include "sst-dsp.h" @@ -109,10 +108,9 @@ static int ipc_tx_message(struct sst_generic_ipc *ipc, u64 header, ipc->ops.tx_data_copy(msg, tx_data, tx_bytes); list_add_tail(&msg->list, &ipc->tx_list); + schedule_work(&ipc->kwork); spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); - kthread_queue_work(&ipc->kworker, &ipc->kwork); - if (wait) return tx_wait_done(ipc, msg, rx_data); else @@ -156,35 +154,32 @@ free_mem: return -ENOMEM; } -static void ipc_tx_msgs(struct kthread_work *work) +static void ipc_tx_msgs(struct work_struct *work) { struct sst_generic_ipc *ipc = container_of(work, struct sst_generic_ipc, kwork); struct ipc_message *msg; - unsigned long flags; - spin_lock_irqsave(&ipc->dsp->spinlock, flags); + spin_lock_irq(&ipc->dsp->spinlock); - if (list_empty(&ipc->tx_list) || ipc->pending) { - spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); - return; - } - - /* if the DSP is busy, we will TX messages after IRQ. - * also postpone if we are in the middle of procesing completion irq*/ - if (ipc->ops.is_dsp_busy && ipc->ops.is_dsp_busy(ipc->dsp)) { - dev_dbg(ipc->dev, "ipc_tx_msgs dsp busy\n"); - spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); - return; - } + while (!list_empty(&ipc->tx_list) && !ipc->pending) { + /* if the DSP is busy, we will TX messages after IRQ. + * also postpone if we are in the middle of processing + * completion irq + */ + if (ipc->ops.is_dsp_busy && ipc->ops.is_dsp_busy(ipc->dsp)) { + dev_dbg(ipc->dev, "ipc_tx_msgs dsp busy\n"); + break; + } - msg = list_first_entry(&ipc->tx_list, struct ipc_message, list); - list_move(&msg->list, &ipc->rx_list); + msg = list_first_entry(&ipc->tx_list, struct ipc_message, list); + list_move(&msg->list, &ipc->rx_list); - if (ipc->ops.tx_msg != NULL) - ipc->ops.tx_msg(ipc, msg); + if (ipc->ops.tx_msg != NULL) + ipc->ops.tx_msg(ipc, msg); + } - spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); + spin_unlock_irq(&ipc->dsp->spinlock); } int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header, @@ -305,19 +300,7 @@ int sst_ipc_init(struct sst_generic_ipc *ipc) if (ret < 0) return -ENOMEM; - /* start the IPC message thread */ - kthread_init_worker(&ipc->kworker); - ipc->tx_thread = kthread_run(kthread_worker_fn, - &ipc->kworker, "%s", - dev_name(ipc->dev)); - if (IS_ERR(ipc->tx_thread)) { - dev_err(ipc->dev, "error: failed to create message TX task\n"); - ret = PTR_ERR(ipc->tx_thread); - kfree(ipc->msg); - return ret; - } - - kthread_init_work(&ipc->kwork, ipc_tx_msgs); + INIT_WORK(&ipc->kwork, ipc_tx_msgs); return 0; } EXPORT_SYMBOL_GPL(sst_ipc_init); @@ -326,8 +309,7 @@ void sst_ipc_fini(struct sst_generic_ipc *ipc) { int i; - if (ipc->tx_thread) - kthread_stop(ipc->tx_thread); + cancel_work_sync(&ipc->kwork); if (ipc->msg) { for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { diff --git a/sound/soc/intel/common/sst-ipc.h b/sound/soc/intel/common/sst-ipc.h index f4aab1b3789a..7ed42a640ad6 100644 --- a/sound/soc/intel/common/sst-ipc.h +++ b/sound/soc/intel/common/sst-ipc.h @@ -23,7 +23,6 @@ #include #include #include -#include #define IPC_MAX_MAILBOX_BYTES 256 @@ -66,8 +65,7 @@ struct sst_generic_ipc { struct list_head empty_list; wait_queue_head_t wait_txq; struct task_struct *tx_thread; - struct kthread_worker kworker; - struct kthread_work kwork; + struct work_struct kwork; bool pending; struct ipc_message *msg; int tx_data_max_size; diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c index e432a31fd9f2..a3459d1682a6 100644 --- a/sound/soc/intel/haswell/sst-haswell-ipc.c +++ b/sound/soc/intel/haswell/sst-haswell-ipc.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -818,7 +817,7 @@ static irqreturn_t hsw_irq_thread(int irq, void *context) spin_unlock_irqrestore(&sst->spinlock, flags); /* continue to send any remaining messages... */ - kthread_queue_work(&ipc->kworker, &ipc->kwork); + schedule_work(&ipc->kwork); return IRQ_HANDLED; } diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c index efa2532114ba..c9f6d87381db 100644 --- a/sound/soc/intel/skylake/skl-sst-cldma.c +++ b/sound/soc/intel/skylake/skl-sst-cldma.c @@ -17,7 +17,6 @@ #include #include -#include #include #include "../common/sst-dsp.h" #include "../common/sst-dsp-priv.h" diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 594623a4b4cd..e1391dfbc9e9 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -498,7 +498,7 @@ irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context) skl_ipc_int_enable(dsp); /* continue to send any remaining messages... */ - kthread_queue_work(&ipc->kworker, &ipc->kwork); + schedule_work(&ipc->kwork); return IRQ_HANDLED; } diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index 0568f2e8fc57..cc40341233fa 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -16,7 +16,6 @@ #ifndef __SKL_IPC_H #define __SKL_IPC_H -#include #include #include "../common/sst-ipc.h" -- cgit v1.2.3 From fee3244cd1f5af813a24537950e211eee4f33297 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 25 Nov 2016 15:40:18 +0100 Subject: ASoC: cht_bsw_rt5672: Use HID translation unit Instead of hard-coded "i2c-10EC5670:00", use the translation helper to avoid the mismatch between i2c-codec and ACPI strings just like what we've done for bytcr_rt5640. This gives more robust binding on funky devices like Dell Wyse 3040. Signed-off-by: Takashi Iwai Reviewed-by: Pierre-Louis Bossart Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_rt5672.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index df9d254baa18..fe607d8701a0 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -25,12 +25,14 @@ #include #include "../../codecs/rt5670.h" #include "../atom/sst-atom-controls.h" +#include "../common/sst-acpi.h" /* The platform clock #3 outputs 19.2Mhz clock to codec as I2S MCLK */ #define CHT_PLAT_CLK_3_HZ 19200000 #define CHT_CODEC_DAI "rt5670-aif1" static struct snd_soc_jack cht_bsw_headset; +static char cht_bsw_codec_name[16]; /* Headset jack detection DAPM pins */ static struct snd_soc_jack_pin cht_bsw_headset_pins[] = { @@ -295,7 +297,7 @@ static int cht_suspend_pre(struct snd_soc_card *card) struct snd_soc_codec *codec; list_for_each_entry(codec, &card->codec_dev_list, card_list) { - if (!strcmp(codec->component.name, "i2c-10EC5670:00")) { + if (!strcmp(codec->component.name, cht_bsw_codec_name)) { dev_dbg(codec->dev, "disabling jack detect before going to suspend.\n"); rt5670_jack_suspend(codec); break; @@ -309,7 +311,7 @@ static int cht_resume_post(struct snd_soc_card *card) struct snd_soc_codec *codec; list_for_each_entry(codec, &card->codec_dev_list, card_list) { - if (!strcmp(codec->component.name, "i2c-10EC5670:00")) { + if (!strcmp(codec->component.name, cht_bsw_codec_name)) { dev_dbg(codec->dev, "enabling jack detect for resume.\n"); rt5670_jack_resume(codec); break; @@ -335,9 +337,33 @@ static struct snd_soc_card snd_soc_card_cht = { .resume_post = cht_resume_post, }; +#define RT5672_I2C_DEFAULT "i2c-10EC5670:00" + static int snd_cht_mc_probe(struct platform_device *pdev) { int ret_val = 0; + struct sst_acpi_mach *mach = pdev->dev.platform_data; + const char *i2c_name; + int i; + + strcpy(cht_bsw_codec_name, RT5672_I2C_DEFAULT); + + /* fixup codec name based on HID */ + if (mach) { + i2c_name = sst_acpi_find_name_from_hid(mach->id); + if (i2c_name) { + snprintf(cht_bsw_codec_name, sizeof(cht_bsw_codec_name), + "i2c-%s", i2c_name); + for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { + if (!strcmp(cht_dailink[i].codec_name, + RT5672_I2C_DEFAULT)) { + cht_dailink[i].codec_name = + cht_bsw_codec_name; + break; + } + } + } + } /* register the soc card */ snd_soc_card_cht.dev = &pdev->dev; -- cgit v1.2.3 From fade74dfab7cdba55a197db08f3d15cf2319bf4c Mon Sep 17 00:00:00 2001 From: Sebastien Guiriec Date: Mon, 5 Dec 2016 17:45:02 +0100 Subject: ASoC: Intel: atom: Add sysfs entry in order to store FW version This patch is adding a sysfs entry in order to be able to get access to SST FW version. Signed-off-by: Sebastien Guiriec Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c index 9b6e27385dc9..f9ba71315e33 100644 --- a/sound/soc/intel/atom/sst/sst.c +++ b/sound/soc/intel/atom/sst/sst.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -242,6 +243,32 @@ int sst_alloc_drv_context(struct intel_sst_drv **ctx, } EXPORT_SYMBOL_GPL(sst_alloc_drv_context); +static ssize_t firmware_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct intel_sst_drv *ctx = dev_get_drvdata(dev); + + if (ctx->fw_version.type == 0 && ctx->fw_version.major == 0 && + ctx->fw_version.minor == 0 && ctx->fw_version.build == 0) + return sprintf(buf, "FW not yet loaded\n"); + else + return sprintf(buf, "v%02x.%02x.%02x.%02x\n", + ctx->fw_version.type, ctx->fw_version.major, + ctx->fw_version.minor, ctx->fw_version.build); + +} + +DEVICE_ATTR_RO(firmware_version); + +static const struct attribute *sst_fw_version_attrs[] = { + &dev_attr_firmware_version.attr, + NULL, +}; + +static const struct attribute_group sst_fw_version_attr_group = { + .attrs = (struct attribute **)sst_fw_version_attrs, +}; + int sst_context_init(struct intel_sst_drv *ctx) { int ret = 0, i; @@ -315,8 +342,19 @@ int sst_context_init(struct intel_sst_drv *ctx) dev_err(ctx->dev, "Firmware download failed:%d\n", ret); goto do_free_mem; } + + ret = sysfs_create_group(&ctx->dev->kobj, + &sst_fw_version_attr_group); + if (ret) { + dev_err(ctx->dev, + "Unable to create sysfs\n"); + goto err_sysfs; + } + sst_register(ctx->dev); return 0; +err_sysfs: + sysfs_remove_group(&ctx->dev->kobj, &sst_fw_version_attr_group); do_free_mem: destroy_workqueue(ctx->post_msg_wq); @@ -330,6 +368,7 @@ void sst_context_cleanup(struct intel_sst_drv *ctx) pm_runtime_disable(ctx->dev); sst_unregister(ctx->dev); sst_set_fw_state_locked(ctx, SST_SHUTDOWN); + sysfs_remove_group(&ctx->dev->kobj, &sst_fw_version_attr_group); flush_scheduled_work(); destroy_workqueue(ctx->post_msg_wq); pm_qos_remove_request(ctx->qos); -- cgit v1.2.3 From c7da1e9d2641f67e8b20703118ac02fe79604f10 Mon Sep 17 00:00:00 2001 From: Sebastien Guiriec Date: Mon, 5 Dec 2016 17:45:01 +0100 Subject: ASoC: Intel: atom: save FW version After the boot of the SST FW the firmware version is send back to the driver. This patch is saving the FW version inside the driver. Signed-off-by: Sebastien Guiriec Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst.h | 1 + sound/soc/intel/atom/sst/sst_ipc.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/sound/soc/intel/atom/sst/sst.h b/sound/soc/intel/atom/sst/sst.h index 3f493862e98d..5c9a51cc77aa 100644 --- a/sound/soc/intel/atom/sst/sst.h +++ b/sound/soc/intel/atom/sst/sst.h @@ -436,6 +436,7 @@ struct intel_sst_drv { */ char firmware_name[FW_NAME_SIZE]; + struct snd_sst_fw_version fw_version; struct sst_fw_save *fw_save; }; diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c index 7934a0047384..374bb61c596d 100644 --- a/sound/soc/intel/atom/sst/sst_ipc.c +++ b/sound/soc/intel/atom/sst/sst_ipc.c @@ -242,6 +242,12 @@ static void process_fw_init(struct intel_sst_drv *sst_drv_ctx, dev_dbg(sst_drv_ctx->dev, "Build date %s Time %s\n", init->build_info.date, init->build_info.time); + /* Save FW version */ + sst_drv_ctx->fw_version.type = init->fw_version.type; + sst_drv_ctx->fw_version.major = init->fw_version.major; + sst_drv_ctx->fw_version.minor = init->fw_version.minor; + sst_drv_ctx->fw_version.build = init->fw_version.build; + ret: sst_wake_up_block(sst_drv_ctx, retval, FW_DWNL_ID, 0 , NULL, 0); } -- cgit v1.2.3 From da91723ce0c5e0bbd5dc91d66447ba165241c257 Mon Sep 17 00:00:00 2001 From: Sebastien Guiriec Date: Mon, 5 Dec 2016 17:45:03 +0100 Subject: ASoC: Intel: Add ASoC Intel SST Atom sysfs description For ASoC Intel SST Atom based devices a sysfs entry is created in order to track FW version. The FW version is useful in order to check the different Version of LPE DSP FW across Intel SoCs. Signed-off-by: Sebastien Guiriec Acked-by: Vinod Koul Signed-off-by: Mark Brown --- Documentation/ABI/testing/sysfs-platform-sst-atom | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-platform-sst-atom diff --git a/Documentation/ABI/testing/sysfs-platform-sst-atom b/Documentation/ABI/testing/sysfs-platform-sst-atom new file mode 100644 index 000000000000..0d07c0395660 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-platform-sst-atom @@ -0,0 +1,17 @@ +What: /sys/devices/platform/8086%x:00/firmware_version +Date: November 2016 +KernelVersion: 4.10 +Contact: "Sebastien Guiriec" +Description: + LPE Firmware version for SST driver on all atom + plaforms (BYT/CHT/Merrifield/BSW). + If the FW has never been loaded it will display: + "FW not yet loaded" + If FW has been loaded it will display: + "v01.aa.bb.cc" + aa: Major version is reflecting SoC version: + 0d: BYT FW + 0b: BSW FW + 07: Merrifield FW + bb: Minor version + cc: Build version -- cgit v1.2.3 From c1aee1d828caa86a663c57a56eead7fd5f22d80f Mon Sep 17 00:00:00 2001 From: Sathyanarayana Nujella Date: Tue, 6 Dec 2016 07:08:36 -0800 Subject: ASoC: Intel: update bxt_da7219_max98357a to support quad ch dmic capture This patch updates FE channel constraints & BE fixup to support quad channel DMIC capture. DMIC pin's BE fixup is configured based on channel input, i.e. either stereo or quad. Signed-off-by: Sathyanarayana Nujella Signed-off-by: Harsha Priya Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index bff80b467262..3a8c24a59020 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -30,6 +30,7 @@ #define BXT_DIALOG_CODEC_DAI "da7219-hifi" #define BXT_MAXIM_CODEC_DAI "HiFi" #define DUAL_CHANNEL 2 +#define QUAD_CHANNEL 4 static struct snd_soc_jack broxton_headset; @@ -182,6 +183,16 @@ static struct snd_pcm_hw_constraint_list constraints_channels = { .mask = 0, }; +static unsigned int channels_quad[] = { + QUAD_CHANNEL, +}; + +static struct snd_pcm_hw_constraint_list constraints_channels_quad = { + .count = ARRAY_SIZE(channels_quad), + .list = channels_quad, + .mask = 0, +}; + static int bxt_fe_startup(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -258,7 +269,10 @@ static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd, { struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - channels->min = channels->max = DUAL_CHANNEL; + if (params_channels(params) == 2) + channels->min = channels->max = 2; + else + channels->min = channels->max = 4; return 0; } @@ -267,9 +281,9 @@ static int broxton_dmic_startup(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - runtime->hw.channels_max = DUAL_CHANNEL; + runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels); + &constraints_channels_quad); return snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -- cgit v1.2.3