Пример #1
0
static int mxr_runtime_suspend(struct device *dev)
{
	struct mxr_device *mdev = to_mdev(dev);
	struct mxr_resources *res = &mdev->res;
	struct s5p_mxr_platdata *pdata = mdev->pdata;
	mxr_dbg(mdev, "suspend - start\n");
	mutex_lock(&mdev->mutex);
	/* disable system mmu for tv. It must be disabled before disabling
	 * mixer's clock. Because of system mmu limitation. */
	mdev->vb2->suspend(mdev->alloc_ctx);
	/* turn clocks off */
#if defined(CONFIG_ARCH_EXYNOS4)
	clk_disable_unprepare(res->vp);
#endif
	clk_disable_unprepare(res->mixer);
	if (is_ip_ver_5a || is_ip_ver_5s || is_ip_ver_5s2)
		clk_disable_unprepare(res->axi_disp1);
	mutex_unlock(&mdev->mutex);
	mxr_dbg(mdev, "suspend - finished\n");
	return 0;
}
Пример #2
0
void mxr_output_put(struct mxr_device *mdev)
{
	mutex_lock(&mdev->mutex);
	--mdev->n_output;
	mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_output);
	/* turn on auxiliary driver */
	if (mdev->n_output == 0)
		v4l2_subdev_call(to_outsd(mdev), core, s_power, 0);
	WARN(mdev->n_output < 0, "negative number of output users (%d)\n",
		mdev->n_output);
	mutex_unlock(&mdev->mutex);
}
Пример #3
0
static int mxr_runtime_suspend(struct device *dev)
{
	struct mxr_device *mdev = to_mdev(dev);
	struct mxr_resources *res = &mdev->res;
	mxr_dbg(mdev, "suspend - start\n");
	mutex_lock(&mdev->mutex);
	/* disable system mmu for tv. It must be disabled before disabling
	 * mixer's clock. Because of system mmu limitation. */
	mdev->vb2->suspend(mdev->alloc_ctx);
	/* turn clocks off */
#if defined(CONFIG_CPU_EXYNOS4210)
	clk_disable(res->sclk_mixer);
#endif
#if defined(CONFIG_ARCH_EXYNOS4)
	clk_disable(res->vp);
#endif
	clk_disable(res->mixer);
	mutex_unlock(&mdev->mutex);
	mxr_dbg(mdev, "suspend - finished\n");
	return 0;
}
Пример #4
0
static int mxr_runtime_resume(struct device *dev)
{
	struct mxr_device *mdev = to_mdev(dev);
	struct mxr_resources *res = &mdev->res;
	int ret;

	mxr_dbg(mdev, "resume - start\n");
	mutex_lock(&mdev->mutex);
	/* turn clocks on */
	ret = clk_prepare_enable(res->mixer);
	if (ret < 0) {
		dev_err(mdev->dev, "clk_prepare_enable(mixer) failed\n");
		goto fail;
	}
	ret = clk_prepare_enable(res->vp);
	if (ret < 0) {
		dev_err(mdev->dev, "clk_prepare_enable(vp) failed\n");
		goto fail_mixer;
	}
	ret = clk_prepare_enable(res->sclk_mixer);
	if (ret < 0) {
		dev_err(mdev->dev, "clk_prepare_enable(sclk_mixer) failed\n");
		goto fail_vp;
	}
	/* apply default configuration */
	mxr_reg_reset(mdev);
	mxr_dbg(mdev, "resume - finished\n");

	mutex_unlock(&mdev->mutex);
	return 0;

fail_vp:
	clk_disable_unprepare(res->vp);
fail_mixer:
	clk_disable_unprepare(res->mixer);
fail:
	mutex_unlock(&mdev->mutex);
	dev_err(mdev->dev, "resume failed\n");
	return ret;
}
Пример #5
0
/* 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);
	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;

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

	return 0;
}
Пример #6
0
void mxr_power_put(struct mxr_device *mdev)
{
	--mdev->n_power;
	mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_power);
	/* If runtime PM is not implemented, mxr_runtime_suspend
	 * function is directly called.
	 */
	if (mdev->n_power == 0) {
#ifdef CONFIG_PM_RUNTIME
		pm_runtime_put_sync(mdev->dev);
#else
		mxr_runtime_suspend(mdev->dev);
#endif
	}
}
static int mxr_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
{
	struct mxr_layer *layer = video_drvdata(file);
	struct mxr_crop *crop;

	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
	crop = choose_crop_by_type(&layer->geo, a->type);
	if (crop == NULL)
		return -EINVAL;
	crop->x_offset = a->c.left;
	crop->y_offset = a->c.top;
	crop->width = a->c.width;
	crop->height = a->c.height;
	mxr_layer_geo_fix(layer);
	return 0;
}
Пример #8
0
static void mxr_video_fix_geometry(struct mxr_layer *layer)
{
	struct mxr_geometry *geo = &layer->geo;

	mxr_dbg(layer->mdev, "%s start\n", __func__);
	geo->dst.x_offset = clamp_val(geo->dst.x_offset, 0,
			geo->dst.full_width - 1);
	geo->dst.y_offset = clamp_val(geo->dst.y_offset, 0,
			geo->dst.full_height - 1);

	/* mixer scale-up is unuseful. so no use it */
	geo->dst.width = clamp_val(geo->dst.width, 1,
			geo->dst.full_width - geo->dst.x_offset);
	geo->dst.height = clamp_val(geo->dst.height, 1,
			geo->dst.full_height - geo->dst.y_offset);
}
static int mxr_querycap(struct file *file, void *priv,
	struct v4l2_capability *cap)
{
	struct mxr_layer *layer = video_drvdata(file);

	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);

	strlcpy(cap->driver, MXR_DRIVER_NAME, sizeof cap->driver);
	strlcpy(cap->card, layer->vfd.name, sizeof cap->card);
	snprintf(cap->bus_info, sizeof(cap->bus_info), "%d", layer->idx);
	cap->version = KERNEL_VERSION(0, 1, 0);
	cap->capabilities = V4L2_CAP_STREAMING |
		V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE;

	return 0;
}
static int mxr_enum_fmt(struct file *file, void  *priv,
	struct v4l2_fmtdesc *f)
{
	struct mxr_layer *layer = video_drvdata(file);
	struct mxr_device *mdev = layer->mdev;
	const struct mxr_format *fmt;

	mxr_dbg(mdev, "%s\n", __func__);
	fmt = find_format_by_index(layer, f->index);
	if (fmt == NULL)
		return -EINVAL;

	strlcpy(f->description, fmt->name, sizeof(f->description));
	f->pixelformat = fmt->fourcc;

	return 0;
}
static int mxr_g_fmt(struct file *file, void *priv,
			     struct v4l2_format *f)
{
	struct mxr_layer *layer = video_drvdata(file);
	struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;

	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);

	pix->width = layer->geo.src.full_width;
	pix->height = layer->geo.src.full_height;
	pix->field = V4L2_FIELD_NONE;
	pix->pixelformat = layer->fmt->fourcc;
	pix->colorspace = layer->fmt->colorspace;
	mxr_mplane_fill(pix->plane_fmt, layer->fmt, pix->width, pix->height);

	return 0;
}
Пример #12
0
int mxr_power_get(struct mxr_device *mdev)
{
	int ret = 0;

	++mdev->n_power;
	mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_power);
	/* If runtime PM is not implemented, mxr_runtime_resume
	 * function is directly called.
	 */
	if (mdev->n_power == 1) {
#ifdef CONFIG_PM_RUNTIME
		ret = pm_runtime_get_sync(mdev->dev);
#else
		mxr_runtime_resume(mdev->dev);
#endif
	}
	return ret;
}
static void mxr_geometry_dump(struct mxr_device *mdev, struct mxr_geometry *geo)
{
	mxr_dbg(mdev, "src.full_size = (%u, %u)\n",
		geo->src.full_width, geo->src.full_height);
	mxr_dbg(mdev, "src.size = (%u, %u)\n",
		geo->src.width, geo->src.height);
	mxr_dbg(mdev, "src.offset = (%u, %u)\n",
		geo->src.x_offset, geo->src.y_offset);
	mxr_dbg(mdev, "dst.full_size = (%u, %u)\n",
		geo->dst.full_width, geo->dst.full_height);
	mxr_dbg(mdev, "dst.size = (%u, %u)\n",
		geo->dst.width, geo->dst.height);
	mxr_dbg(mdev, "dst.offset = (%u, %u)\n",
		geo->dst.x_offset, geo->dst.y_offset);
	mxr_dbg(mdev, "ratio = (%u, %u)\n",
		geo->x_ratio, geo->y_ratio);
}
static int mxr_s_dv_preset(struct file *file, void *fh,
	struct v4l2_dv_preset *preset)
{
	struct mxr_layer *layer = video_drvdata(file);
	struct mxr_device *mdev = layer->mdev;
	int ret;

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

	/* lock protects from changing sd_out */
	mutex_lock(&mdev->mutex);

	ret = v4l2_subdev_call(to_outsd(mdev), video, s_dv_preset, preset);

	mutex_unlock(&mdev->mutex);

	/* any failure should return EINVAL according to V4L2 doc */
	return ret ? -EINVAL : 0;
}
static int mxr_video_release(struct file *file)
{
	struct mxr_layer *layer = video_drvdata(file);

	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);

	/* initialize alpha blending variables */
	layer->layer_blend_en = 0;
	layer->layer_alpha = 0;
	layer->pixel_blend_en = 0;
	layer->chroma_en = 0;
	layer->chroma_val = 0;

	if (v4l2_fh_is_singular_file(file))
		vb2_queue_release(&layer->vb_queue);

	v4l2_fh_release(file);
	return 0;
}
Пример #16
0
static void mxr_vp_fix_geometry(struct mxr_layer *layer)
{
	struct mxr_geometry *geo = &layer->geo;

	mxr_dbg(layer->mdev, "%s start\n", __func__);
	/* align horizontal size to 8 pixels */
	geo->src.full_width = ALIGN(geo->src.full_width, 8);
	/* limit to boundary size */
	geo->src.full_width = clamp_val(geo->src.full_width, 8, 8192);
	geo->src.full_height = clamp_val(geo->src.full_height, 1, 8192);
	geo->src.width = clamp_val(geo->src.width, 32, geo->src.full_width);
	geo->src.width = min(geo->src.width, 2047U);
	geo->src.height = clamp_val(geo->src.height, 4, geo->src.full_height);
	geo->src.height = min(geo->src.height, 2047U);

	/* setting size of output window */
	geo->dst.width = clamp_val(geo->dst.width, 8, geo->dst.full_width);
	geo->dst.height = clamp_val(geo->dst.height, 1, geo->dst.full_height);

	/* ensure that scaling is in range 1/4x to 16x */
	if (geo->src.width >= 4 * geo->dst.width)
		geo->src.width = 4 * geo->dst.width;
	if (geo->dst.width >= 16 * geo->src.width)
		geo->dst.width = 16 * geo->src.width;
	if (geo->src.height >= 4 * geo->dst.height)
		geo->src.height = 4 * geo->dst.height;
	if (geo->dst.height >= 16 * geo->src.height)
		geo->dst.height = 16 * geo->src.height;

	/* setting scaling ratio */
	geo->x_ratio = (geo->src.width << 16) / geo->dst.width;
	geo->y_ratio = (geo->src.height << 16) / geo->dst.height;

	/* adjust offsets */
	geo->src.x_offset = min(geo->src.x_offset,
		geo->src.full_width - geo->src.width);
	geo->src.y_offset = min(geo->src.y_offset,
		geo->src.full_height - geo->src.height);
	geo->dst.x_offset = min(geo->dst.x_offset,
		geo->dst.full_width - geo->dst.width);
	geo->dst.y_offset = min(geo->dst.y_offset,
		geo->dst.full_height - geo->dst.height);
}
static int mxr_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a)
{
	struct mxr_layer *layer = video_drvdata(file);
	struct mxr_crop *crop;

	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
	crop = choose_crop_by_type(&layer->geo, a->type);
	if (crop == NULL)
		return -EINVAL;
	mxr_layer_geo_fix(layer);
	a->bounds.left = 0;
	a->bounds.top = 0;
	a->bounds.width = crop->full_width;
	a->bounds.top = crop->full_height;
	a->defrect = a->bounds;
	/* setting pixel aspect to 1/1 */
	a->pixelaspect.numerator = 1;
	a->pixelaspect.denominator = 1;
	return 0;
}
static int mxr_s_output(struct file *file, void *fh, unsigned int i)
{
	struct video_device *vfd = video_devdata(file);
	struct mxr_layer *layer = video_drvdata(file);
	struct mxr_device *mdev = layer->mdev;
	int ret = 0;

	if (i >= mdev->output_cnt || mdev->output[i] == NULL)
		return -EINVAL;

	mutex_lock(&mdev->mutex);
	mdev->current_output = i;
	vfd->tvnorms = 0;
	v4l2_subdev_call(to_outsd(mdev), video, g_tvnorms_output,
		&vfd->tvnorms);
	mutex_unlock(&mdev->mutex);
	mxr_dbg(mdev, "tvnorms = %08llx\n", vfd->tvnorms);

	return ret;
}
Пример #19
0
void mxr_streamer_put(struct mxr_device *mdev)
{
	mutex_lock(&mdev->mutex);
	--mdev->n_streamer;
	mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);
	if (mdev->n_streamer == 0) {
		int ret;
		struct v4l2_subdev *sd = to_outsd(mdev);

		mxr_reg_streamoff(mdev);
		/* vsync applies Mixer setup */
		ret = mxr_reg_wait4vsync(mdev);
		WARN(ret, "failed to get vsync (%d) from output\n", ret);
		ret = v4l2_subdev_call(sd, video, s_stream, 0);
		WARN(ret, "stopping stream failed for output %s\n", sd->name);
	}
	WARN(mdev->n_streamer < 0, "negative number of streamers (%d)\n",
		mdev->n_streamer);
	mutex_unlock(&mdev->mutex);
	mxr_reg_dump(mdev);
}
void mxr_layer_default_geo(struct mxr_layer *layer)
{
	struct mxr_device *mdev = layer->mdev;
	struct v4l2_mbus_framefmt mbus_fmt;

	mxr_dbg(layer->mdev, "%s start\n", __func__);
	memset(&layer->geo, 0, sizeof layer->geo);

	mxr_get_mbus_fmt(mdev, &mbus_fmt);

	layer->geo.dst.full_width = mbus_fmt.width;
	layer->geo.dst.full_height = mbus_fmt.height;
	layer->geo.dst.width = layer->geo.dst.full_width;
	layer->geo.dst.height = layer->geo.dst.full_height;
	layer->geo.dst.field = mbus_fmt.field;

	layer->geo.src.full_width = mbus_fmt.width;
	layer->geo.src.full_height = mbus_fmt.height;
	layer->geo.src.width = layer->geo.src.full_width;
	layer->geo.src.height = layer->geo.src.full_height;

	layer->ops.fix_geometry(layer);
}
static int mxr_video_open(struct file *file)
{
	struct mxr_layer *layer = video_drvdata(file);
	struct mxr_device *mdev = layer->mdev;
	int ret = 0;

	mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
	/* assure device probe is finished */
	wait_for_device_probe();
	/* creating context for file descriptor */
	ret = v4l2_fh_open(file);
	if (ret) {
		mxr_err(mdev, "v4l2_fh_open failed\n");
		return ret;
	}

	/* leaving if layer is already initialized */
	if (!v4l2_fh_is_singular_file(file))
		return 0;

	ret = vb2_queue_init(&layer->vb_queue);
	if (ret != 0) {
		mxr_err(mdev, "failed to initialize vb2 queue\n");
		goto fail_fh_open;
	}
	/* set default format, first on the list */
	layer->fmt = layer->fmt_array[0];
	/* setup default geometry */
	mxr_layer_default_geo(layer);

	return 0;

fail_fh_open:
	v4l2_fh_release(file);

	return ret;
}
Пример #22
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;

	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;
}
Пример #23
0
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;
}
Пример #24
0
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;
}
Пример #25
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;
}
Пример #26
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;
}