summaryrefslogtreecommitdiff
path: root/sound/hda
diff options
context:
space:
mode:
Diffstat (limited to 'sound/hda')
-rw-r--r--sound/hda/ext/hdac_ext_stream.c43
-rw-r--r--sound/hda/hdac_i915.c24
-rw-r--r--sound/hda/hdac_stream.c23
3 files changed, 74 insertions, 16 deletions
diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c
index 11b7119cc47e..a3ac738f1130 100644
--- a/sound/hda/ext/hdac_ext_stream.c
+++ b/sound/hda/ext/hdac_ext_stream.c
@@ -10,6 +10,8 @@
*/
#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
#include <linux/slab.h>
#include <sound/pcm.h>
#include <sound/hda_register.h>
@@ -17,6 +19,39 @@
#include <sound/compress_driver.h>
/**
+ * snd_hdac_ext_host_stream_setup - Setup a HOST stream.
+ * @hext_stream: HDAudio stream to set up.
+ * @code_loading: Whether the stream is for PCM or code-loading.
+ *
+ * Return: Zero on success or negative error code.
+ */
+int snd_hdac_ext_host_stream_setup(struct hdac_ext_stream *hext_stream, bool code_loading)
+{
+ return hext_stream->host_setup(hdac_stream(hext_stream), code_loading);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_host_stream_setup);
+
+/**
+ * snd_hdac_apl_host_stream_setup - Setup a HOST stream following procedure
+ * recommended for ApolloLake devices.
+ * @hstream: HDAudio stream to set up.
+ * @code_loading: Whether the stream is for PCM or code-loading.
+ *
+ * Return: Zero on success or negative error code.
+ */
+static int snd_hdac_apl_host_stream_setup(struct hdac_stream *hstream, bool code_loading)
+{
+ struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
+ int ret;
+
+ snd_hdac_ext_stream_decouple(hstream->bus, hext_stream, false);
+ ret = snd_hdac_stream_setup(hstream, code_loading);
+ snd_hdac_ext_stream_decouple(hstream->bus, hext_stream, true);
+
+ return ret;
+}
+
+/**
* snd_hdac_ext_stream_init - initialize each stream (aka device)
* @bus: HD-audio core bus
* @hext_stream: HD-audio ext core stream object to initialize
@@ -55,9 +90,16 @@ static void snd_hdac_ext_stream_init(struct hdac_bus *bus,
int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx,
int num_stream, int dir)
{
+ struct pci_dev *pci = to_pci_dev(bus->dev);
+ int (*setup_op)(struct hdac_stream *, bool);
int stream_tag = 0;
int i, tag, idx = start_idx;
+ if (pci->device == PCI_DEVICE_ID_INTEL_HDA_APL)
+ setup_op = snd_hdac_apl_host_stream_setup;
+ else
+ setup_op = snd_hdac_stream_setup;
+
for (i = 0; i < num_stream; i++) {
struct hdac_ext_stream *hext_stream =
kzalloc(sizeof(*hext_stream), GFP_KERNEL);
@@ -66,6 +108,7 @@ int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx,
tag = ++stream_tag;
snd_hdac_ext_stream_init(bus, hext_stream, idx, dir, tag);
idx++;
+ hext_stream->host_setup = setup_op;
}
return 0;
diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c
index b428537f284c..365c36fdf205 100644
--- a/sound/hda/hdac_i915.c
+++ b/sound/hda/hdac_i915.c
@@ -10,6 +10,12 @@
#include <sound/hdaudio.h>
#include <sound/hda_i915.h>
#include <sound/hda_register.h>
+#include <video/nomodeset.h>
+
+static int gpu_bind = -1;
+module_param(gpu_bind, int, 0644);
+MODULE_PARM_DESC(gpu_bind, "Whether to bind sound component to GPU "
+ "(1=always, 0=never, -1=on nomodeset(default))");
/**
* snd_hdac_i915_set_bclk - Reprogram BCLK for HSW/BDW
@@ -109,7 +115,8 @@ static int i915_component_master_match(struct device *dev, int subcomponent,
hdac_pci = to_pci_dev(bus->dev);
i915_pci = to_pci_dev(dev);
- if (!strcmp(dev->driver->name, "i915") &&
+ if ((!strcmp(dev->driver->name, "i915") ||
+ !strcmp(dev->driver->name, "xe")) &&
subcomponent == I915_COMPONENT_AUDIO &&
connectivity_check(i915_pci, hdac_pci))
return 1;
@@ -122,6 +129,9 @@ static int i915_gfx_present(struct pci_dev *hdac_pci)
{
struct pci_dev *display_dev = NULL;
+ if (!gpu_bind || (gpu_bind < 0 && video_firmware_drivers_only()))
+ return false;
+
for_each_pci_dev(display_dev) {
if (display_dev->vendor == PCI_VENDOR_ID_INTEL &&
(display_dev->class >> 16) == PCI_BASE_CLASS_DISPLAY &&
@@ -163,17 +173,9 @@ int snd_hdac_i915_init(struct hdac_bus *bus)
if (!acomp)
return -ENODEV;
if (!acomp->ops) {
- if (!IS_ENABLED(CONFIG_MODULES) ||
- !request_module("i915")) {
- /* 60s timeout */
- wait_for_completion_killable_timeout(&acomp->master_bind_complete,
- msecs_to_jiffies(60 * 1000));
- }
- }
- if (!acomp->ops) {
- dev_info(bus->dev, "couldn't bind with audio component\n");
snd_hdac_acomp_exit(bus);
- return -ENODEV;
+ return dev_err_probe(bus->dev, -EPROBE_DEFER,
+ "couldn't bind with audio component\n");
}
return 0;
}
diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c
index 2633a4bb1d85..6ce24e248f8e 100644
--- a/sound/hda/hdac_stream.c
+++ b/sound/hda/hdac_stream.c
@@ -252,12 +252,15 @@ EXPORT_SYMBOL_GPL(snd_hdac_stream_reset);
/**
* snd_hdac_stream_setup - set up the SD for streaming
* @azx_dev: HD-audio core stream to set up
+ * @code_loading: Whether the stream is for PCM or code-loading.
*/
-int snd_hdac_stream_setup(struct hdac_stream *azx_dev)
+int snd_hdac_stream_setup(struct hdac_stream *azx_dev, bool code_loading)
{
struct hdac_bus *bus = azx_dev->bus;
struct snd_pcm_runtime *runtime;
unsigned int val;
+ u16 reg;
+ int ret;
if (azx_dev->substream)
runtime = azx_dev->substream->runtime;
@@ -300,7 +303,15 @@ int snd_hdac_stream_setup(struct hdac_stream *azx_dev)
/* set the interrupt enable bits in the descriptor control register */
snd_hdac_stream_updatel(azx_dev, SD_CTL, 0, SD_INT_MASK);
- azx_dev->fifo_size = snd_hdac_stream_readw(azx_dev, SD_FIFOSIZE) + 1;
+ if (!code_loading) {
+ /* Once SDxFMT is set, the controller programs SDxFIFOS to non-zero value. */
+ ret = snd_hdac_stream_readw_poll(azx_dev, SD_FIFOSIZE, reg,
+ reg & AZX_SD_FIFOSIZE_MASK, 3, 300);
+ if (ret)
+ dev_dbg(bus->dev, "polling SD_FIFOSIZE 0x%04x failed: %d\n",
+ AZX_REG_SD_FIFOSIZE, ret);
+ azx_dev->fifo_size = reg;
+ }
/* when LPIB delay correction gives a small negative value,
* we ignore it; currently set the threshold statically to
@@ -354,8 +365,10 @@ struct hdac_stream *snd_hdac_stream_assign(struct hdac_bus *bus,
struct hdac_stream *res = NULL;
/* make a non-zero unique key for the substream */
- int key = (substream->pcm->device << 16) | (substream->number << 2) |
- (substream->stream + 1);
+ int key = (substream->number << 2) | (substream->stream + 1);
+
+ if (substream->pcm)
+ key |= (substream->pcm->device << 16);
spin_lock_irq(&bus->reg_lock);
list_for_each_entry(azx_dev, &bus->stream_list, list) {
@@ -943,7 +956,7 @@ int snd_hdac_dsp_prepare(struct hdac_stream *azx_dev, unsigned int format,
if (err < 0)
goto error;
- snd_hdac_stream_setup(azx_dev);
+ snd_hdac_stream_setup(azx_dev, true);
snd_hdac_dsp_unlock(azx_dev);
return azx_dev->stream_tag;