/* * isp_csi2_isr - CSI2 interrupt handling. * * Return -EIO on Transmission error */ int isp_csi2_isr(struct isp_csi2_device *csi2) { u32 csi2_irqstatus, cpxio1_irqstatus; struct isp_device *isp = csi2->isp; int retval = 0; if (!csi2->available) return -ENODEV; csi2_irqstatus = isp_reg_readl(isp, csi2->regs1, ISPCSI2_IRQSTATUS); isp_reg_writel(isp, csi2_irqstatus, csi2->regs1, ISPCSI2_IRQSTATUS); /* Failure Cases */ if (csi2_irqstatus & ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ) { cpxio1_irqstatus = isp_reg_readl(isp, csi2->regs1, ISPCSI2_PHY_IRQSTATUS); isp_reg_writel(isp, cpxio1_irqstatus, csi2->regs1, ISPCSI2_PHY_IRQSTATUS); dev_dbg(isp->dev, "CSI2: ComplexIO Error IRQ " "%x\n", cpxio1_irqstatus); retval = -EIO; } if (csi2_irqstatus & (ISPCSI2_IRQSTATUS_OCP_ERR_IRQ | ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ | ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ | ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ | ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ)) { dev_dbg(isp->dev, "CSI2 Err:" " OCP:%d," " Short_pack:%d," " ECC:%d," " CPXIO2:%d," " FIFO_OVF:%d," "\n", (csi2_irqstatus & ISPCSI2_IRQSTATUS_OCP_ERR_IRQ) ? 1 : 0, (csi2_irqstatus & ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ) ? 1 : 0, (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ) ? 1 : 0, (csi2_irqstatus & ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ) ? 1 : 0, (csi2_irqstatus & ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ) ? 1 : 0); retval = -EIO; } if (isp_module_sync_is_stopping(&csi2->wait, &csi2->stopping)) return 0; /* Successful cases */ if (csi2_irqstatus & ISPCSI2_IRQSTATUS_CONTEXT(0)) isp_csi2_isr_ctx(csi2, &csi2->contexts[0]); if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ) dev_dbg(isp->dev, "CSI2: ECC correction done\n"); return retval; }
/** * isph3a_aewb_update_regs - Helper function to update h3a registers. **/ void isph3a_aewb_config_registers(struct isp_h3a_device *isp_h3a) { struct device *dev = to_device(isp_h3a); unsigned long irqflags; if (!isp_h3a->aewb_config_local.aewb_enable) return; spin_lock_irqsave(isp_h3a->lock, irqflags); isp_reg_writel(dev, isp_h3a->buf_next->iommu_addr, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWBUFST); if (!isp_h3a->update) { spin_unlock_irqrestore(isp_h3a->lock, irqflags); return; } isp_reg_writel(dev, isp_h3a->regs.win1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWWIN1); isp_reg_writel(dev, isp_h3a->regs.start, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINSTART); isp_reg_writel(dev, isp_h3a->regs.blk, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINBLK); isp_reg_writel(dev, isp_h3a->regs.subwin, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWSUBWIN); isp_reg_and_or(dev, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR, ~ISPH3A_PCR_AEW_MASK, isp_h3a->regs.pcr); isp_h3a->update = 0; spin_unlock_irqrestore(isp_h3a->lock, irqflags); }
/* * ispresizer_adjust_bandwidth - Reduces read bandwidth when scaling up. * Otherwise there will be SBL overflows. * * The ISP read speed is 256.0 / max(256, 1024 * ISPSBL_SDR_REQ_EXP). This * formula is correct, no matter what the TRM says. Thus, the first * step to use is 0.25 (REQ_EXP=1). * * Ratios: * 0 = 1.0 * 1 = 0.25 * 2 = 0.125 * 3 = 0.083333... * 4 = 0.0625 * 5 = 0.05 and so on... * * TRM says that read bandwidth should be no more than 83MB/s, half * of the maximum of 166MB/s. * * HOWEVER, the read speed must be chosen so that the resizer always * has time to process the frame before the next frame comes in. * Failure to do so will result in a pile-up and endless "resizer busy!" * messages. * * Zoom ratio must not exceed 4.0. This is checked in * ispresizer_check_crop_boundaries(). */ static void ispresizer_adjust_bandwidth(struct isp_res_device *res, int input_width, int input_height, int output_width, int output_height) { struct isp_device *isp = to_isp_device(res); /* Table for dividers. This allows hand tuning. */ static const unsigned char area_to_divider[] = { 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 5 /* 1........2...........3.......................4 Zoom level */ }; unsigned int input_area = input_width * input_height; unsigned int output_area = output_width * output_height; if (input_area < output_area && input_area > 0) { u32 val = area_to_divider[output_area / input_area - 1]; dev_dbg(isp->dev, "%s: area factor = %i, val = %i\n", __func__, output_area / input_area, val); isp_reg_writel(isp, val << ISPSBL_SDR_REQ_RSZ_EXP_SHIFT, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP); } else { /* Required input bandwidth greater than output, no limit. */ dev_dbg(isp->dev, "%s: resetting\n", __func__); isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP); } }
/* * csi2_set_outaddr - Set memory address to save output image * @csi2: Pointer to ISP CSI2a device. * @addr: ISP MMU Mapped 32-bit memory address aligned on 32 byte boundary. * * Sets the memory address where the output will be saved. * * Returns 0 if successful, or -EINVAL if the address is not in the 32 byte * boundary. */ static void csi2_set_outaddr(struct isp_csi2_device *csi2, u32 addr) { struct isp_device *isp = csi2->isp; struct isp_csi2_ctx_cfg *ctx = &csi2->contexts[0]; ctx->ping_addr = ctx->pong_addr = addr; isp_reg_writel(isp, ctx->ping_addr, csi2->regs1, ISPCSI2_CTX_DAT_PING_ADDR(ctx->ctxnum)); isp_reg_writel(isp, ctx->pong_addr, csi2->regs1, ISPCSI2_CTX_DAT_PONG_ADDR(ctx->ctxnum)); }
/** * ispresizer_set_luma_enhance - Set luminance enhancer parameters. * @yenh: Pointer to structure containing desired values or NULL * to user default values for core, slope, gain and algo parameters. **/ void ispresizer_set_luma_enhance(struct device *dev, struct isprsz_yenh *yenh) { if (yenh != NULL) { isp_reg_writel(dev, (yenh->algo << ISPRSZ_YENH_ALGO_SHIFT) | (yenh->gain << ISPRSZ_YENH_GAIN_SHIFT) | (yenh->slope << ISPRSZ_YENH_SLOP_SHIFT) | (yenh->coreoffset << ISPRSZ_YENH_CORE_SHIFT), OMAP3_ISP_IOMEM_RESZ, ISPRSZ_YENH); } else { isp_reg_writel(dev, 0, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_YENH); } }
/* * isp_power_settings - Sysconfig settings, for Power Management. * @isp: OMAP3 ISP device * @idle: Consider idle state. * * Sets the power settings for the ISP, and SBL bus. */ static void isp_power_settings(struct isp_device *isp, int idle) { isp_reg_writel(isp, ((idle ? ISP_SYSCONFIG_MIDLEMODE_SMARTSTANDBY : ISP_SYSCONFIG_MIDLEMODE_FORCESTANDBY) << ISP_SYSCONFIG_MIDLEMODE_SHIFT) | ((isp->revision == ISP_REVISION_15_0) ? ISP_SYSCONFIG_AUTOIDLE : 0), OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG); if (isp->autoidle) isp_reg_writel(isp, ISPCTRL_SBL_AUTOIDLE, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL); }
/** * ispresizer_set_coeffs - Setup default coefficents for polyphase filter. * @dst: Target registers map structure. * @coeffs: filter coefficients structure or NULL for default values * @h_ratio: Horizontal resizing value. * @v_ratio: Vertical resizing value. */ void ispresizer_set_coeffs(struct device *dev, struct isprsz_coef *coeffs, unsigned h_ratio, unsigned v_ratio) { const u16 *cf_ptr; int ix; u32 rval; /* Init horizontal filter coefficients */ if (h_ratio > MID_RESIZE_VALUE) { if (coeffs != NULL) cf_ptr = coeffs->h_filter_coef_7tap; else cf_ptr = ispreszdefcoef.h_filter_coef_7tap; } else { if (coeffs != NULL) cf_ptr = coeffs->h_filter_coef_4tap; else cf_ptr = ispreszdefcoef.h_filter_coef_4tap; } for (ix = ISPRSZ_HFILT10; ix <= ISPRSZ_HFILT3130; ix += sizeof(u32)) { rval = (*cf_ptr++ & ISPRSZ_HFILT_COEF0_MASK) << ISPRSZ_HFILT_COEF0_SHIFT; rval |= (*cf_ptr++ & ISPRSZ_HFILT_COEF1_MASK) << ISPRSZ_HFILT_COEF1_SHIFT; isp_reg_writel(dev, rval, OMAP3_ISP_IOMEM_RESZ, ix); } /* Init vertical filter coefficients */ if (v_ratio > MID_RESIZE_VALUE) { if (coeffs != NULL) cf_ptr = coeffs->v_filter_coef_7tap; else cf_ptr = ispreszdefcoef.v_filter_coef_7tap; } else { if (coeffs != NULL) cf_ptr = coeffs->v_filter_coef_4tap; else cf_ptr = ispreszdefcoef.v_filter_coef_4tap; } for (ix = ISPRSZ_VFILT10; ix <= ISPRSZ_VFILT3130; ix += sizeof(u32)) { rval = (*cf_ptr++ & ISPRSZ_VFILT_COEF0_MASK) << ISPRSZ_VFILT_COEF0_SHIFT; rval |= (*cf_ptr++ & ISPRSZ_VFILT_COEF1_MASK) << ISPRSZ_VFILT_COEF1_SHIFT; isp_reg_writel(dev, rval, OMAP3_ISP_IOMEM_RESZ, ix); } }
/* * ispresizer_set_src_offs - Setup the memory offset for the input lines * @isp_res: Device context. * @offset: Memory offset. * * The 5 LSBs are forced to be zeros by the hardware to align on a 32-byte * boundary; the 5 LSBs are read-only. This field must be programmed to be * 0x0 if the resizer input is from preview engine/CCDC. */ static void ispresizer_set_input_offset(struct isp_res_device *res, u32 offset) { struct isp_device *isp = to_isp_device(res); isp_reg_writel(isp, offset, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INOFF); }
/* * ispresizer_set_ratio - Setup horizontal and vertical resizing value * @isp_res: Device context. * @ratio: Structure for ratio parameters. * * Resizing range from 64 to 1024 */ static void ispresizer_set_ratio(struct isp_res_device *res, const struct resizer_ratio *ratio) { struct isp_device *isp = to_isp_device(res); const u16 *h_filter, *v_filter; u32 rgval = 0; rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) & ~(ISPRSZ_CNT_HRSZ_MASK | ISPRSZ_CNT_VRSZ_MASK); rgval |= ((ratio->horz - 1) << ISPRSZ_CNT_HRSZ_SHIFT) & ISPRSZ_CNT_HRSZ_MASK; rgval |= ((ratio->vert - 1) << ISPRSZ_CNT_VRSZ_SHIFT) & ISPRSZ_CNT_VRSZ_MASK; isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT); /* prepare horizontal filter coefficients */ if (ratio->horz > MID_RESIZE_VALUE) h_filter = &filter_coefs.h_filter_coef_7tap[0]; else h_filter = &filter_coefs.h_filter_coef_4tap[0]; /* prepare vertical filter coefficients */ if (ratio->vert > MID_RESIZE_VALUE) v_filter = &filter_coefs.v_filter_coef_7tap[0]; else v_filter = &filter_coefs.v_filter_coef_4tap[0]; ispresizer_set_filters(res, h_filter, v_filter); }
void isp_reg_and_or(enum isp_mem_resources mmio_range, u32 reg, u32 and_bits, u32 or_bits) { u32 v = isp_reg_readl(mmio_range, reg); isp_reg_writel((v & and_bits) | or_bits, mmio_range, reg); }
/* * 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; }
/* * csi2_recv_config - CSI2 receiver module configuration. * @currctrl: isp_csi2_ctrl_cfg structure * */ static void csi2_recv_config(struct isp_device *isp, struct isp_csi2_device *csi2, struct isp_csi2_ctrl_cfg *currctrl) { u32 reg; reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTRL); if (currctrl->frame_mode) reg |= ISPCSI2_CTRL_FRAME; else reg &= ~ISPCSI2_CTRL_FRAME; if (currctrl->vp_clk_enable) reg |= ISPCSI2_CTRL_VP_CLK_EN; else reg &= ~ISPCSI2_CTRL_VP_CLK_EN; if (currctrl->vp_only_enable) reg |= ISPCSI2_CTRL_VP_ONLY_EN; else reg &= ~ISPCSI2_CTRL_VP_ONLY_EN; reg &= ~ISPCSI2_CTRL_VP_OUT_CTRL_MASK; reg |= currctrl->vp_out_ctrl << ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT; if (currctrl->ecc_enable) reg |= ISPCSI2_CTRL_ECC_EN; else reg &= ~ISPCSI2_CTRL_ECC_EN; isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTRL); }
/* * csi2_ctx_enable - Enable specified CSI2 context * @ctxnum: Context number, valid between 0 and 7 values. * @enable: enable * */ static void csi2_ctx_enable(struct isp_device *isp, struct isp_csi2_device *csi2, u8 ctxnum, u8 enable) { struct isp_csi2_ctx_cfg *ctx = &csi2->contexts[ctxnum]; unsigned int skip = 0; u32 reg; reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL1(ctxnum)); if (enable) { if (csi2->frame_skip) skip = csi2->frame_skip; else if (csi2->output & CSI2_OUTPUT_MEMORY) skip = 1; reg &= ~ISPCSI2_CTX_CTRL1_COUNT_MASK; reg |= ISPCSI2_CTX_CTRL1_COUNT_UNLOCK | (skip << ISPCSI2_CTX_CTRL1_COUNT_SHIFT) | ISPCSI2_CTX_CTRL1_CTX_EN; } else { reg &= ~ISPCSI2_CTX_CTRL1_CTX_EN; } isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL1(ctxnum)); ctx->enabled = enable; }
/** * ispresizer_set_inaddr - Sets the memory address of the input frame. * @addr: 32bit memory address aligned on 32byte boundary. * @offset: Starting offset. * * Returns 0 if successful, or -EINVAL if address is not 32 bits aligned. **/ int ispresizer_set_inaddr(struct isp_res_device *isp_res, u32 addr, struct isp_node *pipe) { struct device *dev = to_device(isp_res); u32 in_buf_plus_offs = 0; if (addr % 32) return -EINVAL; isp_res->in_buff_addr = addr; if (pipe != NULL) { dev_dbg(dev, "%s: In crop top: %d[%d] left: %d[%d]\n", __func__, isp_res->phy_rect.top, pipe->in.crop.top, isp_res->phy_rect.left, pipe->in.crop.left); /* Calculate additional part to prepare crop offsets */ in_buf_plus_offs = ((isp_res->phy_rect.top * (pipe->in.image.bytesperline / 2) + (isp_res->phy_rect.left & ~0xf)) * ISP_BYTES_PER_PIXEL); /* Set the fractional part of the crop */ ispresizer_set_start(dev, isp_res->phy_rect.left & 0xf, 0); dev_dbg(dev, "%s: In address offs: 0x%08X\n", __func__, in_buf_plus_offs); } isp_reg_writel(dev, isp_res->in_buff_addr + in_buf_plus_offs, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD); dev_dbg(dev, "%s: In address base: 0x%08X\n", __func__, addr); return 0; }
/* * ispccp2_phyif_config - Initialize CCP2 phy interface config * @ccp2: Pointer to ISP CCP2 device * @config: CCP2 platform data * * Configure the CCP2 physical interface module from platform data. * * Returns -EIO if strobe is chosen in CSI1 mode, or 0 on success. */ static int ispccp2_phyif_config(struct isp_ccp2_device *ccp2, const struct isp_ccp2_platform_data *pdata) { struct isp_device *isp = to_isp_device(ccp2); u32 val; /* CCP2B mode */ val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL) | ISPCCP2_CTRL_IO_OUT_SEL | ISPCCP2_CTRL_MODE; /* Data/strobe physical layer */ BIT_SET(val, ISPCCP2_CTRL_PHY_SEL_SHIFT, ISPCCP2_CTRL_PHY_SEL_MASK, pdata->phy_layer); BIT_SET(val, ISPCCP2_CTRL_INV_SHIFT, ISPCCP2_CTRL_INV_MASK, pdata->strobe_clk_pol); isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); if (!(val & ISPCCP2_CTRL_MODE)) { if (pdata->ccp2_mode) dev_warn(isp->dev, "OMAP3 CCP2 bus not available\n"); if (pdata->phy_layer == ISPCCP2_CTRL_PHY_SEL_STROBE) /* Strobe mode requires CCP2 */ return -EIO; } return 0; }
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; }
/* * csi2_timing_config - CSI2 timing configuration. * @timing: csi2_timing_cfg structure */ static void csi2_timing_config(struct isp_device *isp, struct isp_csi2_device *csi2, struct isp_csi2_timing_cfg *timing) { u32 reg; reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_TIMING); if (timing->force_rx_mode) reg |= ISPCSI2_TIMING_FORCE_RX_MODE_IO(timing->ionum); else reg &= ~ISPCSI2_TIMING_FORCE_RX_MODE_IO(timing->ionum); if (timing->stop_state_16x) reg |= ISPCSI2_TIMING_STOP_STATE_X16_IO(timing->ionum); else reg &= ~ISPCSI2_TIMING_STOP_STATE_X16_IO(timing->ionum); if (timing->stop_state_4x) reg |= ISPCSI2_TIMING_STOP_STATE_X4_IO(timing->ionum); else reg &= ~ISPCSI2_TIMING_STOP_STATE_X4_IO(timing->ionum); reg &= ~ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_MASK(timing->ionum); reg |= timing->stop_state_counter << ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(timing->ionum); isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_TIMING); }
/** * isph3a_aewb_update_regs - Helper function to update h3a registers. **/ static void isph3a_aewb_update_regs(struct isp_h3a_device *isp_h3a) { u32 pcr; if (!isp_h3a->update) return; pcr = isp_reg_readl(isp_h3a->dev, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR); isp_reg_writel(isp_h3a->dev, (pcr & ~ISPH3A_PCR_AEW_MASK) | (isp_h3a->regs.pcr & ~ISPH3A_PCR_AEW_EN), OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR); if (!isp_h3a->aewb_config_local.aewb_enable) return; if (isph3a_aewb_busy(isp_h3a)) { isp_reg_writel(isp_h3a->dev, (pcr & ~ISPH3A_PCR_AEW_MASK) | isp_h3a->regs.pcr, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR); return; } isp_reg_writel(isp_h3a->dev, isp_h3a->regs.win1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWWIN1); isp_reg_writel(isp_h3a->dev, isp_h3a->regs.start, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINSTART); isp_reg_writel(isp_h3a->dev, isp_h3a->regs.blk, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINBLK); isp_reg_writel(isp_h3a->dev, isp_h3a->regs.subwin, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWSUBWIN); isp_reg_writel(isp_h3a->dev, (pcr & ~ISPH3A_PCR_AEW_MASK) | isp_h3a->regs.pcr, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR); isp_h3a->update = 0; }
/* * isp_enable_interrupts - Enable ISP interrupts. * @isp: OMAP3 ISP device */ static void isp_enable_interrupts(struct isp_device *isp) { static const u32 irq = IRQ0ENABLE_CSIA_IRQ | IRQ0ENABLE_CSIB_IRQ | IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ | IRQ0ENABLE_CCDC_LSC_DONE_IRQ | IRQ0ENABLE_CCDC_VD0_IRQ | IRQ0ENABLE_CCDC_VD1_IRQ | IRQ0ENABLE_HS_VS_IRQ | IRQ0ENABLE_HIST_DONE_IRQ | IRQ0ENABLE_H3A_AWB_DONE_IRQ | IRQ0ENABLE_H3A_AF_DONE_IRQ | IRQ0ENABLE_PRV_DONE_IRQ | IRQ0ENABLE_RSZ_DONE_IRQ; isp_reg_writel(isp, irq, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS); isp_reg_writel(isp, irq, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE); }
/* * ispccp2_pwr_cfg - Configure the power mode settings * @ccp2: pointer to ISP CCP2 device */ static void ispccp2_pwr_cfg(struct isp_ccp2_device *ccp2) { struct isp_device *isp = to_isp_device(ccp2); isp_reg_writel(isp, ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SMART | ((isp->revision == ISP_REVISION_15_0 && isp->autoidle) ? ISPCCP2_SYSCONFIG_AUTO_IDLE : 0), OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSCONFIG); }
/** * Configures the memory address to which the output frame is written. * @addr: 32bit memory address aligned on 32byte boundary. **/ int ispresizer_set_outaddr(u32 addr) { DPRINTK_ISPRESZ("ispresizer_set_outaddr()+\n"); if (addr % 32) return -EINVAL; isp_reg_writel(addr << ISPRSZ_SDR_OUTADD_ADDR_SHIFT, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD); DPRINTK_ISPRESZ("ispresizer_set_outaddr()-\n"); return 0; }
/** * ispresizer_config_outlineoffset - Configures the write address line offset. * @offset: Line offset for the preview output. * * Returns 0 if successful, or -EINVAL if address is not 32 bits aligned. **/ int ispresizer_config_outlineoffset(u32 offset) { DPRINTK_ISPRESZ("ispresizer_config_outlineoffset()+\n"); if (offset % 32) return -EINVAL; isp_reg_writel(offset << ISPRSZ_SDR_OUTOFF_OFFSET_SHIFT, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF); DPRINTK_ISPRESZ("ispresizer_config_outlineoffset()-\n"); return 0; }
/** * ispccdc_config_fpc - Configures the Faulty Pixel Correction parameters. * @fpc: Structure containing the number of faulty pixels corrected in the * frame, address of the FPC table. * * Returns 0 if successful, or -EINVAL if FPC Address is not on the 64 byte * boundary. **/ int ispccdc_config_fpc(struct ispccdc_fpc fpc) { u32 fpc_val = 0; fpc_val = isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC); if ((fpc.fpcaddr & 0xFFFFFFC0) == fpc.fpcaddr) { isp_reg_writel(fpc_val & (~ISPCCDC_FPC_FPCEN), OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC); isp_reg_writel(fpc.fpcaddr, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC_ADDR); } else { DPRINTK_ISPCCDC("FPC Address should be on 64byte boundary\n"); return -EINVAL; } isp_reg_writel(fpc_val | (fpc.fpnum << ISPCCDC_FPC_FPNUM_SHIFT), OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC); return 0; }
/** * ispccdc_config_culling - Configures the culling parameters. * @cull: Structure containing the vertical culling pattern, and horizontal * culling pattern for odd and even lines. **/ void ispccdc_config_culling(struct ispccdc_culling cull) { u32 culling_val = 0; culling_val |= cull.v_pattern << ISPCCDC_CULLING_CULV_SHIFT; culling_val |= cull.h_even << ISPCCDC_CULLING_CULHEVN_SHIFT; culling_val |= cull.h_odd << ISPCCDC_CULLING_CULHODD_SHIFT; isp_reg_writel(culling_val, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CULLING); }
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; }
/** * ispccdc_config_black_comp - Configures Black Level Compensation parameters. * @blcomp: Structure containing the black level compensation value for RGrGbB * pixels. in 2's complement. **/ void ispccdc_config_black_comp(struct ispccdc_blcomp blcomp) { u32 blcomp_val = 0; blcomp_val |= blcomp.b_mg << ISPCCDC_BLKCMP_B_MG_SHIFT; blcomp_val |= blcomp.gb_g << ISPCCDC_BLKCMP_GB_G_SHIFT; blcomp_val |= blcomp.gr_cy << ISPCCDC_BLKCMP_GR_CY_SHIFT; blcomp_val |= blcomp.r_ye << ISPCCDC_BLKCMP_R_YE_SHIFT; isp_reg_writel(blcomp_val, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_BLKCMP); }
/* * csi2_irq_status_set - Enables CSI2 Status IRQs. * @enable: Enable/disable CSI2 Status interrupts */ static void csi2_irq_status_set(struct isp_device *isp, struct isp_csi2_device *csi2, int enable) { u32 reg; reg = ISPCSI2_IRQSTATUS_OCP_ERR_IRQ | ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ | ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ | ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ | ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ | ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ | ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ | ISPCSI2_IRQSTATUS_CONTEXT(0); isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_IRQSTATUS); if (enable) reg |= isp_reg_readl(isp, csi2->regs1, ISPCSI2_IRQENABLE); else reg = 0; isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_IRQENABLE); }
/** * ispresizer_set_inaddr - Sets the memory address of the input frame. * @addr: 32bit memory address aligned on 32byte boundary. * * Returns 0 if successful, or -EINVAL if address is not 32 bits aligned. **/ int ispresizer_set_inaddr(u32 addr) { DPRINTK_ISPRESZ("ispresizer_set_inaddr()+\n"); if (addr % 32) return -EINVAL; isp_reg_writel(addr << ISPRSZ_SDR_INADD_ADDR_SHIFT, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD); ispres_obj.tmp_buf = addr; DPRINTK_ISPRESZ("ispresizer_set_inaddr()-\n"); return 0; }
static void __ispstat_pcr_enable(struct ispstat *stat, u8 pcr_enable) { u32 pcr = isp_reg_readl(stat->isp, stat->pcr->base, stat->pcr->offset); if (pcr_enable) pcr |= stat->pcr->enable; else pcr &= ~stat->pcr->enable; isp_reg_writel(stat->isp, pcr, stat->pcr->base, stat->pcr->offset); }
/* * Configures the memory address to which the output frame is written. * @addr: 32bit memory address aligned on 32byte boundary. * Note: For SBL efficiency reasons the address should be on a 256-byte * boundary. */ static void ispresizer_set_outaddr(struct isp_res_device *res, u32 addr) { struct isp_device *isp = to_isp_device(res); /* * Set output address. This needs to be in its own function * because it changes often. */ isp_reg_writel(isp, addr << ISPRSZ_SDR_OUTADD_ADDR_SHIFT, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD); }