summaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_intel.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-02-21 11:34:25 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2013-02-21 11:34:25 -0800
commit460dc1eecf37263c8e3b17685ef236f0d236facb (patch)
tree1d20e367cefccddb969b48afaab140b8125cea4e /sound/pci/hda/hda_intel.c
parent024e4ec1856d57bb78c06ec903d29dcf716f5f47 (diff)
parentb531f81b0d70ffbe8d70500512483227cc532608 (diff)
Merge tag 'sound-3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai: "The biggest change in this update is the unification of HD-audio codec parsers. Now the HD-audio codec is parsed in a generic parser code which is invoked by each HD-audio codec driver. Some background information is found in David Henningsson's blog entry: http://voices.canonical.com/david.henningsson/2013/01/18/upcoming-changes-to-the-intel-hda-drivers/ Other than that, some random updates/fixes like USB-audio and a bunch of small AoC updates as usual. Highlights: - Unification of HD-audio parser code (aka generic parser) - Support of new Intel HD-audio controller, new IDT codecs - Fixes for HD-audio HDMI audio hotplug - Haswell HDMI audio fixup - Support of Creative CA0132 DSP code - A few fixes of HDSP driver - USB-audio fix for Roland A-PRO, M-Audio FT C600 - Support PM for aloop driver (and fixes Oops) - Compress API updates for gapless playback support For ASoC part: - Support for a wider range of hardware in the compressed stream code - The ability to mute capture streams as well as playback streams while inactive - DT support for AK4642, FSI, Samsung I2S and WM8962 - AC'97 support for Tegra - New driver for max98090, replacing the stub which was there - A new driver from Dialog Note that due to dependencies, DTification of DMA support for Samsung platforms (used only by the and I2S driver and SPI) is merged here as well." Fix up trivial conflict in drivers/spi/spi-s3c64xx.c due to removed code being changed. * tag 'sound-3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (453 commits) ALSA: usb: Fix Processing Unit Descriptor parsers ALSA: hda - hdmi: Notify userspace when ELD control changes ALSA: hda - hdmi: Protect ELD buffer ALSA: hda - hdmi: Refactor hdmi_eld into parsed_hdmi_eld ALSA: hda - hdmi: Do not expose eld data when eld is invalid ALSA: hda - hdmi: ELD shouldn't be valid after unplug ALSA: hda - Fix the silent speaker output on Fujitsu S7020 laptop ALSA: hda - add quirks for mute LED on two HP machines ALSA: usb/quirks, fix out-of-bounds access ASoC: codecs: Add da7213 codec ALSA: au88x0 - Define channel map for au88x0 ALSA: compress: add support for gapless playback ALSA: hda - Remove speaker clicks on CX20549 ALSA: hda - Disable runtime PM for Intel 5 Series/3400 ALSA: hda - Increase badness for missing multi-io ASoC: arizona: Automatically manage input mutes ALSA: hda - Fix broken workaround for HDMI/SPDIF conflicts ALSA: hda/ca0132 - Add missing \n to debug prints ALSA: hda/ca0132 - Fix type of INVALID_CHIP_ADDRESS ALSA: hda - update documentation for no-primary-hp fixup ...
Diffstat (limited to 'sound/pci/hda/hda_intel.c')
-rw-r--r--sound/pci/hda/hda_intel.c154
1 files changed, 143 insertions, 11 deletions
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index c78286f6e5d..4cea6bb6fad 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -134,8 +134,8 @@ MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
* this may give more power-saving, but will take longer time to
* wake up.
*/
-static bool power_save_controller = 1;
-module_param(power_save_controller, bool, 0644);
+static int power_save_controller = -1;
+module_param(power_save_controller, bint, 0644);
MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
#endif /* CONFIG_PM */
@@ -811,7 +811,7 @@ static int azx_corb_send_cmd(struct hda_bus *bus, u32 val)
{
struct azx *chip = bus->private_data;
unsigned int addr = azx_command_addr(val);
- unsigned int wp;
+ unsigned int wp, rp;
spin_lock_irq(&chip->reg_lock);
@@ -820,11 +820,18 @@ static int azx_corb_send_cmd(struct hda_bus *bus, u32 val)
if (wp == 0xffff) {
/* something wrong, controller likely turned to D3 */
spin_unlock_irq(&chip->reg_lock);
- return -1;
+ return -EIO;
}
wp++;
wp %= ICH6_MAX_CORB_ENTRIES;
+ rp = azx_readw(chip, CORBRP);
+ if (wp == rp) {
+ /* oops, it's full */
+ spin_unlock_irq(&chip->reg_lock);
+ return -EAGAIN;
+ }
+
chip->rirb.cmds[addr]++;
chip->corb.buf[wp] = cpu_to_le32(val);
azx_writel(chip, CORBWP, wp);
@@ -1078,6 +1085,15 @@ static unsigned int azx_get_response(struct hda_bus *bus,
static void azx_power_notify(struct hda_bus *bus, bool power_up);
#endif
+#ifdef CONFIG_SND_HDA_DSP_LOADER
+static int azx_load_dsp_prepare(struct hda_bus *bus, unsigned int format,
+ unsigned int byte_size,
+ struct snd_dma_buffer *bufp);
+static void azx_load_dsp_trigger(struct hda_bus *bus, bool start);
+static void azx_load_dsp_cleanup(struct hda_bus *bus,
+ struct snd_dma_buffer *dmab);
+#endif
+
/* reset codec link */
static int azx_reset(struct azx *chip, int full_reset)
{
@@ -1401,7 +1417,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
* set up a BDL entry
*/
static int setup_bdle(struct azx *chip,
- struct snd_pcm_substream *substream,
+ struct snd_dma_buffer *dmab,
struct azx_dev *azx_dev, u32 **bdlp,
int ofs, int size, int with_ioc)
{
@@ -1414,12 +1430,12 @@ static int setup_bdle(struct azx *chip,
if (azx_dev->frags >= AZX_MAX_BDL_ENTRIES)
return -EINVAL;
- addr = snd_pcm_sgbuf_get_addr(substream, ofs);
+ addr = snd_sgbuf_get_addr(dmab, ofs);
/* program the address field of the BDL entry */
bdl[0] = cpu_to_le32((u32)addr);
bdl[1] = cpu_to_le32(upper_32_bits(addr));
/* program the size field of the BDL entry */
- chunk = snd_pcm_sgbuf_get_chunk_size(substream, ofs, size);
+ chunk = snd_sgbuf_get_chunk_size(dmab, ofs, size);
/* one BDLE cannot cross 4K boundary on CTHDA chips */
if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY) {
u32 remain = 0x1000 - (ofs & 0xfff);
@@ -1478,7 +1494,8 @@ static int azx_setup_periods(struct azx *chip,
pci_name(chip->pci), bdl_pos_adj[chip->dev_index]);
pos_adj = 0;
} else {
- ofs = setup_bdle(chip, substream, azx_dev,
+ ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream),
+ azx_dev,
&bdl, ofs, pos_adj, true);
if (ofs < 0)
goto error;
@@ -1487,10 +1504,12 @@ static int azx_setup_periods(struct azx *chip,
pos_adj = 0;
for (i = 0; i < periods; i++) {
if (i == periods - 1 && pos_adj)
- ofs = setup_bdle(chip, substream, azx_dev, &bdl, ofs,
+ ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream),
+ azx_dev, &bdl, ofs,
period_bytes - pos_adj, 0);
else
- ofs = setup_bdle(chip, substream, azx_dev, &bdl, ofs,
+ ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream),
+ azx_dev, &bdl, ofs,
period_bytes,
!azx_dev->no_period_wakeup);
if (ofs < 0)
@@ -1668,6 +1687,11 @@ static int azx_codec_create(struct azx *chip, const char *model)
bus_temp.power_save = &power_save;
bus_temp.ops.pm_notify = azx_power_notify;
#endif
+#ifdef CONFIG_SND_HDA_DSP_LOADER
+ bus_temp.ops.load_dsp_prepare = azx_load_dsp_prepare;
+ bus_temp.ops.load_dsp_trigger = azx_load_dsp_trigger;
+ bus_temp.ops.load_dsp_cleanup = azx_load_dsp_cleanup;
+#endif
err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus);
if (err < 0)
@@ -2576,6 +2600,102 @@ static void azx_stop_chip(struct azx *chip)
chip->initialized = 0;
}
+#ifdef CONFIG_SND_HDA_DSP_LOADER
+/*
+ * DSP loading code (e.g. for CA0132)
+ */
+
+/* use the first stream for loading DSP */
+static struct azx_dev *
+azx_get_dsp_loader_dev(struct azx *chip)
+{
+ return &chip->azx_dev[chip->playback_index_offset];
+}
+
+static int azx_load_dsp_prepare(struct hda_bus *bus, unsigned int format,
+ unsigned int byte_size,
+ struct snd_dma_buffer *bufp)
+{
+ u32 *bdl;
+ struct azx *chip = bus->private_data;
+ struct azx_dev *azx_dev;
+ int err;
+
+ if (snd_hda_lock_devices(bus))
+ return -EBUSY;
+
+ err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG,
+ snd_dma_pci_data(chip->pci),
+ byte_size, bufp);
+ if (err < 0)
+ goto unlock;
+
+ mark_pages_wc(chip, bufp, true);
+ azx_dev = azx_get_dsp_loader_dev(chip);
+ azx_dev->bufsize = byte_size;
+ azx_dev->period_bytes = byte_size;
+ azx_dev->format_val = format;
+
+ azx_stream_reset(chip, azx_dev);
+
+ /* reset BDL address */
+ azx_sd_writel(azx_dev, SD_BDLPL, 0);
+ azx_sd_writel(azx_dev, SD_BDLPU, 0);
+
+ azx_dev->frags = 0;
+ bdl = (u32 *)azx_dev->bdl.area;
+ err = setup_bdle(chip, bufp, azx_dev, &bdl, 0, byte_size, 0);
+ if (err < 0)
+ goto error;
+
+ azx_setup_controller(chip, azx_dev);
+ return azx_dev->stream_tag;
+
+ error:
+ mark_pages_wc(chip, bufp, false);
+ snd_dma_free_pages(bufp);
+unlock:
+ snd_hda_unlock_devices(bus);
+ return err;
+}
+
+static void azx_load_dsp_trigger(struct hda_bus *bus, bool start)
+{
+ struct azx *chip = bus->private_data;
+ struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip);
+
+ if (start)
+ azx_stream_start(chip, azx_dev);
+ else
+ azx_stream_stop(chip, azx_dev);
+ azx_dev->running = start;
+}
+
+static void azx_load_dsp_cleanup(struct hda_bus *bus,
+ struct snd_dma_buffer *dmab)
+{
+ struct azx *chip = bus->private_data;
+ struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip);
+
+ if (!dmab->area)
+ return;
+
+ /* reset BDL address */
+ azx_sd_writel(azx_dev, SD_BDLPL, 0);
+ azx_sd_writel(azx_dev, SD_BDLPU, 0);
+ azx_sd_writel(azx_dev, SD_CTL, 0);
+ azx_dev->bufsize = 0;
+ azx_dev->period_bytes = 0;
+ azx_dev->format_val = 0;
+
+ mark_pages_wc(chip, dmab, false);
+ snd_dma_free_pages(dmab);
+ dmab->area = NULL;
+
+ snd_hda_unlock_devices(bus);
+}
+#endif /* CONFIG_SND_HDA_DSP_LOADER */
+
#ifdef CONFIG_PM
/* power-up/down the controller */
static void azx_power_notify(struct hda_bus *bus, bool power_up)
@@ -2726,6 +2846,8 @@ static int azx_runtime_idle(struct device *dev)
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip = card->private_data;
+ if (power_save_controller > 0)
+ return 0;
if (!power_save_controller ||
!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
return -EBUSY;
@@ -3150,6 +3272,9 @@ static void azx_check_snoop_available(struct azx *chip)
/* new ATI HDMI requires non-snoop */
snoop = false;
break;
+ case AZX_DRIVER_CTHDA:
+ snoop = false;
+ break;
}
if (snoop != chip->snoop) {
@@ -3611,6 +3736,11 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
/* Lynx Point */
{ PCI_DEVICE(0x8086, 0x8c20),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+ /* Wellsburg */
+ { PCI_DEVICE(0x8086, 0x8d20),
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+ { PCI_DEVICE(0x8086, 0x8d21),
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
/* Lynx Point-LP */
{ PCI_DEVICE(0x8086, 0x9c20),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
@@ -3618,13 +3748,15 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
{ PCI_DEVICE(0x8086, 0x9c21),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
/* Haswell */
+ { PCI_DEVICE(0x8086, 0x0a0c),
+ .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH },
{ PCI_DEVICE(0x8086, 0x0c0c),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH },
{ PCI_DEVICE(0x8086, 0x0d0c),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH },
/* 5 Series/3400 */
{ PCI_DEVICE(0x8086, 0x3b56),
- .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH },
+ .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },
/* Poulsbo */
{ PCI_DEVICE(0x8086, 0x811b),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },