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); }
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; }