aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/video/omap3isp/ispccdc.c180
-rw-r--r--drivers/media/video/omap3isp/ispccdc.h2
2 files changed, 169 insertions, 13 deletions
diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c
index 17207c7037f7..8c73197005c6 100644
--- a/drivers/media/video/omap3isp/ispccdc.c
+++ b/drivers/media/video/omap3isp/ispccdc.c
@@ -38,6 +38,9 @@
38#include "ispreg.h" 38#include "ispreg.h"
39#include "ispccdc.h" 39#include "ispccdc.h"
40 40
41#define CCDC_MIN_WIDTH 32
42#define CCDC_MIN_HEIGHT 32
43
41static struct v4l2_mbus_framefmt * 44static struct v4l2_mbus_framefmt *
42__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, 45__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
43 unsigned int pad, enum v4l2_subdev_format_whence which); 46 unsigned int pad, enum v4l2_subdev_format_whence which);
@@ -1118,6 +1121,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
1118 struct isp_parallel_platform_data *pdata = NULL; 1121 struct isp_parallel_platform_data *pdata = NULL;
1119 struct v4l2_subdev *sensor; 1122 struct v4l2_subdev *sensor;
1120 struct v4l2_mbus_framefmt *format; 1123 struct v4l2_mbus_framefmt *format;
1124 const struct v4l2_rect *crop;
1121 const struct isp_format_info *fmt_info; 1125 const struct isp_format_info *fmt_info;
1122 struct v4l2_subdev_format fmt_src; 1126 struct v4l2_subdev_format fmt_src;
1123 unsigned int depth_out; 1127 unsigned int depth_out;
@@ -1211,14 +1215,14 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
1211 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VDINT); 1215 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VDINT);
1212 1216
1213 /* CCDC_PAD_SOURCE_OF */ 1217 /* CCDC_PAD_SOURCE_OF */
1214 format = &ccdc->formats[CCDC_PAD_SOURCE_OF]; 1218 crop = &ccdc->crop;
1215 1219
1216 isp_reg_writel(isp, (0 << ISPCCDC_HORZ_INFO_SPH_SHIFT) | 1220 isp_reg_writel(isp, (crop->left << ISPCCDC_HORZ_INFO_SPH_SHIFT) |
1217 ((format->width - 1) << ISPCCDC_HORZ_INFO_NPH_SHIFT), 1221 ((crop->width - 1) << ISPCCDC_HORZ_INFO_NPH_SHIFT),
1218 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO); 1222 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO);
1219 isp_reg_writel(isp, 0 << ISPCCDC_VERT_START_SLV0_SHIFT, 1223 isp_reg_writel(isp, crop->top << ISPCCDC_VERT_START_SLV0_SHIFT,
1220 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_START); 1224 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_START);
1221 isp_reg_writel(isp, (format->height - 1) 1225 isp_reg_writel(isp, (crop->height - 1)
1222 << ISPCCDC_VERT_LINES_NLV_SHIFT, 1226 << ISPCCDC_VERT_LINES_NLV_SHIFT,
1223 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_LINES); 1227 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_LINES);
1224 1228
@@ -1793,6 +1797,16 @@ __ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
1793 return &ccdc->formats[pad]; 1797 return &ccdc->formats[pad];
1794} 1798}
1795 1799
1800static struct v4l2_rect *
1801__ccdc_get_crop(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
1802 enum v4l2_subdev_format_whence which)
1803{
1804 if (which == V4L2_SUBDEV_FORMAT_TRY)
1805 return v4l2_subdev_get_try_crop(fh, CCDC_PAD_SOURCE_OF);
1806 else
1807 return &ccdc->crop;
1808}
1809
1796/* 1810/*
1797 * ccdc_try_format - Try video format on a pad 1811 * ccdc_try_format - Try video format on a pad
1798 * @ccdc: ISP CCDC device 1812 * @ccdc: ISP CCDC device
@@ -1809,6 +1823,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
1809 const struct isp_format_info *info; 1823 const struct isp_format_info *info;
1810 unsigned int width = fmt->width; 1824 unsigned int width = fmt->width;
1811 unsigned int height = fmt->height; 1825 unsigned int height = fmt->height;
1826 struct v4l2_rect *crop;
1812 unsigned int i; 1827 unsigned int i;
1813 1828
1814 switch (pad) { 1829 switch (pad) {
@@ -1834,14 +1849,10 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
1834 format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which); 1849 format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which);
1835 memcpy(fmt, format, sizeof(*fmt)); 1850 memcpy(fmt, format, sizeof(*fmt));
1836 1851
1837 /* The data formatter truncates the number of horizontal output 1852 /* Hardcode the output size to the crop rectangle size. */
1838 * pixels to a multiple of 16. To avoid clipping data, allow 1853 crop = __ccdc_get_crop(ccdc, fh, which);
1839 * callers to request an output size bigger than the input size 1854 fmt->width = crop->width;
1840 * up to the nearest multiple of 16. 1855 fmt->height = crop->height;
1841 */
1842 fmt->width = clamp_t(u32, width, 32, fmt->width + 15);
1843 fmt->width &= ~15;
1844 fmt->height = clamp_t(u32, height, 32, fmt->height);
1845 break; 1856 break;
1846 1857
1847 case CCDC_PAD_SOURCE_VP: 1858 case CCDC_PAD_SOURCE_VP:
@@ -1869,6 +1880,49 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
1869} 1880}
1870 1881
1871/* 1882/*
1883 * ccdc_try_crop - Validate a crop rectangle
1884 * @ccdc: ISP CCDC device
1885 * @sink: format on the sink pad
1886 * @crop: crop rectangle to be validated
1887 */
1888static void ccdc_try_crop(struct isp_ccdc_device *ccdc,
1889 const struct v4l2_mbus_framefmt *sink,
1890 struct v4l2_rect *crop)
1891{
1892 const struct isp_format_info *info;
1893 unsigned int max_width;
1894
1895 /* For Bayer formats, restrict left/top and width/height to even values
1896 * to keep the Bayer pattern.
1897 */
1898 info = omap3isp_video_format_info(sink->code);
1899 if (info->flavor != V4L2_MBUS_FMT_Y8_1X8) {
1900 crop->left &= ~1;
1901 crop->top &= ~1;
1902 }
1903
1904 crop->left = clamp_t(u32, crop->left, 0, sink->width - CCDC_MIN_WIDTH);
1905 crop->top = clamp_t(u32, crop->top, 0, sink->height - CCDC_MIN_HEIGHT);
1906
1907 /* The data formatter truncates the number of horizontal output pixels
1908 * to a multiple of 16. To avoid clipping data, allow callers to request
1909 * an output size bigger than the input size up to the nearest multiple
1910 * of 16.
1911 */
1912 max_width = (sink->width - crop->left + 15) & ~15;
1913 crop->width = clamp_t(u32, crop->width, CCDC_MIN_WIDTH, max_width)
1914 & ~15;
1915 crop->height = clamp_t(u32, crop->height, CCDC_MIN_HEIGHT,
1916 sink->height - crop->top);
1917
1918 /* Odd width/height values don't make sense for Bayer formats. */
1919 if (info->flavor != V4L2_MBUS_FMT_Y8_1X8) {
1920 crop->width &= ~1;
1921 crop->height &= ~1;
1922 }
1923}
1924
1925/*
1872 * ccdc_enum_mbus_code - Handle pixel format enumeration 1926 * ccdc_enum_mbus_code - Handle pixel format enumeration
1873 * @sd : pointer to v4l2 subdev structure 1927 * @sd : pointer to v4l2 subdev structure
1874 * @fh : V4L2 subdev file handle 1928 * @fh : V4L2 subdev file handle
@@ -1940,6 +1994,93 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd,
1940} 1994}
1941 1995
1942/* 1996/*
1997 * ccdc_get_selection - Retrieve a selection rectangle on a pad
1998 * @sd: ISP CCDC V4L2 subdevice
1999 * @fh: V4L2 subdev file handle
2000 * @sel: Selection rectangle
2001 *
2002 * The only supported rectangles are the crop rectangles on the output formatter
2003 * source pad.
2004 *
2005 * Return 0 on success or a negative error code otherwise.
2006 */
2007static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
2008 struct v4l2_subdev_selection *sel)
2009{
2010 struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
2011 struct v4l2_mbus_framefmt *format;
2012
2013 if (sel->pad != CCDC_PAD_SOURCE_OF)
2014 return -EINVAL;
2015
2016 switch (sel->target) {
2017 case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS:
2018 sel->r.left = 0;
2019 sel->r.top = 0;
2020 sel->r.width = INT_MAX;
2021 sel->r.height = INT_MAX;
2022
2023 format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, sel->which);
2024 ccdc_try_crop(ccdc, format, &sel->r);
2025 break;
2026
2027 case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
2028 sel->r = *__ccdc_get_crop(ccdc, fh, sel->which);
2029 break;
2030
2031 default:
2032 return -EINVAL;
2033 }
2034
2035 return 0;
2036}
2037
2038/*
2039 * ccdc_set_selection - Set a selection rectangle on a pad
2040 * @sd: ISP CCDC V4L2 subdevice
2041 * @fh: V4L2 subdev file handle
2042 * @sel: Selection rectangle
2043 *
2044 * The only supported rectangle is the actual crop rectangle on the output
2045 * formatter source pad.
2046 *
2047 * Return 0 on success or a negative error code otherwise.
2048 */
2049static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
2050 struct v4l2_subdev_selection *sel)
2051{
2052 struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
2053 struct v4l2_mbus_framefmt *format;
2054
2055 if (sel->target != V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL ||
2056 sel->pad != CCDC_PAD_SOURCE_OF)
2057 return -EINVAL;
2058
2059 /* The crop rectangle can't be changed while streaming. */
2060 if (ccdc->state != ISP_PIPELINE_STREAM_STOPPED)
2061 return -EBUSY;
2062
2063 /* Modifying the crop rectangle always changes the format on the source
2064 * pad. If the KEEP_CONFIG flag is set, just return the current crop
2065 * rectangle.
2066 */
2067 if (sel->flags & V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG) {
2068 sel->r = *__ccdc_get_crop(ccdc, fh, sel->which);
2069 return 0;
2070 }
2071
2072 format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, sel->which);
2073 ccdc_try_crop(ccdc, format, &sel->r);
2074 *__ccdc_get_crop(ccdc, fh, sel->which) = sel->r;
2075
2076 /* Update the source format. */
2077 format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF, sel->which);
2078 ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_OF, format, sel->which);
2079
2080 return 0;
2081}
2082
2083/*
1943 * ccdc_get_format - Retrieve the video format on a pad 2084 * ccdc_get_format - Retrieve the video format on a pad
1944 * @sd : ISP CCDC V4L2 subdevice 2085 * @sd : ISP CCDC V4L2 subdevice
1945 * @fh : V4L2 subdev file handle 2086 * @fh : V4L2 subdev file handle
@@ -1976,6 +2117,7 @@ static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1976{ 2117{
1977 struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); 2118 struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
1978 struct v4l2_mbus_framefmt *format; 2119 struct v4l2_mbus_framefmt *format;
2120 struct v4l2_rect *crop;
1979 2121
1980 format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which); 2122 format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which);
1981 if (format == NULL) 2123 if (format == NULL)
@@ -1986,6 +2128,16 @@ static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1986 2128
1987 /* Propagate the format from sink to source */ 2129 /* Propagate the format from sink to source */
1988 if (fmt->pad == CCDC_PAD_SINK) { 2130 if (fmt->pad == CCDC_PAD_SINK) {
2131 /* Reset the crop rectangle. */
2132 crop = __ccdc_get_crop(ccdc, fh, fmt->which);
2133 crop->left = 0;
2134 crop->top = 0;
2135 crop->width = fmt->format.width;
2136 crop->height = fmt->format.height;
2137
2138 ccdc_try_crop(ccdc, &fmt->format, crop);
2139
2140 /* Update the source formats. */
1989 format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF, 2141 format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF,
1990 fmt->which); 2142 fmt->which);
1991 *format = fmt->format; 2143 *format = fmt->format;
@@ -2044,6 +2196,8 @@ static const struct v4l2_subdev_pad_ops ccdc_v4l2_pad_ops = {
2044 .enum_frame_size = ccdc_enum_frame_size, 2196 .enum_frame_size = ccdc_enum_frame_size,
2045 .get_fmt = ccdc_get_format, 2197 .get_fmt = ccdc_get_format,
2046 .set_fmt = ccdc_set_format, 2198 .set_fmt = ccdc_set_format,
2199 .get_selection = ccdc_get_selection,
2200 .set_selection = ccdc_set_selection,
2047}; 2201};
2048 2202
2049/* V4L2 subdev operations */ 2203/* V4L2 subdev operations */
diff --git a/drivers/media/video/omap3isp/ispccdc.h b/drivers/media/video/omap3isp/ispccdc.h
index 6d0264bab75b..966bbf8a1262 100644
--- a/drivers/media/video/omap3isp/ispccdc.h
+++ b/drivers/media/video/omap3isp/ispccdc.h
@@ -147,6 +147,7 @@ struct ispccdc_lsc {
147 * @subdev: V4L2 subdevice 147 * @subdev: V4L2 subdevice
148 * @pads: Sink and source media entity pads 148 * @pads: Sink and source media entity pads
149 * @formats: Active video formats 149 * @formats: Active video formats
150 * @crop: Active crop rectangle on the OF source pad
150 * @input: Active input 151 * @input: Active input
151 * @output: Active outputs 152 * @output: Active outputs
152 * @video_out: Output video node 153 * @video_out: Output video node
@@ -173,6 +174,7 @@ struct isp_ccdc_device {
173 struct v4l2_subdev subdev; 174 struct v4l2_subdev subdev;
174 struct media_pad pads[CCDC_PADS_NUM]; 175 struct media_pad pads[CCDC_PADS_NUM];
175 struct v4l2_mbus_framefmt formats[CCDC_PADS_NUM]; 176 struct v4l2_mbus_framefmt formats[CCDC_PADS_NUM];
177 struct v4l2_rect crop;
176 178
177 enum ccdc_input_entity input; 179 enum ccdc_input_entity input;
178 unsigned int output; 180 unsigned int output;