<br><br>2011³â 11¿ù 9ÀÏ ¼ö¿äÀÏ¿¡ Jesse Barnes<<a href="mailto:jbarnes@virtuousgeek.org">jbarnes@virtuousgeek.org</a>>´ÔÀÌ ÀÛ¼º:<br>> Planes are a bit like half-CRTCs. They have a location and fb, but<br>> don't drive outputs directly. Add support for handling them to the core<br>
> KMS code.<br>><br>> Acked-by: Alan Cox <<a href="mailto:alan@lxorguk.ukuu.org.uk">alan@lxorguk.ukuu.org.uk</a>><br>> Reviewed-by: Rob Clark <<a href="mailto:rob.clark@linaro.org">rob.clark@linaro.org</a>><br>
> Reviewed-by: Daniel Vetter <<a href="mailto:daniel.vetter@ffwll.ch">daniel.vetter@ffwll.ch</a>><br>> Signed-off-by: Jesse Barnes <<a href="mailto:jbarnes@virtuousgeek.org">jbarnes@virtuousgeek.org</a>><br>
<br>Reviewed-by: Joonyoung Shim <<a href="mailto:jy0922.shim@samsung.com">jy0922.shim@samsung.com</a>><br><br>Thanks.<br><br>> ---<br>> drivers/gpu/drm/drm_crtc.c | 257 +++++++++++++++++++++++++++++++++++++++++++-<br>
> drivers/gpu/drm/drm_drv.c | 3 +<br>> include/drm/drm.h | 3 +<br>> include/drm/drm_crtc.h | 75 +++++++++++++-<br>> include/drm/drm_mode.h | 33 ++++++<br>> 5 files changed, 368 insertions(+), 3 deletions(-)<br>
><br>> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c<br>> index fe738f0..804ef12 100644<br>> --- a/drivers/gpu/drm/drm_crtc.c<br>> +++ b/drivers/gpu/drm/drm_crtc.c<br>> @@ -321,6 +321,7 @@ void drm_framebuffer_cleanup(struct drm_framebuffer *fb)<br>
> {<br>> struct drm_device *dev = fb->dev;<br>> struct drm_crtc *crtc;<br>> + struct drm_plane *plane;<br>> struct drm_mode_set set;<br>> int ret;<br>><br>> @@ -337,6 +338,15 @@ void drm_framebuffer_cleanup(struct drm_framebuffer *fb)<br>
> }<br>> }<br>><br>> + list_for_each_entry(plane, &dev->mode_config.plane_list, head) {<br>> + if (plane->fb == fb) {<br>> + /* should turn off the crtc */<br>
> + ret = plane->funcs->disable_plane(plane);<br>> + if (ret)<br>> + DRM_ERROR("failed to disable plane with busy fb\n");<br>
> + }<br>> + }<br>> +<br>> drm_mode_object_put(dev, &fb->base);<br>> list_del(&fb->head);<br>> dev->mode_config.num_fb--;<br>> @@ -535,6 +545,50 @@ void drm_encoder_cleanup(struct drm_encoder *encoder)<br>
> }<br>> EXPORT_SYMBOL(drm_encoder_cleanup);<br>><br>> +int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,<br>> + unsigned long possible_crtcs,<br>> + const struct drm_plane_funcs *funcs,<br>
> + uint32_t *formats, uint32_t format_count)<br>> +{<br>> + mutex_lock(&dev->mode_config.mutex);<br>> +<br>> + plane->dev = dev;<br>> + drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);<br>
> + plane->funcs = funcs;<br>> + plane->format_types = kmalloc(sizeof(uint32_t) * format_count,<br>> + GFP_KERNEL);<br>> + if (!plane->format_types) {<br>
> + DRM_DEBUG_KMS("out of memory when allocating plane\n");<br>> + drm_mode_object_put(dev, &plane->base);<br>> + return -ENOMEM;<br>> + }<br>> +<br>
> + memcpy(plane->format_types, formats, format_count);<br>> + plane->format_count = format_count;<br>> + plane->possible_crtcs = possible_crtcs;<br>> +<br>> + list_add_tail(&plane->head, &dev->mode_config.plane_list);<br>
> + dev->mode_config.num_plane++;<br>> +<br>> + mutex_unlock(&dev->mode_config.mutex);<br>> +<br>> + return 0;<br>> +}<br>> +EXPORT_SYMBOL(drm_plane_init);<br>> +<br>> +void drm_plane_cleanup(struct drm_plane *plane)<br>
> +{<br>> + struct drm_device *dev = plane->dev;<br>> +<br>> + mutex_lock(&dev->mode_config.mutex);<br>> + kfree(plane->format_types);<br>> + drm_mode_object_put(dev, &plane->base);<br>
> + list_del(&plane->head);<br>> + dev->mode_config.num_plane--;<br>> + mutex_unlock(&dev->mode_config.mutex);<br>> +}<br>> +EXPORT_SYMBOL(drm_plane_cleanup);<br>> +<br>
> /**<br>> * drm_mode_create - create a new display mode<br>> * @dev: DRM device<br>> @@ -866,6 +920,7 @@ void drm_mode_config_init(struct drm_device *dev)<br>> INIT_LIST_HEAD(&dev->mode_config.encoder_list);<br>
> INIT_LIST_HEAD(&dev->mode_config.property_list);<br>> INIT_LIST_HEAD(&dev->mode_config.property_blob_list);<br>> + INIT_LIST_HEAD(&dev->mode_config.plane_list);<br>> idr_init(&dev->mode_config.crtc_idr);<br>
><br>> mutex_lock(&dev->mode_config.mutex);<br>> @@ -942,6 +997,7 @@ void drm_mode_config_cleanup(struct drm_device *dev)<br>> struct drm_encoder *encoder, *enct;<br>> struct drm_framebuffer *fb, *fbt;<br>
> struct drm_property *property, *pt;<br>> + struct drm_plane *plane, *plt;<br>><br>> list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list,<br>> head) {<br>
> @@ -966,6 +1022,10 @@ void drm_mode_config_cleanup(struct drm_device *dev)<br>> crtc->funcs->destroy(crtc);<br>> }<br>><br>> + list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list,<br>
> + head) {<br>> + plane->funcs->destroy(plane);<br>> + }<br>> }<br>> EXPORT_SYMBOL(drm_mode_config_cleanup);<br>><br>> @@ -1466,6 +1526,197 @@ out:<br>
> }<br>><br>> /**<br>> + * drm_mode_getplane_res - get plane info<br>> + * @dev: DRM device<br>> + * @data: ioctl data<br>> + * @file_priv: DRM file info<br>> + *<br>> + * Return an plane count and set of IDs.<br>
> + */<br>> +int drm_mode_getplane_res(struct drm_device *dev, void *data,<br>> + struct drm_file *file_priv)<br>> +{<br>> + struct drm_mode_get_plane_res *plane_resp = data;<br>
> + struct drm_mode_config *config;<br>> + struct drm_plane *plane;<br>> + uint32_t __user *plane_ptr;<br>> + int copied = 0, ret = 0;<br>> +<br>> + if (!drm_core_check_feature(dev, DRIVER_MODESET))<br>
> + return -EINVAL;<br>> +<br>> + mutex_lock(&dev->mode_config.mutex);<br>> + config = &dev->mode_config;<br>> +<br>> + /*<br>> + * This ioctl is called twice, once to determine how much space is<br>
> + * needed, and the 2nd time to fill it.<br>> + */<br>> + if (config->num_plane &&<br>> + (plane_resp->count_planes >= config->num_plane)) {<br>> + plane_ptr = (uint32_t *)(unsigned long)plane_resp->plane_id_ptr;<br>
> +<br>> + list_for_each_entry(plane, &config->plane_list, head) {<br>> + if (put_user(plane-><a href="http://base.id">base.id</a>, plane_ptr + copied)) {<br>> + ret = -EFAULT;<br>
> + goto out;<br>> + }<br>> + copied++;<br>> + }<br>> + }<br>> + plane_resp->count_planes = config->num_plane;<br>
> +<br>> +out:<br>> + mutex_unlock(&dev->mode_config.mutex);<br>> + return ret;<br>> +}<br>> +<br>> +/**<br>> + * drm_mode_getplane - get plane info<br>> + * @dev: DRM device<br>
> + * @data: ioctl data<br>> + * @file_priv: DRM file info<br>> + *<br>> + * Return plane info, including formats supported, gamma size, any<br>> + * current fb, etc.<br>> + */<br>> +int drm_mode_getplane(struct drm_device *dev, void *data,<br>
> + struct drm_file *file_priv)<br>> +{<br>> + struct drm_mode_get_plane *plane_resp = data;<br>> + struct drm_mode_object *obj;<br>> + struct drm_plane *plane;<br>> + uint32_t __user *format_ptr;<br>
> + int ret = 0;<br>> +<br>> + if (!drm_core_check_feature(dev, DRIVER_MODESET))<br>> + return -EINVAL;<br>> +<br>> + mutex_lock(&dev->mode_config.mutex);<br>> + obj = drm_mode_object_find(dev, plane_resp->plane_id,<br>
> + DRM_MODE_OBJECT_PLANE);<br>> + if (!obj) {<br>> + ret = -ENOENT;<br>> + goto out;<br>> + }<br>> + plane = obj_to_plane(obj);<br>
> +<br>> + if (plane->crtc)<br>> + plane_resp->crtc_id = plane->crtc-><a href="http://base.id">base.id</a>;<br>> + else<br>> + plane_resp->crtc_id = 0;<br>
> +<br>> + if (plane->fb)<br>> + plane_resp->fb_id = plane->fb-><a href="http://base.id">base.id</a>;<br>> + else<br>> + plane_resp->fb_id = 0;<br>> +<br>
> + plane_resp->plane_id = plane-><a href="http://base.id">base.id</a>;<br>> + plane_resp->possible_crtcs = plane->possible_crtcs;<br>> + plane_resp->gamma_size = plane->gamma_size;<br>
> +<br>> + /*<br>> + * This ioctl is called twice, once to determine how much space is<br>> + * needed, and the 2nd time to fill it.<br>> + */<br>> + if (plane->format_count &&<br>
> + (plane_resp->count_format_types >= plane->format_count)) {<br>> + format_ptr = (uint32_t *)(unsigned long)plane_resp->format_type_ptr;<br>> + if (copy_to_user(format_ptr,<br>
> + plane->format_types,<br>> + sizeof(uint32_t) * plane->format_count)) {<br>> + ret = -EFAULT;<br>> + goto out;<br>
> + }<br>> + }<br>> + plane_resp->count_format_types = plane->format_count;<br>> +<br>> +out:<br>> + mutex_unlock(&dev->mode_config.mutex);<br>> + return ret;<br>
> +}<br>> +<br>> +/**<br>> + * drm_mode_setplane - set up or tear down an plane<br>> + * @dev: DRM device<br>> + * @data: ioctl data*<br>> + * @file_prive: DRM file info<br>> + *<br>> + * Set plane info, including placement, fb, scaling, and other factors.<br>
> + * Or pass a NULL fb to disable.<br>> + */<br>> +int drm_mode_setplane(struct drm_device *dev, void *data,<br>> + struct drm_file *file_priv)<br>> +{<br>> + struct drm_mode_set_plane *plane_req = data;<br>
> + struct drm_mode_object *obj;<br>> + struct drm_plane *plane;<br>> + struct drm_crtc *crtc;<br>> + struct drm_framebuffer *fb;<br>> + int ret = 0;<br>> +<br>> + if (!drm_core_check_feature(dev, DRIVER_MODESET))<br>
> + return -EINVAL;<br>> +<br>> + mutex_lock(&dev->mode_config.mutex);<br>> +<br>> + /*<br>> + * First, find the plane, crtc, and fb objects. If not available,<br>
> + * we don't bother to call the driver.<br>> + */<br>> + obj = drm_mode_object_find(dev, plane_req->plane_id,<br>> + DRM_MODE_OBJECT_PLANE);<br>> + if (!obj) {<br>
> + DRM_DEBUG_KMS("Unknown plane ID %d\n",<br>> + plane_req->plane_id);<br>> + ret = -ENOENT;<br>> + goto out;<br>> + }<br>
> + plane = obj_to_plane(obj);<br>> +<br>> + /* No fb means shut it down */<br>> + if (!plane_req->fb_id) {<br>> + plane->funcs->disable_plane(plane);<br>> + goto out;<br>
> + }<br>> +<br>> + obj = drm_mode_object_find(dev, plane_req->crtc_id,<br>> + DRM_MODE_OBJECT_CRTC);<br>> + if (!obj) {<br>> + DRM_DEBUG_KMS("Unknown crtc ID %d\n",<br>
> + plane_req->crtc_id);<br>> + ret = -ENOENT;<br>> + goto out;<br>> + }<br>> + crtc = obj_to_crtc(obj);<br>> +<br>> + obj = drm_mode_object_find(dev, plane_req->fb_id,<br>
> + DRM_MODE_OBJECT_FB);<br>> + if (!obj) {<br>> + DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",<br>> + plane_req->fb_id);<br>
> + ret = -ENOENT;<br>> + goto out;<br>> + }<br>> + fb = obj_to_fb(obj);<br>> +<br>> + ret = plane->funcs->update_plane(plane, crtc, fb,<br>> + plane_req->crtc_x, plane_req->crtc_y,<br>
> + plane_req->crtc_w, plane_req->crtc_h,<br>> + plane_req->src_x, plane_req->src_y,<br>> + plane_req->src_w, plane_req->src_h);<br>
> + if (!ret) {<br>> + plane->crtc = crtc;<br>> + plane->fb = fb;<br>> + }<br>> +<br>> +out:<br>> + mutex_unlock(&dev->mode_config.mutex);<br>
> +<br>> + return ret;<br>> +}<br>> +<br>> +/**<br>> * drm_mode_setcrtc - set CRTC configuration<br>> * @inode: inode from the ioctl<br>> * @filp: file * from the ioctl<br>> @@ -1688,11 +1939,13 @@ int drm_mode_addfb(struct drm_device *dev,<br>
> return -EINVAL;<br>><br>> if ((config->min_width > r->width) || (r->width > config->max_width)) {<br>> - DRM_ERROR("mode new framebuffer width not within limits\n");<br>
> + DRM_ERROR("bad framebuffer width %d, should be >= %d && <= %d\n",<br>> + r->width, config->min_width, config->max_width);<br>> return -EINVAL;<br>
> index 8020798..e20867e 100644<br>> --- a/include/drm/drm_crtc.h<br>> +++ b/include/drm/drm_crtc.h<br>> @@ -44,6 +44,7 @@ struct drm_framebuffer;<br>> #define DRM_MODE_OBJECT_PROPERTY 0xb0b0b0b0<br>> #define DRM_MODE_OBJECT_+extern int drm_pl<br>
<br>-- <br>- Joonyoung Shim<br>