Commit 8f3f600b authored by Takashi Iwai's avatar Takashi Iwai

ALSA: hda - Add DSP loader to core library code

Copied from the legacy driver code, no transition done yet.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 14752412
...@@ -187,6 +187,11 @@ struct hdac_io_ops { ...@@ -187,6 +187,11 @@ struct hdac_io_ops {
u16 (*reg_readw)(u16 __iomem *addr); u16 (*reg_readw)(u16 __iomem *addr);
void (*reg_writeb)(u8 value, u8 __iomem *addr); void (*reg_writeb)(u8 value, u8 __iomem *addr);
u8 (*reg_readb)(u8 __iomem *addr); u8 (*reg_readb)(u8 __iomem *addr);
/* Allocation ops */
int (*dma_alloc_pages)(struct hdac_bus *bus, int type, size_t size,
struct snd_dma_buffer *buf);
void (*dma_free_pages)(struct hdac_bus *bus,
struct snd_dma_buffer *buf);
}; };
#define HDA_UNSOL_QUEUE_SIZE 64 #define HDA_UNSOL_QUEUE_SIZE 64
...@@ -374,6 +379,7 @@ struct hdac_stream { ...@@ -374,6 +379,7 @@ struct hdac_stream {
bool opened:1; bool opened:1;
bool running:1; bool running:1;
bool no_period_wakeup:1; bool no_period_wakeup:1;
bool locked:1;
/* timestamp */ /* timestamp */
unsigned long start_wallclk; /* start + minimum wallclk */ unsigned long start_wallclk; /* start + minimum wallclk */
...@@ -383,6 +389,10 @@ struct hdac_stream { ...@@ -383,6 +389,10 @@ struct hdac_stream {
int delay_negative_threshold; int delay_negative_threshold;
struct list_head list; struct list_head list;
#ifdef CONFIG_SND_HDA_DSP_LOADER
/* DSP access mutex */
struct mutex dsp_mutex;
#endif
}; };
void snd_hdac_stream_init(struct hdac_bus *bus, struct hdac_stream *azx_dev, void snd_hdac_stream_init(struct hdac_bus *bus, struct hdac_stream *azx_dev,
...@@ -440,6 +450,42 @@ void snd_hdac_stream_timecounter_init(struct hdac_stream *azx_dev, ...@@ -440,6 +450,42 @@ void snd_hdac_stream_timecounter_init(struct hdac_stream *azx_dev,
(snd_hdac_stream_readb(dev, reg) & \ (snd_hdac_stream_readb(dev, reg) & \
~(mask)) | (val)) ~(mask)) | (val))
#ifdef CONFIG_SND_HDA_DSP_LOADER
/* DSP lock helpers */
#define snd_hdac_dsp_lock_init(dev) mutex_init(&(dev)->dsp_mutex)
#define snd_hdac_dsp_lock(dev) mutex_lock(&(dev)->dsp_mutex)
#define snd_hdac_dsp_unlock(dev) mutex_unlock(&(dev)->dsp_mutex)
#define snd_hdac_stream_is_locked(dev) ((dev)->locked)
/* DSP loader helpers */
int snd_hdac_dsp_prepare(struct hdac_stream *azx_dev, unsigned int format,
unsigned int byte_size, struct snd_dma_buffer *bufp);
void snd_hdac_dsp_trigger(struct hdac_stream *azx_dev, bool start);
void snd_hdac_dsp_cleanup(struct hdac_stream *azx_dev,
struct snd_dma_buffer *dmab);
#else /* CONFIG_SND_HDA_DSP_LOADER */
#define snd_hdac_dsp_lock_init(dev) do {} while (0)
#define snd_hdac_dsp_lock(dev) do {} while (0)
#define snd_hdac_dsp_unlock(dev) do {} while (0)
#define snd_hdac_stream_is_locked(dev) 0
static inline int
snd_hdac_dsp_prepare(struct hdac_stream *azx_dev, unsigned int format,
unsigned int byte_size, struct snd_dma_buffer *bufp)
{
return 0;
}
static inline void snd_hdac_dsp_trigger(struct hdac_stream *azx_dev, bool start)
{
}
static inline void snd_hdac_dsp_cleanup(struct hdac_stream *azx_dev,
struct snd_dma_buffer *dmab)
{
}
#endif /* CONFIG_SND_HDA_DSP_LOADER */
/* /*
* generic array helpers * generic array helpers
*/ */
......
config SND_HDA_CORE config SND_HDA_CORE
tristate tristate
select REGMAP select REGMAP
config SND_HDA_DSP_LOADER
bool
...@@ -33,6 +33,7 @@ void snd_hdac_stream_init(struct hdac_bus *bus, struct hdac_stream *azx_dev, ...@@ -33,6 +33,7 @@ void snd_hdac_stream_init(struct hdac_bus *bus, struct hdac_stream *azx_dev,
azx_dev->index = idx; azx_dev->index = idx;
azx_dev->direction = direction; azx_dev->direction = direction;
azx_dev->stream_tag = tag; azx_dev->stream_tag = tag;
snd_hdac_dsp_lock_init(azx_dev);
list_add_tail(&azx_dev->list, &bus->stream_list); list_add_tail(&azx_dev->list, &bus->stream_list);
} }
EXPORT_SYMBOL_GPL(snd_hdac_stream_init); EXPORT_SYMBOL_GPL(snd_hdac_stream_init);
...@@ -534,3 +535,115 @@ void snd_hdac_stream_sync(struct hdac_stream *azx_dev, bool start, ...@@ -534,3 +535,115 @@ void snd_hdac_stream_sync(struct hdac_stream *azx_dev, bool start,
} }
} }
EXPORT_SYMBOL_GPL(snd_hdac_stream_sync); EXPORT_SYMBOL_GPL(snd_hdac_stream_sync);
#ifdef CONFIG_SND_HDA_DSP_LOADER
/**
* snd_hdac_dsp_prepare - prepare for DSP loading
* @azx_dev: HD-audio core stream used for DSP loading
* @format: HD-audio stream format
* @byte_size: data chunk byte size
* @bufp: allocated buffer
*
* Allocate the buffer for the given size and set up the given stream for
* DSP loading. Returns the stream tag (>= 0), or a negative error code.
*/
int snd_hdac_dsp_prepare(struct hdac_stream *azx_dev, unsigned int format,
unsigned int byte_size, struct snd_dma_buffer *bufp)
{
struct hdac_bus *bus = azx_dev->bus;
u32 *bdl;
int err;
snd_hdac_dsp_lock(azx_dev);
spin_lock_irq(&bus->reg_lock);
if (azx_dev->running || azx_dev->locked) {
spin_unlock_irq(&bus->reg_lock);
err = -EBUSY;
goto unlock;
}
azx_dev->locked = true;
spin_unlock_irq(&bus->reg_lock);
err = bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV_SG,
byte_size, bufp);
if (err < 0)
goto err_alloc;
azx_dev->bufsize = byte_size;
azx_dev->period_bytes = byte_size;
azx_dev->format_val = format;
snd_hdac_stream_reset(azx_dev);
/* reset BDL address */
snd_hdac_stream_writel(azx_dev, SD_BDLPL, 0);
snd_hdac_stream_writel(azx_dev, SD_BDLPU, 0);
azx_dev->frags = 0;
bdl = (u32 *)azx_dev->bdl.area;
err = setup_bdle(bus, bufp, azx_dev, &bdl, 0, byte_size, 0);
if (err < 0)
goto error;
snd_hdac_stream_setup(azx_dev);
snd_hdac_dsp_unlock(azx_dev);
return azx_dev->stream_tag;
error:
bus->io_ops->dma_free_pages(bus, bufp);
err_alloc:
spin_lock_irq(&bus->reg_lock);
azx_dev->locked = false;
spin_unlock_irq(&bus->reg_lock);
unlock:
snd_hdac_dsp_unlock(azx_dev);
return err;
}
EXPORT_SYMBOL_GPL(snd_hdac_dsp_prepare);
/**
* snd_hdac_dsp_trigger - start / stop DSP loading
* @azx_dev: HD-audio core stream used for DSP loading
* @start: trigger start or stop
*/
void snd_hdac_dsp_trigger(struct hdac_stream *azx_dev, bool start)
{
if (start)
snd_hdac_stream_start(azx_dev, true);
else
snd_hdac_stream_stop(azx_dev);
}
EXPORT_SYMBOL_GPL(snd_hdac_dsp_trigger);
/**
* snd_hdac_dsp_cleanup - clean up the stream from DSP loading to normal
* @azx_dev: HD-audio core stream used for DSP loading
* @dmab: buffer used by DSP loading
*/
void snd_hdac_dsp_cleanup(struct hdac_stream *azx_dev,
struct snd_dma_buffer *dmab)
{
struct hdac_bus *bus = azx_dev->bus;
if (!dmab->area || !azx_dev->locked)
return;
snd_hdac_dsp_lock(azx_dev);
/* reset BDL address */
snd_hdac_stream_writel(azx_dev, SD_BDLPL, 0);
snd_hdac_stream_writel(azx_dev, SD_BDLPU, 0);
snd_hdac_stream_writel(azx_dev, SD_CTL, 0);
azx_dev->bufsize = 0;
azx_dev->period_bytes = 0;
azx_dev->format_val = 0;
bus->io_ops->dma_free_pages(bus, dmab);
dmab->area = NULL;
spin_lock_irq(&bus->reg_lock);
azx_dev->locked = false;
spin_unlock_irq(&bus->reg_lock);
snd_hdac_dsp_unlock(azx_dev);
}
EXPORT_SYMBOL_GPL(snd_hdac_dsp_cleanup);
#endif /* CONFIG_SND_HDA_DSP_LOADER */
...@@ -38,9 +38,6 @@ config SND_HDA_TEGRA ...@@ -38,9 +38,6 @@ config SND_HDA_TEGRA
if SND_HDA if SND_HDA
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
......
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