Beispiel #1
0
static int isp_video_s_fmt_mplane(struct file *file, void *priv,
					struct v4l2_format *f)
{
	struct fimc_isp *isp = video_drvdata(file);
	struct fimc_is *is = fimc_isp_to_is(isp);
	struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
	const struct fimc_fmt *ifmt = NULL;
	struct param_dma_output *dma = __get_isp_dma2(is);

	__isp_video_try_fmt(isp, pixm, &ifmt);

	if (WARN_ON(ifmt == NULL))
		return -EINVAL;

	dma->format = DMA_OUTPUT_FORMAT_BAYER;
	dma->order = DMA_OUTPUT_ORDER_GB_BG;
	dma->plane = ifmt->memplanes;
	dma->bitwidth = ifmt->depth[0];
	dma->width = pixm->width;
	dma->height = pixm->height;

	fimc_is_mem_barrier();

	isp->video_capture.format = ifmt;
	isp->video_capture.pixfmt = *pixm;

	return 0;
}
Beispiel #2
0
static void isp_video_capture_stop_streaming(struct vb2_queue *q)
{
	struct fimc_isp *isp = vb2_get_drv_priv(q);
	struct fimc_is *is = fimc_isp_to_is(isp);
	struct param_dma_output *dma = __get_isp_dma2(is);
	int ret;

	ret = fimc_pipeline_call(&isp->video_capture.ve, set_stream, 0);
	if (ret < 0)
		return;

	dma->cmd = DMA_OUTPUT_COMMAND_DISABLE;
	dma->notify_dma_done = DMA_OUTPUT_NOTIFY_DMA_DONE_DISABLE;
	dma->buffer_number = 0;
	dma->buffer_address = 0;
	dma->dma_out_mask = 0;

	fimc_is_set_param_bit(is, PARAM_ISP_DMA2_OUTPUT);
	__fimc_is_hw_update_param(is, PARAM_ISP_DMA2_OUTPUT);

	ret = fimc_is_itf_s_param(is, false);
	if (ret < 0)
		dev_warn(&is->pdev->dev, "%s: DMA stop failed\n", __func__);

	fimc_is_hw_set_isp_buf_mask(is, 0);

	clear_bit(ST_ISP_VID_CAP_BUF_PREP, &isp->state);
	clear_bit(ST_ISP_VID_CAP_STREAMING, &isp->state);

	isp->video_capture.buf_count = 0;
}
Beispiel #3
0
static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd,
				   struct v4l2_subdev_fh *fh,
				   struct v4l2_subdev_format *fmt)
{
	struct fimc_isp *isp = v4l2_get_subdevdata(sd);
	struct fimc_is *is = fimc_isp_to_is(isp);
	struct v4l2_mbus_framefmt *mf = &fmt->format;
	int ret = 0;

	isp_dbg(1, sd, "%s: pad%d: code: 0x%x, %dx%d\n",
		 __func__, fmt->pad, mf->code, mf->width, mf->height);

	mutex_lock(&isp->subdev_lock);
	__isp_subdev_try_format(isp, fh, fmt);

	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
		mf = v4l2_subdev_get_try_format(fh, fmt->pad);
		*mf = fmt->format;

		/* Propagate format to the source pads */
		if (fmt->pad == FIMC_ISP_SD_PAD_SINK) {
			struct v4l2_subdev_format format = *fmt;
			unsigned int pad;

			for (pad = FIMC_ISP_SD_PAD_SRC_FIFO;
					pad < FIMC_ISP_SD_PADS_NUM; pad++) {
				format.pad = pad;
				__isp_subdev_try_format(isp, fh, &format);
				mf = v4l2_subdev_get_try_format(fh, pad);
				*mf = format.format;
			}
		}
	} else {
		if (sd->entity.stream_count == 0) {
			if (fmt->pad == FIMC_ISP_SD_PAD_SINK) {
				struct v4l2_subdev_format format = *fmt;

				isp->sink_fmt = *mf;

				format.pad = FIMC_ISP_SD_PAD_SRC_DMA;
				__isp_subdev_try_format(isp, fh, &format);

				isp->src_fmt = format.format;
				__is_set_frame_size(is, &isp->src_fmt);
			} else {
				isp->src_fmt = *mf;
			}
		} else {
			ret = -EBUSY;
		}
	}

	mutex_unlock(&isp->subdev_lock);
	return ret;
}
Beispiel #4
0
static void __isp_subdev_set_default_format(struct fimc_isp *isp)
{
	struct fimc_is *is = fimc_isp_to_is(isp);

	isp->sink_fmt.width = DEFAULT_PREVIEW_STILL_WIDTH +
				FIMC_ISP_CAC_MARGIN_WIDTH;
	isp->sink_fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT +
				FIMC_ISP_CAC_MARGIN_HEIGHT;
	isp->sink_fmt.code = V4L2_MBUS_FMT_SGRBG10_1X10;

	isp->src_fmt.width = DEFAULT_PREVIEW_STILL_WIDTH;
	isp->src_fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT;
	isp->src_fmt.code = V4L2_MBUS_FMT_SGRBG10_1X10;
	__is_set_frame_size(is, &isp->src_fmt);
}
Beispiel #5
0
static int fimc_isp_subdev_s_stream(struct v4l2_subdev *sd, int on)
{
	struct fimc_isp *isp = v4l2_get_subdevdata(sd);
	struct fimc_is *is = fimc_isp_to_is(isp);
	int ret;

	isp_dbg(1, sd, "%s: on: %d\n", __func__, on);

	if (!test_bit(IS_ST_INIT_DONE, &is->state))
		return -EBUSY;

	fimc_is_mem_barrier();

	if (on) {
		if (__get_pending_param_count(is)) {
			ret = fimc_is_itf_s_param(is, true);
			if (ret < 0)
				return ret;
		}

		isp_dbg(1, sd, "changing mode to %d\n", is->config_index);

		ret = fimc_is_itf_mode_change(is);
		if (ret)
			return -EINVAL;

		clear_bit(IS_ST_STREAM_ON, &is->state);
		fimc_is_hw_stream_on(is);
		ret = fimc_is_wait_event(is, IS_ST_STREAM_ON, 1,
					 FIMC_IS_CONFIG_TIMEOUT);
		if (ret < 0) {
			v4l2_err(sd, "stream on timeout\n");
			return ret;
		}
	} else {
		clear_bit(IS_ST_STREAM_OFF, &is->state);
		fimc_is_hw_stream_off(is);
		ret = fimc_is_wait_event(is, IS_ST_STREAM_OFF, 1,
					 FIMC_IS_CONFIG_TIMEOUT);
		if (ret < 0) {
			v4l2_err(sd, "stream off timeout\n");
			return ret;
		}
		is->setfile.sub_index = 0;
	}

	return 0;
}
Beispiel #6
0
static void isp_video_capture_buffer_queue(struct vb2_buffer *vb)
{
	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
	struct fimc_isp *isp = vb2_get_drv_priv(vb->vb2_queue);
	struct fimc_is_video *video = &isp->video_capture;
	struct fimc_is *is = fimc_isp_to_is(isp);
	struct isp_video_buf *ivb = to_isp_video_buf(vbuf);
	unsigned long flags;
	unsigned int i;

	if (test_bit(ST_ISP_VID_CAP_BUF_PREP, &isp->state)) {
		spin_lock_irqsave(&is->slock, flags);
		video->buf_mask |= BIT(ivb->index);
		spin_unlock_irqrestore(&is->slock, flags);
	} else {
		unsigned int num_planes = video->format->memplanes;

		ivb->index = video->buf_count;
		video->buffers[ivb->index] = ivb;

		for (i = 0; i < num_planes; i++) {
			int buf_index = ivb->index * num_planes + i;

			ivb->dma_addr[i] = vb2_dma_contig_plane_dma_addr(vb, i);
			is->is_p_region->shared[32 + buf_index] =
							ivb->dma_addr[i];

			isp_dbg(2, &video->ve.vdev,
				"dma_buf %pad (%d/%d/%d) addr: %pad\n",
				&buf_index, ivb->index, i, vb->index,
				&ivb->dma_addr[i]);
		}

		if (++video->buf_count < video->reqbufs_count)
			return;

		video->buf_mask = (1UL << video->buf_count) - 1;
		set_bit(ST_ISP_VID_CAP_BUF_PREP, &isp->state);
	}

	if (!test_bit(ST_ISP_VID_CAP_STREAMING, &isp->state))
		isp_video_capture_start_streaming(vb->vb2_queue, 0);
}
Beispiel #7
0
static int isp_video_capture_start_streaming(struct vb2_queue *q,
						unsigned int count)
{
	struct fimc_isp *isp = vb2_get_drv_priv(q);
	struct fimc_is *is = fimc_isp_to_is(isp);
	struct param_dma_output *dma = __get_isp_dma2(is);
	struct fimc_is_video *video = &isp->video_capture;
	int ret;

	if (!test_bit(ST_ISP_VID_CAP_BUF_PREP, &isp->state) ||
	    test_bit(ST_ISP_VID_CAP_STREAMING, &isp->state))
		return 0;


	dma->cmd = DMA_OUTPUT_COMMAND_ENABLE;
	dma->notify_dma_done = DMA_OUTPUT_NOTIFY_DMA_DONE_ENABLE;
	dma->buffer_address = is->is_dma_p_region +
				DMA2_OUTPUT_ADDR_ARRAY_OFFS;
	dma->buffer_number = video->reqbufs_count;
	dma->dma_out_mask = video->buf_mask;

	isp_dbg(2, &video->ve.vdev,
		"buf_count: %d, planes: %d, dma addr table: %#x\n",
		video->buf_count, video->format->memplanes,
		dma->buffer_address);

	fimc_is_mem_barrier();

	fimc_is_set_param_bit(is, PARAM_ISP_DMA2_OUTPUT);
	__fimc_is_hw_update_param(is, PARAM_ISP_DMA2_OUTPUT);

	ret = fimc_is_itf_s_param(is, false);
	if (ret < 0)
		return ret;

	ret = fimc_pipeline_call(&video->ve, set_stream, 1);
	if (ret < 0)
		return ret;

	set_bit(ST_ISP_VID_CAP_STREAMING, &isp->state);
	return ret;
}
Beispiel #8
0
static int fimc_is_s_ctrl(struct v4l2_ctrl *ctrl)
{
	struct fimc_isp *isp = ctrl_to_fimc_isp(ctrl);
	struct fimc_is *is = fimc_isp_to_is(isp);
	bool set_param = true;
	int ret = 0;

	switch (ctrl->id) {
	case V4L2_CID_CONTRAST:
		__is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_CONTRAST,
				    ctrl->val);
		break;

	case V4L2_CID_SATURATION:
		__is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_SATURATION,
				    ctrl->val);
		break;

	case V4L2_CID_SHARPNESS:
		__is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_SHARPNESS,
				    ctrl->val);
		break;

	case V4L2_CID_EXPOSURE_ABSOLUTE:
		__is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_EXPOSURE,
				    ctrl->val);
		break;

	case V4L2_CID_BRIGHTNESS:
		__is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_BRIGHTNESS,
				    ctrl->val);
		break;

	case V4L2_CID_HUE:
		__is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_HUE,
				    ctrl->val);
		break;

	case V4L2_CID_EXPOSURE_METERING:
		ret = __ctrl_set_metering(is, ctrl->val);
		break;

	case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
		ret = __ctrl_set_white_balance(is, ctrl->val);
		break;

	case V4L2_CID_3A_LOCK:
		ret = __ctrl_set_aewb_lock(is, ctrl);
		set_param = false;
		break;

	case V4L2_CID_ISO_SENSITIVITY_AUTO:
		ret = __ctrl_set_iso(is, ctrl->val);
		break;

	case V4L2_CID_POWER_LINE_FREQUENCY:
		ret = __ctrl_set_afc(is, ctrl->val);
		break;

	case V4L2_CID_COLORFX:
		__ctrl_set_image_effect(is, ctrl->val);
		break;

	default:
		ret = -EINVAL;
		break;
	}

	if (ret < 0) {
		v4l2_err(&isp->subdev, "Failed to set control: %s (%d)\n",
						ctrl->name, ctrl->val);
		return ret;
	}

	if (set_param && test_bit(IS_ST_STREAM_ON, &is->state))
		return fimc_is_itf_s_param(is, true);

	return 0;
}
Beispiel #9
0
static int fimc_isp_subdev_s_power(struct v4l2_subdev *sd, int on)
{
	struct fimc_isp *isp = v4l2_get_subdevdata(sd);
	struct fimc_is *is = fimc_isp_to_is(isp);
	int ret = 0;

	pr_debug("on: %d\n", on);

	if (on) {
		ret = pm_runtime_get_sync(&is->pdev->dev);
		if (ret < 0)
			return ret;
		set_bit(IS_ST_PWR_ON, &is->state);

		ret = fimc_is_start_firmware(is);
		if (ret < 0) {
			v4l2_err(sd, "firmware booting failed\n");
			pm_runtime_put(&is->pdev->dev);
			return ret;
		}
		set_bit(IS_ST_PWR_SUBIP_ON, &is->state);

		ret = fimc_is_hw_initialize(is);
	} else {
		/* Close sensor */
		if (!test_bit(IS_ST_PWR_ON, &is->state)) {
			fimc_is_hw_close_sensor(is, 0);

			ret = fimc_is_wait_event(is, IS_ST_OPEN_SENSOR, 0,
						 FIMC_IS_CONFIG_TIMEOUT);
			if (ret < 0) {
				v4l2_err(sd, "sensor close timeout\n");
				return ret;
			}
		}

		/* SUB IP power off */
		if (test_bit(IS_ST_PWR_SUBIP_ON, &is->state)) {
			fimc_is_hw_subip_power_off(is);
			ret = fimc_is_wait_event(is, IS_ST_PWR_SUBIP_ON, 0,
						 FIMC_IS_CONFIG_TIMEOUT);
			if (ret < 0) {
				v4l2_err(sd, "sub-IP power off timeout\n");
				return ret;
			}
		}

		fimc_is_cpu_set_power(is, 0);
		pm_runtime_put_sync(&is->pdev->dev);

		clear_bit(IS_ST_PWR_ON, &is->state);
		clear_bit(IS_ST_INIT_DONE, &is->state);
		is->state = 0;
		is->config[is->config_index].p_region_index[0] = 0;
		is->config[is->config_index].p_region_index[1] = 0;
		set_bit(IS_ST_IDLE, &is->state);
		wmb();
	}

	return ret;
}