diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-04-27 18:17:52 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-04-27 18:17:52 -0400 |
commit | 7fcaa9aaea48996ba308c047a381de7a17ce03b2 (patch) | |
tree | aa66519921a9a6e56f5448d7630386565fd31c89 /drivers/media/video/omap3isp | |
parent | 8e10cd74342c7f5ce259cceca36f6eba084f5d58 (diff) | |
parent | 13b140953ab4fd86e2065adfef892fe833986ffa (diff) |
Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6
* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (42 commits)
[media] media: vb2: correct queue initialization order
[media] media: vb2: fix incorrect v4l2_buffer->flags handling
[media] s5p-fimc: Add support for the buffer timestamps and sequence
[media] s5p-fimc: Fix bytesperline and plane payload setup
[media] s5p-fimc: Do not allow changing format after REQBUFS
[media] s5p-fimc: Fix FIMC3 pixel limits on Exynos4
[media] tda18271: update tda18271c2_rf_cal as per NXP's rev.04 datasheet
[media] tda18271: update tda18271_rf_band as per NXP's rev.04 datasheet
[media] tda18271: fix bad calculation of main post divider byte
[media] tda18271: prog_cal and prog_tab variables should be s32, not u8
[media] tda18271: fix calculation bug in tda18271_rf_tracking_filters_init
[media] omap3isp: queue: Don't corrupt buf->npages when get_user_pages() fails
[media] v4l: Don't register media entities for subdev device nodes
[media] omap3isp: Don't increment node entity use count when poweron fails
[media] omap3isp: lane shifter support
[media] omap3isp: ccdc: support Y10/12, 8-bit bayer fmts
[media] media: add missing 8-bit bayer formats and Y12
[media] v4l: add V4L2_PIX_FMT_Y12 format
cx23885: Fix stv0367 Kconfig dependency
[media] omap3isp: Use isp xclk defines
...
Fix up trivial conflict (spelink errurs) in drivers/media/video/omap3isp/isp.c
Diffstat (limited to 'drivers/media/video/omap3isp')
-rw-r--r-- | drivers/media/video/omap3isp/isp.c | 34 | ||||
-rw-r--r-- | drivers/media/video/omap3isp/isp.h | 12 | ||||
-rw-r--r-- | drivers/media/video/omap3isp/ispccdc.c | 37 | ||||
-rw-r--r-- | drivers/media/video/omap3isp/isppreview.c | 2 | ||||
-rw-r--r-- | drivers/media/video/omap3isp/ispqueue.c | 6 | ||||
-rw-r--r-- | drivers/media/video/omap3isp/ispresizer.c | 75 | ||||
-rw-r--r-- | drivers/media/video/omap3isp/ispstat.h | 6 | ||||
-rw-r--r-- | drivers/media/video/omap3isp/ispvideo.c | 108 | ||||
-rw-r--r-- | drivers/media/video/omap3isp/ispvideo.h | 3 |
9 files changed, 225 insertions, 58 deletions
diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index 503bd7922bd6..472a69359e60 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c | |||
@@ -215,20 +215,21 @@ static u32 isp_set_xclk(struct isp_device *isp, u32 xclk, u8 xclksel) | |||
215 | } | 215 | } |
216 | 216 | ||
217 | switch (xclksel) { | 217 | switch (xclksel) { |
218 | case 0: | 218 | case ISP_XCLK_A: |
219 | isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL, | 219 | isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL, |
220 | ISPTCTRL_CTRL_DIVA_MASK, | 220 | ISPTCTRL_CTRL_DIVA_MASK, |
221 | divisor << ISPTCTRL_CTRL_DIVA_SHIFT); | 221 | divisor << ISPTCTRL_CTRL_DIVA_SHIFT); |
222 | dev_dbg(isp->dev, "isp_set_xclk(): cam_xclka set to %d Hz\n", | 222 | dev_dbg(isp->dev, "isp_set_xclk(): cam_xclka set to %d Hz\n", |
223 | currentxclk); | 223 | currentxclk); |
224 | break; | 224 | break; |
225 | case 1: | 225 | case ISP_XCLK_B: |
226 | isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL, | 226 | isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL, |
227 | ISPTCTRL_CTRL_DIVB_MASK, | 227 | ISPTCTRL_CTRL_DIVB_MASK, |
228 | divisor << ISPTCTRL_CTRL_DIVB_SHIFT); | 228 | divisor << ISPTCTRL_CTRL_DIVB_SHIFT); |
229 | dev_dbg(isp->dev, "isp_set_xclk(): cam_xclkb set to %d Hz\n", | 229 | dev_dbg(isp->dev, "isp_set_xclk(): cam_xclkb set to %d Hz\n", |
230 | currentxclk); | 230 | currentxclk); |
231 | break; | 231 | break; |
232 | case ISP_XCLK_NONE: | ||
232 | default: | 233 | default: |
233 | omap3isp_put(isp); | 234 | omap3isp_put(isp); |
234 | dev_dbg(isp->dev, "ISP_ERR: isp_set_xclk(): Invalid requested " | 235 | dev_dbg(isp->dev, "ISP_ERR: isp_set_xclk(): Invalid requested " |
@@ -237,13 +238,13 @@ static u32 isp_set_xclk(struct isp_device *isp, u32 xclk, u8 xclksel) | |||
237 | } | 238 | } |
238 | 239 | ||
239 | /* Do we go from stable whatever to clock? */ | 240 | /* Do we go from stable whatever to clock? */ |
240 | if (divisor >= 2 && isp->xclk_divisor[xclksel] < 2) | 241 | if (divisor >= 2 && isp->xclk_divisor[xclksel - 1] < 2) |
241 | omap3isp_get(isp); | 242 | omap3isp_get(isp); |
242 | /* Stopping the clock. */ | 243 | /* Stopping the clock. */ |
243 | else if (divisor < 2 && isp->xclk_divisor[xclksel] >= 2) | 244 | else if (divisor < 2 && isp->xclk_divisor[xclksel - 1] >= 2) |
244 | omap3isp_put(isp); | 245 | omap3isp_put(isp); |
245 | 246 | ||
246 | isp->xclk_divisor[xclksel] = divisor; | 247 | isp->xclk_divisor[xclksel - 1] = divisor; |
247 | 248 | ||
248 | omap3isp_put(isp); | 249 | omap3isp_put(isp); |
249 | 250 | ||
@@ -285,7 +286,8 @@ static void isp_power_settings(struct isp_device *isp, int idle) | |||
285 | */ | 286 | */ |
286 | void omap3isp_configure_bridge(struct isp_device *isp, | 287 | void omap3isp_configure_bridge(struct isp_device *isp, |
287 | enum ccdc_input_entity input, | 288 | enum ccdc_input_entity input, |
288 | const struct isp_parallel_platform_data *pdata) | 289 | const struct isp_parallel_platform_data *pdata, |
290 | unsigned int shift) | ||
289 | { | 291 | { |
290 | u32 ispctrl_val; | 292 | u32 ispctrl_val; |
291 | 293 | ||
@@ -298,9 +300,9 @@ void omap3isp_configure_bridge(struct isp_device *isp, | |||
298 | switch (input) { | 300 | switch (input) { |
299 | case CCDC_INPUT_PARALLEL: | 301 | case CCDC_INPUT_PARALLEL: |
300 | ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_PARALLEL; | 302 | ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_PARALLEL; |
301 | ispctrl_val |= pdata->data_lane_shift << ISPCTRL_SHIFT_SHIFT; | ||
302 | ispctrl_val |= pdata->clk_pol << ISPCTRL_PAR_CLK_POL_SHIFT; | 303 | ispctrl_val |= pdata->clk_pol << ISPCTRL_PAR_CLK_POL_SHIFT; |
303 | ispctrl_val |= pdata->bridge << ISPCTRL_PAR_BRIDGE_SHIFT; | 304 | ispctrl_val |= pdata->bridge << ISPCTRL_PAR_BRIDGE_SHIFT; |
305 | shift += pdata->data_lane_shift * 2; | ||
304 | break; | 306 | break; |
305 | 307 | ||
306 | case CCDC_INPUT_CSI2A: | 308 | case CCDC_INPUT_CSI2A: |
@@ -319,6 +321,8 @@ void omap3isp_configure_bridge(struct isp_device *isp, | |||
319 | return; | 321 | return; |
320 | } | 322 | } |
321 | 323 | ||
324 | ispctrl_val |= ((shift/2) << ISPCTRL_SHIFT_SHIFT) & ISPCTRL_SHIFT_MASK; | ||
325 | |||
322 | ispctrl_val &= ~ISPCTRL_SYNC_DETECT_MASK; | 326 | ispctrl_val &= ~ISPCTRL_SYNC_DETECT_MASK; |
323 | ispctrl_val |= ISPCTRL_SYNC_DETECT_VSRISE; | 327 | ispctrl_val |= ISPCTRL_SYNC_DETECT_VSRISE; |
324 | 328 | ||
@@ -658,6 +662,8 @@ int omap3isp_pipeline_pm_use(struct media_entity *entity, int use) | |||
658 | 662 | ||
659 | /* Apply power change to connected non-nodes. */ | 663 | /* Apply power change to connected non-nodes. */ |
660 | ret = isp_pipeline_pm_power(entity, change); | 664 | ret = isp_pipeline_pm_power(entity, change); |
665 | if (ret < 0) | ||
666 | entity->use_count -= change; | ||
661 | 667 | ||
662 | mutex_unlock(&entity->parent->graph_mutex); | 668 | mutex_unlock(&entity->parent->graph_mutex); |
663 | 669 | ||
@@ -872,6 +878,9 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe) | |||
872 | } | 878 | } |
873 | } | 879 | } |
874 | 880 | ||
881 | if (failure < 0) | ||
882 | isp->needs_reset = true; | ||
883 | |||
875 | return failure; | 884 | return failure; |
876 | } | 885 | } |
877 | 886 | ||
@@ -884,7 +893,8 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe) | |||
884 | * single-shot or continuous mode. | 893 | * single-shot or continuous mode. |
885 | * | 894 | * |
886 | * Return 0 if successful, or the return value of the failed video::s_stream | 895 | * Return 0 if successful, or the return value of the failed video::s_stream |
887 | * operation otherwise. | 896 | * operation otherwise. The pipeline state is not updated when the operation |
897 | * fails, except when stopping the pipeline. | ||
888 | */ | 898 | */ |
889 | int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, | 899 | int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, |
890 | enum isp_pipeline_stream_state state) | 900 | enum isp_pipeline_stream_state state) |
@@ -895,7 +905,9 @@ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, | |||
895 | ret = isp_pipeline_disable(pipe); | 905 | ret = isp_pipeline_disable(pipe); |
896 | else | 906 | else |
897 | ret = isp_pipeline_enable(pipe, state); | 907 | ret = isp_pipeline_enable(pipe, state); |
898 | pipe->stream_state = state; | 908 | |
909 | if (ret == 0 || state == ISP_PIPELINE_STREAM_STOPPED) | ||
910 | pipe->stream_state = state; | ||
899 | 911 | ||
900 | return ret; | 912 | return ret; |
901 | } | 913 | } |
@@ -1481,6 +1493,10 @@ void omap3isp_put(struct isp_device *isp) | |||
1481 | if (--isp->ref_count == 0) { | 1493 | if (--isp->ref_count == 0) { |
1482 | isp_disable_interrupts(isp); | 1494 | isp_disable_interrupts(isp); |
1483 | isp_save_ctx(isp); | 1495 | isp_save_ctx(isp); |
1496 | if (isp->needs_reset) { | ||
1497 | isp_reset(isp); | ||
1498 | isp->needs_reset = false; | ||
1499 | } | ||
1484 | isp_disable_clocks(isp); | 1500 | isp_disable_clocks(isp); |
1485 | } | 1501 | } |
1486 | mutex_unlock(&isp->isp_mutex); | 1502 | mutex_unlock(&isp->isp_mutex); |
diff --git a/drivers/media/video/omap3isp/isp.h b/drivers/media/video/omap3isp/isp.h index cf5214e95a92..2620c405f5e4 100644 --- a/drivers/media/video/omap3isp/isp.h +++ b/drivers/media/video/omap3isp/isp.h | |||
@@ -132,7 +132,6 @@ struct isp_reg { | |||
132 | 132 | ||
133 | /** | 133 | /** |
134 | * struct isp_parallel_platform_data - Parallel interface platform data | 134 | * struct isp_parallel_platform_data - Parallel interface platform data |
135 | * @width: Parallel bus width in bits (8, 10, 11 or 12) | ||
136 | * @data_lane_shift: Data lane shifter | 135 | * @data_lane_shift: Data lane shifter |
137 | * 0 - CAMEXT[13:0] -> CAM[13:0] | 136 | * 0 - CAMEXT[13:0] -> CAM[13:0] |
138 | * 1 - CAMEXT[13:2] -> CAM[11:0] | 137 | * 1 - CAMEXT[13:2] -> CAM[11:0] |
@@ -146,7 +145,6 @@ struct isp_reg { | |||
146 | * ISPCTRL_PAR_BRIDGE_BENDIAN - Big endian | 145 | * ISPCTRL_PAR_BRIDGE_BENDIAN - Big endian |
147 | */ | 146 | */ |
148 | struct isp_parallel_platform_data { | 147 | struct isp_parallel_platform_data { |
149 | unsigned int width; | ||
150 | unsigned int data_lane_shift:2; | 148 | unsigned int data_lane_shift:2; |
151 | unsigned int clk_pol:1; | 149 | unsigned int clk_pol:1; |
152 | unsigned int bridge:4; | 150 | unsigned int bridge:4; |
@@ -262,6 +260,7 @@ struct isp_device { | |||
262 | /* ISP Obj */ | 260 | /* ISP Obj */ |
263 | spinlock_t stat_lock; /* common lock for statistic drivers */ | 261 | spinlock_t stat_lock; /* common lock for statistic drivers */ |
264 | struct mutex isp_mutex; /* For handling ref_count field */ | 262 | struct mutex isp_mutex; /* For handling ref_count field */ |
263 | bool needs_reset; | ||
265 | int has_context; | 264 | int has_context; |
266 | int ref_count; | 265 | int ref_count; |
267 | unsigned int autoidle; | 266 | unsigned int autoidle; |
@@ -311,11 +310,12 @@ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, | |||
311 | enum isp_pipeline_stream_state state); | 310 | enum isp_pipeline_stream_state state); |
312 | void omap3isp_configure_bridge(struct isp_device *isp, | 311 | void omap3isp_configure_bridge(struct isp_device *isp, |
313 | enum ccdc_input_entity input, | 312 | enum ccdc_input_entity input, |
314 | const struct isp_parallel_platform_data *pdata); | 313 | const struct isp_parallel_platform_data *pdata, |
314 | unsigned int shift); | ||
315 | 315 | ||
316 | #define ISP_XCLK_NONE -1 | 316 | #define ISP_XCLK_NONE 0 |
317 | #define ISP_XCLK_A 0 | 317 | #define ISP_XCLK_A 1 |
318 | #define ISP_XCLK_B 1 | 318 | #define ISP_XCLK_B 2 |
319 | 319 | ||
320 | struct isp_device *omap3isp_get(struct isp_device *isp); | 320 | struct isp_device *omap3isp_get(struct isp_device *isp); |
321 | void omap3isp_put(struct isp_device *isp); | 321 | void omap3isp_put(struct isp_device *isp); |
diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index 5ff9d14ce710..39d501bda636 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c | |||
@@ -43,6 +43,12 @@ __ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, | |||
43 | 43 | ||
44 | static const unsigned int ccdc_fmts[] = { | 44 | static const unsigned int ccdc_fmts[] = { |
45 | V4L2_MBUS_FMT_Y8_1X8, | 45 | V4L2_MBUS_FMT_Y8_1X8, |
46 | V4L2_MBUS_FMT_Y10_1X10, | ||
47 | V4L2_MBUS_FMT_Y12_1X12, | ||
48 | V4L2_MBUS_FMT_SGRBG8_1X8, | ||
49 | V4L2_MBUS_FMT_SRGGB8_1X8, | ||
50 | V4L2_MBUS_FMT_SBGGR8_1X8, | ||
51 | V4L2_MBUS_FMT_SGBRG8_1X8, | ||
46 | V4L2_MBUS_FMT_SGRBG10_1X10, | 52 | V4L2_MBUS_FMT_SGRBG10_1X10, |
47 | V4L2_MBUS_FMT_SRGGB10_1X10, | 53 | V4L2_MBUS_FMT_SRGGB10_1X10, |
48 | V4L2_MBUS_FMT_SBGGR10_1X10, | 54 | V4L2_MBUS_FMT_SBGGR10_1X10, |
@@ -1110,21 +1116,38 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) | |||
1110 | struct isp_parallel_platform_data *pdata = NULL; | 1116 | struct isp_parallel_platform_data *pdata = NULL; |
1111 | struct v4l2_subdev *sensor; | 1117 | struct v4l2_subdev *sensor; |
1112 | struct v4l2_mbus_framefmt *format; | 1118 | struct v4l2_mbus_framefmt *format; |
1119 | const struct isp_format_info *fmt_info; | ||
1120 | struct v4l2_subdev_format fmt_src; | ||
1121 | unsigned int depth_out; | ||
1122 | unsigned int depth_in = 0; | ||
1113 | struct media_pad *pad; | 1123 | struct media_pad *pad; |
1114 | unsigned long flags; | 1124 | unsigned long flags; |
1125 | unsigned int shift; | ||
1115 | u32 syn_mode; | 1126 | u32 syn_mode; |
1116 | u32 ccdc_pattern; | 1127 | u32 ccdc_pattern; |
1117 | 1128 | ||
1118 | if (ccdc->input == CCDC_INPUT_PARALLEL) { | 1129 | pad = media_entity_remote_source(&ccdc->pads[CCDC_PAD_SINK]); |
1119 | pad = media_entity_remote_source(&ccdc->pads[CCDC_PAD_SINK]); | 1130 | sensor = media_entity_to_v4l2_subdev(pad->entity); |
1120 | sensor = media_entity_to_v4l2_subdev(pad->entity); | 1131 | if (ccdc->input == CCDC_INPUT_PARALLEL) |
1121 | pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv) | 1132 | pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv) |
1122 | ->bus.parallel; | 1133 | ->bus.parallel; |
1134 | |||
1135 | /* Compute shift value for lane shifter to configure the bridge. */ | ||
1136 | fmt_src.pad = pad->index; | ||
1137 | fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE; | ||
1138 | if (!v4l2_subdev_call(sensor, pad, get_fmt, NULL, &fmt_src)) { | ||
1139 | fmt_info = omap3isp_video_format_info(fmt_src.format.code); | ||
1140 | depth_in = fmt_info->bpp; | ||
1123 | } | 1141 | } |
1124 | 1142 | ||
1125 | omap3isp_configure_bridge(isp, ccdc->input, pdata); | 1143 | fmt_info = omap3isp_video_format_info |
1144 | (isp->isp_ccdc.formats[CCDC_PAD_SINK].code); | ||
1145 | depth_out = fmt_info->bpp; | ||
1146 | |||
1147 | shift = depth_in - depth_out; | ||
1148 | omap3isp_configure_bridge(isp, ccdc->input, pdata, shift); | ||
1126 | 1149 | ||
1127 | ccdc->syncif.datsz = pdata ? pdata->width : 10; | 1150 | ccdc->syncif.datsz = depth_out; |
1128 | ccdc_config_sync_if(ccdc, &ccdc->syncif); | 1151 | ccdc_config_sync_if(ccdc, &ccdc->syncif); |
1129 | 1152 | ||
1130 | /* CCDC_PAD_SINK */ | 1153 | /* CCDC_PAD_SINK */ |
@@ -1338,7 +1361,7 @@ static int ccdc_sbl_wait_idle(struct isp_ccdc_device *ccdc, | |||
1338 | * @ccdc: Pointer to ISP CCDC device. | 1361 | * @ccdc: Pointer to ISP CCDC device. |
1339 | * @event: Pointing which event trigger handler | 1362 | * @event: Pointing which event trigger handler |
1340 | * | 1363 | * |
1341 | * Return 1 when the event and stopping request combination is satisfyied, | 1364 | * Return 1 when the event and stopping request combination is satisfied, |
1342 | * zero otherwise. | 1365 | * zero otherwise. |
1343 | */ | 1366 | */ |
1344 | static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event) | 1367 | static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event) |
@@ -1618,7 +1641,7 @@ static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer) | |||
1618 | 1641 | ||
1619 | ccdc_set_outaddr(ccdc, buffer->isp_addr); | 1642 | ccdc_set_outaddr(ccdc, buffer->isp_addr); |
1620 | 1643 | ||
1621 | /* We now have a buffer queued on the output, restart the pipeline in | 1644 | /* We now have a buffer queued on the output, restart the pipeline |
1622 | * on the next CCDC interrupt if running in continuous mode (or when | 1645 | * on the next CCDC interrupt if running in continuous mode (or when |
1623 | * starting the stream). | 1646 | * starting the stream). |
1624 | */ | 1647 | */ |
diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c index 2b16988a501d..aba537af87e4 100644 --- a/drivers/media/video/omap3isp/isppreview.c +++ b/drivers/media/video/omap3isp/isppreview.c | |||
@@ -755,7 +755,7 @@ static struct preview_update update_attrs[] = { | |||
755 | * @configs - pointer to update config structure. | 755 | * @configs - pointer to update config structure. |
756 | * @config - return pointer to appropriate structure field. | 756 | * @config - return pointer to appropriate structure field. |
757 | * @bit - for which feature to return pointers. | 757 | * @bit - for which feature to return pointers. |
758 | * Return size of coresponding prev_params member | 758 | * Return size of corresponding prev_params member |
759 | */ | 759 | */ |
760 | static u32 | 760 | static u32 |
761 | __preview_get_ptrs(struct prev_params *params, void **param, | 761 | __preview_get_ptrs(struct prev_params *params, void **param, |
diff --git a/drivers/media/video/omap3isp/ispqueue.c b/drivers/media/video/omap3isp/ispqueue.c index 8fddc5806b0d..9c317148205f 100644 --- a/drivers/media/video/omap3isp/ispqueue.c +++ b/drivers/media/video/omap3isp/ispqueue.c | |||
@@ -339,7 +339,7 @@ static int isp_video_buffer_prepare_user(struct isp_video_buffer *buf) | |||
339 | up_read(¤t->mm->mmap_sem); | 339 | up_read(¤t->mm->mmap_sem); |
340 | 340 | ||
341 | if (ret != buf->npages) { | 341 | if (ret != buf->npages) { |
342 | buf->npages = ret; | 342 | buf->npages = ret < 0 ? 0 : ret; |
343 | isp_video_buffer_cleanup(buf); | 343 | isp_video_buffer_cleanup(buf); |
344 | return -EFAULT; | 344 | return -EFAULT; |
345 | } | 345 | } |
@@ -408,8 +408,8 @@ done: | |||
408 | * isp_video_buffer_prepare_vm_flags - Get VMA flags for a userspace address | 408 | * isp_video_buffer_prepare_vm_flags - Get VMA flags for a userspace address |
409 | * | 409 | * |
410 | * This function locates the VMAs for the buffer's userspace address and checks | 410 | * This function locates the VMAs for the buffer's userspace address and checks |
411 | * that their flags match. The onlflag that we need to care for at the moment is | 411 | * that their flags match. The only flag that we need to care for at the moment |
412 | * VM_PFNMAP. | 412 | * is VM_PFNMAP. |
413 | * | 413 | * |
414 | * The buffer vm_flags field is set to the first VMA flags. | 414 | * The buffer vm_flags field is set to the first VMA flags. |
415 | * | 415 | * |
diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c index 653f88ba56db..0bb0f8cd36f5 100644 --- a/drivers/media/video/omap3isp/ispresizer.c +++ b/drivers/media/video/omap3isp/ispresizer.c | |||
@@ -714,19 +714,50 @@ static void resizer_print_status(struct isp_res_device *res) | |||
714 | * iw and ih are the input width and height after cropping. Those equations need | 714 | * iw and ih are the input width and height after cropping. Those equations need |
715 | * to be satisfied exactly for the resizer to work correctly. | 715 | * to be satisfied exactly for the resizer to work correctly. |
716 | * | 716 | * |
717 | * Reverting the equations, we can compute the resizing ratios with | 717 | * The equations can't be easily reverted, as the >> 8 operation is not linear. |
718 | * In addition, not all input sizes can be achieved for a given output size. To | ||
719 | * get the highest input size lower than or equal to the requested input size, | ||
720 | * we need to compute the highest resizing ratio that satisfies the following | ||
721 | * inequality (taking the 4-tap mode width equation as an example) | ||
722 | * | ||
723 | * iw >= (32 * sph + (ow - 1) * hrsz + 16) >> 8 - 7 | ||
724 | * | ||
725 | * (where iw is the requested input width) which can be rewritten as | ||
726 | * | ||
727 | * iw - 7 >= (32 * sph + (ow - 1) * hrsz + 16) >> 8 | ||
728 | * (iw - 7) << 8 >= 32 * sph + (ow - 1) * hrsz + 16 - b | ||
729 | * ((iw - 7) << 8) + b >= 32 * sph + (ow - 1) * hrsz + 16 | ||
730 | * | ||
731 | * where b is the value of the 8 least significant bits of the right hand side | ||
732 | * expression of the last inequality. The highest resizing ratio value will be | ||
733 | * achieved when b is equal to its maximum value of 255. That resizing ratio | ||
734 | * value will still satisfy the original inequality, as b will disappear when | ||
735 | * the expression will be shifted right by 8. | ||
736 | * | ||
737 | * The reverted the equations thus become | ||
718 | * | 738 | * |
719 | * - 8-phase, 4-tap mode | 739 | * - 8-phase, 4-tap mode |
720 | * hrsz = ((iw - 7) * 256 - 16 - 32 * sph) / (ow - 1) | 740 | * hrsz = ((iw - 7) * 256 + 255 - 16 - 32 * sph) / (ow - 1) |
721 | * vrsz = ((ih - 4) * 256 - 16 - 32 * spv) / (oh - 1) | 741 | * vrsz = ((ih - 4) * 256 + 255 - 16 - 32 * spv) / (oh - 1) |
722 | * - 4-phase, 7-tap mode | 742 | * - 4-phase, 7-tap mode |
723 | * hrsz = ((iw - 7) * 256 - 32 - 64 * sph) / (ow - 1) | 743 | * hrsz = ((iw - 7) * 256 + 255 - 32 - 64 * sph) / (ow - 1) |
724 | * vrsz = ((ih - 7) * 256 - 32 - 64 * spv) / (oh - 1) | 744 | * vrsz = ((ih - 7) * 256 + 255 - 32 - 64 * spv) / (oh - 1) |
725 | * | 745 | * |
726 | * The ratios are integer values, and must be rounded down to ensure that the | 746 | * The ratios are integer values, and are rounded down to ensure that the |
727 | * cropped input size is not bigger than the uncropped input size. As the ratio | 747 | * cropped input size is not bigger than the uncropped input size. |
728 | * in 7-tap mode is always smaller than the ratio in 4-tap mode, we can use the | 748 | * |
729 | * 7-tap mode equations to compute a ratio approximation. | 749 | * As the number of phases/taps, used to select the correct equations to compute |
750 | * the ratio, depends on the ratio, we start with the 4-tap mode equations to | ||
751 | * compute an approximation of the ratio, and switch to the 7-tap mode equations | ||
752 | * if the approximation is higher than the ratio threshold. | ||
753 | * | ||
754 | * As the 7-tap mode equations will return a ratio smaller than or equal to the | ||
755 | * 4-tap mode equations, the resulting ratio could become lower than or equal to | ||
756 | * the ratio threshold. This 'equations loop' isn't an issue as long as the | ||
757 | * correct equations are used to compute the final input size. Starting with the | ||
758 | * 4-tap mode equations ensure that, in case of values resulting in a 'ratio | ||
759 | * loop', the smallest of the ratio values will be used, never exceeding the | ||
760 | * requested input size. | ||
730 | * | 761 | * |
731 | * We first clamp the output size according to the hardware capabilitie to avoid | 762 | * We first clamp the output size according to the hardware capabilitie to avoid |
732 | * auto-cropping the input more than required to satisfy the TRM equations. The | 763 | * auto-cropping the input more than required to satisfy the TRM equations. The |
@@ -775,6 +806,8 @@ static void resizer_calc_ratios(struct isp_res_device *res, | |||
775 | unsigned int max_width; | 806 | unsigned int max_width; |
776 | unsigned int max_height; | 807 | unsigned int max_height; |
777 | unsigned int width_alignment; | 808 | unsigned int width_alignment; |
809 | unsigned int width; | ||
810 | unsigned int height; | ||
778 | 811 | ||
779 | /* | 812 | /* |
780 | * Clamp the output height based on the hardware capabilities and | 813 | * Clamp the output height based on the hardware capabilities and |
@@ -786,19 +819,22 @@ static void resizer_calc_ratios(struct isp_res_device *res, | |||
786 | max_height = min_t(unsigned int, max_height, MAX_OUT_HEIGHT); | 819 | max_height = min_t(unsigned int, max_height, MAX_OUT_HEIGHT); |
787 | output->height = clamp(output->height, min_height, max_height); | 820 | output->height = clamp(output->height, min_height, max_height); |
788 | 821 | ||
789 | ratio->vert = ((input->height - 7) * 256 - 32 - 64 * spv) | 822 | ratio->vert = ((input->height - 4) * 256 + 255 - 16 - 32 * spv) |
790 | / (output->height - 1); | 823 | / (output->height - 1); |
824 | if (ratio->vert > MID_RESIZE_VALUE) | ||
825 | ratio->vert = ((input->height - 7) * 256 + 255 - 32 - 64 * spv) | ||
826 | / (output->height - 1); | ||
791 | ratio->vert = clamp_t(unsigned int, ratio->vert, | 827 | ratio->vert = clamp_t(unsigned int, ratio->vert, |
792 | MIN_RESIZE_VALUE, MAX_RESIZE_VALUE); | 828 | MIN_RESIZE_VALUE, MAX_RESIZE_VALUE); |
793 | 829 | ||
794 | if (ratio->vert <= MID_RESIZE_VALUE) { | 830 | if (ratio->vert <= MID_RESIZE_VALUE) { |
795 | upscaled_height = (output->height - 1) * ratio->vert | 831 | upscaled_height = (output->height - 1) * ratio->vert |
796 | + 32 * spv + 16; | 832 | + 32 * spv + 16; |
797 | input->height = (upscaled_height >> 8) + 4; | 833 | height = (upscaled_height >> 8) + 4; |
798 | } else { | 834 | } else { |
799 | upscaled_height = (output->height - 1) * ratio->vert | 835 | upscaled_height = (output->height - 1) * ratio->vert |
800 | + 64 * spv + 32; | 836 | + 64 * spv + 32; |
801 | input->height = (upscaled_height >> 8) + 7; | 837 | height = (upscaled_height >> 8) + 7; |
802 | } | 838 | } |
803 | 839 | ||
804 | /* | 840 | /* |
@@ -854,20 +890,29 @@ static void resizer_calc_ratios(struct isp_res_device *res, | |||
854 | max_width & ~(width_alignment - 1)); | 890 | max_width & ~(width_alignment - 1)); |
855 | output->width = ALIGN(output->width, width_alignment); | 891 | output->width = ALIGN(output->width, width_alignment); |
856 | 892 | ||
857 | ratio->horz = ((input->width - 7) * 256 - 32 - 64 * sph) | 893 | ratio->horz = ((input->width - 7) * 256 + 255 - 16 - 32 * sph) |
858 | / (output->width - 1); | 894 | / (output->width - 1); |
895 | if (ratio->horz > MID_RESIZE_VALUE) | ||
896 | ratio->horz = ((input->width - 7) * 256 + 255 - 32 - 64 * sph) | ||
897 | / (output->width - 1); | ||
859 | ratio->horz = clamp_t(unsigned int, ratio->horz, | 898 | ratio->horz = clamp_t(unsigned int, ratio->horz, |
860 | MIN_RESIZE_VALUE, MAX_RESIZE_VALUE); | 899 | MIN_RESIZE_VALUE, MAX_RESIZE_VALUE); |
861 | 900 | ||
862 | if (ratio->horz <= MID_RESIZE_VALUE) { | 901 | if (ratio->horz <= MID_RESIZE_VALUE) { |
863 | upscaled_width = (output->width - 1) * ratio->horz | 902 | upscaled_width = (output->width - 1) * ratio->horz |
864 | + 32 * sph + 16; | 903 | + 32 * sph + 16; |
865 | input->width = (upscaled_width >> 8) + 7; | 904 | width = (upscaled_width >> 8) + 7; |
866 | } else { | 905 | } else { |
867 | upscaled_width = (output->width - 1) * ratio->horz | 906 | upscaled_width = (output->width - 1) * ratio->horz |
868 | + 64 * sph + 32; | 907 | + 64 * sph + 32; |
869 | input->width = (upscaled_width >> 8) + 7; | 908 | width = (upscaled_width >> 8) + 7; |
870 | } | 909 | } |
910 | |||
911 | /* Center the new crop rectangle. */ | ||
912 | input->left += (input->width - width) / 2; | ||
913 | input->top += (input->height - height) / 2; | ||
914 | input->width = width; | ||
915 | input->height = height; | ||
871 | } | 916 | } |
872 | 917 | ||
873 | /* | 918 | /* |
diff --git a/drivers/media/video/omap3isp/ispstat.h b/drivers/media/video/omap3isp/ispstat.h index 820950c9ef46..d86da94fa50d 100644 --- a/drivers/media/video/omap3isp/ispstat.h +++ b/drivers/media/video/omap3isp/ispstat.h | |||
@@ -131,9 +131,9 @@ struct ispstat { | |||
131 | struct ispstat_generic_config { | 131 | struct ispstat_generic_config { |
132 | /* | 132 | /* |
133 | * Fields must be in the same order as in: | 133 | * Fields must be in the same order as in: |
134 | * - isph3a_aewb_config | 134 | * - omap3isp_h3a_aewb_config |
135 | * - isph3a_af_config | 135 | * - omap3isp_h3a_af_config |
136 | * - isphist_config | 136 | * - omap3isp_hist_config |
137 | */ | 137 | */ |
138 | u32 buf_size; | 138 | u32 buf_size; |
139 | u16 config_counter; | 139 | u16 config_counter; |
diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c index 208a7ec739d7..9cd8f1aa567b 100644 --- a/drivers/media/video/omap3isp/ispvideo.c +++ b/drivers/media/video/omap3isp/ispvideo.c | |||
@@ -47,29 +47,59 @@ | |||
47 | 47 | ||
48 | static struct isp_format_info formats[] = { | 48 | static struct isp_format_info formats[] = { |
49 | { V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8, | 49 | { V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8, |
50 | V4L2_MBUS_FMT_Y8_1X8, V4L2_PIX_FMT_GREY, 8, }, | 50 | V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8, |
51 | V4L2_PIX_FMT_GREY, 8, }, | ||
52 | { V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y10_1X10, | ||
53 | V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y8_1X8, | ||
54 | V4L2_PIX_FMT_Y10, 10, }, | ||
55 | { V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y10_1X10, | ||
56 | V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y8_1X8, | ||
57 | V4L2_PIX_FMT_Y12, 12, }, | ||
58 | { V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8, | ||
59 | V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8, | ||
60 | V4L2_PIX_FMT_SBGGR8, 8, }, | ||
61 | { V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8, | ||
62 | V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8, | ||
63 | V4L2_PIX_FMT_SGBRG8, 8, }, | ||
64 | { V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8, | ||
65 | V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8, | ||
66 | V4L2_PIX_FMT_SGRBG8, 8, }, | ||
67 | { V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8, | ||
68 | V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8, | ||
69 | V4L2_PIX_FMT_SRGGB8, 8, }, | ||
51 | { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, | 70 | { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, |
52 | V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10DPCM8, 8, }, | 71 | V4L2_MBUS_FMT_SGRBG10_1X10, 0, |
72 | V4L2_PIX_FMT_SGRBG10DPCM8, 8, }, | ||
53 | { V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10, | 73 | { V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10, |
54 | V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10, 10, }, | 74 | V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR8_1X8, |
75 | V4L2_PIX_FMT_SBGGR10, 10, }, | ||
55 | { V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG10_1X10, | 76 | { V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG10_1X10, |
56 | V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10, 10, }, | 77 | V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG8_1X8, |
78 | V4L2_PIX_FMT_SGBRG10, 10, }, | ||
57 | { V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG10_1X10, | 79 | { V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG10_1X10, |
58 | V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10, 10, }, | 80 | V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG8_1X8, |
81 | V4L2_PIX_FMT_SGRBG10, 10, }, | ||
59 | { V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB10_1X10, | 82 | { V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB10_1X10, |
60 | V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10, 10, }, | 83 | V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB8_1X8, |
84 | V4L2_PIX_FMT_SRGGB10, 10, }, | ||
61 | { V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR10_1X10, | 85 | { V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR10_1X10, |
62 | V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12, 12, }, | 86 | V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR8_1X8, |
87 | V4L2_PIX_FMT_SBGGR12, 12, }, | ||
63 | { V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG10_1X10, | 88 | { V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG10_1X10, |
64 | V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12, 12, }, | 89 | V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG8_1X8, |
90 | V4L2_PIX_FMT_SGBRG12, 12, }, | ||
65 | { V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG10_1X10, | 91 | { V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG10_1X10, |
66 | V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12, 12, }, | 92 | V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG8_1X8, |
93 | V4L2_PIX_FMT_SGRBG12, 12, }, | ||
67 | { V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB10_1X10, | 94 | { V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB10_1X10, |
68 | V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12, 12, }, | 95 | V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB8_1X8, |
96 | V4L2_PIX_FMT_SRGGB12, 12, }, | ||
69 | { V4L2_MBUS_FMT_UYVY8_1X16, V4L2_MBUS_FMT_UYVY8_1X16, | 97 | { V4L2_MBUS_FMT_UYVY8_1X16, V4L2_MBUS_FMT_UYVY8_1X16, |
70 | V4L2_MBUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 16, }, | 98 | V4L2_MBUS_FMT_UYVY8_1X16, 0, |
99 | V4L2_PIX_FMT_UYVY, 16, }, | ||
71 | { V4L2_MBUS_FMT_YUYV8_1X16, V4L2_MBUS_FMT_YUYV8_1X16, | 100 | { V4L2_MBUS_FMT_YUYV8_1X16, V4L2_MBUS_FMT_YUYV8_1X16, |
72 | V4L2_MBUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 16, }, | 101 | V4L2_MBUS_FMT_YUYV8_1X16, 0, |
102 | V4L2_PIX_FMT_YUYV, 16, }, | ||
73 | }; | 103 | }; |
74 | 104 | ||
75 | const struct isp_format_info * | 105 | const struct isp_format_info * |
@@ -86,6 +116,37 @@ omap3isp_video_format_info(enum v4l2_mbus_pixelcode code) | |||
86 | } | 116 | } |
87 | 117 | ||
88 | /* | 118 | /* |
119 | * Decide whether desired output pixel code can be obtained with | ||
120 | * the lane shifter by shifting the input pixel code. | ||
121 | * @in: input pixelcode to shifter | ||
122 | * @out: output pixelcode from shifter | ||
123 | * @additional_shift: # of bits the sensor's LSB is offset from CAMEXT[0] | ||
124 | * | ||
125 | * return true if the combination is possible | ||
126 | * return false otherwise | ||
127 | */ | ||
128 | static bool isp_video_is_shiftable(enum v4l2_mbus_pixelcode in, | ||
129 | enum v4l2_mbus_pixelcode out, | ||
130 | unsigned int additional_shift) | ||
131 | { | ||
132 | const struct isp_format_info *in_info, *out_info; | ||
133 | |||
134 | if (in == out) | ||
135 | return true; | ||
136 | |||
137 | in_info = omap3isp_video_format_info(in); | ||
138 | out_info = omap3isp_video_format_info(out); | ||
139 | |||
140 | if ((in_info->flavor == 0) || (out_info->flavor == 0)) | ||
141 | return false; | ||
142 | |||
143 | if (in_info->flavor != out_info->flavor) | ||
144 | return false; | ||
145 | |||
146 | return in_info->bpp - out_info->bpp + additional_shift <= 6; | ||
147 | } | ||
148 | |||
149 | /* | ||
89 | * isp_video_mbus_to_pix - Convert v4l2_mbus_framefmt to v4l2_pix_format | 150 | * isp_video_mbus_to_pix - Convert v4l2_mbus_framefmt to v4l2_pix_format |
90 | * @video: ISP video instance | 151 | * @video: ISP video instance |
91 | * @mbus: v4l2_mbus_framefmt format (input) | 152 | * @mbus: v4l2_mbus_framefmt format (input) |
@@ -235,6 +296,7 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe) | |||
235 | return -EPIPE; | 296 | return -EPIPE; |
236 | 297 | ||
237 | while (1) { | 298 | while (1) { |
299 | unsigned int shifter_link; | ||
238 | /* Retrieve the sink format */ | 300 | /* Retrieve the sink format */ |
239 | pad = &subdev->entity.pads[0]; | 301 | pad = &subdev->entity.pads[0]; |
240 | if (!(pad->flags & MEDIA_PAD_FL_SINK)) | 302 | if (!(pad->flags & MEDIA_PAD_FL_SINK)) |
@@ -263,6 +325,10 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe) | |||
263 | return -ENOSPC; | 325 | return -ENOSPC; |
264 | } | 326 | } |
265 | 327 | ||
328 | /* If sink pad is on CCDC, the link has the lane shifter | ||
329 | * in the middle of it. */ | ||
330 | shifter_link = subdev == &isp->isp_ccdc.subdev; | ||
331 | |||
266 | /* Retrieve the source format */ | 332 | /* Retrieve the source format */ |
267 | pad = media_entity_remote_source(pad); | 333 | pad = media_entity_remote_source(pad); |
268 | if (pad == NULL || | 334 | if (pad == NULL || |
@@ -278,10 +344,24 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe) | |||
278 | return -EPIPE; | 344 | return -EPIPE; |
279 | 345 | ||
280 | /* Check if the two ends match */ | 346 | /* Check if the two ends match */ |
281 | if (fmt_source.format.code != fmt_sink.format.code || | 347 | if (fmt_source.format.width != fmt_sink.format.width || |
282 | fmt_source.format.width != fmt_sink.format.width || | ||
283 | fmt_source.format.height != fmt_sink.format.height) | 348 | fmt_source.format.height != fmt_sink.format.height) |
284 | return -EPIPE; | 349 | return -EPIPE; |
350 | |||
351 | if (shifter_link) { | ||
352 | unsigned int parallel_shift = 0; | ||
353 | if (isp->isp_ccdc.input == CCDC_INPUT_PARALLEL) { | ||
354 | struct isp_parallel_platform_data *pdata = | ||
355 | &((struct isp_v4l2_subdevs_group *) | ||
356 | subdev->host_priv)->bus.parallel; | ||
357 | parallel_shift = pdata->data_lane_shift * 2; | ||
358 | } | ||
359 | if (!isp_video_is_shiftable(fmt_source.format.code, | ||
360 | fmt_sink.format.code, | ||
361 | parallel_shift)) | ||
362 | return -EPIPE; | ||
363 | } else if (fmt_source.format.code != fmt_sink.format.code) | ||
364 | return -EPIPE; | ||
285 | } | 365 | } |
286 | 366 | ||
287 | return 0; | 367 | return 0; |
diff --git a/drivers/media/video/omap3isp/ispvideo.h b/drivers/media/video/omap3isp/ispvideo.h index 524a1acd0906..911bea64e78a 100644 --- a/drivers/media/video/omap3isp/ispvideo.h +++ b/drivers/media/video/omap3isp/ispvideo.h | |||
@@ -49,6 +49,8 @@ struct v4l2_pix_format; | |||
49 | * bits. Identical to @code if the format is 10 bits wide or less. | 49 | * bits. Identical to @code if the format is 10 bits wide or less. |
50 | * @uncompressed: V4L2 media bus format code for the corresponding uncompressed | 50 | * @uncompressed: V4L2 media bus format code for the corresponding uncompressed |
51 | * format. Identical to @code if the format is not DPCM compressed. | 51 | * format. Identical to @code if the format is not DPCM compressed. |
52 | * @flavor: V4L2 media bus format code for the same pixel layout but | ||
53 | * shifted to be 8 bits per pixel. =0 if format is not shiftable. | ||
52 | * @pixelformat: V4L2 pixel format FCC identifier | 54 | * @pixelformat: V4L2 pixel format FCC identifier |
53 | * @bpp: Bits per pixel | 55 | * @bpp: Bits per pixel |
54 | */ | 56 | */ |
@@ -56,6 +58,7 @@ struct isp_format_info { | |||
56 | enum v4l2_mbus_pixelcode code; | 58 | enum v4l2_mbus_pixelcode code; |
57 | enum v4l2_mbus_pixelcode truncated; | 59 | enum v4l2_mbus_pixelcode truncated; |
58 | enum v4l2_mbus_pixelcode uncompressed; | 60 | enum v4l2_mbus_pixelcode uncompressed; |
61 | enum v4l2_mbus_pixelcode flavor; | ||
59 | u32 pixelformat; | 62 | u32 pixelformat; |
60 | unsigned int bpp; | 63 | unsigned int bpp; |
61 | }; | 64 | }; |