示例#1
0
static int gsc_cap_stop_capture(struct gsc_dev *gsc)
{
	int ret;
	if (!gsc_cap_active(gsc)) {
		gsc_warn("already stopped\n");
		return 0;
	}
	gsc_dbg("G-Scaler h/w disable control");
	gsc_hw_enable_control(gsc, false);
	clear_bit(ST_CAPT_STREAM, &gsc->state);
	ret = gsc_wait_stop(gsc);
	if (ret) {
		gsc_err("GSCALER_OP_STATUS is operating\n");
		return ret;
	}

	return gsc_capture_state_cleanup(gsc);
}
示例#2
0
static int gsc_capture_subdev_s_stream(struct v4l2_subdev *sd, int enable)
{
	struct gsc_dev *gsc = v4l2_get_subdevdata(sd);
	struct gsc_capture_device *cap = &gsc->cap;
	struct gsc_ctx *ctx = cap->ctx;

	if (enable) {
		gsc_dbg("start");
		gsc_hw_set_frm_done_irq_mask(gsc, false);
		gsc_hw_set_overflow_irq_mask(gsc, false);
		gsc_hw_set_one_frm_mode(gsc, false);
		gsc_hw_set_gsc_irq_enable(gsc, true);

		if (gsc->pipeline.disp) {
			gsc_hw_set_sysreg_writeback(gsc);
			gsc_hw_set_pixelasync_reset_wb(gsc);
		} else {
			gsc_hw_set_pxlasync_camif_lo_mask(gsc, true);
		}

		gsc_hw_set_input_path(ctx);
		gsc_hw_set_in_size(ctx);
		gsc_hw_set_in_image_format(ctx);
		gsc_hw_set_output_path(ctx);
		gsc_hw_set_out_size(ctx);
		gsc_hw_set_out_image_format(ctx);
		gsc_hw_set_global_alpha(ctx);

		gsc_capture_scaler_info(ctx);
		gsc_hw_set_prescaler(ctx);
		gsc_hw_set_mainscaler(ctx);
		gsc_hw_set_h_coef(ctx);
		gsc_hw_set_v_coef(ctx);

		set_bit(ST_CAPT_PEND, &gsc->state);

		gsc_hw_enable_control(gsc, true);
		set_bit(ST_CAPT_STREAM, &gsc->state);
	} else {
		gsc_dbg("stop");
	}

	return 0;
}
示例#3
0
static void gsc_capture_buf_queue(struct vb2_buffer *vb)
{
	struct gsc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
	struct gsc_dev *gsc = ctx->gsc_dev;
	struct gsc_capture_device *cap = &gsc->cap;
	struct exynos_md *mdev = gsc->mdev[MDEV_CAPTURE];
	int min_bufs, ret;
	unsigned long flags;

	spin_lock_irqsave(&gsc->slock, flags);
	ret = gsc_capture_set_addr(vb);
	if (ret)
		gsc_err("Failed to prepare output addr");

	gsc_hw_set_output_buf_masking(gsc, vb->v4l2_buf.index, 0);

	min_bufs = cap->reqbufs_cnt > 1 ? 2 : 1;

	if (vb2_is_streaming(&cap->vbq) &&
		(gsc_hw_get_nr_unmask_bits(gsc) >= min_bufs) &&
		!test_bit(ST_CAPT_STREAM, &gsc->state)) {
		if (!test_and_set_bit(ST_CAPT_PIPE_STREAM, &gsc->state)) {
			spin_unlock_irqrestore(&gsc->slock, flags);
			if (!mdev->is_flite_on)
				gsc_cap_pipeline_s_stream(gsc, 1);
			else
				v4l2_subdev_call(gsc->cap.sd_cap, video,
							s_stream, 1);
			return;
		}

		if (!test_bit(ST_CAPT_STREAM, &gsc->state)) {
			gsc_dbg("G-Scaler h/w enable control");
			gsc_hw_enable_control(gsc, true);
			set_bit(ST_CAPT_STREAM, &gsc->state);
		}
	}
	spin_unlock_irqrestore(&gsc->slock, flags);

	return;
}
示例#4
0
static void gsc_capture_buf_queue(struct vb2_buffer *vb)
{
	struct gsc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
	struct gsc_dev *gsc = ctx->gsc_dev;
	struct gsc_capture_device *cap = &gsc->cap;
	int min_bufs, ret;
	unsigned long flags;

	spin_lock_irqsave(&gsc->slock, flags);
	ret = gsc_capture_set_addr(vb);
	if (ret)
		gsc_err("Failed to prepare output addr");

	if (!test_bit(ST_CAPT_SUSPENDED, &gsc->state)) {
		gsc_info("buf_index : %d", vb->v4l2_buf.index);
		gsc_hw_set_output_buf_masking(gsc, vb->v4l2_buf.index, 0);
	}

	min_bufs = cap->reqbufs_cnt > 1 ? 2 : 1;

	if (vb2_is_streaming(&cap->vbq) &&
		(gsc_hw_get_nr_unmask_bits(gsc) >= min_bufs) &&
		!test_bit(ST_CAPT_STREAM, &gsc->state)) {
		if (!test_and_set_bit(ST_CAPT_PIPE_STREAM, &gsc->state)) {
			spin_unlock_irqrestore(&gsc->slock, flags);
			gsc_cap_pipeline_s_stream(gsc, 1);
			return;
		}

		if (!test_bit(ST_CAPT_STREAM, &gsc->state)) {
			gsc_info("G-Scaler h/w enable control");
			gsc_hw_enable_control(gsc, true);
			set_bit(ST_CAPT_STREAM, &gsc->state);
		}
	}
	spin_unlock_irqrestore(&gsc->slock, flags);

	return;
}
示例#5
0
static int gsc_capture_close(struct file *file)
{
	struct gsc_dev *gsc = video_drvdata(file);

	gsc_dbg("pid: %d, state: 0x%lx", task_pid_nr(current), gsc->state);

	if (--gsc->cap.refcnt == 0) {
		clear_bit(ST_CAPT_OPEN, &gsc->state);
		gsc_dbg("G-Scaler h/w disable control");
		gsc_hw_enable_control(gsc, false);
		clear_bit(ST_CAPT_STREAM, &gsc->state);
		gsc_cap_pipeline_shutdown(gsc);
	}

	if (gsc->cap.refcnt == 0) {
		vb2_queue_release(&gsc->cap.vbq);
		gsc_ctrls_delete(gsc->cap.ctx);
	}

	pm_runtime_put_sync(&gsc->pdev->dev);

	return v4l2_fh_release(file);
}
示例#6
0
static void gsc_m2m_device_run(void *priv)
{
	struct gsc_ctx *ctx = priv;
	struct gsc_dev *gsc;
	unsigned long flags;
	int ret;
	bool is_set = false;

	if (WARN(!ctx, "null hardware context\n"))
		return;

	gsc = ctx->gsc_dev;
	spin_lock_irqsave(&gsc->slock, flags);

	set_bit(ST_M2M_PEND, &gsc->state);

	/* Reconfigure hardware if the context has changed. */
	if (gsc->m2m.ctx != ctx) {
		pr_debug("gsc->m2m.ctx = 0x%p, current_ctx = 0x%p",
				gsc->m2m.ctx, ctx);
		ctx->state |= GSC_PARAMS;
		gsc->m2m.ctx = ctx;
	}

	is_set = ctx->state & GSC_CTX_STOP_REQ;
	if (is_set) {
		ctx->state &= ~GSC_CTX_STOP_REQ;
		ctx->state |= GSC_CTX_ABORT;
		wake_up(&gsc->irq_queue);
		goto put_device;
	}

	ret = gsc_get_bufs(ctx);
	if (ret) {
		pr_err("Wrong address");
		goto put_device;
	}

	gsc_set_prefbuf(gsc, &ctx->s_frame);
	gsc_hw_set_input_addr(gsc, &ctx->s_frame.addr, GSC_M2M_BUF_NUM);
	gsc_hw_set_output_addr(gsc, &ctx->d_frame.addr, GSC_M2M_BUF_NUM);

	if (ctx->state & GSC_PARAMS) {
		gsc_hw_set_input_buf_masking(gsc, GSC_M2M_BUF_NUM, false);
		gsc_hw_set_output_buf_masking(gsc, GSC_M2M_BUF_NUM, false);
		gsc_hw_set_frm_done_irq_mask(gsc, false);
		gsc_hw_set_gsc_irq_enable(gsc, true);

		if (gsc_set_scaler_info(ctx)) {
			pr_err("Scaler setup error");
			goto put_device;
		}

		gsc_hw_set_input_path(ctx);
		gsc_hw_set_in_size(ctx);
		gsc_hw_set_in_image_format(ctx);

		gsc_hw_set_output_path(ctx);
		gsc_hw_set_out_size(ctx);
		gsc_hw_set_out_image_format(ctx);

		gsc_hw_set_prescaler(ctx);
		gsc_hw_set_mainscaler(ctx);
		gsc_hw_set_rotation(ctx);
		gsc_hw_set_global_alpha(ctx);
	}

	/* update shadow registers */
	gsc_hw_set_sfr_update(ctx);

	ctx->state &= ~GSC_PARAMS;
	gsc_hw_enable_control(gsc, true);

	spin_unlock_irqrestore(&gsc->slock, flags);
	return;

put_device:
	ctx->state &= ~GSC_PARAMS;
	spin_unlock_irqrestore(&gsc->slock, flags);
}
示例#7
0
static void gsc_m2m_device_run(void *priv)
{
	struct gsc_ctx *ctx = priv;
	struct gsc_dev *gsc;
	unsigned long flags;
	int ret;
	bool is_set = false;

	if (WARN(!ctx, "null hardware context\n"))
		return;

	gsc = ctx->gsc_dev;

	if (in_irq())
		ret = pm_runtime_get(&gsc->pdev->dev);
	else
		ret = pm_runtime_get_sync(&gsc->pdev->dev);

	if (ret < 0) {
		gsc_err("fail to pm_runtime_get");
		return;
	}

	spin_lock_irqsave(&ctx->slock, flags);
	/* Reconfigure hardware if the context has changed. */
	if (gsc->m2m.ctx != ctx) {
		gsc_dbg("gsc->m2m.ctx = 0x%p, current_ctx = 0x%p",
			  gsc->m2m.ctx, ctx);
		ctx->state |= GSC_PARAMS;
		gsc->m2m.ctx = ctx;
	}

	is_set = (ctx->state & GSC_CTX_STOP_REQ) ? 1 : 0;
	ctx->state &= ~GSC_CTX_STOP_REQ;
	if (is_set) {
		wake_up(&gsc->irq_queue);
		goto put_device;
	}

	ret = gsc_fill_addr(ctx);
	if (ret) {
		gsc_err("Wrong address");
		goto put_device;
	}

	if (ctx->state & GSC_PARAMS) {
		gsc_hw_set_sw_reset(gsc);
		ret = gsc_wait_reset(gsc);
		if (ret < 0) {
			gsc_err("gscaler s/w reset timeout");
			goto put_device;
		}
		gsc_hw_set_input_buf_masking(gsc, GSC_M2M_BUF_NUM, false);
		gsc_hw_set_output_buf_masking(gsc, GSC_M2M_BUF_NUM, false);
		gsc_hw_set_frm_done_irq_mask(gsc, false);
		gsc_hw_set_deadlock_irq_mask(gsc, false);
		gsc_hw_set_read_slave_error_mask(gsc, false);
		gsc_hw_set_write_slave_error_mask(gsc, false);
		gsc_hw_set_gsc_irq_enable(gsc, true);
		gsc_hw_set_one_frm_mode(gsc, true);
		gsc_hw_set_freerun_clock_mode(gsc, false);

		if (gsc_set_scaler_info(ctx)) {
			gsc_err("Scaler setup error");
			goto put_device;
		}

		gsc_hw_set_input_path(ctx);
		gsc_hw_set_in_size(ctx);
		gsc_hw_set_in_image_format(ctx);

		gsc_hw_set_output_path(ctx);
		gsc_hw_set_out_size(ctx);
		gsc_hw_set_out_image_format(ctx);

		gsc_hw_set_prescaler(ctx);
		gsc_hw_set_mainscaler(ctx);
		gsc_hw_set_h_coef(ctx);
		gsc_hw_set_v_coef(ctx);
		if (ctx->scaler.is_scaled_down)
			gsc_hw_set_output_rotation(ctx);
		else
			gsc_hw_set_input_rotation(ctx);
		gsc_hw_set_global_alpha(ctx);
		if (is_rotation) {
			ret = gsc_check_rotation_size(ctx);
			if (ret < 0)
				goto put_device;
		}
	}

	gsc_hw_set_input_addr(gsc, &ctx->s_frame.addr, GSC_M2M_BUF_NUM);
	gsc_hw_set_output_addr(gsc, &ctx->d_frame.addr, GSC_M2M_BUF_NUM);

	ctx->state &= ~GSC_PARAMS;

	if (!test_and_set_bit(ST_M2M_RUN, &gsc->state)) {
		/* One frame mode sequence
		 GSCALER_ON on -> GSCALER_OP_STATUS is operating ->
		 GSCALER_ON off */
		gsc_hw_enable_control(gsc, true);
#ifdef GSC_PERF
		gsc->start_time = sched_clock();
#endif
		ret = gsc_wait_operating(gsc);
		if (ret < 0) {
			gsc_err("gscaler wait operating timeout");
			goto put_device;
		}
		gsc->op_timer.expires = (jiffies + 2 * HZ);
		mod_timer(&gsc->op_timer, gsc->op_timer.expires);
	}

	spin_unlock_irqrestore(&ctx->slock, flags);

	iovmm_set_fault_handler(&gsc->pdev->dev,
			gsc_sysmmu_m2m_fault_handler, ctx);

	return;

put_device:
	ctx->state &= ~GSC_PARAMS;
	spin_unlock_irqrestore(&ctx->slock, flags);
	pm_runtime_put_sync(&gsc->pdev->dev);
}
示例#8
0
static void gsc_m2m_device_run(void *priv)
{
	struct gsc_ctx *ctx = priv;
	struct gsc_dev *gsc;
	unsigned long flags;
	int ret;
	bool is_set = false;

	if (WARN(!ctx, "null hardware context\n"))
		return;

	gsc = ctx->gsc_dev;

	if (!in_irq()) {
		pm_runtime_get_sync(&gsc->pdev->dev);
		gsc->runtime_get_cnt++;
	} else {
		pm_runtime_get(&gsc->pdev->dev);
		gsc->runtime_get_cnt++;
		gsc_info("irq context");
	}

#ifdef CONFIG_SOC_EXYNOS5420
	if (!(readl(EXYNOS5_CLKSRC_TOP5) & (1 << 28))) {
		if (clk_set_parent(gsc->clock[CLK_CHILD],
			gsc->clock[CLK_PARENT])) {
			u32 reg = readl(EXYNOS5_CLKSRC_TOP5);
			reg |= (1 << 28);
			writel(reg, EXYNOS5_CLKSRC_TOP5);
			gsc_err("Unable to set parent of gsc");
		}
		gsc_err("get_cnt : %d, put_cnt : %d",
			gsc->runtime_get_cnt, gsc->runtime_put_cnt);
		gsc_err("state : 0x%lx", gsc->state);
	}
#endif
	spin_lock_irqsave(&ctx->slock, flags);
	/* Reconfigure hardware if the context has changed. */
	if (gsc->m2m.ctx != ctx) {
		gsc_dbg("gsc->m2m.ctx = 0x%p, current_ctx = 0x%p",
			  gsc->m2m.ctx, ctx);
		ctx->state |= GSC_PARAMS;
		gsc->m2m.ctx = ctx;
	}

	is_set = (ctx->state & GSC_CTX_STOP_REQ) ? 1 : 0;
	ctx->state &= ~GSC_CTX_STOP_REQ;
	if (is_set) {
		wake_up(&gsc->irq_queue);
		goto put_device;
	}

	ret = gsc_fill_addr(ctx);
	if (ret) {
		gsc_err("Wrong address");
		goto put_device;
	}

	if (!gsc->protected_content) {
		struct gsc_frame *frame = &ctx->s_frame;
		exynos_sysmmu_set_pbuf(&gsc->pdev->dev, frame->fmt->nr_comp,
				ctx->prebuf);
	}

	if (ctx->state & GSC_PARAMS) {
		gsc_hw_set_sw_reset(gsc);
		ret = gsc_wait_reset(gsc);
		if (ret < 0) {
			gsc_err("gscaler s/w reset timeout");
			goto put_device;
		}
		gsc_hw_set_input_buf_masking(gsc, GSC_M2M_BUF_NUM, false);
		gsc_hw_set_output_buf_masking(gsc, GSC_M2M_BUF_NUM, false);
		gsc_hw_set_frm_done_irq_mask(gsc, false);
		gsc_hw_set_gsc_irq_enable(gsc, true);
		gsc_hw_set_one_frm_mode(gsc, true);
		gsc_hw_set_freerun_clock_mode(gsc, false);

		if (gsc_set_scaler_info(ctx)) {
			gsc_err("Scaler setup error");
			goto put_device;
		}

		gsc_hw_set_input_path(ctx);
		gsc_hw_set_in_size(ctx);
		gsc_hw_set_in_image_format(ctx);

		gsc_hw_set_output_path(ctx);
		gsc_hw_set_out_size(ctx);
		gsc_hw_set_out_image_format(ctx);

		gsc_hw_set_prescaler(ctx);
		gsc_hw_set_mainscaler(ctx);
		gsc_hw_set_h_coef(ctx);
		gsc_hw_set_v_coef(ctx);
		gsc_hw_set_rotation(ctx);
		gsc_hw_set_global_alpha(ctx);
	}

	gsc_hw_set_input_addr(gsc, &ctx->s_frame.addr, GSC_M2M_BUF_NUM);
	gsc_hw_set_output_addr(gsc, &ctx->d_frame.addr, GSC_M2M_BUF_NUM);

	ctx->state &= ~GSC_PARAMS;

	if (!test_and_set_bit(ST_M2M_RUN, &gsc->state)) {
		/* One frame mode sequence
		 GSCALER_ON on -> GSCALER_OP_STATUS is operating ->
		 GSCALER_ON off */
		gsc_hw_enable_control(gsc, true);
#ifdef GSC_PERF
		gsc->start_time = sched_clock();
#endif
		ret = gsc_wait_operating(gsc);
		if (ret < 0) {
			gsc_err("gscaler wait operating timeout");
			goto put_device;
		}
		gsc->op_timer.expires = (jiffies + 2 * HZ);
		add_timer(&gsc->op_timer);
	}

	spin_unlock_irqrestore(&ctx->slock, flags);
	return;

put_device:
	ctx->state &= ~GSC_PARAMS;
	spin_unlock_irqrestore(&ctx->slock, flags);
	pm_runtime_put_sync(&gsc->pdev->dev);
}
static void gsc_capture_buf_queue(struct vb2_buffer *vb)
{
	struct gsc_input_buf *buf
		= container_of(vb, struct gsc_input_buf, vb);
	struct vb2_queue *q = vb->vb2_queue;
	struct gsc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
	struct gsc_dev *gsc = ctx->gsc_dev;
	int ret;

	if (vb->acquire_fence) {
		gsc_dbg("acquire fence has..");
		ret = sync_fence_wait(vb->acquire_fence, 100);
		sync_fence_put(vb->acquire_fence);
		vb->acquire_fence = NULL;
		if (ret < 0) {
			gsc_err("synce_fence_wait() timeout");
			return;
		}
	}

	if (!q->streaming) {
		gsc_info("gsc-wb initialize");
		INIT_LIST_HEAD(&gsc->cap.active_buf_q);
		ret = v4l2_subdev_call(gsc->cap.sd, video,
						s_stream, 1);
		if (ret) {
			gsc_err("gsc s_stream failed");
			return;
		}
	}

	ret = gsc_cap_set_addr(gsc, ctx, buf, vb->v4l2_buf.index);
	if (ret) {
		gsc_err("Failed to prepare output addr");
		return;
	}

	if (!test_and_set_bit(ST_CAPT_RUN, &gsc->state)) {
		ret = gsc_set_scaler_info(ctx);
		if (ret) {
			gsc_err("Scaler setup error");
			return;
		}
		gsc_hw_set_in_size(ctx);
		gsc_hw_set_out_size(ctx);
		gsc_hw_set_prescaler(ctx);
		gsc_hw_set_mainscaler(ctx);
		gsc_hw_set_h_coef(ctx);
		gsc_hw_set_v_coef(ctx);

		gsc_hw_set_output_rotation(ctx);

		gsc_hw_set_global_alpha(ctx);
		if (is_rotation) {
			ret = gsc_check_rotation_size(ctx);
			if (ret < 0) {
				gsc_err("Scaler setup error");
				return;
			}
		}

		gsc_hw_set_sfr_update(ctx);
		gsc_hw_enable_control(gsc, true);
		ret = gsc_wait_operating(gsc);
		if (ret < 0) {
			gsc_err("gscaler wait operating timeout");
			return;
		}
		gsc_dbg("gsc-wb start");
	} else {
		gsc_err();
	}
}
示例#10
0
static void gsc_m2m_device_run(void *priv)
{
	struct gsc_ctx *ctx = priv;
	struct gsc_dev *gsc;
	unsigned long flags;
	int ret = 0;
	bool is_set = false;

	if (WARN(!ctx, "null hardware context\n"))
		return;

	gsc = ctx->gsc_dev;

	spin_lock_irqsave(&ctx->slock, flags);
	/* Reconfigure hardware if the context has changed. */
	if (gsc->m2m.ctx != ctx) {
		gsc_dbg("gsc->m2m.ctx = 0x%p, current_ctx = 0x%p",
			  gsc->m2m.ctx, ctx);
		ctx->state |= GSC_PARAMS;
		gsc->m2m.ctx = ctx;
	}

	is_set = (ctx->state & GSC_CTX_STOP_REQ) ? 1 : 0;
	ctx->state &= ~GSC_CTX_STOP_REQ;
	if (is_set) {
		wake_up(&gsc->irq_queue);
		goto put_device;
	}

	ret = gsc_get_bufs(ctx);
	if (ret) {
		gsc_err("Wrong address");
		goto put_device;
	}

	gsc_set_prefbuf(gsc, ctx->s_frame);
	gsc_hw_set_input_addr(gsc, &ctx->s_frame.addr, GSC_M2M_BUF_NUM);
	gsc_hw_set_output_addr(gsc, &ctx->d_frame.addr, GSC_M2M_BUF_NUM);

	if (ctx->state & GSC_PARAMS) {
		gsc_hw_set_input_buf_masking(gsc, GSC_M2M_BUF_NUM, false);
		gsc_hw_set_output_buf_masking(gsc, GSC_M2M_BUF_NUM, false);
		gsc_hw_set_frm_done_irq_mask(gsc, false);
		gsc_hw_set_gsc_irq_enable(gsc, true);

		if (gsc_set_scaler_info(ctx)) {
			gsc_err("Scaler setup error");
			goto put_device;
		}

		gsc_hw_set_input_path(ctx);
		gsc_hw_set_in_size(ctx);
		gsc_hw_set_in_image_format(ctx);

		gsc_hw_set_output_path(ctx);
		gsc_hw_set_out_size(ctx);
		gsc_hw_set_out_image_format(ctx);

		gsc_hw_set_prescaler(ctx);
		gsc_hw_set_mainscaler(ctx);
		gsc_hw_set_rotation(ctx);
		gsc_hw_set_global_alpha(ctx);
	}
	/* When you update SFRs in the middle of operating
	gsc_hw_set_sfr_update(ctx);
	*/

	ctx->state &= ~GSC_PARAMS;

	if (!test_and_set_bit(ST_M2M_RUN, &gsc->state)) {
		/* One frame mode sequence
		 GSCALER_ON on -> GSCALER_OP_STATUS is operating ->
		 GSCALER_ON off */
		gsc_hw_enable_control(gsc, true);
		ret = gsc_wait_operating(gsc);
		if (ret < 0) {
			gsc_err("gscaler wait operating timeout");
			goto put_device;
		}
		gsc_hw_enable_control(gsc, false);
	}

	spin_unlock_irqrestore(&ctx->slock, flags);
	return;

put_device:
	ctx->state &= ~GSC_PARAMS;
	spin_unlock_irqrestore(&ctx->slock, flags);
}