162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT 262306a36Sopenharmony_ci/************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright 2009-2023 VMware, Inc., Palo Alto, CA., USA 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 762306a36Sopenharmony_ci * copy of this software and associated documentation files (the 862306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 962306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 1062306a36Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 1162306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 1262306a36Sopenharmony_ci * the following conditions: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the 1562306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 1662306a36Sopenharmony_ci * of the Software. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1962306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2062306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 2162306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 2262306a36Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 2362306a36Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 2462306a36Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci **************************************************************************/ 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include "vmwgfx_bo.h" 2962306a36Sopenharmony_ci#include "vmwgfx_kms.h" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include <drm/drm_atomic.h> 3262306a36Sopenharmony_ci#include <drm/drm_atomic_helper.h> 3362306a36Sopenharmony_ci#include <drm/drm_fourcc.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define vmw_crtc_to_ldu(x) \ 3762306a36Sopenharmony_ci container_of(x, struct vmw_legacy_display_unit, base.crtc) 3862306a36Sopenharmony_ci#define vmw_encoder_to_ldu(x) \ 3962306a36Sopenharmony_ci container_of(x, struct vmw_legacy_display_unit, base.encoder) 4062306a36Sopenharmony_ci#define vmw_connector_to_ldu(x) \ 4162306a36Sopenharmony_ci container_of(x, struct vmw_legacy_display_unit, base.connector) 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistruct vmw_legacy_display { 4462306a36Sopenharmony_ci struct list_head active; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci unsigned num_active; 4762306a36Sopenharmony_ci unsigned last_num_active; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci struct vmw_framebuffer *fb; 5062306a36Sopenharmony_ci}; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* 5362306a36Sopenharmony_ci * Display unit using the legacy register interface. 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_cistruct vmw_legacy_display_unit { 5662306a36Sopenharmony_ci struct vmw_display_unit base; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci struct list_head active; 5962306a36Sopenharmony_ci}; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic void vmw_ldu_destroy(struct vmw_legacy_display_unit *ldu) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci list_del_init(&ldu->active); 6462306a36Sopenharmony_ci vmw_du_cleanup(&ldu->base); 6562306a36Sopenharmony_ci kfree(ldu); 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* 7062306a36Sopenharmony_ci * Legacy Display Unit CRTC functions 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic void vmw_ldu_crtc_destroy(struct drm_crtc *crtc) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci vmw_ldu_destroy(vmw_crtc_to_ldu(crtc)); 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic int vmw_ldu_commit_list(struct vmw_private *dev_priv) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci struct vmw_legacy_display *lds = dev_priv->ldu_priv; 8162306a36Sopenharmony_ci struct vmw_legacy_display_unit *entry; 8262306a36Sopenharmony_ci struct drm_framebuffer *fb = NULL; 8362306a36Sopenharmony_ci struct drm_crtc *crtc = NULL; 8462306a36Sopenharmony_ci int i; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci /* If there is no display topology the host just assumes 8762306a36Sopenharmony_ci * that the guest will set the same layout as the host. 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_ci if (!(dev_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY)) { 9062306a36Sopenharmony_ci int w = 0, h = 0; 9162306a36Sopenharmony_ci list_for_each_entry(entry, &lds->active, active) { 9262306a36Sopenharmony_ci crtc = &entry->base.crtc; 9362306a36Sopenharmony_ci w = max(w, crtc->x + crtc->mode.hdisplay); 9462306a36Sopenharmony_ci h = max(h, crtc->y + crtc->mode.vdisplay); 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci if (crtc == NULL) 9862306a36Sopenharmony_ci return 0; 9962306a36Sopenharmony_ci fb = crtc->primary->state->fb; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci return vmw_kms_write_svga(dev_priv, w, h, fb->pitches[0], 10262306a36Sopenharmony_ci fb->format->cpp[0] * 8, 10362306a36Sopenharmony_ci fb->format->depth); 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (!list_empty(&lds->active)) { 10762306a36Sopenharmony_ci entry = list_entry(lds->active.next, typeof(*entry), active); 10862306a36Sopenharmony_ci fb = entry->base.crtc.primary->state->fb; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci vmw_kms_write_svga(dev_priv, fb->width, fb->height, fb->pitches[0], 11162306a36Sopenharmony_ci fb->format->cpp[0] * 8, fb->format->depth); 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci /* Make sure we always show something. */ 11562306a36Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 11662306a36Sopenharmony_ci lds->num_active ? lds->num_active : 1); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci i = 0; 11962306a36Sopenharmony_ci list_for_each_entry(entry, &lds->active, active) { 12062306a36Sopenharmony_ci crtc = &entry->base.crtc; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, i); 12362306a36Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_DISPLAY_IS_PRIMARY, !i); 12462306a36Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_X, crtc->x); 12562306a36Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_Y, crtc->y); 12662306a36Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_DISPLAY_WIDTH, crtc->mode.hdisplay); 12762306a36Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_DISPLAY_HEIGHT, crtc->mode.vdisplay); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci i++; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci BUG_ON(i != lds->num_active); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci lds->last_num_active = lds->num_active; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci return 0; 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/* 14062306a36Sopenharmony_ci * Pin the buffer in a location suitable for access by the 14162306a36Sopenharmony_ci * display system. 14262306a36Sopenharmony_ci */ 14362306a36Sopenharmony_cistatic int vmw_ldu_fb_pin(struct vmw_framebuffer *vfb) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(vfb->base.dev); 14662306a36Sopenharmony_ci struct vmw_bo *buf; 14762306a36Sopenharmony_ci int ret; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci buf = vfb->bo ? vmw_framebuffer_to_vfbd(&vfb->base)->buffer : 15062306a36Sopenharmony_ci vmw_framebuffer_to_vfbs(&vfb->base)->surface->res.guest_memory_bo; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci if (!buf) 15362306a36Sopenharmony_ci return 0; 15462306a36Sopenharmony_ci WARN_ON(dev_priv->active_display_unit != vmw_du_legacy); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (dev_priv->active_display_unit == vmw_du_legacy) { 15762306a36Sopenharmony_ci vmw_overlay_pause_all(dev_priv); 15862306a36Sopenharmony_ci ret = vmw_bo_pin_in_start_of_vram(dev_priv, buf, false); 15962306a36Sopenharmony_ci vmw_overlay_resume_all(dev_priv); 16062306a36Sopenharmony_ci } else 16162306a36Sopenharmony_ci ret = -EINVAL; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci return ret; 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic int vmw_ldu_fb_unpin(struct vmw_framebuffer *vfb) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(vfb->base.dev); 16962306a36Sopenharmony_ci struct vmw_bo *buf; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci buf = vfb->bo ? vmw_framebuffer_to_vfbd(&vfb->base)->buffer : 17262306a36Sopenharmony_ci vmw_framebuffer_to_vfbs(&vfb->base)->surface->res.guest_memory_bo; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci if (WARN_ON(!buf)) 17562306a36Sopenharmony_ci return 0; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci return vmw_bo_unpin(dev_priv, buf, false); 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic int vmw_ldu_del_active(struct vmw_private *vmw_priv, 18162306a36Sopenharmony_ci struct vmw_legacy_display_unit *ldu) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci struct vmw_legacy_display *ld = vmw_priv->ldu_priv; 18462306a36Sopenharmony_ci if (list_empty(&ldu->active)) 18562306a36Sopenharmony_ci return 0; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci /* Must init otherwise list_empty(&ldu->active) will not work. */ 18862306a36Sopenharmony_ci list_del_init(&ldu->active); 18962306a36Sopenharmony_ci if (--(ld->num_active) == 0) { 19062306a36Sopenharmony_ci BUG_ON(!ld->fb); 19162306a36Sopenharmony_ci WARN_ON(vmw_ldu_fb_unpin(ld->fb)); 19262306a36Sopenharmony_ci ld->fb = NULL; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci return 0; 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic int vmw_ldu_add_active(struct vmw_private *vmw_priv, 19962306a36Sopenharmony_ci struct vmw_legacy_display_unit *ldu, 20062306a36Sopenharmony_ci struct vmw_framebuffer *vfb) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci struct vmw_legacy_display *ld = vmw_priv->ldu_priv; 20362306a36Sopenharmony_ci struct vmw_legacy_display_unit *entry; 20462306a36Sopenharmony_ci struct list_head *at; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci BUG_ON(!ld->num_active && ld->fb); 20762306a36Sopenharmony_ci if (vfb != ld->fb) { 20862306a36Sopenharmony_ci if (ld->fb) 20962306a36Sopenharmony_ci WARN_ON(vmw_ldu_fb_unpin(ld->fb)); 21062306a36Sopenharmony_ci vmw_svga_enable(vmw_priv); 21162306a36Sopenharmony_ci WARN_ON(vmw_ldu_fb_pin(vfb)); 21262306a36Sopenharmony_ci ld->fb = vfb; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (!list_empty(&ldu->active)) 21662306a36Sopenharmony_ci return 0; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci at = &ld->active; 21962306a36Sopenharmony_ci list_for_each_entry(entry, &ld->active, active) { 22062306a36Sopenharmony_ci if (entry->base.unit > ldu->base.unit) 22162306a36Sopenharmony_ci break; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci at = &entry->active; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci list_add(&ldu->active, at); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci ld->num_active++; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci return 0; 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci/** 23462306a36Sopenharmony_ci * vmw_ldu_crtc_mode_set_nofb - Enable svga 23562306a36Sopenharmony_ci * 23662306a36Sopenharmony_ci * @crtc: CRTC associated with the new screen 23762306a36Sopenharmony_ci * 23862306a36Sopenharmony_ci * For LDU, just enable the svga 23962306a36Sopenharmony_ci */ 24062306a36Sopenharmony_cistatic void vmw_ldu_crtc_mode_set_nofb(struct drm_crtc *crtc) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci/** 24562306a36Sopenharmony_ci * vmw_ldu_crtc_atomic_enable - Noop 24662306a36Sopenharmony_ci * 24762306a36Sopenharmony_ci * @crtc: CRTC associated with the new screen 24862306a36Sopenharmony_ci * @state: Unused 24962306a36Sopenharmony_ci * 25062306a36Sopenharmony_ci * This is called after a mode set has been completed. Here's 25162306a36Sopenharmony_ci * usually a good place to call vmw_ldu_add_active/vmw_ldu_del_active 25262306a36Sopenharmony_ci * but since for LDU the display plane is closely tied to the 25362306a36Sopenharmony_ci * CRTC, it makes more sense to do those at plane update time. 25462306a36Sopenharmony_ci */ 25562306a36Sopenharmony_cistatic void vmw_ldu_crtc_atomic_enable(struct drm_crtc *crtc, 25662306a36Sopenharmony_ci struct drm_atomic_state *state) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci/** 26162306a36Sopenharmony_ci * vmw_ldu_crtc_atomic_disable - Turns off CRTC 26262306a36Sopenharmony_ci * 26362306a36Sopenharmony_ci * @crtc: CRTC to be turned off 26462306a36Sopenharmony_ci * @state: Unused 26562306a36Sopenharmony_ci */ 26662306a36Sopenharmony_cistatic void vmw_ldu_crtc_atomic_disable(struct drm_crtc *crtc, 26762306a36Sopenharmony_ci struct drm_atomic_state *state) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic const struct drm_crtc_funcs vmw_legacy_crtc_funcs = { 27262306a36Sopenharmony_ci .gamma_set = vmw_du_crtc_gamma_set, 27362306a36Sopenharmony_ci .destroy = vmw_ldu_crtc_destroy, 27462306a36Sopenharmony_ci .reset = vmw_du_crtc_reset, 27562306a36Sopenharmony_ci .atomic_duplicate_state = vmw_du_crtc_duplicate_state, 27662306a36Sopenharmony_ci .atomic_destroy_state = vmw_du_crtc_destroy_state, 27762306a36Sopenharmony_ci .set_config = drm_atomic_helper_set_config, 27862306a36Sopenharmony_ci .page_flip = drm_atomic_helper_page_flip, 27962306a36Sopenharmony_ci}; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci/* 28362306a36Sopenharmony_ci * Legacy Display Unit encoder functions 28462306a36Sopenharmony_ci */ 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic void vmw_ldu_encoder_destroy(struct drm_encoder *encoder) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci vmw_ldu_destroy(vmw_encoder_to_ldu(encoder)); 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic const struct drm_encoder_funcs vmw_legacy_encoder_funcs = { 29262306a36Sopenharmony_ci .destroy = vmw_ldu_encoder_destroy, 29362306a36Sopenharmony_ci}; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci/* 29662306a36Sopenharmony_ci * Legacy Display Unit connector functions 29762306a36Sopenharmony_ci */ 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic void vmw_ldu_connector_destroy(struct drm_connector *connector) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci vmw_ldu_destroy(vmw_connector_to_ldu(connector)); 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic const struct drm_connector_funcs vmw_legacy_connector_funcs = { 30562306a36Sopenharmony_ci .dpms = vmw_du_connector_dpms, 30662306a36Sopenharmony_ci .detect = vmw_du_connector_detect, 30762306a36Sopenharmony_ci .fill_modes = vmw_du_connector_fill_modes, 30862306a36Sopenharmony_ci .destroy = vmw_ldu_connector_destroy, 30962306a36Sopenharmony_ci .reset = vmw_du_connector_reset, 31062306a36Sopenharmony_ci .atomic_duplicate_state = vmw_du_connector_duplicate_state, 31162306a36Sopenharmony_ci .atomic_destroy_state = vmw_du_connector_destroy_state, 31262306a36Sopenharmony_ci}; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic const struct 31562306a36Sopenharmony_cidrm_connector_helper_funcs vmw_ldu_connector_helper_funcs = { 31662306a36Sopenharmony_ci}; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic int vmw_kms_ldu_do_bo_dirty(struct vmw_private *dev_priv, 31962306a36Sopenharmony_ci struct vmw_framebuffer *framebuffer, 32062306a36Sopenharmony_ci unsigned int flags, unsigned int color, 32162306a36Sopenharmony_ci struct drm_mode_rect *clips, 32262306a36Sopenharmony_ci unsigned int num_clips); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci/* 32562306a36Sopenharmony_ci * Legacy Display Plane Functions 32662306a36Sopenharmony_ci */ 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic void 32962306a36Sopenharmony_civmw_ldu_primary_plane_atomic_update(struct drm_plane *plane, 33062306a36Sopenharmony_ci struct drm_atomic_state *state) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, 33362306a36Sopenharmony_ci plane); 33462306a36Sopenharmony_ci struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, 33562306a36Sopenharmony_ci plane); 33662306a36Sopenharmony_ci struct vmw_private *dev_priv; 33762306a36Sopenharmony_ci struct vmw_legacy_display_unit *ldu; 33862306a36Sopenharmony_ci struct vmw_framebuffer *vfb; 33962306a36Sopenharmony_ci struct drm_framebuffer *fb; 34062306a36Sopenharmony_ci struct drm_crtc *crtc = new_state->crtc ?: old_state->crtc; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci ldu = vmw_crtc_to_ldu(crtc); 34362306a36Sopenharmony_ci dev_priv = vmw_priv(plane->dev); 34462306a36Sopenharmony_ci fb = new_state->fb; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (vfb) 34962306a36Sopenharmony_ci vmw_ldu_add_active(dev_priv, ldu, vfb); 35062306a36Sopenharmony_ci else 35162306a36Sopenharmony_ci vmw_ldu_del_active(dev_priv, ldu); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci vmw_ldu_commit_list(dev_priv); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci if (vfb && vmw_cmd_supported(dev_priv)) { 35662306a36Sopenharmony_ci struct drm_mode_rect fb_rect = { 35762306a36Sopenharmony_ci .x1 = 0, 35862306a36Sopenharmony_ci .y1 = 0, 35962306a36Sopenharmony_ci .x2 = vfb->base.width, 36062306a36Sopenharmony_ci .y2 = vfb->base.height 36162306a36Sopenharmony_ci }; 36262306a36Sopenharmony_ci struct drm_mode_rect *damage_rects = drm_plane_get_damage_clips(new_state); 36362306a36Sopenharmony_ci u32 rect_count = drm_plane_get_damage_clips_count(new_state); 36462306a36Sopenharmony_ci int ret; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci if (!damage_rects) { 36762306a36Sopenharmony_ci damage_rects = &fb_rect; 36862306a36Sopenharmony_ci rect_count = 1; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci ret = vmw_kms_ldu_do_bo_dirty(dev_priv, vfb, 0, 0, damage_rects, rect_count); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci drm_WARN_ONCE(plane->dev, ret, 37462306a36Sopenharmony_ci "vmw_kms_ldu_do_bo_dirty failed with: ret=%d\n", ret); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci vmw_cmd_flush(dev_priv, false); 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic const struct drm_plane_funcs vmw_ldu_plane_funcs = { 38162306a36Sopenharmony_ci .update_plane = drm_atomic_helper_update_plane, 38262306a36Sopenharmony_ci .disable_plane = drm_atomic_helper_disable_plane, 38362306a36Sopenharmony_ci .destroy = vmw_du_primary_plane_destroy, 38462306a36Sopenharmony_ci .reset = vmw_du_plane_reset, 38562306a36Sopenharmony_ci .atomic_duplicate_state = vmw_du_plane_duplicate_state, 38662306a36Sopenharmony_ci .atomic_destroy_state = vmw_du_plane_destroy_state, 38762306a36Sopenharmony_ci}; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_cistatic const struct drm_plane_funcs vmw_ldu_cursor_funcs = { 39062306a36Sopenharmony_ci .update_plane = drm_atomic_helper_update_plane, 39162306a36Sopenharmony_ci .disable_plane = drm_atomic_helper_disable_plane, 39262306a36Sopenharmony_ci .destroy = vmw_du_cursor_plane_destroy, 39362306a36Sopenharmony_ci .reset = vmw_du_plane_reset, 39462306a36Sopenharmony_ci .atomic_duplicate_state = vmw_du_plane_duplicate_state, 39562306a36Sopenharmony_ci .atomic_destroy_state = vmw_du_plane_destroy_state, 39662306a36Sopenharmony_ci}; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci/* 39962306a36Sopenharmony_ci * Atomic Helpers 40062306a36Sopenharmony_ci */ 40162306a36Sopenharmony_cistatic const struct 40262306a36Sopenharmony_cidrm_plane_helper_funcs vmw_ldu_cursor_plane_helper_funcs = { 40362306a36Sopenharmony_ci .atomic_check = vmw_du_cursor_plane_atomic_check, 40462306a36Sopenharmony_ci .atomic_update = vmw_du_cursor_plane_atomic_update, 40562306a36Sopenharmony_ci .prepare_fb = vmw_du_cursor_plane_prepare_fb, 40662306a36Sopenharmony_ci .cleanup_fb = vmw_du_cursor_plane_cleanup_fb, 40762306a36Sopenharmony_ci}; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic const struct 41062306a36Sopenharmony_cidrm_plane_helper_funcs vmw_ldu_primary_plane_helper_funcs = { 41162306a36Sopenharmony_ci .atomic_check = vmw_du_primary_plane_atomic_check, 41262306a36Sopenharmony_ci .atomic_update = vmw_ldu_primary_plane_atomic_update, 41362306a36Sopenharmony_ci}; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic const struct drm_crtc_helper_funcs vmw_ldu_crtc_helper_funcs = { 41662306a36Sopenharmony_ci .mode_set_nofb = vmw_ldu_crtc_mode_set_nofb, 41762306a36Sopenharmony_ci .atomic_check = vmw_du_crtc_atomic_check, 41862306a36Sopenharmony_ci .atomic_begin = vmw_du_crtc_atomic_begin, 41962306a36Sopenharmony_ci .atomic_flush = vmw_du_crtc_atomic_flush, 42062306a36Sopenharmony_ci .atomic_enable = vmw_ldu_crtc_atomic_enable, 42162306a36Sopenharmony_ci .atomic_disable = vmw_ldu_crtc_atomic_disable, 42262306a36Sopenharmony_ci}; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci struct vmw_legacy_display_unit *ldu; 42862306a36Sopenharmony_ci struct drm_device *dev = &dev_priv->drm; 42962306a36Sopenharmony_ci struct drm_connector *connector; 43062306a36Sopenharmony_ci struct drm_encoder *encoder; 43162306a36Sopenharmony_ci struct drm_plane *primary; 43262306a36Sopenharmony_ci struct vmw_cursor_plane *cursor; 43362306a36Sopenharmony_ci struct drm_crtc *crtc; 43462306a36Sopenharmony_ci int ret; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci ldu = kzalloc(sizeof(*ldu), GFP_KERNEL); 43762306a36Sopenharmony_ci if (!ldu) 43862306a36Sopenharmony_ci return -ENOMEM; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci ldu->base.unit = unit; 44162306a36Sopenharmony_ci crtc = &ldu->base.crtc; 44262306a36Sopenharmony_ci encoder = &ldu->base.encoder; 44362306a36Sopenharmony_ci connector = &ldu->base.connector; 44462306a36Sopenharmony_ci primary = &ldu->base.primary; 44562306a36Sopenharmony_ci cursor = &ldu->base.cursor; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci INIT_LIST_HEAD(&ldu->active); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci ldu->base.pref_active = (unit == 0); 45062306a36Sopenharmony_ci ldu->base.pref_width = dev_priv->initial_width; 45162306a36Sopenharmony_ci ldu->base.pref_height = dev_priv->initial_height; 45262306a36Sopenharmony_ci ldu->base.pref_mode = NULL; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci /* 45562306a36Sopenharmony_ci * Remove this after enabling atomic because property values can 45662306a36Sopenharmony_ci * only exist in a state object 45762306a36Sopenharmony_ci */ 45862306a36Sopenharmony_ci ldu->base.is_implicit = true; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci /* Initialize primary plane */ 46162306a36Sopenharmony_ci ret = drm_universal_plane_init(dev, primary, 46262306a36Sopenharmony_ci 0, &vmw_ldu_plane_funcs, 46362306a36Sopenharmony_ci vmw_primary_plane_formats, 46462306a36Sopenharmony_ci ARRAY_SIZE(vmw_primary_plane_formats), 46562306a36Sopenharmony_ci NULL, DRM_PLANE_TYPE_PRIMARY, NULL); 46662306a36Sopenharmony_ci if (ret) { 46762306a36Sopenharmony_ci DRM_ERROR("Failed to initialize primary plane"); 46862306a36Sopenharmony_ci goto err_free; 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci drm_plane_helper_add(primary, &vmw_ldu_primary_plane_helper_funcs); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci /* 47462306a36Sopenharmony_ci * We're going to be using traces and software cursors 47562306a36Sopenharmony_ci */ 47662306a36Sopenharmony_ci if (vmw_cmd_supported(dev_priv)) { 47762306a36Sopenharmony_ci /* Initialize cursor plane */ 47862306a36Sopenharmony_ci ret = drm_universal_plane_init(dev, &cursor->base, 47962306a36Sopenharmony_ci 0, &vmw_ldu_cursor_funcs, 48062306a36Sopenharmony_ci vmw_cursor_plane_formats, 48162306a36Sopenharmony_ci ARRAY_SIZE(vmw_cursor_plane_formats), 48262306a36Sopenharmony_ci NULL, DRM_PLANE_TYPE_CURSOR, NULL); 48362306a36Sopenharmony_ci if (ret) { 48462306a36Sopenharmony_ci DRM_ERROR("Failed to initialize cursor plane"); 48562306a36Sopenharmony_ci drm_plane_cleanup(&ldu->base.primary); 48662306a36Sopenharmony_ci goto err_free; 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci drm_plane_helper_add(&cursor->base, &vmw_ldu_cursor_plane_helper_funcs); 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci ret = drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, 49362306a36Sopenharmony_ci DRM_MODE_CONNECTOR_VIRTUAL); 49462306a36Sopenharmony_ci if (ret) { 49562306a36Sopenharmony_ci DRM_ERROR("Failed to initialize connector\n"); 49662306a36Sopenharmony_ci goto err_free; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci drm_connector_helper_add(connector, &vmw_ldu_connector_helper_funcs); 50062306a36Sopenharmony_ci connector->status = vmw_du_connector_detect(connector, true); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci ret = drm_encoder_init(dev, encoder, &vmw_legacy_encoder_funcs, 50362306a36Sopenharmony_ci DRM_MODE_ENCODER_VIRTUAL, NULL); 50462306a36Sopenharmony_ci if (ret) { 50562306a36Sopenharmony_ci DRM_ERROR("Failed to initialize encoder\n"); 50662306a36Sopenharmony_ci goto err_free_connector; 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci (void) drm_connector_attach_encoder(connector, encoder); 51062306a36Sopenharmony_ci encoder->possible_crtcs = (1 << unit); 51162306a36Sopenharmony_ci encoder->possible_clones = 0; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci ret = drm_connector_register(connector); 51462306a36Sopenharmony_ci if (ret) { 51562306a36Sopenharmony_ci DRM_ERROR("Failed to register connector\n"); 51662306a36Sopenharmony_ci goto err_free_encoder; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci ret = drm_crtc_init_with_planes(dev, crtc, primary, 52062306a36Sopenharmony_ci vmw_cmd_supported(dev_priv) ? &cursor->base : NULL, 52162306a36Sopenharmony_ci &vmw_legacy_crtc_funcs, NULL); 52262306a36Sopenharmony_ci if (ret) { 52362306a36Sopenharmony_ci DRM_ERROR("Failed to initialize CRTC\n"); 52462306a36Sopenharmony_ci goto err_free_unregister; 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci drm_crtc_helper_add(crtc, &vmw_ldu_crtc_helper_funcs); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci drm_mode_crtc_set_gamma_size(crtc, 256); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci drm_object_attach_property(&connector->base, 53262306a36Sopenharmony_ci dev_priv->hotplug_mode_update_property, 1); 53362306a36Sopenharmony_ci drm_object_attach_property(&connector->base, 53462306a36Sopenharmony_ci dev->mode_config.suggested_x_property, 0); 53562306a36Sopenharmony_ci drm_object_attach_property(&connector->base, 53662306a36Sopenharmony_ci dev->mode_config.suggested_y_property, 0); 53762306a36Sopenharmony_ci if (dev_priv->implicit_placement_property) 53862306a36Sopenharmony_ci drm_object_attach_property 53962306a36Sopenharmony_ci (&connector->base, 54062306a36Sopenharmony_ci dev_priv->implicit_placement_property, 54162306a36Sopenharmony_ci 1); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci return 0; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_cierr_free_unregister: 54662306a36Sopenharmony_ci drm_connector_unregister(connector); 54762306a36Sopenharmony_cierr_free_encoder: 54862306a36Sopenharmony_ci drm_encoder_cleanup(encoder); 54962306a36Sopenharmony_cierr_free_connector: 55062306a36Sopenharmony_ci drm_connector_cleanup(connector); 55162306a36Sopenharmony_cierr_free: 55262306a36Sopenharmony_ci kfree(ldu); 55362306a36Sopenharmony_ci return ret; 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ciint vmw_kms_ldu_init_display(struct vmw_private *dev_priv) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci struct drm_device *dev = &dev_priv->drm; 55962306a36Sopenharmony_ci int i, ret; 56062306a36Sopenharmony_ci int num_display_units = (dev_priv->capabilities & SVGA_CAP_MULTIMON) ? 56162306a36Sopenharmony_ci VMWGFX_NUM_DISPLAY_UNITS : 1; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if (unlikely(dev_priv->ldu_priv)) { 56462306a36Sopenharmony_ci return -EINVAL; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci dev_priv->ldu_priv = kmalloc(sizeof(*dev_priv->ldu_priv), GFP_KERNEL); 56862306a36Sopenharmony_ci if (!dev_priv->ldu_priv) 56962306a36Sopenharmony_ci return -ENOMEM; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci INIT_LIST_HEAD(&dev_priv->ldu_priv->active); 57262306a36Sopenharmony_ci dev_priv->ldu_priv->num_active = 0; 57362306a36Sopenharmony_ci dev_priv->ldu_priv->last_num_active = 0; 57462306a36Sopenharmony_ci dev_priv->ldu_priv->fb = NULL; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci vmw_kms_create_implicit_placement_property(dev_priv); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci for (i = 0; i < num_display_units; ++i) { 57962306a36Sopenharmony_ci ret = vmw_ldu_init(dev_priv, i); 58062306a36Sopenharmony_ci if (ret != 0) 58162306a36Sopenharmony_ci goto err_free; 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci dev_priv->active_display_unit = vmw_du_legacy; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci drm_mode_config_reset(dev); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci return 0; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cierr_free: 59162306a36Sopenharmony_ci kfree(dev_priv->ldu_priv); 59262306a36Sopenharmony_ci dev_priv->ldu_priv = NULL; 59362306a36Sopenharmony_ci return ret; 59462306a36Sopenharmony_ci} 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ciint vmw_kms_ldu_close_display(struct vmw_private *dev_priv) 59762306a36Sopenharmony_ci{ 59862306a36Sopenharmony_ci if (!dev_priv->ldu_priv) 59962306a36Sopenharmony_ci return -ENOSYS; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci BUG_ON(!list_empty(&dev_priv->ldu_priv->active)); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci kfree(dev_priv->ldu_priv); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci return 0; 60662306a36Sopenharmony_ci} 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cistatic int vmw_kms_ldu_do_bo_dirty(struct vmw_private *dev_priv, 61062306a36Sopenharmony_ci struct vmw_framebuffer *framebuffer, 61162306a36Sopenharmony_ci unsigned int flags, unsigned int color, 61262306a36Sopenharmony_ci struct drm_mode_rect *clips, 61362306a36Sopenharmony_ci unsigned int num_clips) 61462306a36Sopenharmony_ci{ 61562306a36Sopenharmony_ci size_t fifo_size; 61662306a36Sopenharmony_ci int i; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci struct { 61962306a36Sopenharmony_ci uint32_t header; 62062306a36Sopenharmony_ci SVGAFifoCmdUpdate body; 62162306a36Sopenharmony_ci } *cmd; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci fifo_size = sizeof(*cmd) * num_clips; 62462306a36Sopenharmony_ci cmd = VMW_CMD_RESERVE(dev_priv, fifo_size); 62562306a36Sopenharmony_ci if (unlikely(cmd == NULL)) 62662306a36Sopenharmony_ci return -ENOMEM; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci memset(cmd, 0, fifo_size); 62962306a36Sopenharmony_ci for (i = 0; i < num_clips; i++, clips++) { 63062306a36Sopenharmony_ci cmd[i].header = SVGA_CMD_UPDATE; 63162306a36Sopenharmony_ci cmd[i].body.x = clips->x1; 63262306a36Sopenharmony_ci cmd[i].body.y = clips->y1; 63362306a36Sopenharmony_ci cmd[i].body.width = clips->x2 - clips->x1; 63462306a36Sopenharmony_ci cmd[i].body.height = clips->y2 - clips->y1; 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci vmw_cmd_commit(dev_priv, fifo_size); 63862306a36Sopenharmony_ci return 0; 63962306a36Sopenharmony_ci} 640