mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 03:40:35 +09:00
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:
@@ -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");
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user