1/* 2 * Copyright 2008 Red Hat, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * on the rights to use, copy, modify, merge, publish, distribute, sub 8 * license, and/or sell copies of the Software, and to permit persons to whom 9 * the Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 */ 22 23/* code to handle UMS modesetting */ 24 25#ifdef HAVE_CONFIG_H 26#include <config.h> 27#endif 28#include "qxl.h" 29 30/* These constants govern which modes are reported to X as preferred */ 31#define DEFAULT_WIDTH 1024 32#define DEFAULT_HEIGHT 768 33 34static void qxl_update_monitors_config (qxl_screen_t *qxl); 35 36static DisplayModePtr 37screen_create_mode (ScrnInfoPtr pScrn, int width, int height, int type) 38{ 39 DisplayModePtr mode; 40 41 mode = xnfcalloc (1, sizeof (DisplayModeRec)); 42 43 mode->status = MODE_OK; 44 mode->type = type; 45 mode->HDisplay = width; 46 mode->HSyncStart = (width * 105 / 100 + 7) & ~7; 47 mode->HSyncEnd = (width * 115 / 100 + 7) & ~7; 48 mode->HTotal = (width * 130 / 100 + 7) & ~7; 49 mode->VDisplay = height; 50 mode->VSyncStart = height + 1; 51 mode->VSyncEnd = height + 4; 52 mode->VTotal = height * 1035 / 1000; 53 mode->Clock = mode->HTotal * mode->VTotal * 60 / 1000; 54 mode->Flags = V_NHSYNC | V_PVSYNC; 55 56 xf86SetModeDefaultName (mode); 57 xf86SetModeCrtc (mode, pScrn->adjustFlags); /* needed? xf86-video-modesetting does this */ 58 59 return mode; 60} 61 62static DisplayModePtr 63qxl_add_mode (qxl_screen_t *qxl, ScrnInfoPtr pScrn, int width, int height, int type) 64{ 65 DisplayModePtr mode; 66 67 mode = screen_create_mode (pScrn, width, height, type); 68 pScrn->modes = qxl->x_modes = xf86ModesAdd (qxl->x_modes, mode); 69 70 return mode; 71} 72 73static int 74check_crtc (qxl_screen_t *qxl) 75{ 76 int i, count = 0; 77 xf86CrtcPtr crtc; 78 79 if (qxl->crtcs == NULL) { 80 return 0; 81 } 82 83 for (i = 0 ; i < qxl->num_heads; ++i) 84 { 85 crtc = qxl->crtcs[i]; 86 87 if (!crtc->enabled || crtc->mode.CrtcHDisplay == 0 || 88 crtc->mode.CrtcVDisplay == 0) 89 { 90 continue; 91 } 92 count++; 93 } 94 95#if 0 96 if (count == 0) 97 { 98 ErrorF ("check crtc failed, count == 0!!\n"); 99 BREAKPOINT (); 100 } 101#endif 102 103 return count; 104} 105 106static void 107qxl_update_monitors_config (qxl_screen_t *qxl) 108{ 109 int i; 110 QXLHead *head; 111 xf86CrtcPtr crtc; 112 qxl_output_private *qxl_output; 113 QXLRam * ram = get_ram_header (qxl); 114 115 if (check_crtc (qxl) == 0) 116 return; 117 118 qxl->monitors_config->count = 0; 119 qxl->monitors_config->max_allowed = qxl->num_heads; 120 for (i = 0 ; i < qxl->num_heads; ++i) 121 { 122 head = &qxl->monitors_config->heads[qxl->monitors_config->count]; 123 crtc = qxl->crtcs[i]; 124 qxl_output = qxl->outputs[i]->driver_private; 125 head->id = i; 126 head->surface_id = 0; 127 head->flags = 0; 128 129 if (!crtc->enabled || crtc->mode.CrtcHDisplay == 0 || 130 crtc->mode.CrtcVDisplay == 0) 131 { 132 head->width = head->height = head->x = head->y = 0; 133 qxl_output->status = XF86OutputStatusDisconnected; 134 } 135 else 136 { 137 head->width = crtc->mode.CrtcHDisplay; 138 head->height = crtc->mode.CrtcVDisplay; 139 head->x = crtc->x; 140 head->y = crtc->y; 141 qxl->monitors_config->count++; 142 qxl_output->status = XF86OutputStatusConnected; 143 } 144 } 145 /* initialize when actually used, memslots should be initialized by now */ 146 if (ram->monitors_config == 0) 147 { 148 ram->monitors_config = physical_address (qxl, qxl->monitors_config, 149 qxl->main_mem_slot); 150 } 151 152 qxl_io_monitors_config_async (qxl); 153} 154 155static Bool 156crtc_set_mode_major (xf86CrtcPtr crtc, DisplayModePtr mode, 157 Rotation rotation, int x, int y) 158{ 159 qxl_crtc_private *crtc_private = crtc->driver_private; 160 qxl_screen_t * qxl = crtc_private->qxl; 161 162 if (crtc == qxl->crtcs[0] && mode == NULL) 163 { 164 /* disallow disabling of monitor 0 mode */ 165 ErrorF ("%s: not allowing crtc 0 disablement\n", __func__); 166 return FALSE; 167 } 168 169 crtc->mode = *mode; 170 crtc->x = x; 171 crtc->y = y; 172 crtc->rotation = rotation; 173#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC (1, 5, 99, 0, 0) 174 crtc->transformPresent = FALSE; 175#endif 176 /* TODO set EDID here */ 177 return TRUE; 178} 179 180Bool 181qxl_create_desired_modes (qxl_screen_t *qxl) 182{ 183 int i; 184 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR (qxl->pScrn); 185 186 CHECK_POINT (); 187 188 for (i = 0 ; i < config->num_crtc; ++i) 189 { 190 xf86CrtcPtr crtc = config->crtc[i]; 191 if (!crtc->enabled) 192 continue; 193 194 if (!crtc_set_mode_major ( 195 crtc, &crtc->desiredMode, crtc->desiredRotation, 196 crtc->desiredX, crtc->desiredY)) 197 { 198 return FALSE; 199 } 200 } 201 202 qxl_update_monitors_config(qxl); 203 return TRUE; 204} 205 206void 207qxl_update_edid (qxl_screen_t *qxl) 208{ 209 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR (qxl->pScrn); 210 int i; 211 212 for (i = 0; i < config->num_crtc; ++i) 213 { 214 xf86CrtcPtr crtc = config->crtc[i]; 215 216 if (!crtc->enabled) 217 continue; 218 219 /* TODO set EDID here */ 220 } 221} 222 223 224static DisplayModePtr 225qxl_output_get_modes (xf86OutputPtr output) 226{ 227 qxl_output_private *qxl_output = output->driver_private; 228 DisplayModePtr modes = xf86DuplicateModes (qxl_output->qxl->pScrn, qxl_output->qxl->x_modes); 229 230 /* xf86ProbeOutputModes owns this memory */ 231 return modes; 232} 233 234static void 235qxl_output_destroy (xf86OutputPtr output) 236{ 237 qxl_output_private *qxl_output = output->driver_private; 238 239 xf86DrvMsg (qxl_output->qxl->pScrn->scrnIndex, X_INFO, 240 "%s", __func__); 241} 242 243static void 244qxl_output_dpms (xf86OutputPtr output, int mode) 245{ 246} 247 248static void 249qxl_output_create_resources (xf86OutputPtr output) 250{ 251} 252 253static Bool 254qxl_output_set_property (xf86OutputPtr output, Atom property, 255 RRPropertyValuePtr value) 256{ 257 /* EDID data is stored in the "EDID" atom property, we must return 258 * TRUE here for that. No penalty to say ok to everything else. */ 259 return TRUE; 260} 261 262static Bool 263qxl_output_get_property (xf86OutputPtr output, Atom property) 264{ 265 return TRUE; 266} 267 268static xf86OutputStatus 269qxl_output_detect (xf86OutputPtr output) 270{ 271 qxl_output_private *qxl_output = output->driver_private; 272 273 return qxl_output->status; 274} 275 276static Bool 277qxl_output_mode_valid (xf86OutputPtr output, DisplayModePtr pModes) 278{ 279 return MODE_OK; 280} 281 282static const xf86OutputFuncsRec qxl_output_funcs = { 283 .dpms = qxl_output_dpms, 284 .create_resources = qxl_output_create_resources, 285#ifdef RANDR_12_INTERFACE 286 .set_property = qxl_output_set_property, 287 .get_property = qxl_output_get_property, 288#endif 289 .detect = qxl_output_detect, 290 .mode_valid = qxl_output_mode_valid, 291 292 .get_modes = qxl_output_get_modes, 293 .destroy = qxl_output_destroy 294}; 295 296 297static void 298qxl_crtc_dpms (xf86CrtcPtr crtc, int mode) 299{ 300} 301 302static Bool 303qxl_crtc_set_mode_major (xf86CrtcPtr crtc, DisplayModePtr mode, 304 Rotation rotation, int x, int y) 305{ 306 qxl_crtc_private *crtc_private = crtc->driver_private; 307 qxl_screen_t * qxl = crtc_private->qxl; 308 309 CHECK_POINT (); 310 311 if (!crtc_set_mode_major (crtc, mode, rotation, x, y)) 312 return FALSE; 313 314 qxl_update_monitors_config (qxl); 315 316 return TRUE; 317} 318 319static void 320qxl_crtc_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg) 321{ 322} 323 324static void 325qxl_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y) 326{ 327} 328 329static void 330qxl_crtc_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image) 331{ 332} 333 334static void 335qxl_crtc_hide_cursor (xf86CrtcPtr crtc) 336{ 337} 338 339static void 340qxl_crtc_show_cursor (xf86CrtcPtr crtc) 341{ 342} 343 344static void 345qxl_crtc_gamma_set (xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, 346 uint16_t *blue, int size) 347{ 348} 349 350static void 351qxl_crtc_destroy (xf86CrtcPtr crtc) 352{ 353 qxl_crtc_private *crtc_private = crtc->driver_private; 354 qxl_screen_t * qxl = crtc_private->qxl; 355 356 xf86DrvMsg (qxl->pScrn->scrnIndex, X_INFO, "%s\n", __func__); 357} 358 359static Bool 360qxl_crtc_lock (xf86CrtcPtr crtc) 361{ 362 qxl_crtc_private *crtc_private = crtc->driver_private; 363 qxl_screen_t * qxl = crtc_private->qxl; 364 365 xf86DrvMsg (qxl->pScrn->scrnIndex, X_INFO, "%s\n", __func__); 366 return TRUE; 367} 368 369static void 370qxl_crtc_unlock (xf86CrtcPtr crtc) 371{ 372 qxl_crtc_private *crtc_private = crtc->driver_private; 373 qxl_screen_t * qxl = crtc_private->qxl; 374 375 xf86DrvMsg (qxl->pScrn->scrnIndex, X_INFO, "%s\n", __func__); 376 qxl_update_monitors_config (qxl); 377} 378 379static const xf86CrtcFuncsRec qxl_crtc_funcs = { 380 .dpms = qxl_crtc_dpms, 381 .set_mode_major = qxl_crtc_set_mode_major, 382 .set_cursor_colors = qxl_crtc_set_cursor_colors, 383 .set_cursor_position = qxl_crtc_set_cursor_position, 384 .show_cursor = qxl_crtc_show_cursor, 385 .hide_cursor = qxl_crtc_hide_cursor, 386 .load_cursor_argb = qxl_crtc_load_cursor_argb, 387 .lock = qxl_crtc_lock, 388 .unlock = qxl_crtc_unlock, 389 390 .gamma_set = qxl_crtc_gamma_set, 391 .destroy = qxl_crtc_destroy, 392}; 393 394 395static Bool 396qxl_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height) 397{ 398 qxl_screen_t *qxl = scrn->driverPrivate; 399 400 xf86DrvMsg (scrn->scrnIndex, X_INFO, "%s: Placeholder resize %dx%d\n", 401 __func__, width, height); 402 if (!qxl_resize_primary (qxl, width, height)) 403 return FALSE; 404 405 scrn->virtualX = width; 406 scrn->virtualY = height; 407 408 // when starting, no monitor is enabled, and count == 0 409 // we want to avoid server/client freaking out with temporary config 410 qxl_update_monitors_config (qxl); 411 412 return TRUE; 413} 414 415static const xf86CrtcConfigFuncsRec qxl_xf86crtc_config_funcs = { 416 qxl_xf86crtc_resize 417}; 418 419void 420qxl_initialize_x_modes (qxl_screen_t *qxl, ScrnInfoPtr pScrn, 421 unsigned int *max_x, unsigned int *max_y) 422{ 423 int i; 424 int size; 425 int preferred_flag; 426 427 *max_x = *max_y = 0; 428 /* Create a list of modes used by the qxl_output_get_modes */ 429 for (i = 0; i < qxl->num_modes; i++) 430 { 431 if (qxl->modes[i].orientation == 0) 432 { 433 size = qxl->modes[i].y_res * qxl->modes[i].stride; 434 if (size > qxl->surface0_size) 435 { 436 ErrorF ("skipping mode %dx%d not fitting in surface0\n", 437 qxl->modes[i].x_res, qxl->modes[i].y_res); 438 continue; 439 } 440 441 if (qxl->modes[i].x_res == DEFAULT_WIDTH && qxl->modes[i].y_res == DEFAULT_HEIGHT) 442 preferred_flag = M_T_PREFERRED; 443 else 444 preferred_flag = 0; 445 446 qxl_add_mode (qxl, pScrn, qxl->modes[i].x_res, qxl->modes[i].y_res, 447 M_T_DRIVER | preferred_flag); 448 449 if (qxl->modes[i].x_res > *max_x) 450 *max_x = qxl->modes[i].x_res; 451 if (qxl->modes[i].y_res > *max_y) 452 *max_y = qxl->modes[i].y_res; 453 } 454 } 455} 456 457void 458qxl_init_randr (ScrnInfoPtr pScrn, qxl_screen_t *qxl) 459{ 460 char name[32]; 461 qxl_output_private *qxl_output; 462 qxl_crtc_private * qxl_crtc; 463 int i; 464 xf86OutputPtr output; 465 466 xf86CrtcConfigInit (pScrn, &qxl_xf86crtc_config_funcs); 467 468 /* CHECKME: This is actually redundant, it's overwritten by a later call via 469 * xf86InitialConfiguration */ 470 xf86CrtcSetSizeRange (pScrn, 320, 200, 8192, 8192); 471 472 qxl->crtcs = xnfcalloc (sizeof (xf86CrtcPtr), qxl->num_heads); 473 qxl->outputs = xnfcalloc (sizeof (xf86OutputPtr), qxl->num_heads); 474 475 for (i = 0 ; i < qxl->num_heads; ++i) 476 { 477 qxl->crtcs[i] = xf86CrtcCreate (pScrn, &qxl_crtc_funcs); 478 if (!qxl->crtcs[i]) 479 xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "failed to create Crtc %d", i); 480 481 qxl_crtc = xnfcalloc (sizeof (qxl_crtc_private), 1); 482 qxl->crtcs[i]->driver_private = qxl_crtc; 483 qxl_crtc->head = i; 484 qxl_crtc->qxl = qxl; 485 snprintf (name, sizeof (name), "qxl-%d", i); 486 qxl->outputs[i] = output = xf86OutputCreate (pScrn, &qxl_output_funcs, name); 487 if (!output) 488 xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "failed to create Output %d", i); 489 490 output->possible_crtcs = (1 << i); /* bitrange of allowed outputs - do a 1:1 */ 491 output->possible_clones = 0; /* TODO: not? */ 492 qxl_output = xnfcalloc (sizeof (qxl_output_private), 1); 493 output->driver_private = qxl_output; 494 qxl_output->head = i; 495 qxl_output->qxl = qxl; 496 qxl_output->status = i ? XF86OutputStatusDisconnected : XF86OutputStatusConnected; 497 qxl_crtc->output = output; 498 } 499 500 xf86InitialConfiguration (pScrn, TRUE); 501 502 qxl->virtual_x = pScrn->virtualX; 503 qxl->virtual_y = pScrn->virtualY; 504 /* all crtcs are enabled here, but their mode is 0, 505 resulting monitor config empty atm */ 506} 507