drivers/dma/dw-edma/dw-edma-v0-core.c

Source file repositories/reference/linux-study-clean/drivers/dma/dw-edma/dw-edma-v0-core.c

File Facts

System
Linux kernel
Corpus path
drivers/dma/dw-edma/dw-edma-v0-core.c
Extension
.c
Size
13595 bytes
Lines
547
Domain
Driver Families
Bucket
drivers/dma
Inferred role
Driver Families: implementation source
Status
source 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

if (!j) {
			control |= DW_EDMA_V0_LIE;
			if (!(chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL))
				control |= DW_EDMA_V0_RIE;
		}

		dw_edma_v0_write_ll_data(chunk, i++, control, child->sz,
					 child->sar, child->dar);
	}

	control = DW_EDMA_V0_LLP | DW_EDMA_V0_TCB;
	if (!chunk->cb)
		control |= DW_EDMA_V0_CB;

	dw_edma_v0_write_ll_link(chunk, i, control, chunk->ll_region.paddr);
}

static void dw_edma_v0_sync_ll_data(struct dw_edma_chunk *chunk)
{
	/*
	 * In case of remote eDMA engine setup, the DW PCIe RP/EP internal
	 * configuration registers and application memory are normally accessed
	 * over different buses. Ensure LL-data reaches the memory before the
	 * doorbell register is toggled by issuing the dummy-read from the remote
	 * LL memory in a hope that the MRd TLP will return only after the
	 * last MWr TLP is completed
	 */
	if (!(chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL))
		readl(chunk->ll_region.vaddr.io);
}

static void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
{
	struct dw_edma_chan *chan = chunk->chan;
	struct dw_edma *dw = chan->dw;
	u32 tmp;

	dw_edma_v0_core_write_chunk(chunk);

	if (first) {
		/* Enable engine */
		SET_RW_32(dw, chan->dir, engine_en, BIT(0));
		if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
			switch (chan->id) {
			case 0:
				SET_RW_COMPAT(dw, chan->dir, ch0_pwr_en,
					      BIT(0));
				break;
			case 1:
				SET_RW_COMPAT(dw, chan->dir, ch1_pwr_en,
					      BIT(0));
				break;
			case 2:
				SET_RW_COMPAT(dw, chan->dir, ch2_pwr_en,
					      BIT(0));
				break;
			case 3:
				SET_RW_COMPAT(dw, chan->dir, ch3_pwr_en,
					      BIT(0));
				break;
			case 4:
				SET_RW_COMPAT(dw, chan->dir, ch4_pwr_en,
					      BIT(0));
				break;
			case 5:
				SET_RW_COMPAT(dw, chan->dir, ch5_pwr_en,
					      BIT(0));
				break;
			case 6:
				SET_RW_COMPAT(dw, chan->dir, ch6_pwr_en,
					      BIT(0));
				break;
			case 7:
				SET_RW_COMPAT(dw, chan->dir, ch7_pwr_en,
					      BIT(0));
				break;
			}
		}
		/* Interrupt unmask - done, abort */
		tmp = GET_RW_32(dw, chan->dir, int_mask);
		tmp &= ~FIELD_PREP(EDMA_V0_DONE_INT_MASK, BIT(chan->id));
		tmp &= ~FIELD_PREP(EDMA_V0_ABORT_INT_MASK, BIT(chan->id));
		SET_RW_32(dw, chan->dir, int_mask, tmp);
		/* Linked list error */
		tmp = GET_RW_32(dw, chan->dir, linked_list_err_en);
		tmp |= FIELD_PREP(EDMA_V0_LINKED_LIST_ERR_MASK, BIT(chan->id));
		SET_RW_32(dw, chan->dir, linked_list_err_en, tmp);
		/* Channel control */
		SET_CH_32(dw, chan->dir, chan->id, ch_control1,
			  (DW_EDMA_V0_CCS | DW_EDMA_V0_LLE));

Annotation

Implementation Notes