2018-05-07 01:16:26 +02:00
|
|
|
// SPDX-License-Identifier: GPL-2.0 OR MIT
|
2009-12-10 00:19:58 +00:00
|
|
|
/**************************************************************************
|
|
|
|
*
|
2024-07-22 14:41:15 -04:00
|
|
|
* Copyright (c) 2009-2024 Broadcom. All Rights Reserved. The term
|
|
|
|
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
|
2009-12-10 00:19:58 +00:00
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
* copy of this software and associated documentation files (the
|
|
|
|
* "Software"), to deal in the Software without restriction, including
|
|
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
* distribute, sub license, and/or sell copies of the Software, and to
|
|
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
|
|
* the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice (including the
|
|
|
|
* next paragraph) shall be included in all copies or substantial portions
|
|
|
|
* of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
|
|
|
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
|
|
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
|
|
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
*
|
|
|
|
**************************************************************************/
|
|
|
|
|
2023-01-30 22:35:38 -05:00
|
|
|
#include "vmwgfx_bo.h"
|
|
|
|
#include "vmwgfx_kms.h"
|
2024-04-11 22:55:07 -04:00
|
|
|
#include "vmwgfx_vkms.h"
|
2023-01-30 22:35:38 -05:00
|
|
|
|
2017-03-23 11:48:44 -07:00
|
|
|
#include <drm/drm_atomic.h>
|
|
|
|
#include <drm/drm_atomic_helper.h>
|
2019-06-23 12:23:33 +02:00
|
|
|
#include <drm/drm_fourcc.h>
|
2009-12-10 00:19:58 +00:00
|
|
|
|
2010-10-01 10:21:49 +02:00
|
|
|
|
2009-12-10 00:19:58 +00:00
|
|
|
#define vmw_crtc_to_ldu(x) \
|
|
|
|
container_of(x, struct vmw_legacy_display_unit, base.crtc)
|
|
|
|
#define vmw_encoder_to_ldu(x) \
|
|
|
|
container_of(x, struct vmw_legacy_display_unit, base.encoder)
|
|
|
|
#define vmw_connector_to_ldu(x) \
|
|
|
|
container_of(x, struct vmw_legacy_display_unit, base.connector)
|
|
|
|
|
|
|
|
struct vmw_legacy_display {
|
|
|
|
struct list_head active;
|
|
|
|
|
|
|
|
unsigned num_active;
|
2010-05-28 11:21:59 +02:00
|
|
|
unsigned last_num_active;
|
2009-12-10 00:19:58 +00:00
|
|
|
|
|
|
|
struct vmw_framebuffer *fb;
|
|
|
|
};
|
|
|
|
|
2021-01-15 18:12:46 +00:00
|
|
|
/*
|
2009-12-10 00:19:58 +00:00
|
|
|
* Display unit using the legacy register interface.
|
|
|
|
*/
|
|
|
|
struct vmw_legacy_display_unit {
|
|
|
|
struct vmw_display_unit base;
|
|
|
|
|
|
|
|
struct list_head active;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void vmw_ldu_destroy(struct vmw_legacy_display_unit *ldu)
|
|
|
|
{
|
|
|
|
list_del_init(&ldu->active);
|
2015-06-26 01:23:42 -07:00
|
|
|
vmw_du_cleanup(&ldu->base);
|
2009-12-10 00:19:58 +00:00
|
|
|
kfree(ldu);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Legacy Display Unit CRTC functions
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void vmw_ldu_crtc_destroy(struct drm_crtc *crtc)
|
|
|
|
{
|
|
|
|
vmw_ldu_destroy(vmw_crtc_to_ldu(crtc));
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vmw_ldu_commit_list(struct vmw_private *dev_priv)
|
|
|
|
{
|
|
|
|
struct vmw_legacy_display *lds = dev_priv->ldu_priv;
|
|
|
|
struct vmw_legacy_display_unit *entry;
|
2010-05-28 11:21:59 +02:00
|
|
|
struct drm_framebuffer *fb = NULL;
|
|
|
|
struct drm_crtc *crtc = NULL;
|
2020-06-26 13:34:37 +03:00
|
|
|
int i;
|
2009-12-10 00:19:58 +00:00
|
|
|
|
2010-05-28 11:21:59 +02:00
|
|
|
/* If there is no display topology the host just assumes
|
|
|
|
* that the guest will set the same layout as the host.
|
|
|
|
*/
|
|
|
|
if (!(dev_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY)) {
|
|
|
|
int w = 0, h = 0;
|
|
|
|
list_for_each_entry(entry, &lds->active, active) {
|
|
|
|
crtc = &entry->base.crtc;
|
|
|
|
w = max(w, crtc->x + crtc->mode.hdisplay);
|
|
|
|
h = max(h, crtc->y + crtc->mode.vdisplay);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (crtc == NULL)
|
|
|
|
return 0;
|
2020-06-26 13:34:37 +03:00
|
|
|
fb = crtc->primary->state->fb;
|
2010-05-28 11:21:59 +02:00
|
|
|
|
2011-12-20 00:06:49 +02:00
|
|
|
return vmw_kms_write_svga(dev_priv, w, h, fb->pitches[0],
|
2016-12-14 23:32:20 +02:00
|
|
|
fb->format->cpp[0] * 8,
|
2016-12-14 23:31:35 +02:00
|
|
|
fb->format->depth);
|
2010-05-28 11:21:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!list_empty(&lds->active)) {
|
|
|
|
entry = list_entry(lds->active.next, typeof(*entry), active);
|
2017-03-23 14:38:18 -07:00
|
|
|
fb = entry->base.crtc.primary->state->fb;
|
2010-05-28 11:21:59 +02:00
|
|
|
|
2011-12-20 00:06:49 +02:00
|
|
|
vmw_kms_write_svga(dev_priv, fb->width, fb->height, fb->pitches[0],
|
2016-12-14 23:32:20 +02:00
|
|
|
fb->format->cpp[0] * 8, fb->format->depth);
|
2010-05-28 11:21:59 +02:00
|
|
|
}
|
|
|
|
|
2010-05-28 11:22:03 +02:00
|
|
|
/* Make sure we always show something. */
|
|
|
|
vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS,
|
|
|
|
lds->num_active ? lds->num_active : 1);
|
|
|
|
|
2009-12-10 00:19:58 +00:00
|
|
|
i = 0;
|
|
|
|
list_for_each_entry(entry, &lds->active, active) {
|
|
|
|
crtc = &entry->base.crtc;
|
|
|
|
|
|
|
|
vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, i);
|
|
|
|
vmw_write(dev_priv, SVGA_REG_DISPLAY_IS_PRIMARY, !i);
|
|
|
|
vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_X, crtc->x);
|
|
|
|
vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_Y, crtc->y);
|
|
|
|
vmw_write(dev_priv, SVGA_REG_DISPLAY_WIDTH, crtc->mode.hdisplay);
|
|
|
|
vmw_write(dev_priv, SVGA_REG_DISPLAY_HEIGHT, crtc->mode.vdisplay);
|
|
|
|
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
2010-05-28 11:21:59 +02:00
|
|
|
BUG_ON(i != lds->num_active);
|
|
|
|
|
|
|
|
lds->last_num_active = lds->num_active;
|
|
|
|
|
2009-12-10 00:19:58 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-01-30 22:35:38 -05:00
|
|
|
/*
|
|
|
|
* Pin the buffer in a location suitable for access by the
|
|
|
|
* display system.
|
|
|
|
*/
|
|
|
|
static int vmw_ldu_fb_pin(struct vmw_framebuffer *vfb)
|
|
|
|
{
|
|
|
|
struct vmw_private *dev_priv = vmw_priv(vfb->base.dev);
|
|
|
|
struct vmw_bo *buf;
|
|
|
|
int ret;
|
|
|
|
|
2024-07-22 14:41:15 -04:00
|
|
|
buf = vfb->bo ?
|
|
|
|
vmw_framebuffer_to_vfbd(&vfb->base)->buffer :
|
|
|
|
vmw_user_object_buffer(&vmw_framebuffer_to_vfbs(&vfb->base)->uo);
|
2023-01-30 22:35:38 -05:00
|
|
|
|
|
|
|
if (!buf)
|
|
|
|
return 0;
|
|
|
|
WARN_ON(dev_priv->active_display_unit != vmw_du_legacy);
|
|
|
|
|
|
|
|
if (dev_priv->active_display_unit == vmw_du_legacy) {
|
|
|
|
vmw_overlay_pause_all(dev_priv);
|
|
|
|
ret = vmw_bo_pin_in_start_of_vram(dev_priv, buf, false);
|
|
|
|
vmw_overlay_resume_all(dev_priv);
|
|
|
|
} else
|
|
|
|
ret = -EINVAL;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vmw_ldu_fb_unpin(struct vmw_framebuffer *vfb)
|
|
|
|
{
|
|
|
|
struct vmw_private *dev_priv = vmw_priv(vfb->base.dev);
|
|
|
|
struct vmw_bo *buf;
|
|
|
|
|
2024-07-22 14:41:15 -04:00
|
|
|
buf = vfb->bo ?
|
|
|
|
vmw_framebuffer_to_vfbd(&vfb->base)->buffer :
|
|
|
|
vmw_user_object_buffer(&vmw_framebuffer_to_vfbs(&vfb->base)->uo);
|
|
|
|
|
2023-01-30 22:35:38 -05:00
|
|
|
|
|
|
|
if (WARN_ON(!buf))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return vmw_bo_unpin(dev_priv, buf, false);
|
|
|
|
}
|
|
|
|
|
2009-12-10 00:19:58 +00:00
|
|
|
static int vmw_ldu_del_active(struct vmw_private *vmw_priv,
|
|
|
|
struct vmw_legacy_display_unit *ldu)
|
|
|
|
{
|
|
|
|
struct vmw_legacy_display *ld = vmw_priv->ldu_priv;
|
|
|
|
if (list_empty(&ldu->active))
|
|
|
|
return 0;
|
|
|
|
|
2010-05-28 11:21:55 +02:00
|
|
|
/* Must init otherwise list_empty(&ldu->active) will not work. */
|
2009-12-10 00:19:58 +00:00
|
|
|
list_del_init(&ldu->active);
|
|
|
|
if (--(ld->num_active) == 0) {
|
|
|
|
BUG_ON(!ld->fb);
|
2023-01-30 22:35:38 -05:00
|
|
|
WARN_ON(vmw_ldu_fb_unpin(ld->fb));
|
2009-12-10 00:19:58 +00:00
|
|
|
ld->fb = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vmw_ldu_add_active(struct vmw_private *vmw_priv,
|
|
|
|
struct vmw_legacy_display_unit *ldu,
|
|
|
|
struct vmw_framebuffer *vfb)
|
|
|
|
{
|
|
|
|
struct vmw_legacy_display *ld = vmw_priv->ldu_priv;
|
|
|
|
struct vmw_legacy_display_unit *entry;
|
|
|
|
struct list_head *at;
|
|
|
|
|
2010-05-28 11:21:56 +02:00
|
|
|
BUG_ON(!ld->num_active && ld->fb);
|
|
|
|
if (vfb != ld->fb) {
|
2023-01-30 22:35:38 -05:00
|
|
|
if (ld->fb)
|
|
|
|
WARN_ON(vmw_ldu_fb_unpin(ld->fb));
|
2017-03-23 13:14:54 -07:00
|
|
|
vmw_svga_enable(vmw_priv);
|
2023-01-30 22:35:38 -05:00
|
|
|
WARN_ON(vmw_ldu_fb_pin(vfb));
|
2010-05-28 11:21:56 +02:00
|
|
|
ld->fb = vfb;
|
|
|
|
}
|
|
|
|
|
2009-12-10 00:19:58 +00:00
|
|
|
if (!list_empty(&ldu->active))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
at = &ld->active;
|
|
|
|
list_for_each_entry(entry, &ld->active, active) {
|
2010-05-28 11:22:01 +02:00
|
|
|
if (entry->base.unit > ldu->base.unit)
|
2009-12-10 00:19:58 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
at = &entry->active;
|
|
|
|
}
|
|
|
|
|
|
|
|
list_add(&ldu->active, at);
|
2010-05-28 11:21:56 +02:00
|
|
|
|
|
|
|
ld->num_active++;
|
2009-12-10 00:19:58 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-03-23 13:14:54 -07:00
|
|
|
/**
|
|
|
|
* vmw_ldu_crtc_mode_set_nofb - Enable svga
|
|
|
|
*
|
|
|
|
* @crtc: CRTC associated with the new screen
|
|
|
|
*
|
|
|
|
* For LDU, just enable the svga
|
|
|
|
*/
|
|
|
|
static void vmw_ldu_crtc_mode_set_nofb(struct drm_crtc *crtc)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2015-12-15 12:21:15 +01:00
|
|
|
static const struct drm_crtc_funcs vmw_legacy_crtc_funcs = {
|
2011-10-04 20:13:20 +02:00
|
|
|
.gamma_set = vmw_du_crtc_gamma_set,
|
2009-12-10 00:19:58 +00:00
|
|
|
.destroy = vmw_ldu_crtc_destroy,
|
2017-03-23 11:33:39 -07:00
|
|
|
.reset = vmw_du_crtc_reset,
|
|
|
|
.atomic_duplicate_state = vmw_du_crtc_duplicate_state,
|
|
|
|
.atomic_destroy_state = vmw_du_crtc_destroy_state,
|
2018-09-26 17:17:33 -07:00
|
|
|
.set_config = drm_atomic_helper_set_config,
|
2023-03-20 22:09:49 -04:00
|
|
|
.page_flip = drm_atomic_helper_page_flip,
|
2024-04-11 22:55:07 -04:00
|
|
|
.enable_vblank = vmw_vkms_enable_vblank,
|
|
|
|
.disable_vblank = vmw_vkms_disable_vblank,
|
|
|
|
.get_vblank_timestamp = vmw_vkms_get_vblank_timestamp,
|
2009-12-10 00:19:58 +00:00
|
|
|
};
|
|
|
|
|
2011-10-04 20:13:20 +02:00
|
|
|
|
2009-12-10 00:19:58 +00:00
|
|
|
/*
|
|
|
|
* Legacy Display Unit encoder functions
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void vmw_ldu_encoder_destroy(struct drm_encoder *encoder)
|
|
|
|
{
|
|
|
|
vmw_ldu_destroy(vmw_encoder_to_ldu(encoder));
|
|
|
|
}
|
|
|
|
|
2015-12-15 12:21:15 +01:00
|
|
|
static const struct drm_encoder_funcs vmw_legacy_encoder_funcs = {
|
2009-12-10 00:19:58 +00:00
|
|
|
.destroy = vmw_ldu_encoder_destroy,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Legacy Display Unit connector functions
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void vmw_ldu_connector_destroy(struct drm_connector *connector)
|
|
|
|
{
|
|
|
|
vmw_ldu_destroy(vmw_connector_to_ldu(connector));
|
|
|
|
}
|
|
|
|
|
2015-12-15 12:21:15 +01:00
|
|
|
static const struct drm_connector_funcs vmw_legacy_connector_funcs = {
|
2011-10-04 20:13:20 +02:00
|
|
|
.dpms = vmw_du_connector_dpms,
|
|
|
|
.detect = vmw_du_connector_detect,
|
2024-01-26 15:08:00 -05:00
|
|
|
.fill_modes = drm_helper_probe_single_connector_modes,
|
2009-12-10 00:19:58 +00:00
|
|
|
.destroy = vmw_ldu_connector_destroy,
|
2017-03-23 11:48:44 -07:00
|
|
|
.reset = vmw_du_connector_reset,
|
2018-01-17 10:16:20 -05:00
|
|
|
.atomic_duplicate_state = vmw_du_connector_duplicate_state,
|
|
|
|
.atomic_destroy_state = vmw_du_connector_destroy_state,
|
2009-12-10 00:19:58 +00:00
|
|
|
};
|
|
|
|
|
2017-03-23 14:23:20 -07:00
|
|
|
static const struct
|
|
|
|
drm_connector_helper_funcs vmw_ldu_connector_helper_funcs = {
|
2024-01-26 15:08:00 -05:00
|
|
|
.get_modes = vmw_connector_get_modes,
|
|
|
|
.mode_valid = vmw_connector_mode_valid
|
2017-03-23 14:23:20 -07:00
|
|
|
};
|
|
|
|
|
2023-03-20 22:09:49 -04:00
|
|
|
static int vmw_kms_ldu_do_bo_dirty(struct vmw_private *dev_priv,
|
|
|
|
struct vmw_framebuffer *framebuffer,
|
|
|
|
unsigned int flags, unsigned int color,
|
|
|
|
struct drm_mode_rect *clips,
|
|
|
|
unsigned int num_clips);
|
|
|
|
|
2017-03-23 11:28:11 -07:00
|
|
|
/*
|
|
|
|
* Legacy Display Plane Functions
|
|
|
|
*/
|
|
|
|
|
2017-03-23 14:18:32 -07:00
|
|
|
static void
|
|
|
|
vmw_ldu_primary_plane_atomic_update(struct drm_plane *plane,
|
drm/atomic: Pass the full state to planes atomic disable and update
The current atomic helpers have either their object state being passed as
an argument or the full atomic state.
The former is the pattern that was done at first, before switching to the
latter for new hooks or when it was needed.
Let's convert the remaining helpers to provide a consistent interface,
this time with the planes atomic_update and atomic_disable.
The conversion was done using the coccinelle script below, built tested on
all the drivers.
@@
identifier plane, plane_state;
symbol state;
@@
struct drm_plane_helper_funcs {
...
void (*atomic_update)(struct drm_plane *plane,
- struct drm_plane_state *plane_state);
+ struct drm_atomic_state *state);
...
}
@@
identifier plane, plane_state;
symbol state;
@@
struct drm_plane_helper_funcs {
...
void (*atomic_disable)(struct drm_plane *plane,
- struct drm_plane_state *plane_state);
+ struct drm_atomic_state *state);
...
}
@ plane_atomic_func @
identifier helpers;
identifier func;
@@
(
static const struct drm_plane_helper_funcs helpers = {
...,
.atomic_update = func,
...,
};
|
static const struct drm_plane_helper_funcs helpers = {
...,
.atomic_disable = func,
...,
};
)
@@
struct drm_plane_helper_funcs *FUNCS;
identifier f;
identifier crtc_state;
identifier plane, plane_state, state;
expression e;
@@
f(struct drm_crtc_state *crtc_state)
{
...
struct drm_atomic_state *state = e;
<+...
(
- FUNCS->atomic_disable(plane, plane_state)
+ FUNCS->atomic_disable(plane, state)
|
- FUNCS->atomic_update(plane, plane_state)
+ FUNCS->atomic_update(plane, state)
)
...+>
}
@@
identifier plane_atomic_func.func;
identifier plane;
symbol state;
@@
func(struct drm_plane *plane,
- struct drm_plane_state *state)
+ struct drm_plane_state *old_plane_state)
{
<...
- state
+ old_plane_state
...>
}
@ ignores_old_state @
identifier plane_atomic_func.func;
identifier plane, old_state;
@@
func(struct drm_plane *plane, struct drm_plane_state *old_state)
{
... when != old_state
}
@ adds_old_state depends on plane_atomic_func && !ignores_old_state @
identifier plane_atomic_func.func;
identifier plane, plane_state;
@@
func(struct drm_plane *plane, struct drm_plane_state *plane_state)
{
+ struct drm_plane_state *plane_state = drm_atomic_get_old_plane_state(state, plane);
...
}
@ depends on plane_atomic_func @
identifier plane_atomic_func.func;
identifier plane, plane_state;
@@
func(struct drm_plane *plane,
- struct drm_plane_state *plane_state
+ struct drm_atomic_state *state
)
{ ... }
@ include depends on adds_old_state @
@@
#include <drm/drm_atomic.h>
@ no_include depends on !include && adds_old_state @
@@
+ #include <drm/drm_atomic.h>
#include <drm/...>
@@
identifier plane_atomic_func.func;
identifier plane, state;
identifier plane_state;
@@
func(struct drm_plane *plane, struct drm_atomic_state *state) {
...
struct drm_plane_state *plane_state = drm_atomic_get_old_plane_state(state, plane);
<+...
- plane_state->state
+ state
...+>
}
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20210219120032.260676-9-maxime@cerno.tech
2021-02-19 13:00:29 +01:00
|
|
|
struct drm_atomic_state *state)
|
2017-03-23 14:18:32 -07:00
|
|
|
{
|
drm/atomic: Pass the full state to planes atomic disable and update
The current atomic helpers have either their object state being passed as
an argument or the full atomic state.
The former is the pattern that was done at first, before switching to the
latter for new hooks or when it was needed.
Let's convert the remaining helpers to provide a consistent interface,
this time with the planes atomic_update and atomic_disable.
The conversion was done using the coccinelle script below, built tested on
all the drivers.
@@
identifier plane, plane_state;
symbol state;
@@
struct drm_plane_helper_funcs {
...
void (*atomic_update)(struct drm_plane *plane,
- struct drm_plane_state *plane_state);
+ struct drm_atomic_state *state);
...
}
@@
identifier plane, plane_state;
symbol state;
@@
struct drm_plane_helper_funcs {
...
void (*atomic_disable)(struct drm_plane *plane,
- struct drm_plane_state *plane_state);
+ struct drm_atomic_state *state);
...
}
@ plane_atomic_func @
identifier helpers;
identifier func;
@@
(
static const struct drm_plane_helper_funcs helpers = {
...,
.atomic_update = func,
...,
};
|
static const struct drm_plane_helper_funcs helpers = {
...,
.atomic_disable = func,
...,
};
)
@@
struct drm_plane_helper_funcs *FUNCS;
identifier f;
identifier crtc_state;
identifier plane, plane_state, state;
expression e;
@@
f(struct drm_crtc_state *crtc_state)
{
...
struct drm_atomic_state *state = e;
<+...
(
- FUNCS->atomic_disable(plane, plane_state)
+ FUNCS->atomic_disable(plane, state)
|
- FUNCS->atomic_update(plane, plane_state)
+ FUNCS->atomic_update(plane, state)
)
...+>
}
@@
identifier plane_atomic_func.func;
identifier plane;
symbol state;
@@
func(struct drm_plane *plane,
- struct drm_plane_state *state)
+ struct drm_plane_state *old_plane_state)
{
<...
- state
+ old_plane_state
...>
}
@ ignores_old_state @
identifier plane_atomic_func.func;
identifier plane, old_state;
@@
func(struct drm_plane *plane, struct drm_plane_state *old_state)
{
... when != old_state
}
@ adds_old_state depends on plane_atomic_func && !ignores_old_state @
identifier plane_atomic_func.func;
identifier plane, plane_state;
@@
func(struct drm_plane *plane, struct drm_plane_state *plane_state)
{
+ struct drm_plane_state *plane_state = drm_atomic_get_old_plane_state(state, plane);
...
}
@ depends on plane_atomic_func @
identifier plane_atomic_func.func;
identifier plane, plane_state;
@@
func(struct drm_plane *plane,
- struct drm_plane_state *plane_state
+ struct drm_atomic_state *state
)
{ ... }
@ include depends on adds_old_state @
@@
#include <drm/drm_atomic.h>
@ no_include depends on !include && adds_old_state @
@@
+ #include <drm/drm_atomic.h>
#include <drm/...>
@@
identifier plane_atomic_func.func;
identifier plane, state;
identifier plane_state;
@@
func(struct drm_plane *plane, struct drm_atomic_state *state) {
...
struct drm_plane_state *plane_state = drm_atomic_get_old_plane_state(state, plane);
<+...
- plane_state->state
+ state
...+>
}
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20210219120032.260676-9-maxime@cerno.tech
2021-02-19 13:00:29 +01:00
|
|
|
struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
|
|
|
|
plane);
|
drm: Use state helper instead of the plane state pointer
Many drivers reference the plane->state pointer in order to get the
current plane state in their atomic_update or atomic_disable hooks,
which would be the new plane state in the global atomic state since
_swap_state happened when those hooks are run.
Use the drm_atomic_get_new_plane_state helper to get that state to make it
more obvious.
This was made using the coccinelle script below:
@ plane_atomic_func @
identifier helpers;
identifier func;
@@
(
static const struct drm_plane_helper_funcs helpers = {
...,
.atomic_disable = func,
...,
};
|
static const struct drm_plane_helper_funcs helpers = {
...,
.atomic_update = func,
...,
};
)
@ adds_new_state @
identifier plane_atomic_func.func;
identifier plane, state;
identifier new_state;
@@
func(struct drm_plane *plane, struct drm_atomic_state *state)
{
...
- struct drm_plane_state *new_state = plane->state;
+ struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);
...
}
@ include depends on adds_new_state @
@@
#include <drm/drm_atomic.h>
@ no_include depends on !include && adds_new_state @
@@
+ #include <drm/drm_atomic.h>
#include <drm/...>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://lore.kernel.org/r/20210219120032.260676-1-maxime@cerno.tech
2021-02-19 13:00:30 +01:00
|
|
|
struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
|
|
|
|
plane);
|
2017-03-23 14:42:36 -07:00
|
|
|
struct vmw_private *dev_priv;
|
|
|
|
struct vmw_legacy_display_unit *ldu;
|
|
|
|
struct vmw_framebuffer *vfb;
|
|
|
|
struct drm_framebuffer *fb;
|
drm: Store new plane state in a variable for atomic_update and disable
In order to store the new plane state in a subsequent helper, let's move
the plane->state dereferences into a variable.
This was done using the following coccinelle script, plus some hand
changes for vmwgfx:
@ plane_atomic_func @
identifier helpers;
identifier func;
@@
(
static const struct drm_plane_helper_funcs helpers = {
...,
.atomic_disable = func,
...,
};
|
static const struct drm_plane_helper_funcs helpers = {
...,
.atomic_update = func,
...,
};
)
@ has_new_state_old_state @
identifier plane_atomic_func.func;
identifier plane;
identifier new_state;
symbol old_state;
@@
func(struct drm_plane *plane, struct drm_plane_state *old_state)
{
...
struct drm_plane_state *new_state = plane->state;
...
}
@ depends on !has_new_state_old_state @
identifier plane_atomic_func.func;
identifier plane;
symbol old_state;
@@
func(struct drm_plane *plane, struct drm_plane_state *old_state)
{
+ struct drm_plane_state *new_state = plane->state;
<+...
- plane->state
+ new_state
...+>
}
@ has_new_state_state @
identifier plane_atomic_func.func;
identifier plane;
identifier new_state;
symbol state;
@@
func(struct drm_plane *plane, struct drm_plane_state *state)
{
...
struct drm_plane_state *new_state = plane->state;
...
}
@ depends on !has_new_state_state @
identifier plane_atomic_func.func;
identifier plane;
symbol state;
@@
func(struct drm_plane *plane, struct drm_plane_state *state)
{
+ struct drm_plane_state *new_plane_state = plane->state;
<+...
- plane->state
+ new_plane_state
...+>
}
@ has_new_state_old_s @
identifier plane_atomic_func.func;
identifier plane;
identifier new_state;
symbol old_s;
@@
func(struct drm_plane *plane, struct drm_plane_state *old_s)
{
...
struct drm_plane_state *new_state = plane->state;
...
}
@ depends on !has_new_state_old_s @
identifier plane_atomic_func.func;
identifier plane;
symbol old_s;
@@
func(struct drm_plane *plane, struct drm_plane_state *old_s)
{
+ struct drm_plane_state *new_s = plane->state;
<+...
- plane->state
+ new_s
...+>
}
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://lore.kernel.org/r/20210219120032.260676-1-maxime@cerno.tech
2021-02-19 13:00:27 +01:00
|
|
|
struct drm_crtc *crtc = new_state->crtc ?: old_state->crtc;
|
2017-03-23 14:42:36 -07:00
|
|
|
|
|
|
|
ldu = vmw_crtc_to_ldu(crtc);
|
|
|
|
dev_priv = vmw_priv(plane->dev);
|
drm: Store new plane state in a variable for atomic_update and disable
In order to store the new plane state in a subsequent helper, let's move
the plane->state dereferences into a variable.
This was done using the following coccinelle script, plus some hand
changes for vmwgfx:
@ plane_atomic_func @
identifier helpers;
identifier func;
@@
(
static const struct drm_plane_helper_funcs helpers = {
...,
.atomic_disable = func,
...,
};
|
static const struct drm_plane_helper_funcs helpers = {
...,
.atomic_update = func,
...,
};
)
@ has_new_state_old_state @
identifier plane_atomic_func.func;
identifier plane;
identifier new_state;
symbol old_state;
@@
func(struct drm_plane *plane, struct drm_plane_state *old_state)
{
...
struct drm_plane_state *new_state = plane->state;
...
}
@ depends on !has_new_state_old_state @
identifier plane_atomic_func.func;
identifier plane;
symbol old_state;
@@
func(struct drm_plane *plane, struct drm_plane_state *old_state)
{
+ struct drm_plane_state *new_state = plane->state;
<+...
- plane->state
+ new_state
...+>
}
@ has_new_state_state @
identifier plane_atomic_func.func;
identifier plane;
identifier new_state;
symbol state;
@@
func(struct drm_plane *plane, struct drm_plane_state *state)
{
...
struct drm_plane_state *new_state = plane->state;
...
}
@ depends on !has_new_state_state @
identifier plane_atomic_func.func;
identifier plane;
symbol state;
@@
func(struct drm_plane *plane, struct drm_plane_state *state)
{
+ struct drm_plane_state *new_plane_state = plane->state;
<+...
- plane->state
+ new_plane_state
...+>
}
@ has_new_state_old_s @
identifier plane_atomic_func.func;
identifier plane;
identifier new_state;
symbol old_s;
@@
func(struct drm_plane *plane, struct drm_plane_state *old_s)
{
...
struct drm_plane_state *new_state = plane->state;
...
}
@ depends on !has_new_state_old_s @
identifier plane_atomic_func.func;
identifier plane;
symbol old_s;
@@
func(struct drm_plane *plane, struct drm_plane_state *old_s)
{
+ struct drm_plane_state *new_s = plane->state;
<+...
- plane->state
+ new_s
...+>
}
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://lore.kernel.org/r/20210219120032.260676-1-maxime@cerno.tech
2021-02-19 13:00:27 +01:00
|
|
|
fb = new_state->fb;
|
2017-03-23 14:42:36 -07:00
|
|
|
|
|
|
|
vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL;
|
|
|
|
|
|
|
|
if (vfb)
|
|
|
|
vmw_ldu_add_active(dev_priv, ldu, vfb);
|
|
|
|
else
|
|
|
|
vmw_ldu_del_active(dev_priv, ldu);
|
|
|
|
|
|
|
|
vmw_ldu_commit_list(dev_priv);
|
2017-03-23 14:18:32 -07:00
|
|
|
|
2023-03-20 22:09:49 -04:00
|
|
|
if (vfb && vmw_cmd_supported(dev_priv)) {
|
|
|
|
struct drm_mode_rect fb_rect = {
|
|
|
|
.x1 = 0,
|
|
|
|
.y1 = 0,
|
|
|
|
.x2 = vfb->base.width,
|
|
|
|
.y2 = vfb->base.height
|
|
|
|
};
|
|
|
|
struct drm_mode_rect *damage_rects = drm_plane_get_damage_clips(new_state);
|
|
|
|
u32 rect_count = drm_plane_get_damage_clips_count(new_state);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!damage_rects) {
|
|
|
|
damage_rects = &fb_rect;
|
|
|
|
rect_count = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = vmw_kms_ldu_do_bo_dirty(dev_priv, vfb, 0, 0, damage_rects, rect_count);
|
|
|
|
|
|
|
|
drm_WARN_ONCE(plane->dev, ret,
|
|
|
|
"vmw_kms_ldu_do_bo_dirty failed with: ret=%d\n", ret);
|
|
|
|
|
|
|
|
vmw_cmd_flush(dev_priv, false);
|
|
|
|
}
|
|
|
|
}
|
2017-03-23 14:18:32 -07:00
|
|
|
|
2017-03-23 11:28:11 -07:00
|
|
|
static const struct drm_plane_funcs vmw_ldu_plane_funcs = {
|
2017-03-23 14:38:18 -07:00
|
|
|
.update_plane = drm_atomic_helper_update_plane,
|
|
|
|
.disable_plane = drm_atomic_helper_disable_plane,
|
2017-03-23 11:28:11 -07:00
|
|
|
.destroy = vmw_du_primary_plane_destroy,
|
2017-03-23 11:36:05 -07:00
|
|
|
.reset = vmw_du_plane_reset,
|
|
|
|
.atomic_duplicate_state = vmw_du_plane_duplicate_state,
|
|
|
|
.atomic_destroy_state = vmw_du_plane_destroy_state,
|
2017-03-23 11:28:11 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
static const struct drm_plane_funcs vmw_ldu_cursor_funcs = {
|
2017-03-23 14:38:18 -07:00
|
|
|
.update_plane = drm_atomic_helper_update_plane,
|
|
|
|
.disable_plane = drm_atomic_helper_disable_plane,
|
2025-03-07 07:57:38 -05:00
|
|
|
.destroy = vmw_cursor_plane_destroy,
|
2017-03-23 11:36:05 -07:00
|
|
|
.reset = vmw_du_plane_reset,
|
|
|
|
.atomic_duplicate_state = vmw_du_plane_duplicate_state,
|
|
|
|
.atomic_destroy_state = vmw_du_plane_destroy_state,
|
2017-03-23 11:28:11 -07:00
|
|
|
};
|
|
|
|
|
2017-03-23 13:14:54 -07:00
|
|
|
/*
|
|
|
|
* Atomic Helpers
|
|
|
|
*/
|
2017-03-23 14:18:32 -07:00
|
|
|
static const struct
|
|
|
|
drm_plane_helper_funcs vmw_ldu_cursor_plane_helper_funcs = {
|
2025-03-07 07:57:38 -05:00
|
|
|
.atomic_check = vmw_cursor_plane_atomic_check,
|
|
|
|
.atomic_update = vmw_cursor_plane_atomic_update,
|
|
|
|
.prepare_fb = vmw_cursor_plane_prepare_fb,
|
|
|
|
.cleanup_fb = vmw_cursor_plane_cleanup_fb,
|
2017-03-23 14:18:32 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
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,
|
|
|
|
};
|
|
|
|
|
2017-03-23 13:14:54 -07:00
|
|
|
static const struct drm_crtc_helper_funcs vmw_ldu_crtc_helper_funcs = {
|
|
|
|
.mode_set_nofb = vmw_ldu_crtc_mode_set_nofb,
|
|
|
|
.atomic_check = vmw_du_crtc_atomic_check,
|
|
|
|
.atomic_begin = vmw_du_crtc_atomic_begin,
|
2024-04-11 22:55:07 -04:00
|
|
|
.atomic_flush = vmw_vkms_crtc_atomic_flush,
|
|
|
|
.atomic_enable = vmw_vkms_crtc_atomic_enable,
|
|
|
|
.atomic_disable = vmw_vkms_crtc_atomic_disable,
|
2017-03-23 13:14:54 -07:00
|
|
|
};
|
|
|
|
|
2017-03-23 11:28:11 -07:00
|
|
|
|
2009-12-10 00:19:58 +00:00
|
|
|
static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
|
|
|
|
{
|
|
|
|
struct vmw_legacy_display_unit *ldu;
|
2020-11-03 22:21:34 -05:00
|
|
|
struct drm_device *dev = &dev_priv->drm;
|
2009-12-10 00:19:58 +00:00
|
|
|
struct drm_connector *connector;
|
|
|
|
struct drm_encoder *encoder;
|
2022-03-02 10:24:19 -05:00
|
|
|
struct drm_plane *primary;
|
|
|
|
struct vmw_cursor_plane *cursor;
|
2009-12-10 00:19:58 +00:00
|
|
|
struct drm_crtc *crtc;
|
2017-03-23 11:28:11 -07:00
|
|
|
int ret;
|
2009-12-10 00:19:58 +00:00
|
|
|
|
|
|
|
ldu = kzalloc(sizeof(*ldu), GFP_KERNEL);
|
|
|
|
if (!ldu)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2010-05-28 11:22:01 +02:00
|
|
|
ldu->base.unit = unit;
|
2009-12-10 00:19:58 +00:00
|
|
|
crtc = &ldu->base.crtc;
|
|
|
|
encoder = &ldu->base.encoder;
|
|
|
|
connector = &ldu->base.connector;
|
2017-03-23 11:36:05 -07:00
|
|
|
primary = &ldu->base.primary;
|
|
|
|
cursor = &ldu->base.cursor;
|
2009-12-10 00:19:58 +00:00
|
|
|
|
2010-05-28 11:21:58 +02:00
|
|
|
INIT_LIST_HEAD(&ldu->active);
|
|
|
|
|
2011-10-04 20:13:20 +02:00
|
|
|
ldu->base.pref_active = (unit == 0);
|
2012-02-09 16:56:46 +01:00
|
|
|
ldu->base.pref_width = dev_priv->initial_width;
|
|
|
|
ldu->base.pref_height = dev_priv->initial_height;
|
2017-03-23 11:33:39 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove this after enabling atomic because property values can
|
|
|
|
* only exist in a state object
|
|
|
|
*/
|
2011-11-02 09:43:11 +01:00
|
|
|
ldu->base.is_implicit = true;
|
2010-06-01 11:54:20 +02:00
|
|
|
|
2017-03-23 11:28:11 -07:00
|
|
|
/* Initialize primary plane */
|
2022-03-02 10:24:19 -05:00
|
|
|
ret = drm_universal_plane_init(dev, primary,
|
2017-03-23 11:28:11 -07:00
|
|
|
0, &vmw_ldu_plane_funcs,
|
|
|
|
vmw_primary_plane_formats,
|
|
|
|
ARRAY_SIZE(vmw_primary_plane_formats),
|
2017-07-23 20:46:38 -07:00
|
|
|
NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
|
2017-03-23 11:28:11 -07:00
|
|
|
if (ret) {
|
|
|
|
DRM_ERROR("Failed to initialize primary plane");
|
|
|
|
goto err_free;
|
|
|
|
}
|
|
|
|
|
2017-03-23 14:18:32 -07:00
|
|
|
drm_plane_helper_add(primary, &vmw_ldu_primary_plane_helper_funcs);
|
|
|
|
|
2021-05-05 15:10:07 -04:00
|
|
|
/*
|
|
|
|
* We're going to be using traces and software cursors
|
|
|
|
*/
|
|
|
|
if (vmw_cmd_supported(dev_priv)) {
|
|
|
|
/* Initialize cursor plane */
|
2022-03-02 10:24:19 -05:00
|
|
|
ret = drm_universal_plane_init(dev, &cursor->base,
|
2021-05-05 15:10:07 -04:00
|
|
|
0, &vmw_ldu_cursor_funcs,
|
|
|
|
vmw_cursor_plane_formats,
|
|
|
|
ARRAY_SIZE(vmw_cursor_plane_formats),
|
|
|
|
NULL, DRM_PLANE_TYPE_CURSOR, NULL);
|
|
|
|
if (ret) {
|
|
|
|
DRM_ERROR("Failed to initialize cursor plane");
|
|
|
|
drm_plane_cleanup(&ldu->base.primary);
|
|
|
|
goto err_free;
|
|
|
|
}
|
2017-03-23 11:28:11 -07:00
|
|
|
|
2022-03-02 10:24:19 -05:00
|
|
|
drm_plane_helper_add(&cursor->base, &vmw_ldu_cursor_plane_helper_funcs);
|
2021-05-05 15:10:07 -04:00
|
|
|
}
|
2017-03-23 14:18:32 -07:00
|
|
|
|
2017-03-23 11:28:11 -07:00
|
|
|
ret = drm_connector_init(dev, connector, &vmw_legacy_connector_funcs,
|
|
|
|
DRM_MODE_CONNECTOR_VIRTUAL);
|
|
|
|
if (ret) {
|
|
|
|
DRM_ERROR("Failed to initialize connector\n");
|
|
|
|
goto err_free;
|
|
|
|
}
|
2017-03-23 14:23:20 -07:00
|
|
|
|
|
|
|
drm_connector_helper_add(connector, &vmw_ldu_connector_helper_funcs);
|
2009-12-10 00:19:58 +00:00
|
|
|
|
2017-03-23 11:28:11 -07:00
|
|
|
ret = drm_encoder_init(dev, encoder, &vmw_legacy_encoder_funcs,
|
|
|
|
DRM_MODE_ENCODER_VIRTUAL, NULL);
|
|
|
|
if (ret) {
|
|
|
|
DRM_ERROR("Failed to initialize encoder\n");
|
|
|
|
goto err_free_connector;
|
|
|
|
}
|
|
|
|
|
2018-07-09 10:40:07 +02:00
|
|
|
(void) drm_connector_attach_encoder(connector, encoder);
|
2009-12-10 00:19:58 +00:00
|
|
|
encoder->possible_crtcs = (1 << unit);
|
|
|
|
encoder->possible_clones = 0;
|
|
|
|
|
2017-03-23 11:28:11 -07:00
|
|
|
ret = drm_connector_register(connector);
|
|
|
|
if (ret) {
|
|
|
|
DRM_ERROR("Failed to register connector\n");
|
|
|
|
goto err_free_encoder;
|
|
|
|
}
|
2013-12-02 06:04:38 -08:00
|
|
|
|
2022-03-02 10:24:19 -05:00
|
|
|
ret = drm_crtc_init_with_planes(dev, crtc, primary,
|
|
|
|
vmw_cmd_supported(dev_priv) ? &cursor->base : NULL,
|
2021-05-05 15:10:07 -04:00
|
|
|
&vmw_legacy_crtc_funcs, NULL);
|
2017-03-23 11:28:11 -07:00
|
|
|
if (ret) {
|
|
|
|
DRM_ERROR("Failed to initialize CRTC\n");
|
|
|
|
goto err_free_unregister;
|
|
|
|
}
|
2009-12-10 00:19:58 +00:00
|
|
|
|
2017-03-23 13:14:54 -07:00
|
|
|
drm_crtc_helper_add(crtc, &vmw_ldu_crtc_helper_funcs);
|
|
|
|
|
2011-08-31 07:42:47 +00:00
|
|
|
drm_mode_crtc_set_gamma_size(crtc, 256);
|
|
|
|
|
2016-02-12 09:45:42 +01:00
|
|
|
drm_object_attach_property(&connector->base,
|
|
|
|
dev_priv->hotplug_mode_update_property, 1);
|
|
|
|
drm_object_attach_property(&connector->base,
|
|
|
|
dev->mode_config.suggested_x_property, 0);
|
|
|
|
drm_object_attach_property(&connector->base,
|
|
|
|
dev->mode_config.suggested_y_property, 0);
|
2016-02-12 09:55:45 +01:00
|
|
|
if (dev_priv->implicit_placement_property)
|
|
|
|
drm_object_attach_property
|
|
|
|
(&connector->base,
|
|
|
|
dev_priv->implicit_placement_property,
|
|
|
|
1);
|
2009-12-10 00:19:58 +00:00
|
|
|
|
2024-04-11 22:55:07 -04:00
|
|
|
vmw_du_init(&ldu->base);
|
|
|
|
|
2009-12-10 00:19:58 +00:00
|
|
|
return 0;
|
2017-03-23 11:28:11 -07:00
|
|
|
|
|
|
|
err_free_unregister:
|
|
|
|
drm_connector_unregister(connector);
|
|
|
|
err_free_encoder:
|
|
|
|
drm_encoder_cleanup(encoder);
|
|
|
|
err_free_connector:
|
|
|
|
drm_connector_cleanup(connector);
|
|
|
|
err_free:
|
|
|
|
kfree(ldu);
|
|
|
|
return ret;
|
2009-12-10 00:19:58 +00:00
|
|
|
}
|
|
|
|
|
2015-06-26 01:23:42 -07:00
|
|
|
int vmw_kms_ldu_init_display(struct vmw_private *dev_priv)
|
2009-12-10 00:19:58 +00:00
|
|
|
{
|
2020-11-03 22:21:34 -05:00
|
|
|
struct drm_device *dev = &dev_priv->drm;
|
2011-10-17 11:59:44 +02:00
|
|
|
int i, ret;
|
2022-03-02 10:24:20 -05:00
|
|
|
int num_display_units = (dev_priv->capabilities & SVGA_CAP_MULTIMON) ?
|
|
|
|
VMWGFX_NUM_DISPLAY_UNITS : 1;
|
2010-10-01 10:21:49 +02:00
|
|
|
|
2021-07-23 12:51:51 -04:00
|
|
|
if (unlikely(dev_priv->ldu_priv)) {
|
2009-12-10 00:19:58 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2010-10-31 22:33:53 +00:00
|
|
|
dev_priv->ldu_priv = kmalloc(sizeof(*dev_priv->ldu_priv), GFP_KERNEL);
|
2009-12-10 00:19:58 +00:00
|
|
|
if (!dev_priv->ldu_priv)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
INIT_LIST_HEAD(&dev_priv->ldu_priv->active);
|
|
|
|
dev_priv->ldu_priv->num_active = 0;
|
2010-05-28 11:21:59 +02:00
|
|
|
dev_priv->ldu_priv->last_num_active = 0;
|
2009-12-10 00:19:58 +00:00
|
|
|
dev_priv->ldu_priv->fb = NULL;
|
|
|
|
|
2018-10-04 22:38:17 +00:00
|
|
|
vmw_kms_create_implicit_placement_property(dev_priv);
|
2016-02-12 09:55:45 +01:00
|
|
|
|
2022-03-02 10:24:20 -05:00
|
|
|
for (i = 0; i < num_display_units; ++i) {
|
|
|
|
ret = vmw_ldu_init(dev_priv, i);
|
|
|
|
if (ret != 0)
|
|
|
|
goto err_free;
|
|
|
|
}
|
2009-12-10 00:19:58 +00:00
|
|
|
|
2015-06-26 01:23:42 -07:00
|
|
|
dev_priv->active_display_unit = vmw_du_legacy;
|
|
|
|
|
2020-08-07 22:04:33 +02:00
|
|
|
drm_mode_config_reset(dev);
|
|
|
|
|
2011-10-17 11:59:43 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_free:
|
|
|
|
kfree(dev_priv->ldu_priv);
|
|
|
|
dev_priv->ldu_priv = NULL;
|
2010-10-01 10:21:49 +02:00
|
|
|
return ret;
|
2009-12-10 00:19:58 +00:00
|
|
|
}
|
|
|
|
|
2015-06-26 01:23:42 -07:00
|
|
|
int vmw_kms_ldu_close_display(struct vmw_private *dev_priv)
|
2009-12-10 00:19:58 +00:00
|
|
|
{
|
|
|
|
if (!dev_priv->ldu_priv)
|
|
|
|
return -ENOSYS;
|
|
|
|
|
|
|
|
BUG_ON(!list_empty(&dev_priv->ldu_priv->active));
|
|
|
|
|
|
|
|
kfree(dev_priv->ldu_priv);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2015-06-26 01:23:42 -07:00
|
|
|
|
|
|
|
|
2023-03-20 22:09:49 -04:00
|
|
|
static int vmw_kms_ldu_do_bo_dirty(struct vmw_private *dev_priv,
|
|
|
|
struct vmw_framebuffer *framebuffer,
|
|
|
|
unsigned int flags, unsigned int color,
|
|
|
|
struct drm_mode_rect *clips,
|
|
|
|
unsigned int num_clips)
|
2015-06-26 01:23:42 -07:00
|
|
|
{
|
|
|
|
size_t fifo_size;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
struct {
|
|
|
|
uint32_t header;
|
|
|
|
SVGAFifoCmdUpdate body;
|
|
|
|
} *cmd;
|
|
|
|
|
|
|
|
fifo_size = sizeof(*cmd) * num_clips;
|
2020-11-18 12:54:19 -05:00
|
|
|
cmd = VMW_CMD_RESERVE(dev_priv, fifo_size);
|
2019-02-14 16:15:39 -08:00
|
|
|
if (unlikely(cmd == NULL))
|
2015-06-26 01:23:42 -07:00
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
memset(cmd, 0, fifo_size);
|
2023-03-20 22:09:49 -04:00
|
|
|
for (i = 0; i < num_clips; i++, clips++) {
|
2015-04-02 02:39:45 -07:00
|
|
|
cmd[i].header = SVGA_CMD_UPDATE;
|
|
|
|
cmd[i].body.x = clips->x1;
|
|
|
|
cmd[i].body.y = clips->y1;
|
|
|
|
cmd[i].body.width = clips->x2 - clips->x1;
|
|
|
|
cmd[i].body.height = clips->y2 - clips->y1;
|
2015-06-26 01:23:42 -07:00
|
|
|
}
|
|
|
|
|
2020-11-18 12:54:19 -05:00
|
|
|
vmw_cmd_commit(dev_priv, fifo_size);
|
2015-06-26 01:23:42 -07:00
|
|
|
return 0;
|
|
|
|
}
|