diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/hda/ext/hdac_ext_stream.c | 15 | ||||
-rw-r--r-- | sound/soc/codecs/hdac_hdmi.c | 238 | ||||
-rw-r--r-- | sound/soc/intel/Kconfig | 51 | ||||
-rw-r--r-- | sound/soc/intel/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/intel/atom/Makefile | 7 | ||||
-rw-r--r-- | sound/soc/intel/atom/sst-mfld-platform-pcm.c | 5 | ||||
-rw-r--r-- | sound/soc/intel/atom/sst/sst_ipc.c | 2 | ||||
-rw-r--r-- | sound/soc/intel/atom/sst/sst_stream.c | 2 | ||||
-rw-r--r-- | sound/soc/intel/boards/broadwell.c | 2 | ||||
-rw-r--r-- | sound/soc/intel/boards/bxt_da7219_max98357a.c | 1 | ||||
-rw-r--r-- | sound/soc/intel/boards/bytcr_rt5640.c | 10 | ||||
-rw-r--r-- | sound/soc/intel/common/sst-dsp.c | 52 | ||||
-rw-r--r-- | sound/soc/intel/skylake/bxt-sst.c | 64 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl-pcm.c | 164 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl-sst-dsp.h | 4 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl-sst-ipc.h | 5 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl-topology.c | 65 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl-topology.h | 19 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl-tplg-interface.h | 12 | ||||
-rw-r--r-- | sound/soc/soc-core.c | 134 |
20 files changed, 454 insertions, 400 deletions
diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c index 3be051ab5..c96d7a7 100644 --- a/sound/hda/ext/hdac_ext_stream.c +++ b/sound/hda/ext/hdac_ext_stream.c @@ -128,14 +128,17 @@ void snd_hdac_ext_stream_decouple(struct hdac_ext_bus *ebus, { struct hdac_stream *hstream = &stream->hstream; struct hdac_bus *bus = &ebus->bus; + u32 val; + int mask = AZX_PPCTL_PROCEN(hstream->index); spin_lock_irq(&bus->reg_lock); - if (decouple) - snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0, - AZX_PPCTL_PROCEN(hstream->index)); - else - snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, - AZX_PPCTL_PROCEN(hstream->index), 0); + val = readw(bus->ppcap + AZX_REG_PP_PPCTL) & mask; + + if (decouple && !val) + snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, mask, mask); + else if (!decouple && val) + snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, mask, 0); + stream->decoupled = decouple; spin_unlock_irq(&bus->reg_lock); } diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 0c6228a..4b4e376 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -46,6 +46,10 @@ #define ELD_MAX_SIZE 256 #define ELD_FIXED_BYTES 20 +#define ELD_VER_CEA_861D 2 +#define ELD_VER_PARTIAL 31 +#define ELD_MAX_MNL 16 + struct hdac_hdmi_cvt_params { unsigned int channels_min; unsigned int channels_max; @@ -81,8 +85,6 @@ struct hdac_hdmi_pin { hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; struct hdac_hdmi_eld eld; struct hdac_ext_device *edev; - int repoll_count; - struct delayed_work work; struct mutex lock; bool chmap_set; unsigned char chmap[8]; /* ALSA API channel-map */ @@ -114,6 +116,12 @@ struct hdac_hdmi_priv { struct hdac_chmap chmap; }; +static void hdac_hdmi_enable_cvt(struct hdac_ext_device *edev, + struct hdac_hdmi_dai_pin_map *dai_map); + +static int hdac_hdmi_enable_pin(struct hdac_ext_device *hdac, + struct hdac_hdmi_dai_pin_map *dai_map); + static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi, int pcm_idx) { @@ -173,80 +181,6 @@ format_constraint: } - /* HDMI ELD routines */ -static unsigned int hdac_hdmi_get_eld_data(struct hdac_device *codec, - hda_nid_t nid, int byte_index) -{ - unsigned int val; - - val = snd_hdac_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_ELDD, - byte_index); - - dev_dbg(&codec->dev, "HDMI: ELD data byte %d: 0x%x\n", - byte_index, val); - - return val; -} - -static int hdac_hdmi_get_eld_size(struct hdac_device *codec, hda_nid_t nid) -{ - return snd_hdac_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, - AC_DIPSIZE_ELD_BUF); -} - -/* - * This function queries the ELD size and ELD data and fills in the buffer - * passed by user - */ -static int hdac_hdmi_get_eld(struct hdac_device *codec, hda_nid_t nid, - unsigned char *buf, int *eld_size) -{ - int i, size, ret = 0; - - /* - * ELD size is initialized to zero in caller function. If no errors and - * ELD is valid, actual eld_size is assigned. - */ - - size = hdac_hdmi_get_eld_size(codec, nid); - if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) { - dev_err(&codec->dev, "HDMI: invalid ELD buf size %d\n", size); - return -ERANGE; - } - - /* set ELD buffer */ - for (i = 0; i < size; i++) { - unsigned int val = hdac_hdmi_get_eld_data(codec, nid, i); - /* - * Graphics driver might be writing to ELD buffer right now. - * Just abort. The caller will repoll after a while. - */ - if (!(val & AC_ELDD_ELD_VALID)) { - dev_err(&codec->dev, - "HDMI: invalid ELD data byte %d\n", i); - ret = -EINVAL; - goto error; - } - val &= AC_ELDD_ELD_DATA; - /* - * The first byte cannot be zero. This can happen on some DVI - * connections. Some Intel chips may also need some 250ms delay - * to return non-zero ELD data, even when the graphics driver - * correctly writes ELD content before setting ELD_valid bit. - */ - if (!val && !i) { - dev_err(&codec->dev, "HDMI: 0 ELD data\n"); - ret = -EINVAL; - goto error; - } - buf[i] = val; - } - - *eld_size = size; -error: - return ret; -} - static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac, hda_nid_t cvt_nid, hda_nid_t pin_nid, u32 stream_tag, int format) @@ -411,6 +345,10 @@ static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream, dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n", dd->stream_tag, dd->format); + hdac_hdmi_enable_cvt(hdac, dai_map); + ret = hdac_hdmi_enable_pin(hdac, dai_map); + if (ret < 0) + return ret; mutex_lock(&pin->lock); pin->channels = substream->runtime->channels; @@ -464,12 +402,7 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai); struct hdac_ext_dma_params *dd; - struct hdac_hdmi_priv *hdmi = edev->private_data; - struct hdac_hdmi_dai_pin_map *dai_map; - - dai_map = &hdmi->dai_map[dai->id]; dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); @@ -622,11 +555,6 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, dai_map->pin = pin; - hdac_hdmi_enable_cvt(hdac, dai_map); - ret = hdac_hdmi_enable_pin(hdac, dai_map); - if (ret < 0) - return ret; - ret = hdac_hdmi_eld_limit_formats(substream->runtime, pin->eld.eld_buffer); if (ret < 0) @@ -639,18 +567,15 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, static int hdac_hdmi_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { - struct hdac_hdmi_dai_pin_map *dai_map; - struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); - struct hdac_hdmi_priv *hdmi = hdac->private_data; - int ret; - - dai_map = &hdmi->dai_map[dai->id]; - if (cmd == SNDRV_PCM_TRIGGER_RESUME) { - ret = hdac_hdmi_enable_pin(hdac, dai_map); - if (ret < 0) - return ret; + switch (cmd) { + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: return hdac_hdmi_playback_prepare(substream, dai); + + default: + return 0; } return 0; @@ -1059,32 +984,59 @@ static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid) return hdac_hdmi_query_cvt_params(&edev->hdac, cvt); } -static void hdac_hdmi_parse_eld(struct hdac_ext_device *edev, +static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev, struct hdac_hdmi_pin *pin) { + unsigned int ver, mnl; + + ver = (pin->eld.eld_buffer[DRM_ELD_VER] & DRM_ELD_VER_MASK) + >> DRM_ELD_VER_SHIFT; + + if (ver != ELD_VER_CEA_861D && ver != ELD_VER_PARTIAL) { + dev_err(&edev->hdac.dev, "HDMI: Unknown ELD version %d\n", ver); + return -EINVAL; + } + + mnl = (pin->eld.eld_buffer[DRM_ELD_CEA_EDID_VER_MNL] & + DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT; + + if (mnl > ELD_MAX_MNL) { + dev_err(&edev->hdac.dev, "HDMI: MNL Invalid %d\n", mnl); + return -EINVAL; + } + pin->eld.info.spk_alloc = pin->eld.eld_buffer[DRM_ELD_SPEAKER]; + + return 0; } -static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) +static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin) { struct hdac_ext_device *edev = pin->edev; struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm; - int val; - - pin->repoll_count = repoll; + int size; - pm_runtime_get_sync(&edev->hdac.dev); - val = snd_hdac_codec_read(&edev->hdac, pin->nid, 0, - AC_VERB_GET_PIN_SENSE, 0); + mutex_lock(&hdmi->pin_mutex); + pin->eld.monitor_present = false; - dev_dbg(&edev->hdac.dev, "Pin sense val %x for pin: %d\n", - val, pin->nid); + size = snd_hdac_acomp_get_eld(&edev->hdac, pin->nid, -1, + &pin->eld.monitor_present, pin->eld.eld_buffer, + ELD_MAX_SIZE); + if (size > 0) { + size = min(size, ELD_MAX_SIZE); + if (hdac_hdmi_parse_eld(edev, pin) < 0) + size = -EINVAL; + } - mutex_lock(&hdmi->pin_mutex); - pin->eld.monitor_present = !!(val & AC_PINSENSE_PRESENCE); - pin->eld.eld_valid = !!(val & AC_PINSENSE_ELDV); + if (size > 0) { + pin->eld.eld_valid = true; + pin->eld.eld_size = size; + } else { + pin->eld.eld_valid = false; + pin->eld.eld_size = 0; + } pcm = hdac_hdmi_get_pcm(edev, pin); @@ -1106,66 +1058,23 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) } mutex_unlock(&hdmi->pin_mutex); - goto put_hdac_device; + return; } if (pin->eld.monitor_present && pin->eld.eld_valid) { - /* TODO: use i915 component for reading ELD later */ - if (hdac_hdmi_get_eld(&edev->hdac, pin->nid, - pin->eld.eld_buffer, - &pin->eld.eld_size) == 0) { - - if (pcm) { - dev_dbg(&edev->hdac.dev, - "jack report for pcm=%d\n", - pcm->pcm_id); - - snd_jack_report(pcm->jack, SND_JACK_AVOUT); - } - hdac_hdmi_parse_eld(edev, pin); - - print_hex_dump_debug("ELD: ", - DUMP_PREFIX_OFFSET, 16, 1, - pin->eld.eld_buffer, pin->eld.eld_size, - true); - } else { - pin->eld.monitor_present = false; - pin->eld.eld_valid = false; - - if (pcm) { - dev_dbg(&edev->hdac.dev, - "jack report for pcm=%d\n", - pcm->pcm_id); + if (pcm) { + dev_dbg(&edev->hdac.dev, + "jack report for pcm=%d\n", + pcm->pcm_id); - snd_jack_report(pcm->jack, 0); - } + snd_jack_report(pcm->jack, SND_JACK_AVOUT); } + + print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1, + pin->eld.eld_buffer, pin->eld.eld_size, false); } mutex_unlock(&hdmi->pin_mutex); - - /* - * Sometimes the pin_sense may present invalid monitor - * present and eld_valid. If ELD data is not valid, loop few - * more times to get correct pin sense and valid ELD. - */ - if ((!pin->eld.monitor_present || !pin->eld.eld_valid) && repoll) - schedule_delayed_work(&pin->work, msecs_to_jiffies(300)); - -put_hdac_device: - pm_runtime_put_sync(&edev->hdac.dev); -} - -static void hdac_hdmi_repoll_eld(struct work_struct *work) -{ - struct hdac_hdmi_pin *pin = - container_of(to_delayed_work(work), struct hdac_hdmi_pin, work); - - /* picked from legacy HDA driver */ - if (pin->repoll_count++ > 6) - pin->repoll_count = 0; - - hdac_hdmi_present_sense(pin, pin->repoll_count); } static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) @@ -1184,7 +1093,6 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) pin->edev = edev; mutex_init(&pin->lock); - INIT_DELAYED_WORK(&pin->work, hdac_hdmi_repoll_eld); return 0; } @@ -1395,7 +1303,7 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) list_for_each_entry(pin, &hdmi->pin_list, head) { if (pin->nid == pin_nid) - hdac_hdmi_present_sense(pin, 1); + hdac_hdmi_present_sense(pin); } } @@ -1496,7 +1404,7 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec) } list_for_each_entry(pin, &hdmi->pin_list, head) - hdac_hdmi_present_sense(pin, 1); + hdac_hdmi_present_sense(pin); /* Imp: Store the card pointer in hda_codec */ edev->card = dapm->card->snd_card; @@ -1561,7 +1469,7 @@ static void hdmi_codec_complete(struct device *dev) * all pins here. */ list_for_each_entry(pin, &hdmi->pin_list, head) - hdac_hdmi_present_sense(pin, 1); + hdac_hdmi_present_sense(pin); pm_runtime_put_sync(&edev->hdac.dev); } diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index fd5d1e0..526855a 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -2,7 +2,7 @@ config SND_MFLD_MACHINE tristate "SOC Machine Audio driver for Intel Medfield MID platform" depends on INTEL_SCU_IPC select SND_SOC_SN95031 - select SND_SST_MFLD_PLATFORM + select SND_SST_ATOM_HIFI2_PLATFORM select SND_SST_IPC_PCI help This adds support for ASoC machine driver for Intel(R) MID Medfield platform @@ -10,7 +10,7 @@ config SND_MFLD_MACHINE Say Y if you have such a device. If unsure select "N". -config SND_SST_MFLD_PLATFORM +config SND_SST_ATOM_HIFI2_PLATFORM tristate select SND_SOC_COMPRESS @@ -31,13 +31,10 @@ config SND_SOC_INTEL_SST tristate select SND_SOC_INTEL_SST_ACPI if ACPI select SND_SOC_INTEL_SST_MATCH if ACPI - depends on (X86 || COMPILE_TEST) -# firmware stuff depends DW_DMAC_CORE; since there is no depends-on from -# the reverse selection, each machine driver needs to select -# SND_SOC_INTEL_SST_FIRMWARE carefully depending on DW_DMAC_CORE config SND_SOC_INTEL_SST_FIRMWARE tristate + select DW_DMAC_CORE config SND_SOC_INTEL_SST_ACPI tristate @@ -47,16 +44,18 @@ config SND_SOC_INTEL_SST_MATCH config SND_SOC_INTEL_HASWELL tristate + select SND_SOC_INTEL_SST select SND_SOC_INTEL_SST_FIRMWARE config SND_SOC_INTEL_BAYTRAIL tristate + select SND_SOC_INTEL_SST + select SND_SOC_INTEL_SST_FIRMWARE config SND_SOC_INTEL_HASWELL_MACH tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint" depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM - depends on DW_DMAC_CORE - select SND_SOC_INTEL_SST + depends on DMADEVICES select SND_SOC_INTEL_HASWELL select SND_SOC_RT5640 help @@ -68,7 +67,6 @@ config SND_SOC_INTEL_HASWELL_MACH config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH tristate "ASoC Audio driver for Broxton with DA7219 and MAX98357A in I2S Mode" depends on X86 && ACPI && I2C - select SND_SOC_INTEL_SST select SND_SOC_INTEL_SKYLAKE select SND_SOC_DA7219 select SND_SOC_MAX98357A @@ -84,7 +82,6 @@ config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH config SND_SOC_INTEL_BXT_RT298_MACH tristate "ASoC Audio driver for Broxton with RT298 I2S mode" depends on X86 && ACPI && I2C - select SND_SOC_INTEL_SST select SND_SOC_INTEL_SKYLAKE select SND_SOC_RT298 select SND_SOC_DMIC @@ -99,9 +96,8 @@ config SND_SOC_INTEL_BXT_RT298_MACH config SND_SOC_INTEL_BYT_RT5640_MACH tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec" depends on X86_INTEL_LPSS && I2C - depends on DW_DMAC_CORE && (SND_SST_IPC_ACPI = n) - select SND_SOC_INTEL_SST - select SND_SOC_INTEL_SST_FIRMWARE + depends on DMADEVICES + depends on SND_SST_IPC_ACPI = n select SND_SOC_INTEL_BAYTRAIL select SND_SOC_RT5640 help @@ -112,9 +108,8 @@ config SND_SOC_INTEL_BYT_RT5640_MACH config SND_SOC_INTEL_BYT_MAX98090_MACH tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec" depends on X86_INTEL_LPSS && I2C - depends on DW_DMAC_CORE && (SND_SST_IPC_ACPI = n) - select SND_SOC_INTEL_SST - select SND_SOC_INTEL_SST_FIRMWARE + depends on DMADEVICES + depends on SND_SST_IPC_ACPI = n select SND_SOC_INTEL_BAYTRAIL select SND_SOC_MAX98090 help @@ -123,9 +118,8 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH config SND_SOC_INTEL_BDW_RT5677_MACH tristate "ASoC Audio driver for Intel Broadwell with RT5677 codec" - depends on X86_INTEL_LPSS && GPIOLIB && I2C && DW_DMAC - depends on DW_DMAC_CORE=y - select SND_SOC_INTEL_SST + depends on X86_INTEL_LPSS && GPIOLIB && I2C + depends on DMADEVICES select SND_SOC_INTEL_HASWELL select SND_SOC_RT5677 help @@ -134,10 +128,8 @@ config SND_SOC_INTEL_BDW_RT5677_MACH config SND_SOC_INTEL_BROADWELL_MACH tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" - depends on X86_INTEL_LPSS && I2C && DW_DMAC && \ - I2C_DESIGNWARE_PLATFORM - depends on DW_DMAC_CORE - select SND_SOC_INTEL_SST + depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM + depends on DMADEVICES select SND_SOC_INTEL_HASWELL select SND_SOC_RT286 help @@ -150,7 +142,7 @@ config SND_SOC_INTEL_BYTCR_RT5640_MACH tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec" depends on X86 && I2C && ACPI select SND_SOC_RT5640 - select SND_SST_MFLD_PLATFORM + select SND_SST_ATOM_HIFI2_PLATFORM select SND_SST_IPC_ACPI select SND_SOC_INTEL_SST_MATCH if ACPI help @@ -163,7 +155,7 @@ config SND_SOC_INTEL_BYTCR_RT5651_MACH tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec" depends on X86 && I2C && ACPI select SND_SOC_RT5651 - select SND_SST_MFLD_PLATFORM + select SND_SST_ATOM_HIFI2_PLATFORM select SND_SST_IPC_ACPI select SND_SOC_INTEL_SST_MATCH if ACPI help @@ -176,7 +168,7 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec" depends on X86_INTEL_LPSS && I2C && ACPI select SND_SOC_RT5670 - select SND_SST_MFLD_PLATFORM + select SND_SST_ATOM_HIFI2_PLATFORM select SND_SST_IPC_ACPI select SND_SOC_INTEL_SST_MATCH if ACPI help @@ -189,7 +181,7 @@ config SND_SOC_INTEL_CHT_BSW_RT5645_MACH tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645/5650 codec" depends on X86_INTEL_LPSS && I2C && ACPI select SND_SOC_RT5645 - select SND_SST_MFLD_PLATFORM + select SND_SST_ATOM_HIFI2_PLATFORM select SND_SST_IPC_ACPI select SND_SOC_INTEL_SST_MATCH if ACPI help @@ -202,7 +194,7 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH depends on X86_INTEL_LPSS && I2C && ACPI select SND_SOC_MAX98090 select SND_SOC_TS3A227E - select SND_SST_MFLD_PLATFORM + select SND_SST_ATOM_HIFI2_PLATFORM select SND_SST_IPC_ACPI select SND_SOC_INTEL_SST_MATCH if ACPI help @@ -220,7 +212,6 @@ config SND_SOC_INTEL_SKYLAKE config SND_SOC_INTEL_SKL_RT286_MACH tristate "ASoC Audio driver for SKL with RT286 I2S mode" depends on X86 && ACPI && I2C - select SND_SOC_INTEL_SST select SND_SOC_INTEL_SKYLAKE select SND_SOC_RT286 select SND_SOC_DMIC @@ -234,7 +225,6 @@ config SND_SOC_INTEL_SKL_RT286_MACH config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH tristate "ASoC Audio driver for SKL with NAU88L25 and SSM4567 in I2S Mode" depends on X86_INTEL_LPSS && I2C - select SND_SOC_INTEL_SST select SND_SOC_INTEL_SKYLAKE select SND_SOC_NAU8825 select SND_SOC_SSM4567 @@ -249,7 +239,6 @@ config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH tristate "ASoC Audio driver for SKL with NAU88L25 and MAX98357A in I2S Mode" depends on X86_INTEL_LPSS && I2C - select SND_SOC_INTEL_SST select SND_SOC_INTEL_SKYLAKE select SND_SOC_NAU8825 select SND_SOC_MAX98357A diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index 2b45435..cdd495f 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_SND_SOC_INTEL_SST) += common/ # Platform Support obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/ obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += baytrail/ -obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += atom/ +obj-$(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM) += atom/ obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += skylake/ # Machine support diff --git a/sound/soc/intel/atom/Makefile b/sound/soc/intel/atom/Makefile index ce8074f..aa6548c 100644 --- a/sound/soc/intel/atom/Makefile +++ b/sound/soc/intel/atom/Makefile @@ -1,7 +1,8 @@ -snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o \ - sst-mfld-platform-compress.o sst-atom-controls.o +snd-soc-sst-atom-hifi2-platform-objs := sst-mfld-platform-pcm.o \ + sst-mfld-platform-compress.o \ + sst-atom-controls.o -obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o +obj-$(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM) += snd-soc-sst-atom-hifi2-platform.o # DSP driver obj-$(CONFIG_SND_SST_IPC) += sst/ diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index f5a8050..21cac1c 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -357,14 +357,14 @@ static void sst_media_close(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct sst_runtime_stream *stream; - int ret_val = 0, str_id; + int str_id; stream = substream->runtime->private_data; power_down_sst(stream); str_id = stream->stream_info.str_id; if (str_id) - ret_val = stream->ops->close(sst->dev, str_id); + stream->ops->close(sst->dev, str_id); module_put(sst->dev->driver->owner); kfree(stream); } @@ -839,4 +839,5 @@ MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver"); MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>"); MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:sst-atom-hifi2-platform"); MODULE_ALIAS("platform:sst-mfld-platform"); diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c index 374bb61..14c2d9d1 100644 --- a/sound/soc/intel/atom/sst/sst_ipc.c +++ b/sound/soc/intel/atom/sst/sst_ipc.c @@ -260,10 +260,8 @@ static void process_fw_async_msg(struct intel_sst_drv *sst_drv_ctx, u32 data_size, i; void *data_offset; struct stream_info *stream; - union ipc_header_high msg_high; u32 msg_low, pipe_id; - msg_high = msg->mrfld_header.p.header_high; msg_low = msg->mrfld_header.p.header_low_payload; msg_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->cmd_id; data_offset = (msg->mailbox_data + sizeof(struct ipc_dsp_hdr)); diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c index 51bdeee..83d8dda 100644 --- a/sound/soc/intel/atom/sst/sst_stream.c +++ b/sound/soc/intel/atom/sst/sst_stream.c @@ -394,7 +394,6 @@ int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) { int retval = 0; struct stream_info *str_info; - struct intel_sst_ops *ops; dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_free_stream for %d\n", str_id); @@ -407,7 +406,6 @@ int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) str_info = get_stream_info(sst_drv_ctx, str_id); if (!str_info) return -EINVAL; - ops = sst_drv_ctx->ops; mutex_lock(&str_info->lock); if (str_info->status != STREAM_UN_INIT) { diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index 4d7e9de..faf865b 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -270,6 +270,8 @@ static int broadwell_audio_probe(struct platform_device *pdev) { broadwell_rt286.dev = &pdev->dev; + snd_soc_set_dmi_name(&broadwell_rt286, NULL); + return devm_snd_soc_register_card(&pdev->dev, &broadwell_rt286); } diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 1b4330c..02439ac 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -357,7 +357,6 @@ static struct snd_soc_dai_link broxton_dais[] = { .platform_name = "0000:00:0e.0", .init = NULL, .dpcm_capture = 1, - .ignore_suspend = 1, .nonatomic = 1, .dynamic = 1, .ops = &broxton_refcap_ops, diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 507a86a..613e528 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -387,6 +387,16 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF1), }, + { + .callback = byt_rt5640_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), + }, + .driver_data = (unsigned long *)(BYT_RT5640_IN3_MAP | + BYT_RT5640_MCLK_EN | + BYT_RT5640_SSP0_AIF1), + + }, {} }; diff --git a/sound/soc/intel/common/sst-dsp.c b/sound/soc/intel/common/sst-dsp.c index c00ede4..11c0805 100644 --- a/sound/soc/intel/common/sst-dsp.c +++ b/sound/soc/intel/common/sst-dsp.c @@ -252,44 +252,44 @@ void sst_dsp_shim_update_bits_forced(struct sst_dsp *sst, u32 offset, EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced); int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask, - u32 target, u32 timeout, char *operation) + u32 target, u32 time, char *operation) { - int time, ret; u32 reg; - bool done = false; + unsigned long timeout; + int k = 0, s = 500; /* - * we will poll for couple of ms using mdelay, if not successful - * then go to longer sleep using usleep_range + * split the loop into sleeps of varying resolution. more accurately, + * the range of wakeups are: + * Phase 1(first 5ms): min sleep 0.5ms; max sleep 1ms. + * Phase 2:( 5ms to 10ms) : min sleep 0.5ms; max sleep 10ms + * (usleep_range (500, 1000) and usleep_range(5000, 10000) are + * both possible in this phase depending on whether k > 10 or not). + * Phase 3: (beyond 10 ms) min sleep 5ms; max sleep 10ms. */ - /* check if set state successful */ - for (time = 0; time < 5; time++) { - if ((sst_dsp_shim_read_unlocked(ctx, offset) & mask) == target) { - done = true; - break; - } - mdelay(1); + timeout = jiffies + msecs_to_jiffies(time); + while (((sst_dsp_shim_read_unlocked(ctx, offset) & mask) != target) + && time_before(jiffies, timeout)) { + k++; + if (k > 10) + s = 5000; + + usleep_range(s, 2*s); } - if (done == false) { - /* sleeping in 10ms steps so adjust timeout value */ - timeout /= 10; + reg = sst_dsp_shim_read_unlocked(ctx, offset); - for (time = 0; time < timeout; time++) { - if ((sst_dsp_shim_read_unlocked(ctx, offset) & mask) == target) - break; + if ((reg & mask) == target) { + dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s successful\n", + reg, operation); - usleep_range(5000, 10000); - } + return 0; } - reg = sst_dsp_shim_read_unlocked(ctx, offset); - dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s %s\n", reg, operation, - (time < timeout) ? "successful" : "timedout"); - ret = time < timeout ? 0 : -ETIME; - - return ret; + dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s timedout\n", + reg, operation); + return -ETIME; } EXPORT_SYMBOL_GPL(sst_dsp_register_poll); diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c index 1f9f33d..15a063a 100644 --- a/sound/soc/intel/skylake/bxt-sst.c +++ b/sound/soc/intel/skylake/bxt-sst.c @@ -23,7 +23,6 @@ #include "../common/sst-dsp.h" #include "../common/sst-dsp-priv.h" #include "skl-sst-ipc.h" -#include "skl-tplg-interface.h" #define BXT_BASEFW_TIMEOUT 3000 #define BXT_INIT_TIMEOUT 500 @@ -52,7 +51,7 @@ static unsigned int bxt_get_errorcode(struct sst_dsp *ctx) } static int -bxt_load_library(struct sst_dsp *ctx, struct skl_dfw_manifest *minfo) +bxt_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count) { struct snd_dma_buffer dmab; struct skl_sst *skl = ctx->thread_context; @@ -61,11 +60,11 @@ bxt_load_library(struct sst_dsp *ctx, struct skl_dfw_manifest *minfo) int ret = 0, i, dma_id, stream_tag; /* library indices start from 1 to N. 0 represents base FW */ - for (i = 1; i < minfo->lib_count; i++) { - ret = request_firmware(&fw, minfo->lib[i].name, ctx->dev); + for (i = 1; i < lib_count; i++) { + ret = request_firmware(&fw, linfo[i].name, ctx->dev); if (ret < 0) { dev_err(ctx->dev, "Request lib %s failed:%d\n", - minfo->lib[i].name, ret); + linfo[i].name, ret); return ret; } @@ -96,7 +95,7 @@ bxt_load_library(struct sst_dsp *ctx, struct skl_dfw_manifest *minfo) ret = skl_sst_ipc_load_library(&skl->ipc, dma_id, i); if (ret < 0) dev_err(ctx->dev, "IPC Load Lib for %s fail: %d\n", - minfo->lib[i].name, ret); + linfo[i].name, ret); ctx->dsp_ops.trigger(ctx->dev, false, stream_tag); ctx->dsp_ops.cleanup(ctx->dev, &dmab, stream_tag); @@ -119,8 +118,7 @@ load_library_failed: static int sst_bxt_prepare_fw(struct sst_dsp *ctx, const void *fwdata, u32 fwsize) { - int stream_tag, ret, i; - u32 reg; + int stream_tag, ret; stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab); if (stream_tag <= 0) { @@ -153,23 +151,13 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx, } /* Step 4: Wait for DONE Bit */ - for (i = BXT_INIT_TIMEOUT; i > 0; --i) { - reg = sst_dsp_shim_read(ctx, SKL_ADSP_REG_HIPCIE); - - if (reg & SKL_ADSP_REG_HIPCIE_DONE) { - sst_dsp_shim_update_bits_forced(ctx, - SKL_ADSP_REG_HIPCIE, + ret = sst_dsp_register_poll(ctx, SKL_ADSP_REG_HIPCIE, SKL_ADSP_REG_HIPCIE_DONE, - SKL_ADSP_REG_HIPCIE_DONE); - break; - } - mdelay(1); - } - if (!i) { - dev_info(ctx->dev, "Waiting for HIPCIE done, reg: 0x%x\n", reg); - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCIE, - SKL_ADSP_REG_HIPCIE_DONE, - SKL_ADSP_REG_HIPCIE_DONE); + SKL_ADSP_REG_HIPCIE_DONE, + BXT_INIT_TIMEOUT, "HIPCIE Done"); + if (ret < 0) { + dev_err(ctx->dev, "Timout for Purge Request%d\n", ret); + goto base_fw_load_failed; } /* Step 5: power down core1 */ @@ -184,19 +172,10 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx, skl_ipc_op_int_enable(ctx); /* Step 7: Wait for ROM init */ - for (i = BXT_INIT_TIMEOUT; i > 0; --i) { - if (SKL_FW_INIT == - (sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS) & - SKL_FW_STS_MASK)) { - - dev_info(ctx->dev, "ROM loaded, continue FW loading\n"); - break; - } - mdelay(1); - } - if (!i) { - dev_err(ctx->dev, "Timeout for ROM init, HIPCIE: 0x%x\n", reg); - ret = -EIO; + ret = sst_dsp_register_poll(ctx, BXT_ADSP_FW_STATUS, SKL_FW_STS_MASK, + SKL_FW_INIT, BXT_INIT_TIMEOUT, "ROM Load"); + if (ret < 0) { + dev_err(ctx->dev, "Timeout for ROM init, ret:%d\n", ret); goto base_fw_load_failed; } @@ -432,7 +411,6 @@ static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) int ret; struct skl_ipc_dxstate_info dx; unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); - struct skl_dfw_manifest *minfo = &skl->manifest; if (skl->fw_loaded == false) { skl->boot_complete = false; @@ -442,8 +420,9 @@ static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) return ret; } - if (minfo->lib_count > 1) { - ret = bxt_load_library(ctx, minfo); + if (skl->lib_count > 1) { + ret = bxt_load_library(ctx, skl->lib_info, + skl->lib_count); if (ret < 0) { dev_err(ctx->dev, "reload libs failed: %d\n", ret); return ret; @@ -640,8 +619,9 @@ int bxt_sst_init_fw(struct device *dev, struct skl_sst *ctx) skl_dsp_init_core_state(sst); - if (ctx->manifest.lib_count > 1) { - ret = sst->fw_ops.load_library(sst, &ctx->manifest); + if (ctx->lib_count > 1) { + ret = sst->fw_ops.load_library(sst, ctx->lib_info, + ctx->lib_count); if (ret < 0) { dev_err(dev, "Load Library failed : %x\n", ret); return ret; diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 84b5101..ae7997a 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -137,6 +137,80 @@ static void skl_set_suspend_active(struct snd_pcm_substream *substream, skl->supend_active--; } +int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params) +{ + struct hdac_ext_bus *ebus = dev_get_drvdata(dev); + struct hdac_bus *bus = ebus_to_hbus(ebus); + unsigned int format_val; + struct hdac_stream *hstream; + struct hdac_ext_stream *stream; + int err; + + hstream = snd_hdac_get_stream(bus, params->stream, + params->host_dma_id + 1); + if (!hstream) + return -EINVAL; + + stream = stream_to_hdac_ext_stream(hstream); + snd_hdac_ext_stream_decouple(ebus, stream, true); + + format_val = snd_hdac_calc_stream_format(params->s_freq, + params->ch, params->format, 32, 0); + + dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", + format_val, params->s_freq, params->ch, params->format); + + snd_hdac_stream_reset(hdac_stream(stream)); + err = snd_hdac_stream_set_params(hdac_stream(stream), format_val); + if (err < 0) + return err; + + err = snd_hdac_stream_setup(hdac_stream(stream)); + if (err < 0) + return err; + + hdac_stream(stream)->prepared = 1; + + return 0; +} + +int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params) +{ + struct hdac_ext_bus *ebus = dev_get_drvdata(dev); + struct hdac_bus *bus = ebus_to_hbus(ebus); + unsigned int format_val; + struct hdac_stream *hstream; + struct hdac_ext_stream *stream; + struct hdac_ext_link *link; + + hstream = snd_hdac_get_stream(bus, params->stream, + params->link_dma_id + 1); + if (!hstream) + return -EINVAL; + + stream = stream_to_hdac_ext_stream(hstream); + snd_hdac_ext_stream_decouple(ebus, stream, true); + format_val = snd_hdac_calc_stream_format(params->s_freq, + params->ch, params->format, 24, 0); + + dev_dbg(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_reset(stream); + + snd_hdac_ext_link_stream_setup(stream, format_val); + + list_for_each_entry(link, &ebus->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 skl_pcm_open(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -185,32 +259,6 @@ static int skl_pcm_open(struct snd_pcm_substream *substream, return 0; } -static int skl_get_format(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct skl_dma_params *dma_params; - struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); - int format_val = 0; - - if ((ebus_to_hbus(ebus))->ppcap) { - struct snd_pcm_runtime *runtime = substream->runtime; - - format_val = snd_hdac_calc_stream_format(runtime->rate, - runtime->channels, - runtime->format, - 32, 0); - } else { - struct snd_soc_dai *codec_dai = rtd->codec_dai; - - dma_params = snd_soc_dai_get_dma_data(codec_dai, substream); - if (dma_params) - format_val = dma_params->format; - } - - return format_val; -} - static int skl_be_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -231,37 +279,19 @@ static int skl_be_prepare(struct snd_pcm_substream *substream, static int skl_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); struct skl *skl = get_skl_ctx(dai->dev); - unsigned int format_val; - int err; struct skl_module_cfg *mconfig; dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); - format_val = skl_get_format(substream, dai); - dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d\n", - hdac_stream(stream)->stream_tag, format_val); - snd_hdac_stream_reset(hdac_stream(stream)); - /* In case of XRUN recovery, reset the FW pipe to clean state */ if (mconfig && (substream->runtime->status->state == SNDRV_PCM_STATE_XRUN)) skl_reset_pipe(skl->skl_sst, mconfig->pipe); - err = snd_hdac_stream_set_params(hdac_stream(stream), format_val); - if (err < 0) - return err; - - err = snd_hdac_stream_setup(hdac_stream(stream)); - if (err < 0) - return err; - - hdac_stream(stream)->prepared = 1; - - return err; + return 0; } static int skl_pcm_hw_params(struct snd_pcm_substream *substream, @@ -292,6 +322,7 @@ static int skl_pcm_hw_params(struct snd_pcm_substream *substream, p_params.s_freq = params_rate(params); p_params.host_dma_id = dma_id; p_params.stream = substream->stream; + p_params.format = params_format(params); m_cfg = skl_tplg_fe_get_cpr_module(dai, p_params.stream); if (m_cfg) @@ -435,7 +466,6 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: if (!w->ignore_suspend) { - skl_pcm_prepare(substream, dai); /* * enable DMA Resume enable bit for the stream, set the * dpib & lpib position to resume before starting the @@ -444,7 +474,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, snd_hdac_ext_stream_drsm_enable(ebus, true, hdac_stream(stream)->index); snd_hdac_ext_stream_set_dpibr(ebus, stream, - stream->dpib); + stream->lpib); snd_hdac_ext_stream_set_lpib(stream, stream->lpib); } @@ -456,7 +486,6 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, * pipeline is started but there is a delay in starting the * DMA channel on the host. */ - snd_hdac_ext_stream_decouple(ebus, stream, true); ret = skl_decoupled_trigger(substream, cmd); if (ret < 0) return ret; @@ -506,6 +535,7 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, struct hdac_ext_dma_params *dma_params; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct skl_pipe_params p_params = {0}; + struct hdac_ext_link *link; link_dev = snd_hdac_ext_stream_assign(ebus, substream, HDAC_EXT_STREAM_TYPE_LINK); @@ -514,6 +544,10 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev); + link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name); + if (!link) + return -EINVAL; + /* set the stream tag in the codec dai dma params */ dma_params = snd_soc_dai_get_dma_data(codec_dai, substream); if (dma_params) @@ -524,6 +558,8 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, p_params.s_freq = params_rate(params); p_params.stream = substream->stream; p_params.link_dma_id = hdac_stream(link_dev)->stream_tag - 1; + p_params.link_index = link->index; + p_params.format = params_format(params); return skl_tplg_be_update_params(dai, &p_params); } @@ -531,41 +567,15 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); - struct hdac_ext_stream *link_dev = - snd_soc_dai_get_dma_data(dai, substream); - unsigned int format_val = 0; - struct skl_dma_params *dma_params; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct hdac_ext_link *link; struct skl *skl = get_skl_ctx(dai->dev); struct skl_module_cfg *mconfig = NULL; - dma_params = (struct skl_dma_params *) - snd_soc_dai_get_dma_data(codec_dai, substream); - if (dma_params) - format_val = dma_params->format; - dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d codec_dai_name=%s\n", - hdac_stream(link_dev)->stream_tag, format_val, codec_dai->name); - - link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name); - if (!link) - return -EINVAL; - - snd_hdac_ext_link_stream_reset(link_dev); - /* In case of XRUN recovery, reset the FW pipe to clean state */ mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream); - if (mconfig && (substream->runtime->status->state == - SNDRV_PCM_STATE_XRUN)) + if (mconfig && !mconfig->pipe->passthru && + (substream->runtime->status->state == SNDRV_PCM_STATE_XRUN)) skl_reset_pipe(skl->skl_sst, mconfig->pipe); - snd_hdac_ext_link_stream_setup(link_dev, format_val); - - snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_dev)->stream_tag); - link_dev->link_prepared = 1; - return 0; } @@ -580,10 +590,8 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream, dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd); switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: - skl_link_pcm_prepare(substream, dai); case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - snd_hdac_ext_stream_decouple(ebus, stream, true); snd_hdac_ext_link_stream_start(link_dev); break; diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index 7c272ba..849410d 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -19,7 +19,6 @@ #include <linux/interrupt.h> #include <sound/memalloc.h> #include "skl-sst-cldma.h" -#include "skl-tplg-interface.h" #include "skl-topology.h" struct sst_dsp; @@ -145,7 +144,7 @@ struct skl_dsp_fw_ops { int (*load_fw)(struct sst_dsp *ctx); /* FW module parser/loader */ int (*load_library)(struct sst_dsp *ctx, - struct skl_dfw_manifest *minfo); + struct skl_lib_info *linfo, int count); 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); @@ -236,5 +235,4 @@ int skl_get_pvt_instance_id_map(struct skl_sst *ctx, void skl_freeup_uuid_list(struct skl_sst *ctx); int skl_dsp_strip_extended_manifest(struct firmware *fw); - #endif /*__SKL_SST_DSP_H__*/ diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index cc40341..9660ace 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -97,8 +97,9 @@ struct skl_sst { /* multi-core */ struct skl_dsp_cores cores; - /* tplg manifest */ - struct skl_dfw_manifest manifest; + /* library info */ + struct skl_lib_info lib_info[SKL_MAX_LIB]; + int lib_count; /* Callback to update D0i3C register */ void (*update_d0i3c)(struct device *dev, bool enable); diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index bd313c9..e6e7623 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -496,6 +496,20 @@ static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w) return 0; } +static int skl_tplg_module_prepare(struct skl_sst *ctx, struct skl_pipe *pipe, + struct snd_soc_dapm_widget *w, struct skl_module_cfg *mcfg) +{ + switch (mcfg->dev_type) { + case SKL_DEVICE_HDAHOST: + return skl_pcm_host_dma_prepare(ctx->dev, pipe->p_params); + + case SKL_DEVICE_HDALINK: + return skl_pcm_link_dma_prepare(ctx->dev, pipe->p_params); + } + + return 0; +} + /* * Inside a pipe instance, we can have various modules. These modules need * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by @@ -535,6 +549,11 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) mconfig->m_state = SKL_MODULE_LOADED; } + /* prepare the DMA if the module is gateway cpr */ + ret = skl_tplg_module_prepare(ctx, pipe, w, mconfig); + if (ret < 0) + return ret; + /* update blob if blob is null for be with default value */ skl_tplg_update_be_blob(w, ctx); @@ -974,7 +993,6 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, struct skl_module_cfg *src_module = NULL, *dst_module; struct skl_sst *ctx = skl->skl_sst; struct skl_pipe *s_pipe = mconfig->pipe; - int ret = 0; if (s_pipe->state == SKL_PIPE_INVALID) return -EINVAL; @@ -996,7 +1014,7 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, src_module = dst_module; } - ret = skl_delete_pipe(ctx, mconfig->pipe); + skl_delete_pipe(ctx, mconfig->pipe); return skl_tplg_unload_pipe_modules(ctx, s_pipe); } @@ -1207,6 +1225,7 @@ static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg, switch (mcfg->dev_type) { case SKL_DEVICE_HDALINK: pipe->p_params->link_dma_id = params->link_dma_id; + pipe->p_params->link_index = params->link_index; break; case SKL_DEVICE_HDAHOST: @@ -1220,6 +1239,7 @@ static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg, pipe->p_params->ch = params->ch; pipe->p_params->s_freq = params->s_freq; pipe->p_params->stream = params->stream; + pipe->p_params->format = params->format; } else { memcpy(pipe->p_params, params, sizeof(*params)); @@ -2280,20 +2300,21 @@ static int skl_tplg_control_load(struct snd_soc_component *cmpnt, static int skl_tplg_fill_str_mfest_tkn(struct device *dev, struct snd_soc_tplg_vendor_string_elem *str_elem, - struct skl_dfw_manifest *minfo) + struct skl *skl) { int tkn_count = 0; static int ref_count; switch (str_elem->token) { case SKL_TKN_STR_LIB_NAME: - if (ref_count > minfo->lib_count - 1) { + if (ref_count > skl->skl_sst->lib_count - 1) { ref_count = 0; return -EINVAL; } - strncpy(minfo->lib[ref_count].name, str_elem->string, - ARRAY_SIZE(minfo->lib[ref_count].name)); + strncpy(skl->skl_sst->lib_info[ref_count].name, + str_elem->string, + ARRAY_SIZE(skl->skl_sst->lib_info[ref_count].name)); ref_count++; tkn_count++; break; @@ -2308,14 +2329,14 @@ static int skl_tplg_fill_str_mfest_tkn(struct device *dev, static int skl_tplg_get_str_tkn(struct device *dev, struct snd_soc_tplg_vendor_array *array, - struct skl_dfw_manifest *minfo) + struct skl *skl) { int tkn_count = 0, ret; struct snd_soc_tplg_vendor_string_elem *str_elem; str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value; while (tkn_count < array->num_elems) { - ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, minfo); + ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, skl); str_elem++; if (ret < 0) @@ -2329,13 +2350,13 @@ static int skl_tplg_get_str_tkn(struct device *dev, static int skl_tplg_get_int_tkn(struct device *dev, struct snd_soc_tplg_vendor_value_elem *tkn_elem, - struct skl_dfw_manifest *minfo) + struct skl *skl) { int tkn_count = 0; switch (tkn_elem->token) { case SKL_TKN_U32_LIB_COUNT: - minfo->lib_count = tkn_elem->value; + skl->skl_sst->lib_count = tkn_elem->value; tkn_count++; break; @@ -2352,7 +2373,7 @@ static int skl_tplg_get_int_tkn(struct device *dev, * type. */ static int skl_tplg_get_manifest_tkn(struct device *dev, - char *pvt_data, struct skl_dfw_manifest *minfo, + char *pvt_data, struct skl *skl, int block_size) { int tkn_count = 0, ret; @@ -2368,7 +2389,7 @@ static int skl_tplg_get_manifest_tkn(struct device *dev, off += array->size; switch (array->type) { case SND_SOC_TPLG_TUPLE_TYPE_STRING: - ret = skl_tplg_get_str_tkn(dev, array, minfo); + ret = skl_tplg_get_str_tkn(dev, array, skl); if (ret < 0) return ret; @@ -2390,7 +2411,7 @@ static int skl_tplg_get_manifest_tkn(struct device *dev, while (tkn_count <= array->num_elems - 1) { ret = skl_tplg_get_int_tkn(dev, - tkn_elem, minfo); + tkn_elem, skl); if (ret < 0) return ret; @@ -2411,7 +2432,7 @@ static int skl_tplg_get_manifest_tkn(struct device *dev, * preceded by descriptors for type and size of data block. */ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest, - struct device *dev, struct skl_dfw_manifest *minfo) + struct device *dev, struct skl *skl) { struct snd_soc_tplg_vendor_array *array; int num_blocks, block_size = 0, block_type, off = 0; @@ -2454,7 +2475,7 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest, data = (manifest->priv.data + off); if (block_type == SKL_TYPE_TUPLE) { - ret = skl_tplg_get_manifest_tkn(dev, data, minfo, + ret = skl_tplg_get_manifest_tkn(dev, data, skl, block_size); if (ret < 0) @@ -2472,27 +2493,23 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest, static int skl_manifest_load(struct snd_soc_component *cmpnt, struct snd_soc_tplg_manifest *manifest) { - struct skl_dfw_manifest *minfo; struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt); struct hdac_bus *bus = ebus_to_hbus(ebus); struct skl *skl = ebus_to_skl(ebus); - int ret = 0; /* proceed only if we have private data defined */ if (manifest->priv.size == 0) return 0; - minfo = &skl->skl_sst->manifest; - - skl_tplg_get_manifest_data(manifest, bus->dev, minfo); + skl_tplg_get_manifest_data(manifest, bus->dev, skl); - if (minfo->lib_count > HDA_MAX_LIB) { + if (skl->skl_sst->lib_count > SKL_MAX_LIB) { dev_err(bus->dev, "Exceeding max Library count. Got:%d\n", - minfo->lib_count); - ret = -EINVAL; + skl->skl_sst->lib_count); + return -EINVAL; } - return ret; + return 0; } static struct snd_soc_tplg_ops skl_tplg_ops = { diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 08d3928..fefab0e 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -254,6 +254,8 @@ struct skl_pipe_params { u32 s_freq; u32 s_fmt; u8 linktype; + snd_pcm_format_t format; + int link_index; int stream; }; @@ -332,6 +334,19 @@ struct skl_pipeline { struct list_head node; }; +#define SKL_LIB_NAME_LENGTH 128 +#define SKL_MAX_LIB 16 + +struct skl_lib_info { + char name[SKL_LIB_NAME_LENGTH]; + const struct firmware *fw; +}; + +struct skl_manifest { + u32 lib_count; + struct skl_lib_info lib[SKL_MAX_LIB]; +}; + static inline struct skl *get_skl_ctx(struct device *dev) { struct hdac_ext_bus *ebus = dev_get_drvdata(dev); @@ -383,4 +398,8 @@ int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size, struct skl_module_cfg *skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, int stream); enum skl_bitdepth skl_get_bit_depth(int params); +int skl_pcm_host_dma_prepare(struct device *dev, + struct skl_pipe_params *params); +int skl_pcm_link_dma_prepare(struct device *dev, + struct skl_pipe_params *params); #endif diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h index 2f6281e..7a2febf 100644 --- a/sound/soc/intel/skylake/skl-tplg-interface.h +++ b/sound/soc/intel/skylake/skl-tplg-interface.h @@ -157,18 +157,6 @@ struct skl_dfw_algo_data { char params[0]; } __packed; -#define LIB_NAME_LENGTH 128 -#define HDA_MAX_LIB 16 - -struct lib_info { - char name[LIB_NAME_LENGTH]; -} __packed; - -struct skl_dfw_manifest { - u32 lib_count; - struct lib_info lib[HDA_MAX_LIB]; -} __packed; - enum skl_tkn_dir { SKL_DIR_IN, SKL_DIR_OUT diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f1901bb..530a4db 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -34,6 +34,7 @@ #include <linux/ctype.h> #include <linux/slab.h> #include <linux/of.h> +#include <linux/dmi.h> #include <sound/core.h> #include <sound/jack.h> #include <sound/pcm.h> @@ -1888,6 +1889,139 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, } EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt); + +/* Trim special characters, and replace '-' with '_' since '-' is used to + * separate different DMI fields in the card long name. Only number and + * alphabet characters and a few separator characters are kept. + */ +static void cleanup_dmi_name(char *name) +{ + int i, j = 0; + + for (i = 0; name[i]; i++) { + if (isalnum(name[i]) || (name[i] == '.') + || (name[i] == '_')) + name[j++] = name[i]; + else if (name[i] == '-') + name[j++] = '_'; + } + + name[j] = '\0'; +} + +/** + * snd_soc_set_dmi_name() - Register DMI names to card + * @card: The card to register DMI names + * @flavour: The flavour "differentiator" for the card amongst its peers. + * + * An Intel machine driver may be used by many different devices but are + * difficult for userspace to differentiate, since machine drivers ususally + * use their own name as the card short name and leave the card long name + * blank. To differentiate such devices and fix bugs due to lack of + * device-specific configurations, this function allows DMI info to be used + * as the sound card long name, in the format of + * "vendor-product-version-board" + * (Character '-' is used to separate different DMI fields here). + * This will help the user space to load the device-specific Use Case Manager + * (UCM) configurations for the card. + * + * Possible card long names may be: + * DellInc.-XPS139343-01-0310JH + * ASUSTeKCOMPUTERINC.-T100TA-1.0-T100TA + * Circuitco-MinnowboardMaxD0PLATFORM-D0-MinnowBoardMAX + * + * This function also supports flavoring the card longname to provide + * the extra differentiation, like "vendor-product-version-board-flavor". + * + * We only keep number and alphabet characters and a few separator characters + * in the card long name since UCM in the user space uses the card long names + * as card configuration directory names and AudoConf cannot support special + * charactors like SPACE. + * + * Returns 0 on success, otherwise a negative error code. + */ +int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour) +{ + const char *vendor, *product, *product_version, *board; + size_t longname_buf_size = sizeof(card->snd_card->longname); + size_t len; + + if (card->long_name) + return 0; /* long name already set by driver or from DMI */ + + /* make up dmi long name as: vendor.product.version.board */ + vendor = dmi_get_system_info(DMI_BOARD_VENDOR); + if (!vendor) { + dev_warn(card->dev, "ASoC: no DMI vendor name!\n"); + return 0; + } + + snprintf(card->dmi_longname, sizeof(card->snd_card->longname), + "%s", vendor); + cleanup_dmi_name(card->dmi_longname); + + product = dmi_get_system_info(DMI_PRODUCT_NAME); + if (product) { + len = strlen(card->dmi_longname); + snprintf(card->dmi_longname + len, + longname_buf_size - len, + "-%s", product); + + len++; /* skip the separator "-" */ + if (len < longname_buf_size) + cleanup_dmi_name(card->dmi_longname + len); + + /* some vendors like Lenovo may only put a self-explanatory + * name in the product version field + */ + product_version = dmi_get_system_info(DMI_PRODUCT_VERSION); + if (product_version) { + len = strlen(card->dmi_longname); + snprintf(card->dmi_longname + len, + longname_buf_size - len, + "-%s", product_version); + + len++; + if (len < longname_buf_size) + cleanup_dmi_name(card->dmi_longname + len); + } + } + + board = dmi_get_system_info(DMI_BOARD_NAME); + if (board) { + len = strlen(card->dmi_longname); + snprintf(card->dmi_longname + len, + longname_buf_size - len, + "-%s", board); + + len++; + if (len < longname_buf_size) + cleanup_dmi_name(card->dmi_longname + len); + } else if (!product) { + /* fall back to using legacy name */ + dev_warn(card->dev, "ASoC: no DMI board/product name!\n"); + return 0; + } + + /* Add flavour to dmi long name */ + if (flavour) { + len = strlen(card->dmi_longname); + snprintf(card->dmi_longname + len, + longname_buf_size - len, + "-%s", flavour); + + len++; + if (len < longname_buf_size) + cleanup_dmi_name(card->dmi_longname + len); + } + + /* set the card long name */ + card->long_name = card->dmi_longname; + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_set_dmi_name); + static int snd_soc_instantiate_card(struct snd_soc_card *card) { struct snd_soc_codec *codec; |