drivers/dma/milbeaut-hdmac.c

Source file repositories/reference/linux-study-clean/drivers/dma/milbeaut-hdmac.c

File Facts

System
Linux kernel
Corpus path
drivers/dma/milbeaut-hdmac.c
Extension
.c
Size
14531 bytes
Lines
584
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

struct milbeaut_hdmac_desc {
	struct virt_dma_desc vd;
	struct scatterlist *sgl;
	unsigned int sg_len;
	unsigned int sg_cur;
	enum dma_transfer_direction dir;
};

struct milbeaut_hdmac_chan {
	struct virt_dma_chan vc;
	struct milbeaut_hdmac_device *mdev;
	struct milbeaut_hdmac_desc *md;
	void __iomem *reg_ch_base;
	unsigned int slave_id;
	struct dma_slave_config	cfg;
};

struct milbeaut_hdmac_device {
	struct dma_device ddev;
	struct clk *clk;
	void __iomem *reg_base;
	struct milbeaut_hdmac_chan channels[];
};

static struct milbeaut_hdmac_chan *
to_milbeaut_hdmac_chan(struct virt_dma_chan *vc)
{
	return container_of(vc, struct milbeaut_hdmac_chan, vc);
}

static struct milbeaut_hdmac_desc *
to_milbeaut_hdmac_desc(struct virt_dma_desc *vd)
{
	return container_of(vd, struct milbeaut_hdmac_desc, vd);
}

/* mc->vc.lock must be held by caller */
static struct milbeaut_hdmac_desc *
milbeaut_hdmac_next_desc(struct milbeaut_hdmac_chan *mc)
{
	struct virt_dma_desc *vd;

	vd = vchan_next_desc(&mc->vc);
	if (!vd) {
		mc->md = NULL;
		return NULL;
	}

	list_del(&vd->node);

	mc->md = to_milbeaut_hdmac_desc(vd);

	return mc->md;
}

/* mc->vc.lock must be held by caller */
static void milbeaut_chan_start(struct milbeaut_hdmac_chan *mc,
				struct milbeaut_hdmac_desc *md)
{
	struct scatterlist *sg;
	u32 cb, ca, src_addr, dest_addr, len;
	u32 width, burst;

	sg = &md->sgl[md->sg_cur];
	len = sg_dma_len(sg);

	cb = MLB_HDMAC_CI | MLB_HDMAC_EI;
	if (md->dir == DMA_MEM_TO_DEV) {
		cb |= MLB_HDMAC_FD;
		width = mc->cfg.dst_addr_width;
		burst = mc->cfg.dst_maxburst;
		src_addr = sg_dma_address(sg);
		dest_addr = mc->cfg.dst_addr;
	} else {
		cb |= MLB_HDMAC_FS;
		width = mc->cfg.src_addr_width;
		burst = mc->cfg.src_maxburst;
		src_addr = mc->cfg.src_addr;
		dest_addr = sg_dma_address(sg);
	}
	cb |= FIELD_PREP(MLB_HDMAC_TW, (width >> 1));
	cb |= FIELD_PREP(MLB_HDMAC_MS, 2);

	writel_relaxed(MLB_HDMAC_DE, mc->mdev->reg_base + MLB_HDMAC_DMACR);
	writel_relaxed(src_addr, mc->reg_ch_base + MLB_HDMAC_DMACSA);
	writel_relaxed(dest_addr, mc->reg_ch_base + MLB_HDMAC_DMACDA);
	writel_relaxed(cb, mc->reg_ch_base + MLB_HDMAC_DMACB);

	ca = FIELD_PREP(MLB_HDMAC_IS, mc->slave_id);
	if (burst == 16)

Annotation

Implementation Notes