Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+46 −0
Original line number Diff line number Diff line
@@ -187,6 +187,11 @@ struct hdac_io_ops {
	u16 (*reg_readw)(u16 __iomem *addr);
	void (*reg_writeb)(u8 value, 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
@@ -374,6 +379,7 @@ struct hdac_stream {
	bool opened:1;
	bool running:1;
	bool no_period_wakeup:1;
	bool locked:1;

	/* timestamp */
	unsigned long start_wallclk;	/* start + minimum wallclk */
@@ -383,6 +389,10 @@ struct hdac_stream {
	int delay_negative_threshold;

	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,
@@ -440,6 +450,42 @@ void snd_hdac_stream_timecounter_init(struct hdac_stream *azx_dev,
			       (snd_hdac_stream_readb(dev, reg) & \
				~(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
 */
+3 −0
Original line number Diff line number Diff line
config SND_HDA_CORE
	tristate
	select REGMAP

config SND_HDA_DSP_LOADER
	bool
+113 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ void snd_hdac_stream_init(struct hdac_bus *bus, struct hdac_stream *azx_dev,
	azx_dev->index = idx;
	azx_dev->direction = direction;
	azx_dev->stream_tag = tag;
	snd_hdac_dsp_lock_init(azx_dev);
	list_add_tail(&azx_dev->list, &bus->stream_list);
}
EXPORT_SYMBOL_GPL(snd_hdac_stream_init);
@@ -534,3 +535,115 @@ void snd_hdac_stream_sync(struct hdac_stream *azx_dev, bool start,
	}
}
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 */
+0 −3
Original line number Diff line number Diff line
@@ -38,9 +38,6 @@ config SND_HDA_TEGRA

if SND_HDA

config SND_HDA_DSP_LOADER
	bool

config SND_HDA_PREALLOC_SIZE
	int "Pre-allocated buffer size for HD-audio driver"
	range 0 32768