Beispiel #1
0
static int __devinit mxr_acquire_layers(struct mxr_device *mdev,
	struct mxr_platform_data *pdata)
{
	mdev->layer[0] = mxr_graph_layer_create(mdev, 0);
	mdev->layer[1] = mxr_graph_layer_create(mdev, 1);
	mdev->layer[2] = mxr_vp_layer_create(mdev, 0);

	if (!mdev->layer[0] || !mdev->layer[1] || !mdev->layer[2]) {
		mxr_err(mdev, "failed to acquire layers\n");
		goto fail;
	}

	return 0;

fail:
	mxr_release_layers(mdev);
	return -ENODEV;
}
/* When mixer is connected to gscaler through local path, only gscaler's
 * video device can command alpha blending functionality for mixer */
static int mxr_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
	struct mxr_device *mdev = sd_to_mdev(sd);
	struct mxr_layer *layer;
	int v = ctrl->value;
	int num = 0;

	mxr_dbg(mdev, "%s start\n", __func__);
	mxr_dbg(mdev, "id = %d, value = %d\n", ctrl->id, ctrl->value);

	if (!strcmp(sd->name, "s5p-mixer0"))
		num = MXR_SUB_MIXER0;
	else if (!strcmp(sd->name, "s5p-mixer1"))
		num = MXR_SUB_MIXER1;

	layer = mdev->sub_mxr[num].layer[MXR_LAYER_VIDEO];
	switch (ctrl->id) {
	case V4L2_CID_TV_LAYER_BLEND_ENABLE:
		layer->layer_blend_en = v;
		break;
	case V4L2_CID_TV_LAYER_BLEND_ALPHA:
		layer->layer_alpha = (u32)v;
		break;
	case V4L2_CID_TV_PIXEL_BLEND_ENABLE:
		layer->pixel_blend_en = v;
		break;
	case V4L2_CID_TV_CHROMA_ENABLE:
		layer->chroma_en = v;
		break;
	case V4L2_CID_TV_CHROMA_VALUE:
		layer->chroma_val = (u32)v;
		break;
	case V4L2_CID_TV_LAYER_PRIO:
		layer->prio = (u8)v;
		if (layer->pipe.state == MXR_PIPELINE_STREAMING)
			mxr_reg_set_layer_prio(mdev);
		break;
	default:
		mxr_err(mdev, "invalid control id\n");
		return -EINVAL;
	}

	return 0;
}
Beispiel #3
0
struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx)
{
	struct mxr_layer *layer;
	int ret;
	struct mxr_layer_ops ops = {
		.release = mxr_graph_layer_release,
		.buffer_set = mxr_graph_buffer_set,
		.stream_set = mxr_graph_stream_set,
		.format_set = mxr_graph_format_set,
		.fix_geometry = mxr_graph_fix_geometry,
		.chromakey_enable = mixer_graph_chromakey_enable,
		.chromakey_value = mixer_graph_chromakey_value,
                .change_priority = mixer_graph_change_priority, 
		.layer_blend_enable = mixer_graph_layer_blend_enable,
		.layer_blend_alpha =  mixer_graph_layer_blend_alpha,
		.pixel_blend_enable=  mixer_graph_pixel_blend_enable,
	};
	char name[32];

	sprintf(name, "graph%d", idx);

	layer = mxr_base_layer_create(mdev, idx, name, &ops);
	if (layer == NULL) {
		mxr_err(mdev, "failed to initialize layer(%d) base\n", idx);
		goto fail;
	}

	layer->fmt_array = mxr_graph_format;
	layer->fmt_array_size = ARRAY_SIZE(mxr_graph_format);

	ret = mxr_base_layer_register(layer);
	if (ret)
		goto fail_layer;

	return layer;

fail_layer:
	mxr_base_layer_release(layer);

fail:
	return NULL;
}
Beispiel #4
0
static int mxr_acquire_clocks(struct mxr_device *mdev)
{
	struct mxr_resources *res = &mdev->res;
	struct device *dev = mdev->dev;
	struct s5p_mxr_platdata *pdata = mdev->pdata;

#if defined(CONFIG_ARCH_EXYNOS4)
	res->vp = clk_get(dev, "vp");
	if (IS_ERR_OR_NULL(res->vp)) {
		mxr_err(mdev, "failed to get clock 'vp'\n");
		goto fail;
	}
	res->sclk_mixer = clk_get(dev, "sclk_mixer");
	if (IS_ERR_OR_NULL(res->sclk_mixer)) {
		mxr_err(mdev, "failed to get clock 'sclk_mixer'\n");
		goto fail;
	}
#endif
#if defined(CONFIG_CPU_EXYNOS4210)

	res->sclk_dac = clk_get(dev, "sclk_dac");
	if (IS_ERR_OR_NULL(res->sclk_dac)) {
		mxr_err(mdev, "failed to get clock 'sclk_dac'\n");
		goto fail;
	}
#endif
	if (is_ip_ver_5a_0 || is_ip_ver_5a_1) {
		res->axi_disp1 = clk_get(dev, "axi_disp1");
		if (IS_ERR_OR_NULL(res->axi_disp1)) {
			mxr_err(mdev, "failed to get clock 'axi_disp1'\n");
			goto fail;
		}
	}
	res->mixer = clk_get(dev, "mixer");
	if (IS_ERR_OR_NULL(res->mixer)) {
		mxr_err(mdev, "failed to get clock 'mixer'\n");
		goto fail;
	}
	res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
	if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
		mxr_err(mdev, "failed to get clock 'sclk_hdmi'\n");
		goto fail;
	}

	return 0;
fail:
	mxr_release_clocks(mdev);
	return -ENODEV;
}
static int mxr_acquire_resources(struct mxr_device *mdev,
	struct platform_device *pdev)
{
	int ret;
	ret = mxr_acquire_plat_resources(mdev, pdev);
	if (ret)
		goto fail;

	ret = mxr_acquire_clocks(mdev);
	if (ret)
		goto fail_plat;

	mxr_info(mdev, "resources acquired\n");
	return 0;

fail_plat:
	mxr_release_plat_resources(mdev);
fail:
	mxr_err(mdev, "resources acquire failed\n");
	return ret;
}
struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int cur_mxr,
		int idx, int nr)
{
	struct mxr_layer *layer;
	int ret;
	struct mxr_layer_ops ops = {
		.release = mxr_vp_layer_release,
		.buffer_set = mxr_vp_buffer_set,
		.stream_set = mxr_vp_stream_set,
		.format_set = mxr_vp_format_set,
		.fix_geometry = mxr_vp_fix_geometry,
	};
	char name[32];

	sprintf(name, "mxr%d_video%d", cur_mxr, idx);

	layer = mxr_base_layer_create(mdev, idx, name, &ops);
	if (layer == NULL) {
		mxr_err(mdev, "failed to initialize layer(%d) base\n", idx);
		goto fail;
	}

	layer->fmt_array = mxr_video_format;
	layer->fmt_array_size = ARRAY_SIZE(mxr_video_format);
	layer->minor = nr;
	layer->type = MXR_LAYER_TYPE_VIDEO;

	ret = mxr_base_layer_register(layer);
	if (ret)
		goto fail_layer;

	layer->cur_mxr = cur_mxr;
	return layer;

fail_layer:
	mxr_base_layer_release(layer);

fail:
	return NULL;
}
Beispiel #7
0
struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx)
{
	struct mxr_layer *layer;
	int ret;
	const struct mxr_layer_ops ops = {
		.release = mxr_graph_layer_release,
		.buffer_set = mxr_graph_buffer_set,
		.stream_set = mxr_graph_stream_set,
		.format_set = mxr_graph_format_set,
		.fix_geometry = mxr_graph_fix_geometry,
	};
	char name[32];

	sprintf(name, "graph%d", idx);

	layer = mxr_base_layer_create(mdev, idx, name, &ops);
	if (layer == NULL) {
		mxr_err(mdev, "failed to initialize layer(%d) base\n", idx);
		goto fail;
	}

	layer->fmt_array = mxr_graph_format;
	layer->fmt_array_size = ARRAY_SIZE(mxr_graph_format);

	ret = mxr_base_layer_register(layer);
	if (ret)
		goto fail_layer;

	return layer;

fail_layer:
	mxr_base_layer_release(layer);

fail:
	return NULL;
}
static int mxr_streamer_get(struct mxr_device *mdev, struct v4l2_subdev *sd)
{
	int i;
	int ret = 0;
	int local = 1;
	struct sub_mxr_device *sub_mxr;
	struct mxr_layer *layer;
	struct media_pad *pad;
	struct v4l2_mbus_framefmt mbus_fmt;
#if defined(CONFIG_CPU_EXYNOS4210)
	struct mxr_resources *res = &mdev->res;
#endif
	struct v4l2_control ctrl;

	mutex_lock(&mdev->s_mutex);
	++mdev->n_streamer;
	mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);
	/* If pipeline is started from Gscaler input video device,
	 * TV basic configuration must be set before running mixer */
	if (mdev->mxr_data_from == FROM_GSC_SD) {
		mxr_dbg(mdev, "%s: from gscaler\n", __func__);
		local = 0;
		/* enable mixer clock */
		ret = mxr_power_get(mdev);
		if (ret) {
			mxr_err(mdev, "power on failed\n");
			ret = -ENODEV;
			goto out;
		}
		/* turn on connected output device through link
		 * with mixer */
		mxr_output_get(mdev);

		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->pipe.state = MXR_PIPELINE_STREAMING;
				mxr_layer_geo_fix(layer);
				layer->ops.format_set(layer, layer->fmt,
							    &layer->geo);
				layer->ops.stream_set(layer, 1);
				local += sub_mxr->local;
			}
		}
		if (local == 2)
			mxr_layer_sync(mdev, MXR_ENABLE);

		/* Set the TVOUT register about gsc-mixer local path */
		mxr_reg_local_path_set(mdev, mdev->mxr0_gsc, mdev->mxr1_gsc,
				mdev->flags);
	}

	/* Alpha blending configuration always can be changed
	 * whenever streaming */
	mxr_set_alpha_blend(mdev);
	mxr_reg_set_color_range(mdev);
	mxr_reg_set_layer_prio(mdev);

	if ((mdev->n_streamer == 1 && local == 1) ||
	    (mdev->n_streamer == 2 && 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;
			}
		}

		sd = media_entity_to_v4l2_subdev(pad->entity);

		mxr_dbg(mdev, "cookie of current output = (%d)\n",
			to_output(mdev)->cookie);

#if defined(CONFIG_CPU_EXYNOS4210)
		if (to_output(mdev)->cookie == 0)
			clk_set_parent(res->sclk_mixer, res->sclk_dac);
		else
			clk_set_parent(res->sclk_mixer, res->sclk_hdmi);
#endif
		mxr_reg_s_output(mdev, to_output(mdev)->cookie);

		ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mbus_fmt);
		if (ret) {
			mxr_err(mdev, "failed to get mbus_fmt for output %s\n",
					sd->name);
			goto out;
		}
		ctrl.id = V4L2_CID_TV_GET_DVI_MODE;
		ret = v4l2_subdev_call(sd, core, g_ctrl, &ctrl);
		if (ret) {
			mxr_err(mdev, "failed to get DVI or HDMI mode %s\n",
					sd->name);
			goto out;
		}

		mxr_reg_set_mbus_fmt(mdev, &mbus_fmt, ctrl.value);
		ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mbus_fmt);
		if (ret) {
			mxr_err(mdev, "failed to set mbus_fmt for output %s\n",
					sd->name);
			goto out;
		}
		mxr_reg_streamon(mdev);

		ret = v4l2_subdev_call(sd, video, s_stream, 1);
		if (ret) {
			mxr_err(mdev, "starting stream failed for output %s\n",
					sd->name);
			goto out;
		}

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

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

	return ret;
}
static int __devinit mxr_acquire_plat_resources(struct mxr_device *mdev,
	struct platform_device *pdev)
{
	struct resource *res;
	int ret;

	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mxr");
	if (res == NULL) {
		mxr_err(mdev, "get memory resource failed.\n");
		ret = -ENXIO;
		goto fail;
	}

	mdev->res.mxr_regs = ioremap(res->start, resource_size(res));
	if (mdev->res.mxr_regs == NULL) {
		mxr_err(mdev, "register mapping failed.\n");
		ret = -ENXIO;
		goto fail;
	}

#if defined(CONFIG_ARCH_EXYNOS4)
	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp");
	if (res == NULL) {
		mxr_err(mdev, "get memory resource failed.\n");
		ret = -ENXIO;
		goto fail_mxr_regs;
	}

	mdev->res.vp_regs = ioremap(res->start, resource_size(res));
	if (mdev->res.vp_regs == NULL) {
		mxr_err(mdev, "register mapping failed.\n");
		ret = -ENXIO;
		goto fail_mxr_regs;
	}
#endif

	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq");
	if (res == NULL) {
		mxr_err(mdev, "get interrupt resource failed.\n");
		ret = -ENXIO;
		goto fail_vp_regs;
	}

	ret = request_irq(res->start, mxr_irq_handler, 0, "s5p-mixer", mdev);
	if (ret) {
		mxr_err(mdev, "request interrupt failed.\n");
		goto fail_vp_regs;
	}
	mdev->res.irq = res->start;

	return 0;

fail_vp_regs:
#if defined(CONFIG_ARCH_EXYNOS4)
	iounmap(mdev->res.vp_regs);

fail_mxr_regs:
#endif
	iounmap(mdev->res.mxr_regs);

fail:
	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;
}
static int mxr_streamer_get(struct mxr_device *mdev, struct v4l2_subdev *sd)
{
	int i;
	int ret = 0;
	int local = 1;
	struct sub_mxr_device *sub_mxr;
	struct mxr_layer *layer;
	struct media_pad *pad;
	struct s5p_mxr_platdata *pdata = mdev->pdata;
	struct v4l2_mbus_framefmt mbus_fmt;
	struct v4l2_control ctrl;

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

	/* If pipeline is started from Gscaler input video device,
	 * TV basic configuration must be set before running mixer */
	if (mdev->mxr_data_from == FROM_GSC_SD) {
		mxr_dbg(mdev, "%s: from gscaler\n", __func__);
		local = 0;
		/* enable mixer clock */
		ret = mxr_power_get(mdev);
		if (ret < 0) {
			mxr_err(mdev, "power on failed for video layer\n");
			ret = -ENODEV;
			goto out;
		}

		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->pipe.state = MXR_PIPELINE_STREAMING;
				mxr_layer_geo_fix(layer);
				layer->ops.format_set(layer, layer->fmt,
							    &layer->geo);
				layer->ops.stream_set(layer, 1);
				local += sub_mxr->local;
			}
		}
		if (local == 2)
			mxr_layer_sync(mdev, MXR_ENABLE);

		/* Set the TVOUT register about gsc-mixer local path */
		mxr_reg_local_path_set(mdev);
	}

	/* Alpha blending configuration always can be changed
	 * whenever streaming */
	mxr_set_alpha_blend(mdev);
	mxr_reg_set_color_range(mdev);
	mxr_reg_set_layer_prio(mdev);
	if (is_ip_ver_5s || is_ip_ver_5s2)
		mxr_reg_set_resolution(mdev);

	if ((mdev->n_streamer == 1 && local == 1) ||
	    (mdev->n_streamer == 2 && local == 2)) {
#if defined(CONFIG_TV_USE_BUS_DEVFREQ)
		if (is_ip_ver_5a)
			pm_qos_add_request(&exynos5_tv_mif_qos, PM_QOS_BUS_THROUGHPUT, 800000);
		pm_qos_add_request(&exynos5_tv_int_qos, PM_QOS_DEVICE_THROUGHPUT, 400000);
#endif

		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;
			}
		}

		sd = media_entity_to_v4l2_subdev(pad->entity);

		mxr_dbg(mdev, "cookie of current output = (%d)\n",
			to_output(mdev)->cookie);

		mxr_reg_s_output(mdev, to_output(mdev)->cookie);

		ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mbus_fmt);
		if (ret) {
			mxr_err(mdev, "failed to get mbus_fmt for output %s\n",
					sd->name);
			goto out;
		}
		ctrl.id = V4L2_CID_TV_GET_DVI_MODE;
		ret = v4l2_subdev_call(sd, core, g_ctrl, &ctrl);
		if (ret) {
			mxr_err(mdev, "failed to get DVI or HDMI mode %s\n",
					sd->name);
			goto out;
		}

		mxr_reg_set_mbus_fmt(mdev, &mbus_fmt, ctrl.value);
		ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mbus_fmt);
		if (ret) {
			mxr_err(mdev, "failed to set mbus_fmt for output %s\n",
					sd->name);
			goto out;
		}
		mxr_reg_streamon(mdev);

		/* start hdmi */
		ctrl.id = V4L2_CID_TV_HDMI_STATUS;
		ret = v4l2_subdev_call(sd, core, g_ctrl, &ctrl);
		if (ret) {
			mxr_err(mdev, "failed to get output %s status for start\n",
					sd->name);
			goto out;
		}

		if (ctrl.value == (HDMI_STOP | HPD_HIGH)) {
			ret = v4l2_subdev_call(sd, core, s_power, 1);
			if (ret) {
				mxr_err(mdev, "failed to get power for output %s\n",
						sd->name);
				goto out;
			}
			ret = v4l2_subdev_call(sd, video, s_stream, 1);
			if (ret) {
				mxr_err(mdev, "starting stream failed for output %s\n",
						sd->name);
				goto out;
			}
		}

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

out:
	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;
	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;
}
Beispiel #13
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;
}
static int mxr_s_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl)
{
	struct mxr_layer *layer = video_drvdata(file);
	struct mxr_device *mdev = layer->mdev;
	int v = ctrl->value;
	int ret;

	mxr_dbg(mdev, "%s start\n", __func__);

	ret = mxr_check_ctrl_val(ctrl);
	if (ret) {
		mxr_err(mdev, "alpha value is out of range\n");
		return ret;
	}

	switch (ctrl->id) {
	case V4L2_CID_TV_LAYER_BLEND_ENABLE:
		layer->layer_blend_en = v;
		break;
	case V4L2_CID_TV_LAYER_BLEND_ALPHA:
		layer->layer_alpha = (u32)v;
		break;
	case V4L2_CID_TV_PIXEL_BLEND_ENABLE:
		layer->pixel_blend_en = v;
		break;
	case V4L2_CID_TV_CHROMA_ENABLE:
		layer->chroma_en = v;
		break;
	case V4L2_CID_TV_CHROMA_VALUE:
		layer->chroma_val = (u32)v;
		break;
	case V4L2_CID_TV_SET_COLOR_RANGE:
		mdev->color_range = v;
		v4l2_subdev_call(to_outsd(mdev), core, s_ctrl, ctrl);
		break;
	case V4L2_CID_TV_BLANK:
		mdev->blank = v;
		break;
	case V4L2_CID_TV_ENABLE_HDMI_AUDIO:
	case V4L2_CID_TV_SET_NUM_CHANNELS:
	case V4L2_CID_TV_HPD_STATUS:
	case V4L2_CID_TV_SET_DVI_MODE:
	case V4L2_CID_TV_SET_ASPECT_RATIO:
	case V4L2_CID_TV_HDCP_ENABLE:
		v4l2_subdev_call(to_outsd(mdev), core, s_ctrl, ctrl);
		break;
	case V4L2_CID_TV_LAYER_PRIO:
		layer->prio = (u8)v;
		/* This can be turned on/off each layer while streaming */
		if (layer->pipe.state == MXR_PIPELINE_STREAMING)
			mxr_reg_set_layer_prio(mdev);
		break;
	case V4L2_CID_TV_UPDATE:
		ret = mxr_update(mdev);
		break;
	default:
		mxr_err(mdev, "invalid control id\n");
		ret = -EINVAL;
		break;
	}

	return ret;
}
int __devinit mxr_acquire_video(struct mxr_device *mdev,
	struct mxr_output_conf *output_conf, int output_count)
{
	int i;
	int ret = 0;
	struct v4l2_subdev *sd;
	struct s5p_mxr_platdata *pdata = mdev->pdata;

	mdev->alloc_ctx = mdev->vb2->init(mdev);
	if (IS_ERR_OR_NULL(mdev->alloc_ctx)) {
		mxr_err(mdev, "could not acquire vb2 allocator\n");
		ret = PTR_ERR(mdev->alloc_ctx);
		goto fail;
	}
	if (is_ip_ver_5r) {
		exynos_create_iovmm(mdev->dev, 1, 0);
		iovmm_reserve(mdev->dev, MXR_VA, MXR_VA);
	} else {
		exynos_create_iovmm(mdev->dev, 3, 0);
	}

	/* registering outputs */
	mdev->output_cnt = 0;
	for (i = 0; i < output_count; ++i) {
		struct mxr_output_conf *conf = &output_conf[i];
		struct mxr_output *out;

		/* find subdev of output devices */
		sd = (struct v4l2_subdev *)
			module_name_to_driver_data(conf->module_name);
		/* trying to register next output */
		if (sd == NULL)
			continue;
		out = kzalloc(sizeof *out, GFP_KERNEL);
		if (out == NULL) {
			mxr_err(mdev, "no memory for '%s'\n",
				conf->output_name);
			ret = -ENOMEM;
			/* registered subdevs are removed in fail_v4l2_dev */
			goto fail_output;
		}
		strlcpy(out->name, conf->output_name, sizeof(out->name));
		out->sd = sd;
		out->cookie = conf->cookie;
		mdev->output[mdev->output_cnt++] = out;
		mxr_info(mdev, "added output '%s' from module '%s'\n",
			conf->output_name, conf->module_name);
		/* checking if maximal number of outputs is reached */
		if (mdev->output_cnt >= MXR_MAX_OUTPUTS)
			break;
	}

	if (mdev->output_cnt == 0) {
		mxr_err(mdev, "failed to register any output\n");
		ret = -ENODEV;
		/* skipping fail_output because there is nothing to free */
		goto fail_vb2_allocator;
	}

	return 0;

fail_output:
	/* kfree is NULL-safe */
	for (i = 0; i < mdev->output_cnt; ++i)
		kfree(mdev->output[i]);
	memset(mdev->output, 0, sizeof mdev->output);

fail_vb2_allocator:
	/* freeing allocator context */
	mdev->vb2->cleanup(mdev->alloc_ctx);

fail:
	return ret;
}