static void omap24xxcam_dmahw_init(void __iomem *base) { omap24xxcam_reg_out(base, CAMDMA_OCP_SYSCONFIG, CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY | CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE | CAMDMA_OCP_SYSCONFIG_AUTOIDLE); omap24xxcam_reg_merge(base, CAMDMA_GCR, 0x10, CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH); omap24xxcam_reg_out(base, CAMDMA_IRQENABLE_L0, 0xf); }
/* Ack dmach on CSR and IRQSTATUS_L0 */ static u32 omap24xxcam_dmahw_ack_ch(void __iomem *base, int dmach) { u32 csr; csr = omap24xxcam_reg_in(base, CAMDMA_CSR(dmach)); /* ack interrupt in CSR */ omap24xxcam_reg_out(base, CAMDMA_CSR(dmach), csr); /* ack interrupt in IRQSTATUS */ omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, (1 << dmach)); return csr; }
/* Ack all interrupt on CSR and IRQSTATUS_L0 */ static void omap24xxcam_dmahw_ack_all(void __iomem *base) { u32 csr; int i; for (i = 0; i < NUM_CAMDMA_CHANNELS; ++i) { csr = omap24xxcam_reg_in(base, CAMDMA_CSR(i)); /* ack interrupt in CSR */ omap24xxcam_reg_out(base, CAMDMA_CSR(i), csr); } omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, 0xf); }
static u32 omap24xxcam_dmahw_ack_ch(unsigned long base, int dmach) { u32 csr; csr = omap24xxcam_reg_in(base, CAMDMA_CSR(dmach)); omap24xxcam_reg_out(base, CAMDMA_CSR(dmach), csr); omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, (1 << dmach)); return csr; }
static void omap24xxcam_dmahw_ack_all(unsigned long base) { u32 csr; int i; for (i = 0; i < NUM_CAMDMA_CHANNELS; ++i) { csr = omap24xxcam_reg_in(base, CAMDMA_CSR(i)); omap24xxcam_reg_out(base, CAMDMA_CSR(i), csr); } omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, 0xf); }
static void omap24xxcam_dmahw_transfer_chain(void __iomem *base, int dmach, int free_dmach) { int prev_dmach, ch; if (dmach == 0) prev_dmach = NUM_CAMDMA_CHANNELS - 1; else prev_dmach = dmach - 1; omap24xxcam_reg_out(base, CAMDMA_CLNK_CTRL(prev_dmach), CAMDMA_CLNK_CTRL_ENABLE_LNK | dmach); /* Did we chain the DMA transfer before the previous one * finished? */ ch = (dmach + free_dmach) % NUM_CAMDMA_CHANNELS; while (!(omap24xxcam_reg_in(base, CAMDMA_CCR(ch)) & CAMDMA_CCR_ENABLE)) { if (ch == dmach) { /* The previous transfer has ended and this one * hasn't started, so we must not have chained * to the previous one in time. We'll have to * start it now. */ omap24xxcam_dmahw_transfer_start(base, dmach); break; } else ch = (ch + 1) % NUM_CAMDMA_CHANNELS; } }
/* * (Re)initialise the camera block. */ static void omap24xxcam_hwinit(struct omap24xxcam_device *cam) { omap24xxcam_poweron_reset(cam); /* set the camera subsystem autoidle bit */ omap24xxcam_reg_out(cam->mmio_base, CAM_SYSCONFIG, CAM_SYSCONFIG_AUTOIDLE); /* set the camera MMU autoidle bit */ omap24xxcam_reg_out(cam->mmio_base, CAMMMU_REG_OFFSET + CAMMMU_SYSCONFIG, CAMMMU_SYSCONFIG_AUTOIDLE); omap24xxcam_core_hwinit(cam); omap24xxcam_dma_hwinit(&cam->sgdma.dma); }
/* * Set xclk. * * To disable xclk, use value zero. */ static void omap24xxcam_core_xclk_set(const struct omap24xxcam_device *cam, u32 xclk) { if (xclk) { u32 divisor = CAM_MCLK / xclk; if (divisor == 1) omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL_XCLK, CC_CTRL_XCLK_DIV_BYPASS); else omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL_XCLK, divisor); } else omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL_XCLK, CC_CTRL_XCLK_DIV_STABLE_LOW); }
static void omap24xxcam_dmahw_abort_ch(unsigned long base, int dmach) { omap24xxcam_reg_out(base, CAMDMA_CICR(dmach), 0); omap24xxcam_reg_merge(base, CAMDMA_CLNK_CTRL(dmach), 0, CAMDMA_CLNK_CTRL_ENABLE_LNK); omap24xxcam_reg_merge(base, CAMDMA_CCR(dmach), 0, CAMDMA_CCR_ENABLE); }
/* Abort all chained DMA transfers. After all transfers have been * aborted and the DMA controller is idle, the completion routines for * any aborted transfers will be called in sequence. The DMA * controller may not be idle after this routine completes, because * the completion routines might start new transfers. */ static void omap24xxcam_dmahw_abort_ch(void __iomem *base, int dmach) { /* mask all interrupts from this channel */ omap24xxcam_reg_out(base, CAMDMA_CICR(dmach), 0); /* unlink this channel */ omap24xxcam_reg_merge(base, CAMDMA_CLNK_CTRL(dmach), 0, CAMDMA_CLNK_CTRL_ENABLE_LNK); /* disable this channel */ omap24xxcam_reg_merge(base, CAMDMA_CCR(dmach), 0, CAMDMA_CCR_ENABLE); }
static void omap24xxcam_dmahw_transfer_start(void __iomem *base, int dmach) { omap24xxcam_reg_out(base, CAMDMA_CCR(dmach), CAMDMA_CCR_SEL_SRC_DST_SYNC | CAMDMA_CCR_BS | CAMDMA_CCR_DST_AMODE_POST_INC | CAMDMA_CCR_SRC_AMODE_POST_INC | CAMDMA_CCR_ENABLE | CAMDMA_CCR_FS | CAMDMA_CCR_SYNCHRO_CAMERA); }
static void omap24xxcam_core_hwinit(const struct omap24xxcam_device *cam) { /* * Setting the camera core AUTOIDLE bit causes problems with frame * synchronization, so we will clear the AUTOIDLE bit instead. */ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_SYSCONFIG, CC_SYSCONFIG_AUTOIDLE); /* program the camera interface DMA packet size */ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL_DMA, CC_CTRL_DMA_EN | (DMA_THRESHOLD / 4 - 1)); /* enable camera core error interrupts */ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_IRQENABLE, CC_IRQENABLE_FW_ERR_IRQ | CC_IRQENABLE_FSC_ERR_IRQ | CC_IRQENABLE_SSC_ERR_IRQ | CC_IRQENABLE_FIFO_OF_IRQ); }
/* * Reset camera block to power-on state. */ static void omap24xxcam_poweron_reset(struct omap24xxcam_device *cam) { int max_loop = RESET_TIMEOUT_NS; /* Reset whole camera subsystem */ omap24xxcam_reg_out(cam->mmio_base, CAM_SYSCONFIG, CAM_SYSCONFIG_SOFTRESET); /* Wait till it's finished */ while (!(omap24xxcam_reg_in(cam->mmio_base, CAM_SYSSTATUS) & CAM_SYSSTATUS_RESETDONE) && --max_loop) { ndelay(1); } if (!(omap24xxcam_reg_in(cam->mmio_base, CAM_SYSSTATUS) & CAM_SYSSTATUS_RESETDONE)) dev_err(cam->dev, "camera soft reset timeout\n"); }
/* Interrupt service routine for camera core interrupts. */ static void omap24xxcam_core_isr(struct omap24xxcam_device *cam) { u32 cc_irqstatus; const u32 cc_irqstatus_err = CC_IRQSTATUS_FW_ERR_IRQ | CC_IRQSTATUS_FSC_ERR_IRQ | CC_IRQSTATUS_SSC_ERR_IRQ | CC_IRQSTATUS_FIFO_UF_IRQ | CC_IRQSTATUS_FIFO_OF_IRQ; cc_irqstatus = omap24xxcam_reg_in(cam->mmio_base + CC_REG_OFFSET, CC_IRQSTATUS); omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_IRQSTATUS, cc_irqstatus); if (cc_irqstatus & cc_irqstatus_err && !atomic_read(&cam->in_reset)) { dev_dbg(cam->dev, "resetting camera, cc_irqstatus 0x%x\n", cc_irqstatus); omap24xxcam_reset(cam); } }
static void omap24xxcam_dmahw_transfer_chain(unsigned long base, int dmach, int free_dmach) { int prev_dmach, ch; if (dmach == 0) prev_dmach = NUM_CAMDMA_CHANNELS - 1; else prev_dmach = dmach - 1; omap24xxcam_reg_out(base, CAMDMA_CLNK_CTRL(prev_dmach), CAMDMA_CLNK_CTRL_ENABLE_LNK | dmach); ch = (dmach + free_dmach) % NUM_CAMDMA_CHANNELS; while (!(omap24xxcam_reg_in(base, CAMDMA_CCR(ch)) & CAMDMA_CCR_ENABLE)) { if (ch == dmach) { omap24xxcam_dmahw_transfer_start(base, dmach); break; } else ch = (ch + 1) % NUM_CAMDMA_CHANNELS; } }
static void omap24xxcam_dmahw_transfer_setup(void __iomem *base, int dmach, dma_addr_t start, u32 len) { omap24xxcam_reg_out(base, CAMDMA_CCR(dmach), CAMDMA_CCR_SEL_SRC_DST_SYNC | CAMDMA_CCR_BS | CAMDMA_CCR_DST_AMODE_POST_INC | CAMDMA_CCR_SRC_AMODE_POST_INC | CAMDMA_CCR_FS | CAMDMA_CCR_WR_ACTIVE | CAMDMA_CCR_RD_ACTIVE | CAMDMA_CCR_SYNCHRO_CAMERA); omap24xxcam_reg_out(base, CAMDMA_CLNK_CTRL(dmach), 0); omap24xxcam_reg_out(base, CAMDMA_CEN(dmach), len); omap24xxcam_reg_out(base, CAMDMA_CFN(dmach), 1); omap24xxcam_reg_out(base, CAMDMA_CSDP(dmach), CAMDMA_CSDP_WRITE_MODE_POSTED | CAMDMA_CSDP_DST_BURST_EN_32 | CAMDMA_CSDP_DST_PACKED | CAMDMA_CSDP_SRC_BURST_EN_32 | CAMDMA_CSDP_SRC_PACKED | CAMDMA_CSDP_DATA_TYPE_8BITS); omap24xxcam_reg_out(base, CAMDMA_CSSA(dmach), 0); omap24xxcam_reg_out(base, CAMDMA_CDSA(dmach), start); omap24xxcam_reg_out(base, CAMDMA_CSEI(dmach), 0); omap24xxcam_reg_out(base, CAMDMA_CSFI(dmach), DMA_THRESHOLD); omap24xxcam_reg_out(base, CAMDMA_CDEI(dmach), 0); omap24xxcam_reg_out(base, CAMDMA_CDFI(dmach), 0); omap24xxcam_reg_out(base, CAMDMA_CSR(dmach), CAMDMA_CSR_MISALIGNED_ERR | CAMDMA_CSR_SECURE_ERR | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_BLOCK | CAMDMA_CSR_DROP); omap24xxcam_reg_out(base, CAMDMA_CICR(dmach), CAMDMA_CICR_MISALIGNED_ERR_IE | CAMDMA_CICR_SECURE_ERR_IE | CAMDMA_CICR_TRANS_ERR_IE | CAMDMA_CICR_BLOCK_IE | CAMDMA_CICR_DROP_IE); }
/* * Enable the camera core. * * Data transfer to the camera DMA starts from next starting frame. */ static void omap24xxcam_core_enable(const struct omap24xxcam_device *cam) { omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL, cam->cc_ctrl); }
/* * Disable camera core. * * The data transfer will be stopped immediately (CC_CTRL_CC_RST). The * core internal state machines will be reset. Use * CC_CTRL_CC_FRAME_TRIG instead if you want to transfer the current * frame completely. */ static void omap24xxcam_core_disable(const struct omap24xxcam_device *cam) { omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL, CC_CTRL_CC_RST); }