/* * Configure the bridge. Valid inputs are * * IPIPEIF_INPUT_CSI2A: CSI2a receiver * IPIPEIF_INPUT_CSI2B: CSI2b receiver * * The bridge and lane shifter are configured according to the selected input * and the ISP platform data. */ void omap4iss_configure_bridge(struct iss_device *iss, enum ipipeif_input_entity input) { u32 issctrl_val; u32 isp5ctrl_val; issctrl_val = iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_CTRL); issctrl_val &= ~ISS_CTRL_INPUT_SEL_MASK; issctrl_val &= ~ISS_CTRL_CLK_DIV_MASK; isp5ctrl_val = iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL); switch (input) { case IPIPEIF_INPUT_CSI2A: issctrl_val |= ISS_CTRL_INPUT_SEL_CSI2A; break; case IPIPEIF_INPUT_CSI2B: issctrl_val |= ISS_CTRL_INPUT_SEL_CSI2B; break; default: return; } issctrl_val |= ISS_CTRL_SYNC_DETECT_VS_RAISING; isp5ctrl_val |= ISP5_CTRL_VD_PULSE_EXT | ISP5_CTRL_PSYNC_CLK_SEL | ISP5_CTRL_SYNC_ENABLE; iss_reg_write(iss, OMAP4_ISS_MEM_TOP, ISS_CTRL, issctrl_val); iss_reg_write(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL, isp5ctrl_val); }
/* * csi2_set_outaddr - Set memory address to save output image * @csi2: Pointer to ISS CSI2a device. * @addr: 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 iss_csi2_device *csi2, u32 addr) { struct iss_csi2_ctx_cfg *ctx = &csi2->contexts[0]; ctx->ping_addr = addr; ctx->pong_addr = addr; iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_PING_ADDR(ctx->ctxnum), ctx->ping_addr); iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_PONG_ADDR(ctx->ctxnum), ctx->pong_addr); }
/* * iss_enable_interrupts - Enable ISS interrupts. * @iss: OMAP4 ISS device */ static void iss_enable_interrupts(struct iss_device *iss) { static const u32 hl_irq = ISS_HL_IRQ_CSIA | ISS_HL_IRQ_CSIB | ISS_HL_IRQ_ISP(0); /* Enable HL interrupts */ iss_reg_write(iss, OMAP4_ISS_MEM_TOP, ISS_HL_IRQSTATUS(5), hl_irq); iss_reg_write(iss, OMAP4_ISS_MEM_TOP, ISS_HL_IRQENABLE_SET(5), hl_irq); if (iss->regs[OMAP4_ISS_MEM_ISP_SYS1]) omap4iss_isp_enable_interrupts(iss); }
/* * iss_isp_enable_interrupts - Enable ISS ISP interrupts. * @iss: OMAP4 ISS device */ static void omap4iss_isp_enable_interrupts(struct iss_device *iss) { static const u32 isp_irq = ISP5_IRQ_OCP_ERR | ISP5_IRQ_RSZ_FIFO_IN_BLK_ERR | ISP5_IRQ_RSZ_FIFO_OVF | ISP5_IRQ_RSZ_INT_DMA | ISP5_IRQ_ISIF_INT(0); /* Enable ISP interrupts */ iss_reg_write(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_IRQSTATUS(0), isp_irq); iss_reg_write(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_IRQENABLE_SET(0), isp_irq); }
/* * iss_isr - Interrupt Service Routine for ISS module. * @irq: Not used currently. * @_iss: Pointer to the OMAP4 ISS device * * Handles the corresponding callback if plugged in. * * Returns IRQ_HANDLED when IRQ was correctly handled, or IRQ_NONE when the * IRQ wasn't handled. */ static irqreturn_t iss_isr(int irq, void *_iss) { static const u32 ipipeif_events = ISP5_IRQ_IPIPEIF_IRQ | ISP5_IRQ_ISIF_INT(0); static const u32 resizer_events = ISP5_IRQ_RSZ_FIFO_IN_BLK_ERR | ISP5_IRQ_RSZ_FIFO_OVF | ISP5_IRQ_RSZ_INT_DMA; struct iss_device *iss = _iss; u32 irqstatus; irqstatus = iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_HL_IRQSTATUS(5)); iss_reg_write(iss, OMAP4_ISS_MEM_TOP, ISS_HL_IRQSTATUS(5), irqstatus); if (irqstatus & ISS_HL_IRQ_CSIA) omap4iss_csi2_isr(&iss->csi2a); if (irqstatus & ISS_HL_IRQ_CSIB) omap4iss_csi2_isr(&iss->csi2b); if (irqstatus & ISS_HL_IRQ_ISP(0)) { u32 isp_irqstatus = iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_IRQSTATUS(0)); iss_reg_write(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_IRQSTATUS(0), isp_irqstatus); if (isp_irqstatus & ISP5_IRQ_OCP_ERR) dev_dbg(iss->dev, "ISP5 OCP Error!\n"); if (isp_irqstatus & ipipeif_events) { omap4iss_ipipeif_isr(&iss->ipipeif, isp_irqstatus & ipipeif_events); } if (isp_irqstatus & resizer_events) omap4iss_resizer_isr(&iss->resizer, isp_irqstatus & resizer_events); #ifdef ISS_ISR_DEBUG iss_isp_isr_dbg(iss, isp_irqstatus); #endif } omap4iss_flush(iss); #ifdef ISS_ISR_DEBUG iss_isr_dbg(iss, irqstatus); #endif return IRQ_HANDLED; }
/* * omap4iss_csi2_isr - CSI2 interrupt handling. */ void omap4iss_csi2_isr(struct iss_csi2_device *csi2) { struct iss_pipeline *pipe = to_iss_pipeline(&csi2->subdev.entity); u32 csi2_irqstatus, cpxio1_irqstatus; struct iss_device *iss = csi2->iss; if (!csi2->available) return; csi2_irqstatus = iss_reg_read(csi2->iss, csi2->regs1, CSI2_IRQSTATUS); iss_reg_write(csi2->iss, csi2->regs1, CSI2_IRQSTATUS, csi2_irqstatus); /* Failure Cases */ if (csi2_irqstatus & CSI2_IRQ_COMPLEXIO_ERR) { cpxio1_irqstatus = iss_reg_read(csi2->iss, csi2->regs1, CSI2_COMPLEXIO_IRQSTATUS); iss_reg_write(csi2->iss, csi2->regs1, CSI2_COMPLEXIO_IRQSTATUS, cpxio1_irqstatus); dev_dbg(iss->dev, "CSI2: ComplexIO Error IRQ %x\n", cpxio1_irqstatus); pipe->error = true; } if (csi2_irqstatus & (CSI2_IRQ_OCP_ERR | CSI2_IRQ_SHORT_PACKET | CSI2_IRQ_ECC_NO_CORRECTION | CSI2_IRQ_COMPLEXIO_ERR | CSI2_IRQ_FIFO_OVF)) { dev_dbg(iss->dev, "CSI2 Err: OCP:%d SHORT:%d ECC:%d CPXIO:%d OVF:%d\n", csi2_irqstatus & CSI2_IRQ_OCP_ERR ? 1 : 0, csi2_irqstatus & CSI2_IRQ_SHORT_PACKET ? 1 : 0, csi2_irqstatus & CSI2_IRQ_ECC_NO_CORRECTION ? 1 : 0, csi2_irqstatus & CSI2_IRQ_COMPLEXIO_ERR ? 1 : 0, csi2_irqstatus & CSI2_IRQ_FIFO_OVF ? 1 : 0); pipe->error = true; } if (omap4iss_module_sync_is_stopping(&csi2->wait, &csi2->stopping)) return; /* Successful cases */ if (csi2_irqstatus & CSI2_IRQ_CONTEXT0) csi2_isr_ctx(csi2, &csi2->contexts[0]); if (csi2_irqstatus & CSI2_IRQ_ECC_CORRECTION) dev_dbg(iss->dev, "CSI2: ECC correction done\n"); }
/* * csi2_timing_config - CSI2 timing configuration. * @timing: csi2_timing_cfg structure */ static void csi2_timing_config(struct iss_csi2_device *csi2, struct iss_csi2_timing_cfg *timing) { u32 reg; reg = iss_reg_read(csi2->iss, csi2->regs1, CSI2_TIMING); if (timing->force_rx_mode) reg |= CSI2_TIMING_FORCE_RX_MODE_IO1; else reg &= ~CSI2_TIMING_FORCE_RX_MODE_IO1; if (timing->stop_state_16x) reg |= CSI2_TIMING_STOP_STATE_X16_IO1; else reg &= ~CSI2_TIMING_STOP_STATE_X16_IO1; if (timing->stop_state_4x) reg |= CSI2_TIMING_STOP_STATE_X4_IO1; else reg &= ~CSI2_TIMING_STOP_STATE_X4_IO1; reg &= ~CSI2_TIMING_STOP_STATE_COUNTER_IO1_MASK; reg |= timing->stop_state_counter << CSI2_TIMING_STOP_STATE_COUNTER_IO1_SHIFT; iss_reg_write(csi2->iss, csi2->regs1, CSI2_TIMING, reg); }
/* * csi2_irq_status_set - Enables CSI2 Status IRQs. * @enable: Enable/disable CSI2 Status interrupts */ static void csi2_irq_status_set(struct iss_csi2_device *csi2, int enable) { u32 reg; reg = CSI2_IRQ_OCP_ERR | CSI2_IRQ_SHORT_PACKET | CSI2_IRQ_ECC_CORRECTION | CSI2_IRQ_ECC_NO_CORRECTION | CSI2_IRQ_COMPLEXIO_ERR | CSI2_IRQ_FIFO_OVF | CSI2_IRQ_CONTEXT0; iss_reg_write(csi2->iss, csi2->regs1, CSI2_IRQSTATUS, reg); if (enable) iss_reg_set(csi2->iss, csi2->regs1, CSI2_IRQENABLE, reg); else iss_reg_write(csi2->iss, csi2->regs1, CSI2_IRQENABLE, 0); }
/* * iss_disable_interrupts - Disable ISS interrupts. * @iss: OMAP4 ISS device */ static void iss_disable_interrupts(struct iss_device *iss) { if (iss->regs[OMAP4_ISS_MEM_ISP_SYS1]) omap4iss_isp_disable_interrupts(iss); iss_reg_write(iss, OMAP4_ISS_MEM_TOP, ISS_HL_IRQENABLE_CLR(5), ~0); }
/* * csi2_ctx_enable - Enable specified CSI2 context * @ctxnum: Context number, valid between 0 and 7 values. * @enable: enable * */ static void csi2_ctx_enable(struct iss_csi2_device *csi2, u8 ctxnum, u8 enable) { struct iss_csi2_ctx_cfg *ctx = &csi2->contexts[ctxnum]; u32 reg; reg = iss_reg_read(csi2->iss, csi2->regs1, CSI2_CTX_CTRL1(ctxnum)); if (enable) { unsigned int skip = 0; if (csi2->frame_skip) skip = csi2->frame_skip; else if (csi2->output & CSI2_OUTPUT_MEMORY) skip = 1; reg &= ~CSI2_CTX_CTRL1_COUNT_MASK; reg |= CSI2_CTX_CTRL1_COUNT_UNLOCK | (skip << CSI2_CTX_CTRL1_COUNT_SHIFT) | CSI2_CTX_CTRL1_CTX_EN; } else { reg &= ~CSI2_CTX_CTRL1_CTX_EN; } iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_CTRL1(ctxnum), reg); ctx->enabled = enable; }
/* * ipipe_set_stream - Enable/Disable streaming on the IPIPE module * @sd: ISP IPIPE V4L2 subdevice * @enable: Enable/disable stream */ static int ipipe_set_stream(struct v4l2_subdev *sd, int enable) { struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd); struct iss_device *iss = to_iss_device(ipipe); int ret = 0; if (ipipe->state == ISS_PIPELINE_STREAM_STOPPED) { if (enable == ISS_PIPELINE_STREAM_STOPPED) return 0; omap4iss_isp_subclk_enable(iss, OMAP4_ISS_ISP_SUBCLK_IPIPE); /* Enable clk_arm_g0 */ iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_GCK_MMR, IPIPE_GCK_MMR_REG); /* Enable clk_pix_g[3:0] */ iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_GCK_PIX, IPIPE_GCK_PIX_G3 | IPIPE_GCK_PIX_G2 | IPIPE_GCK_PIX_G1 | IPIPE_GCK_PIX_G0); } switch (enable) { case ISS_PIPELINE_STREAM_CONTINUOUS: ipipe_configure(ipipe); ipipe_print_status(ipipe); atomic_set(&ipipe->stopping, 0); ipipe_enable(ipipe, 1); break; case ISS_PIPELINE_STREAM_STOPPED: if (ipipe->state == ISS_PIPELINE_STREAM_STOPPED) return 0; if (omap4iss_module_sync_idle(&sd->entity, &ipipe->wait, &ipipe->stopping)) ret = -ETIMEDOUT; ipipe_enable(ipipe, 0); omap4iss_isp_subclk_disable(iss, OMAP4_ISS_ISP_SUBCLK_IPIPE); break; } ipipe->state = enable; return ret; }
/* * csi2_ctx_config - CSI2 context configuration. * @ctx: context configuration * */ static void csi2_ctx_config(struct iss_csi2_device *csi2, struct iss_csi2_ctx_cfg *ctx) { u32 reg; /* Set up CSI2_CTx_CTRL1 */ if (ctx->eof_enabled) reg = CSI2_CTX_CTRL1_EOF_EN; if (ctx->eol_enabled) reg |= CSI2_CTX_CTRL1_EOL_EN; if (ctx->checksum_enabled) reg |= CSI2_CTX_CTRL1_CS_EN; iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_CTRL1(ctx->ctxnum), reg); /* Set up CSI2_CTx_CTRL2 */ reg = ctx->virtual_id << CSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT; reg |= ctx->format_id << CSI2_CTX_CTRL2_FORMAT_SHIFT; if (ctx->dpcm_decompress && ctx->dpcm_predictor) reg |= CSI2_CTX_CTRL2_DPCM_PRED; if (is_usr_def_mapping(ctx->format_id)) reg |= 2 << CSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT; iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_CTRL2(ctx->ctxnum), reg); /* Set up CSI2_CTx_CTRL3 */ iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_CTRL3(ctx->ctxnum), ctx->alpha << CSI2_CTX_CTRL3_ALPHA_SHIFT); /* Set up CSI2_CTx_DAT_OFST */ iss_reg_update(csi2->iss, csi2->regs1, CSI2_CTX_DAT_OFST(ctx->ctxnum), CSI2_CTX_DAT_OFST_MASK, ctx->data_offset); iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_PING_ADDR(ctx->ctxnum), ctx->ping_addr); iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_PONG_ADDR(ctx->ctxnum), ctx->pong_addr); }
/* * csi2_recv_config - CSI2 receiver module configuration. * @currctrl: iss_csi2_ctrl_cfg structure * */ static void csi2_recv_config(struct iss_csi2_device *csi2, struct iss_csi2_ctrl_cfg *currctrl) { u32 reg = 0; if (currctrl->frame_mode) reg |= CSI2_CTRL_FRAME; else reg &= ~CSI2_CTRL_FRAME; if (currctrl->vp_clk_enable) reg |= CSI2_CTRL_VP_CLK_EN; else reg &= ~CSI2_CTRL_VP_CLK_EN; if (currctrl->vp_only_enable) reg |= CSI2_CTRL_VP_ONLY_EN; else reg &= ~CSI2_CTRL_VP_ONLY_EN; reg &= ~CSI2_CTRL_VP_OUT_CTRL_MASK; reg |= currctrl->vp_out_ctrl << CSI2_CTRL_VP_OUT_CTRL_SHIFT; if (currctrl->ecc_enable) reg |= CSI2_CTRL_ECC_EN; else reg &= ~CSI2_CTRL_ECC_EN; /* * Set MFlag assertion boundaries to: * Low: 4/8 of FIFO size * High: 6/8 of FIFO size */ reg &= ~(CSI2_CTRL_MFLAG_LEVH_MASK | CSI2_CTRL_MFLAG_LEVL_MASK); reg |= (2 << CSI2_CTRL_MFLAG_LEVH_SHIFT) | (4 << CSI2_CTRL_MFLAG_LEVL_SHIFT); /* Generation of 16x64-bit bursts (Recommended) */ reg |= CSI2_CTRL_BURST_SIZE_EXPAND; /* Do Non-Posted writes (Recommended) */ reg |= CSI2_CTRL_NON_POSTED_WRITE; /* * Enforce Little endian for all formats, including: * YUV4:2:2 8-bit and YUV4:2:0 Legacy */ reg |= CSI2_CTRL_ENDIANNESS; iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTRL, reg); }
/* * csi2_irq_complexio1_set - Enables CSI2 ComplexIO IRQs. * @enable: Enable/disable CSI2 ComplexIO #1 interrupts */ static void csi2_irq_complexio1_set(struct iss_csi2_device *csi2, int enable) { u32 reg; reg = CSI2_COMPLEXIO_IRQ_STATEALLULPMEXIT | CSI2_COMPLEXIO_IRQ_STATEALLULPMENTER | CSI2_COMPLEXIO_IRQ_STATEULPM5 | CSI2_COMPLEXIO_IRQ_ERRCONTROL5 | CSI2_COMPLEXIO_IRQ_ERRESC5 | CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS5 | CSI2_COMPLEXIO_IRQ_ERRSOTHS5 | CSI2_COMPLEXIO_IRQ_STATEULPM4 | CSI2_COMPLEXIO_IRQ_ERRCONTROL4 | CSI2_COMPLEXIO_IRQ_ERRESC4 | CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS4 | CSI2_COMPLEXIO_IRQ_ERRSOTHS4 | CSI2_COMPLEXIO_IRQ_STATEULPM3 | CSI2_COMPLEXIO_IRQ_ERRCONTROL3 | CSI2_COMPLEXIO_IRQ_ERRESC3 | CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS3 | CSI2_COMPLEXIO_IRQ_ERRSOTHS3 | CSI2_COMPLEXIO_IRQ_STATEULPM2 | CSI2_COMPLEXIO_IRQ_ERRCONTROL2 | CSI2_COMPLEXIO_IRQ_ERRESC2 | CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS2 | CSI2_COMPLEXIO_IRQ_ERRSOTHS2 | CSI2_COMPLEXIO_IRQ_STATEULPM1 | CSI2_COMPLEXIO_IRQ_ERRCONTROL1 | CSI2_COMPLEXIO_IRQ_ERRESC1 | CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS1 | CSI2_COMPLEXIO_IRQ_ERRSOTHS1; iss_reg_write(csi2->iss, csi2->regs1, CSI2_COMPLEXIO_IRQSTATUS, reg); if (enable) iss_reg_set(csi2->iss, csi2->regs1, CSI2_COMPLEXIO_IRQENABLE, reg); else iss_reg_write(csi2->iss, csi2->regs1, CSI2_COMPLEXIO_IRQENABLE, 0); }
static void csi2_isr_ctx(struct iss_csi2_device *csi2, struct iss_csi2_ctx_cfg *ctx) { unsigned int n = ctx->ctxnum; u32 status; status = iss_reg_read(csi2->iss, csi2->regs1, CSI2_CTX_IRQSTATUS(n)); iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_IRQSTATUS(n), status); /* Propagate frame number */ if (status & CSI2_CTX_IRQ_FS) { struct iss_pipeline *pipe = to_iss_pipeline(&csi2->subdev.entity); if (pipe->do_propagation) atomic_inc(&pipe->frame_number); } if (!(status & CSI2_CTX_IRQ_FE)) 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(csi2, ctx); csi2_ctx_enable(csi2, n, 1); } return; } if (csi2->output & CSI2_OUTPUT_MEMORY) 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 iss_csi2_device *csi2, int enable) { u32 reg = CSI2_CTX_IRQ_FE; int i; if (csi2->use_fs_irq) reg |= CSI2_CTX_IRQ_FS; for (i = 0; i < 8; i++) { iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_IRQSTATUS(i), reg); if (enable) iss_reg_set(csi2->iss, csi2->regs1, CSI2_CTX_IRQENABLE(i), reg); else iss_reg_clr(csi2->iss, csi2->regs1, CSI2_CTX_IRQENABLE(i), reg); } }
static void ipipe_configure(struct iss_ipipe_device *ipipe) { struct iss_device *iss = to_iss_device(ipipe); struct v4l2_mbus_framefmt *format; /* IPIPE_PAD_SINK */ format = &ipipe->formats[IPIPE_PAD_SINK]; /* NOTE: Currently just supporting pipeline IN: RGB, OUT: YUV422 */ iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_FMT, IPIPE_SRC_FMT_RAW2YUV); /* Enable YUV444 -> YUV422 conversion */ iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_YUV_PHS, IPIPE_YUV_PHS_LPF); iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_VPS, 0); iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_HPS, 0); iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_VSZ, (format->height - 2) & IPIPE_SRC_VSZ_MASK); iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_HSZ, (format->width - 1) & IPIPE_SRC_HSZ_MASK); /* Ignore ipipeif_wrt signal, and operate on-the-fly. */ iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_MODE, IPIPE_SRC_MODE_WRT | IPIPE_SRC_MODE_OST); /* HACK: Values tuned for Ducati SW (OV) */ iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_COL, IPIPE_SRC_COL_EE_B | IPIPE_SRC_COL_EO_GB | IPIPE_SRC_COL_OE_GR | IPIPE_SRC_COL_OO_R); /* IPIPE_PAD_SOURCE_VP */ format = &ipipe->formats[IPIPE_PAD_SOURCE_VP]; /* Do nothing? */ }
static void ipipeif_configure(struct iss_ipipeif_device *ipipeif) { struct iss_device *iss = to_iss_device(ipipeif); const struct iss_format_info *info; struct v4l2_mbus_framefmt *format; u32 isif_ccolp = 0; omap4iss_configure_bridge(iss, ipipeif->input); /* IPIPEIF_PAD_SINK */ format = &ipipeif->formats[IPIPEIF_PAD_SINK]; /* IPIPEIF with YUV422 input from ISIF */ iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_IPIPEIF, IPIPEIF_CFG1, IPIPEIF_CFG1_INPSRC1_MASK | IPIPEIF_CFG1_INPSRC2_MASK); /* Select ISIF/IPIPEIF input format */ switch (format->code) { case V4L2_MBUS_FMT_UYVY8_1X16: case V4L2_MBUS_FMT_YUYV8_1X16: iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_MODESET, ISIF_MODESET_CCDMD | ISIF_MODESET_INPMOD_MASK | ISIF_MODESET_CCDW_MASK, ISIF_MODESET_INPMOD_YCBCR16); iss_reg_update(iss, OMAP4_ISS_MEM_ISP_IPIPEIF, IPIPEIF_CFG2, IPIPEIF_CFG2_YUV8, IPIPEIF_CFG2_YUV16); break; case V4L2_MBUS_FMT_SGRBG10_1X10: isif_ccolp = ISIF_CCOLP_CP0_F0_GR | ISIF_CCOLP_CP1_F0_R | ISIF_CCOLP_CP2_F0_B | ISIF_CCOLP_CP3_F0_GB; goto cont_raw; case V4L2_MBUS_FMT_SRGGB10_1X10: isif_ccolp = ISIF_CCOLP_CP0_F0_R | ISIF_CCOLP_CP1_F0_GR | ISIF_CCOLP_CP2_F0_GB | ISIF_CCOLP_CP3_F0_B; goto cont_raw; case V4L2_MBUS_FMT_SBGGR10_1X10: isif_ccolp = ISIF_CCOLP_CP0_F0_B | ISIF_CCOLP_CP1_F0_GB | ISIF_CCOLP_CP2_F0_GR | ISIF_CCOLP_CP3_F0_R; goto cont_raw; case V4L2_MBUS_FMT_SGBRG10_1X10: isif_ccolp = ISIF_CCOLP_CP0_F0_GB | ISIF_CCOLP_CP1_F0_B | ISIF_CCOLP_CP2_F0_R | ISIF_CCOLP_CP3_F0_GR; cont_raw: iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_IPIPEIF, IPIPEIF_CFG2, IPIPEIF_CFG2_YUV16); iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_MODESET, ISIF_MODESET_CCDMD | ISIF_MODESET_INPMOD_MASK | ISIF_MODESET_CCDW_MASK, ISIF_MODESET_INPMOD_RAW | ISIF_MODESET_CCDW_2BIT); info = omap4iss_video_format_info(format->code); iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_CGAMMAWD, ISIF_CGAMMAWD_GWDI_MASK, ISIF_CGAMMAWD_GWDI(info->bpp)); /* Set RAW Bayer pattern */ iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_CCOLP, isif_ccolp); break; } iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_SPH, 0 & ISIF_SPH_MASK); iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_LNH, (format->width - 1) & ISIF_LNH_MASK); iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_LNV, (format->height - 1) & ISIF_LNV_MASK); /* Generate ISIF0 on the last line of the image */ iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_VDINT(0), format->height - 1); /* IPIPEIF_PAD_SOURCE_ISIF_SF */ format = &ipipeif->formats[IPIPEIF_PAD_SOURCE_ISIF_SF]; iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_HSIZE, (ipipeif->video_out.bpl_value >> 5) & ISIF_HSIZE_HSIZE_MASK); /* IPIPEIF_PAD_SOURCE_VP */ /* Do nothing? */ }
/* * omap4iss_flush - Post pending L3 bus writes by doing a register readback * @iss: OMAP4 ISS device * * In order to force posting of pending writes, we need to write and * readback the same register, in this case the revision register. * * See this link for reference: * http://www.mail-archive.com/[email protected]/msg08149.html */ void omap4iss_flush(struct iss_device *iss) { iss_reg_write(iss, OMAP4_ISS_MEM_TOP, ISS_HL_REVISION, 0); iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_HL_REVISION); }
/* * iss_isp_disable_interrupts - Disable ISS interrupts. * @iss: OMAP4 ISS device */ static void omap4iss_isp_disable_interrupts(struct iss_device *iss) { iss_reg_write(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_IRQENABLE_CLR(0), ~0); }