/* To set the format on the CSI2 requires a mapping function that takes * the following inputs: * - 3 different formats (at this time) * - 2 destinations (mem, vp+mem) (vp only handled separately) * - 2 decompression options (on, off) * - 2 isp revisions (certain format must be handled differently on OMAP3630) * Output should be CSI2 frame format code * Array indices as follows: [format][dest][decompr][is_3630] * Not all combinations are valid. 0 means invalid.
*/ staticconst u16 __csi2_fmt_map[3][2][2][2] = { /* RAW10 formats */
{ /* Output to memory */
{ /* No DPCM decompression */
{ CSI2_PIX_FMT_RAW10_EXP16, CSI2_PIX_FMT_RAW10_EXP16 }, /* DPCM decompression */
{ 0, 0 },
}, /* Output to both */
{ /* No DPCM decompression */
{ CSI2_PIX_FMT_RAW10_EXP16_VP,
CSI2_PIX_FMT_RAW10_EXP16_VP }, /* DPCM decompression */
{ 0, 0 },
},
}, /* RAW10 DPCM8 formats */
{ /* Output to memory */
{ /* No DPCM decompression */
{ CSI2_PIX_FMT_RAW8, CSI2_USERDEF_8BIT_DATA1 }, /* DPCM decompression */
{ CSI2_PIX_FMT_RAW8_DPCM10_EXP16,
CSI2_USERDEF_8BIT_DATA1_DPCM10 },
}, /* Output to both */
{ /* No DPCM decompression */
{ CSI2_PIX_FMT_RAW8_VP,
CSI2_PIX_FMT_RAW8_VP }, /* DPCM decompression */
{ CSI2_PIX_FMT_RAW8_DPCM10_VP,
CSI2_USERDEF_8BIT_DATA1_DPCM10_VP },
},
}, /* YUYV8 2X8 formats */
{ /* Output to memory */
{ /* No DPCM decompression */
{ CSI2_PIX_FMT_YUV422_8BIT,
CSI2_PIX_FMT_YUV422_8BIT }, /* DPCM decompression */
{ 0, 0 },
}, /* Output to both */
{ /* No DPCM decompression */
{ CSI2_PIX_FMT_YUV422_8BIT_VP,
CSI2_PIX_FMT_YUV422_8BIT_VP }, /* DPCM decompression */
{ 0, 0 },
},
},
};
/* * csi2_ctx_map_format - Map CSI2 sink media bus format to CSI2 format ID * @csi2: ISP CSI2 device * * Returns CSI2 physical format id
*/ static u16 csi2_ctx_map_format(struct isp_csi2_device *csi2)
{ conststruct v4l2_mbus_framefmt *fmt = &csi2->formats[CSI2_PAD_SINK]; int fmtidx, destidx, is_3630;
switch (fmt->code) { case MEDIA_BUS_FMT_SGRBG10_1X10: case MEDIA_BUS_FMT_SRGGB10_1X10: case MEDIA_BUS_FMT_SBGGR10_1X10: case MEDIA_BUS_FMT_SGBRG10_1X10:
fmtidx = 0; break; case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8: case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8: case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8: case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8:
fmtidx = 1; break; case MEDIA_BUS_FMT_YUYV8_2X8:
fmtidx = 2; break; default:
WARN(1, KERN_ERR "CSI2: pixel format %08x unsupported!\n",
fmt->code); return 0;
}
if (!(csi2->output & CSI2_OUTPUT_CCDC) &&
!(csi2->output & CSI2_OUTPUT_MEMORY)) { /* Neither output enabled is a valid combination */ return CSI2_PIX_FMT_OTHERS;
}
/* If we need to skip frames at the beginning of the stream disable the * video port to avoid sending the skipped frames to the CCDC.
*/
destidx = csi2->frame_skip ? 0 : !!(csi2->output & CSI2_OUTPUT_CCDC);
is_3630 = csi2->isp->revision == ISP_REVISION_15_0;
/* * csi2_set_outaddr - Set memory address to save output image * @csi2: Pointer to ISP CSI2a device. * @addr: ISP MMU Mapped 32-bit memory address aligned on 32 byte boundary. * * Sets the memory address where the output will be saved. * * Returns 0 if successful, or -EINVAL if the address is not in the 32 byte * boundary.
*/ staticvoid csi2_set_outaddr(struct isp_csi2_device *csi2, u32 addr)
{ struct isp_device *isp = csi2->isp; struct isp_csi2_ctx_cfg *ctx = &csi2->contexts[0];
/* * omap3isp_csi2_reset - Resets the CSI2 module. * * Must be called with the phy lock held. * * Returns 0 if successful, or -EBUSY if power command didn't respond.
*/ int omap3isp_csi2_reset(struct isp_csi2_device *csi2)
{ struct isp_device *isp = csi2->isp;
u8 soft_reset_retries = 0;
u32 reg; int i;
/* * CSI2 fields that can be updated while the context has * been enabled or the interface has been enabled are not * updated dynamically currently. So we do not allow to * reconfigure if either has been enabled
*/ if (csi2->contexts[0].enabled || csi2->ctrl.if_enable) return -EBUSY;
pad = media_pad_remote_pad_first(&csi2->pads[CSI2_PAD_SINK]);
sensor = media_entity_to_v4l2_subdev(pad->entity);
buscfg = v4l2_subdev_to_bus_cfg(pipe->external); if (WARN_ON(!buscfg)) return -EPIPE;
/* * The CSI2 receiver can't do any format conversion except DPCM * decompression, so every set_format call configures both pads * and enables DPCM decompression as a special case:
*/ if (csi2->formats[CSI2_PAD_SINK].code !=
csi2->formats[CSI2_PAD_SOURCE].code)
csi2->dpcm_decompress = true; else
csi2->dpcm_decompress = false;
/* * Enable end of frame and end of line signals generation for * context 0. These signals are generated from CSI2 receiver to * qualify the last pixel of a frame and the last pixel of a line. * Without enabling the signals CSI2 receiver writes data to memory * beyond buffer size and/or data line offset is not handled correctly.
*/
csi2->contexts[0].eof_enabled = 1;
csi2->contexts[0].eol_enabled = 1;
status = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n));
isp_reg_writel(isp, status, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n));
if (!(status & ISPCSI2_CTX_IRQSTATUS_FE_IRQ)) return;
/* Skip interrupts until we reach the frame skip count. The CSI2 will be * automatically disabled, as the frame skip count has been programmed * in the CSI2_CTx_CTRL1::COUNT field, so re-enable it. * * It would have been nice to rely on the FRAME_NUMBER interrupt instead * but it turned out that the interrupt is only generated when the CSI2 * writes to memory (the CSI2_CTx_CTRL1::COUNT field is decreased * correctly and reaches 0 when data is forwarded to the video port only * but no interrupt arrives). Maybe a CSI2 hardware bug.
*/ if (csi2->frame_skip) {
csi2->frame_skip--; if (csi2->frame_skip == 0) {
ctx->format_id = csi2_ctx_map_format(csi2);
csi2_ctx_config(isp, csi2, ctx);
csi2_ctx_enable(isp, csi2, n, 1);
} return;
}
if (csi2->output & CSI2_OUTPUT_MEMORY)
csi2_isr_buffer(csi2);
}
if (omap3isp_module_sync_is_stopping(&csi2->wait, &csi2->stopping)) return;
/* Successful cases */ if (csi2_irqstatus & ISPCSI2_IRQSTATUS_CONTEXT(0))
csi2_isr_ctx(csi2, &csi2->contexts[0]);
if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ)
dev_dbg(isp->dev, "CSI2: ECC correction done\n");
}
/* ----------------------------------------------------------------------------- * ISP video operations
*/
/* * csi2_queue - Queues the first buffer when using memory output * @video: The video node * @buffer: buffer to queue
*/ staticint csi2_queue(struct isp_video *video, struct isp_buffer *buffer)
{ struct isp_device *isp = video->isp; struct isp_csi2_device *csi2 = &isp->isp_csi2a;
csi2_set_outaddr(csi2, buffer->dma);
/* * If streaming was enabled before there was a buffer queued * or underrun happened in the ISR, the hardware was not enabled * and DMA queue flag ISP_VIDEO_DMAQUEUE_UNDERRUN is still set. * Enable it now.
*/ if (csi2->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_UNDERRUN) { /* Enable / disable context 0 and IRQs */
csi2_if_enable(isp, csi2, 1);
csi2_ctx_enable(isp, csi2, 0, 1);
isp_video_dmaqueue_flags_clr(&csi2->video_out);
}
switch (pad) { case CSI2_PAD_SINK: /* Clamp the width and height to valid range (1-8191). */ for (i = 0; i < ARRAY_SIZE(csi2_input_fmts); i++) { if (fmt->code == csi2_input_fmts[i]) break;
}
/* If not found, use SGRBG10 as default */ if (i >= ARRAY_SIZE(csi2_input_fmts))
fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
case CSI2_PAD_SOURCE: /* Source format same as sink format, except for DPCM * compression.
*/
pixelcode = fmt->code;
format = __csi2_get_format(csi2, sd_state, CSI2_PAD_SINK,
which);
memcpy(fmt, format, sizeof(*fmt));
/* * Only Allow DPCM decompression, and check that the * pattern is preserved
*/
info = omap3isp_video_format_info(fmt->code); if (info->uncompressed == pixelcode)
fmt->code = pixelcode; break;
}
/* Propagate the format from sink to source */ if (fmt->pad == CSI2_PAD_SINK) {
format = __csi2_get_format(csi2, sd_state, CSI2_PAD_SOURCE,
fmt->which);
*format = fmt->format;
csi2_try_format(csi2, sd_state, CSI2_PAD_SOURCE, format,
fmt->which);
}
return 0;
}
/* * csi2_init_formats - Initialize formats on all pads * @sd: ISP CSI2 V4L2 subdevice * @fh: V4L2 subdev file handle * * Initialize all pad formats with default values. If fh is not NULL, try * formats are initialized on the file handle. Otherwise active formats are * initialized on the device.
*/ staticint csi2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{ struct v4l2_subdev_format format;
/* * csi2_set_stream - Enable/Disable streaming on the CSI2 module * @sd: ISP CSI2 V4L2 subdevice * @enable: ISP pipeline stream state * * Return 0 on success or a negative error code otherwise.
*/ staticint csi2_set_stream(struct v4l2_subdev *sd, int enable)
{ struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); struct isp_device *isp = csi2->isp; struct isp_video *video_out = &csi2->video_out;
switch (enable) { case ISP_PIPELINE_STREAM_CONTINUOUS: if (omap3isp_csiphy_acquire(csi2->phy, &sd->entity) < 0) return -ENODEV; if (csi2->output & CSI2_OUTPUT_MEMORY)
omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CSI2A_WRITE);
csi2_configure(csi2);
csi2_print_status(csi2);
/* * When outputting to memory with no buffer available, let the * buffer queue handler start the hardware. A DMA queue flag * ISP_VIDEO_DMAQUEUE_QUEUED will be set as soon as there is * a buffer available.
*/ if (csi2->output & CSI2_OUTPUT_MEMORY &&
!(video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED)) break; /* Enable context 0 and IRQs */
atomic_set(&csi2->stopping, 0);
csi2_ctx_enable(isp, csi2, 0, 1);
csi2_if_enable(isp, csi2, 1);
isp_video_dmaqueue_flags_clr(video_out); break;
int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2, struct v4l2_device *vdev)
{ int ret;
/* Register the subdev and video nodes. */
csi2->subdev.dev = vdev->mdev->dev;
ret = v4l2_device_register_subdev(vdev, &csi2->subdev); if (ret < 0) goto error;
ret = omap3isp_video_register(&csi2->video_out, vdev); if (ret < 0) goto error;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.