Commit 990beed9 authored by Vinod Koul's avatar Vinod Koul
Browse files

Merge branch 'topic/sprd' into for-linus

parents f782086a 53197123
Loading
Loading
Loading
Loading
+135 −17
Original line number Diff line number Diff line
@@ -36,6 +36,8 @@
#define SPRD_DMA_GLB_CHN_EN_STS		0x1c
#define SPRD_DMA_GLB_DEBUG_STS		0x20
#define SPRD_DMA_GLB_ARB_SEL_STS	0x24
#define SPRD_DMA_GLB_2STAGE_GRP1	0x28
#define SPRD_DMA_GLB_2STAGE_GRP2	0x2c
#define SPRD_DMA_GLB_REQ_UID(uid)	(0x4 * ((uid) - 1))
#define SPRD_DMA_GLB_REQ_UID_OFFSET	0x2000

@@ -57,6 +59,18 @@
#define SPRD_DMA_CHN_SRC_BLK_STEP	0x38
#define SPRD_DMA_CHN_DES_BLK_STEP	0x3c

/* SPRD_DMA_GLB_2STAGE_GRP register definition */
#define SPRD_DMA_GLB_2STAGE_EN		BIT(24)
#define SPRD_DMA_GLB_CHN_INT_MASK	GENMASK(23, 20)
#define SPRD_DMA_GLB_LIST_DONE_TRG	BIT(19)
#define SPRD_DMA_GLB_TRANS_DONE_TRG	BIT(18)
#define SPRD_DMA_GLB_BLOCK_DONE_TRG	BIT(17)
#define SPRD_DMA_GLB_FRAG_DONE_TRG	BIT(16)
#define SPRD_DMA_GLB_TRG_OFFSET		16
#define SPRD_DMA_GLB_DEST_CHN_MASK	GENMASK(13, 8)
#define SPRD_DMA_GLB_DEST_CHN_OFFSET	8
#define SPRD_DMA_GLB_SRC_CHN_MASK	GENMASK(5, 0)

/* SPRD_DMA_CHN_INTC register definition */
#define SPRD_DMA_INT_MASK		GENMASK(4, 0)
#define SPRD_DMA_INT_CLR_OFFSET		24
@@ -118,6 +132,10 @@
#define SPRD_DMA_SRC_TRSF_STEP_OFFSET	0
#define SPRD_DMA_TRSF_STEP_MASK		GENMASK(15, 0)

/* define DMA channel mode & trigger mode mask */
#define SPRD_DMA_CHN_MODE_MASK		GENMASK(7, 0)
#define SPRD_DMA_TRG_MODE_MASK		GENMASK(7, 0)

/* define the DMA transfer step type */
#define SPRD_DMA_NONE_STEP		0
#define SPRD_DMA_BYTE_STEP		1
@@ -159,6 +177,7 @@ struct sprd_dma_chn_hw {
struct sprd_dma_desc {
	struct virt_dma_desc	vd;
	struct sprd_dma_chn_hw	chn_hw;
	enum dma_transfer_direction dir;
};

/* dma channel description */
@@ -169,6 +188,8 @@ struct sprd_dma_chn {
	struct dma_slave_config	slave_cfg;
	u32			chn_num;
	u32			dev_id;
	enum sprd_dma_chn_mode	chn_mode;
	enum sprd_dma_trg_mode	trg_mode;
	struct sprd_dma_desc	*cur_desc;
};

@@ -205,6 +226,16 @@ static inline struct sprd_dma_desc *to_sprd_dma_desc(struct virt_dma_desc *vd)
	return container_of(vd, struct sprd_dma_desc, vd);
}

static void sprd_dma_glb_update(struct sprd_dma_dev *sdev, u32 reg,
				u32 mask, u32 val)
{
	u32 orig = readl(sdev->glb_base + reg);
	u32 tmp;

	tmp = (orig & ~mask) | val;
	writel(tmp, sdev->glb_base + reg);
}

static void sprd_dma_chn_update(struct sprd_dma_chn *schan, u32 reg,
				u32 mask, u32 val)
{
@@ -331,6 +362,17 @@ static void sprd_dma_stop_and_disable(struct sprd_dma_chn *schan)
	sprd_dma_disable_chn(schan);
}

static unsigned long sprd_dma_get_src_addr(struct sprd_dma_chn *schan)
{
	unsigned long addr, addr_high;

	addr = readl(schan->chn_base + SPRD_DMA_CHN_SRC_ADDR);
	addr_high = readl(schan->chn_base + SPRD_DMA_CHN_WARP_PTR) &
		    SPRD_DMA_HIGH_ADDR_MASK;

	return addr | (addr_high << SPRD_DMA_HIGH_ADDR_OFFSET);
}

static unsigned long sprd_dma_get_dst_addr(struct sprd_dma_chn *schan)
{
	unsigned long addr, addr_high;
@@ -377,6 +419,49 @@ static enum sprd_dma_req_mode sprd_dma_get_req_type(struct sprd_dma_chn *schan)
	return (frag_reg >> SPRD_DMA_REQ_MODE_OFFSET) & SPRD_DMA_REQ_MODE_MASK;
}

static int sprd_dma_set_2stage_config(struct sprd_dma_chn *schan)
{
	struct sprd_dma_dev *sdev = to_sprd_dma_dev(&schan->vc.chan);
	u32 val, chn = schan->chn_num + 1;

	switch (schan->chn_mode) {
	case SPRD_DMA_SRC_CHN0:
		val = chn & SPRD_DMA_GLB_SRC_CHN_MASK;
		val |= BIT(schan->trg_mode - 1) << SPRD_DMA_GLB_TRG_OFFSET;
		val |= SPRD_DMA_GLB_2STAGE_EN;
		sprd_dma_glb_update(sdev, SPRD_DMA_GLB_2STAGE_GRP1, val, val);
		break;

	case SPRD_DMA_SRC_CHN1:
		val = chn & SPRD_DMA_GLB_SRC_CHN_MASK;
		val |= BIT(schan->trg_mode - 1) << SPRD_DMA_GLB_TRG_OFFSET;
		val |= SPRD_DMA_GLB_2STAGE_EN;
		sprd_dma_glb_update(sdev, SPRD_DMA_GLB_2STAGE_GRP2, val, val);
		break;

	case SPRD_DMA_DST_CHN0:
		val = (chn << SPRD_DMA_GLB_DEST_CHN_OFFSET) &
			SPRD_DMA_GLB_DEST_CHN_MASK;
		val |= SPRD_DMA_GLB_2STAGE_EN;
		sprd_dma_glb_update(sdev, SPRD_DMA_GLB_2STAGE_GRP1, val, val);
		break;

	case SPRD_DMA_DST_CHN1:
		val = (chn << SPRD_DMA_GLB_DEST_CHN_OFFSET) &
			SPRD_DMA_GLB_DEST_CHN_MASK;
		val |= SPRD_DMA_GLB_2STAGE_EN;
		sprd_dma_glb_update(sdev, SPRD_DMA_GLB_2STAGE_GRP2, val, val);
		break;

	default:
		dev_err(sdev->dma_dev.dev, "invalid channel mode setting %d\n",
			schan->chn_mode);
		return -EINVAL;
	}

	return 0;
}

static void sprd_dma_set_chn_config(struct sprd_dma_chn *schan,
				    struct sprd_dma_desc *sdesc)
{
@@ -410,6 +495,13 @@ static void sprd_dma_start(struct sprd_dma_chn *schan)
	list_del(&vd->node);
	schan->cur_desc = to_sprd_dma_desc(vd);

	/*
	 * Set 2-stage configuration if the channel starts one 2-stage
	 * transfer.
	 */
	if (schan->chn_mode && sprd_dma_set_2stage_config(schan))
		return;

	/*
	 * Copy the DMA configuration from DMA descriptor to this hardware
	 * channel.
@@ -427,6 +519,7 @@ static void sprd_dma_stop(struct sprd_dma_chn *schan)
	sprd_dma_stop_and_disable(schan);
	sprd_dma_unset_uid(schan);
	sprd_dma_clear_int(schan);
	schan->cur_desc = NULL;
}

static bool sprd_dma_check_trans_done(struct sprd_dma_desc *sdesc,
@@ -450,7 +543,7 @@ static irqreturn_t dma_irq_handle(int irq, void *dev_id)
	struct sprd_dma_desc *sdesc;
	enum sprd_dma_req_mode req_type;
	enum sprd_dma_int_type int_type;
	bool trans_done = false;
	bool trans_done = false, cyclic = false;
	u32 i;

	while (irq_status) {
@@ -465,6 +558,11 @@ static irqreturn_t dma_irq_handle(int irq, void *dev_id)

		sdesc = schan->cur_desc;

		/* cyclic mode schedule callback */
		cyclic = schan->linklist.phy_addr ? true : false;
		if (cyclic == true) {
			vchan_cyclic_callback(&sdesc->vd);
		} else {
			/* Check if the dma request descriptor is done. */
			trans_done = sprd_dma_check_trans_done(sdesc, int_type,
							       req_type);
@@ -473,6 +571,7 @@ static irqreturn_t dma_irq_handle(int irq, void *dev_id)
				schan->cur_desc = NULL;
				sprd_dma_start(schan);
			}
		}
		spin_unlock(&schan->vc.lock);
	}

@@ -534,7 +633,12 @@ static enum dma_status sprd_dma_tx_status(struct dma_chan *chan,
		else
			pos = 0;
	} else if (schan->cur_desc && schan->cur_desc->vd.tx.cookie == cookie) {
		struct sprd_dma_desc *sdesc = to_sprd_dma_desc(vd);

		if (sdesc->dir == DMA_DEV_TO_MEM)
			pos = sprd_dma_get_dst_addr(schan);
		else
			pos = sprd_dma_get_src_addr(schan);
	} else {
		pos = 0;
	}
@@ -593,6 +697,7 @@ static int sprd_dma_fill_desc(struct dma_chan *chan,
{
	struct sprd_dma_dev *sdev = to_sprd_dma_dev(chan);
	struct sprd_dma_chn *schan = to_sprd_dma_chan(chan);
	enum sprd_dma_chn_mode chn_mode = schan->chn_mode;
	u32 req_mode = (flags >> SPRD_DMA_REQ_SHIFT) & SPRD_DMA_REQ_MODE_MASK;
	u32 int_mode = flags & SPRD_DMA_INT_MASK;
	int src_datawidth, dst_datawidth, src_step, dst_step;
@@ -604,6 +709,15 @@ static int sprd_dma_fill_desc(struct dma_chan *chan,
			dev_err(sdev->dma_dev.dev, "invalid source step\n");
			return src_step;
		}

		/*
		 * For 2-stage transfer, destination channel step can not be 0,
		 * since destination device is AON IRAM.
		 */
		if (chn_mode == SPRD_DMA_DST_CHN0 ||
		    chn_mode == SPRD_DMA_DST_CHN1)
			dst_step = src_step;
		else
			dst_step = SPRD_DMA_NONE_STEP;
	} else {
		dst_step = sprd_dma_get_step(slave_cfg->dst_addr_width);
@@ -674,13 +788,11 @@ static int sprd_dma_fill_desc(struct dma_chan *chan,

	/* link-list configuration */
	if (schan->linklist.phy_addr) {
		if (sg_index == sglen - 1)
			hw->frg_len |= SPRD_DMA_LLIST_END;

		hw->cfg |= SPRD_DMA_LINKLIST_EN;

		/* link-list index */
		temp = (sg_index + 1) % sglen;
		temp = sglen ? (sg_index + 1) % sglen : 0;

		/* Next link-list configuration's physical address offset */
		temp = temp * sizeof(*hw) + SPRD_DMA_CHN_SRC_ADDR;
		/*
@@ -804,6 +916,8 @@ sprd_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
	if (!sdesc)
		return NULL;

	sdesc->dir = dir;

	for_each_sg(sgl, sg, sglen, i) {
		len = sg_dma_len(sg);

@@ -831,6 +945,12 @@ sprd_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
		}
	}

	/* Set channel mode and trigger mode for 2-stage transfer */
	schan->chn_mode =
		(flags >> SPRD_DMA_CHN_MODE_SHIFT) & SPRD_DMA_CHN_MODE_MASK;
	schan->trg_mode =
		(flags >> SPRD_DMA_TRG_MODE_SHIFT) & SPRD_DMA_TRG_MODE_MASK;

	ret = sprd_dma_fill_desc(chan, &sdesc->chn_hw, 0, 0, src, dst, len,
				 dir, flags, slave_cfg);
	if (ret) {
@@ -847,9 +967,6 @@ static int sprd_dma_slave_config(struct dma_chan *chan,
	struct sprd_dma_chn *schan = to_sprd_dma_chan(chan);
	struct dma_slave_config *slave_cfg = &schan->slave_cfg;

	if (!is_slave_direction(config->direction))
		return -EINVAL;

	memcpy(slave_cfg, config, sizeof(*config));
	return 0;
}
@@ -1109,4 +1226,5 @@ module_platform_driver(sprd_dma_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("DMA driver for Spreadtrum");
MODULE_AUTHOR("Baolin Wang <baolin.wang@spreadtrum.com>");
MODULE_AUTHOR("Eric Long <eric.long@spreadtrum.com>");
MODULE_ALIAS("platform:sprd-dma");
+59 −3
Original line number Diff line number Diff line
@@ -3,9 +3,65 @@
#ifndef _SPRD_DMA_H_
#define _SPRD_DMA_H_

#define SPRD_DMA_REQ_SHIFT 16
#define SPRD_DMA_FLAGS(req_mode, int_type) \
	((req_mode) << SPRD_DMA_REQ_SHIFT | (int_type))
#define SPRD_DMA_REQ_SHIFT	8
#define SPRD_DMA_TRG_MODE_SHIFT	16
#define SPRD_DMA_CHN_MODE_SHIFT	24
#define SPRD_DMA_FLAGS(chn_mode, trg_mode, req_mode, int_type) \
	((chn_mode) << SPRD_DMA_CHN_MODE_SHIFT | \
	(trg_mode) << SPRD_DMA_TRG_MODE_SHIFT | \
	(req_mode) << SPRD_DMA_REQ_SHIFT | (int_type))

/*
 * The Spreadtrum DMA controller supports channel 2-stage tansfer, that means
 * we can request 2 dma channels, one for source channel, and another one for
 * destination channel. Each channel is independent, and has its own
 * configurations. Once the source channel's transaction is done, it will
 * trigger the destination channel's transaction automatically by hardware
 * signal.
 *
 * To support 2-stage tansfer, we must configure the channel mode and trigger
 * mode as below definition.
 */

/*
 * enum sprd_dma_chn_mode: define the DMA channel mode for 2-stage transfer
 * @SPRD_DMA_CHN_MODE_NONE: No channel mode setting which means channel doesn't
 * support the 2-stage transfer.
 * @SPRD_DMA_SRC_CHN0: Channel used as source channel 0.
 * @SPRD_DMA_SRC_CHN1: Channel used as source channel 1.
 * @SPRD_DMA_DST_CHN0: Channel used as destination channel 0.
 * @SPRD_DMA_DST_CHN1: Channel used as destination channel 1.
 *
 * Now the DMA controller can supports 2 groups 2-stage transfer.
 */
enum sprd_dma_chn_mode {
	SPRD_DMA_CHN_MODE_NONE,
	SPRD_DMA_SRC_CHN0,
	SPRD_DMA_SRC_CHN1,
	SPRD_DMA_DST_CHN0,
	SPRD_DMA_DST_CHN1,
};

/*
 * enum sprd_dma_trg_mode: define the DMA channel trigger mode for 2-stage
 * transfer
 * @SPRD_DMA_NO_TRG: No trigger setting.
 * @SPRD_DMA_FRAG_DONE_TRG: Trigger the transaction of destination channel
 * automatically once the source channel's fragment request is done.
 * @SPRD_DMA_BLOCK_DONE_TRG: Trigger the transaction of destination channel
 * automatically once the source channel's block request is done.
 * @SPRD_DMA_TRANS_DONE_TRG: Trigger the transaction of destination channel
 * automatically once the source channel's transfer request is done.
 * @SPRD_DMA_LIST_DONE_TRG: Trigger the transaction of destination channel
 * automatically once the source channel's link-list request is done.
 */
enum sprd_dma_trg_mode {
	SPRD_DMA_NO_TRG,
	SPRD_DMA_FRAG_DONE_TRG,
	SPRD_DMA_BLOCK_DONE_TRG,
	SPRD_DMA_TRANS_DONE_TRG,
	SPRD_DMA_LIST_DONE_TRG,
};

/*
 * enum sprd_dma_req_mode: define the DMA request mode