]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00218013-3 SDMA:Add support for HDMI_SDMA
authorChen Liangjun <b36089@freescale.com>
Mon, 23 Jul 2012 05:53:05 +0000 (13:53 +0800)
committerLothar Waßmann <LW@KARO-electronics.de>
Fri, 24 May 2013 06:35:07 +0000 (08:35 +0200)
1 Add support for HDMI_SDMA config.
2 Add support for HDMI_SDMA interrupt handler.

Signed-off-by: Chen Liangjun <b36089@freescale.com>
drivers/dma/imx-sdma.c

index 9b139c7acf6eac82c65e4bc356938c373c0e5a4d..dc539f91efc671eec9ede52c4fceb1a34d66a94b 100644 (file)
@@ -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)