/* * csi2_set_stream - Enable/Disable streaming on the CSI2 module * @sd: ISS CSI2 V4L2 subdevice * @enable: ISS pipeline stream state * * Return 0 on success or a negative error code otherwise. */ static int csi2_set_stream(struct v4l2_subdev *sd, int enable) { struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd); struct iss_device *iss = csi2->iss; struct iss_pipeline *pipe = to_iss_pipeline(&csi2->subdev.entity); struct iss_video *video_out = &csi2->video_out; if (csi2->state == ISS_PIPELINE_STREAM_STOPPED) { if (enable == ISS_PIPELINE_STREAM_STOPPED) return 0; omap4iss_subclk_enable(iss, OMAP4_ISS_SUBCLK_CSI2_A); } switch (enable) { case ISS_PIPELINE_STREAM_CONTINUOUS: if (omap4iss_csiphy_acquire(csi2->phy) < 0) return -ENODEV; csi2->use_fs_irq = pipe->do_propagation; 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 * ISS_VIDEO_DMAQUEUE_QUEUED will be set as soon as there is * a buffer available. */ if (csi2->output & CSI2_OUTPUT_MEMORY && !(video_out->dmaqueue_flags & ISS_VIDEO_DMAQUEUE_QUEUED)) break; /* Enable context 0 and IRQs */ atomic_set(&csi2->stopping, 0); csi2_ctx_enable(csi2, 0, 1); csi2_if_enable(csi2, 1); iss_video_dmaqueue_flags_clr(video_out); break; case ISS_PIPELINE_STREAM_STOPPED: if (csi2->state == ISS_PIPELINE_STREAM_STOPPED) return 0; if (omap4iss_module_sync_idle(&sd->entity, &csi2->wait, &csi2->stopping)) dev_dbg(iss->dev, "%s: module stop timeout.\n", sd->name); csi2_ctx_enable(csi2, 0, 0); csi2_if_enable(csi2, 0); csi2_irq_ctx_set(csi2, 0); omap4iss_csiphy_release(csi2->phy); omap4iss_subclk_disable(iss, OMAP4_ISS_SUBCLK_CSI2_A); iss_video_dmaqueue_flags_clr(video_out); break; } csi2->state = enable; return 0; }
/* * 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. */ static int 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) < 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; case ISP_PIPELINE_STREAM_STOPPED: if (csi2->state == ISP_PIPELINE_STREAM_STOPPED) return 0; if (omap3isp_module_sync_idle(&sd->entity, &csi2->wait, &csi2->stopping)) dev_dbg(isp->dev, "%s: module stop timeout.\n", sd->name); csi2_ctx_enable(isp, csi2, 0, 0); csi2_if_enable(isp, csi2, 0); csi2_irq_ctx_set(isp, csi2, 0); omap3isp_csiphy_release(csi2->phy); isp_video_dmaqueue_flags_clr(video_out); omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_CSI2A_WRITE); break; } csi2->state = enable; return 0; }
static int csi2_configure(struct isp_csi2_device *csi2) { const struct isp_v4l2_subdevs_group *pdata; struct isp_device *isp = csi2->isp; struct isp_csi2_timing_cfg *timing = &csi2->timing[0]; struct v4l2_subdev *sensor; struct media_pad *pad; /* * 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_entity_remote_pad(&csi2->pads[CSI2_PAD_SINK]); sensor = media_entity_to_v4l2_subdev(pad->entity); pdata = sensor->host_priv; csi2->frame_skip = 0; v4l2_subdev_call(sensor, sensor, g_skip_frames, &csi2->frame_skip); csi2->ctrl.vp_out_ctrl = pdata->bus.csi2.vpclk_div; csi2->ctrl.frame_mode = ISP_CSI2_FRAME_IMMEDIATE; csi2->ctrl.ecc_enable = pdata->bus.csi2.crc; timing->ionum = 1; timing->force_rx_mode = 1; timing->stop_state_16x = 1; timing->stop_state_4x = 1; timing->stop_state_counter = 0x1FF; /* * 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; csi2->contexts[0].format_id = csi2_ctx_map_format(csi2); if (csi2->video_out.bpl_padding == 0) csi2->contexts[0].data_offset = 0; else csi2->contexts[0].data_offset = csi2->video_out.bpl_value; /* * 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; csi2_irq_complexio1_set(isp, csi2, 1); csi2_irq_ctx_set(isp, csi2, 1); csi2_irq_status_set(isp, csi2, 1); /* Set configuration (timings, format and links) */ csi2_timing_config(isp, csi2, timing); csi2_recv_config(isp, csi2, &csi2->ctrl); csi2_ctx_config(isp, csi2, &csi2->contexts[0]); return 0; }