diff --git a/sound/Makefile b/sound/Makefile index 99d8c31262c8fc..3a37ffbb755f91 100644 --- a/sound/Makefile +++ b/sound/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 # Makefile for the Linux sound card driver # - +export KBUILD_CFLAGS += -DDEBUG obj-$(CONFIG_SOUND) += soundcore.o obj-$(CONFIG_DMASOUND) += oss/dmasound/ obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \ diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c index 1bd27576db98d5..a835558ddbc9b5 100644 --- a/sound/hda/ext/hdac_ext_stream.c +++ b/sound/hda/ext/hdac_ext_stream.c @@ -146,7 +146,8 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_decouple); */ void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *stream) { - snd_hdac_updatel(stream->pplc_addr, AZX_REG_PPLCCTL, 0, AZX_PPLCCTL_RUN); + snd_hdac_updatel(stream->pplc_addr, AZX_REG_PPLCCTL, + AZX_PPLCCTL_RUN, AZX_PPLCCTL_RUN); } EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_start); @@ -171,7 +172,8 @@ void snd_hdac_ext_link_stream_reset(struct hdac_ext_stream *stream) snd_hdac_ext_link_stream_clear(stream); - snd_hdac_updatel(stream->pplc_addr, AZX_REG_PPLCCTL, 0, AZX_PPLCCTL_STRST); + snd_hdac_updatel(stream->pplc_addr, AZX_REG_PPLCCTL, + AZX_PPLCCTL_STRST, AZX_PPLCCTL_STRST); udelay(3); timeout = 50; do { @@ -242,7 +244,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_link_set_stream_id); void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link, int stream) { - snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, 0, (1 << stream)); + snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 0); } EXPORT_SYMBOL_GPL(snd_hdac_ext_link_clear_stream_id); @@ -415,7 +417,6 @@ void snd_hdac_ext_stream_spbcap_enable(struct hdac_bus *bus, bool enable, int index) { u32 mask = 0; - u32 register_mask = 0; if (!bus->spbcap) { dev_err(bus->dev, "Address of SPB capability is NULL\n"); @@ -424,12 +425,8 @@ void snd_hdac_ext_stream_spbcap_enable(struct hdac_bus *bus, mask |= (1 << index); - register_mask = readl(bus->spbcap + AZX_REG_SPB_SPBFCCTL); - - mask |= register_mask; - if (enable) - snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, 0, mask); + snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, mask); else snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, 0); } @@ -503,7 +500,6 @@ void snd_hdac_ext_stream_drsm_enable(struct hdac_bus *bus, bool enable, int index) { u32 mask = 0; - u32 register_mask = 0; if (!bus->drsmcap) { dev_err(bus->dev, "Address of DRSM capability is NULL\n"); @@ -512,12 +508,8 @@ void snd_hdac_ext_stream_drsm_enable(struct hdac_bus *bus, mask |= (1 << index); - register_mask = readl(bus->drsmcap + AZX_REG_SPB_SPBFCCTL); - - mask |= register_mask; - if (enable) - snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, 0, mask); + snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, mask); else snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, 0); } diff --git a/sound/soc/intel/boards/bxt_tdf8532.c b/sound/soc/intel/boards/bxt_tdf8532.c index ebb8bfe19b9d2f..21e5b9d82ab684 100644 --- a/sound/soc/intel/boards/bxt_tdf8532.c +++ b/sound/soc/intel/boards/bxt_tdf8532.c @@ -10,6 +10,19 @@ #include #include #include +#include +#include "../../codecs/hdac_hdmi.h" + +struct bxt_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +struct bxt_sof_private { + struct list_head hdmi_pcm_list; +}; + static const struct snd_kcontrol_new broxton_tdf8532_controls[] = { SOC_DAPM_PIN_SWITCH("Speaker"), @@ -29,6 +42,8 @@ static const struct snd_soc_dapm_widget broxton_tdf8532_widgets[] = { }; static const struct snd_soc_dapm_route broxton_tdf8532_map[] = { +//#ifndef CONFIG_SND_SOC_SOF_FORCE_LEGACY_HDA +#if 1 /* Speaker BE connections */ { "Speaker", NULL, "ssp4 Tx"}, { "ssp4 Tx", NULL, "codec0_out"}, @@ -65,8 +80,52 @@ static const struct snd_soc_dapm_route broxton_tdf8532_map[] = { { "ModemUl", NULL, "ssp3 Tx"}, { "ssp3 Tx", NULL, "Modem_ssp3_out"}, + +//#else + { "hifi3", NULL, "iDisp3 Tx"}, + { "hifi2", NULL, "iDisp2 Tx"}, + { "hifi1", NULL, "iDisp1 Tx"}, +#endif }; +/* Headset jack detection DAPM pins */ +static struct snd_soc_jack broxton_headset; +static struct snd_soc_jack broxton_hdmi[3]; + +#define NAME_SIZE 32 +static int bxt_card_late_probe(struct snd_soc_card *card) +{ + struct bxt_sof_private *ctx = snd_soc_card_get_drvdata(card); + struct bxt_hdmi_pcm *pcm; + struct snd_soc_component *component = NULL; + int err, i = 0; + char jack_name[NAME_SIZE]; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + component = pcm->codec_dai->component; + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &broxton_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &broxton_hdmi[i]); + if (err < 0) + return err; + + i++; + } + + if (!component) + return -EINVAL; + + return hdac_hdmi_jack_port_init(component, &card->dapm); +} + static int bxt_tdf8532_ssp2_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -79,8 +138,29 @@ static int bxt_tdf8532_ssp2_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } +static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd) +{ + struct bxt_sof_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = rtd->codec_dai; + struct bxt_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = dai->id; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + + /* broxton digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link broxton_tdf8532_dais[] = { +//#ifndef CONFIG_SND_SOC_SOF_FORCE_LEGACY_HDA +#if 0 /* Probe DAI links*/ { .name = "Bxt Compress Probe playback", @@ -185,8 +265,10 @@ static struct snd_soc_dai_link broxton_tdf8532_dais[] = { .name = "SSP4-Codec", .id = 4, .cpu_dai_name = "SSP4 Pin", - .codec_name = "i2c-INT34C3:00", - .codec_dai_name = "tdf8532-hifi", +// .codec_name = "i2c-INT34C3:00", +// .codec_dai_name = "tdf8532-hifi", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", .platform_name = "0000:00:0e.0", .ignore_suspend = 1, .dpcm_playback = 1, @@ -211,9 +293,8 @@ static struct snd_soc_dai_link broxton_tdf8532_dais[] = { .cpu_dai_name = "iDisp1 Pin", .codec_name = "ehdaudio0D2", .codec_dai_name = "intel-hdmi-hifi1", -// .codec_name = "i2c-INT34C3:00", -// .codec_dai_name = "tdf8532-hifi", .platform_name = "0000:00:0e.0", + .init = broxton_hdmi_init, .dpcm_playback = 1, .no_pcm = 1, }, @@ -224,6 +305,7 @@ static struct snd_soc_dai_link broxton_tdf8532_dais[] = { .codec_name = "ehdaudio0D2", .codec_dai_name = "intel-hdmi-hifi2", .platform_name = "0000:00:0e.0", + .init = broxton_hdmi_init, .dpcm_playback = 1, .no_pcm = 1, }, @@ -234,9 +316,46 @@ static struct snd_soc_dai_link broxton_tdf8532_dais[] = { .codec_name = "ehdaudio0D2", .codec_dai_name = "intel-hdmi-hifi3", .platform_name = "0000:00:0e.0", + .init = broxton_hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, +#else + /* Back End DAI links */ + { + .name = "iDisp1", + .id = 6, + .cpu_dai_name = "iDisp1 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi1", + .platform_name = "sof-audio", + .init = broxton_hdmi_init, .dpcm_playback = 1, .no_pcm = 1, }, + { + .name = "iDisp2", + .id = 7, + .cpu_dai_name = "iDisp2 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi2", + .platform_name = "sof-audio", + .init = broxton_hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + .name = "iDisp3", + .id = 8, + .cpu_dai_name = "iDisp3 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi3", + .platform_name = "sof-audio", + .init = broxton_hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, +#endif }; #if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) @@ -261,6 +380,7 @@ static struct snd_soc_card broxton_tdf8532 = { .dapm_routes = broxton_tdf8532_map, .num_dapm_routes = ARRAY_SIZE(broxton_tdf8532_map), .fully_routed = true, + .late_probe = bxt_card_late_probe, #if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) .add_dai_link = bxt_add_dai_link, #endif @@ -268,8 +388,19 @@ static struct snd_soc_card broxton_tdf8532 = { static int broxton_tdf8532_audio_probe(struct platform_device *pdev) { + struct bxt_sof_private *ctx; + dev_info(&pdev->dev, "%s registering %s\n", __func__, pdev->name); broxton_tdf8532.dev = &pdev->dev; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + if (!ctx) + return -ENOMEM; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + + snd_soc_card_set_drvdata(&broxton_tdf8532, ctx); + return snd_soc_register_card(&broxton_tdf8532); } diff --git a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c index 333ae36f3fb06e..0923e78f7f5978 100644 --- a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c @@ -17,8 +17,11 @@ static struct snd_soc_acpi_codecs bxt_codecs = { struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { { .id = "INT343A", - .drv_name = "bxt_alc298s_i2s", - .fw_filename = "intel/dsp_fw_bxtn.bin", +// .drv_name = "bxt_alc298s_i2s", +// .fw_filename = "intel/dsp_fw_bxtn.bin", + .drv_name = "bxt_tdf8532", + .sof_fw_filename = "intel/sof-apl.ri", + .sof_tplg_filename = "intel/sof-apl-tdf8532.tplg", }, { .id = "DLGS7219", diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 924220c55b3c6c..c4b057993f92af 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -291,8 +291,10 @@ static int sof_probe(struct platform_device *pdev) goto ipc_err; } +/* bypass DSP if in force legacy hda debug mode */ +#ifndef CONFIG_SND_SOC_SOF_FORCE_LEGACY_HDA /* load the firmware */ - ret = snd_sof_load_firmware(sdev, plat_data->fw, true); + ret = snd_sof_load_firmware(sdev, true); if (ret < 0) { dev_err(sdev->dev, "error: failed to load DSP firmware %d\n", ret); @@ -306,6 +308,7 @@ static int sof_probe(struct platform_device *pdev) ret); goto fw_run_err; } +#endif /* now register audio DSP platform driver */ ret = snd_soc_register_platform(&pdev->dev, &sdev->plat_drv); @@ -324,6 +327,8 @@ static int sof_probe(struct platform_device *pdev) goto comp_err; } +/* bypass DSP if in force legacy hda debug mode */ +#ifndef CONFIG_SND_SOC_SOF_FORCE_LEGACY_HDA /* init DMA trace */ ret = snd_sof_init_trace(sdev); if (ret < 0) { @@ -331,6 +336,7 @@ static int sof_probe(struct platform_device *pdev) dev_warn(sdev->dev, "warning: failed to initialize trace %d\n", ret); } +#endif /* autosuspend sof device */ pm_runtime_mark_last_busy(sdev->dev); @@ -346,9 +352,12 @@ static int sof_probe(struct platform_device *pdev) snd_soc_unregister_component(&pdev->dev); snd_sof_free_topology(sdev); fw_run_err: +/* bypass DSP if in force legacy hda debug mode */ +#ifndef CONFIG_SND_SOC_SOF_FORCE_LEGACY_HDA snd_sof_fw_unload(sdev); fw_load_err: snd_sof_ipc_free(sdev); +#endif ipc_err: snd_sof_free_debug(sdev); dbg_err: diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index d777ddd80d893e..111206ba034605 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -113,4 +113,15 @@ config SND_SOC_SOF_HDA Say Y if you want to enble HDA links with SOF. If unsure select "N". +config SND_SOC_SOF_FORCE_LEGACY_HDA + bool "SOF force legacy hda and bypass DSP" + depends on SND_SOC_SOF_HDA + depends on SND_SOC_SOF_DEBUG + help + This forces the driver to use HDA legacy mode, and bypasses + the embedded DSP in HD-A controller on Intel SKL+ platforms. + This is designed for debugging only. + Say Y if you do wan't to use this mode. + If unsure select "N". + endif ## SND_SOC_SOF_INTEL diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index d3816b99498584..b0e8255883870a 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -81,6 +81,7 @@ struct snd_sof_dsp_ops sof_apl_ops = { .pcm_close = hda_dsp_pcm_close, .pcm_hw_params = hda_dsp_pcm_hw_params, .pcm_trigger = hda_dsp_pcm_trigger, + .pcm_pointer = hda_dsp_pcm_pointer, /* firmware loading */ .load_firmware = hda_dsp_cl_load_fw, diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index d5067db0d9f5c6..1065f2cb294eac 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -9,12 +9,170 @@ */ #include +#include +#include #include "../sof-priv.h" #include "hda.h" #define SKL_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE) +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + +struct hda_pipe_params { + u8 host_dma_id; + u8 link_dma_id; + u32 ch; + u32 s_freq; + u32 s_fmt; + u8 linktype; + snd_pcm_format_t format; + int link_index; + int stream; + unsigned int host_bps; + unsigned int link_bps; +}; + +/* TODO: add hda dai params in tplg, and configure this in topology parsing */ +static int hda_link_dma_params(struct hdac_ext_stream *stream, + struct hda_pipe_params *params) +{ + struct hdac_stream *hstream = &stream->hstream; + struct hdac_bus *bus = hstream->bus; + unsigned int format_val; + struct hdac_ext_link *link; + + snd_hdac_ext_stream_decouple(bus, stream, true); + snd_hdac_ext_link_stream_reset(stream); + + format_val = snd_hdac_calc_stream_format(params->s_freq, params->ch, + params->format, params->link_bps, 0); + + dev_dbg(bus->dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", + format_val, params->s_freq, params->ch, params->format); + + snd_hdac_ext_link_stream_setup(stream, format_val); + + list_for_each_entry(link, &bus->hlink_list, list) { + if (link->index == params->link_index) + snd_hdac_ext_link_set_stream_id(link, + hstream->stream_tag); + } + + stream->link_prepared = 1; + + return 0; +} + +static int hda_link_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct hdac_stream *hstream = substream->runtime->private_data; + struct hdac_bus *bus = hstream->bus; + struct hdac_ext_stream *link_dev; + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct hda_pipe_params p_params = {0}; + struct hdac_ext_link *link; + int stream_tag; + + link_dev = snd_hdac_ext_stream_assign(bus, substream, + HDAC_EXT_STREAM_TYPE_LINK); + if (!link_dev) + return -EBUSY; + + snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev); + + link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name); + if (!link) + return -EINVAL; + + stream_tag = hdac_stream(link_dev)->stream_tag; + + /* set the stream tag in the codec dai dma params */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0); + else + snd_soc_dai_set_tdm_slot(codec_dai, 0, stream_tag, 0, 0); + + p_params.s_fmt = snd_pcm_format_width(params_format(params)); + p_params.ch = params_channels(params); + p_params.s_freq = params_rate(params); + p_params.stream = substream->stream; + p_params.link_dma_id = stream_tag - 1; + p_params.link_index = link->index; + p_params.format = params_format(params); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + p_params.link_bps = codec_dai->driver->playback.sig_bits; + else + p_params.link_bps = codec_dai->driver->capture.sig_bits; + + return hda_link_dma_params(link_dev, &p_params); +} + +static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct hdac_ext_stream *link_dev = + snd_soc_dai_get_dma_data(dai, substream); + struct hdac_stream *hstream = substream->runtime->private_data; + struct hdac_bus *bus = hstream->bus; + struct hdac_ext_stream *stream = stream_to_hdac_ext_stream(hstream); + + dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd); + switch (cmd) { + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + snd_hdac_ext_link_stream_start(link_dev); + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + snd_hdac_ext_link_stream_clear(link_dev); + if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) + snd_hdac_ext_stream_decouple(bus, stream, false); + break; + + default: + return -EINVAL; + } + return 0; +} + +static int hda_link_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct hdac_stream *hstream = substream->runtime->private_data; + struct hdac_bus *bus = hstream->bus; + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct hdac_ext_stream *link_dev = + snd_soc_dai_get_dma_data(dai, substream); + struct hdac_ext_link *link; + + link = snd_hdac_ext_bus_get_link(bus, rtd->codec_dai->component->name); + if (!link) + return -EINVAL; + + snd_hdac_ext_link_clear_stream_id(link, + hdac_stream(link_dev)->stream_tag); + snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK); + + link_dev->link_prepared = 0; + + return 0; +} + +static const struct snd_soc_dai_ops hda_link_dai_ops = { + .hw_params = hda_link_hw_params, + .hw_free = hda_link_hw_free, + .trigger = hda_link_pcm_trigger, +}; +#endif + /* * common dai driver for skl+ platforms. * some products who use this DAI array only physically have a subset of @@ -73,40 +231,48 @@ struct snd_soc_dai_driver skl_dai[] = { .capture = SOF_DAI_STREAM("DMIC16k Rx", 1, 4, SNDRV_PCM_RATE_16000, SKL_FORMATS), }, +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) { .name = "iDisp1 Pin", + .ops = &hda_link_dai_ops, .playback = SOF_DAI_STREAM("iDisp1 Tx", 1, 8, SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), }, { .name = "iDisp2 Pin", + .ops = &hda_link_dai_ops, .playback = SOF_DAI_STREAM("iDisp2 Tx", 1, 8, SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), }, { .name = "iDisp3 Pin", + .ops = &hda_link_dai_ops, .playback = SOF_DAI_STREAM("iDisp3 Tx", 1, 8, SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), }, { - .name = "Analog Codec DAI", - .playback = SOF_DAI_STREAM("Analog Codec Playback", 1, 16, + .name = "Analog CPU DAI", + .ops = &hda_link_dai_ops, + .playback = SOF_DAI_STREAM("Analog CPU Playback", 1, 16, SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), - .capture = SOF_DAI_STREAM("Analog Codec Capture", 1, 16, + .capture = SOF_DAI_STREAM("Analog CPU Capture", 1, 16, SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), }, { - .name = "Digital Codec DAI", - .playback = SOF_DAI_STREAM("Digital Codec Playback", 1, 16, + .name = "Digital CPU DAI", + .ops = &hda_link_dai_ops, + .playback = SOF_DAI_STREAM("Digital CPU Playback", 1, 16, SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), - .capture = SOF_DAI_STREAM("Digital Codec Capture", 1, 16, + .capture = SOF_DAI_STREAM("Digital CPU Capture", 1, 16, SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), }, { - .name = "Alt Analog Codec DAI", - .playback = SOF_DAI_STREAM("Alt Analog Codec Playback", 1, 16, + .name = "Alt Analog CPU DAI", + .ops = &hda_link_dai_ops, + .playback = SOF_DAI_STREAM("Alt Analog CPU Playback", 1, 16, SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), - .capture = SOF_DAI_STREAM("Alt Analog Codec Capture", 1, 16, + .capture = SOF_DAI_STREAM("Alt Analog CPU Capture", 1, 16, SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), }, +#endif }; diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 3d43c4232a0a18..61aceb220f605b 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -298,28 +298,15 @@ static int cl_copy_fw(struct snd_sof_dev *sdev, int tag) return status; } -int hda_dsp_cl_load_fw(struct snd_sof_dev *sdev, const struct firmware *fw, - bool first_boot) +int hda_dsp_cl_load_fw(struct snd_sof_dev *sdev, bool first_boot) { struct snd_sof_pdata *plat_data = dev_get_platdata(sdev->dev); - int ret; /* set code loading condition to true */ sdev->code_loading = 1; - ret = request_firmware(&plat_data->fw, - plat_data->machine->sof_fw_filename, sdev->dev); - - if (ret < 0) { - dev_err(sdev->dev, "error: request firmware failed err: %d\n", - ret); - return -EINVAL; - } - - if (!plat_data->fw) - return -EINVAL; - - return ret; + return request_firmware(&plat_data->fw, + plat_data->machine->sof_fw_filename, sdev->dev); } int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index 7a53166bbb7723..481921443c6e3d 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -136,6 +137,38 @@ int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev, return hda_dsp_stream_trigger(sdev, stream, cmd); } +snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + struct hdac_stream *hstream = substream->runtime->private_data; + struct hdac_ext_stream *stream = stream_to_hdac_ext_stream(hstream); + struct hdac_bus *bus = sof_to_bus(sdev); + snd_pcm_uframes_t pos = 0; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, + AZX_REG_VS_SDXDPIB_XBASE + + (AZX_REG_VS_SDXDPIB_XINTERVAL * + hstream->index)); + } else { + udelay(20); + snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, + AZX_REG_VS_SDXDPIB_XBASE + + (AZX_REG_VS_SDXDPIB_XINTERVAL * + hstream->index)); + pos = snd_hdac_stream_get_pos_posbuf(hstream); + } + + if (pos >= hstream->bufsize) + pos = 0; + + pos = bytes_to_frames(substream->runtime, pos); + + dev_dbg(sdev->dev, "PCM: stream %d dir %d position %lu\n", + hstream->index, substream->stream, pos); + return pos; +} + int hda_dsp_pcm_open(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) { diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index f77421e2e831bb..668b87d5f99b14 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -322,8 +322,12 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, /* decouple host and link DMA */ mask = 0x1 << hstream->index; snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, +#ifndef CONFIG_SND_SOC_SOF_FORCE_LEGACY_HDA mask, mask); - +#else + /* temporary using coupled mode */ + mask, 0); +#endif if (!dmab) { dev_err(sdev->dev, "error: no dma buffer allocated!\n"); return -ENODEV; @@ -460,16 +464,15 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, irqreturn_t hda_dsp_stream_interrupt(int irq, void *context) { - struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; - struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_bus *bus = (struct hdac_bus *)context; u32 status; - if (!pm_runtime_active(sdev->dev)) + if (!pm_runtime_active(bus->dev)) return IRQ_NONE; spin_lock(&bus->reg_lock); - status = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS); + status = snd_hdac_chip_readl(bus, INTSTS); if (status == 0 || status == 0xffffffff) { spin_unlock(&bus->reg_lock); return IRQ_NONE; @@ -477,55 +480,44 @@ irqreturn_t hda_dsp_stream_interrupt(int irq, void *context) #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* clear rirb int */ - status = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_RIRBSTS); + status = snd_hdac_chip_readb(bus, RIRBSTS); if (status & RIRB_INT_MASK) { if (status & RIRB_INT_RESPONSE) snd_hdac_bus_update_rirb(bus); - snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_RIRBSTS, - RIRB_INT_MASK); + snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK); } #endif spin_unlock(&bus->reg_lock); - return snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS) - & SOF_HDA_INT_ALL_STREAM ? IRQ_WAKE_THREAD : IRQ_HANDLED; + return snd_hdac_chip_readl(bus, INTSTS) ? IRQ_WAKE_THREAD : IRQ_HANDLED; } irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context) { - struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; - struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_bus *bus = (struct hdac_bus *)context; struct hdac_stream *s; - int sd_offset; - //struct sof_intel_hda_dev *hdev = sdev->hda; - u32 status = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS); + u32 status = snd_hdac_chip_readl(bus, INTSTS); u32 sd_status; /* check streams */ list_for_each_entry(s, &bus->stream_list, list) { if (status & (1 << s->index) - && !s->opened) { - sd_offset = SOF_STREAM_SD_OFFSET(s); - sd_status = - snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, - sd_offset + - SOF_HDA_ADSP_REG_CL_SD_STS) & - 0xff; - - dev_dbg(sdev->dev, "stream %d status 0x%x\n", + && s->opened) { + sd_status = snd_hdac_stream_readb(s, SD_STS); + + dev_dbg(bus->dev, "stream %d status 0x%x\n", s->index, sd_status); - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, - sd_offset + - SOF_HDA_ADSP_REG_CL_SD_STS, - SOF_HDA_CL_DMA_SD_INT_MASK, - SOF_HDA_CL_DMA_SD_INT_MASK); + snd_hdac_stream_writeb(s, SD_STS, SD_INT_MASK); if (!s->substream || !s->running || - (sd_status & SOF_HDA_CL_DMA_SD_INT_MASK) == 0) + (sd_status & SOF_HDA_CL_DMA_SD_INT_COMPLETE) == 0) continue; +#ifdef USE_POS_BUF + snd_pcm_period_elapsed(s->substream); +#endif } } @@ -624,6 +616,7 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) hstream = &stream->hstream; hstream->bus = bus; + hstream->sd_int_sta_mask = 1 << i; hstream->index = i; sd_offset = SOF_STREAM_SD_OFFSET(hstream); hstream->sd_addr = sdev->bar[HDA_DSP_HDA_BAR] + sd_offset; @@ -682,6 +675,7 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) hstream = &stream->hstream; hstream->bus = bus; + hstream->sd_int_sta_mask = 1 << i; hstream->index = i; sd_offset = SOF_STREAM_SD_OFFSET(hstream); hstream->sd_addr = sdev->bar[HDA_DSP_HDA_BAR] + sd_offset; diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 52c6010d67b7e1..dfab9a2a1b77ba 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -524,12 +524,6 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) goto err; } - /* - * clear TCSEL to clear playback on some HD Audio - * codecs. PCI TCSEL is defined in the Intel manuals. - */ - snd_sof_pci_update_bits(sdev, PCI_TCSEL, 0x07, 0); - /* * register our IRQ * let's try to enable msi firstly @@ -551,16 +545,19 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) sdev->ipc_irq = sdev->hda->irq; } + bus = sof_to_bus(sdev); dev_dbg(sdev->dev, "using HDA IRQ %d\n", sdev->hda->irq); ret = request_threaded_irq(sdev->hda->irq, hda_dsp_stream_interrupt, hda_dsp_stream_threaded_handler, - IRQF_SHARED, "AudioHDA", sdev); + IRQF_SHARED, "AudioHDA", bus); if (ret < 0) { dev_err(sdev->dev, "error: failed to register HDA IRQ %d\n", sdev->hda->irq); goto free_streams; } +/* don't need ipc handler for legacy HDA mode */ +#ifndef CONFIG_SND_SOC_SOF_FORCE_LEGACY_HDA dev_dbg(sdev->dev, "using IPC IRQ %d\n", sdev->ipc_irq); ret = request_threaded_irq(sdev->ipc_irq, hda_dsp_ipc_irq_handler, chip->ops->irq_thread, IRQF_SHARED, @@ -570,10 +567,17 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) sdev->ipc_irq); goto free_hda_irq; } - +#endif pci_set_master(pci); synchronize_irq(pci->irq); + /* + * clear TCSEL to clear playback on some HD Audio + * codecs. PCI TCSEL is defined in the Intel manuals. + */ + snd_sof_pci_update_bits(sdev, PCI_TCSEL, 0x07, 0); + + /* init HDA capabilities */ ret = hda_init_caps(sdev); if (ret < 0) @@ -587,7 +591,6 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) } /* clear stream status */ - bus = sof_to_bus(sdev); list_for_each_entry(stream, &bus->stream_list, list) { sd_offset = SOF_STREAM_SD_OFFSET(stream); snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, @@ -635,7 +638,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) free_ipc_irq: free_irq(sdev->ipc_irq, sdev); free_hda_irq: - free_irq(sdev->hda->irq, sdev); + free_irq(sdev->hda->irq, bus); pci_free_irq_vectors(pci); free_streams: hda_dsp_stream_free(sdev); @@ -648,6 +651,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) int hda_dsp_remove(struct snd_sof_dev *sdev) { + struct hdac_bus *bus = sof_to_bus(sdev); struct pci_dev *pci = sdev->pci; const struct sof_intel_dsp_desc *chip = sdev->hda->desc; @@ -668,7 +672,7 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) SOF_HDA_PPCTL_GPROCEN, 0); free_irq(sdev->ipc_irq, sdev); - free_irq(sdev->pci->irq, sdev); + free_irq(sdev->pci->irq, bus); pci_free_irq_vectors(pci); hda_dsp_stream_free(sdev); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 56efa7714788a7..8c05e8fa778e58 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -314,7 +314,11 @@ (HDA_DSP_BDL_SIZE / sizeof(struct sof_intel_dsp_bdl)) /* Number of DAIs */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) #define SOF_SKL_NUM_DAIS 14 +#else +#define SOF_SKL_NUM_DAIS 8 +#endif struct sof_intel_dsp_bdl { u32 addr_l; @@ -408,6 +412,8 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params); int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, int cmd); +snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream); /* * DSP Stream Operations. @@ -458,8 +464,7 @@ int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir); /* * DSP Code loader. */ -int hda_dsp_cl_load_fw(struct snd_sof_dev *sdev, const struct firmware *fw, - bool first_boot); +int hda_dsp_cl_load_fw(struct snd_sof_dev *sdev, bool first_boot); int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev); /* diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 908f6c9de85154..76cb30123880ec 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -264,6 +264,10 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, struct snd_sof_ipc_msg *msg; unsigned long flags; + /* todo: fix me: temporary disable ipc message sending */ +#ifdef CONFIG_SND_SOC_SOF_FORCE_LEGACY_HDA + return 0; +#endif spin_lock_irqsave(&sdev->ipc_lock, flags); /* get an empty message */ @@ -533,7 +537,9 @@ static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id) posn.host_posn, posn.dai_posn, posn.wallclock); memcpy(&spcm->stream[direction].posn, &posn, sizeof(posn)); +#ifndef USE_POS_BUF snd_pcm_period_elapsed(spcm->stream[direction].substream); +#endif } /* DSP notifies host of an XRUN within FW */ diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 210a8d30989f21..12f88fd2f13016 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "sof-priv.h" #include "ops.h" @@ -208,42 +209,60 @@ static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw) } int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev, - const struct firmware *fw, bool first_boot) + bool first_boot) { + struct snd_sof_pdata *plat_data = dev_get_platdata(sdev->dev); int ret; + /* set code loading condition to true */ + sdev->code_loading = 1; + + ret = request_firmware(&plat_data->fw, + plat_data->machine->sof_fw_filename, sdev->dev); + + if (ret < 0) { + dev_err(sdev->dev, "error: request firmware failed err: %d\n", + ret); + return ret; + } + /* make sure the FW header and file is valid */ - ret = check_header(sdev, fw); + ret = check_header(sdev, plat_data->fw); if (ret < 0) { dev_err(sdev->dev, "error: invalid FW header\n"); - return ret; + goto error; } /* prepare the DSP for FW loading */ ret = snd_sof_dsp_reset(sdev); if (ret < 0) { dev_err(sdev->dev, "error: failed to reset DSP\n"); - return ret; + goto error; } /* parse and load firmware modules to DSP */ - ret = load_modules(sdev, fw); + ret = load_modules(sdev, plat_data->fw); if (ret < 0) { dev_err(sdev->dev, "error: invalid FW modules\n"); - return ret; + goto error; } + return 0; + +error: + release_firmware(plat_data->fw); return ret; + } EXPORT_SYMBOL(snd_sof_load_firmware_memcpy); int snd_sof_load_firmware(struct snd_sof_dev *sdev, - const struct firmware *fw, bool first_boot) + bool first_boot) { dev_dbg(sdev->dev, "loading firmware\n"); if (sdev->ops->load_firmware) - return sdev->ops->load_firmware(sdev, fw, first_boot); + return sdev->ops->load_firmware(sdev, first_boot); return 0; } EXPORT_SYMBOL(snd_sof_load_firmware); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 0d6fa6ef1a3e8b..21f84cc3251167 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "sof-priv.h" @@ -265,6 +266,17 @@ snd_sof_pcm_platform_trigger(struct snd_sof_dev *sdev, return 0; } +/* host stream pointer */ +static inline snd_pcm_uframes_t +snd_sof_pcm_platform_pointer(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + if (sdev->ops && sdev->ops->pcm_pointer) + return sdev->ops->pcm_pointer(sdev, substream); + else + return 0; +} + int snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar, u32 offset, u32 mask, u32 value); diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index a4a14acaa442c0..b9f155aa8b38f7 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -330,6 +330,12 @@ static snd_pcm_uframes_t sof_pcm_pointer(struct snd_pcm_substream *substream) if (rtd->dai_link->no_pcm) return 0; +#ifdef USE_POS_BUF + /* if have dsp ops pointer callback, use that directly */ + if (sdev->ops && sdev->ops->pcm_pointer) + return sdev->ops->pcm_pointer(sdev, substream); +#endif + /* read position from DSP */ host = bytes_to_frames(substream->runtime, spcm->stream[substream->stream].posn.host_posn); @@ -338,7 +344,6 @@ static snd_pcm_uframes_t sof_pcm_pointer(struct snd_pcm_substream *substream) dev_dbg(sdev->dev, "PCM: stream %d dir %d DMA position %lu DAI position %lu\n", spcm->pcm.pcm_id, substream->stream, host, dai); - return host; } @@ -630,7 +635,8 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, /* TODO: add any other DMIC specific fixups */ break; case SOF_DAI_INTEL_HDA: - /* fallthrough */ + /* do nothing for HDA dai_link */ + break; default: dev_err(sdev->dev, "error: invalid DAI type %d\n", dai->dai_config.type); diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 75c1a71feb7981..3e7dee9da87782 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -223,7 +223,7 @@ static int sof_resume(struct device *dev) } /* load the firmware */ - ret = snd_sof_load_firmware(sdev, sdev->pdata->fw, false); + ret = snd_sof_load_firmware(sdev, false); if (ret < 0) { dev_err(sdev->dev, "error: failed to load DSP firmware after resume %d\n", diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index d635e6bda64bb3..0599f998a8a2b0 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -134,30 +134,6 @@ static struct platform_device * return pdev; } -static void sof_acpi_fw_cb(const struct firmware *fw, void *context) -{ - struct sof_platform_priv *priv = context; - struct snd_sof_pdata *sof_pdata = priv->sof_pdata; - const struct snd_soc_acpi_mach *mach = sof_pdata->machine; - struct device *dev = sof_pdata->dev; - - sof_pdata->fw = fw; - if (!fw) { - dev_err(dev, "Cannot load firmware %s\n", - mach->sof_fw_filename); - return; - } - - /* register PCM and DAI driver */ - priv->pdev_pcm = - platform_device_register_data(dev, "sof-audio", -1, - sof_pdata, sizeof(*sof_pdata)); - if (IS_ERR(priv->pdev_pcm)) { - dev_err(dev, "Cannot register device sof-audio. Error %d\n", - (int)PTR_ERR(priv->pdev_pcm)); - } -} - static const struct dev_pm_ops sof_acpi_pm = { SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, @@ -291,14 +267,12 @@ static int sof_acpi_probe(struct platform_device *pdev) dev_dbg(dev, "created machine %s\n", dev_name(&sof_pdata->pdev_mach->dev)); - /* continue SST probing after firmware is loaded */ - dev_info(dev, "info: loading firmware %s\n", mach->sof_fw_filename); - ret = request_firmware_nowait(THIS_MODULE, true, mach->sof_fw_filename, - dev, GFP_KERNEL, priv, sof_acpi_fw_cb); + /* register sof-audio platform driver */ + ret = sof_create_platform_device(priv); if (ret) { platform_device_unregister(sof_pdata->pdev_mach); - dev_err(dev, "error: failed to load firmware %s\n", - mach->sof_fw_filename); + dev_err(dev, "error: failed to create platform device!\n"); + return ret; } /* allow runtime_pm */ diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index c8bf16f75b8416..db70d977ffd070 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -127,30 +127,6 @@ static const struct sof_dev_desc icl_desc = { }; #endif -static void sof_pci_fw_cb(const struct firmware *fw, void *context) -{ - struct sof_platform_priv *priv = context; - struct snd_sof_pdata *sof_pdata = priv->sof_pdata; - const struct snd_soc_acpi_mach *mach = sof_pdata->machine; - struct device *dev = sof_pdata->dev; - - sof_pdata->fw = fw; - if (!fw) { - dev_err(dev, "Cannot load firmware %s\n", - mach->sof_fw_filename); - return; - } - - /* register PCM and DAI driver */ - priv->pdev_pcm = - platform_device_register_data(dev, "sof-audio", -1, - sof_pdata, sizeof(*sof_pdata)); - if (IS_ERR(priv->pdev_pcm)) { - dev_err(dev, "Cannot register device sof-audio. Error %d\n", - (int)PTR_ERR(priv->pdev_pcm)); - } -} - static const struct dev_pm_ops sof_pci_pm = { SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, @@ -282,14 +258,11 @@ static int sof_pci_probe(struct pci_dev *pci, dev_dbg(dev, "created machine %s\n", dev_name(&sof_pdata->pdev_mach->dev)); - /* continue probing after firmware is loaded */ - dev_info(dev, "info: loading firmware %s\n", mach->sof_fw_filename); - ret = request_firmware_nowait(THIS_MODULE, true, mach->sof_fw_filename, - dev, GFP_KERNEL, priv, sof_pci_fw_cb); + /* register sof-audio platform driver */ + ret = sof_create_platform_device(priv); if (ret) { platform_device_unregister(sof_pdata->pdev_mach); - dev_err(dev, "error: failed to load firmware %s\n", - mach->sof_fw_filename); + dev_err(dev, "error: failed to create platform device!\n"); goto release_regions; } @@ -379,7 +352,7 @@ static struct pci_driver snd_sof_pci_driver = { .remove = sof_pci_remove, .shutdown = sof_pci_shutdown, .driver = { - .pm = &sof_pci_pm, +// .pm = &sof_pci_pm, }, }; module_pci_driver(snd_sof_pci_driver); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index ba46c85a77eb35..d60269505da6cd 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -26,6 +26,8 @@ #include #include "../../pci/hda/hda_codec.h" +//#define USE_POS_BUF + /* debug flags */ #define SOF_DBG_REGS BIT(1) #define SOF_DBG_MBOX BIT(2) @@ -139,9 +141,13 @@ struct snd_sof_dsp_ops { int (*pcm_trigger)(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, int cmd); + /* host stream pointer */ + snd_pcm_uframes_t (*pcm_pointer)(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream); + /* FW loading */ int (*load_firmware)(struct snd_sof_dev *sof_dev, - const struct firmware *fw, bool first_boot); + bool first_boot); int (*load_module)(struct snd_sof_dev *sof_dev, struct snd_sof_mod_hdr *hdr); int (*fw_ready)(struct snd_sof_dev *sdev, u32 msg_id); @@ -397,9 +403,9 @@ int snd_sof_create_page_table(struct snd_sof_dev *sdev, * Firmware loading. */ int snd_sof_load_firmware(struct snd_sof_dev *sdev, - const struct firmware *fw, bool first_boot); + bool first_boot); int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev, - const struct firmware *fw, bool first_boot); + bool first_boot); int snd_sof_run_firmware(struct snd_sof_dev *sdev); int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, struct snd_sof_mod_hdr *module); @@ -522,4 +528,9 @@ static inline void sof_oops(struct snd_sof_dev *sdev, void *oops) } extern const struct sof_arch_ops sof_xtensa_arch_ops; + +/* + * Utilities + */ +int sof_create_platform_device(struct sof_platform_priv *priv); #endif diff --git a/sound/soc/sof/sof-spi-dev.c b/sound/soc/sof/sof-spi-dev.c index fb94f24b824076..4368b6138b57d5 100644 --- a/sound/soc/sof/sof-spi-dev.c +++ b/sound/soc/sof/sof-spi-dev.c @@ -19,30 +19,6 @@ #include #include "sof-priv.h" -static void sof_spi_fw_cb(const struct firmware *fw, void *context) -{ - struct sof_platform_priv *priv = context; - struct snd_sof_pdata *sof_pdata = priv->sof_pdata; - const struct snd_sof_machine *mach = sof_pdata->machine; - struct device *dev = sof_pdata->dev; - - sof_pdata->fw = fw; - if (!fw) { - dev_err(dev, "Cannot load firmware %s\n", - mach->sof_fw_filename); - return; - } - - /* register PCM and DAI driver */ - priv->pdev_pcm = - platform_device_register_data(dev, "sof-audio", -1, - sof_pdata, sizeof(*sof_pdata)); - if (IS_ERR(priv->pdev_pcm)) { - dev_err(dev, "Cannot register device sof-audio. Error %d\n", - (int)PTR_ERR(priv->pdev_pcm)); - } -} - static const struct dev_pm_ops sof_spi_pm = { SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, @@ -101,11 +77,13 @@ static int sof_spi_probe(struct spi_device *spi) dev_dbg(dev, "created machine %s\n", dev_name(&sof_pdata->pdev_mach->dev)); - /* continue probing after firmware is loaded */ - ret = request_firmware_nowait(THIS_MODULE, true, mach->sof_fw_filename, - dev, GFP_KERNEL, priv, sof_spi_fw_cb); - if (ret) + /* register sof-audio platform driver */ + ret = sof_create_platform_device(priv); + if (ret) { platform_device_unregister(sof_pdata->pdev_mach); + dev_err(dev, "error: failed to create platform device!\n"); + return ret; + } /* allow runtime_pm */ pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY); diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 702d8a2eaa9509..c71183dec58d0c 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1779,12 +1779,10 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, if (!link->no_pcm) return 0; - /* only support 1 config atm */ - if (le32_to_cpu(cfg->num_hw_configs) != 1) { - dev_err(sdev->dev, "error: unexpected DAI config count %d\n", + /* usually we use 1 config, but for HDA it may be 0 ATM */ + if (le32_to_cpu(cfg->num_hw_configs) != 1) + dev_warn(sdev->dev, "warn: unexpected DAI config count %d!\n", le32_to_cpu(cfg->num_hw_configs)); - return -EINVAL; - } /* check we have some tokens - we need at least DAI type */ if (le32_to_cpu(private->size) == 0) { diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c index 91c8417500af8c..afeec6b93817e6 100644 --- a/sound/soc/sof/utils.c +++ b/sound/soc/sof/utils.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include "sof-priv.h" @@ -47,3 +48,21 @@ int sof_bes_setup(struct device *dev, struct snd_sof_dsp_ops *ops, } EXPORT_SYMBOL(sof_bes_setup); +/* register sof platform device */ +int sof_create_platform_device(struct sof_platform_priv *priv) +{ + struct snd_sof_pdata *sof_pdata = priv->sof_pdata; + struct device *dev = sof_pdata->dev; + + priv->pdev_pcm = + platform_device_register_data(dev, "sof-audio", -1, + sof_pdata, sizeof(*sof_pdata)); + if (IS_ERR(priv->pdev_pcm)) { + dev_err(dev, "Cannot register device sof-audio. Error %d\n", + (int)PTR_ERR(priv->pdev_pcm)); + return PTR_ERR(priv->pdev_pcm); + } + + return 0; +} +EXPORT_SYMBOL(sof_create_platform_device);