|
@@ -1038,6 +1038,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)
|
|
|
{
|
|
@@ -1359,7 +1368,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)
|
|
|
{
|
|
@@ -1372,12 +1381,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);
|
|
@@ -1436,7 +1445,8 @@ static int azx_setup_periods(struct azx *chip,
|
|
|
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;
|
|
@@ -1445,10 +1455,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)
|
|
@@ -1610,6 +1622,11 @@ static int DELAYED_INIT_MARK azx_codec_create(struct azx *chip, const char *mode
|
|
|
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)
|
|
@@ -2427,6 +2444,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)
|