Exemplo n.º 1
0
static int mxr_streamer_put(struct mxr_device *mdev, struct v4l2_subdev *sd)
{
	int i;
	int ret = 0;
	int local = 1;
	struct media_pad *pad;
	struct sub_mxr_device *sub_mxr;
	struct mxr_layer *layer;
	struct v4l2_subdev *hdmi_sd;
	struct v4l2_subdev *gsc_sd;
	struct exynos_entity_data *md_data;
	struct s5p_mxr_platdata *pdata = mdev->pdata;
	struct v4l2_control ctrl;

	mutex_lock(&mdev->s_mutex);
	--mdev->n_streamer;
	mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);

	/* distinction number of local path */
	if (mdev->mxr_data_from == FROM_GSC_SD) {
		local = 0;
		for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
			sub_mxr = &mdev->sub_mxr[i];
			if (sub_mxr->local)
				local += sub_mxr->local;
		}
		if (local == 2)
			mxr_layer_sync(mdev, MXR_DISABLE);

		/* stop gscaler --> waiting for frame done */
		pad = &sd->entity.pads[MXR_PAD_SINK_GSCALER];
		pad = media_entity_remote_source(pad);
		if (pad) {
			gsc_sd = media_entity_to_v4l2_subdev(
					pad->entity);
			mxr_dbg(mdev, "stop from %s\n", gsc_sd->name);
			md_data = (struct exynos_entity_data *)
				gsc_sd->dev_priv;
			if (is_ip_ver_5g_1 || is_ip_ver_5a_0)
				md_data->media_ops->power_off(gsc_sd);
		}

		/* disable video layer */
		for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
			sub_mxr = &mdev->sub_mxr[i];
			if (sub_mxr->local) {
				layer = sub_mxr->layer[MXR_LAYER_VIDEO];
				layer->ops.stream_set(layer, 0);
				layer->pipe.state = MXR_PIPELINE_IDLE;
			}
		}
	}

	if ((mdev->n_streamer == 0 && local == 1) ||
	    (mdev->n_streamer == 1 && local == 2)) {
		for (i = MXR_PAD_SOURCE_GSCALER; i < MXR_PADS_NUM; ++i) {
			pad = &sd->entity.pads[i];

			/* find sink pad of output via enabled link*/
			pad = media_entity_remote_source(pad);
			if (pad)
				if (media_entity_type(pad->entity)
						== MEDIA_ENT_T_V4L2_SUBDEV)
					break;

			if (i == MXR_PAD_SOURCE_GRP1) {
				ret = -ENODEV;
				goto out;
			}
		}

		hdmi_sd = media_entity_to_v4l2_subdev(pad->entity);

		mxr_reg_streamoff(mdev);
		/* vsync applies Mixer setup */
		ret = mxr_reg_wait4update(mdev);
		if (ret) {
			mxr_err(mdev, "failed to get vsync (%d) from output\n",
					ret);
			goto out;
		}

		/* stop hdmi */
		ctrl.id = V4L2_CID_TV_HDMI_STATUS;
		ret = v4l2_subdev_call(hdmi_sd, core, g_ctrl, &ctrl);
		if (ret) {
			mxr_err(mdev, "failed to get output %s status for stop\n",
					hdmi_sd->name);
			goto out;
		}
		/*
		 * HDMI should be turn off only when not in use.
		 * 1. cable out
		 * 2. suspend (blank is called at suspend)
		 */
		if (ctrl.value == (HDMI_STREAMING | HPD_LOW) || mdev->blank) {
			ret = v4l2_subdev_call(hdmi_sd, video, s_stream, 0);
			if (ret) {
				mxr_err(mdev, "stopping stream failed for output %s\n",
						hdmi_sd->name);
				goto out;
			}
			ret = v4l2_subdev_call(hdmi_sd, core, s_power, 0);
			if (ret) {
				mxr_err(mdev, "failed to put power for output %s\n",
						hdmi_sd->name);
				goto out;
			}
			mdev->blank = 0;
		}
	}
	/* disable mixer clock */
	if (mdev->mxr_data_from == FROM_GSC_SD)
		mxr_power_put(mdev);

	WARN(mdev->n_streamer < 0, "negative number of streamers (%d)\n",
		mdev->n_streamer);

out:
#if defined(CONFIG_TV_USE_BUS_DEVFREQ)
	if ((mdev->n_streamer == 0 && local == 1) ||
	    (mdev->n_streamer == 1 && local == 2)) {
		if (is_ip_ver_5a)
			pm_qos_remove_request(&exynos5_tv_mif_qos);
		pm_qos_remove_request(&exynos5_tv_int_qos);
	}
#endif
	mutex_unlock(&mdev->s_mutex);
	mxr_reg_dump(mdev);

	return ret;
}
static int mxr_streamer_put(struct mxr_device *mdev, struct v4l2_subdev *sd)
{
	int i;
	int ret = 0;
	int local = 1;
	struct media_pad *pad;
	struct sub_mxr_device *sub_mxr;
	struct mxr_layer *layer;
	struct v4l2_subdev *hdmi_sd;
	struct v4l2_subdev *gsc_sd;
	struct exynos_entity_data *md_data;

	mutex_lock(&mdev->s_mutex);
	--mdev->n_streamer;
	mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);

	/* distinction number of local path */
	if (mdev->mxr_data_from == FROM_GSC_SD) {
		local = 0;
		for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
			sub_mxr = &mdev->sub_mxr[i];
			if (sub_mxr->local)
				local += sub_mxr->local;
		}
		if (local == 2)
			mxr_layer_sync(mdev, MXR_DISABLE);
	}

	if ((mdev->n_streamer == 0 && local == 1) ||
	    (mdev->n_streamer == 1 && local == 2)) {
		for (i = MXR_PAD_SOURCE_GSCALER; i < MXR_PADS_NUM; ++i) {
			pad = &sd->entity.pads[i];

			/* find sink pad of output via enabled link*/
			pad = media_entity_remote_source(pad);
			if (pad)
				if (media_entity_type(pad->entity)
						== MEDIA_ENT_T_V4L2_SUBDEV)
					break;

			if (i == MXR_PAD_SOURCE_GRP1) {
				ret = -ENODEV;
				goto out;
			}
		}

		hdmi_sd = media_entity_to_v4l2_subdev(pad->entity);

		mxr_reg_streamoff(mdev);
		/* vsync applies Mixer setup */
		ret = mxr_reg_wait4update(mdev);
		if (ret) {
			mxr_err(mdev, "failed to get vsync (%d) from output\n",
					ret);
			goto out;
		}
	}
	/* When using local path between gscaler and mixer, below stop sequence
	 * must be processed */
	if (mdev->mxr_data_from == FROM_GSC_SD) {
		pad = &sd->entity.pads[MXR_PAD_SINK_GSCALER];
		pad = media_entity_remote_source(pad);
		if (pad) {
			gsc_sd = media_entity_to_v4l2_subdev(
					pad->entity);
			mxr_dbg(mdev, "stop from %s\n", gsc_sd->name);
			md_data = (struct exynos_entity_data *)
				gsc_sd->dev_priv;
			md_data->media_ops->power_off(gsc_sd);
		}
	}

	if ((mdev->n_streamer == 0 && local == 1) ||
	    (mdev->n_streamer == 1 && local == 2)) {
		ret = v4l2_subdev_call(hdmi_sd, video, s_stream, 0);
		if (ret) {
			mxr_err(mdev, "stopping stream failed for output %s\n",
					hdmi_sd->name);
			goto out;
		}
	}
	/* turn off connected output device through link
	 * with mixer */
	if (mdev->mxr_data_from == FROM_GSC_SD) {
		for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
			sub_mxr = &mdev->sub_mxr[i];
			if (sub_mxr->local) {
				layer = sub_mxr->layer[MXR_LAYER_VIDEO];
				layer->ops.stream_set(layer, 0);
				layer->pipe.state = MXR_PIPELINE_IDLE;
			}
		}
		mxr_reg_local_path_clear(mdev);
		mxr_output_put(mdev);

		/* disable mixer clock */
		mxr_power_put(mdev);
	}
	WARN(mdev->n_streamer < 0, "negative number of streamers (%d)\n",
		mdev->n_streamer);

out:
	mutex_unlock(&mdev->s_mutex);
	mxr_reg_dump(mdev);

	return ret;
}
Exemplo n.º 3
0
static int mxr_streamer_put(struct mxr_device *mdev, struct v4l2_subdev *sd)
{
	int i;
	int ret = 0;
	int local = 1;
	struct media_pad *pad;
	struct sub_mxr_device *sub_mxr;
	struct mxr_layer *layer;
	struct v4l2_subdev *gsc_sd;
	struct exynos_entity_data *md_data;
	struct s5p_mxr_platdata *pdata = mdev->pdata;

	mutex_lock(&mdev->s_mutex);
	--mdev->n_streamer;
	mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);

	/* distinction number of local path */
	if (mdev->mxr_data_from == FROM_GSC_SD) {
		local = 0;
		for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
			sub_mxr = &mdev->sub_mxr[i];
			if (sub_mxr->local)
				local += sub_mxr->local;
		}
		if (local == 2)
			mxr_layer_sync(mdev, MXR_DISABLE);

		/* stop gscaler --> waiting for frame done */
		pad = &sd->entity.pads[MXR_PAD_SINK_GSCALER];
		pad = media_entity_remote_source(pad);
		if (pad) {
			gsc_sd = media_entity_to_v4l2_subdev(
					pad->entity);
			mxr_dbg(mdev, "stop from %s\n", gsc_sd->name);
			md_data = (struct exynos_entity_data *)
				gsc_sd->dev_priv;
			if (is_ip_ver_5g_1 || is_ip_ver_5a_0)
				md_data->media_ops->power_off(gsc_sd);
		}

		/* disable video layer */
		for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
			sub_mxr = &mdev->sub_mxr[i];
			if (sub_mxr->local) {
				layer = sub_mxr->layer[MXR_LAYER_VIDEO];
				layer->ops.stream_set(layer, 0);
				layer->pipe.state = MXR_PIPELINE_IDLE;
			}
		}
	}

	if ((mdev->n_streamer == 0 && local == 1) ||
	    (mdev->n_streamer == 1 && local == 2)) {
		mxr_reg_streamoff(mdev);
		/* vsync applies Mixer setup */
		ret = mxr_reg_wait4update(mdev);
		if (ret) {
			mxr_err(mdev, "failed to get vsync (%d) from output\n",
					ret);
			goto out;
		}
	}
	/* disable mixer clock */
	if (mdev->mxr_data_from == FROM_GSC_SD)
		mxr_power_put(mdev);

	WARN(mdev->n_streamer < 0, "negative number of streamers (%d)\n",
		mdev->n_streamer);

out:
#if defined(CONFIG_ARM_EXYNOS5410_BUS_DEVFREQ)
	if ((mdev->n_streamer == 0 && local == 1) ||
	    (mdev->n_streamer == 1 && local == 2)) {
		pm_qos_remove_request(&exynos5_tv_mif_qos);
		pm_qos_remove_request(&exynos5_tv_int_qos);
	}
#endif
	mutex_unlock(&mdev->s_mutex);
	mxr_reg_dump(mdev);

	return ret;
}