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