/** * fimc_capture_config_update - apply the camera interface configuration * * To be called from within the interrupt handler with fimc.slock * spinlock held. It updates the camera pixel crop, rotation and * image flip in H/W. */ int fimc_capture_config_update(struct fimc_ctx *ctx) { struct fimc_dev *fimc = ctx->fimc_dev; int ret; if (!test_bit(ST_CAPT_APPLY_CFG, &fimc->state)) return 0; spin_lock(&ctx->slock); fimc_hw_set_camera_offset(fimc, &ctx->s_frame); ret = fimc_set_scaler_info(ctx); if (ret == 0) { fimc_hw_set_prescaler(ctx); fimc_hw_set_mainscaler(ctx); fimc_hw_set_target_format(ctx); fimc_hw_set_rotation(ctx); fimc_prepare_dma_offset(ctx, &ctx->d_frame); fimc_hw_set_out_dma(ctx); if (fimc->variant->has_alpha) fimc_hw_set_rgb_alpha(ctx); clear_bit(ST_CAPT_APPLY_CFG, &fimc->state); } spin_unlock(&ctx->slock); return ret; }
static int start_streaming(struct vb2_queue *q) { struct fimc_ctx *ctx = q->drv_priv; struct fimc_dev *fimc = ctx->fimc_dev; struct s5p_fimc_isp_info *isp_info; int ret; fimc_hw_reset(fimc); ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_stream, 1); if (ret && ret != -ENOIOCTLCMD) return ret; ret = fimc_prepare_config(ctx, ctx->state); if (ret) return ret; isp_info = &fimc->pdata->isp_info[fimc->vid_cap.input_index]; fimc_hw_set_camera_type(fimc, isp_info); fimc_hw_set_camera_source(fimc, isp_info); fimc_hw_set_camera_offset(fimc, &ctx->s_frame); if (ctx->state & FIMC_PARAMS) { ret = fimc_set_scaler_info(ctx); if (ret) { err("Scaler setup error"); return ret; } fimc_hw_set_input_path(ctx); fimc_hw_set_prescaler(ctx); fimc_hw_set_mainscaler(ctx); fimc_hw_set_target_format(ctx); fimc_hw_set_rotation(ctx); fimc_hw_set_effect(ctx); } fimc_hw_set_output_path(ctx); fimc_hw_set_out_dma(ctx); INIT_LIST_HEAD(&fimc->vid_cap.pending_buf_q); INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q); fimc->vid_cap.active_buf_cnt = 0; fimc->vid_cap.frame_count = 0; fimc->vid_cap.buf_index = 0; set_bit(ST_CAPT_PEND, &fimc->state); return 0; }
static int fimc_capture_hw_init(struct fimc_dev *fimc) { struct fimc_ctx *ctx = fimc->vid_cap.ctx; struct fimc_pipeline *p = &fimc->pipeline; struct fimc_sensor_info *sensor; unsigned long flags; int ret = 0; if (p->subdevs[IDX_SENSOR] == NULL || ctx == NULL) return -ENXIO; if (ctx->s_frame.fmt == NULL) return -EINVAL; sensor = v4l2_get_subdev_hostdata(p->subdevs[IDX_SENSOR]); spin_lock_irqsave(&fimc->slock, flags); fimc_prepare_dma_offset(ctx, &ctx->d_frame); fimc_set_yuv_order(ctx); fimc_hw_set_camera_polarity(fimc, &sensor->pdata); fimc_hw_set_camera_type(fimc, &sensor->pdata); fimc_hw_set_camera_source(fimc, &sensor->pdata); fimc_hw_set_camera_offset(fimc, &ctx->s_frame); ret = fimc_set_scaler_info(ctx); if (!ret) { fimc_hw_set_input_path(ctx); fimc_hw_set_prescaler(ctx); fimc_hw_set_mainscaler(ctx); fimc_hw_set_target_format(ctx); fimc_hw_set_rotation(ctx); fimc_hw_set_effect(ctx); fimc_hw_set_output_path(ctx); fimc_hw_set_out_dma(ctx); if (fimc->variant->has_alpha) fimc_hw_set_rgb_alpha(ctx); clear_bit(ST_CAPT_APPLY_CFG, &fimc->state); } spin_unlock_irqrestore(&fimc->slock, flags); return ret; }
static void fimc_device_run(void *priv) { struct vb2_buffer *src_vb, *dst_vb; struct fimc_ctx *ctx = priv; struct fimc_frame *sf, *df; struct fimc_dev *fimc; unsigned long flags; int ret; if (WARN(!ctx, "Null context\n")) return; fimc = ctx->fimc_dev; spin_lock_irqsave(&fimc->slock, flags); set_bit(ST_M2M_PEND, &fimc->state); sf = &ctx->s_frame; df = &ctx->d_frame; if (ctx->state & FIMC_PARAMS) { /* Prepare the DMA offsets for scaler */ fimc_prepare_dma_offset(ctx, sf); fimc_prepare_dma_offset(ctx, df); } src_vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx); ret = fimc_prepare_addr(ctx, src_vb, sf, &sf->paddr); if (ret) goto dma_unlock; dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); ret = fimc_prepare_addr(ctx, dst_vb, df, &df->paddr); if (ret) goto dma_unlock; dst_vb->v4l2_buf.timestamp = src_vb->v4l2_buf.timestamp; /* Reconfigure hardware if the context has changed. */ if (fimc->m2m.ctx != ctx) { ctx->state |= FIMC_PARAMS; fimc->m2m.ctx = ctx; } if (ctx->state & FIMC_PARAMS) { fimc_set_yuv_order(ctx); fimc_hw_set_input_path(ctx); fimc_hw_set_in_dma(ctx); ret = fimc_set_scaler_info(ctx); if (ret) goto dma_unlock; fimc_hw_set_prescaler(ctx); fimc_hw_set_mainscaler(ctx); fimc_hw_set_target_format(ctx); fimc_hw_set_rotation(ctx); fimc_hw_set_effect(ctx); fimc_hw_set_out_dma(ctx); if (fimc->drv_data->alpha_color) fimc_hw_set_rgb_alpha(ctx); fimc_hw_set_output_path(ctx); } fimc_hw_set_input_addr(fimc, &sf->paddr); fimc_hw_set_output_addr(fimc, &df->paddr, -1); fimc_activate_capture(ctx); ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP); fimc_hw_activate_input_dma(fimc, true); dma_unlock: spin_unlock_irqrestore(&fimc->slock, flags); }
static int fimc_cap_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { struct s3c_fimc_isp_info *isp_info; struct fimc_ctx *ctx = priv; struct fimc_dev *fimc = ctx->fimc_dev; int ret = -EBUSY; if (mutex_lock_interruptible(&fimc->lock)) return -ERESTARTSYS; if (fimc_capture_active(fimc) || !fimc->vid_cap.sd) goto s_unlock; if (!(ctx->state & FIMC_DST_FMT)) { v4l2_err(&fimc->vid_cap.v4l2_dev, "Format is not set\n"); ret = -EINVAL; goto s_unlock; } ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_stream, 1); if (ret && ret != -ENOIOCTLCMD) goto s_unlock; ret = fimc_prepare_config(ctx, ctx->state); if (ret) goto s_unlock; isp_info = fimc->pdata->isp_info[fimc->vid_cap.input_index]; fimc_hw_set_camera_type(fimc, isp_info); fimc_hw_set_camera_source(fimc, isp_info); fimc_hw_set_camera_offset(fimc, &ctx->s_frame); if (ctx->state & FIMC_PARAMS) { ret = fimc_set_scaler_info(ctx); if (ret) { err("Scaler setup error"); goto s_unlock; } fimc_hw_set_input_path(ctx); fimc_hw_set_scaler(ctx); fimc_hw_set_target_format(ctx); fimc_hw_set_rotation(ctx); fimc_hw_set_effect(ctx); } fimc_hw_set_output_path(ctx); fimc_hw_set_out_dma(ctx); INIT_LIST_HEAD(&fimc->vid_cap.pending_buf_q); INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q); fimc->vid_cap.active_buf_cnt = 0; fimc->vid_cap.frame_count = 0; set_bit(ST_CAPT_PEND, &fimc->state); ret = videobuf_streamon(&fimc->vid_cap.vbq); s_unlock: mutex_unlock(&fimc->lock); return ret; }