Commit 62ef2b07 authored by David Brownell's avatar David Brownell Committed by Kevin Hilman

EDMA: split channel/slot resource management

EDMA interface update for channel and parameter RAM slot alloc/free.
This is the biggest of these changes, since it's non-cosmetic.

 - Stop talking about "master" and "slave"!  Instead, use the notions
   exposed by the hardware:  a DMA "channel", and a PaRAM slot.  This
   is a general doc/comment update, and affects calling conventions.

 - Split davinci_request_dma() into two simpler routines:
     * edma_alloc_channel() with three fewer parameters
     * edma_alloc_slot() with just one parameter (may be a wildcard)
   The test for successful returns is "value < 0", not "value != 0";
   non-negative values are the returned channel or slot number.

 - Split davinci_free_dma() into two routines, both of which update
   the now-free parameter RAM slot to hold a dummy transfer.
     * void edma_free_channel(unsigned channel)
     * void edma_free_slot(unsigned slot);

 - Fill all PaRAM slots with dummy transfers when they're not in use.

 - Change the channel and slot numbers to "unsigned" in some cases so
   we can avoid some tests for invalid parameters.

A key notion here is to *stop* fuzzing distinctions between DMA channels
and parameter RAM slots.  This makes it easier to match these calls to
hardware docs, and harder to get confused by differences; channels are
(potentially) active, while slots are always passive.

Transfer Completion Code (TCC) values are no longer supported except
through the calls which manipulate entire parameter RAM sets.  This
means that completion IRQ setup (for audio) is a bit different.
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarKevin Hilman <khilman@deeprootsystems.com>
parent ff2f60e6
This diff is collapsed.
......@@ -27,26 +27,29 @@
*/
/*
* The EDMA3 framework for DaVinci abstracts DMA Parameter RAM (PaRAM) slots
* as logical DMA channels. There are two types of logical channel:
* This EDMA3 programming framework exposes two basic kinds of resource:
*
* Master Triggers transfers, usually from a hardware event but
* Channel Triggers transfers, usually from a hardware event but
* also manually or by "chaining" from DMA completions.
* Not all PaRAM slots may be masters; and not all masters
* support hardware event triggering.
* Each channel is coupled to a Parameter RAM (PaRAM) slot.
*
* Slave A master may be linked to a "slave" PaRAM slot, used to
* reload master parameters when a transfer finishes. Any
* PaRAM slot may be such a link target.
* Slot Each PaRAM slot holds a DMA transfer descriptor (PaRAM
* "set"), source and destination addresses, a link to a
* next PaRAM slot (if any), options for the transfer, and
* instructions for updating those addresses. There are
* more than twice as many slots as event channels.
*
* Each PaRAM slot holds a DMA transfer descriptor with destination and
* source addresses, a link to the next PaRAM slot (if any), options for
* the transfer, and instructions for updating those addresses.
* Each PaRAM set describes a sequence of transfers, either for one large
* buffer or for several discontiguous smaller buffers. An EDMA transfer
* is driven only from a channel, which performs the transfers specified
* in its PaRAM slot until there are no more transfers. When that last
* transfer completes, the "link" field may be used to reload the channel's
* PaRAM slot with a new transfer descriptor.
*
* The EDMA Channel Controller (CC) maps requests from master channels
* into physical Transfer Controller (TC) requests when the master
* triggers. The two physical DMA channels provided by the TC are thus
* shared by many logical channels.
* The EDMA Channel Controller (CC) maps requests from channels into physical
* Transfer Controller (TC) requests when the channel triggers (by hardware
* or software events, or by chaining). The two physical DMA channels provided
* by the TCs are thus shared by many logical channels.
*
* DaVinci hardware also has a "QDMA" mechanism which is not currently
* supported through this interface. (DSP firmware uses it though.)
......@@ -79,7 +82,7 @@ struct edmacc_param {
#define STATIC BIT(3)
#define EDMA_FWID (0x07 << 8)
#define TCCMODE BIT(11)
#define TCC (0x3f << 12)
#define EDMA_TCC(t) ((t) << 12)
#define TCINTEN BIT(20)
#define ITCINTEN BIT(21)
#define TCCHEN BIT(22)
......@@ -97,13 +100,6 @@ struct edmacc_param {
#define DAVINCI_EDMA_NUM_REGIONS 4
#define DAVINCI_EDMA_MEMPROTECT 0
#define DAVINCI_NUM_UNUSEDCH 21
#define TCC_ANY -1
/* special values understood by davinci_request_dma() */
#define DAVINCI_EDMA_PARAM_ANY -2
#define DAVINCI_DMA_CHANNEL_ANY -1
/* Drivers should avoid using these symbolic names for dm644x
* channels, and use platform_device IORESOURCE_DMA resources
......@@ -185,10 +181,18 @@ enum sync_dimension {
ABSYNC = 1
};
int davinci_request_dma(int dev_id, const char *dev_name,
void (*callback)(int lch, unsigned short ch_status, void *data),
void *data, int *lch, int *tcc, enum dma_event_q);
void davinci_free_dma(int lch);
#define EDMA_CHANNEL_ANY -1 /* for edma_alloc_channel() */
#define EDMA_SLOT_ANY -1 /* for edma_alloc_slot() */
/* alloc/free DMA channels and their dedicated parameter RAM slots */
int edma_alloc_channel(int channel,
void (*callback)(unsigned channel, u16 ch_status, void *data),
void *data, enum dma_event_q);
void edma_free_channel(unsigned channel);
/* alloc/free parameter RAM slots */
int edma_alloc_slot(int slot);
void edma_free_slot(unsigned slot);
/* calls that operate on part of a parameter RAM slot */
void davinci_set_dma_src_params(int lch, dma_addr_t src_port,
......
......@@ -421,7 +421,7 @@ static void davinci_abort_dma(struct mmc_davinci_host *host)
davinci_clean_channel(sync_dev);
}
static void mmc_davinci_dma_cb(int lch, u16 ch_status, void *data)
static void mmc_davinci_dma_cb(unsigned channel, u16 ch_status, void *data)
{
if (DMA_COMPLETE != ch_status) {
struct mmc_davinci_host *host = data;
......@@ -499,7 +499,7 @@ static void __init mmc_davinci_dma_setup(struct mmc_davinci_host *host,
edma_read_slot(sync_dev, template);
/* don't bother with irqs or chaining */
template->opt &= ~(ITCCHEN | TCCHEN | ITCINTEN | TCINTEN);
template->opt |= sync_dev << 12;
}
static int mmc_davinci_send_dma_request(struct mmc_davinci_host *host,
......@@ -572,34 +572,28 @@ davinci_release_dma_channels(struct mmc_davinci_host *host)
if (!host->use_dma)
return;
davinci_free_dma(host->txdma);
davinci_free_dma(host->rxdma);
edma_free_channel(host->txdma);
edma_free_channel(host->rxdma);
}
static int __init davinci_acquire_dma_channels(struct mmc_davinci_host *host)
{
const char *hostname = mmc_hostname(host->mmc);
int edma_chan_num, tcc = 0, r;
enum dma_event_q queue_no = EVENTQ_0;
int r;
/* Acquire master DMA write channel */
r = davinci_request_dma(host->txdma, hostname,
mmc_davinci_dma_cb, host, &edma_chan_num, &tcc, queue_no);
if (r != 0) {
dev_warn(mmc_dev(host->mmc),
"MMC: davinci_request_dma() failed with %d\n",
r);
r = edma_alloc_channel(host->txdma, mmc_davinci_dma_cb, host, EVENTQ_0);
if (r < 0) {
dev_warn(mmc_dev(host->mmc), "alloc %s channel err %d\n",
"tx", r);
return r;
}
mmc_davinci_dma_setup(host, true, &host->tx_template);
/* Acquire master DMA read channel */
r = davinci_request_dma(host->rxdma, hostname,
mmc_davinci_dma_cb, host, &edma_chan_num, &tcc, queue_no);
if (r != 0) {
dev_warn(mmc_dev(host->mmc),
"MMC: davinci_request_dma() failed with %d\n",
r);
r = edma_alloc_channel(host->rxdma, mmc_davinci_dma_cb, host, EVENTQ_0);
if (r < 0) {
dev_warn(mmc_dev(host->mmc), "alloc %s channel err %d\n",
"rx", r);
goto free_master_write;
}
mmc_davinci_dma_setup(host, false, &host->rx_template);
......@@ -607,7 +601,7 @@ static int __init davinci_acquire_dma_channels(struct mmc_davinci_host *host)
return 0;
free_master_write:
davinci_free_dma(host->txdma);
edma_free_channel(host->txdma);
return r;
}
......
......@@ -108,12 +108,12 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
prtd->period = 0;
}
static void davinci_pcm_dma_irq(int lch, u16 ch_status, void *data)
static void davinci_pcm_dma_irq(unsigned channel, u16 ch_status, void *data)
{
struct snd_pcm_substream *substream = data;
struct davinci_runtime_data *prtd = substream->runtime->private_data;
DPRINTK("lch=%d, status=0x%x\n", lch, ch_status);
DPRINTK("channel=%d, status=0x%x\n", channel, ch_status);
if (unlikely(ch_status != DMA_COMPLETE))
return;
......@@ -132,7 +132,7 @@ static int davinci_pcm_dma_request(struct snd_pcm_substream *substream)
struct davinci_runtime_data *prtd = substream->runtime->private_data;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct davinci_pcm_dma_params *dma_data = rtd->dai->cpu_dai->dma_data;
int tcc = TCC_ANY;
struct edmacc_param p_ram;
int ret;
if (!dma_data)
......@@ -141,22 +141,34 @@ static int davinci_pcm_dma_request(struct snd_pcm_substream *substream)
prtd->params = dma_data;
/* Request master DMA channel */
ret = davinci_request_dma(prtd->params->channel, prtd->params->name,
ret = edma_alloc_channel(prtd->params->channel,
davinci_pcm_dma_irq, substream,
&prtd->master_lch, &tcc, EVENTQ_0);
if (ret)
EVENTQ_0);
if (ret < 0)
return ret;
prtd->master_lch = ret;
/* Request parameter RAM reload slot */
ret = davinci_request_dma(DAVINCI_EDMA_PARAM_ANY, "Link",
NULL, NULL, &prtd->slave_lch, &tcc, EVENTQ_0);
if (ret) {
davinci_free_dma(prtd->master_lch);
ret = edma_alloc_slot(EDMA_SLOT_ANY);
if (ret < 0) {
edma_free_channel(prtd->master_lch);
return ret;
}
/* Link parameter RAM to itself in loopback */
edma_link(prtd->slave_lch, prtd->slave_lch);
prtd->slave_lch = ret;
/* Issue transfer completion IRQ when the channel completes a
* transfer, then always reload from the same slot (by a kind
* of loopback link). The completion IRQ handler will update
* the reload slot with a new buffer.
*
* REVISIT save p_ram here after setting up everything except
* the buffer and its length (ccnt) ... use it as a template
* so davinci_pcm_enqueue_dma() takes less time in IRQ.
*/
edma_read_slot(prtd->slave_lch, &p_ram);
p_ram.opt |= TCINTEN | EDMA_TCC(prtd->master_lch);
p_ram.link_bcntrld = prtd->slave_lch << 5;
edma_write_slot(prtd->slave_lch, &p_ram);
return 0;
}
......@@ -262,8 +274,8 @@ static int davinci_pcm_close(struct snd_pcm_substream *substream)
edma_unlink(prtd->slave_lch);
davinci_free_dma(prtd->slave_lch);
davinci_free_dma(prtd->master_lch);
edma_free_slot(prtd->slave_lch);
edma_free_channel(prtd->master_lch);
kfree(prtd);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment