mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-05 18:39:59 +00:00
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:
parent
90195c3651
commit
67ca6b60a7
2 changed files with 94 additions and 11 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue