gdc: support Y_grey/YUV444p/RGB444P format image
authorkeke.li <keke.li@amlogic.com>
Fri, 14 Sep 2018 08:02:03 +0000 (16:02 +0800)
committerJianxin Pan <jianxin.pan@amlogic.com>
Tue, 18 Sep 2018 11:02:14 +0000 (04:02 -0700)
PD#173042: gdc: support Y_grey/YUV444p/RGB444P format image

Change-Id: I5b6928bfb4000d58d2bbd05bf8b1121b83ec2c0a
Signed-off-by: Keke Li <keke.li@amlogic.com>
drivers/amlogic/media/gdc/app/gdc_main.c
drivers/amlogic/media/gdc/app/gdc_module.c
drivers/amlogic/media/gdc/inc/api/gdc_api.h
drivers/amlogic/media/gdc/src/fw_lib/acamera_gdc.c

index 6e4a947..c6d6311 100644 (file)
@@ -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");
 
index a885a7d..7e6fe1b 100644 (file)
@@ -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));
index 0da9501..da66a02 100644 (file)
@@ -20,9 +20,6 @@
 
 #include <linux/of_address.h>
 
-#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
  *
index 560e104..83a988e 100644 (file)
@@ -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
  *