aboutsummaryrefslogtreecommitdiff
path: root/sys/mips
diff options
context:
space:
mode:
authorRuslan Bukin <br@FreeBSD.org>2018-04-12 15:36:24 +0000
committerRuslan Bukin <br@FreeBSD.org>2018-04-12 15:36:24 +0000
commit3d5b3b0a4487277145ad6cf3bf65da9f5e1d5425 (patch)
tree284ce497263f8409b600d6daedf092372a34d7e6 /sys/mips
parente31b69ec730bfee108c706a71d035792d5524882 (diff)
Notes
Diffstat (limited to 'sys/mips')
-rw-r--r--sys/mips/ingenic/jz4780_aic.c40
-rw-r--r--sys/mips/ingenic/jz4780_pdma.c221
-rw-r--r--sys/mips/ingenic/jz4780_pdma.h8
3 files changed, 159 insertions, 110 deletions
diff --git a/sys/mips/ingenic/jz4780_aic.c b/sys/mips/ingenic/jz4780_aic.c
index d80fecaae6c8..f7a0ff53fac3 100644
--- a/sys/mips/ingenic/jz4780_aic.c
+++ b/sys/mips/ingenic/jz4780_aic.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2016 Ruslan Bukin <br@bsdpad.com>
+ * Copyright (c) 2016-2018 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
@@ -79,9 +79,12 @@ struct aic_softc {
clk_t clk_i2s;
struct aic_rate *sr;
void *ih;
+ int internal_codec;
+
+ /* xDMA */
struct xdma_channel *xchan;
xdma_controller_t *xdma_tx;
- int internal_codec;
+ struct xdma_request req;
};
/* Channel registers */
@@ -288,25 +291,25 @@ aicchan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
}
static int
-aic_intr(void *arg)
+aic_intr(void *arg, xdma_transfer_status_t *status)
{
struct sc_pcminfo *scp;
+ struct xdma_request *req;
xdma_channel_t *xchan;
struct sc_chinfo *ch;
struct aic_softc *sc;
- xdma_config_t *conf;
int bufsize;
scp = arg;
sc = scp->sc;
ch = &scp->chan[0];
+ req = &sc->req;
xchan = sc->xchan;
- conf = &xchan->conf;
bufsize = sndbuf_getsize(ch->buffer);
- sc->pos += conf->block_len;
+ sc->pos += req->block_len;
if (sc->pos >= bufsize)
sc->pos -= bufsize;
@@ -331,20 +334,23 @@ setup_xdma(struct sc_pcminfo *scp)
KASSERT(fmt & AFMT_16BIT, ("16-bit audio supported only."));
- err = xdma_prep_cyclic(sc->xchan,
- XDMA_MEM_TO_DEV, /* direction */
- sc->buf_base_phys, /* src addr */
- sc->aic_fifo_paddr, /* dst addr */
- sndbuf_getblksz(ch->buffer), /* block len */
- sndbuf_getblkcnt(ch->buffer), /* block num */
- 2, /* src port width */
- 2); /* dst port width */
+ sc->req.operation = XDMA_CYCLIC;
+ sc->req.req_type = XR_TYPE_PHYS;
+ sc->req.direction = XDMA_MEM_TO_DEV;
+ sc->req.src_addr = sc->buf_base_phys;
+ sc->req.dst_addr = sc->aic_fifo_paddr;
+ sc->req.src_width = 2;
+ sc->req.dst_width = 2;
+ sc->req.block_len = sndbuf_getblksz(ch->buffer);
+ sc->req.block_num = sndbuf_getblkcnt(ch->buffer);
+
+ err = xdma_request(sc->xchan, &sc->req);
if (err != 0) {
device_printf(sc->dev, "Can't configure virtual channel\n");
return (-1);
}
- xdma_begin(sc->xchan);
+ xdma_control(sc->xchan, XDMA_CMD_BEGIN);
return (0);
}
@@ -385,7 +391,7 @@ aic_stop(struct sc_pcminfo *scp)
reg &= ~(AICCR_TDMS | AICCR_ERPL);
WRITE4(sc, AICCR, reg);
- xdma_terminate(sc->xchan);
+ xdma_control(sc->xchan, XDMA_CMD_TERMINATE);
return (0);
}
@@ -686,7 +692,7 @@ aic_attach(device_t dev)
}
/* Alloc xDMA virtual channel. */
- sc->xchan = xdma_channel_alloc(sc->xdma_tx);
+ sc->xchan = xdma_channel_alloc(sc->xdma_tx, 0);
if (sc->xchan == NULL) {
device_printf(dev, "Can't alloc virtual DMA channel.\n");
return (ENXIO);
diff --git a/sys/mips/ingenic/jz4780_pdma.c b/sys/mips/ingenic/jz4780_pdma.c
index 7800b0a56a77..5637db93a164 100644
--- a/sys/mips/ingenic/jz4780_pdma.c
+++ b/sys/mips/ingenic/jz4780_pdma.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2016 Ruslan Bukin <br@bsdpad.com>
+ * Copyright (c) 2016-2018 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
@@ -61,6 +61,17 @@ __FBSDID("$FreeBSD$");
#include "xdma_if.h"
+#define PDMA_DEBUG
+#undef PDMA_DEBUG
+
+#ifdef PDMA_DEBUG
+#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define dprintf(fmt, ...)
+#endif
+
+#define PDMA_DESC_RING_ALIGN 2048
+
struct pdma_softc {
device_t dev;
struct resource *res[2];
@@ -76,13 +87,22 @@ struct pdma_fdt_data {
};
struct pdma_channel {
- xdma_channel_t *xchan;
struct pdma_fdt_data data;
int cur_desc;
int used;
int index;
int flags;
#define CHAN_DESCR_RELINK (1 << 0)
+
+ /* Descriptors */
+ bus_dma_tag_t desc_tag;
+ bus_dmamap_t desc_map;
+ struct pdma_hwdesc *desc_ring;
+ bus_addr_t desc_ring_paddr;
+
+ /* xDMA */
+ xdma_channel_t *xchan;
+ struct xdma_request *req;
};
#define PDMA_NCHANNELS 32
@@ -102,10 +122,11 @@ static int chan_start(struct pdma_softc *sc, struct pdma_channel *chan);
static void
pdma_intr(void *arg)
{
+ struct xdma_request *req;
+ xdma_transfer_status_t status;
struct pdma_channel *chan;
struct pdma_softc *sc;
xdma_channel_t *xchan;
- xdma_config_t *conf;
int pending;
int i;
@@ -120,7 +141,7 @@ pdma_intr(void *arg)
if (pending & (1 << i)) {
chan = &pdma_channels[i];
xchan = chan->xchan;
- conf = &xchan->conf;
+ req = chan->req;
/* TODO: check for AR, HLT error bits here. */
@@ -130,11 +151,12 @@ pdma_intr(void *arg)
if (chan->flags & CHAN_DESCR_RELINK) {
/* Enable again */
chan->cur_desc = (chan->cur_desc + 1) % \
- conf->block_num;
+ req->block_num;
chan_start(sc, chan);
}
- xdma_callback(chan->xchan);
+ status.error = 0;
+ xdma_callback(chan->xchan, &status);
}
}
}
@@ -217,7 +239,9 @@ chan_start(struct pdma_softc *sc, struct pdma_channel *chan)
/* 8 byte descriptor. */
WRITE4(sc, PDMA_DCS(chan->index), DCS_DES8);
- WRITE4(sc, PDMA_DDA(chan->index), xchan->descs_phys[chan->cur_desc].ds_addr);
+ WRITE4(sc, PDMA_DDA(chan->index),
+ chan->desc_ring_paddr + 8 * 4 * chan->cur_desc);
+
WRITE4(sc, PDMA_DDS, (1 << chan->index));
/* Channel transfer enable. */
@@ -249,6 +273,64 @@ chan_stop(struct pdma_softc *sc, struct pdma_channel *chan)
return (0);
}
+static void
+dwc_get1paddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+{
+
+ if (error != 0)
+ return;
+ *(bus_addr_t *)arg = segs[0].ds_addr;
+}
+
+static int
+pdma_channel_setup_descriptors(device_t dev, struct pdma_channel *chan)
+{
+ struct pdma_softc *sc;
+ int error;
+
+ sc = device_get_softc(dev);
+
+ /*
+ * Set up TX descriptor ring, descriptors, and dma maps.
+ */
+ error = bus_dma_tag_create(
+ bus_get_dma_tag(sc->dev), /* Parent tag. */
+ PDMA_DESC_RING_ALIGN, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ CHAN_DESC_SIZE, 1, /* maxsize, nsegments */
+ CHAN_DESC_SIZE, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &chan->desc_tag);
+ if (error != 0) {
+ device_printf(sc->dev,
+ "could not create TX ring DMA tag.\n");
+ return (-1);
+ }
+
+ error = bus_dmamem_alloc(chan->desc_tag, (void**)&chan->desc_ring,
+ BUS_DMA_COHERENT | BUS_DMA_WAITOK | BUS_DMA_ZERO,
+ &chan->desc_map);
+ if (error != 0) {
+ device_printf(sc->dev,
+ "could not allocate TX descriptor ring.\n");
+ return (-1);
+ }
+
+ error = bus_dmamap_load(chan->desc_tag, chan->desc_map,
+ chan->desc_ring, CHAN_DESC_SIZE, dwc_get1paddr,
+ &chan->desc_ring_paddr, 0);
+ if (error != 0) {
+ device_printf(sc->dev,
+ "could not load TX descriptor ring map.\n");
+ return (-1);
+ }
+
+ return (0);
+}
+
static int
pdma_channel_alloc(device_t dev, struct xdma_channel *xchan)
{
@@ -258,8 +340,6 @@ pdma_channel_alloc(device_t dev, struct xdma_channel *xchan)
sc = device_get_softc(dev);
- xdma_assert_locked();
-
for (i = 0; i < PDMA_NCHANNELS; i++) {
chan = &pdma_channels[i];
if (chan->used == 0) {
@@ -268,6 +348,8 @@ pdma_channel_alloc(device_t dev, struct xdma_channel *xchan)
chan->used = 1;
chan->index = i;
+ pdma_channel_setup_descriptors(dev, chan);
+
return (0);
}
}
@@ -283,8 +365,6 @@ pdma_channel_free(device_t dev, struct xdma_channel *xchan)
sc = device_get_softc(dev);
- xdma_assert_locked();
-
chan = (struct pdma_channel *)xchan->chan;
chan->used = 0;
@@ -292,50 +372,13 @@ pdma_channel_free(device_t dev, struct xdma_channel *xchan)
}
static int
-pdma_channel_prep_memcpy(device_t dev, struct xdma_channel *xchan)
-{
- struct pdma_channel *chan;
- struct pdma_hwdesc *desc;
- struct pdma_softc *sc;
- xdma_config_t *conf;
- int ret;
-
- sc = device_get_softc(dev);
-
- chan = (struct pdma_channel *)xchan->chan;
- /* Ensure we are not in operation */
- chan_stop(sc, chan);
-
- ret = xdma_desc_alloc(xchan, sizeof(struct pdma_hwdesc), 8);
- if (ret != 0) {
- device_printf(sc->dev,
- "%s: Can't allocate descriptors.\n", __func__);
- return (-1);
- }
-
- conf = &xchan->conf;
- desc = (struct pdma_hwdesc *)xchan->descs;
- desc[0].dsa = conf->src_addr;
- desc[0].dta = conf->dst_addr;
- desc[0].drt = DRT_AUTO;
- desc[0].dcm = DCM_SAI | DCM_DAI;
-
- /* 4 byte copy for now. */
- desc[0].dtc = (conf->block_len / 4);
- desc[0].dcm |= DCM_SP_4 | DCM_DP_4 | DCM_TSZ_4;
- desc[0].dcm |= DCM_TIE;
-
- return (0);
-}
-
-static int
-access_width(xdma_config_t *conf, uint32_t *dcm, uint32_t *max_width)
+access_width(struct xdma_request *req, uint32_t *dcm, uint32_t *max_width)
{
*dcm = 0;
- *max_width = max(conf->src_width, conf->dst_width);
+ *max_width = max(req->src_width, req->dst_width);
- switch (conf->src_width) {
+ switch (req->src_width) {
case 1:
*dcm |= DCM_SP_1;
break;
@@ -349,7 +392,7 @@ access_width(xdma_config_t *conf, uint32_t *dcm, uint32_t *max_width)
return (-1);
}
- switch (conf->dst_width) {
+ switch (req->dst_width) {
case 1:
*dcm |= DCM_DP_1;
break;
@@ -381,67 +424,66 @@ access_width(xdma_config_t *conf, uint32_t *dcm, uint32_t *max_width)
}
static int
-pdma_channel_prep_cyclic(device_t dev, struct xdma_channel *xchan)
+pdma_channel_request(device_t dev, struct xdma_channel *xchan, struct xdma_request *req)
{
struct pdma_fdt_data *data;
struct pdma_channel *chan;
struct pdma_hwdesc *desc;
xdma_controller_t *xdma;
struct pdma_softc *sc;
- xdma_config_t *conf;
int max_width;
uint32_t reg;
uint32_t dcm;
- int ret;
int i;
sc = device_get_softc(dev);
- conf = &xchan->conf;
+ dprintf("%s: block_len %d block_num %d\n",
+ __func__, req->block_len, req->block_num);
+
xdma = xchan->xdma;
data = (struct pdma_fdt_data *)xdma->data;
- ret = xdma_desc_alloc(xchan, sizeof(struct pdma_hwdesc), 8);
- if (ret != 0) {
- device_printf(sc->dev,
- "%s: Can't allocate descriptors.\n", __func__);
- return (-1);
- }
-
chan = (struct pdma_channel *)xchan->chan;
/* Ensure we are not in operation */
chan_stop(sc, chan);
- chan->flags = CHAN_DESCR_RELINK;
+ if (req->operation == XDMA_CYCLIC)
+ chan->flags = CHAN_DESCR_RELINK;
chan->cur_desc = 0;
+ chan->req = req;
+
+ for (i = 0; i < req->block_num; i++) {
+ desc = &chan->desc_ring[i];
- desc = (struct pdma_hwdesc *)xchan->descs;
-
- for (i = 0; i < conf->block_num; i++) {
- if (conf->direction == XDMA_MEM_TO_DEV) {
- desc[i].dsa = conf->src_addr + (i * conf->block_len);
- desc[i].dta = conf->dst_addr;
- desc[i].drt = data->tx;
- desc[i].dcm = DCM_SAI;
- } else if (conf->direction == XDMA_DEV_TO_MEM) {
- desc[i].dsa = conf->src_addr;
- desc[i].dta = conf->dst_addr + (i * conf->block_len);
- desc[i].drt = data->rx;
- desc[i].dcm = DCM_DAI;
- } else if (conf->direction == XDMA_MEM_TO_MEM) {
- desc[i].dsa = conf->src_addr + (i * conf->block_len);
- desc[i].dta = conf->dst_addr + (i * conf->block_len);
- desc[i].drt = DRT_AUTO;
- desc[i].dcm = DCM_SAI | DCM_DAI;
+ if (req->direction == XDMA_MEM_TO_DEV) {
+ desc->dsa = req->src_addr + (i * req->block_len);
+ desc->dta = req->dst_addr;
+ desc->drt = data->tx;
+ desc->dcm = DCM_SAI;
+ } else if (req->direction == XDMA_DEV_TO_MEM) {
+ desc->dsa = req->src_addr;
+ desc->dta = req->dst_addr + (i * req->block_len);
+ desc->drt = data->rx;
+ desc->dcm = DCM_DAI;
+ } else if (req->direction == XDMA_MEM_TO_MEM) {
+ desc->dsa = req->src_addr + (i * req->block_len);
+ desc->dta = req->dst_addr + (i * req->block_len);
+ desc->drt = DRT_AUTO;
+ desc->dcm = DCM_SAI | DCM_DAI;
}
- if (access_width(conf, &dcm, &max_width) != 0) {
+ if (access_width(req, &dcm, &max_width) != 0) {
device_printf(dev,
"%s: can't configure access width\n", __func__);
return (-1);
}
- desc[i].dcm |= dcm | DCM_TIE;
- desc[i].dtc = (conf->block_len / max_width);
+ desc->dcm |= dcm | DCM_TIE;
+ desc->dtc = (req->block_len / max_width);
+
+ /*
+ * TODO: bus dma pre read/write sync here
+ */
/*
* PDMA does not provide interrupt after processing each descriptor,
@@ -451,10 +493,10 @@ pdma_channel_prep_cyclic(device_t dev, struct xdma_channel *xchan)
* on each interrupt again.
*/
if ((chan->flags & CHAN_DESCR_RELINK) == 0) {
- if (i != (conf->block_num - 1)) {
- desc[i].dcm |= DCM_LINK;
+ if (i != (req->block_num - 1)) {
+ desc->dcm |= DCM_LINK;
reg = ((i + 1) * sizeof(struct pdma_hwdesc));
- desc[i].dtc |= (reg >> 4) << 24;
+ desc->dtc |= (reg >> 4) << 24;
}
}
}
@@ -522,8 +564,7 @@ static device_method_t pdma_methods[] = {
/* xDMA Interface */
DEVMETHOD(xdma_channel_alloc, pdma_channel_alloc),
DEVMETHOD(xdma_channel_free, pdma_channel_free),
- DEVMETHOD(xdma_channel_prep_cyclic, pdma_channel_prep_cyclic),
- DEVMETHOD(xdma_channel_prep_memcpy, pdma_channel_prep_memcpy),
+ DEVMETHOD(xdma_channel_request, pdma_channel_request),
DEVMETHOD(xdma_channel_control, pdma_channel_control),
#ifdef FDT
DEVMETHOD(xdma_ofw_md_data, pdma_ofw_md_data),
diff --git a/sys/mips/ingenic/jz4780_pdma.h b/sys/mips/ingenic/jz4780_pdma.h
index 93ea1fb644c2..e950077d09d7 100644
--- a/sys/mips/ingenic/jz4780_pdma.h
+++ b/sys/mips/ingenic/jz4780_pdma.h
@@ -37,6 +37,7 @@
#define PDMA_DRT(n) (0x0C + 0x20 * n) /* Channel n Request Source */
#define DRT_AUTO (1 << 3) /* Auto-request. */
#define PDMA_DCS(n) (0x10 + 0x20 * n) /* Channel n Control/Status */
+#define DCS_NDES (1 << 31) /* Non-descriptor mode. */
#define DCS_DES8 (1 << 30) /* Descriptor 8 Word. */
#define DCS_AR (1 << 4) /* Address Error. */
#define DCS_TT (1 << 3) /* Transfer Terminate. */
@@ -45,21 +46,19 @@
#define PDMA_DCM(n) (0x14 + 0x20 * n) /* Channel n Command */
#define DCM_SAI (1 << 23) /* Source Address Increment. */
#define DCM_DAI (1 << 22) /* Destination Address Increment. */
-
#define DCM_SP_S 14 /* Source port width. */
#define DCM_SP_M (0x3 << DCM_SP_S)
#define DCM_SP_1 (0x1 << DCM_SP_S) /* 1 byte */
#define DCM_SP_2 (0x2 << DCM_SP_S) /* 2 bytes */
#define DCM_SP_4 (0x0 << DCM_SP_S) /* 4 bytes */
-
#define DCM_DP_S 12 /* Destination port width. */
#define DCM_DP_M (0x3 << DCM_DP_S)
#define DCM_DP_1 (0x1 << DCM_DP_S) /* 1 byte */
#define DCM_DP_2 (0x2 << DCM_DP_S) /* 2 bytes */
#define DCM_DP_4 (0x0 << DCM_DP_S) /* 4 bytes */
-
#define DCM_TSZ_S 8 /* Transfer Data Size of a data unit. */
#define DCM_TSZ_M (0x7 << DCM_TSZ_S)
+#define DCM_TSZ_A (0x7 << DCM_TSZ_S) /* Autonomy */
#define DCM_TSZ_1 (0x1 << DCM_TSZ_S)
#define DCM_TSZ_2 (0x2 << DCM_TSZ_S)
#define DCM_TSZ_4 (0x0 << DCM_TSZ_S)
@@ -105,3 +104,6 @@ struct pdma_hwdesc {
uint32_t drt; /* DMA Request Type */
uint32_t reserved[2];
};
+
+#define CHAN_DESC_COUNT 4096
+#define CHAN_DESC_SIZE (sizeof(struct pdma_hwdesc) * CHAN_DESC_COUNT)