static void csi2_isr_ctx(struct isp_csi2_device *csi2,
			 struct isp_csi2_ctx_cfg *ctx)
{
	struct isp_device *isp = csi2->isp;
	unsigned int n = ctx->ctxnum;
	u32 status;

	status = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n));
	isp_reg_writel(isp, status, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n));

	/* Propagate frame number */
	if (status & ISPCSI2_CTX_IRQSTATUS_FS_IRQ) {
		struct isp_pipeline *pipe =
				     to_isp_pipeline(&csi2->subdev.entity);
		if (pipe->do_propagation)
			atomic_inc(&pipe->frame_number);
	}

	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 reenable 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);
}
Esempio n. 2
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;
}