sound/soc/loongson/loongson_dma.c

Source file repositories/reference/linux-study-clean/sound/soc/loongson/loongson_dma.c

File Facts

System
Linux kernel
Corpus path
sound/soc/loongson/loongson_dma.c
Extension
.c
Size
12110 bytes
Lines
414
Domain
Driver Families
Bucket
sound/soc
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct loongson_idma_desc {
	u32 order;		/* Next descriptor address register */
	u32 saddr;		/* Source address register */
	u32 daddr;		/* Device address register */
	u32 length;		/* Total length register */
	u32 step_length;	/* Memory stride register */
	u32 step_times;		/* Repeat time register */
	u32 cmd;		/* Command register */
	u32 stats;		/* Status register */
	u32 order_hi;		/* Next descriptor high address register */
	u32 saddr_hi;		/* High source address register */
	u32 res[6];		/* Reserved */
} __packed;

struct loongson_runtime_data {
	struct loongson_idma_data *dma_data;

	struct loongson_idma_desc *dma_desc_arr;
	dma_addr_t dma_desc_arr_phy;
	int dma_desc_arr_size;

	struct loongson_idma_desc *dma_pos_desc;
	dma_addr_t dma_pos_desc_phy;
};

static const struct snd_pcm_hardware loongson_idma_hardware = {
	.info = SNDRV_PCM_INFO_MMAP |
		SNDRV_PCM_INFO_INTERLEAVED |
		SNDRV_PCM_INFO_MMAP_VALID |
		SNDRV_PCM_INFO_RESUME |
		SNDRV_PCM_INFO_PAUSE,
	.formats = (SNDRV_PCM_FMTBIT_S8 |
		SNDRV_PCM_FMTBIT_S16_LE |
		SNDRV_PCM_FMTBIT_S20_3LE |
		SNDRV_PCM_FMTBIT_S24_LE),
	.period_bytes_min = 128,
	.period_bytes_max = 128 * 1024,
	.periods_min = 1,
	.periods_max = PAGE_SIZE / sizeof(struct loongson_idma_desc),
	.buffer_bytes_max = 1024 * 1024,
};

static struct loongson_idma_desc *dma_desc_save(struct loongson_runtime_data *prtd)
{
	void __iomem *order_reg = prtd->dma_data->order_addr;
	u64 val;

	val = (u64)prtd->dma_pos_desc_phy & DMA_ORDER_ASK_MASK;
	val |= (readq(order_reg) & DMA_ORDER_CTRL_MASK);
	val |= DMA_ORDER_ASK_VALID;
	writeq(val, order_reg);

	while (readl(order_reg) & DMA_ORDER_ASK_VALID)
		udelay(2);

	return prtd->dma_pos_desc;
}

static int loongson_idma_pcm_trigger(struct snd_soc_component *component,
				     struct snd_pcm_substream *substream, int cmd)
{
	struct loongson_runtime_data *prtd = substream->runtime->private_data;
	struct device *dev = substream->pcm->card->dev;
	void __iomem *order_reg = prtd->dma_data->order_addr;
	u64 val;

	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_RESUME:
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
		val = prtd->dma_pos_desc_phy & DMA_ORDER_ASK_MASK;
		if (dev->coherent_dma_mask == DMA_BIT_MASK(64))
			val |= DMA_ORDER_ADDR_64;
		else
			val &= ~DMA_ORDER_ADDR_64;
		val |= (readq(order_reg) & DMA_ORDER_CTRL_MASK);
		val |= DMA_ORDER_START;
		writeq(val, order_reg);

		while ((readl(order_reg) & DMA_ORDER_START))
			udelay(2);
		break;
	case SNDRV_PCM_TRIGGER_STOP:
	case SNDRV_PCM_TRIGGER_SUSPEND:
	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
		dma_desc_save(prtd);

		/* dma stop */
		val = readq(order_reg) | DMA_ORDER_STOP;
		writeq(val, order_reg);

Annotation

Implementation Notes