[Letux-kernel] [RFC 18/28] dmaengine: jz4780: add JZ4730 DMA customisations

H. Nikolaus Schaller hns at goldelico.com
Sat Jan 23 17:28:44 CET 2021


From: Paul Boddie <paul at boddie.org.uk>

Add an extra set of parameters to support the JZ4730
and handle some special cases by driver code.

Signed-off-by: Paul Boddie <paul at boddie.org.uk>
Signed-off-by: H. Nikolaus Schaller <hns at goldelico.com>
---
 drivers/dma/dma-jz4780.c | 101 +++++++++++++++++++++++++++++++++------
 1 file changed, 86 insertions(+), 15 deletions(-)

diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c
index 612d353648cf7..6f16f5ab4fd83 100644
--- a/drivers/dma/dma-jz4780.c
+++ b/drivers/dma/dma-jz4780.c
@@ -4,6 +4,8 @@
  *
  * Copyright (c) 2015 Imagination Technologies
  * Author: Alex Smith <alex at alex-smith.me.uk>
+ *
+ * Copyright (C) 2020 Paul Boddie <paul at boddie.org.uk>  JZ4730 customisations
  */
 
 #include <linux/clk.h>
@@ -34,6 +36,9 @@
 #define JZ_DMA_REG_DCIRQP	0x28
 #define JZ_DMA_REG_DCIRQM	0x2c
 
+#define JZ4730_DMA_REG_DIRQP	0x00
+#define JZ4730_DMA_REG_DMAC	0x04
+
 /* Per-channel registers. */
 #define JZ_DMA_REG_CHAN(n)	(n * 0x20)
 #define JZ_DMA_REG_DSA		0x00
@@ -85,9 +90,23 @@
 				 BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
 				 BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))
 
+/* Explicit JZ4730 control/status register macros. */
+#define JZ4730_DMA_REG_DCCSR	0x10
+
+#define JZ4730_DMA_DCCSR_CHDE	BIT(0)
+#define JZ4730_DMA_DCCSR_TIE	BIT(1)
+#define JZ4730_DMA_DCCSR_EACKM	BIT(30)
+
+/* Macro used to select descriptor command (DCM) fields for the JZ4730. */
+#define JZ4730_DMA_DCCSR_MASK	(JZ_DMA_DCM_SAI | JZ_DMA_DCM_DAI | \
+				(0x3 << JZ_DMA_DCM_SP_SHIFT)     | \
+				(0x3 << JZ_DMA_DCM_DP_SHIFT)     | \
+				JZ_DMA_DCM_TSZ_MASK)
+
+/* Offset of control registers from jz4780 peripheral base address */
 #define JZ4780_DMA_CTRL_OFFSET	0x1000
 
-/* macros for use with jz4780_dma_soc_data.flags */
+/* Macros for use with jz4780_dma_soc_data.flags */
 #define JZ_SOC_DATA_ALLOW_LEGACY_DT	BIT(0)
 #define JZ_SOC_DATA_PROGRAMMABLE_DMA	BIT(1)
 #define JZ_SOC_DATA_PER_CHAN_PM		BIT(2)
@@ -142,6 +161,7 @@ struct jz4780_dma_soc_data {
 	unsigned int nb_channels;
 	unsigned int transfer_ord_max;
 	unsigned long flags;
+	unsigned long control, pending, descaddr;
 };
 
 struct jz4780_dma_dev {
@@ -481,6 +501,7 @@ static void jz4780_dma_begin(struct jz4780_dma_chan *jzchan)
 	struct virt_dma_desc *vdesc;
 	unsigned int i;
 	dma_addr_t desc_phys;
+	uint32 dcm;
 
 	if (!jzchan->desc) {
 		vdesc = vchan_next_desc(&jzchan->vchan);
@@ -523,7 +544,7 @@ static void jz4780_dma_begin(struct jz4780_dma_chan *jzchan)
 	/* Enable the channel's clock. */
 	jz4780_dma_chan_enable(jzdma, jzchan->id);
 
-	/* Use 4-word descriptors. */
+	/* Use 4-word descriptors (and also reset the channel). */
 	jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS, 0);
 
 	/* Set transfer type. */
@@ -539,15 +560,37 @@ static void jz4780_dma_begin(struct jz4780_dma_chan *jzchan)
 	jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DTC,
 				jzchan->desc->desc[jzchan->curr_hwdesc].dtc);
 
-	/* Write descriptor address and initiate descriptor fetch. */
-	desc_phys = jzchan->desc->desc_phys +
-		    (jzchan->curr_hwdesc * sizeof(*jzchan->desc->desc));
-	jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DDA, desc_phys);
-	jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DDRS, BIT(jzchan->id));
+	/* Test for descriptor transfer availability (absent in the JZ4730). */
+	if (!jzdma->soc_data->descaddr) {
+		/* Obtain and augment relevant descriptor command details. */
+		dcm = jzchan->desc->desc[jzchan->curr_hwdesc].dcm &
+			JZ4730_DMA_DCCSR_MASK;
+
+		dcm |= JZ4730_DMA_DCCSR_CHDE | JZ4730_DMA_DCCSR_TIE;
+
+		/* Detect peripheral writes, setting an extra flag. */
+		if (!(dcm & JZ_DMA_DCM_DAI))
+			dcm |= JZ4730_DMA_DCCSR_EACKM;
+
+		jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DSA,
+					jzchan->desc->desc[jzchan->curr_hwdesc].dsa);
+		jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DTA,
+					jzchan->desc->desc[jzchan->curr_hwdesc].dta);
 
-	/* Enable the channel. */
-	jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS,
-			      JZ_DMA_DCS_CTE);
+		/* Transfer command fields to the control/status register. */
+		jz4780_dma_chn_writel(jzdma, jzchan->id, JZ4730_DMA_REG_DCCSR, dcm);
+	} else {
+		/* Write descriptor address and initiate descriptor fetch. */
+		desc_phys = jzchan->desc->desc_phys +
+			    (jzchan->curr_hwdesc * sizeof(*jzchan->desc->desc));
+		jz4780_dma_chn_writel(jzdma, jzchan->id, jzdma->soc_data->descaddr,
+					desc_phys);
+		jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DDRS, BIT(jzchan->id));
+
+		/* Enable the channel. */
+		jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS,
+				      JZ_DMA_DCS_CTE);
+	}
 }
 
 static void jz4780_dma_issue_pending(struct dma_chan *chan)
@@ -730,7 +773,7 @@ static irqreturn_t jz4780_dma_irq_handler(int irq, void *data)
 	uint32_t dmac;
 	int i;
 
-	pending = jz4780_dma_ctrl_readl(jzdma, JZ_DMA_REG_DIRQP);
+	pending = jz4780_dma_ctrl_readl(jzdma, jzdma->soc_data->pending);
 
 	for_each_set_bit(i, &pending, nb_channels) {
 		if (jz4780_dma_chan_irq(jzdma, &jzdma->chan[i]))
@@ -738,12 +781,12 @@ static irqreturn_t jz4780_dma_irq_handler(int irq, void *data)
 	}
 
 	/* Clear halt and address error status of all channels. */
-	dmac = jz4780_dma_ctrl_readl(jzdma, JZ_DMA_REG_DMAC);
+	dmac = jz4780_dma_ctrl_readl(jzdma, jzdma->soc_data->control);
 	dmac &= ~(JZ_DMA_DMAC_HLT | JZ_DMA_DMAC_AR);
-	jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMAC, dmac);
+	jz4780_dma_ctrl_writel(jzdma, jzdma->soc_data->control, dmac);
 
 	/* Clear interrupt pending status. */
-	jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DIRQP, pending);
+	jz4780_dma_ctrl_writel(jzdma, jzdma->soc_data->pending, pending);
 
 	return IRQ_HANDLED;
 }
@@ -921,7 +964,7 @@ static int jz4780_dma_probe(struct platform_device *pdev)
 	 * Also set the FMSC bit - it increases MSC performance, so it makes
 	 * little sense not to enable it.
 	 */
-	jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMAC, JZ_DMA_DMAC_DMAE |
+	jz4780_dma_ctrl_writel(jzdma, soc_data->control, JZ_DMA_DMAC_DMAE |
 			       JZ_DMA_DMAC_FAIC | JZ_DMA_DMAC_FMSC);
 
 	if (soc_data->flags & JZ_SOC_DATA_PROGRAMMABLE_DMA)
@@ -995,6 +1038,9 @@ static const struct jz4780_dma_soc_data jz4740_dma_soc_data = {
 	.nb_channels = 6,
 	.transfer_ord_max = 5,
 	.flags = JZ_SOC_DATA_BREAK_LINKS,
+	.control = JZ_DMA_REG_DMAC,
+	.pending = JZ_DMA_REG_DIRQP,
+	.descaddr = JZ_DMA_REG_DDA,
 };
 
 static const struct jz4780_dma_soc_data jz4725b_dma_soc_data = {
@@ -1002,35 +1048,60 @@ static const struct jz4780_dma_soc_data jz4725b_dma_soc_data = {
 	.transfer_ord_max = 5,
 	.flags = JZ_SOC_DATA_PER_CHAN_PM | JZ_SOC_DATA_NO_DCKES_DCKEC |
 		 JZ_SOC_DATA_BREAK_LINKS,
+	.control = JZ_DMA_REG_DMAC,
+	.pending = JZ_DMA_REG_DIRQP,
+	.descaddr = JZ_DMA_REG_DDA,
+};
+
+static const struct jz4780_dma_soc_data jz4730_dma_soc_data = {
+	.nb_channels = 6,
+	.transfer_ord_max = 5,
+	.flags = JZ_SOC_DATA_BREAK_LINKS,
+	.control = JZ4730_DMA_REG_DMAC,
+	.pending = JZ4730_DMA_REG_DIRQP,
+	.descaddr = 0,
 };
 
 static const struct jz4780_dma_soc_data jz4770_dma_soc_data = {
 	.nb_channels = 6,
 	.transfer_ord_max = 6,
 	.flags = JZ_SOC_DATA_PER_CHAN_PM,
+	.control = JZ_DMA_REG_DMAC,
+	.pending = JZ_DMA_REG_DIRQP,
+	.descaddr = JZ_DMA_REG_DDA,
 };
 
 static const struct jz4780_dma_soc_data jz4780_dma_soc_data = {
 	.nb_channels = 32,
 	.transfer_ord_max = 7,
 	.flags = JZ_SOC_DATA_ALLOW_LEGACY_DT | JZ_SOC_DATA_PROGRAMMABLE_DMA,
+	.control = JZ_DMA_REG_DMAC,
+	.pending = JZ_DMA_REG_DIRQP,
+	.descaddr = JZ_DMA_REG_DDA,
 };
 
 static const struct jz4780_dma_soc_data x1000_dma_soc_data = {
 	.nb_channels = 8,
 	.transfer_ord_max = 7,
 	.flags = JZ_SOC_DATA_PROGRAMMABLE_DMA,
+	.control = JZ_DMA_REG_DMAC,
+	.pending = JZ_DMA_REG_DIRQP,
+	.descaddr = JZ_DMA_REG_DDA,
 };
 
 static const struct jz4780_dma_soc_data x1830_dma_soc_data = {
 	.nb_channels = 32,
 	.transfer_ord_max = 7,
 	.flags = JZ_SOC_DATA_PROGRAMMABLE_DMA,
+	.control = JZ_DMA_REG_DMAC,
+	.pending = JZ_DMA_REG_DIRQP,
+	.descaddr = JZ_DMA_REG_DDA,
 };
 
 static const struct of_device_id jz4780_dma_dt_match[] = {
 	{ .compatible = "ingenic,jz4740-dma", .data = &jz4740_dma_soc_data },
 	{ .compatible = "ingenic,jz4725b-dma", .data = &jz4725b_dma_soc_data },
+	{ .compatible = "ingenic,jz4730-dma", .data = &jz4730_dma_soc_data },
 	{ .compatible = "ingenic,jz4770-dma", .data = &jz4770_dma_soc_data },
 	{ .compatible = "ingenic,jz4780-dma", .data = &jz4780_dma_soc_data },
 	{ .compatible = "ingenic,x1000-dma", .data = &x1000_dma_soc_data },
-- 
2.26.2



More information about the Letux-kernel mailing list