static void isp_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 = isp_csi2_ctx_map_format(csi2); isp_csi2_ctx_config(isp, csi2, ctx); isp_csi2_ctx_enable(isp, csi2, n, 1); } return; } if (csi2->output & CSI2_OUTPUT_MEMORY) isp_csi2_isr_buffer(csi2); }
/* * csi2_irq_ctx_set - Enables CSI2 Context IRQs. * @enable: Enable/disable CSI2 Context interrupts */ static void csi2_irq_ctx_set(struct isp_device *isp, struct isp_csi2_device *csi2, int enable) { int i; for (i = 0; i < 8; i++) { isp_reg_writel(isp, ISPCSI2_CTX_IRQSTATUS_FE_IRQ, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(i)); if (enable) isp_reg_set(isp, csi2->regs1, ISPCSI2_CTX_IRQENABLE(i), ISPCSI2_CTX_IRQSTATUS_FE_IRQ); else isp_reg_clr(isp, csi2->regs1, ISPCSI2_CTX_IRQENABLE(i), ISPCSI2_CTX_IRQSTATUS_FE_IRQ); } }
/* * isp_csi2_irq_ctx_set - Enables CSI2 Context IRQs. * @enable: Enable/disable CSI2 Context interrupts */ static void isp_csi2_irq_ctx_set(struct isp_device *isp, struct isp_csi2_device *csi2, int enable) { u32 reg = ISPCSI2_CTX_IRQSTATUS_FE_IRQ; int i; if (csi2->use_fs_irq) reg |= ISPCSI2_CTX_IRQSTATUS_FS_IRQ; for (i = 0; i < 8; i++) { isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(i)); if (enable) isp_reg_set(isp, csi2->regs1, ISPCSI2_CTX_IRQENABLE(i), reg); else isp_reg_clr(isp, csi2->regs1, ISPCSI2_CTX_IRQENABLE(i), reg); } }