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" 4346845023Smrg#include <xf86drm.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/* DPMS */ 51d6c0b56eSmrg#ifdef HAVE_XEXTPROTO_71 52d6c0b56eSmrg#include <X11/extensions/dpmsconst.h> 53d6c0b56eSmrg#else 54d6c0b56eSmrg#define DPMS_SERVER 55d6c0b56eSmrg#include <X11/extensions/dpms.h> 56d6c0b56eSmrg#endif 57d6c0b56eSmrg 58d6c0b56eSmrg#include <gbm.h> 59d6c0b56eSmrg 60d6c0b56eSmrg#define DEFAULT_NOMINAL_FRAME_RATE 60 61d6c0b56eSmrg 62d6c0b56eSmrgstatic Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height); 63d6c0b56eSmrg 64d6c0b56eSmrgstatic Bool 65d6c0b56eSmrgAMDGPUZaphodStringMatches(ScrnInfoPtr pScrn, const char *s, char *output_name) 66d6c0b56eSmrg{ 67d6c0b56eSmrg int i = 0; 68d6c0b56eSmrg char s1[20]; 69d6c0b56eSmrg 70d6c0b56eSmrg do { 71d6c0b56eSmrg switch (*s) { 72d6c0b56eSmrg case ',': 73d6c0b56eSmrg s1[i] = '\0'; 74d6c0b56eSmrg i = 0; 75d6c0b56eSmrg if (strcmp(s1, output_name) == 0) 76d6c0b56eSmrg return TRUE; 77d6c0b56eSmrg break; 78d6c0b56eSmrg case ' ': 79d6c0b56eSmrg case '\t': 80d6c0b56eSmrg case '\n': 81d6c0b56eSmrg case '\r': 82d6c0b56eSmrg break; 83d6c0b56eSmrg default: 84d6c0b56eSmrg s1[i] = *s; 85d6c0b56eSmrg i++; 86d6c0b56eSmrg break; 87d6c0b56eSmrg } 88d6c0b56eSmrg } while (*s++); 89d6c0b56eSmrg 90d6c0b56eSmrg s1[i] = '\0'; 91d6c0b56eSmrg if (strcmp(s1, output_name) == 0) 92d6c0b56eSmrg return TRUE; 93d6c0b56eSmrg 94d6c0b56eSmrg return FALSE; 95d6c0b56eSmrg} 96d6c0b56eSmrg 9724b90cf4Smrg 98d6c0b56eSmrgstatic void 99d6c0b56eSmrgdrmmode_ConvertFromKMode(ScrnInfoPtr scrn, 100d6c0b56eSmrg drmModeModeInfo * kmode, DisplayModePtr mode) 101d6c0b56eSmrg{ 102d6c0b56eSmrg memset(mode, 0, sizeof(DisplayModeRec)); 103d6c0b56eSmrg mode->status = MODE_OK; 104d6c0b56eSmrg 105d6c0b56eSmrg mode->Clock = kmode->clock; 106d6c0b56eSmrg 107d6c0b56eSmrg mode->HDisplay = kmode->hdisplay; 108d6c0b56eSmrg mode->HSyncStart = kmode->hsync_start; 109d6c0b56eSmrg mode->HSyncEnd = kmode->hsync_end; 110d6c0b56eSmrg mode->HTotal = kmode->htotal; 111d6c0b56eSmrg mode->HSkew = kmode->hskew; 112d6c0b56eSmrg 113d6c0b56eSmrg mode->VDisplay = kmode->vdisplay; 114d6c0b56eSmrg mode->VSyncStart = kmode->vsync_start; 115d6c0b56eSmrg mode->VSyncEnd = kmode->vsync_end; 116d6c0b56eSmrg mode->VTotal = kmode->vtotal; 117d6c0b56eSmrg mode->VScan = kmode->vscan; 118d6c0b56eSmrg 119d6c0b56eSmrg mode->Flags = kmode->flags; //& FLAG_BITS; 120d6c0b56eSmrg mode->name = strdup(kmode->name); 121d6c0b56eSmrg 122d6c0b56eSmrg if (kmode->type & DRM_MODE_TYPE_DRIVER) 123d6c0b56eSmrg mode->type = M_T_DRIVER; 124d6c0b56eSmrg if (kmode->type & DRM_MODE_TYPE_PREFERRED) 125d6c0b56eSmrg mode->type |= M_T_PREFERRED; 126d6c0b56eSmrg xf86SetModeCrtc(mode, scrn->adjustFlags); 127d6c0b56eSmrg} 128d6c0b56eSmrg 129d6c0b56eSmrgstatic void 130d6c0b56eSmrgdrmmode_ConvertToKMode(ScrnInfoPtr scrn, 131d6c0b56eSmrg drmModeModeInfo * kmode, DisplayModePtr mode) 132d6c0b56eSmrg{ 133d6c0b56eSmrg memset(kmode, 0, sizeof(*kmode)); 134d6c0b56eSmrg 135d6c0b56eSmrg kmode->clock = mode->Clock; 136d6c0b56eSmrg kmode->hdisplay = mode->HDisplay; 137d6c0b56eSmrg kmode->hsync_start = mode->HSyncStart; 138d6c0b56eSmrg kmode->hsync_end = mode->HSyncEnd; 139d6c0b56eSmrg kmode->htotal = mode->HTotal; 140d6c0b56eSmrg kmode->hskew = mode->HSkew; 141d6c0b56eSmrg 142d6c0b56eSmrg kmode->vdisplay = mode->VDisplay; 143d6c0b56eSmrg kmode->vsync_start = mode->VSyncStart; 144d6c0b56eSmrg kmode->vsync_end = mode->VSyncEnd; 145d6c0b56eSmrg kmode->vtotal = mode->VTotal; 146d6c0b56eSmrg kmode->vscan = mode->VScan; 147d6c0b56eSmrg 148d6c0b56eSmrg kmode->flags = mode->Flags; //& FLAG_BITS; 149d6c0b56eSmrg if (mode->name) 150d6c0b56eSmrg strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN); 151d6c0b56eSmrg kmode->name[DRM_DISPLAY_MODE_LEN - 1] = 0; 152d6c0b56eSmrg 153d6c0b56eSmrg} 154d6c0b56eSmrg 15524b90cf4Smrg/* 15624b90cf4Smrg * Utility helper for drmWaitVBlank 15724b90cf4Smrg */ 15824b90cf4SmrgBool 15924b90cf4Smrgdrmmode_wait_vblank(xf86CrtcPtr crtc, drmVBlankSeqType type, 16024b90cf4Smrg uint32_t target_seq, unsigned long signal, uint64_t *ust, 16124b90cf4Smrg uint32_t *result_seq) 16224b90cf4Smrg{ 16324b90cf4Smrg int crtc_id = drmmode_get_crtc_id(crtc); 16424b90cf4Smrg ScrnInfoPtr scrn = crtc->scrn; 16524b90cf4Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 16624b90cf4Smrg drmVBlank vbl; 16724b90cf4Smrg 16824b90cf4Smrg if (crtc_id == 1) 16924b90cf4Smrg type |= DRM_VBLANK_SECONDARY; 17024b90cf4Smrg else if (crtc_id > 1) 17124b90cf4Smrg type |= (crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT) & 17224b90cf4Smrg DRM_VBLANK_HIGH_CRTC_MASK; 17324b90cf4Smrg 17424b90cf4Smrg vbl.request.type = type; 17524b90cf4Smrg vbl.request.sequence = target_seq; 17624b90cf4Smrg vbl.request.signal = signal; 17724b90cf4Smrg 17824b90cf4Smrg if (drmWaitVBlank(pAMDGPUEnt->fd, &vbl) != 0) 17924b90cf4Smrg return FALSE; 18024b90cf4Smrg 18124b90cf4Smrg if (ust) 18224b90cf4Smrg *ust = (uint64_t)vbl.reply.tval_sec * 1000000 + 18324b90cf4Smrg vbl.reply.tval_usec; 18424b90cf4Smrg if (result_seq) 18524b90cf4Smrg *result_seq = vbl.reply.sequence; 18624b90cf4Smrg 18724b90cf4Smrg return TRUE; 18824b90cf4Smrg} 18924b90cf4Smrg 190d6c0b56eSmrg/* 191d6c0b56eSmrg * Retrieves present time in microseconds that is compatible 192d6c0b56eSmrg * with units used by vblank timestamps. Depending on the kernel 193d6c0b56eSmrg * version and DRM kernel module configuration, the vblank 194d6c0b56eSmrg * timestamp can either be in real time or monotonic time 195d6c0b56eSmrg */ 196d6c0b56eSmrgint drmmode_get_current_ust(int drm_fd, CARD64 * ust) 197d6c0b56eSmrg{ 198d6c0b56eSmrg uint64_t cap_value; 199d6c0b56eSmrg int ret; 200d6c0b56eSmrg struct timespec now; 201d6c0b56eSmrg 202d6c0b56eSmrg ret = drmGetCap(drm_fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap_value); 203d6c0b56eSmrg if (ret || !cap_value) 204d6c0b56eSmrg /* old kernel or drm_timestamp_monotonic turned off */ 205d6c0b56eSmrg ret = clock_gettime(CLOCK_REALTIME, &now); 206d6c0b56eSmrg else 207d6c0b56eSmrg ret = clock_gettime(CLOCK_MONOTONIC, &now); 208d6c0b56eSmrg if (ret) 209d6c0b56eSmrg return ret; 210d6c0b56eSmrg *ust = ((CARD64) now.tv_sec * 1000000) + ((CARD64) now.tv_nsec / 1000); 211d6c0b56eSmrg return 0; 212d6c0b56eSmrg} 213d6c0b56eSmrg 214d6c0b56eSmrg/* 215d6c0b56eSmrg * Get current frame count and frame count timestamp of the crtc. 216d6c0b56eSmrg */ 217d6c0b56eSmrgint drmmode_crtc_get_ust_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc) 218d6c0b56eSmrg{ 219d6c0b56eSmrg ScrnInfoPtr scrn = crtc->scrn; 22024b90cf4Smrg uint32_t seq; 221d6c0b56eSmrg 22224b90cf4Smrg if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, ust, &seq)) { 223d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 224d6c0b56eSmrg "get vblank counter failed: %s\n", strerror(errno)); 22524b90cf4Smrg return -1; 226d6c0b56eSmrg } 227d6c0b56eSmrg 22824b90cf4Smrg *msc = seq; 229d6c0b56eSmrg 230d6c0b56eSmrg return Success; 231d6c0b56eSmrg} 232d6c0b56eSmrg 23390f2b693Smrgstatic uint32_t 23490f2b693Smrgdrmmode_crtc_get_prop_id(uint32_t drm_fd, 23590f2b693Smrg drmModeObjectPropertiesPtr props, 23690f2b693Smrg char const* name) 23790f2b693Smrg{ 23890f2b693Smrg uint32_t i, prop_id = 0; 23990f2b693Smrg 24090f2b693Smrg for (i = 0; !prop_id && i < props->count_props; ++i) { 24190f2b693Smrg drmModePropertyPtr drm_prop = 24290f2b693Smrg drmModeGetProperty(drm_fd, props->props[i]); 24390f2b693Smrg 24490f2b693Smrg if (!drm_prop) 24590f2b693Smrg continue; 24690f2b693Smrg 24790f2b693Smrg if (strcmp(drm_prop->name, name) == 0) 24890f2b693Smrg prop_id = drm_prop->prop_id; 24990f2b693Smrg 25090f2b693Smrg drmModeFreeProperty(drm_prop); 25190f2b693Smrg } 25290f2b693Smrg 25390f2b693Smrg return prop_id; 25490f2b693Smrg} 25590f2b693Smrg 25690f2b693Smrgstatic void drmmode_crtc_vrr_init(int drm_fd, xf86CrtcPtr crtc) 25790f2b693Smrg{ 25890f2b693Smrg drmModeObjectPropertiesPtr drm_props; 25990f2b693Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 26090f2b693Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 26190f2b693Smrg 26290f2b693Smrg if (drmmode->vrr_prop_id) 26390f2b693Smrg return; 26490f2b693Smrg 26590f2b693Smrg drm_props = drmModeObjectGetProperties(drm_fd, 26690f2b693Smrg drmmode_crtc->mode_crtc->crtc_id, 26790f2b693Smrg DRM_MODE_OBJECT_CRTC); 26890f2b693Smrg 26990f2b693Smrg if (!drm_props) 27090f2b693Smrg return; 27190f2b693Smrg 27290f2b693Smrg drmmode->vrr_prop_id = drmmode_crtc_get_prop_id(drm_fd, 27390f2b693Smrg drm_props, 27490f2b693Smrg "VRR_ENABLED"); 27590f2b693Smrg 27690f2b693Smrg drmModeFreeObjectProperties(drm_props); 27790f2b693Smrg} 27890f2b693Smrg 27990f2b693Smrgvoid drmmode_crtc_set_vrr(xf86CrtcPtr crtc, Bool enabled) 28090f2b693Smrg{ 28190f2b693Smrg ScrnInfoPtr pScrn = crtc->scrn; 28290f2b693Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 28390f2b693Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 28490f2b693Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 28590f2b693Smrg 28690f2b693Smrg if (drmmode->vrr_prop_id && 28790f2b693Smrg drmmode_crtc->vrr_enabled != enabled && 28890f2b693Smrg drmModeObjectSetProperty(pAMDGPUEnt->fd, 28990f2b693Smrg drmmode_crtc->mode_crtc->crtc_id, 29090f2b693Smrg DRM_MODE_OBJECT_CRTC, 29190f2b693Smrg drmmode->vrr_prop_id, 29290f2b693Smrg enabled) == 0) 29390f2b693Smrg drmmode_crtc->vrr_enabled = enabled; 29490f2b693Smrg} 29590f2b693Smrg 296d6c0b56eSmrgstatic void 297d6c0b56eSmrgdrmmode_do_crtc_dpms(xf86CrtcPtr crtc, int mode) 298d6c0b56eSmrg{ 299d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 300d6c0b56eSmrg ScrnInfoPtr scrn = crtc->scrn; 301d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 302d6c0b56eSmrg CARD64 ust; 303d6c0b56eSmrg int ret; 304d6c0b56eSmrg 305d6c0b56eSmrg if (drmmode_crtc->dpms_mode == DPMSModeOn && mode != DPMSModeOn) { 30624b90cf4Smrg uint32_t seq; 307d6c0b56eSmrg 30835d5b7c7Smrg amdgpu_drm_wait_pending_flip(crtc); 309504d986fSmrg 310d6c0b56eSmrg /* 311d6c0b56eSmrg * On->Off transition: record the last vblank time, 312d6c0b56eSmrg * sequence number and frame period. 313d6c0b56eSmrg */ 31424b90cf4Smrg if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, &ust, 31524b90cf4Smrg &seq)) 316d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 317d6c0b56eSmrg "%s cannot get last vblank counter\n", 318d6c0b56eSmrg __func__); 319d6c0b56eSmrg else { 320d6c0b56eSmrg CARD64 nominal_frame_rate, pix_in_frame; 321d6c0b56eSmrg 322d6c0b56eSmrg drmmode_crtc->dpms_last_ust = ust; 323d6c0b56eSmrg drmmode_crtc->dpms_last_seq = seq; 324d6c0b56eSmrg nominal_frame_rate = crtc->mode.Clock; 325d6c0b56eSmrg nominal_frame_rate *= 1000; 326d6c0b56eSmrg pix_in_frame = crtc->mode.HTotal * crtc->mode.VTotal; 327d6c0b56eSmrg if (nominal_frame_rate == 0 || pix_in_frame == 0) 328d6c0b56eSmrg nominal_frame_rate = DEFAULT_NOMINAL_FRAME_RATE; 329d6c0b56eSmrg else 330d6c0b56eSmrg nominal_frame_rate /= pix_in_frame; 331d6c0b56eSmrg drmmode_crtc->dpms_last_fps = nominal_frame_rate; 332d6c0b56eSmrg } 33335d5b7c7Smrg 33435d5b7c7Smrg drmmode_crtc->dpms_mode = mode; 33535d5b7c7Smrg amdgpu_drm_queue_handle_deferred(crtc); 336d6c0b56eSmrg } else if (drmmode_crtc->dpms_mode != DPMSModeOn && mode == DPMSModeOn) { 337d6c0b56eSmrg /* 338d6c0b56eSmrg * Off->On transition: calculate and accumulate the 339d6c0b56eSmrg * number of interpolated vblanks while we were in Off state 340d6c0b56eSmrg */ 341d6c0b56eSmrg ret = drmmode_get_current_ust(pAMDGPUEnt->fd, &ust); 342d6c0b56eSmrg if (ret) 343d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 344d6c0b56eSmrg "%s cannot get current time\n", __func__); 345d6c0b56eSmrg else if (drmmode_crtc->dpms_last_ust) { 346d6c0b56eSmrg CARD64 time_elapsed, delta_seq; 347d6c0b56eSmrg time_elapsed = ust - drmmode_crtc->dpms_last_ust; 348d6c0b56eSmrg delta_seq = time_elapsed * drmmode_crtc->dpms_last_fps; 349d6c0b56eSmrg delta_seq /= 1000000; 350d6c0b56eSmrg drmmode_crtc->interpolated_vblanks += delta_seq; 351d6c0b56eSmrg 352d6c0b56eSmrg } 35335d5b7c7Smrg 35435d5b7c7Smrg drmmode_crtc->dpms_mode = DPMSModeOn; 355d6c0b56eSmrg } 356d6c0b56eSmrg} 357d6c0b56eSmrg 358d6c0b56eSmrgstatic void 359d6c0b56eSmrgdrmmode_crtc_dpms(xf86CrtcPtr crtc, int mode) 360d6c0b56eSmrg{ 361d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 362d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 363d6c0b56eSmrg 364d6c0b56eSmrg /* Disable unused CRTCs and enable/disable active CRTCs */ 365504d986fSmrg if (!crtc->enabled || mode != DPMSModeOn) { 36635d5b7c7Smrg drmmode_do_crtc_dpms(crtc, DPMSModeOff); 367d6c0b56eSmrg drmModeSetCrtc(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 368d6c0b56eSmrg 0, 0, 0, NULL, 0, NULL); 36924b90cf4Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, NULL); 370504d986fSmrg } else if (drmmode_crtc->dpms_mode != DPMSModeOn) 371d6c0b56eSmrg crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation, 372d6c0b56eSmrg crtc->x, crtc->y); 373d6c0b56eSmrg} 374d6c0b56eSmrg 37590f2b693Smrg#ifdef USE_GLAMOR 37690f2b693Smrg 377d6c0b56eSmrgstatic PixmapPtr 378d6c0b56eSmrgcreate_pixmap_for_fbcon(drmmode_ptr drmmode, 379d6c0b56eSmrg ScrnInfoPtr pScrn, int fbcon_id) 380d6c0b56eSmrg{ 38135d5b7c7Smrg ScreenPtr pScreen = pScrn->pScreen; 382d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 38335d5b7c7Smrg PixmapPtr pixmap = NULL; 384d6c0b56eSmrg drmModeFBPtr fbcon; 385d6c0b56eSmrg 386d6c0b56eSmrg fbcon = drmModeGetFB(pAMDGPUEnt->fd, fbcon_id); 38735d5b7c7Smrg if (!fbcon) 388d6c0b56eSmrg return NULL; 389d6c0b56eSmrg 390d6c0b56eSmrg if (fbcon->depth != pScrn->depth || 391d6c0b56eSmrg fbcon->width != pScrn->virtualX || 392d6c0b56eSmrg fbcon->height != pScrn->virtualY) 393d6c0b56eSmrg goto out_free_fb; 394d6c0b56eSmrg 39535d5b7c7Smrg pixmap = fbCreatePixmap(pScreen, 0, 0, fbcon->depth, 0); 39635d5b7c7Smrg if (!pixmap) 397d6c0b56eSmrg goto out_free_fb; 398d6c0b56eSmrg 39935d5b7c7Smrg pScreen->ModifyPixmapHeader(pixmap, fbcon->width, fbcon->height, 0, 0, 40035d5b7c7Smrg fbcon->pitch, NULL); 40135d5b7c7Smrg pixmap->devPrivate.ptr = NULL; 402d6c0b56eSmrg 40335d5b7c7Smrg if (!glamor_egl_create_textured_pixmap(pixmap, fbcon->handle, 40435d5b7c7Smrg pixmap->devKind)) { 40535d5b7c7Smrg pScreen->DestroyPixmap(pixmap); 40635d5b7c7Smrg pixmap = NULL; 407d6c0b56eSmrg } 408d6c0b56eSmrg 409d6c0b56eSmrgout_free_fb: 410d6c0b56eSmrg drmModeFreeFB(fbcon); 411d6c0b56eSmrg return pixmap; 412d6c0b56eSmrg} 413d6c0b56eSmrg 41490f2b693Smrg#endif /* USE_GLAMOR */ 41590f2b693Smrg 416d6c0b56eSmrgvoid drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 417d6c0b56eSmrg{ 41890f2b693Smrg#ifdef USE_GLAMOR 419d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 42090f2b693Smrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 421d6c0b56eSmrg ScreenPtr pScreen = pScrn->pScreen; 42224b90cf4Smrg PixmapPtr src, dst = pScreen->GetScreenPixmap(pScreen); 42324b90cf4Smrg struct drmmode_fb *fb = amdgpu_pixmap_get_fb(dst); 424d6c0b56eSmrg int fbcon_id = 0; 425d6c0b56eSmrg GCPtr gc; 426d6c0b56eSmrg int i; 427d6c0b56eSmrg 42890f2b693Smrg if (!info->use_glamor) 42990f2b693Smrg return; 43090f2b693Smrg 431d6c0b56eSmrg for (i = 0; i < xf86_config->num_crtc; i++) { 432d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[i]->driver_private; 433d6c0b56eSmrg 434d6c0b56eSmrg if (drmmode_crtc->mode_crtc->buffer_id) 435d6c0b56eSmrg fbcon_id = drmmode_crtc->mode_crtc->buffer_id; 436d6c0b56eSmrg } 437d6c0b56eSmrg 438d6c0b56eSmrg if (!fbcon_id) 439d6c0b56eSmrg return; 440d6c0b56eSmrg 44124b90cf4Smrg if (fbcon_id == fb->handle) { 442d6c0b56eSmrg /* in some rare case there might be no fbcon and we might already 443d6c0b56eSmrg * be the one with the current fb to avoid a false deadlck in 444d6c0b56eSmrg * kernel ttm code just do nothing as anyway there is nothing 445d6c0b56eSmrg * to do 446d6c0b56eSmrg */ 447d6c0b56eSmrg return; 448d6c0b56eSmrg } 449d6c0b56eSmrg 450d6c0b56eSmrg src = create_pixmap_for_fbcon(drmmode, pScrn, fbcon_id); 451d6c0b56eSmrg if (!src) 452d6c0b56eSmrg return; 453d6c0b56eSmrg 454d6c0b56eSmrg gc = GetScratchGC(pScrn->depth, pScreen); 455d6c0b56eSmrg ValidateGC(&dst->drawable, gc); 456d6c0b56eSmrg 457d6c0b56eSmrg (*gc->ops->CopyArea)(&src->drawable, &dst->drawable, gc, 0, 0, 458d6c0b56eSmrg pScrn->virtualX, pScrn->virtualY, 0, 0); 459d6c0b56eSmrg 460d6c0b56eSmrg FreeScratchGC(gc); 461d6c0b56eSmrg 462d6c0b56eSmrg pScreen->canDoBGNoneRoot = TRUE; 46335d5b7c7Smrg pScreen->DestroyPixmap(src); 46490f2b693Smrg#endif 465d6c0b56eSmrg 466d6c0b56eSmrg return; 467d6c0b56eSmrg} 468d6c0b56eSmrg 46924b90cf4Smrgvoid 47090f2b693Smrgdrmmode_crtc_scanout_free(xf86CrtcPtr crtc) 471504d986fSmrg{ 47290f2b693Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 47390f2b693Smrg 47490f2b693Smrg if (drmmode_crtc->scanout_update_pending) { 47590f2b693Smrg amdgpu_drm_wait_pending_flip(crtc); 47690f2b693Smrg amdgpu_drm_abort_entry(drmmode_crtc->scanout_update_pending); 47790f2b693Smrg drmmode_crtc->scanout_update_pending = 0; 47890f2b693Smrg amdgpu_drm_queue_handle_deferred(crtc); 47990f2b693Smrg } 48090f2b693Smrg 48146845023Smrg drmmode_crtc_scanout_destroy(&drmmode_crtc->scanout[0]); 48246845023Smrg drmmode_crtc_scanout_destroy(&drmmode_crtc->scanout[1]); 483d6c0b56eSmrg 48424b90cf4Smrg if (drmmode_crtc->scanout_damage) 485504d986fSmrg DamageDestroy(drmmode_crtc->scanout_damage); 486d6c0b56eSmrg} 487d6c0b56eSmrg 48846845023Smrgstatic Bool 48946845023Smrgdrmmode_crtc_scanout_create(xf86CrtcPtr crtc, PixmapPtr *scanout, 49011bf0794Smrg int width, int height) 491d6c0b56eSmrg{ 492d6c0b56eSmrg ScrnInfoPtr pScrn = crtc->scrn; 49346845023Smrg ScreenPtr screen = pScrn->pScreen; 494d6c0b56eSmrg 49546845023Smrg if (*scanout) { 49646845023Smrg if ((*scanout)->drawable.width == width && 49746845023Smrg (*scanout)->drawable.height == height) 49846845023Smrg return TRUE; 499d6c0b56eSmrg 50046845023Smrg drmmode_crtc_scanout_destroy(scanout); 501d6c0b56eSmrg } 502d6c0b56eSmrg 50346845023Smrg *scanout = screen->CreatePixmap(screen, width, height, pScrn->depth, 50446845023Smrg AMDGPU_CREATE_PIXMAP_SCANOUT); 50546845023Smrg if (!*scanout) { 50624b90cf4Smrg ErrorF("failed to create CRTC scanout pixmap\n"); 50724b90cf4Smrg goto error; 50824b90cf4Smrg } 50924b90cf4Smrg 51046845023Smrg if (!amdgpu_pixmap_get_fb(*scanout)) { 51124b90cf4Smrg ErrorF("failed to create CRTC scanout FB\n"); 51224b90cf4Smrgerror: 51346845023Smrg drmmode_crtc_scanout_destroy(scanout); 51446845023Smrg return FALSE; 515d6c0b56eSmrg } 516d6c0b56eSmrg 51746845023Smrg return TRUE; 518d6c0b56eSmrg} 519d6c0b56eSmrg 520d6c0b56eSmrgstatic void 521d6c0b56eSmrgamdgpu_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure) 522d6c0b56eSmrg{ 52324b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = closure; 52424b90cf4Smrg 52524b90cf4Smrg if (drmmode_crtc->ignore_damage) { 52624b90cf4Smrg RegionEmpty(&damage->damage); 52724b90cf4Smrg drmmode_crtc->ignore_damage = FALSE; 52824b90cf4Smrg return; 52924b90cf4Smrg } 53024b90cf4Smrg 531d6c0b56eSmrg /* Only keep track of the extents */ 532d6c0b56eSmrg RegionUninit(&damage->damage); 533d6c0b56eSmrg damage->damage.data = NULL; 534d6c0b56eSmrg} 535d6c0b56eSmrg 53624b90cf4Smrgstatic void 53724b90cf4Smrgdrmmode_screen_damage_destroy(DamagePtr damage, void *closure) 53824b90cf4Smrg{ 53924b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = closure; 54024b90cf4Smrg 54124b90cf4Smrg drmmode_crtc->scanout_damage = NULL; 54224b90cf4Smrg RegionUninit(&drmmode_crtc->scanout_last_region); 54324b90cf4Smrg} 54424b90cf4Smrg 545d6c0b56eSmrgstatic Bool 546d6c0b56eSmrgdrmmode_can_use_hw_cursor(xf86CrtcPtr crtc) 547d6c0b56eSmrg{ 548d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn); 549d6c0b56eSmrg 550d6c0b56eSmrg /* Check for Option "SWcursor" */ 551d6c0b56eSmrg if (xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) 552d6c0b56eSmrg return FALSE; 553d6c0b56eSmrg 554d6c0b56eSmrg /* Fall back to SW cursor if the CRTC is transformed */ 555d6c0b56eSmrg if (crtc->transformPresent) 556d6c0b56eSmrg return FALSE; 557d6c0b56eSmrg 55824b90cf4Smrg#if XF86_CRTC_VERSION < 7 559d6c0b56eSmrg /* Xorg doesn't correctly handle cursor position transform in the 560d6c0b56eSmrg * rotation case 561d6c0b56eSmrg */ 562d6c0b56eSmrg if (crtc->driverIsPerformingTransform && 563d6c0b56eSmrg (crtc->rotation & 0xf) != RR_Rotate_0) 564d6c0b56eSmrg return FALSE; 565d6c0b56eSmrg#endif 566d6c0b56eSmrg 567504d986fSmrg /* HW cursor not supported with RandR 1.4 multihead up to 1.18.99.901 */ 568504d986fSmrg if (xorgGetVersion() <= XORG_VERSION_NUMERIC(1,18,99,901,0) && 569504d986fSmrg !xorg_list_is_empty(&crtc->scrn->pScreen->pixmap_dirty_list)) 570d6c0b56eSmrg return FALSE; 571d6c0b56eSmrg 572d6c0b56eSmrg return TRUE; 573d6c0b56eSmrg} 574d6c0b56eSmrg 57511bf0794Smrgstatic void 57611bf0794Smrgdrmmode_crtc_update_tear_free(xf86CrtcPtr crtc) 57711bf0794Smrg{ 57811bf0794Smrg AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn); 57911bf0794Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 58011bf0794Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 58111bf0794Smrg int i; 58211bf0794Smrg 58311bf0794Smrg drmmode_crtc->tear_free = FALSE; 58411bf0794Smrg 58511bf0794Smrg for (i = 0; i < xf86_config->num_output; i++) { 58611bf0794Smrg xf86OutputPtr output = xf86_config->output[i]; 58711bf0794Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 58811bf0794Smrg 58911bf0794Smrg if (output->crtc != crtc) 59011bf0794Smrg continue; 59111bf0794Smrg 59211bf0794Smrg if (drmmode_output->tear_free == 1 || 59311bf0794Smrg (drmmode_output->tear_free == 2 && 59424b90cf4Smrg (crtc->scrn->pScreen->isGPU || 59511bf0794Smrg info->shadow_primary || 59611bf0794Smrg crtc->transformPresent || crtc->rotation != RR_Rotate_0))) { 59711bf0794Smrg drmmode_crtc->tear_free = TRUE; 59811bf0794Smrg return; 59911bf0794Smrg } 60011bf0794Smrg } 60111bf0794Smrg} 60211bf0794Smrg 60311bf0794Smrg#if XF86_CRTC_VERSION < 7 60411bf0794Smrg#define XF86DriverTransformOutput TRUE 60511bf0794Smrg#define XF86DriverTransformNone FALSE 60611bf0794Smrg#endif 60711bf0794Smrg 608d6c0b56eSmrgstatic Bool 609d6c0b56eSmrgdrmmode_handle_transform(xf86CrtcPtr crtc) 610d6c0b56eSmrg{ 611d6c0b56eSmrg Bool ret; 612d6c0b56eSmrg 61324b90cf4Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 61435d5b7c7Smrg crtc->driverIsPerformingTransform = XF86DriverTransformOutput; 61524b90cf4Smrg#else 61624b90cf4Smrg crtc->driverIsPerformingTransform = !crtc->transformPresent && 61724b90cf4Smrg (crtc->rotation & 0xf) == RR_Rotate_0; 61824b90cf4Smrg#endif 619d6c0b56eSmrg 620d6c0b56eSmrg ret = xf86CrtcRotate(crtc); 621d6c0b56eSmrg 622d6c0b56eSmrg crtc->driverIsPerformingTransform &= ret && crtc->transform_in_use; 623d6c0b56eSmrg 624d6c0b56eSmrg return ret; 625d6c0b56eSmrg} 626d6c0b56eSmrg 62711bf0794Smrg 62811bf0794Smrgstatic void 62911bf0794Smrgdrmmode_crtc_prime_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode, 63024b90cf4Smrg unsigned scanout_id, struct drmmode_fb **fb, 63124b90cf4Smrg int *x, int *y) 63211bf0794Smrg{ 63311bf0794Smrg ScrnInfoPtr scrn = crtc->scrn; 63411bf0794Smrg ScreenPtr screen = scrn->pScreen; 63511bf0794Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 63611bf0794Smrg 63746845023Smrg if (drmmode_crtc->tear_free && !drmmode_crtc->scanout[1]) { 63811bf0794Smrg RegionPtr region; 63911bf0794Smrg BoxPtr box; 64011bf0794Smrg 64111bf0794Smrg drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], 64211bf0794Smrg mode->HDisplay, 64311bf0794Smrg mode->VDisplay); 64411bf0794Smrg region = &drmmode_crtc->scanout_last_region; 64511bf0794Smrg RegionUninit(region); 64611bf0794Smrg region->data = NULL; 64711bf0794Smrg box = RegionExtents(region); 64811bf0794Smrg box->x1 = crtc->x; 64911bf0794Smrg box->y1 = crtc->y; 65011bf0794Smrg box->x2 = crtc->x + mode->HDisplay; 65111bf0794Smrg box->y2 = crtc->y + mode->VDisplay; 65211bf0794Smrg } 65311bf0794Smrg 65411bf0794Smrg if (scanout_id != drmmode_crtc->scanout_id) { 65511bf0794Smrg PixmapDirtyUpdatePtr dirty = NULL; 65611bf0794Smrg 65711bf0794Smrg xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, 65811bf0794Smrg ent) { 65924b90cf4Smrg if (amdgpu_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) { 66046845023Smrg dirty->secondary_dst = 66146845023Smrg drmmode_crtc->scanout[scanout_id]; 66211bf0794Smrg break; 66311bf0794Smrg } 66411bf0794Smrg } 66511bf0794Smrg 66611bf0794Smrg if (!drmmode_crtc->tear_free) { 66711bf0794Smrg GCPtr gc = GetScratchGC(scrn->depth, screen); 66811bf0794Smrg 66946845023Smrg ValidateGC(&drmmode_crtc->scanout[0]->drawable, gc); 67046845023Smrg gc->ops->CopyArea(&drmmode_crtc->scanout[1]->drawable, 67146845023Smrg &drmmode_crtc->scanout[0]->drawable, 67211bf0794Smrg gc, 0, 0, mode->HDisplay, mode->VDisplay, 67311bf0794Smrg 0, 0); 67411bf0794Smrg FreeScratchGC(gc); 67511bf0794Smrg amdgpu_glamor_finish(scrn); 67611bf0794Smrg } 67711bf0794Smrg } 67811bf0794Smrg 67946845023Smrg *fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id]); 68011bf0794Smrg *x = *y = 0; 68111bf0794Smrg drmmode_crtc->scanout_id = scanout_id; 68211bf0794Smrg} 68311bf0794Smrg 68411bf0794Smrg 68511bf0794Smrgstatic void 68611bf0794Smrgdrmmode_crtc_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode, 68724b90cf4Smrg unsigned scanout_id, struct drmmode_fb **fb, int *x, 68824b90cf4Smrg int *y) 68911bf0794Smrg{ 69011bf0794Smrg ScrnInfoPtr scrn = crtc->scrn; 69111bf0794Smrg ScreenPtr screen = scrn->pScreen; 69211bf0794Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 69311bf0794Smrg 69424b90cf4Smrg drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[scanout_id], 69511bf0794Smrg mode->HDisplay, mode->VDisplay); 69611bf0794Smrg if (drmmode_crtc->tear_free) { 69724b90cf4Smrg drmmode_crtc_scanout_create(crtc, 69824b90cf4Smrg &drmmode_crtc->scanout[scanout_id ^ 1], 69911bf0794Smrg mode->HDisplay, mode->VDisplay); 70011bf0794Smrg } 70111bf0794Smrg 70246845023Smrg if (drmmode_crtc->scanout[scanout_id] && 70324b90cf4Smrg (!drmmode_crtc->tear_free || 70446845023Smrg drmmode_crtc->scanout[scanout_id ^ 1])) { 70535d5b7c7Smrg BoxRec extents = { .x1 = 0, .y1 = 0, 70635d5b7c7Smrg .x2 = scrn->virtualX, .y2 = scrn->virtualY }; 70711bf0794Smrg 70811bf0794Smrg if (!drmmode_crtc->scanout_damage) { 70911bf0794Smrg drmmode_crtc->scanout_damage = 71011bf0794Smrg DamageCreate(amdgpu_screen_damage_report, 71124b90cf4Smrg drmmode_screen_damage_destroy, 71224b90cf4Smrg DamageReportRawRegion, 71324b90cf4Smrg TRUE, screen, drmmode_crtc); 71424b90cf4Smrg DamageRegister(&screen->root->drawable, 71511bf0794Smrg drmmode_crtc->scanout_damage); 71611bf0794Smrg } 71711bf0794Smrg 71846845023Smrg *fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id]); 71911bf0794Smrg *x = *y = 0; 72011bf0794Smrg 72190f2b693Smrg if (amdgpu_scanout_do_update(crtc, scanout_id, 72290f2b693Smrg screen->GetWindowPixmap(screen->root), 72390f2b693Smrg extents)) { 72490f2b693Smrg RegionEmpty(DamageRegion(drmmode_crtc->scanout_damage)); 72590f2b693Smrg amdgpu_glamor_finish(scrn); 72690f2b693Smrg 72790f2b693Smrg if (!drmmode_crtc->flip_pending) { 72890f2b693Smrg amdgpu_drm_abort_entry(drmmode_crtc-> 72990f2b693Smrg scanout_update_pending); 73090f2b693Smrg } 73190f2b693Smrg } 73211bf0794Smrg } 73311bf0794Smrg} 73411bf0794Smrg 73535d5b7c7Smrgstatic char *cm_prop_names[] = { 73635d5b7c7Smrg "DEGAMMA_LUT", 73735d5b7c7Smrg "CTM", 73835d5b7c7Smrg "GAMMA_LUT", 73935d5b7c7Smrg "DEGAMMA_LUT_SIZE", 74035d5b7c7Smrg "GAMMA_LUT_SIZE", 74135d5b7c7Smrg}; 74235d5b7c7Smrg 74335d5b7c7Smrg/** 74435d5b7c7Smrg * Return the enum of the color management property with the given name. 74535d5b7c7Smrg */ 74635d5b7c7Smrgstatic enum drmmode_cm_prop get_cm_enum_from_str(const char *prop_name) 74735d5b7c7Smrg{ 74835d5b7c7Smrg enum drmmode_cm_prop ret; 74935d5b7c7Smrg 75035d5b7c7Smrg for (ret = 0; ret < CM_NUM_PROPS; ret++) { 75135d5b7c7Smrg if (!strcmp(prop_name, cm_prop_names[ret])) 75235d5b7c7Smrg return ret; 75335d5b7c7Smrg } 75435d5b7c7Smrg return CM_INVALID_PROP; 75535d5b7c7Smrg} 75635d5b7c7Smrg 75735d5b7c7Smrg/** 75835d5b7c7Smrg * If legacy LUT is a, and non-legacy LUT is b, then the result of b(a(x)) is 75935d5b7c7Smrg * returned in out_lut. out_lut's length is expected to be the same as the 76035d5b7c7Smrg * non-legacy LUT b. 76135d5b7c7Smrg * 76235d5b7c7Smrg * @a_(red|green|blue): The red, green, and blue components of the legacy LUT. 76335d5b7c7Smrg * @b_lut: The non-legacy LUT, in DRM's color LUT format. 76435d5b7c7Smrg * @out_lut: The composed LUT, in DRM's color LUT format. 76535d5b7c7Smrg * @len_a: Length of legacy lut. 76635d5b7c7Smrg * @len_b: Length of non-legacy lut. 76735d5b7c7Smrg */ 76835d5b7c7Smrgstatic void drmmode_lut_compose(uint16_t *a_red, 76935d5b7c7Smrg uint16_t *a_green, 77035d5b7c7Smrg uint16_t *a_blue, 77135d5b7c7Smrg struct drm_color_lut *b_lut, 77235d5b7c7Smrg struct drm_color_lut *out_lut, 77335d5b7c7Smrg uint32_t len_a, uint32_t len_b) 77435d5b7c7Smrg{ 77535d5b7c7Smrg uint32_t i_l, i_r, i; 77635d5b7c7Smrg uint32_t i_amax, i_bmax; 77735d5b7c7Smrg uint32_t coeff_ibmax; 77835d5b7c7Smrg uint32_t j; 77935d5b7c7Smrg uint64_t a_out_ibmax; 78035d5b7c7Smrg int color; 78135d5b7c7Smrg size_t struct_size = sizeof(struct drm_color_lut); 78235d5b7c7Smrg 78335d5b7c7Smrg uint32_t max_lut = (1 << 16) - 1; 78435d5b7c7Smrg 78535d5b7c7Smrg i_amax = len_a - 1; 78635d5b7c7Smrg i_bmax = len_b - 1; 78735d5b7c7Smrg 78835d5b7c7Smrg /* A linear interpolation is done on the legacy LUT before it is 78935d5b7c7Smrg * composed, to bring it up-to-size with the non-legacy LUT. The 79035d5b7c7Smrg * interpolation uses integers by keeping things multiplied until the 79135d5b7c7Smrg * last moment. 79235d5b7c7Smrg */ 79335d5b7c7Smrg for (color = 0; color < 3; color++) { 79435d5b7c7Smrg uint16_t *a, *b, *out; 79535d5b7c7Smrg 79635d5b7c7Smrg /* Set the initial pointers to the right color components. The 79735d5b7c7Smrg * inner for-loop will then maintain the correct offset from 79835d5b7c7Smrg * the initial element. 79935d5b7c7Smrg */ 80035d5b7c7Smrg if (color == 0) { 80135d5b7c7Smrg a = a_red; 80235d5b7c7Smrg b = &b_lut[0].red; 80335d5b7c7Smrg out = &out_lut[0].red; 80435d5b7c7Smrg } else if (color == 1) { 80535d5b7c7Smrg a = a_green; 80635d5b7c7Smrg b = &b_lut[0].green; 80735d5b7c7Smrg out = &out_lut[0].green; 80835d5b7c7Smrg } else { 80935d5b7c7Smrg a = a_blue; 81035d5b7c7Smrg b = &b_lut[0].blue; 81135d5b7c7Smrg out = &out_lut[0].blue; 81235d5b7c7Smrg } 81335d5b7c7Smrg 81435d5b7c7Smrg for (i = 0; i < len_b; i++) { 81535d5b7c7Smrg /* i_l and i_r tracks the left and right elements in 81635d5b7c7Smrg * a_lut, to the sample point i. Also handle last 81735d5b7c7Smrg * element edge case, when i_l = i_amax. 81835d5b7c7Smrg */ 81935d5b7c7Smrg i_l = i * i_amax / i_bmax; 82035d5b7c7Smrg i_r = i_l + !!(i_amax - i_l); 82135d5b7c7Smrg 82235d5b7c7Smrg /* coeff is intended to be in [0, 1), depending on 82335d5b7c7Smrg * where sample i is between i_l and i_r. We keep it 82435d5b7c7Smrg * multiplied with i_bmax throughout to maintain 82535d5b7c7Smrg * precision */ 82635d5b7c7Smrg coeff_ibmax = (i * i_amax) - (i_l * i_bmax); 82735d5b7c7Smrg a_out_ibmax = i_bmax * a[i_l] + 82835d5b7c7Smrg coeff_ibmax * (a[i_r] - a[i_l]); 82935d5b7c7Smrg 83035d5b7c7Smrg /* j = floor((a_out/max_lut)*i_bmax). 83135d5b7c7Smrg * i.e. the element in LUT b that a_out maps to. We 83235d5b7c7Smrg * have to divide by max_lut to normalize a_out, since 83335d5b7c7Smrg * values in the LUTs are [0, 1<<16) 83435d5b7c7Smrg */ 83535d5b7c7Smrg j = a_out_ibmax / max_lut; 83635d5b7c7Smrg *(uint16_t*)((void*)out + (i*struct_size)) = 83735d5b7c7Smrg *(uint16_t*)((void*)b + (j*struct_size)); 83835d5b7c7Smrg } 83935d5b7c7Smrg } 84035d5b7c7Smrg 84135d5b7c7Smrg for (i = 0; i < len_b; i++) 84235d5b7c7Smrg out_lut[i].reserved = 0; 84335d5b7c7Smrg} 84435d5b7c7Smrg 84535d5b7c7Smrg/** 84635d5b7c7Smrg * Resize a LUT, using linear interpolation. 84735d5b7c7Smrg * 84835d5b7c7Smrg * @in_(red|green|blue): Legacy LUT components 84935d5b7c7Smrg * @out_lut: The resized LUT is returned here, in DRM color LUT format. 85035d5b7c7Smrg * @len_in: Length of legacy LUT. 85135d5b7c7Smrg * @len_out: Length of out_lut, i.e. the target size. 85235d5b7c7Smrg */ 85335d5b7c7Smrgstatic void drmmode_lut_interpolate(uint16_t *in_red, 85435d5b7c7Smrg uint16_t *in_green, 85535d5b7c7Smrg uint16_t *in_blue, 85635d5b7c7Smrg struct drm_color_lut *out_lut, 85735d5b7c7Smrg uint32_t len_in, uint32_t len_out) 85835d5b7c7Smrg{ 85935d5b7c7Smrg uint32_t i_l, i_r, i; 86035d5b7c7Smrg uint32_t i_amax, i_bmax; 86135d5b7c7Smrg uint32_t coeff_ibmax; 86235d5b7c7Smrg uint64_t out_ibmax; 86335d5b7c7Smrg int color; 86435d5b7c7Smrg size_t struct_size = sizeof(struct drm_color_lut); 86535d5b7c7Smrg 86635d5b7c7Smrg i_amax = len_in - 1; 86735d5b7c7Smrg i_bmax = len_out - 1; 86835d5b7c7Smrg 86935d5b7c7Smrg /* See @drmmode_lut_compose for details */ 87035d5b7c7Smrg for (color = 0; color < 3; color++) { 87135d5b7c7Smrg uint16_t *in, *out; 87235d5b7c7Smrg 87335d5b7c7Smrg if (color == 0) { 87435d5b7c7Smrg in = in_red; 87535d5b7c7Smrg out = &out_lut[0].red; 87635d5b7c7Smrg } else if (color == 1) { 87735d5b7c7Smrg in = in_green; 87835d5b7c7Smrg out = &out_lut[0].green; 87935d5b7c7Smrg } else { 88035d5b7c7Smrg in = in_blue; 88135d5b7c7Smrg out = &out_lut[0].blue; 88235d5b7c7Smrg } 88335d5b7c7Smrg 88435d5b7c7Smrg for (i = 0; i < len_out; i++) { 88535d5b7c7Smrg i_l = i * i_amax / i_bmax; 88635d5b7c7Smrg i_r = i_l + !!(i_amax - i_l); 88735d5b7c7Smrg 88835d5b7c7Smrg coeff_ibmax = (i * i_amax) - (i_l * i_bmax); 88935d5b7c7Smrg out_ibmax = i_bmax * in[i_l] + 89035d5b7c7Smrg coeff_ibmax * (in[i_r] - in[i_l]); 89135d5b7c7Smrg 89235d5b7c7Smrg *(uint16_t*)((void*)out + (i*struct_size)) = 89335d5b7c7Smrg out_ibmax / i_bmax; 89435d5b7c7Smrg } 89535d5b7c7Smrg } 89635d5b7c7Smrg 89735d5b7c7Smrg for (i = 0; i < len_out; i++) 89835d5b7c7Smrg out_lut[i].reserved = 0; 89935d5b7c7Smrg} 90035d5b7c7Smrg 90135d5b7c7Smrg/** 90235d5b7c7Smrg * Configure and change a color property on a CRTC, through RandR. Only the 90335d5b7c7Smrg * specified output will be affected, even if the CRTC is attached to multiple 90435d5b7c7Smrg * outputs. Note that changes will be non-pending: the changes won't be pushed 90535d5b7c7Smrg * to kernel driver. 90635d5b7c7Smrg * 90735d5b7c7Smrg * @output: RandR output to set the property on. 90835d5b7c7Smrg * @crtc: The driver-private CRTC object containing the color properties. 90935d5b7c7Smrg * If this is NULL, "disabled" values of 0 will be used. 91035d5b7c7Smrg * @cm_prop_index: Color management property to configure and change. 91135d5b7c7Smrg * 91235d5b7c7Smrg * Return 0 on success, X-defined error code otherwise. 91335d5b7c7Smrg */ 91435d5b7c7Smrgstatic int rr_configure_and_change_cm_property(xf86OutputPtr output, 91535d5b7c7Smrg drmmode_crtc_private_ptr crtc, 91635d5b7c7Smrg enum drmmode_cm_prop cm_prop_index) 91735d5b7c7Smrg{ 91835d5b7c7Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 91935d5b7c7Smrg drmmode_ptr drmmode = drmmode_output->drmmode; 92035d5b7c7Smrg Bool need_configure = TRUE; 92135d5b7c7Smrg unsigned long length = 0; 92235d5b7c7Smrg void *data = NULL; 92335d5b7c7Smrg int format = 0; 92435d5b7c7Smrg uint32_t zero = 0; 92535d5b7c7Smrg INT32 range[2]; 92635d5b7c7Smrg Atom atom; 92735d5b7c7Smrg int err; 92835d5b7c7Smrg 92935d5b7c7Smrg if (cm_prop_index == CM_INVALID_PROP) 93035d5b7c7Smrg return BadName; 93135d5b7c7Smrg 93235d5b7c7Smrg switch(cm_prop_index) { 93335d5b7c7Smrg case CM_GAMMA_LUT_SIZE: 93435d5b7c7Smrg format = 32; 93535d5b7c7Smrg length = 1; 93635d5b7c7Smrg data = &drmmode->gamma_lut_size; 93735d5b7c7Smrg range[0] = 0; 93835d5b7c7Smrg range[1] = -1; 93935d5b7c7Smrg break; 94035d5b7c7Smrg case CM_DEGAMMA_LUT_SIZE: 94135d5b7c7Smrg format = 32; 94235d5b7c7Smrg length = 1; 94335d5b7c7Smrg data = &drmmode->degamma_lut_size; 94435d5b7c7Smrg range[0] = 0; 94535d5b7c7Smrg range[1] = -1; 94635d5b7c7Smrg break; 94735d5b7c7Smrg case CM_GAMMA_LUT: 94835d5b7c7Smrg format = 16; 94935d5b7c7Smrg range[0] = 0; 95035d5b7c7Smrg range[1] = (1 << 16) - 1; // Max 16 bit unsigned int. 95135d5b7c7Smrg if (crtc && crtc->gamma_lut) { 95235d5b7c7Smrg /* Convert from 8bit size to 16bit size */ 95335d5b7c7Smrg length = sizeof(*crtc->gamma_lut) >> 1; 95435d5b7c7Smrg length *= drmmode->gamma_lut_size; 95535d5b7c7Smrg data = crtc->gamma_lut; 95635d5b7c7Smrg } else { 95735d5b7c7Smrg length = 1; 95835d5b7c7Smrg data = &zero; 95935d5b7c7Smrg } 96035d5b7c7Smrg break; 96135d5b7c7Smrg case CM_DEGAMMA_LUT: 96235d5b7c7Smrg format = 16; 96335d5b7c7Smrg range[0] = 0; 96435d5b7c7Smrg range[1] = (1 << 16) - 1; 96535d5b7c7Smrg if (crtc && crtc->degamma_lut) { 96635d5b7c7Smrg length = sizeof(*crtc->degamma_lut) >> 1; 96735d5b7c7Smrg length *= drmmode->degamma_lut_size; 96835d5b7c7Smrg data = crtc->degamma_lut; 96935d5b7c7Smrg } else { 97035d5b7c7Smrg length = 1; 97135d5b7c7Smrg data = &zero; 97235d5b7c7Smrg } 97335d5b7c7Smrg break; 97435d5b7c7Smrg case CM_CTM: 97535d5b7c7Smrg /* CTM is fixed-point S31.32 format. */ 97635d5b7c7Smrg format = 32; 97735d5b7c7Smrg need_configure = FALSE; 97835d5b7c7Smrg if (crtc && crtc->ctm) { 97935d5b7c7Smrg /* Convert from 8bit size to 32bit size */ 98035d5b7c7Smrg length = sizeof(*crtc->ctm) >> 2; 98135d5b7c7Smrg data = crtc->ctm; 98235d5b7c7Smrg } else { 98335d5b7c7Smrg length = 1; 98435d5b7c7Smrg data = &zero; 98535d5b7c7Smrg } 98635d5b7c7Smrg break; 98735d5b7c7Smrg default: 98835d5b7c7Smrg return BadName; 98935d5b7c7Smrg } 99035d5b7c7Smrg 99135d5b7c7Smrg atom = MakeAtom(cm_prop_names[cm_prop_index], 99235d5b7c7Smrg strlen(cm_prop_names[cm_prop_index]), 99335d5b7c7Smrg TRUE); 99435d5b7c7Smrg if (!atom) 99535d5b7c7Smrg return BadAlloc; 99635d5b7c7Smrg 99735d5b7c7Smrg if (need_configure) { 99835d5b7c7Smrg err = RRConfigureOutputProperty(output->randr_output, atom, 99935d5b7c7Smrg FALSE, TRUE, FALSE, 2, range); 100035d5b7c7Smrg if (err) { 100135d5b7c7Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 100235d5b7c7Smrg "Configuring color management property %s failed with %d\n", 100335d5b7c7Smrg cm_prop_names[cm_prop_index], err); 100435d5b7c7Smrg return err; 100535d5b7c7Smrg } 100635d5b7c7Smrg } 100735d5b7c7Smrg 100835d5b7c7Smrg /* Always issue a non-pending change. We'll push cm properties 100935d5b7c7Smrg * ourselves. 101035d5b7c7Smrg */ 101135d5b7c7Smrg err = RRChangeOutputProperty(output->randr_output, atom, 101235d5b7c7Smrg XA_INTEGER, format, 101335d5b7c7Smrg PropModeReplace, 101435d5b7c7Smrg length, data, FALSE, FALSE); 101535d5b7c7Smrg if (err) 101635d5b7c7Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 101735d5b7c7Smrg "Changing color management property %s failed with %d\n", 101835d5b7c7Smrg cm_prop_names[cm_prop_index], err); 101935d5b7c7Smrg return err; 102035d5b7c7Smrg} 102135d5b7c7Smrg 102235d5b7c7Smrg/** 102335d5b7c7Smrg* Stage a color management property. This parses the property value, according 102435d5b7c7Smrg* to the cm property type, then stores it within the driver-private CRTC 102535d5b7c7Smrg* object. 102635d5b7c7Smrg* 102735d5b7c7Smrg* @crtc: The CRTC to stage the new color management properties in 102835d5b7c7Smrg* @cm_prop_index: The color property to stage 102935d5b7c7Smrg* @value: The RandR property value to stage 103035d5b7c7Smrg* 103135d5b7c7Smrg* Return 0 on success, X-defined error code on failure. 103235d5b7c7Smrg*/ 103335d5b7c7Smrgstatic int drmmode_crtc_stage_cm_prop(xf86CrtcPtr crtc, 103435d5b7c7Smrg enum drmmode_cm_prop cm_prop_index, 103535d5b7c7Smrg RRPropertyValuePtr value) 103635d5b7c7Smrg{ 103735d5b7c7Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 103835d5b7c7Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 103935d5b7c7Smrg size_t expected_bytes = 0; 104035d5b7c7Smrg void **blob_data = NULL; 104135d5b7c7Smrg Bool use_default = FALSE; 104235d5b7c7Smrg 104335d5b7c7Smrg /* Update properties on the driver-private CRTC */ 104435d5b7c7Smrg switch (cm_prop_index) { 104535d5b7c7Smrg case CM_GAMMA_LUT: 104635d5b7c7Smrg /* Calculate the expected size of value in bytes */ 104735d5b7c7Smrg expected_bytes = sizeof(struct drm_color_lut) * 104835d5b7c7Smrg drmmode->gamma_lut_size; 104935d5b7c7Smrg 105035d5b7c7Smrg /* For gamma and degamma, we allow a default SRGB curve to be 105135d5b7c7Smrg * set via setting a single element 105235d5b7c7Smrg * 105335d5b7c7Smrg * Otherwise, value size is in terms of the value format. 105435d5b7c7Smrg * Ensure it's also in bytes (<< 1) before comparing with the 105535d5b7c7Smrg * expected bytes. 105635d5b7c7Smrg */ 105735d5b7c7Smrg if (value->size == 1) 105835d5b7c7Smrg use_default = TRUE; 105935d5b7c7Smrg else if (value->type != XA_INTEGER || value->format != 16 || 106035d5b7c7Smrg (size_t)(value->size << 1) != expected_bytes) 106135d5b7c7Smrg return BadLength; 106235d5b7c7Smrg 106335d5b7c7Smrg blob_data = (void**)&drmmode_crtc->gamma_lut; 106435d5b7c7Smrg break; 106535d5b7c7Smrg case CM_DEGAMMA_LUT: 106635d5b7c7Smrg expected_bytes = sizeof(struct drm_color_lut) * 106735d5b7c7Smrg drmmode->degamma_lut_size; 106835d5b7c7Smrg 106935d5b7c7Smrg if (value->size == 1) 107035d5b7c7Smrg use_default = TRUE; 107135d5b7c7Smrg else if (value->type != XA_INTEGER || value->format != 16 || 107235d5b7c7Smrg (size_t)(value->size << 1) != expected_bytes) 107335d5b7c7Smrg return BadLength; 107435d5b7c7Smrg 107535d5b7c7Smrg blob_data = (void**)&drmmode_crtc->degamma_lut; 107635d5b7c7Smrg break; 107735d5b7c7Smrg case CM_CTM: 107835d5b7c7Smrg expected_bytes = sizeof(struct drm_color_ctm); 107935d5b7c7Smrg 108035d5b7c7Smrg if (value->size == 1) 108135d5b7c7Smrg use_default = TRUE; 108235d5b7c7Smrg if (value->type != XA_INTEGER || value->format != 32 || 108335d5b7c7Smrg (size_t)(value->size << 2) != expected_bytes) 108435d5b7c7Smrg return BadLength; 108535d5b7c7Smrg 108635d5b7c7Smrg blob_data = (void**)&drmmode_crtc->ctm; 108735d5b7c7Smrg break; 108835d5b7c7Smrg default: 108935d5b7c7Smrg return BadName; 109035d5b7c7Smrg } 109135d5b7c7Smrg 109235d5b7c7Smrg free(*blob_data); 109335d5b7c7Smrg if (!use_default) { 109435d5b7c7Smrg *blob_data = malloc(expected_bytes); 109535d5b7c7Smrg if (!*blob_data) 109635d5b7c7Smrg return BadAlloc; 109735d5b7c7Smrg memcpy(*blob_data, value->data, expected_bytes); 109835d5b7c7Smrg } else 109935d5b7c7Smrg *blob_data = NULL; 110035d5b7c7Smrg 110135d5b7c7Smrg return Success; 110235d5b7c7Smrg} 110335d5b7c7Smrg 110435d5b7c7Smrg/** 110535d5b7c7Smrg * Push staged color management properties on the CRTC to DRM. 110635d5b7c7Smrg * 110735d5b7c7Smrg * @crtc: The CRTC containing staged properties 110835d5b7c7Smrg * @cm_prop_index: The color property to push 110935d5b7c7Smrg * 111035d5b7c7Smrg * Return 0 on success, X-defined error codes on failure. 111135d5b7c7Smrg */ 111235d5b7c7Smrgstatic int drmmode_crtc_push_cm_prop(xf86CrtcPtr crtc, 111335d5b7c7Smrg enum drmmode_cm_prop cm_prop_index) 111435d5b7c7Smrg{ 111535d5b7c7Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 111635d5b7c7Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 111735d5b7c7Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 111835d5b7c7Smrg Bool free_blob_data = FALSE; 111935d5b7c7Smrg uint32_t created_blob_id = 0; 112035d5b7c7Smrg uint32_t drm_prop_id; 112135d5b7c7Smrg size_t expected_bytes = 0; 112235d5b7c7Smrg void *blob_data = NULL; 112335d5b7c7Smrg int ret; 112435d5b7c7Smrg 112535d5b7c7Smrg switch (cm_prop_index) { 112635d5b7c7Smrg case CM_GAMMA_LUT: 112735d5b7c7Smrg /* Calculate the expected size of value in bytes */ 112835d5b7c7Smrg expected_bytes = sizeof(struct drm_color_lut) * 112935d5b7c7Smrg drmmode->gamma_lut_size; 113035d5b7c7Smrg 113135d5b7c7Smrg /* Legacy gamma LUT is disabled on deep 30bpp color. In which 113235d5b7c7Smrg * case, directly use non-legacy LUT. 113335d5b7c7Smrg */ 113435d5b7c7Smrg if (!crtc->funcs->gamma_set) { 113535d5b7c7Smrg blob_data = drmmode_crtc->gamma_lut; 113635d5b7c7Smrg goto do_push; 113735d5b7c7Smrg } 113835d5b7c7Smrg 113935d5b7c7Smrg blob_data = malloc(expected_bytes); 114035d5b7c7Smrg if (!blob_data) 114135d5b7c7Smrg return BadAlloc; 114235d5b7c7Smrg 114335d5b7c7Smrg free_blob_data = TRUE; 114435d5b7c7Smrg /* 114535d5b7c7Smrg * Compose legacy and non-legacy LUT if non-legacy was set. 114635d5b7c7Smrg * Otherwise, interpolate legacy LUT to non-legacy size. 114735d5b7c7Smrg */ 114835d5b7c7Smrg if (drmmode_crtc->gamma_lut) { 114935d5b7c7Smrg drmmode_lut_compose(crtc->gamma_red, 115035d5b7c7Smrg crtc->gamma_green, 115135d5b7c7Smrg crtc->gamma_blue, 115235d5b7c7Smrg drmmode_crtc->gamma_lut, 115335d5b7c7Smrg blob_data, crtc->gamma_size, 115435d5b7c7Smrg drmmode->gamma_lut_size); 115535d5b7c7Smrg } else { 115635d5b7c7Smrg drmmode_lut_interpolate(crtc->gamma_red, 115735d5b7c7Smrg crtc->gamma_green, 115835d5b7c7Smrg crtc->gamma_blue, 115935d5b7c7Smrg blob_data, 116035d5b7c7Smrg crtc->gamma_size, 116135d5b7c7Smrg drmmode->gamma_lut_size); 116235d5b7c7Smrg } 116335d5b7c7Smrg break; 116435d5b7c7Smrg case CM_DEGAMMA_LUT: 116535d5b7c7Smrg expected_bytes = sizeof(struct drm_color_lut) * 116635d5b7c7Smrg drmmode->degamma_lut_size; 116735d5b7c7Smrg blob_data = drmmode_crtc->degamma_lut; 116835d5b7c7Smrg break; 116935d5b7c7Smrg case CM_CTM: 117035d5b7c7Smrg expected_bytes = sizeof(struct drm_color_ctm); 117135d5b7c7Smrg blob_data = drmmode_crtc->ctm; 117235d5b7c7Smrg break; 117335d5b7c7Smrg default: 117435d5b7c7Smrg return BadName; 117535d5b7c7Smrg } 117635d5b7c7Smrg 117735d5b7c7Smrgdo_push: 117835d5b7c7Smrg if (blob_data) { 117935d5b7c7Smrg ret = drmModeCreatePropertyBlob(pAMDGPUEnt->fd, 118035d5b7c7Smrg blob_data, expected_bytes, 118135d5b7c7Smrg &created_blob_id); 118235d5b7c7Smrg if (ret) { 118335d5b7c7Smrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 118435d5b7c7Smrg "Creating DRM blob failed with errno %d\n", 118535d5b7c7Smrg ret); 118635d5b7c7Smrg if (free_blob_data) 118735d5b7c7Smrg free(blob_data); 118835d5b7c7Smrg return BadRequest; 118935d5b7c7Smrg } 119035d5b7c7Smrg } 119135d5b7c7Smrg 119235d5b7c7Smrg drm_prop_id = drmmode_crtc->drmmode->cm_prop_ids[cm_prop_index]; 119335d5b7c7Smrg ret = drmModeObjectSetProperty(pAMDGPUEnt->fd, 119435d5b7c7Smrg drmmode_crtc->mode_crtc->crtc_id, 119535d5b7c7Smrg DRM_MODE_OBJECT_CRTC, 119635d5b7c7Smrg drm_prop_id, 119735d5b7c7Smrg (uint64_t)created_blob_id); 119835d5b7c7Smrg 119935d5b7c7Smrg /* If successful, kernel will have a reference already. Safe to destroy 120035d5b7c7Smrg * the blob either way. 120135d5b7c7Smrg */ 120235d5b7c7Smrg if (blob_data) 120335d5b7c7Smrg drmModeDestroyPropertyBlob(pAMDGPUEnt->fd, created_blob_id); 120435d5b7c7Smrg 120535d5b7c7Smrg if (ret) { 120635d5b7c7Smrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 120735d5b7c7Smrg "Setting DRM property blob failed with errno %d\n", 120835d5b7c7Smrg ret); 120935d5b7c7Smrg if (free_blob_data) 121035d5b7c7Smrg free(blob_data); 121135d5b7c7Smrg return BadRequest; 121235d5b7c7Smrg } 121335d5b7c7Smrg 121435d5b7c7Smrg if (free_blob_data) 121535d5b7c7Smrg free(blob_data); 121635d5b7c7Smrg 121735d5b7c7Smrg return Success; 121835d5b7c7Smrg} 121935d5b7c7Smrg 122024b90cf4Smrgstatic void 122124b90cf4Smrgdrmmode_crtc_gamma_do_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, 122224b90cf4Smrg uint16_t *blue, int size) 122324b90cf4Smrg{ 122424b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 122524b90cf4Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 122635d5b7c7Smrg int ret; 122735d5b7c7Smrg 122835d5b7c7Smrg /* Use legacy if no support for non-legacy gamma */ 122935d5b7c7Smrg if (!drmmode_cm_enabled(drmmode_crtc->drmmode)) { 123035d5b7c7Smrg drmModeCrtcSetGamma(pAMDGPUEnt->fd, 123135d5b7c7Smrg drmmode_crtc->mode_crtc->crtc_id, 123235d5b7c7Smrg size, red, green, blue); 123335d5b7c7Smrg return; 123435d5b7c7Smrg } 123524b90cf4Smrg 123635d5b7c7Smrg ret = drmmode_crtc_push_cm_prop(crtc, CM_GAMMA_LUT); 123735d5b7c7Smrg if (ret) 123835d5b7c7Smrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 123935d5b7c7Smrg "Setting Gamma LUT failed with errno %d\n", 124035d5b7c7Smrg ret); 124124b90cf4Smrg} 124224b90cf4Smrg 124324b90cf4SmrgBool 124424b90cf4Smrgdrmmode_set_mode(xf86CrtcPtr crtc, struct drmmode_fb *fb, DisplayModePtr mode, 124524b90cf4Smrg int x, int y) 124624b90cf4Smrg{ 124724b90cf4Smrg ScrnInfoPtr scrn = crtc->scrn; 124824b90cf4Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 124924b90cf4Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 125024b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 125124b90cf4Smrg uint32_t *output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); 125224b90cf4Smrg int output_count = 0; 125324b90cf4Smrg drmModeModeInfo kmode; 125424b90cf4Smrg Bool ret; 125524b90cf4Smrg int i; 125624b90cf4Smrg 125724b90cf4Smrg if (!output_ids) 125824b90cf4Smrg return FALSE; 125924b90cf4Smrg 126024b90cf4Smrg for (i = 0; i < xf86_config->num_output; i++) { 126124b90cf4Smrg xf86OutputPtr output = xf86_config->output[i]; 126224b90cf4Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 126324b90cf4Smrg 126424b90cf4Smrg if (output->crtc != crtc) 126524b90cf4Smrg continue; 126624b90cf4Smrg 126724b90cf4Smrg output_ids[output_count] = drmmode_output->mode_output->connector_id; 126824b90cf4Smrg output_count++; 126924b90cf4Smrg } 127024b90cf4Smrg 127124b90cf4Smrg drmmode_ConvertToKMode(scrn, &kmode, mode); 127224b90cf4Smrg 127324b90cf4Smrg ret = drmModeSetCrtc(pAMDGPUEnt->fd, 127424b90cf4Smrg drmmode_crtc->mode_crtc->crtc_id, 127524b90cf4Smrg fb->handle, x, y, output_ids, 127624b90cf4Smrg output_count, &kmode) == 0; 127724b90cf4Smrg 127824b90cf4Smrg if (ret) { 127924b90cf4Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, fb); 128024b90cf4Smrg } else { 128124b90cf4Smrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 128224b90cf4Smrg "failed to set mode: %s\n", strerror(errno)); 128324b90cf4Smrg } 128424b90cf4Smrg 128524b90cf4Smrg free(output_ids); 128624b90cf4Smrg return ret; 128724b90cf4Smrg} 128824b90cf4Smrg 1289d6c0b56eSmrgstatic Bool 1290d6c0b56eSmrgdrmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, 1291d6c0b56eSmrg Rotation rotation, int x, int y) 1292d6c0b56eSmrg{ 1293d6c0b56eSmrg ScrnInfoPtr pScrn = crtc->scrn; 1294d6c0b56eSmrg ScreenPtr pScreen = pScrn->pScreen; 1295d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1296d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1297d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 1298d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 129990f2b693Smrg Bool handle_deferred = FALSE; 130011bf0794Smrg unsigned scanout_id = 0; 1301d6c0b56eSmrg int saved_x, saved_y; 1302d6c0b56eSmrg Rotation saved_rotation; 1303d6c0b56eSmrg DisplayModeRec saved_mode; 1304504d986fSmrg Bool ret = FALSE; 1305d6c0b56eSmrg int i; 130624b90cf4Smrg struct drmmode_fb *fb = NULL; 130724b90cf4Smrg 130824b90cf4Smrg /* The root window contents may be undefined before the WindowExposures 130924b90cf4Smrg * hook is called for it, so bail if we get here before that 131024b90cf4Smrg */ 131124b90cf4Smrg if (pScreen->WindowExposures == AMDGPUWindowExposures_oneshot) 131224b90cf4Smrg return FALSE; 1313d6c0b56eSmrg 1314d6c0b56eSmrg saved_mode = crtc->mode; 1315d6c0b56eSmrg saved_x = crtc->x; 1316d6c0b56eSmrg saved_y = crtc->y; 1317d6c0b56eSmrg saved_rotation = crtc->rotation; 1318d6c0b56eSmrg 1319d6c0b56eSmrg if (mode) { 1320d6c0b56eSmrg crtc->mode = *mode; 1321d6c0b56eSmrg crtc->x = x; 1322d6c0b56eSmrg crtc->y = y; 1323d6c0b56eSmrg crtc->rotation = rotation; 1324d6c0b56eSmrg 1325d6c0b56eSmrg if (!drmmode_handle_transform(crtc)) 1326d6c0b56eSmrg goto done; 1327d6c0b56eSmrg 132811bf0794Smrg drmmode_crtc_update_tear_free(crtc); 132911bf0794Smrg if (drmmode_crtc->tear_free) 133011bf0794Smrg scanout_id = drmmode_crtc->scanout_id; 133135d5b7c7Smrg else 133235d5b7c7Smrg drmmode_crtc->scanout_id = 0; 1333d6c0b56eSmrg 133424b90cf4Smrg if (drmmode_crtc->prime_scanout_pixmap) { 133511bf0794Smrg drmmode_crtc_prime_scanout_update(crtc, mode, scanout_id, 133624b90cf4Smrg &fb, &x, &y); 133746845023Smrg } else if (drmmode_crtc->rotate) { 133846845023Smrg fb = amdgpu_pixmap_get_fb(drmmode_crtc->rotate); 1339d6c0b56eSmrg x = y = 0; 134011bf0794Smrg 134124b90cf4Smrg } else if (!pScreen->isGPU && 134211bf0794Smrg (drmmode_crtc->tear_free || 1343504d986fSmrg crtc->driverIsPerformingTransform || 1344504d986fSmrg info->shadow_primary)) { 134511bf0794Smrg drmmode_crtc_scanout_update(crtc, mode, scanout_id, 134624b90cf4Smrg &fb, &x, &y); 1347d6c0b56eSmrg } 1348d6c0b56eSmrg 134924b90cf4Smrg if (!fb) 135024b90cf4Smrg fb = amdgpu_pixmap_get_fb(pScreen->GetWindowPixmap(pScreen->root)); 135124b90cf4Smrg if (!fb) { 135224b90cf4Smrg union gbm_bo_handle bo_handle; 135324b90cf4Smrg 135424b90cf4Smrg bo_handle = gbm_bo_get_handle(info->front_buffer->bo.gbm); 135524b90cf4Smrg fb = amdgpu_fb_create(pScrn, pAMDGPUEnt->fd, 135624b90cf4Smrg pScrn->virtualX, pScrn->virtualY, 135724b90cf4Smrg pScrn->displayWidth * info->pixel_bytes, 135824b90cf4Smrg bo_handle.u32); 135924b90cf4Smrg /* Prevent refcnt of ad-hoc FBs from reaching 2 */ 136024b90cf4Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, NULL); 136124b90cf4Smrg drmmode_crtc->fb = fb; 136224b90cf4Smrg } 136324b90cf4Smrg if (!fb) { 136424b90cf4Smrg ErrorF("failed to add FB for modeset\n"); 136524b90cf4Smrg goto done; 1366504d986fSmrg } 1367504d986fSmrg 136835d5b7c7Smrg amdgpu_drm_wait_pending_flip(crtc); 136990f2b693Smrg handle_deferred = TRUE; 137024b90cf4Smrg 137124b90cf4Smrg if (!drmmode_set_mode(crtc, fb, mode, x, y)) 1372d6c0b56eSmrg goto done; 137324b90cf4Smrg 137424b90cf4Smrg ret = TRUE; 1375d6c0b56eSmrg 1376d6c0b56eSmrg if (pScreen) 1377d6c0b56eSmrg xf86CrtcSetScreenSubpixelOrder(pScreen); 1378d6c0b56eSmrg 1379d6c0b56eSmrg drmmode_crtc->need_modeset = FALSE; 1380d6c0b56eSmrg 1381d6c0b56eSmrg /* go through all the outputs and force DPMS them back on? */ 1382d6c0b56eSmrg for (i = 0; i < xf86_config->num_output; i++) { 1383d6c0b56eSmrg xf86OutputPtr output = xf86_config->output[i]; 1384d6c0b56eSmrg 1385d6c0b56eSmrg if (output->crtc != crtc) 1386d6c0b56eSmrg continue; 1387d6c0b56eSmrg 1388d6c0b56eSmrg output->funcs->dpms(output, DPMSModeOn); 1389d6c0b56eSmrg } 1390d6c0b56eSmrg } 1391d6c0b56eSmrg 1392d6c0b56eSmrg /* Compute index of this CRTC into xf86_config->crtc */ 1393d6c0b56eSmrg for (i = 0; i < xf86_config->num_crtc; i++) { 1394d6c0b56eSmrg if (xf86_config->crtc[i] != crtc) 1395d6c0b56eSmrg continue; 1396d6c0b56eSmrg 1397d6c0b56eSmrg if (!crtc->enabled || drmmode_can_use_hw_cursor(crtc)) 1398d6c0b56eSmrg info->hwcursor_disabled &= ~(1 << i); 1399d6c0b56eSmrg else 1400d6c0b56eSmrg info->hwcursor_disabled |= 1 << i; 1401d6c0b56eSmrg 1402d6c0b56eSmrg break; 1403d6c0b56eSmrg } 1404d6c0b56eSmrg 1405d6c0b56eSmrg#ifndef HAVE_XF86_CURSOR_RESET_CURSOR 1406d6c0b56eSmrg if (!info->hwcursor_disabled) 1407d6c0b56eSmrg xf86_reload_cursors(pScreen); 1408d6c0b56eSmrg#endif 1409d6c0b56eSmrg 1410d6c0b56eSmrgdone: 1411d6c0b56eSmrg if (!ret) { 1412d6c0b56eSmrg crtc->x = saved_x; 1413d6c0b56eSmrg crtc->y = saved_y; 1414d6c0b56eSmrg crtc->rotation = saved_rotation; 1415d6c0b56eSmrg crtc->mode = saved_mode; 1416504d986fSmrg } else { 1417d6c0b56eSmrg crtc->active = TRUE; 1418d6c0b56eSmrg 141946845023Smrg if (drmmode_crtc->scanout[scanout_id] && 142046845023Smrg fb != amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id])) { 142190f2b693Smrg drmmode_crtc_scanout_free(crtc); 142235d5b7c7Smrg } else if (!drmmode_crtc->tear_free) { 142346845023Smrg drmmode_crtc_scanout_destroy(&drmmode_crtc->scanout[1]); 142411bf0794Smrg } 1425504d986fSmrg } 1426504d986fSmrg 142790f2b693Smrg if (handle_deferred) 142890f2b693Smrg amdgpu_drm_queue_handle_deferred(crtc); 142990f2b693Smrg 1430d6c0b56eSmrg return ret; 1431d6c0b56eSmrg} 1432d6c0b56eSmrg 1433d6c0b56eSmrgstatic void drmmode_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg) 1434d6c0b56eSmrg{ 1435d6c0b56eSmrg 1436d6c0b56eSmrg} 1437d6c0b56eSmrg 1438d6c0b56eSmrgstatic void drmmode_set_cursor_position(xf86CrtcPtr crtc, int x, int y) 1439d6c0b56eSmrg{ 1440d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1441d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 1442d6c0b56eSmrg 144324b90cf4Smrg#if XF86_CRTC_VERSION < 7 1444d6c0b56eSmrg if (crtc->driverIsPerformingTransform) { 1445d6c0b56eSmrg x += crtc->x; 1446d6c0b56eSmrg y += crtc->y; 1447d6c0b56eSmrg xf86CrtcTransformCursorPos(crtc, &x, &y); 1448d6c0b56eSmrg } 1449d6c0b56eSmrg#endif 1450d6c0b56eSmrg 145190f2b693Smrg drmmode_crtc->cursor_x = x; 145290f2b693Smrg drmmode_crtc->cursor_y = y; 145390f2b693Smrg 1454d6c0b56eSmrg drmModeMoveCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, x, y); 1455d6c0b56eSmrg} 1456d6c0b56eSmrg 145724b90cf4Smrg#if XF86_CRTC_VERSION < 7 1458d6c0b56eSmrg 1459d6c0b56eSmrgstatic int 1460d6c0b56eSmrgdrmmode_cursor_src_offset(Rotation rotation, int width, int height, 1461d6c0b56eSmrg int x_dst, int y_dst) 1462d6c0b56eSmrg{ 1463d6c0b56eSmrg int t; 1464d6c0b56eSmrg 1465d6c0b56eSmrg switch (rotation & 0xf) { 1466d6c0b56eSmrg case RR_Rotate_90: 1467d6c0b56eSmrg t = x_dst; 1468d6c0b56eSmrg x_dst = height - y_dst - 1; 1469d6c0b56eSmrg y_dst = t; 1470d6c0b56eSmrg break; 1471d6c0b56eSmrg case RR_Rotate_180: 1472d6c0b56eSmrg x_dst = width - x_dst - 1; 1473d6c0b56eSmrg y_dst = height - y_dst - 1; 1474d6c0b56eSmrg break; 1475d6c0b56eSmrg case RR_Rotate_270: 1476d6c0b56eSmrg t = x_dst; 1477d6c0b56eSmrg x_dst = y_dst; 1478d6c0b56eSmrg y_dst = width - t - 1; 1479d6c0b56eSmrg break; 1480d6c0b56eSmrg } 1481d6c0b56eSmrg 1482d6c0b56eSmrg if (rotation & RR_Reflect_X) 1483d6c0b56eSmrg x_dst = width - x_dst - 1; 1484d6c0b56eSmrg if (rotation & RR_Reflect_Y) 1485d6c0b56eSmrg y_dst = height - y_dst - 1; 1486d6c0b56eSmrg 1487d6c0b56eSmrg return y_dst * height + x_dst; 1488d6c0b56eSmrg} 1489d6c0b56eSmrg 1490d6c0b56eSmrg#endif 1491d6c0b56eSmrg 149290f2b693Smrgstatic Bool 149390f2b693Smrgdrmmode_cursor_pixel(xf86CrtcPtr crtc, uint32_t *argb, Bool *premultiplied, 149490f2b693Smrg Bool *apply_gamma) 149535d5b7c7Smrg{ 149690f2b693Smrg uint32_t alpha = *argb >> 24; 149790f2b693Smrg uint32_t rgb[3]; 149890f2b693Smrg int i; 149935d5b7c7Smrg 150090f2b693Smrg if (premultiplied) { 150190f2b693Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1, 18, 4, 0, 0) 150290f2b693Smrg if (alpha == 0 && (*argb & 0xffffff) != 0) { 150390f2b693Smrg /* Doesn't look like premultiplied alpha */ 150490f2b693Smrg *premultiplied = FALSE; 150590f2b693Smrg return FALSE; 150690f2b693Smrg } 150790f2b693Smrg#endif 150835d5b7c7Smrg 150990f2b693Smrg if (!(*apply_gamma)) 151090f2b693Smrg return TRUE; 151135d5b7c7Smrg 151290f2b693Smrg if (*argb > (alpha | alpha << 8 | alpha << 16 | alpha << 24)) { 151390f2b693Smrg /* Un-premultiplied R/G/B would overflow gamma LUT, 151490f2b693Smrg * don't apply gamma correction 151590f2b693Smrg */ 151690f2b693Smrg *apply_gamma = FALSE; 151790f2b693Smrg return FALSE; 151890f2b693Smrg } 151990f2b693Smrg } 152024b90cf4Smrg 152190f2b693Smrg if (!alpha) { 152290f2b693Smrg *argb = 0; 152390f2b693Smrg return TRUE; 152490f2b693Smrg } 152524b90cf4Smrg 152690f2b693Smrg /* Extract RGB */ 152724b90cf4Smrg for (i = 0; i < 3; i++) 152890f2b693Smrg rgb[i] = (*argb >> (i * 8)) & 0xff; 152924b90cf4Smrg 153090f2b693Smrg if (premultiplied) { 153190f2b693Smrg /* Un-premultiply alpha */ 153290f2b693Smrg for (i = 0; i < 3; i++) 153390f2b693Smrg rgb[i] = rgb[i] * 0xff / alpha; 153490f2b693Smrg } 153590f2b693Smrg 153690f2b693Smrg if (*apply_gamma) { 153790f2b693Smrg rgb[0] = crtc->gamma_blue[rgb[0]] >> 8; 153890f2b693Smrg rgb[1] = crtc->gamma_green[rgb[1]] >> 8; 153990f2b693Smrg rgb[2] = crtc->gamma_red[rgb[2]] >> 8; 154090f2b693Smrg } 154190f2b693Smrg 154290f2b693Smrg /* Premultiply alpha */ 154390f2b693Smrg for (i = 0; i < 3; i++) 154490f2b693Smrg rgb[i] = rgb[i] * alpha / 0xff; 154524b90cf4Smrg 154690f2b693Smrg *argb = alpha << 24 | rgb[2] << 16 | rgb[1] << 8 | rgb[0]; 154790f2b693Smrg return TRUE; 154824b90cf4Smrg} 154924b90cf4Smrg 155090f2b693Smrgstatic void drmmode_load_cursor_argb(xf86CrtcPtr crtc, CARD32 * image) 1551d6c0b56eSmrg{ 155290f2b693Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1553d6c0b56eSmrg ScrnInfoPtr pScrn = crtc->scrn; 1554d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 155590f2b693Smrg unsigned id = drmmode_crtc->cursor_id; 155690f2b693Smrg Bool premultiplied = TRUE; 155790f2b693Smrg Bool apply_gamma = TRUE; 155890f2b693Smrg uint32_t argb; 155990f2b693Smrg uint32_t *ptr; 156035d5b7c7Smrg 156135d5b7c7Smrg if ((crtc->scrn->depth != 24 && crtc->scrn->depth != 32) || 156235d5b7c7Smrg drmmode_cm_enabled(&info->drmmode)) 156390f2b693Smrg apply_gamma = FALSE; 156490f2b693Smrg 156590f2b693Smrg if (drmmode_crtc->cursor && 156690f2b693Smrg XF86_CRTC_CONFIG_PTR(pScrn)->cursor != drmmode_crtc->cursor) 156790f2b693Smrg id ^= 1; 156890f2b693Smrg 156990f2b693Smrg ptr = (uint32_t *) (drmmode_crtc->cursor_buffer[id]->cpu_ptr); 1570d6c0b56eSmrg 157124b90cf4Smrg#if XF86_CRTC_VERSION < 7 1572d6c0b56eSmrg if (crtc->driverIsPerformingTransform) { 1573d6c0b56eSmrg uint32_t cursor_w = info->cursor_w, cursor_h = info->cursor_h; 1574d6c0b56eSmrg int dstx, dsty; 1575d6c0b56eSmrg int srcoffset; 1576d6c0b56eSmrg 157790f2b693Smrgretry_transform: 1578d6c0b56eSmrg for (dsty = 0; dsty < cursor_h; dsty++) { 1579d6c0b56eSmrg for (dstx = 0; dstx < cursor_w; dstx++) { 1580d6c0b56eSmrg srcoffset = drmmode_cursor_src_offset(crtc->rotation, 1581d6c0b56eSmrg cursor_w, 1582d6c0b56eSmrg cursor_h, 1583d6c0b56eSmrg dstx, dsty); 158490f2b693Smrg argb = image[srcoffset]; 158590f2b693Smrg if (!drmmode_cursor_pixel(crtc, &argb, &premultiplied, 158690f2b693Smrg &apply_gamma)) 158790f2b693Smrg goto retry_transform; 1588d6c0b56eSmrg 158990f2b693Smrg ptr[dsty * info->cursor_w + dstx] = cpu_to_le32(argb); 1590d6c0b56eSmrg } 1591d6c0b56eSmrg } 1592d6c0b56eSmrg } else 1593d6c0b56eSmrg#endif 1594d6c0b56eSmrg { 1595d6c0b56eSmrg uint32_t cursor_size = info->cursor_w * info->cursor_h; 1596d6c0b56eSmrg int i; 1597d6c0b56eSmrg 159890f2b693Smrgretry: 159990f2b693Smrg for (i = 0; i < cursor_size; i++) { 160090f2b693Smrg argb = image[i]; 160190f2b693Smrg if (!drmmode_cursor_pixel(crtc, &argb, &premultiplied, 160290f2b693Smrg &apply_gamma)) 160390f2b693Smrg goto retry; 1604d6c0b56eSmrg 160590f2b693Smrg ptr[i] = cpu_to_le32(argb); 160690f2b693Smrg } 160790f2b693Smrg } 1608d6c0b56eSmrg 160990f2b693Smrg if (id != drmmode_crtc->cursor_id) { 161090f2b693Smrg drmmode_crtc->cursor_id = id; 161190f2b693Smrg crtc->funcs->show_cursor(crtc); 1612d6c0b56eSmrg } 1613d6c0b56eSmrg} 1614d6c0b56eSmrg 1615d6c0b56eSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 1616d6c0b56eSmrg 1617d6c0b56eSmrgstatic Bool drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 * image) 1618d6c0b56eSmrg{ 1619d6c0b56eSmrg if (!drmmode_can_use_hw_cursor(crtc)) 1620d6c0b56eSmrg return FALSE; 1621d6c0b56eSmrg 1622d6c0b56eSmrg drmmode_load_cursor_argb(crtc, image); 1623d6c0b56eSmrg return TRUE; 1624d6c0b56eSmrg} 1625d6c0b56eSmrg 1626d6c0b56eSmrg#endif 1627d6c0b56eSmrg 1628d6c0b56eSmrgstatic void drmmode_hide_cursor(xf86CrtcPtr crtc) 1629d6c0b56eSmrg{ 1630d6c0b56eSmrg ScrnInfoPtr pScrn = crtc->scrn; 1631d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1632d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1633d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1634d6c0b56eSmrg 1635d6c0b56eSmrg drmModeSetCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 1636d6c0b56eSmrg info->cursor_w, info->cursor_h); 163790f2b693Smrg drmmode_crtc->cursor = NULL; 1638d6c0b56eSmrg} 1639d6c0b56eSmrg 1640d6c0b56eSmrgstatic void drmmode_show_cursor(xf86CrtcPtr crtc) 1641d6c0b56eSmrg{ 1642d6c0b56eSmrg ScrnInfoPtr pScrn = crtc->scrn; 1643d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1644d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1645d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 164690f2b693Smrg struct amdgpu_buffer *cursor_buffer = 164790f2b693Smrg drmmode_crtc->cursor_buffer[drmmode_crtc->cursor_id]; 164890f2b693Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 164990f2b693Smrg CursorPtr cursor = xf86_config->cursor; 165090f2b693Smrg int xhot = cursor->bits->xhot; 165190f2b693Smrg int yhot = cursor->bits->yhot; 1652d6c0b56eSmrg static Bool use_set_cursor2 = TRUE; 165390f2b693Smrg struct drm_mode_cursor2 arg; 1654d6c0b56eSmrg 165590f2b693Smrg drmmode_crtc->cursor = xf86_config->cursor; 165690f2b693Smrg 165790f2b693Smrg memset(&arg, 0, sizeof(arg)); 165890f2b693Smrg 165990f2b693Smrg if (!amdgpu_bo_get_handle(cursor_buffer, &arg.handle)) { 1660d6c0b56eSmrg ErrorF("failed to get BO handle for cursor\n"); 1661d6c0b56eSmrg return; 1662d6c0b56eSmrg } 1663d6c0b56eSmrg 166490f2b693Smrg arg.flags = DRM_MODE_CURSOR_BO; 166590f2b693Smrg arg.crtc_id = drmmode_crtc->mode_crtc->crtc_id; 166690f2b693Smrg arg.width = info->cursor_w; 166790f2b693Smrg arg.height = info->cursor_h; 166890f2b693Smrg 166990f2b693Smrg if (crtc->rotation != RR_Rotate_0 && 167090f2b693Smrg crtc->rotation != (RR_Rotate_180 | RR_Reflect_X | 167190f2b693Smrg RR_Reflect_Y)) { 167290f2b693Smrg int t; 167390f2b693Smrg 167490f2b693Smrg /* Reflect & rotate hotspot position */ 167590f2b693Smrg if (crtc->rotation & RR_Reflect_X) 167690f2b693Smrg xhot = info->cursor_w - xhot - 1; 167790f2b693Smrg if (crtc->rotation & RR_Reflect_Y) 167890f2b693Smrg yhot = info->cursor_h - yhot - 1; 167990f2b693Smrg 168090f2b693Smrg switch (crtc->rotation & 0xf) { 168190f2b693Smrg case RR_Rotate_90: 168290f2b693Smrg t = xhot; 168390f2b693Smrg xhot = yhot; 168490f2b693Smrg yhot = info->cursor_w - t - 1; 168590f2b693Smrg break; 168690f2b693Smrg case RR_Rotate_180: 168790f2b693Smrg xhot = info->cursor_w - xhot - 1; 168890f2b693Smrg yhot = info->cursor_h - yhot - 1; 168990f2b693Smrg break; 169090f2b693Smrg case RR_Rotate_270: 169190f2b693Smrg t = xhot; 169290f2b693Smrg xhot = info->cursor_h - yhot - 1; 169390f2b693Smrg yhot = t; 169490f2b693Smrg } 169590f2b693Smrg } 169690f2b693Smrg 169790f2b693Smrg if (xhot != drmmode_crtc->cursor_xhot || yhot != drmmode_crtc->cursor_yhot) { 169890f2b693Smrg arg.flags |= DRM_MODE_CURSOR_MOVE; 169990f2b693Smrg arg.x = drmmode_crtc->cursor_x += drmmode_crtc->cursor_xhot - xhot; 170090f2b693Smrg arg.y = drmmode_crtc->cursor_y += drmmode_crtc->cursor_yhot - yhot; 170190f2b693Smrg drmmode_crtc->cursor_xhot = xhot; 170290f2b693Smrg drmmode_crtc->cursor_yhot = yhot; 170390f2b693Smrg } 170490f2b693Smrg 1705d6c0b56eSmrg if (use_set_cursor2) { 1706d6c0b56eSmrg int ret; 1707d6c0b56eSmrg 170890f2b693Smrg arg.hot_x = xhot; 170990f2b693Smrg arg.hot_y = yhot; 1710504d986fSmrg 171190f2b693Smrg ret = drmIoctl(pAMDGPUEnt->fd, DRM_IOCTL_MODE_CURSOR2, &arg); 171246845023Smrg if (ret == -1 && errno == EINVAL) 1713d6c0b56eSmrg use_set_cursor2 = FALSE; 1714d6c0b56eSmrg else 1715d6c0b56eSmrg return; 1716d6c0b56eSmrg } 1717d6c0b56eSmrg 171890f2b693Smrg drmIoctl(pAMDGPUEnt->fd, DRM_IOCTL_MODE_CURSOR, &arg); 1719d6c0b56eSmrg} 1720d6c0b56eSmrg 172111bf0794Smrg/* Xorg expects a non-NULL return value from drmmode_crtc_shadow_allocate, and 172211bf0794Smrg * passes that back to drmmode_crtc_scanout_create; it doesn't use it for 172311bf0794Smrg * anything else. 172411bf0794Smrg */ 172511bf0794Smrgstatic void * 172611bf0794Smrgdrmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) 1727d6c0b56eSmrg{ 1728d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1729d6c0b56eSmrg 173011bf0794Smrg if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width, 173111bf0794Smrg height)) 173211bf0794Smrg return NULL; 173311bf0794Smrg 173411bf0794Smrg return (void*)~0UL; 1735d6c0b56eSmrg} 1736d6c0b56eSmrg 1737d6c0b56eSmrgstatic PixmapPtr 1738d6c0b56eSmrgdrmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) 1739d6c0b56eSmrg{ 1740d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1741d6c0b56eSmrg 174211bf0794Smrg if (!data) { 174311bf0794Smrg drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width, 174411bf0794Smrg height); 174511bf0794Smrg } 174611bf0794Smrg 174746845023Smrg return drmmode_crtc->rotate; 1748d6c0b56eSmrg} 1749d6c0b56eSmrg 1750d6c0b56eSmrgstatic void 1751d6c0b56eSmrgdrmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, 1752d6c0b56eSmrg void *data) 1753d6c0b56eSmrg{ 1754d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1755d6c0b56eSmrg 175646845023Smrg drmmode_crtc_scanout_destroy(&drmmode_crtc->rotate); 1757d6c0b56eSmrg} 1758d6c0b56eSmrg 1759d6c0b56eSmrgstatic void 1760d6c0b56eSmrgdrmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t * red, uint16_t * green, 1761d6c0b56eSmrg uint16_t * blue, int size) 1762d6c0b56eSmrg{ 176324b90cf4Smrg ScrnInfoPtr scrn = crtc->scrn; 176424b90cf4Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 176524b90cf4Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 176624b90cf4Smrg int i; 1767d6c0b56eSmrg 176824b90cf4Smrg drmmode_crtc_gamma_do_set(crtc, red, green, blue, size); 176924b90cf4Smrg 177024b90cf4Smrg /* Compute index of this CRTC into xf86_config->crtc */ 177124b90cf4Smrg for (i = 0; xf86_config->crtc[i] != crtc; i++) {} 177224b90cf4Smrg 177324b90cf4Smrg if (info->hwcursor_disabled & (1 << i)) 177424b90cf4Smrg return; 177524b90cf4Smrg 177624b90cf4Smrg#ifdef HAVE_XF86_CURSOR_RESET_CURSOR 177724b90cf4Smrg xf86CursorResetCursor(scrn->pScreen); 177824b90cf4Smrg#else 177924b90cf4Smrg xf86_reload_cursors(scrn->pScreen); 178024b90cf4Smrg#endif 1781d6c0b56eSmrg} 1782d6c0b56eSmrg 1783d6c0b56eSmrgstatic Bool drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) 1784d6c0b56eSmrg{ 1785d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 178611bf0794Smrg unsigned scanout_id = drmmode_crtc->scanout_id; 1787504d986fSmrg ScreenPtr screen = crtc->scrn->pScreen; 1788504d986fSmrg PixmapDirtyUpdatePtr dirty; 1789d6c0b56eSmrg 1790504d986fSmrg xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { 179124b90cf4Smrg if (amdgpu_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) { 179246845023Smrg PixmapStopDirtyTracking(dirty->src, dirty->secondary_dst); 179324b90cf4Smrg break; 179424b90cf4Smrg } 1795d6c0b56eSmrg } 1796d6c0b56eSmrg 179790f2b693Smrg drmmode_crtc_scanout_free(crtc); 179824b90cf4Smrg drmmode_crtc->prime_scanout_pixmap = NULL; 179924b90cf4Smrg 1800504d986fSmrg if (!ppix) 1801504d986fSmrg return TRUE; 1802504d986fSmrg 1803504d986fSmrg if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[0], 1804504d986fSmrg ppix->drawable.width, 1805504d986fSmrg ppix->drawable.height)) 1806504d986fSmrg return FALSE; 1807d6c0b56eSmrg 180811bf0794Smrg if (drmmode_crtc->tear_free && 1809504d986fSmrg !drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], 1810504d986fSmrg ppix->drawable.width, 1811504d986fSmrg ppix->drawable.height)) { 181290f2b693Smrg drmmode_crtc_scanout_free(crtc); 1813504d986fSmrg return FALSE; 1814d6c0b56eSmrg } 1815504d986fSmrg 181624b90cf4Smrg drmmode_crtc->prime_scanout_pixmap = ppix; 181724b90cf4Smrg 181824b90cf4Smrg#ifdef HAS_DIRTYTRACKING_DRAWABLE_SRC 181924b90cf4Smrg PixmapStartDirtyTracking(&ppix->drawable, 182046845023Smrg drmmode_crtc->scanout[scanout_id], 182124b90cf4Smrg 0, 0, 0, 0, RR_Rotate_0); 182224b90cf4Smrg#elif defined(HAS_DIRTYTRACKING_ROTATION) 182346845023Smrg PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id], 1824504d986fSmrg 0, 0, 0, 0, RR_Rotate_0); 1825d6c0b56eSmrg#elif defined(HAS_DIRTYTRACKING2) 182646845023Smrg PixmapStartDirtyTracking2(ppix, drmmode_crtc->scanout[scanout_id], 1827504d986fSmrg 0, 0, 0, 0); 1828d6c0b56eSmrg#else 182946845023Smrg PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id], 0, 0); 1830d6c0b56eSmrg#endif 1831d6c0b56eSmrg return TRUE; 1832d6c0b56eSmrg} 1833d6c0b56eSmrg 183435d5b7c7Smrgstatic void drmmode_crtc_destroy(xf86CrtcPtr crtc) 183535d5b7c7Smrg{ 183635d5b7c7Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 183735d5b7c7Smrg 183835d5b7c7Smrg drmModeFreeCrtc(drmmode_crtc->mode_crtc); 183935d5b7c7Smrg 184035d5b7c7Smrg /* Free LUTs and CTM */ 184135d5b7c7Smrg free(drmmode_crtc->gamma_lut); 184235d5b7c7Smrg free(drmmode_crtc->degamma_lut); 184335d5b7c7Smrg free(drmmode_crtc->ctm); 184435d5b7c7Smrg 184535d5b7c7Smrg free(drmmode_crtc); 184635d5b7c7Smrg crtc->driver_private = NULL; 184735d5b7c7Smrg} 184835d5b7c7Smrg 184935d5b7c7Smrg 1850d6c0b56eSmrgstatic xf86CrtcFuncsRec drmmode_crtc_funcs = { 1851d6c0b56eSmrg .dpms = drmmode_crtc_dpms, 1852d6c0b56eSmrg .set_mode_major = drmmode_set_mode_major, 1853d6c0b56eSmrg .set_cursor_colors = drmmode_set_cursor_colors, 1854d6c0b56eSmrg .set_cursor_position = drmmode_set_cursor_position, 1855d6c0b56eSmrg .show_cursor = drmmode_show_cursor, 1856d6c0b56eSmrg .hide_cursor = drmmode_hide_cursor, 1857d6c0b56eSmrg .load_cursor_argb = drmmode_load_cursor_argb, 1858d6c0b56eSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 1859d6c0b56eSmrg .load_cursor_argb_check = drmmode_load_cursor_argb_check, 1860d6c0b56eSmrg#endif 1861d6c0b56eSmrg 1862d6c0b56eSmrg .gamma_set = drmmode_crtc_gamma_set, 1863d6c0b56eSmrg .shadow_create = drmmode_crtc_shadow_create, 1864d6c0b56eSmrg .shadow_allocate = drmmode_crtc_shadow_allocate, 1865d6c0b56eSmrg .shadow_destroy = drmmode_crtc_shadow_destroy, 186635d5b7c7Smrg .destroy = drmmode_crtc_destroy, 1867d6c0b56eSmrg .set_scanout_pixmap = drmmode_set_scanout_pixmap, 1868d6c0b56eSmrg}; 1869d6c0b56eSmrg 1870d6c0b56eSmrgint drmmode_get_crtc_id(xf86CrtcPtr crtc) 1871d6c0b56eSmrg{ 1872d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1873d6c0b56eSmrg return drmmode_crtc->hw_id; 1874d6c0b56eSmrg} 1875d6c0b56eSmrg 1876d6c0b56eSmrgvoid drmmode_crtc_hw_id(xf86CrtcPtr crtc) 1877d6c0b56eSmrg{ 1878d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1879d6c0b56eSmrg ScrnInfoPtr pScrn = crtc->scrn; 1880d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1881d6c0b56eSmrg int r; 1882d6c0b56eSmrg 1883d6c0b56eSmrg r = amdgpu_query_crtc_from_id(pAMDGPUEnt->pDev, 1884d6c0b56eSmrg drmmode_crtc->mode_crtc->crtc_id, 1885d6c0b56eSmrg &drmmode_crtc->hw_id); 1886d6c0b56eSmrg if (r) 1887d6c0b56eSmrg drmmode_crtc->hw_id = -1; 1888d6c0b56eSmrg} 1889d6c0b56eSmrg 189035d5b7c7Smrg/** 189135d5b7c7Smrg * Initialize color management properties for the given CRTC by programming 189235d5b7c7Smrg * the default gamma/degamma LUTs and CTM. 189335d5b7c7Smrg * 189435d5b7c7Smrg * If the CRTC does not support color management, or if errors occur during 189535d5b7c7Smrg * initialization, all color properties on the driver-private CRTC will left 189635d5b7c7Smrg * as NULL. 189735d5b7c7Smrg * 189835d5b7c7Smrg * @drm_fd: DRM file descriptor 189935d5b7c7Smrg * @crtc: CRTC to initialize color management on. 190035d5b7c7Smrg */ 190135d5b7c7Smrgstatic void drmmode_crtc_cm_init(int drm_fd, xf86CrtcPtr crtc) 190235d5b7c7Smrg{ 190335d5b7c7Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 190435d5b7c7Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 190535d5b7c7Smrg int i; 190635d5b7c7Smrg 190735d5b7c7Smrg if (!drmmode_cm_enabled(drmmode)) 190835d5b7c7Smrg return; 190935d5b7c7Smrg 191035d5b7c7Smrg /* Init CTM to identity. Values are in S31.32 fixed-point format */ 191135d5b7c7Smrg drmmode_crtc->ctm = calloc(1, sizeof(*drmmode_crtc->ctm)); 191235d5b7c7Smrg if (!drmmode_crtc->ctm) { 191335d5b7c7Smrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 191435d5b7c7Smrg "Memory error initializing CTM for CRTC%d", 191535d5b7c7Smrg drmmode_get_crtc_id(crtc)); 191635d5b7c7Smrg return; 191735d5b7c7Smrg } 191835d5b7c7Smrg 191935d5b7c7Smrg drmmode_crtc->ctm->matrix[0] = drmmode_crtc->ctm->matrix[4] = 192035d5b7c7Smrg drmmode_crtc->ctm->matrix[8] = (uint64_t)1 << 32; 192135d5b7c7Smrg 192235d5b7c7Smrg /* Push properties to reset properties currently in hardware */ 192335d5b7c7Smrg for (i = 0; i < CM_GAMMA_LUT; i++) { 192435d5b7c7Smrg if (drmmode_crtc_push_cm_prop(crtc, i)) 192535d5b7c7Smrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 192635d5b7c7Smrg "Failed to initialize color management " 192735d5b7c7Smrg "property %s on CRTC%d. Property value may " 192835d5b7c7Smrg "not reflect actual hardware state.\n", 192935d5b7c7Smrg cm_prop_names[i], 193035d5b7c7Smrg drmmode_get_crtc_id(crtc)); 193135d5b7c7Smrg } 193235d5b7c7Smrg} 193335d5b7c7Smrg 1934d6c0b56eSmrgstatic unsigned int 1935d6c0b56eSmrgdrmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num) 1936d6c0b56eSmrg{ 1937d6c0b56eSmrg xf86CrtcPtr crtc; 1938d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc; 1939d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 194024b90cf4Smrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1941d6c0b56eSmrg 194224b90cf4Smrg crtc = xf86CrtcCreate(pScrn, &info->drmmode_crtc_funcs); 194335d5b7c7Smrg if (!crtc) 1944d6c0b56eSmrg return 0; 1945d6c0b56eSmrg 1946d6c0b56eSmrg drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1); 1947d6c0b56eSmrg drmmode_crtc->mode_crtc = 1948d6c0b56eSmrg drmModeGetCrtc(pAMDGPUEnt->fd, mode_res->crtcs[num]); 1949d6c0b56eSmrg drmmode_crtc->drmmode = drmmode; 1950d6c0b56eSmrg drmmode_crtc->dpms_mode = DPMSModeOff; 1951d6c0b56eSmrg crtc->driver_private = drmmode_crtc; 1952d6c0b56eSmrg drmmode_crtc_hw_id(crtc); 1953d6c0b56eSmrg 195435d5b7c7Smrg drmmode_crtc_cm_init(pAMDGPUEnt->fd, crtc); 195590f2b693Smrg drmmode_crtc_vrr_init(pAMDGPUEnt->fd, crtc); 195635d5b7c7Smrg 1957d6c0b56eSmrg /* Mark num'th crtc as in use on this device. */ 1958d6c0b56eSmrg pAMDGPUEnt->assigned_crtcs |= (1 << num); 1959d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 1960d6c0b56eSmrg "Allocated crtc nr. %d to this screen.\n", num); 1961d6c0b56eSmrg 1962d6c0b56eSmrg return 1; 1963d6c0b56eSmrg} 1964d6c0b56eSmrg 196524b90cf4Smrg/* 196624b90cf4Smrg * Update all of the property values for an output 196724b90cf4Smrg */ 196824b90cf4Smrgstatic void 196924b90cf4Smrgdrmmode_output_update_properties(xf86OutputPtr output) 197024b90cf4Smrg{ 197124b90cf4Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 197224b90cf4Smrg int i, j, k; 197324b90cf4Smrg int err; 197424b90cf4Smrg drmModeConnectorPtr koutput; 197524b90cf4Smrg 197624b90cf4Smrg /* Use the most recently fetched values from the kernel */ 197724b90cf4Smrg koutput = drmmode_output->mode_output; 197824b90cf4Smrg 197924b90cf4Smrg if (!koutput) 198024b90cf4Smrg return; 198124b90cf4Smrg 198224b90cf4Smrg for (i = 0; i < drmmode_output->num_props; i++) { 198324b90cf4Smrg drmmode_prop_ptr p = &drmmode_output->props[i]; 198424b90cf4Smrg 198524b90cf4Smrg for (j = 0; j < koutput->count_props; j++) { 198624b90cf4Smrg if (koutput->props[j] != p->mode_prop->prop_id) 198724b90cf4Smrg continue; 198824b90cf4Smrg 198924b90cf4Smrg /* Check to see if the property value has changed */ 199024b90cf4Smrg if (koutput->prop_values[j] == p->value) 199124b90cf4Smrg break; 199224b90cf4Smrg 199324b90cf4Smrg p->value = koutput->prop_values[j]; 199424b90cf4Smrg 199524b90cf4Smrg if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 199624b90cf4Smrg INT32 value = p->value; 199724b90cf4Smrg 199824b90cf4Smrg err = RRChangeOutputProperty(output->randr_output, 199924b90cf4Smrg p->atoms[0], XA_INTEGER, 200024b90cf4Smrg 32, PropModeReplace, 1, 200124b90cf4Smrg &value, FALSE, TRUE); 200224b90cf4Smrg if (err != 0) { 200324b90cf4Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 200424b90cf4Smrg "RRChangeOutputProperty error, %d\n", 200524b90cf4Smrg err); 200624b90cf4Smrg } 200724b90cf4Smrg } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 200824b90cf4Smrg for (k = 0; k < p->mode_prop->count_enums; k++) { 200924b90cf4Smrg if (p->mode_prop->enums[k].value == p->value) 201024b90cf4Smrg break; 201124b90cf4Smrg } 201224b90cf4Smrg if (k < p->mode_prop->count_enums) { 201324b90cf4Smrg err = RRChangeOutputProperty(output->randr_output, 201424b90cf4Smrg p->atoms[0], XA_ATOM, 201524b90cf4Smrg 32, PropModeReplace, 1, 201624b90cf4Smrg &p->atoms[k + 1], FALSE, 201724b90cf4Smrg TRUE); 201824b90cf4Smrg if (err != 0) { 201924b90cf4Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 202024b90cf4Smrg "RRChangeOutputProperty error, %d\n", 202124b90cf4Smrg err); 202224b90cf4Smrg } 202324b90cf4Smrg } 202424b90cf4Smrg } 202524b90cf4Smrg 202624b90cf4Smrg break; 202724b90cf4Smrg } 202824b90cf4Smrg } 202924b90cf4Smrg} 203024b90cf4Smrg 2031d6c0b56eSmrgstatic xf86OutputStatus drmmode_output_detect(xf86OutputPtr output) 2032d6c0b56eSmrg{ 2033d6c0b56eSmrg /* go to the hw and retrieve a new output struct */ 2034d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 2035d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 2036d6c0b56eSmrg xf86OutputStatus status; 2037d6c0b56eSmrg drmModeFreeConnector(drmmode_output->mode_output); 2038d6c0b56eSmrg 2039d6c0b56eSmrg drmmode_output->mode_output = 2040d6c0b56eSmrg drmModeGetConnector(pAMDGPUEnt->fd, drmmode_output->output_id); 204124b90cf4Smrg if (!drmmode_output->mode_output) { 204224b90cf4Smrg drmmode_output->output_id = -1; 2043d6c0b56eSmrg return XF86OutputStatusDisconnected; 204424b90cf4Smrg } 204524b90cf4Smrg 204624b90cf4Smrg drmmode_output_update_properties(output); 2047d6c0b56eSmrg 2048d6c0b56eSmrg switch (drmmode_output->mode_output->connection) { 2049d6c0b56eSmrg case DRM_MODE_CONNECTED: 2050d6c0b56eSmrg status = XF86OutputStatusConnected; 2051d6c0b56eSmrg break; 2052d6c0b56eSmrg case DRM_MODE_DISCONNECTED: 2053d6c0b56eSmrg status = XF86OutputStatusDisconnected; 2054d6c0b56eSmrg break; 2055d6c0b56eSmrg default: 2056d6c0b56eSmrg case DRM_MODE_UNKNOWNCONNECTION: 2057d6c0b56eSmrg status = XF86OutputStatusUnknown; 2058d6c0b56eSmrg break; 2059d6c0b56eSmrg } 2060d6c0b56eSmrg return status; 2061d6c0b56eSmrg} 2062d6c0b56eSmrg 2063d6c0b56eSmrgstatic Bool 2064d6c0b56eSmrgdrmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes) 2065d6c0b56eSmrg{ 2066d6c0b56eSmrg return MODE_OK; 2067d6c0b56eSmrg} 2068d6c0b56eSmrg 2069852bcc3bSmrgstatic void 2070852bcc3bSmrgdrmmode_output_attach_tile(xf86OutputPtr output) 2071852bcc3bSmrg{ 2072852bcc3bSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1, 17, 99, 901, 0) 2073852bcc3bSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 2074852bcc3bSmrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 2075852bcc3bSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 2076852bcc3bSmrg struct xf86CrtcTileInfo tile_info, *set = NULL; 2077852bcc3bSmrg int i; 2078852bcc3bSmrg 2079852bcc3bSmrg if (!koutput) { 2080852bcc3bSmrg xf86OutputSetTile(output, NULL); 2081852bcc3bSmrg return; 2082852bcc3bSmrg } 2083852bcc3bSmrg 2084852bcc3bSmrg /* look for a TILE property */ 2085852bcc3bSmrg for (i = 0; i < koutput->count_props; i++) { 2086852bcc3bSmrg drmModePropertyPtr props; 2087852bcc3bSmrg props = drmModeGetProperty(pAMDGPUEnt->fd, koutput->props[i]); 2088852bcc3bSmrg if (!props) 2089852bcc3bSmrg continue; 2090852bcc3bSmrg 2091852bcc3bSmrg if (!(props->flags & DRM_MODE_PROP_BLOB)) { 2092852bcc3bSmrg drmModeFreeProperty(props); 2093852bcc3bSmrg continue; 2094852bcc3bSmrg } 2095852bcc3bSmrg 2096852bcc3bSmrg if (!strcmp(props->name, "TILE")) { 2097852bcc3bSmrg drmModeFreePropertyBlob(drmmode_output->tile_blob); 2098852bcc3bSmrg drmmode_output->tile_blob = 2099852bcc3bSmrg drmModeGetPropertyBlob(pAMDGPUEnt->fd, 2100852bcc3bSmrg koutput->prop_values[i]); 2101852bcc3bSmrg } 2102852bcc3bSmrg drmModeFreeProperty(props); 2103852bcc3bSmrg } 2104852bcc3bSmrg if (drmmode_output->tile_blob) { 2105852bcc3bSmrg if (xf86OutputParseKMSTile(drmmode_output->tile_blob->data, 2106852bcc3bSmrg drmmode_output->tile_blob->length, 2107852bcc3bSmrg &tile_info) == TRUE) 2108852bcc3bSmrg set = &tile_info; 2109852bcc3bSmrg } 2110852bcc3bSmrg xf86OutputSetTile(output, set); 2111852bcc3bSmrg#endif 2112852bcc3bSmrg} 2113852bcc3bSmrg 211424b90cf4Smrgstatic int 211524b90cf4Smrgkoutput_get_prop_idx(int fd, drmModeConnectorPtr koutput, 211624b90cf4Smrg int type, const char *name) 211724b90cf4Smrg{ 211824b90cf4Smrg int idx = -1; 211924b90cf4Smrg 212024b90cf4Smrg for (int i = 0; i < koutput->count_props; i++) { 212124b90cf4Smrg drmModePropertyPtr prop = drmModeGetProperty(fd, koutput->props[i]); 212224b90cf4Smrg 212324b90cf4Smrg if (!prop) 212424b90cf4Smrg continue; 212524b90cf4Smrg 212624b90cf4Smrg if (drm_property_type_is(prop, type) && !strcmp(prop->name, name)) 212724b90cf4Smrg idx = i; 212824b90cf4Smrg 212924b90cf4Smrg drmModeFreeProperty(prop); 213024b90cf4Smrg 213124b90cf4Smrg if (idx > -1) 213224b90cf4Smrg break; 213324b90cf4Smrg } 213424b90cf4Smrg 213524b90cf4Smrg return idx; 213624b90cf4Smrg} 213724b90cf4Smrg 213824b90cf4Smrgstatic int 213924b90cf4Smrgkoutput_get_prop_id(int fd, drmModeConnectorPtr koutput, 214024b90cf4Smrg int type, const char *name) 214124b90cf4Smrg{ 214224b90cf4Smrg int idx = koutput_get_prop_idx(fd, koutput, type, name); 214324b90cf4Smrg 214424b90cf4Smrg return (idx > -1) ? koutput->props[idx] : -1; 214524b90cf4Smrg} 214624b90cf4Smrg 214724b90cf4Smrgstatic drmModePropertyBlobPtr 214824b90cf4Smrgkoutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name) 214924b90cf4Smrg{ 215024b90cf4Smrg drmModePropertyBlobPtr blob = NULL; 215124b90cf4Smrg int idx = koutput_get_prop_idx(fd, koutput, DRM_MODE_PROP_BLOB, name); 215224b90cf4Smrg 215324b90cf4Smrg if (idx > -1) 215424b90cf4Smrg blob = drmModeGetPropertyBlob(fd, koutput->prop_values[idx]); 215524b90cf4Smrg 215624b90cf4Smrg return blob; 215724b90cf4Smrg} 215824b90cf4Smrg 2159d6c0b56eSmrgstatic DisplayModePtr drmmode_output_get_modes(xf86OutputPtr output) 2160d6c0b56eSmrg{ 2161d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 2162d6c0b56eSmrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 2163d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 2164d6c0b56eSmrg int i; 2165d6c0b56eSmrg DisplayModePtr Modes = NULL, Mode; 2166d6c0b56eSmrg xf86MonPtr mon = NULL; 2167d6c0b56eSmrg 2168d6c0b56eSmrg if (!koutput) 2169d6c0b56eSmrg return NULL; 2170d6c0b56eSmrg 217124b90cf4Smrg drmModeFreePropertyBlob(drmmode_output->edid_blob); 217224b90cf4Smrg 2173d6c0b56eSmrg /* look for an EDID property */ 217424b90cf4Smrg drmmode_output->edid_blob = 217524b90cf4Smrg koutput_get_prop_blob(pAMDGPUEnt->fd, koutput, "EDID"); 2176d6c0b56eSmrg 2177d6c0b56eSmrg if (drmmode_output->edid_blob) { 2178d6c0b56eSmrg mon = xf86InterpretEDID(output->scrn->scrnIndex, 2179d6c0b56eSmrg drmmode_output->edid_blob->data); 2180d6c0b56eSmrg if (mon && drmmode_output->edid_blob->length > 128) 2181d6c0b56eSmrg mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; 2182d6c0b56eSmrg } 2183d6c0b56eSmrg xf86OutputSetEDID(output, mon); 2184d6c0b56eSmrg 2185852bcc3bSmrg drmmode_output_attach_tile(output); 2186852bcc3bSmrg 2187d6c0b56eSmrg /* modes should already be available */ 2188d6c0b56eSmrg for (i = 0; i < koutput->count_modes; i++) { 2189d6c0b56eSmrg Mode = xnfalloc(sizeof(DisplayModeRec)); 2190d6c0b56eSmrg 2191d6c0b56eSmrg drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], 2192d6c0b56eSmrg Mode); 2193d6c0b56eSmrg Modes = xf86ModesAdd(Modes, Mode); 2194d6c0b56eSmrg 2195d6c0b56eSmrg } 2196d6c0b56eSmrg return Modes; 2197d6c0b56eSmrg} 2198d6c0b56eSmrg 2199d6c0b56eSmrgstatic void drmmode_output_destroy(xf86OutputPtr output) 2200d6c0b56eSmrg{ 2201d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 2202d6c0b56eSmrg int i; 2203d6c0b56eSmrg 2204852bcc3bSmrg drmModeFreePropertyBlob(drmmode_output->edid_blob); 2205852bcc3bSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1, 17, 99, 901, 0) 2206852bcc3bSmrg drmModeFreePropertyBlob(drmmode_output->tile_blob); 2207852bcc3bSmrg#endif 2208852bcc3bSmrg 2209d6c0b56eSmrg for (i = 0; i < drmmode_output->num_props; i++) { 2210d6c0b56eSmrg drmModeFreeProperty(drmmode_output->props[i].mode_prop); 2211d6c0b56eSmrg free(drmmode_output->props[i].atoms); 2212d6c0b56eSmrg } 2213d6c0b56eSmrg for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) { 2214d6c0b56eSmrg drmModeFreeEncoder(drmmode_output->mode_encoders[i]); 2215d6c0b56eSmrg } 2216d6c0b56eSmrg free(drmmode_output->mode_encoders); 2217d6c0b56eSmrg free(drmmode_output->props); 2218d6c0b56eSmrg drmModeFreeConnector(drmmode_output->mode_output); 2219d6c0b56eSmrg free(drmmode_output); 2220d6c0b56eSmrg output->driver_private = NULL; 2221d6c0b56eSmrg} 2222d6c0b56eSmrg 2223d6c0b56eSmrgstatic void drmmode_output_dpms(xf86OutputPtr output, int mode) 2224d6c0b56eSmrg{ 2225d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 2226d6c0b56eSmrg xf86CrtcPtr crtc = output->crtc; 2227d6c0b56eSmrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 2228d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 2229d6c0b56eSmrg 2230d6c0b56eSmrg if (!koutput) 2231d6c0b56eSmrg return; 2232d6c0b56eSmrg 223324b90cf4Smrg if (mode != DPMSModeOn && crtc) 2234d6c0b56eSmrg drmmode_do_crtc_dpms(crtc, mode); 2235d6c0b56eSmrg 2236d6c0b56eSmrg drmModeConnectorSetProperty(pAMDGPUEnt->fd, koutput->connector_id, 2237d6c0b56eSmrg drmmode_output->dpms_enum_id, mode); 2238d6c0b56eSmrg 2239d6c0b56eSmrg if (mode == DPMSModeOn && crtc) { 2240d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 2241d6c0b56eSmrg 2242d6c0b56eSmrg if (drmmode_crtc->need_modeset) 2243d6c0b56eSmrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 2244d6c0b56eSmrg crtc->x, crtc->y); 2245d6c0b56eSmrg else 2246d6c0b56eSmrg drmmode_do_crtc_dpms(output->crtc, mode); 2247d6c0b56eSmrg } 2248d6c0b56eSmrg} 2249d6c0b56eSmrg 2250d6c0b56eSmrgstatic Bool drmmode_property_ignore(drmModePropertyPtr prop) 2251d6c0b56eSmrg{ 2252d6c0b56eSmrg if (!prop) 2253d6c0b56eSmrg return TRUE; 2254d6c0b56eSmrg /* ignore blob prop */ 2255d6c0b56eSmrg if (prop->flags & DRM_MODE_PROP_BLOB) 2256d6c0b56eSmrg return TRUE; 2257d6c0b56eSmrg /* ignore standard property */ 2258d6c0b56eSmrg if (!strcmp(prop->name, "EDID") || !strcmp(prop->name, "DPMS")) 2259d6c0b56eSmrg return TRUE; 2260d6c0b56eSmrg 2261d6c0b56eSmrg return FALSE; 2262d6c0b56eSmrg} 2263d6c0b56eSmrg 2264d6c0b56eSmrgstatic void drmmode_output_create_resources(xf86OutputPtr output) 2265d6c0b56eSmrg{ 226611bf0794Smrg AMDGPUInfoPtr info = AMDGPUPTR(output->scrn); 2267d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 226835d5b7c7Smrg drmmode_crtc_private_ptr drmmode_crtc; 2269d6c0b56eSmrg drmModeConnectorPtr mode_output = drmmode_output->mode_output; 2270d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 227111bf0794Smrg drmModePropertyPtr drmmode_prop, tearfree_prop; 2272d6c0b56eSmrg int i, j, err; 227335d5b7c7Smrg Atom name; 227435d5b7c7Smrg 227535d5b7c7Smrg /* Create CONNECTOR_ID property */ 227635d5b7c7Smrg name = MakeAtom("CONNECTOR_ID", 12, TRUE); 227735d5b7c7Smrg if (name != BAD_RESOURCE) { 227835d5b7c7Smrg INT32 value = mode_output->connector_id; 227935d5b7c7Smrg 228035d5b7c7Smrg err = RRConfigureOutputProperty(output->randr_output, name, 228135d5b7c7Smrg FALSE, FALSE, TRUE, 1, &value); 228235d5b7c7Smrg if (err != Success) { 228335d5b7c7Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 228435d5b7c7Smrg "RRConfigureOutputProperty error, %d\n", err); 228535d5b7c7Smrg } 228635d5b7c7Smrg 228735d5b7c7Smrg err = RRChangeOutputProperty(output->randr_output, name, 228835d5b7c7Smrg XA_INTEGER, 32, PropModeReplace, 1, 228935d5b7c7Smrg &value, FALSE, FALSE); 229035d5b7c7Smrg if (err != Success) { 229135d5b7c7Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 229235d5b7c7Smrg "RRChangeOutputProperty error, %d\n", err); 229335d5b7c7Smrg } 229435d5b7c7Smrg } 2295d6c0b56eSmrg 2296d6c0b56eSmrg drmmode_output->props = 229711bf0794Smrg calloc(mode_output->count_props + 1, sizeof(drmmode_prop_rec)); 2298d6c0b56eSmrg if (!drmmode_output->props) 2299d6c0b56eSmrg return; 2300d6c0b56eSmrg 2301d6c0b56eSmrg drmmode_output->num_props = 0; 2302d6c0b56eSmrg for (i = 0, j = 0; i < mode_output->count_props; i++) { 2303d6c0b56eSmrg drmmode_prop = 2304d6c0b56eSmrg drmModeGetProperty(pAMDGPUEnt->fd, mode_output->props[i]); 2305d6c0b56eSmrg if (drmmode_property_ignore(drmmode_prop)) { 2306d6c0b56eSmrg drmModeFreeProperty(drmmode_prop); 2307d6c0b56eSmrg continue; 2308d6c0b56eSmrg } 2309d6c0b56eSmrg drmmode_output->props[j].mode_prop = drmmode_prop; 2310d6c0b56eSmrg drmmode_output->props[j].value = mode_output->prop_values[i]; 2311d6c0b56eSmrg drmmode_output->num_props++; 2312d6c0b56eSmrg j++; 2313d6c0b56eSmrg } 2314d6c0b56eSmrg 231511bf0794Smrg /* Userspace-only property for TearFree */ 231611bf0794Smrg tearfree_prop = calloc(1, sizeof(*tearfree_prop)); 231711bf0794Smrg tearfree_prop->flags = DRM_MODE_PROP_ENUM; 231835d5b7c7Smrg strcpy(tearfree_prop->name, "TearFree"); 231911bf0794Smrg tearfree_prop->count_enums = 3; 232011bf0794Smrg tearfree_prop->enums = calloc(tearfree_prop->count_enums, 232111bf0794Smrg sizeof(*tearfree_prop->enums)); 232235d5b7c7Smrg strcpy(tearfree_prop->enums[0].name, "off"); 232335d5b7c7Smrg strcpy(tearfree_prop->enums[1].name, "on"); 232411bf0794Smrg tearfree_prop->enums[1].value = 1; 232535d5b7c7Smrg strcpy(tearfree_prop->enums[2].name, "auto"); 232611bf0794Smrg tearfree_prop->enums[2].value = 2; 232711bf0794Smrg drmmode_output->props[j].mode_prop = tearfree_prop; 232811bf0794Smrg drmmode_output->props[j].value = info->tear_free; 232911bf0794Smrg drmmode_output->tear_free = info->tear_free; 233011bf0794Smrg drmmode_output->num_props++; 233111bf0794Smrg 2332d6c0b56eSmrg for (i = 0; i < drmmode_output->num_props; i++) { 2333d6c0b56eSmrg drmmode_prop_ptr p = &drmmode_output->props[i]; 2334d6c0b56eSmrg drmmode_prop = p->mode_prop; 2335d6c0b56eSmrg 2336d6c0b56eSmrg if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { 2337d6c0b56eSmrg INT32 range[2]; 2338d6c0b56eSmrg INT32 value = p->value; 2339d6c0b56eSmrg 2340d6c0b56eSmrg p->num_atoms = 1; 2341d6c0b56eSmrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 2342d6c0b56eSmrg if (!p->atoms) 2343d6c0b56eSmrg continue; 2344d6c0b56eSmrg p->atoms[0] = 2345d6c0b56eSmrg MakeAtom(drmmode_prop->name, 2346d6c0b56eSmrg strlen(drmmode_prop->name), TRUE); 2347d6c0b56eSmrg range[0] = drmmode_prop->values[0]; 2348d6c0b56eSmrg range[1] = drmmode_prop->values[1]; 2349d6c0b56eSmrg err = 2350d6c0b56eSmrg RRConfigureOutputProperty(output->randr_output, 2351d6c0b56eSmrg p->atoms[0], FALSE, TRUE, 2352d6c0b56eSmrg drmmode_prop->flags & 2353d6c0b56eSmrg DRM_MODE_PROP_IMMUTABLE ? 2354d6c0b56eSmrg TRUE : FALSE, 2, range); 2355d6c0b56eSmrg if (err != 0) { 2356d6c0b56eSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2357d6c0b56eSmrg "RRConfigureOutputProperty error, %d\n", 2358d6c0b56eSmrg err); 2359d6c0b56eSmrg } 2360d6c0b56eSmrg err = 2361d6c0b56eSmrg RRChangeOutputProperty(output->randr_output, 2362d6c0b56eSmrg p->atoms[0], XA_INTEGER, 32, 2363d6c0b56eSmrg PropModeReplace, 1, &value, 2364d6c0b56eSmrg FALSE, TRUE); 2365d6c0b56eSmrg if (err != 0) { 2366d6c0b56eSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2367d6c0b56eSmrg "RRChangeOutputProperty error, %d\n", 2368d6c0b56eSmrg err); 2369d6c0b56eSmrg } 2370d6c0b56eSmrg } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { 2371d6c0b56eSmrg p->num_atoms = drmmode_prop->count_enums + 1; 2372d6c0b56eSmrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 2373d6c0b56eSmrg if (!p->atoms) 2374d6c0b56eSmrg continue; 2375d6c0b56eSmrg p->atoms[0] = 2376d6c0b56eSmrg MakeAtom(drmmode_prop->name, 2377d6c0b56eSmrg strlen(drmmode_prop->name), TRUE); 2378d6c0b56eSmrg for (j = 1; j <= drmmode_prop->count_enums; j++) { 2379d6c0b56eSmrg struct drm_mode_property_enum *e = 2380d6c0b56eSmrg &drmmode_prop->enums[j - 1]; 2381d6c0b56eSmrg p->atoms[j] = 2382d6c0b56eSmrg MakeAtom(e->name, strlen(e->name), TRUE); 2383d6c0b56eSmrg } 2384d6c0b56eSmrg err = 2385d6c0b56eSmrg RRConfigureOutputProperty(output->randr_output, 2386d6c0b56eSmrg p->atoms[0], FALSE, FALSE, 2387d6c0b56eSmrg drmmode_prop->flags & 2388d6c0b56eSmrg DRM_MODE_PROP_IMMUTABLE ? 2389d6c0b56eSmrg TRUE : FALSE, 2390d6c0b56eSmrg p->num_atoms - 1, 2391d6c0b56eSmrg (INT32 *) & p->atoms[1]); 2392d6c0b56eSmrg if (err != 0) { 2393d6c0b56eSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2394d6c0b56eSmrg "RRConfigureOutputProperty error, %d\n", 2395d6c0b56eSmrg err); 2396d6c0b56eSmrg } 2397d6c0b56eSmrg for (j = 0; j < drmmode_prop->count_enums; j++) 2398d6c0b56eSmrg if (drmmode_prop->enums[j].value == p->value) 2399d6c0b56eSmrg break; 2400d6c0b56eSmrg /* there's always a matching value */ 2401d6c0b56eSmrg err = 2402d6c0b56eSmrg RRChangeOutputProperty(output->randr_output, 2403d6c0b56eSmrg p->atoms[0], XA_ATOM, 32, 2404d6c0b56eSmrg PropModeReplace, 1, 2405d6c0b56eSmrg &p->atoms[j + 1], FALSE, 2406d6c0b56eSmrg TRUE); 2407d6c0b56eSmrg if (err != 0) { 2408d6c0b56eSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2409d6c0b56eSmrg "RRChangeOutputProperty error, %d\n", 2410d6c0b56eSmrg err); 2411d6c0b56eSmrg } 2412d6c0b56eSmrg } 2413d6c0b56eSmrg } 241435d5b7c7Smrg 241535d5b7c7Smrg /* Do not configure cm properties on output if there's no support. */ 241635d5b7c7Smrg if (!drmmode_cm_enabled(drmmode_output->drmmode)) 241735d5b7c7Smrg return; 241835d5b7c7Smrg 241935d5b7c7Smrg drmmode_crtc = output->crtc ? output->crtc->driver_private : NULL; 242035d5b7c7Smrg 242135d5b7c7Smrg for (i = 0; i < CM_NUM_PROPS; i++) 242235d5b7c7Smrg rr_configure_and_change_cm_property(output, drmmode_crtc, i); 242335d5b7c7Smrg} 242435d5b7c7Smrg 242535d5b7c7Smrgstatic void 242635d5b7c7Smrgdrmmode_output_set_tear_free(AMDGPUEntPtr pAMDGPUEnt, 242735d5b7c7Smrg drmmode_output_private_ptr drmmode_output, 242835d5b7c7Smrg xf86CrtcPtr crtc, int tear_free) 242935d5b7c7Smrg{ 243035d5b7c7Smrg if (drmmode_output->tear_free == tear_free) 243135d5b7c7Smrg return; 243235d5b7c7Smrg 243335d5b7c7Smrg drmmode_output->tear_free = tear_free; 243435d5b7c7Smrg 243535d5b7c7Smrg if (crtc) { 243635d5b7c7Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 243735d5b7c7Smrg crtc->x, crtc->y); 243835d5b7c7Smrg } 2439d6c0b56eSmrg} 2440d6c0b56eSmrg 2441d6c0b56eSmrgstatic Bool 2442d6c0b56eSmrgdrmmode_output_set_property(xf86OutputPtr output, Atom property, 2443d6c0b56eSmrg RRPropertyValuePtr value) 2444d6c0b56eSmrg{ 2445d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 2446d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 244735d5b7c7Smrg enum drmmode_cm_prop cm_prop_index; 2448d6c0b56eSmrg int i; 2449d6c0b56eSmrg 245035d5b7c7Smrg cm_prop_index = get_cm_enum_from_str(NameForAtom(property)); 245135d5b7c7Smrg if (cm_prop_index >= 0 && cm_prop_index < CM_DEGAMMA_LUT_SIZE) { 245235d5b7c7Smrg if (!output->crtc) 245335d5b7c7Smrg return FALSE; 245435d5b7c7Smrg if (drmmode_crtc_stage_cm_prop(output->crtc, cm_prop_index, 245535d5b7c7Smrg value)) 245635d5b7c7Smrg return FALSE; 245735d5b7c7Smrg if (drmmode_crtc_push_cm_prop(output->crtc, cm_prop_index)) 245835d5b7c7Smrg return FALSE; 245935d5b7c7Smrg return TRUE; 246035d5b7c7Smrg } 246135d5b7c7Smrg 2462d6c0b56eSmrg for (i = 0; i < drmmode_output->num_props; i++) { 2463d6c0b56eSmrg drmmode_prop_ptr p = &drmmode_output->props[i]; 2464d6c0b56eSmrg 2465d6c0b56eSmrg if (p->atoms[0] != property) 2466d6c0b56eSmrg continue; 2467d6c0b56eSmrg 2468d6c0b56eSmrg if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 2469d6c0b56eSmrg uint32_t val; 2470d6c0b56eSmrg 2471d6c0b56eSmrg if (value->type != XA_INTEGER || value->format != 32 || 2472d6c0b56eSmrg value->size != 1) 2473d6c0b56eSmrg return FALSE; 2474d6c0b56eSmrg val = *(uint32_t *) value->data; 2475d6c0b56eSmrg 2476d6c0b56eSmrg drmModeConnectorSetProperty(pAMDGPUEnt->fd, 2477d6c0b56eSmrg drmmode_output->output_id, 2478d6c0b56eSmrg p->mode_prop->prop_id, 2479d6c0b56eSmrg (uint64_t) val); 2480d6c0b56eSmrg return TRUE; 2481d6c0b56eSmrg } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 2482d6c0b56eSmrg Atom atom; 2483d6c0b56eSmrg const char *name; 2484d6c0b56eSmrg int j; 2485d6c0b56eSmrg 2486d6c0b56eSmrg if (value->type != XA_ATOM || value->format != 32 2487d6c0b56eSmrg || value->size != 1) 2488d6c0b56eSmrg return FALSE; 2489d6c0b56eSmrg memcpy(&atom, value->data, 4); 249024b90cf4Smrg if (!(name = NameForAtom(atom))) 249124b90cf4Smrg return FALSE; 2492d6c0b56eSmrg 2493d6c0b56eSmrg /* search for matching name string, then set its value down */ 2494d6c0b56eSmrg for (j = 0; j < p->mode_prop->count_enums; j++) { 2495d6c0b56eSmrg if (!strcmp(p->mode_prop->enums[j].name, name)) { 249611bf0794Smrg if (i == (drmmode_output->num_props - 1)) { 249735d5b7c7Smrg drmmode_output_set_tear_free(pAMDGPUEnt, 249835d5b7c7Smrg drmmode_output, 249935d5b7c7Smrg output->crtc, j); 250011bf0794Smrg } else { 250111bf0794Smrg drmModeConnectorSetProperty(pAMDGPUEnt->fd, 250211bf0794Smrg drmmode_output->output_id, 250311bf0794Smrg p->mode_prop->prop_id, 250411bf0794Smrg p->mode_prop->enums[j].value); 250511bf0794Smrg } 250611bf0794Smrg 2507d6c0b56eSmrg return TRUE; 2508d6c0b56eSmrg } 2509d6c0b56eSmrg } 2510d6c0b56eSmrg } 2511d6c0b56eSmrg } 2512d6c0b56eSmrg 2513d6c0b56eSmrg return TRUE; 2514d6c0b56eSmrg} 2515d6c0b56eSmrg 2516d6c0b56eSmrgstatic Bool drmmode_output_get_property(xf86OutputPtr output, Atom property) 2517d6c0b56eSmrg{ 251835d5b7c7Smrg drmmode_crtc_private_ptr drmmode_crtc; 251935d5b7c7Smrg enum drmmode_cm_prop cm_prop_id; 252035d5b7c7Smrg int ret; 252135d5b7c7Smrg 252235d5b7c7Smrg /* First, see if it's a cm property */ 252335d5b7c7Smrg cm_prop_id = get_cm_enum_from_str(NameForAtom(property)); 252435d5b7c7Smrg if (output->crtc && cm_prop_id != CM_INVALID_PROP) { 252535d5b7c7Smrg drmmode_crtc = output->crtc->driver_private; 252635d5b7c7Smrg 252735d5b7c7Smrg ret = rr_configure_and_change_cm_property(output, drmmode_crtc, 252835d5b7c7Smrg cm_prop_id); 252935d5b7c7Smrg if (ret) { 253035d5b7c7Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 253135d5b7c7Smrg "Error getting color property: %d\n", 253235d5b7c7Smrg ret); 253335d5b7c7Smrg return FALSE; 253435d5b7c7Smrg } 253535d5b7c7Smrg return TRUE; 253635d5b7c7Smrg } 253735d5b7c7Smrg 253835d5b7c7Smrg /* Otherwise, must be an output property. */ 2539d6c0b56eSmrg return TRUE; 2540d6c0b56eSmrg} 2541d6c0b56eSmrg 2542d6c0b56eSmrgstatic const xf86OutputFuncsRec drmmode_output_funcs = { 2543d6c0b56eSmrg .dpms = drmmode_output_dpms, 2544d6c0b56eSmrg .create_resources = drmmode_output_create_resources, 2545d6c0b56eSmrg .set_property = drmmode_output_set_property, 2546d6c0b56eSmrg .get_property = drmmode_output_get_property, 2547d6c0b56eSmrg .detect = drmmode_output_detect, 2548d6c0b56eSmrg .mode_valid = drmmode_output_mode_valid, 2549d6c0b56eSmrg 2550d6c0b56eSmrg .get_modes = drmmode_output_get_modes, 2551d6c0b56eSmrg .destroy = drmmode_output_destroy 2552d6c0b56eSmrg}; 2553d6c0b56eSmrg 2554d6c0b56eSmrgstatic int subpixel_conv_table[7] = { 0, SubPixelUnknown, 2555d6c0b56eSmrg SubPixelHorizontalRGB, 2556d6c0b56eSmrg SubPixelHorizontalBGR, 2557d6c0b56eSmrg SubPixelVerticalRGB, 2558d6c0b56eSmrg SubPixelVerticalBGR, 2559d6c0b56eSmrg SubPixelNone 2560d6c0b56eSmrg}; 2561d6c0b56eSmrg 2562d6c0b56eSmrgconst char *output_names[] = { "None", 2563d6c0b56eSmrg "VGA", 2564d6c0b56eSmrg "DVI-I", 2565d6c0b56eSmrg "DVI-D", 2566d6c0b56eSmrg "DVI-A", 2567d6c0b56eSmrg "Composite", 2568d6c0b56eSmrg "S-video", 2569d6c0b56eSmrg "LVDS", 2570d6c0b56eSmrg "CTV", 2571d6c0b56eSmrg "DIN", 2572d6c0b56eSmrg "DisplayPort", 2573d6c0b56eSmrg "HDMI-A", 2574d6c0b56eSmrg "HDMI-B", 2575d6c0b56eSmrg "TV", 2576d6c0b56eSmrg "eDP", 2577d6c0b56eSmrg "Virtual", 2578d6c0b56eSmrg "DSI", 2579d6c0b56eSmrg}; 2580d6c0b56eSmrg 2581d6c0b56eSmrg#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0])) 2582d6c0b56eSmrg 2583d6c0b56eSmrgstatic xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id) 2584d6c0b56eSmrg{ 2585d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 2586d6c0b56eSmrg int i; 2587d6c0b56eSmrg for (i = 0; i < xf86_config->num_output; i++) { 2588d6c0b56eSmrg xf86OutputPtr output = xf86_config->output[i]; 2589d6c0b56eSmrg drmmode_output_private_ptr drmmode_output; 2590d6c0b56eSmrg drmmode_output = output->driver_private; 2591d6c0b56eSmrg if (drmmode_output->output_id == id) 2592d6c0b56eSmrg return output; 2593d6c0b56eSmrg } 2594d6c0b56eSmrg return NULL; 2595d6c0b56eSmrg} 2596d6c0b56eSmrg 2597d6c0b56eSmrgstatic int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path) 2598d6c0b56eSmrg{ 2599d6c0b56eSmrg char *conn; 2600d6c0b56eSmrg char conn_id[5]; 2601d6c0b56eSmrg int id, len; 2602d6c0b56eSmrg char *blob_data; 2603d6c0b56eSmrg 2604d6c0b56eSmrg if (!path_blob) 2605d6c0b56eSmrg return -1; 2606d6c0b56eSmrg 2607d6c0b56eSmrg blob_data = path_blob->data; 2608d6c0b56eSmrg /* we only handle MST paths for now */ 2609d6c0b56eSmrg if (strncmp(blob_data, "mst:", 4)) 2610d6c0b56eSmrg return -1; 2611d6c0b56eSmrg 2612d6c0b56eSmrg conn = strchr(blob_data + 4, '-'); 2613d6c0b56eSmrg if (!conn) 2614d6c0b56eSmrg return -1; 2615d6c0b56eSmrg len = conn - (blob_data + 4); 2616d6c0b56eSmrg if (len + 1 > 5) 2617d6c0b56eSmrg return -1; 2618d6c0b56eSmrg memcpy(conn_id, blob_data + 4, len); 2619d6c0b56eSmrg conn_id[len] = '\0'; 2620d6c0b56eSmrg id = strtoul(conn_id, NULL, 10); 2621d6c0b56eSmrg 2622d6c0b56eSmrg *conn_base_id = id; 2623d6c0b56eSmrg 2624d6c0b56eSmrg *path = conn + 1; 2625d6c0b56eSmrg return 0; 2626d6c0b56eSmrg} 2627d6c0b56eSmrg 2628d6c0b56eSmrgstatic void 2629d6c0b56eSmrgdrmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name, 2630d6c0b56eSmrg drmModePropertyBlobPtr path_blob, int *num_dvi, int *num_hdmi) 2631d6c0b56eSmrg{ 2632d6c0b56eSmrg xf86OutputPtr output; 2633d6c0b56eSmrg int conn_id; 2634d6c0b56eSmrg char *extra_path; 2635d6c0b56eSmrg 2636d6c0b56eSmrg output = NULL; 2637d6c0b56eSmrg if (parse_path_blob(path_blob, &conn_id, &extra_path) == 0) 2638d6c0b56eSmrg output = find_output(pScrn, conn_id); 2639d6c0b56eSmrg if (output) { 2640d6c0b56eSmrg snprintf(name, 32, "%s-%s", output->name, extra_path); 2641d6c0b56eSmrg } else { 264224b90cf4Smrg if (koutput->connector_type >= NUM_OUTPUT_NAMES) { 2643d6c0b56eSmrg snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, koutput->connector_type_id - 1); 264424b90cf4Smrg } else if (pScrn->is_gpu) { 2645d6c0b56eSmrg snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type], 2646d6c0b56eSmrg pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id - 1); 264724b90cf4Smrg } else { 2648d6c0b56eSmrg /* need to do smart conversion here for compat with non-kms ATI driver */ 2649d6c0b56eSmrg if (koutput->connector_type_id == 1) { 2650d6c0b56eSmrg switch(koutput->connector_type) { 2651d6c0b56eSmrg case DRM_MODE_CONNECTOR_DVII: 2652d6c0b56eSmrg case DRM_MODE_CONNECTOR_DVID: 2653d6c0b56eSmrg case DRM_MODE_CONNECTOR_DVIA: 2654d6c0b56eSmrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi); 2655d6c0b56eSmrg (*num_dvi)++; 2656d6c0b56eSmrg break; 2657d6c0b56eSmrg case DRM_MODE_CONNECTOR_HDMIA: 2658d6c0b56eSmrg case DRM_MODE_CONNECTOR_HDMIB: 2659d6c0b56eSmrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi); 2660d6c0b56eSmrg (*num_hdmi)++; 2661d6c0b56eSmrg break; 2662d6c0b56eSmrg case DRM_MODE_CONNECTOR_VGA: 2663d6c0b56eSmrg case DRM_MODE_CONNECTOR_DisplayPort: 2664d6c0b56eSmrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); 2665d6c0b56eSmrg break; 2666d6c0b56eSmrg default: 2667d6c0b56eSmrg snprintf(name, 32, "%s", output_names[koutput->connector_type]); 2668d6c0b56eSmrg break; 2669d6c0b56eSmrg } 2670d6c0b56eSmrg } else { 2671d6c0b56eSmrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); 2672d6c0b56eSmrg } 2673d6c0b56eSmrg } 2674d6c0b56eSmrg } 2675d6c0b56eSmrg} 2676d6c0b56eSmrg 2677d6c0b56eSmrg 2678d6c0b56eSmrgstatic unsigned int 2679d6c0b56eSmrgdrmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int *num_dvi, int *num_hdmi, int dynamic) 2680d6c0b56eSmrg{ 2681d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 2682d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 2683d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 2684d6c0b56eSmrg xf86OutputPtr output; 2685d6c0b56eSmrg drmModeConnectorPtr koutput; 2686d6c0b56eSmrg drmModeEncoderPtr *kencoders = NULL; 2687d6c0b56eSmrg drmmode_output_private_ptr drmmode_output; 2688d6c0b56eSmrg drmModePropertyBlobPtr path_blob = NULL; 268935d5b7c7Smrg#if XF86_CRTC_VERSION >= 8 269035d5b7c7Smrg Bool nonDesktop = FALSE; 269135d5b7c7Smrg#endif 2692d6c0b56eSmrg char name[32]; 2693d6c0b56eSmrg int i; 2694d6c0b56eSmrg const char *s; 2695d6c0b56eSmrg 2696d6c0b56eSmrg koutput = 2697d6c0b56eSmrg drmModeGetConnector(pAMDGPUEnt->fd, 2698d6c0b56eSmrg mode_res->connectors[num]); 2699d6c0b56eSmrg if (!koutput) 2700d6c0b56eSmrg return 0; 2701d6c0b56eSmrg 270224b90cf4Smrg path_blob = koutput_get_prop_blob(pAMDGPUEnt->fd, koutput, "PATH"); 2703d6c0b56eSmrg 270435d5b7c7Smrg#if XF86_CRTC_VERSION >= 8 270535d5b7c7Smrg i = koutput_get_prop_idx(pAMDGPUEnt->fd, koutput, DRM_MODE_PROP_RANGE, 270635d5b7c7Smrg "non-desktop"); 270735d5b7c7Smrg if (i >= 0) 270835d5b7c7Smrg nonDesktop = koutput->prop_values[i] != 0; 270935d5b7c7Smrg#endif 271035d5b7c7Smrg 2711d6c0b56eSmrg kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders); 2712d6c0b56eSmrg if (!kencoders) { 2713d6c0b56eSmrg goto out_free_encoders; 2714d6c0b56eSmrg } 2715d6c0b56eSmrg 2716d6c0b56eSmrg for (i = 0; i < koutput->count_encoders; i++) { 2717d6c0b56eSmrg kencoders[i] = 2718d6c0b56eSmrg drmModeGetEncoder(pAMDGPUEnt->fd, koutput->encoders[i]); 2719d6c0b56eSmrg if (!kencoders[i]) { 2720d6c0b56eSmrg goto out_free_encoders; 2721d6c0b56eSmrg } 2722d6c0b56eSmrg } 2723d6c0b56eSmrg 2724d6c0b56eSmrg drmmode_create_name(pScrn, koutput, name, path_blob, num_dvi, num_hdmi); 2725d6c0b56eSmrg if (path_blob) { 2726d6c0b56eSmrg drmModeFreePropertyBlob(path_blob); 2727d6c0b56eSmrg } 2728d6c0b56eSmrg 2729d6c0b56eSmrg if (path_blob && dynamic) { 2730d6c0b56eSmrg /* See if we have an output with this name already 2731d6c0b56eSmrg * and hook stuff up. 2732d6c0b56eSmrg */ 2733d6c0b56eSmrg for (i = 0; i < xf86_config->num_output; i++) { 2734d6c0b56eSmrg output = xf86_config->output[i]; 2735d6c0b56eSmrg 2736d6c0b56eSmrg if (strncmp(output->name, name, 32)) 2737d6c0b56eSmrg continue; 2738d6c0b56eSmrg 2739d6c0b56eSmrg drmmode_output = output->driver_private; 2740d6c0b56eSmrg drmmode_output->output_id = mode_res->connectors[num]; 2741d6c0b56eSmrg drmmode_output->mode_output = koutput; 274235d5b7c7Smrg#if XF86_CRTC_VERSION >= 8 274335d5b7c7Smrg output->non_desktop = nonDesktop; 274435d5b7c7Smrg#endif 2745d6c0b56eSmrg for (i = 0; i < koutput->count_encoders; i++) { 2746d6c0b56eSmrg drmModeFreeEncoder(kencoders[i]); 2747d6c0b56eSmrg } 2748d6c0b56eSmrg free(kencoders); 2749d6c0b56eSmrg return 1; 2750d6c0b56eSmrg } 2751d6c0b56eSmrg } 2752d6c0b56eSmrg 2753d6c0b56eSmrg if (xf86IsEntityShared(pScrn->entityList[0])) { 2754d6c0b56eSmrg if ((s = 2755d6c0b56eSmrg xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) { 2756d6c0b56eSmrg if (!AMDGPUZaphodStringMatches(pScrn, s, name)) 2757d6c0b56eSmrg goto out_free_encoders; 2758d6c0b56eSmrg } else { 275990f2b693Smrg if (info->instance_id != num) 2760d6c0b56eSmrg goto out_free_encoders; 2761d6c0b56eSmrg } 2762d6c0b56eSmrg } 2763d6c0b56eSmrg 2764d6c0b56eSmrg output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name); 2765d6c0b56eSmrg if (!output) { 2766d6c0b56eSmrg goto out_free_encoders; 2767d6c0b56eSmrg } 2768d6c0b56eSmrg 2769d6c0b56eSmrg drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1); 2770d6c0b56eSmrg if (!drmmode_output) { 2771d6c0b56eSmrg xf86OutputDestroy(output); 2772d6c0b56eSmrg goto out_free_encoders; 2773d6c0b56eSmrg } 2774d6c0b56eSmrg 2775d6c0b56eSmrg drmmode_output->output_id = mode_res->connectors[num]; 2776d6c0b56eSmrg drmmode_output->mode_output = koutput; 2777d6c0b56eSmrg drmmode_output->mode_encoders = kencoders; 2778d6c0b56eSmrg drmmode_output->drmmode = drmmode; 2779d6c0b56eSmrg output->mm_width = koutput->mmWidth; 2780d6c0b56eSmrg output->mm_height = koutput->mmHeight; 2781d6c0b56eSmrg 2782d6c0b56eSmrg output->subpixel_order = subpixel_conv_table[koutput->subpixel]; 2783d6c0b56eSmrg output->interlaceAllowed = TRUE; 2784d6c0b56eSmrg output->doubleScanAllowed = TRUE; 2785d6c0b56eSmrg output->driver_private = drmmode_output; 278635d5b7c7Smrg#if XF86_CRTC_VERSION >= 8 278735d5b7c7Smrg output->non_desktop = nonDesktop; 278835d5b7c7Smrg#endif 2789d6c0b56eSmrg 2790d6c0b56eSmrg output->possible_crtcs = 0xffffffff; 2791d6c0b56eSmrg for (i = 0; i < koutput->count_encoders; i++) { 2792d6c0b56eSmrg output->possible_crtcs &= kencoders[i]->possible_crtcs; 2793d6c0b56eSmrg } 2794d6c0b56eSmrg /* work out the possible clones later */ 2795d6c0b56eSmrg output->possible_clones = 0; 2796d6c0b56eSmrg 279724b90cf4Smrg drmmode_output->dpms_enum_id = 279824b90cf4Smrg koutput_get_prop_id(pAMDGPUEnt->fd, koutput, DRM_MODE_PROP_ENUM, 279924b90cf4Smrg "DPMS"); 2800d6c0b56eSmrg 2801d6c0b56eSmrg if (dynamic) { 2802d6c0b56eSmrg output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output); 2803d6c0b56eSmrg drmmode_output_create_resources(output); 2804d6c0b56eSmrg } 2805d6c0b56eSmrg 2806d6c0b56eSmrg return 1; 2807d6c0b56eSmrgout_free_encoders: 2808d6c0b56eSmrg if (kencoders) { 2809d6c0b56eSmrg for (i = 0; i < koutput->count_encoders; i++) 2810d6c0b56eSmrg drmModeFreeEncoder(kencoders[i]); 2811d6c0b56eSmrg free(kencoders); 2812d6c0b56eSmrg } 2813d6c0b56eSmrg drmModeFreeConnector(koutput); 2814d6c0b56eSmrg return 0; 2815d6c0b56eSmrg} 2816d6c0b56eSmrg 2817d6c0b56eSmrguint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output) 2818d6c0b56eSmrg{ 2819d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = 2820d6c0b56eSmrg output->driver_private, clone_drmout; 2821d6c0b56eSmrg int i; 2822d6c0b56eSmrg xf86OutputPtr clone_output; 2823d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2824d6c0b56eSmrg int index_mask = 0; 2825d6c0b56eSmrg 2826d6c0b56eSmrg if (drmmode_output->enc_clone_mask == 0) 2827d6c0b56eSmrg return index_mask; 2828d6c0b56eSmrg 2829d6c0b56eSmrg for (i = 0; i < xf86_config->num_output; i++) { 2830d6c0b56eSmrg clone_output = xf86_config->output[i]; 2831d6c0b56eSmrg clone_drmout = clone_output->driver_private; 2832d6c0b56eSmrg if (output == clone_output) 2833d6c0b56eSmrg continue; 2834d6c0b56eSmrg 2835d6c0b56eSmrg if (clone_drmout->enc_mask == 0) 2836d6c0b56eSmrg continue; 2837d6c0b56eSmrg if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask) 2838d6c0b56eSmrg index_mask |= (1 << i); 2839d6c0b56eSmrg } 2840d6c0b56eSmrg return index_mask; 2841d6c0b56eSmrg} 2842d6c0b56eSmrg 2843d6c0b56eSmrgstatic void drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res) 2844d6c0b56eSmrg{ 2845d6c0b56eSmrg int i, j; 2846d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2847d6c0b56eSmrg 2848d6c0b56eSmrg for (i = 0; i < xf86_config->num_output; i++) { 2849d6c0b56eSmrg xf86OutputPtr output = xf86_config->output[i]; 2850d6c0b56eSmrg drmmode_output_private_ptr drmmode_output; 2851d6c0b56eSmrg 2852d6c0b56eSmrg drmmode_output = output->driver_private; 2853d6c0b56eSmrg drmmode_output->enc_clone_mask = 0xff; 2854d6c0b56eSmrg /* and all the possible encoder clones for this output together */ 2855d6c0b56eSmrg for (j = 0; j < drmmode_output->mode_output->count_encoders; 2856d6c0b56eSmrg j++) { 2857d6c0b56eSmrg int k; 2858d6c0b56eSmrg for (k = 0; k < mode_res->count_encoders; k++) { 2859d6c0b56eSmrg if (mode_res->encoders[k] == 2860d6c0b56eSmrg drmmode_output-> 2861d6c0b56eSmrg mode_encoders[j]->encoder_id) 2862d6c0b56eSmrg drmmode_output->enc_mask |= (1 << k); 2863d6c0b56eSmrg } 2864d6c0b56eSmrg 2865d6c0b56eSmrg drmmode_output->enc_clone_mask &= 2866d6c0b56eSmrg drmmode_output->mode_encoders[j]->possible_clones; 2867d6c0b56eSmrg } 2868d6c0b56eSmrg } 2869d6c0b56eSmrg 2870d6c0b56eSmrg for (i = 0; i < xf86_config->num_output; i++) { 2871d6c0b56eSmrg xf86OutputPtr output = xf86_config->output[i]; 2872d6c0b56eSmrg output->possible_clones = find_clones(scrn, output); 2873d6c0b56eSmrg } 2874d6c0b56eSmrg} 2875d6c0b56eSmrg 2876d6c0b56eSmrg/* returns pitch alignment in pixels */ 2877d6c0b56eSmrgint drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe) 2878d6c0b56eSmrg{ 2879d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 2880d6c0b56eSmrg 2881d6c0b56eSmrg if (info->have_tiling_info) 2882d6c0b56eSmrg /* linear aligned requirements */ 2883d6c0b56eSmrg return MAX(64, info->group_bytes / bpe); 2884d6c0b56eSmrg else 2885d6c0b56eSmrg /* default to 512 elements if we don't know the real 2886d6c0b56eSmrg * group size otherwise the kernel may reject the CS 2887d6c0b56eSmrg * if the group sizes don't match as the pitch won't 2888d6c0b56eSmrg * be aligned properly. 2889d6c0b56eSmrg */ 2890d6c0b56eSmrg return 512; 2891d6c0b56eSmrg} 2892d6c0b56eSmrg 2893d6c0b56eSmrgstatic Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height) 2894d6c0b56eSmrg{ 2895d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2896d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 2897d6c0b56eSmrg struct amdgpu_buffer *old_front = NULL; 2898d6c0b56eSmrg ScreenPtr screen = xf86ScrnToScreen(scrn); 2899d6c0b56eSmrg int i, pitch, old_width, old_height, old_pitch; 2900d6c0b56eSmrg int cpp = info->pixel_bytes; 2901d6c0b56eSmrg PixmapPtr ppix = screen->GetScreenPixmap(screen); 290246845023Smrg int hint = AMDGPU_CREATE_PIXMAP_SCANOUT; 2903d6c0b56eSmrg void *fb_shadow; 2904d6c0b56eSmrg 2905d6c0b56eSmrg if (scrn->virtualX == width && scrn->virtualY == height) 2906d6c0b56eSmrg return TRUE; 2907d6c0b56eSmrg 290835d5b7c7Smrg if (width > xf86_config->maxWidth || height > xf86_config->maxHeight) { 290935d5b7c7Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 291035d5b7c7Smrg "Xorg tried resizing screen to %dx%d, but maximum " 291135d5b7c7Smrg "supported is %dx%d\n", width, height, 291235d5b7c7Smrg xf86_config->maxWidth, xf86_config->maxHeight); 291335d5b7c7Smrg return FALSE; 291435d5b7c7Smrg } 291535d5b7c7Smrg 2916d6c0b56eSmrg if (info->shadow_primary) 291746845023Smrg hint |= AMDGPU_CREATE_PIXMAP_LINEAR | AMDGPU_CREATE_PIXMAP_GTT; 2918d6c0b56eSmrg else if (!info->use_glamor) 291946845023Smrg hint |= AMDGPU_CREATE_PIXMAP_LINEAR; 2920d6c0b56eSmrg 2921d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_INFO, 2922d6c0b56eSmrg "Allocate new frame buffer %dx%d\n", width, height); 2923d6c0b56eSmrg 2924d6c0b56eSmrg old_width = scrn->virtualX; 2925d6c0b56eSmrg old_height = scrn->virtualY; 2926d6c0b56eSmrg old_pitch = scrn->displayWidth; 2927d6c0b56eSmrg old_front = info->front_buffer; 2928d6c0b56eSmrg 2929d6c0b56eSmrg scrn->virtualX = width; 2930d6c0b56eSmrg scrn->virtualY = height; 2931d6c0b56eSmrg 2932d6c0b56eSmrg info->front_buffer = 2933d6c0b56eSmrg amdgpu_alloc_pixmap_bo(scrn, scrn->virtualX, scrn->virtualY, 2934d6c0b56eSmrg scrn->depth, hint, scrn->bitsPerPixel, 2935d6c0b56eSmrg &pitch); 2936d6c0b56eSmrg if (!info->front_buffer) { 2937d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 2938d6c0b56eSmrg "Failed to allocate front buffer memory\n"); 2939d6c0b56eSmrg goto fail; 2940d6c0b56eSmrg } 2941d6c0b56eSmrg 2942d6c0b56eSmrg if (!info->use_glamor && amdgpu_bo_map(scrn, info->front_buffer) != 0) { 2943d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 2944d6c0b56eSmrg "Failed to map front buffer memory\n"); 2945d6c0b56eSmrg goto fail; 2946d6c0b56eSmrg } 2947d6c0b56eSmrg 2948d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_INFO, " => pitch %d bytes\n", pitch); 2949d6c0b56eSmrg scrn->displayWidth = pitch / cpp; 2950d6c0b56eSmrg 2951d6c0b56eSmrg if (info->use_glamor || 2952d6c0b56eSmrg (info->front_buffer->flags & AMDGPU_BO_FLAGS_GBM)) { 2953d6c0b56eSmrg screen->ModifyPixmapHeader(ppix, 2954d6c0b56eSmrg width, height, -1, -1, pitch, info->front_buffer->cpu_ptr); 2955d6c0b56eSmrg } else { 2956d6c0b56eSmrg fb_shadow = calloc(1, pitch * scrn->virtualY); 295735d5b7c7Smrg if (!fb_shadow) 2958d6c0b56eSmrg goto fail; 2959d6c0b56eSmrg free(info->fb_shadow); 2960d6c0b56eSmrg info->fb_shadow = fb_shadow; 2961d6c0b56eSmrg screen->ModifyPixmapHeader(ppix, 2962d6c0b56eSmrg width, height, -1, -1, pitch, 2963d6c0b56eSmrg info->fb_shadow); 2964d6c0b56eSmrg } 2965d6c0b56eSmrg 2966504d986fSmrg if (!amdgpu_glamor_create_screen_resources(scrn->pScreen)) 2967504d986fSmrg goto fail; 2968504d986fSmrg 296990f2b693Smrg if (info->use_glamor || info->dri2.enabled) { 2970504d986fSmrg if (!amdgpu_set_pixmap_bo(ppix, info->front_buffer)) 2971504d986fSmrg goto fail; 2972504d986fSmrg } 2973d6c0b56eSmrg 297424b90cf4Smrg amdgpu_pixmap_clear(ppix); 2975d6c0b56eSmrg amdgpu_glamor_finish(scrn); 2976d6c0b56eSmrg 2977d6c0b56eSmrg for (i = 0; i < xf86_config->num_crtc; i++) { 2978d6c0b56eSmrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 2979d6c0b56eSmrg 2980d6c0b56eSmrg if (!crtc->enabled) 2981d6c0b56eSmrg continue; 2982d6c0b56eSmrg 2983d6c0b56eSmrg drmmode_set_mode_major(crtc, &crtc->mode, 2984d6c0b56eSmrg crtc->rotation, crtc->x, crtc->y); 2985d6c0b56eSmrg } 2986d6c0b56eSmrg 2987d6c0b56eSmrg if (old_front) { 2988d6c0b56eSmrg amdgpu_bo_unref(&old_front); 2989d6c0b56eSmrg } 2990d6c0b56eSmrg 2991d6c0b56eSmrg return TRUE; 2992d6c0b56eSmrg 2993d6c0b56eSmrgfail: 2994d6c0b56eSmrg if (info->front_buffer) { 2995d6c0b56eSmrg amdgpu_bo_unref(&info->front_buffer); 2996d6c0b56eSmrg } 2997d6c0b56eSmrg info->front_buffer = old_front; 2998d6c0b56eSmrg scrn->virtualX = old_width; 2999d6c0b56eSmrg scrn->virtualY = old_height; 3000d6c0b56eSmrg scrn->displayWidth = old_pitch; 3001d6c0b56eSmrg 3002d6c0b56eSmrg return FALSE; 3003d6c0b56eSmrg} 3004d6c0b56eSmrg 300535d5b7c7Smrgstatic void 300635d5b7c7Smrgdrmmode_validate_leases(ScrnInfoPtr scrn) 300735d5b7c7Smrg{ 300835d5b7c7Smrg#ifdef XF86_LEASE_VERSION 300935d5b7c7Smrg ScreenPtr screen = scrn->pScreen; 301035d5b7c7Smrg rrScrPrivPtr scr_priv = rrGetScrPriv(screen); 301135d5b7c7Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 301235d5b7c7Smrg drmModeLesseeListPtr lessees; 301335d5b7c7Smrg RRLeasePtr lease, next; 301435d5b7c7Smrg int l; 301535d5b7c7Smrg 301635d5b7c7Smrg /* We can't talk to the kernel about leases when VT switched */ 301735d5b7c7Smrg if (!scrn->vtSema) 301835d5b7c7Smrg return; 301935d5b7c7Smrg 302035d5b7c7Smrg lessees = drmModeListLessees(pAMDGPUEnt->fd); 302135d5b7c7Smrg if (!lessees) 302235d5b7c7Smrg return; 302335d5b7c7Smrg 302435d5b7c7Smrg xorg_list_for_each_entry_safe(lease, next, &scr_priv->leases, list) { 302535d5b7c7Smrg drmmode_lease_private_ptr lease_private = lease->devPrivate; 302635d5b7c7Smrg 302735d5b7c7Smrg for (l = 0; l < lessees->count; l++) { 302835d5b7c7Smrg if (lessees->lessees[l] == lease_private->lessee_id) 302935d5b7c7Smrg break; 303035d5b7c7Smrg } 303135d5b7c7Smrg 303235d5b7c7Smrg /* check to see if the lease has gone away */ 303335d5b7c7Smrg if (l == lessees->count) { 303435d5b7c7Smrg free(lease_private); 303535d5b7c7Smrg lease->devPrivate = NULL; 303635d5b7c7Smrg xf86CrtcLeaseTerminated(lease); 303735d5b7c7Smrg } 303835d5b7c7Smrg } 303935d5b7c7Smrg 304035d5b7c7Smrg free(lessees); 304135d5b7c7Smrg#endif 304235d5b7c7Smrg} 304335d5b7c7Smrg 304435d5b7c7Smrg#ifdef XF86_LEASE_VERSION 304535d5b7c7Smrg 304635d5b7c7Smrgstatic int 304735d5b7c7Smrgdrmmode_create_lease(RRLeasePtr lease, int *fd) 304835d5b7c7Smrg{ 304935d5b7c7Smrg ScreenPtr screen = lease->screen; 305035d5b7c7Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 305135d5b7c7Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 305235d5b7c7Smrg drmmode_lease_private_ptr lease_private; 305335d5b7c7Smrg int noutput = lease->numOutputs; 305435d5b7c7Smrg int ncrtc = lease->numCrtcs; 305535d5b7c7Smrg uint32_t *objects; 305635d5b7c7Smrg size_t nobjects; 305735d5b7c7Smrg int lease_fd; 305835d5b7c7Smrg int c, o; 305935d5b7c7Smrg int i; 306035d5b7c7Smrg 306135d5b7c7Smrg nobjects = ncrtc + noutput; 306235d5b7c7Smrg if (nobjects == 0 || nobjects > (SIZE_MAX / 4) || 306335d5b7c7Smrg ncrtc > (SIZE_MAX - noutput)) 306435d5b7c7Smrg return BadValue; 306535d5b7c7Smrg 306635d5b7c7Smrg lease_private = calloc(1, sizeof (drmmode_lease_private_rec)); 306735d5b7c7Smrg if (!lease_private) 306835d5b7c7Smrg return BadAlloc; 306935d5b7c7Smrg 307035d5b7c7Smrg objects = malloc(nobjects * 4); 307135d5b7c7Smrg if (!objects) { 307235d5b7c7Smrg free(lease_private); 307335d5b7c7Smrg return BadAlloc; 307435d5b7c7Smrg } 307535d5b7c7Smrg 307635d5b7c7Smrg i = 0; 307735d5b7c7Smrg 307835d5b7c7Smrg /* Add CRTC ids */ 307935d5b7c7Smrg for (c = 0; c < ncrtc; c++) { 308035d5b7c7Smrg xf86CrtcPtr crtc = lease->crtcs[c]->devPrivate; 308135d5b7c7Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 308235d5b7c7Smrg 308335d5b7c7Smrg objects[i++] = drmmode_crtc->mode_crtc->crtc_id; 308435d5b7c7Smrg } 308535d5b7c7Smrg 308635d5b7c7Smrg /* Add connector ids */ 308735d5b7c7Smrg for (o = 0; o < noutput; o++) { 308835d5b7c7Smrg xf86OutputPtr output = lease->outputs[o]->devPrivate; 308935d5b7c7Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 309035d5b7c7Smrg 309135d5b7c7Smrg objects[i++] = drmmode_output->mode_output->connector_id; 309235d5b7c7Smrg } 309335d5b7c7Smrg 309435d5b7c7Smrg /* call kernel to create lease */ 309535d5b7c7Smrg assert (i == nobjects); 309635d5b7c7Smrg 309735d5b7c7Smrg lease_fd = drmModeCreateLease(pAMDGPUEnt->fd, objects, nobjects, 0, 309835d5b7c7Smrg &lease_private->lessee_id); 309935d5b7c7Smrg 310035d5b7c7Smrg free(objects); 310135d5b7c7Smrg 310235d5b7c7Smrg if (lease_fd < 0) { 310335d5b7c7Smrg free(lease_private); 310435d5b7c7Smrg return BadMatch; 310535d5b7c7Smrg } 310635d5b7c7Smrg 310735d5b7c7Smrg lease->devPrivate = lease_private; 310835d5b7c7Smrg 310935d5b7c7Smrg xf86CrtcLeaseStarted(lease); 311035d5b7c7Smrg 311135d5b7c7Smrg *fd = lease_fd; 311235d5b7c7Smrg return Success; 311335d5b7c7Smrg} 311435d5b7c7Smrg 311535d5b7c7Smrgstatic void 311635d5b7c7Smrgdrmmode_terminate_lease(RRLeasePtr lease) 311735d5b7c7Smrg{ 311835d5b7c7Smrg drmmode_lease_private_ptr lease_private = lease->devPrivate; 311935d5b7c7Smrg ScreenPtr screen = lease->screen; 312035d5b7c7Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 312135d5b7c7Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 312235d5b7c7Smrg 312335d5b7c7Smrg if (drmModeRevokeLease(pAMDGPUEnt->fd, lease_private->lessee_id) == 0) { 312435d5b7c7Smrg free(lease_private); 312535d5b7c7Smrg lease->devPrivate = NULL; 312635d5b7c7Smrg xf86CrtcLeaseTerminated(lease); 312735d5b7c7Smrg } 312835d5b7c7Smrg} 312935d5b7c7Smrg 313035d5b7c7Smrg#endif // XF86_LEASE_VERSION 313135d5b7c7Smrg 3132d6c0b56eSmrgstatic const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { 313335d5b7c7Smrg .resize = drmmode_xf86crtc_resize, 313435d5b7c7Smrg#ifdef XF86_LEASE_VERSION 313535d5b7c7Smrg .create_lease = drmmode_create_lease, 313635d5b7c7Smrg .terminate_lease = drmmode_terminate_lease 313735d5b7c7Smrg#endif 3138d6c0b56eSmrg}; 3139d6c0b56eSmrg 3140d6c0b56eSmrgstatic void 3141d6c0b56eSmrgdrmmode_flip_abort(xf86CrtcPtr crtc, void *event_data) 3142d6c0b56eSmrg{ 314324b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 314424b90cf4Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 3145d6c0b56eSmrg drmmode_flipdata_ptr flipdata = event_data; 314635d5b7c7Smrg int crtc_id = drmmode_get_crtc_id(crtc); 314735d5b7c7Smrg struct drmmode_fb **fb = &flipdata->fb[crtc_id]; 314835d5b7c7Smrg 314935d5b7c7Smrg if (drmmode_crtc->flip_pending == *fb) { 315035d5b7c7Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending, 315135d5b7c7Smrg NULL); 315235d5b7c7Smrg } 315335d5b7c7Smrg drmmode_fb_reference(pAMDGPUEnt->fd, fb, NULL); 3154d6c0b56eSmrg 3155d6c0b56eSmrg if (--flipdata->flip_count == 0) { 3156504d986fSmrg if (!flipdata->fe_crtc) 3157504d986fSmrg flipdata->fe_crtc = crtc; 3158504d986fSmrg flipdata->abort(flipdata->fe_crtc, flipdata->event_data); 3159d6c0b56eSmrg free(flipdata); 3160d6c0b56eSmrg } 3161d6c0b56eSmrg} 3162d6c0b56eSmrg 3163d6c0b56eSmrgstatic void 3164d6c0b56eSmrgdrmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *event_data) 3165d6c0b56eSmrg{ 3166d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 316724b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 3168d6c0b56eSmrg drmmode_flipdata_ptr flipdata = event_data; 316935d5b7c7Smrg int crtc_id = drmmode_get_crtc_id(crtc); 317035d5b7c7Smrg struct drmmode_fb **fb = &flipdata->fb[crtc_id]; 3171d6c0b56eSmrg 3172d6c0b56eSmrg /* Is this the event whose info shall be delivered to higher level? */ 3173d6c0b56eSmrg if (crtc == flipdata->fe_crtc) { 3174d6c0b56eSmrg /* Yes: Cache msc, ust for later delivery. */ 3175d6c0b56eSmrg flipdata->fe_frame = frame; 3176d6c0b56eSmrg flipdata->fe_usec = usec; 3177d6c0b56eSmrg } 3178d6c0b56eSmrg 317990f2b693Smrg if (*fb) { 318090f2b693Smrg if (drmmode_crtc->flip_pending == *fb) { 318190f2b693Smrg drmmode_fb_reference(pAMDGPUEnt->fd, 318290f2b693Smrg &drmmode_crtc->flip_pending, NULL); 318390f2b693Smrg } 318490f2b693Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, *fb); 318590f2b693Smrg drmmode_fb_reference(pAMDGPUEnt->fd, fb, NULL); 318624b90cf4Smrg } 318724b90cf4Smrg 3188d6c0b56eSmrg if (--flipdata->flip_count == 0) { 3189504d986fSmrg /* Deliver MSC & UST from reference/current CRTC to flip event 3190504d986fSmrg * handler 3191504d986fSmrg */ 3192d6c0b56eSmrg if (flipdata->fe_crtc) 3193504d986fSmrg flipdata->handler(flipdata->fe_crtc, flipdata->fe_frame, 3194504d986fSmrg flipdata->fe_usec, flipdata->event_data); 3195504d986fSmrg else 3196504d986fSmrg flipdata->handler(crtc, frame, usec, flipdata->event_data); 3197d6c0b56eSmrg 3198d6c0b56eSmrg free(flipdata); 3199d6c0b56eSmrg } 3200d6c0b56eSmrg} 3201d6c0b56eSmrg 3202504d986fSmrg#if HAVE_NOTIFY_FD 3203504d986fSmrgstatic void drmmode_notify_fd(int fd, int notify, void *data) 3204504d986fSmrg{ 3205504d986fSmrg drmmode_ptr drmmode = data; 320635d5b7c7Smrg amdgpu_drm_handle_event(fd, &drmmode->event_context); 3207504d986fSmrg} 3208504d986fSmrg#else 3209d6c0b56eSmrgstatic void drm_wakeup_handler(pointer data, int err, pointer p) 3210d6c0b56eSmrg{ 3211d6c0b56eSmrg drmmode_ptr drmmode = data; 3212d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(drmmode->scrn); 3213d6c0b56eSmrg fd_set *read_mask = p; 3214d6c0b56eSmrg 3215d6c0b56eSmrg if (err >= 0 && FD_ISSET(pAMDGPUEnt->fd, read_mask)) { 321635d5b7c7Smrg amdgpu_drm_handle_event(pAMDGPUEnt->fd, &drmmode->event_context); 3217d6c0b56eSmrg } 3218d6c0b56eSmrg} 3219504d986fSmrg#endif 3220d6c0b56eSmrg 322111bf0794Smrgstatic Bool drmmode_probe_page_flip_target(AMDGPUEntPtr pAMDGPUEnt) 322211bf0794Smrg{ 322311bf0794Smrg uint64_t cap_value; 322411bf0794Smrg 322511bf0794Smrg return drmGetCap(pAMDGPUEnt->fd, DRM_CAP_PAGE_FLIP_TARGET, 322611bf0794Smrg &cap_value) == 0 && cap_value != 0; 322711bf0794Smrg} 322811bf0794Smrg 322911bf0794Smrgstatic int 323011bf0794Smrgdrmmode_page_flip(AMDGPUEntPtr pAMDGPUEnt, drmmode_crtc_private_ptr drmmode_crtc, 323111bf0794Smrg int fb_id, uint32_t flags, uintptr_t drm_queue_seq) 323211bf0794Smrg{ 323311bf0794Smrg flags |= DRM_MODE_PAGE_FLIP_EVENT; 323411bf0794Smrg return drmModePageFlip(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 323511bf0794Smrg fb_id, flags, (void*)drm_queue_seq); 323611bf0794Smrg} 323711bf0794Smrg 323811bf0794Smrgint 323911bf0794Smrgdrmmode_page_flip_target_absolute(AMDGPUEntPtr pAMDGPUEnt, 324011bf0794Smrg drmmode_crtc_private_ptr drmmode_crtc, 324111bf0794Smrg int fb_id, uint32_t flags, 324211bf0794Smrg uintptr_t drm_queue_seq, uint32_t target_msc) 324311bf0794Smrg{ 324411bf0794Smrg if (pAMDGPUEnt->has_page_flip_target) { 324511bf0794Smrg flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE; 324611bf0794Smrg return drmModePageFlipTarget(pAMDGPUEnt->fd, 324711bf0794Smrg drmmode_crtc->mode_crtc->crtc_id, 324811bf0794Smrg fb_id, flags, (void*)drm_queue_seq, 324911bf0794Smrg target_msc); 325011bf0794Smrg } 325111bf0794Smrg 325211bf0794Smrg return drmmode_page_flip(pAMDGPUEnt, drmmode_crtc, fb_id, flags, 325311bf0794Smrg drm_queue_seq); 325411bf0794Smrg} 325511bf0794Smrg 325611bf0794Smrgint 325711bf0794Smrgdrmmode_page_flip_target_relative(AMDGPUEntPtr pAMDGPUEnt, 325811bf0794Smrg drmmode_crtc_private_ptr drmmode_crtc, 325911bf0794Smrg int fb_id, uint32_t flags, 326011bf0794Smrg uintptr_t drm_queue_seq, uint32_t target_msc) 326111bf0794Smrg{ 326211bf0794Smrg if (pAMDGPUEnt->has_page_flip_target) { 326311bf0794Smrg flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_RELATIVE; 326411bf0794Smrg return drmModePageFlipTarget(pAMDGPUEnt->fd, 326511bf0794Smrg drmmode_crtc->mode_crtc->crtc_id, 326611bf0794Smrg fb_id, flags, (void*)drm_queue_seq, 326711bf0794Smrg target_msc); 326811bf0794Smrg } 326911bf0794Smrg 327011bf0794Smrg return drmmode_page_flip(pAMDGPUEnt, drmmode_crtc, fb_id, flags, 327111bf0794Smrg drm_queue_seq); 327211bf0794Smrg} 327311bf0794Smrg 327435d5b7c7Smrg/** 327535d5b7c7Smrg * Initialize DDX color management support. It does two things: 327635d5b7c7Smrg * 327735d5b7c7Smrg * 1. Cache DRM color management property type IDs, as they do not change. They 327835d5b7c7Smrg * will be used later to modify color management via DRM, or to determine if 327935d5b7c7Smrg * there's kernel support for color management. 328035d5b7c7Smrg * 328135d5b7c7Smrg * 2. Cache degamma/gamma LUT sizes, since all CRTCs have the same LUT sizes on 328235d5b7c7Smrg * AMD hardware. 328335d5b7c7Smrg * 328435d5b7c7Smrg * If the cached ID's are all 0 after calling this function, then color 328535d5b7c7Smrg * management is not supported. For short, checking if the gamma LUT size 328635d5b7c7Smrg * property ID == 0 is sufficient. 328735d5b7c7Smrg * 328835d5b7c7Smrg * This should be called before CRTCs are initialized within pre_init, as the 328935d5b7c7Smrg * cached values will be used there. 329035d5b7c7Smrg * 329135d5b7c7Smrg * @drm_fd: DRM file descriptor 329235d5b7c7Smrg * @drmmode: drmmode object, where the cached IDs are stored 329335d5b7c7Smrg * @mode_res: The DRM mode resource containing the CRTC ids 329435d5b7c7Smrg */ 329535d5b7c7Smrgstatic void drmmode_cm_init(int drm_fd, drmmode_ptr drmmode, 329635d5b7c7Smrg drmModeResPtr mode_res) 329735d5b7c7Smrg{ 329835d5b7c7Smrg drmModeObjectPropertiesPtr drm_props; 329935d5b7c7Smrg drmModePropertyPtr drm_prop; 330035d5b7c7Smrg enum drmmode_cm_prop cm_prop; 330135d5b7c7Smrg uint32_t cm_enabled = 0; 330235d5b7c7Smrg uint32_t cm_all_enabled = (1 << CM_NUM_PROPS) - 1; 330335d5b7c7Smrg int i; 330435d5b7c7Smrg 330535d5b7c7Smrg memset(drmmode->cm_prop_ids, 0, sizeof(drmmode->cm_prop_ids)); 330635d5b7c7Smrg drmmode->gamma_lut_size = drmmode->degamma_lut_size = 0; 330735d5b7c7Smrg 330835d5b7c7Smrg if (!mode_res->crtcs) 330935d5b7c7Smrg return; 331035d5b7c7Smrg 331135d5b7c7Smrg /* AMD hardware has color management support on all pipes. It is 331235d5b7c7Smrg * therefore sufficient to only check the first CRTC. 331335d5b7c7Smrg */ 331435d5b7c7Smrg drm_props = drmModeObjectGetProperties(drm_fd, 331535d5b7c7Smrg mode_res->crtcs[0], 331635d5b7c7Smrg DRM_MODE_OBJECT_CRTC); 331735d5b7c7Smrg if (!drm_props) 331835d5b7c7Smrg return; 331935d5b7c7Smrg 332035d5b7c7Smrg for (i = 0; i < drm_props->count_props; i++) { 332135d5b7c7Smrg drm_prop = drmModeGetProperty(drm_fd, 332235d5b7c7Smrg drm_props->props[i]); 332335d5b7c7Smrg if (!drm_prop) 332435d5b7c7Smrg continue; 332535d5b7c7Smrg 332635d5b7c7Smrg cm_prop = get_cm_enum_from_str(drm_prop->name); 332735d5b7c7Smrg if (cm_prop == CM_INVALID_PROP) 332835d5b7c7Smrg continue; 332935d5b7c7Smrg 333035d5b7c7Smrg if (cm_prop == CM_DEGAMMA_LUT_SIZE) 333135d5b7c7Smrg drmmode->degamma_lut_size = drm_props->prop_values[i]; 333235d5b7c7Smrg else if (cm_prop == CM_GAMMA_LUT_SIZE) 333335d5b7c7Smrg drmmode->gamma_lut_size = drm_props->prop_values[i]; 333435d5b7c7Smrg 333535d5b7c7Smrg drmmode->cm_prop_ids[cm_prop] = drm_props->props[i]; 333635d5b7c7Smrg cm_enabled |= 1 << cm_prop; 333735d5b7c7Smrg 333835d5b7c7Smrg drmModeFreeProperty(drm_prop); 333935d5b7c7Smrg } 334035d5b7c7Smrg drmModeFreeObjectProperties(drm_props); 334135d5b7c7Smrg 334235d5b7c7Smrg /* cm is enabled only if all prop ids are found */ 334335d5b7c7Smrg if (cm_enabled == cm_all_enabled) 334435d5b7c7Smrg return; 334535d5b7c7Smrg 334635d5b7c7Smrg /* Otherwise, disable DDX cm support */ 334735d5b7c7Smrg memset(drmmode->cm_prop_ids, 0, sizeof(drmmode->cm_prop_ids)); 334835d5b7c7Smrg drmmode->gamma_lut_size = drmmode->degamma_lut_size = 0; 334935d5b7c7Smrg} 335035d5b7c7Smrg 3351d6c0b56eSmrgBool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp) 3352d6c0b56eSmrg{ 3353d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 3354d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 3355d6c0b56eSmrg int i, num_dvi = 0, num_hdmi = 0; 3356d6c0b56eSmrg unsigned int crtcs_needed = 0; 335790f2b693Smrg unsigned int crtcs_got = 0; 3358d6c0b56eSmrg drmModeResPtr mode_res; 335946845023Smrg char *provider_name; 3360d6c0b56eSmrg 3361d6c0b56eSmrg xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs); 3362d6c0b56eSmrg 3363d6c0b56eSmrg drmmode->scrn = pScrn; 3364d6c0b56eSmrg mode_res = drmModeGetResources(pAMDGPUEnt->fd); 3365d6c0b56eSmrg if (!mode_res) 3366d6c0b56eSmrg return FALSE; 3367d6c0b56eSmrg 3368d6c0b56eSmrg drmmode->count_crtcs = mode_res->count_crtcs; 3369d6c0b56eSmrg xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width, 3370d6c0b56eSmrg mode_res->max_height); 3371d6c0b56eSmrg 3372d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 3373d6c0b56eSmrg "Initializing outputs ...\n"); 3374d6c0b56eSmrg for (i = 0; i < mode_res->count_connectors; i++) 3375d6c0b56eSmrg crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, i, &num_dvi, &num_hdmi, 0); 3376d6c0b56eSmrg 3377d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 3378d6c0b56eSmrg "%d crtcs needed for screen.\n", crtcs_needed); 3379d6c0b56eSmrg 338024b90cf4Smrg /* Need per-screen drmmode_crtc_funcs, based on our global template, 338124b90cf4Smrg * so we can disable some functions, depending on screen settings. 338224b90cf4Smrg */ 338324b90cf4Smrg info->drmmode_crtc_funcs = drmmode_crtc_funcs; 338424b90cf4Smrg 3385d6c0b56eSmrg if (!info->use_glamor) { 3386d6c0b56eSmrg /* Rotation requires hardware acceleration */ 338724b90cf4Smrg info->drmmode_crtc_funcs.shadow_allocate = NULL; 338824b90cf4Smrg info->drmmode_crtc_funcs.shadow_create = NULL; 338924b90cf4Smrg info->drmmode_crtc_funcs.shadow_destroy = NULL; 3390d6c0b56eSmrg } 3391d6c0b56eSmrg 339235d5b7c7Smrg drmmode_cm_init(pAMDGPUEnt->fd, drmmode, mode_res); 339335d5b7c7Smrg 339435d5b7c7Smrg /* Spare the server the effort to compute and update unused CLUTs. */ 339535d5b7c7Smrg if (pScrn->depth == 30 && !drmmode_cm_enabled(drmmode)) 339624b90cf4Smrg info->drmmode_crtc_funcs.gamma_set = NULL; 339724b90cf4Smrg 339890f2b693Smrg for (i = 0; i < mode_res->count_crtcs; i++) { 3399d6c0b56eSmrg if (!xf86IsEntityShared(pScrn->entityList[0]) || 340090f2b693Smrg (crtcs_got < crtcs_needed && 340190f2b693Smrg !(pAMDGPUEnt->assigned_crtcs & (1 << i)))) 340290f2b693Smrg crtcs_got += drmmode_crtc_init(pScrn, drmmode, mode_res, i); 340390f2b693Smrg } 3404d6c0b56eSmrg 3405d6c0b56eSmrg /* All ZaphodHeads outputs provided with matching crtcs? */ 340690f2b693Smrg if (crtcs_got < crtcs_needed) { 340790f2b693Smrg if (crtcs_got == 0) { 340890f2b693Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 340990f2b693Smrg "No ZaphodHeads CRTC available, needed %u\n", 341090f2b693Smrg crtcs_needed); 341190f2b693Smrg return FALSE; 341290f2b693Smrg } 341390f2b693Smrg 3414d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 3415d6c0b56eSmrg "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n", 3416d6c0b56eSmrg crtcs_needed); 341790f2b693Smrg } 3418d6c0b56eSmrg 3419d6c0b56eSmrg /* workout clones */ 3420d6c0b56eSmrg drmmode_clones_init(pScrn, drmmode, mode_res); 3421d6c0b56eSmrg 342246845023Smrg XNFasprintf(&provider_name, "%s @ %s", pScrn->chipset, pAMDGPUEnt->busid); 3423d6c0b56eSmrg xf86ProviderSetup(pScrn, NULL, provider_name); 3424d6c0b56eSmrg free(provider_name); 3425d6c0b56eSmrg 3426d6c0b56eSmrg xf86InitialConfiguration(pScrn, TRUE); 3427d6c0b56eSmrg 342811bf0794Smrg pAMDGPUEnt->has_page_flip_target = drmmode_probe_page_flip_target(pAMDGPUEnt); 342911bf0794Smrg 3430d6c0b56eSmrg drmModeFreeResources(mode_res); 3431d6c0b56eSmrg return TRUE; 3432d6c0b56eSmrg} 3433d6c0b56eSmrg 3434d6c0b56eSmrgvoid drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 3435d6c0b56eSmrg{ 3436d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 3437d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 3438d6c0b56eSmrg 3439d6c0b56eSmrg info->drmmode_inited = TRUE; 3440d6c0b56eSmrg if (pAMDGPUEnt->fd_wakeup_registered != serverGeneration) { 3441504d986fSmrg#if HAVE_NOTIFY_FD 3442504d986fSmrg SetNotifyFd(pAMDGPUEnt->fd, drmmode_notify_fd, X_NOTIFY_READ, drmmode); 3443504d986fSmrg#else 3444d6c0b56eSmrg AddGeneralSocket(pAMDGPUEnt->fd); 3445d6c0b56eSmrg RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr) NoopDDA, 3446d6c0b56eSmrg drm_wakeup_handler, drmmode); 3447504d986fSmrg#endif 3448d6c0b56eSmrg pAMDGPUEnt->fd_wakeup_registered = serverGeneration; 3449d6c0b56eSmrg pAMDGPUEnt->fd_wakeup_ref = 1; 3450d6c0b56eSmrg } else 3451d6c0b56eSmrg pAMDGPUEnt->fd_wakeup_ref++; 3452d6c0b56eSmrg} 3453d6c0b56eSmrg 3454d6c0b56eSmrgvoid drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 3455d6c0b56eSmrg{ 3456504d986fSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 3457d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 3458d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 3459504d986fSmrg int c; 3460d6c0b56eSmrg 3461d6c0b56eSmrg if (!info->drmmode_inited) 3462d6c0b56eSmrg return; 3463d6c0b56eSmrg 346490f2b693Smrg for (c = 0; c < config->num_crtc; c++) 346590f2b693Smrg drmmode_crtc_scanout_free(config->crtc[c]); 346690f2b693Smrg 3467d6c0b56eSmrg if (pAMDGPUEnt->fd_wakeup_registered == serverGeneration && 3468d6c0b56eSmrg !--pAMDGPUEnt->fd_wakeup_ref) { 3469504d986fSmrg#if HAVE_NOTIFY_FD 3470504d986fSmrg RemoveNotifyFd(pAMDGPUEnt->fd); 3471504d986fSmrg#else 3472d6c0b56eSmrg RemoveGeneralSocket(pAMDGPUEnt->fd); 3473d6c0b56eSmrg RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr) NoopDDA, 3474d6c0b56eSmrg drm_wakeup_handler, drmmode); 3475504d986fSmrg#endif 3476504d986fSmrg } 3477d6c0b56eSmrg} 3478d6c0b56eSmrg 347924b90cf4Smrgstatic void drmmode_sprite_do_set_cursor(struct amdgpu_device_priv *device_priv, 348024b90cf4Smrg ScrnInfoPtr scrn, int x, int y) 348124b90cf4Smrg{ 348224b90cf4Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 348324b90cf4Smrg CursorPtr cursor = device_priv->cursor; 348424b90cf4Smrg Bool sprite_visible = device_priv->sprite_visible; 348524b90cf4Smrg 348624b90cf4Smrg if (cursor) { 348724b90cf4Smrg x -= cursor->bits->xhot; 348824b90cf4Smrg y -= cursor->bits->yhot; 348924b90cf4Smrg 349024b90cf4Smrg device_priv->sprite_visible = 349124b90cf4Smrg x < scrn->virtualX && y < scrn->virtualY && 349224b90cf4Smrg (x + cursor->bits->width > 0) && 349324b90cf4Smrg (y + cursor->bits->height > 0); 349424b90cf4Smrg } else { 349524b90cf4Smrg device_priv->sprite_visible = FALSE; 349624b90cf4Smrg } 349724b90cf4Smrg 349824b90cf4Smrg info->sprites_visible += device_priv->sprite_visible - sprite_visible; 349924b90cf4Smrg} 350024b90cf4Smrg 350135d5b7c7Smrgstatic void drmmode_sprite_set_cursor(DeviceIntPtr pDev, ScreenPtr pScreen, 350235d5b7c7Smrg CursorPtr pCursor, int x, int y) 350324b90cf4Smrg{ 350424b90cf4Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 350524b90cf4Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 350624b90cf4Smrg struct amdgpu_device_priv *device_priv = 350724b90cf4Smrg dixLookupScreenPrivate(&pDev->devPrivates, 350824b90cf4Smrg &amdgpu_device_private_key, pScreen); 350924b90cf4Smrg 351024b90cf4Smrg device_priv->cursor = pCursor; 351124b90cf4Smrg drmmode_sprite_do_set_cursor(device_priv, scrn, x, y); 351224b90cf4Smrg 351335d5b7c7Smrg info->SpriteFuncs->SetCursor(pDev, pScreen, pCursor, x, y); 351424b90cf4Smrg} 351524b90cf4Smrg 351635d5b7c7Smrgstatic void drmmode_sprite_move_cursor(DeviceIntPtr pDev, ScreenPtr pScreen, 351735d5b7c7Smrg int x, int y) 351824b90cf4Smrg{ 351924b90cf4Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 352024b90cf4Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 352124b90cf4Smrg struct amdgpu_device_priv *device_priv = 352224b90cf4Smrg dixLookupScreenPrivate(&pDev->devPrivates, 352324b90cf4Smrg &amdgpu_device_private_key, pScreen); 352424b90cf4Smrg 352524b90cf4Smrg drmmode_sprite_do_set_cursor(device_priv, scrn, x, y); 352624b90cf4Smrg 352735d5b7c7Smrg info->SpriteFuncs->MoveCursor(pDev, pScreen, x, y); 352824b90cf4Smrg} 352924b90cf4Smrg 353035d5b7c7Smrgstatic Bool drmmode_sprite_realize_realize_cursor(DeviceIntPtr pDev, 353135d5b7c7Smrg ScreenPtr pScreen, 353235d5b7c7Smrg CursorPtr pCursor) 353335d5b7c7Smrg{ 353435d5b7c7Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 353535d5b7c7Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 353635d5b7c7Smrg 353735d5b7c7Smrg return info->SpriteFuncs->RealizeCursor(pDev, pScreen, pCursor); 353835d5b7c7Smrg} 353935d5b7c7Smrg 354035d5b7c7Smrgstatic Bool drmmode_sprite_realize_unrealize_cursor(DeviceIntPtr pDev, 354135d5b7c7Smrg ScreenPtr pScreen, 354235d5b7c7Smrg CursorPtr pCursor) 354335d5b7c7Smrg{ 354435d5b7c7Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 354535d5b7c7Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 354635d5b7c7Smrg 354735d5b7c7Smrg return info->SpriteFuncs->UnrealizeCursor(pDev, pScreen, pCursor); 354835d5b7c7Smrg} 354935d5b7c7Smrg 355035d5b7c7Smrgstatic Bool drmmode_sprite_device_cursor_initialize(DeviceIntPtr pDev, 355135d5b7c7Smrg ScreenPtr pScreen) 355235d5b7c7Smrg{ 355335d5b7c7Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 355435d5b7c7Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 355535d5b7c7Smrg 355635d5b7c7Smrg return info->SpriteFuncs->DeviceCursorInitialize(pDev, pScreen); 355735d5b7c7Smrg} 355835d5b7c7Smrg 355935d5b7c7Smrgstatic void drmmode_sprite_device_cursor_cleanup(DeviceIntPtr pDev, 356035d5b7c7Smrg ScreenPtr pScreen) 356135d5b7c7Smrg{ 356235d5b7c7Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 356335d5b7c7Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 356435d5b7c7Smrg 356535d5b7c7Smrg info->SpriteFuncs->DeviceCursorCleanup(pDev, pScreen); 356635d5b7c7Smrg} 356735d5b7c7Smrg 356835d5b7c7SmrgmiPointerSpriteFuncRec drmmode_sprite_funcs = { 356935d5b7c7Smrg .RealizeCursor = drmmode_sprite_realize_realize_cursor, 357035d5b7c7Smrg .UnrealizeCursor = drmmode_sprite_realize_unrealize_cursor, 357135d5b7c7Smrg .SetCursor = drmmode_sprite_set_cursor, 357235d5b7c7Smrg .MoveCursor = drmmode_sprite_move_cursor, 357335d5b7c7Smrg .DeviceCursorInitialize = drmmode_sprite_device_cursor_initialize, 357435d5b7c7Smrg .DeviceCursorCleanup = drmmode_sprite_device_cursor_cleanup, 357535d5b7c7Smrg}; 357635d5b7c7Smrg 357735d5b7c7Smrg 3578d6c0b56eSmrgvoid drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y) 3579d6c0b56eSmrg{ 3580d6c0b56eSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 3581d6c0b56eSmrg xf86OutputPtr output = config->output[config->compat_output]; 3582d6c0b56eSmrg xf86CrtcPtr crtc = output->crtc; 3583d6c0b56eSmrg 3584d6c0b56eSmrg if (crtc && crtc->enabled) { 3585d6c0b56eSmrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y); 3586d6c0b56eSmrg } 3587d6c0b56eSmrg} 3588d6c0b56eSmrg 3589d6c0b56eSmrgBool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, 3590d6c0b56eSmrg Bool set_hw) 3591d6c0b56eSmrg{ 3592d6c0b56eSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 359324b90cf4Smrg unsigned num_desired = 0, num_on = 0; 3594d6c0b56eSmrg int c; 3595d6c0b56eSmrg 359624b90cf4Smrg /* First, disable all unused CRTCs */ 359724b90cf4Smrg if (set_hw) { 359824b90cf4Smrg for (c = 0; c < config->num_crtc; c++) { 359924b90cf4Smrg xf86CrtcPtr crtc = config->crtc[c]; 360024b90cf4Smrg 360124b90cf4Smrg /* Skip disabled CRTCs */ 360224b90cf4Smrg if (crtc->enabled) 360324b90cf4Smrg continue; 360424b90cf4Smrg 360535d5b7c7Smrg drmmode_crtc_dpms(crtc, DPMSModeOff); 360624b90cf4Smrg } 360724b90cf4Smrg } 360824b90cf4Smrg 360924b90cf4Smrg /* Then, try setting the chosen mode on each CRTC */ 3610d6c0b56eSmrg for (c = 0; c < config->num_crtc; c++) { 3611d6c0b56eSmrg xf86CrtcPtr crtc = config->crtc[c]; 3612d6c0b56eSmrg xf86OutputPtr output = NULL; 3613d6c0b56eSmrg int o; 3614d6c0b56eSmrg 361524b90cf4Smrg if (!crtc->enabled) 3616d6c0b56eSmrg continue; 3617d6c0b56eSmrg 3618d6c0b56eSmrg if (config->output[config->compat_output]->crtc == crtc) 3619d6c0b56eSmrg output = config->output[config->compat_output]; 3620d6c0b56eSmrg else { 3621d6c0b56eSmrg for (o = 0; o < config->num_output; o++) 3622d6c0b56eSmrg if (config->output[o]->crtc == crtc) { 3623d6c0b56eSmrg output = config->output[o]; 3624d6c0b56eSmrg break; 3625d6c0b56eSmrg } 3626d6c0b56eSmrg } 3627d6c0b56eSmrg /* paranoia */ 3628d6c0b56eSmrg if (!output) 3629d6c0b56eSmrg continue; 3630d6c0b56eSmrg 363124b90cf4Smrg num_desired++; 363224b90cf4Smrg 3633d6c0b56eSmrg /* Mark that we'll need to re-set the mode for sure */ 3634d6c0b56eSmrg memset(&crtc->mode, 0, sizeof(crtc->mode)); 3635d6c0b56eSmrg if (!crtc->desiredMode.CrtcHDisplay) { 3636d6c0b56eSmrg DisplayModePtr mode = xf86OutputFindClosestMode(output, 3637d6c0b56eSmrg pScrn-> 3638d6c0b56eSmrg currentMode); 3639d6c0b56eSmrg 364024b90cf4Smrg if (!mode) { 364124b90cf4Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 364224b90cf4Smrg "Failed to find mode for CRTC %d\n", c); 364324b90cf4Smrg continue; 364424b90cf4Smrg } 3645d6c0b56eSmrg crtc->desiredMode = *mode; 3646d6c0b56eSmrg crtc->desiredRotation = RR_Rotate_0; 3647d6c0b56eSmrg crtc->desiredX = 0; 3648d6c0b56eSmrg crtc->desiredY = 0; 3649d6c0b56eSmrg } 3650d6c0b56eSmrg 3651d6c0b56eSmrg if (set_hw) { 365224b90cf4Smrg if (crtc->funcs->set_mode_major(crtc, &crtc->desiredMode, 365324b90cf4Smrg crtc->desiredRotation, 365424b90cf4Smrg crtc->desiredX, 365524b90cf4Smrg crtc->desiredY)) { 365624b90cf4Smrg num_on++; 365724b90cf4Smrg } else { 365824b90cf4Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 365924b90cf4Smrg "Failed to set mode on CRTC %d\n", c); 366035d5b7c7Smrg RRCrtcSet(crtc->randr_crtc, NULL, crtc->x, crtc->y, 366135d5b7c7Smrg crtc->rotation, 0, NULL); 366224b90cf4Smrg } 3663d6c0b56eSmrg } else { 3664d6c0b56eSmrg crtc->mode = crtc->desiredMode; 3665d6c0b56eSmrg crtc->rotation = crtc->desiredRotation; 3666d6c0b56eSmrg crtc->x = crtc->desiredX; 3667d6c0b56eSmrg crtc->y = crtc->desiredY; 366824b90cf4Smrg if (drmmode_handle_transform(crtc)) 366924b90cf4Smrg num_on++; 3670d6c0b56eSmrg } 3671d6c0b56eSmrg } 367224b90cf4Smrg 367324b90cf4Smrg if (num_on == 0 && num_desired > 0) { 367424b90cf4Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to enable any CRTC\n"); 367524b90cf4Smrg return FALSE; 367624b90cf4Smrg } 367724b90cf4Smrg 367835d5b7c7Smrg /* Validate leases on VT re-entry */ 367990f2b693Smrg if (dixPrivateKeyRegistered(rrPrivKey)) 368090f2b693Smrg drmmode_validate_leases(pScrn); 368135d5b7c7Smrg 3682d6c0b56eSmrg return TRUE; 3683d6c0b56eSmrg} 3684d6c0b56eSmrg 3685d6c0b56eSmrgBool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn) 3686d6c0b56eSmrg{ 3687d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 368835d5b7c7Smrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 368935d5b7c7Smrg int i; 3690d6c0b56eSmrg 3691d6c0b56eSmrg if (xf86_config->num_crtc) { 3692d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 3693d6c0b56eSmrg "Initializing kms color map\n"); 3694d6c0b56eSmrg if (!miCreateDefColormap(pScreen)) 3695d6c0b56eSmrg return FALSE; 369635d5b7c7Smrg 369735d5b7c7Smrg if (pScrn->depth == 30) { 369835d5b7c7Smrg if (!drmmode_cm_enabled(&info->drmmode)) 369935d5b7c7Smrg return TRUE; 370035d5b7c7Smrg 370135d5b7c7Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 370235d5b7c7Smrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 370335d5b7c7Smrg void *gamma; 370435d5b7c7Smrg 370535d5b7c7Smrg if (crtc->gamma_size == 1024) 370635d5b7c7Smrg continue; 370735d5b7c7Smrg 370835d5b7c7Smrg gamma = malloc(1024 * 3 * sizeof(CARD16)); 370935d5b7c7Smrg if (!gamma) { 371035d5b7c7Smrg ErrorF("Failed to allocate gamma LUT memory\n"); 371135d5b7c7Smrg return FALSE; 371235d5b7c7Smrg } 371335d5b7c7Smrg 371435d5b7c7Smrg free(crtc->gamma_red); 371535d5b7c7Smrg crtc->gamma_size = 1024; 371635d5b7c7Smrg crtc->gamma_red = gamma; 371735d5b7c7Smrg crtc->gamma_green = crtc->gamma_red + crtc->gamma_size; 371835d5b7c7Smrg crtc->gamma_blue = crtc->gamma_green + crtc->gamma_size; 371935d5b7c7Smrg } 372035d5b7c7Smrg } 372135d5b7c7Smrg 372235d5b7c7Smrg /* All Radeons support 10 bit CLUTs. */ 372335d5b7c7Smrg if (!xf86HandleColormaps(pScreen, 1 << pScrn->rgbBits, 10, 372435d5b7c7Smrg NULL, NULL, CMAP_PALETTED_TRUECOLOR 3725d6c0b56eSmrg | CMAP_RELOAD_ON_MODE_SWITCH)) 3726d6c0b56eSmrg return FALSE; 372735d5b7c7Smrg 372835d5b7c7Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 372935d5b7c7Smrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 373035d5b7c7Smrg 373135d5b7c7Smrg drmmode_crtc_gamma_do_set(crtc, crtc->gamma_red, 373235d5b7c7Smrg crtc->gamma_green, 373335d5b7c7Smrg crtc->gamma_blue, 373435d5b7c7Smrg crtc->gamma_size); 373535d5b7c7Smrg } 3736d6c0b56eSmrg } 373735d5b7c7Smrg 3738d6c0b56eSmrg return TRUE; 3739d6c0b56eSmrg} 3740d6c0b56eSmrg 3741504d986fSmrgstatic Bool 3742504d986fSmrgdrmmode_find_output(ScrnInfoPtr scrn, int output_id, int *num_dvi, 3743504d986fSmrg int *num_hdmi) 3744504d986fSmrg{ 3745504d986fSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3746504d986fSmrg int i; 3747504d986fSmrg 3748504d986fSmrg for (i = 0; i < config->num_output; i++) { 3749504d986fSmrg xf86OutputPtr output = config->output[i]; 3750504d986fSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 3751504d986fSmrg 3752504d986fSmrg if (drmmode_output->output_id == output_id) { 3753504d986fSmrg switch(drmmode_output->mode_output->connector_type) { 3754504d986fSmrg case DRM_MODE_CONNECTOR_DVII: 3755504d986fSmrg case DRM_MODE_CONNECTOR_DVID: 3756504d986fSmrg case DRM_MODE_CONNECTOR_DVIA: 3757504d986fSmrg (*num_dvi)++; 3758504d986fSmrg break; 3759504d986fSmrg case DRM_MODE_CONNECTOR_HDMIA: 3760504d986fSmrg case DRM_MODE_CONNECTOR_HDMIB: 3761504d986fSmrg (*num_hdmi)++; 3762504d986fSmrg break; 3763504d986fSmrg } 3764504d986fSmrg 3765504d986fSmrg return TRUE; 3766504d986fSmrg } 3767504d986fSmrg } 3768504d986fSmrg 3769504d986fSmrg return FALSE; 3770504d986fSmrg} 3771d6c0b56eSmrg 3772d6c0b56eSmrgvoid 3773d6c0b56eSmrgamdgpu_mode_hotplug(ScrnInfoPtr scrn, drmmode_ptr drmmode) 3774d6c0b56eSmrg{ 3775d6c0b56eSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3776d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 3777d6c0b56eSmrg drmModeResPtr mode_res; 3778d6c0b56eSmrg int i, j; 3779d6c0b56eSmrg Bool found; 3780d6c0b56eSmrg Bool changed = FALSE; 3781504d986fSmrg int num_dvi = 0, num_hdmi = 0; 3782d6c0b56eSmrg 378324b90cf4Smrg /* Try to re-set the mode on all the connectors with a BAD link-state: 378424b90cf4Smrg * This may happen if a link degrades and a new modeset is necessary, using 378524b90cf4Smrg * different link-training parameters. If the kernel found that the current 378624b90cf4Smrg * mode is not achievable anymore, it should have pruned the mode before 378724b90cf4Smrg * sending the hotplug event. Try to re-set the currently-set mode to keep 378824b90cf4Smrg * the display alive, this will fail if the mode has been pruned. 378924b90cf4Smrg * In any case, we will send randr events for the Desktop Environment to 379024b90cf4Smrg * deal with it, if it wants to. 379124b90cf4Smrg */ 379224b90cf4Smrg for (i = 0; i < config->num_output; i++) { 379324b90cf4Smrg xf86OutputPtr output = config->output[i]; 379424b90cf4Smrg xf86CrtcPtr crtc = output->crtc; 379524b90cf4Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 379624b90cf4Smrg 379724b90cf4Smrg drmmode_output_detect(output); 379824b90cf4Smrg 379924b90cf4Smrg if (!crtc || !drmmode_output->mode_output) 380024b90cf4Smrg continue; 380124b90cf4Smrg 380224b90cf4Smrg /* Get an updated view of the properties for the current connector and 380324b90cf4Smrg * look for the link-status property 380424b90cf4Smrg */ 380524b90cf4Smrg for (j = 0; j < drmmode_output->num_props; j++) { 380624b90cf4Smrg drmmode_prop_ptr p = &drmmode_output->props[j]; 380724b90cf4Smrg 380824b90cf4Smrg if (!strcmp(p->mode_prop->name, "link-status")) { 380924b90cf4Smrg if (p->value != DRM_MODE_LINK_STATUS_BAD) 381024b90cf4Smrg break; 381124b90cf4Smrg 381224b90cf4Smrg /* the connector got a link failure, re-set the current mode */ 381324b90cf4Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 381424b90cf4Smrg crtc->x, crtc->y); 381524b90cf4Smrg 381624b90cf4Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 381724b90cf4Smrg "hotplug event: connector %u's link-state is BAD, " 381824b90cf4Smrg "tried resetting the current mode. You may be left" 381924b90cf4Smrg "with a black screen if this fails...\n", 382024b90cf4Smrg drmmode_output->mode_output->connector_id); 382124b90cf4Smrg 382224b90cf4Smrg break; 382324b90cf4Smrg } 382424b90cf4Smrg } 382524b90cf4Smrg } 382624b90cf4Smrg 3827d6c0b56eSmrg mode_res = drmModeGetResources(pAMDGPUEnt->fd); 3828d6c0b56eSmrg if (!mode_res) 3829d6c0b56eSmrg goto out; 3830d6c0b56eSmrg 3831d6c0b56eSmrgrestart_destroy: 3832d6c0b56eSmrg for (i = 0; i < config->num_output; i++) { 3833d6c0b56eSmrg xf86OutputPtr output = config->output[i]; 3834d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 3835d6c0b56eSmrg found = FALSE; 3836d6c0b56eSmrg for (j = 0; j < mode_res->count_connectors; j++) { 3837d6c0b56eSmrg if (mode_res->connectors[j] == drmmode_output->output_id) { 3838d6c0b56eSmrg found = TRUE; 3839d6c0b56eSmrg break; 3840d6c0b56eSmrg } 3841d6c0b56eSmrg } 3842d6c0b56eSmrg if (found) 3843d6c0b56eSmrg continue; 3844d6c0b56eSmrg 3845d6c0b56eSmrg drmModeFreeConnector(drmmode_output->mode_output); 3846d6c0b56eSmrg drmmode_output->mode_output = NULL; 3847d6c0b56eSmrg drmmode_output->output_id = -1; 3848d6c0b56eSmrg 3849d6c0b56eSmrg changed = TRUE; 3850d6c0b56eSmrg if (drmmode->delete_dp_12_displays) { 3851d6c0b56eSmrg RROutputDestroy(output->randr_output); 3852d6c0b56eSmrg xf86OutputDestroy(output); 3853d6c0b56eSmrg goto restart_destroy; 3854d6c0b56eSmrg } 3855d6c0b56eSmrg } 3856d6c0b56eSmrg 3857d6c0b56eSmrg /* find new output ids we don't have outputs for */ 3858d6c0b56eSmrg for (i = 0; i < mode_res->count_connectors; i++) { 385990f2b693Smrg for (j = 0; j < pAMDGPUEnt->num_scrns; j++) { 386090f2b693Smrg if (drmmode_find_output(pAMDGPUEnt->scrn[j], 386190f2b693Smrg mode_res->connectors[i], 386290f2b693Smrg &num_dvi, &num_hdmi)) 386390f2b693Smrg break; 386490f2b693Smrg } 386590f2b693Smrg 386690f2b693Smrg if (j < pAMDGPUEnt->num_scrns) 3867d6c0b56eSmrg continue; 3868d6c0b56eSmrg 3869504d986fSmrg if (drmmode_output_init(scrn, drmmode, mode_res, i, &num_dvi, 3870504d986fSmrg &num_hdmi, 1) != 0) 3871504d986fSmrg changed = TRUE; 3872d6c0b56eSmrg } 3873d6c0b56eSmrg 387435d5b7c7Smrg /* Check to see if a lessee has disappeared */ 387535d5b7c7Smrg drmmode_validate_leases(scrn); 387635d5b7c7Smrg 387790f2b693Smrg if (changed) { 3878d6c0b56eSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,2,0) 3879d6c0b56eSmrg RRSetChanged(xf86ScrnToScreen(scrn)); 3880d6c0b56eSmrg#else 3881d6c0b56eSmrg rrScrPrivPtr rrScrPriv = rrGetScrPriv(scrn->pScreen); 3882d6c0b56eSmrg rrScrPriv->changed = TRUE; 3883d6c0b56eSmrg#endif 3884d6c0b56eSmrg RRTellChanged(xf86ScrnToScreen(scrn)); 3885d6c0b56eSmrg } 3886d6c0b56eSmrg 3887d6c0b56eSmrg drmModeFreeResources(mode_res); 3888d6c0b56eSmrgout: 3889d6c0b56eSmrg RRGetInfo(xf86ScrnToScreen(scrn), TRUE); 3890d6c0b56eSmrg} 3891d6c0b56eSmrg 3892d6c0b56eSmrg#ifdef HAVE_LIBUDEV 3893d6c0b56eSmrgstatic void drmmode_handle_uevents(int fd, void *closure) 3894d6c0b56eSmrg{ 3895d6c0b56eSmrg drmmode_ptr drmmode = closure; 3896d6c0b56eSmrg ScrnInfoPtr scrn = drmmode->scrn; 3897d6c0b56eSmrg struct udev_device *dev; 3898504d986fSmrg Bool received = FALSE; 389911bf0794Smrg struct timeval tv = { 0, 0 }; 390011bf0794Smrg fd_set readfd; 390111bf0794Smrg 390211bf0794Smrg FD_ZERO(&readfd); 390311bf0794Smrg FD_SET(fd, &readfd); 390411bf0794Smrg 390511bf0794Smrg while (select(fd + 1, &readfd, NULL, NULL, &tv) > 0 && 390611bf0794Smrg FD_ISSET(fd, &readfd)) { 390711bf0794Smrg /* select() ensured that this will not block */ 390811bf0794Smrg dev = udev_monitor_receive_device(drmmode->uevent_monitor); 390911bf0794Smrg if (dev) { 391011bf0794Smrg udev_device_unref(dev); 391111bf0794Smrg received = TRUE; 391211bf0794Smrg } 3913504d986fSmrg } 3914504d986fSmrg 3915504d986fSmrg if (received) 3916504d986fSmrg amdgpu_mode_hotplug(scrn, drmmode); 3917d6c0b56eSmrg} 3918d6c0b56eSmrg#endif 3919d6c0b56eSmrg 3920d6c0b56eSmrgvoid drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode) 3921d6c0b56eSmrg{ 3922d6c0b56eSmrg#ifdef HAVE_LIBUDEV 3923d6c0b56eSmrg struct udev *u; 3924d6c0b56eSmrg struct udev_monitor *mon; 3925d6c0b56eSmrg 3926d6c0b56eSmrg u = udev_new(); 3927d6c0b56eSmrg if (!u) 3928d6c0b56eSmrg return; 3929d6c0b56eSmrg mon = udev_monitor_new_from_netlink(u, "udev"); 3930d6c0b56eSmrg if (!mon) { 3931d6c0b56eSmrg udev_unref(u); 3932d6c0b56eSmrg return; 3933d6c0b56eSmrg } 3934d6c0b56eSmrg 3935d6c0b56eSmrg if (udev_monitor_filter_add_match_subsystem_devtype(mon, 3936d6c0b56eSmrg "drm", 3937d6c0b56eSmrg "drm_minor") < 0 || 3938d6c0b56eSmrg udev_monitor_enable_receiving(mon) < 0) { 3939d6c0b56eSmrg udev_monitor_unref(mon); 3940d6c0b56eSmrg udev_unref(u); 3941d6c0b56eSmrg return; 3942d6c0b56eSmrg } 3943d6c0b56eSmrg 3944d6c0b56eSmrg drmmode->uevent_handler = 3945d6c0b56eSmrg xf86AddGeneralHandler(udev_monitor_get_fd(mon), 3946d6c0b56eSmrg drmmode_handle_uevents, drmmode); 3947d6c0b56eSmrg 3948d6c0b56eSmrg drmmode->uevent_monitor = mon; 3949d6c0b56eSmrg#endif 3950d6c0b56eSmrg} 3951d6c0b56eSmrg 3952d6c0b56eSmrgvoid drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode) 3953d6c0b56eSmrg{ 3954d6c0b56eSmrg#ifdef HAVE_LIBUDEV 3955d6c0b56eSmrg if (drmmode->uevent_handler) { 3956d6c0b56eSmrg struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor); 3957d6c0b56eSmrg xf86RemoveGeneralHandler(drmmode->uevent_handler); 3958d6c0b56eSmrg 3959d6c0b56eSmrg udev_monitor_unref(drmmode->uevent_monitor); 3960d6c0b56eSmrg udev_unref(u); 3961d6c0b56eSmrg } 3962d6c0b56eSmrg#endif 3963d6c0b56eSmrg} 3964d6c0b56eSmrg 3965d6c0b56eSmrgBool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, 3966d6c0b56eSmrg PixmapPtr new_front, uint64_t id, void *data, 396724b90cf4Smrg xf86CrtcPtr ref_crtc, amdgpu_drm_handler_proc handler, 3968504d986fSmrg amdgpu_drm_abort_proc abort, 396911bf0794Smrg enum drmmode_flip_sync flip_sync, 397011bf0794Smrg uint32_t target_msc) 3971d6c0b56eSmrg{ 3972d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 3973e49c54bcSmrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 3974d6c0b56eSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3975d6c0b56eSmrg xf86CrtcPtr crtc = NULL; 3976d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private; 397790f2b693Smrg int crtc_id; 397811bf0794Smrg uint32_t flip_flags = flip_sync == FLIP_ASYNC ? DRM_MODE_PAGE_FLIP_ASYNC : 0; 3979e49c54bcSmrg uint32_t sec_flip_flags = flip_flags; 3980d6c0b56eSmrg drmmode_flipdata_ptr flipdata; 398135d5b7c7Smrg Bool handle_deferred = FALSE; 3982d6c0b56eSmrg uintptr_t drm_queue_seq = 0; 398335d5b7c7Smrg struct drmmode_fb *fb; 398435d5b7c7Smrg int i = 0; 3985d6c0b56eSmrg 3986e49c54bcSmrg /* 3987e49c54bcSmrg * Flip secondary non-ref_crtc crtc's async if possible and requested 3988e49c54bcSmrg * by xorg.conf option "AsyncFlipSecondaries". Otherwise follow the lead 3989e49c54bcSmrg * of flip_sync. 3990e49c54bcSmrg */ 3991e49c54bcSmrg if (info->can_async_flip && info->async_flip_secondaries) 3992e49c54bcSmrg sec_flip_flags |= DRM_MODE_PAGE_FLIP_ASYNC; 3993e49c54bcSmrg 399490f2b693Smrg flipdata = calloc(1, sizeof(*flipdata) + drmmode_crtc->drmmode->count_crtcs * 399535d5b7c7Smrg sizeof(flipdata->fb[0])); 3996d6c0b56eSmrg if (!flipdata) { 3997d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 3998d6c0b56eSmrg "flip queue: data alloc failed.\n"); 3999d6c0b56eSmrg goto error; 4000d6c0b56eSmrg } 4001d6c0b56eSmrg 400235d5b7c7Smrg fb = amdgpu_pixmap_get_fb(new_front); 400335d5b7c7Smrg if (!fb) { 400424b90cf4Smrg ErrorF("Failed to get FB for flip\n"); 4005d6c0b56eSmrg goto error; 400624b90cf4Smrg } 4007d6c0b56eSmrg 4008d6c0b56eSmrg /* 4009d6c0b56eSmrg * Queue flips on all enabled CRTCs 4010d6c0b56eSmrg * Note that if/when we get per-CRTC buffers, we'll have to update this. 4011d6c0b56eSmrg * Right now it assumes a single shared fb across all CRTCs, with the 4012d6c0b56eSmrg * kernel fixing up the offset of each CRTC as necessary. 4013d6c0b56eSmrg * 4014d6c0b56eSmrg * Also, flips queued on disabled or incorrectly configured displays 4015d6c0b56eSmrg * may never complete; this is a configuration error. 4016d6c0b56eSmrg */ 4017d6c0b56eSmrg 4018d6c0b56eSmrg flipdata->event_data = data; 4019d6c0b56eSmrg flipdata->handler = handler; 4020d6c0b56eSmrg flipdata->abort = abort; 402124b90cf4Smrg flipdata->fe_crtc = ref_crtc; 4022d6c0b56eSmrg 4023d6c0b56eSmrg for (i = 0; i < config->num_crtc; i++) { 4024d6c0b56eSmrg crtc = config->crtc[i]; 402524b90cf4Smrg drmmode_crtc = crtc->driver_private; 402690f2b693Smrg crtc_id = drmmode_get_crtc_id(crtc); 4027d6c0b56eSmrg 402824b90cf4Smrg if (!drmmode_crtc_can_flip(crtc) || 402924b90cf4Smrg (drmmode_crtc->tear_free && crtc != ref_crtc)) 4030d6c0b56eSmrg continue; 4031d6c0b56eSmrg 4032d6c0b56eSmrg flipdata->flip_count++; 4033d6c0b56eSmrg 4034d6c0b56eSmrg drm_queue_seq = amdgpu_drm_queue_alloc(crtc, client, id, 4035d6c0b56eSmrg flipdata, 4036d6c0b56eSmrg drmmode_flip_handler, 403790f2b693Smrg drmmode_flip_abort, 403890f2b693Smrg TRUE); 4039504d986fSmrg if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) { 4040d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 4041d6c0b56eSmrg "Allocating DRM queue event entry failed.\n"); 4042d6c0b56eSmrg goto error; 4043d6c0b56eSmrg } 4044d6c0b56eSmrg 404524b90cf4Smrg if (drmmode_crtc->tear_free) { 404624b90cf4Smrg BoxRec extents = { .x1 = 0, .y1 = 0, 404724b90cf4Smrg .x2 = new_front->drawable.width, 404824b90cf4Smrg .y2 = new_front->drawable.height }; 404924b90cf4Smrg int scanout_id = drmmode_crtc->scanout_id ^ 1; 405024b90cf4Smrg 405124b90cf4Smrg if (flip_sync == FLIP_ASYNC) { 405224b90cf4Smrg if (!drmmode_wait_vblank(crtc, 405324b90cf4Smrg DRM_VBLANK_RELATIVE | 405424b90cf4Smrg DRM_VBLANK_EVENT, 405524b90cf4Smrg 0, drm_queue_seq, 405624b90cf4Smrg NULL, NULL)) 405724b90cf4Smrg goto flip_error; 405824b90cf4Smrg goto next; 405924b90cf4Smrg } 406024b90cf4Smrg 406190f2b693Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &flipdata->fb[crtc_id], 406246845023Smrg amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id])); 406390f2b693Smrg if (!flipdata->fb[crtc_id]) { 406424b90cf4Smrg ErrorF("Failed to get FB for TearFree flip\n"); 406524b90cf4Smrg goto error; 406624b90cf4Smrg } 406724b90cf4Smrg 406824b90cf4Smrg amdgpu_scanout_do_update(crtc, scanout_id, new_front, 406935d5b7c7Smrg extents); 407035d5b7c7Smrg amdgpu_glamor_flush(crtc->scrn); 407135d5b7c7Smrg 407235d5b7c7Smrg if (drmmode_crtc->scanout_update_pending) { 407335d5b7c7Smrg amdgpu_drm_wait_pending_flip(crtc); 407435d5b7c7Smrg handle_deferred = TRUE; 407535d5b7c7Smrg amdgpu_drm_abort_entry(drmmode_crtc->scanout_update_pending); 407635d5b7c7Smrg drmmode_crtc->scanout_update_pending = 0; 407735d5b7c7Smrg } 407835d5b7c7Smrg } else { 407990f2b693Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &flipdata->fb[crtc_id], fb); 408024b90cf4Smrg } 408124b90cf4Smrg 408224b90cf4Smrg if (crtc == ref_crtc) { 408311bf0794Smrg if (drmmode_page_flip_target_absolute(pAMDGPUEnt, 408411bf0794Smrg drmmode_crtc, 408590f2b693Smrg flipdata->fb[crtc_id]->handle, 408611bf0794Smrg flip_flags, 408711bf0794Smrg drm_queue_seq, 408811bf0794Smrg target_msc) != 0) 408911bf0794Smrg goto flip_error; 409011bf0794Smrg } else { 409111bf0794Smrg if (drmmode_page_flip_target_relative(pAMDGPUEnt, 409211bf0794Smrg drmmode_crtc, 409390f2b693Smrg flipdata->fb[crtc_id]->handle, 4094e49c54bcSmrg sec_flip_flags, 409511bf0794Smrg drm_queue_seq, 0) != 0) 409611bf0794Smrg goto flip_error; 4097d6c0b56eSmrg } 409811bf0794Smrg 409924b90cf4Smrg if (drmmode_crtc->tear_free) { 410024b90cf4Smrg drmmode_crtc->scanout_id ^= 1; 410124b90cf4Smrg drmmode_crtc->ignore_damage = TRUE; 410224b90cf4Smrg } 410324b90cf4Smrg 410435d5b7c7Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending, 410590f2b693Smrg flipdata->fb[crtc_id]); 410690f2b693Smrg 410790f2b693Smrg next: 4108d6c0b56eSmrg drm_queue_seq = 0; 4109d6c0b56eSmrg } 4110d6c0b56eSmrg 411135d5b7c7Smrg if (handle_deferred) 411235d5b7c7Smrg amdgpu_drm_queue_handle_deferred(ref_crtc); 4113d6c0b56eSmrg if (flipdata->flip_count > 0) 4114d6c0b56eSmrg return TRUE; 4115d6c0b56eSmrg 411611bf0794Smrgflip_error: 411711bf0794Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed: %s\n", 411811bf0794Smrg strerror(errno)); 411911bf0794Smrg 4120d6c0b56eSmrgerror: 4121d6c0b56eSmrg if (drm_queue_seq) 4122d6c0b56eSmrg amdgpu_drm_abort_entry(drm_queue_seq); 4123d6c0b56eSmrg else if (crtc) 4124d6c0b56eSmrg drmmode_flip_abort(crtc, flipdata); 412511bf0794Smrg else { 412611bf0794Smrg abort(NULL, data); 4127d6c0b56eSmrg free(flipdata); 412811bf0794Smrg } 4129d6c0b56eSmrg 4130d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n", 4131d6c0b56eSmrg strerror(errno)); 413235d5b7c7Smrg if (handle_deferred) 413335d5b7c7Smrg amdgpu_drm_queue_handle_deferred(ref_crtc); 4134d6c0b56eSmrg return FALSE; 4135d6c0b56eSmrg} 4136