Module Name:    src
Committed By:   jakllsch
Date:           Sat Mar  2 16:55:13 UTC 2019

Modified Files:
        src/sys/arch/arm/sunxi: sun6i_dma.c

Log Message:
Validate burst and width arguments.

Also add some more register definitions, and a (disabled) example of
how to set the DMA flow control mode.


To generate a diff of this commit:
cvs rdiff -u -r1.7 -r1.8 src/sys/arch/arm/sunxi/sun6i_dma.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/arm/sunxi/sun6i_dma.c
diff -u src/sys/arch/arm/sunxi/sun6i_dma.c:1.7 src/sys/arch/arm/sunxi/sun6i_dma.c:1.8
--- src/sys/arch/arm/sunxi/sun6i_dma.c:1.7	Sat Mar  2 03:21:17 2019
+++ src/sys/arch/arm/sunxi/sun6i_dma.c	Sat Mar  2 16:55:13 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: sun6i_dma.c,v 1.7 2019/03/02 03:21:17 jakllsch Exp $ */
+/* $NetBSD: sun6i_dma.c,v 1.8 2019/03/02 16:55:13 jakllsch Exp $ */
 
 /*-
  * Copyright (c) 2014-2017 Jared McNeill <jmcne...@invisible.ca>
@@ -29,7 +29,7 @@
 #include "opt_ddb.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sun6i_dma.c,v 1.7 2019/03/02 03:21:17 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sun6i_dma.c,v 1.8 2019/03/02 16:55:13 jakllsch Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -79,6 +79,13 @@ __KERNEL_RCSID(0, "$NetBSD: sun6i_dma.c,
 #define DMA_PARA_REG(n)			(0x0100 + (n) * 0x40 + 0x1C)
 #define  DMA_PARA_DATA_BLK_SIZE			__BITS(15,8)
 #define  DMA_PARA_WAIT_CYC			__BITS(7,0)
+#define DMA_MODE_REG(n)			(0x0100 + (n) * 0x40 + 0x28)
+#define  MODE_WAIT				0b0
+#define  MODE_HANDSHAKE				0b1
+#define  DMA_MODE_DST(m)			__SHIFTIN((m), __BIT(3))
+#define  DMA_MODE_SRC(m)			__SHIFTIN((m), __BIT(2))
+#define DMA_FDESC_ADDR_REG(n)		(0x0100 + (n) * 0x40 + 0x2C)
+#define DMA_PKG_NUM_REG(n)		(0x0100 + (n) * 0x40 + 0x30)
 
 struct sun6idma_desc {
 	uint32_t	dma_config;
@@ -93,14 +100,25 @@ struct sun6idma_desc {
 struct sun6idma_config {
 	u_int		num_channels;
 	bool		autogate;
+	uint8_t		bursts;
+	uint8_t		widths;
 	bus_size_t	autogate_reg;
 	uint32_t	autogate_mask;
 	uint32_t	burst_mask;
 };
 
+#define IL2B(x)			__BIT(ilog2(x))
+#define IL2B_RANGE(x, y)	__BITS(ilog2(x), ilog2(y))
+#define WIDTHS_1_2_4		IL2B_RANGE(4, 1)
+#define WIDTHS_1_2_4_8		IL2B_RANGE(8, 1)
+#define BURSTS_1_8		(IL2B(8)|IL2B(1))
+#define BURSTS_1_4_8_16		(IL2B(16)|IL2B(8)|IL2B(4)|IL2B(1))
+
 static const struct sun6idma_config sun6i_a31_dma_config = {
 	.num_channels = 16,
 	.burst_mask = __BITS(8,7),
+	.bursts = BURSTS_1_8,
+	.widths = WIDTHS_1_2_4,
 };
 
 static const struct sun6idma_config sun8i_a83t_dma_config = {
@@ -109,6 +127,8 @@ static const struct sun6idma_config sun8
 	.autogate_reg = 0x20,
 	.autogate_mask = 0x4,
 	.burst_mask = __BITS(8,7),
+	.bursts = BURSTS_1_8,
+	.widths = WIDTHS_1_2_4,
 };
 
 static const struct sun6idma_config sun8i_h3_dma_config = {
@@ -117,6 +137,8 @@ static const struct sun6idma_config sun8
 	.autogate_reg = 0x28,
 	.autogate_mask = 0x4,
 	.burst_mask = __BITS(7,6),
+	.bursts = BURSTS_1_4_8_16,
+	.widths = WIDTHS_1_2_4_8,
 };
 
 static const struct sun6idma_config sun50i_a64_dma_config = {
@@ -125,6 +147,8 @@ static const struct sun6idma_config sun5
 	.autogate_reg = 0x28,
 	.autogate_mask = 0x4,
 	.burst_mask = __BITS(7,6),
+	.bursts = BURSTS_1_4_8_16,
+	.widths = WIDTHS_1_2_4_8,
 };
 
 static const struct of_compat_data compat_data[] = {
@@ -158,6 +182,8 @@ struct sun6idma_softc {
 	struct sun6idma_channel	*sc_chan;
 	u_int			sc_nchan;
 	u_int			sc_ndesc_ch;
+	uint8_t			sc_widths;
+	uint8_t			sc_bursts;
 
 	bus_dma_segment_t	sc_dmasegs[1];
 	bus_dmamap_t		sc_dmamap;
@@ -259,6 +285,19 @@ sun6idma_transfer(device_t dev, void *pr
 	if (req->dreq_nsegs > sc->sc_ndesc_ch)
 		return EINVAL;
 
+	if ((sc->sc_widths &
+	    IL2B(req->dreq_mem_opt.opt_bus_width/NBBY)) == 0)
+		return EINVAL;
+	if ((sc->sc_widths &
+	    IL2B(req->dreq_dev_opt.opt_bus_width/NBBY)) == 0)
+		return EINVAL;
+	if ((sc->sc_bursts &
+	    IL2B(req->dreq_mem_opt.opt_burst_len)) == 0)
+		return EINVAL;
+	if ((sc->sc_bursts &
+	    IL2B(req->dreq_dev_opt.opt_burst_len)) == 0)
+		return EINVAL;
+
 	mem_width = DMA_CFG_DATA_WIDTH(req->dreq_mem_opt.opt_bus_width);
 	dev_width = DMA_CFG_DATA_WIDTH(req->dreq_dev_opt.opt_bus_width);
 	mem_burst = DMA_CFG_BST_LEN(req->dreq_mem_opt.opt_burst_len);
@@ -296,6 +335,11 @@ sun6idma_transfer(device_t dev, void *pr
 			desc[j].dma_next = htole32(DMA_NULL);
 	}
 
+#if maybenever
+	DMA_WRITE(sc, DMA_MODE_REG(ch->ch_index),
+	    DMA_MODE_DST(MODE_HANDSHAKE)|DMA_MODE_SRC(MODE_HANDSHAKE));
+#endif
+
 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, DESC_OFFS(ch->ch_index, 0),
 	    DESC_LEN(req->dreq_nsegs), BUS_DMASYNC_PREWRITE);
 
@@ -419,6 +463,8 @@ sun6idma_attach(device_t parent, device_
 
 	sc->sc_burst_mask = conf->burst_mask;
 	sc->sc_nchan = conf->num_channels;
+	sc->sc_widths = conf->widths;
+	sc->sc_bursts = conf->bursts;
 	sc->sc_chan = kmem_alloc(sizeof(*sc->sc_chan) * sc->sc_nchan, KM_SLEEP);
 	desclen = DESC_OFFS(sc->sc_nchan, 0);
 	sc->sc_ndesc_ch = DESC_OFFS(1, 0) / sizeof(struct sun6idma_desc);
@@ -509,6 +555,9 @@ sun6idma_dump(void)
 		device_printf(dev, " %2d: DMA_CUR_DEST_REG:   %08x\n", index, DMA_READ(sc, DMA_CUR_DEST_REG(index)));
 		device_printf(dev, " %2d: DMA_BCNT_LEFT_REG:  %08x\n", index, DMA_READ(sc, DMA_BCNT_LEFT_REG(index)));
 		device_printf(dev, " %2d: DMA_PARA_REG:       %08x\n", index, DMA_READ(sc, DMA_PARA_REG(index)));
+		device_printf(dev, " %2d: DMA_MODE_REG:       %08x\n", index, DMA_READ(sc, DMA_MODE_REG(index)));
+		device_printf(dev, " %2d: DMA_FDESC_ADDR_REG: %08x\n", index, DMA_READ(sc, DMA_FDESC_ADDR_REG(index)));
+		device_printf(dev, " %2d: DMA_PKG_NUM_REG:    %08x\n", index, DMA_READ(sc, DMA_PKG_NUM_REG(index)));
 	}
 }
 #endif

Reply via email to