[media] adv7511: fix quantization range handling

Commit 1fb69bfd29 (adv7511: improve
colorspace handling) introduced a number of bugs, specifically with
regards to YCbCr output and quantization range handling:

- if the output is not RGB, then disable the full-to-limited range
  CSC matrix since that is meant for RGB formats. YCbCr formats are
  always limited range, so there is nothing to convert. (OK, full
  range YCbCr is possible, but we don't support that right now).

- the mediabus code that was passed to adv7511_set_fmt was always cleared
  by the memset in adv7511_fill_format. This made it effectively impossible
  to select YCbCr output.

- adv7511_set_fmt never updated the rgb quantization range.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
This commit is contained in:
Hans Verkuil 2016-06-28 11:32:36 -03:00 committed by Mauro Carvalho Chehab
parent afd620f81b
commit 0a25a01251

View File

@ -382,16 +382,20 @@ static void adv7511_csc_rgb_full2limit(struct v4l2_subdev *sd, bool enable)
} }
} }
static int adv7511_set_rgb_quantization_mode(struct v4l2_subdev *sd, struct v4l2_ctrl *ctrl) static void adv7511_set_rgb_quantization_mode(struct v4l2_subdev *sd, struct v4l2_ctrl *ctrl)
{ {
switch (ctrl->val) { struct adv7511_state *state = get_adv7511_state(sd);
default:
return -EINVAL;
break;
case V4L2_DV_RGB_RANGE_AUTO: {
/* automatic */
struct adv7511_state *state = get_adv7511_state(sd);
/* Only makes sense for RGB formats */
if (state->fmt_code != MEDIA_BUS_FMT_RGB888_1X24) {
/* so just keep quantization */
adv7511_csc_rgb_full2limit(sd, false);
return;
}
switch (ctrl->val) {
case V4L2_DV_RGB_RANGE_AUTO:
/* automatic */
if (state->dv_timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) { if (state->dv_timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) {
/* CE format, RGB limited range (16-235) */ /* CE format, RGB limited range (16-235) */
adv7511_csc_rgb_full2limit(sd, true); adv7511_csc_rgb_full2limit(sd, true);
@ -399,7 +403,6 @@ static int adv7511_set_rgb_quantization_mode(struct v4l2_subdev *sd, struct v4l2
/* not CE format, RGB full range (0-255) */ /* not CE format, RGB full range (0-255) */
adv7511_csc_rgb_full2limit(sd, false); adv7511_csc_rgb_full2limit(sd, false);
} }
}
break; break;
case V4L2_DV_RGB_RANGE_LIMITED: case V4L2_DV_RGB_RANGE_LIMITED:
/* RGB limited range (16-235) */ /* RGB limited range (16-235) */
@ -410,7 +413,6 @@ static int adv7511_set_rgb_quantization_mode(struct v4l2_subdev *sd, struct v4l2
adv7511_csc_rgb_full2limit(sd, false); adv7511_csc_rgb_full2limit(sd, false);
break; break;
} }
return 0;
} }
/* ------------------------------ CTRL OPS ------------------------------ */ /* ------------------------------ CTRL OPS ------------------------------ */
@ -427,8 +429,10 @@ static int adv7511_s_ctrl(struct v4l2_ctrl *ctrl)
adv7511_wr_and_or(sd, 0xaf, 0xfd, ctrl->val == V4L2_DV_TX_MODE_HDMI ? 0x02 : 0x00); adv7511_wr_and_or(sd, 0xaf, 0xfd, ctrl->val == V4L2_DV_TX_MODE_HDMI ? 0x02 : 0x00);
return 0; return 0;
} }
if (state->rgb_quantization_range_ctrl == ctrl) if (state->rgb_quantization_range_ctrl == ctrl) {
return adv7511_set_rgb_quantization_mode(sd, ctrl); adv7511_set_rgb_quantization_mode(sd, ctrl);
return 0;
}
if (state->content_type_ctrl == ctrl) { if (state->content_type_ctrl == ctrl) {
u8 itc, cn; u8 itc, cn;
@ -1235,8 +1239,6 @@ static int adv7511_enum_mbus_code(struct v4l2_subdev *sd,
static void adv7511_fill_format(struct adv7511_state *state, static void adv7511_fill_format(struct adv7511_state *state,
struct v4l2_mbus_framefmt *format) struct v4l2_mbus_framefmt *format)
{ {
memset(format, 0, sizeof(*format));
format->width = state->dv_timings.bt.width; format->width = state->dv_timings.bt.width;
format->height = state->dv_timings.bt.height; format->height = state->dv_timings.bt.height;
format->field = V4L2_FIELD_NONE; format->field = V4L2_FIELD_NONE;
@ -1251,6 +1253,7 @@ static int adv7511_get_fmt(struct v4l2_subdev *sd,
if (format->pad != 0) if (format->pad != 0)
return -EINVAL; return -EINVAL;
memset(&format->format, 0, sizeof(format->format));
adv7511_fill_format(state, &format->format); adv7511_fill_format(state, &format->format);
if (format->which == V4L2_SUBDEV_FORMAT_TRY) { if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
@ -1411,6 +1414,7 @@ static int adv7511_set_fmt(struct v4l2_subdev *sd,
adv7511_wr_and_or(sd, 0x57, 0x83, (ec << 4) | (q << 2) | (itc << 7)); adv7511_wr_and_or(sd, 0x57, 0x83, (ec << 4) | (q << 2) | (itc << 7));
adv7511_wr_and_or(sd, 0x59, 0x0f, (yq << 6) | (cn << 4)); adv7511_wr_and_or(sd, 0x59, 0x0f, (yq << 6) | (cn << 4));
adv7511_wr_and_or(sd, 0x4a, 0xff, 1); adv7511_wr_and_or(sd, 0x4a, 0xff, 1);
adv7511_set_rgb_quantization_mode(sd, state->rgb_quantization_range_ctrl);
return 0; return 0;
} }