Commit 45acc86b authored by Takashi Iwai's avatar Takashi Iwai

Merge branch 'topic/hda-ca0132-dsp' into for-next

parents 0186f4f4 24f3cede
...@@ -15,6 +15,9 @@ menuconfig SND_HDA_INTEL ...@@ -15,6 +15,9 @@ menuconfig SND_HDA_INTEL
if SND_HDA_INTEL if SND_HDA_INTEL
config SND_HDA_DSP_LOADER
bool
config SND_HDA_PREALLOC_SIZE config SND_HDA_PREALLOC_SIZE
int "Pre-allocated buffer size for HD-audio driver" int "Pre-allocated buffer size for HD-audio driver"
range 0 32768 range 0 32768
...@@ -200,6 +203,17 @@ config SND_HDA_CODEC_CA0132 ...@@ -200,6 +203,17 @@ config SND_HDA_CODEC_CA0132
snd-hda-codec-ca0132. snd-hda-codec-ca0132.
This module is automatically loaded at probing. This module is automatically loaded at probing.
config SND_HDA_CODEC_CA0132_DSP
bool "Support new DSP code for CA0132 codec"
depends on SND_HDA_CODEC_CA0132 && FW_LOADER
select SND_HDA_DSP_LOADER
help
Say Y here to enable the DSP for Creative CA0132 for extended
features like equalizer or echo cancellation.
Note that this option requires the external firmware file
(ctefx.bin).
config SND_HDA_CODEC_CMEDIA config SND_HDA_CODEC_CMEDIA
bool "Build C-Media HD-audio codec support" bool "Build C-Media HD-audio codec support"
default y default y
......
This diff is collapsed.
...@@ -618,6 +618,17 @@ struct hda_bus_ops { ...@@ -618,6 +618,17 @@ struct hda_bus_ops {
/* notify power-up/down from codec to controller */ /* notify power-up/down from codec to controller */
void (*pm_notify)(struct hda_bus *bus, bool power_up); void (*pm_notify)(struct hda_bus *bus, bool power_up);
#endif #endif
#ifdef CONFIG_SND_HDA_DSP_LOADER
/* prepare DSP transfer */
int (*load_dsp_prepare)(struct hda_bus *bus, unsigned int format,
unsigned int byte_size,
struct snd_dma_buffer *bufp);
/* start/stop DSP transfer */
void (*load_dsp_trigger)(struct hda_bus *bus, bool start);
/* clean up DSP transfer */
void (*load_dsp_cleanup)(struct hda_bus *bus,
struct snd_dma_buffer *dmab);
#endif
}; };
/* template to pass to the bus constructor */ /* template to pass to the bus constructor */
...@@ -1150,6 +1161,40 @@ static inline void snd_hda_power_sync(struct hda_codec *codec) ...@@ -1150,6 +1161,40 @@ static inline void snd_hda_power_sync(struct hda_codec *codec)
int snd_hda_load_patch(struct hda_bus *bus, size_t size, const void *buf); int snd_hda_load_patch(struct hda_bus *bus, size_t size, const void *buf);
#endif #endif
#ifdef CONFIG_SND_HDA_DSP_LOADER
static inline int
snd_hda_codec_load_dsp_prepare(struct hda_codec *codec, unsigned int format,
unsigned int size,
struct snd_dma_buffer *bufp)
{
return codec->bus->ops.load_dsp_prepare(codec->bus, format, size, bufp);
}
static inline void
snd_hda_codec_load_dsp_trigger(struct hda_codec *codec, bool start)
{
return codec->bus->ops.load_dsp_trigger(codec->bus, start);
}
static inline void
snd_hda_codec_load_dsp_cleanup(struct hda_codec *codec,
struct snd_dma_buffer *dmab)
{
return codec->bus->ops.load_dsp_cleanup(codec->bus, dmab);
}
#else
static inline int
snd_hda_codec_load_dsp_prepare(struct hda_codec *codec, unsigned int format,
unsigned int size,
struct snd_dma_buffer *bufp)
{
return -ENOSYS;
}
static inline void
snd_hda_codec_load_dsp_trigger(struct hda_codec *codec, bool start) {}
static inline void
snd_hda_codec_load_dsp_cleanup(struct hda_codec *codec,
struct snd_dma_buffer *dmab) {}
#endif
/* /*
* Codec modularization * Codec modularization
*/ */
......
...@@ -1085,6 +1085,15 @@ static unsigned int azx_get_response(struct hda_bus *bus, ...@@ -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); static void azx_power_notify(struct hda_bus *bus, bool power_up);
#endif #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 */ /* reset codec link */
static int azx_reset(struct azx *chip, int full_reset) static int azx_reset(struct azx *chip, int full_reset)
{ {
...@@ -1408,7 +1417,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) ...@@ -1408,7 +1417,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
* set up a BDL entry * set up a BDL entry
*/ */
static int setup_bdle(struct azx *chip, static int setup_bdle(struct azx *chip,
struct snd_pcm_substream *substream, struct snd_dma_buffer *dmab,
struct azx_dev *azx_dev, u32 **bdlp, struct azx_dev *azx_dev, u32 **bdlp,
int ofs, int size, int with_ioc) int ofs, int size, int with_ioc)
{ {
...@@ -1421,12 +1430,12 @@ static int setup_bdle(struct azx *chip, ...@@ -1421,12 +1430,12 @@ static int setup_bdle(struct azx *chip,
if (azx_dev->frags >= AZX_MAX_BDL_ENTRIES) if (azx_dev->frags >= AZX_MAX_BDL_ENTRIES)
return -EINVAL; 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 */ /* program the address field of the BDL entry */
bdl[0] = cpu_to_le32((u32)addr); bdl[0] = cpu_to_le32((u32)addr);
bdl[1] = cpu_to_le32(upper_32_bits(addr)); bdl[1] = cpu_to_le32(upper_32_bits(addr));
/* program the size field of the BDL entry */ /* 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 */ /* one BDLE cannot cross 4K boundary on CTHDA chips */
if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY) { if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY) {
u32 remain = 0x1000 - (ofs & 0xfff); u32 remain = 0x1000 - (ofs & 0xfff);
...@@ -1485,7 +1494,8 @@ static int azx_setup_periods(struct azx *chip, ...@@ -1485,7 +1494,8 @@ static int azx_setup_periods(struct azx *chip,
pci_name(chip->pci), bdl_pos_adj[chip->dev_index]); pci_name(chip->pci), bdl_pos_adj[chip->dev_index]);
pos_adj = 0; pos_adj = 0;
} else { } 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); &bdl, ofs, pos_adj, true);
if (ofs < 0) if (ofs < 0)
goto error; goto error;
...@@ -1494,10 +1504,12 @@ static int azx_setup_periods(struct azx *chip, ...@@ -1494,10 +1504,12 @@ static int azx_setup_periods(struct azx *chip,
pos_adj = 0; pos_adj = 0;
for (i = 0; i < periods; i++) { for (i = 0; i < periods; i++) {
if (i == periods - 1 && pos_adj) 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); period_bytes - pos_adj, 0);
else 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, period_bytes,
!azx_dev->no_period_wakeup); !azx_dev->no_period_wakeup);
if (ofs < 0) if (ofs < 0)
...@@ -1675,6 +1687,11 @@ static int azx_codec_create(struct azx *chip, const char *model) ...@@ -1675,6 +1687,11 @@ static int azx_codec_create(struct azx *chip, const char *model)
bus_temp.power_save = &power_save; bus_temp.power_save = &power_save;
bus_temp.ops.pm_notify = azx_power_notify; bus_temp.ops.pm_notify = azx_power_notify;
#endif #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); err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus);
if (err < 0) if (err < 0)
...@@ -2583,6 +2600,93 @@ static void azx_stop_chip(struct azx *chip) ...@@ -2583,6 +2600,93 @@ static void azx_stop_chip(struct azx *chip)
chip->initialized = 0; 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 #ifdef CONFIG_PM
/* power-up/down the controller */ /* power-up/down the controller */
static void azx_power_notify(struct hda_bus *bus, bool power_up) static void azx_power_notify(struct hda_bus *bus, bool power_up)
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment