/*
* TI EDMA DMA engine driver
*
* Copyright 2012 Texas Instruments
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/platform_data/edma.h>
#include "dmaengine.h"
#include "virt-dma.h"
/*
* This will go away when the private EDMA API is folded
* into this driver and the platform device(s) are
* instantiated in the arch code. We can only get away
* with this simplification because DA8XX may not be built
* in the same kernel image with other DaVinci parts. This
* avoids having to sprinkle dmaengine driver platform devices
* and data throughout all the existing board files.
*/
#ifdef CONFIG_ARCH_DAVINCI_DA8XX
#define EDMA_CTLRS 2
#define EDMA_CHANS 32
#else
#define EDMA_CTLRS 1
#define EDMA_CHANS 64
#endif /* CONFIG_ARCH_DAVINCI_DA8XX */
/*
* Max of 20 segments per channel to conserve PaRAM slots
* Also note that MAX_NR_SG should be atleast the no.of periods
* that are required for ASoC, otherwise DMA prep calls will
* fail. Today davinci-pcm is the only user of this driver and
* requires atleast 17 slots, so we setup the default to 20.
*/
#define MAX_NR_SG 20
#define EDMA_MAX_SLOTS MAX_NR_SG
#define EDMA_DESCRIPTORS 16
struct edma_pset {
struct edmacc_param param;
};
struct edma_desc {
struct virt_dma_desc vdesc;
struct list_head node;
int cyclic;
int absync;
int pset_nr;
int processed;
u32 residue;
struct edma_pset pset[0];
};
struct edma_cc;
struct edma_chan {
struct virt_dma_chan vchan;
struct list_head node;
struct edma_desc *edesc;
struct edma_cc *ecc;
int ch_num;
bool alloced;
int slot[EDMA_MAX_SLOTS];
int missed;
struct dma_slave_config cfg;
};
struct edma_cc {
int ctlr;
struct dma_device dma_slave;
struct edma_chan slave_chans[EDMA_CHANS];
int num_slave_chans;
int dummy_slot;
};
static inline struct edma_cc *to_edma_cc(struct dma_device *d)
{
return container_of(d, struct edma_cc, dma_slave);
}
static inline struct edma_chan *to_edma_chan(struct dma_chan *c)
{
return container_of(c, struct edma_chan, vchan.chan);
}
static inline struct edma_desc
*to_edma_desc(struct dma_async_tx_descriptor *tx)
{
return container_of(tx, struct edma_desc, vdesc.tx);
}
static void edma_desc_free(struct virt_dma_desc *vdesc)
{
kfree(container_of(vdesc, struct edma_desc, vdesc));
}
/* Dispatch a queued descriptor to the controller (caller holds lock) */
static void edma_execute(struct edma_chan *echan)
{
struct virt_dma_desc *vdesc;
struct edma_desc *edesc;
struct device *dev = echan->vchan.chan.device->dev;
int i, j, left, nslots;
/* If either we processed all psets or we're still not started */
if (!echan->edesc ||
echan->edesc->pset_nr == echan->edesc->processed) {
/* Get next vdesc */
vdesc = vchan_next_desc(&echan->vchan);
if (!vdesc) {
echan->edesc = NULL;
return;
}
list_del(&vdesc->node);
echan->edesc = to_edma_desc(&vdesc->tx);
}
edesc = echan->edesc;
/* Find out how many left */
left = edesc->pset_nr - edesc->processed;
nslots = min(MAX_NR_SG, left);
/* Write descriptor PaRAM set(s) */
for (i = 0; i < nslots; i++) {
j = i + edesc->processed;
edma_write_slot(echan->slot[i], &edesc->pset[j].param);
dev_vdbg(echan->vchan.chan.device->dev,
"\n pset[%d]:\n"
" chnum\t%d\n"
" slot\t%d\n"
" opt\t%08x\n"
" src\t%08x\n"
" dst\t%08x\n"
" abcnt\t%08x\n"
" ccnt\t%08x\n"
" bidx\t%08x\n"
" cidx\t%08x\n"