📄 s3c2440camif.c
字号:
u32 preHratio, preVratio; u32 Hshift, Vshift; u32 shfactor; u32 preDstWidth, preDstHeight; u32 Hscale, Vscale; u32 mainHratio, mainVratio; u32 ciprscpreratio; u32 ciprscpredst; u32 ciprscctrl; u32 cicoscpreratio; u32 cicoscpredst; u32 cicoscctrl; switch (formats[pdev->format].pixelformat) { case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB24: /* CIPRSCPRERATIO. */ calc_prescaler_ratio_shift(pdev->wndHsize, pdev->preTargetHsize, &preHratio, &Hshift); calc_prescaler_ratio_shift(pdev->wndVsize, pdev->preTargetVsize, &preVratio, &Vshift); PDEBUG("preHratio = %d, Hshift = %d.\n", preHratio, Hshift); PDEBUG("preVratiod = %d, Vshift = %d.\n", preVratio, Vshift); shfactor = 10 - (Hshift + Vshift); ciprscpreratio = (shfactor<<28) // shift factor for preview pre-scaler |(preHratio<<16) // horizontal ratio of preview pre-scaler |(preVratio<<0); // vertical ratio of preview pre-scaler iowrite32(ciprscpreratio, S3C244X_CIPRSCPRERATIO); /* CIPRSCPREDST. */ preDstWidth = pdev->wndHsize / preHratio; preDstHeight = pdev->wndVsize / preVratio; PDEBUG("preDstWidth = %d, preDstHeight = %d\n", preDstWidth, preDstHeight); PDEBUG("pdev->wndHsize = %d, pdev->wndVsize = %d\n", pdev->wndHsize, pdev->wndVsize); ciprscpredst = (preDstWidth<<16) // destination width for preview pre-scaler |(preDstHeight<<0); // destination height for preview pre-scaler iowrite32(ciprscpredst, S3C244X_CIPRSCPREDST); /* CIPRSCCTRL. */ Hscale = (pdev->wndHsize >= pdev->preTargetHsize)?0:1; Vscale = (pdev->wndVsize >= pdev->preTargetVsize)?0:1; mainHratio = (pdev->wndHsize<<8)/(pdev->preTargetHsize<<Hshift); mainVratio = (pdev->wndVsize<<8)/(pdev->preTargetVsize<<Vshift); ciprscctrl = ioread32(S3C244X_CIPRSCCTRL); ciprscctrl &= (1<<30)|(1<<15); // keep preview image format (RGB565 or RGB24), and preview scaler start state. ciprscctrl |= (1<<31) // this bit should be always 1. |(Hscale<<29) // ???, horizontal scale up/down. |(Vscale<<28) // ???, vertical scale up/down. |(mainHratio<<16) // horizontal scale ratio for preview main-scaler |(mainVratio<<0); // vertical scale ratio for preview main-scaler iowrite32(ciprscctrl, S3C244X_CIPRSCCTRL); break; case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YUYV: /* CICOSCPRERATIO. */ calc_prescaler_ratio_shift(pdev->wndHsize, pdev->coTargetHsize, &preHratio, &Hshift); calc_prescaler_ratio_shift(pdev->wndVsize, pdev->coTargetVsize, &preVratio, &Vshift); shfactor = 10 - (Hshift + Vshift); cicoscpreratio = (shfactor<<28) // shift factor for codec pre-scaler |(preHratio<<16) // horizontal ratio of codec pre-scaler |(preVratio<<0); // vertical ratio of codec pre-scaler iowrite32(cicoscpreratio, S3C244X_CICOSCPRERATIO); /* CICOSCPREDST. */ preDstWidth = pdev->wndHsize / preHratio; preDstHeight = pdev->wndVsize / preVratio; cicoscpredst = (preDstWidth<<16) // destination width for codec pre-scaler |(preDstHeight<<0); // destination height for codec pre-scaler iowrite32(cicoscpredst, S3C244X_CICOSCPREDST); /* CICOSCCTRL. */ Hscale = (pdev->wndHsize >= pdev->coTargetHsize)?0:1; Vscale = (pdev->wndVsize >= pdev->coTargetVsize)?0:1; mainHratio = (pdev->wndHsize<<8)/(pdev->coTargetHsize<<Hshift); mainVratio = (pdev->wndVsize<<8)/(pdev->coTargetVsize<<Vshift); cicoscctrl = ioread32(S3C244X_CICOSCCTRL) & (1<<15); // keep codec scaler start state. cicoscctrl |= (0<<31) // not in codec scaler bypass mode. |(Hscale<<30) // ???, horizontal scale up/down. |(Vscale<<29) // ???, vertical scale up/down. |(mainHratio<<16) // horizontal scale ratio for codec main-scaler |(mainVratio<<0); // vertical scale ratio for codec main-scaler iowrite32(cicoscctrl, S3C244X_CICOSCCTRL); break; default: PDEBUG("bug here.\n"); BUG(); break; }}/* update camif registers, called only when camif ready, or ISR. */static void __inline__ update_camif_regs(struct s3c2440camif_dev * pdev){ if (!in_irq()) { if (pdev->state != CAMIF_STATE_READY) { PDEBUG("bug here.\n"); BUG(); } while(1) // wait until VSYNC is 'L' { barrier(); if ((ioread32(S3C244X_CICOSTATUS)&(1<<28)) == 0) break; } } /* WARNING: don't change the statement sort below!!! */ update_source_fmt_regs(pdev); update_target_wnd_regs(pdev); update_target_fmt_regs(pdev); update_target_zoom_regs(pdev);}/* start image capture. * * param 'stream' means capture pictures streamly or capture only one picture. */static int start_capture(struct s3c2440camif_dev * pdev, int stream){ int ret; u32 ciwdofst; u32 ciprscctrl; u32 cicoscctrl; u32 ciimgcpt; if (pdev->state != CAMIF_STATE_READY) { PDEBUG("bug here, pdev->state = %d.\n", pdev->state); BUG(); } ciwdofst = ioread32(S3C244X_CIWDOFST); ciwdofst |= (1<<30) // Clear the overflow indication flag of input CODEC FIFO Y |(1<<15) // Clear the overflow indication flag of input CODEC FIFO Cb |(1<<14) // Clear the overflow indication flag of input CODEC FIFO Cr |(1<<13) // Clear the overflow indication flag of input PREVIEW FIFO Cb |(1<<12); // Clear the overflow indication flag of input PREVIEW FIFO Cr iowrite32(ciwdofst, S3C244X_CIWDOFST); switch (formats[pdev->format].pixelformat) { case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB24: ciprscctrl = ioread32(S3C244X_CIPRSCCTRL); ciprscctrl |= 1<<15; // preview scaler start iowrite32(ciprscctrl, S3C244X_CIPRSCCTRL); spin_lock(&pdev->statelock); pdev->state = CAMIF_STATE_PREVIEWING; spin_unlock(&pdev->statelock); PDEBUG("Now in previewing state!\n"); ciimgcpt = (1<<31) // camera interface global capture enable |(1<<29); // capture enable for preview scaler. iowrite32(ciimgcpt, S3C244X_CIIMGCPT); break; case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YUYV: cicoscctrl = ioread32(S3C244X_CICOSCCTRL); cicoscctrl |= 1<<15; // codec scaler start iowrite32(cicoscctrl, S3C244X_CICOSCCTRL); spin_lock(&pdev->statelock); pdev->state = CAMIF_STATE_CODECING; spin_unlock(&pdev->statelock); PDEBUG("Now in codecing state!\n"); ciimgcpt = (1<<31) // camera interface global capture enable |(1<<30); // capture enable for codec scaler. iowrite32(ciimgcpt, S3C244X_CIIMGCPT); break; default: PDEBUG("bug here.\n"); BUG(); }// print_regs(); ret = 0; if (stream == 0) { spin_lock(&pdev->cmdlock); pdev->cmdcode = CAMIF_CMD_STOP; spin_unlock(&pdev->cmdlock); PDEBUG("wait here until capturing stops.\n"); ret = wait_event_interruptible(pdev->cmdqueue, pdev->cmdcode == CAMIF_CMD_NONE); } return ret;}/* stop image capture, always called in ISR. * P-path regs: * CIPRSCCTRL * CIPRCTRL * C-path regs: * CICOSCCTRL. * CICOCTRL * Global regs: * CIIMGCPT */static void stop_capture(struct s3c2440camif_dev * pdev){ u32 ciprscctrl; u32 ciprctrl; u32 cicoscctrl; u32 cicoctrl; PDEBUG("now in %s()\n", __FUNCTION__); spin_lock(&pdev->statelock); switch(pdev->state) { case CAMIF_STATE_PREVIEWING: /* CIPRCTRL. */ ciprctrl = ioread32(S3C244X_CIPRCTRL); ciprctrl |= 1<<2; // enable last IRQ at the end of frame capture. iowrite32(ciprctrl, S3C244X_CIPRCTRL); /* CIPRSCCTRL. */ ciprscctrl = ioread32(S3C244X_CIPRSCCTRL); ciprscctrl &= ~(1<<15); // clear preview scaler start bit. iowrite32(ciprscctrl, S3C244X_CIPRSCCTRL); /* CIIMGCPT. */ iowrite32(0, S3C244X_CIIMGCPT); pdev->state = CAMIF_STATE_READY; PDEBUG("previewing stopped!\n"); break; case CAMIF_STATE_CODECING: /* CICOCTRL. */ cicoctrl = ioread32(S3C244X_CICOCTRL); cicoctrl |= 1<<2; // enable last IRQ at the end of frame capture. iowrite32(cicoctrl, S3C244X_CICOCTRL); /* CICOSCCTRL. */ cicoscctrl = ioread32(S3C244X_CICOSCCTRL); cicoscctrl &= ~(1<<15); // clear codec scaler start bit. iowrite32(cicoscctrl, S3C244X_CICOSCCTRL); /* CIIMGCPT. */ iowrite32(0, S3C244X_CIIMGCPT); pdev->state = CAMIF_STATE_READY; PDEBUG("codecing stopped!\n"); break; default: PDEBUG("bug here.\n"); PDEBUG("now camif is in state %d\n", pdev->state); BUG(); break; } spin_unlock(&pdev->statelock);}/* update camera interface with the new config. */static void update_camif_config (struct s3c2440camif_fh * fh, u32 cmdcode){ struct s3c2440camif_dev * pdev; pdev = fh->dev; spin_lock(&pdev->statelock); switch (pdev->state) { case CAMIF_STATE_READY: spin_unlock(&pdev->statelock); // release state spinlock first. /* camif is ready, set to regs directly .... */ PDEBUG("%s(), camif ready, set regs directly.\n", __FUNCTION__); spin_lock(&pdev->cmdlock); // lock cmd spinlock update_camif_regs(fh->dev); // config the regs directly. spin_unlock(&pdev->cmdlock); // release cmd spinlock PDEBUG("command done!\n"); break; case CAMIF_STATE_PREVIEWING: spin_unlock(&pdev->statelock); // release state spinlock first. /* camif is previewing image. */ PDEBUG("command in previewing...\n"); disable_irq(IRQ_S3C2440_CAM_P); // disable cam-preview irq. spin_lock(&pdev->cmdlock); // lock cmd spinlock /* source image format. */ if (cmdcode & CAMIF_CMD_SFMT) { // ignore it, nothing to do now. } /* target image format. */ if (cmdcode & CAMIF_CMD_TFMT) { if ((formats[pdev->format].pixelformat == V4L2_PIX_FMT_RGB565) ||(formats[pdev->format].pixelformat == V4L2_PIX_FMT_RGB24)) { /* change target image format only. */ pdev->cmdcode |= CAMIF_CMD_TFMT; } else if ((formats[pdev->format].pixelformat == V4L2_PIX_FMT_YUV420) ||(formats[pdev->format].pixelformat == V4L2_PIX_FMT_YUYV)) { /* change target image format, and switch from P-path output to C-path output. */ pdev->cmdcode |= CAMIF_CMD_TFMT|CAMIF_CMD_P2C; } else { spin_unlock(&pdev->cmdlock); // unlock cmd spinlock enable_irq(IRQ_S3C2440_CAM_P); PDEBUG("bug here.\n"); BUG(); } } /* target image window offset. */ if (cmdcode & CAMIF_CMD_WND) { pdev->cmdcode |= CAMIF_CMD_WND; } /* target image zoomi & zoomout. */ if (cmdcode & CAMIF_CMD_ZOOM) { pdev->cmdcode |= CAMIF_CMD_ZOOM; } /* stop previewing. */ if (cmdcode & CAMIF_CMD_STOP) { pdev->cmdcode |= CAMIF_CMD_STOP; } spin_unlock(&pdev->cmdlock); // unlock cmd spinlock enable_irq(IRQ_S3C2440_CAM_P); // enable cam-preview irq. wait_event(pdev->cmdqueue, (pdev->cmdcode==CAMIF_CMD_NONE)); // wait until the ISR completes command. PDEBUG("command done!"); break; case CAMIF_STATE_CODECING: spin_unlock(&pdev->statelock); // release state spinlock first. /* camif is previewing image. */ PDEBUG("command in codecing...\n"); disable_irq(IRQ_S3C2440_CAM_C); // disable cam-codec irq. spin_lock(&pdev->cmdlock); // lock cmd spinlock /* source image format. */ if (cmdcode & CAMIF_CMD_SFMT) { // ignore it, nothing to do now. } /* target image format. */ if (cmdcode & CAMIF_CMD_TFMT) { if ((formats[pdev->format].pixelformat == V4L2_PIX_FMT_RGB565) ||(formats[pdev->format].pixelformat == V4L2_PIX_FMT_RGB24)) { /* change target image format only. */ pdev->cmdcode |= CAMIF_CMD_TFMT; } else if ((formats[pdev->format].pixelformat == V4L2_PIX_FMT_YUV420) ||(formats[pdev->format].pixelformat == V4L2_PIX_FMT_YUYV)) { /* change target image format, and switch from P-path output to C-path output. */ pdev->cmdcode |= CAMIF_CMD_TFMT|CAMIF_CMD_P2C; } else { spin_unlock(&pdev->cmdlock); // unlock cmd spinlock enable_irq(IRQ_S3C2440_CAM_C); // enable cam-codec irq. PDEBUG("bug here.\n"); BUG(); } } /* target image window offset. */ if (cmdcode & CAMIF_CMD_WND) { pdev->cmdcode |= CAMIF_CMD_WND; } /* target image zoomi & zoomout. */ if (cmdcode & CAMIF_CMD_ZOOM) { pdev->cmdcode |= CAMIF_CMD_ZOOM; } /* stop previewing. */ if (cmdcode & CAMIF_CMD_STOP) { pdev->cmdcode |= CAMIF_CMD_STOP; } spin_unlock(&pdev->cmdlock); // unlock cmd spinlock enable_irq(IRQ_S3C2440_CAM_C); // enable cam-codec irq. wait_event(pdev->cmdqueue, (pdev->cmdcode==CAMIF_CMD_NONE)); // wait until the ISR completes command. PDEBUG("command done!"); break; default: spin_unlock(&pdev->statelock);// release state spinlock first. PDEBUG("bug here.\n"); BUG(); break; }}/* config camif when master-open camera.*/static void init_camif_config(struct s3c2440camif_fh * fh){ struct s3c2440camif_dev * pdev; if (fh->master == 0) { PDEBUG("bug here!\n"); BUG(); } pdev = fh->dev; pdev->c_format = 2; // FIXME, C-path default format, see formats[] for detail. pdev->p_format = 0; // FIXME, P-path default format, see formats[] for detail. pdev->input = 0; // FIXME, the default input image format, see inputs[] for detail. /* the source image size (input from external camera). */ pdev->srcHsize = 1280; // FIXME, the OV9650's horizontal output pixels. pdev->srcVsize = 1024; // FIXME, the OV9650's verical output pixels. /* the windowed image size. */ pdev->wndHsize = 1280; pdev->wndVsize = 1024; /* codec-path target(output) image size. */ pdev->coTargetHsize = pdev->wndHsize; pdev->coTargetVsize = pdev->wndVsize; /* preview-path target(preview) image size. */ pdev->preTargetHsize = 240; pdev->preTargetVsize = 256; update_camif_config(fh, (u32)-1);}static void __inline__ invalid_image_buffer(void){ img_buff[0].state = CAMIF_BUFF_INVALID; img_buff[1].state = CAMIF_BUFF_INVALID; img_buff[2].state = CAMIF_BUFF_INVALID; img_buff[3].state = CAMIF_BUFF_INVALID;}/* init image buffer (only when the camif is first open). */static int __inline__ init_image_buffer(void){ int size1, size2; unsigned long size; unsigned int order; if ((img_buff[0].virt_base != (unsigned long)NULL) ||(img_buff[1].virt_base != (unsigned long)NULL) ||(img_buff[2].virt_base != (unsigned long)NULL) ||(img_buff[3].virt_base != (unsigned long)NULL)) { PDEBUG("bug here."); BUG(); } /* size1 is the max image size of codec path. */ size1 = MAX_C_WIDTH * MAX_C_HEIGHT * formats[3].depth / 8; /* size2 is the max image size of preview path. */ size2 = MAX_P_WIDTH * MAX_P_HEIGHT * formats[1].depth / 8; size = (size1 > size2)?size1:size2; PDEBUG("each image buffer is %dKBytes.\n", (int)(size/1024)); order = get_order(size); img_buff[0].order = order; img_buff[0].virt_base = __get_free_pages(GFP_KERNEL|GFP_DMA, img_buff[0].order); if (img_buff[0].virt_base == (unsigned long)NULL) { PDEBUG("__get_free_pages() for img_buff[0] fail!\n"); goto error0; } img_buff[0].phy_base = img_buff[0].virt_base - PAGE_OFFSET + PHYS_OFFSET; // the DMA address. img_buff[1].order = order; img_buff[1].virt_base = __get_free_pages(GFP_KERNEL|GFP_DMA, img_buff[1].order); if (img_buff[1].virt_base == (unsigned long)NULL) { PDEBUG("__get_free_pages() for img_buff[1] fail!\n"); goto error1; } img_buff[1].phy_base = img_buff[1].virt_base - PAGE_OFFSET + PHYS_OFFSET; // the DMA address. img_buff[2].order = order; img_buff[2].virt_base = __get_free_pages(GFP_KERNEL|GFP_DMA, img_buff[2].order); if (img_buff[2].virt_base == (unsigned long)NULL) { PDEBUG("__get_free_pages() for img_buff[2] fail!\n"); goto error2; } img_buff[2].phy_base = img_buff[2].virt_base - PAGE_OFFSET + PHYS_OFFSET; // the DMA address. img_buff[3].order = order; img_buff[3].virt_base = __get_free_pages(GFP_KERNEL|GFP_DMA, img_buff[3].order); if (img_buff[3].virt_base == (unsigned long)NULL) { PDEBUG("__get_free_pages() for img_buff[3] fail!\n"); goto error3; } img_buff[3].phy_base = img_buff[3].virt_base - PAGE_OFFSET + PHYS_OFFSET; // the DMA address. PDEBUG("get pages for img_buff[0..3] done.\n"); invalid_image_buffer();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -