PERFORCE change 180502 for review
Jakub Wojciech Klama
jceel at FreeBSD.org
Mon Jul 5 21:17:32 UTC 2010
http://p4web.freebsd.org/@@180502?ac=10
Change 180502 by jceel at jceel on 2010/07/05 21:17:11
* Add support for linked transfers in EDMA3 driver
* Some cosmeting and style(9) changes
Affected files ...
.. //depot/projects/soc2010/jceel_dma/sys/arm/davinci/davinci_edma.c#4 edit
.. //depot/projects/soc2010/jceel_dma/sys/arm/davinci/davinci_edmareg.h#4 edit
Differences ...
==== //depot/projects/soc2010/jceel_dma/sys/arm/davinci/davinci_edma.c#4 (text+ko) ====
@@ -86,8 +86,11 @@
int dc_chno;
int dc_status;
#define CHANNEL_ACTIVE 1
+#define CHANNEL_ACTIVE_LINKED 2
#define CHANNEL_IDLE 0
+ int dc_laststatus;
struct dmae_transfer * dc_xfer;
+ struct dmae_transfer * dc_linkxfer;
};
struct davinci_edma_softc {
@@ -131,6 +134,9 @@
static void davinci_edma_intr_tcerr1(void *);
static void davinci_edma_tcerr(struct davinci_edma_softc *, int);
+static int davinci_edma_setupdesc(struct dmae_transfer *,
+ struct davinci_edma_desc *);
+static uint64_t ffs64(uint64_t);
#define davinci_edma_lock(sc) \
mtx_lock(&sc->ds_mtx)
@@ -246,66 +252,36 @@
{
struct davinci_edma_softc *sc = device_get_softc(dev);
struct davinci_edma_channel *ch;
- struct davinci_edma_desc param_desc;
- uint32_t acnt, bcnt, srcbidx, dstbidx;
-
- debugf("setup channel: chno=%d, xfer=%p", chno, xfer);
- debugf("srcbuf=0x%08lx, dstbuf=0x%08lx length=%ld",
- xfer->dt_src.db_addr, xfer->dt_dst.db_addr,
- xfer->dt_dst.db_length);
+ struct davinci_edma_desc param_desc, link_desc;
+ int ret;
if (chno < 0 || chno > DAVINCI_EDMA_NCHANNELS)
return (EINVAL);
+
+ ch = &sc->ds_channels[chno];
+ ch->dc_xfer = xfer;
- if (xfer->dt_src.db_type == DMAEBUF_FRAME ||
- xfer->dt_dst.db_type == DMAEBUF_FRAME) {
- if (xfer->dt_src.db_type == DMAEBUF_FRAME &&
- xfer->dt_dst.db_type == DMAEBUF_FRAME &&
- xfer->dt_src.db_stride_width !=
- xfer->dt_dst.db_stride_width)
- return (EINVAL);
+ /* Allow at most one linked transfer */
+ if (xfer->dt_next != NULL && xfer->dt_next->dt_next != NULL)
+ return (EINVAL);
- acnt = (xfer->dt_src.db_type == DMAEBUF_FRAME
- ? xfer->dt_src.db_stride_width
- : xfer->dt_dst.db_stride_width);
- bcnt = (xfer->dt_src.db_type == DMAEBUF_FRAME
- ? xfer->dt_src.db_length /
- (acnt + xfer->dt_src.db_stride_spacing)
- : xfer->dt_dst.db_length /
- (acnt + xfer->dt_dst.db_stride_spacing));
-
- srcbidx = dstbidx = acnt;
+ /* Setup transfer descriptor */
+ ret = davinci_edma_setupdesc(xfer, ¶m_desc);
+ if (ret)
+ return (ret);
- if (xfer->dt_src.db_type == DMAEBUF_FRAME)
- srcbidx += xfer->dt_src.db_stride_spacing;
+ davinci_edma_copydesc(sc, ¶m_desc, chno);
- if (xfer->dt_dst.db_type == DMAEBUF_FRAME)
- dstbidx += xfer->dt_dst.db_stride_spacing;
- } else {
- acnt = xfer->dt_dst.db_length;
- bcnt = 1;
- srcbidx = 0;
- dstbidx = 0;
+ /* Setup linked descriptor (if present) */
+ if (xfer->dt_next != NULL) {
+ ch->dc_linkxfer = xfer->dt_next;
+ ret = davinci_edma_setupdesc(xfer->dt_next, &link_desc);
+ if (ret)
+ return (ret);
+ printf("calling davinci_edma_copydesc(&link_desc=%p, chno=%d)\n", &link_desc, chno + 64);
+ davinci_edma_copydesc(sc, &link_desc, chno + 64);
}
- ch = &sc->ds_channels[chno];
- ch->dc_xfer = xfer;
-
- /* Set up DMA descriptor */
- param_desc.edma_src = xfer->dt_src.db_addr;
- param_desc.edma_dst = xfer->dt_dst.db_addr;
- param_desc.edma_opt =
- DAVINCI_EDMA_OPT_TCINTEN |
- DAVINCI_EDMA_OPT_ITCINTEN |
- DAVINCI_EDMA_OPT_SYNCDIM |
- (chno << DAVINCI_EDMA_OPT_TCCSHIFT);
- param_desc.edma_abcnt = (bcnt << 16) | acnt;
- param_desc.edma_bidx = (dstbidx << 16) | srcbidx;
- param_desc.edma_cidx = 0;
- param_desc.edma_ccnt = 1;
-
- davinci_edma_copydesc(sc, ¶m_desc, chno);
-
/* Enable channel interrupts */
// if ((xfer->dt_flags & DMAE_TRANSFER_EXTTRIG) == 0)
// davinci_edma_enable_channel(sc, chno);
@@ -375,7 +351,27 @@
static int
davinci_edma_poll_channel(device_t dev, int chno, int *status)
{
- return (0);
+ struct davinci_edma_softc *sc = device_get_softc(dev);
+ struct davinci_edma_channel *ch;
+ uint32_t ipr;
+ int active = 0;
+
+ ch = &sc->ds_channels[chno];
+
+ if (chno < 32) {
+ ipr = davinci_read_edmacc_4(sc, DAVINCI_EDMACC_IPR);
+ if (ipr & (1 << chno))
+ active = 1;
+ } else {
+ ipr = davinci_read_edmacc_4(sc, DAVINCI_EDMACC_IPRH);
+ if (ipr & (1 << (chno-32)))
+ active = 1;
+ }
+
+ if (active)
+ return (DMAE_TRANSFER_INPROGRESS);
+ else
+ return (ch->dc_laststatus);
}
static void
@@ -384,54 +380,46 @@
struct davinci_edma_softc *sc = (struct davinci_edma_softc *)arg;
struct davinci_edma_channel *ch;
struct dmae_transfer *xfer = NULL;
- uint32_t ipr, iprh;
+ uint64_t ipr;
+ uint32_t iprl, iprh;
int chno;
debugf("transfer completion interrupt");
while (1) {
- ipr = davinci_read_edmacc_4(sc, DAVINCI_EDMACC_IPR);
+ iprl = davinci_read_edmacc_4(sc, DAVINCI_EDMACC_IPR);
iprh = davinci_read_edmacc_4(sc, DAVINCI_EDMACC_IPRH);
+ ipr = (uint64_t)iprh << 32 | iprl;
- if (ipr == 0 && iprh == 0)
+ if (ipr == 0)
return;
- while ((chno = (ffs(ipr) - 1)) != -1) {
+ while ((chno = (ffs64(ipr) - 1)) != -1) {
ch = &sc->ds_channels[chno];
xfer = ch->dc_xfer;
debugf("interrupt on channel %d", chno);
- KASSERT(ch->dc_status == CHANNEL_ACTIVE, "edma spurious interrupt");
+ KASSERT(ch->dc_status != CHANNEL_IDLE, ("invalid channel state"));
if (xfer->dt_callback != NULL) {
- xfer->dt_callback(DMAE_TRANSFER_COMPLETED,
- xfer->dt_callback_arg);
+ xfer->dt_callback(DMAE_TRANSFER_COMPLETED,
+ xfer->dt_callback_arg);
}
+
+ if (chno > 32)
+ davinci_write_edmacc_4(sc, DAVINCI_EDMACC_ICRH, (1 << (chno - 32)));
+ else
+ davinci_write_edmacc_4(sc, DAVINCI_EDMACC_ICR, (1 << chno));
- ch->dc_status = 0;
-
- davinci_write_edmacc_4(sc, DAVINCI_EDMACC_ICR, (1 << chno));
- ipr &= ~(1 << chno);
- }
+ ipr &= ~(1ULL << chno);
+ ch->dc_status = CHANNEL_IDLE;
- while ((chno = (ffs(iprh) + 31)) != 31) {
- ch = &sc->ds_channels[chno];
- xfer = ch->dc_xfer;
-
- KASSERT(ch->dc_status == CHANNEL_ACTIVE, "edma spurious interrupt");
-
- debugf("interrupt on channel %d", chno);
-
- if (xfer->dt_callback != NULL) {
- xfer->dt_callback(DMAE_TRANSFER_COMPLETED,
-
- xfer->dt_callback_arg);
+ if (xfer->dt_next != NULL) {
+ ch->dc_xfer = xfer->dt_next;
+ davinci_edma_start_channel(sc->ds_dev, chno);
+ return;
}
-
- ch->dc_status = 0;
- davinci_write_edmacc_4(sc, DAVINCI_EDMACC_ICRH, (1 << (chno-32)));
- iprh &= ~(1 << (chno - 32));
}
}
}
@@ -442,48 +430,38 @@
struct davinci_edma_softc *sc = (struct davinci_edma_softc *)arg;
struct davinci_edma_channel *ch;
struct dmae_transfer *xfer = NULL;
- uint32_t emr, emrh;
+ uint64_t emr;
+ uint32_t emrl, emrh;
int chno;
- emr = davinci_read_edmacc_4(sc, DAVINCI_EDMACC_EMR);
+ emrl = davinci_read_edmacc_4(sc, DAVINCI_EDMACC_EMR);
emrh = davinci_read_edmacc_4(sc, DAVINCI_EDMACC_EMRH);
+ emr = (uint64_t)emrh << 32 | emrl;
- if (emr == 0 && emrh == 0)
+ if (emr == 0)
return;
- while ((chno = (ffs(emr) - 1)) != -1) {
+ while ((chno = (ffs64(emr) - 1)) != -1) {
ch = &sc->ds_channels[chno];
xfer = ch->dc_xfer;
debugf("error interrupt on channel %d", chno);
- KASSERT(ch->dc_status == CHANNEL_ACTIVE, "edma spurious interrupt");
+ KASSERT(ch->dc_status != CHANNEL_IDLE, ("invalid channel state"));
if (xfer->dt_callback != NULL) {
xfer->dt_callback(DMAE_TRANSFER_ERROR,
xfer->dt_callback_arg);
}
- ch->dc_status = 0;
-
- davinci_write_edmacc_4(sc, DAVINCI_EDMACC_EMR, (1 << chno));
- emr &= ~(1 << chno);
- }
+ ch->dc_status = CHANNEL_IDLE;
+
+ if (chno >= 32)
+ davinci_write_edmacc_4(sc, DAVINCI_EDMACC_EMRH, (1 << (chno - 32)));
+ else
+ davinci_write_edmacc_4(sc, DAVINCI_EDMACC_EMR, (1 << chno));
- while ((chno = (ffs(emrh) + 31)) != 31) {
- ch = &sc->ds_channels[chno];
- KASSERT(ch->dc_status == CHANNEL_ACTIVE, "edma spurious interrupt");
-
- debugf("error interrupt on channel %d", chno);
-
- if (xfer->dt_callback != NULL) {
- xfer->dt_callback(DMAE_TRANSFER_ERROR,
- xfer->dt_callback_arg);
- }
-
- ch->dc_status = 0;
- davinci_write_edmacc_4(sc, DAVINCI_EDMACC_EMRH, (1 << (chno-32)));
- emr &= ~(1 << (chno - 32));
+ emr &= ~(1ULL << chno);
}
}
@@ -523,7 +501,7 @@
DAVINCI_EDMATC_ERRDET_TCCMASK;
ch = &sc->ds_channels[chno];
- xfer = dc->dc_xfer;
+ xfer = ch->dc_xfer;
if (xfer->dt_callback != NULL) {
xfer->dt_callback(DMAE_TRANSFER_ERROR,
@@ -531,6 +509,87 @@
}
}
+static int
+davinci_edma_setupdesc(struct dmae_transfer *xfer,
+ struct davinci_edma_desc *desc)
+{
+ int chno;
+ uint32_t acnt, bcnt, srcbidx, dstbidx;
+
+ chno = rman_get_start(xfer->dt_res);
+
+ debugf("setup desc: chno=%d, xfer=%p", chno, xfer);
+ debugf("srcbuf=0x%08lx, dstbuf=0x%08lx length=%ld",
+ xfer->dt_src.db_addr, xfer->dt_dst.db_addr,
+ xfer->dt_dst.db_length);
+
+ if (xfer->dt_src.db_length == 0 || xfer->dt_dst.db_length == 0)
+ return (EINVAL);
+
+ if (xfer->dt_src.db_type == DMAEBUF_FRAME ||
+ xfer->dt_dst.db_type == DMAEBUF_FRAME) {
+ if (xfer->dt_src.db_type == DMAEBUF_FRAME &&
+ xfer->dt_dst.db_type == DMAEBUF_FRAME &&
+ xfer->dt_src.db_stride_width !=
+ xfer->dt_dst.db_stride_width)
+ return (EINVAL);
+
+ acnt = (xfer->dt_src.db_type == DMAEBUF_FRAME
+ ? xfer->dt_src.db_stride_width
+ : xfer->dt_dst.db_stride_width);
+ bcnt = (xfer->dt_src.db_type == DMAEBUF_FRAME
+ ? xfer->dt_src.db_length /
+ (acnt + xfer->dt_src.db_stride_spacing)
+ : xfer->dt_dst.db_length /
+ (acnt + xfer->dt_dst.db_stride_spacing));
+
+ srcbidx = dstbidx = acnt;
+
+ if (xfer->dt_src.db_type == DMAEBUF_FRAME)
+ srcbidx += xfer->dt_src.db_stride_spacing;
+
+ if (xfer->dt_dst.db_type == DMAEBUF_FRAME)
+ dstbidx += xfer->dt_dst.db_stride_spacing;
+ } else {
+ acnt = xfer->dt_dst.db_length;
+ bcnt = 1;
+ srcbidx = 0;
+ dstbidx = 0;
+ }
+
+ /* Set up DMA descriptor */
+ desc->edma_src = xfer->dt_src.db_addr;
+ desc->edma_dst = xfer->dt_dst.db_addr;
+ desc->edma_opt =
+ DAVINCI_EDMA_OPT_TCINTEN |
+ /* DAVINCI_EDMA_OPT_ITCINTEN | */
+ DAVINCI_EDMA_OPT_SYNCDIM |
+ (chno << DAVINCI_EDMA_OPT_TCCSHIFT);
+ desc->edma_abcnt = (bcnt << 16) | acnt;
+ desc->edma_bidx = (dstbidx << 16) | srcbidx;
+ desc->edma_cidx = 0;
+ desc->edma_ccnt = 1;
+ desc->edma_link = (xfer->dt_next != NULL)
+ ? ((chno + 64) * sizeof(*desc)) + 0x4000
+ : 0xffff;
+
+ return (0);
+}
+
+static __inline uint64_t
+ffs64(uint64_t mask)
+{
+ uint64_t bit;
+
+ if (mask == 0)
+ return (0);
+
+ for (bit = 1; (mask & 1UL) == 0; bit++)
+ mask >>= 1UL;
+
+ return (bit);
+}
+
static device_method_t davinci_edma_methods[] = {
/* Device methods */
DEVMETHOD(device_probe, davinci_edma_probe),
==== //depot/projects/soc2010/jceel_dma/sys/arm/davinci/davinci_edmareg.h#4 (text+ko) ====
@@ -143,6 +143,6 @@
} __packed;
#define DAVINCI_EDMA_PARAM_BASE 0x4000
-#define DAVINCI_EDMA_PARAM(_n) (DAVINCI_EDMA_PARAM_BASE + (_n * sizeof(struct davinci_edma_desc)))
+#define DAVINCI_EDMA_PARAM(_n) (DAVINCI_EDMA_PARAM_BASE + ((_n) * sizeof(struct davinci_edma_desc)))
#endif /* _ARM_DAVINCI_DAVINCI_EDMAREG_H */
More information about the p4-projects
mailing list