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 <keke.li@amlogic.com>
This commit is contained in:
keke.li
2018-09-14 16:02:03 +08:00
committed by Jianxin Pan
parent 6fbde97524
commit 09b8979dfd
4 changed files with 328 additions and 41 deletions

View 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");

View 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));

View 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
*

View 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
*