drivers/dma/st_fdma.c

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

File Facts

System
Linux kernel
Corpus path
drivers/dma/st_fdma.c
Extension
.c
Size
22202 bytes
Lines
869
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 (fdev->dreq_mask == ~0L) {
			dev_err(fdev->dev, "No req lines available\n");
			return -EINVAL;
		}

		if (try || req_line_cfg >= ST_FDMA_NR_DREQS) {
			dev_err(fdev->dev, "Invalid or used req line\n");
			return -EINVAL;
		} else {
			dreq_line = req_line_cfg;
		}

		try++;
	} while (test_and_set_bit(dreq_line, &fdev->dreq_mask));

	dev_dbg(fdev->dev, "get dreq_line:%d mask:%#lx\n",
		dreq_line, fdev->dreq_mask);

	return dreq_line;
}

static void st_fdma_dreq_put(struct st_fdma_chan *fchan)
{
	struct st_fdma_dev *fdev = fchan->fdev;

	dev_dbg(fdev->dev, "put dreq_line:%#lx\n", fchan->dreq_line);
	clear_bit(fchan->dreq_line, &fdev->dreq_mask);
}

static void st_fdma_xfer_desc(struct st_fdma_chan *fchan)
{
	struct virt_dma_desc *vdesc;
	unsigned long nbytes, ch_cmd, cmd;

	vdesc = vchan_next_desc(&fchan->vchan);
	if (!vdesc)
		return;

	fchan->fdesc = to_st_fdma_desc(vdesc);
	nbytes = fchan->fdesc->node[0].desc->nbytes;
	cmd = FDMA_CMD_START(fchan->vchan.chan.chan_id);
	ch_cmd = fchan->fdesc->node[0].pdesc | FDMA_CH_CMD_STA_START;

	/* start the channel for the descriptor */
	fnode_write(fchan, nbytes, FDMA_CNTN_OFST);
	fchan_write(fchan, ch_cmd, FDMA_CH_CMD_OFST);
	writel(cmd,
		fchan->fdev->slim_rproc->peri + FDMA_CMD_SET_OFST);

	dev_dbg(fchan->fdev->dev, "start chan:%d\n", fchan->vchan.chan.chan_id);
}

static void st_fdma_ch_sta_update(struct st_fdma_chan *fchan,
				  unsigned long int_sta)
{
	unsigned long ch_sta, ch_err;
	int ch_id = fchan->vchan.chan.chan_id;
	struct st_fdma_dev *fdev = fchan->fdev;

	ch_sta = fchan_read(fchan, FDMA_CH_CMD_OFST);
	ch_err = ch_sta & FDMA_CH_CMD_ERR_MASK;
	ch_sta &= FDMA_CH_CMD_STA_MASK;

	if (int_sta & FDMA_INT_STA_ERR) {
		dev_warn(fdev->dev, "chan:%d, error:%ld\n", ch_id, ch_err);
		fchan->status = DMA_ERROR;
		return;
	}

	switch (ch_sta) {
	case FDMA_CH_CMD_STA_PAUSED:
		fchan->status = DMA_PAUSED;
		break;

	case FDMA_CH_CMD_STA_RUNNING:
		fchan->status = DMA_IN_PROGRESS;
		break;
	}
}

static irqreturn_t st_fdma_irq_handler(int irq, void *dev_id)
{
	struct st_fdma_dev *fdev = dev_id;
	irqreturn_t ret = IRQ_NONE;
	struct st_fdma_chan *fchan = &fdev->chans[0];
	unsigned long int_sta, clr;

	int_sta = fdma_read(fdev, FDMA_INT_STA_OFST);
	clr = int_sta;

Annotation

Implementation Notes