summaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_ca0132.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda/patch_ca0132.c')
-rw-r--r--sound/pci/hda/patch_ca0132.c119
1 files changed, 119 insertions, 0 deletions
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index f9fafd0f725b..c3ae9e4f715b 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -1863,6 +1863,18 @@ static void chipio_set_stream_control(struct hda_codec *codec,
CONTROL_PARAM_STREAM_CONTROL, enable);
}
+/*
+ * Get ChipIO audio stream's status.
+ */
+static void chipio_get_stream_control(struct hda_codec *codec,
+ int streamid, unsigned int *enable)
+{
+ chipio_set_control_param_no_mutex(codec,
+ CONTROL_PARAM_STREAM_ID, streamid);
+ *enable = snd_hda_codec_read(codec, WIDGET_CHIP_CTRL, 0,
+ VENDOR_CHIPIO_PARAM_GET,
+ CONTROL_PARAM_STREAM_CONTROL);
+}
/*
* Set sampling rate of the connection point. NO MUTEX.
@@ -7513,6 +7525,109 @@ static void ca0132_refresh_widget_caps(struct hda_codec *codec)
}
}
+
+/* If there is an active channel for some reason, find it and free it. */
+static void ca0132_alt_free_active_dma_channels(struct hda_codec *codec)
+{
+ unsigned int i, tmp;
+ int status;
+
+ /* Read active DSPDMAC channel register. */
+ status = chipio_read(codec, DSPDMAC_CHNLSTART_MODULE_OFFSET, &tmp);
+ if (status >= 0) {
+ /* AND against 0xfff to get the active channel bits. */
+ tmp = tmp & 0xfff;
+
+ /* If there are no active channels, nothing to free. */
+ if (!tmp)
+ return;
+ } else {
+ codec_dbg(codec, "%s: Failed to read active DSP DMA channel register.\n",
+ __func__);
+ return;
+ }
+
+ /*
+ * Check each DSP DMA channel for activity, and if the channel is
+ * active, free it.
+ */
+ for (i = 0; i < DSPDMAC_DMA_CFG_CHANNEL_COUNT; i++) {
+ if (dsp_is_dma_active(codec, i)) {
+ status = dspio_free_dma_chan(codec, i);
+ if (status < 0)
+ codec_dbg(codec, "%s: Failed to free active DSP DMA channel %d.\n",
+ __func__, i);
+ }
+ }
+}
+
+/*
+ * In the case of CT_EXTENSIONS_ENABLE being set to 1, and the DSP being in
+ * use, audio is no longer routed directly to the DAC/ADC from the HDA stream.
+ * Instead, audio is now routed through the DSP's DMA controllers, which
+ * the DSP is tasked with setting up itself. Through debugging, it seems the
+ * cause of most of the no-audio on startup issues were due to improperly
+ * configured DSP DMA channels.
+ *
+ * Normally, the DSP configures these the first time an HDA audio stream is
+ * started post DSP firmware download. That is why creating a 'dummy' stream
+ * worked in fixing the audio in some cases. This works most of the time, but
+ * sometimes if a stream is started/stopped before the DSP can setup the DMA
+ * configuration registers, it ends up in a broken state. Issues can also
+ * arise if streams are started in an unusual order, i.e the audio output dma
+ * channel being sandwiched between the mic1 and mic2 dma channels.
+ *
+ * The solution to this is to make sure that the DSP has no DMA channels
+ * in use post DSP firmware download, and then to manually start each default
+ * DSP stream that uses the DMA channels. These are 0x0c, the audio output
+ * stream, 0x03, analog mic 1, and 0x04, analog mic 2.
+ */
+static void ca0132_alt_start_dsp_audio_streams(struct hda_codec *codec)
+{
+ const unsigned int dsp_dma_stream_ids[] = { 0x0c, 0x03, 0x04 };
+ struct ca0132_spec *spec = codec->spec;
+ unsigned int i, tmp;
+
+ /*
+ * Check if any of the default streams are active, and if they are,
+ * stop them.
+ */
+ mutex_lock(&spec->chipio_mutex);
+
+ for (i = 0; i < ARRAY_SIZE(dsp_dma_stream_ids); i++) {
+ chipio_get_stream_control(codec, dsp_dma_stream_ids[i], &tmp);
+
+ if (tmp) {
+ chipio_set_stream_control(codec,
+ dsp_dma_stream_ids[i], 0);
+ }
+ }
+
+ mutex_unlock(&spec->chipio_mutex);
+
+ /*
+ * If all DSP streams are inactive, there should be no active DSP DMA
+ * channels. Check and make sure this is the case, and if it isn't,
+ * free any active channels.
+ */
+ ca0132_alt_free_active_dma_channels(codec);
+
+ mutex_lock(&spec->chipio_mutex);
+
+ /* Make sure stream 0x0c is six channels. */
+ chipio_set_stream_channels(codec, 0x0c, 6);
+
+ for (i = 0; i < ARRAY_SIZE(dsp_dma_stream_ids); i++) {
+ chipio_set_stream_control(codec,
+ dsp_dma_stream_ids[i], 1);
+
+ /* Give the DSP some time to setup the DMA channel. */
+ msleep(75);
+ }
+
+ mutex_unlock(&spec->chipio_mutex);
+}
+
/*
* The region of ChipIO memory from 0x190000-0x1903fc is a sort of 'audio
* router', where each entry represents a 48khz audio channel, with a format
@@ -8250,6 +8365,7 @@ static void r3d_setup_defaults(struct hda_codec *codec)
ca0132_alt_dsp_scp_startup(codec);
ca0132_alt_init_analog_mics(codec);
+ ca0132_alt_start_dsp_audio_streams(codec);
/*remove DSP headroom*/
tmp = FLOAT_ZERO;
@@ -8300,6 +8416,7 @@ static void sbz_setup_defaults(struct hda_codec *codec)
ca0132_alt_dsp_scp_startup(codec);
ca0132_alt_init_analog_mics(codec);
+ ca0132_alt_start_dsp_audio_streams(codec);
sbz_connect_streams(codec);
sbz_chipio_startup_data(codec);
@@ -8359,6 +8476,7 @@ static void ae5_setup_defaults(struct hda_codec *codec)
ca0132_alt_dsp_scp_startup(codec);
ca0132_alt_init_analog_mics(codec);
+ ca0132_alt_start_dsp_audio_streams(codec);
chipio_set_stream_control(codec, 0x03, 1);
chipio_set_stream_control(codec, 0x04, 1);
@@ -8428,6 +8546,7 @@ static void ae7_setup_defaults(struct hda_codec *codec)
ca0132_alt_dsp_scp_startup(codec);
ca0132_alt_init_analog_mics(codec);
+ ca0132_alt_start_dsp_audio_streams(codec);
ae7_post_dsp_setup_ports(codec);
tmp = FLOAT_ZERO;