Commit eec5ce01 authored by Guennadi Liakhovetski's avatar Guennadi Liakhovetski Committed by Mauro Carvalho Chehab

[media] V4L: sh_mobile_ceu_camera: output image sizes must be a multiple of 4

CEU can only produce images with 4 pixel aligned width and height.
Enforce this alignment, adjust comments and simplify some calculations.
Signed-off-by: default avatarGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 4860c738
...@@ -121,7 +121,7 @@ struct sh_mobile_ceu_dev { ...@@ -121,7 +121,7 @@ struct sh_mobile_ceu_dev {
}; };
struct sh_mobile_ceu_cam { struct sh_mobile_ceu_cam {
/* CEU offsets within scaled by the CEU camera output */ /* CEU offsets within the camera output, before the CEU scaler */
unsigned int ceu_left; unsigned int ceu_left;
unsigned int ceu_top; unsigned int ceu_top;
/* Client output, as seen by the CEU */ /* Client output, as seen by the CEU */
...@@ -628,22 +628,22 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd) ...@@ -628,22 +628,22 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd)
left_offset = cam->ceu_left; left_offset = cam->ceu_left;
top_offset = cam->ceu_top; top_offset = cam->ceu_top;
/* CEU cropping (CFSZR) is applied _after_ the scaling filter (CFLCR) */ WARN_ON(icd->user_width & 3 || icd->user_height & 3);
width = icd->user_width;
if (pcdev->image_mode) { if (pcdev->image_mode) {
in_width = cam->width; in_width = cam->width;
if (!pcdev->is_16bit) { if (!pcdev->is_16bit) {
in_width *= 2; in_width *= 2;
left_offset *= 2; left_offset *= 2;
} }
width = icd->user_width; cdwdr_width = width;
cdwdr_width = icd->user_width;
} else { } else {
int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, int bytes_per_line = soc_mbus_bytes_per_line(width,
icd->current_fmt->host_fmt); icd->current_fmt->host_fmt);
unsigned int w_factor; unsigned int w_factor;
width = icd->user_width;
switch (icd->current_fmt->host_fmt->packing) { switch (icd->current_fmt->host_fmt->packing) {
case SOC_MBUS_PACKING_2X8_PADHI: case SOC_MBUS_PACKING_2X8_PADHI:
w_factor = 2; w_factor = 2;
...@@ -653,10 +653,10 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd) ...@@ -653,10 +653,10 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd)
} }
in_width = cam->width * w_factor; in_width = cam->width * w_factor;
left_offset = left_offset * w_factor; left_offset *= w_factor;
if (bytes_per_line < 0) if (bytes_per_line < 0)
cdwdr_width = icd->user_width; cdwdr_width = width;
else else
cdwdr_width = bytes_per_line; cdwdr_width = bytes_per_line;
} }
...@@ -664,7 +664,7 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd) ...@@ -664,7 +664,7 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd)
height = icd->user_height; height = icd->user_height;
in_height = cam->height; in_height = cam->height;
if (V4L2_FIELD_NONE != pcdev->field) { if (V4L2_FIELD_NONE != pcdev->field) {
height /= 2; height = (height / 2) & ~3;
in_height /= 2; in_height /= 2;
top_offset /= 2; top_offset /= 2;
cdwdr_width *= 2; cdwdr_width *= 2;
...@@ -686,6 +686,7 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd) ...@@ -686,6 +686,7 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd)
ceu_write(pcdev, CAMOR, camor); ceu_write(pcdev, CAMOR, camor);
ceu_write(pcdev, CAPWR, (in_height << 16) | in_width); ceu_write(pcdev, CAPWR, (in_height << 16) | in_width);
/* CFSZR clipping is applied _after_ the scaling filter (CFLCR) */
ceu_write(pcdev, CFSZR, (height << 16) | width); ceu_write(pcdev, CFSZR, (height << 16) | width);
ceu_write(pcdev, CDWDR, cdwdr_width); ceu_write(pcdev, CDWDR, cdwdr_width);
} }
...@@ -1414,7 +1415,10 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, ...@@ -1414,7 +1415,10 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
capsr = capture_save_reset(pcdev); capsr = capture_save_reset(pcdev);
dev_dbg(dev, "CAPSR 0x%x, CFLCR 0x%x\n", capsr, pcdev->cflcr); dev_dbg(dev, "CAPSR 0x%x, CFLCR 0x%x\n", capsr, pcdev->cflcr);
/* 1. - 2. Apply iterative camera S_CROP for new input window. */ /*
* 1. - 2. Apply iterative camera S_CROP for new input window, read back
* actual camera rectangle.
*/
ret = client_s_crop(icd, a, &cam_crop); ret = client_s_crop(icd, a, &cam_crop);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -1498,8 +1502,9 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, ...@@ -1498,8 +1502,9 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
ceu_write(pcdev, CFLCR, cflcr); ceu_write(pcdev, CFLCR, cflcr);
} }
icd->user_width = out_width; icd->user_width = out_width & ~3;
icd->user_height = out_height; icd->user_height = out_height & ~3;
/* Offsets are applied at the CEU scaling filter input */
cam->ceu_left = scale_down(rect->left - cam_rect->left, scale_cam_h) & ~1; cam->ceu_left = scale_down(rect->left - cam_rect->left, scale_cam_h) & ~1;
cam->ceu_top = scale_down(rect->top - cam_rect->top, scale_cam_v) & ~1; cam->ceu_top = scale_down(rect->top - cam_rect->top, scale_cam_v) & ~1;
...@@ -1538,7 +1543,7 @@ static int sh_mobile_ceu_get_crop(struct soc_camera_device *icd, ...@@ -1538,7 +1543,7 @@ static int sh_mobile_ceu_get_crop(struct soc_camera_device *icd,
* CEU crop, mapped backed onto the client input (subrect). * CEU crop, mapped backed onto the client input (subrect).
*/ */
static void calculate_client_output(struct soc_camera_device *icd, static void calculate_client_output(struct soc_camera_device *icd,
struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mf) const struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mf)
{ {
struct sh_mobile_ceu_cam *cam = icd->host_priv; struct sh_mobile_ceu_cam *cam = icd->host_priv;
struct device *dev = icd->parent; struct device *dev = icd->parent;
...@@ -1623,7 +1628,7 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, ...@@ -1623,7 +1628,7 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
} }
/* 1.-4. Calculate client output geometry */ /* 1.-4. Calculate client output geometry */
calculate_client_output(icd, &f->fmt.pix, &mf); calculate_client_output(icd, pix, &mf);
mf.field = pix->field; mf.field = pix->field;
mf.colorspace = pix->colorspace; mf.colorspace = pix->colorspace;
mf.code = xlate->code; mf.code = xlate->code;
...@@ -1700,6 +1705,10 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, ...@@ -1700,6 +1705,10 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
pcdev->field = field; pcdev->field = field;
pcdev->image_mode = image_mode; pcdev->image_mode = image_mode;
/* CFSZR requirement */
pix->width &= ~3;
pix->height &= ~3;
return 0; return 0;
} }
...@@ -1725,7 +1734,8 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, ...@@ -1725,7 +1734,8 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
/* FIXME: calculate using depth and bus width */ /* FIXME: calculate using depth and bus width */
v4l_bound_align_image(&pix->width, 2, 2560, 1, /* CFSZR requires height and width to be 4-pixel aligned */
v4l_bound_align_image(&pix->width, 2, 2560, 2,
&pix->height, 4, 1920, 2, 0); &pix->height, 4, 1920, 2, 0);
width = pix->width; width = pix->width;
...@@ -1778,6 +1788,9 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, ...@@ -1778,6 +1788,9 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
pix->height = height; pix->height = height;
} }
pix->width &= ~3;
pix->height &= ~3;
dev_geo(icd->parent, "%s(): return %d, fmt 0x%x, %ux%u\n", dev_geo(icd->parent, "%s(): return %d, fmt 0x%x, %ux%u\n",
__func__, ret, pix->pixelformat, pix->width, pix->height); __func__, ret, pix->pixelformat, pix->width, pix->height);
...@@ -1824,8 +1837,8 @@ static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd, ...@@ -1824,8 +1837,8 @@ static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd,
out_height != f.fmt.pix.height)) out_height != f.fmt.pix.height))
ret = -EINVAL; ret = -EINVAL;
if (!ret) { if (!ret) {
icd->user_width = out_width; icd->user_width = out_width & ~3;
icd->user_height = out_height; icd->user_height = out_height & ~3;
ret = sh_mobile_ceu_set_bus_param(icd, ret = sh_mobile_ceu_set_bus_param(icd,
icd->current_fmt->host_fmt->fourcc); icd->current_fmt->host_fmt->fourcc);
} }
......
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