Commit 69705ad2 authored by Marek Szyprowski's avatar Marek Szyprowski Committed by Inki Dae
Browse files

drm/exynos: ipp: Rework checking for the correct buffer formats



Prepare a common function for size and scale checks and call it for
source and destination buffers. Then also move there the state-less checks
from exynos_drm_ipp_task_setup_buffer, so the format information is already
available in limits processing. Finally perform the IPP_LIMIT_BUFFER check
on the real width of the buffer (the width calculated from the provided
buffer pitch).

Signed-off-by: default avatarMarek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: default avatarInki Dae <inki.dae@samsung.com>
parent 2d8aa4ef
Loading
Loading
Loading
Loading
+57 −51
Original line number Diff line number Diff line
@@ -345,27 +345,6 @@ static int exynos_drm_ipp_task_setup_buffer(struct exynos_drm_ipp_buffer *buf,
	int ret = 0;
	int i;

	/* basic checks */
	if (buf->buf.width == 0 || buf->buf.height == 0)
		return -EINVAL;
	buf->format = drm_format_info(buf->buf.fourcc);
	for (i = 0; i < buf->format->num_planes; i++) {
		unsigned int width = (i == 0) ? buf->buf.width :
			     DIV_ROUND_UP(buf->buf.width, buf->format->hsub);

		if (buf->buf.pitch[i] == 0)
			buf->buf.pitch[i] = width * buf->format->cpp[i];
		if (buf->buf.pitch[i] < width * buf->format->cpp[i])
			return -EINVAL;
		if (!buf->buf.gem_id[i])
			return -ENOENT;
	}

	/* pitch for additional planes must match */
	if (buf->format->num_planes > 2 &&
	    buf->buf.pitch[1] != buf->buf.pitch[2])
		return -EINVAL;

	/* get GEM buffers and check their size */
	for (i = 0; i < buf->format->num_planes; i++) {
		unsigned int height = (i == 0) ? buf->buf.height :
@@ -495,12 +474,13 @@ static int exynos_drm_ipp_check_size_limits(struct exynos_drm_ipp_buffer *buf,
	enum drm_ipp_size_id id = rotate ? IPP_LIMIT_ROTATED : IPP_LIMIT_AREA;
	struct drm_ipp_limit l;
	struct drm_exynos_ipp_limit_val *lh = &l.h, *lv = &l.v;
	int real_width = buf->buf.pitch[0] / buf->format->cpp[0];

	if (!limits)
		return 0;

	__get_size_limit(limits, num_limits, IPP_LIMIT_BUFFER, &l);
	if (!__size_limit_check(buf->buf.width, &l.h) ||
	if (!__size_limit_check(real_width, &l.h) ||
	    !__size_limit_check(buf->buf.height, &l.v))
		return -EINVAL;

@@ -560,10 +540,62 @@ static int exynos_drm_ipp_check_scale_limits(
	return 0;
}

static int exynos_drm_ipp_check_format(struct exynos_drm_ipp_task *task,
				       struct exynos_drm_ipp_buffer *buf,
				       struct exynos_drm_ipp_buffer *src,
				       struct exynos_drm_ipp_buffer *dst,
				       bool rotate, bool swap)
{
	const struct exynos_drm_ipp_formats *fmt;
	int ret, i;

	fmt = __ipp_format_get(task->ipp, buf->buf.fourcc, buf->buf.modifier,
			       buf == src ? DRM_EXYNOS_IPP_FORMAT_SOURCE :
					    DRM_EXYNOS_IPP_FORMAT_DESTINATION);
	if (!fmt) {
		DRM_DEBUG_DRIVER("Task %pK: %s format not supported\n", task,
				 buf == src ? "src" : "dst");
		return -EINVAL;
	}

	/* basic checks */
	if (buf->buf.width == 0 || buf->buf.height == 0)
		return -EINVAL;

	buf->format = drm_format_info(buf->buf.fourcc);
	for (i = 0; i < buf->format->num_planes; i++) {
		unsigned int width = (i == 0) ? buf->buf.width :
			     DIV_ROUND_UP(buf->buf.width, buf->format->hsub);

		if (buf->buf.pitch[i] == 0)
			buf->buf.pitch[i] = width * buf->format->cpp[i];
		if (buf->buf.pitch[i] < width * buf->format->cpp[i])
			return -EINVAL;
		if (!buf->buf.gem_id[i])
			return -ENOENT;
	}

	/* pitch for additional planes must match */
	if (buf->format->num_planes > 2 &&
	    buf->buf.pitch[1] != buf->buf.pitch[2])
		return -EINVAL;

	/* check driver limits */
	ret = exynos_drm_ipp_check_size_limits(buf, fmt->limits,
					       fmt->num_limits,
					       rotate,
					       buf == dst ? swap : false);
	if (ret)
		return ret;
	ret = exynos_drm_ipp_check_scale_limits(&src->rect, &dst->rect,
						fmt->limits,
						fmt->num_limits, swap);
	return ret;
}

static int exynos_drm_ipp_task_check(struct exynos_drm_ipp_task *task)
{
	struct exynos_drm_ipp *ipp = task->ipp;
	const struct exynos_drm_ipp_formats *src_fmt, *dst_fmt;
	struct exynos_drm_ipp_buffer *src = &task->src, *dst = &task->dst;
	unsigned int rotation = task->transform.rotation;
	int ret = 0;
@@ -607,37 +639,11 @@ static int exynos_drm_ipp_task_check(struct exynos_drm_ipp_task *task)
		return -EINVAL;
	}

	src_fmt = __ipp_format_get(ipp, src->buf.fourcc, src->buf.modifier,
				   DRM_EXYNOS_IPP_FORMAT_SOURCE);
	if (!src_fmt) {
		DRM_DEBUG_DRIVER("Task %pK: src format not supported\n", task);
		return -EINVAL;
	}
	ret = exynos_drm_ipp_check_size_limits(src, src_fmt->limits,
					       src_fmt->num_limits,
					       rotate, false);
	if (ret)
		return ret;
	ret = exynos_drm_ipp_check_scale_limits(&src->rect, &dst->rect,
						src_fmt->limits,
						src_fmt->num_limits, swap);
	ret = exynos_drm_ipp_check_format(task, src, src, dst, rotate, swap);
	if (ret)
		return ret;

	dst_fmt = __ipp_format_get(ipp, dst->buf.fourcc, dst->buf.modifier,
				   DRM_EXYNOS_IPP_FORMAT_DESTINATION);
	if (!dst_fmt) {
		DRM_DEBUG_DRIVER("Task %pK: dst format not supported\n", task);
		return -EINVAL;
	}
	ret = exynos_drm_ipp_check_size_limits(dst, dst_fmt->limits,
					       dst_fmt->num_limits,
					       false, swap);
	if (ret)
		return ret;
	ret = exynos_drm_ipp_check_scale_limits(&src->rect, &dst->rect,
						dst_fmt->limits,
						dst_fmt->num_limits, swap);
	ret = exynos_drm_ipp_check_format(task, dst, src, dst, false, swap);
	if (ret)
		return ret;