diff options
Diffstat (limited to 'drivers/media/video/omap3isp/isppreview.c')
| -rw-r--r-- | drivers/media/video/omap3isp/isppreview.c | 419 |
1 files changed, 269 insertions, 150 deletions
diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c index aba537af87e4..ccb876fe023f 100644 --- a/drivers/media/video/omap3isp/isppreview.c +++ b/drivers/media/video/omap3isp/isppreview.c | |||
| @@ -76,9 +76,51 @@ static struct omap3isp_prev_csc flr_prev_csc = { | |||
| 76 | 76 | ||
| 77 | #define DEF_DETECT_CORRECT_VAL 0xe | 77 | #define DEF_DETECT_CORRECT_VAL 0xe |
| 78 | 78 | ||
| 79 | #define PREV_MIN_WIDTH 64 | 79 | /* |
| 80 | #define PREV_MIN_HEIGHT 8 | 80 | * Margins and image size limits. |
| 81 | #define PREV_MAX_HEIGHT 16384 | 81 | * |
| 82 | * The preview engine crops several rows and columns internally depending on | ||
| 83 | * which filters are enabled. To avoid format changes when the filters are | ||
| 84 | * enabled or disabled (which would prevent them from being turned on or off | ||
| 85 | * during streaming), the driver assumes all the filters are enabled when | ||
| 86 | * computing sink crop and source format limits. | ||
| 87 | * | ||
| 88 | * If a filter is disabled, additional cropping is automatically added at the | ||
| 89 | * preview engine input by the driver to avoid overflow at line and frame end. | ||
| 90 | * This is completely transparent for applications. | ||
| 91 | * | ||
| 92 | * Median filter 4 pixels | ||
| 93 | * Noise filter, | ||
| 94 | * Faulty pixels correction 4 pixels, 4 lines | ||
| 95 | * CFA filter 4 pixels, 4 lines in Bayer mode | ||
| 96 | * 2 lines in other modes | ||
| 97 | * Color suppression 2 pixels | ||
| 98 | * or luma enhancement | ||
| 99 | * ------------------------------------------------------------- | ||
| 100 | * Maximum total 14 pixels, 8 lines | ||
| 101 | * | ||
| 102 | * The color suppression and luma enhancement filters are applied after bayer to | ||
| 103 | * YUV conversion. They thus can crop one pixel on the left and one pixel on the | ||
| 104 | * right side of the image without changing the color pattern. When both those | ||
| 105 | * filters are disabled, the driver must crop the two pixels on the same side of | ||
| 106 | * the image to avoid changing the bayer pattern. The left margin is thus set to | ||
| 107 | * 8 pixels and the right margin to 6 pixels. | ||
| 108 | */ | ||
| 109 | |||
| 110 | #define PREV_MARGIN_LEFT 8 | ||
| 111 | #define PREV_MARGIN_RIGHT 6 | ||
| 112 | #define PREV_MARGIN_TOP 4 | ||
| 113 | #define PREV_MARGIN_BOTTOM 4 | ||
| 114 | |||
| 115 | #define PREV_MIN_IN_WIDTH 64 | ||
| 116 | #define PREV_MIN_IN_HEIGHT 8 | ||
| 117 | #define PREV_MAX_IN_HEIGHT 16384 | ||
| 118 | |||
| 119 | #define PREV_MIN_OUT_WIDTH 0 | ||
| 120 | #define PREV_MIN_OUT_HEIGHT 0 | ||
| 121 | #define PREV_MAX_OUT_WIDTH 1280 | ||
| 122 | #define PREV_MAX_OUT_WIDTH_ES2 3300 | ||
| 123 | #define PREV_MAX_OUT_WIDTH_3630 4096 | ||
| 82 | 124 | ||
| 83 | /* | 125 | /* |
| 84 | * Coeficient Tables for the submodules in Preview. | 126 | * Coeficient Tables for the submodules in Preview. |
| @@ -979,52 +1021,36 @@ static void preview_config_averager(struct isp_prev_device *prev, u8 average) | |||
| 979 | * enabled when reporting source pad formats to userspace. If this assumption is | 1021 | * enabled when reporting source pad formats to userspace. If this assumption is |
| 980 | * not true, rows and columns must be manually cropped at the preview engine | 1022 | * not true, rows and columns must be manually cropped at the preview engine |
| 981 | * input to avoid overflows at the end of lines and frames. | 1023 | * input to avoid overflows at the end of lines and frames. |
| 1024 | * | ||
| 1025 | * See the explanation at the PREV_MARGIN_* definitions for more details. | ||
| 982 | */ | 1026 | */ |
| 983 | static void preview_config_input_size(struct isp_prev_device *prev) | 1027 | static void preview_config_input_size(struct isp_prev_device *prev) |
| 984 | { | 1028 | { |
| 985 | struct isp_device *isp = to_isp_device(prev); | 1029 | struct isp_device *isp = to_isp_device(prev); |
| 986 | struct prev_params *params = &prev->params; | 1030 | struct prev_params *params = &prev->params; |
| 987 | struct v4l2_mbus_framefmt *format = &prev->formats[PREV_PAD_SINK]; | 1031 | unsigned int sph = prev->crop.left; |
| 988 | unsigned int sph = 0; | 1032 | unsigned int eph = prev->crop.left + prev->crop.width - 1; |
| 989 | unsigned int eph = format->width - 1; | 1033 | unsigned int slv = prev->crop.top; |
| 990 | unsigned int slv = 0; | 1034 | unsigned int elv = prev->crop.top + prev->crop.height - 1; |
| 991 | unsigned int elv = format->height - 1; | 1035 | |
| 992 | 1036 | if (params->features & PREV_CFA) { | |
| 993 | if (prev->input == PREVIEW_INPUT_CCDC) { | 1037 | sph -= 2; |
| 994 | sph += 2; | 1038 | eph += 2; |
| 995 | eph -= 2; | 1039 | slv -= 2; |
| 1040 | elv += 2; | ||
| 996 | } | 1041 | } |
| 997 | 1042 | if (params->features & (PREV_DEFECT_COR | PREV_NOISE_FILTER)) { | |
| 998 | /* | 1043 | sph -= 2; |
| 999 | * Median filter 4 pixels | 1044 | eph += 2; |
| 1000 | * Noise filter 4 pixels, 4 lines | 1045 | slv -= 2; |
| 1001 | * or faulty pixels correction | 1046 | elv += 2; |
| 1002 | * CFA filter 4 pixels, 4 lines in Bayer mode | ||
| 1003 | * 2 lines in other modes | ||
| 1004 | * Color suppression 2 pixels | ||
| 1005 | * or luma enhancement | ||
| 1006 | * ------------------------------------------------------------- | ||
| 1007 | * Maximum total 14 pixels, 8 lines | ||
| 1008 | */ | ||
| 1009 | |||
| 1010 | if (!(params->features & PREV_CFA)) { | ||
| 1011 | sph += 2; | ||
| 1012 | eph -= 2; | ||
| 1013 | slv += 2; | ||
| 1014 | elv -= 2; | ||
| 1015 | } | 1047 | } |
| 1016 | if (!(params->features & (PREV_DEFECT_COR | PREV_NOISE_FILTER))) { | 1048 | if (params->features & PREV_HORZ_MEDIAN_FILTER) { |
| 1017 | sph += 2; | 1049 | sph -= 2; |
| 1018 | eph -= 2; | 1050 | eph += 2; |
| 1019 | slv += 2; | ||
| 1020 | elv -= 2; | ||
| 1021 | } | 1051 | } |
| 1022 | if (!(params->features & PREV_HORZ_MEDIAN_FILTER)) { | 1052 | if (params->features & (PREV_CHROMA_SUPPRESS | PREV_LUMA_ENHANCE)) |
| 1023 | sph += 2; | 1053 | sph -= 2; |
| 1024 | eph -= 2; | ||
| 1025 | } | ||
| 1026 | if (!(params->features & (PREV_CHROMA_SUPPRESS | PREV_LUMA_ENHANCE))) | ||
| 1027 | sph += 2; | ||
| 1028 | 1054 | ||
| 1029 | isp_reg_writel(isp, (sph << ISPPRV_HORZ_INFO_SPH_SHIFT) | eph, | 1055 | isp_reg_writel(isp, (sph << ISPPRV_HORZ_INFO_SPH_SHIFT) | eph, |
| 1030 | OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO); | 1056 | OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO); |
| @@ -1228,7 +1254,6 @@ static void preview_init_params(struct isp_prev_device *prev) | |||
| 1228 | /* Init values */ | 1254 | /* Init values */ |
| 1229 | params->contrast = ISPPRV_CONTRAST_DEF * ISPPRV_CONTRAST_UNITS; | 1255 | params->contrast = ISPPRV_CONTRAST_DEF * ISPPRV_CONTRAST_UNITS; |
| 1230 | params->brightness = ISPPRV_BRIGHT_DEF * ISPPRV_BRIGHT_UNITS; | 1256 | params->brightness = ISPPRV_BRIGHT_DEF * ISPPRV_BRIGHT_UNITS; |
| 1231 | params->average = NO_AVE; | ||
| 1232 | params->cfa.format = OMAP3ISP_CFAFMT_BAYER; | 1257 | params->cfa.format = OMAP3ISP_CFAFMT_BAYER; |
| 1233 | memcpy(params->cfa.table, cfa_coef_table, | 1258 | memcpy(params->cfa.table, cfa_coef_table, |
| 1234 | sizeof(params->cfa.table)); | 1259 | sizeof(params->cfa.table)); |
| @@ -1281,14 +1306,14 @@ static unsigned int preview_max_out_width(struct isp_prev_device *prev) | |||
| 1281 | 1306 | ||
| 1282 | switch (isp->revision) { | 1307 | switch (isp->revision) { |
| 1283 | case ISP_REVISION_1_0: | 1308 | case ISP_REVISION_1_0: |
| 1284 | return ISPPRV_MAXOUTPUT_WIDTH; | 1309 | return PREV_MAX_OUT_WIDTH; |
| 1285 | 1310 | ||
| 1286 | case ISP_REVISION_2_0: | 1311 | case ISP_REVISION_2_0: |
| 1287 | default: | 1312 | default: |
| 1288 | return ISPPRV_MAXOUTPUT_WIDTH_ES2; | 1313 | return PREV_MAX_OUT_WIDTH_ES2; |
| 1289 | 1314 | ||
| 1290 | case ISP_REVISION_15_0: | 1315 | case ISP_REVISION_15_0: |
| 1291 | return ISPPRV_MAXOUTPUT_WIDTH_3630; | 1316 | return PREV_MAX_OUT_WIDTH_3630; |
| 1292 | } | 1317 | } |
| 1293 | } | 1318 | } |
| 1294 | 1319 | ||
| @@ -1296,8 +1321,6 @@ static void preview_configure(struct isp_prev_device *prev) | |||
| 1296 | { | 1321 | { |
| 1297 | struct isp_device *isp = to_isp_device(prev); | 1322 | struct isp_device *isp = to_isp_device(prev); |
| 1298 | struct v4l2_mbus_framefmt *format; | 1323 | struct v4l2_mbus_framefmt *format; |
| 1299 | unsigned int max_out_width; | ||
| 1300 | unsigned int format_avg; | ||
| 1301 | 1324 | ||
| 1302 | preview_setup_hw(prev); | 1325 | preview_setup_hw(prev); |
| 1303 | 1326 | ||
| @@ -1335,10 +1358,7 @@ static void preview_configure(struct isp_prev_device *prev) | |||
| 1335 | preview_config_outlineoffset(prev, | 1358 | preview_config_outlineoffset(prev, |
| 1336 | ALIGN(format->width, 0x10) * 2); | 1359 | ALIGN(format->width, 0x10) * 2); |
| 1337 | 1360 | ||
| 1338 | max_out_width = preview_max_out_width(prev); | 1361 | preview_config_averager(prev, 0); |
| 1339 | |||
| 1340 | format_avg = fls(DIV_ROUND_UP(format->width, max_out_width) - 1); | ||
| 1341 | preview_config_averager(prev, format_avg); | ||
| 1342 | preview_config_ycpos(prev, format->code); | 1362 | preview_config_ycpos(prev, format->code); |
| 1343 | } | 1363 | } |
| 1344 | 1364 | ||
| @@ -1597,6 +1617,16 @@ __preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh, | |||
| 1597 | return &prev->formats[pad]; | 1617 | return &prev->formats[pad]; |
| 1598 | } | 1618 | } |
| 1599 | 1619 | ||
| 1620 | static struct v4l2_rect * | ||
| 1621 | __preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh, | ||
| 1622 | enum v4l2_subdev_format_whence which) | ||
| 1623 | { | ||
| 1624 | if (which == V4L2_SUBDEV_FORMAT_TRY) | ||
| 1625 | return v4l2_subdev_get_try_crop(fh, PREV_PAD_SINK); | ||
| 1626 | else | ||
| 1627 | return &prev->crop; | ||
| 1628 | } | ||
| 1629 | |||
| 1600 | /* previewer format descriptions */ | 1630 | /* previewer format descriptions */ |
| 1601 | static const unsigned int preview_input_fmts[] = { | 1631 | static const unsigned int preview_input_fmts[] = { |
| 1602 | V4L2_MBUS_FMT_SGRBG10_1X10, | 1632 | V4L2_MBUS_FMT_SGRBG10_1X10, |
| @@ -1611,24 +1641,25 @@ static const unsigned int preview_output_fmts[] = { | |||
| 1611 | }; | 1641 | }; |
| 1612 | 1642 | ||
| 1613 | /* | 1643 | /* |
| 1614 | * preview_try_format - Handle try format by pad subdev method | 1644 | * preview_try_format - Validate a format |
| 1615 | * @prev: ISP preview device | 1645 | * @prev: ISP preview engine |
| 1616 | * @fh : V4L2 subdev file handle | 1646 | * @fh: V4L2 subdev file handle |
| 1617 | * @pad: pad num | 1647 | * @pad: pad number |
| 1618 | * @fmt: pointer to v4l2 format structure | 1648 | * @fmt: format to be validated |
| 1649 | * @which: try/active format selector | ||
| 1650 | * | ||
| 1651 | * Validate and adjust the given format for the given pad based on the preview | ||
| 1652 | * engine limits and the format and crop rectangles on other pads. | ||
| 1619 | */ | 1653 | */ |
| 1620 | static void preview_try_format(struct isp_prev_device *prev, | 1654 | static void preview_try_format(struct isp_prev_device *prev, |
| 1621 | struct v4l2_subdev_fh *fh, unsigned int pad, | 1655 | struct v4l2_subdev_fh *fh, unsigned int pad, |
| 1622 | struct v4l2_mbus_framefmt *fmt, | 1656 | struct v4l2_mbus_framefmt *fmt, |
| 1623 | enum v4l2_subdev_format_whence which) | 1657 | enum v4l2_subdev_format_whence which) |
| 1624 | { | 1658 | { |
| 1625 | struct v4l2_mbus_framefmt *format; | ||
| 1626 | unsigned int max_out_width; | ||
| 1627 | enum v4l2_mbus_pixelcode pixelcode; | 1659 | enum v4l2_mbus_pixelcode pixelcode; |
| 1660 | struct v4l2_rect *crop; | ||
| 1628 | unsigned int i; | 1661 | unsigned int i; |
| 1629 | 1662 | ||
| 1630 | max_out_width = preview_max_out_width(prev); | ||
| 1631 | |||
| 1632 | switch (pad) { | 1663 | switch (pad) { |
| 1633 | case PREV_PAD_SINK: | 1664 | case PREV_PAD_SINK: |
| 1634 | /* When reading data from the CCDC, the input size has already | 1665 | /* When reading data from the CCDC, the input size has already |
| @@ -1641,10 +1672,11 @@ static void preview_try_format(struct isp_prev_device *prev, | |||
| 1641 | * filter array interpolation. | 1672 | * filter array interpolation. |
| 1642 | */ | 1673 | */ |
| 1643 | if (prev->input == PREVIEW_INPUT_MEMORY) { | 1674 | if (prev->input == PREVIEW_INPUT_MEMORY) { |
| 1644 | fmt->width = clamp_t(u32, fmt->width, PREV_MIN_WIDTH, | 1675 | fmt->width = clamp_t(u32, fmt->width, PREV_MIN_IN_WIDTH, |
| 1645 | max_out_width * 8); | 1676 | preview_max_out_width(prev)); |
| 1646 | fmt->height = clamp_t(u32, fmt->height, PREV_MIN_HEIGHT, | 1677 | fmt->height = clamp_t(u32, fmt->height, |
| 1647 | PREV_MAX_HEIGHT); | 1678 | PREV_MIN_IN_HEIGHT, |
| 1679 | PREV_MAX_IN_HEIGHT); | ||
| 1648 | } | 1680 | } |
| 1649 | 1681 | ||
| 1650 | fmt->colorspace = V4L2_COLORSPACE_SRGB; | 1682 | fmt->colorspace = V4L2_COLORSPACE_SRGB; |
| @@ -1661,15 +1693,8 @@ static void preview_try_format(struct isp_prev_device *prev, | |||
| 1661 | 1693 | ||
| 1662 | case PREV_PAD_SOURCE: | 1694 | case PREV_PAD_SOURCE: |
| 1663 | pixelcode = fmt->code; | 1695 | pixelcode = fmt->code; |
| 1664 | format = __preview_get_format(prev, fh, PREV_PAD_SINK, which); | 1696 | *fmt = *__preview_get_format(prev, fh, PREV_PAD_SINK, which); |
| 1665 | memcpy(fmt, format, sizeof(*fmt)); | ||
| 1666 | 1697 | ||
| 1667 | /* The preview module output size is configurable through the | ||
| 1668 | * input interface (horizontal and vertical cropping) and the | ||
| 1669 | * averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). In | ||
| 1670 | * spite of this, hardcode the output size to the biggest | ||
| 1671 | * possible value for simplicity reasons. | ||
| 1672 | */ | ||
| 1673 | switch (pixelcode) { | 1698 | switch (pixelcode) { |
| 1674 | case V4L2_MBUS_FMT_YUYV8_1X16: | 1699 | case V4L2_MBUS_FMT_YUYV8_1X16: |
| 1675 | case V4L2_MBUS_FMT_UYVY8_1X16: | 1700 | case V4L2_MBUS_FMT_UYVY8_1X16: |
| @@ -1681,31 +1706,14 @@ static void preview_try_format(struct isp_prev_device *prev, | |||
| 1681 | break; | 1706 | break; |
| 1682 | } | 1707 | } |
| 1683 | 1708 | ||
| 1684 | /* The TRM states (12.1.4.7.1.2) that 2 pixels must be cropped | 1709 | /* The preview module output size is configurable through the |
| 1685 | * from the left and right sides when the input source is the | 1710 | * averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). This |
| 1686 | * CCDC. This seems not to be needed in practice, investigation | 1711 | * is not supported yet, hardcode the output size to the crop |
| 1687 | * is required. | 1712 | * rectangle size. |
| 1688 | */ | ||
| 1689 | if (prev->input == PREVIEW_INPUT_CCDC) | ||
| 1690 | fmt->width -= 4; | ||
| 1691 | |||
| 1692 | /* The preview module can output a maximum of 3312 pixels | ||
| 1693 | * horizontally due to fixed memory-line sizes. Compute the | ||
| 1694 | * horizontal averaging factor accordingly. Note that the limit | ||
| 1695 | * applies to the noise filter and CFA interpolation blocks, so | ||
| 1696 | * it doesn't take cropping by further blocks into account. | ||
| 1697 | * | ||
| 1698 | * ES 1.0 hardware revision is limited to 1280 pixels | ||
| 1699 | * horizontally. | ||
| 1700 | */ | ||
| 1701 | fmt->width >>= fls(DIV_ROUND_UP(fmt->width, max_out_width) - 1); | ||
| 1702 | |||
| 1703 | /* Assume that all blocks are enabled and crop pixels and lines | ||
| 1704 | * accordingly. See preview_config_input_size() for more | ||
| 1705 | * information. | ||
| 1706 | */ | 1713 | */ |
| 1707 | fmt->width -= 14; | 1714 | crop = __preview_get_crop(prev, fh, which); |
| 1708 | fmt->height -= 8; | 1715 | fmt->width = crop->width; |
| 1716 | fmt->height = crop->height; | ||
| 1709 | 1717 | ||
| 1710 | fmt->colorspace = V4L2_COLORSPACE_JPEG; | 1718 | fmt->colorspace = V4L2_COLORSPACE_JPEG; |
| 1711 | break; | 1719 | break; |
| @@ -1715,6 +1723,49 @@ static void preview_try_format(struct isp_prev_device *prev, | |||
| 1715 | } | 1723 | } |
| 1716 | 1724 | ||
| 1717 | /* | 1725 | /* |
| 1726 | * preview_try_crop - Validate a crop rectangle | ||
| 1727 | * @prev: ISP preview engine | ||
| 1728 | * @sink: format on the sink pad | ||
| 1729 | * @crop: crop rectangle to be validated | ||
| 1730 | * | ||
| 1731 | * The preview engine crops lines and columns for its internal operation, | ||
| 1732 | * depending on which filters are enabled. Enforce minimum crop margins to | ||
| 1733 | * handle that transparently for userspace. | ||
| 1734 | * | ||
| 1735 | * See the explanation at the PREV_MARGIN_* definitions for more details. | ||
| 1736 | */ | ||
| 1737 | static void preview_try_crop(struct isp_prev_device *prev, | ||
| 1738 | const struct v4l2_mbus_framefmt *sink, | ||
| 1739 | struct v4l2_rect *crop) | ||
| 1740 | { | ||
| 1741 | unsigned int left = PREV_MARGIN_LEFT; | ||
| 1742 | unsigned int right = sink->width - PREV_MARGIN_RIGHT; | ||
| 1743 | unsigned int top = PREV_MARGIN_TOP; | ||
| 1744 | unsigned int bottom = sink->height - PREV_MARGIN_BOTTOM; | ||
| 1745 | |||
| 1746 | /* When processing data on-the-fly from the CCDC, at least 2 pixels must | ||
| 1747 | * be cropped from the left and right sides of the image. As we don't | ||
| 1748 | * know which filters will be enabled, increase the left and right | ||
| 1749 | * margins by two. | ||
| 1750 | */ | ||
| 1751 | if (prev->input == PREVIEW_INPUT_CCDC) { | ||
| 1752 | left += 2; | ||
| 1753 | right -= 2; | ||
| 1754 | } | ||
| 1755 | |||
| 1756 | /* Restrict left/top to even values to keep the Bayer pattern. */ | ||
| 1757 | crop->left &= ~1; | ||
| 1758 | crop->top &= ~1; | ||
| 1759 | |||
| 1760 | crop->left = clamp_t(u32, crop->left, left, right - PREV_MIN_OUT_WIDTH); | ||
| 1761 | crop->top = clamp_t(u32, crop->top, top, bottom - PREV_MIN_OUT_HEIGHT); | ||
| 1762 | crop->width = clamp_t(u32, crop->width, PREV_MIN_OUT_WIDTH, | ||
| 1763 | right - crop->left); | ||
| 1764 | crop->height = clamp_t(u32, crop->height, PREV_MIN_OUT_HEIGHT, | ||
| 1765 | bottom - crop->top); | ||
| 1766 | } | ||
| 1767 | |||
| 1768 | /* | ||
| 1718 | * preview_enum_mbus_code - Handle pixel format enumeration | 1769 | * preview_enum_mbus_code - Handle pixel format enumeration |
| 1719 | * @sd : pointer to v4l2 subdev structure | 1770 | * @sd : pointer to v4l2 subdev structure |
| 1720 | * @fh : V4L2 subdev file handle | 1771 | * @fh : V4L2 subdev file handle |
| @@ -1776,6 +1827,60 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd, | |||
| 1776 | } | 1827 | } |
| 1777 | 1828 | ||
| 1778 | /* | 1829 | /* |
| 1830 | * preview_get_crop - Retrieve the crop rectangle on a pad | ||
| 1831 | * @sd: ISP preview V4L2 subdevice | ||
| 1832 | * @fh: V4L2 subdev file handle | ||
| 1833 | * @crop: crop rectangle | ||
| 1834 | * | ||
| 1835 | * Return 0 on success or a negative error code otherwise. | ||
| 1836 | */ | ||
| 1837 | static int preview_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
| 1838 | struct v4l2_subdev_crop *crop) | ||
| 1839 | { | ||
| 1840 | struct isp_prev_device *prev = v4l2_get_subdevdata(sd); | ||
| 1841 | |||
| 1842 | /* Cropping is only supported on the sink pad. */ | ||
| 1843 | if (crop->pad != PREV_PAD_SINK) | ||
| 1844 | return -EINVAL; | ||
| 1845 | |||
| 1846 | crop->rect = *__preview_get_crop(prev, fh, crop->which); | ||
| 1847 | return 0; | ||
| 1848 | } | ||
| 1849 | |||
| 1850 | /* | ||
| 1851 | * preview_set_crop - Retrieve the crop rectangle on a pad | ||
| 1852 | * @sd: ISP preview V4L2 subdevice | ||
| 1853 | * @fh: V4L2 subdev file handle | ||
| 1854 | * @crop: crop rectangle | ||
| 1855 | * | ||
| 1856 | * Return 0 on success or a negative error code otherwise. | ||
| 1857 | */ | ||
| 1858 | static int preview_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
| 1859 | struct v4l2_subdev_crop *crop) | ||
| 1860 | { | ||
| 1861 | struct isp_prev_device *prev = v4l2_get_subdevdata(sd); | ||
| 1862 | struct v4l2_mbus_framefmt *format; | ||
| 1863 | |||
| 1864 | /* Cropping is only supported on the sink pad. */ | ||
| 1865 | if (crop->pad != PREV_PAD_SINK) | ||
| 1866 | return -EINVAL; | ||
| 1867 | |||
| 1868 | /* The crop rectangle can't be changed while streaming. */ | ||
| 1869 | if (prev->state != ISP_PIPELINE_STREAM_STOPPED) | ||
| 1870 | return -EBUSY; | ||
| 1871 | |||
| 1872 | format = __preview_get_format(prev, fh, PREV_PAD_SINK, crop->which); | ||
| 1873 | preview_try_crop(prev, format, &crop->rect); | ||
| 1874 | *__preview_get_crop(prev, fh, crop->which) = crop->rect; | ||
| 1875 | |||
| 1876 | /* Update the source format. */ | ||
| 1877 | format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, crop->which); | ||
| 1878 | preview_try_format(prev, fh, PREV_PAD_SOURCE, format, crop->which); | ||
| 1879 | |||
| 1880 | return 0; | ||
| 1881 | } | ||
| 1882 | |||
| 1883 | /* | ||
| 1779 | * preview_get_format - Handle get format by pads subdev method | 1884 | * preview_get_format - Handle get format by pads subdev method |
| 1780 | * @sd : pointer to v4l2 subdev structure | 1885 | * @sd : pointer to v4l2 subdev structure |
| 1781 | * @fh : V4L2 subdev file handle | 1886 | * @fh : V4L2 subdev file handle |
| @@ -1808,6 +1913,7 @@ static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | |||
| 1808 | { | 1913 | { |
| 1809 | struct isp_prev_device *prev = v4l2_get_subdevdata(sd); | 1914 | struct isp_prev_device *prev = v4l2_get_subdevdata(sd); |
| 1810 | struct v4l2_mbus_framefmt *format; | 1915 | struct v4l2_mbus_framefmt *format; |
| 1916 | struct v4l2_rect *crop; | ||
| 1811 | 1917 | ||
| 1812 | format = __preview_get_format(prev, fh, fmt->pad, fmt->which); | 1918 | format = __preview_get_format(prev, fh, fmt->pad, fmt->which); |
| 1813 | if (format == NULL) | 1919 | if (format == NULL) |
| @@ -1818,9 +1924,18 @@ static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | |||
| 1818 | 1924 | ||
| 1819 | /* Propagate the format from sink to source */ | 1925 | /* Propagate the format from sink to source */ |
| 1820 | if (fmt->pad == PREV_PAD_SINK) { | 1926 | if (fmt->pad == PREV_PAD_SINK) { |
| 1927 | /* Reset the crop rectangle. */ | ||
| 1928 | crop = __preview_get_crop(prev, fh, fmt->which); | ||
| 1929 | crop->left = 0; | ||
| 1930 | crop->top = 0; | ||
| 1931 | crop->width = fmt->format.width; | ||
| 1932 | crop->height = fmt->format.height; | ||
| 1933 | |||
| 1934 | preview_try_crop(prev, &fmt->format, crop); | ||
| 1935 | |||
| 1936 | /* Update the source format. */ | ||
| 1821 | format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, | 1937 | format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, |
| 1822 | fmt->which); | 1938 | fmt->which); |
| 1823 | *format = fmt->format; | ||
| 1824 | preview_try_format(prev, fh, PREV_PAD_SOURCE, format, | 1939 | preview_try_format(prev, fh, PREV_PAD_SOURCE, format, |
| 1825 | fmt->which); | 1940 | fmt->which); |
| 1826 | } | 1941 | } |
| @@ -1869,6 +1984,8 @@ static const struct v4l2_subdev_pad_ops preview_v4l2_pad_ops = { | |||
| 1869 | .enum_frame_size = preview_enum_frame_size, | 1984 | .enum_frame_size = preview_enum_frame_size, |
| 1870 | .get_fmt = preview_get_format, | 1985 | .get_fmt = preview_get_format, |
| 1871 | .set_fmt = preview_set_format, | 1986 | .set_fmt = preview_set_format, |
| 1987 | .get_crop = preview_get_crop, | ||
| 1988 | .set_crop = preview_set_crop, | ||
| 1872 | }; | 1989 | }; |
| 1873 | 1990 | ||
| 1874 | /* subdev operations */ | 1991 | /* subdev operations */ |
| @@ -1966,8 +2083,44 @@ static const struct media_entity_operations preview_media_ops = { | |||
| 1966 | .link_setup = preview_link_setup, | 2083 | .link_setup = preview_link_setup, |
| 1967 | }; | 2084 | }; |
| 1968 | 2085 | ||
| 2086 | void omap3isp_preview_unregister_entities(struct isp_prev_device *prev) | ||
| 2087 | { | ||
| 2088 | v4l2_device_unregister_subdev(&prev->subdev); | ||
| 2089 | omap3isp_video_unregister(&prev->video_in); | ||
| 2090 | omap3isp_video_unregister(&prev->video_out); | ||
| 2091 | } | ||
| 2092 | |||
| 2093 | int omap3isp_preview_register_entities(struct isp_prev_device *prev, | ||
| 2094 | struct v4l2_device *vdev) | ||
| 2095 | { | ||
| 2096 | int ret; | ||
| 2097 | |||
| 2098 | /* Register the subdev and video nodes. */ | ||
| 2099 | ret = v4l2_device_register_subdev(vdev, &prev->subdev); | ||
| 2100 | if (ret < 0) | ||
| 2101 | goto error; | ||
| 2102 | |||
| 2103 | ret = omap3isp_video_register(&prev->video_in, vdev); | ||
| 2104 | if (ret < 0) | ||
| 2105 | goto error; | ||
| 2106 | |||
| 2107 | ret = omap3isp_video_register(&prev->video_out, vdev); | ||
| 2108 | if (ret < 0) | ||
| 2109 | goto error; | ||
| 2110 | |||
| 2111 | return 0; | ||
| 2112 | |||
| 2113 | error: | ||
| 2114 | omap3isp_preview_unregister_entities(prev); | ||
| 2115 | return ret; | ||
| 2116 | } | ||
| 2117 | |||
| 2118 | /* ----------------------------------------------------------------------------- | ||
| 2119 | * ISP previewer initialisation and cleanup | ||
| 2120 | */ | ||
| 2121 | |||
| 1969 | /* | 2122 | /* |
| 1970 | * review_init_entities - Initialize subdev and media entity. | 2123 | * preview_init_entities - Initialize subdev and media entity. |
| 1971 | * @prev : Pointer to preview structure | 2124 | * @prev : Pointer to preview structure |
| 1972 | * return -ENOMEM or zero on success | 2125 | * return -ENOMEM or zero on success |
| 1973 | */ | 2126 | */ |
| @@ -2024,69 +2177,34 @@ static int preview_init_entities(struct isp_prev_device *prev) | |||
| 2024 | 2177 | ||
| 2025 | ret = omap3isp_video_init(&prev->video_in, "preview"); | 2178 | ret = omap3isp_video_init(&prev->video_in, "preview"); |
| 2026 | if (ret < 0) | 2179 | if (ret < 0) |
| 2027 | return ret; | 2180 | goto error_video_in; |
| 2028 | 2181 | ||
| 2029 | ret = omap3isp_video_init(&prev->video_out, "preview"); | 2182 | ret = omap3isp_video_init(&prev->video_out, "preview"); |
| 2030 | if (ret < 0) | 2183 | if (ret < 0) |
| 2031 | return ret; | 2184 | goto error_video_out; |
| 2032 | 2185 | ||
| 2033 | /* Connect the video nodes to the previewer subdev. */ | 2186 | /* Connect the video nodes to the previewer subdev. */ |
| 2034 | ret = media_entity_create_link(&prev->video_in.video.entity, 0, | 2187 | ret = media_entity_create_link(&prev->video_in.video.entity, 0, |
| 2035 | &prev->subdev.entity, PREV_PAD_SINK, 0); | 2188 | &prev->subdev.entity, PREV_PAD_SINK, 0); |
| 2036 | if (ret < 0) | 2189 | if (ret < 0) |
| 2037 | return ret; | 2190 | goto error_link; |
| 2038 | 2191 | ||
| 2039 | ret = media_entity_create_link(&prev->subdev.entity, PREV_PAD_SOURCE, | 2192 | ret = media_entity_create_link(&prev->subdev.entity, PREV_PAD_SOURCE, |
| 2040 | &prev->video_out.video.entity, 0, 0); | 2193 | &prev->video_out.video.entity, 0, 0); |
| 2041 | if (ret < 0) | 2194 | if (ret < 0) |
| 2042 | return ret; | 2195 | goto error_link; |
| 2043 | 2196 | ||
| 2044 | return 0; | 2197 | return 0; |
| 2045 | } | ||
| 2046 | 2198 | ||
| 2047 | void omap3isp_preview_unregister_entities(struct isp_prev_device *prev) | 2199 | error_link: |
| 2048 | { | 2200 | omap3isp_video_cleanup(&prev->video_out); |
| 2201 | error_video_out: | ||
| 2202 | omap3isp_video_cleanup(&prev->video_in); | ||
| 2203 | error_video_in: | ||
| 2049 | media_entity_cleanup(&prev->subdev.entity); | 2204 | media_entity_cleanup(&prev->subdev.entity); |
| 2050 | |||
| 2051 | v4l2_device_unregister_subdev(&prev->subdev); | ||
| 2052 | v4l2_ctrl_handler_free(&prev->ctrls); | ||
| 2053 | omap3isp_video_unregister(&prev->video_in); | ||
| 2054 | omap3isp_video_unregister(&prev->video_out); | ||
| 2055 | } | ||
| 2056 | |||
| 2057 | int omap3isp_preview_register_entities(struct isp_prev_device *prev, | ||
| 2058 | struct v4l2_device *vdev) | ||
| 2059 | { | ||
| 2060 | int ret; | ||
| 2061 | |||
| 2062 | /* Register the subdev and video nodes. */ | ||
| 2063 | ret = v4l2_device_register_subdev(vdev, &prev->subdev); | ||
| 2064 | if (ret < 0) | ||
| 2065 | goto error; | ||
| 2066 | |||
| 2067 | ret = omap3isp_video_register(&prev->video_in, vdev); | ||
| 2068 | if (ret < 0) | ||
| 2069 | goto error; | ||
| 2070 | |||
| 2071 | ret = omap3isp_video_register(&prev->video_out, vdev); | ||
| 2072 | if (ret < 0) | ||
| 2073 | goto error; | ||
| 2074 | |||
| 2075 | return 0; | ||
| 2076 | |||
| 2077 | error: | ||
| 2078 | omap3isp_preview_unregister_entities(prev); | ||
| 2079 | return ret; | 2205 | return ret; |
| 2080 | } | 2206 | } |
| 2081 | 2207 | ||
| 2082 | /* ----------------------------------------------------------------------------- | ||
| 2083 | * ISP previewer initialisation and cleanup | ||
| 2084 | */ | ||
| 2085 | |||
| 2086 | void omap3isp_preview_cleanup(struct isp_device *isp) | ||
| 2087 | { | ||
| 2088 | } | ||
| 2089 | |||
| 2090 | /* | 2208 | /* |
| 2091 | * isp_preview_init - Previewer initialization. | 2209 | * isp_preview_init - Previewer initialization. |
| 2092 | * @dev : Pointer to ISP device | 2210 | * @dev : Pointer to ISP device |
| @@ -2095,19 +2213,20 @@ void omap3isp_preview_cleanup(struct isp_device *isp) | |||
| 2095 | int omap3isp_preview_init(struct isp_device *isp) | 2213 | int omap3isp_preview_init(struct isp_device *isp) |
| 2096 | { | 2214 | { |
| 2097 | struct isp_prev_device *prev = &isp->isp_prev; | 2215 | struct isp_prev_device *prev = &isp->isp_prev; |
| 2098 | int ret; | ||
| 2099 | 2216 | ||
| 2100 | spin_lock_init(&prev->lock); | 2217 | spin_lock_init(&prev->lock); |
| 2101 | init_waitqueue_head(&prev->wait); | 2218 | init_waitqueue_head(&prev->wait); |
| 2102 | preview_init_params(prev); | 2219 | preview_init_params(prev); |
| 2103 | 2220 | ||
| 2104 | ret = preview_init_entities(prev); | 2221 | return preview_init_entities(prev); |
| 2105 | if (ret < 0) | 2222 | } |
| 2106 | goto out; | ||
| 2107 | 2223 | ||
| 2108 | out: | 2224 | void omap3isp_preview_cleanup(struct isp_device *isp) |
| 2109 | if (ret) | 2225 | { |
| 2110 | omap3isp_preview_cleanup(isp); | 2226 | struct isp_prev_device *prev = &isp->isp_prev; |
| 2111 | 2227 | ||
| 2112 | return ret; | 2228 | v4l2_ctrl_handler_free(&prev->ctrls); |
| 2229 | omap3isp_video_cleanup(&prev->video_in); | ||
| 2230 | omap3isp_video_cleanup(&prev->video_out); | ||
| 2231 | media_entity_cleanup(&prev->subdev.entity); | ||
| 2113 | } | 2232 | } |
