gdc: add gdc workqueue [1/1]
authorPengcheng Chen <pengcheng.chen@amlogic.com>
Fri, 17 May 2019 09:18:03 +0000 (17:18 +0800)
committerPengcheng Chen <pengcheng.chen@amlogic.com>
Mon, 17 Jun 2019 02:40:43 +0000 (10:40 +0800)
PD#SWPL-9642

Problem:
gdc can't support multi-thread, need add workqueue

Solution:
add gdc workqueue

Verify:
verified by w400

Change-Id: Icbe0b872775c0ab5445d260d49ff244528d8200b
Signed-off-by: Pengcheng Chen <pengcheng.chen@amlogic.com>
MAINTAINERS
drivers/amlogic/media/gdc/Makefile
drivers/amlogic/media/gdc/app/gdc_main.c
drivers/amlogic/media/gdc/app/gdc_module.c
drivers/amlogic/media/gdc/app/gdc_wq.c [new file with mode: 0644]
drivers/amlogic/media/gdc/app/gdc_wq.h [new file with mode: 0644]
drivers/amlogic/media/gdc/inc/api/gdc_api.h
drivers/amlogic/media/gdc/inc/gdc/gdc_config.h
drivers/amlogic/media/gdc/src/fw_lib/acamera_gdc.c

index 7b258a1..b5cbd05 100644 (file)
@@ -14963,4 +14963,9 @@ F:  arch/arm/configs/meson64_a32_defconfig
 F:  arch/arm64/boot/dts/amlogic/sm1_s905d3_ac202.dts
 F:  arch/arm64/boot/dts/amlogic/sm1_s905d3_ac202_1g.dts
 F:  arch/arm64/configs/meson64_defconfig
-F:  drivers/amlogic/media/camera/gc2145_mipi.c
\ No newline at end of file
+F:  drivers/amlogic/media/camera/gc2145_mipi.c
+
+AMLOGIC GDC DRIVER
+M:     Pengcheng Chen <pengcheng.chen@amlogic.com>
+F:     drivers/amlogic/media/gdc/app/gdc_wq.c
+F:     drivers/amlogic/media/gdc/app/gdc_wq.h
index d0d4b27..0d1b3a6 100644 (file)
@@ -2,7 +2,8 @@ FW_SRC := src/fw_lib/acamera_gdc.c \
        src/platform/system_gdc_io.c \
        app/gdc_main.c \
        app/gdc_module.c \
-       app/gdc_dmabuf.c
+       app/gdc_dmabuf.c \
+       app/gdc_wq.c
 
 FW_SRC_OBJ := $(FW_SRC:.c=.o)
 
index 538416d..8827123 100644 (file)
 //gdc api functions
 #include "gdc_api.h"
 
-irqreturn_t interrupt_handler_next(int irq, void *param)
-{
-       //handle the start of frame with gdc_process
-       struct gdc_cmd_s *gdc_cmd = (struct gdc_cmd_s *)param;
-
-       gdc_get_frame(gdc_cmd);
-
-       return IRQ_HANDLED;
-}
-
 int gdc_run(struct gdc_cmd_s *g)
 {
 
index 2191096..211bb83 100644 (file)
 //gdc configuration sequence
 #include "gdc_config.h"
 #include "gdc_dmabuf.h"
+#include "gdc_wq.h"
 
 unsigned int gdc_log_level;
-unsigned int gdc_reg_store_mode;
 struct gdc_manager_s gdc_manager;
-static int trace_mode_enable;
-static char *config_out_file;
-static int config_out_path_defined;
+unsigned int gdc_reg_store_mode;
+int trace_mode_enable;
+char *config_out_file;
+int config_out_path_defined;
 
-#define WAIT_THRESHOLD   1000
 #define CONFIG_PATH_LENG 128
 #define CORE_CLK_RATE 800000000
 #define AXI_CLK_RATE  800000000
@@ -71,142 +71,132 @@ static void meson_gdc_cache_flush(struct device *dev,
 //////
 static int meson_gdc_open(struct inode *inode, struct file *file)
 {
-       struct meson_gdc_dev_t *gdc_dev = gdc_manager.gdc_dev;
-       struct mgdc_fh_s *fh = NULL;
-       char ion_client_name[32];
-       int rc = 0;
-
-       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-       if (fh == NULL) {
-               gdc_log(LOG_DEBUG, "devm alloc failed\n");
-               return -ENOMEM;
-       }
+       struct gdc_context_s *context = NULL;
 
-       get_task_comm(fh->task_comm, current);
-       gdc_log(LOG_DEBUG, "%s, %d, call from %s\n",
-                       __func__, __LINE__, fh->task_comm);
-
-       file->private_data = fh;
-       snprintf(ion_client_name, sizeof(fh->task_comm),
-                       "gdc-%s", fh->task_comm);
-       if (!fh->ion_client)
-               fh->ion_client = meson_ion_client_create(-1, ion_client_name);
+       /* we create one gdc  workqueue for this file handler. */
+       context = create_gdc_work_queue();
+       if (!context) {
+               gdc_log(LOG_ERR, "can't create work queue\n");
+               return -1;
+       }
 
-       fh->gdev = gdc_dev;
+       file->private_data = context;
 
        gdc_log(LOG_INFO, "Success open\n");
 
-       return rc;
+       return 0;
 }
 
 static int meson_gdc_release(struct inode *inode, struct file *file)
 {
-       struct mgdc_fh_s *fh = file->private_data;
+       struct gdc_context_s *context = NULL;
        struct page *cma_pages = NULL;
        bool rc = false;
        int ret = 0;
+       struct device *dev = &gdc_manager.gdc_dev->pdev->dev;
 
-       if (fh->ion_client) {
-               ion_client_destroy(fh->ion_client);
-               fh->ion_client = NULL;
+       context = (struct gdc_context_s *)file->private_data;
+       if (!context) {
+               gdc_log(LOG_ERR, "context is null,release work queue error\n");
+               return -1;
        }
 
-       if (fh->i_kaddr != 0 && fh->i_len != 0) {
-               cma_pages = virt_to_page(fh->i_kaddr);
-               rc = dma_release_from_contiguous(&fh->gdev->pdev->dev,
+       if (context->i_kaddr != 0 && context->i_len != 0) {
+               cma_pages = virt_to_page(context->i_kaddr);
+               rc = dma_release_from_contiguous(dev,
                                                cma_pages,
-                                               fh->i_len >> PAGE_SHIFT);
+                                               context->i_len >> PAGE_SHIFT);
                if (rc == false) {
                        ret = ret - 1;
                        gdc_log(LOG_ERR, "Failed to release input buff\n");
                }
-
-               fh->i_kaddr = NULL;
-               fh->i_paddr = 0;
-               fh->i_len = 0;
+               mutex_lock(&context->d_mutext);
+               context->i_kaddr = NULL;
+               context->i_paddr = 0;
+               context->i_len = 0;
+               mutex_unlock(&context->d_mutext);
        }
 
-       if (fh->o_kaddr != 0 && fh->o_len != 0) {
-               cma_pages = virt_to_page(fh->o_kaddr);
-               rc = dma_release_from_contiguous(&fh->gdev->pdev->dev,
+       if (context->o_kaddr != 0 && context->o_len != 0) {
+               cma_pages = virt_to_page(context->o_kaddr);
+               rc = dma_release_from_contiguous(dev,
                                                cma_pages,
-                                               fh->o_len >> PAGE_SHIFT);
+                                               context->o_len >> PAGE_SHIFT);
                if (rc == false) {
                        ret = ret - 1;
                        gdc_log(LOG_ERR, "Failed to release output buff\n");
                }
-
-               fh->o_kaddr = NULL;
-               fh->o_paddr = 0;
-               fh->o_len = 0;
+               mutex_lock(&context->d_mutext);
+               context->o_kaddr = NULL;
+               context->o_paddr = 0;
+               context->o_len = 0;
+               mutex_unlock(&context->d_mutext);
        }
 
-       if (fh->c_kaddr != 0 && fh->c_len != 0) {
-               cma_pages = virt_to_page(fh->c_kaddr);
-               rc = dma_release_from_contiguous(&fh->gdev->pdev->dev,
+       if (context->c_kaddr != 0 && context->c_len != 0) {
+               cma_pages = virt_to_page(context->c_kaddr);
+               rc = dma_release_from_contiguous(dev,
                                                cma_pages,
-                                               fh->c_len >> PAGE_SHIFT);
+                                               context->c_len >> PAGE_SHIFT);
                if (rc == false) {
                        ret = ret - 1;
                        gdc_log(LOG_ERR, "Failed to release config buff\n");
                }
-
-               fh->c_kaddr = NULL;
-               fh->c_paddr = 0;
-               fh->c_len = 0;
+               mutex_lock(&context->d_mutext);
+               context->c_kaddr = NULL;
+               context->c_paddr = 0;
+               context->c_len = 0;
+               mutex_unlock(&context->d_mutext);
        }
-
-       kfree(fh);
-       fh = NULL;
-
-       if (ret == 0)
-               gdc_log(LOG_INFO, "Success release\n");
-       else
-               gdc_log(LOG_ERR, "Error release\n");
+       if (destroy_gdc_work_queue(context) == 0)
+               gdc_log(LOG_INFO, "release one gdc device\n");
 
        return ret;
 }
 
-static long meson_gdc_set_buff(void *f_fh,
+static long meson_gdc_set_buff(struct gdc_context_s *context,
                                        struct page *cma_pages,
                                        unsigned long len)
 {
        int ret = 0;
-       struct mgdc_fh_s *fh = NULL;
 
-       if (f_fh == NULL || cma_pages == NULL || len == 0) {
+       if (context == NULL || cma_pages == NULL || len == 0) {
                gdc_log(LOG_ERR, "Error input param\n");
                return -EINVAL;
        }
 
-       fh = f_fh;
-
-       switch (fh->mmap_type) {
+       switch (context->mmap_type) {
        case INPUT_BUFF_TYPE:
-               if (fh->i_paddr != 0 && fh->i_kaddr != NULL)
+               if (context->i_paddr != 0 && context->i_kaddr != NULL)
                        return -EAGAIN;
-               fh->i_paddr = page_to_phys(cma_pages);
-               fh->i_kaddr = phys_to_virt(fh->i_paddr);
-               fh->i_len = len;
+               mutex_lock(&context->d_mutext);
+               context->i_paddr = page_to_phys(cma_pages);
+               context->i_kaddr = phys_to_virt(context->i_paddr);
+               context->i_len = len;
+               mutex_unlock(&context->d_mutext);
        break;
        case OUTPUT_BUFF_TYPE:
-               if (fh->o_paddr != 0 && fh->o_kaddr != NULL)
+               if (context->o_paddr != 0 && context->o_kaddr != NULL)
                        return -EAGAIN;
-               fh->o_paddr = page_to_phys(cma_pages);
-               fh->o_kaddr = phys_to_virt(fh->o_paddr);
-               fh->o_len = len;
-               meson_gdc_cache_flush(&fh->gdev->pdev->dev,
-                       fh->o_paddr, fh->o_len);
+               mutex_lock(&context->d_mutext);
+               context->o_paddr = page_to_phys(cma_pages);
+               context->o_kaddr = phys_to_virt(context->o_paddr);
+               context->o_len = len;
+               mutex_unlock(&context->d_mutext);
+               meson_gdc_cache_flush(&gdc_manager.gdc_dev->pdev->dev,
+                       context->o_paddr, context->o_len);
        break;
        case CONFIG_BUFF_TYPE:
-               if (fh->c_paddr != 0 && fh->c_kaddr != NULL)
+               if (context->c_paddr != 0 && context->c_kaddr != NULL)
                        return -EAGAIN;
-               fh->c_paddr = page_to_phys(cma_pages);
-               fh->c_kaddr = phys_to_virt(fh->c_paddr);
-               fh->c_len = len;
+               mutex_lock(&context->d_mutext);
+               context->c_paddr = page_to_phys(cma_pages);
+               context->c_kaddr = phys_to_virt(context->c_paddr);
+               context->c_len = len;
+               mutex_unlock(&context->d_mutext);
        break;
        default:
-               gdc_log(LOG_ERR, "Error mmap type:0x%x\n", fh->mmap_type);
+               gdc_log(LOG_ERR, "Error mmap type:0x%x\n", context->mmap_type);
                ret = -EINVAL;
        break;
        }
@@ -399,25 +389,26 @@ static void meson_gdc_dma_unmap(struct gdc_dma_cfg *cfg)
        dma_buf_put(dbuf);
 }
 
-static long meson_gdc_init_dma_addr(struct mgdc_fh_s *fh,
+static long meson_gdc_init_dma_addr(
+       struct gdc_context_s *context,
        struct gdc_settings *gs)
 {
        long ret = -1;
        struct gdc_dma_cfg *dma_cfg = NULL;
-       struct gdc_cmd_s *gdc_cmd = &fh->gdc_cmd;
+       struct gdc_cmd_s *gdc_cmd = &context->cmd;
        struct gdc_config_s *gc = &gdc_cmd->gdc_config;
 
-       if (fh == NULL || gs == NULL) {
+       if (context == NULL || gs == NULL) {
                gdc_log(LOG_ERR, "Error input param\n");
                return -EINVAL;
        }
 
        switch (gc->format) {
        case NV12:
-               dma_cfg = &fh->y_dma_cfg;
+               dma_cfg = &context->y_dma_cfg;
                memset(dma_cfg, 0, sizeof(*dma_cfg));
                dma_cfg->dir = DMA_TO_DEVICE;
-               dma_cfg->dev = &fh->gdev->pdev->dev;
+               dma_cfg->dev = &gdc_manager.gdc_dev->pdev->dev;
                dma_cfg->fd = gs->y_base_fd;
 
                ret = meson_gdc_dma_map(dma_cfg);
@@ -428,10 +419,10 @@ static long meson_gdc_init_dma_addr(struct mgdc_fh_s *fh,
 
                gdc_cmd->y_base_addr = virt_to_phys(dma_cfg->vaddr);
 
-               dma_cfg = &fh->uv_dma_cfg;
+               dma_cfg = &context->uv_dma_cfg;
                memset(dma_cfg, 0, sizeof(*dma_cfg));
                dma_cfg->dir = DMA_TO_DEVICE;
-               dma_cfg->dev = &fh->gdev->pdev->dev;
+               dma_cfg->dev = &gdc_manager.gdc_dev->pdev->dev;
                dma_cfg->fd = gs->uv_base_fd;
 
                ret = meson_gdc_dma_map(dma_cfg);
@@ -443,10 +434,10 @@ static long meson_gdc_init_dma_addr(struct mgdc_fh_s *fh,
                gdc_cmd->uv_base_addr = virt_to_phys(dma_cfg->vaddr);
        break;
        case Y_GREY:
-               dma_cfg = &fh->y_dma_cfg;
+               dma_cfg = &context->y_dma_cfg;
                memset(dma_cfg, 0, sizeof(*dma_cfg));
                dma_cfg->dir = DMA_TO_DEVICE;
-               dma_cfg->dev = &fh->gdev->pdev->dev;
+               dma_cfg->dev = &gdc_manager.gdc_dev->pdev->dev;
                dma_cfg->fd = gs->y_base_fd;
 
                ret = meson_gdc_dma_map(dma_cfg);
@@ -465,27 +456,27 @@ static long meson_gdc_init_dma_addr(struct mgdc_fh_s *fh,
        return ret;
 }
 
-static void meson_gdc_deinit_dma_addr(struct mgdc_fh_s *fh)
+static void meson_gdc_deinit_dma_addr(struct gdc_context_s *context)
 {
        struct gdc_dma_cfg *dma_cfg = NULL;
-       struct gdc_cmd_s *gdc_cmd = &fh->gdc_cmd;
+       struct gdc_cmd_s *gdc_cmd = &context->cmd;
        struct gdc_config_s *gc = &gdc_cmd->gdc_config;
 
-       if (fh == NULL) {
+       if (context == NULL) {
                gdc_log(LOG_ERR, "Error input param\n");
                return;
        }
 
        switch (gc->format) {
        case NV12:
-               dma_cfg = &fh->y_dma_cfg;
+               dma_cfg = &context->y_dma_cfg;
                meson_gdc_dma_unmap(dma_cfg);
 
-               dma_cfg = &fh->uv_dma_cfg;
+               dma_cfg = &context->uv_dma_cfg;
                meson_gdc_dma_unmap(dma_cfg);
        break;
        case Y_GREY:
-               dma_cfg = &fh->y_dma_cfg;
+               dma_cfg = &context->y_dma_cfg;
                meson_gdc_dma_unmap(dma_cfg);
        break;
        default:
@@ -540,179 +531,165 @@ static int gdc_buffer_unmap(struct aml_dma_cfg *cfg)
        return gdc_dma_buffer_unmap_info(gdc_manager.buffer, cfg);
 }
 
-static long gdc_process_input_dma_info(struct mgdc_fh_s *fh,
-       struct gdc_settings_ex *gs_ex)
+static int gdc_get_buffer_fd(int plane_id, struct gdc_buffer_info *buf_info)
 {
-       long ret = -1;
-       unsigned long addr;
-       struct aml_dma_cfg *cfg = NULL;
-       struct gdc_cmd_s *gdc_cmd = &fh->gdc_cmd;
-       struct gdc_config_s *gc = &gdc_cmd->gdc_config;
+       int fd;
 
-       if (fh == NULL || gs_ex == NULL) {
-               gdc_log(LOG_ERR, "Error input param\n");
+       switch (plane_id) {
+       case 0:
+               fd = buf_info->y_base_fd;
+               break;
+       case 1:
+               fd = buf_info->uv_base_fd;
+               break;
+       case 2:
+               fd = buf_info->v_base_fd;
+               break;
+       default:
+               gdc_log(LOG_ERR, "Error plane id\n");
                return -EINVAL;
        }
-       if (gs_ex->input_buffer.plane_number < 1 ||
-               gs_ex->input_buffer.plane_number > 3) {
-               gdc_log(LOG_ERR, "%s, plane_number=%d invalid\n",
-               __func__, gs_ex->input_buffer.plane_number);
+       return fd;
+}
+
+static int gdc_set_output_addr(int plane_id,
+       uint32_t addr,
+       struct gdc_cmd_s *gdc_cmd)
+{
+       switch (plane_id) {
+       case 0:
+               gdc_cmd->buffer_addr = addr;
+               gdc_cmd->current_addr = addr;
+               break;
+       case 1:
+               gdc_cmd->uv_out_base_addr = addr;
+               break;
+       case 2:
+               gdc_cmd->v_out_base_addr = addr;
+               break;
+       default:
+               gdc_log(LOG_ERR, "Error plane id\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static long gdc_set_input_addr(int plane_id,
+                                       uint32_t addr,
+                                       struct gdc_cmd_s *gdc_cmd)
+{
+       struct gdc_config_s *gc = NULL;
+       long size;
+
+       if (gdc_cmd == NULL || addr == 0) {
+               gdc_log(LOG_ERR, "Error input param\n");
                return -EINVAL;
        }
 
+       gc = &gdc_cmd->gdc_config;
+
        switch (gc->format) {
        case NV12:
-               if (gs_ex->input_buffer.plane_number == 1) {
-                       cfg = &fh->dma_cfg.input_cfg_plane1;
-                       cfg->fd = gs_ex->input_buffer.y_base_fd;
-                       cfg->dev = &fh->gdev->pdev->dev;
-                       cfg->dir = DMA_TO_DEVICE;
-
-                       ret = gdc_buffer_get_phys(cfg, &addr);
-                       if (ret < 0) {
-                               gdc_log(LOG_ERR,
-                                       "dma import input fd %d err\n",
-                                       gs_ex->input_buffer.y_base_fd);
-                               return -EINVAL;
-                       }
-                       ret = meson_gdc_set_input_addr(addr, gdc_cmd);
-                       if (ret != 0) {
-                               gdc_log(LOG_ERR, "set input addr err\n");
-                               return -EINVAL;
-                       }
-                       gdc_log(LOG_INFO, "1 plane get input addr=%x\n",
-                               gdc_cmd->y_base_addr);
-               } else if (gs_ex->input_buffer.plane_number == 2) {
-                       cfg = &fh->dma_cfg.input_cfg_plane1;
-                       cfg->fd = gs_ex->input_buffer.y_base_fd;
-                       cfg->dev = &fh->gdev->pdev->dev;
-                       cfg->dir = DMA_TO_DEVICE;
-                       ret = gdc_buffer_get_phys(cfg, &addr);
-                       if (ret < 0) {
-                               gdc_log(LOG_ERR,
-                                       "dma import input fd %d err\n",
-                                       gs_ex->input_buffer.y_base_fd);
-                               return -EINVAL;
-                       }
+               if (plane_id == 0) {
                        gdc_cmd->y_base_addr = addr;
-                       cfg = &fh->dma_cfg.input_cfg_plane2;
-                       cfg->fd = gs_ex->input_buffer.uv_base_fd;
-                       cfg->dev = &fh->gdev->pdev->dev;
-                       cfg->dir = DMA_TO_DEVICE;
-                       ret = gdc_buffer_get_phys(cfg, &addr);
-                       if (ret < 0) {
-                               gdc_log(LOG_ERR,
-                                       "dma import input fd %d err\n",
-                                       gs_ex->input_buffer.uv_base_fd);
-                               return -EINVAL;
-                       }
+                       size = gc->input_y_stride * gc->input_height;
+               } else if (plane_id == 1) {
                        gdc_cmd->uv_base_addr = addr;
-                       gdc_log(LOG_INFO, "2 plane get input y_addr=%x\n",
-                               gdc_cmd->y_base_addr);
-                       gdc_log(LOG_INFO, "2 plane get input uv_addr=%x\n",
-                               gdc_cmd->uv_base_addr);
-               }
-       break;
+                       size = gc->input_y_stride * gc->input_height / 2;
+               } else
+                       gdc_log(LOG_ERR,
+                               "plane_id=%d is invalid for NV12\n",
+                               plane_id);
+               break;
        case YV12:
-       case YUV444_P:
-               if (gs_ex->input_buffer.plane_number == 1) {
-                       cfg = &fh->dma_cfg.input_cfg_plane1;
-                       cfg->fd = gs_ex->input_buffer.y_base_fd;
-                       cfg->dev = &fh->gdev->pdev->dev;
-                       cfg->dir = DMA_TO_DEVICE;
-
-                       ret = gdc_buffer_get_phys(cfg, &addr);
-                       if (ret < 0) {
-                               gdc_log(LOG_ERR,
-                                       "dma import input fd %d err\n",
-                                       gs_ex->input_buffer.y_base_fd);
-                               return -EINVAL;
-                       }
-                       ret = meson_gdc_set_input_addr(addr, gdc_cmd);
-                       if (ret != 0) {
-                               gdc_log(LOG_ERR, "set input addr err\n");
-                               return -EINVAL;
-                       }
-                       gdc_log(LOG_INFO, "1 plane get input addr=%x\n",
-                               gdc_cmd->y_base_addr);
-               } else if (gs_ex->input_buffer.plane_number == 3) {
-                       cfg = &fh->dma_cfg.input_cfg_plane1;
-                       cfg->fd = gs_ex->input_buffer.y_base_fd;
-                       cfg->dev = &fh->gdev->pdev->dev;
-                       cfg->dir = DMA_TO_DEVICE;
-                       ret = gdc_buffer_get_phys(cfg, &addr);
-                       if (ret < 0) {
-                               gdc_log(LOG_ERR,
-                                       "dma import input fd %d err\n",
-                                       gs_ex->input_buffer.y_base_fd);
-                               return -EINVAL;
-                       }
+               if (plane_id == 0) {
                        gdc_cmd->y_base_addr = addr;
-                       cfg = &fh->dma_cfg.input_cfg_plane2;
-                       cfg->fd = gs_ex->input_buffer.u_base_fd;
-                       cfg->dev = &fh->gdev->pdev->dev;
-                       cfg->dir = DMA_TO_DEVICE;
-                       ret = gdc_buffer_get_phys(cfg, &addr);
-                       if (ret < 0) {
-                               gdc_log(LOG_ERR,
-                                       "dma import input fd %d err\n",
-                                       gs_ex->input_buffer.u_base_fd);
-                               return -EINVAL;
-                       }
+                       size = gc->input_y_stride * gc->input_height;
+               } else if (plane_id == 1) {
                        gdc_cmd->u_base_addr = addr;
-                       cfg = &fh->dma_cfg.input_cfg_plane3;
-                       cfg->fd = gs_ex->input_buffer.v_base_fd;
-                       cfg->dev = &fh->gdev->pdev->dev;
-                       cfg->dir = DMA_TO_DEVICE;
-                       ret = gdc_buffer_get_phys(cfg, &addr);
-                       if (ret < 0) {
-                               gdc_log(LOG_ERR,
-                                       "dma import input fd %d err\n",
-                                       gs_ex->input_buffer.u_base_fd);
-                               return -EINVAL;
-                       }
+                       size = gc->input_c_stride * gc->input_height / 2;
+               } else if (plane_id == 2) {
                        gdc_cmd->v_base_addr = addr;
-                       gdc_log(LOG_INFO, "3 plane get input y_addr=%x\n",
-                               gdc_cmd->y_base_addr);
-                       gdc_log(LOG_INFO, "3 plane get input u_addr=%x\n",
-                               gdc_cmd->u_base_addr);
-                       gdc_log(LOG_INFO, "3 plane get input v_addr=%x\n",
-                               gdc_cmd->v_base_addr);
-               }
-       break;
+                       size = gc->input_c_stride * gc->input_height / 2;
+               } else
+                       gdc_log(LOG_ERR,
+                               "plane_id=%d is invalid for YV12\n",
+                               plane_id);
+               break;
        case Y_GREY:
+               if (plane_id == 0) {
+                       gdc_cmd->y_base_addr = addr;
+                       gdc_cmd->u_base_addr = 0;
+                       gdc_cmd->v_base_addr = 0;
+                       size = gc->input_y_stride * gc->input_height;
+               } else
+                       gdc_log(LOG_ERR,
+                               "plane_id=%d is invalid for Y_GREY\n",
+                               plane_id);
+               break;
+       case YUV444_P:
        case RGB444_P:
-               cfg = &fh->dma_cfg.input_cfg_plane1;
-               cfg->fd = gs_ex->input_buffer.y_base_fd;
-               cfg->dev = &(fh->gdev->pdev->dev);
-               cfg->dir = DMA_TO_DEVICE;
-               ret = gdc_buffer_get_phys(cfg, &addr);
-               if (ret < 0) {
+               size = gc->input_y_stride * gc->input_height;
+               if (plane_id == 0)
+                       gdc_cmd->y_base_addr = addr;
+               else if (plane_id == 1)
+                       gdc_cmd->u_base_addr = addr;
+               else if (plane_id == 2)
+                       gdc_cmd->v_base_addr = addr;
+               else
                        gdc_log(LOG_ERR,
-                               "dma import input fd %d failed\n",
-                               gs_ex->input_buffer.shared_fd);
-                       return -EINVAL;
-               }
-               gdc_cmd->y_base_addr = addr;
-               gdc_cmd->uv_base_addr = 0;
-       break;
+                               "plane_id=%d is invalid for format=%d\n",
+                               plane_id, gc->format);
+               break;
        default:
-               gdc_log(LOG_ERR, "Error image format");
-       break;
+               gdc_log(LOG_ERR, "Error config format=%d\n", gc->format);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static long gdc_get_input_size(struct gdc_cmd_s *gdc_cmd)
+{
+       struct gdc_config_s *gc = NULL;
+       long size;
+
+       if (gdc_cmd == NULL) {
+               gdc_log(LOG_ERR, "Error input param\n");
+               return -EINVAL;
+       }
+
+       gc = &gdc_cmd->gdc_config;
+
+       switch (gc->format) {
+       case NV12:
+       case YV12:
+               size = gc->input_y_stride * gc->input_height * 3 / 2;
+               break;
+       case Y_GREY:
+               size = gc->input_y_stride * gc->input_height;
+               break;
+       case YUV444_P:
+       case RGB444_P:
+               size = gc->input_y_stride * gc->input_height * 3;
+               break;
+       default:
+               gdc_log(LOG_ERR, "Error config format\n");
+               return -EINVAL;
        }
        return 0;
 }
 
-static long gdc_process_input_ion_info(struct mgdc_fh_s *fh,
+static long gdc_process_input_dma_info(struct gdc_context_s *context,
        struct gdc_settings_ex *gs_ex)
 {
        long ret = -1;
        unsigned long addr;
-       size_t len;
-       struct gdc_cmd_s *gdc_cmd = &fh->gdc_cmd;
-       struct gdc_config_s *gc = &gdc_cmd->gdc_config;
+       long size;
+       struct aml_dma_cfg *cfg = NULL;
+       struct gdc_cmd_s *gdc_cmd = &context->cmd;
+       int i, plane_number;
 
-       if (fh == NULL || gs_ex == NULL) {
+       if (context == NULL || gs_ex == NULL) {
                gdc_log(LOG_ERR, "Error input param\n");
                return -EINVAL;
        }
@@ -723,139 +700,109 @@ static long gdc_process_input_ion_info(struct mgdc_fh_s *fh,
                return -EINVAL;
        }
 
-       switch (gc->format) {
-       case NV12:
-               if (gs_ex->input_buffer.plane_number == 1) {
-                       ret = meson_ion_share_fd_to_phys(fh->ion_client,
-                               gs_ex->input_buffer.shared_fd,
-                               (ion_phys_addr_t *)&addr, &len);
-                       if (ret < 0) {
-                               gdc_log(LOG_ERR, "ion import input fd %d err\n",
-                                       gs_ex->input_buffer.shared_fd);
-                               return -EINVAL;
-                       }
+       plane_number = gs_ex->input_buffer.plane_number;
+       for (i = 0; i < plane_number; i++) {
+               context->dma_cfg.input_cfg[i].dma_used = 1;
+               cfg = &context->dma_cfg.input_cfg[i].dma_cfg;
+               cfg->fd = gdc_get_buffer_fd(i, &gs_ex->input_buffer);
+               cfg->dev = &gdc_manager.gdc_dev->pdev->dev;
+               cfg->dir = DMA_TO_DEVICE;
+               ret = gdc_buffer_get_phys(cfg, &addr);
+               if (ret < 0) {
+                       gdc_log(LOG_ERR,
+                               "dma import input fd %d err\n",
+                               cfg->fd);
+                       return -EINVAL;
+               }
+               if (plane_number == 1) {
                        ret = meson_gdc_set_input_addr(addr, gdc_cmd);
                        if (ret != 0) {
                                gdc_log(LOG_ERR, "set input addr err\n");
                                return -EINVAL;
                        }
-
-                       gdc_log(LOG_INFO, "1 plane get input addr=%x\n",
-                               gdc_cmd->y_base_addr);
-               } else if (gs_ex->input_buffer.plane_number == 2) {
-                       ret = meson_ion_share_fd_to_phys(fh->ion_client,
-                               gs_ex->input_buffer.y_base_fd,
-                               (ion_phys_addr_t *)&addr, &len);
-                       if (ret < 0) {
-                               gdc_log(LOG_ERR, "ion import input fd %d err\n",
-                                       gs_ex->input_buffer.y_base_fd);
+               } else {
+                       size = gdc_set_input_addr(i, addr, gdc_cmd);
+                       if (size < 0) {
+                               gdc_log(LOG_ERR, "set input addr err\n");
                                return -EINVAL;
                        }
-                       gdc_cmd->y_base_addr = addr;
 
-                       ret = meson_ion_share_fd_to_phys(fh->ion_client,
-                               gs_ex->input_buffer.uv_base_fd,
-                               (ion_phys_addr_t *)&addr, &len);
-                       if (ret < 0) {
-                               gdc_log(LOG_ERR, "ion import input fd %d err\n",
-                                       gs_ex->input_buffer.uv_base_fd);
-                               return -EINVAL;
-                       }
-                       gdc_cmd->uv_base_addr = addr;
-                       gdc_log(LOG_INFO, "2 plane get input y_addr=%x\n",
-                               gdc_cmd->y_base_addr);
-                       gdc_log(LOG_INFO, "2 plane get input uv_addr=%x\n",
-                               gdc_cmd->uv_base_addr);
                }
-       break;
-       case YV12:
-       case YUV444_P:
-               if (gs_ex->input_buffer.plane_number == 1) {
-                       ret = meson_ion_share_fd_to_phys(fh->ion_client,
-                               gs_ex->input_buffer.shared_fd,
-                               (ion_phys_addr_t *)&addr, &len);
-                       if (ret < 0) {
-                               gdc_log(LOG_ERR, "ion import input fd %d err\n",
-                                       gs_ex->input_buffer.shared_fd);
+               gdc_log(LOG_INFO, "plane[%d] get input addr=%lx\n",
+                       i, addr);
+               if (plane_number == 1) {
+                       size = gdc_get_input_size(gdc_cmd);
+                       if (size < 0) {
+                               gdc_log(LOG_ERR, "set input addr err\n");
                                return -EINVAL;
                        }
+               }
+               meson_gdc_dma_flush(&gdc_manager.gdc_dev->pdev->dev,
+                       addr, size);
+       }
+       return 0;
+}
+
+static long gdc_process_input_ion_info(struct gdc_context_s *context,
+       struct gdc_settings_ex *gs_ex)
+{
+       long ret = -1;
+       unsigned long addr;
+       size_t len;
+       struct gdc_cmd_s *gdc_cmd = &context->cmd;
+       int i, plane_number, fd;
 
+       if (context == NULL || gs_ex == NULL) {
+               gdc_log(LOG_ERR, "Error input param\n");
+               return -EINVAL;
+       }
+       if (gs_ex->input_buffer.plane_number < 1 ||
+               gs_ex->input_buffer.plane_number > 3) {
+               gdc_log(LOG_ERR, "%s, plane_number=%d invalid\n",
+               __func__, gs_ex->input_buffer.plane_number);
+               return -EINVAL;
+       }
+
+       plane_number = gs_ex->input_buffer.plane_number;
+       for (i = 0; i < plane_number; i++) {
+               fd = gdc_get_buffer_fd(i, &gs_ex->input_buffer);
+               ret = meson_ion_share_fd_to_phys(gdc_manager.ion_client,
+                       fd, (ion_phys_addr_t *)&addr, &len);
+               if (ret < 0) {
+                       gdc_log(LOG_ERR, "ion import input fd %d err\n", fd);
+                       return -EINVAL;
+               }
+
+               if (plane_number == 1) {
                        ret = meson_gdc_set_input_addr(addr, gdc_cmd);
                        if (ret != 0) {
                                gdc_log(LOG_ERR, "set input addr err\n");
                                return -EINVAL;
                        }
-                       gdc_log(LOG_INFO, "1 plane get input addr=%x\n",
-                               gdc_cmd->y_base_addr);
-               } else if (gs_ex->input_buffer.plane_number == 3) {
-                       ret = meson_ion_share_fd_to_phys(fh->ion_client,
-                               gs_ex->input_buffer.y_base_fd,
-                               (ion_phys_addr_t *)&addr, &len);
-                       if (ret < 0) {
-                               gdc_log(LOG_ERR, "ion import input fd %d err\n",
-                                       gs_ex->input_buffer.y_base_fd);
-                               return -EINVAL;
-                       }
-                       gdc_cmd->y_base_addr = addr;
-
-                       ret = meson_ion_share_fd_to_phys(fh->ion_client,
-                               gs_ex->input_buffer.u_base_fd,
-                               (ion_phys_addr_t *)&addr, &len);
-                       if (ret < 0) {
-                               gdc_log(LOG_ERR, "ion import input fd %d err\n",
-                                       gs_ex->input_buffer.u_base_fd);
-                               return -EINVAL;
-                       }
-                       gdc_cmd->u_base_addr = addr;
-
-                       ret = meson_ion_share_fd_to_phys(fh->ion_client,
-                               gs_ex->input_buffer.v_base_fd,
-                               (ion_phys_addr_t *)&addr, &len);
+               } else {
+                       ret = gdc_set_input_addr(i, addr, gdc_cmd);
                        if (ret < 0) {
-                               gdc_log(LOG_ERR, "ion import input fd %d err\n",
-                                       gs_ex->input_buffer.v_base_fd);
+                               gdc_log(LOG_ERR, "set input addr err\n");
                                return -EINVAL;
                        }
-                       gdc_cmd->v_base_addr = addr;
 
-                       gdc_log(LOG_INFO, "3 plane get input y_addr=%x\n",
-                               gdc_cmd->y_base_addr);
-                       gdc_log(LOG_INFO, "3 plane get input u_addr=%x\n",
-                               gdc_cmd->u_base_addr);
-                       gdc_log(LOG_INFO, "3 plane get input v_addr=%x\n",
-                               gdc_cmd->v_base_addr);
-               }
-       break;
-       case Y_GREY:
-       case RGB444_P:
-               ret = meson_ion_share_fd_to_phys(fh->ion_client,
-                       gs_ex->input_buffer.y_base_fd,
-                       (ion_phys_addr_t *)&addr, &len);
-               if (ret < 0) {
-                       gdc_log(LOG_ERR, "ion import input fd %d err\n",
-                               gs_ex->input_buffer.y_base_fd);
-                       return -EINVAL;
                }
-               gdc_cmd->y_base_addr = addr;
-               gdc_cmd->uv_base_addr = 0;
-       break;
-       default:
-               gdc_log(LOG_ERR, "Error image format");
-       break;
+               gdc_log(LOG_INFO, "plane[%d] get input addr=%lx\n",
+                       i, addr);
        }
        return 0;
 }
 
-static long gdc_process_output_dma_info(struct mgdc_fh_s *fh,
+static long gdc_process_output_dma_info(struct gdc_context_s *context,
        struct gdc_settings_ex *gs_ex)
 {
        long ret = -1;
        unsigned long addr;
        struct aml_dma_cfg *cfg = NULL;
-       struct gdc_cmd_s *gdc_cmd = &fh->gdc_cmd;
-       struct gdc_config_s *gc = &gdc_cmd->gdc_config;
+       struct gdc_cmd_s *gdc_cmd = &context->cmd;
+       int i, plane_number;
 
-       if (fh == NULL || gs_ex == NULL) {
+       if (context == NULL || gs_ex == NULL) {
                gdc_log(LOG_ERR, "Error output param\n");
                return -EINVAL;
        }
@@ -866,159 +813,46 @@ static long gdc_process_output_dma_info(struct mgdc_fh_s *fh,
                __func__, gs_ex->output_buffer.plane_number);
        }
 
-       switch (gc->format) {
-       case NV12:
-               if (gs_ex->output_buffer.plane_number == 1) {
-                       cfg = &fh->dma_cfg.output_cfg_plane1;
-                       cfg->fd = gs_ex->output_buffer.y_base_fd;
-                       cfg->dev = &fh->gdev->pdev->dev;
-                       cfg->dir = DMA_FROM_DEVICE;
-
-                       ret = gdc_buffer_get_phys(cfg, &addr);
-                       if (ret < 0) {
-                               gdc_log(LOG_ERR,
-                                       "dma import output fd %d err\n",
-                                       gs_ex->output_buffer.y_base_fd);
-                               return -EINVAL;
-                       }
-                       gdc_cmd->buffer_addr = addr;
-                       gdc_cmd->current_addr = gdc_cmd->buffer_addr;
-                       gdc_log(LOG_INFO, "1 plane get output addr=%x\n",
-                               gdc_cmd->current_addr);
-               } else if (gs_ex->output_buffer.plane_number == 2) {
-                       cfg = &fh->dma_cfg.output_cfg_plane1;
-                       cfg->fd = gs_ex->output_buffer.y_base_fd;
-                       cfg->dev = &fh->gdev->pdev->dev;
-                       cfg->dir = DMA_FROM_DEVICE;
-                       ret = gdc_buffer_get_phys(cfg, &addr);
-                       if (ret < 0) {
-                               gdc_log(LOG_ERR,
-                                       "dma import output fd %d err\n",
-                                       gs_ex->output_buffer.y_base_fd);
-                               return -EINVAL;
-                       }
-                       gdc_cmd->buffer_addr = addr;
-                       gdc_cmd->current_addr = addr;
-
-                       cfg = &fh->dma_cfg.output_cfg_plane2;
-                       cfg->fd = gs_ex->output_buffer.uv_base_fd;
-                       cfg->dev = &fh->gdev->pdev->dev;
-                       cfg->dir = DMA_FROM_DEVICE;
-                       ret = gdc_buffer_get_phys(cfg, &addr);
-                       if (ret < 0) {
-                               gdc_log(LOG_ERR,
-                                       "dma import output fd %d err\n",
-                                       gs_ex->output_buffer.uv_base_fd);
-                               return -EINVAL;
-                       }
-                       gdc_cmd->uv_out_base_addr = addr;
-
-                       gdc_log(LOG_INFO, "2 plane get output y_addr=%x\n",
-                               gdc_cmd->current_addr);
-                       gdc_log(LOG_INFO, "2 plane get output uv_addr=%x\n",
-                               gdc_cmd->uv_out_base_addr);
+       plane_number = gs_ex->output_buffer.plane_number;
+       for (i = 0; i < plane_number; i++) {
+               context->dma_cfg.output_cfg[i].dma_used = 1;
+               cfg = &context->dma_cfg.output_cfg[i].dma_cfg;
+               cfg->fd = gdc_get_buffer_fd(i, &gs_ex->output_buffer);
+               cfg->dev = &gdc_manager.gdc_dev->pdev->dev;
+               cfg->dir = DMA_TO_DEVICE;
+               ret = gdc_buffer_get_phys(cfg, &addr);
+               if (ret < 0) {
+                       gdc_log(LOG_ERR,
+                               "dma import input fd %d err\n",
+                               cfg->fd);
+                       return -EINVAL;
                }
-       break;
-       case YV12:
-       case YUV444_P:
-       case RGB444_P:
-               if (gs_ex->output_buffer.plane_number == 1) {
-                       cfg = &fh->dma_cfg.output_cfg_plane1;
-                       cfg->fd = gs_ex->output_buffer.y_base_fd;
-                       cfg->dev = &fh->gdev->pdev->dev;
-                       cfg->dir = DMA_FROM_DEVICE;
-                       ret = gdc_buffer_get_phys(cfg, &addr);
-                       if (ret < 0) {
-                               gdc_log(LOG_ERR,
-                                       "dma import output fd %d err\n",
-                                       gs_ex->output_buffer.y_base_fd);
-                               return -EINVAL;
-                       }
+               if (plane_number == 1) {
                        gdc_cmd->buffer_addr = addr;
-                       gdc_cmd->current_addr = addr;
-                       gdc_log(LOG_INFO, "1 plane get output addr=%x\n",
-                               gdc_cmd->current_addr);
-               } else if (gs_ex->output_buffer.plane_number == 3) {
-                       cfg = &fh->dma_cfg.output_cfg_plane1;
-                       cfg->fd = gs_ex->output_buffer.y_base_fd;
-                       cfg->dev = &fh->gdev->pdev->dev;
-                       cfg->dir = DMA_FROM_DEVICE;
-                       ret = gdc_buffer_get_phys(cfg, &addr);
-                       if (ret < 0) {
-                               gdc_log(LOG_ERR,
-                                       "dma import output fd %d err\n",
-                                       gs_ex->output_buffer.y_base_fd);
-                               return -EINVAL;
-                       }
-                       gdc_cmd->buffer_addr = addr;
-                       gdc_cmd->current_addr = addr;
-
-                       cfg = &fh->dma_cfg.output_cfg_plane2;
-                       cfg->fd = gs_ex->output_buffer.u_base_fd;
-                       cfg->dev = &fh->gdev->pdev->dev;
-                       cfg->dir = DMA_FROM_DEVICE;
-                       ret = gdc_buffer_get_phys(cfg, &addr);
-                       if (ret < 0) {
-                               gdc_log(LOG_ERR,
-                                       "dma import output fd %d err\n",
-                                       gs_ex->output_buffer.u_base_fd);
-                               return -EINVAL;
-                       }
-                       gdc_cmd->u_out_base_addr = addr;
-
-                       cfg = &fh->dma_cfg.output_cfg_plane3;
-                       cfg->fd = gs_ex->output_buffer.v_base_fd;
-                       cfg->dev = &fh->gdev->pdev->dev;
-                       cfg->dir = DMA_FROM_DEVICE;
-                       ret = gdc_buffer_get_phys(cfg, &addr);
+                       gdc_cmd->current_addr = gdc_cmd->buffer_addr;
+               } else {
+                       ret = gdc_set_output_addr(i, addr, gdc_cmd);
                        if (ret < 0) {
-                               gdc_log(LOG_ERR,
-                                       "dma import output fd %d err\n",
-                                       gs_ex->output_buffer.u_base_fd);
+                               gdc_log(LOG_ERR, "set input addr err\n");
                                return -EINVAL;
                        }
-                       gdc_cmd->v_out_base_addr = addr;
-
-                       gdc_log(LOG_INFO, "3 plane get output y_addr=%x\n",
-                               gdc_cmd->current_addr);
-                       gdc_log(LOG_INFO, "3 plane get output u_addr=%x\n",
-                               gdc_cmd->u_out_base_addr);
-                       gdc_log(LOG_INFO, "3 plane get output v_addr=%x\n",
-                               gdc_cmd->v_out_base_addr);
                }
-       break;
-       case Y_GREY:
-               cfg = &fh->dma_cfg.output_cfg_plane1;
-               cfg->fd = gs_ex->output_buffer.y_base_fd;
-               cfg->dev = &(fh->gdev->pdev->dev);
-               cfg->dir = DMA_FROM_DEVICE;
-               ret = gdc_buffer_get_phys(cfg, &addr);
-               if (ret < 0) {
-                       gdc_log(LOG_ERR,
-                               "dma import output fd %d err\n",
-                               gs_ex->output_buffer.y_base_fd);
-                       return -EINVAL;
-               }
-               gdc_cmd->buffer_addr = addr;
-               gdc_cmd->current_addr = addr;
-       break;
-       default:
-               gdc_log(LOG_ERR, "Error image format");
-       break;
+               gdc_log(LOG_INFO, "plane[%d] get output addr=%lx\n",
+                       i, addr);
        }
        return 0;
 }
 
-static long gdc_process_output_ion_info(struct mgdc_fh_s *fh,
+static long gdc_process_output_ion_info(struct gdc_context_s *context,
        struct gdc_settings_ex *gs_ex)
 {
        long ret = -1;
        unsigned long addr;
        size_t len;
-       struct gdc_cmd_s *gdc_cmd = &fh->gdc_cmd;
-       struct gdc_config_s *gc = &gdc_cmd->gdc_config;
+       struct gdc_cmd_s *gdc_cmd = &context->cmd;
+       int i, plane_number, fd;
 
-       if (fh == NULL || gs_ex == NULL) {
+       if (context == NULL || gs_ex == NULL) {
                gdc_log(LOG_ERR, "Error output param\n");
                return -EINVAL;
        }
@@ -1029,162 +863,86 @@ static long gdc_process_output_ion_info(struct mgdc_fh_s *fh,
                __func__, gs_ex->output_buffer.plane_number);
        }
 
-       switch (gc->format) {
-       case NV12:
-               if (gs_ex->output_buffer.plane_number == 1) {
-                       ret = meson_ion_share_fd_to_phys(fh->ion_client,
-                               gs_ex->output_buffer.shared_fd,
-                               (ion_phys_addr_t *)&addr, &len);
-                       if (ret < 0) {
-                               gdc_log(LOG_ERR, "ion import out fd %d err\n",
-                                       gs_ex->output_buffer.shared_fd);
-                               return -EINVAL;
-                       }
-                       gdc_cmd->buffer_addr = addr;
-                       gdc_cmd->current_addr = gdc_cmd->buffer_addr;
-                       gdc_log(LOG_INFO, "1 plane get output addr=%x\n",
-                               gdc_cmd->current_addr);
-               } else if (gs_ex->output_buffer.plane_number == 2) {
-                       ret = meson_ion_share_fd_to_phys(fh->ion_client,
-                               gs_ex->output_buffer.y_base_fd,
-                               (ion_phys_addr_t *)&addr, &len);
-                       if (ret < 0) {
-                               gdc_log(LOG_ERR, "ion import out fd %d err\n",
-                                       gs_ex->output_buffer.y_base_fd);
-                               return -EINVAL;
-                       }
-                       gdc_cmd->buffer_addr = addr;
-                       gdc_cmd->current_addr = addr;
-
-                       ret = meson_ion_share_fd_to_phys(fh->ion_client,
-                               gs_ex->output_buffer.uv_base_fd,
-                               (ion_phys_addr_t *)&addr, &len);
-                       if (ret < 0) {
-                               gdc_log(LOG_ERR, "ion import out fd %d err\n",
-                                       gs_ex->output_buffer.uv_base_fd);
-                               return -EINVAL;
-                       }
-                       gdc_cmd->uv_out_base_addr = addr;
-                       gdc_log(LOG_INFO, "2 plane get output y_addr=%x\n",
-                               gdc_cmd->current_addr);
-                       gdc_log(LOG_INFO, "2 plane get output uv_addr=%x\n",
-                               gdc_cmd->uv_out_base_addr);
+       plane_number = gs_ex->output_buffer.plane_number;
+       for (i = 0; i < plane_number; i++) {
+               fd = gdc_get_buffer_fd(i, &gs_ex->output_buffer);
+               ret = meson_ion_share_fd_to_phys(gdc_manager.ion_client,
+                       fd, (ion_phys_addr_t *)&addr, &len);
+               if (ret < 0) {
+                       gdc_log(LOG_ERR, "ion import out fd %d err\n", fd);
+                       return -EINVAL;
                }
-       break;
-       case YV12:
-       case YUV444_P:
-       case RGB444_P:
-               if (gs_ex->output_buffer.plane_number == 1) {
-                       ret = meson_ion_share_fd_to_phys(fh->ion_client,
-                               gs_ex->output_buffer.shared_fd,
-                               (ion_phys_addr_t *)&addr, &len);
-                       if (ret < 0) {
-                               gdc_log(LOG_ERR, "ion import out fd %d err\n",
-                                       gs_ex->output_buffer.shared_fd);
-                               return -EINVAL;
-                       }
-                       gdc_cmd->buffer_addr = addr;
-                       gdc_cmd->current_addr = addr;
-                       gdc_log(LOG_INFO, "1 plane get output addr=%x\n",
-                               gdc_cmd->current_addr);
-               } else if (gs_ex->output_buffer.plane_number == 3) {
-                       ret = meson_ion_share_fd_to_phys(fh->ion_client,
-                               gs_ex->output_buffer.y_base_fd,
-                               (ion_phys_addr_t *)&addr, &len);
-                       if (ret < 0) {
-                               gdc_log(LOG_ERR, "ion import out fd %d err\n",
-                                       gs_ex->output_buffer.y_base_fd);
-                               return -EINVAL;
-                       }
-                       gdc_cmd->buffer_addr = addr;
-                       gdc_cmd->current_addr = addr;
 
-                       ret = meson_ion_share_fd_to_phys(fh->ion_client,
-                               gs_ex->output_buffer.u_base_fd,
-                               (ion_phys_addr_t *)&addr, &len);
-                       if (ret < 0) {
-                               gdc_log(LOG_ERR, "ion import out fd %d err\n",
-                                       gs_ex->output_buffer.u_base_fd);
-                               return -EINVAL;
-                       }
-                       gdc_cmd->u_out_base_addr = addr;
-
-                       ret = meson_ion_share_fd_to_phys(fh->ion_client,
-                               gs_ex->output_buffer.v_base_fd,
-                               (ion_phys_addr_t *)&addr, &len);
+               if (plane_number == 1) {
+                       gdc_cmd->buffer_addr = addr;
+                       gdc_cmd->current_addr = gdc_cmd->buffer_addr;
+               } else {
+                       ret = gdc_set_output_addr(i, addr, gdc_cmd);
                        if (ret < 0) {
-                               gdc_log(LOG_ERR, "ion import out fd %d err\n",
-                                       gs_ex->output_buffer.v_base_fd);
+                               gdc_log(LOG_ERR, "set input addr err\n");
                                return -EINVAL;
                        }
-                       gdc_cmd->v_out_base_addr = addr;
-                       gdc_log(LOG_INFO, "3 plane get output y_addr=%x\n",
-                               gdc_cmd->current_addr);
-                       gdc_log(LOG_INFO, "3 plane get output u_addr=%x\n",
-                               gdc_cmd->u_out_base_addr);
-                       gdc_log(LOG_INFO, "3 plane get output v_addr=%x\n",
-                               gdc_cmd->v_out_base_addr);
                }
-       break;
-       case Y_GREY:
-               ret = meson_ion_share_fd_to_phys(fh->ion_client,
-                       gs_ex->output_buffer.shared_fd,
-                       (ion_phys_addr_t *)&addr, &len);
-               if (ret < 0) {
-                       gdc_log(LOG_ERR, "ion import out fd %d err\n",
-                               gs_ex->output_buffer.shared_fd);
-                       return -EINVAL;
-               }
-               gdc_cmd->buffer_addr = addr;
-               gdc_cmd->current_addr = addr;
-       break;
-       default:
-               gdc_log(LOG_ERR, "Error image format");
-       break;
+               gdc_log(LOG_INFO, "plane[%d] get output addr=%lx\n",
+                       i, addr);
        }
        return 0;
 }
 
-static long gdc_process_ex_info(struct mgdc_fh_s *fh,
+static long gdc_process_ex_info(struct gdc_context_s *context,
        struct gdc_settings_ex *gs_ex)
 {
        long ret;
        unsigned long addr = 0;
        size_t len;
        struct aml_dma_cfg *cfg = NULL;
-       struct gdc_cmd_s *gdc_cmd = &fh->gdc_cmd;
+       struct gdc_cmd_s *gdc_cmd = &context->cmd;
+       struct gdc_queue_item_s *pitem;
+       int i;
 
-       if (fh == NULL || gs_ex == NULL) {
+       if (context == NULL || gs_ex == NULL) {
                gdc_log(LOG_ERR, "Error input param\n");
                return -EINVAL;
        }
+       mutex_lock(&context->d_mutext);
        memcpy(&(gdc_cmd->gdc_config), &(gs_ex->gdc_config),
                sizeof(struct gdc_config_s));
-       gdc_cmd->fh = fh;
+       for (i = 0; i < MAX_PLANE; i++) {
+               context->dma_cfg.input_cfg[i].dma_used = 0;
+               context->dma_cfg.output_cfg[i].dma_used = 0;
+       }
+       context->dma_cfg.config_cfg.dma_used = 0;
+
        if (gs_ex->output_buffer.mem_alloc_type == AML_GDC_MEM_ION) {
-               ret = gdc_process_output_ion_info(fh, gs_ex);
-               if (ret < 0)
+               ret = gdc_process_output_ion_info(context, gs_ex);
+               if (ret < 0) {
+                       mutex_unlock(&context->d_mutext);
                        return -EINVAL;
+               }
        } else if (gs_ex->output_buffer.mem_alloc_type == AML_GDC_MEM_DMABUF) {
-               ret = gdc_process_output_dma_info(fh, gs_ex);
-               if (ret < 0)
-                       return -EINVAL;
+               ret = gdc_process_output_dma_info(context, gs_ex);
+               if (ret < 0) {
+                       ret = -EINVAL;
+                       goto unmap;
+               }
        }
        gdc_cmd->base_gdc = 0;
 
        if (gs_ex->config_buffer.mem_alloc_type == AML_GDC_MEM_ION) {
                /* ion alloc */
-               ret = meson_ion_share_fd_to_phys(fh->ion_client,
+               ret = meson_ion_share_fd_to_phys(gdc_manager.ion_client,
                        gs_ex->config_buffer.shared_fd,
                        (ion_phys_addr_t *)&addr, &len);
                if (ret < 0) {
                        gdc_log(LOG_ERR, "ion import config fd %d failed\n",
                                gs_ex->config_buffer.shared_fd);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto unmap;
                }
        } else if (gs_ex->config_buffer.mem_alloc_type == AML_GDC_MEM_DMABUF) {
                /* dma alloc */
-               cfg = &fh->dma_cfg.config_cfg;
+               context->dma_cfg.config_cfg.dma_used = 1;
+               cfg = &context->dma_cfg.config_cfg.dma_cfg;
                cfg->fd = gs_ex->config_buffer.y_base_fd;
                cfg->dev = &(gdc_manager.gdc_dev->pdev->dev);
                cfg->dir = DMA_TO_DEVICE;
@@ -1192,7 +950,8 @@ static long gdc_process_ex_info(struct mgdc_fh_s *fh,
                if (ret < 0) {
                        gdc_log(LOG_ERR, "dma import config fd %d failed\n",
                                gs_ex->config_buffer.shared_fd);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto unmap;
                }
        }
        gdc_cmd->gdc_config.config_addr = addr;
@@ -1200,14 +959,18 @@ static long gdc_process_ex_info(struct mgdc_fh_s *fh,
 
        if (gs_ex->input_buffer.mem_alloc_type == AML_GDC_MEM_ION) {
                /* ion alloc */
-               ret = gdc_process_input_ion_info(fh, gs_ex);
-               if (ret < 0)
-                       return -EINVAL;
+               ret = gdc_process_input_ion_info(context, gs_ex);
+               if (ret < 0) {
+                       ret = -EINVAL;
+                       goto unmap;
+               }
        } else if (gs_ex->input_buffer.mem_alloc_type == AML_GDC_MEM_DMABUF) {
                /* dma alloc */
-               ret = gdc_process_input_dma_info(fh, gs_ex);
-               if (ret < 0)
-                       return -EINVAL;
+               ret = gdc_process_input_dma_info(context, gs_ex);
+               if (ret < 0) {
+                       ret = -EINVAL;
+                       goto unmap;
+               }
        }
        gdc_cmd->outplane = gs_ex->output_buffer.plane_number;
        if (gdc_cmd->outplane < 1 || gdc_cmd->outplane > 3) {
@@ -1215,88 +978,42 @@ static long gdc_process_ex_info(struct mgdc_fh_s *fh,
                gdc_log(LOG_ERR, "%s, plane_number=%d invalid\n",
                __func__, gs_ex->output_buffer.plane_number);
        }
-       mutex_lock(&fh->gdev->d_mutext);
+       /* set block mode */
+       context->cmd.wait_done_flag = 1;
 
+       pitem = gdc_prepare_item(context);
+       if (pitem == NULL) {
+               gdc_log(LOG_ERR, "get item error\n");
+               ret = -ENOMEM;
+               goto unmap;
+       }
+       mutex_unlock(&context->d_mutext);
        if (gs_ex->config_buffer.mem_alloc_type == AML_GDC_MEM_DMABUF)
                gdc_buffer_dma_flush(gs_ex->config_buffer.shared_fd);
-       gdc_pwr_config(true);
-       ret = gdc_run(gdc_cmd);
-       if (ret < 0)
-               gdc_log(LOG_ERR, "gdc process failed ret = %ld\n", ret);
-
-       ret = wait_for_completion_timeout(&fh->gdev->d_com,
-                                       msecs_to_jiffies(40));
-       if (ret == 0)
-               gdc_log(LOG_ERR, "gdc timeout\n");
-
-       gdc_stop(gdc_cmd);
-       if (!gdc_reg_store_mode)
-               gdc_pwr_config(false);
-       mutex_unlock(&fh->gdev->d_mutext);
-       if (gs_ex->input_buffer.mem_alloc_type == AML_GDC_MEM_DMABUF) {
-               gdc_buffer_unmap(&fh->dma_cfg.input_cfg_plane1);
-               if (gs_ex->input_buffer.plane_number == 2)
-                       gdc_buffer_unmap(&fh->dma_cfg.input_cfg_plane2);
-               if (gs_ex->input_buffer.plane_number == 3) {
-                       gdc_buffer_unmap(&fh->dma_cfg.input_cfg_plane2);
-                       gdc_buffer_unmap(&fh->dma_cfg.input_cfg_plane3);
+
+       gdc_wq_add_work(context, pitem);
+       return 0;
+unmap:
+       /* if dma buf detach it */
+       for (i = 0; i < MAX_PLANE; i++) {
+               if (pitem->dma_cfg.input_cfg[i].dma_used) {
+                       gdc_buffer_unmap
+                               (&pitem->dma_cfg.input_cfg[i].dma_cfg);
+                       pitem->dma_cfg.input_cfg[i].dma_used = 0;
                }
-       }
-       if (gs_ex->config_buffer.mem_alloc_type == AML_GDC_MEM_DMABUF)
-               gdc_buffer_unmap(&fh->dma_cfg.config_cfg);
-       if (gs_ex->output_buffer.mem_alloc_type == AML_GDC_MEM_DMABUF) {
-               gdc_buffer_unmap(&fh->dma_cfg.output_cfg_plane1);
-               if (gs_ex->output_buffer.plane_number == 2)
-                       gdc_buffer_unmap(&fh->dma_cfg.output_cfg_plane2);
-               if (gs_ex->output_buffer.plane_number == 3) {
-                       gdc_buffer_unmap(&fh->dma_cfg.output_cfg_plane2);
-                       gdc_buffer_unmap(&fh->dma_cfg.output_cfg_plane3);
+               if (pitem->dma_cfg.output_cfg[i].dma_used) {
+                       gdc_buffer_unmap
+                               (&pitem->dma_cfg.output_cfg[i].dma_cfg);
+                       pitem->dma_cfg.output_cfg[i].dma_used = 0;
                }
        }
-       return 0;
-}
-
-u8 __iomem *map_virt_from_phys(phys_addr_t phys, unsigned long total_size)
-{
-       u32 offset, npages;
-       struct page **pages = NULL;
-       pgprot_t pgprot;
-       u8 __iomem *vaddr;
-       int i;
-
-       npages = PAGE_ALIGN(total_size) / PAGE_SIZE;
-       offset = phys & (~PAGE_MASK);
-       if (offset)
-               npages++;
-       pages = vmalloc(sizeof(struct page *) * npages);
-       if (!pages)
-               return NULL;
-       for (i = 0; i < npages; i++) {
-               pages[i] = phys_to_page(phys);
-               phys += PAGE_SIZE;
-       }
-       /*nocache*/
-       pgprot = pgprot_noncached(PAGE_KERNEL);
-
-       vaddr = vmap(pages, npages, VM_MAP, pgprot);
-       if (!vaddr) {
-               pr_err("vmaped fail, size: %d\n",
-                       npages << PAGE_SHIFT);
-               vfree(pages);
-               return NULL;
-       }
-       vfree(pages);
-
-       return vaddr;
-}
-
-void unmap_virt_from_phys(u8 __iomem *vaddr)
-{
-       if (vaddr) {
-               /* unmap prevois vaddr */
-               vunmap(vaddr);
-               vaddr = NULL;
+       if (pitem->dma_cfg.config_cfg.dma_used) {
+               gdc_buffer_unmap
+                       (&pitem->dma_cfg.config_cfg.dma_cfg);
+               pitem->dma_cfg.config_cfg.dma_used = 0;
        }
+       mutex_unlock(&context->d_mutext);
+       return ret;
 }
 
 static void release_config_firmware(struct gdc_settings_with_fw *gs_with_fw)
@@ -1395,14 +1112,16 @@ release:
        return ret;
 }
 
-static long gdc_process_with_fw(struct mgdc_fh_s *fh,
+static long gdc_process_with_fw(struct gdc_context_s *context,
        struct gdc_settings_with_fw *gs_with_fw)
 {
        long ret = -1;
-       struct gdc_cmd_s *gdc_cmd = &fh->gdc_cmd;
+       struct gdc_cmd_s *gdc_cmd = &context->cmd;
        char *fw_name = NULL;
+       struct gdc_queue_item_s *pitem;
+       int i;
 
-       if (fh == NULL || gs_with_fw == NULL) {
+       if (context == NULL || gs_with_fw == NULL) {
                gdc_log(LOG_ERR, "Error input param\n");
                return -EINVAL;
        }
@@ -1410,19 +1129,17 @@ static long gdc_process_with_fw(struct mgdc_fh_s *fh,
        gs_with_fw->fw_info.virt_addr = NULL;
        gs_with_fw->fw_info.cma_pages = NULL;
 
-       memcpy(&(gdc_cmd->gdc_config), &(gs_with_fw->gdc_config),
-               sizeof(struct gdc_config_s));
-
        fw_name = kzalloc(CONFIG_PATH_LENG, GFP_KERNEL);
        if (!fw_name) {
                gdc_log(LOG_ERR, "cannot malloc fw_name!\n");
                return -ENOMEM;
        }
-
-       gdc_cmd->fh = fh;
+       mutex_lock(&context->d_mutext);
+       memcpy(&(gdc_cmd->gdc_config), &(gs_with_fw->gdc_config),
+               sizeof(struct gdc_config_s));
        if (gs_with_fw->output_buffer.mem_alloc_type == AML_GDC_MEM_ION) {
                /* ion alloc */
-               ret = gdc_process_output_ion_info(fh,
+               ret = gdc_process_output_ion_info(context,
                                        (struct gdc_settings_ex *)gs_with_fw);
                if (ret < 0) {
                        ret = -EINVAL;
@@ -1431,7 +1148,7 @@ static long gdc_process_with_fw(struct mgdc_fh_s *fh,
        } else if (gs_with_fw->output_buffer.mem_alloc_type ==
                                                        AML_GDC_MEM_DMABUF) {
                /* dma alloc */
-               ret = gdc_process_output_dma_info(fh,
+               ret = gdc_process_output_dma_info(context,
                                        (struct gdc_settings_ex *)gs_with_fw);
                if (ret < 0) {
                        ret = -EINVAL;
@@ -1442,7 +1159,7 @@ static long gdc_process_with_fw(struct mgdc_fh_s *fh,
 
        if (gs_with_fw->input_buffer.mem_alloc_type == AML_GDC_MEM_ION) {
                /* ion alloc */
-               ret = gdc_process_input_ion_info(fh,
+               ret = gdc_process_input_ion_info(context,
                                        (struct gdc_settings_ex *)gs_with_fw);
                if (ret < 0) {
                        ret = -EINVAL;
@@ -1451,7 +1168,7 @@ static long gdc_process_with_fw(struct mgdc_fh_s *fh,
        } else if (gs_with_fw->input_buffer.mem_alloc_type ==
                                                AML_GDC_MEM_DMABUF) {
                /* dma alloc */
-               gdc_process_input_dma_info(fh,
+               gdc_process_input_dma_info(context,
                                        (struct gdc_settings_ex *)gs_with_fw);
        }
 
@@ -1587,96 +1304,58 @@ static long gdc_process_with_fw(struct mgdc_fh_s *fh,
        gdc_cmd->gdc_config.config_size =
                gs_with_fw->gdc_config.config_size;
 
-       mutex_lock(&fh->gdev->d_mutext);
-       gdc_pwr_config(true);
-       ret = gdc_run(gdc_cmd);
-       if (ret < 0)
-               gdc_log(LOG_ERR, "gdc process failed ret = %ld\n", ret);
-
-       ret = wait_for_completion_timeout(&fh->gdev->d_com,
-                                       msecs_to_jiffies(40));
-       if (ret == 0)
-               gdc_log(LOG_ERR, "gdc timeout\n");
-
-       gdc_stop(gdc_cmd);
-       if (!gdc_reg_store_mode)
-               gdc_pwr_config(false);
-       mutex_unlock(&fh->gdev->d_mutext);
+       /* set block mode */
+       context->cmd.wait_done_flag = 1;
 
+       pitem = gdc_prepare_item(context);
+       if (pitem == NULL) {
+               gdc_log(LOG_ERR, "get item error\n");
+               ret = -ENOMEM;
+               goto release_fw;
+       }
+       mutex_unlock(&context->d_mutext);
+       gdc_wq_add_work(context, pitem);
+       release_config_firmware(gs_with_fw);
+       kfree(fw_name);
+       return 0;
 release_fw:
        release_config_firmware(gs_with_fw);
-
 unmap:
-       if (gs_with_fw->input_buffer.mem_alloc_type == AML_GDC_MEM_DMABUF) {
-               gdc_dma_buffer_unmap(&fh->dma_cfg.input_cfg_plane1);
-               if (gs_with_fw->input_buffer.plane_number == 2)
-                       gdc_dma_buffer_unmap(&fh->dma_cfg.input_cfg_plane2);
-               if (gs_with_fw->input_buffer.plane_number == 3) {
-                       gdc_dma_buffer_unmap(&fh->dma_cfg.input_cfg_plane2);
-                       gdc_dma_buffer_unmap(&fh->dma_cfg.input_cfg_plane3);
+       /* if dma buf detach it */
+       for (i = 0; i < MAX_PLANE; i++) {
+               if (pitem->dma_cfg.input_cfg[i].dma_used) {
+                       gdc_dma_buffer_unmap
+                               (&pitem->dma_cfg.input_cfg[i].dma_cfg);
+                       pitem->dma_cfg.input_cfg[i].dma_used = 0;
                }
-       }
-
-       if (gs_with_fw->output_buffer.mem_alloc_type == AML_GDC_MEM_DMABUF) {
-               gdc_dma_buffer_unmap(&fh->dma_cfg.output_cfg_plane1);
-               if (gs_with_fw->output_buffer.plane_number == 2)
-                       gdc_dma_buffer_unmap(&fh->dma_cfg.output_cfg_plane2);
-               if (gs_with_fw->output_buffer.plane_number == 3) {
-                       gdc_dma_buffer_unmap(&fh->dma_cfg.output_cfg_plane2);
-                       gdc_dma_buffer_unmap(&fh->dma_cfg.output_cfg_plane3);
+               if (pitem->dma_cfg.output_cfg[i].dma_used) {
+                       gdc_dma_buffer_unmap
+                               (&pitem->dma_cfg.output_cfg[i].dma_cfg);
+                       pitem->dma_cfg.output_cfg[i].dma_used = 0;
                }
        }
-
+       if (pitem->dma_cfg.config_cfg.dma_used) {
+               gdc_dma_buffer_unmap
+                       (&pitem->dma_cfg.config_cfg.dma_cfg);
+               pitem->dma_cfg.config_cfg.dma_used = 0;
+       }
+       mutex_unlock(&context->d_mutext);
 release_fw_name:
        kfree(fw_name);
 
        return ret;
 }
 EXPORT_SYMBOL(gdc_process_with_fw);
-int write_buf_to_file(char *path, char *buf, int size)
-{
-       int ret = 0;
-       struct file *fp = NULL;
-       mm_segment_t old_fs;
-       loff_t pos = 0;
-       int w_size = 0;
-
-       if (!path || !config_out_path_defined) {
-               gdc_log(LOG_ERR, "please define path first\n");
-               return -1;
-       }
-
-       /* change to KERNEL_DS address limit */
-       old_fs = get_fs();
-       set_fs(KERNEL_DS);
-
-       /* open file to write */
-       fp = filp_open(path, O_WRONLY|O_CREAT, 0640);
-       if (IS_ERR(fp)) {
-               gdc_log(LOG_ERR, "open file error\n");
-               ret = -1;
-       }
-
-       /* Write buf to file */
-       w_size = vfs_write(fp, buf, size, &pos);
-       gdc_log(LOG_INFO, "write w_size = %u, size = %u\n", w_size, size);
-
-       vfs_fsync(fp, 0);
-       filp_close(fp, NULL);
-       set_fs(old_fs);
-
-       return w_size;
-}
 
 static long meson_gdc_ioctl(struct file *file, unsigned int cmd,
                unsigned long arg)
 {
        long ret = -1;
        size_t len;
-       struct mgdc_fh_s *fh = file->private_data;
+       struct gdc_context_s *context = NULL;
        struct gdc_settings gs;
-       struct gdc_cmd_s *gdc_cmd = &fh->gdc_cmd;
-       struct gdc_config_s *gc = &gdc_cmd->gdc_config;
+       struct gdc_cmd_s *gdc_cmd = NULL;
+       struct gdc_config_s *gc = NULL;
        struct gdc_buf_cfg buf_cfg;
        struct page *cma_pages = NULL;
        struct gdc_settings_ex gs_ex;
@@ -1686,12 +1365,12 @@ static long meson_gdc_ioctl(struct file *file, unsigned int cmd,
        ion_phys_addr_t addr;
        int index, dma_fd;
        void __user *argp = (void __user *)arg;
-       void __iomem *config_virt_addr;
-       ktime_t start_time, stop_time, diff_time;
-       int process_time = 0;
-       int i = 0;
+       struct gdc_queue_item_s *pitem;
+       struct device *dev = NULL;
 
-       start_time.tv64 = 0;
+       context = (struct gdc_context_s *)file->private_data;
+       gdc_cmd = &context->cmd;
+       gc = &gdc_cmd->gdc_config;
        switch (cmd) {
        case GDC_PROCESS:
                ret = copy_from_user(&gs, argp, sizeof(gs));
@@ -1704,13 +1383,14 @@ static long meson_gdc_ioctl(struct file *file, unsigned int cmd,
                                sizeof(gs), gs.magic);
 
                //configure gdc config, buffer address and resolution
-               ret = meson_ion_share_fd_to_phys(fh->ion_client,
+               ret = meson_ion_share_fd_to_phys(gdc_manager.ion_client,
                                gs.out_fd, &addr, &len);
                if (ret < 0) {
                        gdc_log(LOG_ERR,
                                "import out fd %d failed\n", gs.out_fd);
                        return -EINVAL;
                }
+               mutex_lock(&context->d_mutext);
                memcpy(&gdc_cmd->gdc_config, &gs.gdc_config,
                        sizeof(struct gdc_config_s));
                gdc_cmd->buffer_addr = addr;
@@ -1719,247 +1399,122 @@ static long meson_gdc_ioctl(struct file *file, unsigned int cmd,
                gdc_cmd->base_gdc = 0;
                gdc_cmd->current_addr = gdc_cmd->buffer_addr;
 
-               ret = meson_ion_share_fd_to_phys(fh->ion_client,
+               ret = meson_ion_share_fd_to_phys(gdc_manager.ion_client,
                                gc->config_addr, &addr, &len);
                if (ret < 0) {
                        gdc_log(LOG_ERR, "import config fd failed\n");
+                       mutex_unlock(&context->d_mutext);
                        return -EINVAL;
                }
 
                gc->config_addr = addr;
 
-               ret = meson_ion_share_fd_to_phys(fh->ion_client,
+               ret = meson_ion_share_fd_to_phys(gdc_manager.ion_client,
                                gs.in_fd, &addr, &len);
                if (ret < 0) {
                        gdc_log(LOG_ERR, "import in fd %d failed\n", gs.in_fd);
+                       mutex_unlock(&context->d_mutext);
                        return -EINVAL;
                }
 
                ret = meson_gdc_set_input_addr(addr, gdc_cmd);
                if (ret != 0) {
                        gdc_log(LOG_ERR, "set input addr failed\n");
+                       mutex_unlock(&context->d_mutext);
                        return -EINVAL;
                }
 
-               gdc_cmd->fh = fh;
                gdc_cmd->outplane = 1;
-               mutex_lock(&fh->gdev->d_mutext);
-
-               if (trace_mode_enable >= 1)
-                       start_time = ktime_get();
-
-               gdc_pwr_config(true);
-               ret = gdc_run(gdc_cmd);
-               if (ret < 0)
-                       gdc_log(LOG_ERR, "gdc process ret = %ld\n", ret);
-
-               ret = wait_for_completion_timeout(&fh->gdev->d_com,
-                                       msecs_to_jiffies(WAIT_THRESHOLD));
-               if (ret == 0)
-                       gdc_log(LOG_ERR, "gdc timeout\n");
-
-               if (ret == 0) {
-                       gdc_log(LOG_ERR, "gdc timeout, status = 0x%x\n",
-                               gdc_status_read());
-
-                       if (trace_mode_enable >= 2) {
-                               /* dump regs */
-                               for (i = 0; i <= 0xFF; i += 4)
-                                       gdc_log(LOG_ERR, "reg[0x%x] = 0x%x\n",
-                                               i, system_gdc_read_32(i));
-
-                               /* dump config buffer */
-                               config_virt_addr =
-                                       map_virt_from_phys(gc->config_addr,
-                                       PAGE_ALIGN(gc->config_size * 4));
-                               ret = write_buf_to_file(config_out_file,
-                                                       config_virt_addr,
-                                                       (gc->config_size * 4));
-                               if (ret <= 0)
-                                       gdc_log(LOG_ERR,
-                                               "Failed to read_file_to_buf\n");
-                               unmap_virt_from_phys(config_virt_addr);
-                       }
-               }
-
-               gdc_stop(gdc_cmd);
-
-               if (trace_mode_enable >= 1) {
-                       stop_time = ktime_get();
-                       diff_time = ktime_sub(stop_time, start_time);
-                       process_time = ktime_to_ms(diff_time);
-                       if (process_time > 50)
-                               gdc_log(LOG_ERR, "gdc process time = %d\n",
-                                       process_time);
+               /* set block mode */
+               context->cmd.wait_done_flag = 1;
+               pitem = gdc_prepare_item(context);
+               if (pitem == NULL) {
+                       gdc_log(LOG_ERR, "get item error\n");
+                       mutex_unlock(&context->d_mutext);
+                       return -ENOMEM;
                }
-               if (!gdc_reg_store_mode)
-                       gdc_pwr_config(false);
-               mutex_unlock(&fh->gdev->d_mutext);
+               mutex_unlock(&context->d_mutext);
+               gdc_wq_add_work(context, pitem);
        break;
        case GDC_RUN:
                ret = copy_from_user(&gs, argp, sizeof(gs));
                if (ret < 0)
                        gdc_log(LOG_ERR, "copy from user failed\n");
-
+               mutex_lock(&context->d_mutext);
                memcpy(&gdc_cmd->gdc_config, &gs.gdc_config,
                        sizeof(struct gdc_config_s));
-               gdc_cmd->buffer_addr = fh->o_paddr;
-               gdc_cmd->buffer_size = fh->o_len;
+               gdc_cmd->buffer_addr = context->o_paddr;
+               gdc_cmd->buffer_size = context->o_len;
 
                gdc_cmd->base_gdc = 0;
                gdc_cmd->current_addr = gdc_cmd->buffer_addr;
 
-               gc->config_addr = fh->c_paddr;
+               gc->config_addr = context->c_paddr;
 
-               ret = meson_gdc_set_input_addr(fh->i_paddr, gdc_cmd);
+               ret = meson_gdc_set_input_addr(context->i_paddr, gdc_cmd);
                if (ret != 0) {
                        gdc_log(LOG_ERR, "set input addr failed\n");
+                       mutex_unlock(&context->d_mutext);
                        return -EINVAL;
                }
-
-               gdc_cmd->fh = fh;
                gdc_cmd->outplane = 1;
-               mutex_lock(&fh->gdev->d_mutext);
-               meson_gdc_dma_flush(&fh->gdev->pdev->dev,
-                                       fh->i_paddr, fh->i_len);
-               meson_gdc_dma_flush(&fh->gdev->pdev->dev,
-                                       fh->c_paddr, fh->c_len);
-
-               if (trace_mode_enable >= 1)
-                       start_time = ktime_get();
-
-               gdc_pwr_config(true);
-               ret = gdc_run(gdc_cmd);
-               if (ret < 0)
-                       gdc_log(LOG_ERR, "gdc process failed ret = %ld\n", ret);
-
-               ret = wait_for_completion_timeout(&fh->gdev->d_com,
-                                       msecs_to_jiffies(WAIT_THRESHOLD));
-               if (ret == 0)
-                       gdc_log(LOG_ERR, "gdc timeout\n");
-
-               if (ret == 0) {
-                       gdc_log(LOG_ERR, "gdc timeout, status = 0x%x\n",
-                               gdc_status_read());
-
-                       if (trace_mode_enable >= 2) {
-                               /* dump regs */
-                               for (i = 0; i <= 0xFF; i += 4)
-                                       gdc_log(LOG_ERR, "reg[0x%x] = 0x%x\n",
-                                               i, system_gdc_read_32(i));
-
-                               /* dump config buffer */
-                               config_virt_addr =
-                                       map_virt_from_phys(gc->config_addr,
-                                       PAGE_ALIGN(gc->config_size * 4));
-                               ret = write_buf_to_file(config_out_file,
-                                                       config_virt_addr,
-                                                       (gc->config_size * 4));
-                               if (ret <= 0)
-                                       gdc_log(LOG_ERR,
-                                               "Failed to read_file_to_buf\n");
-                               unmap_virt_from_phys(config_virt_addr);
-                       }
-               }
-
-               gdc_stop(gdc_cmd);
-               if (trace_mode_enable >= 1) {
-                       stop_time = ktime_get();
-                       diff_time = ktime_sub(stop_time, start_time);
-                       process_time = ktime_to_ms(diff_time);
-                       if (process_time > 50)
-                               gdc_log(LOG_ERR, "gdc process time = %d\n",
-                                       process_time);
+               /* set block mode */
+               context->cmd.wait_done_flag = 1;
+               pitem = gdc_prepare_item(context);
+               if (pitem == NULL) {
+                       gdc_log(LOG_ERR, "get item error\n");
+                       mutex_unlock(&context->d_mutext);
+                       return -ENOMEM;
                }
-               meson_gdc_cache_flush(&fh->gdev->pdev->dev,
-                                       fh->o_paddr, fh->o_len);
-
-               if (!gdc_reg_store_mode)
-                       gdc_pwr_config(false);
-               mutex_unlock(&fh->gdev->d_mutext);
+               mutex_unlock(&context->d_mutext);
+               dev = &gdc_manager.gdc_dev->pdev->dev;
+               meson_gdc_dma_flush(dev,
+                                       context->i_paddr, context->i_len);
+               meson_gdc_dma_flush(dev,
+                                       context->c_paddr, context->c_len);
+               gdc_wq_add_work(context, pitem);
+               meson_gdc_cache_flush(dev,
+                                       context->o_paddr, context->o_len);
        break;
        case GDC_HANDLE:
                ret = copy_from_user(&gs, argp, sizeof(gs));
                if (ret < 0)
                        gdc_log(LOG_ERR, "copy from user failed\n");
-
+               mutex_lock(&context->d_mutext);
                memcpy(&gdc_cmd->gdc_config, &gs.gdc_config,
                        sizeof(struct gdc_config_s));
-               gdc_cmd->buffer_addr = fh->o_paddr;
-               gdc_cmd->buffer_size = fh->o_len;
+               gdc_cmd->buffer_addr = context->o_paddr;
+               gdc_cmd->buffer_size = context->o_len;
 
                gdc_cmd->base_gdc = 0;
                gdc_cmd->current_addr = gdc_cmd->buffer_addr;
 
-               gc->config_addr = fh->c_paddr;
+               gc->config_addr = context->c_paddr;
 
-               gdc_cmd->fh = fh;
                gdc_cmd->outplane = 1;
-               mutex_lock(&fh->gdev->d_mutext);
-               ret = meson_gdc_init_dma_addr(fh, &gs);
+               /* set block mode */
+               context->cmd.wait_done_flag = 1;
+               ret = meson_gdc_init_dma_addr(context, &gs);
                if (ret != 0) {
-                       mutex_unlock(&fh->gdev->d_mutext);
+                       mutex_unlock(&context->d_mutext);
                        gdc_log(LOG_ERR, "Failed to init dma addr");
                        return ret;
                }
-               meson_gdc_dma_flush(&fh->gdev->pdev->dev,
-                                       fh->c_paddr, fh->c_len);
-
-
-               if (trace_mode_enable >= 1)
-                       start_time = ktime_get();
-
-               gdc_pwr_config(true);
-               ret = gdc_run(gdc_cmd);
-               if (ret < 0)
-                       gdc_log(LOG_ERR, "gdc process failed ret = %ld\n", ret);
-
-               ret = wait_for_completion_timeout(&fh->gdev->d_com,
-                                       msecs_to_jiffies(WAIT_THRESHOLD));
-               if (ret == 0)
-                       gdc_log(LOG_ERR, "gdc timeout\n");
-
-               if (ret == 0) {
-                       gdc_log(LOG_ERR, "gdc timeout, status = 0x%x\n",
-                               gdc_status_read());
-
-                       if (trace_mode_enable >= 2) {
-                               /* dump regs */
-                               for (i = 0; i <= 0xFF; i += 4)
-                                       gdc_log(LOG_ERR, "reg[0x%x] = 0x%x\n",
-                                               i, system_gdc_read_32(i));
-
-                               /* dump config buffer */
-                               config_virt_addr =
-                                       map_virt_from_phys(gc->config_addr,
-                                       PAGE_ALIGN(gc->config_size * 4));
-                               ret = write_buf_to_file(config_out_file,
-                                                       config_virt_addr,
-                                                       (gc->config_size * 4));
-                               if (ret <= 0)
-                                       gdc_log(LOG_ERR,
-                                               "Failed to read_file_to_buf\n");
-                               unmap_virt_from_phys(config_virt_addr);
-                       }
-               }
-
-               gdc_stop(gdc_cmd);
-
-               if (trace_mode_enable >= 1) {
-                       stop_time = ktime_get();
-                       diff_time = ktime_sub(stop_time, start_time);
-                       process_time = ktime_to_ms(diff_time);
-                       if (process_time > 50)
-                               gdc_log(LOG_ERR, "gdc process time = %d\n",
-                                       process_time);
+               pitem = gdc_prepare_item(context);
+               if (pitem == NULL) {
+                       gdc_log(LOG_ERR, "get item error\n");
+                       mutex_unlock(&context->d_mutext);
+                       return -ENOMEM;
                }
-               meson_gdc_cache_flush(&fh->gdev->pdev->dev,
-                                       fh->o_paddr, fh->o_len);
-               meson_gdc_deinit_dma_addr(fh);
-
-               if (!gdc_reg_store_mode)
-                       gdc_pwr_config(false);
-               mutex_unlock(&fh->gdev->d_mutext);
+               mutex_unlock(&context->d_mutext);
+
+               dev = &gdc_manager.gdc_dev->pdev->dev;
+               meson_gdc_dma_flush(dev,
+                                       context->c_paddr, context->c_len);
+               gdc_wq_add_work(context, pitem);
+               meson_gdc_cache_flush(dev,
+                                       context->o_paddr, context->o_len);
+               meson_gdc_deinit_dma_addr(context);
        break;
        case GDC_REQUEST_BUFF:
                ret = copy_from_user(&buf_cfg, argp, sizeof(buf_cfg));
@@ -1969,15 +1524,17 @@ static long meson_gdc_ioctl(struct file *file, unsigned int cmd,
                }
 
                buf_cfg.len = PAGE_ALIGN(buf_cfg.len);
-
-               cma_pages = dma_alloc_from_contiguous(&fh->gdev->pdev->dev,
+               dev = &gdc_manager.gdc_dev->pdev->dev;
+               cma_pages = dma_alloc_from_contiguous
+                                               (dev,
                                                buf_cfg.len >> PAGE_SHIFT, 0);
                if (cma_pages != NULL) {
-                       fh->mmap_type = buf_cfg.type;
-                       ret = meson_gdc_set_buff(fh, cma_pages, buf_cfg.len);
+                       context->mmap_type = buf_cfg.type;
+                       ret = meson_gdc_set_buff(context,
+                               cma_pages, buf_cfg.len);
                        if (ret != 0) {
                                dma_release_from_contiguous(
-                                               &fh->gdev->pdev->dev,
+                                               dev,
                                                cma_pages,
                                                buf_cfg.len >> PAGE_SHIFT);
                                gdc_log(LOG_ERR, "Failed to set buff\n");
@@ -1995,15 +1552,13 @@ static long meson_gdc_ioctl(struct file *file, unsigned int cmd,
                        gdc_log(LOG_ERR, "copy from user failed\n");
                memcpy(&gdc_cmd->gdc_config, &gs_with_fw.gdc_config,
                        sizeof(struct gdc_config_s));
-               ret = gdc_process_with_fw(fh, &gs_with_fw);
+               ret = gdc_process_with_fw(context, &gs_with_fw);
                break;
        case GDC_PROCESS_EX:
                ret = copy_from_user(&gs_ex, argp, sizeof(gs_ex));
                if (ret < 0)
                        gdc_log(LOG_ERR, "copy from user failed\n");
-               memcpy(&gdc_cmd->gdc_config, &gs_ex.gdc_config,
-                       sizeof(struct gdc_config_s));
-               ret = gdc_process_ex_info(fh, &gs_ex);
+               ret = gdc_process_ex_info(context, &gs_ex);
                break;
        case GDC_REQUEST_DMA_BUFF:
                ret = copy_from_user(&gdc_req_buf, argp,
@@ -2070,21 +1625,22 @@ static int meson_gdc_mmap(struct file *file_p,
 {
        int ret = -1;
        unsigned long buf_len = 0;
-       struct mgdc_fh_s *fh = file_p->private_data;
+       struct gdc_context_s *context = NULL;
 
        buf_len = vma->vm_end - vma->vm_start;
+       context = (struct gdc_context_s *)file_p->private_data;
 
-       switch (fh->mmap_type) {
+       switch (context->mmap_type) {
        case INPUT_BUFF_TYPE:
                ret = remap_pfn_range(vma, vma->vm_start,
-                       fh->i_paddr >> PAGE_SHIFT,
+                       context->i_paddr >> PAGE_SHIFT,
                        buf_len, vma->vm_page_prot);
                if (ret != 0)
                        gdc_log(LOG_ERR, "Failed to mmap input buffer\n");
        break;
        case OUTPUT_BUFF_TYPE:
                ret = remap_pfn_range(vma, vma->vm_start,
-                       fh->o_paddr >> PAGE_SHIFT,
+                       context->o_paddr >> PAGE_SHIFT,
                        buf_len, vma->vm_page_prot);
                if (ret != 0)
                        gdc_log(LOG_ERR, "Failed to mmap input buffer\n");
@@ -2092,13 +1648,13 @@ static int meson_gdc_mmap(struct file *file_p,
        break;
        case CONFIG_BUFF_TYPE:
                ret = remap_pfn_range(vma, vma->vm_start,
-                       fh->c_paddr >> PAGE_SHIFT,
+                       context->c_paddr >> PAGE_SHIFT,
                        buf_len, vma->vm_page_prot);
                if (ret != 0)
                        gdc_log(LOG_ERR, "Failed to mmap input buffer\n");
        break;
        default:
-               gdc_log(LOG_ERR, "Error mmap type:0x%x\n", fh->mmap_type);
+               gdc_log(LOG_ERR, "Error mmap type:0x%x\n", context->mmap_type);
        break;
        }
 
@@ -2259,10 +1815,7 @@ static DEVICE_ATTR(config_out_path, 0664, config_out_path_show,
 
 irqreturn_t gdc_interrupt_handler(int irq, void *param)
 {
-       struct meson_gdc_dev_t *gdc_dev = param;
-
-       complete(&gdc_dev->d_com);
-
+       complete(&gdc_manager.event.d_com);
        return IRQ_HANDLED;
 }
 
@@ -2308,7 +1861,6 @@ static int gdc_platform_probe(struct platform_device *pdev)
        gdc_dev->misc_dev.minor = meson_gdc_dev.minor;
        gdc_dev->misc_dev.name = meson_gdc_dev.name;
        gdc_dev->misc_dev.fops = meson_gdc_dev.fops;
-       spin_lock_init(&gdc_dev->slock);
 
        gdc_dev->irq = platform_get_irq(pdev, 0);
        if (gdc_dev->irq < 0) {
@@ -2347,17 +1899,14 @@ static int gdc_platform_probe(struct platform_device *pdev)
                gdc_log(LOG_INFO, "gdc axi clk is %d MHZ\n", rc/1000000);
        }
 
-       mutex_init(&gdc_dev->d_mutext);
-       init_completion(&gdc_dev->d_com);
-
        rc = devm_request_irq(&pdev->dev, gdc_dev->irq,
                                                gdc_interrupt_handler,
                                                IRQF_SHARED, "gdc", gdc_dev);
        if (rc != 0)
                gdc_log(LOG_ERR, "cannot create irq func gdc\n");
 
-       gdc_manager.buffer = gdc_dma_buffer_create();
-       gdc_manager.gdc_dev = gdc_dev;
+       gdc_wq_init(gdc_dev);
+
        rc = misc_register(&gdc_dev->misc_dev);
        if (rc < 0) {
                dev_err(&pdev->dev,
@@ -2395,11 +1944,9 @@ static int gdc_platform_remove(struct platform_device *pdev)
        device_remove_file(meson_gdc_dev.this_device,
                &dev_attr_config_out_path);
 
-       gdc_dma_buffer_destroy(gdc_manager.buffer);
-       gdc_manager.gdc_dev = NULL;
-
        kfree(config_out_file);
        config_out_file = NULL;
+       gdc_wq_deinit();
 
        misc_deregister(&meson_gdc_dev);
        return 0;
diff --git a/drivers/amlogic/media/gdc/app/gdc_wq.c b/drivers/amlogic/media/gdc/app/gdc_wq.c
new file mode 100644 (file)
index 0000000..0a78969
--- /dev/null
@@ -0,0 +1,508 @@
+/*
+ * drivers/amlogic/media/gdc/app/gdc_wq.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/miscdevice.h>
+#include <linux/types.h>
+#include <linux/clk.h>
+#include <linux/uaccess.h>
+#include <meson_ion.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/dma-contiguous.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/dma-buf.h>
+
+#include <linux/of_address.h>
+#include <api/gdc_api.h>
+#include "system_log.h"
+
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+
+#include "gdc_config.h"
+#include "gdc_dmabuf.h"
+#include "gdc_wq.h"
+
+#define WAIT_THRESHOLD 1000
+
+u8 __iomem *map_virt_from_phys(phys_addr_t phys, unsigned long total_size)
+{
+       u32 offset, npages;
+       struct page **pages = NULL;
+       pgprot_t pgprot;
+       u8 __iomem *vaddr;
+       int i;
+
+       npages = PAGE_ALIGN(total_size) / PAGE_SIZE;
+       offset = phys & (~PAGE_MASK);
+       if (offset)
+               npages++;
+       pages = vmalloc(sizeof(struct page *) * npages);
+       if (!pages)
+               return NULL;
+       for (i = 0; i < npages; i++) {
+               pages[i] = phys_to_page(phys);
+               phys += PAGE_SIZE;
+       }
+       /*nocache*/
+       pgprot = pgprot_noncached(PAGE_KERNEL);
+
+       vaddr = vmap(pages, npages, VM_MAP, pgprot);
+       if (!vaddr) {
+               pr_err("vmaped fail, size: %d\n",
+                       npages << PAGE_SHIFT);
+               vfree(pages);
+               return NULL;
+       }
+       vfree(pages);
+
+       return vaddr;
+}
+
+void unmap_virt_from_phys(u8 __iomem *vaddr)
+{
+       if (vaddr) {
+               /* unmap prevois vaddr */
+               vunmap(vaddr);
+               vaddr = NULL;
+       }
+}
+
+static int write_buf_to_file(char *path, char *buf, int size)
+{
+       int ret = 0;
+       struct file *fp = NULL;
+       mm_segment_t old_fs;
+       loff_t pos = 0;
+       int w_size = 0;
+
+       if (!path || !config_out_path_defined) {
+               gdc_log(LOG_ERR, "please define path first\n");
+               return -1;
+       }
+
+       /* change to KERNEL_DS address limit */
+       old_fs = get_fs();
+       set_fs(KERNEL_DS);
+
+       /* open file to write */
+       fp = filp_open(path, O_WRONLY|O_CREAT, 0640);
+       if (IS_ERR(fp)) {
+               gdc_log(LOG_ERR, "open file error\n");
+               ret = -1;
+       }
+
+       /* Write buf to file */
+       w_size = vfs_write(fp, buf, size, &pos);
+       gdc_log(LOG_INFO, "write w_size = %u, size = %u\n", w_size, size);
+
+       vfs_fsync(fp, 0);
+       filp_close(fp, NULL);
+       set_fs(old_fs);
+
+       return w_size;
+}
+
+static void dump_config_file(struct gdc_config_s *gc)
+{
+       void __iomem *config_virt_addr;
+       int ret;
+
+       /* dump config buffer */
+       config_virt_addr =
+               map_virt_from_phys(gc->config_addr,
+               PAGE_ALIGN(gc->config_size * 4));
+       ret = write_buf_to_file(config_out_file,
+                               config_virt_addr,
+                               (gc->config_size * 4));
+       if (ret <= 0)
+               gdc_log(LOG_ERR,
+                       "Failed to read_file_to_buf\n");
+       unmap_virt_from_phys(config_virt_addr);
+}
+
+static void dump_gdc_regs(void)
+{
+       int i;
+
+       for (i = 0; i <= 0xFF; i += 4)
+               gdc_log(LOG_ERR, "reg[0x%x] = 0x%x\n",
+                       i, system_gdc_read_32(i));
+
+}
+
+static int gdc_process_work_queue(struct gdc_context_s *wq)
+{
+       struct gdc_queue_item_s *pitem;
+       struct list_head  *head = &wq->work_queue, *pos;
+       int ret = 0, i = 0;
+       unsigned int block_mode;
+       int timeout = 0;
+       ktime_t start_time, stop_time, diff_time;
+       int process_time = 0;
+
+       if (wq->gdc_request_exit)
+               goto exit;
+       gdc_manager.gdc_state = GDC_STATE_RUNNING;
+       pos = head->next;
+       if (pos != head) { /* current work queue not empty. */
+               if (wq != gdc_manager.last_wq) { /* maybe */
+                       /* modify the first item . */
+                       pitem = (struct gdc_queue_item_s *)pos;
+                       if (!pitem) {
+                               gdc_log(LOG_ERR, "can't get pitem\n");
+                               ret = -1;
+                               goto  exit;
+                       }
+               } else
+                       /* modify the first item . */
+                       pitem = (struct gdc_queue_item_s *)pos;
+
+       } else {
+               ret = -1;
+               goto  exit;
+       }
+       do {
+               block_mode = pitem->cmd.wait_done_flag;
+               if (trace_mode_enable >= 1)
+                       start_time = ktime_get();
+               ret = gdc_run(&pitem->cmd);
+               if (ret < 0)
+                       gdc_log(LOG_ERR, "gdc process failed ret = %d\n", ret);
+               timeout = wait_for_completion_timeout(&gdc_manager.event.d_com,
+                       msecs_to_jiffies(WAIT_THRESHOLD));
+               if (timeout == 0) {
+                       gdc_log(LOG_ERR, "gdc timeout, status = 0x%x\n",
+                               gdc_status_read());
+                       /*soft_rst(); */
+                       if (trace_mode_enable >= 2) {
+                               /* dump regs */
+                               dump_gdc_regs();
+                               /* dump config buffer */
+                               dump_config_file(&pitem->cmd.gdc_config);
+                       }
+               }
+               gdc_stop(&pitem->cmd);
+               if (trace_mode_enable >= 1) {
+                       stop_time = ktime_get();
+                       diff_time = ktime_sub(stop_time, start_time);
+                       process_time = ktime_to_ms(diff_time);
+                       if (process_time > 50)
+                               gdc_log(LOG_ERR, "gdc process time = %d\n",
+                                       process_time);
+               }
+
+               /* if block mode (cmd) */
+               if (block_mode) {
+                       pitem->cmd.wait_done_flag = 0;
+                       wake_up_interruptible(&wq->cmd_complete);
+               }
+               spin_lock(&wq->lock);
+               pos = pos->next;
+               list_move_tail(&pitem->list, &wq->free_queue);
+               spin_unlock(&wq->lock);
+               /* if dma buf detach it */
+               for (i = 0; i < MAX_PLANE; i++) {
+                       if (pitem->dma_cfg.input_cfg[i].dma_used) {
+                               gdc_dma_buffer_unmap_info(gdc_manager.buffer,
+                                       &pitem->dma_cfg.input_cfg[i].dma_cfg);
+                               pitem->dma_cfg.input_cfg[i].dma_used = 0;
+                       }
+                       if (pitem->dma_cfg.output_cfg[i].dma_used) {
+                               gdc_dma_buffer_unmap_info(gdc_manager.buffer,
+                                       &pitem->dma_cfg.output_cfg[i].dma_cfg);
+                               pitem->dma_cfg.output_cfg[i].dma_used = 0;
+                       }
+               }
+               if (pitem->dma_cfg.config_cfg.dma_used) {
+                       gdc_dma_buffer_unmap_info(gdc_manager.buffer,
+                               &pitem->dma_cfg.config_cfg.dma_cfg);
+                       pitem->dma_cfg.config_cfg.dma_used = 0;
+               }
+               pitem = (struct gdc_queue_item_s *)pos;
+       } while (pos != head);
+       gdc_manager.last_wq = wq;
+exit:
+       if (wq->gdc_request_exit)
+               complete(&gdc_manager.event.process_complete);
+       gdc_manager.gdc_state = GDC_STATE_IDLE;
+       return ret;
+}
+
+static inline struct gdc_context_s *get_next_gdc_work_queue(
+               struct gdc_manager_s *manager)
+{
+       struct gdc_context_s *pcontext;
+
+       spin_lock(&manager->event.sem_lock);
+       list_for_each_entry(pcontext, &manager->process_queue, list) {
+               /* not lock maybe delay to next time. */
+               if (!list_empty(&pcontext->work_queue)) {
+                       /* move head . */
+                       list_move(&manager->process_queue, &pcontext->list);
+                       spin_unlock(&manager->event.sem_lock);
+                       return pcontext;
+               }
+       }
+       spin_unlock(&manager->event.sem_lock);
+       return NULL;
+}
+
+static int gdc_monitor_thread(void *data)
+{
+       int ret;
+       struct gdc_manager_s *manager = (struct gdc_manager_s *)data;
+
+       gdc_log(LOG_INFO, "gdc workqueue monitor start\n");
+       /* setup current_wq here. */
+       while (manager->process_queue_state != GDC_PROCESS_QUEUE_STOP) {
+               ret = down_interruptible(&manager->event.cmd_in_sem);
+               gdc_pwr_config(true);
+               while ((manager->current_wq =
+                               get_next_gdc_work_queue(manager)) != NULL)
+                       gdc_process_work_queue(manager->current_wq);
+               if (!gdc_reg_store_mode)
+                       gdc_pwr_config(false);
+       }
+       gdc_log(LOG_INFO, "exit gdc_monitor_thread\n");
+       return 0;
+}
+
+static int gdc_start_monitor(void)
+{
+       int ret = 0;
+
+       gdc_log(LOG_INFO, "gdc start monitor\n");
+       gdc_manager.process_queue_state = GDC_PROCESS_QUEUE_START;
+       gdc_manager.gdc_thread = kthread_run(gdc_monitor_thread,
+                                              &gdc_manager,
+                                              "gdc_monitor");
+       if (IS_ERR(gdc_manager.gdc_thread)) {
+               ret = PTR_ERR(gdc_manager.gdc_thread);
+               gdc_log(LOG_ERR, "failed to start kthread (%d)\n", ret);
+       }
+       return ret;
+}
+
+static int gdc_stop_monitor(void)
+{
+       gdc_log(LOG_INFO, "gdc stop monitor\n");
+       if (gdc_manager.gdc_thread) {
+               gdc_manager.process_queue_state = GDC_PROCESS_QUEUE_STOP;
+               up(&gdc_manager.event.cmd_in_sem);
+               kthread_stop(gdc_manager.gdc_thread);
+               gdc_manager.gdc_thread = NULL;
+       }
+       return  0;
+}
+
+static inline int work_queue_no_space(struct gdc_context_s *queue)
+{
+       return  list_empty(&queue->free_queue);
+}
+
+struct gdc_context_s *create_gdc_work_queue(void)
+{
+       int  i;
+       struct gdc_queue_item_s *p_item;
+       struct gdc_context_s *gdc_work_queue;
+       int  empty;
+
+       gdc_work_queue = kzalloc(sizeof(struct gdc_context_s), GFP_KERNEL);
+       if (IS_ERR(gdc_work_queue)) {
+               gdc_log(LOG_ERR, "can't create work queue\n");
+               return NULL;
+       }
+       gdc_work_queue->gdc_request_exit = 0;
+       INIT_LIST_HEAD(&gdc_work_queue->work_queue);
+       INIT_LIST_HEAD(&gdc_work_queue->free_queue);
+       init_waitqueue_head(&gdc_work_queue->cmd_complete);
+       mutex_init(&gdc_work_queue->d_mutext);
+       spin_lock_init(&gdc_work_queue->lock);  /* for process lock. */
+       for (i = 0; i < MAX_GDC_CMD; i++) {
+               p_item = kcalloc(1,
+                               sizeof(struct gdc_queue_item_s),
+                               GFP_KERNEL);
+               if (IS_ERR(p_item)) {
+                       gdc_log(LOG_ERR, "can't request queue item memory\n");
+                       goto fail;
+               }
+               list_add_tail(&p_item->list, &gdc_work_queue->free_queue);
+       }
+
+       /* put this process queue  into manager queue list. */
+       /* maybe process queue is changing . */
+       spin_lock(&gdc_manager.event.sem_lock);
+       empty = list_empty(&gdc_manager.process_queue);
+       list_add_tail(&gdc_work_queue->list, &gdc_manager.process_queue);
+       spin_unlock(&gdc_manager.event.sem_lock);
+       return gdc_work_queue; /* find it */
+fail:
+       {
+               struct list_head *head;
+               struct gdc_queue_item_s *tmp;
+
+               head = &gdc_work_queue->free_queue;
+               list_for_each_entry_safe(p_item, tmp, head, list) {
+                       if (p_item) {
+                               list_del(&p_item->list);
+                               kfree(p_item);
+                       }
+               }
+               return NULL;
+       }
+}
+EXPORT_SYMBOL(create_gdc_work_queue);
+
+int destroy_gdc_work_queue(struct gdc_context_s *gdc_work_queue)
+{
+       struct gdc_queue_item_s *pitem, *tmp;
+       struct list_head                *head;
+       int empty, timeout = 0;
+
+       if (gdc_work_queue) {
+               /* first detatch it from the process queue,then delete it . */
+               /* maybe process queue is changing .so we lock it. */
+               spin_lock(&gdc_manager.event.sem_lock);
+               list_del(&gdc_work_queue->list);
+               empty = list_empty(&gdc_manager.process_queue);
+               spin_unlock(&gdc_manager.event.sem_lock);
+               if ((gdc_manager.current_wq == gdc_work_queue) &&
+                   (gdc_manager.gdc_state == GDC_STATE_RUNNING)) {
+                       gdc_work_queue->gdc_request_exit = 1;
+                       timeout = wait_for_completion_timeout(
+                                       &gdc_manager.event.process_complete,
+                                       msecs_to_jiffies(500));
+                       if (!timeout)
+                               gdc_log(LOG_ERR, "wait timeout\n");
+                       /* condition so complex ,simplify it . */
+                       gdc_manager.last_wq = NULL;
+               } /* else we can delete it safely. */
+
+               head = &gdc_work_queue->work_queue;
+               list_for_each_entry_safe(pitem, tmp, head, list) {
+                       if (pitem) {
+                               list_del(&pitem->list);
+                               kfree(pitem);
+                       }
+               }
+               head = &gdc_work_queue->free_queue;
+               list_for_each_entry_safe(pitem, tmp, head, list) {
+                       if (pitem) {
+                               list_del(&pitem->list);
+                               kfree(pitem);
+                       }
+               }
+
+               kfree(gdc_work_queue);
+               gdc_work_queue = NULL;
+               return 0;
+       }
+
+       return  -1;
+}
+EXPORT_SYMBOL(destroy_gdc_work_queue);
+
+void *gdc_prepare_item(struct gdc_context_s *wq)
+{
+       struct gdc_queue_item_s *pitem;
+
+       if (work_queue_no_space(wq)) {
+               gdc_log(LOG_ERR, "work queue no space\n");
+               return NULL;
+       }
+
+       pitem = list_entry(wq->free_queue.next, struct gdc_queue_item_s, list);
+       if (IS_ERR(pitem))
+               return NULL;
+
+       memcpy(&pitem->cmd, &wq->cmd, sizeof(struct gdc_cmd_s));
+       memcpy(&pitem->dma_cfg, &wq->dma_cfg, sizeof(struct gdc_dma_cfg_t));
+       return pitem;
+}
+
+int gdc_wq_add_work(struct gdc_context_s *wq,
+       struct gdc_queue_item_s *pitem)
+{
+       gdc_log(LOG_INFO, "gdc add work\n");
+       spin_lock(&wq->lock);
+       list_move_tail(&pitem->list, &wq->work_queue);
+       spin_unlock(&wq->lock);
+       gdc_log(LOG_INFO, "gdc add work ok\n");
+       /* only read not need lock */
+       if (gdc_manager.event.cmd_in_sem.count == 0)
+               up(&gdc_manager.event.cmd_in_sem);/* new cmd come in */
+       /* add block mode   if() */
+       if (pitem->cmd.wait_done_flag) {
+               wait_event_interruptible(wq->cmd_complete,
+                               pitem->cmd.wait_done_flag == 0);
+               /* interruptible_sleep_on(&wq->cmd_complete); */
+       }
+       return 0;
+}
+
+int gdc_wq_init(struct meson_gdc_dev_t *gdc_dev)
+{
+       gdc_log(LOG_INFO, "init gdc device\n");
+       gdc_manager.gdc_dev = gdc_dev;
+
+       /* prepare bottom half */
+       spin_lock_init(&gdc_manager.event.sem_lock);
+       sema_init(&gdc_manager.event.cmd_in_sem, 1);
+       init_completion(&gdc_manager.event.d_com);
+       init_completion(&gdc_manager.event.process_complete);
+       INIT_LIST_HEAD(&gdc_manager.process_queue);
+       gdc_manager.last_wq = NULL;
+       gdc_manager.gdc_thread = NULL;
+       gdc_manager.buffer = gdc_dma_buffer_create();
+       if (!gdc_manager.buffer)
+               return -1;
+       if (!gdc_manager.ion_client)
+               gdc_manager.ion_client =
+               meson_ion_client_create(-1, "meson-gdc");
+
+       if (gdc_start_monitor()) {
+               gdc_log(LOG_ERR, "gdc create thread error\n");
+               return -1;
+       }
+       return 0;
+}
+
+int gdc_wq_deinit(void)
+{
+       if (gdc_manager.ion_client) {
+               ion_client_destroy(gdc_manager.ion_client);
+               gdc_manager.ion_client = NULL;
+       }
+
+       gdc_stop_monitor();
+       gdc_log(LOG_INFO, "deinit gdc device\n");
+
+       gdc_dma_buffer_destroy(gdc_manager.buffer);
+       gdc_manager.buffer = NULL;
+       gdc_manager.gdc_dev = NULL;
+       return  0;
+}
diff --git a/drivers/amlogic/media/gdc/app/gdc_wq.h b/drivers/amlogic/media/gdc/app/gdc_wq.h
new file mode 100644 (file)
index 0000000..265ac27
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * drivers/amlogic/media/gdc/app/gdc_wq.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef _GDC_WQ_H_
+#define _GDC_WQ_H_
+
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <gdc_config.h>
+
+struct gdc_cmd_s;
+#define MAX_GDC_CMD  32   /* 64 */
+#define MAX_PLANE    3
+#define GDC_STATE_IDLE                 0
+#define GDC_STATE_RUNNING              1
+
+#define        GDC_PROCESS_QUEUE_START        0
+#define        GDC_PROCESS_QUEUE_STOP         1
+
+struct gdc_dmabuf_cfg_s {
+       int dma_used;
+       struct aml_dma_cfg dma_cfg;
+};
+
+struct gdc_dma_cfg_t {
+       struct gdc_dmabuf_cfg_s config_cfg;
+       struct gdc_dmabuf_cfg_s input_cfg[MAX_PLANE];
+       struct gdc_dmabuf_cfg_s output_cfg[MAX_PLANE];
+};
+
+struct gdc_queue_item_s {
+       struct list_head list;
+       struct gdc_cmd_s cmd;
+       struct gdc_dma_cfg_t dma_cfg;
+};
+
+struct gdc_context_s {
+       /* connect all process in one queue for RR process. */
+       struct list_head   list;
+       /* current wq configuration */
+       uint32_t mmap_type;
+       dma_addr_t i_paddr;
+       dma_addr_t o_paddr;
+       dma_addr_t c_paddr;
+       void *i_kaddr;
+       void *o_kaddr;
+       void *c_kaddr;
+       unsigned long i_len;
+       unsigned long o_len;
+       unsigned long c_len;
+       struct gdc_dma_cfg y_dma_cfg;
+       struct gdc_dma_cfg uv_dma_cfg;
+       struct gdc_dma_cfg_t dma_cfg;
+       struct mutex d_mutext;
+
+       struct gdc_cmd_s        cmd;
+       struct list_head        work_queue;
+       struct list_head        free_queue;
+       wait_queue_head_t       cmd_complete;
+       int                     gdc_request_exit;
+       spinlock_t              lock;/* for get and release item. */
+};
+
+extern unsigned int gdc_reg_store_mode;
+extern int trace_mode_enable;
+extern char *config_out_file;
+extern int config_out_path_defined;
+
+u8 __iomem *map_virt_from_phys(phys_addr_t phys, unsigned long total_size);
+void unmap_virt_from_phys(u8 __iomem *vaddr);
+
+int gdc_wq_init(struct meson_gdc_dev_t *gdc_dev);
+int gdc_wq_deinit(void);
+void *gdc_prepare_item(struct gdc_context_s *wq);
+int gdc_wq_add_work(struct gdc_context_s *wq,
+       struct gdc_queue_item_s *pitem);
+struct gdc_context_s *create_gdc_work_queue(void);
+int destroy_gdc_work_queue(struct gdc_context_s *gdc_work_queue);
+#endif
index f0695c2..5aa1c31 100644 (file)
@@ -21,8 +21,6 @@
 #include <linux/of_address.h>
 #include <linux/dma-direction.h>
 
-extern struct gdc_manager_s gdc_manager;
-
 enum gdc_memtype_s {
        AML_GDC_MEM_ION,
        AML_GDC_MEM_DMABUF,
@@ -216,13 +214,7 @@ struct gdc_cmd_s {
        };
        uint32_t v_base_addr;
 
-       //when inititialised this callback will be called
-       //to update frame buffer addresses and offsets
-       void (*get_frame_buffer)(uint32_t y_base_addr,
-                       uint32_t uv_base_addr,
-                       uint32_t y_line_offset,
-                       uint32_t uv_line_offset);
-       void *fh;
+       unsigned char wait_done_flag;
 };
 
 /* path: "/vendor/lib/firmware/gdc/" */
index 1d47b0d..866b275 100644 (file)
 #include "system_gdc_io.h"
 #include "gdc_api.h"
 #include "gdc_dmabuf.h"
-struct gdc_cmd_s;
 
-struct gdc_manager_s {
-       struct aml_dma_buffer *buffer;
-       struct meson_gdc_dev_t *gdc_dev;
-};
+struct gdc_context_s;
 
 struct meson_gdc_dev_t {
        struct platform_device *pdev;
-       void    *reg_base;
+       int irq;
        struct clk      *clk_core;
        struct clk      *clk_axi;
-       spinlock_t      slock;
-       struct mutex d_mutext;
-       struct completion d_com;
-       int      irq;
        struct miscdevice misc_dev;
 };
 
-struct gdc_dma_cfg_t {
-       struct aml_dma_cfg config_cfg;
-       struct aml_dma_cfg input_cfg_plane1;
-       struct aml_dma_cfg input_cfg_plane2;
-       struct aml_dma_cfg input_cfg_plane3;
-       struct aml_dma_cfg output_cfg_plane1;
-       struct aml_dma_cfg output_cfg_plane2;
-       struct aml_dma_cfg output_cfg_plane3;
+struct gdc_event_s {
+       struct completion d_com;
+       struct completion process_complete;
+       /* for queue switch and create destroy queue. */
+       spinlock_t sem_lock;
+       struct semaphore cmd_in_sem;
 };
 
-struct mgdc_fh_s {
-       struct list_head list;
-       wait_queue_head_t       irq_queue;
-       struct meson_gdc_dev_t *gdev;
-       char task_comm[32];
+struct gdc_manager_s {
        struct ion_client   *ion_client;
-       struct gdc_cmd_s gdc_cmd;
-       uint32_t mmap_type;
-       dma_addr_t i_paddr;
-       dma_addr_t o_paddr;
-       dma_addr_t c_paddr;
-       void *i_kaddr;
-       void *o_kaddr;
-       void *c_kaddr;
-       unsigned long i_len;
-       unsigned long o_len;
-       unsigned long c_len;
-       struct gdc_dma_cfg y_dma_cfg;
-       struct gdc_dma_cfg uv_dma_cfg;
-       struct gdc_dma_cfg_t dma_cfg;
+       struct list_head process_queue;
+       struct gdc_context_s *current_wq;
+       struct gdc_context_s *last_wq;
+       struct task_struct *gdc_thread;
+       struct gdc_event_s event;
+       struct aml_dma_buffer *buffer;
+       int gdc_state;
+       int process_queue_state;//thread running flag
+       struct meson_gdc_dev_t *gdc_dev;
 };
 
+extern struct gdc_manager_s gdc_manager;
+
 irqreturn_t interrupt_handler_next(int irq, void *param);
 // ----------------------------------- //
 // Instance 'gdc' of module 'gdc_ip_config'
index aabc66b..30ead28 100644 (file)
@@ -29,7 +29,6 @@
 #include "system_log.h"
 #include "gdc_config.h"
 
-
 /**
  *   Configure the output gdc configuration address/size
  *
@@ -462,6 +461,7 @@ int gdc_process_rgb444p(struct gdc_cmd_s *gdc_cmd,
        return 0;
 }
 
+#if 0
 /**
  *   This function gets the GDC output frame addresses
  *
@@ -507,7 +507,7 @@ int gdc_get_frame(struct gdc_cmd_s *gdc_cmd)
        //spin_unlock_irqrestore(&gdev->slock, flags);
        return 0;
 }
-
+#endif
 /**
  *   This function set the GDC power on/off
  *