Commit 9448ab7d authored by Sylwester Nawrocki's avatar Sylwester Nawrocki Committed by Mauro Carvalho Chehab

[media] s5p-fimc: Add color effect control

Add support for V4L2_CID_COLORFX control at the mem-to-mem and capture
video nodes.
Signed-off-by: default avatarSylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 0c9204d3
...@@ -62,7 +62,7 @@ static int fimc_capture_hw_init(struct fimc_dev *fimc) ...@@ -62,7 +62,7 @@ static int fimc_capture_hw_init(struct fimc_dev *fimc)
fimc_hw_set_mainscaler(ctx); fimc_hw_set_mainscaler(ctx);
fimc_hw_set_target_format(ctx); fimc_hw_set_target_format(ctx);
fimc_hw_set_rotation(ctx); fimc_hw_set_rotation(ctx);
fimc_hw_set_effect(ctx, false); fimc_hw_set_effect(ctx);
fimc_hw_set_output_path(ctx); fimc_hw_set_output_path(ctx);
fimc_hw_set_out_dma(ctx); fimc_hw_set_out_dma(ctx);
if (fimc->variant->has_alpha) if (fimc->variant->has_alpha)
...@@ -164,6 +164,7 @@ static int fimc_capture_config_update(struct fimc_ctx *ctx) ...@@ -164,6 +164,7 @@ static int fimc_capture_config_update(struct fimc_ctx *ctx)
fimc_hw_set_mainscaler(ctx); fimc_hw_set_mainscaler(ctx);
fimc_hw_set_target_format(ctx); fimc_hw_set_target_format(ctx);
fimc_hw_set_rotation(ctx); fimc_hw_set_rotation(ctx);
fimc_hw_set_effect(ctx);
fimc_prepare_dma_offset(ctx, &ctx->d_frame); fimc_prepare_dma_offset(ctx, &ctx->d_frame);
fimc_hw_set_out_dma(ctx); fimc_hw_set_out_dma(ctx);
if (fimc->variant->has_alpha) if (fimc->variant->has_alpha)
...@@ -462,14 +463,14 @@ int fimc_capture_ctrls_create(struct fimc_dev *fimc) ...@@ -462,14 +463,14 @@ int fimc_capture_ctrls_create(struct fimc_dev *fimc)
if (WARN_ON(vid_cap->ctx == NULL)) if (WARN_ON(vid_cap->ctx == NULL))
return -ENXIO; return -ENXIO;
if (vid_cap->ctx->ctrls_rdy) if (vid_cap->ctx->ctrls.ready)
return 0; return 0;
ret = fimc_ctrls_create(vid_cap->ctx); ret = fimc_ctrls_create(vid_cap->ctx);
if (ret || vid_cap->user_subdev_api) if (ret || vid_cap->user_subdev_api || !vid_cap->ctx->ctrls.ready)
return ret; return ret;
return v4l2_ctrl_add_handler(&vid_cap->ctx->ctrl_handler, return v4l2_ctrl_add_handler(&vid_cap->ctx->ctrls.handler,
fimc->pipeline.subdevs[IDX_SENSOR]->ctrl_handler); fimc->pipeline.subdevs[IDX_SENSOR]->ctrl_handler);
} }
...@@ -1588,7 +1589,7 @@ static int fimc_register_capture_device(struct fimc_dev *fimc, ...@@ -1588,7 +1589,7 @@ static int fimc_register_capture_device(struct fimc_dev *fimc,
v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n", v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n",
vfd->name, video_device_node_name(vfd)); vfd->name, video_device_node_name(vfd));
vfd->ctrl_handler = &ctx->ctrl_handler; vfd->ctrl_handler = &ctx->ctrls.handler;
return 0; return 0;
err_vd: err_vd:
......
...@@ -463,11 +463,53 @@ void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f) ...@@ -463,11 +463,53 @@ void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
f->fmt->color, f->dma_offset.y_h, f->dma_offset.y_v); f->fmt->color, f->dma_offset.y_h, f->dma_offset.y_v);
} }
int fimc_set_color_effect(struct fimc_ctx *ctx, enum v4l2_colorfx colorfx)
{
struct fimc_effect *effect = &ctx->effect;
switch (colorfx) {
case V4L2_COLORFX_NONE:
effect->type = FIMC_REG_CIIMGEFF_FIN_BYPASS;
break;
case V4L2_COLORFX_BW:
effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY;
effect->pat_cb = 128;
effect->pat_cr = 128;
break;
case V4L2_COLORFX_SEPIA:
effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY;
effect->pat_cb = 115;
effect->pat_cr = 145;
break;
case V4L2_COLORFX_NEGATIVE:
effect->type = FIMC_REG_CIIMGEFF_FIN_NEGATIVE;
break;
case V4L2_COLORFX_EMBOSS:
effect->type = FIMC_REG_CIIMGEFF_FIN_EMBOSSING;
break;
case V4L2_COLORFX_ART_FREEZE:
effect->type = FIMC_REG_CIIMGEFF_FIN_ARTFREEZE;
break;
case V4L2_COLORFX_SILHOUETTE:
effect->type = FIMC_REG_CIIMGEFF_FIN_SILHOUETTE;
break;
case V4L2_COLORFX_SET_CBCR:
effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY;
effect->pat_cb = ctx->ctrls.colorfx_cbcr->val >> 8;
effect->pat_cr = ctx->ctrls.colorfx_cbcr->val & 0xff;
break;
default:
return -EINVAL;
}
return 0;
}
/* /*
* V4L2 controls handling * V4L2 controls handling
*/ */
#define ctrl_to_ctx(__ctrl) \ #define ctrl_to_ctx(__ctrl) \
container_of((__ctrl)->handler, struct fimc_ctx, ctrl_handler) container_of((__ctrl)->handler, struct fimc_ctx, ctrls.handler)
static int __fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_ctrl *ctrl) static int __fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_ctrl *ctrl)
{ {
...@@ -507,7 +549,14 @@ static int __fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_ctrl *ctrl) ...@@ -507,7 +549,14 @@ static int __fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_ctrl *ctrl)
case V4L2_CID_ALPHA_COMPONENT: case V4L2_CID_ALPHA_COMPONENT:
ctx->d_frame.alpha = ctrl->val; ctx->d_frame.alpha = ctrl->val;
break; break;
case V4L2_CID_COLORFX:
ret = fimc_set_color_effect(ctx, ctrl->val);
if (ret)
return ret;
break;
} }
ctx->state |= FIMC_PARAMS; ctx->state |= FIMC_PARAMS;
set_bit(ST_CAPT_APPLY_CFG, &fimc->state); set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
return 0; return 0;
...@@ -534,69 +583,91 @@ int fimc_ctrls_create(struct fimc_ctx *ctx) ...@@ -534,69 +583,91 @@ int fimc_ctrls_create(struct fimc_ctx *ctx)
{ {
struct fimc_variant *variant = ctx->fimc_dev->variant; struct fimc_variant *variant = ctx->fimc_dev->variant;
unsigned int max_alpha = fimc_get_alpha_mask(ctx->d_frame.fmt); unsigned int max_alpha = fimc_get_alpha_mask(ctx->d_frame.fmt);
struct fimc_ctrls *ctrls = &ctx->ctrls;
struct v4l2_ctrl_handler *handler = &ctrls->handler;
if (ctx->ctrls_rdy) if (ctx->ctrls.ready)
return 0; return 0;
v4l2_ctrl_handler_init(&ctx->ctrl_handler, 4);
ctx->ctrl_rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops, v4l2_ctrl_handler_init(handler, 6);
ctrls->rotate = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
V4L2_CID_ROTATE, 0, 270, 90, 0); V4L2_CID_ROTATE, 0, 270, 90, 0);
ctx->ctrl_hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops, ctrls->hflip = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
V4L2_CID_HFLIP, 0, 1, 1, 0); V4L2_CID_HFLIP, 0, 1, 1, 0);
ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops, ctrls->vflip = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0); V4L2_CID_VFLIP, 0, 1, 1, 0);
if (variant->has_alpha) if (variant->has_alpha)
ctx->ctrl_alpha = v4l2_ctrl_new_std(&ctx->ctrl_handler, ctrls->alpha = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
&fimc_ctrl_ops, V4L2_CID_ALPHA_COMPONENT, V4L2_CID_ALPHA_COMPONENT,
0, max_alpha, 1, 0); 0, max_alpha, 1, 0);
else else
ctx->ctrl_alpha = NULL; ctrls->alpha = NULL;
ctrls->colorfx = v4l2_ctrl_new_std_menu(handler, &fimc_ctrl_ops,
V4L2_CID_COLORFX, V4L2_COLORFX_SET_CBCR,
~0x983f, V4L2_COLORFX_NONE);
ctrls->colorfx_cbcr = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
V4L2_CID_COLORFX_CBCR, 0, 0xffff, 1, 0);
ctx->ctrls_rdy = ctx->ctrl_handler.error == 0; ctx->effect.type = FIMC_REG_CIIMGEFF_FIN_BYPASS;
return ctx->ctrl_handler.error; if (!handler->error) {
v4l2_ctrl_cluster(3, &ctrls->colorfx);
ctrls->ready = true;
}
return handler->error;
} }
void fimc_ctrls_delete(struct fimc_ctx *ctx) void fimc_ctrls_delete(struct fimc_ctx *ctx)
{ {
if (ctx->ctrls_rdy) { struct fimc_ctrls *ctrls = &ctx->ctrls;
v4l2_ctrl_handler_free(&ctx->ctrl_handler);
ctx->ctrls_rdy = false; if (ctrls->ready) {
ctx->ctrl_alpha = NULL; v4l2_ctrl_handler_free(&ctrls->handler);
ctrls->ready = false;
ctrls->alpha = NULL;
} }
} }
void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active) void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active)
{ {
unsigned int has_alpha = ctx->d_frame.fmt->flags & FMT_HAS_ALPHA; unsigned int has_alpha = ctx->d_frame.fmt->flags & FMT_HAS_ALPHA;
struct fimc_ctrls *ctrls = &ctx->ctrls;
if (!ctx->ctrls_rdy) if (!ctrls->ready)
return; return;
mutex_lock(&ctx->ctrl_handler.lock); mutex_lock(&ctrls->handler.lock);
v4l2_ctrl_activate(ctx->ctrl_rotate, active); v4l2_ctrl_activate(ctrls->rotate, active);
v4l2_ctrl_activate(ctx->ctrl_hflip, active); v4l2_ctrl_activate(ctrls->hflip, active);
v4l2_ctrl_activate(ctx->ctrl_vflip, active); v4l2_ctrl_activate(ctrls->vflip, active);
if (ctx->ctrl_alpha) v4l2_ctrl_activate(ctrls->colorfx, active);
v4l2_ctrl_activate(ctx->ctrl_alpha, active && has_alpha); if (ctrls->alpha)
v4l2_ctrl_activate(ctrls->alpha, active && has_alpha);
if (active) { if (active) {
ctx->rotation = ctx->ctrl_rotate->val; fimc_set_color_effect(ctx, ctrls->colorfx->cur.val);
ctx->hflip = ctx->ctrl_hflip->val; ctx->rotation = ctrls->rotate->val;
ctx->vflip = ctx->ctrl_vflip->val; ctx->hflip = ctrls->hflip->val;
ctx->vflip = ctrls->vflip->val;
} else { } else {
ctx->effect.type = FIMC_REG_CIIMGEFF_FIN_BYPASS;
ctx->rotation = 0; ctx->rotation = 0;
ctx->hflip = 0; ctx->hflip = 0;
ctx->vflip = 0; ctx->vflip = 0;
} }
mutex_unlock(&ctx->ctrl_handler.lock); mutex_unlock(&ctrls->handler.lock);
} }
/* Update maximum value of the alpha color control */ /* Update maximum value of the alpha color control */
void fimc_alpha_ctrl_update(struct fimc_ctx *ctx) void fimc_alpha_ctrl_update(struct fimc_ctx *ctx)
{ {
struct fimc_dev *fimc = ctx->fimc_dev; struct fimc_dev *fimc = ctx->fimc_dev;
struct v4l2_ctrl *ctrl = ctx->ctrl_alpha; struct v4l2_ctrl *ctrl = ctx->ctrls.alpha;
if (ctrl == NULL || !fimc->variant->has_alpha) if (ctrl == NULL || !fimc->variant->has_alpha)
return; return;
......
...@@ -445,6 +445,30 @@ struct fimc_dev { ...@@ -445,6 +445,30 @@ struct fimc_dev {
struct fimc_pipeline pipeline; struct fimc_pipeline pipeline;
}; };
/**
* struct fimc_ctrls - v4l2 controls structure
* @handler: the control handler
* @colorfx: image effect control
* @colorfx_cbcr: Cb/Cr coefficients control
* @rotate: image rotation control
* @hflip: horizontal flip control
* @vflip: vertical flip control
* @alpha: RGB alpha control
* @ready: true if @handler is initialized
*/
struct fimc_ctrls {
struct v4l2_ctrl_handler handler;
struct {
struct v4l2_ctrl *colorfx;
struct v4l2_ctrl *colorfx_cbcr;
};
struct v4l2_ctrl *rotate;
struct v4l2_ctrl *hflip;
struct v4l2_ctrl *vflip;
struct v4l2_ctrl *alpha;
bool ready;
};
/** /**
* fimc_ctx - the device context data * fimc_ctx - the device context data
* @s_frame: source frame properties * @s_frame: source frame properties
...@@ -465,12 +489,7 @@ struct fimc_dev { ...@@ -465,12 +489,7 @@ struct fimc_dev {
* @fimc_dev: the FIMC device this context applies to * @fimc_dev: the FIMC device this context applies to
* @m2m_ctx: memory-to-memory device context * @m2m_ctx: memory-to-memory device context
* @fh: v4l2 file handle * @fh: v4l2 file handle
* @ctrl_handler: v4l2 controls handler * @ctrls: v4l2 controls structure
* @ctrl_rotate image rotation control
* @ctrl_hflip horizontal flip control
* @ctrl_vflip vertical flip control
* @ctrl_alpha RGB alpha control
* @ctrls_rdy: true if the control handler is initialized
*/ */
struct fimc_ctx { struct fimc_ctx {
struct fimc_frame s_frame; struct fimc_frame s_frame;
...@@ -491,12 +510,7 @@ struct fimc_ctx { ...@@ -491,12 +510,7 @@ struct fimc_ctx {
struct fimc_dev *fimc_dev; struct fimc_dev *fimc_dev;
struct v4l2_m2m_ctx *m2m_ctx; struct v4l2_m2m_ctx *m2m_ctx;
struct v4l2_fh fh; struct v4l2_fh fh;
struct v4l2_ctrl_handler ctrl_handler; struct fimc_ctrls ctrls;
struct v4l2_ctrl *ctrl_rotate;
struct v4l2_ctrl *ctrl_hflip;
struct v4l2_ctrl *ctrl_vflip;
struct v4l2_ctrl *ctrl_alpha;
bool ctrls_rdy;
}; };
#define fh_to_ctx(__fh) container_of(__fh, struct fimc_ctx, fh) #define fh_to_ctx(__fh) container_of(__fh, struct fimc_ctx, fh)
......
...@@ -150,7 +150,7 @@ static void fimc_device_run(void *priv) ...@@ -150,7 +150,7 @@ static void fimc_device_run(void *priv)
fimc_hw_set_mainscaler(ctx); fimc_hw_set_mainscaler(ctx);
fimc_hw_set_target_format(ctx); fimc_hw_set_target_format(ctx);
fimc_hw_set_rotation(ctx); fimc_hw_set_rotation(ctx);
fimc_hw_set_effect(ctx, false); fimc_hw_set_effect(ctx);
fimc_hw_set_out_dma(ctx); fimc_hw_set_out_dma(ctx);
if (fimc->variant->has_alpha) if (fimc->variant->has_alpha)
fimc_hw_set_rgb_alpha(ctx); fimc_hw_set_rgb_alpha(ctx);
...@@ -669,7 +669,7 @@ static int fimc_m2m_open(struct file *file) ...@@ -669,7 +669,7 @@ static int fimc_m2m_open(struct file *file)
goto error_fh; goto error_fh;
/* Use separate control handler per file handle */ /* Use separate control handler per file handle */
ctx->fh.ctrl_handler = &ctx->ctrl_handler; ctx->fh.ctrl_handler = &ctx->ctrls.handler;
file->private_data = &ctx->fh; file->private_data = &ctx->fh;
v4l2_fh_add(&ctx->fh); v4l2_fh_add(&ctx->fh);
......
...@@ -368,13 +368,13 @@ void fimc_hw_en_capture(struct fimc_ctx *ctx) ...@@ -368,13 +368,13 @@ void fimc_hw_en_capture(struct fimc_ctx *ctx)
writel(cfg, dev->regs + FIMC_REG_CIIMGCPT); writel(cfg, dev->regs + FIMC_REG_CIIMGCPT);
} }
void fimc_hw_set_effect(struct fimc_ctx *ctx, bool active) void fimc_hw_set_effect(struct fimc_ctx *ctx)
{ {
struct fimc_dev *dev = ctx->fimc_dev; struct fimc_dev *dev = ctx->fimc_dev;
struct fimc_effect *effect = &ctx->effect; struct fimc_effect *effect = &ctx->effect;
u32 cfg = 0; u32 cfg = 0;
if (active) { if (effect->type != FIMC_REG_CIIMGEFF_FIN_BYPASS) {
cfg |= FIMC_REG_CIIMGEFF_IE_SC_AFTER | cfg |= FIMC_REG_CIIMGEFF_IE_SC_AFTER |
FIMC_REG_CIIMGEFF_IE_ENABLE; FIMC_REG_CIIMGEFF_IE_ENABLE;
cfg |= effect->type; cfg |= effect->type;
......
...@@ -288,7 +288,7 @@ void fimc_hw_en_irq(struct fimc_dev *fimc, int enable); ...@@ -288,7 +288,7 @@ void fimc_hw_en_irq(struct fimc_dev *fimc, int enable);
void fimc_hw_set_prescaler(struct fimc_ctx *ctx); void fimc_hw_set_prescaler(struct fimc_ctx *ctx);
void fimc_hw_set_mainscaler(struct fimc_ctx *ctx); void fimc_hw_set_mainscaler(struct fimc_ctx *ctx);
void fimc_hw_en_capture(struct fimc_ctx *ctx); void fimc_hw_en_capture(struct fimc_ctx *ctx);
void fimc_hw_set_effect(struct fimc_ctx *ctx, bool active); void fimc_hw_set_effect(struct fimc_ctx *ctx);
void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx); void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx);
void fimc_hw_set_in_dma(struct fimc_ctx *ctx); void fimc_hw_set_in_dma(struct fimc_ctx *ctx);
void fimc_hw_set_input_path(struct fimc_ctx *ctx); void fimc_hw_set_input_path(struct fimc_ctx *ctx);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment