mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
drm/vmwgfx: Add and connect plane helper functions
Refactor previous FB and cursor plane update code into their atomic counterparts: check, update, prepare, cleanup, and disable. These helpers won't be called until we flip on the atomic support flag or set drm_crtc_funcs->set_config to using the atomic helper. v2: * Removed unnecessary pinning of cursor surface * Added a few function headers v3: * Set clip region equal to the destination region * Fixed surface pinning policy * Enable SVGA mode in vmw_sou_primary_plane_prepare_fb Signed-off-by: Sinclair Yeh <syeh@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com>
This commit is contained in:
parent
06ec41909e
commit
060e2ad570
5 changed files with 695 additions and 1 deletions
|
@ -26,8 +26,10 @@
|
|||
**************************************************************************/
|
||||
|
||||
#include "vmwgfx_kms.h"
|
||||
#include <drm/drm_plane_helper.h>
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_rect.h>
|
||||
|
||||
|
||||
/* Might need a hrtimer here? */
|
||||
|
@ -390,6 +392,260 @@ void vmw_du_primary_plane_destroy(struct drm_plane *plane)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* vmw_du_vps_unpin_surf - unpins resource associated with a framebuffer surface
|
||||
*
|
||||
* @vps: plane state associated with the display surface
|
||||
* @unreference: true if we also want to unreference the display.
|
||||
*/
|
||||
void vmw_du_plane_unpin_surf(struct vmw_plane_state *vps,
|
||||
bool unreference)
|
||||
{
|
||||
if (vps->surf) {
|
||||
if (vps->pinned) {
|
||||
vmw_resource_unpin(&vps->surf->res);
|
||||
vps->pinned--;
|
||||
}
|
||||
|
||||
if (unreference) {
|
||||
if (vps->pinned)
|
||||
DRM_ERROR("Surface still pinned\n");
|
||||
vmw_surface_unreference(&vps->surf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* vmw_du_plane_cleanup_fb - Unpins the cursor
|
||||
*
|
||||
* @plane: display plane
|
||||
* @old_state: Contains the FB to clean up
|
||||
*
|
||||
* Unpins the framebuffer surface
|
||||
*
|
||||
* Returns 0 on success
|
||||
*/
|
||||
void
|
||||
vmw_du_plane_cleanup_fb(struct drm_plane *plane,
|
||||
struct drm_plane_state *old_state)
|
||||
{
|
||||
struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state);
|
||||
|
||||
vmw_du_plane_unpin_surf(vps, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* vmw_du_cursor_plane_prepare_fb - Readies the cursor by referencing it
|
||||
*
|
||||
* @plane: display plane
|
||||
* @new_state: info on the new plane state, including the FB
|
||||
*
|
||||
* Returns 0 on success
|
||||
*/
|
||||
int
|
||||
vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane,
|
||||
struct drm_plane_state *new_state)
|
||||
{
|
||||
struct drm_framebuffer *fb = new_state->fb;
|
||||
struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state);
|
||||
|
||||
|
||||
if (vps->surf)
|
||||
vmw_surface_unreference(&vps->surf);
|
||||
|
||||
if (vps->dmabuf)
|
||||
vmw_dmabuf_unreference(&vps->dmabuf);
|
||||
|
||||
if (fb) {
|
||||
if (vmw_framebuffer_to_vfb(fb)->dmabuf) {
|
||||
vps->dmabuf = vmw_framebuffer_to_vfbd(fb)->buffer;
|
||||
vmw_dmabuf_reference(vps->dmabuf);
|
||||
} else {
|
||||
vps->surf = vmw_framebuffer_to_vfbs(fb)->surface;
|
||||
vmw_surface_reference(vps->surf);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
vmw_du_cursor_plane_atomic_disable(struct drm_plane *plane,
|
||||
struct drm_plane_state *old_state)
|
||||
{
|
||||
struct drm_crtc *crtc = plane->state->crtc ?: old_state->crtc;
|
||||
struct vmw_private *dev_priv = vmw_priv(crtc->dev);
|
||||
|
||||
drm_atomic_set_fb_for_plane(plane->state, NULL);
|
||||
vmw_cursor_update_position(dev_priv, false, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
vmw_du_cursor_plane_atomic_update(struct drm_plane *plane,
|
||||
struct drm_plane_state *old_state)
|
||||
{
|
||||
struct drm_crtc *crtc = plane->state->crtc ?: old_state->crtc;
|
||||
struct vmw_private *dev_priv = vmw_priv(crtc->dev);
|
||||
struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
|
||||
struct vmw_plane_state *vps = vmw_plane_state_to_vps(plane->state);
|
||||
s32 hotspot_x, hotspot_y;
|
||||
int ret = 0;
|
||||
|
||||
|
||||
hotspot_x = du->hotspot_x;
|
||||
hotspot_y = du->hotspot_y;
|
||||
du->cursor_surface = vps->surf;
|
||||
du->cursor_dmabuf = vps->dmabuf;
|
||||
|
||||
/* setup new image */
|
||||
if (vps->surf) {
|
||||
du->cursor_age = du->cursor_surface->snooper.age;
|
||||
|
||||
ret = vmw_cursor_update_image(dev_priv,
|
||||
vps->surf->snooper.image,
|
||||
64, 64, hotspot_x, hotspot_y);
|
||||
} else if (vps->dmabuf) {
|
||||
ret = vmw_cursor_update_dmabuf(dev_priv, vps->dmabuf,
|
||||
plane->state->crtc_w,
|
||||
plane->state->crtc_h,
|
||||
hotspot_x, hotspot_y);
|
||||
} else {
|
||||
vmw_cursor_update_position(dev_priv, false, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
du->cursor_x = plane->state->crtc_x + du->set_gui_x;
|
||||
du->cursor_y = plane->state->crtc_y + du->set_gui_y;
|
||||
|
||||
vmw_cursor_update_position(dev_priv, true,
|
||||
du->cursor_x + hotspot_x,
|
||||
du->cursor_y + hotspot_y);
|
||||
} else {
|
||||
DRM_ERROR("Failed to update cursor image\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* vmw_du_primary_plane_atomic_check - check if the new state is okay
|
||||
*
|
||||
* @plane: display plane
|
||||
* @state: info on the new plane state, including the FB
|
||||
*
|
||||
* Check if the new state is settable given the current state. Other
|
||||
* than what the atomic helper checks, we care about crtc fitting
|
||||
* the FB and maintaining one active framebuffer.
|
||||
*
|
||||
* Returns 0 on success
|
||||
*/
|
||||
int vmw_du_primary_plane_atomic_check(struct drm_plane *plane,
|
||||
struct drm_plane_state *state)
|
||||
{
|
||||
struct drm_framebuffer *new_fb = state->fb;
|
||||
bool visible;
|
||||
|
||||
struct drm_rect src = {
|
||||
.x1 = state->src_x,
|
||||
.y1 = state->src_y,
|
||||
.x2 = state->src_x + state->src_w,
|
||||
.y2 = state->src_y + state->src_h,
|
||||
};
|
||||
struct drm_rect dest = {
|
||||
.x1 = state->crtc_x,
|
||||
.y1 = state->crtc_y,
|
||||
.x2 = state->crtc_x + state->crtc_w,
|
||||
.y2 = state->crtc_y + state->crtc_h,
|
||||
};
|
||||
struct drm_rect clip = dest;
|
||||
int ret;
|
||||
|
||||
ret = drm_plane_helper_check_update(plane, state->crtc, new_fb,
|
||||
&src, &dest, &clip,
|
||||
DRM_ROTATE_0,
|
||||
DRM_PLANE_HELPER_NO_SCALING,
|
||||
DRM_PLANE_HELPER_NO_SCALING,
|
||||
false, true, &visible);
|
||||
|
||||
|
||||
if (!ret && new_fb) {
|
||||
struct drm_crtc *crtc = state->crtc;
|
||||
struct vmw_connector_state *vcs;
|
||||
struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
|
||||
struct vmw_private *dev_priv = vmw_priv(crtc->dev);
|
||||
struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(new_fb);
|
||||
|
||||
vcs = vmw_connector_state_to_vcs(du->connector.state);
|
||||
|
||||
if ((dest.x2 > new_fb->width ||
|
||||
dest.y2 > new_fb->height)) {
|
||||
DRM_ERROR("CRTC area outside of framebuffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Only one active implicit framebuffer at a time. */
|
||||
mutex_lock(&dev_priv->global_kms_state_mutex);
|
||||
if (vcs->is_implicit && dev_priv->implicit_fb &&
|
||||
!(dev_priv->num_implicit == 1 && du->active_implicit)
|
||||
&& dev_priv->implicit_fb != vfb) {
|
||||
DRM_ERROR("Multiple implicit framebuffers "
|
||||
"not supported.\n");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
mutex_unlock(&dev_priv->global_kms_state_mutex);
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* vmw_du_cursor_plane_atomic_check - check if the new state is okay
|
||||
*
|
||||
* @plane: cursor plane
|
||||
* @state: info on the new plane state
|
||||
*
|
||||
* This is a chance to fail if the new cursor state does not fit
|
||||
* our requirements.
|
||||
*
|
||||
* Returns 0 on success
|
||||
*/
|
||||
int vmw_du_cursor_plane_atomic_check(struct drm_plane *plane,
|
||||
struct drm_plane_state *new_state)
|
||||
{
|
||||
int ret = 0;
|
||||
struct vmw_surface *surface = NULL;
|
||||
struct drm_framebuffer *fb = new_state->fb;
|
||||
|
||||
|
||||
/* Turning off */
|
||||
if (!fb)
|
||||
return ret;
|
||||
|
||||
/* A lot of the code assumes this */
|
||||
if (new_state->crtc_w != 64 || new_state->crtc_h != 64) {
|
||||
DRM_ERROR("Invalid cursor dimensions (%d, %d)\n",
|
||||
new_state->crtc_w, new_state->crtc_h);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
if (!vmw_framebuffer_to_vfb(fb)->dmabuf)
|
||||
surface = vmw_framebuffer_to_vfbs(fb)->surface;
|
||||
|
||||
if (surface && !surface->snooper.image) {
|
||||
DRM_ERROR("surface not suitable for cursor\n");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int vmw_du_crtc_atomic_check(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *new_state)
|
||||
{
|
||||
|
|
|
@ -345,10 +345,25 @@ int vmw_du_cursor_plane_update(struct drm_plane *plane,
|
|||
uint32_t src_w, uint32_t src_h);
|
||||
|
||||
/* Atomic Helpers */
|
||||
int vmw_du_primary_plane_atomic_check(struct drm_plane *plane,
|
||||
struct drm_plane_state *state);
|
||||
int vmw_du_cursor_plane_atomic_check(struct drm_plane *plane,
|
||||
struct drm_plane_state *state);
|
||||
void vmw_du_cursor_plane_atomic_update(struct drm_plane *plane,
|
||||
struct drm_plane_state *old_state);
|
||||
void vmw_du_cursor_plane_atomic_disable(struct drm_plane *plane,
|
||||
struct drm_plane_state *old_state);
|
||||
int vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane,
|
||||
struct drm_plane_state *new_state);
|
||||
void vmw_du_plane_cleanup_fb(struct drm_plane *plane,
|
||||
struct drm_plane_state *old_state);
|
||||
void vmw_du_plane_reset(struct drm_plane *plane);
|
||||
struct drm_plane_state *vmw_du_plane_duplicate_state(struct drm_plane *plane);
|
||||
void vmw_du_plane_destroy_state(struct drm_plane *plane,
|
||||
struct drm_plane_state *state);
|
||||
void vmw_du_plane_unpin_surf(struct vmw_plane_state *vps,
|
||||
bool unreference);
|
||||
|
||||
int vmw_du_crtc_atomic_check(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *state);
|
||||
void vmw_du_crtc_atomic_begin(struct drm_crtc *crtc,
|
||||
|
|
|
@ -234,7 +234,7 @@ static void vmw_ldu_crtc_helper_commit(struct drm_crtc *crtc)
|
|||
|
||||
ldu = vmw_crtc_to_ldu(crtc);
|
||||
dev_priv = vmw_priv(crtc->dev);
|
||||
fb = crtc->primary->fb;
|
||||
fb = crtc->primary->state->fb;
|
||||
|
||||
vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL;
|
||||
|
||||
|
@ -242,6 +242,8 @@ static void vmw_ldu_crtc_helper_commit(struct drm_crtc *crtc)
|
|||
vmw_ldu_add_active(dev_priv, ldu, vfb);
|
||||
else
|
||||
vmw_ldu_del_active(dev_priv, ldu);
|
||||
|
||||
vmw_ldu_commit_list(dev_priv);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -391,6 +393,46 @@ static const struct drm_connector_funcs vmw_legacy_connector_funcs = {
|
|||
* Legacy Display Plane Functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* vmw_ldu_primary_plane_cleanup_fb - Unpin fb
|
||||
*
|
||||
* @plane: display plane
|
||||
* @old_state: Contains the FB to clean up
|
||||
*
|
||||
* Unpins the display surface
|
||||
*
|
||||
* Returns 0 on success
|
||||
*/
|
||||
static void
|
||||
vmw_ldu_primary_plane_cleanup_fb(struct drm_plane *plane,
|
||||
struct drm_plane_state *old_state)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* vmw_ldu_primary_plane_prepare_fb -
|
||||
*
|
||||
* @plane: display plane
|
||||
* @new_state: info on the new plane state, including the FB
|
||||
*
|
||||
* Returns 0 on success
|
||||
*/
|
||||
static int
|
||||
vmw_ldu_primary_plane_prepare_fb(struct drm_plane *plane,
|
||||
struct drm_plane_state *new_state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
vmw_ldu_primary_plane_atomic_update(struct drm_plane *plane,
|
||||
struct drm_plane_state *old_state)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static const struct drm_plane_funcs vmw_ldu_plane_funcs = {
|
||||
.update_plane = drm_primary_helper_update,
|
||||
.disable_plane = drm_primary_helper_disable,
|
||||
|
@ -412,6 +454,22 @@ static const struct drm_plane_funcs vmw_ldu_cursor_funcs = {
|
|||
/*
|
||||
* Atomic Helpers
|
||||
*/
|
||||
static const struct
|
||||
drm_plane_helper_funcs vmw_ldu_cursor_plane_helper_funcs = {
|
||||
.atomic_check = vmw_du_cursor_plane_atomic_check,
|
||||
.atomic_update = vmw_du_cursor_plane_atomic_update,
|
||||
.prepare_fb = vmw_du_cursor_plane_prepare_fb,
|
||||
.cleanup_fb = vmw_du_plane_cleanup_fb,
|
||||
};
|
||||
|
||||
static const struct
|
||||
drm_plane_helper_funcs vmw_ldu_primary_plane_helper_funcs = {
|
||||
.atomic_check = vmw_du_primary_plane_atomic_check,
|
||||
.atomic_update = vmw_ldu_primary_plane_atomic_update,
|
||||
.prepare_fb = vmw_ldu_primary_plane_prepare_fb,
|
||||
.cleanup_fb = vmw_ldu_primary_plane_cleanup_fb,
|
||||
};
|
||||
|
||||
static const struct drm_crtc_helper_funcs vmw_ldu_crtc_helper_funcs = {
|
||||
.prepare = vmw_ldu_crtc_helper_prepare,
|
||||
.commit = vmw_ldu_crtc_helper_commit,
|
||||
|
@ -471,6 +529,8 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
|
|||
goto err_free;
|
||||
}
|
||||
|
||||
drm_plane_helper_add(primary, &vmw_ldu_primary_plane_helper_funcs);
|
||||
|
||||
/* Initialize cursor plane */
|
||||
vmw_du_plane_reset(cursor);
|
||||
|
||||
|
@ -485,6 +545,10 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
|
|||
goto err_free;
|
||||
}
|
||||
|
||||
drm_plane_helper_add(cursor, &vmw_ldu_cursor_plane_helper_funcs);
|
||||
|
||||
|
||||
vmw_du_connector_reset(connector);
|
||||
ret = drm_connector_init(dev, connector, &vmw_legacy_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_VIRTUAL);
|
||||
if (ret) {
|
||||
|
|
|
@ -612,6 +612,100 @@ static const struct drm_connector_funcs vmw_sou_connector_funcs = {
|
|||
* Screen Object Display Plane Functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* vmw_sou_primary_plane_cleanup_fb - Frees sou backing buffer
|
||||
*
|
||||
* @plane: display plane
|
||||
* @old_state: Contains the FB to clean up
|
||||
*
|
||||
* Unpins the display surface
|
||||
*
|
||||
* Returns 0 on success
|
||||
*/
|
||||
static void
|
||||
vmw_sou_primary_plane_cleanup_fb(struct drm_plane *plane,
|
||||
struct drm_plane_state *old_state)
|
||||
{
|
||||
struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state);
|
||||
|
||||
vmw_dmabuf_unreference(&vps->dmabuf);
|
||||
vps->dmabuf_size = 0;
|
||||
|
||||
vmw_du_plane_cleanup_fb(plane, old_state);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* vmw_sou_primary_plane_prepare_fb - allocate backing buffer
|
||||
*
|
||||
* @plane: display plane
|
||||
* @new_state: info on the new plane state, including the FB
|
||||
*
|
||||
* The SOU backing buffer is our equivalent of the display plane.
|
||||
*
|
||||
* Returns 0 on success
|
||||
*/
|
||||
static int
|
||||
vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane,
|
||||
struct drm_plane_state *new_state)
|
||||
{
|
||||
struct drm_framebuffer *new_fb = new_state->fb;
|
||||
struct drm_crtc *crtc = plane->state->crtc ?: new_state->crtc;
|
||||
struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state);
|
||||
struct vmw_private *dev_priv;
|
||||
size_t size;
|
||||
int ret;
|
||||
|
||||
|
||||
if (!new_fb) {
|
||||
vmw_dmabuf_unreference(&vps->dmabuf);
|
||||
vps->dmabuf_size = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size = new_state->crtc_w * new_state->crtc_h * 4;
|
||||
|
||||
if (vps->dmabuf) {
|
||||
if (vps->dmabuf_size == size)
|
||||
return 0;
|
||||
|
||||
vmw_dmabuf_unreference(&vps->dmabuf);
|
||||
vps->dmabuf_size = 0;
|
||||
}
|
||||
|
||||
vps->dmabuf = kzalloc(sizeof(*vps->dmabuf), GFP_KERNEL);
|
||||
if (!vps->dmabuf)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_priv = vmw_priv(crtc->dev);
|
||||
vmw_svga_enable(dev_priv);
|
||||
|
||||
/* After we have alloced the backing store might not be able to
|
||||
* resume the overlays, this is preferred to failing to alloc.
|
||||
*/
|
||||
vmw_overlay_pause_all(dev_priv);
|
||||
ret = vmw_dmabuf_init(dev_priv, vps->dmabuf, size,
|
||||
&vmw_vram_ne_placement,
|
||||
false, &vmw_dmabuf_bo_free);
|
||||
vmw_overlay_resume_all(dev_priv);
|
||||
|
||||
if (ret != 0)
|
||||
vps->dmabuf = NULL; /* vmw_dmabuf_init frees on error */
|
||||
else
|
||||
vps->dmabuf_size = size;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
vmw_sou_primary_plane_atomic_update(struct drm_plane *plane,
|
||||
struct drm_plane_state *old_state)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static const struct drm_plane_funcs vmw_sou_plane_funcs = {
|
||||
.update_plane = drm_primary_helper_update,
|
||||
.disable_plane = drm_primary_helper_disable,
|
||||
|
@ -633,6 +727,22 @@ static const struct drm_plane_funcs vmw_sou_cursor_funcs = {
|
|||
/*
|
||||
* Atomic Helpers
|
||||
*/
|
||||
static const struct
|
||||
drm_plane_helper_funcs vmw_sou_cursor_plane_helper_funcs = {
|
||||
.atomic_check = vmw_du_cursor_plane_atomic_check,
|
||||
.atomic_update = vmw_du_cursor_plane_atomic_update,
|
||||
.prepare_fb = vmw_du_cursor_plane_prepare_fb,
|
||||
.cleanup_fb = vmw_du_plane_cleanup_fb,
|
||||
};
|
||||
|
||||
static const struct
|
||||
drm_plane_helper_funcs vmw_sou_primary_plane_helper_funcs = {
|
||||
.atomic_check = vmw_du_primary_plane_atomic_check,
|
||||
.atomic_update = vmw_sou_primary_plane_atomic_update,
|
||||
.prepare_fb = vmw_sou_primary_plane_prepare_fb,
|
||||
.cleanup_fb = vmw_sou_primary_plane_cleanup_fb,
|
||||
};
|
||||
|
||||
static const struct drm_crtc_helper_funcs vmw_sou_crtc_helper_funcs = {
|
||||
.prepare = vmw_sou_crtc_helper_prepare,
|
||||
.commit = vmw_sou_crtc_helper_commit,
|
||||
|
@ -691,6 +801,8 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
|
|||
goto err_free;
|
||||
}
|
||||
|
||||
drm_plane_helper_add(primary, &vmw_sou_primary_plane_helper_funcs);
|
||||
|
||||
/* Initialize cursor plane */
|
||||
vmw_du_plane_reset(cursor);
|
||||
|
||||
|
@ -705,6 +817,9 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
|
|||
goto err_free;
|
||||
}
|
||||
|
||||
drm_plane_helper_add(cursor, &vmw_sou_cursor_plane_helper_funcs);
|
||||
|
||||
vmw_du_connector_reset(connector);
|
||||
ret = drm_connector_init(dev, connector, &vmw_sou_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_VIRTUAL);
|
||||
if (ret) {
|
||||
|
|
|
@ -1194,6 +1194,230 @@ static const struct drm_connector_funcs vmw_stdu_connector_funcs = {
|
|||
* Screen Target Display Plane Functions
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* vmw_stdu_primary_plane_cleanup_fb - Unpins the display surface
|
||||
*
|
||||
* @plane: display plane
|
||||
* @old_state: Contains the FB to clean up
|
||||
*
|
||||
* Unpins the display surface
|
||||
*
|
||||
* Returns 0 on success
|
||||
*/
|
||||
static void
|
||||
vmw_stdu_primary_plane_cleanup_fb(struct drm_plane *plane,
|
||||
struct drm_plane_state *old_state)
|
||||
{
|
||||
struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state);
|
||||
|
||||
if (vps->surf)
|
||||
WARN_ON(!vps->pinned);
|
||||
|
||||
vmw_du_plane_cleanup_fb(plane, old_state);
|
||||
|
||||
vps->content_fb_type = SAME_AS_DISPLAY;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* vmw_stdu_primary_plane_prepare_fb - Readies the display surface
|
||||
*
|
||||
* @plane: display plane
|
||||
* @new_state: info on the new plane state, including the FB
|
||||
*
|
||||
* This function allocates a new display surface if the content is
|
||||
* backed by a DMA. The display surface is pinned here, and it'll
|
||||
* be unpinned in .cleanup_fb()
|
||||
*
|
||||
* Returns 0 on success
|
||||
*/
|
||||
static int
|
||||
vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane,
|
||||
struct drm_plane_state *new_state)
|
||||
{
|
||||
struct drm_framebuffer *new_fb = new_state->fb;
|
||||
struct vmw_framebuffer *vfb;
|
||||
struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state);
|
||||
enum stdu_content_type new_content_type;
|
||||
struct vmw_framebuffer_surface *new_vfbs;
|
||||
struct drm_crtc *crtc = new_state->crtc;
|
||||
uint32_t hdisplay = new_state->crtc_w, vdisplay = new_state->crtc_h;
|
||||
int ret;
|
||||
|
||||
/* No FB to prepare */
|
||||
if (!new_fb) {
|
||||
if (vps->surf) {
|
||||
WARN_ON(vps->pinned != 0);
|
||||
vmw_surface_unreference(&vps->surf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
vfb = vmw_framebuffer_to_vfb(new_fb);
|
||||
new_vfbs = (vfb->dmabuf) ? NULL : vmw_framebuffer_to_vfbs(new_fb);
|
||||
|
||||
if (new_vfbs && new_vfbs->surface->base_size.width == hdisplay &&
|
||||
new_vfbs->surface->base_size.height == vdisplay)
|
||||
new_content_type = SAME_AS_DISPLAY;
|
||||
else if (vfb->dmabuf)
|
||||
new_content_type = SEPARATE_DMA;
|
||||
else
|
||||
new_content_type = SEPARATE_SURFACE;
|
||||
|
||||
if (new_content_type != SAME_AS_DISPLAY) {
|
||||
struct vmw_surface content_srf;
|
||||
struct drm_vmw_size display_base_size = {0};
|
||||
|
||||
display_base_size.width = hdisplay;
|
||||
display_base_size.height = vdisplay;
|
||||
display_base_size.depth = 1;
|
||||
|
||||
/*
|
||||
* If content buffer is a DMA buf, then we have to construct
|
||||
* surface info
|
||||
*/
|
||||
if (new_content_type == SEPARATE_DMA) {
|
||||
|
||||
switch (new_fb->format->cpp[0]*8) {
|
||||
case 32:
|
||||
content_srf.format = SVGA3D_X8R8G8B8;
|
||||
break;
|
||||
|
||||
case 16:
|
||||
content_srf.format = SVGA3D_R5G6B5;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
content_srf.format = SVGA3D_P8;
|
||||
break;
|
||||
|
||||
default:
|
||||
DRM_ERROR("Invalid format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
content_srf.flags = 0;
|
||||
content_srf.mip_levels[0] = 1;
|
||||
content_srf.multisample_count = 0;
|
||||
} else {
|
||||
content_srf = *new_vfbs->surface;
|
||||
}
|
||||
|
||||
if (vps->surf) {
|
||||
struct drm_vmw_size cur_base_size = vps->surf->base_size;
|
||||
|
||||
if (cur_base_size.width != display_base_size.width ||
|
||||
cur_base_size.height != display_base_size.height ||
|
||||
vps->surf->format != content_srf.format) {
|
||||
WARN_ON(vps->pinned != 0);
|
||||
vmw_surface_unreference(&vps->surf);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!vps->surf) {
|
||||
ret = vmw_surface_gb_priv_define
|
||||
(crtc->dev,
|
||||
/* Kernel visible only */
|
||||
0,
|
||||
content_srf.flags,
|
||||
content_srf.format,
|
||||
true, /* a scanout buffer */
|
||||
content_srf.mip_levels[0],
|
||||
content_srf.multisample_count,
|
||||
0,
|
||||
display_base_size,
|
||||
&vps->surf);
|
||||
if (ret != 0) {
|
||||
DRM_ERROR("Couldn't allocate STDU surface.\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* prepare_fb and clean_fb should only take care of pinning
|
||||
* and unpinning. References are tracked by state objects.
|
||||
* The only time we add a reference in prepare_fb is if the
|
||||
* state object doesn't have a reference to begin with
|
||||
*/
|
||||
if (vps->surf) {
|
||||
WARN_ON(vps->pinned != 0);
|
||||
vmw_surface_unreference(&vps->surf);
|
||||
}
|
||||
|
||||
vps->surf = vmw_surface_reference(new_vfbs->surface);
|
||||
}
|
||||
|
||||
if (vps->surf) {
|
||||
|
||||
/* Pin new surface before flipping */
|
||||
ret = vmw_resource_pin(&vps->surf->res, false);
|
||||
if (ret)
|
||||
goto out_srf_unref;
|
||||
|
||||
vps->pinned++;
|
||||
}
|
||||
|
||||
vps->content_fb_type = new_content_type;
|
||||
return 0;
|
||||
|
||||
out_srf_unref:
|
||||
vmw_surface_unreference(&vps->surf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* vmw_stdu_primary_plane_atomic_update - formally switches STDU to new plane
|
||||
*
|
||||
* @plane: display plane
|
||||
* @old_state: Only used to get crtc info
|
||||
*
|
||||
* Formally update stdu->display_srf to the new plane, and bind the new
|
||||
* plane STDU. This function is called during the commit phase when
|
||||
* all the preparation have been done and all the configurations have
|
||||
* been checked.
|
||||
*/
|
||||
static void
|
||||
vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane,
|
||||
struct drm_plane_state *old_state)
|
||||
{
|
||||
struct vmw_private *dev_priv;
|
||||
struct vmw_screen_target_display_unit *stdu;
|
||||
struct vmw_plane_state *vps = vmw_plane_state_to_vps(plane->state);
|
||||
struct drm_crtc *crtc = plane->state->crtc ?: old_state->crtc;
|
||||
int ret;
|
||||
|
||||
stdu = vmw_crtc_to_stdu(crtc);
|
||||
dev_priv = vmw_priv(crtc->dev);
|
||||
|
||||
stdu->display_srf = vps->surf;
|
||||
stdu->content_fb_type = vps->content_fb_type;
|
||||
|
||||
if (!stdu->defined)
|
||||
return;
|
||||
|
||||
if (plane->state->fb)
|
||||
ret = vmw_stdu_bind_st(dev_priv, stdu, &stdu->display_srf->res);
|
||||
else
|
||||
ret = vmw_stdu_bind_st(dev_priv, stdu, NULL);
|
||||
|
||||
/*
|
||||
* We cannot really fail this function, so if we do, then output an
|
||||
* error and quit
|
||||
*/
|
||||
if (ret)
|
||||
DRM_ERROR("Failed to bind surface to STDU.\n");
|
||||
else
|
||||
crtc->primary->fb = plane->state->fb;
|
||||
}
|
||||
|
||||
|
||||
static const struct drm_plane_funcs vmw_stdu_plane_funcs = {
|
||||
.update_plane = drm_primary_helper_update,
|
||||
.disable_plane = drm_primary_helper_disable,
|
||||
|
@ -1216,6 +1440,22 @@ static const struct drm_plane_funcs vmw_stdu_cursor_funcs = {
|
|||
/*
|
||||
* Atomic Helpers
|
||||
*/
|
||||
static const struct
|
||||
drm_plane_helper_funcs vmw_stdu_cursor_plane_helper_funcs = {
|
||||
.atomic_check = vmw_du_cursor_plane_atomic_check,
|
||||
.atomic_update = vmw_du_cursor_plane_atomic_update,
|
||||
.prepare_fb = vmw_du_cursor_plane_prepare_fb,
|
||||
.cleanup_fb = vmw_du_plane_cleanup_fb,
|
||||
};
|
||||
|
||||
static const struct
|
||||
drm_plane_helper_funcs vmw_stdu_primary_plane_helper_funcs = {
|
||||
.atomic_check = vmw_du_primary_plane_atomic_check,
|
||||
.atomic_update = vmw_stdu_primary_plane_atomic_update,
|
||||
.prepare_fb = vmw_stdu_primary_plane_prepare_fb,
|
||||
.cleanup_fb = vmw_stdu_primary_plane_cleanup_fb,
|
||||
};
|
||||
|
||||
static const struct drm_crtc_helper_funcs vmw_stdu_crtc_helper_funcs = {
|
||||
.prepare = vmw_stdu_crtc_helper_prepare,
|
||||
.commit = vmw_stdu_crtc_helper_commit,
|
||||
|
@ -1283,6 +1523,8 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
|
|||
goto err_free;
|
||||
}
|
||||
|
||||
drm_plane_helper_add(primary, &vmw_stdu_primary_plane_helper_funcs);
|
||||
|
||||
/* Initialize cursor plane */
|
||||
vmw_du_plane_reset(cursor);
|
||||
|
||||
|
@ -1297,6 +1539,8 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
|
|||
goto err_free;
|
||||
}
|
||||
|
||||
drm_plane_helper_add(cursor, &vmw_stdu_cursor_plane_helper_funcs);
|
||||
|
||||
vmw_du_connector_reset(connector);
|
||||
|
||||
ret = drm_connector_init(dev, connector, &vmw_stdu_connector_funcs,
|
||||
|
|
Loading…
Reference in a new issue