Commit 67ca6b60 authored by Philipp Zabel's avatar Philipp Zabel

drm/imx: ipuv3-plane: Add more thorough checks for plane parameter limitations

The IPU addresses multiplanar formats using a base address and relative
offsets for the secondary planes. Since those offsets must be positive
and not too large, and none of the plane parameters except the base address
may be changed while scanout is active, store the pitches and u/v offsets
and check all values against IDMAC limitations.
Signed-off-by: default avatarPhilipp Zabel <p.zabel@pengutronix.de>
parent 90195c36
......@@ -72,22 +72,101 @@ static inline int calc_bandwidth(int width, int height, unsigned int vref)
int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
int x, int y)
{
struct drm_gem_cma_object *cma_obj;
unsigned long eba;
int active;
cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
if (!cma_obj) {
DRM_DEBUG_KMS("entry is null.\n");
struct drm_gem_cma_object *cma_obj[3];
unsigned long eba, ubo, vbo;
int active, i;
for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) {
cma_obj[i] = drm_fb_cma_get_gem_obj(fb, i);
if (!cma_obj[i]) {
DRM_DEBUG_KMS("plane %d entry is null.\n", i);
return -EFAULT;
}
}
dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d",
&cma_obj->paddr, x, y);
eba = cma_obj->paddr + fb->offsets[0] +
eba = cma_obj[0]->paddr + fb->offsets[0] +
fb->pitches[0] * y + (fb->bits_per_pixel >> 3) * x;
if (eba & 0x7) {
DRM_DEBUG_KMS("base address must be a multiple of 8.\n");
return -EINVAL;
}
if (fb->pitches[0] < 1 || fb->pitches[0] > 16384) {
DRM_DEBUG_KMS("pitches out of range.\n");
return -EINVAL;
}
if (ipu_plane->enabled && fb->pitches[0] != ipu_plane->stride[0]) {
DRM_DEBUG_KMS("pitches must not change while plane is enabled.\n");
return -EINVAL;
}
ipu_plane->stride[0] = fb->pitches[0];
switch (fb->pixel_format) {
case DRM_FORMAT_YUV420:
case DRM_FORMAT_YVU420:
/*
* Multiplanar formats have to meet the following restrictions:
* - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO
* - EBA, UBO and VBO are a multiple of 8
* - UBO and VBO are unsigned and not larger than 0xfffff8
* - Only EBA may be changed while scanout is active
* - The strides of U and V planes must be identical.
*/
ubo = cma_obj[1]->paddr + fb->offsets[1] +
fb->pitches[1] * y / 2 + x / 2 - eba;
vbo = cma_obj[2]->paddr + fb->offsets[2] +
fb->pitches[2] * y / 2 + x / 2 - eba;
if ((ubo & 0x7) || (vbo & 0x7)) {
DRM_DEBUG_KMS("U/V buffer offsets must be a multiple of 8.\n");
return -EINVAL;
}
if ((ubo > 0xfffff8) || (vbo > 0xfffff8)) {
DRM_DEBUG_KMS("U/V buffer offsets must be positive and not larger than 0xfffff8.\n");
return -EINVAL;
}
if (ipu_plane->enabled && ((ipu_plane->u_offset != ubo) ||
(ipu_plane->v_offset != vbo))) {
DRM_DEBUG_KMS("U/V buffer offsets must not change while plane is enabled.\n");
return -EINVAL;
}
if (fb->pitches[1] != fb->pitches[2]) {
DRM_DEBUG_KMS("U/V pitches must be identical.\n");
return -EINVAL;
}
if (fb->pitches[1] < 1 || fb->pitches[1] > 16384) {
DRM_DEBUG_KMS("U/V pitches out of range.\n");
return -EINVAL;
}
if (ipu_plane->enabled &&
(ipu_plane->stride[1] != fb->pitches[1])) {
DRM_DEBUG_KMS("U/V pitches must not change while plane is enabled.\n");
return -EINVAL;
}
ipu_plane->u_offset = ubo;
ipu_plane->v_offset = vbo;
ipu_plane->stride[1] = fb->pitches[1];
dev_dbg(ipu_plane->base.dev->dev,
"phys = %pad %pad %pad, x = %d, y = %d",
&cma_obj[0]->paddr, &cma_obj[1]->paddr,
&cma_obj[2]->paddr, x, y);
break;
default:
dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d",
&cma_obj[0]->paddr, x, y);
break;
}
if (ipu_plane->enabled) {
active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch);
ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba);
......
......@@ -29,6 +29,10 @@ struct ipu_plane {
int w;
int h;
unsigned int u_offset;
unsigned int v_offset;
unsigned int stride[2];
bool enabled;
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment