1 /* 2 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. 3 * All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sub license, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the 14 * next paragraph) shall be included in all copies or substantial portions 15 * of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 20 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 * 25 * 26 * Author: Alan Hourihane <alanh (at) tungstengraphics.com> 27 * Author: Jakob Bornecrantz <wallbraker (at) gmail.com> 28 * 29 */ 30 31 #include <unistd.h> 32 #include <string.h> 33 #include <assert.h> 34 #include <stdlib.h> 35 #include <math.h> 36 #include <stdint.h> 37 38 #include "xorg-server.h" 39 #include <xf86.h> 40 #include <xf86i2c.h> 41 #include <xf86Crtc.h> 42 #include <cursorstr.h> 43 #include "xorg_tracker.h" 44 #include "xf86Modes.h" 45 46 #ifdef HAVE_XEXTPROTO_71 47 #include <X11/extensions/dpmsconst.h> 48 #else 49 #define DPMS_SERVER 50 #include <X11/extensions/dpms.h> 51 #endif 52 53 #include "state_tracker/drm_driver.h" 54 #include "util/u_inlines.h" 55 #include "util/u_rect.h" 56 57 #ifdef HAVE_LIBKMS 58 #include "libkms/libkms.h" 59 #endif 60 61 struct crtc_private 62 { 63 drmModeCrtcPtr drm_crtc; 64 65 /* hwcursor */ 66 struct pipe_resource *cursor_tex; 67 struct kms_bo *cursor_bo; 68 69 unsigned cursor_handle; 70 }; 71 72 static void 73 crtc_dpms(xf86CrtcPtr crtc, int mode) 74 { 75 /* ScrnInfoPtr pScrn = crtc->scrn; */ 76 77 switch (mode) { 78 case DPMSModeOn: 79 case DPMSModeStandby: 80 case DPMSModeSuspend: 81 break; 82 case DPMSModeOff: 83 break; 84 } 85 } 86 87 static Bool 88 crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, 89 Rotation rotation, int x, int y) 90 { 91 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 92 modesettingPtr ms = modesettingPTR(crtc->scrn); 93 xf86OutputPtr output = NULL; 94 struct crtc_private *crtcp = crtc->driver_private; 95 drmModeCrtcPtr drm_crtc = crtcp->drm_crtc; 96 drmModeModeInfo drm_mode; 97 int i, ret; 98 unsigned int connector_id; 99 100 for (i = 0; i < config->num_output; output = NULL, i++) { 101 output = config->output[i]; 102 103 if (output->crtc == crtc) 104 break; 105 } 106 107 if (!output) 108 return FALSE; 109 110 connector_id = xorg_output_get_id(output); 111 112 drm_mode.clock = mode->Clock; 113 drm_mode.hdisplay = mode->HDisplay; 114 drm_mode.hsync_start = mode->HSyncStart; 115 drm_mode.hsync_end = mode->HSyncEnd; 116 drm_mode.htotal = mode->HTotal; 117 drm_mode.vdisplay = mode->VDisplay; 118 drm_mode.vsync_start = mode->VSyncStart; 119 drm_mode.vsync_end = mode->VSyncEnd; 120 drm_mode.vtotal = mode->VTotal; 121 drm_mode.flags = mode->Flags; 122 drm_mode.hskew = mode->HSkew; 123 drm_mode.vscan = mode->VScan; 124 drm_mode.vrefresh = mode->VRefresh; 125 drm_mode.type = 0; 126 if (!mode->name) 127 xf86SetModeDefaultName(mode); 128 strncpy(drm_mode.name, mode->name, DRM_DISPLAY_MODE_LEN - 1); 129 drm_mode.name[DRM_DISPLAY_MODE_LEN - 1] = '\0'; 130 131 ret = drmModeSetCrtc(ms->fd, drm_crtc->crtc_id, ms->fb_id, x, y, 132 &connector_id, 1, &drm_mode); 133 134 if (ret) 135 return FALSE; 136 137 /* Only set gamma when needed, to avoid unneeded delays. */ 138 #if defined(XF86_CRTC_VERSION) && XF86_CRTC_VERSION >= 3 139 if (!crtc->active && crtc->version >= 3) 140 crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, 141 crtc->gamma_blue, crtc->gamma_size); 142 crtc->active = TRUE; 143 #endif 144 145 crtc->x = x; 146 crtc->y = y; 147 crtc->mode = *mode; 148 crtc->rotation = rotation; 149 150 return TRUE; 151 } 152 153 static void 154 crtc_gamma_set(xf86CrtcPtr crtc, CARD16 * red, CARD16 * green, CARD16 * blue, 155 int size) 156 { 157 modesettingPtr ms = modesettingPTR(crtc->scrn); 158 struct crtc_private *crtcp = crtc->driver_private; 159 160 drmModeCrtcSetGamma(ms->fd, crtcp->drm_crtc->crtc_id, size, red, green, blue); 161 } 162 163 #if 0 /* Implement and enable to enable rotation and reflection. */ 164 static void * 165 crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) 166 { 167 /* ScrnInfoPtr pScrn = crtc->scrn; */ 168 169 return NULL; 170 } 171 172 static PixmapPtr 173 crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) 174 { 175 /* ScrnInfoPtr pScrn = crtc->scrn; */ 176 177 return NULL; 178 } 179 180 static void 181 crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) 182 { 183 /* ScrnInfoPtr pScrn = crtc->scrn; */ 184 } 185 186 #endif 187 188 /* 189 * Cursor functions 190 */ 191 192 static void 193 crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg) 194 { 195 /* XXX: See if this one is needed, as we only support ARGB cursors */ 196 } 197 198 static void 199 crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y) 200 { 201 modesettingPtr ms = modesettingPTR(crtc->scrn); 202 struct crtc_private *crtcp = crtc->driver_private; 203 204 drmModeMoveCursor(ms->fd, crtcp->drm_crtc->crtc_id, x, y); 205 } 206 207 static void 208 crtc_load_cursor_argb_ga3d(xf86CrtcPtr crtc, CARD32 * image) 209 { 210 unsigned char *ptr; 211 modesettingPtr ms = modesettingPTR(crtc->scrn); 212 struct crtc_private *crtcp = crtc->driver_private; 213 struct pipe_transfer *transfer; 214 struct pipe_fence_handle *fence = NULL; 215 struct pipe_context *ctx = ms->ctx; 216 struct pipe_screen *screen = ms->screen; 217 218 if (!crtcp->cursor_tex) { 219 struct pipe_resource templat; 220 struct winsys_handle whandle; 221 222 memset(&templat, 0, sizeof(templat)); 223 templat.bind |= PIPE_BIND_RENDER_TARGET; 224 templat.bind |= PIPE_BIND_SCANOUT; 225 templat.bind |= PIPE_BIND_CURSOR; 226 templat.target = PIPE_TEXTURE_2D; 227 templat.last_level = 0; 228 templat.depth0 = 1; 229 templat.array_size = 1; 230 templat.format = PIPE_FORMAT_B8G8R8A8_UNORM; 231 templat.width0 = 64; 232 templat.height0 = 64; 233 234 memset(&whandle, 0, sizeof(whandle)); 235 whandle.type = DRM_API_HANDLE_TYPE_KMS; 236 237 crtcp->cursor_tex = screen->resource_create(screen, &templat); 238 screen->resource_get_handle(screen, crtcp->cursor_tex, &whandle); 239 240 crtcp->cursor_handle = whandle.handle; 241 } 242 243 transfer = pipe_get_transfer(ctx, crtcp->cursor_tex, 244 0, 0, 245 PIPE_TRANSFER_WRITE, 246 0, 0, 64, 64); 247 ptr = ctx->transfer_map(ctx, transfer); 248 util_copy_rect(ptr, crtcp->cursor_tex->format, 249 transfer->stride, 0, 0, 250 64, 64, (void*)image, 64 * 4, 0, 0); 251 ctx->transfer_unmap(ctx, transfer); 252 ctx->transfer_destroy(ctx, transfer); 253 ctx->flush(ctx, &fence); 254 255 if (fence) { 256 screen->fence_finish(screen, fence, PIPE_TIMEOUT_INFINITE); 257 screen->fence_reference(screen, &fence, NULL); 258 } 259 260 if (crtc->cursor_shown) 261 drmModeSetCursor(ms->fd, crtcp->drm_crtc->crtc_id, 262 crtcp->cursor_handle, 64, 64); 263 } 264 265 #if HAVE_LIBKMS 266 static void 267 crtc_load_cursor_argb_kms(xf86CrtcPtr crtc, CARD32 * image) 268 { 269 modesettingPtr ms = modesettingPTR(crtc->scrn); 270 struct crtc_private *crtcp = crtc->driver_private; 271 unsigned char *ptr; 272 273 if (!crtcp->cursor_bo) { 274 unsigned attr[8]; 275 276 attr[0] = KMS_BO_TYPE; 277 #ifdef KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8 278 attr[1] = KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8; 279 #else 280 attr[1] = KMS_BO_TYPE_CURSOR; 281 #endif 282 attr[2] = KMS_WIDTH; 283 attr[3] = 64; 284 attr[4] = KMS_HEIGHT; 285 attr[5] = 64; 286 attr[6] = 0; 287 288 if (kms_bo_create(ms->kms, attr, &crtcp->cursor_bo)) 289 return; 290 291 if (kms_bo_get_prop(crtcp->cursor_bo, KMS_HANDLE, 292 &crtcp->cursor_handle)) 293 goto err_bo_destroy; 294 } 295 296 kms_bo_map(crtcp->cursor_bo, (void**)&ptr); 297 memcpy(ptr, image, 64*64*4); 298 kms_bo_unmap(crtcp->cursor_bo); 299 300 if (crtc->cursor_shown) 301 drmModeSetCursor(ms->fd, crtcp->drm_crtc->crtc_id, 302 crtcp->cursor_handle, 64, 64); 303 304 return; 305 306 err_bo_destroy: 307 kms_bo_destroy(&crtcp->cursor_bo); 308 } 309 #endif 310 311 static void 312 crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 * image) 313 { 314 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 315 modesettingPtr ms = modesettingPTR(crtc->scrn); 316 317 /* Older X servers have cursor reference counting bugs leading to use of 318 * freed memory and consequently random crashes. Should be fixed as of 319 * xserver 1.8, but this workaround shouldn't hurt anyway. 320 */ 321 if (config->cursor) 322 config->cursor->refcnt++; 323 324 if (ms->cursor) 325 FreeCursor(ms->cursor, None); 326 327 ms->cursor = config->cursor; 328 329 if (ms->screen) 330 crtc_load_cursor_argb_ga3d(crtc, image); 331 #ifdef HAVE_LIBKMS 332 else if (ms->kms) 333 crtc_load_cursor_argb_kms(crtc, image); 334 #endif 335 } 336 337 static void 338 crtc_show_cursor(xf86CrtcPtr crtc) 339 { 340 modesettingPtr ms = modesettingPTR(crtc->scrn); 341 struct crtc_private *crtcp = crtc->driver_private; 342 343 if (crtcp->cursor_tex || crtcp->cursor_bo) 344 drmModeSetCursor(ms->fd, crtcp->drm_crtc->crtc_id, 345 crtcp->cursor_handle, 64, 64); 346 } 347 348 static void 349 crtc_hide_cursor(xf86CrtcPtr crtc) 350 { 351 modesettingPtr ms = modesettingPTR(crtc->scrn); 352 struct crtc_private *crtcp = crtc->driver_private; 353 354 drmModeSetCursor(ms->fd, crtcp->drm_crtc->crtc_id, 0, 0, 0); 355 } 356 357 /** 358 * Called at vt leave 359 */ 360 void 361 xorg_crtc_cursor_destroy(xf86CrtcPtr crtc) 362 { 363 struct crtc_private *crtcp = crtc->driver_private; 364 365 if (crtcp->cursor_tex) 366 pipe_resource_reference(&crtcp->cursor_tex, NULL); 367 #ifdef HAVE_LIBKMS 368 if (crtcp->cursor_bo) 369 kms_bo_destroy(&crtcp->cursor_bo); 370 #endif 371 } 372 373 /* 374 * Misc functions 375 */ 376 377 static void 378 crtc_destroy(xf86CrtcPtr crtc) 379 { 380 struct crtc_private *crtcp = crtc->driver_private; 381 382 xorg_crtc_cursor_destroy(crtc); 383 384 drmModeFreeCrtc(crtcp->drm_crtc); 385 386 free(crtcp); 387 crtc->driver_private = NULL; 388 } 389 390 static const xf86CrtcFuncsRec crtc_funcs = { 391 .dpms = crtc_dpms, 392 .set_mode_major = crtc_set_mode_major, 393 394 .set_cursor_colors = crtc_set_cursor_colors, 395 .set_cursor_position = crtc_set_cursor_position, 396 .show_cursor = crtc_show_cursor, 397 .hide_cursor = crtc_hide_cursor, 398 .load_cursor_argb = crtc_load_cursor_argb, 399 400 .shadow_create = NULL, 401 .shadow_allocate = NULL, 402 .shadow_destroy = NULL, 403 404 .gamma_set = crtc_gamma_set, 405 .destroy = crtc_destroy, 406 }; 407 408 void 409 xorg_crtc_init(ScrnInfoPtr pScrn) 410 { 411 modesettingPtr ms = modesettingPTR(pScrn); 412 xf86CrtcPtr crtc; 413 drmModeResPtr res; 414 drmModeCrtcPtr drm_crtc = NULL; 415 struct crtc_private *crtcp; 416 int c; 417 418 res = drmModeGetResources(ms->fd); 419 if (res == 0) { 420 ErrorF("Failed drmModeGetResources %d\n", errno); 421 return; 422 } 423 424 for (c = 0; c < res->count_crtcs; c++) { 425 drm_crtc = drmModeGetCrtc(ms->fd, res->crtcs[c]); 426 427 if (!drm_crtc) 428 continue; 429 430 crtc = xf86CrtcCreate(pScrn, &crtc_funcs); 431 if (crtc == NULL) 432 goto out; 433 434 crtcp = calloc(1, sizeof(struct crtc_private)); 435 if (!crtcp) { 436 xf86CrtcDestroy(crtc); 437 goto out; 438 } 439 440 crtcp->drm_crtc = drm_crtc; 441 442 crtc->driver_private = crtcp; 443 } 444 445 out: 446 drmModeFreeResources(res); 447 } 448 449 /* vim: set sw=4 ts=8 sts=4: */ 450