1 1.2 riastrad /* $NetBSD: vmwgfx_ldu.c,v 1.3 2021/12/18 23:45:45 riastradh Exp $ */ 2 1.2 riastrad 3 1.3 riastrad // SPDX-License-Identifier: GPL-2.0 OR MIT 4 1.1 riastrad /************************************************************************** 5 1.1 riastrad * 6 1.3 riastrad * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA 7 1.1 riastrad * 8 1.1 riastrad * Permission is hereby granted, free of charge, to any person obtaining a 9 1.1 riastrad * copy of this software and associated documentation files (the 10 1.1 riastrad * "Software"), to deal in the Software without restriction, including 11 1.1 riastrad * without limitation the rights to use, copy, modify, merge, publish, 12 1.1 riastrad * distribute, sub license, and/or sell copies of the Software, and to 13 1.1 riastrad * permit persons to whom the Software is furnished to do so, subject to 14 1.1 riastrad * the following conditions: 15 1.1 riastrad * 16 1.1 riastrad * The above copyright notice and this permission notice (including the 17 1.1 riastrad * next paragraph) shall be included in all copies or substantial portions 18 1.1 riastrad * of the Software. 19 1.1 riastrad * 20 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 1.1 riastrad * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 1.1 riastrad * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 23 1.1 riastrad * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 24 1.1 riastrad * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 25 1.1 riastrad * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 26 1.1 riastrad * USE OR OTHER DEALINGS IN THE SOFTWARE. 27 1.1 riastrad * 28 1.1 riastrad **************************************************************************/ 29 1.1 riastrad 30 1.2 riastrad #include <sys/cdefs.h> 31 1.2 riastrad __KERNEL_RCSID(0, "$NetBSD: vmwgfx_ldu.c,v 1.3 2021/12/18 23:45:45 riastradh Exp $"); 32 1.2 riastrad 33 1.3 riastrad #include <drm/drm_atomic.h> 34 1.3 riastrad #include <drm/drm_atomic_helper.h> 35 1.3 riastrad #include <drm/drm_fourcc.h> 36 1.2 riastrad #include <drm/drm_plane_helper.h> 37 1.3 riastrad #include <drm/drm_vblank.h> 38 1.1 riastrad 39 1.3 riastrad #include "vmwgfx_kms.h" 40 1.1 riastrad 41 1.1 riastrad #define vmw_crtc_to_ldu(x) \ 42 1.1 riastrad container_of(x, struct vmw_legacy_display_unit, base.crtc) 43 1.1 riastrad #define vmw_encoder_to_ldu(x) \ 44 1.1 riastrad container_of(x, struct vmw_legacy_display_unit, base.encoder) 45 1.1 riastrad #define vmw_connector_to_ldu(x) \ 46 1.1 riastrad container_of(x, struct vmw_legacy_display_unit, base.connector) 47 1.1 riastrad 48 1.1 riastrad struct vmw_legacy_display { 49 1.1 riastrad struct list_head active; 50 1.1 riastrad 51 1.1 riastrad unsigned num_active; 52 1.1 riastrad unsigned last_num_active; 53 1.1 riastrad 54 1.1 riastrad struct vmw_framebuffer *fb; 55 1.1 riastrad }; 56 1.1 riastrad 57 1.1 riastrad /** 58 1.1 riastrad * Display unit using the legacy register interface. 59 1.1 riastrad */ 60 1.1 riastrad struct vmw_legacy_display_unit { 61 1.1 riastrad struct vmw_display_unit base; 62 1.1 riastrad 63 1.1 riastrad struct list_head active; 64 1.1 riastrad }; 65 1.1 riastrad 66 1.1 riastrad static void vmw_ldu_destroy(struct vmw_legacy_display_unit *ldu) 67 1.1 riastrad { 68 1.1 riastrad list_del_init(&ldu->active); 69 1.2 riastrad vmw_du_cleanup(&ldu->base); 70 1.1 riastrad kfree(ldu); 71 1.1 riastrad } 72 1.1 riastrad 73 1.1 riastrad 74 1.1 riastrad /* 75 1.1 riastrad * Legacy Display Unit CRTC functions 76 1.1 riastrad */ 77 1.1 riastrad 78 1.1 riastrad static void vmw_ldu_crtc_destroy(struct drm_crtc *crtc) 79 1.1 riastrad { 80 1.1 riastrad vmw_ldu_destroy(vmw_crtc_to_ldu(crtc)); 81 1.1 riastrad } 82 1.1 riastrad 83 1.1 riastrad static int vmw_ldu_commit_list(struct vmw_private *dev_priv) 84 1.1 riastrad { 85 1.1 riastrad struct vmw_legacy_display *lds = dev_priv->ldu_priv; 86 1.1 riastrad struct vmw_legacy_display_unit *entry; 87 1.1 riastrad struct drm_framebuffer *fb = NULL; 88 1.1 riastrad struct drm_crtc *crtc = NULL; 89 1.3 riastrad int i = 0; 90 1.1 riastrad 91 1.1 riastrad /* If there is no display topology the host just assumes 92 1.1 riastrad * that the guest will set the same layout as the host. 93 1.1 riastrad */ 94 1.1 riastrad if (!(dev_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY)) { 95 1.1 riastrad int w = 0, h = 0; 96 1.1 riastrad list_for_each_entry(entry, &lds->active, active) { 97 1.1 riastrad crtc = &entry->base.crtc; 98 1.1 riastrad w = max(w, crtc->x + crtc->mode.hdisplay); 99 1.1 riastrad h = max(h, crtc->y + crtc->mode.vdisplay); 100 1.1 riastrad i++; 101 1.1 riastrad } 102 1.1 riastrad 103 1.1 riastrad if (crtc == NULL) 104 1.1 riastrad return 0; 105 1.3 riastrad fb = entry->base.crtc.primary->state->fb; 106 1.1 riastrad 107 1.1 riastrad return vmw_kms_write_svga(dev_priv, w, h, fb->pitches[0], 108 1.3 riastrad fb->format->cpp[0] * 8, 109 1.3 riastrad fb->format->depth); 110 1.1 riastrad } 111 1.1 riastrad 112 1.1 riastrad if (!list_empty(&lds->active)) { 113 1.1 riastrad entry = list_entry(lds->active.next, typeof(*entry), active); 114 1.3 riastrad fb = entry->base.crtc.primary->state->fb; 115 1.1 riastrad 116 1.1 riastrad vmw_kms_write_svga(dev_priv, fb->width, fb->height, fb->pitches[0], 117 1.3 riastrad fb->format->cpp[0] * 8, fb->format->depth); 118 1.1 riastrad } 119 1.1 riastrad 120 1.1 riastrad /* Make sure we always show something. */ 121 1.1 riastrad vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 122 1.1 riastrad lds->num_active ? lds->num_active : 1); 123 1.1 riastrad 124 1.1 riastrad i = 0; 125 1.1 riastrad list_for_each_entry(entry, &lds->active, active) { 126 1.1 riastrad crtc = &entry->base.crtc; 127 1.1 riastrad 128 1.1 riastrad vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, i); 129 1.1 riastrad vmw_write(dev_priv, SVGA_REG_DISPLAY_IS_PRIMARY, !i); 130 1.1 riastrad vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_X, crtc->x); 131 1.1 riastrad vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_Y, crtc->y); 132 1.1 riastrad vmw_write(dev_priv, SVGA_REG_DISPLAY_WIDTH, crtc->mode.hdisplay); 133 1.1 riastrad vmw_write(dev_priv, SVGA_REG_DISPLAY_HEIGHT, crtc->mode.vdisplay); 134 1.1 riastrad vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); 135 1.1 riastrad 136 1.1 riastrad i++; 137 1.1 riastrad } 138 1.1 riastrad 139 1.1 riastrad BUG_ON(i != lds->num_active); 140 1.1 riastrad 141 1.1 riastrad lds->last_num_active = lds->num_active; 142 1.1 riastrad 143 1.1 riastrad return 0; 144 1.1 riastrad } 145 1.1 riastrad 146 1.1 riastrad static int vmw_ldu_del_active(struct vmw_private *vmw_priv, 147 1.1 riastrad struct vmw_legacy_display_unit *ldu) 148 1.1 riastrad { 149 1.1 riastrad struct vmw_legacy_display *ld = vmw_priv->ldu_priv; 150 1.1 riastrad if (list_empty(&ldu->active)) 151 1.1 riastrad return 0; 152 1.1 riastrad 153 1.1 riastrad /* Must init otherwise list_empty(&ldu->active) will not work. */ 154 1.1 riastrad list_del_init(&ldu->active); 155 1.1 riastrad if (--(ld->num_active) == 0) { 156 1.1 riastrad BUG_ON(!ld->fb); 157 1.1 riastrad if (ld->fb->unpin) 158 1.1 riastrad ld->fb->unpin(ld->fb); 159 1.1 riastrad ld->fb = NULL; 160 1.1 riastrad } 161 1.1 riastrad 162 1.1 riastrad return 0; 163 1.1 riastrad } 164 1.1 riastrad 165 1.1 riastrad static int vmw_ldu_add_active(struct vmw_private *vmw_priv, 166 1.1 riastrad struct vmw_legacy_display_unit *ldu, 167 1.1 riastrad struct vmw_framebuffer *vfb) 168 1.1 riastrad { 169 1.1 riastrad struct vmw_legacy_display *ld = vmw_priv->ldu_priv; 170 1.1 riastrad struct vmw_legacy_display_unit *entry; 171 1.1 riastrad struct list_head *at; 172 1.1 riastrad 173 1.1 riastrad BUG_ON(!ld->num_active && ld->fb); 174 1.1 riastrad if (vfb != ld->fb) { 175 1.1 riastrad if (ld->fb && ld->fb->unpin) 176 1.1 riastrad ld->fb->unpin(ld->fb); 177 1.3 riastrad vmw_svga_enable(vmw_priv); 178 1.1 riastrad if (vfb->pin) 179 1.1 riastrad vfb->pin(vfb); 180 1.1 riastrad ld->fb = vfb; 181 1.1 riastrad } 182 1.1 riastrad 183 1.1 riastrad if (!list_empty(&ldu->active)) 184 1.1 riastrad return 0; 185 1.1 riastrad 186 1.1 riastrad at = &ld->active; 187 1.1 riastrad list_for_each_entry(entry, &ld->active, active) { 188 1.1 riastrad if (entry->base.unit > ldu->base.unit) 189 1.1 riastrad break; 190 1.1 riastrad 191 1.1 riastrad at = &entry->active; 192 1.1 riastrad } 193 1.1 riastrad 194 1.1 riastrad list_add(&ldu->active, at); 195 1.1 riastrad 196 1.1 riastrad ld->num_active++; 197 1.1 riastrad 198 1.1 riastrad return 0; 199 1.1 riastrad } 200 1.1 riastrad 201 1.3 riastrad /** 202 1.3 riastrad * vmw_ldu_crtc_mode_set_nofb - Enable svga 203 1.3 riastrad * 204 1.3 riastrad * @crtc: CRTC associated with the new screen 205 1.3 riastrad * 206 1.3 riastrad * For LDU, just enable the svga 207 1.3 riastrad */ 208 1.3 riastrad static void vmw_ldu_crtc_mode_set_nofb(struct drm_crtc *crtc) 209 1.1 riastrad { 210 1.3 riastrad } 211 1.1 riastrad 212 1.3 riastrad /** 213 1.3 riastrad * vmw_ldu_crtc_atomic_enable - Noop 214 1.3 riastrad * 215 1.3 riastrad * @crtc: CRTC associated with the new screen 216 1.3 riastrad * 217 1.3 riastrad * This is called after a mode set has been completed. Here's 218 1.3 riastrad * usually a good place to call vmw_ldu_add_active/vmw_ldu_del_active 219 1.3 riastrad * but since for LDU the display plane is closely tied to the 220 1.3 riastrad * CRTC, it makes more sense to do those at plane update time. 221 1.3 riastrad */ 222 1.3 riastrad static void vmw_ldu_crtc_atomic_enable(struct drm_crtc *crtc, 223 1.3 riastrad struct drm_crtc_state *old_state) 224 1.3 riastrad { 225 1.3 riastrad } 226 1.1 riastrad 227 1.3 riastrad /** 228 1.3 riastrad * vmw_ldu_crtc_atomic_disable - Turns off CRTC 229 1.3 riastrad * 230 1.3 riastrad * @crtc: CRTC to be turned off 231 1.3 riastrad */ 232 1.3 riastrad static void vmw_ldu_crtc_atomic_disable(struct drm_crtc *crtc, 233 1.3 riastrad struct drm_crtc_state *old_state) 234 1.3 riastrad { 235 1.3 riastrad } 236 1.1 riastrad 237 1.3 riastrad static const struct drm_crtc_funcs vmw_legacy_crtc_funcs = { 238 1.1 riastrad .gamma_set = vmw_du_crtc_gamma_set, 239 1.1 riastrad .destroy = vmw_ldu_crtc_destroy, 240 1.3 riastrad .reset = vmw_du_crtc_reset, 241 1.3 riastrad .atomic_duplicate_state = vmw_du_crtc_duplicate_state, 242 1.3 riastrad .atomic_destroy_state = vmw_du_crtc_destroy_state, 243 1.3 riastrad .set_config = drm_atomic_helper_set_config, 244 1.1 riastrad }; 245 1.1 riastrad 246 1.1 riastrad 247 1.1 riastrad /* 248 1.1 riastrad * Legacy Display Unit encoder functions 249 1.1 riastrad */ 250 1.1 riastrad 251 1.1 riastrad static void vmw_ldu_encoder_destroy(struct drm_encoder *encoder) 252 1.1 riastrad { 253 1.1 riastrad vmw_ldu_destroy(vmw_encoder_to_ldu(encoder)); 254 1.1 riastrad } 255 1.1 riastrad 256 1.3 riastrad static const struct drm_encoder_funcs vmw_legacy_encoder_funcs = { 257 1.1 riastrad .destroy = vmw_ldu_encoder_destroy, 258 1.1 riastrad }; 259 1.1 riastrad 260 1.1 riastrad /* 261 1.1 riastrad * Legacy Display Unit connector functions 262 1.1 riastrad */ 263 1.1 riastrad 264 1.1 riastrad static void vmw_ldu_connector_destroy(struct drm_connector *connector) 265 1.1 riastrad { 266 1.1 riastrad vmw_ldu_destroy(vmw_connector_to_ldu(connector)); 267 1.1 riastrad } 268 1.1 riastrad 269 1.3 riastrad static const struct drm_connector_funcs vmw_legacy_connector_funcs = { 270 1.1 riastrad .dpms = vmw_du_connector_dpms, 271 1.1 riastrad .detect = vmw_du_connector_detect, 272 1.1 riastrad .fill_modes = vmw_du_connector_fill_modes, 273 1.1 riastrad .destroy = vmw_ldu_connector_destroy, 274 1.3 riastrad .reset = vmw_du_connector_reset, 275 1.3 riastrad .atomic_duplicate_state = vmw_du_connector_duplicate_state, 276 1.3 riastrad .atomic_destroy_state = vmw_du_connector_destroy_state, 277 1.3 riastrad }; 278 1.3 riastrad 279 1.3 riastrad static const struct 280 1.3 riastrad drm_connector_helper_funcs vmw_ldu_connector_helper_funcs = { 281 1.3 riastrad }; 282 1.3 riastrad 283 1.3 riastrad /* 284 1.3 riastrad * Legacy Display Plane Functions 285 1.3 riastrad */ 286 1.3 riastrad 287 1.3 riastrad static void 288 1.3 riastrad vmw_ldu_primary_plane_atomic_update(struct drm_plane *plane, 289 1.3 riastrad struct drm_plane_state *old_state) 290 1.3 riastrad { 291 1.3 riastrad struct vmw_private *dev_priv; 292 1.3 riastrad struct vmw_legacy_display_unit *ldu; 293 1.3 riastrad struct vmw_framebuffer *vfb; 294 1.3 riastrad struct drm_framebuffer *fb; 295 1.3 riastrad struct drm_crtc *crtc = plane->state->crtc ?: old_state->crtc; 296 1.3 riastrad 297 1.3 riastrad 298 1.3 riastrad ldu = vmw_crtc_to_ldu(crtc); 299 1.3 riastrad dev_priv = vmw_priv(plane->dev); 300 1.3 riastrad fb = plane->state->fb; 301 1.3 riastrad 302 1.3 riastrad vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL; 303 1.3 riastrad 304 1.3 riastrad if (vfb) 305 1.3 riastrad vmw_ldu_add_active(dev_priv, ldu, vfb); 306 1.3 riastrad else 307 1.3 riastrad vmw_ldu_del_active(dev_priv, ldu); 308 1.3 riastrad 309 1.3 riastrad vmw_ldu_commit_list(dev_priv); 310 1.3 riastrad } 311 1.3 riastrad 312 1.3 riastrad 313 1.3 riastrad static const struct drm_plane_funcs vmw_ldu_plane_funcs = { 314 1.3 riastrad .update_plane = drm_atomic_helper_update_plane, 315 1.3 riastrad .disable_plane = drm_atomic_helper_disable_plane, 316 1.3 riastrad .destroy = vmw_du_primary_plane_destroy, 317 1.3 riastrad .reset = vmw_du_plane_reset, 318 1.3 riastrad .atomic_duplicate_state = vmw_du_plane_duplicate_state, 319 1.3 riastrad .atomic_destroy_state = vmw_du_plane_destroy_state, 320 1.3 riastrad }; 321 1.3 riastrad 322 1.3 riastrad static const struct drm_plane_funcs vmw_ldu_cursor_funcs = { 323 1.3 riastrad .update_plane = drm_atomic_helper_update_plane, 324 1.3 riastrad .disable_plane = drm_atomic_helper_disable_plane, 325 1.3 riastrad .destroy = vmw_du_cursor_plane_destroy, 326 1.3 riastrad .reset = vmw_du_plane_reset, 327 1.3 riastrad .atomic_duplicate_state = vmw_du_plane_duplicate_state, 328 1.3 riastrad .atomic_destroy_state = vmw_du_plane_destroy_state, 329 1.3 riastrad }; 330 1.3 riastrad 331 1.3 riastrad /* 332 1.3 riastrad * Atomic Helpers 333 1.3 riastrad */ 334 1.3 riastrad static const struct 335 1.3 riastrad drm_plane_helper_funcs vmw_ldu_cursor_plane_helper_funcs = { 336 1.3 riastrad .atomic_check = vmw_du_cursor_plane_atomic_check, 337 1.3 riastrad .atomic_update = vmw_du_cursor_plane_atomic_update, 338 1.3 riastrad .prepare_fb = vmw_du_cursor_plane_prepare_fb, 339 1.3 riastrad .cleanup_fb = vmw_du_plane_cleanup_fb, 340 1.3 riastrad }; 341 1.3 riastrad 342 1.3 riastrad static const struct 343 1.3 riastrad drm_plane_helper_funcs vmw_ldu_primary_plane_helper_funcs = { 344 1.3 riastrad .atomic_check = vmw_du_primary_plane_atomic_check, 345 1.3 riastrad .atomic_update = vmw_ldu_primary_plane_atomic_update, 346 1.3 riastrad }; 347 1.3 riastrad 348 1.3 riastrad static const struct drm_crtc_helper_funcs vmw_ldu_crtc_helper_funcs = { 349 1.3 riastrad .mode_set_nofb = vmw_ldu_crtc_mode_set_nofb, 350 1.3 riastrad .atomic_check = vmw_du_crtc_atomic_check, 351 1.3 riastrad .atomic_begin = vmw_du_crtc_atomic_begin, 352 1.3 riastrad .atomic_flush = vmw_du_crtc_atomic_flush, 353 1.3 riastrad .atomic_enable = vmw_ldu_crtc_atomic_enable, 354 1.3 riastrad .atomic_disable = vmw_ldu_crtc_atomic_disable, 355 1.1 riastrad }; 356 1.1 riastrad 357 1.3 riastrad 358 1.1 riastrad static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) 359 1.1 riastrad { 360 1.1 riastrad struct vmw_legacy_display_unit *ldu; 361 1.1 riastrad struct drm_device *dev = dev_priv->dev; 362 1.1 riastrad struct drm_connector *connector; 363 1.1 riastrad struct drm_encoder *encoder; 364 1.3 riastrad struct drm_plane *primary, *cursor; 365 1.1 riastrad struct drm_crtc *crtc; 366 1.3 riastrad int ret; 367 1.1 riastrad 368 1.1 riastrad ldu = kzalloc(sizeof(*ldu), GFP_KERNEL); 369 1.1 riastrad if (!ldu) 370 1.1 riastrad return -ENOMEM; 371 1.1 riastrad 372 1.1 riastrad ldu->base.unit = unit; 373 1.1 riastrad crtc = &ldu->base.crtc; 374 1.1 riastrad encoder = &ldu->base.encoder; 375 1.1 riastrad connector = &ldu->base.connector; 376 1.3 riastrad primary = &ldu->base.primary; 377 1.3 riastrad cursor = &ldu->base.cursor; 378 1.1 riastrad 379 1.1 riastrad INIT_LIST_HEAD(&ldu->active); 380 1.1 riastrad 381 1.1 riastrad ldu->base.pref_active = (unit == 0); 382 1.1 riastrad ldu->base.pref_width = dev_priv->initial_width; 383 1.1 riastrad ldu->base.pref_height = dev_priv->initial_height; 384 1.1 riastrad ldu->base.pref_mode = NULL; 385 1.3 riastrad 386 1.3 riastrad /* 387 1.3 riastrad * Remove this after enabling atomic because property values can 388 1.3 riastrad * only exist in a state object 389 1.3 riastrad */ 390 1.1 riastrad ldu->base.is_implicit = true; 391 1.1 riastrad 392 1.3 riastrad /* Initialize primary plane */ 393 1.3 riastrad vmw_du_plane_reset(primary); 394 1.3 riastrad 395 1.3 riastrad ret = drm_universal_plane_init(dev, &ldu->base.primary, 396 1.3 riastrad 0, &vmw_ldu_plane_funcs, 397 1.3 riastrad vmw_primary_plane_formats, 398 1.3 riastrad ARRAY_SIZE(vmw_primary_plane_formats), 399 1.3 riastrad NULL, DRM_PLANE_TYPE_PRIMARY, NULL); 400 1.3 riastrad if (ret) { 401 1.3 riastrad DRM_ERROR("Failed to initialize primary plane"); 402 1.3 riastrad goto err_free; 403 1.3 riastrad } 404 1.3 riastrad 405 1.3 riastrad drm_plane_helper_add(primary, &vmw_ldu_primary_plane_helper_funcs); 406 1.3 riastrad 407 1.3 riastrad /* Initialize cursor plane */ 408 1.3 riastrad vmw_du_plane_reset(cursor); 409 1.3 riastrad 410 1.3 riastrad ret = drm_universal_plane_init(dev, &ldu->base.cursor, 411 1.3 riastrad 0, &vmw_ldu_cursor_funcs, 412 1.3 riastrad vmw_cursor_plane_formats, 413 1.3 riastrad ARRAY_SIZE(vmw_cursor_plane_formats), 414 1.3 riastrad NULL, DRM_PLANE_TYPE_CURSOR, NULL); 415 1.3 riastrad if (ret) { 416 1.3 riastrad DRM_ERROR("Failed to initialize cursor plane"); 417 1.3 riastrad drm_plane_cleanup(&ldu->base.primary); 418 1.3 riastrad goto err_free; 419 1.3 riastrad } 420 1.3 riastrad 421 1.3 riastrad drm_plane_helper_add(cursor, &vmw_ldu_cursor_plane_helper_funcs); 422 1.3 riastrad 423 1.3 riastrad vmw_du_connector_reset(connector); 424 1.3 riastrad ret = drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, 425 1.3 riastrad DRM_MODE_CONNECTOR_VIRTUAL); 426 1.3 riastrad if (ret) { 427 1.3 riastrad DRM_ERROR("Failed to initialize connector\n"); 428 1.3 riastrad goto err_free; 429 1.3 riastrad } 430 1.3 riastrad 431 1.3 riastrad drm_connector_helper_add(connector, &vmw_ldu_connector_helper_funcs); 432 1.1 riastrad connector->status = vmw_du_connector_detect(connector, true); 433 1.1 riastrad 434 1.3 riastrad ret = drm_encoder_init(dev, encoder, &vmw_legacy_encoder_funcs, 435 1.3 riastrad DRM_MODE_ENCODER_VIRTUAL, NULL); 436 1.3 riastrad if (ret) { 437 1.3 riastrad DRM_ERROR("Failed to initialize encoder\n"); 438 1.3 riastrad goto err_free_connector; 439 1.3 riastrad } 440 1.3 riastrad 441 1.3 riastrad (void) drm_connector_attach_encoder(connector, encoder); 442 1.1 riastrad encoder->possible_crtcs = (1 << unit); 443 1.1 riastrad encoder->possible_clones = 0; 444 1.1 riastrad 445 1.3 riastrad ret = drm_connector_register(connector); 446 1.3 riastrad if (ret) { 447 1.3 riastrad DRM_ERROR("Failed to register connector\n"); 448 1.3 riastrad goto err_free_encoder; 449 1.3 riastrad } 450 1.3 riastrad 451 1.3 riastrad vmw_du_crtc_reset(crtc); 452 1.3 riastrad ret = drm_crtc_init_with_planes(dev, crtc, &ldu->base.primary, 453 1.3 riastrad &ldu->base.cursor, 454 1.3 riastrad &vmw_legacy_crtc_funcs, NULL); 455 1.3 riastrad if (ret) { 456 1.3 riastrad DRM_ERROR("Failed to initialize CRTC\n"); 457 1.3 riastrad goto err_free_unregister; 458 1.3 riastrad } 459 1.2 riastrad 460 1.3 riastrad drm_crtc_helper_add(crtc, &vmw_ldu_crtc_helper_funcs); 461 1.1 riastrad 462 1.1 riastrad drm_mode_crtc_set_gamma_size(crtc, 256); 463 1.1 riastrad 464 1.1 riastrad drm_object_attach_property(&connector->base, 465 1.3 riastrad dev_priv->hotplug_mode_update_property, 1); 466 1.3 riastrad drm_object_attach_property(&connector->base, 467 1.3 riastrad dev->mode_config.suggested_x_property, 0); 468 1.3 riastrad drm_object_attach_property(&connector->base, 469 1.3 riastrad dev->mode_config.suggested_y_property, 0); 470 1.3 riastrad if (dev_priv->implicit_placement_property) 471 1.3 riastrad drm_object_attach_property 472 1.3 riastrad (&connector->base, 473 1.3 riastrad dev_priv->implicit_placement_property, 474 1.3 riastrad 1); 475 1.1 riastrad 476 1.1 riastrad return 0; 477 1.3 riastrad 478 1.3 riastrad err_free_unregister: 479 1.3 riastrad drm_connector_unregister(connector); 480 1.3 riastrad err_free_encoder: 481 1.3 riastrad drm_encoder_cleanup(encoder); 482 1.3 riastrad err_free_connector: 483 1.3 riastrad drm_connector_cleanup(connector); 484 1.3 riastrad err_free: 485 1.3 riastrad kfree(ldu); 486 1.3 riastrad return ret; 487 1.1 riastrad } 488 1.1 riastrad 489 1.2 riastrad int vmw_kms_ldu_init_display(struct vmw_private *dev_priv) 490 1.1 riastrad { 491 1.1 riastrad struct drm_device *dev = dev_priv->dev; 492 1.1 riastrad int i, ret; 493 1.1 riastrad 494 1.1 riastrad if (dev_priv->ldu_priv) { 495 1.1 riastrad DRM_INFO("ldu system already on\n"); 496 1.1 riastrad return -EINVAL; 497 1.1 riastrad } 498 1.1 riastrad 499 1.1 riastrad dev_priv->ldu_priv = kmalloc(sizeof(*dev_priv->ldu_priv), GFP_KERNEL); 500 1.1 riastrad if (!dev_priv->ldu_priv) 501 1.1 riastrad return -ENOMEM; 502 1.1 riastrad 503 1.1 riastrad INIT_LIST_HEAD(&dev_priv->ldu_priv->active); 504 1.1 riastrad dev_priv->ldu_priv->num_active = 0; 505 1.1 riastrad dev_priv->ldu_priv->last_num_active = 0; 506 1.1 riastrad dev_priv->ldu_priv->fb = NULL; 507 1.1 riastrad 508 1.1 riastrad /* for old hardware without multimon only enable one display */ 509 1.1 riastrad if (dev_priv->capabilities & SVGA_CAP_MULTIMON) 510 1.1 riastrad ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS); 511 1.1 riastrad else 512 1.1 riastrad ret = drm_vblank_init(dev, 1); 513 1.1 riastrad if (ret != 0) 514 1.1 riastrad goto err_free; 515 1.1 riastrad 516 1.3 riastrad vmw_kms_create_implicit_placement_property(dev_priv); 517 1.1 riastrad 518 1.1 riastrad if (dev_priv->capabilities & SVGA_CAP_MULTIMON) 519 1.1 riastrad for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) 520 1.1 riastrad vmw_ldu_init(dev_priv, i); 521 1.1 riastrad else 522 1.1 riastrad vmw_ldu_init(dev_priv, 0); 523 1.1 riastrad 524 1.2 riastrad dev_priv->active_display_unit = vmw_du_legacy; 525 1.2 riastrad 526 1.2 riastrad DRM_INFO("Legacy Display Unit initialized\n"); 527 1.2 riastrad 528 1.1 riastrad return 0; 529 1.1 riastrad 530 1.1 riastrad err_free: 531 1.1 riastrad kfree(dev_priv->ldu_priv); 532 1.1 riastrad dev_priv->ldu_priv = NULL; 533 1.1 riastrad return ret; 534 1.1 riastrad } 535 1.1 riastrad 536 1.2 riastrad int vmw_kms_ldu_close_display(struct vmw_private *dev_priv) 537 1.1 riastrad { 538 1.1 riastrad if (!dev_priv->ldu_priv) 539 1.1 riastrad return -ENOSYS; 540 1.1 riastrad 541 1.1 riastrad BUG_ON(!list_empty(&dev_priv->ldu_priv->active)); 542 1.1 riastrad 543 1.1 riastrad kfree(dev_priv->ldu_priv); 544 1.1 riastrad 545 1.1 riastrad return 0; 546 1.1 riastrad } 547 1.2 riastrad 548 1.2 riastrad 549 1.3 riastrad int vmw_kms_ldu_do_bo_dirty(struct vmw_private *dev_priv, 550 1.3 riastrad struct vmw_framebuffer *framebuffer, 551 1.3 riastrad unsigned int flags, unsigned int color, 552 1.3 riastrad struct drm_clip_rect *clips, 553 1.3 riastrad unsigned int num_clips, int increment) 554 1.2 riastrad { 555 1.2 riastrad size_t fifo_size; 556 1.2 riastrad int i; 557 1.2 riastrad 558 1.2 riastrad struct { 559 1.2 riastrad uint32_t header; 560 1.2 riastrad SVGAFifoCmdUpdate body; 561 1.2 riastrad } *cmd; 562 1.2 riastrad 563 1.2 riastrad fifo_size = sizeof(*cmd) * num_clips; 564 1.3 riastrad cmd = VMW_FIFO_RESERVE(dev_priv, fifo_size); 565 1.3 riastrad if (unlikely(cmd == NULL)) 566 1.2 riastrad return -ENOMEM; 567 1.2 riastrad 568 1.2 riastrad memset(cmd, 0, fifo_size); 569 1.2 riastrad for (i = 0; i < num_clips; i++, clips += increment) { 570 1.2 riastrad cmd[i].header = SVGA_CMD_UPDATE; 571 1.2 riastrad cmd[i].body.x = clips->x1; 572 1.2 riastrad cmd[i].body.y = clips->y1; 573 1.2 riastrad cmd[i].body.width = clips->x2 - clips->x1; 574 1.2 riastrad cmd[i].body.height = clips->y2 - clips->y1; 575 1.2 riastrad } 576 1.2 riastrad 577 1.2 riastrad vmw_fifo_commit(dev_priv, fifo_size); 578 1.2 riastrad return 0; 579 1.2 riastrad } 580