static void inner_touch_range(struct fimg2d_bltcmd *cmd)
{
	struct fimg2d_image *img;
	struct fimg2d_dma *c;
	int i;

	for (i = 0; i < MAX_IMAGES; i++) {
		img = &cmd->image[i];

		/* 1st plane */
		c = &cmd->dma[i].base;
		if (!c->cached)
			continue;

		fimg2d_touch_range(c->addr, c->cached);

		/* 2nd plane */
		if (!is_yuvfmt(img->fmt))
			continue;

		if (img->order != P2_CRCB && img->order != P2_CBCR)
			continue;

		c = &cmd->dma[i].plane2;
		if (!c->cached)
			continue;

		fimg2d_touch_range(c->addr, c->cached);
	}
}
static int fimg2d_check_address(struct fimg2d_bltcmd *cmd)
{
	struct fimg2d_dma *c;
	struct fimg2d_image *img;
	int i;

	for (i = 0; i < MAX_IMAGES; i++) {
		img = &cmd->image[i];
		if (!img->addr.type)
			continue;

		c = &cmd->dma[i].base;

		if (fimg2d_check_address_range(c->addr, c->size))
			return -EINVAL;

		/* 2nd plane */
		if (!is_yuvfmt(img->fmt))
			continue;

		if (img->order != P2_CRCB && img->order != P2_CBCR)
			continue;

		c = &cmd->dma[i].plane2;

		if (fimg2d_check_address_range(c->addr, c->size))
			return -EINVAL;
	}
	return 0;
}
Пример #3
0
static int fimg2d_import_bufs(struct fimg2d_control *info,
		struct fimg2d_bltcmd *cmd)
{
	int ret = 0;
	int i;
	size_t j;

	for (i = 0; i < MAX_IMAGES; i++) {
		struct fimg2d_image *img = &cmd->image[i];
		size_t num_planes = fimg2d_num_planes(img);

		for (j = 0; j < num_planes; j++) {
			int stride;
			unsigned int buf_size = fimg2d_map_dma_buf(info,
					&cmd->dma[i][j], img->addr.fd[j],
					fimg2d_dma_direction(i));
			if (!buf_size) {
				ret = -ENOMEM;
				goto err;
			}

			if (is_yuvfmt(img->fmt)) {
				stride = yuv_stride(img->width, img->fmt,
						img->order, j);
			} else {
				stride = img->stride;
			}

			if (buf_size < stride * img->height) {
				dev_err(info->dev,
						"%s plane %u too small (height = %d, stride = %d, buf_size = %u)\n",
						imagename(i), j,
						img->height, stride, buf_size);
				ret = -EINVAL;
				goto err;
			}
		}
	}

err:
	if (ret)
		for (i = 0; i < MAX_IMAGES; i++)
			for (j = 0; j < FIMG2D_MAX_PLANES; j++)
				fimg2d_unmap_dma_buf(info, &cmd->dma[i][j]);

	return ret;
}
Пример #4
0
int fimg2d_check_pgd(struct mm_struct *mm, struct fimg2d_bltcmd *cmd)
{
	struct fimg2d_dma *c;
	struct fimg2d_image *img;
	enum pt_status pt;
	int i, ret;


	for (i = 0; i < MAX_IMAGES; i++) {
		img = &cmd->image[i];
		if (!img->addr.type)
			continue;

		c = &cmd->dma[i].base;
		if (!c->size)
			continue;

		pt = fimg2d_check_pagetable(mm, c->addr, c->size, i == IDST);
		if (pt == PT_FAULT) {
			ret = -EFAULT;
			goto err_pgtable;
		}

		/* 2nd plane */
		if (!is_yuvfmt(img->fmt))
			continue;

		if (img->order != P2_CRCB && img->order != P2_CBCR)
			continue;

		c = &cmd->dma[i].plane2;
		if (!c->size)
			continue;

		pt = fimg2d_check_pagetable(mm, c->addr, c->size, i == IDST);
		if (pt == PT_FAULT) {
			ret = -EFAULT;
			goto err_pgtable;
		}
	}
	return 0;

err_pgtable:
	return ret;
}
Пример #5
0
static void outer_flush_clip_range(struct fimg2d_bltcmd *cmd)
{
	struct mm_struct *mm;
	struct fimg2d_blit *blt = &cmd->blt;
	struct fimg2d_image *img;
	struct fimg2d_clip *clp;
	struct fimg2d_rect *r;
	struct fimg2d_dma *c;
	int clp_x, clp_w, clp_h, y, i, dir;
	int x1, y1, x2, y2, bpp, stride;
	unsigned long start;

	if (WARN_ON(!cmd->ctx))
		return;

	mm = cmd->ctx->mm;

	clp = &blt->param.clipping;
	dir = CACHE_CLEAN;

	for (i = 0; i < MAX_IMAGES; i++) {
		img = &cmd->image[i];

		/* clean pagetable on outercache */
		c = &cmd->dma[i].base;
		if (c->size)
			fimg2d_clean_outer_pagetable(mm, c->addr, c->size);

		c = &cmd->dma[i].plane2;
		if (c->size)
			fimg2d_clean_outer_pagetable(mm, c->addr, c->size);

		if (i == IMAGE_DST)
			dir = CACHE_FLUSH;

		/* 1st plane */
		c = &cmd->dma[i].base;
		if (!c->cached)
			continue;

		r = &img->rect;

		if (i == IMAGE_DST && clp->enable) {
			x1 = clp->x1;
			y1 = clp->y1;
			x2 = clp->x2;
			y2 = clp->y2;
		} else {
			x1 = r->x1;
			y1 = r->y1;
			x2 = r->x2;
			y2 = r->y2;
		}

		bpp = bit_per_pixel(img, 0);
		stride = width2bytes(img->width, bpp);

		clp_x = pixel2offset(x1, bpp);
		clp_w = width2bytes(x2 - x1, bpp);
		clp_h = y2 - y1;

		if (is_outer_flushrange(stride - clp_w))
			fimg2d_dma_sync_outer(mm, c->addr, c->cached, dir);
		else {
			for (y = 0; y < clp_h; y++) {
				start = c->addr + (stride * y) + clp_x;
				fimg2d_dma_sync_outer(mm, start, clp_w, dir);
			}
		}

		/* 2nd plane */
		if (!is_yuvfmt(img->fmt))
			continue;

		if (img->order != P2_CRCB && img->order != P2_CBCR)
			continue;

		c = &cmd->dma[i].plane2;
		if (!c->cached)
			continue;

		bpp = bit_per_pixel(img, 1);
		stride = width2bytes(img->width, bpp);

		clp_x = pixel2offset(x1, bpp);
		clp_w = width2bytes(x2 - x1, bpp);
		if (img->fmt == CF_YCBCR_420)
			clp_h = (y2 - y1)/2;
		else
			clp_h = y2 - y1;

		if (is_outer_flushrange(stride - clp_w))
			fimg2d_dma_sync_outer(mm, c->addr, c->cached, dir);
		else {
			for (y = 0; y < clp_h; y++) {
				start = c->addr + (stride * y) + clp_x;
				fimg2d_dma_sync_outer(mm, start, clp_w, dir);
			}
		}
	}
}
Пример #6
0
static void inner_flush_clip_range(struct fimg2d_bltcmd *cmd)
{
	struct fimg2d_blit *blt = &cmd->blt;
	struct fimg2d_image *img;
	struct fimg2d_clip *clp;
	struct fimg2d_rect *r;
	struct fimg2d_dma *c;
	int i, y, clp_x, clp_w, clp_h, dir;
	int x1, y1, x2, y2, bpp, stride;
	unsigned long start;

	clp = &blt->param.clipping;
	dir = DMA_TO_DEVICE;

	for (i = 0; i < MAX_IMAGES; i++) {
		if (i == IMAGE_DST)
			dir = DMA_BIDIRECTIONAL;

		img = &cmd->image[i];

		r = &img->rect;

		/* 1st plane */
		c = &cmd->dma[i].base;
		if (!c->cached)
			continue;

		if (i == IMAGE_DST && clp->enable) {
			x1 = clp->x1;
			y1 = clp->y1;
			x2 = clp->x2;
			y2 = clp->y2;
		} else {
			x1 = r->x1;
			y1 = r->y1;
			x2 = r->x2;
			y2 = r->y2;
		}

		bpp = bit_per_pixel(img, 0);
		stride = width2bytes(img->width, bpp);

		clp_x = pixel2offset(x1, bpp);
		clp_w = width2bytes(x2 - x1, bpp);
		clp_h = y2 - y1;

		if (is_inner_flushrange(stride - clp_w))
			fimg2d_dma_sync_inner(c->addr, c->cached, dir);
		else {
			for (y = 0; y < clp_h; y++) {
				start = c->addr + (stride * y) + clp_x;
				fimg2d_dma_sync_inner(start, clp_w, dir);
			}
		}

		/* 2nd plane */
		if (!is_yuvfmt(img->fmt))
			continue;

		if (img->order != P2_CRCB && img->order != P2_CBCR)
			continue;

		c = &cmd->dma[i].plane2;
		if (!c->cached)
			continue;

		bpp = bit_per_pixel(img, 1);
		stride = width2bytes(img->width, bpp);

		clp_x = pixel2offset(x1, bpp);
		clp_w = width2bytes(x2 - x1, bpp);
		if (img->fmt == CF_YCBCR_420)
			clp_h = (y2 - y1)/2;
		else
			clp_h = y2 - y1;

		if (is_inner_flushrange(stride - clp_w))
			fimg2d_dma_sync_inner(c->addr, c->cached, dir);
		else {
			for (y = 0; y < clp_h; y++) {
				start = c->addr + (stride * y) + clp_x;
				fimg2d_dma_sync_inner(c->addr, c->cached, dir);
			}
		}
	}
}
Пример #7
0
static int fimg2d_calc_dma_size(struct fimg2d_bltcmd *cmd)
{
	struct fimg2d_blit *blt = &cmd->blt;
	struct fimg2d_image *img;
	struct fimg2d_clip *clp;
	struct fimg2d_rect *r;
	struct fimg2d_dma *c;
	enum addr_space addr_type;
	int i, y1, y2, stride, clp_h, bpp;

	addr_type = blt->dst->addr.type;

	if (addr_type != ADDR_USER && addr_type != ADDR_USER_CONTIG)
		return -1;

	clp = &blt->param.clipping;

	for (i = 0; i < MAX_IMAGES; i++) {
		img = &cmd->image[i];

		r = &img->rect;

		if (i == IMAGE_DST && clp->enable) {
			y1 = clp->y1;
			y2 = clp->y2;
		} else {
			y1 = r->y1;
			y2 = r->y2;
		}

		/* 1st plane */
		bpp = bit_per_pixel(img, 0);
		stride = width2bytes(img->width, bpp);

		clp_h = y2 - y1;

		c = &cmd->dma[i].base;
		c->addr = img->addr.start + (stride * y1);
		c->size = stride * clp_h;

		if (img->need_cacheopr) {
			c->cached = c->size;
			cmd->dma_all += c->cached;
		}

		if (!is_yuvfmt(img->fmt))
			continue;

		/* 2nd plane */
		if (img->order == P2_CRCB || img->order == P2_CBCR) {
			bpp = bit_per_pixel(img, 1);
			stride = width2bytes(img->width, bpp);
			if (img->fmt == CF_YCBCR_420)
				clp_h = (y2 - y1)/2;
			else
				clp_h = y2 - y1;

			c = &cmd->dma[i].plane2;
			c->addr = img->plane2.start + (stride * y1);
			c->size = stride * clp_h;

			if (img->need_cacheopr) {
				c->cached = c->size;
				cmd->dma_all += c->cached;
			}
		}
	}

	return 0;
}
Пример #8
0
static int fimg2d_check_params(struct fimg2d_control *info,
		struct fimg2d_bltcmd *cmd)
{
	int w, h, i;
	struct fimg2d_param *p = &cmd->param;
	struct fimg2d_image *img;
	struct fimg2d_scale *scl;
	struct fimg2d_clip *clp;
	struct fimg2d_rect *r;

	/* dst is mandatory */
	if (!cmd->image[IDST].addr.type)
		return -1;

	/* DST op makes no effect */
	if (cmd->op < 0 || cmd->op == BLIT_OP_DST || cmd->op >= BLIT_OP_END)
		return -1;

	for (i = 0; i < MAX_IMAGES; i++) {
		img = &cmd->image[i];
		if (!img->addr.type)
			continue;

		w = img->width;
		h = img->height;
		r = &img->rect;

		/* 8000: max width & height */
		if (w > 8000 || h > 8000) {
			dev_err(info->dev, "%s too large (w = %d, h = %d)\n",
					imagename(i), w, h);
			return -1;
		}

		if (r->x1 < 0 || r->y1 < 0 ||
			r->x1 >= w || r->y1 >= h ||
			r->x1 >= r->x2 || r->y1 >= r->y2) {
			dev_err(info->dev,
					"%s has invalid clipping rectangle (r = [%d, %d, %d, %d], w = %d, h = %d)\n",
					imagename(i), r->x1, r->y1, r->x2,
					r->y2, w, h);
			return -1;
		}

		if (is_yuvfmt(img->fmt) && img->stride != w) {
			dev_err(info->dev,
					"YUV %s stride and width not equal (stride = %d, w = %d)\n",
					imagename(i), img->stride, w);
			return -1;
		}

		if (img->fmt == CF_YCBCR_422 ||
				img->fmt == CF_YCBCR_420) {
			const char *fmtname = img->fmt == CF_YCBCR_422 ?
					"YCbCr422" : "YCbCr420";

			if ((r->x1 & 1) ||
					(r->x2 & 1)) {
				dev_err(info->dev,
						"%s %s clipping rectangle X coordinates not even (x1 = %d, x2 = %d)\n",
						fmtname, imagename(i),
						r->x1, r->x2);
				return -1;

			}

			if (img->stride & 1) {
				dev_err(info->dev,
						"%s %s stride not even (stride = %d)\n",
						fmtname, imagename(i),
						img->stride);
				return -1;
			}
		}

		if (img->fmt == CF_YCBCR_420) {
			if ((r->y1 & 1) ||
					(r->y2 & 1)) {
				dev_err(info->dev,
						"YCbCr420 %s clipping rectangle Y coordinates not even (y1 = %d, y2 = %d)\n",
						imagename(i),
						r->y1, r->y2);
				return -1;

			}
		}
	}

	clp = &p->clipping;
	if (clp->enable) {
		img = &cmd->image[IDST];

		w = img->width;
		h = img->height;
		r = &img->rect;

		if (clp->x1 < 0 || clp->y1 < 0 ||
			clp->x1 >= w || clp->y1 >= h ||
			clp->x1 >= clp->x2 || clp->y1 >= clp->y2 ||
			clp->x1 >= r->x2 || clp->x2 <= r->x1 ||
			clp->y1 >= r->y2 || clp->y2 <= r->y1)
			return -1;
	}

	scl = &p->scaling;
	if (scl->mode) {
		if (!scl->src_w || !scl->src_h || !scl->dst_w || !scl->dst_h)
			return -1;
	}

	return 0;
}