Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

authored by

Guennadi Liakhovetski and committed by
Mauro Carvalho Chehab
eca430c8 c67f1a30

+71 -59
+71 -59
drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
··· 1005 1005 fmt->packing == SOC_MBUS_PACKING_EXTEND16); 1006 1006 } 1007 1007 1008 - static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect); 1008 + static int soc_camera_client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect); 1009 1009 1010 1010 static struct soc_camera_device *ctrl_to_icd(struct v4l2_ctrl *ctrl) 1011 1011 { ··· 1084 1084 /* FIXME: subwindow is lost between close / open */ 1085 1085 1086 1086 /* Cache current client geometry */ 1087 - ret = client_g_rect(sd, &rect); 1087 + ret = soc_camera_client_g_rect(sd, &rect); 1088 1088 if (ret < 0) 1089 1089 return ret; 1090 1090 ··· 1208 1208 r1->top + r1->height < r2->top + r2->height; 1209 1209 } 1210 1210 1211 - static unsigned int scale_down(unsigned int size, unsigned int scale) 1211 + static unsigned int soc_camera_shift_scale(unsigned int size, unsigned int shift, 1212 + unsigned int scale) 1212 1213 { 1213 - return (size * 4096 + scale / 2) / scale; 1214 + return ((size << shift) + scale / 2) / scale; 1214 1215 } 1215 1216 1216 - static unsigned int calc_generic_scale(unsigned int input, unsigned int output) 1217 + static unsigned int soc_camera_calc_scale(unsigned int input, unsigned int shift, 1218 + unsigned int output) 1217 1219 { 1218 - return (input * 4096 + output / 2) / output; 1220 + return soc_camera_shift_scale(input, shift, output); 1219 1221 } 1222 + 1223 + #define scale_down(size, scale) soc_camera_shift_scale(size, 12, scale) 1224 + #define calc_generic_scale(in, out) soc_camera_shift_scale(in, 12, out) 1220 1225 1221 1226 /* Get and store current client crop */ 1222 - static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect) 1227 + static int soc_camera_client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect) 1223 1228 { 1224 1229 struct v4l2_crop crop; 1225 1230 struct v4l2_cropcap cap; ··· 1249 1244 } 1250 1245 1251 1246 /* Client crop has changed, update our sub-rectangle to remain within the area */ 1252 - static void update_subrect(struct sh_mobile_ceu_cam *cam) 1247 + static void update_subrect(struct v4l2_rect *rect, struct v4l2_rect *subrect) 1253 1248 { 1254 - struct v4l2_rect *rect = &cam->rect, *subrect = &cam->subrect; 1255 - 1256 1249 if (rect->width < subrect->width) 1257 1250 subrect->width = rect->width; 1258 1251 ··· 1278 1275 * 2. if (1) failed, try to double the client image until we get one big enough 1279 1276 * 3. if (2) failed, try to request the maximum image 1280 1277 */ 1281 - static int client_s_crop(struct soc_camera_device *icd, struct v4l2_crop *crop, 1282 - struct v4l2_crop *cam_crop) 1278 + static int soc_camera_client_s_crop(struct v4l2_subdev *sd, 1279 + struct v4l2_crop *crop, struct v4l2_crop *cam_crop, 1280 + struct v4l2_rect *target_rect, struct v4l2_rect *subrect) 1283 1281 { 1284 - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); 1285 1282 struct v4l2_rect *rect = &crop->c, *cam_rect = &cam_crop->c; 1286 1283 struct device *dev = sd->v4l2_dev->dev; 1287 - struct sh_mobile_ceu_cam *cam = icd->host_priv; 1288 1284 struct v4l2_cropcap cap; 1289 1285 int ret; 1290 1286 unsigned int width, height; 1291 1287 1292 1288 v4l2_subdev_call(sd, video, s_crop, crop); 1293 - ret = client_g_rect(sd, cam_rect); 1289 + ret = soc_camera_client_g_rect(sd, cam_rect); 1294 1290 if (ret < 0) 1295 1291 return ret; 1296 1292 ··· 1301 1299 /* Even if camera S_CROP failed, but camera rectangle matches */ 1302 1300 dev_dbg(dev, "Camera S_CROP successful for %dx%d@%d:%d\n", 1303 1301 rect->width, rect->height, rect->left, rect->top); 1304 - cam->rect = *cam_rect; 1302 + *target_rect = *cam_rect; 1305 1303 return 0; 1306 1304 } 1307 1305 ··· 1367 1365 cam_rect->top; 1368 1366 1369 1367 v4l2_subdev_call(sd, video, s_crop, cam_crop); 1370 - ret = client_g_rect(sd, cam_rect); 1368 + ret = soc_camera_client_g_rect(sd, cam_rect); 1371 1369 dev_geo(dev, "Camera S_CROP %d for %dx%d@%d:%d\n", ret, 1372 1370 cam_rect->width, cam_rect->height, 1373 1371 cam_rect->left, cam_rect->top); ··· 1381 1379 */ 1382 1380 *cam_rect = cap.bounds; 1383 1381 v4l2_subdev_call(sd, video, s_crop, cam_crop); 1384 - ret = client_g_rect(sd, cam_rect); 1382 + ret = soc_camera_client_g_rect(sd, cam_rect); 1385 1383 dev_geo(dev, "Camera S_CROP %d for max %dx%d@%d:%d\n", ret, 1386 1384 cam_rect->width, cam_rect->height, 1387 1385 cam_rect->left, cam_rect->top); 1388 1386 } 1389 1387 1390 1388 if (!ret) { 1391 - cam->rect = *cam_rect; 1392 - update_subrect(cam); 1389 + *target_rect = *cam_rect; 1390 + update_subrect(target_rect, subrect); 1393 1391 } 1394 1392 1395 1393 return ret; ··· 1397 1395 1398 1396 /* Iterative s_mbus_fmt, also updates cached client crop on success */ 1399 1397 static int client_s_fmt(struct soc_camera_device *icd, 1400 - struct v4l2_mbus_framefmt *mf, bool ceu_can_scale) 1398 + struct v4l2_rect *rect, struct v4l2_rect *subrect, 1399 + unsigned int max_width, unsigned int max_height, 1400 + struct v4l2_mbus_framefmt *mf, bool host_can_scale) 1401 1401 { 1402 - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); 1403 - struct sh_mobile_ceu_dev *pcdev = ici->priv; 1404 - struct sh_mobile_ceu_cam *cam = icd->host_priv; 1405 1402 struct v4l2_subdev *sd = soc_camera_to_subdev(icd); 1406 1403 struct device *dev = icd->parent; 1407 1404 unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h; 1408 - unsigned int max_width, max_height; 1409 1405 struct v4l2_cropcap cap; 1410 1406 bool ceu_1to1; 1411 1407 int ret; ··· 1423 1423 } 1424 1424 1425 1425 ceu_1to1 = false; 1426 - if (!ceu_can_scale) 1426 + if (!host_can_scale) 1427 1427 goto update_cache; 1428 1428 1429 1429 cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ··· 1432 1432 if (ret < 0) 1433 1433 return ret; 1434 1434 1435 - max_width = min(cap.bounds.width, pcdev->max_width); 1436 - max_height = min(cap.bounds.height, pcdev->max_height); 1435 + if (max_width > cap.bounds.width) 1436 + max_width = cap.bounds.width; 1437 + if (max_height > cap.bounds.height) 1438 + max_height = cap.bounds.height; 1437 1439 1438 1440 /* Camera set a format, but geometry is not precise, try to improve */ 1439 1441 tmp_w = mf->width; ··· 1462 1460 1463 1461 update_cache: 1464 1462 /* Update cache */ 1465 - ret = client_g_rect(sd, &cam->rect); 1463 + ret = soc_camera_client_g_rect(sd, rect); 1466 1464 if (ret < 0) 1467 1465 return ret; 1468 1466 1469 1467 if (ceu_1to1) 1470 - cam->subrect = cam->rect; 1468 + *subrect = *rect; 1471 1469 else 1472 - update_subrect(cam); 1470 + update_subrect(rect, subrect); 1473 1471 1474 1472 return 0; 1475 1473 } 1476 1474 1477 1475 /** 1478 - * @width - on output: user width, mapped back to input 1479 - * @height - on output: user height, mapped back to input 1476 + * @icd - soc-camera device 1477 + * @rect - camera cropping window 1478 + * @subrect - part of rect, sent to the user 1480 1479 * @mf - in- / output camera output window 1480 + * @width - on input: max host input width 1481 + * on output: user width, mapped back to input 1482 + * @height - on input: max host input height 1483 + * on output: user height, mapped back to input 1484 + * @host_can_scale - host can scale this pixel format 1485 + * @shift - shift, used for scaling 1481 1486 */ 1482 - static int client_scale(struct soc_camera_device *icd, 1487 + static int soc_camera_client_scale(struct soc_camera_device *icd, 1488 + struct v4l2_rect *rect, struct v4l2_rect *subrect, 1483 1489 struct v4l2_mbus_framefmt *mf, 1484 1490 unsigned int *width, unsigned int *height, 1485 - bool ceu_can_scale) 1491 + bool host_can_scale, unsigned int shift) 1486 1492 { 1487 - struct sh_mobile_ceu_cam *cam = icd->host_priv; 1488 1493 struct device *dev = icd->parent; 1489 1494 struct v4l2_mbus_framefmt mf_tmp = *mf; 1490 1495 unsigned int scale_h, scale_v; ··· 1501 1492 * 5. Apply iterative camera S_FMT for camera user window (also updates 1502 1493 * client crop cache and the imaginary sub-rectangle). 1503 1494 */ 1504 - ret = client_s_fmt(icd, &mf_tmp, ceu_can_scale); 1495 + ret = client_s_fmt(icd, rect, subrect, *width, *height, 1496 + &mf_tmp, host_can_scale); 1505 1497 if (ret < 0) 1506 1498 return ret; 1507 1499 ··· 1514 1504 /* unneeded - it is already in "mf_tmp" */ 1515 1505 1516 1506 /* 7. Calculate new client scales. */ 1517 - scale_h = calc_generic_scale(cam->rect.width, mf_tmp.width); 1518 - scale_v = calc_generic_scale(cam->rect.height, mf_tmp.height); 1507 + scale_h = soc_camera_calc_scale(rect->width, shift, mf_tmp.width); 1508 + scale_v = soc_camera_calc_scale(rect->height, shift, mf_tmp.height); 1519 1509 1520 1510 mf->width = mf_tmp.width; 1521 1511 mf->height = mf_tmp.height; ··· 1525 1515 * 8. Calculate new CEU crop - apply camera scales to previously 1526 1516 * updated "effective" crop. 1527 1517 */ 1528 - *width = scale_down(cam->subrect.width, scale_h); 1529 - *height = scale_down(cam->subrect.height, scale_v); 1518 + *width = soc_camera_shift_scale(subrect->width, shift, scale_h); 1519 + *height = soc_camera_shift_scale(subrect->height, shift, scale_v); 1530 1520 1531 1521 dev_geo(dev, "8: new client sub-window %ux%u\n", *width, *height); 1532 1522 ··· 1569 1559 * 1. - 2. Apply iterative camera S_CROP for new input window, read back 1570 1560 * actual camera rectangle. 1571 1561 */ 1572 - ret = client_s_crop(icd, &a_writable, &cam_crop); 1562 + ret = soc_camera_client_s_crop(sd, &a_writable, &cam_crop, 1563 + &cam->rect, &cam->subrect); 1573 1564 if (ret < 0) 1574 1565 return ret; 1575 1566 ··· 1694 1683 * client crop. New scales are calculated from the requested output format and 1695 1684 * CEU crop, mapped backed onto the client input (subrect). 1696 1685 */ 1697 - static void calculate_client_output(struct soc_camera_device *icd, 1698 - const struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mf) 1686 + static void soc_camera_calc_client_output(struct soc_camera_device *icd, 1687 + struct v4l2_rect *rect, struct v4l2_rect *subrect, 1688 + const struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mf, 1689 + unsigned int shift) 1699 1690 { 1700 - struct sh_mobile_ceu_cam *cam = icd->host_priv; 1701 1691 struct device *dev = icd->parent; 1702 - struct v4l2_rect *cam_subrect = &cam->subrect; 1703 1692 unsigned int scale_v, scale_h; 1704 1693 1705 - if (cam_subrect->width == cam->rect.width && 1706 - cam_subrect->height == cam->rect.height) { 1694 + if (subrect->width == rect->width && 1695 + subrect->height == rect->height) { 1707 1696 /* No sub-cropping */ 1708 1697 mf->width = pix->width; 1709 1698 mf->height = pix->height; ··· 1713 1702 /* 1.-2. Current camera scales and subwin - cached. */ 1714 1703 1715 1704 dev_geo(dev, "2: subwin %ux%u@%u:%u\n", 1716 - cam_subrect->width, cam_subrect->height, 1717 - cam_subrect->left, cam_subrect->top); 1705 + subrect->width, subrect->height, 1706 + subrect->left, subrect->top); 1718 1707 1719 1708 /* 1720 1709 * 3. Calculate new combined scales from input sub-window to requested ··· 1725 1714 * TODO: CEU cannot scale images larger than VGA to smaller than SubQCIF 1726 1715 * (128x96) or larger than VGA 1727 1716 */ 1728 - scale_h = calc_generic_scale(cam_subrect->width, pix->width); 1729 - scale_v = calc_generic_scale(cam_subrect->height, pix->height); 1717 + scale_h = soc_camera_calc_scale(subrect->width, shift, pix->width); 1718 + scale_v = soc_camera_calc_scale(subrect->height, shift, pix->height); 1730 1719 1731 1720 dev_geo(dev, "3: scales %u:%u\n", scale_h, scale_v); 1732 1721 ··· 1734 1723 * 4. Calculate desired client output window by applying combined scales 1735 1724 * to client (real) input window. 1736 1725 */ 1737 - mf->width = scale_down(cam->rect.width, scale_h); 1738 - mf->height = scale_down(cam->rect.height, scale_v); 1726 + mf->width = soc_camera_shift_scale(rect->width, shift, scale_h); 1727 + mf->height = soc_camera_shift_scale(rect->height, shift, scale_v); 1739 1728 } 1740 1729 1741 1730 /* Similar to set_crop multistage iterative algorithm */ ··· 1750 1739 struct v4l2_mbus_framefmt mf; 1751 1740 __u32 pixfmt = pix->pixelformat; 1752 1741 const struct soc_camera_format_xlate *xlate; 1753 - /* Keep Compiler Happy */ 1754 - unsigned int ceu_sub_width = 0, ceu_sub_height = 0; 1742 + unsigned int ceu_sub_width = pcdev->max_width, 1743 + ceu_sub_height = pcdev->max_height; 1755 1744 u16 scale_v, scale_h; 1756 1745 int ret; 1757 1746 bool image_mode; ··· 1778 1767 } 1779 1768 1780 1769 /* 1.-4. Calculate desired client output geometry */ 1781 - calculate_client_output(icd, pix, &mf); 1770 + soc_camera_calc_client_output(icd, &cam->rect, &cam->subrect, pix, &mf, 12); 1782 1771 mf.field = pix->field; 1783 1772 mf.colorspace = pix->colorspace; 1784 1773 mf.code = xlate->code; ··· 1800 1789 dev_geo(dev, "4: request camera output %ux%u\n", mf.width, mf.height); 1801 1790 1802 1791 /* 5. - 9. */ 1803 - ret = client_scale(icd, &mf, &ceu_sub_width, &ceu_sub_height, 1804 - image_mode && V4L2_FIELD_NONE == field); 1792 + ret = soc_camera_client_scale(icd, &cam->rect, &cam->subrect, 1793 + &mf, &ceu_sub_width, &ceu_sub_height, 1794 + image_mode && V4L2_FIELD_NONE == field, 12); 1805 1795 1806 1796 dev_geo(dev, "5-9: client scale return %d\n", ret); 1807 1797