Commit 9de7af4d authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Mauro Carvalho Chehab

[media] omap3isp: ccdc: Add support for BT.656 YUV format at the CCDC input

Query the CCDC input media bus type from the subdev connected to the
CCDC sink pad and configure the CCDC accordingly to support BT.656
synchronization.
Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Tested-by: default avatarEnrico Butera <ebutera@users.sourceforge.net>
Acked-by: default avatarSakari Ailus <sakari.ailus@iki.fi>
Signed-off-by: default avatarMauro Carvalho Chehab <m.chehab@samsung.com>
parent bcb4e0ef
...@@ -970,9 +970,15 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc, ...@@ -970,9 +970,15 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc,
if (format->code == V4L2_MBUS_FMT_YUYV8_2X8 || if (format->code == V4L2_MBUS_FMT_YUYV8_2X8 ||
format->code == V4L2_MBUS_FMT_UYVY8_2X8) { format->code == V4L2_MBUS_FMT_UYVY8_2X8) {
/* The bridge is enabled for YUV8 formats. Configure the input /* According to the OMAP3 TRM the input mode only affects SYNC
* mode accordingly. * mode, enabling BT.656 mode should take precedence. However,
*/ * in practice setting the input mode to YCbCr data on 8 bits
* seems to be required in BT.656 mode. In SYNC mode set it to
* YCbCr on 16 bits as the bridge is enabled in that case.
*/
if (ccdc->bt656)
syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR8;
else
syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR16; syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR16;
} }
...@@ -997,7 +1003,10 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc, ...@@ -997,7 +1003,10 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc,
if (pdata && pdata->hs_pol) if (pdata && pdata->hs_pol)
syn_mode |= ISPCCDC_SYN_MODE_HDPOL; syn_mode |= ISPCCDC_SYN_MODE_HDPOL;
if (pdata && pdata->vs_pol) /* The polarity of the vertical sync signal output by the BT.656
* decoder is not documented and seems to be active low.
*/
if ((pdata && pdata->vs_pol) || ccdc->bt656)
syn_mode |= ISPCCDC_SYN_MODE_VDPOL; syn_mode |= ISPCCDC_SYN_MODE_VDPOL;
if (pdata && pdata->fld_pol) if (pdata && pdata->fld_pol)
...@@ -1015,8 +1024,16 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc, ...@@ -1015,8 +1024,16 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc,
isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG, isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
ISPCCDC_CFG_Y8POS); ISPCCDC_CFG_Y8POS);
/* Enable or disable BT.656 mode, including error correction for the
* synchronization codes.
*/
if (ccdc->bt656)
isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF,
ISPCCDC_REC656IF_R656ON | ISPCCDC_REC656IF_ECCFVH);
else
isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF, isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF,
ISPCCDC_REC656IF_R656ON); ISPCCDC_REC656IF_R656ON | ISPCCDC_REC656IF_ECCFVH);
} }
/* CCDC formats descriptions */ /* CCDC formats descriptions */
...@@ -1107,20 +1124,32 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) ...@@ -1107,20 +1124,32 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
unsigned long flags; unsigned long flags;
unsigned int bridge; unsigned int bridge;
unsigned int shift; unsigned int shift;
unsigned int nph;
unsigned int sph;
u32 syn_mode; u32 syn_mode;
u32 ccdc_pattern; u32 ccdc_pattern;
ccdc->bt656 = false;
pad = media_entity_remote_pad(&ccdc->pads[CCDC_PAD_SINK]); pad = media_entity_remote_pad(&ccdc->pads[CCDC_PAD_SINK]);
sensor = media_entity_to_v4l2_subdev(pad->entity); sensor = media_entity_to_v4l2_subdev(pad->entity);
if (ccdc->input == CCDC_INPUT_PARALLEL) if (ccdc->input == CCDC_INPUT_PARALLEL) {
struct v4l2_mbus_config cfg;
int ret;
ret = v4l2_subdev_call(sensor, video, g_mbus_config, &cfg);
if (!ret)
ccdc->bt656 = cfg.type == V4L2_MBUS_BT656;
pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv) pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv)
->bus.parallel; ->bus.parallel;
}
/* CCDC_PAD_SINK */ /* CCDC_PAD_SINK */
format = &ccdc->formats[CCDC_PAD_SINK]; format = &ccdc->formats[CCDC_PAD_SINK];
/* Compute the lane shifter shift value and enable the bridge when the /* Compute the lane shifter shift value and enable the bridge when the
* input format is YUV. * input format is a non-BT.656 YUV variant.
*/ */
fmt_src.pad = pad->index; fmt_src.pad = pad->index;
fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE; fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE;
...@@ -1133,7 +1162,9 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) ...@@ -1133,7 +1162,9 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
depth_out = fmt_info->width; depth_out = fmt_info->width;
shift = depth_in - depth_out; shift = depth_in - depth_out;
if (fmt_info->code == V4L2_MBUS_FMT_YUYV8_2X8) if (ccdc->bt656)
bridge = ISPCTRL_PAR_BRIDGE_DISABLE;
else if (fmt_info->code == V4L2_MBUS_FMT_YUYV8_2X8)
bridge = ISPCTRL_PAR_BRIDGE_LENDIAN; bridge = ISPCTRL_PAR_BRIDGE_LENDIAN;
else if (fmt_info->code == V4L2_MBUS_FMT_UYVY8_2X8) else if (fmt_info->code == V4L2_MBUS_FMT_UYVY8_2X8)
bridge = ISPCTRL_PAR_BRIDGE_BENDIAN; bridge = ISPCTRL_PAR_BRIDGE_BENDIAN;
...@@ -1194,10 +1225,24 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) ...@@ -1194,10 +1225,24 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
format = &ccdc->formats[CCDC_PAD_SOURCE_OF]; format = &ccdc->formats[CCDC_PAD_SOURCE_OF];
crop = &ccdc->crop; crop = &ccdc->crop;
isp_reg_writel(isp, (crop->left << ISPCCDC_HORZ_INFO_SPH_SHIFT) | /* The horizontal coordinates are expressed in pixel clock cycles. We
((crop->width - 1) << ISPCCDC_HORZ_INFO_NPH_SHIFT), * need two cycles per pixel in BT.656 mode, and one cycle per pixel in
* SYNC mode regardless of the format as the bridge is enabled for YUV
* formats in that case.
*/
if (ccdc->bt656) {
sph = crop->left * 2;
nph = crop->width * 2 - 1;
} else {
sph = crop->left;
nph = crop->width - 1;
}
isp_reg_writel(isp, (sph << ISPCCDC_HORZ_INFO_SPH_SHIFT) |
(nph << ISPCCDC_HORZ_INFO_NPH_SHIFT),
OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO); OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO);
isp_reg_writel(isp, crop->top << ISPCCDC_VERT_START_SLV0_SHIFT, isp_reg_writel(isp, (crop->top << ISPCCDC_VERT_START_SLV0_SHIFT) |
(crop->top << ISPCCDC_VERT_START_SLV1_SHIFT),
OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_START); OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_START);
isp_reg_writel(isp, (crop->height - 1) isp_reg_writel(isp, (crop->height - 1)
<< ISPCCDC_VERT_LINES_NLV_SHIFT, << ISPCCDC_VERT_LINES_NLV_SHIFT,
...@@ -1225,8 +1270,11 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) ...@@ -1225,8 +1270,11 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG, isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
ISPCCDC_CFG_BSWD); ISPCCDC_CFG_BSWD);
/* Use PACK8 mode for 1byte per pixel formats. */ /* Use PACK8 mode for 1byte per pixel formats. Check for BT.656 mode
if (omap3isp_video_format_info(format->code)->width <= 8) * explicitly as the driver reports 1X16 instead of 2X8 at the OF pad
* for simplicity.
*/
if (omap3isp_video_format_info(format->code)->width <= 8 || ccdc->bt656)
syn_mode |= ISPCCDC_SYN_MODE_PACK8; syn_mode |= ISPCCDC_SYN_MODE_PACK8;
else else
syn_mode &= ~ISPCCDC_SYN_MODE_PACK8; syn_mode &= ~ISPCCDC_SYN_MODE_PACK8;
...@@ -1598,6 +1646,16 @@ static void ccdc_vd1_isr(struct isp_ccdc_device *ccdc) ...@@ -1598,6 +1646,16 @@ static void ccdc_vd1_isr(struct isp_ccdc_device *ccdc)
{ {
unsigned long flags; unsigned long flags;
/* In BT.656 mode the CCDC doesn't generate an HS/VS interrupt. We thus
* need to increment the frame counter here.
*/
if (ccdc->bt656) {
struct isp_pipeline *pipe =
to_isp_pipeline(&ccdc->subdev.entity);
atomic_inc(&pipe->frame_number);
}
spin_lock_irqsave(&ccdc->lsc.req_lock, flags); spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
/* /*
...@@ -1885,8 +1943,12 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, ...@@ -1885,8 +1943,12 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
field = fmt->field; field = fmt->field;
*fmt = *__ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which); *fmt = *__ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which);
/* YUV formats are converted from 2X8 to 1X16 by the bridge and /* In SYNC mode the bridge converts YUV formats from 2X8 to
* can be byte-swapped. * 1X16. In BT.656 no such conversion occurs. As we don't know
* at this point whether the source will use SYNC or BT.656 mode
* let's pretend the conversion always occurs. The CCDC will be
* configured to pack bytes in BT.656, hiding the inaccuracy.
* In all cases bytes can be swapped.
*/ */
if (fmt->code == V4L2_MBUS_FMT_YUYV8_2X8 || if (fmt->code == V4L2_MBUS_FMT_YUYV8_2X8 ||
fmt->code == V4L2_MBUS_FMT_UYVY8_2X8) { fmt->code == V4L2_MBUS_FMT_UYVY8_2X8) {
......
...@@ -113,6 +113,7 @@ struct ispccdc_lsc { ...@@ -113,6 +113,7 @@ struct ispccdc_lsc {
* @lsc: Lens shading compensation configuration * @lsc: Lens shading compensation configuration
* @update: Bitmask of controls to update during the next interrupt * @update: Bitmask of controls to update during the next interrupt
* @shadow_update: Controls update in progress by userspace * @shadow_update: Controls update in progress by userspace
* @bt656: Whether the input interface uses BT.656 synchronization
* @underrun: A buffer underrun occurred and a new buffer has been queued * @underrun: A buffer underrun occurred and a new buffer has been queued
* @state: Streaming state * @state: Streaming state
* @lock: Serializes shadow_update with interrupt handler * @lock: Serializes shadow_update with interrupt handler
...@@ -141,6 +142,7 @@ struct isp_ccdc_device { ...@@ -141,6 +142,7 @@ struct isp_ccdc_device {
unsigned int update; unsigned int update;
unsigned int shadow_update; unsigned int shadow_update;
bool bt656;
unsigned int underrun:1; unsigned int underrun:1;
enum isp_pipeline_stream_state state; enum isp_pipeline_stream_state state;
spinlock_t lock; spinlock_t lock;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment