drmmode_display.c revision 35d5b7c7
1d6c0b56eSmrg/* 2d6c0b56eSmrg * Copyright © 2007 Red Hat, Inc. 3d6c0b56eSmrg * 4d6c0b56eSmrg * Permission is hereby granted, free of charge, to any person obtaining a 5d6c0b56eSmrg * copy of this software and associated documentation files (the "Software"), 6d6c0b56eSmrg * to deal in the Software without restriction, including without limitation 7d6c0b56eSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8d6c0b56eSmrg * and/or sell copies of the Software, and to permit persons to whom the 9d6c0b56eSmrg * Software is furnished to do so, subject to the following conditions: 10d6c0b56eSmrg * 11d6c0b56eSmrg * The above copyright notice and this permission notice (including the next 12d6c0b56eSmrg * paragraph) shall be included in all copies or substantial portions of the 13d6c0b56eSmrg * Software. 14d6c0b56eSmrg * 15d6c0b56eSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16d6c0b56eSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17d6c0b56eSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18d6c0b56eSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19d6c0b56eSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20d6c0b56eSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21d6c0b56eSmrg * SOFTWARE. 22d6c0b56eSmrg * 23d6c0b56eSmrg * Authors: 24d6c0b56eSmrg * Dave Airlie <airlied@redhat.com> 25d6c0b56eSmrg * 26d6c0b56eSmrg */ 27d6c0b56eSmrg 28d6c0b56eSmrg#ifdef HAVE_CONFIG_H 29d6c0b56eSmrg#include "config.h" 30d6c0b56eSmrg#endif 31d6c0b56eSmrg 32d6c0b56eSmrg#include <errno.h> 33d6c0b56eSmrg#include <sys/ioctl.h> 34d6c0b56eSmrg#include <time.h> 35d6c0b56eSmrg#include "cursorstr.h" 36d6c0b56eSmrg#include "damagestr.h" 3724b90cf4Smrg#include "inputstr.h" 3824b90cf4Smrg#include "list.h" 39d6c0b56eSmrg#include "micmap.h" 4035d5b7c7Smrg#include "mipointrst.h" 41d6c0b56eSmrg#include "xf86cmap.h" 42504d986fSmrg#include "xf86Priv.h" 43d6c0b56eSmrg#include "sarea.h" 44d6c0b56eSmrg 45d6c0b56eSmrg#include "drmmode_display.h" 46d6c0b56eSmrg#include "amdgpu_bo_helper.h" 47d6c0b56eSmrg#include "amdgpu_glamor.h" 48d6c0b56eSmrg#include "amdgpu_pixmap.h" 49d6c0b56eSmrg 50d6c0b56eSmrg#include <dri.h> 51d6c0b56eSmrg 52d6c0b56eSmrg/* DPMS */ 53d6c0b56eSmrg#ifdef HAVE_XEXTPROTO_71 54d6c0b56eSmrg#include <X11/extensions/dpmsconst.h> 55d6c0b56eSmrg#else 56d6c0b56eSmrg#define DPMS_SERVER 57d6c0b56eSmrg#include <X11/extensions/dpms.h> 58d6c0b56eSmrg#endif 59d6c0b56eSmrg 60d6c0b56eSmrg#include <gbm.h> 61d6c0b56eSmrg 62d6c0b56eSmrg#define DEFAULT_NOMINAL_FRAME_RATE 60 63d6c0b56eSmrg 64d6c0b56eSmrgstatic Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height); 65d6c0b56eSmrg 66d6c0b56eSmrgstatic Bool 67d6c0b56eSmrgAMDGPUZaphodStringMatches(ScrnInfoPtr pScrn, const char *s, char *output_name) 68d6c0b56eSmrg{ 69d6c0b56eSmrg int i = 0; 70d6c0b56eSmrg char s1[20]; 71d6c0b56eSmrg 72d6c0b56eSmrg do { 73d6c0b56eSmrg switch (*s) { 74d6c0b56eSmrg case ',': 75d6c0b56eSmrg s1[i] = '\0'; 76d6c0b56eSmrg i = 0; 77d6c0b56eSmrg if (strcmp(s1, output_name) == 0) 78d6c0b56eSmrg return TRUE; 79d6c0b56eSmrg break; 80d6c0b56eSmrg case ' ': 81d6c0b56eSmrg case '\t': 82d6c0b56eSmrg case '\n': 83d6c0b56eSmrg case '\r': 84d6c0b56eSmrg break; 85d6c0b56eSmrg default: 86d6c0b56eSmrg s1[i] = *s; 87d6c0b56eSmrg i++; 88d6c0b56eSmrg break; 89d6c0b56eSmrg } 90d6c0b56eSmrg } while (*s++); 91d6c0b56eSmrg 92d6c0b56eSmrg s1[i] = '\0'; 93d6c0b56eSmrg if (strcmp(s1, output_name) == 0) 94d6c0b56eSmrg return TRUE; 95d6c0b56eSmrg 96d6c0b56eSmrg return FALSE; 97d6c0b56eSmrg} 98d6c0b56eSmrg 9924b90cf4Smrg 100d6c0b56eSmrgstatic PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn, 101d6c0b56eSmrg int width, int height, 102d6c0b56eSmrg int depth, int bpp, 103d6c0b56eSmrg int pitch, 104d6c0b56eSmrg struct amdgpu_buffer *bo) 105d6c0b56eSmrg{ 106d6c0b56eSmrg ScreenPtr pScreen = pScrn->pScreen; 107d6c0b56eSmrg PixmapPtr pixmap; 108d6c0b56eSmrg 109d6c0b56eSmrg pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 110d6c0b56eSmrg AMDGPU_CREATE_PIXMAP_SCANOUT); 111d6c0b56eSmrg if (!pixmap) 112d6c0b56eSmrg return NULL; 113d6c0b56eSmrg 114d6c0b56eSmrg if (!(*pScreen->ModifyPixmapHeader) (pixmap, width, height, 115504d986fSmrg depth, bpp, pitch, NULL)) 116504d986fSmrg goto fail; 117d6c0b56eSmrg 118504d986fSmrg if (!amdgpu_glamor_create_textured_pixmap(pixmap, bo)) 119504d986fSmrg goto fail; 120d6c0b56eSmrg 121504d986fSmrg if (amdgpu_set_pixmap_bo(pixmap, bo)) 122504d986fSmrg return pixmap; 123d6c0b56eSmrg 124504d986fSmrgfail: 125504d986fSmrg pScreen->DestroyPixmap(pixmap); 126504d986fSmrg return NULL; 127d6c0b56eSmrg} 128d6c0b56eSmrg 129d6c0b56eSmrgstatic void drmmode_destroy_bo_pixmap(PixmapPtr pixmap) 130d6c0b56eSmrg{ 131d6c0b56eSmrg ScreenPtr pScreen = pixmap->drawable.pScreen; 132d6c0b56eSmrg 133d6c0b56eSmrg (*pScreen->DestroyPixmap) (pixmap); 134d6c0b56eSmrg} 135d6c0b56eSmrg 136d6c0b56eSmrgstatic void 137d6c0b56eSmrgdrmmode_ConvertFromKMode(ScrnInfoPtr scrn, 138d6c0b56eSmrg drmModeModeInfo * kmode, DisplayModePtr mode) 139d6c0b56eSmrg{ 140d6c0b56eSmrg memset(mode, 0, sizeof(DisplayModeRec)); 141d6c0b56eSmrg mode->status = MODE_OK; 142d6c0b56eSmrg 143d6c0b56eSmrg mode->Clock = kmode->clock; 144d6c0b56eSmrg 145d6c0b56eSmrg mode->HDisplay = kmode->hdisplay; 146d6c0b56eSmrg mode->HSyncStart = kmode->hsync_start; 147d6c0b56eSmrg mode->HSyncEnd = kmode->hsync_end; 148d6c0b56eSmrg mode->HTotal = kmode->htotal; 149d6c0b56eSmrg mode->HSkew = kmode->hskew; 150d6c0b56eSmrg 151d6c0b56eSmrg mode->VDisplay = kmode->vdisplay; 152d6c0b56eSmrg mode->VSyncStart = kmode->vsync_start; 153d6c0b56eSmrg mode->VSyncEnd = kmode->vsync_end; 154d6c0b56eSmrg mode->VTotal = kmode->vtotal; 155d6c0b56eSmrg mode->VScan = kmode->vscan; 156d6c0b56eSmrg 157d6c0b56eSmrg mode->Flags = kmode->flags; //& FLAG_BITS; 158d6c0b56eSmrg mode->name = strdup(kmode->name); 159d6c0b56eSmrg 160d6c0b56eSmrg if (kmode->type & DRM_MODE_TYPE_DRIVER) 161d6c0b56eSmrg mode->type = M_T_DRIVER; 162d6c0b56eSmrg if (kmode->type & DRM_MODE_TYPE_PREFERRED) 163d6c0b56eSmrg mode->type |= M_T_PREFERRED; 164d6c0b56eSmrg xf86SetModeCrtc(mode, scrn->adjustFlags); 165d6c0b56eSmrg} 166d6c0b56eSmrg 167d6c0b56eSmrgstatic void 168d6c0b56eSmrgdrmmode_ConvertToKMode(ScrnInfoPtr scrn, 169d6c0b56eSmrg drmModeModeInfo * kmode, DisplayModePtr mode) 170d6c0b56eSmrg{ 171d6c0b56eSmrg memset(kmode, 0, sizeof(*kmode)); 172d6c0b56eSmrg 173d6c0b56eSmrg kmode->clock = mode->Clock; 174d6c0b56eSmrg kmode->hdisplay = mode->HDisplay; 175d6c0b56eSmrg kmode->hsync_start = mode->HSyncStart; 176d6c0b56eSmrg kmode->hsync_end = mode->HSyncEnd; 177d6c0b56eSmrg kmode->htotal = mode->HTotal; 178d6c0b56eSmrg kmode->hskew = mode->HSkew; 179d6c0b56eSmrg 180d6c0b56eSmrg kmode->vdisplay = mode->VDisplay; 181d6c0b56eSmrg kmode->vsync_start = mode->VSyncStart; 182d6c0b56eSmrg kmode->vsync_end = mode->VSyncEnd; 183d6c0b56eSmrg kmode->vtotal = mode->VTotal; 184d6c0b56eSmrg kmode->vscan = mode->VScan; 185d6c0b56eSmrg 186d6c0b56eSmrg kmode->flags = mode->Flags; //& FLAG_BITS; 187d6c0b56eSmrg if (mode->name) 188d6c0b56eSmrg strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN); 189d6c0b56eSmrg kmode->name[DRM_DISPLAY_MODE_LEN - 1] = 0; 190d6c0b56eSmrg 191d6c0b56eSmrg} 192d6c0b56eSmrg 19324b90cf4Smrg/* 19424b90cf4Smrg * Utility helper for drmWaitVBlank 19524b90cf4Smrg */ 19624b90cf4SmrgBool 19724b90cf4Smrgdrmmode_wait_vblank(xf86CrtcPtr crtc, drmVBlankSeqType type, 19824b90cf4Smrg uint32_t target_seq, unsigned long signal, uint64_t *ust, 19924b90cf4Smrg uint32_t *result_seq) 20024b90cf4Smrg{ 20124b90cf4Smrg int crtc_id = drmmode_get_crtc_id(crtc); 20224b90cf4Smrg ScrnInfoPtr scrn = crtc->scrn; 20324b90cf4Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 20424b90cf4Smrg drmVBlank vbl; 20524b90cf4Smrg 20624b90cf4Smrg if (crtc_id == 1) 20724b90cf4Smrg type |= DRM_VBLANK_SECONDARY; 20824b90cf4Smrg else if (crtc_id > 1) 20924b90cf4Smrg type |= (crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT) & 21024b90cf4Smrg DRM_VBLANK_HIGH_CRTC_MASK; 21124b90cf4Smrg 21224b90cf4Smrg vbl.request.type = type; 21324b90cf4Smrg vbl.request.sequence = target_seq; 21424b90cf4Smrg vbl.request.signal = signal; 21524b90cf4Smrg 21624b90cf4Smrg if (drmWaitVBlank(pAMDGPUEnt->fd, &vbl) != 0) 21724b90cf4Smrg return FALSE; 21824b90cf4Smrg 21924b90cf4Smrg if (ust) 22024b90cf4Smrg *ust = (uint64_t)vbl.reply.tval_sec * 1000000 + 22124b90cf4Smrg vbl.reply.tval_usec; 22224b90cf4Smrg if (result_seq) 22324b90cf4Smrg *result_seq = vbl.reply.sequence; 22424b90cf4Smrg 22524b90cf4Smrg return TRUE; 22624b90cf4Smrg} 22724b90cf4Smrg 228d6c0b56eSmrg/* 229d6c0b56eSmrg * Retrieves present time in microseconds that is compatible 230d6c0b56eSmrg * with units used by vblank timestamps. Depending on the kernel 231d6c0b56eSmrg * version and DRM kernel module configuration, the vblank 232d6c0b56eSmrg * timestamp can either be in real time or monotonic time 233d6c0b56eSmrg */ 234d6c0b56eSmrgint drmmode_get_current_ust(int drm_fd, CARD64 * ust) 235d6c0b56eSmrg{ 236d6c0b56eSmrg uint64_t cap_value; 237d6c0b56eSmrg int ret; 238d6c0b56eSmrg struct timespec now; 239d6c0b56eSmrg 240d6c0b56eSmrg ret = drmGetCap(drm_fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap_value); 241d6c0b56eSmrg if (ret || !cap_value) 242d6c0b56eSmrg /* old kernel or drm_timestamp_monotonic turned off */ 243d6c0b56eSmrg ret = clock_gettime(CLOCK_REALTIME, &now); 244d6c0b56eSmrg else 245d6c0b56eSmrg ret = clock_gettime(CLOCK_MONOTONIC, &now); 246d6c0b56eSmrg if (ret) 247d6c0b56eSmrg return ret; 248d6c0b56eSmrg *ust = ((CARD64) now.tv_sec * 1000000) + ((CARD64) now.tv_nsec / 1000); 249d6c0b56eSmrg return 0; 250d6c0b56eSmrg} 251d6c0b56eSmrg 252d6c0b56eSmrg/* 253d6c0b56eSmrg * Get current frame count and frame count timestamp of the crtc. 254d6c0b56eSmrg */ 255d6c0b56eSmrgint drmmode_crtc_get_ust_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc) 256d6c0b56eSmrg{ 257d6c0b56eSmrg ScrnInfoPtr scrn = crtc->scrn; 25824b90cf4Smrg uint32_t seq; 259d6c0b56eSmrg 26024b90cf4Smrg if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, ust, &seq)) { 261d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 262d6c0b56eSmrg "get vblank counter failed: %s\n", strerror(errno)); 26324b90cf4Smrg return -1; 264d6c0b56eSmrg } 265d6c0b56eSmrg 26624b90cf4Smrg *msc = seq; 267d6c0b56eSmrg 268d6c0b56eSmrg return Success; 269d6c0b56eSmrg} 270d6c0b56eSmrg 271d6c0b56eSmrgstatic void 272d6c0b56eSmrgdrmmode_do_crtc_dpms(xf86CrtcPtr crtc, int mode) 273d6c0b56eSmrg{ 274d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 275d6c0b56eSmrg ScrnInfoPtr scrn = crtc->scrn; 276d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 277d6c0b56eSmrg CARD64 ust; 278d6c0b56eSmrg int ret; 279d6c0b56eSmrg 280d6c0b56eSmrg if (drmmode_crtc->dpms_mode == DPMSModeOn && mode != DPMSModeOn) { 28124b90cf4Smrg uint32_t seq; 282d6c0b56eSmrg 28335d5b7c7Smrg amdgpu_drm_wait_pending_flip(crtc); 284504d986fSmrg 285d6c0b56eSmrg /* 286d6c0b56eSmrg * On->Off transition: record the last vblank time, 287d6c0b56eSmrg * sequence number and frame period. 288d6c0b56eSmrg */ 28924b90cf4Smrg if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, &ust, 29024b90cf4Smrg &seq)) 291d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 292d6c0b56eSmrg "%s cannot get last vblank counter\n", 293d6c0b56eSmrg __func__); 294d6c0b56eSmrg else { 295d6c0b56eSmrg CARD64 nominal_frame_rate, pix_in_frame; 296d6c0b56eSmrg 297d6c0b56eSmrg drmmode_crtc->dpms_last_ust = ust; 298d6c0b56eSmrg drmmode_crtc->dpms_last_seq = seq; 299d6c0b56eSmrg nominal_frame_rate = crtc->mode.Clock; 300d6c0b56eSmrg nominal_frame_rate *= 1000; 301d6c0b56eSmrg pix_in_frame = crtc->mode.HTotal * crtc->mode.VTotal; 302d6c0b56eSmrg if (nominal_frame_rate == 0 || pix_in_frame == 0) 303d6c0b56eSmrg nominal_frame_rate = DEFAULT_NOMINAL_FRAME_RATE; 304d6c0b56eSmrg else 305d6c0b56eSmrg nominal_frame_rate /= pix_in_frame; 306d6c0b56eSmrg drmmode_crtc->dpms_last_fps = nominal_frame_rate; 307d6c0b56eSmrg } 30835d5b7c7Smrg 30935d5b7c7Smrg drmmode_crtc->dpms_mode = mode; 31035d5b7c7Smrg amdgpu_drm_queue_handle_deferred(crtc); 311d6c0b56eSmrg } else if (drmmode_crtc->dpms_mode != DPMSModeOn && mode == DPMSModeOn) { 312d6c0b56eSmrg /* 313d6c0b56eSmrg * Off->On transition: calculate and accumulate the 314d6c0b56eSmrg * number of interpolated vblanks while we were in Off state 315d6c0b56eSmrg */ 316d6c0b56eSmrg ret = drmmode_get_current_ust(pAMDGPUEnt->fd, &ust); 317d6c0b56eSmrg if (ret) 318d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 319d6c0b56eSmrg "%s cannot get current time\n", __func__); 320d6c0b56eSmrg else if (drmmode_crtc->dpms_last_ust) { 321d6c0b56eSmrg CARD64 time_elapsed, delta_seq; 322d6c0b56eSmrg time_elapsed = ust - drmmode_crtc->dpms_last_ust; 323d6c0b56eSmrg delta_seq = time_elapsed * drmmode_crtc->dpms_last_fps; 324d6c0b56eSmrg delta_seq /= 1000000; 325d6c0b56eSmrg drmmode_crtc->interpolated_vblanks += delta_seq; 326d6c0b56eSmrg 327d6c0b56eSmrg } 32835d5b7c7Smrg 32935d5b7c7Smrg drmmode_crtc->dpms_mode = DPMSModeOn; 330d6c0b56eSmrg } 331d6c0b56eSmrg} 332d6c0b56eSmrg 333d6c0b56eSmrgstatic void 334d6c0b56eSmrgdrmmode_crtc_dpms(xf86CrtcPtr crtc, int mode) 335d6c0b56eSmrg{ 336d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 337d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 338d6c0b56eSmrg 339d6c0b56eSmrg /* Disable unused CRTCs and enable/disable active CRTCs */ 340504d986fSmrg if (!crtc->enabled || mode != DPMSModeOn) { 34135d5b7c7Smrg drmmode_do_crtc_dpms(crtc, DPMSModeOff); 342d6c0b56eSmrg drmModeSetCrtc(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 343d6c0b56eSmrg 0, 0, 0, NULL, 0, NULL); 34424b90cf4Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, NULL); 345504d986fSmrg } else if (drmmode_crtc->dpms_mode != DPMSModeOn) 346d6c0b56eSmrg crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation, 347d6c0b56eSmrg crtc->x, crtc->y); 348d6c0b56eSmrg} 349d6c0b56eSmrg 350d6c0b56eSmrgstatic PixmapPtr 351d6c0b56eSmrgcreate_pixmap_for_fbcon(drmmode_ptr drmmode, 352d6c0b56eSmrg ScrnInfoPtr pScrn, int fbcon_id) 353d6c0b56eSmrg{ 35435d5b7c7Smrg ScreenPtr pScreen = pScrn->pScreen; 355d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 35635d5b7c7Smrg PixmapPtr pixmap = NULL; 357d6c0b56eSmrg drmModeFBPtr fbcon; 358d6c0b56eSmrg 359d6c0b56eSmrg fbcon = drmModeGetFB(pAMDGPUEnt->fd, fbcon_id); 36035d5b7c7Smrg if (!fbcon) 361d6c0b56eSmrg return NULL; 362d6c0b56eSmrg 363d6c0b56eSmrg if (fbcon->depth != pScrn->depth || 364d6c0b56eSmrg fbcon->width != pScrn->virtualX || 365d6c0b56eSmrg fbcon->height != pScrn->virtualY) 366d6c0b56eSmrg goto out_free_fb; 367d6c0b56eSmrg 36835d5b7c7Smrg pixmap = fbCreatePixmap(pScreen, 0, 0, fbcon->depth, 0); 36935d5b7c7Smrg if (!pixmap) 370d6c0b56eSmrg goto out_free_fb; 371d6c0b56eSmrg 37235d5b7c7Smrg pScreen->ModifyPixmapHeader(pixmap, fbcon->width, fbcon->height, 0, 0, 37335d5b7c7Smrg fbcon->pitch, NULL); 37435d5b7c7Smrg pixmap->devPrivate.ptr = NULL; 375d6c0b56eSmrg 37635d5b7c7Smrg if (!glamor_egl_create_textured_pixmap(pixmap, fbcon->handle, 37735d5b7c7Smrg pixmap->devKind)) { 37835d5b7c7Smrg pScreen->DestroyPixmap(pixmap); 37935d5b7c7Smrg pixmap = NULL; 380d6c0b56eSmrg } 381d6c0b56eSmrg 382d6c0b56eSmrgout_free_fb: 383d6c0b56eSmrg drmModeFreeFB(fbcon); 384d6c0b56eSmrg return pixmap; 385d6c0b56eSmrg} 386d6c0b56eSmrg 387d6c0b56eSmrgvoid drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 388d6c0b56eSmrg{ 389d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 390d6c0b56eSmrg ScreenPtr pScreen = pScrn->pScreen; 39124b90cf4Smrg PixmapPtr src, dst = pScreen->GetScreenPixmap(pScreen); 39224b90cf4Smrg struct drmmode_fb *fb = amdgpu_pixmap_get_fb(dst); 393d6c0b56eSmrg int fbcon_id = 0; 394d6c0b56eSmrg GCPtr gc; 395d6c0b56eSmrg int i; 396d6c0b56eSmrg 397d6c0b56eSmrg for (i = 0; i < xf86_config->num_crtc; i++) { 398d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[i]->driver_private; 399d6c0b56eSmrg 400d6c0b56eSmrg if (drmmode_crtc->mode_crtc->buffer_id) 401d6c0b56eSmrg fbcon_id = drmmode_crtc->mode_crtc->buffer_id; 402d6c0b56eSmrg } 403d6c0b56eSmrg 404d6c0b56eSmrg if (!fbcon_id) 405d6c0b56eSmrg return; 406d6c0b56eSmrg 40724b90cf4Smrg if (fbcon_id == fb->handle) { 408d6c0b56eSmrg /* in some rare case there might be no fbcon and we might already 409d6c0b56eSmrg * be the one with the current fb to avoid a false deadlck in 410d6c0b56eSmrg * kernel ttm code just do nothing as anyway there is nothing 411d6c0b56eSmrg * to do 412d6c0b56eSmrg */ 413d6c0b56eSmrg return; 414d6c0b56eSmrg } 415d6c0b56eSmrg 416d6c0b56eSmrg src = create_pixmap_for_fbcon(drmmode, pScrn, fbcon_id); 417d6c0b56eSmrg if (!src) 418d6c0b56eSmrg return; 419d6c0b56eSmrg 420d6c0b56eSmrg gc = GetScratchGC(pScrn->depth, pScreen); 421d6c0b56eSmrg ValidateGC(&dst->drawable, gc); 422d6c0b56eSmrg 423d6c0b56eSmrg (*gc->ops->CopyArea)(&src->drawable, &dst->drawable, gc, 0, 0, 424d6c0b56eSmrg pScrn->virtualX, pScrn->virtualY, 0, 0); 425d6c0b56eSmrg 426d6c0b56eSmrg FreeScratchGC(gc); 427d6c0b56eSmrg 428d6c0b56eSmrg pScreen->canDoBGNoneRoot = TRUE; 42935d5b7c7Smrg pScreen->DestroyPixmap(src); 430d6c0b56eSmrg 431d6c0b56eSmrg return; 432d6c0b56eSmrg} 433d6c0b56eSmrg 43424b90cf4Smrgvoid 435d6c0b56eSmrgdrmmode_crtc_scanout_destroy(drmmode_ptr drmmode, 436d6c0b56eSmrg struct drmmode_scanout *scanout) 437d6c0b56eSmrg{ 438d6c0b56eSmrg 439d6c0b56eSmrg if (scanout->pixmap) { 440d6c0b56eSmrg drmmode_destroy_bo_pixmap(scanout->pixmap); 441d6c0b56eSmrg scanout->pixmap = NULL; 442d6c0b56eSmrg } 443d6c0b56eSmrg 444d6c0b56eSmrg if (scanout->bo) { 445d6c0b56eSmrg amdgpu_bo_unref(&scanout->bo); 446d6c0b56eSmrg scanout->bo = NULL; 447d6c0b56eSmrg } 448504d986fSmrg} 449504d986fSmrg 45024b90cf4Smrgvoid 451504d986fSmrgdrmmode_crtc_scanout_free(drmmode_crtc_private_ptr drmmode_crtc) 452504d986fSmrg{ 45324b90cf4Smrg drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, 45424b90cf4Smrg &drmmode_crtc->scanout[0]); 45524b90cf4Smrg drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, 45624b90cf4Smrg &drmmode_crtc->scanout[1]); 457d6c0b56eSmrg 45824b90cf4Smrg if (drmmode_crtc->scanout_damage) 459504d986fSmrg DamageDestroy(drmmode_crtc->scanout_damage); 460d6c0b56eSmrg} 461d6c0b56eSmrg 46224b90cf4SmrgPixmapPtr 46311bf0794Smrgdrmmode_crtc_scanout_create(xf86CrtcPtr crtc, struct drmmode_scanout *scanout, 46411bf0794Smrg int width, int height) 465d6c0b56eSmrg{ 466d6c0b56eSmrg ScrnInfoPtr pScrn = crtc->scrn; 467d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 468d6c0b56eSmrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 46911bf0794Smrg int pitch; 470d6c0b56eSmrg 47111bf0794Smrg if (scanout->pixmap) { 472d6c0b56eSmrg if (scanout->width == width && scanout->height == height) 47311bf0794Smrg return scanout->pixmap; 474d6c0b56eSmrg 475d6c0b56eSmrg drmmode_crtc_scanout_destroy(drmmode, scanout); 476d6c0b56eSmrg } 477d6c0b56eSmrg 478d6c0b56eSmrg scanout->bo = amdgpu_alloc_pixmap_bo(pScrn, width, height, 47911bf0794Smrg pScrn->depth, 0, 48011bf0794Smrg pScrn->bitsPerPixel, &pitch); 481d6c0b56eSmrg if (!scanout->bo) { 482d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 48311bf0794Smrg "Failed to allocate scanout buffer memory\n"); 48424b90cf4Smrg return NULL; 485d6c0b56eSmrg } 486d6c0b56eSmrg 487d6c0b56eSmrg scanout->pixmap = drmmode_create_bo_pixmap(pScrn, 488d6c0b56eSmrg width, height, 489d6c0b56eSmrg pScrn->depth, 490d6c0b56eSmrg pScrn->bitsPerPixel, 49111bf0794Smrg pitch, scanout->bo); 49224b90cf4Smrg if (!scanout->pixmap) { 49324b90cf4Smrg ErrorF("failed to create CRTC scanout pixmap\n"); 49424b90cf4Smrg goto error; 49524b90cf4Smrg } 49624b90cf4Smrg 49724b90cf4Smrg if (amdgpu_pixmap_get_fb(scanout->pixmap)) { 49811bf0794Smrg scanout->width = width; 49911bf0794Smrg scanout->height = height; 50011bf0794Smrg } else { 50124b90cf4Smrg ErrorF("failed to create CRTC scanout FB\n"); 50224b90cf4Smrgerror: 50311bf0794Smrg drmmode_crtc_scanout_destroy(drmmode, scanout); 504d6c0b56eSmrg } 505d6c0b56eSmrg 50611bf0794Smrg return scanout->pixmap; 507d6c0b56eSmrg} 508d6c0b56eSmrg 509d6c0b56eSmrgstatic void 510d6c0b56eSmrgamdgpu_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure) 511d6c0b56eSmrg{ 51224b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = closure; 51324b90cf4Smrg 51424b90cf4Smrg if (drmmode_crtc->ignore_damage) { 51524b90cf4Smrg RegionEmpty(&damage->damage); 51624b90cf4Smrg drmmode_crtc->ignore_damage = FALSE; 51724b90cf4Smrg return; 51824b90cf4Smrg } 51924b90cf4Smrg 520d6c0b56eSmrg /* Only keep track of the extents */ 521d6c0b56eSmrg RegionUninit(&damage->damage); 522d6c0b56eSmrg damage->damage.data = NULL; 523d6c0b56eSmrg} 524d6c0b56eSmrg 52524b90cf4Smrgstatic void 52624b90cf4Smrgdrmmode_screen_damage_destroy(DamagePtr damage, void *closure) 52724b90cf4Smrg{ 52824b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = closure; 52924b90cf4Smrg 53024b90cf4Smrg drmmode_crtc->scanout_damage = NULL; 53124b90cf4Smrg RegionUninit(&drmmode_crtc->scanout_last_region); 53224b90cf4Smrg} 53324b90cf4Smrg 534d6c0b56eSmrgstatic Bool 535d6c0b56eSmrgdrmmode_can_use_hw_cursor(xf86CrtcPtr crtc) 536d6c0b56eSmrg{ 537d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn); 538d6c0b56eSmrg 539d6c0b56eSmrg /* Check for Option "SWcursor" */ 540d6c0b56eSmrg if (xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) 541d6c0b56eSmrg return FALSE; 542d6c0b56eSmrg 543d6c0b56eSmrg /* Fall back to SW cursor if the CRTC is transformed */ 544d6c0b56eSmrg if (crtc->transformPresent) 545d6c0b56eSmrg return FALSE; 546d6c0b56eSmrg 54724b90cf4Smrg#if XF86_CRTC_VERSION < 7 548d6c0b56eSmrg /* Xorg doesn't correctly handle cursor position transform in the 549d6c0b56eSmrg * rotation case 550d6c0b56eSmrg */ 551d6c0b56eSmrg if (crtc->driverIsPerformingTransform && 552d6c0b56eSmrg (crtc->rotation & 0xf) != RR_Rotate_0) 553d6c0b56eSmrg return FALSE; 554d6c0b56eSmrg#endif 555d6c0b56eSmrg 556504d986fSmrg /* HW cursor not supported with RandR 1.4 multihead up to 1.18.99.901 */ 557504d986fSmrg if (xorgGetVersion() <= XORG_VERSION_NUMERIC(1,18,99,901,0) && 558504d986fSmrg !xorg_list_is_empty(&crtc->scrn->pScreen->pixmap_dirty_list)) 559d6c0b56eSmrg return FALSE; 560d6c0b56eSmrg 561d6c0b56eSmrg return TRUE; 562d6c0b56eSmrg} 563d6c0b56eSmrg 56411bf0794Smrgstatic void 56511bf0794Smrgdrmmode_crtc_update_tear_free(xf86CrtcPtr crtc) 56611bf0794Smrg{ 56711bf0794Smrg AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn); 56811bf0794Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 56911bf0794Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 57011bf0794Smrg int i; 57111bf0794Smrg 57211bf0794Smrg drmmode_crtc->tear_free = FALSE; 57311bf0794Smrg 57411bf0794Smrg for (i = 0; i < xf86_config->num_output; i++) { 57511bf0794Smrg xf86OutputPtr output = xf86_config->output[i]; 57611bf0794Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 57711bf0794Smrg 57811bf0794Smrg if (output->crtc != crtc) 57911bf0794Smrg continue; 58011bf0794Smrg 58111bf0794Smrg if (drmmode_output->tear_free == 1 || 58211bf0794Smrg (drmmode_output->tear_free == 2 && 58324b90cf4Smrg (crtc->scrn->pScreen->isGPU || 58411bf0794Smrg info->shadow_primary || 58511bf0794Smrg crtc->transformPresent || crtc->rotation != RR_Rotate_0))) { 58611bf0794Smrg drmmode_crtc->tear_free = TRUE; 58711bf0794Smrg return; 58811bf0794Smrg } 58911bf0794Smrg } 59011bf0794Smrg} 59111bf0794Smrg 59211bf0794Smrg#if XF86_CRTC_VERSION < 7 59311bf0794Smrg#define XF86DriverTransformOutput TRUE 59411bf0794Smrg#define XF86DriverTransformNone FALSE 59511bf0794Smrg#endif 59611bf0794Smrg 597d6c0b56eSmrgstatic Bool 598d6c0b56eSmrgdrmmode_handle_transform(xf86CrtcPtr crtc) 599d6c0b56eSmrg{ 600d6c0b56eSmrg Bool ret; 601d6c0b56eSmrg 60224b90cf4Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 60335d5b7c7Smrg crtc->driverIsPerformingTransform = XF86DriverTransformOutput; 60424b90cf4Smrg#else 60524b90cf4Smrg crtc->driverIsPerformingTransform = !crtc->transformPresent && 60624b90cf4Smrg (crtc->rotation & 0xf) == RR_Rotate_0; 60724b90cf4Smrg#endif 608d6c0b56eSmrg 609d6c0b56eSmrg ret = xf86CrtcRotate(crtc); 610d6c0b56eSmrg 611d6c0b56eSmrg crtc->driverIsPerformingTransform &= ret && crtc->transform_in_use; 612d6c0b56eSmrg 613d6c0b56eSmrg return ret; 614d6c0b56eSmrg} 615d6c0b56eSmrg 61611bf0794Smrg 61711bf0794Smrgstatic void 61811bf0794Smrgdrmmode_crtc_prime_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode, 61924b90cf4Smrg unsigned scanout_id, struct drmmode_fb **fb, 62024b90cf4Smrg int *x, int *y) 62111bf0794Smrg{ 62211bf0794Smrg ScrnInfoPtr scrn = crtc->scrn; 62311bf0794Smrg ScreenPtr screen = scrn->pScreen; 62411bf0794Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 62511bf0794Smrg 62611bf0794Smrg if (drmmode_crtc->tear_free && 62711bf0794Smrg !drmmode_crtc->scanout[1].pixmap) { 62811bf0794Smrg RegionPtr region; 62911bf0794Smrg BoxPtr box; 63011bf0794Smrg 63111bf0794Smrg drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], 63211bf0794Smrg mode->HDisplay, 63311bf0794Smrg mode->VDisplay); 63411bf0794Smrg region = &drmmode_crtc->scanout_last_region; 63511bf0794Smrg RegionUninit(region); 63611bf0794Smrg region->data = NULL; 63711bf0794Smrg box = RegionExtents(region); 63811bf0794Smrg box->x1 = crtc->x; 63911bf0794Smrg box->y1 = crtc->y; 64011bf0794Smrg box->x2 = crtc->x + mode->HDisplay; 64111bf0794Smrg box->y2 = crtc->y + mode->VDisplay; 64211bf0794Smrg } 64311bf0794Smrg 64411bf0794Smrg if (scanout_id != drmmode_crtc->scanout_id) { 64511bf0794Smrg PixmapDirtyUpdatePtr dirty = NULL; 64611bf0794Smrg 64711bf0794Smrg xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, 64811bf0794Smrg ent) { 64924b90cf4Smrg if (amdgpu_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) { 65011bf0794Smrg dirty->slave_dst = 65111bf0794Smrg drmmode_crtc->scanout[scanout_id].pixmap; 65211bf0794Smrg break; 65311bf0794Smrg } 65411bf0794Smrg } 65511bf0794Smrg 65611bf0794Smrg if (!drmmode_crtc->tear_free) { 65711bf0794Smrg GCPtr gc = GetScratchGC(scrn->depth, screen); 65811bf0794Smrg 65911bf0794Smrg ValidateGC(&drmmode_crtc->scanout[0].pixmap->drawable, gc); 66011bf0794Smrg gc->ops->CopyArea(&drmmode_crtc->scanout[1].pixmap->drawable, 66111bf0794Smrg &drmmode_crtc->scanout[0].pixmap->drawable, 66211bf0794Smrg gc, 0, 0, mode->HDisplay, mode->VDisplay, 66311bf0794Smrg 0, 0); 66411bf0794Smrg FreeScratchGC(gc); 66511bf0794Smrg amdgpu_glamor_finish(scrn); 66611bf0794Smrg } 66711bf0794Smrg } 66811bf0794Smrg 66924b90cf4Smrg *fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap); 67011bf0794Smrg *x = *y = 0; 67111bf0794Smrg drmmode_crtc->scanout_id = scanout_id; 67211bf0794Smrg} 67311bf0794Smrg 67411bf0794Smrg 67511bf0794Smrgstatic void 67611bf0794Smrgdrmmode_crtc_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode, 67724b90cf4Smrg unsigned scanout_id, struct drmmode_fb **fb, int *x, 67824b90cf4Smrg int *y) 67911bf0794Smrg{ 68011bf0794Smrg ScrnInfoPtr scrn = crtc->scrn; 68111bf0794Smrg ScreenPtr screen = scrn->pScreen; 68211bf0794Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 68311bf0794Smrg 68424b90cf4Smrg drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[scanout_id], 68511bf0794Smrg mode->HDisplay, mode->VDisplay); 68611bf0794Smrg if (drmmode_crtc->tear_free) { 68724b90cf4Smrg drmmode_crtc_scanout_create(crtc, 68824b90cf4Smrg &drmmode_crtc->scanout[scanout_id ^ 1], 68911bf0794Smrg mode->HDisplay, mode->VDisplay); 69011bf0794Smrg } 69111bf0794Smrg 69224b90cf4Smrg if (drmmode_crtc->scanout[scanout_id].pixmap && 69324b90cf4Smrg (!drmmode_crtc->tear_free || 69424b90cf4Smrg drmmode_crtc->scanout[scanout_id ^ 1].pixmap)) { 69535d5b7c7Smrg BoxRec extents = { .x1 = 0, .y1 = 0, 69635d5b7c7Smrg .x2 = scrn->virtualX, .y2 = scrn->virtualY }; 69711bf0794Smrg 69811bf0794Smrg if (!drmmode_crtc->scanout_damage) { 69911bf0794Smrg drmmode_crtc->scanout_damage = 70011bf0794Smrg DamageCreate(amdgpu_screen_damage_report, 70124b90cf4Smrg drmmode_screen_damage_destroy, 70224b90cf4Smrg DamageReportRawRegion, 70324b90cf4Smrg TRUE, screen, drmmode_crtc); 70424b90cf4Smrg DamageRegister(&screen->root->drawable, 70511bf0794Smrg drmmode_crtc->scanout_damage); 70611bf0794Smrg } 70711bf0794Smrg 70824b90cf4Smrg *fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap); 70911bf0794Smrg *x = *y = 0; 71011bf0794Smrg 71124b90cf4Smrg amdgpu_scanout_do_update(crtc, scanout_id, 71224b90cf4Smrg screen->GetWindowPixmap(screen->root), 71335d5b7c7Smrg extents); 71435d5b7c7Smrg RegionEmpty(DamageRegion(drmmode_crtc->scanout_damage)); 71511bf0794Smrg amdgpu_glamor_finish(scrn); 71611bf0794Smrg } 71711bf0794Smrg} 71811bf0794Smrg 71935d5b7c7Smrgstatic char *cm_prop_names[] = { 72035d5b7c7Smrg "DEGAMMA_LUT", 72135d5b7c7Smrg "CTM", 72235d5b7c7Smrg "GAMMA_LUT", 72335d5b7c7Smrg "DEGAMMA_LUT_SIZE", 72435d5b7c7Smrg "GAMMA_LUT_SIZE", 72535d5b7c7Smrg}; 72635d5b7c7Smrg 72735d5b7c7Smrg/** 72835d5b7c7Smrg * Return the enum of the color management property with the given name. 72935d5b7c7Smrg */ 73035d5b7c7Smrgstatic enum drmmode_cm_prop get_cm_enum_from_str(const char *prop_name) 73135d5b7c7Smrg{ 73235d5b7c7Smrg enum drmmode_cm_prop ret; 73335d5b7c7Smrg 73435d5b7c7Smrg for (ret = 0; ret < CM_NUM_PROPS; ret++) { 73535d5b7c7Smrg if (!strcmp(prop_name, cm_prop_names[ret])) 73635d5b7c7Smrg return ret; 73735d5b7c7Smrg } 73835d5b7c7Smrg return CM_INVALID_PROP; 73935d5b7c7Smrg} 74035d5b7c7Smrg 74135d5b7c7Smrg/** 74235d5b7c7Smrg * Return TRUE if kernel supports non-legacy color management. 74335d5b7c7Smrg */ 74435d5b7c7Smrgstatic Bool drmmode_cm_enabled(drmmode_ptr drmmode) 74535d5b7c7Smrg{ 74635d5b7c7Smrg return drmmode->cm_prop_ids[CM_GAMMA_LUT_SIZE] != 0; 74735d5b7c7Smrg} 74835d5b7c7Smrg 74935d5b7c7Smrg/** 75035d5b7c7Smrg * If legacy LUT is a, and non-legacy LUT is b, then the result of b(a(x)) is 75135d5b7c7Smrg * returned in out_lut. out_lut's length is expected to be the same as the 75235d5b7c7Smrg * non-legacy LUT b. 75335d5b7c7Smrg * 75435d5b7c7Smrg * @a_(red|green|blue): The red, green, and blue components of the legacy LUT. 75535d5b7c7Smrg * @b_lut: The non-legacy LUT, in DRM's color LUT format. 75635d5b7c7Smrg * @out_lut: The composed LUT, in DRM's color LUT format. 75735d5b7c7Smrg * @len_a: Length of legacy lut. 75835d5b7c7Smrg * @len_b: Length of non-legacy lut. 75935d5b7c7Smrg */ 76035d5b7c7Smrgstatic void drmmode_lut_compose(uint16_t *a_red, 76135d5b7c7Smrg uint16_t *a_green, 76235d5b7c7Smrg uint16_t *a_blue, 76335d5b7c7Smrg struct drm_color_lut *b_lut, 76435d5b7c7Smrg struct drm_color_lut *out_lut, 76535d5b7c7Smrg uint32_t len_a, uint32_t len_b) 76635d5b7c7Smrg{ 76735d5b7c7Smrg uint32_t i_l, i_r, i; 76835d5b7c7Smrg uint32_t i_amax, i_bmax; 76935d5b7c7Smrg uint32_t coeff_ibmax; 77035d5b7c7Smrg uint32_t j; 77135d5b7c7Smrg uint64_t a_out_ibmax; 77235d5b7c7Smrg int color; 77335d5b7c7Smrg size_t struct_size = sizeof(struct drm_color_lut); 77435d5b7c7Smrg 77535d5b7c7Smrg uint32_t max_lut = (1 << 16) - 1; 77635d5b7c7Smrg 77735d5b7c7Smrg i_amax = len_a - 1; 77835d5b7c7Smrg i_bmax = len_b - 1; 77935d5b7c7Smrg 78035d5b7c7Smrg /* A linear interpolation is done on the legacy LUT before it is 78135d5b7c7Smrg * composed, to bring it up-to-size with the non-legacy LUT. The 78235d5b7c7Smrg * interpolation uses integers by keeping things multiplied until the 78335d5b7c7Smrg * last moment. 78435d5b7c7Smrg */ 78535d5b7c7Smrg for (color = 0; color < 3; color++) { 78635d5b7c7Smrg uint16_t *a, *b, *out; 78735d5b7c7Smrg 78835d5b7c7Smrg /* Set the initial pointers to the right color components. The 78935d5b7c7Smrg * inner for-loop will then maintain the correct offset from 79035d5b7c7Smrg * the initial element. 79135d5b7c7Smrg */ 79235d5b7c7Smrg if (color == 0) { 79335d5b7c7Smrg a = a_red; 79435d5b7c7Smrg b = &b_lut[0].red; 79535d5b7c7Smrg out = &out_lut[0].red; 79635d5b7c7Smrg } else if (color == 1) { 79735d5b7c7Smrg a = a_green; 79835d5b7c7Smrg b = &b_lut[0].green; 79935d5b7c7Smrg out = &out_lut[0].green; 80035d5b7c7Smrg } else { 80135d5b7c7Smrg a = a_blue; 80235d5b7c7Smrg b = &b_lut[0].blue; 80335d5b7c7Smrg out = &out_lut[0].blue; 80435d5b7c7Smrg } 80535d5b7c7Smrg 80635d5b7c7Smrg for (i = 0; i < len_b; i++) { 80735d5b7c7Smrg /* i_l and i_r tracks the left and right elements in 80835d5b7c7Smrg * a_lut, to the sample point i. Also handle last 80935d5b7c7Smrg * element edge case, when i_l = i_amax. 81035d5b7c7Smrg */ 81135d5b7c7Smrg i_l = i * i_amax / i_bmax; 81235d5b7c7Smrg i_r = i_l + !!(i_amax - i_l); 81335d5b7c7Smrg 81435d5b7c7Smrg /* coeff is intended to be in [0, 1), depending on 81535d5b7c7Smrg * where sample i is between i_l and i_r. We keep it 81635d5b7c7Smrg * multiplied with i_bmax throughout to maintain 81735d5b7c7Smrg * precision */ 81835d5b7c7Smrg coeff_ibmax = (i * i_amax) - (i_l * i_bmax); 81935d5b7c7Smrg a_out_ibmax = i_bmax * a[i_l] + 82035d5b7c7Smrg coeff_ibmax * (a[i_r] - a[i_l]); 82135d5b7c7Smrg 82235d5b7c7Smrg /* j = floor((a_out/max_lut)*i_bmax). 82335d5b7c7Smrg * i.e. the element in LUT b that a_out maps to. We 82435d5b7c7Smrg * have to divide by max_lut to normalize a_out, since 82535d5b7c7Smrg * values in the LUTs are [0, 1<<16) 82635d5b7c7Smrg */ 82735d5b7c7Smrg j = a_out_ibmax / max_lut; 82835d5b7c7Smrg *(uint16_t*)((void*)out + (i*struct_size)) = 82935d5b7c7Smrg *(uint16_t*)((void*)b + (j*struct_size)); 83035d5b7c7Smrg } 83135d5b7c7Smrg } 83235d5b7c7Smrg 83335d5b7c7Smrg for (i = 0; i < len_b; i++) 83435d5b7c7Smrg out_lut[i].reserved = 0; 83535d5b7c7Smrg} 83635d5b7c7Smrg 83735d5b7c7Smrg/** 83835d5b7c7Smrg * Resize a LUT, using linear interpolation. 83935d5b7c7Smrg * 84035d5b7c7Smrg * @in_(red|green|blue): Legacy LUT components 84135d5b7c7Smrg * @out_lut: The resized LUT is returned here, in DRM color LUT format. 84235d5b7c7Smrg * @len_in: Length of legacy LUT. 84335d5b7c7Smrg * @len_out: Length of out_lut, i.e. the target size. 84435d5b7c7Smrg */ 84535d5b7c7Smrgstatic void drmmode_lut_interpolate(uint16_t *in_red, 84635d5b7c7Smrg uint16_t *in_green, 84735d5b7c7Smrg uint16_t *in_blue, 84835d5b7c7Smrg struct drm_color_lut *out_lut, 84935d5b7c7Smrg uint32_t len_in, uint32_t len_out) 85035d5b7c7Smrg{ 85135d5b7c7Smrg uint32_t i_l, i_r, i; 85235d5b7c7Smrg uint32_t i_amax, i_bmax; 85335d5b7c7Smrg uint32_t coeff_ibmax; 85435d5b7c7Smrg uint64_t out_ibmax; 85535d5b7c7Smrg int color; 85635d5b7c7Smrg size_t struct_size = sizeof(struct drm_color_lut); 85735d5b7c7Smrg 85835d5b7c7Smrg i_amax = len_in - 1; 85935d5b7c7Smrg i_bmax = len_out - 1; 86035d5b7c7Smrg 86135d5b7c7Smrg /* See @drmmode_lut_compose for details */ 86235d5b7c7Smrg for (color = 0; color < 3; color++) { 86335d5b7c7Smrg uint16_t *in, *out; 86435d5b7c7Smrg 86535d5b7c7Smrg if (color == 0) { 86635d5b7c7Smrg in = in_red; 86735d5b7c7Smrg out = &out_lut[0].red; 86835d5b7c7Smrg } else if (color == 1) { 86935d5b7c7Smrg in = in_green; 87035d5b7c7Smrg out = &out_lut[0].green; 87135d5b7c7Smrg } else { 87235d5b7c7Smrg in = in_blue; 87335d5b7c7Smrg out = &out_lut[0].blue; 87435d5b7c7Smrg } 87535d5b7c7Smrg 87635d5b7c7Smrg for (i = 0; i < len_out; i++) { 87735d5b7c7Smrg i_l = i * i_amax / i_bmax; 87835d5b7c7Smrg i_r = i_l + !!(i_amax - i_l); 87935d5b7c7Smrg 88035d5b7c7Smrg coeff_ibmax = (i * i_amax) - (i_l * i_bmax); 88135d5b7c7Smrg out_ibmax = i_bmax * in[i_l] + 88235d5b7c7Smrg coeff_ibmax * (in[i_r] - in[i_l]); 88335d5b7c7Smrg 88435d5b7c7Smrg *(uint16_t*)((void*)out + (i*struct_size)) = 88535d5b7c7Smrg out_ibmax / i_bmax; 88635d5b7c7Smrg } 88735d5b7c7Smrg } 88835d5b7c7Smrg 88935d5b7c7Smrg for (i = 0; i < len_out; i++) 89035d5b7c7Smrg out_lut[i].reserved = 0; 89135d5b7c7Smrg} 89235d5b7c7Smrg 89335d5b7c7Smrg/** 89435d5b7c7Smrg * Configure and change a color property on a CRTC, through RandR. Only the 89535d5b7c7Smrg * specified output will be affected, even if the CRTC is attached to multiple 89635d5b7c7Smrg * outputs. Note that changes will be non-pending: the changes won't be pushed 89735d5b7c7Smrg * to kernel driver. 89835d5b7c7Smrg * 89935d5b7c7Smrg * @output: RandR output to set the property on. 90035d5b7c7Smrg * @crtc: The driver-private CRTC object containing the color properties. 90135d5b7c7Smrg * If this is NULL, "disabled" values of 0 will be used. 90235d5b7c7Smrg * @cm_prop_index: Color management property to configure and change. 90335d5b7c7Smrg * 90435d5b7c7Smrg * Return 0 on success, X-defined error code otherwise. 90535d5b7c7Smrg */ 90635d5b7c7Smrgstatic int rr_configure_and_change_cm_property(xf86OutputPtr output, 90735d5b7c7Smrg drmmode_crtc_private_ptr crtc, 90835d5b7c7Smrg enum drmmode_cm_prop cm_prop_index) 90935d5b7c7Smrg{ 91035d5b7c7Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 91135d5b7c7Smrg drmmode_ptr drmmode = drmmode_output->drmmode; 91235d5b7c7Smrg Bool need_configure = TRUE; 91335d5b7c7Smrg unsigned long length = 0; 91435d5b7c7Smrg void *data = NULL; 91535d5b7c7Smrg int format = 0; 91635d5b7c7Smrg uint32_t zero = 0; 91735d5b7c7Smrg INT32 range[2]; 91835d5b7c7Smrg Atom atom; 91935d5b7c7Smrg int err; 92035d5b7c7Smrg 92135d5b7c7Smrg if (cm_prop_index == CM_INVALID_PROP) 92235d5b7c7Smrg return BadName; 92335d5b7c7Smrg 92435d5b7c7Smrg switch(cm_prop_index) { 92535d5b7c7Smrg case CM_GAMMA_LUT_SIZE: 92635d5b7c7Smrg format = 32; 92735d5b7c7Smrg length = 1; 92835d5b7c7Smrg data = &drmmode->gamma_lut_size; 92935d5b7c7Smrg range[0] = 0; 93035d5b7c7Smrg range[1] = -1; 93135d5b7c7Smrg break; 93235d5b7c7Smrg case CM_DEGAMMA_LUT_SIZE: 93335d5b7c7Smrg format = 32; 93435d5b7c7Smrg length = 1; 93535d5b7c7Smrg data = &drmmode->degamma_lut_size; 93635d5b7c7Smrg range[0] = 0; 93735d5b7c7Smrg range[1] = -1; 93835d5b7c7Smrg break; 93935d5b7c7Smrg case CM_GAMMA_LUT: 94035d5b7c7Smrg format = 16; 94135d5b7c7Smrg range[0] = 0; 94235d5b7c7Smrg range[1] = (1 << 16) - 1; // Max 16 bit unsigned int. 94335d5b7c7Smrg if (crtc && crtc->gamma_lut) { 94435d5b7c7Smrg /* Convert from 8bit size to 16bit size */ 94535d5b7c7Smrg length = sizeof(*crtc->gamma_lut) >> 1; 94635d5b7c7Smrg length *= drmmode->gamma_lut_size; 94735d5b7c7Smrg data = crtc->gamma_lut; 94835d5b7c7Smrg } else { 94935d5b7c7Smrg length = 1; 95035d5b7c7Smrg data = &zero; 95135d5b7c7Smrg } 95235d5b7c7Smrg break; 95335d5b7c7Smrg case CM_DEGAMMA_LUT: 95435d5b7c7Smrg format = 16; 95535d5b7c7Smrg range[0] = 0; 95635d5b7c7Smrg range[1] = (1 << 16) - 1; 95735d5b7c7Smrg if (crtc && crtc->degamma_lut) { 95835d5b7c7Smrg length = sizeof(*crtc->degamma_lut) >> 1; 95935d5b7c7Smrg length *= drmmode->degamma_lut_size; 96035d5b7c7Smrg data = crtc->degamma_lut; 96135d5b7c7Smrg } else { 96235d5b7c7Smrg length = 1; 96335d5b7c7Smrg data = &zero; 96435d5b7c7Smrg } 96535d5b7c7Smrg break; 96635d5b7c7Smrg case CM_CTM: 96735d5b7c7Smrg /* CTM is fixed-point S31.32 format. */ 96835d5b7c7Smrg format = 32; 96935d5b7c7Smrg need_configure = FALSE; 97035d5b7c7Smrg if (crtc && crtc->ctm) { 97135d5b7c7Smrg /* Convert from 8bit size to 32bit size */ 97235d5b7c7Smrg length = sizeof(*crtc->ctm) >> 2; 97335d5b7c7Smrg data = crtc->ctm; 97435d5b7c7Smrg } else { 97535d5b7c7Smrg length = 1; 97635d5b7c7Smrg data = &zero; 97735d5b7c7Smrg } 97835d5b7c7Smrg break; 97935d5b7c7Smrg default: 98035d5b7c7Smrg return BadName; 98135d5b7c7Smrg } 98235d5b7c7Smrg 98335d5b7c7Smrg atom = MakeAtom(cm_prop_names[cm_prop_index], 98435d5b7c7Smrg strlen(cm_prop_names[cm_prop_index]), 98535d5b7c7Smrg TRUE); 98635d5b7c7Smrg if (!atom) 98735d5b7c7Smrg return BadAlloc; 98835d5b7c7Smrg 98935d5b7c7Smrg if (need_configure) { 99035d5b7c7Smrg err = RRConfigureOutputProperty(output->randr_output, atom, 99135d5b7c7Smrg FALSE, TRUE, FALSE, 2, range); 99235d5b7c7Smrg if (err) { 99335d5b7c7Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 99435d5b7c7Smrg "Configuring color management property %s failed with %d\n", 99535d5b7c7Smrg cm_prop_names[cm_prop_index], err); 99635d5b7c7Smrg return err; 99735d5b7c7Smrg } 99835d5b7c7Smrg } 99935d5b7c7Smrg 100035d5b7c7Smrg /* Always issue a non-pending change. We'll push cm properties 100135d5b7c7Smrg * ourselves. 100235d5b7c7Smrg */ 100335d5b7c7Smrg err = RRChangeOutputProperty(output->randr_output, atom, 100435d5b7c7Smrg XA_INTEGER, format, 100535d5b7c7Smrg PropModeReplace, 100635d5b7c7Smrg length, data, FALSE, FALSE); 100735d5b7c7Smrg if (err) 100835d5b7c7Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 100935d5b7c7Smrg "Changing color management property %s failed with %d\n", 101035d5b7c7Smrg cm_prop_names[cm_prop_index], err); 101135d5b7c7Smrg return err; 101235d5b7c7Smrg} 101335d5b7c7Smrg 101435d5b7c7Smrg/** 101535d5b7c7Smrg* Stage a color management property. This parses the property value, according 101635d5b7c7Smrg* to the cm property type, then stores it within the driver-private CRTC 101735d5b7c7Smrg* object. 101835d5b7c7Smrg* 101935d5b7c7Smrg* @crtc: The CRTC to stage the new color management properties in 102035d5b7c7Smrg* @cm_prop_index: The color property to stage 102135d5b7c7Smrg* @value: The RandR property value to stage 102235d5b7c7Smrg* 102335d5b7c7Smrg* Return 0 on success, X-defined error code on failure. 102435d5b7c7Smrg*/ 102535d5b7c7Smrgstatic int drmmode_crtc_stage_cm_prop(xf86CrtcPtr crtc, 102635d5b7c7Smrg enum drmmode_cm_prop cm_prop_index, 102735d5b7c7Smrg RRPropertyValuePtr value) 102835d5b7c7Smrg{ 102935d5b7c7Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 103035d5b7c7Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 103135d5b7c7Smrg size_t expected_bytes = 0; 103235d5b7c7Smrg void **blob_data = NULL; 103335d5b7c7Smrg Bool use_default = FALSE; 103435d5b7c7Smrg 103535d5b7c7Smrg /* Update properties on the driver-private CRTC */ 103635d5b7c7Smrg switch (cm_prop_index) { 103735d5b7c7Smrg case CM_GAMMA_LUT: 103835d5b7c7Smrg /* Calculate the expected size of value in bytes */ 103935d5b7c7Smrg expected_bytes = sizeof(struct drm_color_lut) * 104035d5b7c7Smrg drmmode->gamma_lut_size; 104135d5b7c7Smrg 104235d5b7c7Smrg /* For gamma and degamma, we allow a default SRGB curve to be 104335d5b7c7Smrg * set via setting a single element 104435d5b7c7Smrg * 104535d5b7c7Smrg * Otherwise, value size is in terms of the value format. 104635d5b7c7Smrg * Ensure it's also in bytes (<< 1) before comparing with the 104735d5b7c7Smrg * expected bytes. 104835d5b7c7Smrg */ 104935d5b7c7Smrg if (value->size == 1) 105035d5b7c7Smrg use_default = TRUE; 105135d5b7c7Smrg else if (value->type != XA_INTEGER || value->format != 16 || 105235d5b7c7Smrg (size_t)(value->size << 1) != expected_bytes) 105335d5b7c7Smrg return BadLength; 105435d5b7c7Smrg 105535d5b7c7Smrg blob_data = (void**)&drmmode_crtc->gamma_lut; 105635d5b7c7Smrg break; 105735d5b7c7Smrg case CM_DEGAMMA_LUT: 105835d5b7c7Smrg expected_bytes = sizeof(struct drm_color_lut) * 105935d5b7c7Smrg drmmode->degamma_lut_size; 106035d5b7c7Smrg 106135d5b7c7Smrg if (value->size == 1) 106235d5b7c7Smrg use_default = TRUE; 106335d5b7c7Smrg else if (value->type != XA_INTEGER || value->format != 16 || 106435d5b7c7Smrg (size_t)(value->size << 1) != expected_bytes) 106535d5b7c7Smrg return BadLength; 106635d5b7c7Smrg 106735d5b7c7Smrg blob_data = (void**)&drmmode_crtc->degamma_lut; 106835d5b7c7Smrg break; 106935d5b7c7Smrg case CM_CTM: 107035d5b7c7Smrg expected_bytes = sizeof(struct drm_color_ctm); 107135d5b7c7Smrg 107235d5b7c7Smrg if (value->size == 1) 107335d5b7c7Smrg use_default = TRUE; 107435d5b7c7Smrg if (value->type != XA_INTEGER || value->format != 32 || 107535d5b7c7Smrg (size_t)(value->size << 2) != expected_bytes) 107635d5b7c7Smrg return BadLength; 107735d5b7c7Smrg 107835d5b7c7Smrg blob_data = (void**)&drmmode_crtc->ctm; 107935d5b7c7Smrg break; 108035d5b7c7Smrg default: 108135d5b7c7Smrg return BadName; 108235d5b7c7Smrg } 108335d5b7c7Smrg 108435d5b7c7Smrg free(*blob_data); 108535d5b7c7Smrg if (!use_default) { 108635d5b7c7Smrg *blob_data = malloc(expected_bytes); 108735d5b7c7Smrg if (!*blob_data) 108835d5b7c7Smrg return BadAlloc; 108935d5b7c7Smrg memcpy(*blob_data, value->data, expected_bytes); 109035d5b7c7Smrg } else 109135d5b7c7Smrg *blob_data = NULL; 109235d5b7c7Smrg 109335d5b7c7Smrg return Success; 109435d5b7c7Smrg} 109535d5b7c7Smrg 109635d5b7c7Smrg/** 109735d5b7c7Smrg * Push staged color management properties on the CRTC to DRM. 109835d5b7c7Smrg * 109935d5b7c7Smrg * @crtc: The CRTC containing staged properties 110035d5b7c7Smrg * @cm_prop_index: The color property to push 110135d5b7c7Smrg * 110235d5b7c7Smrg * Return 0 on success, X-defined error codes on failure. 110335d5b7c7Smrg */ 110435d5b7c7Smrgstatic int drmmode_crtc_push_cm_prop(xf86CrtcPtr crtc, 110535d5b7c7Smrg enum drmmode_cm_prop cm_prop_index) 110635d5b7c7Smrg{ 110735d5b7c7Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 110835d5b7c7Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 110935d5b7c7Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 111035d5b7c7Smrg Bool free_blob_data = FALSE; 111135d5b7c7Smrg uint32_t created_blob_id = 0; 111235d5b7c7Smrg uint32_t drm_prop_id; 111335d5b7c7Smrg size_t expected_bytes = 0; 111435d5b7c7Smrg void *blob_data = NULL; 111535d5b7c7Smrg int ret; 111635d5b7c7Smrg 111735d5b7c7Smrg switch (cm_prop_index) { 111835d5b7c7Smrg case CM_GAMMA_LUT: 111935d5b7c7Smrg /* Calculate the expected size of value in bytes */ 112035d5b7c7Smrg expected_bytes = sizeof(struct drm_color_lut) * 112135d5b7c7Smrg drmmode->gamma_lut_size; 112235d5b7c7Smrg 112335d5b7c7Smrg /* Legacy gamma LUT is disabled on deep 30bpp color. In which 112435d5b7c7Smrg * case, directly use non-legacy LUT. 112535d5b7c7Smrg */ 112635d5b7c7Smrg if (!crtc->funcs->gamma_set) { 112735d5b7c7Smrg blob_data = drmmode_crtc->gamma_lut; 112835d5b7c7Smrg goto do_push; 112935d5b7c7Smrg } 113035d5b7c7Smrg 113135d5b7c7Smrg blob_data = malloc(expected_bytes); 113235d5b7c7Smrg if (!blob_data) 113335d5b7c7Smrg return BadAlloc; 113435d5b7c7Smrg 113535d5b7c7Smrg free_blob_data = TRUE; 113635d5b7c7Smrg /* 113735d5b7c7Smrg * Compose legacy and non-legacy LUT if non-legacy was set. 113835d5b7c7Smrg * Otherwise, interpolate legacy LUT to non-legacy size. 113935d5b7c7Smrg */ 114035d5b7c7Smrg if (drmmode_crtc->gamma_lut) { 114135d5b7c7Smrg drmmode_lut_compose(crtc->gamma_red, 114235d5b7c7Smrg crtc->gamma_green, 114335d5b7c7Smrg crtc->gamma_blue, 114435d5b7c7Smrg drmmode_crtc->gamma_lut, 114535d5b7c7Smrg blob_data, crtc->gamma_size, 114635d5b7c7Smrg drmmode->gamma_lut_size); 114735d5b7c7Smrg } else { 114835d5b7c7Smrg drmmode_lut_interpolate(crtc->gamma_red, 114935d5b7c7Smrg crtc->gamma_green, 115035d5b7c7Smrg crtc->gamma_blue, 115135d5b7c7Smrg blob_data, 115235d5b7c7Smrg crtc->gamma_size, 115335d5b7c7Smrg drmmode->gamma_lut_size); 115435d5b7c7Smrg } 115535d5b7c7Smrg break; 115635d5b7c7Smrg case CM_DEGAMMA_LUT: 115735d5b7c7Smrg expected_bytes = sizeof(struct drm_color_lut) * 115835d5b7c7Smrg drmmode->degamma_lut_size; 115935d5b7c7Smrg blob_data = drmmode_crtc->degamma_lut; 116035d5b7c7Smrg break; 116135d5b7c7Smrg case CM_CTM: 116235d5b7c7Smrg expected_bytes = sizeof(struct drm_color_ctm); 116335d5b7c7Smrg blob_data = drmmode_crtc->ctm; 116435d5b7c7Smrg break; 116535d5b7c7Smrg default: 116635d5b7c7Smrg return BadName; 116735d5b7c7Smrg } 116835d5b7c7Smrg 116935d5b7c7Smrgdo_push: 117035d5b7c7Smrg if (blob_data) { 117135d5b7c7Smrg ret = drmModeCreatePropertyBlob(pAMDGPUEnt->fd, 117235d5b7c7Smrg blob_data, expected_bytes, 117335d5b7c7Smrg &created_blob_id); 117435d5b7c7Smrg if (ret) { 117535d5b7c7Smrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 117635d5b7c7Smrg "Creating DRM blob failed with errno %d\n", 117735d5b7c7Smrg ret); 117835d5b7c7Smrg if (free_blob_data) 117935d5b7c7Smrg free(blob_data); 118035d5b7c7Smrg return BadRequest; 118135d5b7c7Smrg } 118235d5b7c7Smrg } 118335d5b7c7Smrg 118435d5b7c7Smrg drm_prop_id = drmmode_crtc->drmmode->cm_prop_ids[cm_prop_index]; 118535d5b7c7Smrg ret = drmModeObjectSetProperty(pAMDGPUEnt->fd, 118635d5b7c7Smrg drmmode_crtc->mode_crtc->crtc_id, 118735d5b7c7Smrg DRM_MODE_OBJECT_CRTC, 118835d5b7c7Smrg drm_prop_id, 118935d5b7c7Smrg (uint64_t)created_blob_id); 119035d5b7c7Smrg 119135d5b7c7Smrg /* If successful, kernel will have a reference already. Safe to destroy 119235d5b7c7Smrg * the blob either way. 119335d5b7c7Smrg */ 119435d5b7c7Smrg if (blob_data) 119535d5b7c7Smrg drmModeDestroyPropertyBlob(pAMDGPUEnt->fd, created_blob_id); 119635d5b7c7Smrg 119735d5b7c7Smrg if (ret) { 119835d5b7c7Smrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 119935d5b7c7Smrg "Setting DRM property blob failed with errno %d\n", 120035d5b7c7Smrg ret); 120135d5b7c7Smrg if (free_blob_data) 120235d5b7c7Smrg free(blob_data); 120335d5b7c7Smrg return BadRequest; 120435d5b7c7Smrg } 120535d5b7c7Smrg 120635d5b7c7Smrg if (free_blob_data) 120735d5b7c7Smrg free(blob_data); 120835d5b7c7Smrg 120935d5b7c7Smrg return Success; 121035d5b7c7Smrg} 121135d5b7c7Smrg 121224b90cf4Smrgstatic void 121324b90cf4Smrgdrmmode_crtc_gamma_do_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, 121424b90cf4Smrg uint16_t *blue, int size) 121524b90cf4Smrg{ 121624b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 121724b90cf4Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 121835d5b7c7Smrg int ret; 121935d5b7c7Smrg 122035d5b7c7Smrg /* Use legacy if no support for non-legacy gamma */ 122135d5b7c7Smrg if (!drmmode_cm_enabled(drmmode_crtc->drmmode)) { 122235d5b7c7Smrg drmModeCrtcSetGamma(pAMDGPUEnt->fd, 122335d5b7c7Smrg drmmode_crtc->mode_crtc->crtc_id, 122435d5b7c7Smrg size, red, green, blue); 122535d5b7c7Smrg return; 122635d5b7c7Smrg } 122724b90cf4Smrg 122835d5b7c7Smrg ret = drmmode_crtc_push_cm_prop(crtc, CM_GAMMA_LUT); 122935d5b7c7Smrg if (ret) 123035d5b7c7Smrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 123135d5b7c7Smrg "Setting Gamma LUT failed with errno %d\n", 123235d5b7c7Smrg ret); 123324b90cf4Smrg} 123424b90cf4Smrg 123524b90cf4SmrgBool 123624b90cf4Smrgdrmmode_set_mode(xf86CrtcPtr crtc, struct drmmode_fb *fb, DisplayModePtr mode, 123724b90cf4Smrg int x, int y) 123824b90cf4Smrg{ 123924b90cf4Smrg ScrnInfoPtr scrn = crtc->scrn; 124024b90cf4Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 124124b90cf4Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 124224b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 124324b90cf4Smrg uint32_t *output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); 124424b90cf4Smrg int output_count = 0; 124524b90cf4Smrg drmModeModeInfo kmode; 124624b90cf4Smrg Bool ret; 124724b90cf4Smrg int i; 124824b90cf4Smrg 124924b90cf4Smrg if (!output_ids) 125024b90cf4Smrg return FALSE; 125124b90cf4Smrg 125224b90cf4Smrg for (i = 0; i < xf86_config->num_output; i++) { 125324b90cf4Smrg xf86OutputPtr output = xf86_config->output[i]; 125424b90cf4Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 125524b90cf4Smrg 125624b90cf4Smrg if (output->crtc != crtc) 125724b90cf4Smrg continue; 125824b90cf4Smrg 125924b90cf4Smrg output_ids[output_count] = drmmode_output->mode_output->connector_id; 126024b90cf4Smrg output_count++; 126124b90cf4Smrg } 126224b90cf4Smrg 126324b90cf4Smrg drmmode_ConvertToKMode(scrn, &kmode, mode); 126424b90cf4Smrg 126524b90cf4Smrg ret = drmModeSetCrtc(pAMDGPUEnt->fd, 126624b90cf4Smrg drmmode_crtc->mode_crtc->crtc_id, 126724b90cf4Smrg fb->handle, x, y, output_ids, 126824b90cf4Smrg output_count, &kmode) == 0; 126924b90cf4Smrg 127024b90cf4Smrg if (ret) { 127124b90cf4Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, fb); 127224b90cf4Smrg } else { 127324b90cf4Smrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 127424b90cf4Smrg "failed to set mode: %s\n", strerror(errno)); 127524b90cf4Smrg } 127624b90cf4Smrg 127724b90cf4Smrg free(output_ids); 127824b90cf4Smrg return ret; 127924b90cf4Smrg} 128024b90cf4Smrg 1281d6c0b56eSmrgstatic Bool 1282d6c0b56eSmrgdrmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, 1283d6c0b56eSmrg Rotation rotation, int x, int y) 1284d6c0b56eSmrg{ 1285d6c0b56eSmrg ScrnInfoPtr pScrn = crtc->scrn; 1286d6c0b56eSmrg ScreenPtr pScreen = pScrn->pScreen; 1287d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1288d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1289d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 1290d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 129111bf0794Smrg unsigned scanout_id = 0; 1292d6c0b56eSmrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 1293d6c0b56eSmrg int saved_x, saved_y; 1294d6c0b56eSmrg Rotation saved_rotation; 1295d6c0b56eSmrg DisplayModeRec saved_mode; 1296504d986fSmrg Bool ret = FALSE; 1297d6c0b56eSmrg int i; 129824b90cf4Smrg struct drmmode_fb *fb = NULL; 129924b90cf4Smrg 130024b90cf4Smrg /* The root window contents may be undefined before the WindowExposures 130124b90cf4Smrg * hook is called for it, so bail if we get here before that 130224b90cf4Smrg */ 130324b90cf4Smrg if (pScreen->WindowExposures == AMDGPUWindowExposures_oneshot) 130424b90cf4Smrg return FALSE; 1305d6c0b56eSmrg 1306d6c0b56eSmrg saved_mode = crtc->mode; 1307d6c0b56eSmrg saved_x = crtc->x; 1308d6c0b56eSmrg saved_y = crtc->y; 1309d6c0b56eSmrg saved_rotation = crtc->rotation; 1310d6c0b56eSmrg 1311d6c0b56eSmrg if (mode) { 1312d6c0b56eSmrg crtc->mode = *mode; 1313d6c0b56eSmrg crtc->x = x; 1314d6c0b56eSmrg crtc->y = y; 1315d6c0b56eSmrg crtc->rotation = rotation; 1316d6c0b56eSmrg 1317d6c0b56eSmrg if (!drmmode_handle_transform(crtc)) 1318d6c0b56eSmrg goto done; 1319d6c0b56eSmrg 132011bf0794Smrg drmmode_crtc_update_tear_free(crtc); 132111bf0794Smrg if (drmmode_crtc->tear_free) 132211bf0794Smrg scanout_id = drmmode_crtc->scanout_id; 132335d5b7c7Smrg else 132435d5b7c7Smrg drmmode_crtc->scanout_id = 0; 1325d6c0b56eSmrg 132624b90cf4Smrg if (drmmode_crtc->prime_scanout_pixmap) { 132711bf0794Smrg drmmode_crtc_prime_scanout_update(crtc, mode, scanout_id, 132824b90cf4Smrg &fb, &x, &y); 132924b90cf4Smrg } else if (drmmode_crtc->rotate.pixmap) { 133024b90cf4Smrg fb = amdgpu_pixmap_get_fb(drmmode_crtc->rotate.pixmap); 1331d6c0b56eSmrg x = y = 0; 133211bf0794Smrg 133324b90cf4Smrg } else if (!pScreen->isGPU && 133411bf0794Smrg (drmmode_crtc->tear_free || 1335504d986fSmrg crtc->driverIsPerformingTransform || 1336504d986fSmrg info->shadow_primary)) { 133711bf0794Smrg drmmode_crtc_scanout_update(crtc, mode, scanout_id, 133824b90cf4Smrg &fb, &x, &y); 1339d6c0b56eSmrg } 1340d6c0b56eSmrg 134124b90cf4Smrg if (!fb) 134224b90cf4Smrg fb = amdgpu_pixmap_get_fb(pScreen->GetWindowPixmap(pScreen->root)); 134324b90cf4Smrg if (!fb) { 134424b90cf4Smrg union gbm_bo_handle bo_handle; 134524b90cf4Smrg 134624b90cf4Smrg bo_handle = gbm_bo_get_handle(info->front_buffer->bo.gbm); 134724b90cf4Smrg fb = amdgpu_fb_create(pScrn, pAMDGPUEnt->fd, 134824b90cf4Smrg pScrn->virtualX, pScrn->virtualY, 134924b90cf4Smrg pScrn->displayWidth * info->pixel_bytes, 135024b90cf4Smrg bo_handle.u32); 135124b90cf4Smrg /* Prevent refcnt of ad-hoc FBs from reaching 2 */ 135224b90cf4Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, NULL); 135324b90cf4Smrg drmmode_crtc->fb = fb; 135424b90cf4Smrg } 135524b90cf4Smrg if (!fb) { 135624b90cf4Smrg ErrorF("failed to add FB for modeset\n"); 135724b90cf4Smrg goto done; 1358504d986fSmrg } 1359504d986fSmrg 136035d5b7c7Smrg amdgpu_drm_wait_pending_flip(crtc); 136124b90cf4Smrg 136224b90cf4Smrg if (!drmmode_set_mode(crtc, fb, mode, x, y)) 1363d6c0b56eSmrg goto done; 136424b90cf4Smrg 136524b90cf4Smrg ret = TRUE; 1366d6c0b56eSmrg 1367d6c0b56eSmrg if (pScreen) 1368d6c0b56eSmrg xf86CrtcSetScreenSubpixelOrder(pScreen); 1369d6c0b56eSmrg 1370d6c0b56eSmrg drmmode_crtc->need_modeset = FALSE; 1371d6c0b56eSmrg 1372d6c0b56eSmrg /* go through all the outputs and force DPMS them back on? */ 1373d6c0b56eSmrg for (i = 0; i < xf86_config->num_output; i++) { 1374d6c0b56eSmrg xf86OutputPtr output = xf86_config->output[i]; 1375d6c0b56eSmrg 1376d6c0b56eSmrg if (output->crtc != crtc) 1377d6c0b56eSmrg continue; 1378d6c0b56eSmrg 1379d6c0b56eSmrg output->funcs->dpms(output, DPMSModeOn); 1380d6c0b56eSmrg } 1381d6c0b56eSmrg } 1382d6c0b56eSmrg 1383d6c0b56eSmrg /* Compute index of this CRTC into xf86_config->crtc */ 1384d6c0b56eSmrg for (i = 0; i < xf86_config->num_crtc; i++) { 1385d6c0b56eSmrg if (xf86_config->crtc[i] != crtc) 1386d6c0b56eSmrg continue; 1387d6c0b56eSmrg 1388d6c0b56eSmrg if (!crtc->enabled || drmmode_can_use_hw_cursor(crtc)) 1389d6c0b56eSmrg info->hwcursor_disabled &= ~(1 << i); 1390d6c0b56eSmrg else 1391d6c0b56eSmrg info->hwcursor_disabled |= 1 << i; 1392d6c0b56eSmrg 1393d6c0b56eSmrg break; 1394d6c0b56eSmrg } 1395d6c0b56eSmrg 1396d6c0b56eSmrg#ifndef HAVE_XF86_CURSOR_RESET_CURSOR 1397d6c0b56eSmrg if (!info->hwcursor_disabled) 1398d6c0b56eSmrg xf86_reload_cursors(pScreen); 1399d6c0b56eSmrg#endif 1400d6c0b56eSmrg 1401d6c0b56eSmrgdone: 1402d6c0b56eSmrg if (!ret) { 1403d6c0b56eSmrg crtc->x = saved_x; 1404d6c0b56eSmrg crtc->y = saved_y; 1405d6c0b56eSmrg crtc->rotation = saved_rotation; 1406d6c0b56eSmrg crtc->mode = saved_mode; 1407504d986fSmrg } else { 1408d6c0b56eSmrg crtc->active = TRUE; 1409d6c0b56eSmrg 141024b90cf4Smrg if (drmmode_crtc->scanout[scanout_id].pixmap && 141124b90cf4Smrg fb != amdgpu_pixmap_get_fb(drmmode_crtc-> 141235d5b7c7Smrg scanout[scanout_id].pixmap)) { 141335d5b7c7Smrg amdgpu_drm_abort_entry(drmmode_crtc->scanout_update_pending); 141435d5b7c7Smrg drmmode_crtc->scanout_update_pending = 0; 1415504d986fSmrg drmmode_crtc_scanout_free(drmmode_crtc); 141635d5b7c7Smrg } else if (!drmmode_crtc->tear_free) { 141711bf0794Smrg drmmode_crtc_scanout_destroy(drmmode, 141811bf0794Smrg &drmmode_crtc->scanout[1]); 141911bf0794Smrg } 1420504d986fSmrg } 1421504d986fSmrg 142235d5b7c7Smrg amdgpu_drm_queue_handle_deferred(crtc); 1423d6c0b56eSmrg return ret; 1424d6c0b56eSmrg} 1425d6c0b56eSmrg 1426d6c0b56eSmrgstatic void drmmode_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg) 1427d6c0b56eSmrg{ 1428d6c0b56eSmrg 1429d6c0b56eSmrg} 1430d6c0b56eSmrg 1431d6c0b56eSmrgstatic void drmmode_set_cursor_position(xf86CrtcPtr crtc, int x, int y) 1432d6c0b56eSmrg{ 1433d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1434d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 1435d6c0b56eSmrg 143624b90cf4Smrg#if XF86_CRTC_VERSION < 7 1437d6c0b56eSmrg if (crtc->driverIsPerformingTransform) { 1438d6c0b56eSmrg x += crtc->x; 1439d6c0b56eSmrg y += crtc->y; 1440d6c0b56eSmrg xf86CrtcTransformCursorPos(crtc, &x, &y); 1441d6c0b56eSmrg } 1442d6c0b56eSmrg#endif 1443d6c0b56eSmrg 1444d6c0b56eSmrg drmModeMoveCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, x, y); 1445d6c0b56eSmrg} 1446d6c0b56eSmrg 144724b90cf4Smrg#if XF86_CRTC_VERSION < 7 1448d6c0b56eSmrg 1449d6c0b56eSmrgstatic int 1450d6c0b56eSmrgdrmmode_cursor_src_offset(Rotation rotation, int width, int height, 1451d6c0b56eSmrg int x_dst, int y_dst) 1452d6c0b56eSmrg{ 1453d6c0b56eSmrg int t; 1454d6c0b56eSmrg 1455d6c0b56eSmrg switch (rotation & 0xf) { 1456d6c0b56eSmrg case RR_Rotate_90: 1457d6c0b56eSmrg t = x_dst; 1458d6c0b56eSmrg x_dst = height - y_dst - 1; 1459d6c0b56eSmrg y_dst = t; 1460d6c0b56eSmrg break; 1461d6c0b56eSmrg case RR_Rotate_180: 1462d6c0b56eSmrg x_dst = width - x_dst - 1; 1463d6c0b56eSmrg y_dst = height - y_dst - 1; 1464d6c0b56eSmrg break; 1465d6c0b56eSmrg case RR_Rotate_270: 1466d6c0b56eSmrg t = x_dst; 1467d6c0b56eSmrg x_dst = y_dst; 1468d6c0b56eSmrg y_dst = width - t - 1; 1469d6c0b56eSmrg break; 1470d6c0b56eSmrg } 1471d6c0b56eSmrg 1472d6c0b56eSmrg if (rotation & RR_Reflect_X) 1473d6c0b56eSmrg x_dst = width - x_dst - 1; 1474d6c0b56eSmrg if (rotation & RR_Reflect_Y) 1475d6c0b56eSmrg y_dst = height - y_dst - 1; 1476d6c0b56eSmrg 1477d6c0b56eSmrg return y_dst * height + x_dst; 1478d6c0b56eSmrg} 1479d6c0b56eSmrg 1480d6c0b56eSmrg#endif 1481d6c0b56eSmrg 148235d5b7c7Smrgstatic uint32_t 148335d5b7c7Smrgdrmmode_cursor_gamma_passthrough(xf86CrtcPtr crtc, uint32_t argb) 148435d5b7c7Smrg{ 148535d5b7c7Smrg uint32_t alpha = argb >> 24; 148635d5b7c7Smrg 148735d5b7c7Smrg if (!alpha) 148835d5b7c7Smrg return 0; 148935d5b7c7Smrg 149035d5b7c7Smrg return argb; 149135d5b7c7Smrg} 149235d5b7c7Smrg 149324b90cf4Smrgstatic uint32_t 149424b90cf4Smrgdrmmode_cursor_gamma(xf86CrtcPtr crtc, uint32_t argb) 149524b90cf4Smrg{ 149624b90cf4Smrg uint32_t alpha = argb >> 24; 149724b90cf4Smrg uint32_t rgb[3]; 149824b90cf4Smrg int i; 149924b90cf4Smrg 150024b90cf4Smrg if (!alpha) 150124b90cf4Smrg return 0; 150224b90cf4Smrg 150324b90cf4Smrg /* Un-premultiply alpha */ 150424b90cf4Smrg for (i = 0; i < 3; i++) 150524b90cf4Smrg rgb[i] = ((argb >> (i * 8)) & 0xff) * 0xff / alpha; 150624b90cf4Smrg 150724b90cf4Smrg /* Apply gamma correction and pre-multiply alpha */ 150824b90cf4Smrg rgb[0] = (crtc->gamma_blue[rgb[0]] >> 8) * alpha / 0xff; 150924b90cf4Smrg rgb[1] = (crtc->gamma_green[rgb[1]] >> 8) * alpha / 0xff; 151024b90cf4Smrg rgb[2] = (crtc->gamma_red[rgb[2]] >> 8) * alpha / 0xff; 151124b90cf4Smrg 151224b90cf4Smrg return alpha << 24 | rgb[2] << 16 | rgb[1] << 8 | rgb[0]; 151324b90cf4Smrg} 151424b90cf4Smrg 1515d6c0b56eSmrgstatic void drmmode_do_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image, uint32_t *ptr) 1516d6c0b56eSmrg{ 1517d6c0b56eSmrg ScrnInfoPtr pScrn = crtc->scrn; 1518d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 151935d5b7c7Smrg uint32_t (*cursor_gamma)(xf86CrtcPtr crtc, uint32_t argb) = 152035d5b7c7Smrg drmmode_cursor_gamma; 152135d5b7c7Smrg 152235d5b7c7Smrg if ((crtc->scrn->depth != 24 && crtc->scrn->depth != 32) || 152335d5b7c7Smrg drmmode_cm_enabled(&info->drmmode)) 152435d5b7c7Smrg cursor_gamma = drmmode_cursor_gamma_passthrough; 1525d6c0b56eSmrg 152624b90cf4Smrg#if XF86_CRTC_VERSION < 7 1527d6c0b56eSmrg if (crtc->driverIsPerformingTransform) { 1528d6c0b56eSmrg uint32_t cursor_w = info->cursor_w, cursor_h = info->cursor_h; 1529d6c0b56eSmrg int dstx, dsty; 1530d6c0b56eSmrg int srcoffset; 1531d6c0b56eSmrg 1532d6c0b56eSmrg for (dsty = 0; dsty < cursor_h; dsty++) { 1533d6c0b56eSmrg for (dstx = 0; dstx < cursor_w; dstx++) { 1534d6c0b56eSmrg srcoffset = drmmode_cursor_src_offset(crtc->rotation, 1535d6c0b56eSmrg cursor_w, 1536d6c0b56eSmrg cursor_h, 1537d6c0b56eSmrg dstx, dsty); 1538d6c0b56eSmrg 1539d6c0b56eSmrg ptr[dsty * info->cursor_w + dstx] = 154035d5b7c7Smrg cpu_to_le32(cursor_gamma(crtc, image[srcoffset])); 1541d6c0b56eSmrg } 1542d6c0b56eSmrg } 1543d6c0b56eSmrg } else 1544d6c0b56eSmrg#endif 1545d6c0b56eSmrg { 1546d6c0b56eSmrg uint32_t cursor_size = info->cursor_w * info->cursor_h; 1547d6c0b56eSmrg int i; 1548d6c0b56eSmrg 1549d6c0b56eSmrg for (i = 0; i < cursor_size; i++) 155035d5b7c7Smrg ptr[i] = cpu_to_le32(cursor_gamma(crtc, image[i])); 1551d6c0b56eSmrg } 1552d6c0b56eSmrg} 1553d6c0b56eSmrg 1554d6c0b56eSmrgstatic void drmmode_load_cursor_argb(xf86CrtcPtr crtc, CARD32 * image) 1555d6c0b56eSmrg{ 1556d6c0b56eSmrg ScrnInfoPtr pScrn = crtc->scrn; 1557d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1558d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1559d6c0b56eSmrg uint32_t cursor_size = info->cursor_w * info->cursor_h; 1560d6c0b56eSmrg 1561d6c0b56eSmrg if (info->gbm) { 1562d6c0b56eSmrg uint32_t ptr[cursor_size]; 1563d6c0b56eSmrg 1564d6c0b56eSmrg drmmode_do_load_cursor_argb(crtc, image, ptr); 1565d6c0b56eSmrg gbm_bo_write(drmmode_crtc->cursor_buffer->bo.gbm, ptr, cursor_size * 4); 1566d6c0b56eSmrg } else { 1567d6c0b56eSmrg /* cursor should be mapped already */ 1568d6c0b56eSmrg uint32_t *ptr = (uint32_t *) (drmmode_crtc->cursor_buffer->cpu_ptr); 1569d6c0b56eSmrg 1570d6c0b56eSmrg drmmode_do_load_cursor_argb(crtc, image, ptr); 1571d6c0b56eSmrg } 1572d6c0b56eSmrg} 1573d6c0b56eSmrg 1574d6c0b56eSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 1575d6c0b56eSmrg 1576d6c0b56eSmrgstatic Bool drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 * image) 1577d6c0b56eSmrg{ 1578d6c0b56eSmrg if (!drmmode_can_use_hw_cursor(crtc)) 1579d6c0b56eSmrg return FALSE; 1580d6c0b56eSmrg 1581d6c0b56eSmrg drmmode_load_cursor_argb(crtc, image); 1582d6c0b56eSmrg return TRUE; 1583d6c0b56eSmrg} 1584d6c0b56eSmrg 1585d6c0b56eSmrg#endif 1586d6c0b56eSmrg 1587d6c0b56eSmrgstatic void drmmode_hide_cursor(xf86CrtcPtr crtc) 1588d6c0b56eSmrg{ 1589d6c0b56eSmrg ScrnInfoPtr pScrn = crtc->scrn; 1590d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1591d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1592d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1593d6c0b56eSmrg 1594d6c0b56eSmrg drmModeSetCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 1595d6c0b56eSmrg info->cursor_w, info->cursor_h); 1596d6c0b56eSmrg 1597d6c0b56eSmrg} 1598d6c0b56eSmrg 1599d6c0b56eSmrgstatic void drmmode_show_cursor(xf86CrtcPtr crtc) 1600d6c0b56eSmrg{ 1601d6c0b56eSmrg ScrnInfoPtr pScrn = crtc->scrn; 1602d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1603d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1604d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1605d6c0b56eSmrg uint32_t bo_handle; 1606d6c0b56eSmrg static Bool use_set_cursor2 = TRUE; 1607d6c0b56eSmrg 1608d6c0b56eSmrg if (!amdgpu_bo_get_handle(drmmode_crtc->cursor_buffer, &bo_handle)) { 1609d6c0b56eSmrg ErrorF("failed to get BO handle for cursor\n"); 1610d6c0b56eSmrg return; 1611d6c0b56eSmrg } 1612d6c0b56eSmrg 1613d6c0b56eSmrg if (use_set_cursor2) { 1614d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 1615d6c0b56eSmrg CursorPtr cursor = xf86_config->cursor; 1616504d986fSmrg int xhot = cursor->bits->xhot; 1617504d986fSmrg int yhot = cursor->bits->yhot; 1618d6c0b56eSmrg int ret; 1619d6c0b56eSmrg 1620504d986fSmrg if (crtc->rotation != RR_Rotate_0 && 1621504d986fSmrg crtc->rotation != (RR_Rotate_180 | RR_Reflect_X | 1622504d986fSmrg RR_Reflect_Y)) { 1623504d986fSmrg int t; 1624504d986fSmrg 1625504d986fSmrg /* Reflect & rotate hotspot position */ 1626504d986fSmrg if (crtc->rotation & RR_Reflect_X) 1627504d986fSmrg xhot = info->cursor_w - xhot - 1; 1628504d986fSmrg if (crtc->rotation & RR_Reflect_Y) 1629504d986fSmrg yhot = info->cursor_h - yhot - 1; 1630504d986fSmrg 1631504d986fSmrg switch (crtc->rotation & 0xf) { 1632504d986fSmrg case RR_Rotate_90: 1633504d986fSmrg t = xhot; 1634504d986fSmrg xhot = yhot; 1635504d986fSmrg yhot = info->cursor_w - t - 1; 1636504d986fSmrg break; 1637504d986fSmrg case RR_Rotate_180: 1638504d986fSmrg xhot = info->cursor_w - xhot - 1; 1639504d986fSmrg yhot = info->cursor_h - yhot - 1; 1640504d986fSmrg break; 1641504d986fSmrg case RR_Rotate_270: 1642504d986fSmrg t = xhot; 1643504d986fSmrg xhot = info->cursor_h - yhot - 1; 1644504d986fSmrg yhot = t; 1645504d986fSmrg } 1646504d986fSmrg } 1647504d986fSmrg 1648d6c0b56eSmrg ret = drmModeSetCursor2(pAMDGPUEnt->fd, 1649d6c0b56eSmrg drmmode_crtc->mode_crtc->crtc_id, 1650d6c0b56eSmrg bo_handle, 1651d6c0b56eSmrg info->cursor_w, info->cursor_h, 1652504d986fSmrg xhot, yhot); 1653d6c0b56eSmrg if (ret == -EINVAL) 1654d6c0b56eSmrg use_set_cursor2 = FALSE; 1655d6c0b56eSmrg else 1656d6c0b56eSmrg return; 1657d6c0b56eSmrg } 1658d6c0b56eSmrg 1659d6c0b56eSmrg drmModeSetCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, bo_handle, 1660d6c0b56eSmrg info->cursor_w, info->cursor_h); 1661d6c0b56eSmrg} 1662d6c0b56eSmrg 166311bf0794Smrg/* Xorg expects a non-NULL return value from drmmode_crtc_shadow_allocate, and 166411bf0794Smrg * passes that back to drmmode_crtc_scanout_create; it doesn't use it for 166511bf0794Smrg * anything else. 166611bf0794Smrg */ 166711bf0794Smrgstatic void * 166811bf0794Smrgdrmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) 1669d6c0b56eSmrg{ 1670d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1671d6c0b56eSmrg 167211bf0794Smrg if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width, 167311bf0794Smrg height)) 167411bf0794Smrg return NULL; 167511bf0794Smrg 167611bf0794Smrg return (void*)~0UL; 1677d6c0b56eSmrg} 1678d6c0b56eSmrg 1679d6c0b56eSmrgstatic PixmapPtr 1680d6c0b56eSmrgdrmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) 1681d6c0b56eSmrg{ 1682d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1683d6c0b56eSmrg 168411bf0794Smrg if (!data) { 168511bf0794Smrg drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width, 168611bf0794Smrg height); 168711bf0794Smrg } 168811bf0794Smrg 168911bf0794Smrg return drmmode_crtc->rotate.pixmap; 1690d6c0b56eSmrg} 1691d6c0b56eSmrg 1692d6c0b56eSmrgstatic void 1693d6c0b56eSmrgdrmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, 1694d6c0b56eSmrg void *data) 1695d6c0b56eSmrg{ 1696d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1697d6c0b56eSmrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 1698d6c0b56eSmrg 1699d6c0b56eSmrg drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->rotate); 1700d6c0b56eSmrg} 1701d6c0b56eSmrg 1702d6c0b56eSmrgstatic void 1703d6c0b56eSmrgdrmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t * red, uint16_t * green, 1704d6c0b56eSmrg uint16_t * blue, int size) 1705d6c0b56eSmrg{ 170624b90cf4Smrg ScrnInfoPtr scrn = crtc->scrn; 170724b90cf4Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 170824b90cf4Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 170924b90cf4Smrg int i; 1710d6c0b56eSmrg 171124b90cf4Smrg drmmode_crtc_gamma_do_set(crtc, red, green, blue, size); 171224b90cf4Smrg 171324b90cf4Smrg /* Compute index of this CRTC into xf86_config->crtc */ 171424b90cf4Smrg for (i = 0; xf86_config->crtc[i] != crtc; i++) {} 171524b90cf4Smrg 171624b90cf4Smrg if (info->hwcursor_disabled & (1 << i)) 171724b90cf4Smrg return; 171824b90cf4Smrg 171924b90cf4Smrg#ifdef HAVE_XF86_CURSOR_RESET_CURSOR 172024b90cf4Smrg xf86CursorResetCursor(scrn->pScreen); 172124b90cf4Smrg#else 172224b90cf4Smrg xf86_reload_cursors(scrn->pScreen); 172324b90cf4Smrg#endif 1724d6c0b56eSmrg} 1725d6c0b56eSmrg 1726d6c0b56eSmrgstatic Bool drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) 1727d6c0b56eSmrg{ 1728d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 172911bf0794Smrg unsigned scanout_id = drmmode_crtc->scanout_id; 1730504d986fSmrg ScreenPtr screen = crtc->scrn->pScreen; 1731504d986fSmrg PixmapDirtyUpdatePtr dirty; 1732d6c0b56eSmrg 1733504d986fSmrg xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { 173424b90cf4Smrg if (amdgpu_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) { 173524b90cf4Smrg PixmapStopDirtyTracking(dirty->src, dirty->slave_dst); 173624b90cf4Smrg break; 173724b90cf4Smrg } 1738d6c0b56eSmrg } 1739d6c0b56eSmrg 174024b90cf4Smrg drmmode_crtc_scanout_free(drmmode_crtc); 174124b90cf4Smrg drmmode_crtc->prime_scanout_pixmap = NULL; 174224b90cf4Smrg 1743504d986fSmrg if (!ppix) 1744504d986fSmrg return TRUE; 1745504d986fSmrg 1746504d986fSmrg if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[0], 1747504d986fSmrg ppix->drawable.width, 1748504d986fSmrg ppix->drawable.height)) 1749504d986fSmrg return FALSE; 1750d6c0b56eSmrg 175111bf0794Smrg if (drmmode_crtc->tear_free && 1752504d986fSmrg !drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], 1753504d986fSmrg ppix->drawable.width, 1754504d986fSmrg ppix->drawable.height)) { 1755504d986fSmrg drmmode_crtc_scanout_free(drmmode_crtc); 1756504d986fSmrg return FALSE; 1757d6c0b56eSmrg } 1758504d986fSmrg 175924b90cf4Smrg drmmode_crtc->prime_scanout_pixmap = ppix; 176024b90cf4Smrg 176124b90cf4Smrg#ifdef HAS_DIRTYTRACKING_DRAWABLE_SRC 176224b90cf4Smrg PixmapStartDirtyTracking(&ppix->drawable, 176324b90cf4Smrg drmmode_crtc->scanout[scanout_id].pixmap, 176424b90cf4Smrg 0, 0, 0, 0, RR_Rotate_0); 176524b90cf4Smrg#elif defined(HAS_DIRTYTRACKING_ROTATION) 176611bf0794Smrg PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 1767504d986fSmrg 0, 0, 0, 0, RR_Rotate_0); 1768d6c0b56eSmrg#elif defined(HAS_DIRTYTRACKING2) 176911bf0794Smrg PixmapStartDirtyTracking2(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 1770504d986fSmrg 0, 0, 0, 0); 1771d6c0b56eSmrg#else 177211bf0794Smrg PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 0, 0); 1773d6c0b56eSmrg#endif 1774d6c0b56eSmrg return TRUE; 1775d6c0b56eSmrg} 1776d6c0b56eSmrg 177735d5b7c7Smrgstatic void drmmode_crtc_destroy(xf86CrtcPtr crtc) 177835d5b7c7Smrg{ 177935d5b7c7Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 178035d5b7c7Smrg 178135d5b7c7Smrg drmModeFreeCrtc(drmmode_crtc->mode_crtc); 178235d5b7c7Smrg 178335d5b7c7Smrg /* Free LUTs and CTM */ 178435d5b7c7Smrg free(drmmode_crtc->gamma_lut); 178535d5b7c7Smrg free(drmmode_crtc->degamma_lut); 178635d5b7c7Smrg free(drmmode_crtc->ctm); 178735d5b7c7Smrg 178835d5b7c7Smrg free(drmmode_crtc); 178935d5b7c7Smrg crtc->driver_private = NULL; 179035d5b7c7Smrg} 179135d5b7c7Smrg 179235d5b7c7Smrg 1793d6c0b56eSmrgstatic xf86CrtcFuncsRec drmmode_crtc_funcs = { 1794d6c0b56eSmrg .dpms = drmmode_crtc_dpms, 1795d6c0b56eSmrg .set_mode_major = drmmode_set_mode_major, 1796d6c0b56eSmrg .set_cursor_colors = drmmode_set_cursor_colors, 1797d6c0b56eSmrg .set_cursor_position = drmmode_set_cursor_position, 1798d6c0b56eSmrg .show_cursor = drmmode_show_cursor, 1799d6c0b56eSmrg .hide_cursor = drmmode_hide_cursor, 1800d6c0b56eSmrg .load_cursor_argb = drmmode_load_cursor_argb, 1801d6c0b56eSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 1802d6c0b56eSmrg .load_cursor_argb_check = drmmode_load_cursor_argb_check, 1803d6c0b56eSmrg#endif 1804d6c0b56eSmrg 1805d6c0b56eSmrg .gamma_set = drmmode_crtc_gamma_set, 1806d6c0b56eSmrg .shadow_create = drmmode_crtc_shadow_create, 1807d6c0b56eSmrg .shadow_allocate = drmmode_crtc_shadow_allocate, 1808d6c0b56eSmrg .shadow_destroy = drmmode_crtc_shadow_destroy, 180935d5b7c7Smrg .destroy = drmmode_crtc_destroy, 1810d6c0b56eSmrg .set_scanout_pixmap = drmmode_set_scanout_pixmap, 1811d6c0b56eSmrg}; 1812d6c0b56eSmrg 1813d6c0b56eSmrgint drmmode_get_crtc_id(xf86CrtcPtr crtc) 1814d6c0b56eSmrg{ 1815d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1816d6c0b56eSmrg return drmmode_crtc->hw_id; 1817d6c0b56eSmrg} 1818d6c0b56eSmrg 1819d6c0b56eSmrgvoid drmmode_crtc_hw_id(xf86CrtcPtr crtc) 1820d6c0b56eSmrg{ 1821d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1822d6c0b56eSmrg ScrnInfoPtr pScrn = crtc->scrn; 1823d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1824d6c0b56eSmrg int r; 1825d6c0b56eSmrg 1826d6c0b56eSmrg r = amdgpu_query_crtc_from_id(pAMDGPUEnt->pDev, 1827d6c0b56eSmrg drmmode_crtc->mode_crtc->crtc_id, 1828d6c0b56eSmrg &drmmode_crtc->hw_id); 1829d6c0b56eSmrg if (r) 1830d6c0b56eSmrg drmmode_crtc->hw_id = -1; 1831d6c0b56eSmrg} 1832d6c0b56eSmrg 183335d5b7c7Smrg/** 183435d5b7c7Smrg * Initialize color management properties for the given CRTC by programming 183535d5b7c7Smrg * the default gamma/degamma LUTs and CTM. 183635d5b7c7Smrg * 183735d5b7c7Smrg * If the CRTC does not support color management, or if errors occur during 183835d5b7c7Smrg * initialization, all color properties on the driver-private CRTC will left 183935d5b7c7Smrg * as NULL. 184035d5b7c7Smrg * 184135d5b7c7Smrg * @drm_fd: DRM file descriptor 184235d5b7c7Smrg * @crtc: CRTC to initialize color management on. 184335d5b7c7Smrg */ 184435d5b7c7Smrgstatic void drmmode_crtc_cm_init(int drm_fd, xf86CrtcPtr crtc) 184535d5b7c7Smrg{ 184635d5b7c7Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 184735d5b7c7Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 184835d5b7c7Smrg int i; 184935d5b7c7Smrg 185035d5b7c7Smrg if (!drmmode_cm_enabled(drmmode)) 185135d5b7c7Smrg return; 185235d5b7c7Smrg 185335d5b7c7Smrg /* Init CTM to identity. Values are in S31.32 fixed-point format */ 185435d5b7c7Smrg drmmode_crtc->ctm = calloc(1, sizeof(*drmmode_crtc->ctm)); 185535d5b7c7Smrg if (!drmmode_crtc->ctm) { 185635d5b7c7Smrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 185735d5b7c7Smrg "Memory error initializing CTM for CRTC%d", 185835d5b7c7Smrg drmmode_get_crtc_id(crtc)); 185935d5b7c7Smrg return; 186035d5b7c7Smrg } 186135d5b7c7Smrg 186235d5b7c7Smrg drmmode_crtc->ctm->matrix[0] = drmmode_crtc->ctm->matrix[4] = 186335d5b7c7Smrg drmmode_crtc->ctm->matrix[8] = (uint64_t)1 << 32; 186435d5b7c7Smrg 186535d5b7c7Smrg /* Push properties to reset properties currently in hardware */ 186635d5b7c7Smrg for (i = 0; i < CM_GAMMA_LUT; i++) { 186735d5b7c7Smrg if (drmmode_crtc_push_cm_prop(crtc, i)) 186835d5b7c7Smrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 186935d5b7c7Smrg "Failed to initialize color management " 187035d5b7c7Smrg "property %s on CRTC%d. Property value may " 187135d5b7c7Smrg "not reflect actual hardware state.\n", 187235d5b7c7Smrg cm_prop_names[i], 187335d5b7c7Smrg drmmode_get_crtc_id(crtc)); 187435d5b7c7Smrg } 187535d5b7c7Smrg} 187635d5b7c7Smrg 1877d6c0b56eSmrgstatic unsigned int 1878d6c0b56eSmrgdrmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num) 1879d6c0b56eSmrg{ 1880d6c0b56eSmrg xf86CrtcPtr crtc; 1881d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc; 1882d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 188324b90cf4Smrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1884d6c0b56eSmrg 188524b90cf4Smrg crtc = xf86CrtcCreate(pScrn, &info->drmmode_crtc_funcs); 188635d5b7c7Smrg if (!crtc) 1887d6c0b56eSmrg return 0; 1888d6c0b56eSmrg 1889d6c0b56eSmrg drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1); 1890d6c0b56eSmrg drmmode_crtc->mode_crtc = 1891d6c0b56eSmrg drmModeGetCrtc(pAMDGPUEnt->fd, mode_res->crtcs[num]); 1892d6c0b56eSmrg drmmode_crtc->drmmode = drmmode; 1893d6c0b56eSmrg drmmode_crtc->dpms_mode = DPMSModeOff; 1894d6c0b56eSmrg crtc->driver_private = drmmode_crtc; 1895d6c0b56eSmrg drmmode_crtc_hw_id(crtc); 1896d6c0b56eSmrg 189735d5b7c7Smrg drmmode_crtc_cm_init(pAMDGPUEnt->fd, crtc); 189835d5b7c7Smrg 1899d6c0b56eSmrg /* Mark num'th crtc as in use on this device. */ 1900d6c0b56eSmrg pAMDGPUEnt->assigned_crtcs |= (1 << num); 1901d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 1902d6c0b56eSmrg "Allocated crtc nr. %d to this screen.\n", num); 1903d6c0b56eSmrg 1904d6c0b56eSmrg return 1; 1905d6c0b56eSmrg} 1906d6c0b56eSmrg 190724b90cf4Smrg/* 190824b90cf4Smrg * Update all of the property values for an output 190924b90cf4Smrg */ 191024b90cf4Smrgstatic void 191124b90cf4Smrgdrmmode_output_update_properties(xf86OutputPtr output) 191224b90cf4Smrg{ 191324b90cf4Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 191424b90cf4Smrg int i, j, k; 191524b90cf4Smrg int err; 191624b90cf4Smrg drmModeConnectorPtr koutput; 191724b90cf4Smrg 191824b90cf4Smrg /* Use the most recently fetched values from the kernel */ 191924b90cf4Smrg koutput = drmmode_output->mode_output; 192024b90cf4Smrg 192124b90cf4Smrg if (!koutput) 192224b90cf4Smrg return; 192324b90cf4Smrg 192424b90cf4Smrg for (i = 0; i < drmmode_output->num_props; i++) { 192524b90cf4Smrg drmmode_prop_ptr p = &drmmode_output->props[i]; 192624b90cf4Smrg 192724b90cf4Smrg for (j = 0; j < koutput->count_props; j++) { 192824b90cf4Smrg if (koutput->props[j] != p->mode_prop->prop_id) 192924b90cf4Smrg continue; 193024b90cf4Smrg 193124b90cf4Smrg /* Check to see if the property value has changed */ 193224b90cf4Smrg if (koutput->prop_values[j] == p->value) 193324b90cf4Smrg break; 193424b90cf4Smrg 193524b90cf4Smrg p->value = koutput->prop_values[j]; 193624b90cf4Smrg 193724b90cf4Smrg if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 193824b90cf4Smrg INT32 value = p->value; 193924b90cf4Smrg 194024b90cf4Smrg err = RRChangeOutputProperty(output->randr_output, 194124b90cf4Smrg p->atoms[0], XA_INTEGER, 194224b90cf4Smrg 32, PropModeReplace, 1, 194324b90cf4Smrg &value, FALSE, TRUE); 194424b90cf4Smrg if (err != 0) { 194524b90cf4Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 194624b90cf4Smrg "RRChangeOutputProperty error, %d\n", 194724b90cf4Smrg err); 194824b90cf4Smrg } 194924b90cf4Smrg } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 195024b90cf4Smrg for (k = 0; k < p->mode_prop->count_enums; k++) { 195124b90cf4Smrg if (p->mode_prop->enums[k].value == p->value) 195224b90cf4Smrg break; 195324b90cf4Smrg } 195424b90cf4Smrg if (k < p->mode_prop->count_enums) { 195524b90cf4Smrg err = RRChangeOutputProperty(output->randr_output, 195624b90cf4Smrg p->atoms[0], XA_ATOM, 195724b90cf4Smrg 32, PropModeReplace, 1, 195824b90cf4Smrg &p->atoms[k + 1], FALSE, 195924b90cf4Smrg TRUE); 196024b90cf4Smrg if (err != 0) { 196124b90cf4Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 196224b90cf4Smrg "RRChangeOutputProperty error, %d\n", 196324b90cf4Smrg err); 196424b90cf4Smrg } 196524b90cf4Smrg } 196624b90cf4Smrg } 196724b90cf4Smrg 196824b90cf4Smrg break; 196924b90cf4Smrg } 197024b90cf4Smrg } 197124b90cf4Smrg} 197224b90cf4Smrg 1973d6c0b56eSmrgstatic xf86OutputStatus drmmode_output_detect(xf86OutputPtr output) 1974d6c0b56eSmrg{ 1975d6c0b56eSmrg /* go to the hw and retrieve a new output struct */ 1976d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1977d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 1978d6c0b56eSmrg xf86OutputStatus status; 1979d6c0b56eSmrg drmModeFreeConnector(drmmode_output->mode_output); 1980d6c0b56eSmrg 1981d6c0b56eSmrg drmmode_output->mode_output = 1982d6c0b56eSmrg drmModeGetConnector(pAMDGPUEnt->fd, drmmode_output->output_id); 198324b90cf4Smrg if (!drmmode_output->mode_output) { 198424b90cf4Smrg drmmode_output->output_id = -1; 1985d6c0b56eSmrg return XF86OutputStatusDisconnected; 198624b90cf4Smrg } 198724b90cf4Smrg 198824b90cf4Smrg drmmode_output_update_properties(output); 1989d6c0b56eSmrg 1990d6c0b56eSmrg switch (drmmode_output->mode_output->connection) { 1991d6c0b56eSmrg case DRM_MODE_CONNECTED: 1992d6c0b56eSmrg status = XF86OutputStatusConnected; 1993d6c0b56eSmrg break; 1994d6c0b56eSmrg case DRM_MODE_DISCONNECTED: 1995d6c0b56eSmrg status = XF86OutputStatusDisconnected; 1996d6c0b56eSmrg break; 1997d6c0b56eSmrg default: 1998d6c0b56eSmrg case DRM_MODE_UNKNOWNCONNECTION: 1999d6c0b56eSmrg status = XF86OutputStatusUnknown; 2000d6c0b56eSmrg break; 2001d6c0b56eSmrg } 2002d6c0b56eSmrg return status; 2003d6c0b56eSmrg} 2004d6c0b56eSmrg 2005d6c0b56eSmrgstatic Bool 2006d6c0b56eSmrgdrmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes) 2007d6c0b56eSmrg{ 2008d6c0b56eSmrg return MODE_OK; 2009d6c0b56eSmrg} 2010d6c0b56eSmrg 201124b90cf4Smrgstatic int 201224b90cf4Smrgkoutput_get_prop_idx(int fd, drmModeConnectorPtr koutput, 201324b90cf4Smrg int type, const char *name) 201424b90cf4Smrg{ 201524b90cf4Smrg int idx = -1; 201624b90cf4Smrg 201724b90cf4Smrg for (int i = 0; i < koutput->count_props; i++) { 201824b90cf4Smrg drmModePropertyPtr prop = drmModeGetProperty(fd, koutput->props[i]); 201924b90cf4Smrg 202024b90cf4Smrg if (!prop) 202124b90cf4Smrg continue; 202224b90cf4Smrg 202324b90cf4Smrg if (drm_property_type_is(prop, type) && !strcmp(prop->name, name)) 202424b90cf4Smrg idx = i; 202524b90cf4Smrg 202624b90cf4Smrg drmModeFreeProperty(prop); 202724b90cf4Smrg 202824b90cf4Smrg if (idx > -1) 202924b90cf4Smrg break; 203024b90cf4Smrg } 203124b90cf4Smrg 203224b90cf4Smrg return idx; 203324b90cf4Smrg} 203424b90cf4Smrg 203524b90cf4Smrgstatic int 203624b90cf4Smrgkoutput_get_prop_id(int fd, drmModeConnectorPtr koutput, 203724b90cf4Smrg int type, const char *name) 203824b90cf4Smrg{ 203924b90cf4Smrg int idx = koutput_get_prop_idx(fd, koutput, type, name); 204024b90cf4Smrg 204124b90cf4Smrg return (idx > -1) ? koutput->props[idx] : -1; 204224b90cf4Smrg} 204324b90cf4Smrg 204424b90cf4Smrgstatic drmModePropertyBlobPtr 204524b90cf4Smrgkoutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name) 204624b90cf4Smrg{ 204724b90cf4Smrg drmModePropertyBlobPtr blob = NULL; 204824b90cf4Smrg int idx = koutput_get_prop_idx(fd, koutput, DRM_MODE_PROP_BLOB, name); 204924b90cf4Smrg 205024b90cf4Smrg if (idx > -1) 205124b90cf4Smrg blob = drmModeGetPropertyBlob(fd, koutput->prop_values[idx]); 205224b90cf4Smrg 205324b90cf4Smrg return blob; 205424b90cf4Smrg} 205524b90cf4Smrg 2056d6c0b56eSmrgstatic DisplayModePtr drmmode_output_get_modes(xf86OutputPtr output) 2057d6c0b56eSmrg{ 2058d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 2059d6c0b56eSmrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 2060d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 2061d6c0b56eSmrg int i; 2062d6c0b56eSmrg DisplayModePtr Modes = NULL, Mode; 2063d6c0b56eSmrg xf86MonPtr mon = NULL; 2064d6c0b56eSmrg 2065d6c0b56eSmrg if (!koutput) 2066d6c0b56eSmrg return NULL; 2067d6c0b56eSmrg 206824b90cf4Smrg drmModeFreePropertyBlob(drmmode_output->edid_blob); 206924b90cf4Smrg 2070d6c0b56eSmrg /* look for an EDID property */ 207124b90cf4Smrg drmmode_output->edid_blob = 207224b90cf4Smrg koutput_get_prop_blob(pAMDGPUEnt->fd, koutput, "EDID"); 2073d6c0b56eSmrg 2074d6c0b56eSmrg if (drmmode_output->edid_blob) { 2075d6c0b56eSmrg mon = xf86InterpretEDID(output->scrn->scrnIndex, 2076d6c0b56eSmrg drmmode_output->edid_blob->data); 2077d6c0b56eSmrg if (mon && drmmode_output->edid_blob->length > 128) 2078d6c0b56eSmrg mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; 2079d6c0b56eSmrg } 2080d6c0b56eSmrg xf86OutputSetEDID(output, mon); 2081d6c0b56eSmrg 2082d6c0b56eSmrg /* modes should already be available */ 2083d6c0b56eSmrg for (i = 0; i < koutput->count_modes; i++) { 2084d6c0b56eSmrg Mode = xnfalloc(sizeof(DisplayModeRec)); 2085d6c0b56eSmrg 2086d6c0b56eSmrg drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], 2087d6c0b56eSmrg Mode); 2088d6c0b56eSmrg Modes = xf86ModesAdd(Modes, Mode); 2089d6c0b56eSmrg 2090d6c0b56eSmrg } 2091d6c0b56eSmrg return Modes; 2092d6c0b56eSmrg} 2093d6c0b56eSmrg 2094d6c0b56eSmrgstatic void drmmode_output_destroy(xf86OutputPtr output) 2095d6c0b56eSmrg{ 2096d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 2097d6c0b56eSmrg int i; 2098d6c0b56eSmrg 2099d6c0b56eSmrg if (drmmode_output->edid_blob) 2100d6c0b56eSmrg drmModeFreePropertyBlob(drmmode_output->edid_blob); 2101d6c0b56eSmrg for (i = 0; i < drmmode_output->num_props; i++) { 2102d6c0b56eSmrg drmModeFreeProperty(drmmode_output->props[i].mode_prop); 2103d6c0b56eSmrg free(drmmode_output->props[i].atoms); 2104d6c0b56eSmrg } 2105d6c0b56eSmrg for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) { 2106d6c0b56eSmrg drmModeFreeEncoder(drmmode_output->mode_encoders[i]); 2107d6c0b56eSmrg } 2108d6c0b56eSmrg free(drmmode_output->mode_encoders); 2109d6c0b56eSmrg free(drmmode_output->props); 2110d6c0b56eSmrg drmModeFreeConnector(drmmode_output->mode_output); 2111d6c0b56eSmrg free(drmmode_output); 2112d6c0b56eSmrg output->driver_private = NULL; 2113d6c0b56eSmrg} 2114d6c0b56eSmrg 2115d6c0b56eSmrgstatic void drmmode_output_dpms(xf86OutputPtr output, int mode) 2116d6c0b56eSmrg{ 2117d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 2118d6c0b56eSmrg xf86CrtcPtr crtc = output->crtc; 2119d6c0b56eSmrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 2120d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 2121d6c0b56eSmrg 2122d6c0b56eSmrg if (!koutput) 2123d6c0b56eSmrg return; 2124d6c0b56eSmrg 212524b90cf4Smrg if (mode != DPMSModeOn && crtc) 2126d6c0b56eSmrg drmmode_do_crtc_dpms(crtc, mode); 2127d6c0b56eSmrg 2128d6c0b56eSmrg drmModeConnectorSetProperty(pAMDGPUEnt->fd, koutput->connector_id, 2129d6c0b56eSmrg drmmode_output->dpms_enum_id, mode); 2130d6c0b56eSmrg 2131d6c0b56eSmrg if (mode == DPMSModeOn && crtc) { 2132d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 2133d6c0b56eSmrg 2134d6c0b56eSmrg if (drmmode_crtc->need_modeset) 2135d6c0b56eSmrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 2136d6c0b56eSmrg crtc->x, crtc->y); 2137d6c0b56eSmrg else 2138d6c0b56eSmrg drmmode_do_crtc_dpms(output->crtc, mode); 2139d6c0b56eSmrg } 2140d6c0b56eSmrg} 2141d6c0b56eSmrg 2142d6c0b56eSmrgstatic Bool drmmode_property_ignore(drmModePropertyPtr prop) 2143d6c0b56eSmrg{ 2144d6c0b56eSmrg if (!prop) 2145d6c0b56eSmrg return TRUE; 2146d6c0b56eSmrg /* ignore blob prop */ 2147d6c0b56eSmrg if (prop->flags & DRM_MODE_PROP_BLOB) 2148d6c0b56eSmrg return TRUE; 2149d6c0b56eSmrg /* ignore standard property */ 2150d6c0b56eSmrg if (!strcmp(prop->name, "EDID") || !strcmp(prop->name, "DPMS")) 2151d6c0b56eSmrg return TRUE; 2152d6c0b56eSmrg 2153d6c0b56eSmrg return FALSE; 2154d6c0b56eSmrg} 2155d6c0b56eSmrg 2156d6c0b56eSmrgstatic void drmmode_output_create_resources(xf86OutputPtr output) 2157d6c0b56eSmrg{ 215811bf0794Smrg AMDGPUInfoPtr info = AMDGPUPTR(output->scrn); 2159d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 216035d5b7c7Smrg drmmode_crtc_private_ptr drmmode_crtc; 2161d6c0b56eSmrg drmModeConnectorPtr mode_output = drmmode_output->mode_output; 2162d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 216311bf0794Smrg drmModePropertyPtr drmmode_prop, tearfree_prop; 2164d6c0b56eSmrg int i, j, err; 216535d5b7c7Smrg Atom name; 216635d5b7c7Smrg 216735d5b7c7Smrg /* Create CONNECTOR_ID property */ 216835d5b7c7Smrg name = MakeAtom("CONNECTOR_ID", 12, TRUE); 216935d5b7c7Smrg if (name != BAD_RESOURCE) { 217035d5b7c7Smrg INT32 value = mode_output->connector_id; 217135d5b7c7Smrg 217235d5b7c7Smrg err = RRConfigureOutputProperty(output->randr_output, name, 217335d5b7c7Smrg FALSE, FALSE, TRUE, 1, &value); 217435d5b7c7Smrg if (err != Success) { 217535d5b7c7Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 217635d5b7c7Smrg "RRConfigureOutputProperty error, %d\n", err); 217735d5b7c7Smrg } 217835d5b7c7Smrg 217935d5b7c7Smrg err = RRChangeOutputProperty(output->randr_output, name, 218035d5b7c7Smrg XA_INTEGER, 32, PropModeReplace, 1, 218135d5b7c7Smrg &value, FALSE, FALSE); 218235d5b7c7Smrg if (err != Success) { 218335d5b7c7Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 218435d5b7c7Smrg "RRChangeOutputProperty error, %d\n", err); 218535d5b7c7Smrg } 218635d5b7c7Smrg } 2187d6c0b56eSmrg 2188d6c0b56eSmrg drmmode_output->props = 218911bf0794Smrg calloc(mode_output->count_props + 1, sizeof(drmmode_prop_rec)); 2190d6c0b56eSmrg if (!drmmode_output->props) 2191d6c0b56eSmrg return; 2192d6c0b56eSmrg 2193d6c0b56eSmrg drmmode_output->num_props = 0; 2194d6c0b56eSmrg for (i = 0, j = 0; i < mode_output->count_props; i++) { 2195d6c0b56eSmrg drmmode_prop = 2196d6c0b56eSmrg drmModeGetProperty(pAMDGPUEnt->fd, mode_output->props[i]); 2197d6c0b56eSmrg if (drmmode_property_ignore(drmmode_prop)) { 2198d6c0b56eSmrg drmModeFreeProperty(drmmode_prop); 2199d6c0b56eSmrg continue; 2200d6c0b56eSmrg } 2201d6c0b56eSmrg drmmode_output->props[j].mode_prop = drmmode_prop; 2202d6c0b56eSmrg drmmode_output->props[j].value = mode_output->prop_values[i]; 2203d6c0b56eSmrg drmmode_output->num_props++; 2204d6c0b56eSmrg j++; 2205d6c0b56eSmrg } 2206d6c0b56eSmrg 220711bf0794Smrg /* Userspace-only property for TearFree */ 220811bf0794Smrg tearfree_prop = calloc(1, sizeof(*tearfree_prop)); 220911bf0794Smrg tearfree_prop->flags = DRM_MODE_PROP_ENUM; 221035d5b7c7Smrg strcpy(tearfree_prop->name, "TearFree"); 221111bf0794Smrg tearfree_prop->count_enums = 3; 221211bf0794Smrg tearfree_prop->enums = calloc(tearfree_prop->count_enums, 221311bf0794Smrg sizeof(*tearfree_prop->enums)); 221435d5b7c7Smrg strcpy(tearfree_prop->enums[0].name, "off"); 221535d5b7c7Smrg strcpy(tearfree_prop->enums[1].name, "on"); 221611bf0794Smrg tearfree_prop->enums[1].value = 1; 221735d5b7c7Smrg strcpy(tearfree_prop->enums[2].name, "auto"); 221811bf0794Smrg tearfree_prop->enums[2].value = 2; 221911bf0794Smrg drmmode_output->props[j].mode_prop = tearfree_prop; 222011bf0794Smrg drmmode_output->props[j].value = info->tear_free; 222111bf0794Smrg drmmode_output->tear_free = info->tear_free; 222211bf0794Smrg drmmode_output->num_props++; 222311bf0794Smrg 2224d6c0b56eSmrg for (i = 0; i < drmmode_output->num_props; i++) { 2225d6c0b56eSmrg drmmode_prop_ptr p = &drmmode_output->props[i]; 2226d6c0b56eSmrg drmmode_prop = p->mode_prop; 2227d6c0b56eSmrg 2228d6c0b56eSmrg if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { 2229d6c0b56eSmrg INT32 range[2]; 2230d6c0b56eSmrg INT32 value = p->value; 2231d6c0b56eSmrg 2232d6c0b56eSmrg p->num_atoms = 1; 2233d6c0b56eSmrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 2234d6c0b56eSmrg if (!p->atoms) 2235d6c0b56eSmrg continue; 2236d6c0b56eSmrg p->atoms[0] = 2237d6c0b56eSmrg MakeAtom(drmmode_prop->name, 2238d6c0b56eSmrg strlen(drmmode_prop->name), TRUE); 2239d6c0b56eSmrg range[0] = drmmode_prop->values[0]; 2240d6c0b56eSmrg range[1] = drmmode_prop->values[1]; 2241d6c0b56eSmrg err = 2242d6c0b56eSmrg RRConfigureOutputProperty(output->randr_output, 2243d6c0b56eSmrg p->atoms[0], FALSE, TRUE, 2244d6c0b56eSmrg drmmode_prop->flags & 2245d6c0b56eSmrg DRM_MODE_PROP_IMMUTABLE ? 2246d6c0b56eSmrg TRUE : FALSE, 2, range); 2247d6c0b56eSmrg if (err != 0) { 2248d6c0b56eSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2249d6c0b56eSmrg "RRConfigureOutputProperty error, %d\n", 2250d6c0b56eSmrg err); 2251d6c0b56eSmrg } 2252d6c0b56eSmrg err = 2253d6c0b56eSmrg RRChangeOutputProperty(output->randr_output, 2254d6c0b56eSmrg p->atoms[0], XA_INTEGER, 32, 2255d6c0b56eSmrg PropModeReplace, 1, &value, 2256d6c0b56eSmrg FALSE, TRUE); 2257d6c0b56eSmrg if (err != 0) { 2258d6c0b56eSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2259d6c0b56eSmrg "RRChangeOutputProperty error, %d\n", 2260d6c0b56eSmrg err); 2261d6c0b56eSmrg } 2262d6c0b56eSmrg } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { 2263d6c0b56eSmrg p->num_atoms = drmmode_prop->count_enums + 1; 2264d6c0b56eSmrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 2265d6c0b56eSmrg if (!p->atoms) 2266d6c0b56eSmrg continue; 2267d6c0b56eSmrg p->atoms[0] = 2268d6c0b56eSmrg MakeAtom(drmmode_prop->name, 2269d6c0b56eSmrg strlen(drmmode_prop->name), TRUE); 2270d6c0b56eSmrg for (j = 1; j <= drmmode_prop->count_enums; j++) { 2271d6c0b56eSmrg struct drm_mode_property_enum *e = 2272d6c0b56eSmrg &drmmode_prop->enums[j - 1]; 2273d6c0b56eSmrg p->atoms[j] = 2274d6c0b56eSmrg MakeAtom(e->name, strlen(e->name), TRUE); 2275d6c0b56eSmrg } 2276d6c0b56eSmrg err = 2277d6c0b56eSmrg RRConfigureOutputProperty(output->randr_output, 2278d6c0b56eSmrg p->atoms[0], FALSE, FALSE, 2279d6c0b56eSmrg drmmode_prop->flags & 2280d6c0b56eSmrg DRM_MODE_PROP_IMMUTABLE ? 2281d6c0b56eSmrg TRUE : FALSE, 2282d6c0b56eSmrg p->num_atoms - 1, 2283d6c0b56eSmrg (INT32 *) & p->atoms[1]); 2284d6c0b56eSmrg if (err != 0) { 2285d6c0b56eSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2286d6c0b56eSmrg "RRConfigureOutputProperty error, %d\n", 2287d6c0b56eSmrg err); 2288d6c0b56eSmrg } 2289d6c0b56eSmrg for (j = 0; j < drmmode_prop->count_enums; j++) 2290d6c0b56eSmrg if (drmmode_prop->enums[j].value == p->value) 2291d6c0b56eSmrg break; 2292d6c0b56eSmrg /* there's always a matching value */ 2293d6c0b56eSmrg err = 2294d6c0b56eSmrg RRChangeOutputProperty(output->randr_output, 2295d6c0b56eSmrg p->atoms[0], XA_ATOM, 32, 2296d6c0b56eSmrg PropModeReplace, 1, 2297d6c0b56eSmrg &p->atoms[j + 1], FALSE, 2298d6c0b56eSmrg TRUE); 2299d6c0b56eSmrg if (err != 0) { 2300d6c0b56eSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2301d6c0b56eSmrg "RRChangeOutputProperty error, %d\n", 2302d6c0b56eSmrg err); 2303d6c0b56eSmrg } 2304d6c0b56eSmrg } 2305d6c0b56eSmrg } 230635d5b7c7Smrg 230735d5b7c7Smrg /* Do not configure cm properties on output if there's no support. */ 230835d5b7c7Smrg if (!drmmode_cm_enabled(drmmode_output->drmmode)) 230935d5b7c7Smrg return; 231035d5b7c7Smrg 231135d5b7c7Smrg drmmode_crtc = output->crtc ? output->crtc->driver_private : NULL; 231235d5b7c7Smrg 231335d5b7c7Smrg for (i = 0; i < CM_NUM_PROPS; i++) 231435d5b7c7Smrg rr_configure_and_change_cm_property(output, drmmode_crtc, i); 231535d5b7c7Smrg} 231635d5b7c7Smrg 231735d5b7c7Smrgstatic void 231835d5b7c7Smrgdrmmode_output_set_tear_free(AMDGPUEntPtr pAMDGPUEnt, 231935d5b7c7Smrg drmmode_output_private_ptr drmmode_output, 232035d5b7c7Smrg xf86CrtcPtr crtc, int tear_free) 232135d5b7c7Smrg{ 232235d5b7c7Smrg if (drmmode_output->tear_free == tear_free) 232335d5b7c7Smrg return; 232435d5b7c7Smrg 232535d5b7c7Smrg drmmode_output->tear_free = tear_free; 232635d5b7c7Smrg 232735d5b7c7Smrg if (crtc) { 232835d5b7c7Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 232935d5b7c7Smrg crtc->x, crtc->y); 233035d5b7c7Smrg } 2331d6c0b56eSmrg} 2332d6c0b56eSmrg 2333d6c0b56eSmrgstatic Bool 2334d6c0b56eSmrgdrmmode_output_set_property(xf86OutputPtr output, Atom property, 2335d6c0b56eSmrg RRPropertyValuePtr value) 2336d6c0b56eSmrg{ 2337d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 2338d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 233935d5b7c7Smrg enum drmmode_cm_prop cm_prop_index; 2340d6c0b56eSmrg int i; 2341d6c0b56eSmrg 234235d5b7c7Smrg cm_prop_index = get_cm_enum_from_str(NameForAtom(property)); 234335d5b7c7Smrg if (cm_prop_index >= 0 && cm_prop_index < CM_DEGAMMA_LUT_SIZE) { 234435d5b7c7Smrg if (!output->crtc) 234535d5b7c7Smrg return FALSE; 234635d5b7c7Smrg if (drmmode_crtc_stage_cm_prop(output->crtc, cm_prop_index, 234735d5b7c7Smrg value)) 234835d5b7c7Smrg return FALSE; 234935d5b7c7Smrg if (drmmode_crtc_push_cm_prop(output->crtc, cm_prop_index)) 235035d5b7c7Smrg return FALSE; 235135d5b7c7Smrg return TRUE; 235235d5b7c7Smrg } 235335d5b7c7Smrg 2354d6c0b56eSmrg for (i = 0; i < drmmode_output->num_props; i++) { 2355d6c0b56eSmrg drmmode_prop_ptr p = &drmmode_output->props[i]; 2356d6c0b56eSmrg 2357d6c0b56eSmrg if (p->atoms[0] != property) 2358d6c0b56eSmrg continue; 2359d6c0b56eSmrg 2360d6c0b56eSmrg if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 2361d6c0b56eSmrg uint32_t val; 2362d6c0b56eSmrg 2363d6c0b56eSmrg if (value->type != XA_INTEGER || value->format != 32 || 2364d6c0b56eSmrg value->size != 1) 2365d6c0b56eSmrg return FALSE; 2366d6c0b56eSmrg val = *(uint32_t *) value->data; 2367d6c0b56eSmrg 2368d6c0b56eSmrg drmModeConnectorSetProperty(pAMDGPUEnt->fd, 2369d6c0b56eSmrg drmmode_output->output_id, 2370d6c0b56eSmrg p->mode_prop->prop_id, 2371d6c0b56eSmrg (uint64_t) val); 2372d6c0b56eSmrg return TRUE; 2373d6c0b56eSmrg } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 2374d6c0b56eSmrg Atom atom; 2375d6c0b56eSmrg const char *name; 2376d6c0b56eSmrg int j; 2377d6c0b56eSmrg 2378d6c0b56eSmrg if (value->type != XA_ATOM || value->format != 32 2379d6c0b56eSmrg || value->size != 1) 2380d6c0b56eSmrg return FALSE; 2381d6c0b56eSmrg memcpy(&atom, value->data, 4); 238224b90cf4Smrg if (!(name = NameForAtom(atom))) 238324b90cf4Smrg return FALSE; 2384d6c0b56eSmrg 2385d6c0b56eSmrg /* search for matching name string, then set its value down */ 2386d6c0b56eSmrg for (j = 0; j < p->mode_prop->count_enums; j++) { 2387d6c0b56eSmrg if (!strcmp(p->mode_prop->enums[j].name, name)) { 238811bf0794Smrg if (i == (drmmode_output->num_props - 1)) { 238935d5b7c7Smrg drmmode_output_set_tear_free(pAMDGPUEnt, 239035d5b7c7Smrg drmmode_output, 239135d5b7c7Smrg output->crtc, j); 239211bf0794Smrg } else { 239311bf0794Smrg drmModeConnectorSetProperty(pAMDGPUEnt->fd, 239411bf0794Smrg drmmode_output->output_id, 239511bf0794Smrg p->mode_prop->prop_id, 239611bf0794Smrg p->mode_prop->enums[j].value); 239711bf0794Smrg } 239811bf0794Smrg 2399d6c0b56eSmrg return TRUE; 2400d6c0b56eSmrg } 2401d6c0b56eSmrg } 2402d6c0b56eSmrg } 2403d6c0b56eSmrg } 2404d6c0b56eSmrg 2405d6c0b56eSmrg return TRUE; 2406d6c0b56eSmrg} 2407d6c0b56eSmrg 2408d6c0b56eSmrgstatic Bool drmmode_output_get_property(xf86OutputPtr output, Atom property) 2409d6c0b56eSmrg{ 241035d5b7c7Smrg drmmode_crtc_private_ptr drmmode_crtc; 241135d5b7c7Smrg enum drmmode_cm_prop cm_prop_id; 241235d5b7c7Smrg int ret; 241335d5b7c7Smrg 241435d5b7c7Smrg /* First, see if it's a cm property */ 241535d5b7c7Smrg cm_prop_id = get_cm_enum_from_str(NameForAtom(property)); 241635d5b7c7Smrg if (output->crtc && cm_prop_id != CM_INVALID_PROP) { 241735d5b7c7Smrg drmmode_crtc = output->crtc->driver_private; 241835d5b7c7Smrg 241935d5b7c7Smrg ret = rr_configure_and_change_cm_property(output, drmmode_crtc, 242035d5b7c7Smrg cm_prop_id); 242135d5b7c7Smrg if (ret) { 242235d5b7c7Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 242335d5b7c7Smrg "Error getting color property: %d\n", 242435d5b7c7Smrg ret); 242535d5b7c7Smrg return FALSE; 242635d5b7c7Smrg } 242735d5b7c7Smrg return TRUE; 242835d5b7c7Smrg } 242935d5b7c7Smrg 243035d5b7c7Smrg /* Otherwise, must be an output property. */ 2431d6c0b56eSmrg return TRUE; 2432d6c0b56eSmrg} 2433d6c0b56eSmrg 2434d6c0b56eSmrgstatic const xf86OutputFuncsRec drmmode_output_funcs = { 2435d6c0b56eSmrg .dpms = drmmode_output_dpms, 2436d6c0b56eSmrg .create_resources = drmmode_output_create_resources, 2437d6c0b56eSmrg .set_property = drmmode_output_set_property, 2438d6c0b56eSmrg .get_property = drmmode_output_get_property, 2439d6c0b56eSmrg .detect = drmmode_output_detect, 2440d6c0b56eSmrg .mode_valid = drmmode_output_mode_valid, 2441d6c0b56eSmrg 2442d6c0b56eSmrg .get_modes = drmmode_output_get_modes, 2443d6c0b56eSmrg .destroy = drmmode_output_destroy 2444d6c0b56eSmrg}; 2445d6c0b56eSmrg 2446d6c0b56eSmrgstatic int subpixel_conv_table[7] = { 0, SubPixelUnknown, 2447d6c0b56eSmrg SubPixelHorizontalRGB, 2448d6c0b56eSmrg SubPixelHorizontalBGR, 2449d6c0b56eSmrg SubPixelVerticalRGB, 2450d6c0b56eSmrg SubPixelVerticalBGR, 2451d6c0b56eSmrg SubPixelNone 2452d6c0b56eSmrg}; 2453d6c0b56eSmrg 2454d6c0b56eSmrgconst char *output_names[] = { "None", 2455d6c0b56eSmrg "VGA", 2456d6c0b56eSmrg "DVI-I", 2457d6c0b56eSmrg "DVI-D", 2458d6c0b56eSmrg "DVI-A", 2459d6c0b56eSmrg "Composite", 2460d6c0b56eSmrg "S-video", 2461d6c0b56eSmrg "LVDS", 2462d6c0b56eSmrg "CTV", 2463d6c0b56eSmrg "DIN", 2464d6c0b56eSmrg "DisplayPort", 2465d6c0b56eSmrg "HDMI-A", 2466d6c0b56eSmrg "HDMI-B", 2467d6c0b56eSmrg "TV", 2468d6c0b56eSmrg "eDP", 2469d6c0b56eSmrg "Virtual", 2470d6c0b56eSmrg "DSI", 2471d6c0b56eSmrg}; 2472d6c0b56eSmrg 2473d6c0b56eSmrg#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0])) 2474d6c0b56eSmrg 2475d6c0b56eSmrgstatic xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id) 2476d6c0b56eSmrg{ 2477d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 2478d6c0b56eSmrg int i; 2479d6c0b56eSmrg for (i = 0; i < xf86_config->num_output; i++) { 2480d6c0b56eSmrg xf86OutputPtr output = xf86_config->output[i]; 2481d6c0b56eSmrg drmmode_output_private_ptr drmmode_output; 2482d6c0b56eSmrg drmmode_output = output->driver_private; 2483d6c0b56eSmrg if (drmmode_output->output_id == id) 2484d6c0b56eSmrg return output; 2485d6c0b56eSmrg } 2486d6c0b56eSmrg return NULL; 2487d6c0b56eSmrg} 2488d6c0b56eSmrg 2489d6c0b56eSmrgstatic int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path) 2490d6c0b56eSmrg{ 2491d6c0b56eSmrg char *conn; 2492d6c0b56eSmrg char conn_id[5]; 2493d6c0b56eSmrg int id, len; 2494d6c0b56eSmrg char *blob_data; 2495d6c0b56eSmrg 2496d6c0b56eSmrg if (!path_blob) 2497d6c0b56eSmrg return -1; 2498d6c0b56eSmrg 2499d6c0b56eSmrg blob_data = path_blob->data; 2500d6c0b56eSmrg /* we only handle MST paths for now */ 2501d6c0b56eSmrg if (strncmp(blob_data, "mst:", 4)) 2502d6c0b56eSmrg return -1; 2503d6c0b56eSmrg 2504d6c0b56eSmrg conn = strchr(blob_data + 4, '-'); 2505d6c0b56eSmrg if (!conn) 2506d6c0b56eSmrg return -1; 2507d6c0b56eSmrg len = conn - (blob_data + 4); 2508d6c0b56eSmrg if (len + 1 > 5) 2509d6c0b56eSmrg return -1; 2510d6c0b56eSmrg memcpy(conn_id, blob_data + 4, len); 2511d6c0b56eSmrg conn_id[len] = '\0'; 2512d6c0b56eSmrg id = strtoul(conn_id, NULL, 10); 2513d6c0b56eSmrg 2514d6c0b56eSmrg *conn_base_id = id; 2515d6c0b56eSmrg 2516d6c0b56eSmrg *path = conn + 1; 2517d6c0b56eSmrg return 0; 2518d6c0b56eSmrg} 2519d6c0b56eSmrg 2520d6c0b56eSmrgstatic void 2521d6c0b56eSmrgdrmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name, 2522d6c0b56eSmrg drmModePropertyBlobPtr path_blob, int *num_dvi, int *num_hdmi) 2523d6c0b56eSmrg{ 2524d6c0b56eSmrg xf86OutputPtr output; 2525d6c0b56eSmrg int conn_id; 2526d6c0b56eSmrg char *extra_path; 2527d6c0b56eSmrg 2528d6c0b56eSmrg output = NULL; 2529d6c0b56eSmrg if (parse_path_blob(path_blob, &conn_id, &extra_path) == 0) 2530d6c0b56eSmrg output = find_output(pScrn, conn_id); 2531d6c0b56eSmrg if (output) { 2532d6c0b56eSmrg snprintf(name, 32, "%s-%s", output->name, extra_path); 2533d6c0b56eSmrg } else { 253424b90cf4Smrg if (koutput->connector_type >= NUM_OUTPUT_NAMES) { 2535d6c0b56eSmrg snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, koutput->connector_type_id - 1); 253624b90cf4Smrg } else if (pScrn->is_gpu) { 2537d6c0b56eSmrg snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type], 2538d6c0b56eSmrg pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id - 1); 253924b90cf4Smrg } else { 2540d6c0b56eSmrg /* need to do smart conversion here for compat with non-kms ATI driver */ 2541d6c0b56eSmrg if (koutput->connector_type_id == 1) { 2542d6c0b56eSmrg switch(koutput->connector_type) { 2543d6c0b56eSmrg case DRM_MODE_CONNECTOR_DVII: 2544d6c0b56eSmrg case DRM_MODE_CONNECTOR_DVID: 2545d6c0b56eSmrg case DRM_MODE_CONNECTOR_DVIA: 2546d6c0b56eSmrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi); 2547d6c0b56eSmrg (*num_dvi)++; 2548d6c0b56eSmrg break; 2549d6c0b56eSmrg case DRM_MODE_CONNECTOR_HDMIA: 2550d6c0b56eSmrg case DRM_MODE_CONNECTOR_HDMIB: 2551d6c0b56eSmrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi); 2552d6c0b56eSmrg (*num_hdmi)++; 2553d6c0b56eSmrg break; 2554d6c0b56eSmrg case DRM_MODE_CONNECTOR_VGA: 2555d6c0b56eSmrg case DRM_MODE_CONNECTOR_DisplayPort: 2556d6c0b56eSmrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); 2557d6c0b56eSmrg break; 2558d6c0b56eSmrg default: 2559d6c0b56eSmrg snprintf(name, 32, "%s", output_names[koutput->connector_type]); 2560d6c0b56eSmrg break; 2561d6c0b56eSmrg } 2562d6c0b56eSmrg } else { 2563d6c0b56eSmrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); 2564d6c0b56eSmrg } 2565d6c0b56eSmrg } 2566d6c0b56eSmrg } 2567d6c0b56eSmrg} 2568d6c0b56eSmrg 2569d6c0b56eSmrg 2570d6c0b56eSmrgstatic unsigned int 2571d6c0b56eSmrgdrmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int *num_dvi, int *num_hdmi, int dynamic) 2572d6c0b56eSmrg{ 2573d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 2574d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 2575d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 2576d6c0b56eSmrg xf86OutputPtr output; 2577d6c0b56eSmrg drmModeConnectorPtr koutput; 2578d6c0b56eSmrg drmModeEncoderPtr *kencoders = NULL; 2579d6c0b56eSmrg drmmode_output_private_ptr drmmode_output; 2580d6c0b56eSmrg drmModePropertyBlobPtr path_blob = NULL; 258135d5b7c7Smrg#if XF86_CRTC_VERSION >= 8 258235d5b7c7Smrg Bool nonDesktop = FALSE; 258335d5b7c7Smrg#endif 2584d6c0b56eSmrg char name[32]; 2585d6c0b56eSmrg int i; 2586d6c0b56eSmrg const char *s; 2587d6c0b56eSmrg 2588d6c0b56eSmrg koutput = 2589d6c0b56eSmrg drmModeGetConnector(pAMDGPUEnt->fd, 2590d6c0b56eSmrg mode_res->connectors[num]); 2591d6c0b56eSmrg if (!koutput) 2592d6c0b56eSmrg return 0; 2593d6c0b56eSmrg 259424b90cf4Smrg path_blob = koutput_get_prop_blob(pAMDGPUEnt->fd, koutput, "PATH"); 2595d6c0b56eSmrg 259635d5b7c7Smrg#if XF86_CRTC_VERSION >= 8 259735d5b7c7Smrg i = koutput_get_prop_idx(pAMDGPUEnt->fd, koutput, DRM_MODE_PROP_RANGE, 259835d5b7c7Smrg "non-desktop"); 259935d5b7c7Smrg if (i >= 0) 260035d5b7c7Smrg nonDesktop = koutput->prop_values[i] != 0; 260135d5b7c7Smrg#endif 260235d5b7c7Smrg 2603d6c0b56eSmrg kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders); 2604d6c0b56eSmrg if (!kencoders) { 2605d6c0b56eSmrg goto out_free_encoders; 2606d6c0b56eSmrg } 2607d6c0b56eSmrg 2608d6c0b56eSmrg for (i = 0; i < koutput->count_encoders; i++) { 2609d6c0b56eSmrg kencoders[i] = 2610d6c0b56eSmrg drmModeGetEncoder(pAMDGPUEnt->fd, koutput->encoders[i]); 2611d6c0b56eSmrg if (!kencoders[i]) { 2612d6c0b56eSmrg goto out_free_encoders; 2613d6c0b56eSmrg } 2614d6c0b56eSmrg } 2615d6c0b56eSmrg 2616d6c0b56eSmrg drmmode_create_name(pScrn, koutput, name, path_blob, num_dvi, num_hdmi); 2617d6c0b56eSmrg if (path_blob) { 2618d6c0b56eSmrg drmModeFreePropertyBlob(path_blob); 2619d6c0b56eSmrg } 2620d6c0b56eSmrg 2621d6c0b56eSmrg if (path_blob && dynamic) { 2622d6c0b56eSmrg /* See if we have an output with this name already 2623d6c0b56eSmrg * and hook stuff up. 2624d6c0b56eSmrg */ 2625d6c0b56eSmrg for (i = 0; i < xf86_config->num_output; i++) { 2626d6c0b56eSmrg output = xf86_config->output[i]; 2627d6c0b56eSmrg 2628d6c0b56eSmrg if (strncmp(output->name, name, 32)) 2629d6c0b56eSmrg continue; 2630d6c0b56eSmrg 2631d6c0b56eSmrg drmmode_output = output->driver_private; 2632d6c0b56eSmrg drmmode_output->output_id = mode_res->connectors[num]; 2633d6c0b56eSmrg drmmode_output->mode_output = koutput; 263435d5b7c7Smrg#if XF86_CRTC_VERSION >= 8 263535d5b7c7Smrg output->non_desktop = nonDesktop; 263635d5b7c7Smrg#endif 2637d6c0b56eSmrg for (i = 0; i < koutput->count_encoders; i++) { 2638d6c0b56eSmrg drmModeFreeEncoder(kencoders[i]); 2639d6c0b56eSmrg } 2640d6c0b56eSmrg free(kencoders); 2641d6c0b56eSmrg return 1; 2642d6c0b56eSmrg } 2643d6c0b56eSmrg } 2644d6c0b56eSmrg 2645d6c0b56eSmrg if (xf86IsEntityShared(pScrn->entityList[0])) { 2646d6c0b56eSmrg if ((s = 2647d6c0b56eSmrg xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) { 2648d6c0b56eSmrg if (!AMDGPUZaphodStringMatches(pScrn, s, name)) 2649d6c0b56eSmrg goto out_free_encoders; 2650d6c0b56eSmrg } else { 2651d6c0b56eSmrg if (!info->IsSecondary && (num != 0)) 2652d6c0b56eSmrg goto out_free_encoders; 2653d6c0b56eSmrg else if (info->IsSecondary && (num != 1)) 2654d6c0b56eSmrg goto out_free_encoders; 2655d6c0b56eSmrg } 2656d6c0b56eSmrg } 2657d6c0b56eSmrg 2658d6c0b56eSmrg output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name); 2659d6c0b56eSmrg if (!output) { 2660d6c0b56eSmrg goto out_free_encoders; 2661d6c0b56eSmrg } 2662d6c0b56eSmrg 2663d6c0b56eSmrg drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1); 2664d6c0b56eSmrg if (!drmmode_output) { 2665d6c0b56eSmrg xf86OutputDestroy(output); 2666d6c0b56eSmrg goto out_free_encoders; 2667d6c0b56eSmrg } 2668d6c0b56eSmrg 2669d6c0b56eSmrg drmmode_output->output_id = mode_res->connectors[num]; 2670d6c0b56eSmrg drmmode_output->mode_output = koutput; 2671d6c0b56eSmrg drmmode_output->mode_encoders = kencoders; 2672d6c0b56eSmrg drmmode_output->drmmode = drmmode; 2673d6c0b56eSmrg output->mm_width = koutput->mmWidth; 2674d6c0b56eSmrg output->mm_height = koutput->mmHeight; 2675d6c0b56eSmrg 2676d6c0b56eSmrg output->subpixel_order = subpixel_conv_table[koutput->subpixel]; 2677d6c0b56eSmrg output->interlaceAllowed = TRUE; 2678d6c0b56eSmrg output->doubleScanAllowed = TRUE; 2679d6c0b56eSmrg output->driver_private = drmmode_output; 268035d5b7c7Smrg#if XF86_CRTC_VERSION >= 8 268135d5b7c7Smrg output->non_desktop = nonDesktop; 268235d5b7c7Smrg#endif 2683d6c0b56eSmrg 2684d6c0b56eSmrg output->possible_crtcs = 0xffffffff; 2685d6c0b56eSmrg for (i = 0; i < koutput->count_encoders; i++) { 2686d6c0b56eSmrg output->possible_crtcs &= kencoders[i]->possible_crtcs; 2687d6c0b56eSmrg } 2688d6c0b56eSmrg /* work out the possible clones later */ 2689d6c0b56eSmrg output->possible_clones = 0; 2690d6c0b56eSmrg 269124b90cf4Smrg drmmode_output->dpms_enum_id = 269224b90cf4Smrg koutput_get_prop_id(pAMDGPUEnt->fd, koutput, DRM_MODE_PROP_ENUM, 269324b90cf4Smrg "DPMS"); 2694d6c0b56eSmrg 2695d6c0b56eSmrg if (dynamic) { 2696d6c0b56eSmrg output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output); 2697d6c0b56eSmrg drmmode_output_create_resources(output); 2698d6c0b56eSmrg } 2699d6c0b56eSmrg 2700d6c0b56eSmrg return 1; 2701d6c0b56eSmrgout_free_encoders: 2702d6c0b56eSmrg if (kencoders) { 2703d6c0b56eSmrg for (i = 0; i < koutput->count_encoders; i++) 2704d6c0b56eSmrg drmModeFreeEncoder(kencoders[i]); 2705d6c0b56eSmrg free(kencoders); 2706d6c0b56eSmrg } 2707d6c0b56eSmrg drmModeFreeConnector(koutput); 2708d6c0b56eSmrg return 0; 2709d6c0b56eSmrg} 2710d6c0b56eSmrg 2711d6c0b56eSmrguint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output) 2712d6c0b56eSmrg{ 2713d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = 2714d6c0b56eSmrg output->driver_private, clone_drmout; 2715d6c0b56eSmrg int i; 2716d6c0b56eSmrg xf86OutputPtr clone_output; 2717d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2718d6c0b56eSmrg int index_mask = 0; 2719d6c0b56eSmrg 2720d6c0b56eSmrg if (drmmode_output->enc_clone_mask == 0) 2721d6c0b56eSmrg return index_mask; 2722d6c0b56eSmrg 2723d6c0b56eSmrg for (i = 0; i < xf86_config->num_output; i++) { 2724d6c0b56eSmrg clone_output = xf86_config->output[i]; 2725d6c0b56eSmrg clone_drmout = clone_output->driver_private; 2726d6c0b56eSmrg if (output == clone_output) 2727d6c0b56eSmrg continue; 2728d6c0b56eSmrg 2729d6c0b56eSmrg if (clone_drmout->enc_mask == 0) 2730d6c0b56eSmrg continue; 2731d6c0b56eSmrg if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask) 2732d6c0b56eSmrg index_mask |= (1 << i); 2733d6c0b56eSmrg } 2734d6c0b56eSmrg return index_mask; 2735d6c0b56eSmrg} 2736d6c0b56eSmrg 2737d6c0b56eSmrgstatic void drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res) 2738d6c0b56eSmrg{ 2739d6c0b56eSmrg int i, j; 2740d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2741d6c0b56eSmrg 2742d6c0b56eSmrg for (i = 0; i < xf86_config->num_output; i++) { 2743d6c0b56eSmrg xf86OutputPtr output = xf86_config->output[i]; 2744d6c0b56eSmrg drmmode_output_private_ptr drmmode_output; 2745d6c0b56eSmrg 2746d6c0b56eSmrg drmmode_output = output->driver_private; 2747d6c0b56eSmrg drmmode_output->enc_clone_mask = 0xff; 2748d6c0b56eSmrg /* and all the possible encoder clones for this output together */ 2749d6c0b56eSmrg for (j = 0; j < drmmode_output->mode_output->count_encoders; 2750d6c0b56eSmrg j++) { 2751d6c0b56eSmrg int k; 2752d6c0b56eSmrg for (k = 0; k < mode_res->count_encoders; k++) { 2753d6c0b56eSmrg if (mode_res->encoders[k] == 2754d6c0b56eSmrg drmmode_output-> 2755d6c0b56eSmrg mode_encoders[j]->encoder_id) 2756d6c0b56eSmrg drmmode_output->enc_mask |= (1 << k); 2757d6c0b56eSmrg } 2758d6c0b56eSmrg 2759d6c0b56eSmrg drmmode_output->enc_clone_mask &= 2760d6c0b56eSmrg drmmode_output->mode_encoders[j]->possible_clones; 2761d6c0b56eSmrg } 2762d6c0b56eSmrg } 2763d6c0b56eSmrg 2764d6c0b56eSmrg for (i = 0; i < xf86_config->num_output; i++) { 2765d6c0b56eSmrg xf86OutputPtr output = xf86_config->output[i]; 2766d6c0b56eSmrg output->possible_clones = find_clones(scrn, output); 2767d6c0b56eSmrg } 2768d6c0b56eSmrg} 2769d6c0b56eSmrg 2770d6c0b56eSmrg/* returns pitch alignment in pixels */ 2771d6c0b56eSmrgint drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe) 2772d6c0b56eSmrg{ 2773d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 2774d6c0b56eSmrg 2775d6c0b56eSmrg if (info->have_tiling_info) 2776d6c0b56eSmrg /* linear aligned requirements */ 2777d6c0b56eSmrg return MAX(64, info->group_bytes / bpe); 2778d6c0b56eSmrg else 2779d6c0b56eSmrg /* default to 512 elements if we don't know the real 2780d6c0b56eSmrg * group size otherwise the kernel may reject the CS 2781d6c0b56eSmrg * if the group sizes don't match as the pitch won't 2782d6c0b56eSmrg * be aligned properly. 2783d6c0b56eSmrg */ 2784d6c0b56eSmrg return 512; 2785d6c0b56eSmrg} 2786d6c0b56eSmrg 2787d6c0b56eSmrgstatic Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height) 2788d6c0b56eSmrg{ 2789d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2790d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 2791d6c0b56eSmrg struct amdgpu_buffer *old_front = NULL; 2792d6c0b56eSmrg ScreenPtr screen = xf86ScrnToScreen(scrn); 2793d6c0b56eSmrg int i, pitch, old_width, old_height, old_pitch; 2794d6c0b56eSmrg int cpp = info->pixel_bytes; 2795d6c0b56eSmrg PixmapPtr ppix = screen->GetScreenPixmap(screen); 2796d6c0b56eSmrg void *fb_shadow; 2797d6c0b56eSmrg int hint = 0; 2798d6c0b56eSmrg 2799d6c0b56eSmrg if (scrn->virtualX == width && scrn->virtualY == height) 2800d6c0b56eSmrg return TRUE; 2801d6c0b56eSmrg 280235d5b7c7Smrg if (width > xf86_config->maxWidth || height > xf86_config->maxHeight) { 280335d5b7c7Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 280435d5b7c7Smrg "Xorg tried resizing screen to %dx%d, but maximum " 280535d5b7c7Smrg "supported is %dx%d\n", width, height, 280635d5b7c7Smrg xf86_config->maxWidth, xf86_config->maxHeight); 280735d5b7c7Smrg return FALSE; 280835d5b7c7Smrg } 280935d5b7c7Smrg 2810d6c0b56eSmrg if (info->shadow_primary) 2811d6c0b56eSmrg hint = AMDGPU_CREATE_PIXMAP_LINEAR | AMDGPU_CREATE_PIXMAP_GTT; 2812d6c0b56eSmrg else if (!info->use_glamor) 2813d6c0b56eSmrg hint = AMDGPU_CREATE_PIXMAP_LINEAR; 2814d6c0b56eSmrg 2815d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_INFO, 2816d6c0b56eSmrg "Allocate new frame buffer %dx%d\n", width, height); 2817d6c0b56eSmrg 2818d6c0b56eSmrg old_width = scrn->virtualX; 2819d6c0b56eSmrg old_height = scrn->virtualY; 2820d6c0b56eSmrg old_pitch = scrn->displayWidth; 2821d6c0b56eSmrg old_front = info->front_buffer; 2822d6c0b56eSmrg 2823d6c0b56eSmrg scrn->virtualX = width; 2824d6c0b56eSmrg scrn->virtualY = height; 2825d6c0b56eSmrg 2826d6c0b56eSmrg info->front_buffer = 2827d6c0b56eSmrg amdgpu_alloc_pixmap_bo(scrn, scrn->virtualX, scrn->virtualY, 2828d6c0b56eSmrg scrn->depth, hint, scrn->bitsPerPixel, 2829d6c0b56eSmrg &pitch); 2830d6c0b56eSmrg if (!info->front_buffer) { 2831d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 2832d6c0b56eSmrg "Failed to allocate front buffer memory\n"); 2833d6c0b56eSmrg goto fail; 2834d6c0b56eSmrg } 2835d6c0b56eSmrg 2836d6c0b56eSmrg if (!info->use_glamor && amdgpu_bo_map(scrn, info->front_buffer) != 0) { 2837d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 2838d6c0b56eSmrg "Failed to map front buffer memory\n"); 2839d6c0b56eSmrg goto fail; 2840d6c0b56eSmrg } 2841d6c0b56eSmrg 2842d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_INFO, " => pitch %d bytes\n", pitch); 2843d6c0b56eSmrg scrn->displayWidth = pitch / cpp; 2844d6c0b56eSmrg 2845d6c0b56eSmrg if (info->use_glamor || 2846d6c0b56eSmrg (info->front_buffer->flags & AMDGPU_BO_FLAGS_GBM)) { 2847d6c0b56eSmrg screen->ModifyPixmapHeader(ppix, 2848d6c0b56eSmrg width, height, -1, -1, pitch, info->front_buffer->cpu_ptr); 2849d6c0b56eSmrg } else { 2850d6c0b56eSmrg fb_shadow = calloc(1, pitch * scrn->virtualY); 285135d5b7c7Smrg if (!fb_shadow) 2852d6c0b56eSmrg goto fail; 2853d6c0b56eSmrg free(info->fb_shadow); 2854d6c0b56eSmrg info->fb_shadow = fb_shadow; 2855d6c0b56eSmrg screen->ModifyPixmapHeader(ppix, 2856d6c0b56eSmrg width, height, -1, -1, pitch, 2857d6c0b56eSmrg info->fb_shadow); 2858d6c0b56eSmrg } 2859d6c0b56eSmrg 2860504d986fSmrg if (!amdgpu_glamor_create_screen_resources(scrn->pScreen)) 2861504d986fSmrg goto fail; 2862504d986fSmrg 2863504d986fSmrg if (info->use_glamor || 2864504d986fSmrg (info->front_buffer->flags & AMDGPU_BO_FLAGS_GBM)) { 2865504d986fSmrg if (!amdgpu_set_pixmap_bo(ppix, info->front_buffer)) 2866504d986fSmrg goto fail; 2867504d986fSmrg } 2868d6c0b56eSmrg 286924b90cf4Smrg amdgpu_pixmap_clear(ppix); 2870d6c0b56eSmrg amdgpu_glamor_finish(scrn); 2871d6c0b56eSmrg 2872d6c0b56eSmrg for (i = 0; i < xf86_config->num_crtc; i++) { 2873d6c0b56eSmrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 2874d6c0b56eSmrg 2875d6c0b56eSmrg if (!crtc->enabled) 2876d6c0b56eSmrg continue; 2877d6c0b56eSmrg 2878d6c0b56eSmrg drmmode_set_mode_major(crtc, &crtc->mode, 2879d6c0b56eSmrg crtc->rotation, crtc->x, crtc->y); 2880d6c0b56eSmrg } 2881d6c0b56eSmrg 2882d6c0b56eSmrg if (old_front) { 2883d6c0b56eSmrg amdgpu_bo_unref(&old_front); 2884d6c0b56eSmrg } 2885d6c0b56eSmrg 2886d6c0b56eSmrg return TRUE; 2887d6c0b56eSmrg 2888d6c0b56eSmrgfail: 2889d6c0b56eSmrg if (info->front_buffer) { 2890d6c0b56eSmrg amdgpu_bo_unref(&info->front_buffer); 2891d6c0b56eSmrg } 2892d6c0b56eSmrg info->front_buffer = old_front; 2893d6c0b56eSmrg scrn->virtualX = old_width; 2894d6c0b56eSmrg scrn->virtualY = old_height; 2895d6c0b56eSmrg scrn->displayWidth = old_pitch; 2896d6c0b56eSmrg 2897d6c0b56eSmrg return FALSE; 2898d6c0b56eSmrg} 2899d6c0b56eSmrg 290035d5b7c7Smrgstatic void 290135d5b7c7Smrgdrmmode_validate_leases(ScrnInfoPtr scrn) 290235d5b7c7Smrg{ 290335d5b7c7Smrg#ifdef XF86_LEASE_VERSION 290435d5b7c7Smrg ScreenPtr screen = scrn->pScreen; 290535d5b7c7Smrg rrScrPrivPtr scr_priv = rrGetScrPriv(screen); 290635d5b7c7Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 290735d5b7c7Smrg drmModeLesseeListPtr lessees; 290835d5b7c7Smrg RRLeasePtr lease, next; 290935d5b7c7Smrg int l; 291035d5b7c7Smrg 291135d5b7c7Smrg /* We can't talk to the kernel about leases when VT switched */ 291235d5b7c7Smrg if (!scrn->vtSema) 291335d5b7c7Smrg return; 291435d5b7c7Smrg 291535d5b7c7Smrg lessees = drmModeListLessees(pAMDGPUEnt->fd); 291635d5b7c7Smrg if (!lessees) 291735d5b7c7Smrg return; 291835d5b7c7Smrg 291935d5b7c7Smrg xorg_list_for_each_entry_safe(lease, next, &scr_priv->leases, list) { 292035d5b7c7Smrg drmmode_lease_private_ptr lease_private = lease->devPrivate; 292135d5b7c7Smrg 292235d5b7c7Smrg for (l = 0; l < lessees->count; l++) { 292335d5b7c7Smrg if (lessees->lessees[l] == lease_private->lessee_id) 292435d5b7c7Smrg break; 292535d5b7c7Smrg } 292635d5b7c7Smrg 292735d5b7c7Smrg /* check to see if the lease has gone away */ 292835d5b7c7Smrg if (l == lessees->count) { 292935d5b7c7Smrg free(lease_private); 293035d5b7c7Smrg lease->devPrivate = NULL; 293135d5b7c7Smrg xf86CrtcLeaseTerminated(lease); 293235d5b7c7Smrg } 293335d5b7c7Smrg } 293435d5b7c7Smrg 293535d5b7c7Smrg free(lessees); 293635d5b7c7Smrg#endif 293735d5b7c7Smrg} 293835d5b7c7Smrg 293935d5b7c7Smrg#ifdef XF86_LEASE_VERSION 294035d5b7c7Smrg 294135d5b7c7Smrgstatic int 294235d5b7c7Smrgdrmmode_create_lease(RRLeasePtr lease, int *fd) 294335d5b7c7Smrg{ 294435d5b7c7Smrg ScreenPtr screen = lease->screen; 294535d5b7c7Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 294635d5b7c7Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 294735d5b7c7Smrg drmmode_lease_private_ptr lease_private; 294835d5b7c7Smrg int noutput = lease->numOutputs; 294935d5b7c7Smrg int ncrtc = lease->numCrtcs; 295035d5b7c7Smrg uint32_t *objects; 295135d5b7c7Smrg size_t nobjects; 295235d5b7c7Smrg int lease_fd; 295335d5b7c7Smrg int c, o; 295435d5b7c7Smrg int i; 295535d5b7c7Smrg 295635d5b7c7Smrg nobjects = ncrtc + noutput; 295735d5b7c7Smrg if (nobjects == 0 || nobjects > (SIZE_MAX / 4) || 295835d5b7c7Smrg ncrtc > (SIZE_MAX - noutput)) 295935d5b7c7Smrg return BadValue; 296035d5b7c7Smrg 296135d5b7c7Smrg lease_private = calloc(1, sizeof (drmmode_lease_private_rec)); 296235d5b7c7Smrg if (!lease_private) 296335d5b7c7Smrg return BadAlloc; 296435d5b7c7Smrg 296535d5b7c7Smrg objects = malloc(nobjects * 4); 296635d5b7c7Smrg if (!objects) { 296735d5b7c7Smrg free(lease_private); 296835d5b7c7Smrg return BadAlloc; 296935d5b7c7Smrg } 297035d5b7c7Smrg 297135d5b7c7Smrg i = 0; 297235d5b7c7Smrg 297335d5b7c7Smrg /* Add CRTC ids */ 297435d5b7c7Smrg for (c = 0; c < ncrtc; c++) { 297535d5b7c7Smrg xf86CrtcPtr crtc = lease->crtcs[c]->devPrivate; 297635d5b7c7Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 297735d5b7c7Smrg 297835d5b7c7Smrg objects[i++] = drmmode_crtc->mode_crtc->crtc_id; 297935d5b7c7Smrg } 298035d5b7c7Smrg 298135d5b7c7Smrg /* Add connector ids */ 298235d5b7c7Smrg for (o = 0; o < noutput; o++) { 298335d5b7c7Smrg xf86OutputPtr output = lease->outputs[o]->devPrivate; 298435d5b7c7Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 298535d5b7c7Smrg 298635d5b7c7Smrg objects[i++] = drmmode_output->mode_output->connector_id; 298735d5b7c7Smrg } 298835d5b7c7Smrg 298935d5b7c7Smrg /* call kernel to create lease */ 299035d5b7c7Smrg assert (i == nobjects); 299135d5b7c7Smrg 299235d5b7c7Smrg lease_fd = drmModeCreateLease(pAMDGPUEnt->fd, objects, nobjects, 0, 299335d5b7c7Smrg &lease_private->lessee_id); 299435d5b7c7Smrg 299535d5b7c7Smrg free(objects); 299635d5b7c7Smrg 299735d5b7c7Smrg if (lease_fd < 0) { 299835d5b7c7Smrg free(lease_private); 299935d5b7c7Smrg return BadMatch; 300035d5b7c7Smrg } 300135d5b7c7Smrg 300235d5b7c7Smrg lease->devPrivate = lease_private; 300335d5b7c7Smrg 300435d5b7c7Smrg xf86CrtcLeaseStarted(lease); 300535d5b7c7Smrg 300635d5b7c7Smrg *fd = lease_fd; 300735d5b7c7Smrg return Success; 300835d5b7c7Smrg} 300935d5b7c7Smrg 301035d5b7c7Smrgstatic void 301135d5b7c7Smrgdrmmode_terminate_lease(RRLeasePtr lease) 301235d5b7c7Smrg{ 301335d5b7c7Smrg drmmode_lease_private_ptr lease_private = lease->devPrivate; 301435d5b7c7Smrg ScreenPtr screen = lease->screen; 301535d5b7c7Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 301635d5b7c7Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 301735d5b7c7Smrg 301835d5b7c7Smrg if (drmModeRevokeLease(pAMDGPUEnt->fd, lease_private->lessee_id) == 0) { 301935d5b7c7Smrg free(lease_private); 302035d5b7c7Smrg lease->devPrivate = NULL; 302135d5b7c7Smrg xf86CrtcLeaseTerminated(lease); 302235d5b7c7Smrg } 302335d5b7c7Smrg} 302435d5b7c7Smrg 302535d5b7c7Smrg#endif // XF86_LEASE_VERSION 302635d5b7c7Smrg 3027d6c0b56eSmrgstatic const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { 302835d5b7c7Smrg .resize = drmmode_xf86crtc_resize, 302935d5b7c7Smrg#ifdef XF86_LEASE_VERSION 303035d5b7c7Smrg .create_lease = drmmode_create_lease, 303135d5b7c7Smrg .terminate_lease = drmmode_terminate_lease 303235d5b7c7Smrg#endif 3033d6c0b56eSmrg}; 3034d6c0b56eSmrg 3035d6c0b56eSmrgstatic void 3036d6c0b56eSmrgdrmmode_flip_abort(xf86CrtcPtr crtc, void *event_data) 3037d6c0b56eSmrg{ 303824b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 303924b90cf4Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 3040d6c0b56eSmrg drmmode_flipdata_ptr flipdata = event_data; 304135d5b7c7Smrg int crtc_id = drmmode_get_crtc_id(crtc); 304235d5b7c7Smrg struct drmmode_fb **fb = &flipdata->fb[crtc_id]; 304335d5b7c7Smrg 304435d5b7c7Smrg if (drmmode_crtc->flip_pending == *fb) { 304535d5b7c7Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending, 304635d5b7c7Smrg NULL); 304735d5b7c7Smrg } 304835d5b7c7Smrg drmmode_fb_reference(pAMDGPUEnt->fd, fb, NULL); 3049d6c0b56eSmrg 3050d6c0b56eSmrg if (--flipdata->flip_count == 0) { 3051504d986fSmrg if (!flipdata->fe_crtc) 3052504d986fSmrg flipdata->fe_crtc = crtc; 3053504d986fSmrg flipdata->abort(flipdata->fe_crtc, flipdata->event_data); 3054d6c0b56eSmrg free(flipdata); 3055d6c0b56eSmrg } 3056d6c0b56eSmrg} 3057d6c0b56eSmrg 3058d6c0b56eSmrgstatic void 3059d6c0b56eSmrgdrmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *event_data) 3060d6c0b56eSmrg{ 3061d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 306224b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 3063d6c0b56eSmrg drmmode_flipdata_ptr flipdata = event_data; 306435d5b7c7Smrg int crtc_id = drmmode_get_crtc_id(crtc); 306535d5b7c7Smrg struct drmmode_fb **fb = &flipdata->fb[crtc_id]; 3066d6c0b56eSmrg 3067d6c0b56eSmrg /* Is this the event whose info shall be delivered to higher level? */ 3068d6c0b56eSmrg if (crtc == flipdata->fe_crtc) { 3069d6c0b56eSmrg /* Yes: Cache msc, ust for later delivery. */ 3070d6c0b56eSmrg flipdata->fe_frame = frame; 3071d6c0b56eSmrg flipdata->fe_usec = usec; 3072d6c0b56eSmrg } 3073d6c0b56eSmrg 307435d5b7c7Smrg if (drmmode_crtc->flip_pending == *fb) { 307524b90cf4Smrg drmmode_fb_reference(pAMDGPUEnt->fd, 307624b90cf4Smrg &drmmode_crtc->flip_pending, NULL); 307724b90cf4Smrg } 307835d5b7c7Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, *fb); 307935d5b7c7Smrg drmmode_fb_reference(pAMDGPUEnt->fd, fb, NULL); 308024b90cf4Smrg 3081d6c0b56eSmrg if (--flipdata->flip_count == 0) { 3082504d986fSmrg /* Deliver MSC & UST from reference/current CRTC to flip event 3083504d986fSmrg * handler 3084504d986fSmrg */ 3085d6c0b56eSmrg if (flipdata->fe_crtc) 3086504d986fSmrg flipdata->handler(flipdata->fe_crtc, flipdata->fe_frame, 3087504d986fSmrg flipdata->fe_usec, flipdata->event_data); 3088504d986fSmrg else 3089504d986fSmrg flipdata->handler(crtc, frame, usec, flipdata->event_data); 3090d6c0b56eSmrg 3091d6c0b56eSmrg free(flipdata); 3092d6c0b56eSmrg } 3093d6c0b56eSmrg} 3094d6c0b56eSmrg 3095504d986fSmrg#if HAVE_NOTIFY_FD 3096504d986fSmrgstatic void drmmode_notify_fd(int fd, int notify, void *data) 3097504d986fSmrg{ 3098504d986fSmrg drmmode_ptr drmmode = data; 309935d5b7c7Smrg amdgpu_drm_handle_event(fd, &drmmode->event_context); 3100504d986fSmrg} 3101504d986fSmrg#else 3102d6c0b56eSmrgstatic void drm_wakeup_handler(pointer data, int err, pointer p) 3103d6c0b56eSmrg{ 3104d6c0b56eSmrg drmmode_ptr drmmode = data; 3105d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(drmmode->scrn); 3106d6c0b56eSmrg fd_set *read_mask = p; 3107d6c0b56eSmrg 3108d6c0b56eSmrg if (err >= 0 && FD_ISSET(pAMDGPUEnt->fd, read_mask)) { 310935d5b7c7Smrg amdgpu_drm_handle_event(pAMDGPUEnt->fd, &drmmode->event_context); 3110d6c0b56eSmrg } 3111d6c0b56eSmrg} 3112504d986fSmrg#endif 3113d6c0b56eSmrg 311411bf0794Smrgstatic Bool drmmode_probe_page_flip_target(AMDGPUEntPtr pAMDGPUEnt) 311511bf0794Smrg{ 311611bf0794Smrg uint64_t cap_value; 311711bf0794Smrg 311811bf0794Smrg return drmGetCap(pAMDGPUEnt->fd, DRM_CAP_PAGE_FLIP_TARGET, 311911bf0794Smrg &cap_value) == 0 && cap_value != 0; 312011bf0794Smrg} 312111bf0794Smrg 312211bf0794Smrgstatic int 312311bf0794Smrgdrmmode_page_flip(AMDGPUEntPtr pAMDGPUEnt, drmmode_crtc_private_ptr drmmode_crtc, 312411bf0794Smrg int fb_id, uint32_t flags, uintptr_t drm_queue_seq) 312511bf0794Smrg{ 312611bf0794Smrg flags |= DRM_MODE_PAGE_FLIP_EVENT; 312711bf0794Smrg return drmModePageFlip(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 312811bf0794Smrg fb_id, flags, (void*)drm_queue_seq); 312911bf0794Smrg} 313011bf0794Smrg 313111bf0794Smrgint 313211bf0794Smrgdrmmode_page_flip_target_absolute(AMDGPUEntPtr pAMDGPUEnt, 313311bf0794Smrg drmmode_crtc_private_ptr drmmode_crtc, 313411bf0794Smrg int fb_id, uint32_t flags, 313511bf0794Smrg uintptr_t drm_queue_seq, uint32_t target_msc) 313611bf0794Smrg{ 313711bf0794Smrg if (pAMDGPUEnt->has_page_flip_target) { 313811bf0794Smrg flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE; 313911bf0794Smrg return drmModePageFlipTarget(pAMDGPUEnt->fd, 314011bf0794Smrg drmmode_crtc->mode_crtc->crtc_id, 314111bf0794Smrg fb_id, flags, (void*)drm_queue_seq, 314211bf0794Smrg target_msc); 314311bf0794Smrg } 314411bf0794Smrg 314511bf0794Smrg return drmmode_page_flip(pAMDGPUEnt, drmmode_crtc, fb_id, flags, 314611bf0794Smrg drm_queue_seq); 314711bf0794Smrg} 314811bf0794Smrg 314911bf0794Smrgint 315011bf0794Smrgdrmmode_page_flip_target_relative(AMDGPUEntPtr pAMDGPUEnt, 315111bf0794Smrg drmmode_crtc_private_ptr drmmode_crtc, 315211bf0794Smrg int fb_id, uint32_t flags, 315311bf0794Smrg uintptr_t drm_queue_seq, uint32_t target_msc) 315411bf0794Smrg{ 315511bf0794Smrg if (pAMDGPUEnt->has_page_flip_target) { 315611bf0794Smrg flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_RELATIVE; 315711bf0794Smrg return drmModePageFlipTarget(pAMDGPUEnt->fd, 315811bf0794Smrg drmmode_crtc->mode_crtc->crtc_id, 315911bf0794Smrg fb_id, flags, (void*)drm_queue_seq, 316011bf0794Smrg target_msc); 316111bf0794Smrg } 316211bf0794Smrg 316311bf0794Smrg return drmmode_page_flip(pAMDGPUEnt, drmmode_crtc, fb_id, flags, 316411bf0794Smrg drm_queue_seq); 316511bf0794Smrg} 316611bf0794Smrg 316735d5b7c7Smrg/** 316835d5b7c7Smrg * Initialize DDX color management support. It does two things: 316935d5b7c7Smrg * 317035d5b7c7Smrg * 1. Cache DRM color management property type IDs, as they do not change. They 317135d5b7c7Smrg * will be used later to modify color management via DRM, or to determine if 317235d5b7c7Smrg * there's kernel support for color management. 317335d5b7c7Smrg * 317435d5b7c7Smrg * 2. Cache degamma/gamma LUT sizes, since all CRTCs have the same LUT sizes on 317535d5b7c7Smrg * AMD hardware. 317635d5b7c7Smrg * 317735d5b7c7Smrg * If the cached ID's are all 0 after calling this function, then color 317835d5b7c7Smrg * management is not supported. For short, checking if the gamma LUT size 317935d5b7c7Smrg * property ID == 0 is sufficient. 318035d5b7c7Smrg * 318135d5b7c7Smrg * This should be called before CRTCs are initialized within pre_init, as the 318235d5b7c7Smrg * cached values will be used there. 318335d5b7c7Smrg * 318435d5b7c7Smrg * @drm_fd: DRM file descriptor 318535d5b7c7Smrg * @drmmode: drmmode object, where the cached IDs are stored 318635d5b7c7Smrg * @mode_res: The DRM mode resource containing the CRTC ids 318735d5b7c7Smrg */ 318835d5b7c7Smrgstatic void drmmode_cm_init(int drm_fd, drmmode_ptr drmmode, 318935d5b7c7Smrg drmModeResPtr mode_res) 319035d5b7c7Smrg{ 319135d5b7c7Smrg drmModeObjectPropertiesPtr drm_props; 319235d5b7c7Smrg drmModePropertyPtr drm_prop; 319335d5b7c7Smrg enum drmmode_cm_prop cm_prop; 319435d5b7c7Smrg uint32_t cm_enabled = 0; 319535d5b7c7Smrg uint32_t cm_all_enabled = (1 << CM_NUM_PROPS) - 1; 319635d5b7c7Smrg int i; 319735d5b7c7Smrg 319835d5b7c7Smrg memset(drmmode->cm_prop_ids, 0, sizeof(drmmode->cm_prop_ids)); 319935d5b7c7Smrg drmmode->gamma_lut_size = drmmode->degamma_lut_size = 0; 320035d5b7c7Smrg 320135d5b7c7Smrg if (!mode_res->crtcs) 320235d5b7c7Smrg return; 320335d5b7c7Smrg 320435d5b7c7Smrg /* AMD hardware has color management support on all pipes. It is 320535d5b7c7Smrg * therefore sufficient to only check the first CRTC. 320635d5b7c7Smrg */ 320735d5b7c7Smrg drm_props = drmModeObjectGetProperties(drm_fd, 320835d5b7c7Smrg mode_res->crtcs[0], 320935d5b7c7Smrg DRM_MODE_OBJECT_CRTC); 321035d5b7c7Smrg if (!drm_props) 321135d5b7c7Smrg return; 321235d5b7c7Smrg 321335d5b7c7Smrg for (i = 0; i < drm_props->count_props; i++) { 321435d5b7c7Smrg drm_prop = drmModeGetProperty(drm_fd, 321535d5b7c7Smrg drm_props->props[i]); 321635d5b7c7Smrg if (!drm_prop) 321735d5b7c7Smrg continue; 321835d5b7c7Smrg 321935d5b7c7Smrg cm_prop = get_cm_enum_from_str(drm_prop->name); 322035d5b7c7Smrg if (cm_prop == CM_INVALID_PROP) 322135d5b7c7Smrg continue; 322235d5b7c7Smrg 322335d5b7c7Smrg if (cm_prop == CM_DEGAMMA_LUT_SIZE) 322435d5b7c7Smrg drmmode->degamma_lut_size = drm_props->prop_values[i]; 322535d5b7c7Smrg else if (cm_prop == CM_GAMMA_LUT_SIZE) 322635d5b7c7Smrg drmmode->gamma_lut_size = drm_props->prop_values[i]; 322735d5b7c7Smrg 322835d5b7c7Smrg drmmode->cm_prop_ids[cm_prop] = drm_props->props[i]; 322935d5b7c7Smrg cm_enabled |= 1 << cm_prop; 323035d5b7c7Smrg 323135d5b7c7Smrg drmModeFreeProperty(drm_prop); 323235d5b7c7Smrg } 323335d5b7c7Smrg drmModeFreeObjectProperties(drm_props); 323435d5b7c7Smrg 323535d5b7c7Smrg /* cm is enabled only if all prop ids are found */ 323635d5b7c7Smrg if (cm_enabled == cm_all_enabled) 323735d5b7c7Smrg return; 323835d5b7c7Smrg 323935d5b7c7Smrg /* Otherwise, disable DDX cm support */ 324035d5b7c7Smrg memset(drmmode->cm_prop_ids, 0, sizeof(drmmode->cm_prop_ids)); 324135d5b7c7Smrg drmmode->gamma_lut_size = drmmode->degamma_lut_size = 0; 324235d5b7c7Smrg} 324335d5b7c7Smrg 3244d6c0b56eSmrgBool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp) 3245d6c0b56eSmrg{ 3246d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 3247d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 3248d6c0b56eSmrg int i, num_dvi = 0, num_hdmi = 0; 3249d6c0b56eSmrg unsigned int crtcs_needed = 0; 3250d6c0b56eSmrg drmModeResPtr mode_res; 3251d6c0b56eSmrg char *bus_id_string, *provider_name; 3252d6c0b56eSmrg 3253d6c0b56eSmrg xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs); 3254d6c0b56eSmrg 3255d6c0b56eSmrg drmmode->scrn = pScrn; 3256d6c0b56eSmrg mode_res = drmModeGetResources(pAMDGPUEnt->fd); 3257d6c0b56eSmrg if (!mode_res) 3258d6c0b56eSmrg return FALSE; 3259d6c0b56eSmrg 3260d6c0b56eSmrg drmmode->count_crtcs = mode_res->count_crtcs; 3261d6c0b56eSmrg xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width, 3262d6c0b56eSmrg mode_res->max_height); 3263d6c0b56eSmrg 3264d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 3265d6c0b56eSmrg "Initializing outputs ...\n"); 3266d6c0b56eSmrg for (i = 0; i < mode_res->count_connectors; i++) 3267d6c0b56eSmrg crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, i, &num_dvi, &num_hdmi, 0); 3268d6c0b56eSmrg 3269d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 3270d6c0b56eSmrg "%d crtcs needed for screen.\n", crtcs_needed); 3271d6c0b56eSmrg 327224b90cf4Smrg /* Need per-screen drmmode_crtc_funcs, based on our global template, 327324b90cf4Smrg * so we can disable some functions, depending on screen settings. 327424b90cf4Smrg */ 327524b90cf4Smrg info->drmmode_crtc_funcs = drmmode_crtc_funcs; 327624b90cf4Smrg 3277d6c0b56eSmrg if (!info->use_glamor) { 3278d6c0b56eSmrg /* Rotation requires hardware acceleration */ 327924b90cf4Smrg info->drmmode_crtc_funcs.shadow_allocate = NULL; 328024b90cf4Smrg info->drmmode_crtc_funcs.shadow_create = NULL; 328124b90cf4Smrg info->drmmode_crtc_funcs.shadow_destroy = NULL; 3282d6c0b56eSmrg } 3283d6c0b56eSmrg 328435d5b7c7Smrg drmmode_cm_init(pAMDGPUEnt->fd, drmmode, mode_res); 328535d5b7c7Smrg 328635d5b7c7Smrg /* Spare the server the effort to compute and update unused CLUTs. */ 328735d5b7c7Smrg if (pScrn->depth == 30 && !drmmode_cm_enabled(drmmode)) 328824b90cf4Smrg info->drmmode_crtc_funcs.gamma_set = NULL; 328924b90cf4Smrg 3290d6c0b56eSmrg for (i = 0; i < mode_res->count_crtcs; i++) 3291d6c0b56eSmrg if (!xf86IsEntityShared(pScrn->entityList[0]) || 3292d6c0b56eSmrg (crtcs_needed && !(pAMDGPUEnt->assigned_crtcs & (1 << i)))) 3293d6c0b56eSmrg crtcs_needed -= drmmode_crtc_init(pScrn, drmmode, mode_res, i); 3294d6c0b56eSmrg 3295d6c0b56eSmrg /* All ZaphodHeads outputs provided with matching crtcs? */ 3296d6c0b56eSmrg if (xf86IsEntityShared(pScrn->entityList[0]) && (crtcs_needed > 0)) 3297d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 3298d6c0b56eSmrg "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n", 3299d6c0b56eSmrg crtcs_needed); 3300d6c0b56eSmrg 3301d6c0b56eSmrg /* workout clones */ 3302d6c0b56eSmrg drmmode_clones_init(pScrn, drmmode, mode_res); 3303d6c0b56eSmrg 3304d6c0b56eSmrg bus_id_string = DRICreatePCIBusID(info->PciInfo); 3305d6c0b56eSmrg XNFasprintf(&provider_name, "%s @ %s", pScrn->chipset, bus_id_string); 3306d6c0b56eSmrg free(bus_id_string); 3307d6c0b56eSmrg xf86ProviderSetup(pScrn, NULL, provider_name); 3308d6c0b56eSmrg free(provider_name); 3309d6c0b56eSmrg 3310d6c0b56eSmrg xf86InitialConfiguration(pScrn, TRUE); 3311d6c0b56eSmrg 331211bf0794Smrg pAMDGPUEnt->has_page_flip_target = drmmode_probe_page_flip_target(pAMDGPUEnt); 331311bf0794Smrg 3314d6c0b56eSmrg drmModeFreeResources(mode_res); 3315d6c0b56eSmrg return TRUE; 3316d6c0b56eSmrg} 3317d6c0b56eSmrg 3318d6c0b56eSmrgvoid drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 3319d6c0b56eSmrg{ 3320d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 3321d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 3322d6c0b56eSmrg 3323d6c0b56eSmrg info->drmmode_inited = TRUE; 3324d6c0b56eSmrg if (pAMDGPUEnt->fd_wakeup_registered != serverGeneration) { 3325504d986fSmrg#if HAVE_NOTIFY_FD 3326504d986fSmrg SetNotifyFd(pAMDGPUEnt->fd, drmmode_notify_fd, X_NOTIFY_READ, drmmode); 3327504d986fSmrg#else 3328d6c0b56eSmrg AddGeneralSocket(pAMDGPUEnt->fd); 3329d6c0b56eSmrg RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr) NoopDDA, 3330d6c0b56eSmrg drm_wakeup_handler, drmmode); 3331504d986fSmrg#endif 3332d6c0b56eSmrg pAMDGPUEnt->fd_wakeup_registered = serverGeneration; 3333d6c0b56eSmrg pAMDGPUEnt->fd_wakeup_ref = 1; 3334d6c0b56eSmrg } else 3335d6c0b56eSmrg pAMDGPUEnt->fd_wakeup_ref++; 3336d6c0b56eSmrg} 3337d6c0b56eSmrg 3338d6c0b56eSmrgvoid drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 3339d6c0b56eSmrg{ 3340504d986fSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 3341d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 3342d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 3343504d986fSmrg int c; 3344d6c0b56eSmrg 3345d6c0b56eSmrg if (!info->drmmode_inited) 3346d6c0b56eSmrg return; 3347d6c0b56eSmrg 3348d6c0b56eSmrg if (pAMDGPUEnt->fd_wakeup_registered == serverGeneration && 3349d6c0b56eSmrg !--pAMDGPUEnt->fd_wakeup_ref) { 3350504d986fSmrg#if HAVE_NOTIFY_FD 3351504d986fSmrg RemoveNotifyFd(pAMDGPUEnt->fd); 3352504d986fSmrg#else 3353d6c0b56eSmrg RemoveGeneralSocket(pAMDGPUEnt->fd); 3354d6c0b56eSmrg RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr) NoopDDA, 3355d6c0b56eSmrg drm_wakeup_handler, drmmode); 3356504d986fSmrg#endif 3357504d986fSmrg } 3358504d986fSmrg 335911bf0794Smrg for (c = 0; c < config->num_crtc; c++) 336011bf0794Smrg drmmode_crtc_scanout_free(config->crtc[c]->driver_private); 3361d6c0b56eSmrg} 3362d6c0b56eSmrg 336324b90cf4Smrgstatic void drmmode_sprite_do_set_cursor(struct amdgpu_device_priv *device_priv, 336424b90cf4Smrg ScrnInfoPtr scrn, int x, int y) 336524b90cf4Smrg{ 336624b90cf4Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 336724b90cf4Smrg CursorPtr cursor = device_priv->cursor; 336824b90cf4Smrg Bool sprite_visible = device_priv->sprite_visible; 336924b90cf4Smrg 337024b90cf4Smrg if (cursor) { 337124b90cf4Smrg x -= cursor->bits->xhot; 337224b90cf4Smrg y -= cursor->bits->yhot; 337324b90cf4Smrg 337424b90cf4Smrg device_priv->sprite_visible = 337524b90cf4Smrg x < scrn->virtualX && y < scrn->virtualY && 337624b90cf4Smrg (x + cursor->bits->width > 0) && 337724b90cf4Smrg (y + cursor->bits->height > 0); 337824b90cf4Smrg } else { 337924b90cf4Smrg device_priv->sprite_visible = FALSE; 338024b90cf4Smrg } 338124b90cf4Smrg 338224b90cf4Smrg info->sprites_visible += device_priv->sprite_visible - sprite_visible; 338324b90cf4Smrg} 338424b90cf4Smrg 338535d5b7c7Smrgstatic void drmmode_sprite_set_cursor(DeviceIntPtr pDev, ScreenPtr pScreen, 338635d5b7c7Smrg CursorPtr pCursor, int x, int y) 338724b90cf4Smrg{ 338824b90cf4Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 338924b90cf4Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 339024b90cf4Smrg struct amdgpu_device_priv *device_priv = 339124b90cf4Smrg dixLookupScreenPrivate(&pDev->devPrivates, 339224b90cf4Smrg &amdgpu_device_private_key, pScreen); 339324b90cf4Smrg 339424b90cf4Smrg device_priv->cursor = pCursor; 339524b90cf4Smrg drmmode_sprite_do_set_cursor(device_priv, scrn, x, y); 339624b90cf4Smrg 339735d5b7c7Smrg info->SpriteFuncs->SetCursor(pDev, pScreen, pCursor, x, y); 339824b90cf4Smrg} 339924b90cf4Smrg 340035d5b7c7Smrgstatic void drmmode_sprite_move_cursor(DeviceIntPtr pDev, ScreenPtr pScreen, 340135d5b7c7Smrg int x, int y) 340224b90cf4Smrg{ 340324b90cf4Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 340424b90cf4Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 340524b90cf4Smrg struct amdgpu_device_priv *device_priv = 340624b90cf4Smrg dixLookupScreenPrivate(&pDev->devPrivates, 340724b90cf4Smrg &amdgpu_device_private_key, pScreen); 340824b90cf4Smrg 340924b90cf4Smrg drmmode_sprite_do_set_cursor(device_priv, scrn, x, y); 341024b90cf4Smrg 341135d5b7c7Smrg info->SpriteFuncs->MoveCursor(pDev, pScreen, x, y); 341224b90cf4Smrg} 341324b90cf4Smrg 341435d5b7c7Smrgstatic Bool drmmode_sprite_realize_realize_cursor(DeviceIntPtr pDev, 341535d5b7c7Smrg ScreenPtr pScreen, 341635d5b7c7Smrg CursorPtr pCursor) 341735d5b7c7Smrg{ 341835d5b7c7Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 341935d5b7c7Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 342035d5b7c7Smrg 342135d5b7c7Smrg return info->SpriteFuncs->RealizeCursor(pDev, pScreen, pCursor); 342235d5b7c7Smrg} 342335d5b7c7Smrg 342435d5b7c7Smrgstatic Bool drmmode_sprite_realize_unrealize_cursor(DeviceIntPtr pDev, 342535d5b7c7Smrg ScreenPtr pScreen, 342635d5b7c7Smrg CursorPtr pCursor) 342735d5b7c7Smrg{ 342835d5b7c7Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 342935d5b7c7Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 343035d5b7c7Smrg 343135d5b7c7Smrg return info->SpriteFuncs->UnrealizeCursor(pDev, pScreen, pCursor); 343235d5b7c7Smrg} 343335d5b7c7Smrg 343435d5b7c7Smrgstatic Bool drmmode_sprite_device_cursor_initialize(DeviceIntPtr pDev, 343535d5b7c7Smrg ScreenPtr pScreen) 343635d5b7c7Smrg{ 343735d5b7c7Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 343835d5b7c7Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 343935d5b7c7Smrg 344035d5b7c7Smrg return info->SpriteFuncs->DeviceCursorInitialize(pDev, pScreen); 344135d5b7c7Smrg} 344235d5b7c7Smrg 344335d5b7c7Smrgstatic void drmmode_sprite_device_cursor_cleanup(DeviceIntPtr pDev, 344435d5b7c7Smrg ScreenPtr pScreen) 344535d5b7c7Smrg{ 344635d5b7c7Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 344735d5b7c7Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 344835d5b7c7Smrg 344935d5b7c7Smrg info->SpriteFuncs->DeviceCursorCleanup(pDev, pScreen); 345035d5b7c7Smrg} 345135d5b7c7Smrg 345235d5b7c7SmrgmiPointerSpriteFuncRec drmmode_sprite_funcs = { 345335d5b7c7Smrg .RealizeCursor = drmmode_sprite_realize_realize_cursor, 345435d5b7c7Smrg .UnrealizeCursor = drmmode_sprite_realize_unrealize_cursor, 345535d5b7c7Smrg .SetCursor = drmmode_sprite_set_cursor, 345635d5b7c7Smrg .MoveCursor = drmmode_sprite_move_cursor, 345735d5b7c7Smrg .DeviceCursorInitialize = drmmode_sprite_device_cursor_initialize, 345835d5b7c7Smrg .DeviceCursorCleanup = drmmode_sprite_device_cursor_cleanup, 345935d5b7c7Smrg}; 346035d5b7c7Smrg 346135d5b7c7Smrg 3462d6c0b56eSmrgvoid drmmode_set_cursor(ScrnInfoPtr scrn, drmmode_ptr drmmode, int id, 3463d6c0b56eSmrg struct amdgpu_buffer *bo) 3464d6c0b56eSmrg{ 3465d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 3466d6c0b56eSmrg xf86CrtcPtr crtc = xf86_config->crtc[id]; 3467d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 3468d6c0b56eSmrg 3469d6c0b56eSmrg drmmode_crtc->cursor_buffer = bo; 3470d6c0b56eSmrg} 3471d6c0b56eSmrg 3472d6c0b56eSmrgvoid drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y) 3473d6c0b56eSmrg{ 3474d6c0b56eSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 3475d6c0b56eSmrg xf86OutputPtr output = config->output[config->compat_output]; 3476d6c0b56eSmrg xf86CrtcPtr crtc = output->crtc; 3477d6c0b56eSmrg 3478d6c0b56eSmrg if (crtc && crtc->enabled) { 3479d6c0b56eSmrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y); 3480d6c0b56eSmrg } 3481d6c0b56eSmrg} 3482d6c0b56eSmrg 3483d6c0b56eSmrgBool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, 3484d6c0b56eSmrg Bool set_hw) 3485d6c0b56eSmrg{ 3486d6c0b56eSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 348724b90cf4Smrg unsigned num_desired = 0, num_on = 0; 3488d6c0b56eSmrg int c; 3489d6c0b56eSmrg 349024b90cf4Smrg /* First, disable all unused CRTCs */ 349124b90cf4Smrg if (set_hw) { 349224b90cf4Smrg for (c = 0; c < config->num_crtc; c++) { 349324b90cf4Smrg xf86CrtcPtr crtc = config->crtc[c]; 349424b90cf4Smrg 349524b90cf4Smrg /* Skip disabled CRTCs */ 349624b90cf4Smrg if (crtc->enabled) 349724b90cf4Smrg continue; 349824b90cf4Smrg 349935d5b7c7Smrg drmmode_crtc_dpms(crtc, DPMSModeOff); 350024b90cf4Smrg } 350124b90cf4Smrg } 350224b90cf4Smrg 350324b90cf4Smrg /* Then, try setting the chosen mode on each CRTC */ 3504d6c0b56eSmrg for (c = 0; c < config->num_crtc; c++) { 3505d6c0b56eSmrg xf86CrtcPtr crtc = config->crtc[c]; 3506d6c0b56eSmrg xf86OutputPtr output = NULL; 3507d6c0b56eSmrg int o; 3508d6c0b56eSmrg 350924b90cf4Smrg if (!crtc->enabled) 3510d6c0b56eSmrg continue; 3511d6c0b56eSmrg 3512d6c0b56eSmrg if (config->output[config->compat_output]->crtc == crtc) 3513d6c0b56eSmrg output = config->output[config->compat_output]; 3514d6c0b56eSmrg else { 3515d6c0b56eSmrg for (o = 0; o < config->num_output; o++) 3516d6c0b56eSmrg if (config->output[o]->crtc == crtc) { 3517d6c0b56eSmrg output = config->output[o]; 3518d6c0b56eSmrg break; 3519d6c0b56eSmrg } 3520d6c0b56eSmrg } 3521d6c0b56eSmrg /* paranoia */ 3522d6c0b56eSmrg if (!output) 3523d6c0b56eSmrg continue; 3524d6c0b56eSmrg 352524b90cf4Smrg num_desired++; 352624b90cf4Smrg 3527d6c0b56eSmrg /* Mark that we'll need to re-set the mode for sure */ 3528d6c0b56eSmrg memset(&crtc->mode, 0, sizeof(crtc->mode)); 3529d6c0b56eSmrg if (!crtc->desiredMode.CrtcHDisplay) { 3530d6c0b56eSmrg DisplayModePtr mode = xf86OutputFindClosestMode(output, 3531d6c0b56eSmrg pScrn-> 3532d6c0b56eSmrg currentMode); 3533d6c0b56eSmrg 353424b90cf4Smrg if (!mode) { 353524b90cf4Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 353624b90cf4Smrg "Failed to find mode for CRTC %d\n", c); 353724b90cf4Smrg continue; 353824b90cf4Smrg } 3539d6c0b56eSmrg crtc->desiredMode = *mode; 3540d6c0b56eSmrg crtc->desiredRotation = RR_Rotate_0; 3541d6c0b56eSmrg crtc->desiredX = 0; 3542d6c0b56eSmrg crtc->desiredY = 0; 3543d6c0b56eSmrg } 3544d6c0b56eSmrg 3545d6c0b56eSmrg if (set_hw) { 354624b90cf4Smrg if (crtc->funcs->set_mode_major(crtc, &crtc->desiredMode, 354724b90cf4Smrg crtc->desiredRotation, 354824b90cf4Smrg crtc->desiredX, 354924b90cf4Smrg crtc->desiredY)) { 355024b90cf4Smrg num_on++; 355124b90cf4Smrg } else { 355224b90cf4Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 355324b90cf4Smrg "Failed to set mode on CRTC %d\n", c); 355435d5b7c7Smrg RRCrtcSet(crtc->randr_crtc, NULL, crtc->x, crtc->y, 355535d5b7c7Smrg crtc->rotation, 0, NULL); 355624b90cf4Smrg } 3557d6c0b56eSmrg } else { 3558d6c0b56eSmrg crtc->mode = crtc->desiredMode; 3559d6c0b56eSmrg crtc->rotation = crtc->desiredRotation; 3560d6c0b56eSmrg crtc->x = crtc->desiredX; 3561d6c0b56eSmrg crtc->y = crtc->desiredY; 356224b90cf4Smrg if (drmmode_handle_transform(crtc)) 356324b90cf4Smrg num_on++; 3564d6c0b56eSmrg } 3565d6c0b56eSmrg } 356624b90cf4Smrg 356724b90cf4Smrg if (num_on == 0 && num_desired > 0) { 356824b90cf4Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to enable any CRTC\n"); 356924b90cf4Smrg return FALSE; 357024b90cf4Smrg } 357124b90cf4Smrg 357235d5b7c7Smrg /* Validate leases on VT re-entry */ 357335d5b7c7Smrg drmmode_validate_leases(pScrn); 357435d5b7c7Smrg 3575d6c0b56eSmrg return TRUE; 3576d6c0b56eSmrg} 3577d6c0b56eSmrg 3578d6c0b56eSmrgBool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn) 3579d6c0b56eSmrg{ 3580d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 358135d5b7c7Smrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 358235d5b7c7Smrg int i; 3583d6c0b56eSmrg 3584d6c0b56eSmrg if (xf86_config->num_crtc) { 3585d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 3586d6c0b56eSmrg "Initializing kms color map\n"); 3587d6c0b56eSmrg if (!miCreateDefColormap(pScreen)) 3588d6c0b56eSmrg return FALSE; 358935d5b7c7Smrg 359035d5b7c7Smrg if (pScrn->depth == 30) { 359135d5b7c7Smrg if (!drmmode_cm_enabled(&info->drmmode)) 359235d5b7c7Smrg return TRUE; 359335d5b7c7Smrg 359435d5b7c7Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 359535d5b7c7Smrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 359635d5b7c7Smrg void *gamma; 359735d5b7c7Smrg 359835d5b7c7Smrg if (crtc->gamma_size == 1024) 359935d5b7c7Smrg continue; 360035d5b7c7Smrg 360135d5b7c7Smrg gamma = malloc(1024 * 3 * sizeof(CARD16)); 360235d5b7c7Smrg if (!gamma) { 360335d5b7c7Smrg ErrorF("Failed to allocate gamma LUT memory\n"); 360435d5b7c7Smrg return FALSE; 360535d5b7c7Smrg } 360635d5b7c7Smrg 360735d5b7c7Smrg free(crtc->gamma_red); 360835d5b7c7Smrg crtc->gamma_size = 1024; 360935d5b7c7Smrg crtc->gamma_red = gamma; 361035d5b7c7Smrg crtc->gamma_green = crtc->gamma_red + crtc->gamma_size; 361135d5b7c7Smrg crtc->gamma_blue = crtc->gamma_green + crtc->gamma_size; 361235d5b7c7Smrg } 361335d5b7c7Smrg } 361435d5b7c7Smrg 361535d5b7c7Smrg /* All Radeons support 10 bit CLUTs. */ 361635d5b7c7Smrg if (!xf86HandleColormaps(pScreen, 1 << pScrn->rgbBits, 10, 361735d5b7c7Smrg NULL, NULL, CMAP_PALETTED_TRUECOLOR 3618d6c0b56eSmrg | CMAP_RELOAD_ON_MODE_SWITCH)) 3619d6c0b56eSmrg return FALSE; 362035d5b7c7Smrg 362135d5b7c7Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 362235d5b7c7Smrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 362335d5b7c7Smrg 362435d5b7c7Smrg drmmode_crtc_gamma_do_set(crtc, crtc->gamma_red, 362535d5b7c7Smrg crtc->gamma_green, 362635d5b7c7Smrg crtc->gamma_blue, 362735d5b7c7Smrg crtc->gamma_size); 362835d5b7c7Smrg } 3629d6c0b56eSmrg } 363035d5b7c7Smrg 3631d6c0b56eSmrg return TRUE; 3632d6c0b56eSmrg} 3633d6c0b56eSmrg 3634504d986fSmrgstatic Bool 3635504d986fSmrgdrmmode_find_output(ScrnInfoPtr scrn, int output_id, int *num_dvi, 3636504d986fSmrg int *num_hdmi) 3637504d986fSmrg{ 3638504d986fSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3639504d986fSmrg int i; 3640504d986fSmrg 3641504d986fSmrg for (i = 0; i < config->num_output; i++) { 3642504d986fSmrg xf86OutputPtr output = config->output[i]; 3643504d986fSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 3644504d986fSmrg 3645504d986fSmrg if (drmmode_output->output_id == output_id) { 3646504d986fSmrg switch(drmmode_output->mode_output->connector_type) { 3647504d986fSmrg case DRM_MODE_CONNECTOR_DVII: 3648504d986fSmrg case DRM_MODE_CONNECTOR_DVID: 3649504d986fSmrg case DRM_MODE_CONNECTOR_DVIA: 3650504d986fSmrg (*num_dvi)++; 3651504d986fSmrg break; 3652504d986fSmrg case DRM_MODE_CONNECTOR_HDMIA: 3653504d986fSmrg case DRM_MODE_CONNECTOR_HDMIB: 3654504d986fSmrg (*num_hdmi)++; 3655504d986fSmrg break; 3656504d986fSmrg } 3657504d986fSmrg 3658504d986fSmrg return TRUE; 3659504d986fSmrg } 3660504d986fSmrg } 3661504d986fSmrg 3662504d986fSmrg return FALSE; 3663504d986fSmrg} 3664d6c0b56eSmrg 3665d6c0b56eSmrgvoid 3666d6c0b56eSmrgamdgpu_mode_hotplug(ScrnInfoPtr scrn, drmmode_ptr drmmode) 3667d6c0b56eSmrg{ 3668d6c0b56eSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3669d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 3670d6c0b56eSmrg drmModeResPtr mode_res; 3671d6c0b56eSmrg int i, j; 3672d6c0b56eSmrg Bool found; 3673d6c0b56eSmrg Bool changed = FALSE; 3674504d986fSmrg int num_dvi = 0, num_hdmi = 0; 3675d6c0b56eSmrg 367624b90cf4Smrg /* Try to re-set the mode on all the connectors with a BAD link-state: 367724b90cf4Smrg * This may happen if a link degrades and a new modeset is necessary, using 367824b90cf4Smrg * different link-training parameters. If the kernel found that the current 367924b90cf4Smrg * mode is not achievable anymore, it should have pruned the mode before 368024b90cf4Smrg * sending the hotplug event. Try to re-set the currently-set mode to keep 368124b90cf4Smrg * the display alive, this will fail if the mode has been pruned. 368224b90cf4Smrg * In any case, we will send randr events for the Desktop Environment to 368324b90cf4Smrg * deal with it, if it wants to. 368424b90cf4Smrg */ 368524b90cf4Smrg for (i = 0; i < config->num_output; i++) { 368624b90cf4Smrg xf86OutputPtr output = config->output[i]; 368724b90cf4Smrg xf86CrtcPtr crtc = output->crtc; 368824b90cf4Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 368924b90cf4Smrg 369024b90cf4Smrg drmmode_output_detect(output); 369124b90cf4Smrg 369224b90cf4Smrg if (!crtc || !drmmode_output->mode_output) 369324b90cf4Smrg continue; 369424b90cf4Smrg 369524b90cf4Smrg /* Get an updated view of the properties for the current connector and 369624b90cf4Smrg * look for the link-status property 369724b90cf4Smrg */ 369824b90cf4Smrg for (j = 0; j < drmmode_output->num_props; j++) { 369924b90cf4Smrg drmmode_prop_ptr p = &drmmode_output->props[j]; 370024b90cf4Smrg 370124b90cf4Smrg if (!strcmp(p->mode_prop->name, "link-status")) { 370224b90cf4Smrg if (p->value != DRM_MODE_LINK_STATUS_BAD) 370324b90cf4Smrg break; 370424b90cf4Smrg 370524b90cf4Smrg /* the connector got a link failure, re-set the current mode */ 370624b90cf4Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 370724b90cf4Smrg crtc->x, crtc->y); 370824b90cf4Smrg 370924b90cf4Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 371024b90cf4Smrg "hotplug event: connector %u's link-state is BAD, " 371124b90cf4Smrg "tried resetting the current mode. You may be left" 371224b90cf4Smrg "with a black screen if this fails...\n", 371324b90cf4Smrg drmmode_output->mode_output->connector_id); 371424b90cf4Smrg 371524b90cf4Smrg break; 371624b90cf4Smrg } 371724b90cf4Smrg } 371824b90cf4Smrg } 371924b90cf4Smrg 3720d6c0b56eSmrg mode_res = drmModeGetResources(pAMDGPUEnt->fd); 3721d6c0b56eSmrg if (!mode_res) 3722d6c0b56eSmrg goto out; 3723d6c0b56eSmrg 3724d6c0b56eSmrgrestart_destroy: 3725d6c0b56eSmrg for (i = 0; i < config->num_output; i++) { 3726d6c0b56eSmrg xf86OutputPtr output = config->output[i]; 3727d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 3728d6c0b56eSmrg found = FALSE; 3729d6c0b56eSmrg for (j = 0; j < mode_res->count_connectors; j++) { 3730d6c0b56eSmrg if (mode_res->connectors[j] == drmmode_output->output_id) { 3731d6c0b56eSmrg found = TRUE; 3732d6c0b56eSmrg break; 3733d6c0b56eSmrg } 3734d6c0b56eSmrg } 3735d6c0b56eSmrg if (found) 3736d6c0b56eSmrg continue; 3737d6c0b56eSmrg 3738d6c0b56eSmrg drmModeFreeConnector(drmmode_output->mode_output); 3739d6c0b56eSmrg drmmode_output->mode_output = NULL; 3740d6c0b56eSmrg drmmode_output->output_id = -1; 3741d6c0b56eSmrg 3742d6c0b56eSmrg changed = TRUE; 3743d6c0b56eSmrg if (drmmode->delete_dp_12_displays) { 3744d6c0b56eSmrg RROutputDestroy(output->randr_output); 3745d6c0b56eSmrg xf86OutputDestroy(output); 3746d6c0b56eSmrg goto restart_destroy; 3747d6c0b56eSmrg } 3748d6c0b56eSmrg } 3749d6c0b56eSmrg 3750d6c0b56eSmrg /* find new output ids we don't have outputs for */ 3751d6c0b56eSmrg for (i = 0; i < mode_res->count_connectors; i++) { 3752504d986fSmrg if (drmmode_find_output(pAMDGPUEnt->primary_scrn, 3753504d986fSmrg mode_res->connectors[i], 3754504d986fSmrg &num_dvi, &num_hdmi) || 3755504d986fSmrg (pAMDGPUEnt->secondary_scrn && 3756504d986fSmrg drmmode_find_output(pAMDGPUEnt->secondary_scrn, 3757504d986fSmrg mode_res->connectors[i], 3758504d986fSmrg &num_dvi, &num_hdmi))) 3759d6c0b56eSmrg continue; 3760d6c0b56eSmrg 3761504d986fSmrg if (drmmode_output_init(scrn, drmmode, mode_res, i, &num_dvi, 3762504d986fSmrg &num_hdmi, 1) != 0) 3763504d986fSmrg changed = TRUE; 3764d6c0b56eSmrg } 3765d6c0b56eSmrg 376635d5b7c7Smrg /* Check to see if a lessee has disappeared */ 376735d5b7c7Smrg drmmode_validate_leases(scrn); 376835d5b7c7Smrg 3769504d986fSmrg if (changed && dixPrivateKeyRegistered(rrPrivKey)) { 3770d6c0b56eSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,2,0) 3771d6c0b56eSmrg RRSetChanged(xf86ScrnToScreen(scrn)); 3772d6c0b56eSmrg#else 3773d6c0b56eSmrg rrScrPrivPtr rrScrPriv = rrGetScrPriv(scrn->pScreen); 3774d6c0b56eSmrg rrScrPriv->changed = TRUE; 3775d6c0b56eSmrg#endif 3776d6c0b56eSmrg RRTellChanged(xf86ScrnToScreen(scrn)); 3777d6c0b56eSmrg } 3778d6c0b56eSmrg 3779d6c0b56eSmrg drmModeFreeResources(mode_res); 3780d6c0b56eSmrgout: 3781d6c0b56eSmrg RRGetInfo(xf86ScrnToScreen(scrn), TRUE); 3782d6c0b56eSmrg} 3783d6c0b56eSmrg 3784d6c0b56eSmrg#ifdef HAVE_LIBUDEV 3785d6c0b56eSmrgstatic void drmmode_handle_uevents(int fd, void *closure) 3786d6c0b56eSmrg{ 3787d6c0b56eSmrg drmmode_ptr drmmode = closure; 3788d6c0b56eSmrg ScrnInfoPtr scrn = drmmode->scrn; 3789d6c0b56eSmrg struct udev_device *dev; 3790504d986fSmrg Bool received = FALSE; 379111bf0794Smrg struct timeval tv = { 0, 0 }; 379211bf0794Smrg fd_set readfd; 379311bf0794Smrg 379411bf0794Smrg FD_ZERO(&readfd); 379511bf0794Smrg FD_SET(fd, &readfd); 379611bf0794Smrg 379711bf0794Smrg while (select(fd + 1, &readfd, NULL, NULL, &tv) > 0 && 379811bf0794Smrg FD_ISSET(fd, &readfd)) { 379911bf0794Smrg /* select() ensured that this will not block */ 380011bf0794Smrg dev = udev_monitor_receive_device(drmmode->uevent_monitor); 380111bf0794Smrg if (dev) { 380211bf0794Smrg udev_device_unref(dev); 380311bf0794Smrg received = TRUE; 380411bf0794Smrg } 3805504d986fSmrg } 3806504d986fSmrg 3807504d986fSmrg if (received) 3808504d986fSmrg amdgpu_mode_hotplug(scrn, drmmode); 3809d6c0b56eSmrg} 3810d6c0b56eSmrg#endif 3811d6c0b56eSmrg 3812d6c0b56eSmrgvoid drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode) 3813d6c0b56eSmrg{ 3814d6c0b56eSmrg#ifdef HAVE_LIBUDEV 3815d6c0b56eSmrg struct udev *u; 3816d6c0b56eSmrg struct udev_monitor *mon; 3817d6c0b56eSmrg 3818d6c0b56eSmrg u = udev_new(); 3819d6c0b56eSmrg if (!u) 3820d6c0b56eSmrg return; 3821d6c0b56eSmrg mon = udev_monitor_new_from_netlink(u, "udev"); 3822d6c0b56eSmrg if (!mon) { 3823d6c0b56eSmrg udev_unref(u); 3824d6c0b56eSmrg return; 3825d6c0b56eSmrg } 3826d6c0b56eSmrg 3827d6c0b56eSmrg if (udev_monitor_filter_add_match_subsystem_devtype(mon, 3828d6c0b56eSmrg "drm", 3829d6c0b56eSmrg "drm_minor") < 0 || 3830d6c0b56eSmrg udev_monitor_enable_receiving(mon) < 0) { 3831d6c0b56eSmrg udev_monitor_unref(mon); 3832d6c0b56eSmrg udev_unref(u); 3833d6c0b56eSmrg return; 3834d6c0b56eSmrg } 3835d6c0b56eSmrg 3836d6c0b56eSmrg drmmode->uevent_handler = 3837d6c0b56eSmrg xf86AddGeneralHandler(udev_monitor_get_fd(mon), 3838d6c0b56eSmrg drmmode_handle_uevents, drmmode); 3839d6c0b56eSmrg 3840d6c0b56eSmrg drmmode->uevent_monitor = mon; 3841d6c0b56eSmrg#endif 3842d6c0b56eSmrg} 3843d6c0b56eSmrg 3844d6c0b56eSmrgvoid drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode) 3845d6c0b56eSmrg{ 3846d6c0b56eSmrg#ifdef HAVE_LIBUDEV 3847d6c0b56eSmrg if (drmmode->uevent_handler) { 3848d6c0b56eSmrg struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor); 3849d6c0b56eSmrg xf86RemoveGeneralHandler(drmmode->uevent_handler); 3850d6c0b56eSmrg 3851d6c0b56eSmrg udev_monitor_unref(drmmode->uevent_monitor); 3852d6c0b56eSmrg udev_unref(u); 3853d6c0b56eSmrg } 3854d6c0b56eSmrg#endif 3855d6c0b56eSmrg} 3856d6c0b56eSmrg 3857d6c0b56eSmrgBool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, 3858d6c0b56eSmrg PixmapPtr new_front, uint64_t id, void *data, 385924b90cf4Smrg xf86CrtcPtr ref_crtc, amdgpu_drm_handler_proc handler, 3860504d986fSmrg amdgpu_drm_abort_proc abort, 386111bf0794Smrg enum drmmode_flip_sync flip_sync, 386211bf0794Smrg uint32_t target_msc) 3863d6c0b56eSmrg{ 3864d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 3865d6c0b56eSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3866d6c0b56eSmrg xf86CrtcPtr crtc = NULL; 3867d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private; 386811bf0794Smrg uint32_t flip_flags = flip_sync == FLIP_ASYNC ? DRM_MODE_PAGE_FLIP_ASYNC : 0; 3869d6c0b56eSmrg drmmode_flipdata_ptr flipdata; 387035d5b7c7Smrg Bool handle_deferred = FALSE; 3871d6c0b56eSmrg uintptr_t drm_queue_seq = 0; 387235d5b7c7Smrg struct drmmode_fb *fb; 387335d5b7c7Smrg int i = 0; 3874d6c0b56eSmrg 387535d5b7c7Smrg flipdata = calloc(1, sizeof(*flipdata) + config->num_crtc * 387635d5b7c7Smrg sizeof(flipdata->fb[0])); 3877d6c0b56eSmrg if (!flipdata) { 3878d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 3879d6c0b56eSmrg "flip queue: data alloc failed.\n"); 3880d6c0b56eSmrg goto error; 3881d6c0b56eSmrg } 3882d6c0b56eSmrg 388335d5b7c7Smrg fb = amdgpu_pixmap_get_fb(new_front); 388435d5b7c7Smrg if (!fb) { 388524b90cf4Smrg ErrorF("Failed to get FB for flip\n"); 3886d6c0b56eSmrg goto error; 388724b90cf4Smrg } 3888d6c0b56eSmrg 3889d6c0b56eSmrg /* 3890d6c0b56eSmrg * Queue flips on all enabled CRTCs 3891d6c0b56eSmrg * Note that if/when we get per-CRTC buffers, we'll have to update this. 3892d6c0b56eSmrg * Right now it assumes a single shared fb across all CRTCs, with the 3893d6c0b56eSmrg * kernel fixing up the offset of each CRTC as necessary. 3894d6c0b56eSmrg * 3895d6c0b56eSmrg * Also, flips queued on disabled or incorrectly configured displays 3896d6c0b56eSmrg * may never complete; this is a configuration error. 3897d6c0b56eSmrg */ 3898d6c0b56eSmrg 3899d6c0b56eSmrg flipdata->event_data = data; 3900d6c0b56eSmrg flipdata->handler = handler; 3901d6c0b56eSmrg flipdata->abort = abort; 390224b90cf4Smrg flipdata->fe_crtc = ref_crtc; 3903d6c0b56eSmrg 3904d6c0b56eSmrg for (i = 0; i < config->num_crtc; i++) { 3905d6c0b56eSmrg crtc = config->crtc[i]; 390624b90cf4Smrg drmmode_crtc = crtc->driver_private; 3907d6c0b56eSmrg 390824b90cf4Smrg if (!drmmode_crtc_can_flip(crtc) || 390924b90cf4Smrg (drmmode_crtc->tear_free && crtc != ref_crtc)) 3910d6c0b56eSmrg continue; 3911d6c0b56eSmrg 3912d6c0b56eSmrg flipdata->flip_count++; 3913d6c0b56eSmrg 3914d6c0b56eSmrg drm_queue_seq = amdgpu_drm_queue_alloc(crtc, client, id, 3915d6c0b56eSmrg flipdata, 3916d6c0b56eSmrg drmmode_flip_handler, 3917d6c0b56eSmrg drmmode_flip_abort); 3918504d986fSmrg if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) { 3919d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 3920d6c0b56eSmrg "Allocating DRM queue event entry failed.\n"); 3921d6c0b56eSmrg goto error; 3922d6c0b56eSmrg } 3923d6c0b56eSmrg 392424b90cf4Smrg if (drmmode_crtc->tear_free) { 392524b90cf4Smrg BoxRec extents = { .x1 = 0, .y1 = 0, 392624b90cf4Smrg .x2 = new_front->drawable.width, 392724b90cf4Smrg .y2 = new_front->drawable.height }; 392824b90cf4Smrg int scanout_id = drmmode_crtc->scanout_id ^ 1; 392924b90cf4Smrg 393024b90cf4Smrg if (flip_sync == FLIP_ASYNC) { 393124b90cf4Smrg if (!drmmode_wait_vblank(crtc, 393224b90cf4Smrg DRM_VBLANK_RELATIVE | 393324b90cf4Smrg DRM_VBLANK_EVENT, 393424b90cf4Smrg 0, drm_queue_seq, 393524b90cf4Smrg NULL, NULL)) 393624b90cf4Smrg goto flip_error; 393724b90cf4Smrg goto next; 393824b90cf4Smrg } 393924b90cf4Smrg 394035d5b7c7Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &flipdata->fb[i], 394135d5b7c7Smrg amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap)); 394235d5b7c7Smrg if (!flipdata->fb[i]) { 394324b90cf4Smrg ErrorF("Failed to get FB for TearFree flip\n"); 394424b90cf4Smrg goto error; 394524b90cf4Smrg } 394624b90cf4Smrg 394724b90cf4Smrg amdgpu_scanout_do_update(crtc, scanout_id, new_front, 394835d5b7c7Smrg extents); 394935d5b7c7Smrg amdgpu_glamor_flush(crtc->scrn); 395035d5b7c7Smrg 395135d5b7c7Smrg if (drmmode_crtc->scanout_update_pending) { 395235d5b7c7Smrg amdgpu_drm_wait_pending_flip(crtc); 395335d5b7c7Smrg handle_deferred = TRUE; 395435d5b7c7Smrg amdgpu_drm_abort_entry(drmmode_crtc->scanout_update_pending); 395535d5b7c7Smrg drmmode_crtc->scanout_update_pending = 0; 395635d5b7c7Smrg } 395735d5b7c7Smrg } else { 395835d5b7c7Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &flipdata->fb[i], fb); 395924b90cf4Smrg } 396024b90cf4Smrg 396124b90cf4Smrg if (crtc == ref_crtc) { 396211bf0794Smrg if (drmmode_page_flip_target_absolute(pAMDGPUEnt, 396311bf0794Smrg drmmode_crtc, 396435d5b7c7Smrg flipdata->fb[i]->handle, 396511bf0794Smrg flip_flags, 396611bf0794Smrg drm_queue_seq, 396711bf0794Smrg target_msc) != 0) 396811bf0794Smrg goto flip_error; 396911bf0794Smrg } else { 397011bf0794Smrg if (drmmode_page_flip_target_relative(pAMDGPUEnt, 397111bf0794Smrg drmmode_crtc, 397235d5b7c7Smrg flipdata->fb[i]->handle, 397311bf0794Smrg flip_flags, 397411bf0794Smrg drm_queue_seq, 0) != 0) 397511bf0794Smrg goto flip_error; 3976d6c0b56eSmrg } 397711bf0794Smrg 397824b90cf4Smrg if (drmmode_crtc->tear_free) { 397924b90cf4Smrg drmmode_crtc->scanout_id ^= 1; 398024b90cf4Smrg drmmode_crtc->ignore_damage = TRUE; 398124b90cf4Smrg } 398224b90cf4Smrg 398324b90cf4Smrg next: 398435d5b7c7Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending, 398535d5b7c7Smrg flipdata->fb[i]); 3986d6c0b56eSmrg drm_queue_seq = 0; 3987d6c0b56eSmrg } 3988d6c0b56eSmrg 398935d5b7c7Smrg if (handle_deferred) 399035d5b7c7Smrg amdgpu_drm_queue_handle_deferred(ref_crtc); 3991d6c0b56eSmrg if (flipdata->flip_count > 0) 3992d6c0b56eSmrg return TRUE; 3993d6c0b56eSmrg 399411bf0794Smrgflip_error: 399511bf0794Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed: %s\n", 399611bf0794Smrg strerror(errno)); 399711bf0794Smrg 3998d6c0b56eSmrgerror: 3999d6c0b56eSmrg if (drm_queue_seq) 4000d6c0b56eSmrg amdgpu_drm_abort_entry(drm_queue_seq); 4001d6c0b56eSmrg else if (crtc) 4002d6c0b56eSmrg drmmode_flip_abort(crtc, flipdata); 400311bf0794Smrg else { 400411bf0794Smrg abort(NULL, data); 4005d6c0b56eSmrg free(flipdata); 400611bf0794Smrg } 4007d6c0b56eSmrg 4008d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n", 4009d6c0b56eSmrg strerror(errno)); 401035d5b7c7Smrg if (handle_deferred) 401135d5b7c7Smrg amdgpu_drm_queue_handle_deferred(ref_crtc); 4012d6c0b56eSmrg return FALSE; 4013d6c0b56eSmrg} 4014