Merge branch 'topic/hda-ca0132-dsp' into for-next
[~shefty/rdma-dev.git] / sound / pci / hda / hda_intel.c
index d9e37ffdb0486eb87164a787578ef5a927f063cd..4b099c603fe116d6416cc056f5bf0f243ef152fd 100644 (file)
@@ -1085,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)
 {
@@ -1408,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)
 {
@@ -1421,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);
@@ -1485,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;
@@ -1494,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)
@@ -1675,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)
@@ -2583,6 +2600,93 @@ 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 error;
+
+       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:
+       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);
+
+       /* 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;
+
+       snd_dma_free_pages(dmab);
+
+       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)