From 09b8979dfd29e35ee0d5e68e585647bccde1ff96 Mon Sep 17 00:00:00 2001 From: "keke.li" Date: Fri, 14 Sep 2018 16:02:03 +0800 Subject: [PATCH] gdc: support Y_grey/YUV444p/RGB444P format image PD#173042: gdc: support Y_grey/YUV444p/RGB444P format image Change-Id: I5b6928bfb4000d58d2bbd05bf8b1121b83ec2c0a Signed-off-by: Keke Li --- drivers/amlogic/media/gdc/app/gdc_main.c | 33 +++- drivers/amlogic/media/gdc/app/gdc_module.c | 109 ++++++++--- drivers/amlogic/media/gdc/inc/api/gdc_api.h | 23 ++- drivers/amlogic/media/gdc/src/fw_lib/acamera_gdc.c | 204 +++++++++++++++++++++ 4 files changed, 328 insertions(+), 41 deletions(-) diff --git a/drivers/amlogic/media/gdc/app/gdc_main.c b/drivers/amlogic/media/gdc/app/gdc_main.c index 6e4a947..c6d6311 100644 --- a/drivers/amlogic/media/gdc/app/gdc_main.c +++ b/drivers/amlogic/media/gdc/app/gdc_main.c @@ -47,14 +47,31 @@ int gdc_run(struct gdc_settings *g) LOG(LOG_INFO, "Done gdc config..\n"); - //start gdc process with input address for y and uv planes - if (g->gdc_config.format == NV12) { - gdc_process(g, (uint32_t)g->y_base_addr, - (uint32_t)g->uv_base_addr); - } else { - gdc_process_yuv420p(g, (uint32_t)g->y_base_addr, - (uint32_t)g->u_base_addr, - (uint32_t)g->v_base_addr); + switch (g->gdc_config.format) { + case NV12: + gdc_process(g, g->y_base_addr, g->uv_base_addr); + break; + case YV12: + gdc_process_yuv420p(g, g->y_base_addr, + g->u_base_addr, + g->v_base_addr); + break; + case Y_GREY: + gdc_process_y_grey(g, g->y_base_addr); + break; + case YUV444_P: + gdc_process_yuv444p(g, g->y_base_addr, + g->u_base_addr, + g->v_base_addr); + break; + case RGB444_P: + gdc_process_rgb444p(g, g->y_base_addr, + g->u_base_addr, + g->v_base_addr); + break; + default: + LOG(LOG_ERR, "Error config format\n"); + break; } LOG(LOG_DEBUG, "call gdc process\n"); diff --git a/drivers/amlogic/media/gdc/app/gdc_module.c b/drivers/amlogic/media/gdc/app/gdc_module.c index a885a7d..7e6fe1b 100644 --- a/drivers/amlogic/media/gdc/app/gdc_module.c +++ b/drivers/amlogic/media/gdc/app/gdc_module.c @@ -196,13 +196,66 @@ static long meson_gdc_set_buff(void *f_fh, return ret; } +static long meson_gdc_set_input_addr(uint32_t start_addr, + struct gdc_settings *gs) +{ + struct gdc_config *gc = NULL; + + if (gs == NULL || start_addr == 0) { + LOG(LOG_ERR, "Error input param\n"); + return -EINVAL; + } + + gc = &gs->gdc_config; + + switch (gc->format) { + case NV12: + gs->y_base_addr = start_addr; + gs->uv_base_addr = start_addr + + gc->input_y_stride * gc->input_height; + break; + case YV12: + gs->y_base_addr = start_addr; + gs->u_base_addr = start_addr + + gc->input_y_stride * gc->input_height; + gs->v_base_addr = gs->u_base_addr + + gc->input_c_stride * gc->input_height / 2; + break; + case Y_GREY: + gs->y_base_addr = start_addr; + gs->u_base_addr = 0; + gs->v_base_addr = 0; + break; + case YUV444_P: + gs->y_base_addr = start_addr; + gs->u_base_addr = start_addr + + gc->input_y_stride * gc->input_height; + gs->v_base_addr = gs->u_base_addr + + gc->input_c_stride * gc->input_height; + break; + case RGB444_P: + gs->y_base_addr = start_addr; + gs->u_base_addr = start_addr + + gc->input_y_stride * gc->input_height; + gs->v_base_addr = gs->u_base_addr + + gc->input_c_stride * gc->input_height; + break; + default: + LOG(LOG_ERR, "Error config format\n"); + return -EINVAL; + break; + } + + return 0; +} + static long meson_gdc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret = 0; size_t len; struct mgdc_fh_s *fh = file->private_data; - struct gdc_settings *gs = &fh->gs; + struct gdc_settings *gs = &fh->gs; struct gdc_config *gc = &gs->gdc_config; struct gdc_buf_cfg buf_cfg; struct page *cma_pages = NULL; @@ -212,8 +265,10 @@ static long meson_gdc_ioctl(struct file *file, unsigned int cmd, switch (cmd) { case GDC_PROCESS: ret = copy_from_user(gs, argp, sizeof(*gs)); - if (ret < 0) - LOG(LOG_DEBUG, "copy from user failed\n"); + if (ret < 0) { + LOG(LOG_ERR, "copy from user failed\n"); + return -EINVAL; + } LOG(LOG_DEBUG, "sizeof(gs)=%zu, magic=%d\n", sizeof(*gs), gs->magic); @@ -221,37 +276,38 @@ static long meson_gdc_ioctl(struct file *file, unsigned int cmd, //configure gdc config, buffer address and resolution ret = meson_ion_share_fd_to_phys(fh->ion_client, gs->out_fd, &addr, &len); + if (ret < 0) { + LOG(LOG_ERR, "import out fd %d failed\n", gs->out_fd); + return -EINVAL; + } gs->buffer_addr = addr; gs->buffer_size = len; - if (ret < 0) - LOG(LOG_DEBUG, "import out fd %d failed\n", gs->out_fd); gs->base_gdc = 0; gs->current_addr = gs->buffer_addr; ret = meson_ion_share_fd_to_phys(fh->ion_client, gc->config_addr, &addr, &len); + if (ret < 0) { + LOG(LOG_ERR, "import config fd failed\n"); + return -EINVAL; + } gc->config_addr = addr; ret = meson_ion_share_fd_to_phys(fh->ion_client, gs->in_fd, &addr, &len); - if (gc->format == NV12) { - gs->y_base_addr = addr; - gs->uv_base_addr = addr + - gc->input_y_stride * gc->input_height; - } else if (gc->format == YV12) { - gs->y_base_addr = addr; - gs->u_base_addr = addr - + gc->input_y_stride * gc->input_height; - - gs->v_base_addr = gs->u_base_addr + - gc->input_c_stride * gc->input_height / 2; + if (ret < 0) { + LOG(LOG_ERR, "import in fd %d failed\n", gs->in_fd); + return -EINVAL; } - if (ret < 0) - LOG(LOG_DEBUG, "import in fd %d failed\n", gs->in_fd); + ret = meson_gdc_set_input_addr(addr, gs); + if (ret != 0) { + LOG(LOG_ERR, "set input addr failed\n"); + return -EINVAL; + } gs->fh = fh; @@ -281,17 +337,10 @@ static long meson_gdc_ioctl(struct file *file, unsigned int cmd, gc->config_addr = fh->c_paddr; - if (gc->format == NV12) { - gs->y_base_addr = fh->i_paddr; - gs->uv_base_addr = fh->i_paddr + - gc->input_y_stride * gc->input_height; - } else if (gc->format == YV12) { - gs->y_base_addr = fh->i_paddr; - gs->u_base_addr = fh->i_paddr + - gc->input_y_stride * gc->input_height; - - gs->v_base_addr = gs->u_base_addr + - gc->input_c_stride * gc->input_height / 2; + ret = meson_gdc_set_input_addr(fh->i_paddr, gs); + if (ret != 0) { + LOG(LOG_ERR, "set input addr failed\n"); + return -EINVAL; } gs->fh = fh; @@ -299,7 +348,7 @@ static long meson_gdc_ioctl(struct file *file, unsigned int cmd, mutex_lock(&fh->gdev->d_mutext); ret = gdc_run(gs); if (ret < 0) - LOG(LOG_ERR, "gdc process ret = %ld\n", ret); + LOG(LOG_ERR, "gdc process failed ret = %ld\n", ret); ret = wait_for_completion_timeout(&fh->gdev->d_com, msecs_to_jiffies(40)); diff --git a/drivers/amlogic/media/gdc/inc/api/gdc_api.h b/drivers/amlogic/media/gdc/inc/api/gdc_api.h index 0da9501..da66a02 100644 --- a/drivers/amlogic/media/gdc/inc/api/gdc_api.h +++ b/drivers/amlogic/media/gdc/inc/api/gdc_api.h @@ -20,9 +20,6 @@ #include -#define NV12 1 -#define YV12 2 - struct gdc_buf_cfg { uint32_t type; unsigned long len; @@ -97,6 +94,15 @@ enum { GDC_BUFF_TYPE_MAX }; +enum { + NV12 = 1, + YV12, + Y_GREY, + YUV444_P, + RGB444_P, + FMT_MAX +}; + /** * Configure the output gdc configuration * @@ -154,6 +160,17 @@ int gdc_process_yuv420p(struct gdc_settings *gdc_settings, uint32_t y_base_addr, uint32_t u_base_addr, uint32_t v_base_addr); +int gdc_process_y_grey(struct gdc_settings *gdc_settings, + uint32_t y_base_addr); +int gdc_process_yuv444p(struct gdc_settings *gdc_settings, + uint32_t y_base_addr, + uint32_t u_base_addr, + uint32_t v_base_addr); +int gdc_process_rgb444p(struct gdc_settings *gdc_settings, + uint32_t y_base_addr, + uint32_t u_base_addr, + uint32_t v_base_addr); + /** * This function gets the GDC output frame addresses * 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 560e104..83a988e 100644 --- a/drivers/amlogic/media/gdc/src/fw_lib/acamera_gdc.c +++ b/drivers/amlogic/media/gdc/src/fw_lib/acamera_gdc.c @@ -236,6 +236,210 @@ int gdc_process_yuv420p(struct gdc_settings *gdc_settings, return 0; } + +/** + * This function points gdc to its input resolution + * + * and yuv address and offsets + * + * Shown inputs to GDC are Y plane address and offsets + * + * @param gdc_settings - overall gdc settings and state + * @param active_width - input width resolution + * @param active_height - input height resolution + * @param y_base_addr - input Y base address + * @param y_line_offset - input Y line buffer offset + * + * @return 0 - success + * -1 - no interrupt from GDC. + */ +int gdc_process_y_grey(struct gdc_settings *gdc_settings, + uint32_t y_base_addr) +{ + struct gdc_config *gc = &gdc_settings->gdc_config; + uint32_t gdc_out_base_addr = gdc_settings->current_addr; + uint32_t input_width = gc->input_width; + uint32_t input_height = gc->input_height; + uint32_t input_stride = gc->input_y_stride; + uint32_t output_stride = gc->output_y_stride; + + LOG(LOG_DEBUG, "is_waiting_gdc=%d\n", gdc_settings->is_waiting_gdc); + if (gdc_settings->is_waiting_gdc) { + gdc_start_flag_write(0); + LOG(LOG_CRIT, "No interrupt Still waiting...\n"); + gdc_start_flag_write(1); + return -1; + } + + LOG(LOG_DEBUG, "starting GDC process.\n"); + + gdc_datain_width_write(input_width); + gdc_datain_height_write(input_height); + //input y plane + gdc_data1in_addr_write(y_base_addr); + gdc_data1in_line_offset_write(input_stride); + + //gdc y output + gdc_data1out_addr_write(gdc_out_base_addr); + gdc_data1out_line_offset_write(output_stride); + + gdc_start(gdc_settings); + + return 0; +} + +/** + * This function points gdc to its input resolution + * + * and yuv address and offsets + * + * Shown inputs to GDC are Y and UV plane address and offsets + * + * @param gdc_settings - overall gdc settings and state + * @param active_width - input width resolution + * @param active_height - input height resolution + * @param y_base_addr - input Y base address + * @param uv_base_addr - input UV base address + * @param y_line_offset - input Y line buffer offset + * @param uv_line_offset- input UV line buffer offer + * + * @return 0 - success + * -1 - no interrupt from GDC. + */ +int gdc_process_yuv444p(struct gdc_settings *gdc_settings, + uint32_t y_base_addr, uint32_t u_base_addr, uint32_t v_base_addr) +{ + struct gdc_config *gc = &gdc_settings->gdc_config; + uint32_t gdc_out_base_addr = gdc_settings->current_addr; + uint32_t input_width = gc->input_width; + uint32_t input_height = gc->input_height; + uint32_t input_stride = gc->input_y_stride; + uint32_t input_u_stride = gc->input_c_stride; + uint32_t input_v_stride = gc->input_c_stride; + uint32_t output_height = gc->output_height; + uint32_t output_stride = gc->output_y_stride; + uint32_t output_u_stride = gc->output_c_stride; + uint32_t output_v_stride = gc->output_c_stride; + + LOG(LOG_DEBUG, "is_waiting_gdc=%d\n", gdc_settings->is_waiting_gdc); + if (gdc_settings->is_waiting_gdc) { + gdc_start_flag_write(0); + LOG(LOG_CRIT, "No interrupt Still waiting...\n"); + gdc_start_flag_write(1); + return -1; + } + + LOG(LOG_DEBUG, "starting GDC process.\n"); + + gdc_datain_width_write(input_width); + gdc_datain_height_write(input_height); + //input y plane + gdc_data1in_addr_write(y_base_addr); + gdc_data1in_line_offset_write(input_stride); + + //input u plane + gdc_data2in_addr_write(u_base_addr); + gdc_data2in_line_offset_write(input_u_stride); + + //input v plane + gdc_data3in_addr_write(v_base_addr); + gdc_data3in_line_offset_write(input_v_stride); + + //gdc y output + gdc_data1out_addr_write(gdc_out_base_addr); + gdc_data1out_line_offset_write(output_stride); + + //gdc u output + gdc_out_base_addr += output_height * output_stride; + gdc_data2out_addr_write(gdc_out_base_addr); + gdc_data2out_line_offset_write(output_u_stride); + + //gdc v output + gdc_out_base_addr += output_height * output_u_stride; + gdc_data3out_addr_write(gdc_out_base_addr); + gdc_data3out_line_offset_write(output_v_stride); + gdc_start(gdc_settings); + + return 0; +} + +/** + * This function points gdc to its input resolution + * + * and rgb address and offsets + * + * Shown inputs to GDC are R\G\B plane address and offsets + * + * @param gdc_settings - overall gdc settings and state + * @param active_width - input width resolution + * @param active_height - input height resolution + * @param y_base_addr - input R base address + * @param u_base_addr - input G base address + * @param v_base_addr - input B base address + * @param y_line_offset - input R line buffer offset + * @param u_line_offset- input G line buffer offer + * @param v_line_offset- input B line buffer offer + * + * @return 0 - success + * -1 - no interrupt from GDC. + */ +int gdc_process_rgb444p(struct gdc_settings *gdc_settings, + uint32_t y_base_addr, uint32_t u_base_addr, uint32_t v_base_addr) +{ + struct gdc_config *gc = &gdc_settings->gdc_config; + uint32_t gdc_out_base_addr = gdc_settings->current_addr; + uint32_t input_width = gc->input_width; + uint32_t input_height = gc->input_height; + uint32_t input_stride = gc->input_y_stride; + uint32_t input_u_stride = gc->input_c_stride; + uint32_t input_v_stride = gc->input_c_stride; + uint32_t output_height = gc->output_height; + uint32_t output_stride = gc->output_y_stride; + uint32_t output_u_stride = gc->output_c_stride; + uint32_t output_v_stride = gc->output_c_stride; + + LOG(LOG_DEBUG, "is_waiting_gdc=%d\n", gdc_settings->is_waiting_gdc); + if (gdc_settings->is_waiting_gdc) { + gdc_start_flag_write(0); + LOG(LOG_CRIT, "No interrupt Still waiting...\n"); + gdc_start_flag_write(1); + return -1; + } + + LOG(LOG_DEBUG, "starting GDC process.\n"); + + gdc_datain_width_write(input_width); + gdc_datain_height_write(input_height); + //input y plane + gdc_data1in_addr_write(y_base_addr); + gdc_data1in_line_offset_write(input_stride); + + //input u plane + gdc_data2in_addr_write(u_base_addr); + gdc_data2in_line_offset_write(input_u_stride); + + //input v plane + gdc_data3in_addr_write(v_base_addr); + gdc_data3in_line_offset_write(input_v_stride); + + //gdc y output + gdc_data1out_addr_write(gdc_out_base_addr); + gdc_data1out_line_offset_write(output_stride); + + //gdc u output + gdc_out_base_addr += output_height * output_stride; + gdc_data2out_addr_write(gdc_out_base_addr); + gdc_data2out_line_offset_write(output_u_stride); + + //gdc v output + gdc_out_base_addr += output_height * output_u_stride; + gdc_data3out_addr_write(gdc_out_base_addr); + gdc_data3out_line_offset_write(output_v_stride); + gdc_start(gdc_settings); + + return 0; +} + /** * This function gets the GDC output frame addresses * -- 2.7.4