提交 eca430c8 编写于 作者: G Guennadi Liakhovetski 提交者: Mauro Carvalho Chehab

[media] V4L2: sh_mobile_ceu_camera: remove CEU specific data from generic functions

Several functions in the sh_mobile_ceu_camera driver implement generic
algorithms and can be re-used by other V4L2 camera host drivers too. These
functions attempt to optimise scaling and cropping functions of the
subdevice, e.g. a camera sensor. This patch makes those functions generic
for future re-use by other camera host drivers.
Signed-off-by: NGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: NMauro Carvalho Chehab <mchehab@redhat.com>
上级 c67f1a30
...@@ -1005,7 +1005,7 @@ static bool sh_mobile_ceu_packing_supported(const struct soc_mbus_pixelfmt *fmt) ...@@ -1005,7 +1005,7 @@ static bool sh_mobile_ceu_packing_supported(const struct soc_mbus_pixelfmt *fmt)
fmt->packing == SOC_MBUS_PACKING_EXTEND16); fmt->packing == SOC_MBUS_PACKING_EXTEND16);
} }
static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect); static int soc_camera_client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect);
static struct soc_camera_device *ctrl_to_icd(struct v4l2_ctrl *ctrl) static struct soc_camera_device *ctrl_to_icd(struct v4l2_ctrl *ctrl)
{ {
...@@ -1084,7 +1084,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int ...@@ -1084,7 +1084,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
/* FIXME: subwindow is lost between close / open */ /* FIXME: subwindow is lost between close / open */
/* Cache current client geometry */ /* Cache current client geometry */
ret = client_g_rect(sd, &rect); ret = soc_camera_client_g_rect(sd, &rect);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -1208,18 +1208,23 @@ static bool is_inside(const struct v4l2_rect *r1, const struct v4l2_rect *r2) ...@@ -1208,18 +1208,23 @@ static bool is_inside(const struct v4l2_rect *r1, const struct v4l2_rect *r2)
r1->top + r1->height < r2->top + r2->height; r1->top + r1->height < r2->top + r2->height;
} }
static unsigned int scale_down(unsigned int size, unsigned int scale) static unsigned int soc_camera_shift_scale(unsigned int size, unsigned int shift,
unsigned int scale)
{ {
return (size * 4096 + scale / 2) / scale; return ((size << shift) + scale / 2) / scale;
} }
static unsigned int calc_generic_scale(unsigned int input, unsigned int output) static unsigned int soc_camera_calc_scale(unsigned int input, unsigned int shift,
unsigned int output)
{ {
return (input * 4096 + output / 2) / output; return soc_camera_shift_scale(input, shift, output);
} }
#define scale_down(size, scale) soc_camera_shift_scale(size, 12, scale)
#define calc_generic_scale(in, out) soc_camera_shift_scale(in, 12, out)
/* Get and store current client crop */ /* Get and store current client crop */
static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect) static int soc_camera_client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect)
{ {
struct v4l2_crop crop; struct v4l2_crop crop;
struct v4l2_cropcap cap; struct v4l2_cropcap cap;
...@@ -1244,10 +1249,8 @@ static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect) ...@@ -1244,10 +1249,8 @@ static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect)
} }
/* Client crop has changed, update our sub-rectangle to remain within the area */ /* Client crop has changed, update our sub-rectangle to remain within the area */
static void update_subrect(struct sh_mobile_ceu_cam *cam) static void update_subrect(struct v4l2_rect *rect, struct v4l2_rect *subrect)
{ {
struct v4l2_rect *rect = &cam->rect, *subrect = &cam->subrect;
if (rect->width < subrect->width) if (rect->width < subrect->width)
subrect->width = rect->width; subrect->width = rect->width;
...@@ -1275,19 +1278,18 @@ static void update_subrect(struct sh_mobile_ceu_cam *cam) ...@@ -1275,19 +1278,18 @@ static void update_subrect(struct sh_mobile_ceu_cam *cam)
* 2. if (1) failed, try to double the client image until we get one big enough * 2. if (1) failed, try to double the client image until we get one big enough
* 3. if (2) failed, try to request the maximum image * 3. if (2) failed, try to request the maximum image
*/ */
static int client_s_crop(struct soc_camera_device *icd, struct v4l2_crop *crop, static int soc_camera_client_s_crop(struct v4l2_subdev *sd,
struct v4l2_crop *cam_crop) struct v4l2_crop *crop, struct v4l2_crop *cam_crop,
struct v4l2_rect *target_rect, struct v4l2_rect *subrect)
{ {
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct v4l2_rect *rect = &crop->c, *cam_rect = &cam_crop->c; struct v4l2_rect *rect = &crop->c, *cam_rect = &cam_crop->c;
struct device *dev = sd->v4l2_dev->dev; struct device *dev = sd->v4l2_dev->dev;
struct sh_mobile_ceu_cam *cam = icd->host_priv;
struct v4l2_cropcap cap; struct v4l2_cropcap cap;
int ret; int ret;
unsigned int width, height; unsigned int width, height;
v4l2_subdev_call(sd, video, s_crop, crop); v4l2_subdev_call(sd, video, s_crop, crop);
ret = client_g_rect(sd, cam_rect); ret = soc_camera_client_g_rect(sd, cam_rect);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -1299,7 +1301,7 @@ static int client_s_crop(struct soc_camera_device *icd, struct v4l2_crop *crop, ...@@ -1299,7 +1301,7 @@ static int client_s_crop(struct soc_camera_device *icd, struct v4l2_crop *crop,
/* Even if camera S_CROP failed, but camera rectangle matches */ /* Even if camera S_CROP failed, but camera rectangle matches */
dev_dbg(dev, "Camera S_CROP successful for %dx%d@%d:%d\n", dev_dbg(dev, "Camera S_CROP successful for %dx%d@%d:%d\n",
rect->width, rect->height, rect->left, rect->top); rect->width, rect->height, rect->left, rect->top);
cam->rect = *cam_rect; *target_rect = *cam_rect;
return 0; return 0;
} }
...@@ -1365,7 +1367,7 @@ static int client_s_crop(struct soc_camera_device *icd, struct v4l2_crop *crop, ...@@ -1365,7 +1367,7 @@ static int client_s_crop(struct soc_camera_device *icd, struct v4l2_crop *crop,
cam_rect->top; cam_rect->top;
v4l2_subdev_call(sd, video, s_crop, cam_crop); v4l2_subdev_call(sd, video, s_crop, cam_crop);
ret = client_g_rect(sd, cam_rect); ret = soc_camera_client_g_rect(sd, cam_rect);
dev_geo(dev, "Camera S_CROP %d for %dx%d@%d:%d\n", ret, dev_geo(dev, "Camera S_CROP %d for %dx%d@%d:%d\n", ret,
cam_rect->width, cam_rect->height, cam_rect->width, cam_rect->height,
cam_rect->left, cam_rect->top); cam_rect->left, cam_rect->top);
...@@ -1379,15 +1381,15 @@ static int client_s_crop(struct soc_camera_device *icd, struct v4l2_crop *crop, ...@@ -1379,15 +1381,15 @@ static int client_s_crop(struct soc_camera_device *icd, struct v4l2_crop *crop,
*/ */
*cam_rect = cap.bounds; *cam_rect = cap.bounds;
v4l2_subdev_call(sd, video, s_crop, cam_crop); v4l2_subdev_call(sd, video, s_crop, cam_crop);
ret = client_g_rect(sd, cam_rect); ret = soc_camera_client_g_rect(sd, cam_rect);
dev_geo(dev, "Camera S_CROP %d for max %dx%d@%d:%d\n", ret, dev_geo(dev, "Camera S_CROP %d for max %dx%d@%d:%d\n", ret,
cam_rect->width, cam_rect->height, cam_rect->width, cam_rect->height,
cam_rect->left, cam_rect->top); cam_rect->left, cam_rect->top);
} }
if (!ret) { if (!ret) {
cam->rect = *cam_rect; *target_rect = *cam_rect;
update_subrect(cam); update_subrect(target_rect, subrect);
} }
return ret; return ret;
...@@ -1395,15 +1397,13 @@ static int client_s_crop(struct soc_camera_device *icd, struct v4l2_crop *crop, ...@@ -1395,15 +1397,13 @@ static int client_s_crop(struct soc_camera_device *icd, struct v4l2_crop *crop,
/* Iterative s_mbus_fmt, also updates cached client crop on success */ /* Iterative s_mbus_fmt, also updates cached client crop on success */
static int client_s_fmt(struct soc_camera_device *icd, static int client_s_fmt(struct soc_camera_device *icd,
struct v4l2_mbus_framefmt *mf, bool ceu_can_scale) struct v4l2_rect *rect, struct v4l2_rect *subrect,
unsigned int max_width, unsigned int max_height,
struct v4l2_mbus_framefmt *mf, bool host_can_scale)
{ {
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
struct sh_mobile_ceu_cam *cam = icd->host_priv;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct device *dev = icd->parent; struct device *dev = icd->parent;
unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h; unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h;
unsigned int max_width, max_height;
struct v4l2_cropcap cap; struct v4l2_cropcap cap;
bool ceu_1to1; bool ceu_1to1;
int ret; int ret;
...@@ -1423,7 +1423,7 @@ static int client_s_fmt(struct soc_camera_device *icd, ...@@ -1423,7 +1423,7 @@ static int client_s_fmt(struct soc_camera_device *icd,
} }
ceu_1to1 = false; ceu_1to1 = false;
if (!ceu_can_scale) if (!host_can_scale)
goto update_cache; goto update_cache;
cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
...@@ -1432,8 +1432,10 @@ static int client_s_fmt(struct soc_camera_device *icd, ...@@ -1432,8 +1432,10 @@ static int client_s_fmt(struct soc_camera_device *icd,
if (ret < 0) if (ret < 0)
return ret; return ret;
max_width = min(cap.bounds.width, pcdev->max_width); if (max_width > cap.bounds.width)
max_height = min(cap.bounds.height, pcdev->max_height); max_width = cap.bounds.width;
if (max_height > cap.bounds.height)
max_height = cap.bounds.height;
/* Camera set a format, but geometry is not precise, try to improve */ /* Camera set a format, but geometry is not precise, try to improve */
tmp_w = mf->width; tmp_w = mf->width;
...@@ -1460,29 +1462,36 @@ static int client_s_fmt(struct soc_camera_device *icd, ...@@ -1460,29 +1462,36 @@ static int client_s_fmt(struct soc_camera_device *icd,
update_cache: update_cache:
/* Update cache */ /* Update cache */
ret = client_g_rect(sd, &cam->rect); ret = soc_camera_client_g_rect(sd, rect);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (ceu_1to1) if (ceu_1to1)
cam->subrect = cam->rect; *subrect = *rect;
else else
update_subrect(cam); update_subrect(rect, subrect);
return 0; return 0;
} }
/** /**
* @width - on output: user width, mapped back to input * @icd - soc-camera device
* @height - on output: user height, mapped back to input * @rect - camera cropping window
* @subrect - part of rect, sent to the user
* @mf - in- / output camera output window * @mf - in- / output camera output window
* @width - on input: max host input width
* on output: user width, mapped back to input
* @height - on input: max host input height
* on output: user height, mapped back to input
* @host_can_scale - host can scale this pixel format
* @shift - shift, used for scaling
*/ */
static int client_scale(struct soc_camera_device *icd, static int soc_camera_client_scale(struct soc_camera_device *icd,
struct v4l2_rect *rect, struct v4l2_rect *subrect,
struct v4l2_mbus_framefmt *mf, struct v4l2_mbus_framefmt *mf,
unsigned int *width, unsigned int *height, unsigned int *width, unsigned int *height,
bool ceu_can_scale) bool host_can_scale, unsigned int shift)
{ {
struct sh_mobile_ceu_cam *cam = icd->host_priv;
struct device *dev = icd->parent; struct device *dev = icd->parent;
struct v4l2_mbus_framefmt mf_tmp = *mf; struct v4l2_mbus_framefmt mf_tmp = *mf;
unsigned int scale_h, scale_v; unsigned int scale_h, scale_v;
...@@ -1492,7 +1501,8 @@ static int client_scale(struct soc_camera_device *icd, ...@@ -1492,7 +1501,8 @@ static int client_scale(struct soc_camera_device *icd,
* 5. Apply iterative camera S_FMT for camera user window (also updates * 5. Apply iterative camera S_FMT for camera user window (also updates
* client crop cache and the imaginary sub-rectangle). * client crop cache and the imaginary sub-rectangle).
*/ */
ret = client_s_fmt(icd, &mf_tmp, ceu_can_scale); ret = client_s_fmt(icd, rect, subrect, *width, *height,
&mf_tmp, host_can_scale);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -1504,8 +1514,8 @@ static int client_scale(struct soc_camera_device *icd, ...@@ -1504,8 +1514,8 @@ static int client_scale(struct soc_camera_device *icd,
/* unneeded - it is already in "mf_tmp" */ /* unneeded - it is already in "mf_tmp" */
/* 7. Calculate new client scales. */ /* 7. Calculate new client scales. */
scale_h = calc_generic_scale(cam->rect.width, mf_tmp.width); scale_h = soc_camera_calc_scale(rect->width, shift, mf_tmp.width);
scale_v = calc_generic_scale(cam->rect.height, mf_tmp.height); scale_v = soc_camera_calc_scale(rect->height, shift, mf_tmp.height);
mf->width = mf_tmp.width; mf->width = mf_tmp.width;
mf->height = mf_tmp.height; mf->height = mf_tmp.height;
...@@ -1515,8 +1525,8 @@ static int client_scale(struct soc_camera_device *icd, ...@@ -1515,8 +1525,8 @@ static int client_scale(struct soc_camera_device *icd,
* 8. Calculate new CEU crop - apply camera scales to previously * 8. Calculate new CEU crop - apply camera scales to previously
* updated "effective" crop. * updated "effective" crop.
*/ */
*width = scale_down(cam->subrect.width, scale_h); *width = soc_camera_shift_scale(subrect->width, shift, scale_h);
*height = scale_down(cam->subrect.height, scale_v); *height = soc_camera_shift_scale(subrect->height, shift, scale_v);
dev_geo(dev, "8: new client sub-window %ux%u\n", *width, *height); dev_geo(dev, "8: new client sub-window %ux%u\n", *width, *height);
...@@ -1559,7 +1569,8 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, ...@@ -1559,7 +1569,8 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
* 1. - 2. Apply iterative camera S_CROP for new input window, read back * 1. - 2. Apply iterative camera S_CROP for new input window, read back
* actual camera rectangle. * actual camera rectangle.
*/ */
ret = client_s_crop(icd, &a_writable, &cam_crop); ret = soc_camera_client_s_crop(sd, &a_writable, &cam_crop,
&cam->rect, &cam->subrect);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -1683,16 +1694,16 @@ static int sh_mobile_ceu_get_crop(struct soc_camera_device *icd, ...@@ -1683,16 +1694,16 @@ static int sh_mobile_ceu_get_crop(struct soc_camera_device *icd,
* client crop. New scales are calculated from the requested output format and * client crop. New scales are calculated from the requested output format and
* 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 soc_camera_calc_client_output(struct soc_camera_device *icd,
const struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mf) struct v4l2_rect *rect, struct v4l2_rect *subrect,
const struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mf,
unsigned int shift)
{ {
struct sh_mobile_ceu_cam *cam = icd->host_priv;
struct device *dev = icd->parent; struct device *dev = icd->parent;
struct v4l2_rect *cam_subrect = &cam->subrect;
unsigned int scale_v, scale_h; unsigned int scale_v, scale_h;
if (cam_subrect->width == cam->rect.width && if (subrect->width == rect->width &&
cam_subrect->height == cam->rect.height) { subrect->height == rect->height) {
/* No sub-cropping */ /* No sub-cropping */
mf->width = pix->width; mf->width = pix->width;
mf->height = pix->height; mf->height = pix->height;
...@@ -1702,8 +1713,8 @@ static void calculate_client_output(struct soc_camera_device *icd, ...@@ -1702,8 +1713,8 @@ static void calculate_client_output(struct soc_camera_device *icd,
/* 1.-2. Current camera scales and subwin - cached. */ /* 1.-2. Current camera scales and subwin - cached. */
dev_geo(dev, "2: subwin %ux%u@%u:%u\n", dev_geo(dev, "2: subwin %ux%u@%u:%u\n",
cam_subrect->width, cam_subrect->height, subrect->width, subrect->height,
cam_subrect->left, cam_subrect->top); subrect->left, subrect->top);
/* /*
* 3. Calculate new combined scales from input sub-window to requested * 3. Calculate new combined scales from input sub-window to requested
...@@ -1714,8 +1725,8 @@ static void calculate_client_output(struct soc_camera_device *icd, ...@@ -1714,8 +1725,8 @@ static void calculate_client_output(struct soc_camera_device *icd,
* TODO: CEU cannot scale images larger than VGA to smaller than SubQCIF * TODO: CEU cannot scale images larger than VGA to smaller than SubQCIF
* (128x96) or larger than VGA * (128x96) or larger than VGA
*/ */
scale_h = calc_generic_scale(cam_subrect->width, pix->width); scale_h = soc_camera_calc_scale(subrect->width, shift, pix->width);
scale_v = calc_generic_scale(cam_subrect->height, pix->height); scale_v = soc_camera_calc_scale(subrect->height, shift, pix->height);
dev_geo(dev, "3: scales %u:%u\n", scale_h, scale_v); dev_geo(dev, "3: scales %u:%u\n", scale_h, scale_v);
...@@ -1723,8 +1734,8 @@ static void calculate_client_output(struct soc_camera_device *icd, ...@@ -1723,8 +1734,8 @@ static void calculate_client_output(struct soc_camera_device *icd,
* 4. Calculate desired client output window by applying combined scales * 4. Calculate desired client output window by applying combined scales
* to client (real) input window. * to client (real) input window.
*/ */
mf->width = scale_down(cam->rect.width, scale_h); mf->width = soc_camera_shift_scale(rect->width, shift, scale_h);
mf->height = scale_down(cam->rect.height, scale_v); mf->height = soc_camera_shift_scale(rect->height, shift, scale_v);
} }
/* Similar to set_crop multistage iterative algorithm */ /* Similar to set_crop multistage iterative algorithm */
...@@ -1739,8 +1750,8 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, ...@@ -1739,8 +1750,8 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
struct v4l2_mbus_framefmt mf; struct v4l2_mbus_framefmt mf;
__u32 pixfmt = pix->pixelformat; __u32 pixfmt = pix->pixelformat;
const struct soc_camera_format_xlate *xlate; const struct soc_camera_format_xlate *xlate;
/* Keep Compiler Happy */ unsigned int ceu_sub_width = pcdev->max_width,
unsigned int ceu_sub_width = 0, ceu_sub_height = 0; ceu_sub_height = pcdev->max_height;
u16 scale_v, scale_h; u16 scale_v, scale_h;
int ret; int ret;
bool image_mode; bool image_mode;
...@@ -1767,7 +1778,7 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, ...@@ -1767,7 +1778,7 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
} }
/* 1.-4. Calculate desired client output geometry */ /* 1.-4. Calculate desired client output geometry */
calculate_client_output(icd, pix, &mf); soc_camera_calc_client_output(icd, &cam->rect, &cam->subrect, pix, &mf, 12);
mf.field = pix->field; mf.field = pix->field;
mf.colorspace = pix->colorspace; mf.colorspace = pix->colorspace;
mf.code = xlate->code; mf.code = xlate->code;
...@@ -1789,8 +1800,9 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, ...@@ -1789,8 +1800,9 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
dev_geo(dev, "4: request camera output %ux%u\n", mf.width, mf.height); dev_geo(dev, "4: request camera output %ux%u\n", mf.width, mf.height);
/* 5. - 9. */ /* 5. - 9. */
ret = client_scale(icd, &mf, &ceu_sub_width, &ceu_sub_height, ret = soc_camera_client_scale(icd, &cam->rect, &cam->subrect,
image_mode && V4L2_FIELD_NONE == field); &mf, &ceu_sub_width, &ceu_sub_height,
image_mode && V4L2_FIELD_NONE == field, 12);
dev_geo(dev, "5-9: client scale return %d\n", ret); dev_geo(dev, "5-9: client scale return %d\n", ret);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册