156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz/************************************************************************** 256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * 356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * Copyright © 2011 VMware, Inc., Palo Alto, CA., USA 456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * All Rights Reserved. 556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * 656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * Permission is hereby granted, free of charge, to any person obtaining a 756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * copy of this software and associated documentation files (the 856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * "Software"), to deal in the Software without restriction, including 956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * without limitation the rights to use, copy, modify, merge, publish, 1056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * distribute, sub license, and/or sell copies of the Software, and to 1156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * permit persons to whom the Software is furnished to do so, subject to 1256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * the following conditions: 1356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * 1456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * The above copyright notice and this permission notice (including the 1556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * next paragraph) shall be included in all copies or substantial portions 1656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * of the Software. 1756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * 1856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 2156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 2256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 2356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 2456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * USE OR OTHER DEALINGS IN THE SOFTWARE. 2556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * 2656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz **************************************************************************/ 2756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 2856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz#include "vmwgfx_kms.h" 2956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 3056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 3156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz#define vmw_crtc_to_sou(x) \ 3256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz container_of(x, struct vmw_screen_object_unit, base.crtc) 3356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz#define vmw_encoder_to_sou(x) \ 3456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz container_of(x, struct vmw_screen_object_unit, base.encoder) 3556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz#define vmw_connector_to_sou(x) \ 3656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz container_of(x, struct vmw_screen_object_unit, base.connector) 3756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 3856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantzstruct vmw_screen_object_display { 396987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom unsigned num_implicit; 4056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 416987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom struct vmw_framebuffer *implicit_fb; 4256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz}; 4356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 4456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz/** 4556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * Display unit using screen objects. 4656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz */ 4756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantzstruct vmw_screen_object_unit { 4856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct vmw_display_unit base; 4956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 5056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz unsigned long buffer_size; /**< Size of allocated buffer */ 5156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct vmw_dma_buffer *buffer; /**< Backing store buffer */ 5256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 5356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz bool defined; 546987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom bool active_implicit; 5556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz}; 5656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 5756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantzstatic void vmw_sou_destroy(struct vmw_screen_object_unit *sou) 5856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz{ 5956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz vmw_display_unit_cleanup(&sou->base); 6056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz kfree(sou); 6156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz} 6256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 6356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 6456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz/* 6556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * Screen Object Display Unit CRTC functions 6656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz */ 6756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 6856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantzstatic void vmw_sou_crtc_destroy(struct drm_crtc *crtc) 6956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz{ 7056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz vmw_sou_destroy(vmw_crtc_to_sou(crtc)); 7156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz} 7256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 730e708bc5d6403d1a64a0e4155f1b91e318318989Thomas Hellstromstatic void vmw_sou_del_active(struct vmw_private *vmw_priv, 7456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct vmw_screen_object_unit *sou) 7556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz{ 7656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct vmw_screen_object_display *ld = vmw_priv->sou_priv; 7756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 786987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom if (sou->active_implicit) { 796987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom if (--(ld->num_implicit) == 0) 806987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom ld->implicit_fb = NULL; 816987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom sou->active_implicit = false; 820e708bc5d6403d1a64a0e4155f1b91e318318989Thomas Hellstrom } 8356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz} 8456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 850e708bc5d6403d1a64a0e4155f1b91e318318989Thomas Hellstromstatic void vmw_sou_add_active(struct vmw_private *vmw_priv, 8656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct vmw_screen_object_unit *sou, 8756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct vmw_framebuffer *vfb) 8856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz{ 8956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct vmw_screen_object_display *ld = vmw_priv->sou_priv; 9056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 916987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom BUG_ON(!ld->num_implicit && ld->implicit_fb); 9256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 936987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom if (!sou->active_implicit && sou->base.is_implicit) { 946987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom ld->implicit_fb = vfb; 956987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom sou->active_implicit = true; 966987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom ld->num_implicit++; 9756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz } 9856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz} 9956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 10056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz/** 10156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * Send the fifo command to create a screen. 10256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz */ 10356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantzstatic int vmw_sou_fifo_create(struct vmw_private *dev_priv, 10456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct vmw_screen_object_unit *sou, 10556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz uint32_t x, uint32_t y, 10656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct drm_display_mode *mode) 10756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz{ 10856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz size_t fifo_size; 10956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 11056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct { 11156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct { 11256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz uint32_t cmdType; 11356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz } header; 11456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz SVGAScreenObject obj; 11556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz } *cmd; 11656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 11756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz BUG_ON(!sou->buffer); 11856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 11956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz fifo_size = sizeof(*cmd); 12056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz cmd = vmw_fifo_reserve(dev_priv, fifo_size); 12156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz /* The hardware has hung, nothing we can do about it here. */ 12256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (unlikely(cmd == NULL)) { 12356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz DRM_ERROR("Fifo reserve failed.\n"); 12456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return -ENOMEM; 12556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz } 12656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 12756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz memset(cmd, 0, fifo_size); 12856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz cmd->header.cmdType = SVGA_CMD_DEFINE_SCREEN; 12956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz cmd->obj.structSize = sizeof(SVGAScreenObject); 13056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz cmd->obj.id = sou->base.unit; 13156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz cmd->obj.flags = SVGA_SCREEN_HAS_ROOT | 13256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz (sou->base.unit == 0 ? SVGA_SCREEN_IS_PRIMARY : 0); 13356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz cmd->obj.size.width = mode->hdisplay; 13456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz cmd->obj.size.height = mode->vdisplay; 1356987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom if (sou->base.is_implicit) { 1366987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom cmd->obj.root.x = x; 1376987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom cmd->obj.root.y = y; 1386987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom } else { 1396987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom cmd->obj.root.x = sou->base.gui_x; 1406987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom cmd->obj.root.y = sou->base.gui_y; 1416987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom } 14256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 14356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz /* Ok to assume that buffer is pinned in vram */ 144b37a6b9ad002a6c123a6924668dfef5c5fb0b700Thomas Hellstrom vmw_bo_get_guest_ptr(&sou->buffer->base, &cmd->obj.backingStore.ptr); 14556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz cmd->obj.backingStore.pitch = mode->hdisplay * 4; 14656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 14756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz vmw_fifo_commit(dev_priv, fifo_size); 14856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 14956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz sou->defined = true; 15056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 15156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return 0; 15256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz} 15356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 15456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz/** 15556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * Send the fifo command to destroy a screen. 15656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz */ 15756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantzstatic int vmw_sou_fifo_destroy(struct vmw_private *dev_priv, 15856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct vmw_screen_object_unit *sou) 15956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz{ 16056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz size_t fifo_size; 16156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz int ret; 16256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 16356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct { 16456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct { 16556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz uint32_t cmdType; 16656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz } header; 16756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz SVGAFifoCmdDestroyScreen body; 16856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz } *cmd; 16956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 17056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz /* no need to do anything */ 17156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (unlikely(!sou->defined)) 17256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return 0; 17356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 17456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz fifo_size = sizeof(*cmd); 17556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz cmd = vmw_fifo_reserve(dev_priv, fifo_size); 17656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz /* the hardware has hung, nothing we can do about it here */ 17756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (unlikely(cmd == NULL)) { 17856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz DRM_ERROR("Fifo reserve failed.\n"); 17956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return -ENOMEM; 18056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz } 18156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 18256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz memset(cmd, 0, fifo_size); 18356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz cmd->header.cmdType = SVGA_CMD_DESTROY_SCREEN; 18456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz cmd->body.screenId = sou->base.unit; 18556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 18656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz vmw_fifo_commit(dev_priv, fifo_size); 18756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 18856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz /* Force sync */ 18956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz ret = vmw_fallback_wait(dev_priv, false, true, 0, false, 3*HZ); 19056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (unlikely(ret != 0)) 19156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz DRM_ERROR("Failed to sync with HW"); 19256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz else 19356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz sou->defined = false; 19456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 19556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return ret; 19656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz} 19756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 19856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz/** 19956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * Free the backing store. 20056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz */ 20156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantzstatic void vmw_sou_backing_free(struct vmw_private *dev_priv, 20256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct vmw_screen_object_unit *sou) 20356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz{ 20456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct ttm_buffer_object *bo; 20556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 20656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (unlikely(sou->buffer == NULL)) 20756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return; 20856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 20956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz bo = &sou->buffer->base; 21056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz ttm_bo_unref(&bo); 21156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz sou->buffer = NULL; 21256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz sou->buffer_size = 0; 21356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz} 21456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 21556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz/** 21656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * Allocate the backing store for the buffer. 21756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz */ 21856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantzstatic int vmw_sou_backing_alloc(struct vmw_private *dev_priv, 21956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct vmw_screen_object_unit *sou, 22056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz unsigned long size) 22156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz{ 22256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz int ret; 22356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 22456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (sou->buffer_size == size) 22556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return 0; 22656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 22756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (sou->buffer) 22856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz vmw_sou_backing_free(dev_priv, sou); 22956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 23056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz sou->buffer = kzalloc(sizeof(*sou->buffer), GFP_KERNEL); 23156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (unlikely(sou->buffer == NULL)) 23256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return -ENOMEM; 23356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 23456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz /* After we have alloced the backing store might not be able to 23556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * resume the overlays, this is preferred to failing to alloc. 23656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz */ 23756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz vmw_overlay_pause_all(dev_priv); 23856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz ret = vmw_dmabuf_init(dev_priv, sou->buffer, size, 23956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz &vmw_vram_ne_placement, 24056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz false, &vmw_dmabuf_bo_free); 24156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz vmw_overlay_resume_all(dev_priv); 24256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 24356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (unlikely(ret != 0)) 24456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz sou->buffer = NULL; /* vmw_dmabuf_init frees on error */ 24556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz else 24656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz sou->buffer_size = size; 24756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 24856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return ret; 24956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz} 25056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 25156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantzstatic int vmw_sou_crtc_set_config(struct drm_mode_set *set) 25256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz{ 25356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct vmw_private *dev_priv; 25456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct vmw_screen_object_unit *sou; 25556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct drm_connector *connector; 25656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct drm_display_mode *mode; 25756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct drm_encoder *encoder; 25856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct vmw_framebuffer *vfb; 25956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct drm_framebuffer *fb; 26056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct drm_crtc *crtc; 26156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz int ret = 0; 26256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 26356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (!set) 26456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return -EINVAL; 26556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 26656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (!set->crtc) 26756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return -EINVAL; 26856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 26956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz /* get the sou */ 27056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz crtc = set->crtc; 27156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz sou = vmw_crtc_to_sou(crtc); 27256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz vfb = set->fb ? vmw_framebuffer_to_vfb(set->fb) : NULL; 27356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz dev_priv = vmw_priv(crtc->dev); 27456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 27556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (set->num_connectors > 1) { 27656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz DRM_ERROR("to many connectors\n"); 27756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return -EINVAL; 27856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz } 27956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 28056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (set->num_connectors == 1 && 28156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz set->connectors[0] != &sou->base.connector) { 28256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz DRM_ERROR("connector doesn't match %p %p\n", 28356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz set->connectors[0], &sou->base.connector); 28456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return -EINVAL; 28556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz } 28656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 28756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz /* sou only supports one fb active at the time */ 2886987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom if (sou->base.is_implicit && 2896987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom dev_priv->sou_priv->implicit_fb && vfb && 2906987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom !(dev_priv->sou_priv->num_implicit == 1 && 2916987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom sou->active_implicit) && 2926987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom dev_priv->sou_priv->implicit_fb != vfb) { 29356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz DRM_ERROR("Multiple framebuffers not supported\n"); 29456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return -EINVAL; 29556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz } 29656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 29756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz /* since they always map one to one these are safe */ 29856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz connector = &sou->base.connector; 29956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz encoder = &sou->base.encoder; 30056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 30156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz /* should we turn the crtc off */ 30256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (set->num_connectors == 0 || !set->mode || !set->fb) { 30356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz ret = vmw_sou_fifo_destroy(dev_priv, sou); 30456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz /* the hardware has hung don't do anything more */ 30556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (unlikely(ret != 0)) 30656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return ret; 30756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 30856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz connector->encoder = NULL; 30956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz encoder->crtc = NULL; 31056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz crtc->fb = NULL; 31156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz crtc->x = 0; 31256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz crtc->y = 0; 31356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 31456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz vmw_sou_del_active(dev_priv, sou); 31556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 31656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz vmw_sou_backing_free(dev_priv, sou); 31756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 31856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return 0; 31956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz } 32056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 32156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 32256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz /* we now know we want to set a mode */ 32356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz mode = set->mode; 32456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz fb = set->fb; 32556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 32656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (set->x + mode->hdisplay > fb->width || 32756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz set->y + mode->vdisplay > fb->height) { 32856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz DRM_ERROR("set outside of framebuffer\n"); 32956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return -EINVAL; 33056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz } 33156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 33256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz vmw_fb_off(dev_priv); 33356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 33456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (mode->hdisplay != crtc->mode.hdisplay || 33556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz mode->vdisplay != crtc->mode.vdisplay) { 33656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz /* no need to check if depth is different, because backing 33756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * store depth is forced to 4 by the device. 33856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz */ 33956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 34056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz ret = vmw_sou_fifo_destroy(dev_priv, sou); 34156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz /* the hardware has hung don't do anything more */ 34256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (unlikely(ret != 0)) 34356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return ret; 34456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 34556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz vmw_sou_backing_free(dev_priv, sou); 34656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz } 34756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 34856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (!sou->buffer) { 34956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz /* forced to depth 4 by the device */ 35056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz size_t size = mode->hdisplay * mode->vdisplay * 4; 35156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz ret = vmw_sou_backing_alloc(dev_priv, sou, size); 35256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (unlikely(ret != 0)) 35356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return ret; 35456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz } 35556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 35656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz ret = vmw_sou_fifo_create(dev_priv, sou, set->x, set->y, mode); 35756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (unlikely(ret != 0)) { 35856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz /* 35956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * We are in a bit of a situation here, the hardware has 36056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * hung and we may or may not have a buffer hanging of 36156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * the screen object, best thing to do is not do anything 36256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * if we where defined, if not just turn the crtc of. 36356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * Not what userspace wants but it needs to htfu. 36456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz */ 36556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (sou->defined) 36656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return ret; 36756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 36856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz connector->encoder = NULL; 36956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz encoder->crtc = NULL; 37056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz crtc->fb = NULL; 37156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz crtc->x = 0; 37256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz crtc->y = 0; 37356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 37456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return ret; 37556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz } 37656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 37756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz vmw_sou_add_active(dev_priv, sou, vfb); 37856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 37956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz connector->encoder = encoder; 38056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz encoder->crtc = crtc; 38156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz crtc->mode = *mode; 38256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz crtc->fb = fb; 38356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz crtc->x = set->x; 38456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz crtc->y = set->y; 38556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 38656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return 0; 38756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz} 38856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 38956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantzstatic struct drm_crtc_funcs vmw_screen_object_crtc_funcs = { 39056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz .save = vmw_du_crtc_save, 39156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz .restore = vmw_du_crtc_restore, 39256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz .cursor_set = vmw_du_crtc_cursor_set, 39356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz .cursor_move = vmw_du_crtc_cursor_move, 39456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz .gamma_set = vmw_du_crtc_gamma_set, 39556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz .destroy = vmw_sou_crtc_destroy, 39656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz .set_config = vmw_sou_crtc_set_config, 397b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz .page_flip = vmw_du_page_flip, 39856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz}; 39956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 40056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz/* 40156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * Screen Object Display Unit encoder functions 40256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz */ 40356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 40456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantzstatic void vmw_sou_encoder_destroy(struct drm_encoder *encoder) 40556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz{ 40656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz vmw_sou_destroy(vmw_encoder_to_sou(encoder)); 40756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz} 40856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 40956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantzstatic struct drm_encoder_funcs vmw_screen_object_encoder_funcs = { 41056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz .destroy = vmw_sou_encoder_destroy, 41156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz}; 41256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 41356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz/* 41456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz * Screen Object Display Unit connector functions 41556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz */ 41656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 41756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantzstatic void vmw_sou_connector_destroy(struct drm_connector *connector) 41856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz{ 41956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz vmw_sou_destroy(vmw_connector_to_sou(connector)); 42056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz} 42156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 42256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantzstatic struct drm_connector_funcs vmw_legacy_connector_funcs = { 42356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz .dpms = vmw_du_connector_dpms, 42456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz .save = vmw_du_connector_save, 42556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz .restore = vmw_du_connector_restore, 42656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz .detect = vmw_du_connector_detect, 42756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz .fill_modes = vmw_du_connector_fill_modes, 42856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz .set_property = vmw_du_connector_set_property, 42956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz .destroy = vmw_sou_connector_destroy, 43056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz}; 43156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 43256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantzstatic int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) 43356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz{ 43456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct vmw_screen_object_unit *sou; 43556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct drm_device *dev = dev_priv->dev; 43656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct drm_connector *connector; 43756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct drm_encoder *encoder; 43856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct drm_crtc *crtc; 43956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 44056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz sou = kzalloc(sizeof(*sou), GFP_KERNEL); 44156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (!sou) 44256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return -ENOMEM; 44356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 44456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz sou->base.unit = unit; 44556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz crtc = &sou->base.crtc; 44656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz encoder = &sou->base.encoder; 44756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz connector = &sou->base.connector; 44856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 4496987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom sou->active_implicit = false; 45056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 45156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz sou->base.pref_active = (unit == 0); 452eb4f923b1ceac8a618469c51ff249bd89bc0dfa4Jakob Bornecrantz sou->base.pref_width = dev_priv->initial_width; 453eb4f923b1ceac8a618469c51ff249bd89bc0dfa4Jakob Bornecrantz sou->base.pref_height = dev_priv->initial_height; 45456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz sou->base.pref_mode = NULL; 4556987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom sou->base.is_implicit = true; 45656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 45756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, 458305151e36e3d5e0592580e6db3c5855a68f2bf6bThomas Hellstrom DRM_MODE_CONNECTOR_VIRTUAL); 45956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz connector->status = vmw_du_connector_detect(connector, true); 46056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 46156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz drm_encoder_init(dev, encoder, &vmw_screen_object_encoder_funcs, 462305151e36e3d5e0592580e6db3c5855a68f2bf6bThomas Hellstrom DRM_MODE_ENCODER_VIRTUAL); 46356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz drm_mode_connector_attach_encoder(connector, encoder); 46456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz encoder->possible_crtcs = (1 << unit); 46556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz encoder->possible_clones = 0; 46656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 46756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz drm_crtc_init(dev, crtc, &vmw_screen_object_crtc_funcs); 46856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 46956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz drm_mode_crtc_set_gamma_size(crtc, 256); 47056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 47156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz drm_connector_attach_property(connector, 47256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz dev->mode_config.dirty_info_property, 47356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 1); 47456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 47556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return 0; 47656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz} 47756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 47856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantzint vmw_kms_init_screen_object_display(struct vmw_private *dev_priv) 47956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz{ 48056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct drm_device *dev = dev_priv->dev; 48174b5ea307689b5abf577670b40965921d5dba4d5Jakob Bornecrantz int i, ret; 48256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 48356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (dev_priv->sou_priv) { 48456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz DRM_INFO("sou system already on\n"); 48556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return -EINVAL; 48656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz } 48756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 48856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (!(dev_priv->fifo.capabilities & SVGA_FIFO_CAP_SCREEN_OBJECT_2)) { 48956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz DRM_INFO("Not using screen objects," 49056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz " missing cap SCREEN_OBJECT_2\n"); 49156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return -ENOSYS; 49256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz } 49356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 49456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz ret = -ENOMEM; 49556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz dev_priv->sou_priv = kmalloc(sizeof(*dev_priv->sou_priv), GFP_KERNEL); 49656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (unlikely(!dev_priv->sou_priv)) 49756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz goto err_no_mem; 49856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 4996987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom dev_priv->sou_priv->num_implicit = 0; 5006987427a3953c5038dc14d2a090b5a6c93669428Thomas Hellstrom dev_priv->sou_priv->implicit_fb = NULL; 50156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 50256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS); 50356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (unlikely(ret != 0)) 50456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz goto err_free; 50556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 50674b5ea307689b5abf577670b40965921d5dba4d5Jakob Bornecrantz ret = drm_mode_create_dirty_info_property(dev); 50756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (unlikely(ret != 0)) 50856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz goto err_vblank_cleanup; 50956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 51056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) 51156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz vmw_sou_init(dev_priv, i); 51256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 51356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz DRM_INFO("Screen objects system initialized\n"); 51456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 51556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return 0; 51656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 51756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantzerr_vblank_cleanup: 51856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz drm_vblank_cleanup(dev); 51956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantzerr_free: 52056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz kfree(dev_priv->sou_priv); 52160a16a30d97e8acc9bfed5f4bd1dd03e21a479eaJakob Bornecrantz dev_priv->sou_priv = NULL; 52256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantzerr_no_mem: 52356d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return ret; 52456d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz} 52556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 52656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantzint vmw_kms_close_screen_object_display(struct vmw_private *dev_priv) 52756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz{ 52856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz struct drm_device *dev = dev_priv->dev; 52956d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 53056d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz if (!dev_priv->sou_priv) 53156d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return -ENOSYS; 53256d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 53360a16a30d97e8acc9bfed5f4bd1dd03e21a479eaJakob Bornecrantz drm_vblank_cleanup(dev); 53460a16a30d97e8acc9bfed5f4bd1dd03e21a479eaJakob Bornecrantz 53556d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz kfree(dev_priv->sou_priv); 53656d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz 53756d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz return 0; 53856d1c78df52323cdcd937505dccaa5d665dfab97Jakob Bornecrantz} 539b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz 540b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz/** 541b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz * Returns if this unit can be page flipped. 542b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz * Must be called with the mode_config mutex held. 543b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz */ 544b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantzbool vmw_kms_screen_object_flippable(struct vmw_private *dev_priv, 545b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz struct drm_crtc *crtc) 546b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz{ 547b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc); 548b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz 549b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz if (!sou->base.is_implicit) 550b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz return true; 551b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz 552b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz if (dev_priv->sou_priv->num_implicit != 1) 553b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz return false; 554b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz 555b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz return true; 556b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz} 557b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz 558b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz/** 559b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz * Update the implicit fb to the current fb of this crtc. 560b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz * Must be called with the mode_config mutex held. 561b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz */ 562b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantzvoid vmw_kms_screen_object_update_implicit_fb(struct vmw_private *dev_priv, 563b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz struct drm_crtc *crtc) 564b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz{ 565b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc); 566b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz 567b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz BUG_ON(!sou->base.is_implicit); 568b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz 569b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz dev_priv->sou_priv->implicit_fb = 570b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz vmw_framebuffer_to_vfb(sou->base.crtc.fb); 571b5ec427e8d8c66ea1bb9a3bf09663c1361ecf0b6Jakob Bornecrantz} 572