summaryrefslogtreecommitdiff
path: root/drivers/dma
diff options
context:
space:
mode:
authorXinyu Chen <xinyu.chen@freescale.com>2012-08-01 10:03:09 +0800
committerXinyu Chen <xinyu.chen@freescale.com>2012-08-01 10:03:09 +0800
commitd81dac54ea06a1f8a74acf91499d5946d94d9e6a (patch)
treea137a6698343f3dfb880456cc4d89872f2a9b877 /drivers/dma
parentc72eec4afb9215391f06c1a1ce14a63e17ed64e2 (diff)
parent091604c85f017199cae9d437545a96157ab063e0 (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.c131
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)