static void hist_enable(struct ispstat *hist, int enable) { if (enable) { isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR, ISPHIST_PCR_ENABLE); isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, ISPCTRL_HIST_CLK_EN); } else { isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR, ISPHIST_PCR_ENABLE); isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, ISPCTRL_HIST_CLK_EN); } }
/* * ispccp2_if_enable - Enable CCP2 interface. * @ccp2: pointer to ISP CCP2 device * @enable: enable/disable flag */ static void ispccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable) { struct isp_device *isp = to_isp_device(ccp2); struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity); int i; if (enable && ccp2->vdds_csib) regulator_enable(ccp2->vdds_csib); /* Enable/Disable all the LCx channels */ for (i = 0; i < CCP2_LCx_CHANS_NUM; i++) isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(i), ISPCCP2_LCx_CTRL_CHAN_EN, enable ? ISPCCP2_LCx_CTRL_CHAN_EN : 0); /* Enable/Disable ccp2 interface in ccp2 mode */ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL, ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN, enable ? (ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN) : 0); /* For frame count propagation */ if (pipe->do_propagation) { /* We may want the Frame Start IRQ from LC0 */ if (enable) isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LC01_IRQENABLE, ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ); else isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LC01_IRQENABLE, ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ); } if (!enable && ccp2->vdds_csib) regulator_disable(ccp2->vdds_csib); }
static int hist_buf_pio(struct ispstat *hist) { struct isp_device *isp = hist->isp; u32 *buf = hist->active_buf->virt_addr; unsigned int i; if (!buf) { dev_dbg(isp->dev, "hist: invalid PIO buffer address\n"); hist_reset_mem(hist); return STAT_NO_BUF; } isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR); isp_reg_set(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR); for (i = hist->buf_size / 16; i > 0; i--) { *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); } isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR); return STAT_BUF_DONE; }
/* * hist_reset_mem - clear Histogram memory before start stats engine. */ static void hist_reset_mem(struct ispstat *hist) { struct isp_device *isp = hist->isp; struct omap3isp_hist_config *conf = hist->priv; unsigned int i; isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR); /* * By setting it, the histogram internal buffer is being cleared at the * same time it's being read. This bit must be cleared afterwards. */ isp_reg_set(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR); /* * We'll clear 4 words at each iteration for optimization. It avoids * 3/4 of the jumps. We also know HIST_MEM_SIZE is divisible by 4. */ for (i = OMAP3ISP_HIST_MEM_SIZE / 4; i > 0; i--) { isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); } isp_reg_clr(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR); hist->wait_acc_frames = conf->num_acc_frames; }
static int hist_buf_dma(struct ispstat *hist) { dma_addr_t dma_addr = hist->active_buf->dma_addr; struct dma_async_tx_descriptor *tx; struct dma_slave_config cfg; dma_cookie_t cookie; int ret; if (unlikely(!dma_addr)) { dev_dbg(hist->isp->dev, "hist: invalid DMA buffer address\n"); goto error; } isp_reg_writel(hist->isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR); isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR); omap3isp_flush(hist->isp); memset(&cfg, 0, sizeof(cfg)); cfg.src_addr = hist->isp->mmio_hist_base_phys + ISPHIST_DATA; cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; cfg.src_maxburst = hist->buf_size / 4; ret = dmaengine_slave_config(hist->dma_ch, &cfg); if (ret < 0) { dev_dbg(hist->isp->dev, "hist: DMA slave configuration failed\n"); goto error; } tx = dmaengine_prep_slave_single(hist->dma_ch, dma_addr, hist->buf_size, DMA_DEV_TO_MEM, DMA_CTRL_ACK); if (tx == NULL) { dev_dbg(hist->isp->dev, "hist: DMA slave preparation failed\n"); goto error; } tx->callback = hist_dma_cb; tx->callback_param = hist; cookie = tx->tx_submit(tx); if (dma_submit_error(cookie)) { dev_dbg(hist->isp->dev, "hist: DMA submission failed\n"); goto error; } dma_async_issue_pending(hist->dma_ch); return STAT_BUF_WAITING_DMA; error: hist_reset_mem(hist); return STAT_NO_BUF; }
static void hist_enable(struct ispstat *hist, int enable) { if (enable) { isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR, ISPHIST_PCR_ENABLE); omap3isp_subclk_enable(hist->isp, OMAP3_ISP_SUBCLK_HIST); } else { isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR, ISPHIST_PCR_ENABLE); omap3isp_subclk_disable(hist->isp, OMAP3_ISP_SUBCLK_HIST); } }
/* * 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); } }
/* * ispccp2_reset - Reset the CCP2 * @ccp2: pointer to ISP CCP2 device */ static void ispccp2_reset(struct isp_ccp2_device *ccp2) { struct isp_device *isp = to_isp_device(ccp2); int i = 0; /* Reset the CSI1/CCP2B and wait for reset to complete */ isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSCONFIG, ISPCCP2_SYSCONFIG_SOFT_RESET); while (!(isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSSTATUS) & ISPCCP2_SYSSTATUS_RESET_DONE)) { udelay(10); if (i++ > 10) { /* try read 10 times */ dev_warn(isp->dev, "omap3_isp: timeout waiting for ccp2 reset\n"); break; } } }
static void ccp2_reset(struct isp_ccp2_device *ccp2) { struct isp_device *isp = to_isp_device(ccp2); int i = 0; isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSCONFIG, ISPCCP2_SYSCONFIG_SOFT_RESET); while (!(isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSSTATUS) & ISPCCP2_SYSSTATUS_RESET_DONE)) { udelay(10); if (i++ > 10) { dev_warn(isp->dev, "omap3_isp: timeout waiting for ccp2 reset\n"); break; } } }
/* * 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); } }
static void hist_reset_mem(struct ispstat *hist) { struct isp_device *isp = hist->isp; struct omap3isp_hist_config *conf = hist->priv; unsigned int i; isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR); isp_reg_set(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR); for (i = OMAP3ISP_HIST_MEM_SIZE / 4; i > 0; i--) { isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); } isp_reg_clr(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR); hist->wait_acc_frames = conf->num_acc_frames; }
static int hist_buf_dma(struct ispstat *hist) { dma_addr_t dma_addr = hist->active_buf->dma_addr; if (unlikely(!dma_addr)) { dev_dbg(hist->isp->dev, "hist: invalid DMA buffer address\n"); hist_reset_mem(hist); return STAT_NO_BUF; } isp_reg_writel(hist->isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR); isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR); omap3isp_flush(hist->isp); hist->dma_config.dst_start = dma_addr; hist->dma_config.elem_count = hist->buf_size / sizeof(u32); omap_set_dma_params(hist->dma_ch, &hist->dma_config); omap_start_dma(hist->dma_ch); return STAT_BUF_WAITING_DMA; }
static int hist_buf_pio(struct ispstat *hist) { struct isp_device *isp = hist->isp; u32 *buf = hist->active_buf->virt_addr; unsigned int i; if (!buf) { dev_dbg(isp->dev, "hist: invalid PIO buffer address\n"); hist_reset_mem(hist); return STAT_NO_BUF; } isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR); /* * By setting it, the histogram internal buffer is being cleared at the * same time it's being read. This bit must be cleared just after all * data is acquired. */ isp_reg_set(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR); /* * We'll read 4 times a 4-bytes-word at each iteration for * optimization. It avoids 3/4 of the jumps. We also know buf_size is * divisible by 16. */ for (i = hist->buf_size / 16; i > 0; i--) { *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); } isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR); return STAT_BUF_DONE; }
static void ccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable) { struct isp_device *isp = to_isp_device(ccp2); struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity); int i; if (enable && ccp2->vdds_csib) regulator_enable(ccp2->vdds_csib); for (i = 0; i < CCP2_LCx_CHANS_NUM; i++) isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(i), ISPCCP2_LCx_CTRL_CHAN_EN, enable ? ISPCCP2_LCx_CTRL_CHAN_EN : 0); isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL, ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN, enable ? (ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN) : 0); if (pipe->do_propagation) { if (enable) isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LC01_IRQENABLE, ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ); else isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LC01_IRQENABLE, ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ); } if (!enable && ccp2->vdds_csib) regulator_disable(ccp2->vdds_csib); }
/* * 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; if (!csi2->available) return -ENODEV; if (csi2->phy->phy_in_use) return -EBUSY; isp_reg_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG, ISPCSI2_SYSCONFIG_SOFT_RESET); do { reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_SYSSTATUS) & ISPCSI2_SYSSTATUS_RESET_DONE; if (reg == ISPCSI2_SYSSTATUS_RESET_DONE) break; soft_reset_retries++; if (soft_reset_retries < 5) udelay(100); } while (soft_reset_retries < 5); if (soft_reset_retries == 5) { dev_err(isp->dev, "CSI2: Soft reset try count exceeded!\n"); return -EBUSY; } if (isp->revision == ISP_REVISION_15_0) isp_reg_set(isp, csi2->regs1, ISPCSI2_PHY_CFG, ISPCSI2_PHY_CFG_RESET_CTRL); i = 100; do { reg = isp_reg_readl(isp, csi2->phy->phy_regs, ISPCSIPHY_REG1) & ISPCSIPHY_REG1_RESET_DONE_CTRLCLK; if (reg == ISPCSIPHY_REG1_RESET_DONE_CTRLCLK) break; udelay(100); } while (--i > 0); if (i == 0) { dev_err(isp->dev, "CSI2: Reset for CSI2_96M_FCLK domain Failed!\n"); return -EBUSY; } if (isp->autoidle) isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG, ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK | ISPCSI2_SYSCONFIG_AUTO_IDLE, ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SMART | ((isp->revision == ISP_REVISION_15_0) ? ISPCSI2_SYSCONFIG_AUTO_IDLE : 0)); else isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG, ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK | ISPCSI2_SYSCONFIG_AUTO_IDLE, ISPCSI2_SYSCONFIG_MSTANDBY_MODE_NO); return 0; }