diff options
author | Xinyu Chen <xinyu.chen@freescale.com> | 2012-08-01 10:03:09 +0800 |
---|---|---|
committer | Xinyu Chen <xinyu.chen@freescale.com> | 2012-08-01 10:03:09 +0800 |
commit | d81dac54ea06a1f8a74acf91499d5946d94d9e6a (patch) | |
tree | a137a6698343f3dfb880456cc4d89872f2a9b877 /drivers/dma | |
parent | c72eec4afb9215391f06c1a1ce14a63e17ed64e2 (diff) | |
parent | 091604c85f017199cae9d437545a96157ab063e0 (diff) |
Merge remote branch 'fsl-linux-sdk/imx_3.0.35' into imx_3.0.35_android
Conflicts:
drivers/mxc/vpu/mxc_vpu.c
Diffstat (limited to 'drivers/dma')
-rw-r--r-- | drivers/dma/imx-sdma.c | 131 |
1 files changed, 104 insertions, 27 deletions
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index a4ed05342168..5e24facd12de 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -256,11 +256,13 @@ struct sdma_channel { unsigned int pc_from_device; unsigned int pc_to_device; unsigned int device_to_device; + unsigned int other_script; unsigned long flags; dma_addr_t per_address, per_address2; u32 event_mask0, event_mask1; u32 watermark_level; u32 shp_addr, per_addr; + u32 data_addr1, data_addr2; struct dma_chan chan; spinlock_t lock; struct dma_async_tx_descriptor desc; @@ -270,7 +272,9 @@ struct sdma_channel { unsigned int chn_real_count; }; -#define IMX_DMA_SG_LOOP (1 << 0) +#define IMX_DMA_SG_LOOP (1 << 0) +#define IMX_DMA_INT_OTHER (1 << 1) +#define IMX_DMA_INT_P2P (1 << 2) #define MAX_DMA_CHANNELS 32 #define MXC_SDMA_DEFAULT_PRIORITY 1 @@ -493,6 +497,15 @@ static void mxc_sdma_handle_channel_normal(struct sdma_channel *sdmac) sdmac->desc.callback(sdmac->desc.callback_param); } + +static void sdma_handle_other_intr(struct sdma_channel *sdmac) +{ + sdmac->last_completed = sdmac->desc.cookie; + + if (sdmac->desc.callback) + sdmac->desc.callback(sdmac->desc.callback_param); +} + static void mxc_sdma_handle_channel(struct sdma_channel *sdmac) { complete(&sdmac->done); @@ -503,6 +516,8 @@ static void mxc_sdma_handle_channel(struct sdma_channel *sdmac) if (sdmac->flags & IMX_DMA_SG_LOOP) sdma_handle_channel_loop(sdmac); + else if (sdmac->flags & IMX_DMA_INT_OTHER) + sdma_handle_other_intr(sdmac); else mxc_sdma_handle_channel_normal(sdmac); } @@ -540,10 +555,12 @@ static void sdma_get_pc(struct sdma_channel *sdmac, * two peripherals or memory-to-memory transfers */ int per_2_per = 0, emi_2_emi = 0; + int other = 0; sdmac->pc_from_device = 0; sdmac->pc_to_device = 0; sdmac->device_to_device = 0; + sdmac->other_script = 0; switch (peripheral_type) { case IMX_DMATYPE_MEMORY: @@ -606,6 +623,8 @@ static void sdma_get_pc(struct sdma_channel *sdmac, case IMX_DMATYPE_IPU_MEMORY: emi_2_per = sdma->script_addrs->ext_mem_2_ipu_addr; break; + case IMX_DMATYPE_HDMI: + other = sdma->script_addrs->hdmi_dma_addr; default: break; } @@ -613,6 +632,27 @@ static void sdma_get_pc(struct sdma_channel *sdmac, sdmac->pc_from_device = per_2_emi; sdmac->pc_to_device = emi_2_per; sdmac->device_to_device = per_2_per; + sdmac->other_script = other; +} + +static int sdma_set_context_reg(struct sdma_channel *sdmac, + struct sdma_context_data *context) +{ + switch (sdmac->peripheral_type) { + case IMX_DMATYPE_HDMI: + context->gReg[4] = sdmac->data_addr1; + context->gReg[6] = sdmac->data_addr2; + break; + default: + context->gReg[0] = sdmac->event_mask1; + context->gReg[1] = sdmac->event_mask0; + context->gReg[2] = sdmac->per_addr; + context->gReg[6] = sdmac->shp_addr; + context->gReg[7] = sdmac->watermark_level; + break; + } + + return 0; } static int sdma_load_context(struct sdma_channel *sdmac) @@ -632,7 +672,7 @@ static int sdma_load_context(struct sdma_channel *sdmac) else if (sdmac->direction == DMA_MEM_TO_DEV) load_address = sdmac->pc_to_device; else - load_address = sdmac->pc_to_device; + load_address = sdmac->other_script; if (load_address < 0) @@ -651,11 +691,7 @@ static int sdma_load_context(struct sdma_channel *sdmac) /* Send by context the event mask,base address for peripheral * and watermark level */ - context->gReg[0] = sdmac->event_mask1; - context->gReg[1] = sdmac->event_mask0; - context->gReg[2] = sdmac->per_addr; - context->gReg[6] = sdmac->shp_addr; - context->gReg[7] = sdmac->watermark_level; + sdma_set_context_reg(sdmac, context); bd0->mode.command = C0_SETDM; bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD; @@ -677,16 +713,47 @@ static void sdma_disable_channel(struct sdma_channel *sdmac) sdmac->status = DMA_ERROR; } +static int sdma_set_chan_private_data(struct sdma_channel *sdmac) +{ + struct sdma_engine *sdma = sdmac->sdma; + struct imx_dma_data *data = sdmac->chan.private; + + sdmac->shp_addr = 0; + sdmac->per_addr = 0; + sdmac->data_addr1 = 0; + sdmac->data_addr2 = 0; + + + if (sdmac->direction == DMA_DEV_TO_DEV) { + sdmac->per_addr = sdmac->per_address; + sdmac->shp_addr = sdmac->per_address2; + } else if (sdmac->direction == DMA_TRANS_NONE) { + switch (sdmac->peripheral_type) { + case IMX_DMATYPE_HDMI: + sdmac->data_addr1 = *(u32 *)data->private;; + sdmac->data_addr2 = *((u32 *)data->private + 1); + break; + default: + dev_dbg(sdma->dev, + "periphal type not support for DMA_TRANS_NONE!\n"); + break; + } + } else { + sdmac->shp_addr = sdmac->per_address; + } + + return 0; +} + static int sdma_config_channel(struct sdma_channel *sdmac) { int ret; + struct imx_dma_data *data = sdmac->chan.private; sdma_disable_channel(sdmac); sdmac->event_mask0 = 0; sdmac->event_mask1 = 0; - sdmac->shp_addr = 0; - sdmac->per_addr = 0; if (sdmac->event_id0) sdma_event_enable(sdmac, sdmac->event_id0); @@ -709,7 +776,8 @@ static int sdma_config_channel(struct sdma_channel *sdmac) sdma_get_pc(sdmac, sdmac->peripheral_type); if ((sdmac->peripheral_type != IMX_DMATYPE_MEMORY) && - (sdmac->peripheral_type != IMX_DMATYPE_DSP)) { + (sdmac->peripheral_type != IMX_DMATYPE_DSP) && + (sdmac->peripheral_type != IMX_DMATYPE_HDMI)) { /* Handle multiple event channels differently */ if (sdmac->event_id1) { if (sdmac->event_id0 > 31) { @@ -748,19 +816,10 @@ static int sdma_config_channel(struct sdma_channel *sdmac) } /* Watermark Level */ sdmac->watermark_level |= sdmac->watermark_level; - /* Address */ - switch (sdmac->direction) { - case DMA_DEV_TO_DEV: - sdmac->per_addr = sdmac->per_address; - sdmac->shp_addr = sdmac->per_address2; - break; - default: - sdmac->shp_addr = sdmac->per_address; - break; - } } else { sdmac->watermark_level = 0; /* FIXME: M3_BASE_ADDRESS */ } + sdma_set_chan_private_data(sdmac); ret = sdma_load_context(sdmac); @@ -1027,7 +1086,7 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic( { struct sdma_channel *sdmac = to_sdma_chan(chan); struct sdma_engine *sdma = sdmac->sdma; - int num_periods = buf_len / period_len; + int num_periods; int channel = sdmac->channel; int ret, i = 0, buf = 0; @@ -1037,13 +1096,33 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic( return NULL; sdmac->status = DMA_IN_PROGRESS; - - sdmac->flags |= IMX_DMA_SG_LOOP; sdmac->direction = direction; + + switch (sdmac->direction) { + case DMA_DEV_TO_DEV: + sdmac->flags |= IMX_DMA_INT_P2P; + break; + case DMA_TRANS_NONE: + sdmac->flags |= IMX_DMA_INT_OTHER; + break; + case DMA_MEM_TO_DEV: + case DMA_DEV_TO_MEM: + sdmac->flags |= IMX_DMA_SG_LOOP; + break; + default: + pr_err("SDMA direction is not support!"); + return NULL; + } + ret = sdma_load_context(sdmac); if (ret) goto err_out; + if (period_len) + num_periods = buf_len / period_len; + else + return &sdmac->desc; + if (num_periods > NUM_BD) { dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n", channel, num_periods, NUM_BD); @@ -1108,8 +1187,6 @@ static int sdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, sdma_disable_channel(sdmac); return 0; case DMA_SLAVE_CONFIG: - - sdmac->direction = dmaengine_cfg->direction; if (dmaengine_cfg->direction == DMA_DEV_TO_DEV) { sdmac->per_address = dmaengine_cfg->src_addr; sdmac->per_address2 = dmaengine_cfg->dst_addr; @@ -1123,7 +1200,7 @@ static int sdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, sdmac->per_address = dmaengine_cfg->src_addr; sdmac->watermark_level = dmaengine_cfg->src_maxburst; sdmac->word_size = dmaengine_cfg->src_addr_width; - } else { + } else if (dmaengine_cfg->direction == DMA_MEM_TO_DEV) { sdmac->per_address = dmaengine_cfg->dst_addr; sdmac->watermark_level = dmaengine_cfg->dst_maxburst; sdmac->word_size = dmaengine_cfg->dst_addr_width; @@ -1159,7 +1236,7 @@ static void sdma_issue_pending(struct dma_chan *chan) */ } -#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 37 +#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 38 static void sdma_add_scripts(struct sdma_engine *sdma, const struct sdma_script_start_addrs *addr) |