From: Stanislav Vorobiov Date: Wed, 11 Jun 2014 15:25:52 +0000 (+0400) Subject: VIGS: Support DP memory and planar pixel formats X-Git-Tag: submit/tizen_common/20140905.094502~5^2~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F48%2F26348%2F1;p=sdk%2Femulator%2Femulator-kernel.git VIGS: Support DP memory and planar pixel formats DP memory is used by some of the tizen gstreamer plugins, TBM and X.Org video driver. Its main purpose is to share GEM buffers between media decoding and presentation layers Planar pixel formats such as NV21 need to be supported in order to be able to play video right from decoder's output buffer, i.e. without converting it to RGB Change-Id: Ic16f1bd8b53e73b8ca0d3a5a3a52442f3c04770c Signed-off-by: Stanislav Vorobiov --- diff --git a/drivers/gpu/drm/vigs/Makefile b/drivers/gpu/drm/vigs/Makefile index 7312d42fc87d..5e4dccb7a412 100644 --- a/drivers/gpu/drm/vigs/Makefile +++ b/drivers/gpu/drm/vigs/Makefile @@ -19,6 +19,7 @@ vigs_drm-y := main.o \ vigs_fence.o \ vigs_fenceman.o \ vigs_file.o \ - vigs_plane.o + vigs_plane.o \ + vigs_dp.o obj-$(CONFIG_DRM_VIGS) += vigs_drm.o diff --git a/drivers/gpu/drm/vigs/vigs_comm.c b/drivers/gpu/drm/vigs/vigs_comm.c index 5dfb749a4328..758786f2f124 100644 --- a/drivers/gpu/drm/vigs/vigs_comm.c +++ b/drivers/gpu/drm/vigs/vigs_comm.c @@ -421,7 +421,10 @@ int vigs_comm_update_gpu(struct vigs_comm *comm, int vigs_comm_set_plane(struct vigs_comm *comm, u32 plane, - vigsp_surface_id sfc_id, + u32 width, + u32 height, + vigsp_plane_format format, + vigsp_surface_id surfaces[4], unsigned int src_x, unsigned int src_y, unsigned int src_w, @@ -435,8 +438,8 @@ int vigs_comm_set_plane(struct vigs_comm *comm, int ret; struct vigsp_cmd_set_plane_request *request; - DRM_DEBUG_DRIVER("plane = %u, sfc_id = %u, src_x = %u, src_y = %u, src_w = %u, src_h = %u, dst_x = %d, dst_y = %d, dst_w = %u, dst_h = %u, z_pos = %d\n", - plane, sfc_id, src_x, src_y, src_w, src_h, + DRM_DEBUG_DRIVER("plane = %u, src_x = %u, src_y = %u, src_w = %u, src_h = %u, dst_x = %d, dst_y = %d, dst_w = %u, dst_h = %u, z_pos = %d\n", + plane, src_x, src_y, src_w, src_h, dst_x, dst_y, dst_w, dst_h, z_pos); mutex_lock(&comm->mutex); @@ -448,7 +451,10 @@ int vigs_comm_set_plane(struct vigs_comm *comm, if (ret == 0) { request->plane = plane; - request->sfc_id = sfc_id; + request->width = width; + request->height = height; + request->format = format; + memcpy(request->surfaces, surfaces, sizeof(request->surfaces)); request->src_rect.pos.x = src_x; request->src_rect.pos.y = src_y; request->src_rect.size.w = src_w; diff --git a/drivers/gpu/drm/vigs/vigs_comm.h b/drivers/gpu/drm/vigs/vigs_comm.h index c57f35da9526..1242e9c97a99 100644 --- a/drivers/gpu/drm/vigs/vigs_comm.h +++ b/drivers/gpu/drm/vigs/vigs_comm.h @@ -67,7 +67,10 @@ int vigs_comm_update_gpu(struct vigs_comm *comm, int vigs_comm_set_plane(struct vigs_comm *comm, u32 plane, - vigsp_surface_id sfc_id, + u32 width, + u32 height, + vigsp_plane_format format, + vigsp_surface_id surfaces[4], unsigned int src_x, unsigned int src_y, unsigned int src_w, diff --git a/drivers/gpu/drm/vigs/vigs_crtc.c b/drivers/gpu/drm/vigs/vigs_crtc.c index dbc3487fc5b1..da578a3a02b3 100644 --- a/drivers/gpu/drm/vigs/vigs_crtc.c +++ b/drivers/gpu/drm/vigs/vigs_crtc.c @@ -31,7 +31,7 @@ static int vigs_crtc_update(struct drm_crtc *crtc, vigs_fb = fb_to_vigs_fb(crtc->fb); - if (vigs_fb->fb_sfc->scanout) { + if (vigs_fb->surfaces[0]->scanout) { retry: ret = vigs_framebuffer_pin(vigs_fb); @@ -55,14 +55,14 @@ retry: goto retry; } - vigs_gem_reserve(&vigs_fb->fb_sfc->gem); + vigs_gem_reserve(&vigs_fb->surfaces[0]->gem); ret = vigs_comm_set_root_surface(vigs_dev->comm, - vigs_fb->fb_sfc->id, + vigs_fb->surfaces[0]->id, 1, - vigs_gem_offset(&vigs_fb->fb_sfc->gem)); + vigs_gem_offset(&vigs_fb->surfaces[0]->gem)); - vigs_gem_unreserve(&vigs_fb->fb_sfc->gem); + vigs_gem_unreserve(&vigs_fb->surfaces[0]->gem); if (ret != 0) { vigs_framebuffer_unpin(vigs_fb); @@ -71,7 +71,7 @@ retry: } } else { ret = vigs_comm_set_root_surface(vigs_dev->comm, - vigs_fb->fb_sfc->id, + vigs_fb->surfaces[0]->id, 0, 0); @@ -80,7 +80,7 @@ retry: } } - if (vigs_old_fb && vigs_old_fb->fb_sfc->scanout) { + if (vigs_old_fb && vigs_old_fb->surfaces[0]->scanout) { vigs_framebuffer_unpin(vigs_old_fb); } @@ -302,7 +302,7 @@ static void vigs_crtc_disable(struct drm_crtc *crtc) vigs_comm_set_root_surface(vigs_dev->comm, 0, 0, 0); - if (vigs_fb->fb_sfc->scanout) { + if (vigs_fb->surfaces[0]->scanout) { vigs_framebuffer_unpin(vigs_fb); } } diff --git a/drivers/gpu/drm/vigs/vigs_device.c b/drivers/gpu/drm/vigs/vigs_device.c index 14b64187a224..14a9956ef6d0 100644 --- a/drivers/gpu/drm/vigs/vigs_device.c +++ b/drivers/gpu/drm/vigs/vigs_device.c @@ -9,6 +9,7 @@ #include "vigs_fbdev.h" #include "vigs_execbuffer.h" #include "vigs_surface.h" +#include "vigs_dp.h" #include static void vigs_device_mman_vram_to_gpu(void *user_data, @@ -170,12 +171,18 @@ int vigs_device_init(struct vigs_device *vigs_dev, goto fail4; } - ret = vigs_comm_create(vigs_dev, &vigs_dev->comm); + ret = vigs_dp_create(vigs_dev, &vigs_dev->dp); if (ret != 0) { goto fail5; } + ret = vigs_comm_create(vigs_dev, &vigs_dev->comm); + + if (ret != 0) { + goto fail6; + } + spin_lock_init(&vigs_dev->irq_lock); drm_mode_config_init(vigs_dev->drm_dev); @@ -185,27 +192,27 @@ int vigs_device_init(struct vigs_device *vigs_dev, ret = vigs_crtc_init(vigs_dev); if (ret != 0) { - goto fail6; + goto fail7; } ret = vigs_output_init(vigs_dev); if (ret != 0) { - goto fail6; + goto fail7; } for (i = 0; i < VIGS_MAX_PLANES; ++i) { ret = vigs_plane_init(vigs_dev, i); if (ret != 0) { - goto fail6; + goto fail7; } } ret = drm_vblank_init(drm_dev, 1); if (ret != 0) { - goto fail6; + goto fail7; } /* @@ -217,24 +224,26 @@ int vigs_device_init(struct vigs_device *vigs_dev, ret = drm_irq_install(drm_dev); if (ret != 0) { - goto fail7; + goto fail8; } ret = vigs_fbdev_create(vigs_dev, &vigs_dev->fbdev); if (ret != 0) { - goto fail8; + goto fail9; } return 0; -fail8: +fail9: drm_irq_uninstall(drm_dev); -fail7: +fail8: drm_vblank_cleanup(drm_dev); -fail6: +fail7: drm_mode_config_cleanup(vigs_dev->drm_dev); vigs_comm_destroy(vigs_dev->comm); +fail6: + vigs_dp_destroy(vigs_dev->dp); fail5: vigs_fenceman_destroy(vigs_dev->fenceman); fail4: @@ -259,6 +268,7 @@ void vigs_device_cleanup(struct vigs_device *vigs_dev) drm_vblank_cleanup(vigs_dev->drm_dev); drm_mode_config_cleanup(vigs_dev->drm_dev); vigs_comm_destroy(vigs_dev->comm); + vigs_dp_destroy(vigs_dev->dp); vigs_fenceman_destroy(vigs_dev->fenceman); ttm_object_device_release(&vigs_dev->obj_dev); vigs_mman_destroy(vigs_dev->mman); diff --git a/drivers/gpu/drm/vigs/vigs_device.h b/drivers/gpu/drm/vigs/vigs_device.h index 1ea36dab6e9a..183898137881 100644 --- a/drivers/gpu/drm/vigs/vigs_device.h +++ b/drivers/gpu/drm/vigs/vigs_device.h @@ -6,6 +6,7 @@ struct vigs_mman; struct vigs_fenceman; +struct vigs_dp; struct vigs_comm; struct vigs_fbdev; struct vigs_surface; @@ -39,6 +40,8 @@ struct vigs_device struct vigs_fenceman *fenceman; + struct vigs_dp *dp; + struct vigs_comm *comm; struct vigs_fbdev *fbdev; diff --git a/drivers/gpu/drm/vigs/vigs_dp.c b/drivers/gpu/drm/vigs/vigs_dp.c new file mode 100644 index 000000000000..7680230a52e4 --- /dev/null +++ b/drivers/gpu/drm/vigs/vigs_dp.c @@ -0,0 +1,228 @@ +#include "vigs_dp.h" +#include "vigs_surface.h" +#include "vigs_device.h" + +int vigs_dp_create(struct vigs_device *vigs_dev, + struct vigs_dp **dp) +{ + int ret = 0; + + DRM_DEBUG_DRIVER("enter\n"); + + *dp = kzalloc(sizeof(**dp), GFP_KERNEL); + + if (!*dp) { + ret = -ENOMEM; + goto fail1; + } + + return 0; + +fail1: + *dp = NULL; + + return ret; +} + +void vigs_dp_destroy(struct vigs_dp *dp) +{ + DRM_DEBUG_DRIVER("enter\n"); + + kfree(dp); +} + +void vigs_dp_remove_surface(struct vigs_dp *dp, struct vigs_surface *sfc) +{ + int i, j; + + for (i = 0; i < VIGS_MAX_PLANES; ++i) { + for (j = 0; j < DRM_VIGS_NUM_DP_FB_BUF; ++j) { + if (dp->planes[i].fb_bufs[j].y == sfc) { + dp->planes[i].fb_bufs[j].y = NULL; + } + if (dp->planes[i].fb_bufs[j].c == sfc) { + dp->planes[i].fb_bufs[j].c = NULL; + } + } + } +} + +int vigs_dp_surface_create_ioctl(struct drm_device *drm_dev, + void *data, + struct drm_file *file_priv) +{ + struct vigs_device *vigs_dev = drm_dev->dev_private; + struct vigs_dp *dp = vigs_dev->dp; + struct drm_vigs_dp_create_surface *args = data; + struct vigs_surface *sfc = NULL; + bool busy; + uint32_t handle; + int ret; + + if (args->dp_plane >= VIGS_MAX_PLANES) { + DRM_ERROR("bad DP plane = %u\n", args->dp_plane); + return -ENOMEM; + } + + if (args->dp_fb_buf >= DRM_VIGS_NUM_DP_FB_BUF) { + DRM_ERROR("bad DP fb buf = %u\n", args->dp_fb_buf); + return -ENOMEM; + } + + mutex_lock(&vigs_dev->drm_dev->struct_mutex); + + switch (args->dp_mem_flag) { + case DRM_VIGS_DP_FB_Y: + busy = dp->planes[args->dp_plane].fb_bufs[args->dp_fb_buf].y != NULL; + break; + case DRM_VIGS_DP_FB_C: + busy = dp->planes[args->dp_plane].fb_bufs[args->dp_fb_buf].c != NULL; + break; + default: + mutex_unlock(&vigs_dev->drm_dev->struct_mutex); + DRM_ERROR("bad DP mem flag = %u\n", args->dp_mem_flag); + return -ENOMEM; + } + + mutex_unlock(&vigs_dev->drm_dev->struct_mutex); + + if (busy) { + DRM_INFO("DP mem %u:%u:%u is busy\n", args->dp_plane, + args->dp_fb_buf, + args->dp_mem_flag); + return -ENOMEM; + } + + ret = vigs_surface_create(vigs_dev, + args->width, + args->height, + args->stride, + args->format, + false, + &sfc); + + if (ret != 0) { + return ret; + } + + /* + * Check busy again since DP mem might + * gotten busy while we were creating our surface. + * If it's not busy then occupy it. + */ + + mutex_lock(&vigs_dev->drm_dev->struct_mutex); + + switch (args->dp_mem_flag) { + case DRM_VIGS_DP_FB_Y: + if (dp->planes[args->dp_plane].fb_bufs[args->dp_fb_buf].y) { + busy = true; + } else { + dp->planes[args->dp_plane].fb_bufs[args->dp_fb_buf].y = sfc; + } + break; + case DRM_VIGS_DP_FB_C: + if (dp->planes[args->dp_plane].fb_bufs[args->dp_fb_buf].c) { + busy = true; + } else { + dp->planes[args->dp_plane].fb_bufs[args->dp_fb_buf].c = sfc; + } + break; + default: + drm_gem_object_unreference(&sfc->gem.base); + mutex_unlock(&vigs_dev->drm_dev->struct_mutex); + BUG(); + return -ENOMEM; + } + + mutex_unlock(&vigs_dev->drm_dev->struct_mutex); + + if (busy) { + drm_gem_object_unreference_unlocked(&sfc->gem.base); + + DRM_INFO("DP mem %u:%u:%u is busy\n", args->dp_plane, + args->dp_fb_buf, + args->dp_mem_flag); + return -ENOMEM; + } + + ret = drm_gem_handle_create(file_priv, + &sfc->gem.base, + &handle); + + if (ret == 0) { + args->handle = handle; + args->size = vigs_gem_size(&sfc->gem); + args->id = sfc->id; + } else { + /* + * Don't bother setting DP mem slot to NULL here, DRM + * will do this for us once the GEM is freed. + */ + } + + drm_gem_object_unreference_unlocked(&sfc->gem.base); + + return ret; +} + +int vigs_dp_surface_open_ioctl(struct drm_device *drm_dev, + void *data, + struct drm_file *file_priv) +{ + struct vigs_device *vigs_dev = drm_dev->dev_private; + struct vigs_dp *dp = vigs_dev->dp; + struct drm_vigs_dp_open_surface *args = data; + struct vigs_surface *sfc = NULL; + uint32_t handle; + int ret; + + if (args->dp_plane >= VIGS_MAX_PLANES) { + DRM_ERROR("bad DP plane = %u\n", args->dp_plane); + return -ENOMEM; + } + + if (args->dp_fb_buf >= DRM_VIGS_NUM_DP_FB_BUF) { + DRM_ERROR("bad DP fb buf = %u\n", args->dp_fb_buf); + return -ENOMEM; + } + + mutex_lock(&vigs_dev->drm_dev->struct_mutex); + + switch (args->dp_mem_flag) { + case DRM_VIGS_DP_FB_Y: + sfc = dp->planes[args->dp_plane].fb_bufs[args->dp_fb_buf].y; + break; + case DRM_VIGS_DP_FB_C: + sfc = dp->planes[args->dp_plane].fb_bufs[args->dp_fb_buf].c; + break; + default: + mutex_unlock(&vigs_dev->drm_dev->struct_mutex); + DRM_ERROR("bad DP mem flag = %u\n", args->dp_mem_flag); + return -ENOMEM; + } + + if (sfc) { + drm_gem_object_reference(&sfc->gem.base); + } else { + mutex_unlock(&vigs_dev->drm_dev->struct_mutex); + DRM_INFO("DP mem %u:%u:%u is empty\n", args->dp_plane, + args->dp_fb_buf, + args->dp_mem_flag); + return -ENOMEM; + } + + mutex_unlock(&vigs_dev->drm_dev->struct_mutex); + + ret = drm_gem_handle_create(file_priv, + &sfc->gem.base, + &handle); + + if (ret == 0) { + args->handle = handle; + } + + drm_gem_object_unreference_unlocked(&sfc->gem.base); + + return ret; +} diff --git a/drivers/gpu/drm/vigs/vigs_dp.h b/drivers/gpu/drm/vigs/vigs_dp.h new file mode 100644 index 000000000000..46093ece9fb8 --- /dev/null +++ b/drivers/gpu/drm/vigs/vigs_dp.h @@ -0,0 +1,72 @@ +#ifndef _VIGS_DP_H_ +#define _VIGS_DP_H_ + +#include "drmP.h" +#include "vigs_protocol.h" +#include + +struct vigs_device; +struct vigs_surface; + +struct vigs_dp_fb_buf +{ + /* + * These are weak pointers, no reference is kept + * for them. When surface is destroyed they're + * automatically reset to NULL. Must be + * accessed only with drm_device::struct_mutex held. + * @{ + */ + + struct vigs_surface *y; + struct vigs_surface *c; + + /* + * @} + */ +}; + +struct vigs_dp_plane +{ + struct vigs_dp_fb_buf fb_bufs[DRM_VIGS_NUM_DP_FB_BUF]; +}; + +struct vigs_dp +{ + struct vigs_dp_plane planes[VIGS_MAX_PLANES]; +}; + +int vigs_dp_create(struct vigs_device *vigs_dev, + struct vigs_dp **dp); + +void vigs_dp_destroy(struct vigs_dp *dp); + +/* + * Must be called with drm_device::struct_mutex held. + * @{ + */ + +void vigs_dp_remove_surface(struct vigs_dp *dp, struct vigs_surface *sfc); + +/* + * @} + */ + +/* + * IOCTLs + * @{ + */ + +int vigs_dp_surface_create_ioctl(struct drm_device *drm_dev, + void *data, + struct drm_file *file_priv); + +int vigs_dp_surface_open_ioctl(struct drm_device *drm_dev, + void *data, + struct drm_file *file_priv); + +/* + * @} + */ + +#endif diff --git a/drivers/gpu/drm/vigs/vigs_driver.c b/drivers/gpu/drm/vigs/vigs_driver.c index 110ba4d6415a..07cd0e68aa86 100644 --- a/drivers/gpu/drm/vigs/vigs_driver.c +++ b/drivers/gpu/drm/vigs/vigs_driver.c @@ -10,6 +10,7 @@ #include "vigs_file.h" #include "vigs_plane.h" #include "vigs_mman.h" +#include "vigs_dp.h" #include #include #include @@ -66,7 +67,12 @@ static struct drm_ioctl_desc vigs_drm_ioctls[] = DRM_IOCTL_DEF_DRV(VIGS_FENCE_UNREF, vigs_fence_unref_ioctl, DRM_UNLOCKED | DRM_AUTH), DRM_IOCTL_DEF_DRV(VIGS_PLANE_SET_ZPOS, vigs_plane_set_zpos_ioctl, - DRM_UNLOCKED | DRM_AUTH) + DRM_UNLOCKED | DRM_AUTH), + + DRM_IOCTL_DEF_DRV(VIGS_DP_CREATE_SURFACE, vigs_dp_surface_create_ioctl, + DRM_UNLOCKED | DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIGS_DP_OPEN_SURFACE, vigs_dp_surface_open_ioctl, + DRM_UNLOCKED | DRM_AUTH) }; static const struct file_operations vigs_drm_driver_fops = diff --git a/drivers/gpu/drm/vigs/vigs_execbuffer.c b/drivers/gpu/drm/vigs/vigs_execbuffer.c index db73cdbb66df..d6094489af92 100644 --- a/drivers/gpu/drm/vigs/vigs_execbuffer.c +++ b/drivers/gpu/drm/vigs/vigs_execbuffer.c @@ -11,6 +11,7 @@ union vigs_request struct vigsp_cmd_update_gpu_request *update_gpu; struct vigsp_cmd_copy_request *copy; struct vigsp_cmd_solid_fill_request *solid_fill; + struct vigsp_cmd_ga_copy_request *ga_copy; void *data; }; @@ -146,6 +147,9 @@ int vigs_execbuffer_validate_buffers(struct vigs_execbuffer *execbuffer, case vigsp_cmd_solid_fill: *num_buffers += 1; break; + case vigsp_cmd_ga_copy: + *num_buffers += 2; + break; default: break; } @@ -251,6 +255,36 @@ int vigs_execbuffer_validate_buffers(struct vigs_execbuffer *execbuffer, ++*num_buffers; + break; + case vigsp_cmd_ga_copy: + ret = vigs_execbuffer_validate_buffer(vigs_dev, + &(*buffers)[*num_buffers], + list, + request.ga_copy->src_id, + request_header->cmd, + 0, + request.data); + + if (ret != 0) { + goto fail2; + } + + ++*num_buffers; + + ret = vigs_execbuffer_validate_buffer(vigs_dev, + &(*buffers)[*num_buffers], + list, + request.ga_copy->dst_id, + request_header->cmd, + 1, + request.data); + + if (ret != 0) { + goto fail2; + } + + ++*num_buffers; + break; default: break; @@ -279,7 +313,8 @@ fail1: void vigs_execbuffer_process_buffers(struct vigs_execbuffer *execbuffer, struct vigs_validate_buffer *buffers, - int num_buffers) + int num_buffers, + bool *sync) { union vigs_request request; struct vigs_gem_object *gem; @@ -334,6 +369,20 @@ void vigs_execbuffer_process_buffers(struct vigs_execbuffer *execbuffer, sfc->is_gpu_dirty = true; } break; + case vigsp_cmd_ga_copy: + if (buffers[i].which && vigs_gem_in_vram(&sfc->gem)) { + sfc->is_gpu_dirty = true; + } else if (buffers[i].which == 0) { + if (vigs_gem_in_vram(&sfc->gem)) { + request.ga_copy->src_scanout = true; + request.ga_copy->src_offset = vigs_gem_offset(&sfc->gem); + *sync = true; + } else { + request.ga_copy->src_scanout = false; + request.ga_copy->src_offset = 0; + } + } + break; default: break; } @@ -475,7 +524,7 @@ int vigs_execbuffer_exec_ioctl(struct drm_device *drm_dev, goto out3; } - vigs_execbuffer_process_buffers(execbuffer, buffers, num_buffers); + vigs_execbuffer_process_buffers(execbuffer, buffers, num_buffers, &sync); vigs_execbuffer_fence(execbuffer, fence); diff --git a/drivers/gpu/drm/vigs/vigs_execbuffer.h b/drivers/gpu/drm/vigs/vigs_execbuffer.h index 96af8a1ba1b7..0564954ea2af 100644 --- a/drivers/gpu/drm/vigs/vigs_execbuffer.h +++ b/drivers/gpu/drm/vigs/vigs_execbuffer.h @@ -45,7 +45,8 @@ int vigs_execbuffer_validate_buffers(struct vigs_execbuffer *execbuffer, void vigs_execbuffer_process_buffers(struct vigs_execbuffer *execbuffer, struct vigs_validate_buffer *buffers, - int num_buffers); + int num_buffers, + bool *sync); void vigs_execbuffer_fence(struct vigs_execbuffer *execbuffer, struct vigs_fence *fence); diff --git a/drivers/gpu/drm/vigs/vigs_framebuffer.c b/drivers/gpu/drm/vigs/vigs_framebuffer.c index 712f23dd8912..65c78f584fc9 100644 --- a/drivers/gpu/drm/vigs/vigs_framebuffer.c +++ b/drivers/gpu/drm/vigs/vigs_framebuffer.c @@ -6,65 +6,10 @@ #include "drm_crtc_helper.h" #include -static struct drm_framebuffer *vigs_fb_create(struct drm_device *drm_dev, - struct drm_file *file_priv, - struct drm_mode_fb_cmd2 *mode_cmd) -{ - struct vigs_device *vigs_dev = drm_dev->dev_private; - struct drm_gem_object *gem; - struct vigs_gem_object *vigs_gem; - struct vigs_surface *vigs_sfc; - struct vigs_framebuffer *vigs_fb; - int ret; - - DRM_DEBUG_KMS("enter\n"); - - gem = drm_gem_object_lookup(drm_dev, file_priv, mode_cmd->handles[0]); - - if (!gem) { - DRM_ERROR("GEM lookup failed, handle = %u\n", mode_cmd->handles[0]); - return ERR_PTR(-ENOENT); - } - - vigs_gem = gem_to_vigs_gem(gem); - - if (vigs_gem->type != VIGS_GEM_TYPE_SURFACE) { - DRM_ERROR("GEM is not a surface, handle = %u\n", mode_cmd->handles[0]); - drm_gem_object_unreference_unlocked(gem); - return ERR_PTR(-ENOENT); - } - - vigs_sfc = vigs_gem_to_vigs_surface(vigs_gem); - - ret = vigs_framebuffer_create(vigs_dev, - mode_cmd, - vigs_sfc, - &vigs_fb); - - drm_gem_object_unreference_unlocked(gem); - - if (ret != 0) { - DRM_ERROR("unable to create the framebuffer: %d\n", ret); - return ERR_PTR(ret); - } - - return &vigs_fb->base; -} - -static void vigs_output_poll_changed(struct drm_device *drm_dev) -{ - struct vigs_device *vigs_dev = drm_dev->dev_private; - - DRM_DEBUG_KMS("enter\n"); - - if (vigs_dev->fbdev) { - vigs_fbdev_output_poll_changed(vigs_dev->fbdev); - } -} - static void vigs_framebuffer_destroy(struct drm_framebuffer *fb) { struct vigs_framebuffer *vigs_fb = fb_to_vigs_fb(fb); + int i; DRM_DEBUG_KMS("enter\n"); @@ -77,13 +22,28 @@ static void vigs_framebuffer_destroy(struct drm_framebuffer *fb) drm_framebuffer_cleanup(fb); /* - * And we can finally free the GEM. + * And we can finally free the GEMs. */ - drm_gem_object_unreference_unlocked(&vigs_fb->fb_sfc->gem.base); + for (i = 0; i < 4; ++i) { + if (vigs_fb->surfaces[i]) { + drm_gem_object_unreference_unlocked(&vigs_fb->surfaces[i]->gem.base); + } + } kfree(vigs_fb); } +static int vigs_framebuffer_create_handle(struct drm_framebuffer *fb, + struct drm_file *file_priv, + unsigned int *handle) +{ + struct vigs_framebuffer *vigs_fb = fb_to_vigs_fb(fb); + + DRM_DEBUG_KMS("enter\n"); + + return drm_gem_handle_create(file_priv, &vigs_fb->surfaces[0]->gem.base, handle); +} + static int vigs_framebuffer_dirty(struct drm_framebuffer *fb, struct drm_file *file_priv, unsigned flags, unsigned color, @@ -95,15 +55,93 @@ static int vigs_framebuffer_dirty(struct drm_framebuffer *fb, return 0; } -static int vigs_framebuffer_create_handle(struct drm_framebuffer *fb, - struct drm_file *file_priv, - unsigned int *handle) +static struct drm_framebuffer_funcs vigs_framebuffer_funcs = { - struct vigs_framebuffer *vigs_fb = fb_to_vigs_fb(fb); + .destroy = vigs_framebuffer_destroy, + .create_handle = vigs_framebuffer_create_handle, + .dirty = vigs_framebuffer_dirty, +}; + +static struct drm_framebuffer *vigs_fb_create(struct drm_device *drm_dev, + struct drm_file *file_priv, + struct drm_mode_fb_cmd2 *mode_cmd) +{ + struct vigs_device *vigs_dev = drm_dev->dev_private; + struct vigs_surface *surfaces[4]; + int ret, i; + int num_planes = drm_format_num_planes(mode_cmd->pixel_format); + struct vigs_framebuffer *vigs_fb; + + DRM_DEBUG_KMS("enter\n"); + + for (i = 0; i < num_planes; ++i) { + struct drm_gem_object *gem; + struct vigs_gem_object *vigs_gem; + + gem = drm_gem_object_lookup(drm_dev, file_priv, mode_cmd->handles[i]); + + if (!gem) { + DRM_ERROR("GEM lookup failed, handle = %u\n", mode_cmd->handles[i]); + ret = -ENOENT; + goto fail; + } + + vigs_gem = gem_to_vigs_gem(gem); + + if (vigs_gem->type != VIGS_GEM_TYPE_SURFACE) { + DRM_ERROR("GEM is not a surface, handle = %u\n", mode_cmd->handles[i]); + drm_gem_object_unreference_unlocked(gem); + ret = -ENOENT; + goto fail; + } + + surfaces[i] = vigs_gem_to_vigs_surface(vigs_gem); + } + + vigs_fb = kzalloc(sizeof(*vigs_fb), GFP_KERNEL); + + if (!vigs_fb) { + ret = -ENOMEM; + goto fail; + } + + vigs_fb->comm = vigs_dev->comm; + + for (i = 0; i < num_planes; ++i) { + vigs_fb->surfaces[i] = surfaces[i]; + } + + ret = drm_framebuffer_init(vigs_dev->drm_dev, + &vigs_fb->base, + &vigs_framebuffer_funcs); + + if (ret != 0) { + DRM_ERROR("unable to create the framebuffer: %d\n", ret); + kfree(vigs_fb); + goto fail; + } + + drm_helper_mode_fill_fb_struct(&vigs_fb->base, mode_cmd); + + return &vigs_fb->base; + +fail: + for (i--; i >= 0; i--) { + drm_gem_object_unreference_unlocked(&surfaces[i]->gem.base); + } + + return ERR_PTR(ret); +} + +static void vigs_output_poll_changed(struct drm_device *drm_dev) +{ + struct vigs_device *vigs_dev = drm_dev->dev_private; DRM_DEBUG_KMS("enter\n"); - return drm_gem_handle_create(file_priv, &vigs_fb->fb_sfc->gem.base, handle); + if (vigs_dev->fbdev) { + vigs_fbdev_output_poll_changed(vigs_dev->fbdev); + } } static struct drm_mode_config_funcs vigs_mode_config_funcs = @@ -112,13 +150,6 @@ static struct drm_mode_config_funcs vigs_mode_config_funcs = .output_poll_changed = vigs_output_poll_changed }; -static struct drm_framebuffer_funcs vigs_framebuffer_funcs = -{ - .destroy = vigs_framebuffer_destroy, - .create_handle = vigs_framebuffer_create_handle, - .dirty = vigs_framebuffer_dirty, -}; - void vigs_framebuffer_config_init(struct vigs_device *vigs_dev) { DRM_DEBUG_KMS("enter\n"); @@ -159,7 +190,7 @@ int vigs_framebuffer_create(struct vigs_device *vigs_dev, } (*vigs_fb)->comm = vigs_dev->comm; - (*vigs_fb)->fb_sfc = fb_sfc; + (*vigs_fb)->surfaces[0] = fb_sfc; ret = drm_framebuffer_init(vigs_dev->drm_dev, &(*vigs_fb)->base, @@ -187,20 +218,20 @@ int vigs_framebuffer_pin(struct vigs_framebuffer *vigs_fb) { int ret; - vigs_gem_reserve(&vigs_fb->fb_sfc->gem); + vigs_gem_reserve(&vigs_fb->surfaces[0]->gem); - ret = vigs_gem_pin(&vigs_fb->fb_sfc->gem); + ret = vigs_gem_pin(&vigs_fb->surfaces[0]->gem); - vigs_gem_unreserve(&vigs_fb->fb_sfc->gem); + vigs_gem_unreserve(&vigs_fb->surfaces[0]->gem); return ret; } void vigs_framebuffer_unpin(struct vigs_framebuffer *vigs_fb) { - vigs_gem_reserve(&vigs_fb->fb_sfc->gem); + vigs_gem_reserve(&vigs_fb->surfaces[0]->gem); - vigs_gem_unpin(&vigs_fb->fb_sfc->gem); + vigs_gem_unpin(&vigs_fb->surfaces[0]->gem); - vigs_gem_unreserve(&vigs_fb->fb_sfc->gem); + vigs_gem_unreserve(&vigs_fb->surfaces[0]->gem); } diff --git a/drivers/gpu/drm/vigs/vigs_framebuffer.h b/drivers/gpu/drm/vigs/vigs_framebuffer.h index e18024d9be6c..f95728ef57dc 100644 --- a/drivers/gpu/drm/vigs/vigs_framebuffer.h +++ b/drivers/gpu/drm/vigs/vigs_framebuffer.h @@ -17,7 +17,7 @@ struct vigs_framebuffer */ struct vigs_comm *comm; - struct vigs_surface *fb_sfc; + struct vigs_surface *surfaces[4]; }; static inline struct vigs_framebuffer *fb_to_vigs_fb(struct drm_framebuffer *fb) diff --git a/drivers/gpu/drm/vigs/vigs_gem.c b/drivers/gpu/drm/vigs/vigs_gem.c index 1a15b043e8fb..b1ef09b6cd7a 100644 --- a/drivers/gpu/drm/vigs/vigs_gem.c +++ b/drivers/gpu/drm/vigs/vigs_gem.c @@ -2,6 +2,7 @@ #include "vigs_device.h" #include "vigs_mman.h" #include "vigs_surface.h" +#include "vigs_dp.h" #include #include @@ -261,6 +262,13 @@ void vigs_gem_free_object(struct drm_gem_object *gem) { struct vigs_gem_object *vigs_gem = gem_to_vigs_gem(gem); + if (vigs_gem->type == VIGS_GEM_TYPE_SURFACE) { + struct vigs_device *vigs_dev = gem->dev->dev_private; + + vigs_dp_remove_surface(vigs_dev->dp, + vigs_gem_to_vigs_surface(vigs_gem)); + } + vigs_gem_reserve(vigs_gem); vigs_gem_kunmap(vigs_gem); diff --git a/drivers/gpu/drm/vigs/vigs_plane.c b/drivers/gpu/drm/vigs/vigs_plane.c index f7f06711f0fa..c95c2226694f 100644 --- a/drivers/gpu/drm/vigs/vigs_plane.c +++ b/drivers/gpu/drm/vigs/vigs_plane.c @@ -9,6 +9,9 @@ static const uint32_t formats[] = { DRM_FORMAT_XRGB8888, DRM_FORMAT_ARGB8888, + DRM_FORMAT_NV21, + fourcc_code('N', 'V', '4', '2'), + DRM_FORMAT_NV61 }; static int vigs_plane_update(struct drm_plane *plane, @@ -23,33 +26,66 @@ static int vigs_plane_update(struct drm_plane *plane, struct vigs_plane *vigs_plane = plane_to_vigs_plane(plane); struct vigs_device *vigs_dev = plane->dev->dev_private; struct vigs_framebuffer *vigs_fb = fb_to_vigs_fb(fb); - int ret; + int ret, i; uint32_t src_x_whole = src_x >> 16; uint32_t src_y_whole = src_y >> 16; uint32_t src_w_whole = src_w >> 16; uint32_t src_h_whole = src_h >> 16; + vigsp_surface_id surface_ids[4] = { 0, 0, 0, 0 }; + vigsp_plane_format format; DRM_DEBUG_KMS("enter: crtc_x = %d, crtc_y = %d, crtc_w = %u, crtc_h = %u, src_x = %u, src_y = %u, src_w = %u, src_h = %u\n", crtc_x, crtc_y, crtc_w, crtc_h, src_x, src_y, src_w, src_h); - if (vigs_fb->fb_sfc->scanout) { - vigs_gem_reserve(&vigs_fb->fb_sfc->gem); + if (vigs_fb->surfaces[0]->scanout) { + vigs_gem_reserve(&vigs_fb->surfaces[0]->gem); - if (vigs_gem_in_vram(&vigs_fb->fb_sfc->gem) && - vigs_surface_need_gpu_update(vigs_fb->fb_sfc)) { + if (vigs_gem_in_vram(&vigs_fb->surfaces[0]->gem) && + vigs_surface_need_gpu_update(vigs_fb->surfaces[0])) { vigs_comm_update_gpu(vigs_dev->comm, - vigs_fb->fb_sfc->id, - vigs_fb->fb_sfc->width, - vigs_fb->fb_sfc->height, - vigs_gem_offset(&vigs_fb->fb_sfc->gem)); + vigs_fb->surfaces[0]->id, + vigs_fb->surfaces[0]->width, + vigs_fb->surfaces[0]->height, + vigs_gem_offset(&vigs_fb->surfaces[0]->gem)); + } + + vigs_gem_unreserve(&vigs_fb->surfaces[0]->gem); + } + + for (i = 0; i < 4; ++i) { + if (vigs_fb->surfaces[i]) { + surface_ids[i] = vigs_fb->surfaces[i]->id; } + } - vigs_gem_unreserve(&vigs_fb->fb_sfc->gem); + switch (fb->pixel_format) { + case DRM_FORMAT_XRGB8888: + format = vigsp_plane_bgrx8888; + break; + case DRM_FORMAT_ARGB8888: + format = vigsp_plane_bgra8888; + break; + case DRM_FORMAT_NV21: + format = vigsp_plane_nv21; + break; + case fourcc_code('N', 'V', '4', '2'): + format = vigsp_plane_nv42; + break; + case DRM_FORMAT_NV61: + format = vigsp_plane_nv61; + break; + default: + BUG(); + format = vigsp_plane_bgrx8888; + break; } ret = vigs_comm_set_plane(vigs_dev->comm, vigs_plane->index, - vigs_fb->fb_sfc->id, + fb->width, + fb->height, + format, + surface_ids, src_x_whole, src_y_whole, src_w_whole, @@ -82,6 +118,7 @@ static int vigs_plane_disable(struct drm_plane *plane) struct vigs_plane *vigs_plane = plane_to_vigs_plane(plane); struct vigs_device *vigs_dev = plane->dev->dev_private; int ret; + vigsp_surface_id surface_ids[4] = { 0, 0, 0, 0 }; DRM_DEBUG_KMS("enter\n"); @@ -94,6 +131,9 @@ static int vigs_plane_disable(struct drm_plane *plane) 0, 0, 0, + surface_ids, + 0, + 0, 0, 0, 0, diff --git a/drivers/gpu/drm/vigs/vigs_protocol.h b/drivers/gpu/drm/vigs/vigs_protocol.h index f75b9af4dd3a..cf535ede2447 100644 --- a/drivers/gpu/drm/vigs/vigs_protocol.h +++ b/drivers/gpu/drm/vigs/vigs_protocol.h @@ -8,7 +8,7 @@ /* * Bump this whenever protocol changes. */ -#define VIGS_PROTOCOL_VERSION 17 +#define VIGS_PROTOCOL_VERSION 18 #define VIGS_MAX_PLANES 2 @@ -52,6 +52,7 @@ typedef enum vigsp_cmd_copy = 0x8, vigsp_cmd_solid_fill = 0x9, vigsp_cmd_set_plane = 0xA, + vigsp_cmd_ga_copy = 0xB /* * @} */ @@ -63,6 +64,15 @@ typedef enum vigsp_surface_bgra8888 = 0x1, } vigsp_surface_format; +typedef enum +{ + vigsp_plane_bgrx8888 = 0x0, + vigsp_plane_bgra8888 = 0x1, + vigsp_plane_nv21 = 0x2, + vigsp_plane_nv42 = 0x3, + vigsp_plane_nv61 = 0x4 +} vigsp_plane_format; + #pragma pack(1) struct vigsp_point @@ -303,9 +313,9 @@ struct vigsp_cmd_solid_fill_request /* * cmd_set_plane * - * Assigns surface 'sfc_id' to plane identified by 'plane'. + * Assigns surfaces 'surfaces' to plane identified by 'plane'. * - * Pass 0 as sfc_id in order to disable the plane. + * Pass 0 as surfaces[0] in order to disable the plane. * * @{ */ @@ -313,7 +323,10 @@ struct vigsp_cmd_solid_fill_request struct vigsp_cmd_set_plane_request { vigsp_u32 plane; - vigsp_surface_id sfc_id; + vigsp_u32 width; + vigsp_u32 height; + vigsp_plane_format format; + vigsp_surface_id surfaces[4]; struct vigsp_rect src_rect; vigsp_s32 dst_x; vigsp_s32 dst_y; @@ -321,6 +334,31 @@ struct vigsp_cmd_set_plane_request vigsp_s32 z_pos; }; +/* + * @} + */ + +/* + * cmd_ga_copy + * + * Copies part of surface 'src_id' to + * surface 'dst_id' given surface + * sizes. + * + * @{ + */ + +struct vigsp_cmd_ga_copy_request +{ + vigsp_surface_id src_id; + vigsp_bool src_scanout; + vigsp_offset src_offset; + vigsp_u32 src_stride; + vigsp_surface_id dst_id; + vigsp_u32 dst_stride; + struct vigsp_copy entry; +}; + /* * @} */ diff --git a/include/drm/vigs_drm.h b/include/drm/vigs_drm.h index 9211a17c11e2..933fc85cac16 100644 --- a/include/drm/vigs_drm.h +++ b/include/drm/vigs_drm.h @@ -8,7 +8,7 @@ /* * Bump this whenever driver interface changes. */ -#define DRM_VIGS_DRIVER_VERSION 12 +#define DRM_VIGS_DRIVER_VERSION 13 /* * Surface access flags. @@ -17,6 +17,17 @@ #define DRM_VIGS_SAF_WRITE 2 #define DRM_VIGS_SAF_MASK 3 +/* + * Number of DP framebuffers. + */ +#define DRM_VIGS_NUM_DP_FB_BUF 4 + +/* + * DP memory types. + */ +#define DRM_VIGS_DP_FB_Y 2 +#define DRM_VIGS_DP_FB_C 3 + struct drm_vigs_get_protocol_version { uint32_t version; @@ -115,6 +126,28 @@ struct drm_vigs_plane_set_zpos int zpos; }; +struct drm_vigs_dp_create_surface +{ + uint32_t dp_plane; + uint32_t dp_fb_buf; + uint32_t dp_mem_flag; + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t format; + uint32_t handle; + uint32_t size; + uint32_t id; +}; + +struct drm_vigs_dp_open_surface +{ + uint32_t dp_plane; + uint32_t dp_fb_buf; + uint32_t dp_mem_flag; + uint32_t handle; +}; + #define DRM_VIGS_GET_PROTOCOL_VERSION 0x00 #define DRM_VIGS_CREATE_SURFACE 0x01 #define DRM_VIGS_CREATE_EXECBUFFER 0x02 @@ -131,6 +164,9 @@ struct drm_vigs_plane_set_zpos #define DRM_VIGS_FENCE_UNREF 0x0D #define DRM_VIGS_PLANE_SET_ZPOS 0x0E +#define DRM_VIGS_DP_CREATE_SURFACE 0x20 +#define DRM_VIGS_DP_OPEN_SURFACE 0x21 + #define DRM_IOCTL_VIGS_GET_PROTOCOL_VERSION DRM_IOR(DRM_COMMAND_BASE + \ DRM_VIGS_GET_PROTOCOL_VERSION, struct drm_vigs_get_protocol_version) #define DRM_IOCTL_VIGS_CREATE_SURFACE DRM_IOWR(DRM_COMMAND_BASE + \ @@ -162,4 +198,9 @@ struct drm_vigs_plane_set_zpos #define DRM_IOCTL_VIGS_PLANE_SET_ZPOS DRM_IOW(DRM_COMMAND_BASE + \ DRM_VIGS_PLANE_SET_ZPOS, struct drm_vigs_plane_set_zpos) +#define DRM_IOCTL_VIGS_DP_CREATE_SURFACE DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_VIGS_DP_CREATE_SURFACE, struct drm_vigs_dp_create_surface) +#define DRM_IOCTL_VIGS_DP_OPEN_SURFACE DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_VIGS_DP_OPEN_SURFACE, struct drm_vigs_dp_open_surface) + #endif