예제 #1
0
/* destroy a plane */
static void xilinx_drm_plane_destroy(struct drm_plane *base_plane)
{
	struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
	unsigned int i;

	xilinx_drm_plane_dpms(base_plane, DRM_MODE_DPMS_OFF);

	plane->manager->planes[plane->id] = NULL;

	drm_plane_cleanup(base_plane);

	for (i = 0; i < MAX_NUM_SUB_PLANES; i++)
		if (plane->dma[i].chan)
			dma_release_channel(plane->dma[i].chan);

	if (plane->manager->osd) {
		xilinx_osd_layer_disable(plane->osd_layer);
		xilinx_osd_layer_put(plane->osd_layer);
	}

	if (plane->manager->dp_sub) {
		xilinx_drm_dp_sub_layer_disable(plane->manager->dp_sub,
						plane->dp_layer);
		xilinx_drm_dp_sub_layer_put(plane->manager->dp_sub,
					    plane->dp_layer);
	}
}
예제 #2
0
/* destroy a plane */
static void xilinx_drm_plane_destroy(struct drm_plane *base_plane)
{
	struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);

	xilinx_drm_plane_dpms(base_plane, DRM_MODE_DPMS_OFF);

	plane->manager->planes[plane->id] = NULL;

	drm_plane_cleanup(base_plane);

	dma_release_channel(plane->dma.chan);

	if (plane->manager->osd) {
		xilinx_osd_layer_disable(plane->osd_layer);
		xilinx_osd_layer_put(plane->osd_layer);
	}
}
예제 #3
0
/* create a plane */
static struct xilinx_drm_plane *
xilinx_drm_plane_create(struct xilinx_drm_plane_manager *manager,
			unsigned int possible_crtcs, bool primary)
{
	struct xilinx_drm_plane *plane;
	struct device *dev = manager->drm->dev;
	char name[16];
	struct device_node *plane_node;
	struct device_node *sub_node;
	enum drm_plane_type type;
	uint32_t fmt_in = -1;
	uint32_t fmt_out = -1;
	const char *fmt;
	int i;
	int ret;

	for (i = 0; i < manager->num_planes; i++)
		if (!manager->planes[i])
			break;

	if (i >= manager->num_planes) {
		DRM_ERROR("failed to allocate plane\n");
		return ERR_PTR(-ENODEV);
	}

	snprintf(name, sizeof(name), "plane%d", i);
	plane_node = of_get_child_by_name(manager->node, name);
	if (!plane_node) {
		DRM_ERROR("failed to find a plane node\n");
		return ERR_PTR(-ENODEV);
	}

	plane = devm_kzalloc(dev, sizeof(*plane), GFP_KERNEL);
	if (!plane) {
		ret = -ENOMEM;
		goto err_out;
	}

	plane->primary = primary;
	plane->id = i;
	plane->prio = i;
	plane->zpos = i;
	plane->alpha = manager->default_alpha;
	plane->dpms = DRM_MODE_DPMS_OFF;
	plane->format = -1;
	DRM_DEBUG_KMS("plane->id: %d\n", plane->id);

	for (i = 0; i < MAX_NUM_SUB_PLANES; i++) {
		snprintf(name, sizeof(name), "dma%d", i);
		plane->dma[i].chan = of_dma_request_slave_channel(plane_node,
								  name);
		if (PTR_ERR(plane->dma[i].chan) == -ENODEV) {
			plane->dma[i].chan = NULL;
			continue;
		}

		if (IS_ERR(plane->dma[i].chan)) {
			DRM_ERROR("failed to request dma channel\n");
			ret = PTR_ERR(plane->dma[i].chan);
			plane->dma[i].chan = NULL;
			goto err_dma;
		}
	}

	/* probe color space converter */
	sub_node = of_parse_phandle(plane_node, "xlnx,rgb2yuv", i);
	if (sub_node) {
		plane->rgb2yuv = xilinx_rgb2yuv_probe(dev, sub_node);
		of_node_put(sub_node);
		if (IS_ERR(plane->rgb2yuv)) {
			DRM_ERROR("failed to probe a rgb2yuv\n");
			ret = PTR_ERR(plane->rgb2yuv);
			goto err_dma;
		}

		/* rgb2yuv input format */
		plane->format = DRM_FORMAT_XRGB8888;

		/* rgb2yuv output format */
		fmt_out = DRM_FORMAT_YUV444;
	}

	/* probe chroma resampler */
	sub_node = of_parse_phandle(plane_node, "xlnx,cresample", i);
	if (sub_node) {
		plane->cresample = xilinx_cresample_probe(dev, sub_node);
		of_node_put(sub_node);
		if (IS_ERR(plane->cresample)) {
			DRM_ERROR("failed to probe a cresample\n");
			ret = PTR_ERR(plane->cresample);
			goto err_dma;
		}

		/* cresample input format */
		fmt = xilinx_cresample_get_input_format_name(plane->cresample);
		ret = xilinx_drm_format_by_name(fmt, &fmt_in);
		if (ret)
			goto err_dma;

		/* format sanity check */
		if ((fmt_out != -1) && (fmt_out != fmt_in)) {
			DRM_ERROR("input/output format mismatch\n");
			ret = -EINVAL;
			goto err_dma;
		}

		if (plane->format == -1)
			plane->format = fmt_in;

		/* cresample output format */
		fmt = xilinx_cresample_get_output_format_name(plane->cresample);
		ret = xilinx_drm_format_by_name(fmt, &fmt_out);
		if (ret)
			goto err_dma;
	}

	/* create an OSD layer when OSD is available */
	if (manager->osd) {
		/* format sanity check */
		if ((fmt_out != -1) && (fmt_out != manager->format)) {
			DRM_ERROR("input/output format mismatch\n");
			ret = -EINVAL;
			goto err_dma;
		}

		/* create an osd layer */
		plane->osd_layer = xilinx_osd_layer_get(manager->osd);
		if (IS_ERR(plane->osd_layer)) {
			DRM_ERROR("failed to create a osd layer\n");
			ret = PTR_ERR(plane->osd_layer);
			plane->osd_layer = NULL;
			goto err_dma;
		}

		if (plane->format == -1)
			plane->format = manager->format;
	}

	if (manager->dp_sub) {
		plane->dp_layer = xilinx_drm_dp_sub_layer_get(manager->dp_sub,
							      primary);
		if (IS_ERR(plane->dp_layer)) {
			DRM_ERROR("failed to create a dp_sub layer\n");
			ret = PTR_ERR(plane->dp_layer);
			plane->dp_layer = NULL;
			goto err_dma;
		}

		if (primary) {
			ret = xilinx_drm_dp_sub_layer_set_fmt(manager->dp_sub,
							      plane->dp_layer,
							      manager->format);
			if (ret) {
				DRM_ERROR("failed to set dp_sub layer fmt\n");
				goto err_dma;
			}
		}

		plane->format =
			xilinx_drm_dp_sub_layer_get_fmt(manager->dp_sub,
							plane->dp_layer);
	}

	/* If there's no IP other than VDMA, pick the manager's format */
	if (plane->format == -1)
		plane->format = manager->format;

	/* initialize drm plane */
	type = primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
	ret = drm_universal_plane_init(manager->drm, &plane->base,
				       possible_crtcs, &xilinx_drm_plane_funcs,
				       &plane->format, 1, type, NULL);
	if (ret) {
		DRM_ERROR("failed to initialize plane\n");
		goto err_init;
	}
	plane->manager = manager;
	manager->planes[plane->id] = plane;

	xilinx_drm_plane_attach_property(&plane->base);

	of_node_put(plane_node);

	return plane;

err_init:
	if (manager->dp_sub) {
		xilinx_drm_dp_sub_layer_disable(manager->dp_sub,
						plane->dp_layer);
		xilinx_drm_dp_sub_layer_put(plane->manager->dp_sub,
					    plane->dp_layer);
	}
	if (manager->osd) {
		xilinx_osd_layer_disable(plane->osd_layer);
		xilinx_osd_layer_put(plane->osd_layer);
	}
err_dma:
	for (i = 0; i < MAX_NUM_SUB_PLANES; i++)
		if (plane->dma[i].chan)
			dma_release_channel(plane->dma[i].chan);
err_out:
	of_node_put(plane_node);
	return ERR_PTR(ret);
}
예제 #4
0
/* set plane dpms */
void xilinx_drm_plane_dpms(struct drm_plane *base_plane, int dpms)
{
	struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
	struct xilinx_drm_plane_manager *manager = plane->manager;
	unsigned int i;

	DRM_DEBUG_KMS("plane->id: %d\n", plane->id);
	DRM_DEBUG_KMS("dpms: %d -> %d\n", plane->dpms, dpms);

	if (plane->dpms == dpms)
		return;

	plane->dpms = dpms;
	switch (dpms) {
	case DRM_MODE_DPMS_ON:
		if (manager->dp_sub) {
			if (plane->primary) {
				xilinx_drm_dp_sub_enable_alpha(manager->dp_sub,
						plane->alpha_enable);
				xilinx_drm_dp_sub_set_alpha(manager->dp_sub,
							    plane->alpha);
			}
			xilinx_drm_dp_sub_layer_enable(manager->dp_sub,
						       plane->dp_layer);
		}

		/* start dma engine */
		for (i = 0; i < MAX_NUM_SUB_PLANES; i++)
			if (plane->dma[i].chan && plane->dma[i].is_active)
				dma_async_issue_pending(plane->dma[i].chan);

		if (plane->rgb2yuv)
			xilinx_rgb2yuv_enable(plane->rgb2yuv);

		if (plane->cresample)
			xilinx_cresample_enable(plane->cresample);

		/* enable osd */
		if (manager->osd) {
			xilinx_osd_disable_rue(manager->osd);

			xilinx_osd_layer_set_priority(plane->osd_layer,
						      plane->prio);
			xilinx_osd_layer_enable_alpha(plane->osd_layer,
						   plane->alpha_enable);
			xilinx_osd_layer_set_alpha(plane->osd_layer,
						   plane->alpha);
			xilinx_osd_layer_enable(plane->osd_layer);

			xilinx_osd_enable_rue(manager->osd);
		}

		break;
	default:
		/* disable/reset osd */
		if (manager->osd) {
			xilinx_osd_disable_rue(manager->osd);

			xilinx_osd_layer_set_dimension(plane->osd_layer,
						       0, 0, 0, 0);
			xilinx_osd_layer_disable(plane->osd_layer);

			xilinx_osd_enable_rue(manager->osd);
		}

		if (plane->cresample) {
			xilinx_cresample_disable(plane->cresample);
			xilinx_cresample_reset(plane->cresample);
		}

		if (plane->rgb2yuv) {
			xilinx_rgb2yuv_disable(plane->rgb2yuv);
			xilinx_rgb2yuv_reset(plane->rgb2yuv);
		}

		/* stop dma engine and release descriptors */
		for (i = 0; i < MAX_NUM_SUB_PLANES; i++) {
			if (plane->dma[i].chan && plane->dma[i].is_active) {
				dmaengine_terminate_all(plane->dma[i].chan);
				plane->dma[i].is_active = false;
			}
		}

		if (manager->dp_sub)
			xilinx_drm_dp_sub_layer_disable(manager->dp_sub,
							plane->dp_layer);

		break;
	}
}
예제 #5
0
/* set plane dpms */
void xilinx_drm_plane_dpms(struct drm_plane *base_plane, int dpms)
{
	struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
	struct xilinx_drm_plane_manager *manager = plane->manager;

	DRM_DEBUG_KMS("plane->id: %d\n", plane->id);
	DRM_DEBUG_KMS("dpms: %d -> %d\n", plane->dpms, dpms);

	if (plane->dpms == dpms)
		return;

	plane->dpms = dpms;
	switch (dpms) {
	case DRM_MODE_DPMS_ON:
		/* start dma engine */
		dma_async_issue_pending(plane->dma.chan);

		if (plane->rgb2yuv)
			xilinx_rgb2yuv_enable(plane->rgb2yuv);

		if (plane->cresample)
			xilinx_cresample_enable(plane->cresample);

		/* enable osd */
		if (manager->osd) {
			xilinx_osd_disable_rue(manager->osd);

			xilinx_osd_layer_set_priority(plane->osd_layer,
						      plane->prio);
			xilinx_osd_layer_set_alpha(plane->osd_layer, 1,
						   plane->alpha);
			xilinx_osd_layer_enable(plane->osd_layer);
			if (plane->priv) {
				/* set background color as black */
				xilinx_osd_set_color(manager->osd, 0x0, 0x0,
						     0x0);
				xilinx_osd_enable(manager->osd);
			}

			xilinx_osd_enable_rue(manager->osd);
		}

		break;
	default:
		/* disable/reset osd */
		if (manager->osd) {
			xilinx_osd_disable_rue(manager->osd);

			xilinx_osd_layer_set_dimension(plane->osd_layer,
						       0, 0, 0, 0);
			xilinx_osd_layer_disable(plane->osd_layer);
			if (plane->priv)
				xilinx_osd_reset(manager->osd);

			xilinx_osd_enable_rue(manager->osd);
		}

		if (plane->cresample) {
			xilinx_cresample_disable(plane->cresample);
			xilinx_cresample_reset(plane->cresample);
		}

		if (plane->rgb2yuv) {
			xilinx_rgb2yuv_disable(plane->rgb2yuv);
			xilinx_rgb2yuv_reset(plane->rgb2yuv);
		}

		/* stop dma engine and release descriptors */
		dmaengine_terminate_all(plane->dma.chan);
		break;
	}
}