From e74584708a3ec7a64c888566659c67651f27d224 Mon Sep 17 00:00:00 2001 From: Pengcheng Chen Date: Fri, 17 May 2019 17:18:03 +0800 Subject: [PATCH] gdc: add gdc workqueue [1/1] 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 --- MAINTAINERS | 7 +- drivers/amlogic/media/gdc/Makefile | 3 +- drivers/amlogic/media/gdc/app/gdc_main.c | 10 - drivers/amlogic/media/gdc/app/gdc_module.c | 1507 +++++++------------- drivers/amlogic/media/gdc/app/gdc_wq.c | 508 +++++++ drivers/amlogic/media/gdc/app/gdc_wq.h | 95 ++ drivers/amlogic/media/gdc/inc/api/gdc_api.h | 10 +- drivers/amlogic/media/gdc/inc/gdc/gdc_config.h | 57 +- drivers/amlogic/media/gdc/src/fw_lib/acamera_gdc.c | 4 +- 9 files changed, 1161 insertions(+), 1040 deletions(-) create mode 100644 drivers/amlogic/media/gdc/app/gdc_wq.c create mode 100644 drivers/amlogic/media/gdc/app/gdc_wq.h diff --git a/MAINTAINERS b/MAINTAINERS index 7b258a1..b5cbd05 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -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 +F: drivers/amlogic/media/gdc/app/gdc_wq.c +F: drivers/amlogic/media/gdc/app/gdc_wq.h diff --git a/drivers/amlogic/media/gdc/Makefile b/drivers/amlogic/media/gdc/Makefile index d0d4b27..0d1b3a6 100644 --- a/drivers/amlogic/media/gdc/Makefile +++ b/drivers/amlogic/media/gdc/Makefile @@ -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) diff --git a/drivers/amlogic/media/gdc/app/gdc_main.c b/drivers/amlogic/media/gdc/app/gdc_main.c index 538416d..8827123 100644 --- a/drivers/amlogic/media/gdc/app/gdc_main.c +++ b/drivers/amlogic/media/gdc/app/gdc_main.c @@ -22,16 +22,6 @@ //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) { diff --git a/drivers/amlogic/media/gdc/app/gdc_module.c b/drivers/amlogic/media/gdc/app/gdc_module.c index 2191096..211bb835 100644 --- a/drivers/amlogic/media/gdc/app/gdc_module.c +++ b/drivers/amlogic/media/gdc/app/gdc_module.c @@ -46,15 +46,15 @@ //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 index 0000000..0a78969 --- /dev/null +++ b/drivers/amlogic/media/gdc/app/gdc_wq.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "system_log.h" + +#include +#include +#include +#include + +#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 index 0000000..265ac27 --- /dev/null +++ b/drivers/amlogic/media/gdc/app/gdc_wq.h @@ -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 +#include +#include +#include +#include + +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 diff --git a/drivers/amlogic/media/gdc/inc/api/gdc_api.h b/drivers/amlogic/media/gdc/inc/api/gdc_api.h index f0695c2..5aa1c31 100644 --- a/drivers/amlogic/media/gdc/inc/api/gdc_api.h +++ b/drivers/amlogic/media/gdc/inc/api/gdc_api.h @@ -21,8 +21,6 @@ #include #include -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/" */ diff --git a/drivers/amlogic/media/gdc/inc/gdc/gdc_config.h b/drivers/amlogic/media/gdc/inc/gdc/gdc_config.h index 1d47b0d..866b275 100644 --- a/drivers/amlogic/media/gdc/inc/gdc/gdc_config.h +++ b/drivers/amlogic/media/gdc/inc/gdc/gdc_config.h @@ -26,57 +26,40 @@ #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' diff --git a/drivers/amlogic/media/gdc/src/fw_lib/acamera_gdc.c b/drivers/amlogic/media/gdc/src/fw_lib/acamera_gdc.c index aabc66b..30ead28 100644 --- a/drivers/amlogic/media/gdc/src/fw_lib/acamera_gdc.c +++ b/drivers/amlogic/media/gdc/src/fw_lib/acamera_gdc.c @@ -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 * -- 2.7.4