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: Philipp Zabel <p.zabel@pengutronix.de>
This commit is contained in:
Philipp Zabel 2016-02-23 10:22:51 +01:00
parent 90195c3651
commit 67ca6b60a7
2 changed files with 94 additions and 11 deletions

View file

@ -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;
struct drm_gem_cma_object *cma_obj[3];
unsigned long eba, ubo, vbo;
int active, i;
cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
if (!cma_obj) {
DRM_DEBUG_KMS("entry is null.\n");
return -EFAULT;
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);

View file

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