int fimc_hwset_input_colorspace(struct fimc_control *ctrl, u32 pixelformat) { u32 cfg = readl(ctrl->regs + S3C_MSCTRL); cfg &= ~S3C_MSCTRL_INFORMAT_RGB; /* Color format setting */ switch (pixelformat) { case V4L2_PIX_FMT_YUV420: /* fall through */ case V4L2_PIX_FMT_NV12: /* fall through */ case V4L2_PIX_FMT_NV12T: cfg |= S3C_MSCTRL_INFORMAT_YCBCR420; break; case V4L2_PIX_FMT_YUYV: cfg |= S3C_MSCTRL_INFORMAT_YCBCR422_1PLANE; break; case V4L2_PIX_FMT_RGB565: /* fall through */ case V4L2_PIX_FMT_RGB32: cfg |= S3C_MSCTRL_INFORMAT_RGB; break; default: fimc_err("%s: Invalid pixelformt : %d\n", __func__, pixelformat); return -EINVAL; } writel(cfg, ctrl->regs + S3C_MSCTRL); return 0; }
int fimc_hwset_camera_polarity(struct fimc_control *ctrl) { struct s3c_platform_camera *cam = ctrl->cam; u32 cfg; if (!cam) { fimc_err("%s: no active camera\n", __func__); return -ENODEV; } cfg = readl(ctrl->regs + S3C_CIGCTRL); cfg &= ~(S3C_CIGCTRL_INVPOLPCLK | S3C_CIGCTRL_INVPOLVSYNC | S3C_CIGCTRL_INVPOLHREF | S3C_CIGCTRL_INVPOLHSYNC); if (cam->inv_pclk) cfg |= S3C_CIGCTRL_INVPOLPCLK; if (cam->inv_vsync) cfg |= S3C_CIGCTRL_INVPOLVSYNC; if (cam->inv_href) cfg |= S3C_CIGCTRL_INVPOLHREF; if (cam->inv_hsync) cfg |= S3C_CIGCTRL_INVPOLHSYNC; writel(cfg, ctrl->regs + S3C_CIGCTRL); return 0; }
int fimc_hw_wait_stop_input_dma(struct fimc_control *ctrl) { struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); u32 cfg = readl(ctrl->regs + S3C_MSCTRL); u32 status = S3C_MSCTRL_GET_INDMA_STATUS(cfg); int i = FIMC_FIFOOFF_CNT, j = FIMC_FIFOOFF_CNT; if (pdata->hw_ver == 0x40) return 0; while (status && i--) { cfg = readl(ctrl->regs + S3C_MSCTRL); status = S3C_MSCTRL_GET_INDMA_STATUS(cfg); } cfg = readl(ctrl->regs + S3C_CISTATUS); status = S3C_CISTATUS_GET_ENVID_STATUS(cfg); while (status && j--) { cfg = readl(ctrl->regs + S3C_CISTATUS); status = S3C_CISTATUS_GET_ENVID_STATUS(cfg); } if ((i < 1) || (j < 1)) { fimc_err("Fail : %s\n", __func__); return -EBUSY; } else { return 0; } }
static int fimc_check_pos(struct fimc_control *ctrl, struct fimc_ctx *ctx, struct v4l2_format *f) { if (ctx->win.w.width != f->fmt.win.w.width) { fimc_err("%s: cannot change width(%d,%d)\n", __func__, ctx->win.w.width, f->fmt.win.w.width); return -EINVAL; } else if (ctx->win.w.height != f->fmt.win.w.height) { fimc_err("%s: cannot change height(%d,%d)\n", __func__, ctx->win.w.height, f->fmt.win.w.height); return -EINVAL; } return 0; }
int fimc_hwset_camera_offset(struct fimc_control *ctrl) { struct s3c_platform_camera *cam = ctrl->cam; struct v4l2_rect *rect = &cam->window; u32 cfg, h1, h2, v1, v2; if (!cam) { fimc_err("%s: no active camera\n", __func__); return -ENODEV; } h1 = rect->left; h2 = cam->width - rect->width - rect->left; v1 = rect->top; v2 = cam->height - rect->height - rect->top; cfg = readl(ctrl->regs + S3C_CIWDOFST); cfg &= ~(S3C_CIWDOFST_WINHOROFST_MASK | S3C_CIWDOFST_WINVEROFST_MASK); cfg |= S3C_CIWDOFST_WINHOROFST(h1); cfg |= S3C_CIWDOFST_WINVEROFST(v1); cfg |= S3C_CIWDOFST_WINOFSEN; writel(cfg, ctrl->regs + S3C_CIWDOFST); cfg = 0; cfg |= S3C_CIWDOFST2_WINHOROFST2(h2); cfg |= S3C_CIWDOFST2_WINVEROFST2(v2); writel(cfg, ctrl->regs + S3C_CIWDOFST2); return 0; }
int fimc_hwset_input_yuv(struct fimc_control *ctrl, u32 pixelformat) { u32 cfg = readl(ctrl->regs + S3C_MSCTRL); cfg &= ~(S3C_MSCTRL_ORDER2P_SHIFT_MASK | S3C_MSCTRL_C_INT_IN_2PLANE | S3C_MSCTRL_ORDER422_YCBYCR); switch (pixelformat) { case V4L2_PIX_FMT_YUV420: cfg |= S3C_MSCTRL_C_INT_IN_3PLANE; break; case V4L2_PIX_FMT_YUYV: /* fall through */ cfg |= S3C_MSCTRL_ORDER422_YCBYCR; break; case V4L2_PIX_FMT_NV12: /* fall through */ case V4L2_PIX_FMT_NV12T: cfg |= S3C_MSCTRL_ORDER2P_LSB_CBCR; cfg |= S3C_MSCTRL_C_INT_IN_2PLANE; break; case V4L2_PIX_FMT_RGB565: /* fall through */ case V4L2_PIX_FMT_RGB32: break; default: fimc_err("%s: Invalid pixelformt : %d\n", __func__, pixelformat); } writel(cfg, ctrl->regs + S3C_MSCTRL); return 0; }
int fimc43_hwset_camera_type(struct fimc_control *ctrl) { struct s3c_platform_camera *cam = ctrl->cam; u32 cfg; if (!cam) { fimc_err("%s: no active camera\n", __func__); return -ENODEV; } cfg = readl(ctrl->regs + S3C_CIGCTRL); cfg &= ~(S3C_CIGCTRL_TESTPATTERN_MASK | S3C_CIGCTRL_SELCAM_ITU_MASK | S3C_CIGCTRL_SELCAM_MIPI_MASK | S3C_CIGCTRL_SELCAM_FIMC_MASK | S3C_CIGCTRL_SELWB_CAMIF_MASK); /* Interface selection */ if (cam->id == CAMERA_WB) { cfg |= S3C_CIGCTRL_SELWB_CAMIF_WRITEBACK; } else if (cam->type == CAM_TYPE_MIPI) { cfg |= S3C_CIGCTRL_SELCAM_FIMC_MIPI; /* C110/V210 Support only MIPI A support */ cfg |= S3C_CIGCTRL_SELCAM_MIPI_A; /* FIXME: Temporary MIPI CSIS Data 32 bit aligned */ if (ctrl->cap->fmt.pixelformat == V4L2_PIX_FMT_JPEG) writel((MIPI_USER_DEF_PACKET_1 | (0x1 << 8)), ctrl->regs + S3C_CSIIMGFMT); else writel(cam->fmt | (0x1 << 8), ctrl->regs + S3C_CSIIMGFMT); } else if (cam->type == CAM_TYPE_ITU) { if (cam->id == CAMERA_PAR_A) cfg |= S3C_CIGCTRL_SELCAM_ITU_A; else cfg |= S3C_CIGCTRL_SELCAM_ITU_B; /* switch to ITU interface */ cfg |= S3C_CIGCTRL_SELCAM_FIMC_ITU; } else { fimc_err("%s: invalid camera bus type selected\n", __func__); return -EINVAL; } writel(cfg, ctrl->regs + S3C_CIGCTRL); return 0; }
int fimc_hwset_output_colorspace(struct fimc_control *ctrl, u32 pixelformat) { struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); u32 cfg; if (pdata->hw_ver != 0x40) { if (pixelformat == V4L2_PIX_FMT_YUV444) { cfg = readl(ctrl->regs + S3C_CIEXTEN); cfg |= S3C_CIEXTEN_YUV444_OUT; writel(cfg, ctrl->regs + S3C_CIEXTEN); return 0; } else { cfg = readl(ctrl->regs + S3C_CIEXTEN); cfg &= ~S3C_CIEXTEN_YUV444_OUT; writel(cfg, ctrl->regs + S3C_CIEXTEN); } } cfg = readl(ctrl->regs + S3C_CITRGFMT); cfg &= ~S3C_CITRGFMT_OUTFORMAT_MASK; switch (pixelformat) { case V4L2_PIX_FMT_JPEG: break; case V4L2_PIX_FMT_RGB565: /* fall through */ case V4L2_PIX_FMT_RGB32: cfg |= S3C_CITRGFMT_OUTFORMAT_RGB; break; case V4L2_PIX_FMT_YUYV: /* fall through */ case V4L2_PIX_FMT_UYVY: /* fall through */ case V4L2_PIX_FMT_VYUY: /* fall through */ case V4L2_PIX_FMT_YVYU: cfg |= S3C_CITRGFMT_OUTFORMAT_YCBCR422_1PLANE; break; case V4L2_PIX_FMT_NV16: /* fall through */ case V4L2_PIX_FMT_NV61: /* fall through */ case V4L2_PIX_FMT_YUV422P: cfg |= S3C_CITRGFMT_OUTFORMAT_YCBCR422; break; case V4L2_PIX_FMT_YUV420: /* fall through */ case V4L2_PIX_FMT_NV12: /* fall through */ case V4L2_PIX_FMT_NV12T: /* fall through */ case V4L2_PIX_FMT_NV21: cfg |= S3C_CITRGFMT_OUTFORMAT_YCBCR420; break; default: fimc_err("%s: invalid pixel format\n", __func__); break; } writel(cfg, ctrl->regs + S3C_CITRGFMT); return 0; }
int fimc50_hwset_input_offset(struct fimc_control *ctrl, u32 pixelformat, struct v4l2_rect *bounds, struct v4l2_rect *crop) { u32 cfg_y = 0, cfg_cb = 0, cfg_cr = 0; if (crop->left || crop->top || (bounds->width != crop->width) || (bounds->height != crop->height)) { switch (pixelformat) { case V4L2_PIX_FMT_YUYV: /* fall through */ case V4L2_PIX_FMT_UYVY: /* fall through */ case V4L2_PIX_FMT_YVYU: /* fall through */ case V4L2_PIX_FMT_VYUY: /* fall through */ case V4L2_PIX_FMT_RGB565: cfg_y |= S3C_CIIYOFF_HORIZONTAL(crop->left); cfg_y |= S3C_CIIYOFF_VERTICAL(crop->top); break; case V4L2_PIX_FMT_RGB32: cfg_y |= S3C_CIIYOFF_HORIZONTAL(crop->left); cfg_y |= S3C_CIIYOFF_VERTICAL(crop->top); break; case V4L2_PIX_FMT_NV12: /* fall through*/ case V4L2_PIX_FMT_NV21: /* fall through*/ case V4L2_PIX_FMT_NV12T: cfg_y |= S3C_CIIYOFF_HORIZONTAL(crop->left); cfg_y |= S3C_CIIYOFF_VERTICAL(crop->top); cfg_cb |= S3C_CIICBOFF_HORIZONTAL(crop->left); cfg_cb |= S3C_CIICBOFF_VERTICAL(crop->top); break; case V4L2_PIX_FMT_NV16: /* fall through */ case V4L2_PIX_FMT_NV61: cfg_y |= S3C_CIIYOFF_HORIZONTAL(crop->left); cfg_y |= S3C_CIIYOFF_VERTICAL(crop->top); cfg_cb |= S3C_CIICBOFF_HORIZONTAL(crop->left); cfg_cb |= S3C_CIICBOFF_VERTICAL(crop->top); break; case V4L2_PIX_FMT_YUV420: cfg_y |= S3C_CIIYOFF_HORIZONTAL(crop->left); cfg_y |= S3C_CIIYOFF_VERTICAL(crop->top); cfg_cb |= S3C_CIICBOFF_HORIZONTAL(crop->left); cfg_cb |= S3C_CIICBOFF_VERTICAL(crop->top); cfg_cr |= S3C_CIICROFF_HORIZONTAL(crop->left); cfg_cr |= S3C_CIICROFF_VERTICAL(crop->top); break; default: fimc_err("%s: Invalid pixelformt : %d\n", __func__, pixelformat); } } writel(cfg_y, ctrl->regs + S3C_CIIYOFF); writel(cfg_cb, ctrl->regs + S3C_CIICBOFF); writel(cfg_cr, ctrl->regs + S3C_CIICROFF); return 0; }
int fimc_s_fmt_vid_overlay(struct file *filp, void *fh, struct v4l2_format *f) { struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id; struct fimc_ctx *ctx; int ret = -1; ctx = &ctrl->out->ctx[ctx_id]; fimc_info1("%s: called\n", __func__); switch (ctx->status) { case FIMC_STREAMON: ret = fimc_check_pos(ctrl, ctx, f); if (ret < 0) { fimc_err("When FIMC is running, " "you can only move the position.\n"); return -EBUSY; } ret = fimc_try_fmt_overlay(filp, fh, f); if (ret < 0) return ret; ctx->win = f->fmt.win; fimc_change_fifo_position(ctrl, ctx); break; case FIMC_STREAMOFF: ret = fimc_try_fmt_overlay(filp, fh, f); if (ret < 0) return ret; ctx->win = f->fmt.win; break; default: fimc_err("FIMC is running\n"); fimc_err("%s::FIMC is running(%d)\n", __func__, ctx->status); return -EBUSY; } return ret; }
static inline int fimc_mmap_out_src(struct file *filp, struct vm_area_struct *vma) { struct fimc_control *ctrl = filp->private_data; u32 start_phy_addr = 0; u32 size = vma->vm_end - vma->vm_start; u32 pfn, idx = vma->vm_pgoff; u32 buf_length = 0; int pri_data = 0; buf_length = ctrl->out->src[idx].length[FIMC_ADDR_Y] + \ ctrl->out->src[idx].length[FIMC_ADDR_CB] + \ ctrl->out->src[idx].length[FIMC_ADDR_CR]; if (size > buf_length) { fimc_err("Requested mmap size is too big\n"); return -EINVAL; } pri_data = (ctrl->id * 0x10) + idx; vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); vma->vm_flags |= VM_RESERVED; vma->vm_ops = &fimc_mmap_ops; vma->vm_private_data = (void *)pri_data; if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED)) { fimc_err("writable mapping must be shared\n"); return -EINVAL; } start_phy_addr = ctrl->out->src[idx].base[FIMC_ADDR_Y]; pfn = __phys_to_pfn(start_phy_addr); if (remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot)) { fimc_err("mmap fail\n"); return -EINVAL; } vma->vm_ops->open(vma); ctrl->out->src[idx].flags |= V4L2_BUF_FLAG_MAPPED; return 0; }
int fimc_hwset_camera_type(struct fimc_control *ctrl) { struct s3c_platform_camera *cam = ctrl->cam; u32 cfg; if (!cam) { fimc_err("%s: no active camera\n", __func__); return -ENODEV; } cfg = readl(ctrl->regs + S3C_CIGCTRL); cfg &= ~(S3C_CIGCTRL_TESTPATTERN_MASK | S3C_CIGCTRL_SELCAM_ITU_MASK | S3C_CIGCTRL_SELCAM_MIPI_MASK | S3C_CIGCTRL_SELCAM_FIMC_MASK | S3C_CIGCTRL_SELWB_CAMIF_MASK); /* Interface selection */ if (cam->id == CAMERA_WB) { cfg |= S3C_CIGCTRL_SELWB_CAMIF_WRITEBACK; } else if (cam->type == CAM_TYPE_MIPI) { cfg |= S3C_CIGCTRL_SELCAM_FIMC_MIPI; /* FIXME: temporary only A support */ cfg |= S3C_CIGCTRL_SELCAM_MIPI_A; /* FIXME: temporary hardcoded value used */ writel(cam->fmt | (0x1 << 8), ctrl->regs + S3C_CSIIMGFMT); } else if (cam->type == CAM_TYPE_ITU) { if (cam->id == CAMERA_PAR_A) cfg |= S3C_CIGCTRL_SELCAM_ITU_A; else cfg |= S3C_CIGCTRL_SELCAM_ITU_B; /* switch to ITU interface */ cfg |= S3C_CIGCTRL_SELCAM_FIMC_ITU; } else { fimc_err("%s: invalid camera bus type selected\n", __func__); return -EINVAL; } writel(cfg, ctrl->regs + S3C_CIGCTRL); return 0; }
static int fimc_g_ext_ctrls(struct file *filp, void *fh, struct v4l2_ext_controls *c) { struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; int ret = -1; if (ctrl->cap != NULL) { ret = fimc_g_ext_ctrls_capture(fh, c); } else { fimc_err("%s: Invalid case\n", __func__); return -EINVAL; } return ret; }
static int fimc_streamoff(struct file *filp, void *fh, enum v4l2_buf_type i) { struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; int ret = -1; if (i == V4L2_BUF_TYPE_VIDEO_CAPTURE) { ret = fimc_streamoff_capture(ctrl); } else if (i == V4L2_BUF_TYPE_VIDEO_OUTPUT) { ret = fimc_streamoff_output(fh); } else { fimc_err("V4L2_BUF_TYPE_VIDEO_CAPTURE and " "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); ret = -EINVAL; } return ret; }
static int fimc_querybuf(struct file *filp, void *fh, struct v4l2_buffer *b) { struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; int ret = -1; if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { ret = fimc_querybuf_capture(ctrl, b); } else if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { ret = fimc_querybuf_output(fh, b); } else { fimc_err("V4L2_BUF_TYPE_VIDEO_CAPTURE and " "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); ret = -EINVAL; } return ret; }
static int fimc_s_crop(struct file *filp, void *fh, struct v4l2_crop *a) { struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; int ret = -1; if (a->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { ret = fimc_s_crop_capture(fh, a); } else if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { ret = fimc_s_crop_output(fh, a); } else { fimc_err("V4L2_BUF_TYPE_VIDEO_CAPTURE and " "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); ret = -EINVAL; } return ret; }
static inline int fimc_mmap_out_dst(struct file *filp, struct vm_area_struct *vma, u32 idx) { struct fimc_control *ctrl = filp->private_data; unsigned long pfn = 0, size; int ret = 0; size = vma->vm_end - vma->vm_start; vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); vma->vm_flags |= VM_RESERVED; pfn = __phys_to_pfn(ctrl->out->dst[idx].base[0]); ret = remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot); if (ret != 0) fimc_err("remap_pfn_range fail.\n"); return ret; }
static int fimc_streamon(struct file *filp, void *fh, enum v4l2_buf_type i) { struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; struct s3c_platform_fimc *pdata; int ret = -1; pdata = to_fimc_plat(ctrl->dev); if (i == V4L2_BUF_TYPE_VIDEO_CAPTURE) { ret = fimc_streamon_capture(fh); } else if (i == V4L2_BUF_TYPE_VIDEO_OUTPUT) { ret = fimc_streamon_output(fh); } else { fimc_err("V4L2_BUF_TYPE_VIDEO_CAPTURE and " "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); ret = -EINVAL; } return ret; }
int fimc_hwset_output_colorspace(struct fimc_control *ctrl, u32 pixelformat) { u32 cfg; cfg = readl(ctrl->regs + S3C_CITRGFMT); cfg &= ~S3C_CITRGFMT_OUTFORMAT_MASK; switch (pixelformat) { case V4L2_PIX_FMT_RGB565: /* fall through */ case V4L2_PIX_FMT_RGB32: cfg |= S3C_CITRGFMT_OUTFORMAT_RGB; break; case V4L2_PIX_FMT_YUYV: /* fall through */ case V4L2_PIX_FMT_UYVY: /* fall through */ case V4L2_PIX_FMT_VYUY: /* fall through */ case V4L2_PIX_FMT_YVYU: /* fall through */ cfg |= S3C_CITRGFMT_OUTFORMAT_YCBCR422_1PLANE; break; case V4L2_PIX_FMT_YUV422P: cfg |= S3C_CITRGFMT_OUTFORMAT_YCBCR422; break; case V4L2_PIX_FMT_YUV420: /* fall through */ case V4L2_PIX_FMT_NV12: /* fall through */ case V4L2_PIX_FMT_NV21: /* fall through */ case V4L2_PIX_FMT_NV16: /* fall through */ case V4L2_PIX_FMT_NV61: cfg |= S3C_CITRGFMT_OUTFORMAT_YCBCR420; break; default: fimc_err("%s: invalid pixel format\n", __func__); break; } writel(cfg, ctrl->regs + S3C_CITRGFMT); return 0; }
int fimc_hw_wait_winoff(struct fimc_control *ctrl) { struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); u32 cfg = readl(ctrl->regs + S3C_CISTATUS); u32 status = S3C_CISTATUS_GET_LCD_STATUS(cfg); int i = FIMC_FIFOOFF_CNT; if (pdata->hw_ver == 0x40) return 0; while (status && i--) { cfg = readl(ctrl->regs + S3C_CISTATUS); status = S3C_CISTATUS_GET_LCD_STATUS(cfg); } if (i < 1) { fimc_err("Fail : %s\n", __func__); return -EBUSY; } else return 0; }
static int fimc_g_ctrl(struct file *filp, void *fh, struct v4l2_control *c) { struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); int ret = -1; /* can get hw version at any time */ if (c->id == V4L2_CID_FIMC_VERSION) { c->value = pdata->hw_ver; return 0; } if (ctrl->cap != NULL) { ret = fimc_g_ctrl_capture(fh, c); } else if (ctrl->out != NULL) { ret = fimc_g_ctrl_output(fh, c); } else { fimc_err("%s: Invalid case\n", __func__); return -EINVAL; } return ret; }
static inline int fimc_resume_out(struct fimc_control *ctrl) { int index = -1, ret = -1; switch (ctrl->out->overlay.mode) { case FIMC_OVERLAY_NONE: if (ctrl->status == FIMC_ON_IDLE_SLEEP) { ret = fimc_outdev_set_param(ctrl); if (ret < 0) fimc_err("Fail: fimc_outdev_set_param\n"); ctrl->status = FIMC_STREAMON_IDLE; } else if (ctrl->status == FIMC_OFF_SLEEP) { ctrl->status = FIMC_STREAMOFF; } else { fimc_err("%s: Undefined status : %d\n", __func__, ctrl->status); } break; case FIMC_OVERLAY_DMA_AUTO: if (ctrl->status == FIMC_ON_IDLE_SLEEP) { fimc_outdev_resume_dma(ctrl); ret = fimc_outdev_set_param(ctrl); if (ret < 0) fimc_err("Fail: fimc_outdev_set_param\n"); ctrl->status = FIMC_STREAMON_IDLE; } else if (ctrl->status == FIMC_OFF_SLEEP) { ctrl->status = FIMC_STREAMOFF; } else { fimc_err("%s: Undefined status : %d\n", __func__, ctrl->status); } break; case FIMC_OVERLAY_DMA_MANUAL: if (ctrl->status == FIMC_ON_IDLE_SLEEP) { ret = fimc_outdev_set_param(ctrl); if (ret < 0) fimc_err("Fail: fimc_outdev_set_param\n"); ctrl->status = FIMC_STREAMON_IDLE; } else if (ctrl->status == FIMC_OFF_SLEEP) { ctrl->status = FIMC_STREAMOFF; } else { fimc_err("%s: Undefined status : %d\n", __func__, ctrl->status); } break; case FIMC_OVERLAY_FIFO: if (ctrl->status == FIMC_ON_SLEEP) { ctrl->status = FIMC_READY_ON; ret = fimc_outdev_set_param(ctrl); if (ret < 0) fimc_err("Fail: fimc_outdev_set_param\n"); #if defined(CONFIG_VIDEO_IPC) if (ctrl->out->pix.field == V4L2_FIELD_INTERLACED_TB) ipc_start(); #endif index = ctrl->out->idx.active; fimc_outdev_set_src_addr(ctrl, ctrl->out->src[index].base); ret = fimc_start_fifo(ctrl); if (ret < 0) fimc_err("Fail: fimc_start_fifo\n"); ctrl->status = FIMC_STREAMON; } else if (ctrl->status == FIMC_OFF_SLEEP) { ctrl->status = FIMC_STREAMOFF; } else { fimc_err("%s: Undefined status : %d\n", __func__, ctrl->status); } break; } return 0; }
static inline u32 fimc_irq_out_dma(struct fimc_control *ctrl) { struct fimc_buf_set buf_set; u32 next = 0, wakeup = 1; int idx = ctrl->out->idx.active; int ret = -1, i; if (ctrl->status == FIMC_READY_OFF) { ctrl->out->idx.active = -1; ctrl->status = FIMC_STREAMOFF; return wakeup; } /* Attach done buffer to outgoing queue. */ ret = fimc_attach_out_queue(ctrl, idx); if (ret < 0) fimc_err("Failed: fimc_attach_out_queue\n"); if(ctrl->out->overlay.mode == FIMC_OVERLAY_DMA_AUTO) { ret = s3cfb_direct_ioctl(ctrl->id, S3CFB_SET_WIN_ADDR, \ (unsigned long)ctrl->out->dst[idx].base[FIMC_ADDR_Y]); if (ret < 0) { fimc_err("direct_ioctl(S3CFB_SET_WIN_ADDR) fail\n"); return -EINVAL; } if(ctrl->fb.is_enable == 0) { ret = s3cfb_direct_ioctl(ctrl->id, S3CFB_SET_WIN_ON, \ (unsigned long)NULL); if (ret < 0) { fimc_err("direct_ioctl(S3CFB_SET_WIN_ON) fail\n"); return -EINVAL; } ctrl->fb.is_enable = 1; } } /* Detach buffer from incomming queue. */ ret = fimc_detach_in_queue(ctrl, &next); if (ret == 0) { /* There is a buffer in incomming queue. */ fimc_outdev_set_src_addr(ctrl, ctrl->out->src[next].base); memset(&buf_set, 0x00, sizeof(buf_set)); buf_set.base[FIMC_ADDR_Y] = ctrl->out->dst[next].base[FIMC_ADDR_Y]; for (i = 0; i < FIMC_PHYBUFS; i++) fimc_hwset_output_address(ctrl, &buf_set, i); ret = fimc_outdev_start_camif(ctrl); if (ret < 0) fimc_err("Fail: fimc_start_camif\n"); ctrl->out->idx.active = next; ctrl->status = FIMC_STREAMON; } else { /* There is no buffer in incomming queue. */ ctrl->out->idx.active = -1; ctrl->status = FIMC_STREAMON_IDLE; } return wakeup; }
static struct fimc_control *fimc_register_controller(struct platform_device *pdev) { struct s3c_platform_fimc *pdata; struct fimc_control *ctrl; struct resource *res; int id, mdev_id; id = pdev->id; mdev_id = S3C_MDEV_FIMC0 + id; pdata = to_fimc_plat(&pdev->dev); ctrl = get_fimc_ctrl(id); ctrl->id = id; ctrl->dev = &pdev->dev; ctrl->vd = &fimc_video_device[id]; ctrl->vd->minor = id; /* alloc from bank1 as default */ ctrl->mem.base = s3c_get_media_memory_bank(mdev_id, 1); ctrl->mem.size = s3c_get_media_memsize_bank(mdev_id, 1); ctrl->mem.curr = ctrl->mem.base; ctrl->status = FIMC_STREAMOFF; ctrl->limit = &fimc_limits[id]; ctrl->log = FIMC_LOG_DEFAULT; sprintf(ctrl->name, "%s%d", FIMC_NAME, id); strcpy(ctrl->vd->name, ctrl->name); atomic_set(&ctrl->in_use, 0); mutex_init(&ctrl->lock); mutex_init(&ctrl->v4l2_lock); spin_lock_init(&ctrl->lock_in); spin_lock_init(&ctrl->lock_out); init_waitqueue_head(&ctrl->wq); /* get resource for io memory */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { fimc_err("%s: failed to get io memory region\n", __func__); return NULL; } /* request mem region */ res = request_mem_region(res->start, res->end - res->start + 1, pdev->name); if (!res) { fimc_err("%s: failed to request io memory region\n", __func__); return NULL; } /* ioremap for register block */ ctrl->regs = ioremap(res->start, res->end - res->start + 1); if (!ctrl->regs) { fimc_err("%s: failed to remap io region\n", __func__); return NULL; } /* irq */ ctrl->irq = platform_get_irq(pdev, 0); if (request_irq(ctrl->irq, fimc_irq, IRQF_DISABLED, ctrl->name, ctrl)) fimc_err("%s: request_irq failed\n", __func__); fimc_hwset_reset(ctrl); return ctrl; }
/* * Assign v4l2 device and subdev to fimc * it is called per every fimc ctrl registering */ static int fimc_configure_subdev(struct platform_device *pdev, int id) { struct s3c_platform_fimc *pdata; struct s3c_platform_camera *cam; struct i2c_adapter *i2c_adap; struct i2c_board_info *i2c_info; struct v4l2_subdev *sd; struct fimc_control *ctrl; unsigned short addr; char *name; ctrl = get_fimc_ctrl(id); pdata = to_fimc_plat(&pdev->dev); cam = pdata->camera[id]; /* Subdev registration */ if (cam) { i2c_adap = i2c_get_adapter(cam->i2c_busnum); if (!i2c_adap) { fimc_info1("subdev i2c_adapter missing-skip " "registration\n"); } i2c_info = cam->info; if (!i2c_info) { fimc_err("%s: subdev i2c board info missing\n", __func__); return -ENODEV; } name = i2c_info->type; if (!name) { fimc_info1("subdev i2c dirver name missing-skip " "registration\n"); return -ENODEV; } addr = i2c_info->addr; if (!addr) { fimc_info1("subdev i2c address missing-skip " "registration\n"); return -ENODEV; } /* * NOTE: first time subdev being registered, * s_config is called and try to initialize subdev device * but in this point, we are not giving MCLK and power to subdev * so nothing happens but pass platform data through */ sd = v4l2_i2c_new_subdev_board(&ctrl->v4l2_dev, i2c_adap, name, i2c_info, &addr); if (!sd) { fimc_err("%s: v4l2 subdev board registering failed\n", __func__); } /* Assign camera device to fimc */ fimc_dev->camera[cam->id] = cam; /* Assign subdev to proper camera device pointer */ fimc_dev->camera[cam->id]->sd = sd; } return 0; }
static int fimc_release(struct file *filp) { struct fimc_control *ctrl = filp->private_data; struct s3c_platform_fimc *pdata; struct fimc_overlay_buf *buf; struct mm_struct *mm = current->mm; int ret = 0, i; ctrl->mem.curr = ctrl->mem.base; atomic_dec(&ctrl->in_use); filp->private_data = NULL; pdata = to_fimc_plat(ctrl->dev); /* FIXME: turning off actual working camera */ if (ctrl->cam) { /* shutdown the MCLK */ clk_disable(ctrl->cam->clk); /* shutdown */ if (ctrl->cam->cam_power) ctrl->cam->cam_power(0); /* should be initialized at the next open */ ctrl->cam->initialized = 0; } if (ctrl->cap) { for (i = 0; i < FIMC_CAPBUFS; i++) { fimc_dma_free(ctrl, &ctrl->cap->bufs[i], 0); fimc_dma_free(ctrl, &ctrl->cap->bufs[i], 1); } kfree(ctrl->cap); ctrl->cap = NULL; } if (ctrl->out) { if (ctrl->status != FIMC_STREAMOFF) { ret = fimc_outdev_stop_streaming(ctrl); if (ret < 0) fimc_err("Fail: fimc_stop_streaming\n"); ctrl->status = FIMC_STREAMOFF; } buf = &ctrl->out->overlay.buf; for (i = 0; i < FIMC_OUTBUFS; i++) { if (buf->vir_addr[i]) { ret = do_munmap(mm, buf->vir_addr[i], buf->size[i]); if (ret < 0) fimc_err("%s: do_munmap fail\n", __func__); } } kfree(ctrl->out); ctrl->out = NULL; } if (pdata->clk_off) pdata->clk_off(to_platform_device(ctrl->dev), ctrl->clk); fimc_info1("%s: successfully released\n", __func__); return 0; }
int fimc_s_fbuf(struct file *filp, void *fh, struct v4l2_framebuffer *fb) { struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id; struct fimc_ctx *ctx; u32 bpp = 1; u32 format = fb->fmt.pixelformat; ctx = &ctrl->out->ctx[ctx_id]; fimc_info1("%s: called. width(%d), height(%d)\n", __func__, fb->fmt.width, fb->fmt.height); ctx->fbuf.capability = V4L2_FBUF_CAP_EXTERNOVERLAY; ctx->fbuf.flags = 0; ctx->fbuf.base = fb->base; if (ctx->overlay.mode == FIMC_OVLY_NONE_MULTI_BUF) { ctx->fbuf.fmt.width = fb->fmt.width; ctx->fbuf.fmt.height = fb->fmt.height; ctx->fbuf.fmt.pixelformat = fb->fmt.pixelformat; switch (format) { case V4L2_PIX_FMT_YUV420: /* fall through */ case V4L2_PIX_FMT_NV12: bpp = 1; break; case V4L2_PIX_FMT_RGB565: bpp = 2; break; case V4L2_PIX_FMT_RGB32: bpp = 4; break; } ctx->fbuf.fmt.bytesperline = fb->fmt.width * bpp; ctx->fbuf.fmt.sizeimage = fb->fmt.sizeimage; ctx->fbuf.fmt.colorspace = V4L2_COLORSPACE_SMPTE170M; ctx->fbuf.fmt.priv = 0; } else if (fb->base) { ctx->fbuf.fmt.width = fb->fmt.width; ctx->fbuf.fmt.height = fb->fmt.height; ctx->fbuf.fmt.pixelformat = fb->fmt.pixelformat; switch (format) { case V4L2_PIX_FMT_YUV420: /* fall through */ case V4L2_PIX_FMT_NV12: bpp = 1; break; case V4L2_PIX_FMT_RGB565: bpp = 2; break; case V4L2_PIX_FMT_RGB32: bpp = 4; break; } ctx->fbuf.fmt.bytesperline = fb->fmt.width * bpp; ctx->fbuf.fmt.sizeimage = fb->fmt.sizeimage; ctx->fbuf.fmt.colorspace = V4L2_COLORSPACE_SMPTE170M; ctx->fbuf.fmt.priv = 0; ctx->overlay.mode = FIMC_OVLY_NONE_SINGLE_BUF; } else { int i; unsigned int bits_per_pixel = 0; struct s3cfb_window *win = NULL; ctx->overlay.fb_id = -1; for (i = 0; i < num_registered_fb; i++) { win = (struct s3cfb_window *)registered_fb[i]->par; if (win->id == ctrl->id) { ctx->overlay.fb_id = i; bits_per_pixel = registered_fb[i]->var.bits_per_pixel; fimc_info2("%s: overlay.fb_id = %d\n", __func__, ctx->overlay.fb_id); break; } } if (-1 == ctx->overlay.fb_id) { fimc_err("%s: fb[%d] is not registered. " \ "must be registered for overlay\n", __func__, ctrl->id); return -1; } if (1 == win->enabled) { fimc_err("%s: fb[%d] is already being used. " \ "must be not used for overlay\n", __func__, ctrl->id); return -1; } ctx->overlay.mode = FIMC_OVLY_NOT_FIXED; switch (ctx->rotate) { case 0: case 180: ctx->fbuf.fmt.width = ctrl->fb.lcd_hres; ctx->fbuf.fmt.height = ctrl->fb.lcd_vres; break; case 90: case 270: ctx->fbuf.fmt.width = ctrl->fb.lcd_vres; ctx->fbuf.fmt.height = ctrl->fb.lcd_hres; break; } if (bits_per_pixel == 32) ctx->fbuf.fmt.pixelformat = V4L2_PIX_FMT_RGB32; else ctx->fbuf.fmt.pixelformat = V4L2_PIX_FMT_RGB565; } return 0; }
static int __devinit fimc_probe(struct platform_device *pdev) { struct s3c_platform_fimc *pdata; struct fimc_control *ctrl; int ret; if (!fimc_dev) { fimc_dev = kzalloc(sizeof(*fimc_dev), GFP_KERNEL); if (!fimc_dev) { dev_err(&pdev->dev, "%s: not enough memory\n", __func__); goto err_fimc; } } ctrl = fimc_register_controller(pdev); if (!ctrl) { printk(KERN_ERR "%s: cannot register fimc\n", __func__); goto err_fimc; } pdata = to_fimc_plat(&pdev->dev); if (pdata->cfg_gpio) pdata->cfg_gpio(pdev); /* V4L2 device-subdev registration */ ret = v4l2_device_register(&pdev->dev, &ctrl->v4l2_dev); if (ret) { fimc_err("%s: v4l2 device register failed\n", __func__); goto err_v4l2; } /* things to initialize once */ if (!fimc_dev->initialized) { ret = fimc_init_global(pdev); if (ret) goto err_global; } /* v4l2 subdev configuration */ ret = fimc_configure_subdev(pdev, ctrl->id); if (ret) { fimc_err("%s: subdev[%d] registering failed\n", __func__, ctrl->id); } /* video device register */ ret = video_register_device(ctrl->vd, VFL_TYPE_GRABBER, ctrl->id); if (ret) { fimc_err("%s: cannot register video driver\n", __func__); goto err_global; } video_set_drvdata(ctrl->vd, ctrl); ret = device_create_file(&(pdev->dev), &dev_attr_log_level); if (ret < 0) fimc_err("failed to add sysfs entries\n"); fimc_info1("controller %d registered successfully\n", ctrl->id); return 0; err_global: clk_disable(ctrl->clk); clk_put(ctrl->clk); err_v4l2: fimc_unregister_controller(pdev); err_fimc: return -EINVAL; }