drmmode_display.c revision 90f2b693
1d6c0b56eSmrg/* 2d6c0b56eSmrg * Copyright © 2007 Red Hat, Inc. 3d6c0b56eSmrg * 4d6c0b56eSmrg * Permission is hereby granted, free of charge, to any person obtaining a 5d6c0b56eSmrg * copy of this software and associated documentation files (the "Software"), 6d6c0b56eSmrg * to deal in the Software without restriction, including without limitation 7d6c0b56eSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8d6c0b56eSmrg * and/or sell copies of the Software, and to permit persons to whom the 9d6c0b56eSmrg * Software is furnished to do so, subject to the following conditions: 10d6c0b56eSmrg * 11d6c0b56eSmrg * The above copyright notice and this permission notice (including the next 12d6c0b56eSmrg * paragraph) shall be included in all copies or substantial portions of the 13d6c0b56eSmrg * Software. 14d6c0b56eSmrg * 15d6c0b56eSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16d6c0b56eSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17d6c0b56eSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18d6c0b56eSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19d6c0b56eSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20d6c0b56eSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21d6c0b56eSmrg * SOFTWARE. 22d6c0b56eSmrg * 23d6c0b56eSmrg * Authors: 24d6c0b56eSmrg * Dave Airlie <airlied@redhat.com> 25d6c0b56eSmrg * 26d6c0b56eSmrg */ 27d6c0b56eSmrg 28d6c0b56eSmrg#ifdef HAVE_CONFIG_H 29d6c0b56eSmrg#include "config.h" 30d6c0b56eSmrg#endif 31d6c0b56eSmrg 32d6c0b56eSmrg#include <errno.h> 33d6c0b56eSmrg#include <sys/ioctl.h> 34d6c0b56eSmrg#include <time.h> 35d6c0b56eSmrg#include "cursorstr.h" 36d6c0b56eSmrg#include "damagestr.h" 3724b90cf4Smrg#include "inputstr.h" 3824b90cf4Smrg#include "list.h" 39d6c0b56eSmrg#include "micmap.h" 4035d5b7c7Smrg#include "mipointrst.h" 41d6c0b56eSmrg#include "xf86cmap.h" 42504d986fSmrg#include "xf86Priv.h" 43d6c0b56eSmrg#include "sarea.h" 44d6c0b56eSmrg 45d6c0b56eSmrg#include "drmmode_display.h" 46d6c0b56eSmrg#include "amdgpu_bo_helper.h" 47d6c0b56eSmrg#include "amdgpu_glamor.h" 48d6c0b56eSmrg#include "amdgpu_pixmap.h" 49d6c0b56eSmrg 50d6c0b56eSmrg#include <dri.h> 51d6c0b56eSmrg 52d6c0b56eSmrg/* DPMS */ 53d6c0b56eSmrg#ifdef HAVE_XEXTPROTO_71 54d6c0b56eSmrg#include <X11/extensions/dpmsconst.h> 55d6c0b56eSmrg#else 56d6c0b56eSmrg#define DPMS_SERVER 57d6c0b56eSmrg#include <X11/extensions/dpms.h> 58d6c0b56eSmrg#endif 59d6c0b56eSmrg 60d6c0b56eSmrg#include <gbm.h> 61d6c0b56eSmrg 62d6c0b56eSmrg#define DEFAULT_NOMINAL_FRAME_RATE 60 63d6c0b56eSmrg 64d6c0b56eSmrgstatic Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height); 65d6c0b56eSmrg 66d6c0b56eSmrgstatic Bool 67d6c0b56eSmrgAMDGPUZaphodStringMatches(ScrnInfoPtr pScrn, const char *s, char *output_name) 68d6c0b56eSmrg{ 69d6c0b56eSmrg int i = 0; 70d6c0b56eSmrg char s1[20]; 71d6c0b56eSmrg 72d6c0b56eSmrg do { 73d6c0b56eSmrg switch (*s) { 74d6c0b56eSmrg case ',': 75d6c0b56eSmrg s1[i] = '\0'; 76d6c0b56eSmrg i = 0; 77d6c0b56eSmrg if (strcmp(s1, output_name) == 0) 78d6c0b56eSmrg return TRUE; 79d6c0b56eSmrg break; 80d6c0b56eSmrg case ' ': 81d6c0b56eSmrg case '\t': 82d6c0b56eSmrg case '\n': 83d6c0b56eSmrg case '\r': 84d6c0b56eSmrg break; 85d6c0b56eSmrg default: 86d6c0b56eSmrg s1[i] = *s; 87d6c0b56eSmrg i++; 88d6c0b56eSmrg break; 89d6c0b56eSmrg } 90d6c0b56eSmrg } while (*s++); 91d6c0b56eSmrg 92d6c0b56eSmrg s1[i] = '\0'; 93d6c0b56eSmrg if (strcmp(s1, output_name) == 0) 94d6c0b56eSmrg return TRUE; 95d6c0b56eSmrg 96d6c0b56eSmrg return FALSE; 97d6c0b56eSmrg} 98d6c0b56eSmrg 9924b90cf4Smrg 100d6c0b56eSmrgstatic PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn, 101d6c0b56eSmrg int width, int height, 102d6c0b56eSmrg int depth, int bpp, 103d6c0b56eSmrg int pitch, 104d6c0b56eSmrg struct amdgpu_buffer *bo) 105d6c0b56eSmrg{ 106d6c0b56eSmrg ScreenPtr pScreen = pScrn->pScreen; 107d6c0b56eSmrg PixmapPtr pixmap; 108d6c0b56eSmrg 109d6c0b56eSmrg pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 110d6c0b56eSmrg AMDGPU_CREATE_PIXMAP_SCANOUT); 111d6c0b56eSmrg if (!pixmap) 112d6c0b56eSmrg return NULL; 113d6c0b56eSmrg 114d6c0b56eSmrg if (!(*pScreen->ModifyPixmapHeader) (pixmap, width, height, 115504d986fSmrg depth, bpp, pitch, NULL)) 116504d986fSmrg goto fail; 117d6c0b56eSmrg 118504d986fSmrg if (!amdgpu_glamor_create_textured_pixmap(pixmap, bo)) 119504d986fSmrg goto fail; 120d6c0b56eSmrg 121504d986fSmrg if (amdgpu_set_pixmap_bo(pixmap, bo)) 122504d986fSmrg return pixmap; 123d6c0b56eSmrg 124504d986fSmrgfail: 125504d986fSmrg pScreen->DestroyPixmap(pixmap); 126504d986fSmrg return NULL; 127d6c0b56eSmrg} 128d6c0b56eSmrg 129d6c0b56eSmrgstatic void drmmode_destroy_bo_pixmap(PixmapPtr pixmap) 130d6c0b56eSmrg{ 131d6c0b56eSmrg ScreenPtr pScreen = pixmap->drawable.pScreen; 132d6c0b56eSmrg 133d6c0b56eSmrg (*pScreen->DestroyPixmap) (pixmap); 134d6c0b56eSmrg} 135d6c0b56eSmrg 136d6c0b56eSmrgstatic void 137d6c0b56eSmrgdrmmode_ConvertFromKMode(ScrnInfoPtr scrn, 138d6c0b56eSmrg drmModeModeInfo * kmode, DisplayModePtr mode) 139d6c0b56eSmrg{ 140d6c0b56eSmrg memset(mode, 0, sizeof(DisplayModeRec)); 141d6c0b56eSmrg mode->status = MODE_OK; 142d6c0b56eSmrg 143d6c0b56eSmrg mode->Clock = kmode->clock; 144d6c0b56eSmrg 145d6c0b56eSmrg mode->HDisplay = kmode->hdisplay; 146d6c0b56eSmrg mode->HSyncStart = kmode->hsync_start; 147d6c0b56eSmrg mode->HSyncEnd = kmode->hsync_end; 148d6c0b56eSmrg mode->HTotal = kmode->htotal; 149d6c0b56eSmrg mode->HSkew = kmode->hskew; 150d6c0b56eSmrg 151d6c0b56eSmrg mode->VDisplay = kmode->vdisplay; 152d6c0b56eSmrg mode->VSyncStart = kmode->vsync_start; 153d6c0b56eSmrg mode->VSyncEnd = kmode->vsync_end; 154d6c0b56eSmrg mode->VTotal = kmode->vtotal; 155d6c0b56eSmrg mode->VScan = kmode->vscan; 156d6c0b56eSmrg 157d6c0b56eSmrg mode->Flags = kmode->flags; //& FLAG_BITS; 158d6c0b56eSmrg mode->name = strdup(kmode->name); 159d6c0b56eSmrg 160d6c0b56eSmrg if (kmode->type & DRM_MODE_TYPE_DRIVER) 161d6c0b56eSmrg mode->type = M_T_DRIVER; 162d6c0b56eSmrg if (kmode->type & DRM_MODE_TYPE_PREFERRED) 163d6c0b56eSmrg mode->type |= M_T_PREFERRED; 164d6c0b56eSmrg xf86SetModeCrtc(mode, scrn->adjustFlags); 165d6c0b56eSmrg} 166d6c0b56eSmrg 167d6c0b56eSmrgstatic void 168d6c0b56eSmrgdrmmode_ConvertToKMode(ScrnInfoPtr scrn, 169d6c0b56eSmrg drmModeModeInfo * kmode, DisplayModePtr mode) 170d6c0b56eSmrg{ 171d6c0b56eSmrg memset(kmode, 0, sizeof(*kmode)); 172d6c0b56eSmrg 173d6c0b56eSmrg kmode->clock = mode->Clock; 174d6c0b56eSmrg kmode->hdisplay = mode->HDisplay; 175d6c0b56eSmrg kmode->hsync_start = mode->HSyncStart; 176d6c0b56eSmrg kmode->hsync_end = mode->HSyncEnd; 177d6c0b56eSmrg kmode->htotal = mode->HTotal; 178d6c0b56eSmrg kmode->hskew = mode->HSkew; 179d6c0b56eSmrg 180d6c0b56eSmrg kmode->vdisplay = mode->VDisplay; 181d6c0b56eSmrg kmode->vsync_start = mode->VSyncStart; 182d6c0b56eSmrg kmode->vsync_end = mode->VSyncEnd; 183d6c0b56eSmrg kmode->vtotal = mode->VTotal; 184d6c0b56eSmrg kmode->vscan = mode->VScan; 185d6c0b56eSmrg 186d6c0b56eSmrg kmode->flags = mode->Flags; //& FLAG_BITS; 187d6c0b56eSmrg if (mode->name) 188d6c0b56eSmrg strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN); 189d6c0b56eSmrg kmode->name[DRM_DISPLAY_MODE_LEN - 1] = 0; 190d6c0b56eSmrg 191d6c0b56eSmrg} 192d6c0b56eSmrg 19324b90cf4Smrg/* 19424b90cf4Smrg * Utility helper for drmWaitVBlank 19524b90cf4Smrg */ 19624b90cf4SmrgBool 19724b90cf4Smrgdrmmode_wait_vblank(xf86CrtcPtr crtc, drmVBlankSeqType type, 19824b90cf4Smrg uint32_t target_seq, unsigned long signal, uint64_t *ust, 19924b90cf4Smrg uint32_t *result_seq) 20024b90cf4Smrg{ 20124b90cf4Smrg int crtc_id = drmmode_get_crtc_id(crtc); 20224b90cf4Smrg ScrnInfoPtr scrn = crtc->scrn; 20324b90cf4Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 20424b90cf4Smrg drmVBlank vbl; 20524b90cf4Smrg 20624b90cf4Smrg if (crtc_id == 1) 20724b90cf4Smrg type |= DRM_VBLANK_SECONDARY; 20824b90cf4Smrg else if (crtc_id > 1) 20924b90cf4Smrg type |= (crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT) & 21024b90cf4Smrg DRM_VBLANK_HIGH_CRTC_MASK; 21124b90cf4Smrg 21224b90cf4Smrg vbl.request.type = type; 21324b90cf4Smrg vbl.request.sequence = target_seq; 21424b90cf4Smrg vbl.request.signal = signal; 21524b90cf4Smrg 21624b90cf4Smrg if (drmWaitVBlank(pAMDGPUEnt->fd, &vbl) != 0) 21724b90cf4Smrg return FALSE; 21824b90cf4Smrg 21924b90cf4Smrg if (ust) 22024b90cf4Smrg *ust = (uint64_t)vbl.reply.tval_sec * 1000000 + 22124b90cf4Smrg vbl.reply.tval_usec; 22224b90cf4Smrg if (result_seq) 22324b90cf4Smrg *result_seq = vbl.reply.sequence; 22424b90cf4Smrg 22524b90cf4Smrg return TRUE; 22624b90cf4Smrg} 22724b90cf4Smrg 228d6c0b56eSmrg/* 229d6c0b56eSmrg * Retrieves present time in microseconds that is compatible 230d6c0b56eSmrg * with units used by vblank timestamps. Depending on the kernel 231d6c0b56eSmrg * version and DRM kernel module configuration, the vblank 232d6c0b56eSmrg * timestamp can either be in real time or monotonic time 233d6c0b56eSmrg */ 234d6c0b56eSmrgint drmmode_get_current_ust(int drm_fd, CARD64 * ust) 235d6c0b56eSmrg{ 236d6c0b56eSmrg uint64_t cap_value; 237d6c0b56eSmrg int ret; 238d6c0b56eSmrg struct timespec now; 239d6c0b56eSmrg 240d6c0b56eSmrg ret = drmGetCap(drm_fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap_value); 241d6c0b56eSmrg if (ret || !cap_value) 242d6c0b56eSmrg /* old kernel or drm_timestamp_monotonic turned off */ 243d6c0b56eSmrg ret = clock_gettime(CLOCK_REALTIME, &now); 244d6c0b56eSmrg else 245d6c0b56eSmrg ret = clock_gettime(CLOCK_MONOTONIC, &now); 246d6c0b56eSmrg if (ret) 247d6c0b56eSmrg return ret; 248d6c0b56eSmrg *ust = ((CARD64) now.tv_sec * 1000000) + ((CARD64) now.tv_nsec / 1000); 249d6c0b56eSmrg return 0; 250d6c0b56eSmrg} 251d6c0b56eSmrg 252d6c0b56eSmrg/* 253d6c0b56eSmrg * Get current frame count and frame count timestamp of the crtc. 254d6c0b56eSmrg */ 255d6c0b56eSmrgint drmmode_crtc_get_ust_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc) 256d6c0b56eSmrg{ 257d6c0b56eSmrg ScrnInfoPtr scrn = crtc->scrn; 25824b90cf4Smrg uint32_t seq; 259d6c0b56eSmrg 26024b90cf4Smrg if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, ust, &seq)) { 261d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 262d6c0b56eSmrg "get vblank counter failed: %s\n", strerror(errno)); 26324b90cf4Smrg return -1; 264d6c0b56eSmrg } 265d6c0b56eSmrg 26624b90cf4Smrg *msc = seq; 267d6c0b56eSmrg 268d6c0b56eSmrg return Success; 269d6c0b56eSmrg} 270d6c0b56eSmrg 27190f2b693Smrgstatic uint32_t 27290f2b693Smrgdrmmode_crtc_get_prop_id(uint32_t drm_fd, 27390f2b693Smrg drmModeObjectPropertiesPtr props, 27490f2b693Smrg char const* name) 27590f2b693Smrg{ 27690f2b693Smrg uint32_t i, prop_id = 0; 27790f2b693Smrg 27890f2b693Smrg for (i = 0; !prop_id && i < props->count_props; ++i) { 27990f2b693Smrg drmModePropertyPtr drm_prop = 28090f2b693Smrg drmModeGetProperty(drm_fd, props->props[i]); 28190f2b693Smrg 28290f2b693Smrg if (!drm_prop) 28390f2b693Smrg continue; 28490f2b693Smrg 28590f2b693Smrg if (strcmp(drm_prop->name, name) == 0) 28690f2b693Smrg prop_id = drm_prop->prop_id; 28790f2b693Smrg 28890f2b693Smrg drmModeFreeProperty(drm_prop); 28990f2b693Smrg } 29090f2b693Smrg 29190f2b693Smrg return prop_id; 29290f2b693Smrg} 29390f2b693Smrg 29490f2b693Smrgstatic void drmmode_crtc_vrr_init(int drm_fd, xf86CrtcPtr crtc) 29590f2b693Smrg{ 29690f2b693Smrg drmModeObjectPropertiesPtr drm_props; 29790f2b693Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 29890f2b693Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 29990f2b693Smrg 30090f2b693Smrg if (drmmode->vrr_prop_id) 30190f2b693Smrg return; 30290f2b693Smrg 30390f2b693Smrg drm_props = drmModeObjectGetProperties(drm_fd, 30490f2b693Smrg drmmode_crtc->mode_crtc->crtc_id, 30590f2b693Smrg DRM_MODE_OBJECT_CRTC); 30690f2b693Smrg 30790f2b693Smrg if (!drm_props) 30890f2b693Smrg return; 30990f2b693Smrg 31090f2b693Smrg drmmode->vrr_prop_id = drmmode_crtc_get_prop_id(drm_fd, 31190f2b693Smrg drm_props, 31290f2b693Smrg "VRR_ENABLED"); 31390f2b693Smrg 31490f2b693Smrg drmModeFreeObjectProperties(drm_props); 31590f2b693Smrg} 31690f2b693Smrg 31790f2b693Smrgvoid drmmode_crtc_set_vrr(xf86CrtcPtr crtc, Bool enabled) 31890f2b693Smrg{ 31990f2b693Smrg ScrnInfoPtr pScrn = crtc->scrn; 32090f2b693Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 32190f2b693Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 32290f2b693Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 32390f2b693Smrg 32490f2b693Smrg if (drmmode->vrr_prop_id && 32590f2b693Smrg drmmode_crtc->vrr_enabled != enabled && 32690f2b693Smrg drmModeObjectSetProperty(pAMDGPUEnt->fd, 32790f2b693Smrg drmmode_crtc->mode_crtc->crtc_id, 32890f2b693Smrg DRM_MODE_OBJECT_CRTC, 32990f2b693Smrg drmmode->vrr_prop_id, 33090f2b693Smrg enabled) == 0) 33190f2b693Smrg drmmode_crtc->vrr_enabled = enabled; 33290f2b693Smrg} 33390f2b693Smrg 334d6c0b56eSmrgstatic void 335d6c0b56eSmrgdrmmode_do_crtc_dpms(xf86CrtcPtr crtc, int mode) 336d6c0b56eSmrg{ 337d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 338d6c0b56eSmrg ScrnInfoPtr scrn = crtc->scrn; 339d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 340d6c0b56eSmrg CARD64 ust; 341d6c0b56eSmrg int ret; 342d6c0b56eSmrg 343d6c0b56eSmrg if (drmmode_crtc->dpms_mode == DPMSModeOn && mode != DPMSModeOn) { 34424b90cf4Smrg uint32_t seq; 345d6c0b56eSmrg 34635d5b7c7Smrg amdgpu_drm_wait_pending_flip(crtc); 347504d986fSmrg 348d6c0b56eSmrg /* 349d6c0b56eSmrg * On->Off transition: record the last vblank time, 350d6c0b56eSmrg * sequence number and frame period. 351d6c0b56eSmrg */ 35224b90cf4Smrg if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, &ust, 35324b90cf4Smrg &seq)) 354d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 355d6c0b56eSmrg "%s cannot get last vblank counter\n", 356d6c0b56eSmrg __func__); 357d6c0b56eSmrg else { 358d6c0b56eSmrg CARD64 nominal_frame_rate, pix_in_frame; 359d6c0b56eSmrg 360d6c0b56eSmrg drmmode_crtc->dpms_last_ust = ust; 361d6c0b56eSmrg drmmode_crtc->dpms_last_seq = seq; 362d6c0b56eSmrg nominal_frame_rate = crtc->mode.Clock; 363d6c0b56eSmrg nominal_frame_rate *= 1000; 364d6c0b56eSmrg pix_in_frame = crtc->mode.HTotal * crtc->mode.VTotal; 365d6c0b56eSmrg if (nominal_frame_rate == 0 || pix_in_frame == 0) 366d6c0b56eSmrg nominal_frame_rate = DEFAULT_NOMINAL_FRAME_RATE; 367d6c0b56eSmrg else 368d6c0b56eSmrg nominal_frame_rate /= pix_in_frame; 369d6c0b56eSmrg drmmode_crtc->dpms_last_fps = nominal_frame_rate; 370d6c0b56eSmrg } 37135d5b7c7Smrg 37235d5b7c7Smrg drmmode_crtc->dpms_mode = mode; 37335d5b7c7Smrg amdgpu_drm_queue_handle_deferred(crtc); 374d6c0b56eSmrg } else if (drmmode_crtc->dpms_mode != DPMSModeOn && mode == DPMSModeOn) { 375d6c0b56eSmrg /* 376d6c0b56eSmrg * Off->On transition: calculate and accumulate the 377d6c0b56eSmrg * number of interpolated vblanks while we were in Off state 378d6c0b56eSmrg */ 379d6c0b56eSmrg ret = drmmode_get_current_ust(pAMDGPUEnt->fd, &ust); 380d6c0b56eSmrg if (ret) 381d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 382d6c0b56eSmrg "%s cannot get current time\n", __func__); 383d6c0b56eSmrg else if (drmmode_crtc->dpms_last_ust) { 384d6c0b56eSmrg CARD64 time_elapsed, delta_seq; 385d6c0b56eSmrg time_elapsed = ust - drmmode_crtc->dpms_last_ust; 386d6c0b56eSmrg delta_seq = time_elapsed * drmmode_crtc->dpms_last_fps; 387d6c0b56eSmrg delta_seq /= 1000000; 388d6c0b56eSmrg drmmode_crtc->interpolated_vblanks += delta_seq; 389d6c0b56eSmrg 390d6c0b56eSmrg } 39135d5b7c7Smrg 39235d5b7c7Smrg drmmode_crtc->dpms_mode = DPMSModeOn; 393d6c0b56eSmrg } 394d6c0b56eSmrg} 395d6c0b56eSmrg 396d6c0b56eSmrgstatic void 397d6c0b56eSmrgdrmmode_crtc_dpms(xf86CrtcPtr crtc, int mode) 398d6c0b56eSmrg{ 399d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 400d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 401d6c0b56eSmrg 402d6c0b56eSmrg /* Disable unused CRTCs and enable/disable active CRTCs */ 403504d986fSmrg if (!crtc->enabled || mode != DPMSModeOn) { 40435d5b7c7Smrg drmmode_do_crtc_dpms(crtc, DPMSModeOff); 405d6c0b56eSmrg drmModeSetCrtc(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 406d6c0b56eSmrg 0, 0, 0, NULL, 0, NULL); 40724b90cf4Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, NULL); 408504d986fSmrg } else if (drmmode_crtc->dpms_mode != DPMSModeOn) 409d6c0b56eSmrg crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation, 410d6c0b56eSmrg crtc->x, crtc->y); 411d6c0b56eSmrg} 412d6c0b56eSmrg 41390f2b693Smrg#ifdef USE_GLAMOR 41490f2b693Smrg 415d6c0b56eSmrgstatic PixmapPtr 416d6c0b56eSmrgcreate_pixmap_for_fbcon(drmmode_ptr drmmode, 417d6c0b56eSmrg ScrnInfoPtr pScrn, int fbcon_id) 418d6c0b56eSmrg{ 41935d5b7c7Smrg ScreenPtr pScreen = pScrn->pScreen; 420d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 42135d5b7c7Smrg PixmapPtr pixmap = NULL; 422d6c0b56eSmrg drmModeFBPtr fbcon; 423d6c0b56eSmrg 424d6c0b56eSmrg fbcon = drmModeGetFB(pAMDGPUEnt->fd, fbcon_id); 42535d5b7c7Smrg if (!fbcon) 426d6c0b56eSmrg return NULL; 427d6c0b56eSmrg 428d6c0b56eSmrg if (fbcon->depth != pScrn->depth || 429d6c0b56eSmrg fbcon->width != pScrn->virtualX || 430d6c0b56eSmrg fbcon->height != pScrn->virtualY) 431d6c0b56eSmrg goto out_free_fb; 432d6c0b56eSmrg 43335d5b7c7Smrg pixmap = fbCreatePixmap(pScreen, 0, 0, fbcon->depth, 0); 43435d5b7c7Smrg if (!pixmap) 435d6c0b56eSmrg goto out_free_fb; 436d6c0b56eSmrg 43735d5b7c7Smrg pScreen->ModifyPixmapHeader(pixmap, fbcon->width, fbcon->height, 0, 0, 43835d5b7c7Smrg fbcon->pitch, NULL); 43935d5b7c7Smrg pixmap->devPrivate.ptr = NULL; 440d6c0b56eSmrg 44135d5b7c7Smrg if (!glamor_egl_create_textured_pixmap(pixmap, fbcon->handle, 44235d5b7c7Smrg pixmap->devKind)) { 44335d5b7c7Smrg pScreen->DestroyPixmap(pixmap); 44435d5b7c7Smrg pixmap = NULL; 445d6c0b56eSmrg } 446d6c0b56eSmrg 447d6c0b56eSmrgout_free_fb: 448d6c0b56eSmrg drmModeFreeFB(fbcon); 449d6c0b56eSmrg return pixmap; 450d6c0b56eSmrg} 451d6c0b56eSmrg 45290f2b693Smrg#endif /* USE_GLAMOR */ 45390f2b693Smrg 454d6c0b56eSmrgvoid drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 455d6c0b56eSmrg{ 45690f2b693Smrg#ifdef USE_GLAMOR 457d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 45890f2b693Smrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 459d6c0b56eSmrg ScreenPtr pScreen = pScrn->pScreen; 46024b90cf4Smrg PixmapPtr src, dst = pScreen->GetScreenPixmap(pScreen); 46124b90cf4Smrg struct drmmode_fb *fb = amdgpu_pixmap_get_fb(dst); 462d6c0b56eSmrg int fbcon_id = 0; 463d6c0b56eSmrg GCPtr gc; 464d6c0b56eSmrg int i; 465d6c0b56eSmrg 46690f2b693Smrg if (!info->use_glamor) 46790f2b693Smrg return; 46890f2b693Smrg 469d6c0b56eSmrg for (i = 0; i < xf86_config->num_crtc; i++) { 470d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[i]->driver_private; 471d6c0b56eSmrg 472d6c0b56eSmrg if (drmmode_crtc->mode_crtc->buffer_id) 473d6c0b56eSmrg fbcon_id = drmmode_crtc->mode_crtc->buffer_id; 474d6c0b56eSmrg } 475d6c0b56eSmrg 476d6c0b56eSmrg if (!fbcon_id) 477d6c0b56eSmrg return; 478d6c0b56eSmrg 47924b90cf4Smrg if (fbcon_id == fb->handle) { 480d6c0b56eSmrg /* in some rare case there might be no fbcon and we might already 481d6c0b56eSmrg * be the one with the current fb to avoid a false deadlck in 482d6c0b56eSmrg * kernel ttm code just do nothing as anyway there is nothing 483d6c0b56eSmrg * to do 484d6c0b56eSmrg */ 485d6c0b56eSmrg return; 486d6c0b56eSmrg } 487d6c0b56eSmrg 488d6c0b56eSmrg src = create_pixmap_for_fbcon(drmmode, pScrn, fbcon_id); 489d6c0b56eSmrg if (!src) 490d6c0b56eSmrg return; 491d6c0b56eSmrg 492d6c0b56eSmrg gc = GetScratchGC(pScrn->depth, pScreen); 493d6c0b56eSmrg ValidateGC(&dst->drawable, gc); 494d6c0b56eSmrg 495d6c0b56eSmrg (*gc->ops->CopyArea)(&src->drawable, &dst->drawable, gc, 0, 0, 496d6c0b56eSmrg pScrn->virtualX, pScrn->virtualY, 0, 0); 497d6c0b56eSmrg 498d6c0b56eSmrg FreeScratchGC(gc); 499d6c0b56eSmrg 500d6c0b56eSmrg pScreen->canDoBGNoneRoot = TRUE; 50135d5b7c7Smrg pScreen->DestroyPixmap(src); 50290f2b693Smrg#endif 503d6c0b56eSmrg 504d6c0b56eSmrg return; 505d6c0b56eSmrg} 506d6c0b56eSmrg 50724b90cf4Smrgvoid 508d6c0b56eSmrgdrmmode_crtc_scanout_destroy(drmmode_ptr drmmode, 509d6c0b56eSmrg struct drmmode_scanout *scanout) 510d6c0b56eSmrg{ 511d6c0b56eSmrg 512d6c0b56eSmrg if (scanout->pixmap) { 513d6c0b56eSmrg drmmode_destroy_bo_pixmap(scanout->pixmap); 514d6c0b56eSmrg scanout->pixmap = NULL; 515d6c0b56eSmrg } 516d6c0b56eSmrg 517d6c0b56eSmrg if (scanout->bo) { 518d6c0b56eSmrg amdgpu_bo_unref(&scanout->bo); 519d6c0b56eSmrg scanout->bo = NULL; 520d6c0b56eSmrg } 521504d986fSmrg} 522504d986fSmrg 52324b90cf4Smrgvoid 52490f2b693Smrgdrmmode_crtc_scanout_free(xf86CrtcPtr crtc) 525504d986fSmrg{ 52690f2b693Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 52790f2b693Smrg 52890f2b693Smrg if (drmmode_crtc->scanout_update_pending) { 52990f2b693Smrg amdgpu_drm_wait_pending_flip(crtc); 53090f2b693Smrg amdgpu_drm_abort_entry(drmmode_crtc->scanout_update_pending); 53190f2b693Smrg drmmode_crtc->scanout_update_pending = 0; 53290f2b693Smrg amdgpu_drm_queue_handle_deferred(crtc); 53390f2b693Smrg } 53490f2b693Smrg 53524b90cf4Smrg drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, 53624b90cf4Smrg &drmmode_crtc->scanout[0]); 53724b90cf4Smrg drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, 53824b90cf4Smrg &drmmode_crtc->scanout[1]); 539d6c0b56eSmrg 54024b90cf4Smrg if (drmmode_crtc->scanout_damage) 541504d986fSmrg DamageDestroy(drmmode_crtc->scanout_damage); 542d6c0b56eSmrg} 543d6c0b56eSmrg 54424b90cf4SmrgPixmapPtr 54511bf0794Smrgdrmmode_crtc_scanout_create(xf86CrtcPtr crtc, struct drmmode_scanout *scanout, 54611bf0794Smrg int width, int height) 547d6c0b56eSmrg{ 548d6c0b56eSmrg ScrnInfoPtr pScrn = crtc->scrn; 549d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 550d6c0b56eSmrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 55111bf0794Smrg int pitch; 552d6c0b56eSmrg 55311bf0794Smrg if (scanout->pixmap) { 554d6c0b56eSmrg if (scanout->width == width && scanout->height == height) 55511bf0794Smrg return scanout->pixmap; 556d6c0b56eSmrg 557d6c0b56eSmrg drmmode_crtc_scanout_destroy(drmmode, scanout); 558d6c0b56eSmrg } 559d6c0b56eSmrg 560d6c0b56eSmrg scanout->bo = amdgpu_alloc_pixmap_bo(pScrn, width, height, 56111bf0794Smrg pScrn->depth, 0, 56211bf0794Smrg pScrn->bitsPerPixel, &pitch); 563d6c0b56eSmrg if (!scanout->bo) { 564d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 56511bf0794Smrg "Failed to allocate scanout buffer memory\n"); 56624b90cf4Smrg return NULL; 567d6c0b56eSmrg } 568d6c0b56eSmrg 569d6c0b56eSmrg scanout->pixmap = drmmode_create_bo_pixmap(pScrn, 570d6c0b56eSmrg width, height, 571d6c0b56eSmrg pScrn->depth, 572d6c0b56eSmrg pScrn->bitsPerPixel, 57311bf0794Smrg pitch, scanout->bo); 57424b90cf4Smrg if (!scanout->pixmap) { 57524b90cf4Smrg ErrorF("failed to create CRTC scanout pixmap\n"); 57624b90cf4Smrg goto error; 57724b90cf4Smrg } 57824b90cf4Smrg 57924b90cf4Smrg if (amdgpu_pixmap_get_fb(scanout->pixmap)) { 58011bf0794Smrg scanout->width = width; 58111bf0794Smrg scanout->height = height; 58211bf0794Smrg } else { 58324b90cf4Smrg ErrorF("failed to create CRTC scanout FB\n"); 58424b90cf4Smrgerror: 58511bf0794Smrg drmmode_crtc_scanout_destroy(drmmode, scanout); 586d6c0b56eSmrg } 587d6c0b56eSmrg 58811bf0794Smrg return scanout->pixmap; 589d6c0b56eSmrg} 590d6c0b56eSmrg 591d6c0b56eSmrgstatic void 592d6c0b56eSmrgamdgpu_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure) 593d6c0b56eSmrg{ 59424b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = closure; 59524b90cf4Smrg 59624b90cf4Smrg if (drmmode_crtc->ignore_damage) { 59724b90cf4Smrg RegionEmpty(&damage->damage); 59824b90cf4Smrg drmmode_crtc->ignore_damage = FALSE; 59924b90cf4Smrg return; 60024b90cf4Smrg } 60124b90cf4Smrg 602d6c0b56eSmrg /* Only keep track of the extents */ 603d6c0b56eSmrg RegionUninit(&damage->damage); 604d6c0b56eSmrg damage->damage.data = NULL; 605d6c0b56eSmrg} 606d6c0b56eSmrg 60724b90cf4Smrgstatic void 60824b90cf4Smrgdrmmode_screen_damage_destroy(DamagePtr damage, void *closure) 60924b90cf4Smrg{ 61024b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = closure; 61124b90cf4Smrg 61224b90cf4Smrg drmmode_crtc->scanout_damage = NULL; 61324b90cf4Smrg RegionUninit(&drmmode_crtc->scanout_last_region); 61424b90cf4Smrg} 61524b90cf4Smrg 616d6c0b56eSmrgstatic Bool 617d6c0b56eSmrgdrmmode_can_use_hw_cursor(xf86CrtcPtr crtc) 618d6c0b56eSmrg{ 619d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn); 620d6c0b56eSmrg 621d6c0b56eSmrg /* Check for Option "SWcursor" */ 622d6c0b56eSmrg if (xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) 623d6c0b56eSmrg return FALSE; 624d6c0b56eSmrg 625d6c0b56eSmrg /* Fall back to SW cursor if the CRTC is transformed */ 626d6c0b56eSmrg if (crtc->transformPresent) 627d6c0b56eSmrg return FALSE; 628d6c0b56eSmrg 62924b90cf4Smrg#if XF86_CRTC_VERSION < 7 630d6c0b56eSmrg /* Xorg doesn't correctly handle cursor position transform in the 631d6c0b56eSmrg * rotation case 632d6c0b56eSmrg */ 633d6c0b56eSmrg if (crtc->driverIsPerformingTransform && 634d6c0b56eSmrg (crtc->rotation & 0xf) != RR_Rotate_0) 635d6c0b56eSmrg return FALSE; 636d6c0b56eSmrg#endif 637d6c0b56eSmrg 638504d986fSmrg /* HW cursor not supported with RandR 1.4 multihead up to 1.18.99.901 */ 639504d986fSmrg if (xorgGetVersion() <= XORG_VERSION_NUMERIC(1,18,99,901,0) && 640504d986fSmrg !xorg_list_is_empty(&crtc->scrn->pScreen->pixmap_dirty_list)) 641d6c0b56eSmrg return FALSE; 642d6c0b56eSmrg 643d6c0b56eSmrg return TRUE; 644d6c0b56eSmrg} 645d6c0b56eSmrg 64611bf0794Smrgstatic void 64711bf0794Smrgdrmmode_crtc_update_tear_free(xf86CrtcPtr crtc) 64811bf0794Smrg{ 64911bf0794Smrg AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn); 65011bf0794Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 65111bf0794Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 65211bf0794Smrg int i; 65311bf0794Smrg 65411bf0794Smrg drmmode_crtc->tear_free = FALSE; 65511bf0794Smrg 65611bf0794Smrg for (i = 0; i < xf86_config->num_output; i++) { 65711bf0794Smrg xf86OutputPtr output = xf86_config->output[i]; 65811bf0794Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 65911bf0794Smrg 66011bf0794Smrg if (output->crtc != crtc) 66111bf0794Smrg continue; 66211bf0794Smrg 66311bf0794Smrg if (drmmode_output->tear_free == 1 || 66411bf0794Smrg (drmmode_output->tear_free == 2 && 66524b90cf4Smrg (crtc->scrn->pScreen->isGPU || 66611bf0794Smrg info->shadow_primary || 66711bf0794Smrg crtc->transformPresent || crtc->rotation != RR_Rotate_0))) { 66811bf0794Smrg drmmode_crtc->tear_free = TRUE; 66911bf0794Smrg return; 67011bf0794Smrg } 67111bf0794Smrg } 67211bf0794Smrg} 67311bf0794Smrg 67411bf0794Smrg#if XF86_CRTC_VERSION < 7 67511bf0794Smrg#define XF86DriverTransformOutput TRUE 67611bf0794Smrg#define XF86DriverTransformNone FALSE 67711bf0794Smrg#endif 67811bf0794Smrg 679d6c0b56eSmrgstatic Bool 680d6c0b56eSmrgdrmmode_handle_transform(xf86CrtcPtr crtc) 681d6c0b56eSmrg{ 682d6c0b56eSmrg Bool ret; 683d6c0b56eSmrg 68424b90cf4Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 68535d5b7c7Smrg crtc->driverIsPerformingTransform = XF86DriverTransformOutput; 68624b90cf4Smrg#else 68724b90cf4Smrg crtc->driverIsPerformingTransform = !crtc->transformPresent && 68824b90cf4Smrg (crtc->rotation & 0xf) == RR_Rotate_0; 68924b90cf4Smrg#endif 690d6c0b56eSmrg 691d6c0b56eSmrg ret = xf86CrtcRotate(crtc); 692d6c0b56eSmrg 693d6c0b56eSmrg crtc->driverIsPerformingTransform &= ret && crtc->transform_in_use; 694d6c0b56eSmrg 695d6c0b56eSmrg return ret; 696d6c0b56eSmrg} 697d6c0b56eSmrg 69811bf0794Smrg 69911bf0794Smrgstatic void 70011bf0794Smrgdrmmode_crtc_prime_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode, 70124b90cf4Smrg unsigned scanout_id, struct drmmode_fb **fb, 70224b90cf4Smrg int *x, int *y) 70311bf0794Smrg{ 70411bf0794Smrg ScrnInfoPtr scrn = crtc->scrn; 70511bf0794Smrg ScreenPtr screen = scrn->pScreen; 70611bf0794Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 70711bf0794Smrg 70811bf0794Smrg if (drmmode_crtc->tear_free && 70911bf0794Smrg !drmmode_crtc->scanout[1].pixmap) { 71011bf0794Smrg RegionPtr region; 71111bf0794Smrg BoxPtr box; 71211bf0794Smrg 71311bf0794Smrg drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], 71411bf0794Smrg mode->HDisplay, 71511bf0794Smrg mode->VDisplay); 71611bf0794Smrg region = &drmmode_crtc->scanout_last_region; 71711bf0794Smrg RegionUninit(region); 71811bf0794Smrg region->data = NULL; 71911bf0794Smrg box = RegionExtents(region); 72011bf0794Smrg box->x1 = crtc->x; 72111bf0794Smrg box->y1 = crtc->y; 72211bf0794Smrg box->x2 = crtc->x + mode->HDisplay; 72311bf0794Smrg box->y2 = crtc->y + mode->VDisplay; 72411bf0794Smrg } 72511bf0794Smrg 72611bf0794Smrg if (scanout_id != drmmode_crtc->scanout_id) { 72711bf0794Smrg PixmapDirtyUpdatePtr dirty = NULL; 72811bf0794Smrg 72911bf0794Smrg xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, 73011bf0794Smrg ent) { 73124b90cf4Smrg if (amdgpu_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) { 73211bf0794Smrg dirty->slave_dst = 73311bf0794Smrg drmmode_crtc->scanout[scanout_id].pixmap; 73411bf0794Smrg break; 73511bf0794Smrg } 73611bf0794Smrg } 73711bf0794Smrg 73811bf0794Smrg if (!drmmode_crtc->tear_free) { 73911bf0794Smrg GCPtr gc = GetScratchGC(scrn->depth, screen); 74011bf0794Smrg 74111bf0794Smrg ValidateGC(&drmmode_crtc->scanout[0].pixmap->drawable, gc); 74211bf0794Smrg gc->ops->CopyArea(&drmmode_crtc->scanout[1].pixmap->drawable, 74311bf0794Smrg &drmmode_crtc->scanout[0].pixmap->drawable, 74411bf0794Smrg gc, 0, 0, mode->HDisplay, mode->VDisplay, 74511bf0794Smrg 0, 0); 74611bf0794Smrg FreeScratchGC(gc); 74711bf0794Smrg amdgpu_glamor_finish(scrn); 74811bf0794Smrg } 74911bf0794Smrg } 75011bf0794Smrg 75124b90cf4Smrg *fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap); 75211bf0794Smrg *x = *y = 0; 75311bf0794Smrg drmmode_crtc->scanout_id = scanout_id; 75411bf0794Smrg} 75511bf0794Smrg 75611bf0794Smrg 75711bf0794Smrgstatic void 75811bf0794Smrgdrmmode_crtc_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode, 75924b90cf4Smrg unsigned scanout_id, struct drmmode_fb **fb, int *x, 76024b90cf4Smrg int *y) 76111bf0794Smrg{ 76211bf0794Smrg ScrnInfoPtr scrn = crtc->scrn; 76311bf0794Smrg ScreenPtr screen = scrn->pScreen; 76411bf0794Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 76511bf0794Smrg 76624b90cf4Smrg drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[scanout_id], 76711bf0794Smrg mode->HDisplay, mode->VDisplay); 76811bf0794Smrg if (drmmode_crtc->tear_free) { 76924b90cf4Smrg drmmode_crtc_scanout_create(crtc, 77024b90cf4Smrg &drmmode_crtc->scanout[scanout_id ^ 1], 77111bf0794Smrg mode->HDisplay, mode->VDisplay); 77211bf0794Smrg } 77311bf0794Smrg 77424b90cf4Smrg if (drmmode_crtc->scanout[scanout_id].pixmap && 77524b90cf4Smrg (!drmmode_crtc->tear_free || 77624b90cf4Smrg drmmode_crtc->scanout[scanout_id ^ 1].pixmap)) { 77735d5b7c7Smrg BoxRec extents = { .x1 = 0, .y1 = 0, 77835d5b7c7Smrg .x2 = scrn->virtualX, .y2 = scrn->virtualY }; 77911bf0794Smrg 78011bf0794Smrg if (!drmmode_crtc->scanout_damage) { 78111bf0794Smrg drmmode_crtc->scanout_damage = 78211bf0794Smrg DamageCreate(amdgpu_screen_damage_report, 78324b90cf4Smrg drmmode_screen_damage_destroy, 78424b90cf4Smrg DamageReportRawRegion, 78524b90cf4Smrg TRUE, screen, drmmode_crtc); 78624b90cf4Smrg DamageRegister(&screen->root->drawable, 78711bf0794Smrg drmmode_crtc->scanout_damage); 78811bf0794Smrg } 78911bf0794Smrg 79024b90cf4Smrg *fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap); 79111bf0794Smrg *x = *y = 0; 79211bf0794Smrg 79390f2b693Smrg if (amdgpu_scanout_do_update(crtc, scanout_id, 79490f2b693Smrg screen->GetWindowPixmap(screen->root), 79590f2b693Smrg extents)) { 79690f2b693Smrg RegionEmpty(DamageRegion(drmmode_crtc->scanout_damage)); 79790f2b693Smrg amdgpu_glamor_finish(scrn); 79890f2b693Smrg 79990f2b693Smrg if (!drmmode_crtc->flip_pending) { 80090f2b693Smrg amdgpu_drm_abort_entry(drmmode_crtc-> 80190f2b693Smrg scanout_update_pending); 80290f2b693Smrg } 80390f2b693Smrg } 80411bf0794Smrg } 80511bf0794Smrg} 80611bf0794Smrg 80735d5b7c7Smrgstatic char *cm_prop_names[] = { 80835d5b7c7Smrg "DEGAMMA_LUT", 80935d5b7c7Smrg "CTM", 81035d5b7c7Smrg "GAMMA_LUT", 81135d5b7c7Smrg "DEGAMMA_LUT_SIZE", 81235d5b7c7Smrg "GAMMA_LUT_SIZE", 81335d5b7c7Smrg}; 81435d5b7c7Smrg 81535d5b7c7Smrg/** 81635d5b7c7Smrg * Return the enum of the color management property with the given name. 81735d5b7c7Smrg */ 81835d5b7c7Smrgstatic enum drmmode_cm_prop get_cm_enum_from_str(const char *prop_name) 81935d5b7c7Smrg{ 82035d5b7c7Smrg enum drmmode_cm_prop ret; 82135d5b7c7Smrg 82235d5b7c7Smrg for (ret = 0; ret < CM_NUM_PROPS; ret++) { 82335d5b7c7Smrg if (!strcmp(prop_name, cm_prop_names[ret])) 82435d5b7c7Smrg return ret; 82535d5b7c7Smrg } 82635d5b7c7Smrg return CM_INVALID_PROP; 82735d5b7c7Smrg} 82835d5b7c7Smrg 82935d5b7c7Smrg/** 83035d5b7c7Smrg * If legacy LUT is a, and non-legacy LUT is b, then the result of b(a(x)) is 83135d5b7c7Smrg * returned in out_lut. out_lut's length is expected to be the same as the 83235d5b7c7Smrg * non-legacy LUT b. 83335d5b7c7Smrg * 83435d5b7c7Smrg * @a_(red|green|blue): The red, green, and blue components of the legacy LUT. 83535d5b7c7Smrg * @b_lut: The non-legacy LUT, in DRM's color LUT format. 83635d5b7c7Smrg * @out_lut: The composed LUT, in DRM's color LUT format. 83735d5b7c7Smrg * @len_a: Length of legacy lut. 83835d5b7c7Smrg * @len_b: Length of non-legacy lut. 83935d5b7c7Smrg */ 84035d5b7c7Smrgstatic void drmmode_lut_compose(uint16_t *a_red, 84135d5b7c7Smrg uint16_t *a_green, 84235d5b7c7Smrg uint16_t *a_blue, 84335d5b7c7Smrg struct drm_color_lut *b_lut, 84435d5b7c7Smrg struct drm_color_lut *out_lut, 84535d5b7c7Smrg uint32_t len_a, uint32_t len_b) 84635d5b7c7Smrg{ 84735d5b7c7Smrg uint32_t i_l, i_r, i; 84835d5b7c7Smrg uint32_t i_amax, i_bmax; 84935d5b7c7Smrg uint32_t coeff_ibmax; 85035d5b7c7Smrg uint32_t j; 85135d5b7c7Smrg uint64_t a_out_ibmax; 85235d5b7c7Smrg int color; 85335d5b7c7Smrg size_t struct_size = sizeof(struct drm_color_lut); 85435d5b7c7Smrg 85535d5b7c7Smrg uint32_t max_lut = (1 << 16) - 1; 85635d5b7c7Smrg 85735d5b7c7Smrg i_amax = len_a - 1; 85835d5b7c7Smrg i_bmax = len_b - 1; 85935d5b7c7Smrg 86035d5b7c7Smrg /* A linear interpolation is done on the legacy LUT before it is 86135d5b7c7Smrg * composed, to bring it up-to-size with the non-legacy LUT. The 86235d5b7c7Smrg * interpolation uses integers by keeping things multiplied until the 86335d5b7c7Smrg * last moment. 86435d5b7c7Smrg */ 86535d5b7c7Smrg for (color = 0; color < 3; color++) { 86635d5b7c7Smrg uint16_t *a, *b, *out; 86735d5b7c7Smrg 86835d5b7c7Smrg /* Set the initial pointers to the right color components. The 86935d5b7c7Smrg * inner for-loop will then maintain the correct offset from 87035d5b7c7Smrg * the initial element. 87135d5b7c7Smrg */ 87235d5b7c7Smrg if (color == 0) { 87335d5b7c7Smrg a = a_red; 87435d5b7c7Smrg b = &b_lut[0].red; 87535d5b7c7Smrg out = &out_lut[0].red; 87635d5b7c7Smrg } else if (color == 1) { 87735d5b7c7Smrg a = a_green; 87835d5b7c7Smrg b = &b_lut[0].green; 87935d5b7c7Smrg out = &out_lut[0].green; 88035d5b7c7Smrg } else { 88135d5b7c7Smrg a = a_blue; 88235d5b7c7Smrg b = &b_lut[0].blue; 88335d5b7c7Smrg out = &out_lut[0].blue; 88435d5b7c7Smrg } 88535d5b7c7Smrg 88635d5b7c7Smrg for (i = 0; i < len_b; i++) { 88735d5b7c7Smrg /* i_l and i_r tracks the left and right elements in 88835d5b7c7Smrg * a_lut, to the sample point i. Also handle last 88935d5b7c7Smrg * element edge case, when i_l = i_amax. 89035d5b7c7Smrg */ 89135d5b7c7Smrg i_l = i * i_amax / i_bmax; 89235d5b7c7Smrg i_r = i_l + !!(i_amax - i_l); 89335d5b7c7Smrg 89435d5b7c7Smrg /* coeff is intended to be in [0, 1), depending on 89535d5b7c7Smrg * where sample i is between i_l and i_r. We keep it 89635d5b7c7Smrg * multiplied with i_bmax throughout to maintain 89735d5b7c7Smrg * precision */ 89835d5b7c7Smrg coeff_ibmax = (i * i_amax) - (i_l * i_bmax); 89935d5b7c7Smrg a_out_ibmax = i_bmax * a[i_l] + 90035d5b7c7Smrg coeff_ibmax * (a[i_r] - a[i_l]); 90135d5b7c7Smrg 90235d5b7c7Smrg /* j = floor((a_out/max_lut)*i_bmax). 90335d5b7c7Smrg * i.e. the element in LUT b that a_out maps to. We 90435d5b7c7Smrg * have to divide by max_lut to normalize a_out, since 90535d5b7c7Smrg * values in the LUTs are [0, 1<<16) 90635d5b7c7Smrg */ 90735d5b7c7Smrg j = a_out_ibmax / max_lut; 90835d5b7c7Smrg *(uint16_t*)((void*)out + (i*struct_size)) = 90935d5b7c7Smrg *(uint16_t*)((void*)b + (j*struct_size)); 91035d5b7c7Smrg } 91135d5b7c7Smrg } 91235d5b7c7Smrg 91335d5b7c7Smrg for (i = 0; i < len_b; i++) 91435d5b7c7Smrg out_lut[i].reserved = 0; 91535d5b7c7Smrg} 91635d5b7c7Smrg 91735d5b7c7Smrg/** 91835d5b7c7Smrg * Resize a LUT, using linear interpolation. 91935d5b7c7Smrg * 92035d5b7c7Smrg * @in_(red|green|blue): Legacy LUT components 92135d5b7c7Smrg * @out_lut: The resized LUT is returned here, in DRM color LUT format. 92235d5b7c7Smrg * @len_in: Length of legacy LUT. 92335d5b7c7Smrg * @len_out: Length of out_lut, i.e. the target size. 92435d5b7c7Smrg */ 92535d5b7c7Smrgstatic void drmmode_lut_interpolate(uint16_t *in_red, 92635d5b7c7Smrg uint16_t *in_green, 92735d5b7c7Smrg uint16_t *in_blue, 92835d5b7c7Smrg struct drm_color_lut *out_lut, 92935d5b7c7Smrg uint32_t len_in, uint32_t len_out) 93035d5b7c7Smrg{ 93135d5b7c7Smrg uint32_t i_l, i_r, i; 93235d5b7c7Smrg uint32_t i_amax, i_bmax; 93335d5b7c7Smrg uint32_t coeff_ibmax; 93435d5b7c7Smrg uint64_t out_ibmax; 93535d5b7c7Smrg int color; 93635d5b7c7Smrg size_t struct_size = sizeof(struct drm_color_lut); 93735d5b7c7Smrg 93835d5b7c7Smrg i_amax = len_in - 1; 93935d5b7c7Smrg i_bmax = len_out - 1; 94035d5b7c7Smrg 94135d5b7c7Smrg /* See @drmmode_lut_compose for details */ 94235d5b7c7Smrg for (color = 0; color < 3; color++) { 94335d5b7c7Smrg uint16_t *in, *out; 94435d5b7c7Smrg 94535d5b7c7Smrg if (color == 0) { 94635d5b7c7Smrg in = in_red; 94735d5b7c7Smrg out = &out_lut[0].red; 94835d5b7c7Smrg } else if (color == 1) { 94935d5b7c7Smrg in = in_green; 95035d5b7c7Smrg out = &out_lut[0].green; 95135d5b7c7Smrg } else { 95235d5b7c7Smrg in = in_blue; 95335d5b7c7Smrg out = &out_lut[0].blue; 95435d5b7c7Smrg } 95535d5b7c7Smrg 95635d5b7c7Smrg for (i = 0; i < len_out; i++) { 95735d5b7c7Smrg i_l = i * i_amax / i_bmax; 95835d5b7c7Smrg i_r = i_l + !!(i_amax - i_l); 95935d5b7c7Smrg 96035d5b7c7Smrg coeff_ibmax = (i * i_amax) - (i_l * i_bmax); 96135d5b7c7Smrg out_ibmax = i_bmax * in[i_l] + 96235d5b7c7Smrg coeff_ibmax * (in[i_r] - in[i_l]); 96335d5b7c7Smrg 96435d5b7c7Smrg *(uint16_t*)((void*)out + (i*struct_size)) = 96535d5b7c7Smrg out_ibmax / i_bmax; 96635d5b7c7Smrg } 96735d5b7c7Smrg } 96835d5b7c7Smrg 96935d5b7c7Smrg for (i = 0; i < len_out; i++) 97035d5b7c7Smrg out_lut[i].reserved = 0; 97135d5b7c7Smrg} 97235d5b7c7Smrg 97335d5b7c7Smrg/** 97435d5b7c7Smrg * Configure and change a color property on a CRTC, through RandR. Only the 97535d5b7c7Smrg * specified output will be affected, even if the CRTC is attached to multiple 97635d5b7c7Smrg * outputs. Note that changes will be non-pending: the changes won't be pushed 97735d5b7c7Smrg * to kernel driver. 97835d5b7c7Smrg * 97935d5b7c7Smrg * @output: RandR output to set the property on. 98035d5b7c7Smrg * @crtc: The driver-private CRTC object containing the color properties. 98135d5b7c7Smrg * If this is NULL, "disabled" values of 0 will be used. 98235d5b7c7Smrg * @cm_prop_index: Color management property to configure and change. 98335d5b7c7Smrg * 98435d5b7c7Smrg * Return 0 on success, X-defined error code otherwise. 98535d5b7c7Smrg */ 98635d5b7c7Smrgstatic int rr_configure_and_change_cm_property(xf86OutputPtr output, 98735d5b7c7Smrg drmmode_crtc_private_ptr crtc, 98835d5b7c7Smrg enum drmmode_cm_prop cm_prop_index) 98935d5b7c7Smrg{ 99035d5b7c7Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 99135d5b7c7Smrg drmmode_ptr drmmode = drmmode_output->drmmode; 99235d5b7c7Smrg Bool need_configure = TRUE; 99335d5b7c7Smrg unsigned long length = 0; 99435d5b7c7Smrg void *data = NULL; 99535d5b7c7Smrg int format = 0; 99635d5b7c7Smrg uint32_t zero = 0; 99735d5b7c7Smrg INT32 range[2]; 99835d5b7c7Smrg Atom atom; 99935d5b7c7Smrg int err; 100035d5b7c7Smrg 100135d5b7c7Smrg if (cm_prop_index == CM_INVALID_PROP) 100235d5b7c7Smrg return BadName; 100335d5b7c7Smrg 100435d5b7c7Smrg switch(cm_prop_index) { 100535d5b7c7Smrg case CM_GAMMA_LUT_SIZE: 100635d5b7c7Smrg format = 32; 100735d5b7c7Smrg length = 1; 100835d5b7c7Smrg data = &drmmode->gamma_lut_size; 100935d5b7c7Smrg range[0] = 0; 101035d5b7c7Smrg range[1] = -1; 101135d5b7c7Smrg break; 101235d5b7c7Smrg case CM_DEGAMMA_LUT_SIZE: 101335d5b7c7Smrg format = 32; 101435d5b7c7Smrg length = 1; 101535d5b7c7Smrg data = &drmmode->degamma_lut_size; 101635d5b7c7Smrg range[0] = 0; 101735d5b7c7Smrg range[1] = -1; 101835d5b7c7Smrg break; 101935d5b7c7Smrg case CM_GAMMA_LUT: 102035d5b7c7Smrg format = 16; 102135d5b7c7Smrg range[0] = 0; 102235d5b7c7Smrg range[1] = (1 << 16) - 1; // Max 16 bit unsigned int. 102335d5b7c7Smrg if (crtc && crtc->gamma_lut) { 102435d5b7c7Smrg /* Convert from 8bit size to 16bit size */ 102535d5b7c7Smrg length = sizeof(*crtc->gamma_lut) >> 1; 102635d5b7c7Smrg length *= drmmode->gamma_lut_size; 102735d5b7c7Smrg data = crtc->gamma_lut; 102835d5b7c7Smrg } else { 102935d5b7c7Smrg length = 1; 103035d5b7c7Smrg data = &zero; 103135d5b7c7Smrg } 103235d5b7c7Smrg break; 103335d5b7c7Smrg case CM_DEGAMMA_LUT: 103435d5b7c7Smrg format = 16; 103535d5b7c7Smrg range[0] = 0; 103635d5b7c7Smrg range[1] = (1 << 16) - 1; 103735d5b7c7Smrg if (crtc && crtc->degamma_lut) { 103835d5b7c7Smrg length = sizeof(*crtc->degamma_lut) >> 1; 103935d5b7c7Smrg length *= drmmode->degamma_lut_size; 104035d5b7c7Smrg data = crtc->degamma_lut; 104135d5b7c7Smrg } else { 104235d5b7c7Smrg length = 1; 104335d5b7c7Smrg data = &zero; 104435d5b7c7Smrg } 104535d5b7c7Smrg break; 104635d5b7c7Smrg case CM_CTM: 104735d5b7c7Smrg /* CTM is fixed-point S31.32 format. */ 104835d5b7c7Smrg format = 32; 104935d5b7c7Smrg need_configure = FALSE; 105035d5b7c7Smrg if (crtc && crtc->ctm) { 105135d5b7c7Smrg /* Convert from 8bit size to 32bit size */ 105235d5b7c7Smrg length = sizeof(*crtc->ctm) >> 2; 105335d5b7c7Smrg data = crtc->ctm; 105435d5b7c7Smrg } else { 105535d5b7c7Smrg length = 1; 105635d5b7c7Smrg data = &zero; 105735d5b7c7Smrg } 105835d5b7c7Smrg break; 105935d5b7c7Smrg default: 106035d5b7c7Smrg return BadName; 106135d5b7c7Smrg } 106235d5b7c7Smrg 106335d5b7c7Smrg atom = MakeAtom(cm_prop_names[cm_prop_index], 106435d5b7c7Smrg strlen(cm_prop_names[cm_prop_index]), 106535d5b7c7Smrg TRUE); 106635d5b7c7Smrg if (!atom) 106735d5b7c7Smrg return BadAlloc; 106835d5b7c7Smrg 106935d5b7c7Smrg if (need_configure) { 107035d5b7c7Smrg err = RRConfigureOutputProperty(output->randr_output, atom, 107135d5b7c7Smrg FALSE, TRUE, FALSE, 2, range); 107235d5b7c7Smrg if (err) { 107335d5b7c7Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 107435d5b7c7Smrg "Configuring color management property %s failed with %d\n", 107535d5b7c7Smrg cm_prop_names[cm_prop_index], err); 107635d5b7c7Smrg return err; 107735d5b7c7Smrg } 107835d5b7c7Smrg } 107935d5b7c7Smrg 108035d5b7c7Smrg /* Always issue a non-pending change. We'll push cm properties 108135d5b7c7Smrg * ourselves. 108235d5b7c7Smrg */ 108335d5b7c7Smrg err = RRChangeOutputProperty(output->randr_output, atom, 108435d5b7c7Smrg XA_INTEGER, format, 108535d5b7c7Smrg PropModeReplace, 108635d5b7c7Smrg length, data, FALSE, FALSE); 108735d5b7c7Smrg if (err) 108835d5b7c7Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 108935d5b7c7Smrg "Changing color management property %s failed with %d\n", 109035d5b7c7Smrg cm_prop_names[cm_prop_index], err); 109135d5b7c7Smrg return err; 109235d5b7c7Smrg} 109335d5b7c7Smrg 109435d5b7c7Smrg/** 109535d5b7c7Smrg* Stage a color management property. This parses the property value, according 109635d5b7c7Smrg* to the cm property type, then stores it within the driver-private CRTC 109735d5b7c7Smrg* object. 109835d5b7c7Smrg* 109935d5b7c7Smrg* @crtc: The CRTC to stage the new color management properties in 110035d5b7c7Smrg* @cm_prop_index: The color property to stage 110135d5b7c7Smrg* @value: The RandR property value to stage 110235d5b7c7Smrg* 110335d5b7c7Smrg* Return 0 on success, X-defined error code on failure. 110435d5b7c7Smrg*/ 110535d5b7c7Smrgstatic int drmmode_crtc_stage_cm_prop(xf86CrtcPtr crtc, 110635d5b7c7Smrg enum drmmode_cm_prop cm_prop_index, 110735d5b7c7Smrg RRPropertyValuePtr value) 110835d5b7c7Smrg{ 110935d5b7c7Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 111035d5b7c7Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 111135d5b7c7Smrg size_t expected_bytes = 0; 111235d5b7c7Smrg void **blob_data = NULL; 111335d5b7c7Smrg Bool use_default = FALSE; 111435d5b7c7Smrg 111535d5b7c7Smrg /* Update properties on the driver-private CRTC */ 111635d5b7c7Smrg switch (cm_prop_index) { 111735d5b7c7Smrg case CM_GAMMA_LUT: 111835d5b7c7Smrg /* Calculate the expected size of value in bytes */ 111935d5b7c7Smrg expected_bytes = sizeof(struct drm_color_lut) * 112035d5b7c7Smrg drmmode->gamma_lut_size; 112135d5b7c7Smrg 112235d5b7c7Smrg /* For gamma and degamma, we allow a default SRGB curve to be 112335d5b7c7Smrg * set via setting a single element 112435d5b7c7Smrg * 112535d5b7c7Smrg * Otherwise, value size is in terms of the value format. 112635d5b7c7Smrg * Ensure it's also in bytes (<< 1) before comparing with the 112735d5b7c7Smrg * expected bytes. 112835d5b7c7Smrg */ 112935d5b7c7Smrg if (value->size == 1) 113035d5b7c7Smrg use_default = TRUE; 113135d5b7c7Smrg else if (value->type != XA_INTEGER || value->format != 16 || 113235d5b7c7Smrg (size_t)(value->size << 1) != expected_bytes) 113335d5b7c7Smrg return BadLength; 113435d5b7c7Smrg 113535d5b7c7Smrg blob_data = (void**)&drmmode_crtc->gamma_lut; 113635d5b7c7Smrg break; 113735d5b7c7Smrg case CM_DEGAMMA_LUT: 113835d5b7c7Smrg expected_bytes = sizeof(struct drm_color_lut) * 113935d5b7c7Smrg drmmode->degamma_lut_size; 114035d5b7c7Smrg 114135d5b7c7Smrg if (value->size == 1) 114235d5b7c7Smrg use_default = TRUE; 114335d5b7c7Smrg else if (value->type != XA_INTEGER || value->format != 16 || 114435d5b7c7Smrg (size_t)(value->size << 1) != expected_bytes) 114535d5b7c7Smrg return BadLength; 114635d5b7c7Smrg 114735d5b7c7Smrg blob_data = (void**)&drmmode_crtc->degamma_lut; 114835d5b7c7Smrg break; 114935d5b7c7Smrg case CM_CTM: 115035d5b7c7Smrg expected_bytes = sizeof(struct drm_color_ctm); 115135d5b7c7Smrg 115235d5b7c7Smrg if (value->size == 1) 115335d5b7c7Smrg use_default = TRUE; 115435d5b7c7Smrg if (value->type != XA_INTEGER || value->format != 32 || 115535d5b7c7Smrg (size_t)(value->size << 2) != expected_bytes) 115635d5b7c7Smrg return BadLength; 115735d5b7c7Smrg 115835d5b7c7Smrg blob_data = (void**)&drmmode_crtc->ctm; 115935d5b7c7Smrg break; 116035d5b7c7Smrg default: 116135d5b7c7Smrg return BadName; 116235d5b7c7Smrg } 116335d5b7c7Smrg 116435d5b7c7Smrg free(*blob_data); 116535d5b7c7Smrg if (!use_default) { 116635d5b7c7Smrg *blob_data = malloc(expected_bytes); 116735d5b7c7Smrg if (!*blob_data) 116835d5b7c7Smrg return BadAlloc; 116935d5b7c7Smrg memcpy(*blob_data, value->data, expected_bytes); 117035d5b7c7Smrg } else 117135d5b7c7Smrg *blob_data = NULL; 117235d5b7c7Smrg 117335d5b7c7Smrg return Success; 117435d5b7c7Smrg} 117535d5b7c7Smrg 117635d5b7c7Smrg/** 117735d5b7c7Smrg * Push staged color management properties on the CRTC to DRM. 117835d5b7c7Smrg * 117935d5b7c7Smrg * @crtc: The CRTC containing staged properties 118035d5b7c7Smrg * @cm_prop_index: The color property to push 118135d5b7c7Smrg * 118235d5b7c7Smrg * Return 0 on success, X-defined error codes on failure. 118335d5b7c7Smrg */ 118435d5b7c7Smrgstatic int drmmode_crtc_push_cm_prop(xf86CrtcPtr crtc, 118535d5b7c7Smrg enum drmmode_cm_prop cm_prop_index) 118635d5b7c7Smrg{ 118735d5b7c7Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 118835d5b7c7Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 118935d5b7c7Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 119035d5b7c7Smrg Bool free_blob_data = FALSE; 119135d5b7c7Smrg uint32_t created_blob_id = 0; 119235d5b7c7Smrg uint32_t drm_prop_id; 119335d5b7c7Smrg size_t expected_bytes = 0; 119435d5b7c7Smrg void *blob_data = NULL; 119535d5b7c7Smrg int ret; 119635d5b7c7Smrg 119735d5b7c7Smrg switch (cm_prop_index) { 119835d5b7c7Smrg case CM_GAMMA_LUT: 119935d5b7c7Smrg /* Calculate the expected size of value in bytes */ 120035d5b7c7Smrg expected_bytes = sizeof(struct drm_color_lut) * 120135d5b7c7Smrg drmmode->gamma_lut_size; 120235d5b7c7Smrg 120335d5b7c7Smrg /* Legacy gamma LUT is disabled on deep 30bpp color. In which 120435d5b7c7Smrg * case, directly use non-legacy LUT. 120535d5b7c7Smrg */ 120635d5b7c7Smrg if (!crtc->funcs->gamma_set) { 120735d5b7c7Smrg blob_data = drmmode_crtc->gamma_lut; 120835d5b7c7Smrg goto do_push; 120935d5b7c7Smrg } 121035d5b7c7Smrg 121135d5b7c7Smrg blob_data = malloc(expected_bytes); 121235d5b7c7Smrg if (!blob_data) 121335d5b7c7Smrg return BadAlloc; 121435d5b7c7Smrg 121535d5b7c7Smrg free_blob_data = TRUE; 121635d5b7c7Smrg /* 121735d5b7c7Smrg * Compose legacy and non-legacy LUT if non-legacy was set. 121835d5b7c7Smrg * Otherwise, interpolate legacy LUT to non-legacy size. 121935d5b7c7Smrg */ 122035d5b7c7Smrg if (drmmode_crtc->gamma_lut) { 122135d5b7c7Smrg drmmode_lut_compose(crtc->gamma_red, 122235d5b7c7Smrg crtc->gamma_green, 122335d5b7c7Smrg crtc->gamma_blue, 122435d5b7c7Smrg drmmode_crtc->gamma_lut, 122535d5b7c7Smrg blob_data, crtc->gamma_size, 122635d5b7c7Smrg drmmode->gamma_lut_size); 122735d5b7c7Smrg } else { 122835d5b7c7Smrg drmmode_lut_interpolate(crtc->gamma_red, 122935d5b7c7Smrg crtc->gamma_green, 123035d5b7c7Smrg crtc->gamma_blue, 123135d5b7c7Smrg blob_data, 123235d5b7c7Smrg crtc->gamma_size, 123335d5b7c7Smrg drmmode->gamma_lut_size); 123435d5b7c7Smrg } 123535d5b7c7Smrg break; 123635d5b7c7Smrg case CM_DEGAMMA_LUT: 123735d5b7c7Smrg expected_bytes = sizeof(struct drm_color_lut) * 123835d5b7c7Smrg drmmode->degamma_lut_size; 123935d5b7c7Smrg blob_data = drmmode_crtc->degamma_lut; 124035d5b7c7Smrg break; 124135d5b7c7Smrg case CM_CTM: 124235d5b7c7Smrg expected_bytes = sizeof(struct drm_color_ctm); 124335d5b7c7Smrg blob_data = drmmode_crtc->ctm; 124435d5b7c7Smrg break; 124535d5b7c7Smrg default: 124635d5b7c7Smrg return BadName; 124735d5b7c7Smrg } 124835d5b7c7Smrg 124935d5b7c7Smrgdo_push: 125035d5b7c7Smrg if (blob_data) { 125135d5b7c7Smrg ret = drmModeCreatePropertyBlob(pAMDGPUEnt->fd, 125235d5b7c7Smrg blob_data, expected_bytes, 125335d5b7c7Smrg &created_blob_id); 125435d5b7c7Smrg if (ret) { 125535d5b7c7Smrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 125635d5b7c7Smrg "Creating DRM blob failed with errno %d\n", 125735d5b7c7Smrg ret); 125835d5b7c7Smrg if (free_blob_data) 125935d5b7c7Smrg free(blob_data); 126035d5b7c7Smrg return BadRequest; 126135d5b7c7Smrg } 126235d5b7c7Smrg } 126335d5b7c7Smrg 126435d5b7c7Smrg drm_prop_id = drmmode_crtc->drmmode->cm_prop_ids[cm_prop_index]; 126535d5b7c7Smrg ret = drmModeObjectSetProperty(pAMDGPUEnt->fd, 126635d5b7c7Smrg drmmode_crtc->mode_crtc->crtc_id, 126735d5b7c7Smrg DRM_MODE_OBJECT_CRTC, 126835d5b7c7Smrg drm_prop_id, 126935d5b7c7Smrg (uint64_t)created_blob_id); 127035d5b7c7Smrg 127135d5b7c7Smrg /* If successful, kernel will have a reference already. Safe to destroy 127235d5b7c7Smrg * the blob either way. 127335d5b7c7Smrg */ 127435d5b7c7Smrg if (blob_data) 127535d5b7c7Smrg drmModeDestroyPropertyBlob(pAMDGPUEnt->fd, created_blob_id); 127635d5b7c7Smrg 127735d5b7c7Smrg if (ret) { 127835d5b7c7Smrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 127935d5b7c7Smrg "Setting DRM property blob failed with errno %d\n", 128035d5b7c7Smrg ret); 128135d5b7c7Smrg if (free_blob_data) 128235d5b7c7Smrg free(blob_data); 128335d5b7c7Smrg return BadRequest; 128435d5b7c7Smrg } 128535d5b7c7Smrg 128635d5b7c7Smrg if (free_blob_data) 128735d5b7c7Smrg free(blob_data); 128835d5b7c7Smrg 128935d5b7c7Smrg return Success; 129035d5b7c7Smrg} 129135d5b7c7Smrg 129224b90cf4Smrgstatic void 129324b90cf4Smrgdrmmode_crtc_gamma_do_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, 129424b90cf4Smrg uint16_t *blue, int size) 129524b90cf4Smrg{ 129624b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 129724b90cf4Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 129835d5b7c7Smrg int ret; 129935d5b7c7Smrg 130035d5b7c7Smrg /* Use legacy if no support for non-legacy gamma */ 130135d5b7c7Smrg if (!drmmode_cm_enabled(drmmode_crtc->drmmode)) { 130235d5b7c7Smrg drmModeCrtcSetGamma(pAMDGPUEnt->fd, 130335d5b7c7Smrg drmmode_crtc->mode_crtc->crtc_id, 130435d5b7c7Smrg size, red, green, blue); 130535d5b7c7Smrg return; 130635d5b7c7Smrg } 130724b90cf4Smrg 130835d5b7c7Smrg ret = drmmode_crtc_push_cm_prop(crtc, CM_GAMMA_LUT); 130935d5b7c7Smrg if (ret) 131035d5b7c7Smrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 131135d5b7c7Smrg "Setting Gamma LUT failed with errno %d\n", 131235d5b7c7Smrg ret); 131324b90cf4Smrg} 131424b90cf4Smrg 131524b90cf4SmrgBool 131624b90cf4Smrgdrmmode_set_mode(xf86CrtcPtr crtc, struct drmmode_fb *fb, DisplayModePtr mode, 131724b90cf4Smrg int x, int y) 131824b90cf4Smrg{ 131924b90cf4Smrg ScrnInfoPtr scrn = crtc->scrn; 132024b90cf4Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 132124b90cf4Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 132224b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 132324b90cf4Smrg uint32_t *output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); 132424b90cf4Smrg int output_count = 0; 132524b90cf4Smrg drmModeModeInfo kmode; 132624b90cf4Smrg Bool ret; 132724b90cf4Smrg int i; 132824b90cf4Smrg 132924b90cf4Smrg if (!output_ids) 133024b90cf4Smrg return FALSE; 133124b90cf4Smrg 133224b90cf4Smrg for (i = 0; i < xf86_config->num_output; i++) { 133324b90cf4Smrg xf86OutputPtr output = xf86_config->output[i]; 133424b90cf4Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 133524b90cf4Smrg 133624b90cf4Smrg if (output->crtc != crtc) 133724b90cf4Smrg continue; 133824b90cf4Smrg 133924b90cf4Smrg output_ids[output_count] = drmmode_output->mode_output->connector_id; 134024b90cf4Smrg output_count++; 134124b90cf4Smrg } 134224b90cf4Smrg 134324b90cf4Smrg drmmode_ConvertToKMode(scrn, &kmode, mode); 134424b90cf4Smrg 134524b90cf4Smrg ret = drmModeSetCrtc(pAMDGPUEnt->fd, 134624b90cf4Smrg drmmode_crtc->mode_crtc->crtc_id, 134724b90cf4Smrg fb->handle, x, y, output_ids, 134824b90cf4Smrg output_count, &kmode) == 0; 134924b90cf4Smrg 135024b90cf4Smrg if (ret) { 135124b90cf4Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, fb); 135224b90cf4Smrg } else { 135324b90cf4Smrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 135424b90cf4Smrg "failed to set mode: %s\n", strerror(errno)); 135524b90cf4Smrg } 135624b90cf4Smrg 135724b90cf4Smrg free(output_ids); 135824b90cf4Smrg return ret; 135924b90cf4Smrg} 136024b90cf4Smrg 1361d6c0b56eSmrgstatic Bool 1362d6c0b56eSmrgdrmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, 1363d6c0b56eSmrg Rotation rotation, int x, int y) 1364d6c0b56eSmrg{ 1365d6c0b56eSmrg ScrnInfoPtr pScrn = crtc->scrn; 1366d6c0b56eSmrg ScreenPtr pScreen = pScrn->pScreen; 1367d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1368d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1369d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 1370d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 137190f2b693Smrg Bool handle_deferred = FALSE; 137211bf0794Smrg unsigned scanout_id = 0; 1373d6c0b56eSmrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 1374d6c0b56eSmrg int saved_x, saved_y; 1375d6c0b56eSmrg Rotation saved_rotation; 1376d6c0b56eSmrg DisplayModeRec saved_mode; 1377504d986fSmrg Bool ret = FALSE; 1378d6c0b56eSmrg int i; 137924b90cf4Smrg struct drmmode_fb *fb = NULL; 138024b90cf4Smrg 138124b90cf4Smrg /* The root window contents may be undefined before the WindowExposures 138224b90cf4Smrg * hook is called for it, so bail if we get here before that 138324b90cf4Smrg */ 138424b90cf4Smrg if (pScreen->WindowExposures == AMDGPUWindowExposures_oneshot) 138524b90cf4Smrg return FALSE; 1386d6c0b56eSmrg 1387d6c0b56eSmrg saved_mode = crtc->mode; 1388d6c0b56eSmrg saved_x = crtc->x; 1389d6c0b56eSmrg saved_y = crtc->y; 1390d6c0b56eSmrg saved_rotation = crtc->rotation; 1391d6c0b56eSmrg 1392d6c0b56eSmrg if (mode) { 1393d6c0b56eSmrg crtc->mode = *mode; 1394d6c0b56eSmrg crtc->x = x; 1395d6c0b56eSmrg crtc->y = y; 1396d6c0b56eSmrg crtc->rotation = rotation; 1397d6c0b56eSmrg 1398d6c0b56eSmrg if (!drmmode_handle_transform(crtc)) 1399d6c0b56eSmrg goto done; 1400d6c0b56eSmrg 140111bf0794Smrg drmmode_crtc_update_tear_free(crtc); 140211bf0794Smrg if (drmmode_crtc->tear_free) 140311bf0794Smrg scanout_id = drmmode_crtc->scanout_id; 140435d5b7c7Smrg else 140535d5b7c7Smrg drmmode_crtc->scanout_id = 0; 1406d6c0b56eSmrg 140724b90cf4Smrg if (drmmode_crtc->prime_scanout_pixmap) { 140811bf0794Smrg drmmode_crtc_prime_scanout_update(crtc, mode, scanout_id, 140924b90cf4Smrg &fb, &x, &y); 141024b90cf4Smrg } else if (drmmode_crtc->rotate.pixmap) { 141124b90cf4Smrg fb = amdgpu_pixmap_get_fb(drmmode_crtc->rotate.pixmap); 1412d6c0b56eSmrg x = y = 0; 141311bf0794Smrg 141424b90cf4Smrg } else if (!pScreen->isGPU && 141511bf0794Smrg (drmmode_crtc->tear_free || 1416504d986fSmrg crtc->driverIsPerformingTransform || 1417504d986fSmrg info->shadow_primary)) { 141811bf0794Smrg drmmode_crtc_scanout_update(crtc, mode, scanout_id, 141924b90cf4Smrg &fb, &x, &y); 1420d6c0b56eSmrg } 1421d6c0b56eSmrg 142224b90cf4Smrg if (!fb) 142324b90cf4Smrg fb = amdgpu_pixmap_get_fb(pScreen->GetWindowPixmap(pScreen->root)); 142424b90cf4Smrg if (!fb) { 142524b90cf4Smrg union gbm_bo_handle bo_handle; 142624b90cf4Smrg 142724b90cf4Smrg bo_handle = gbm_bo_get_handle(info->front_buffer->bo.gbm); 142824b90cf4Smrg fb = amdgpu_fb_create(pScrn, pAMDGPUEnt->fd, 142924b90cf4Smrg pScrn->virtualX, pScrn->virtualY, 143024b90cf4Smrg pScrn->displayWidth * info->pixel_bytes, 143124b90cf4Smrg bo_handle.u32); 143224b90cf4Smrg /* Prevent refcnt of ad-hoc FBs from reaching 2 */ 143324b90cf4Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, NULL); 143424b90cf4Smrg drmmode_crtc->fb = fb; 143524b90cf4Smrg } 143624b90cf4Smrg if (!fb) { 143724b90cf4Smrg ErrorF("failed to add FB for modeset\n"); 143824b90cf4Smrg goto done; 1439504d986fSmrg } 1440504d986fSmrg 144135d5b7c7Smrg amdgpu_drm_wait_pending_flip(crtc); 144290f2b693Smrg handle_deferred = TRUE; 144324b90cf4Smrg 144424b90cf4Smrg if (!drmmode_set_mode(crtc, fb, mode, x, y)) 1445d6c0b56eSmrg goto done; 144624b90cf4Smrg 144724b90cf4Smrg ret = TRUE; 1448d6c0b56eSmrg 1449d6c0b56eSmrg if (pScreen) 1450d6c0b56eSmrg xf86CrtcSetScreenSubpixelOrder(pScreen); 1451d6c0b56eSmrg 1452d6c0b56eSmrg drmmode_crtc->need_modeset = FALSE; 1453d6c0b56eSmrg 1454d6c0b56eSmrg /* go through all the outputs and force DPMS them back on? */ 1455d6c0b56eSmrg for (i = 0; i < xf86_config->num_output; i++) { 1456d6c0b56eSmrg xf86OutputPtr output = xf86_config->output[i]; 1457d6c0b56eSmrg 1458d6c0b56eSmrg if (output->crtc != crtc) 1459d6c0b56eSmrg continue; 1460d6c0b56eSmrg 1461d6c0b56eSmrg output->funcs->dpms(output, DPMSModeOn); 1462d6c0b56eSmrg } 1463d6c0b56eSmrg } 1464d6c0b56eSmrg 1465d6c0b56eSmrg /* Compute index of this CRTC into xf86_config->crtc */ 1466d6c0b56eSmrg for (i = 0; i < xf86_config->num_crtc; i++) { 1467d6c0b56eSmrg if (xf86_config->crtc[i] != crtc) 1468d6c0b56eSmrg continue; 1469d6c0b56eSmrg 1470d6c0b56eSmrg if (!crtc->enabled || drmmode_can_use_hw_cursor(crtc)) 1471d6c0b56eSmrg info->hwcursor_disabled &= ~(1 << i); 1472d6c0b56eSmrg else 1473d6c0b56eSmrg info->hwcursor_disabled |= 1 << i; 1474d6c0b56eSmrg 1475d6c0b56eSmrg break; 1476d6c0b56eSmrg } 1477d6c0b56eSmrg 1478d6c0b56eSmrg#ifndef HAVE_XF86_CURSOR_RESET_CURSOR 1479d6c0b56eSmrg if (!info->hwcursor_disabled) 1480d6c0b56eSmrg xf86_reload_cursors(pScreen); 1481d6c0b56eSmrg#endif 1482d6c0b56eSmrg 1483d6c0b56eSmrgdone: 1484d6c0b56eSmrg if (!ret) { 1485d6c0b56eSmrg crtc->x = saved_x; 1486d6c0b56eSmrg crtc->y = saved_y; 1487d6c0b56eSmrg crtc->rotation = saved_rotation; 1488d6c0b56eSmrg crtc->mode = saved_mode; 1489504d986fSmrg } else { 1490d6c0b56eSmrg crtc->active = TRUE; 1491d6c0b56eSmrg 149224b90cf4Smrg if (drmmode_crtc->scanout[scanout_id].pixmap && 149324b90cf4Smrg fb != amdgpu_pixmap_get_fb(drmmode_crtc-> 149435d5b7c7Smrg scanout[scanout_id].pixmap)) { 149590f2b693Smrg drmmode_crtc_scanout_free(crtc); 149635d5b7c7Smrg } else if (!drmmode_crtc->tear_free) { 149711bf0794Smrg drmmode_crtc_scanout_destroy(drmmode, 149811bf0794Smrg &drmmode_crtc->scanout[1]); 149911bf0794Smrg } 1500504d986fSmrg } 1501504d986fSmrg 150290f2b693Smrg if (handle_deferred) 150390f2b693Smrg amdgpu_drm_queue_handle_deferred(crtc); 150490f2b693Smrg 1505d6c0b56eSmrg return ret; 1506d6c0b56eSmrg} 1507d6c0b56eSmrg 1508d6c0b56eSmrgstatic void drmmode_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg) 1509d6c0b56eSmrg{ 1510d6c0b56eSmrg 1511d6c0b56eSmrg} 1512d6c0b56eSmrg 1513d6c0b56eSmrgstatic void drmmode_set_cursor_position(xf86CrtcPtr crtc, int x, int y) 1514d6c0b56eSmrg{ 1515d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1516d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 1517d6c0b56eSmrg 151824b90cf4Smrg#if XF86_CRTC_VERSION < 7 1519d6c0b56eSmrg if (crtc->driverIsPerformingTransform) { 1520d6c0b56eSmrg x += crtc->x; 1521d6c0b56eSmrg y += crtc->y; 1522d6c0b56eSmrg xf86CrtcTransformCursorPos(crtc, &x, &y); 1523d6c0b56eSmrg } 1524d6c0b56eSmrg#endif 1525d6c0b56eSmrg 152690f2b693Smrg drmmode_crtc->cursor_x = x; 152790f2b693Smrg drmmode_crtc->cursor_y = y; 152890f2b693Smrg 1529d6c0b56eSmrg drmModeMoveCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, x, y); 1530d6c0b56eSmrg} 1531d6c0b56eSmrg 153224b90cf4Smrg#if XF86_CRTC_VERSION < 7 1533d6c0b56eSmrg 1534d6c0b56eSmrgstatic int 1535d6c0b56eSmrgdrmmode_cursor_src_offset(Rotation rotation, int width, int height, 1536d6c0b56eSmrg int x_dst, int y_dst) 1537d6c0b56eSmrg{ 1538d6c0b56eSmrg int t; 1539d6c0b56eSmrg 1540d6c0b56eSmrg switch (rotation & 0xf) { 1541d6c0b56eSmrg case RR_Rotate_90: 1542d6c0b56eSmrg t = x_dst; 1543d6c0b56eSmrg x_dst = height - y_dst - 1; 1544d6c0b56eSmrg y_dst = t; 1545d6c0b56eSmrg break; 1546d6c0b56eSmrg case RR_Rotate_180: 1547d6c0b56eSmrg x_dst = width - x_dst - 1; 1548d6c0b56eSmrg y_dst = height - y_dst - 1; 1549d6c0b56eSmrg break; 1550d6c0b56eSmrg case RR_Rotate_270: 1551d6c0b56eSmrg t = x_dst; 1552d6c0b56eSmrg x_dst = y_dst; 1553d6c0b56eSmrg y_dst = width - t - 1; 1554d6c0b56eSmrg break; 1555d6c0b56eSmrg } 1556d6c0b56eSmrg 1557d6c0b56eSmrg if (rotation & RR_Reflect_X) 1558d6c0b56eSmrg x_dst = width - x_dst - 1; 1559d6c0b56eSmrg if (rotation & RR_Reflect_Y) 1560d6c0b56eSmrg y_dst = height - y_dst - 1; 1561d6c0b56eSmrg 1562d6c0b56eSmrg return y_dst * height + x_dst; 1563d6c0b56eSmrg} 1564d6c0b56eSmrg 1565d6c0b56eSmrg#endif 1566d6c0b56eSmrg 156790f2b693Smrgstatic Bool 156890f2b693Smrgdrmmode_cursor_pixel(xf86CrtcPtr crtc, uint32_t *argb, Bool *premultiplied, 156990f2b693Smrg Bool *apply_gamma) 157035d5b7c7Smrg{ 157190f2b693Smrg uint32_t alpha = *argb >> 24; 157290f2b693Smrg uint32_t rgb[3]; 157390f2b693Smrg int i; 157435d5b7c7Smrg 157590f2b693Smrg if (premultiplied) { 157690f2b693Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1, 18, 4, 0, 0) 157790f2b693Smrg if (alpha == 0 && (*argb & 0xffffff) != 0) { 157890f2b693Smrg /* Doesn't look like premultiplied alpha */ 157990f2b693Smrg *premultiplied = FALSE; 158090f2b693Smrg return FALSE; 158190f2b693Smrg } 158290f2b693Smrg#endif 158335d5b7c7Smrg 158490f2b693Smrg if (!(*apply_gamma)) 158590f2b693Smrg return TRUE; 158635d5b7c7Smrg 158790f2b693Smrg if (*argb > (alpha | alpha << 8 | alpha << 16 | alpha << 24)) { 158890f2b693Smrg /* Un-premultiplied R/G/B would overflow gamma LUT, 158990f2b693Smrg * don't apply gamma correction 159090f2b693Smrg */ 159190f2b693Smrg *apply_gamma = FALSE; 159290f2b693Smrg return FALSE; 159390f2b693Smrg } 159490f2b693Smrg } 159524b90cf4Smrg 159690f2b693Smrg if (!alpha) { 159790f2b693Smrg *argb = 0; 159890f2b693Smrg return TRUE; 159990f2b693Smrg } 160024b90cf4Smrg 160190f2b693Smrg /* Extract RGB */ 160224b90cf4Smrg for (i = 0; i < 3; i++) 160390f2b693Smrg rgb[i] = (*argb >> (i * 8)) & 0xff; 160424b90cf4Smrg 160590f2b693Smrg if (premultiplied) { 160690f2b693Smrg /* Un-premultiply alpha */ 160790f2b693Smrg for (i = 0; i < 3; i++) 160890f2b693Smrg rgb[i] = rgb[i] * 0xff / alpha; 160990f2b693Smrg } 161090f2b693Smrg 161190f2b693Smrg if (*apply_gamma) { 161290f2b693Smrg rgb[0] = crtc->gamma_blue[rgb[0]] >> 8; 161390f2b693Smrg rgb[1] = crtc->gamma_green[rgb[1]] >> 8; 161490f2b693Smrg rgb[2] = crtc->gamma_red[rgb[2]] >> 8; 161590f2b693Smrg } 161690f2b693Smrg 161790f2b693Smrg /* Premultiply alpha */ 161890f2b693Smrg for (i = 0; i < 3; i++) 161990f2b693Smrg rgb[i] = rgb[i] * alpha / 0xff; 162024b90cf4Smrg 162190f2b693Smrg *argb = alpha << 24 | rgb[2] << 16 | rgb[1] << 8 | rgb[0]; 162290f2b693Smrg return TRUE; 162324b90cf4Smrg} 162424b90cf4Smrg 162590f2b693Smrgstatic void drmmode_load_cursor_argb(xf86CrtcPtr crtc, CARD32 * image) 1626d6c0b56eSmrg{ 162790f2b693Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1628d6c0b56eSmrg ScrnInfoPtr pScrn = crtc->scrn; 1629d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 163090f2b693Smrg unsigned id = drmmode_crtc->cursor_id; 163190f2b693Smrg Bool premultiplied = TRUE; 163290f2b693Smrg Bool apply_gamma = TRUE; 163390f2b693Smrg uint32_t argb; 163490f2b693Smrg uint32_t *ptr; 163535d5b7c7Smrg 163635d5b7c7Smrg if ((crtc->scrn->depth != 24 && crtc->scrn->depth != 32) || 163735d5b7c7Smrg drmmode_cm_enabled(&info->drmmode)) 163890f2b693Smrg apply_gamma = FALSE; 163990f2b693Smrg 164090f2b693Smrg if (drmmode_crtc->cursor && 164190f2b693Smrg XF86_CRTC_CONFIG_PTR(pScrn)->cursor != drmmode_crtc->cursor) 164290f2b693Smrg id ^= 1; 164390f2b693Smrg 164490f2b693Smrg ptr = (uint32_t *) (drmmode_crtc->cursor_buffer[id]->cpu_ptr); 1645d6c0b56eSmrg 164624b90cf4Smrg#if XF86_CRTC_VERSION < 7 1647d6c0b56eSmrg if (crtc->driverIsPerformingTransform) { 1648d6c0b56eSmrg uint32_t cursor_w = info->cursor_w, cursor_h = info->cursor_h; 1649d6c0b56eSmrg int dstx, dsty; 1650d6c0b56eSmrg int srcoffset; 1651d6c0b56eSmrg 165290f2b693Smrgretry_transform: 1653d6c0b56eSmrg for (dsty = 0; dsty < cursor_h; dsty++) { 1654d6c0b56eSmrg for (dstx = 0; dstx < cursor_w; dstx++) { 1655d6c0b56eSmrg srcoffset = drmmode_cursor_src_offset(crtc->rotation, 1656d6c0b56eSmrg cursor_w, 1657d6c0b56eSmrg cursor_h, 1658d6c0b56eSmrg dstx, dsty); 165990f2b693Smrg argb = image[srcoffset]; 166090f2b693Smrg if (!drmmode_cursor_pixel(crtc, &argb, &premultiplied, 166190f2b693Smrg &apply_gamma)) 166290f2b693Smrg goto retry_transform; 1663d6c0b56eSmrg 166490f2b693Smrg ptr[dsty * info->cursor_w + dstx] = cpu_to_le32(argb); 1665d6c0b56eSmrg } 1666d6c0b56eSmrg } 1667d6c0b56eSmrg } else 1668d6c0b56eSmrg#endif 1669d6c0b56eSmrg { 1670d6c0b56eSmrg uint32_t cursor_size = info->cursor_w * info->cursor_h; 1671d6c0b56eSmrg int i; 1672d6c0b56eSmrg 167390f2b693Smrgretry: 167490f2b693Smrg for (i = 0; i < cursor_size; i++) { 167590f2b693Smrg argb = image[i]; 167690f2b693Smrg if (!drmmode_cursor_pixel(crtc, &argb, &premultiplied, 167790f2b693Smrg &apply_gamma)) 167890f2b693Smrg goto retry; 1679d6c0b56eSmrg 168090f2b693Smrg ptr[i] = cpu_to_le32(argb); 168190f2b693Smrg } 168290f2b693Smrg } 1683d6c0b56eSmrg 168490f2b693Smrg if (id != drmmode_crtc->cursor_id) { 168590f2b693Smrg drmmode_crtc->cursor_id = id; 168690f2b693Smrg crtc->funcs->show_cursor(crtc); 1687d6c0b56eSmrg } 1688d6c0b56eSmrg} 1689d6c0b56eSmrg 1690d6c0b56eSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 1691d6c0b56eSmrg 1692d6c0b56eSmrgstatic Bool drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 * image) 1693d6c0b56eSmrg{ 1694d6c0b56eSmrg if (!drmmode_can_use_hw_cursor(crtc)) 1695d6c0b56eSmrg return FALSE; 1696d6c0b56eSmrg 1697d6c0b56eSmrg drmmode_load_cursor_argb(crtc, image); 1698d6c0b56eSmrg return TRUE; 1699d6c0b56eSmrg} 1700d6c0b56eSmrg 1701d6c0b56eSmrg#endif 1702d6c0b56eSmrg 1703d6c0b56eSmrgstatic void drmmode_hide_cursor(xf86CrtcPtr crtc) 1704d6c0b56eSmrg{ 1705d6c0b56eSmrg ScrnInfoPtr pScrn = crtc->scrn; 1706d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1707d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1708d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1709d6c0b56eSmrg 1710d6c0b56eSmrg drmModeSetCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 1711d6c0b56eSmrg info->cursor_w, info->cursor_h); 171290f2b693Smrg drmmode_crtc->cursor = NULL; 1713d6c0b56eSmrg} 1714d6c0b56eSmrg 1715d6c0b56eSmrgstatic void drmmode_show_cursor(xf86CrtcPtr crtc) 1716d6c0b56eSmrg{ 1717d6c0b56eSmrg ScrnInfoPtr pScrn = crtc->scrn; 1718d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1719d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1720d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 172190f2b693Smrg struct amdgpu_buffer *cursor_buffer = 172290f2b693Smrg drmmode_crtc->cursor_buffer[drmmode_crtc->cursor_id]; 172390f2b693Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 172490f2b693Smrg CursorPtr cursor = xf86_config->cursor; 172590f2b693Smrg int xhot = cursor->bits->xhot; 172690f2b693Smrg int yhot = cursor->bits->yhot; 1727d6c0b56eSmrg static Bool use_set_cursor2 = TRUE; 172890f2b693Smrg struct drm_mode_cursor2 arg; 1729d6c0b56eSmrg 173090f2b693Smrg drmmode_crtc->cursor = xf86_config->cursor; 173190f2b693Smrg 173290f2b693Smrg memset(&arg, 0, sizeof(arg)); 173390f2b693Smrg 173490f2b693Smrg if (!amdgpu_bo_get_handle(cursor_buffer, &arg.handle)) { 1735d6c0b56eSmrg ErrorF("failed to get BO handle for cursor\n"); 1736d6c0b56eSmrg return; 1737d6c0b56eSmrg } 1738d6c0b56eSmrg 173990f2b693Smrg arg.flags = DRM_MODE_CURSOR_BO; 174090f2b693Smrg arg.crtc_id = drmmode_crtc->mode_crtc->crtc_id; 174190f2b693Smrg arg.width = info->cursor_w; 174290f2b693Smrg arg.height = info->cursor_h; 174390f2b693Smrg 174490f2b693Smrg if (crtc->rotation != RR_Rotate_0 && 174590f2b693Smrg crtc->rotation != (RR_Rotate_180 | RR_Reflect_X | 174690f2b693Smrg RR_Reflect_Y)) { 174790f2b693Smrg int t; 174890f2b693Smrg 174990f2b693Smrg /* Reflect & rotate hotspot position */ 175090f2b693Smrg if (crtc->rotation & RR_Reflect_X) 175190f2b693Smrg xhot = info->cursor_w - xhot - 1; 175290f2b693Smrg if (crtc->rotation & RR_Reflect_Y) 175390f2b693Smrg yhot = info->cursor_h - yhot - 1; 175490f2b693Smrg 175590f2b693Smrg switch (crtc->rotation & 0xf) { 175690f2b693Smrg case RR_Rotate_90: 175790f2b693Smrg t = xhot; 175890f2b693Smrg xhot = yhot; 175990f2b693Smrg yhot = info->cursor_w - t - 1; 176090f2b693Smrg break; 176190f2b693Smrg case RR_Rotate_180: 176290f2b693Smrg xhot = info->cursor_w - xhot - 1; 176390f2b693Smrg yhot = info->cursor_h - yhot - 1; 176490f2b693Smrg break; 176590f2b693Smrg case RR_Rotate_270: 176690f2b693Smrg t = xhot; 176790f2b693Smrg xhot = info->cursor_h - yhot - 1; 176890f2b693Smrg yhot = t; 176990f2b693Smrg } 177090f2b693Smrg } 177190f2b693Smrg 177290f2b693Smrg if (xhot != drmmode_crtc->cursor_xhot || yhot != drmmode_crtc->cursor_yhot) { 177390f2b693Smrg arg.flags |= DRM_MODE_CURSOR_MOVE; 177490f2b693Smrg arg.x = drmmode_crtc->cursor_x += drmmode_crtc->cursor_xhot - xhot; 177590f2b693Smrg arg.y = drmmode_crtc->cursor_y += drmmode_crtc->cursor_yhot - yhot; 177690f2b693Smrg drmmode_crtc->cursor_xhot = xhot; 177790f2b693Smrg drmmode_crtc->cursor_yhot = yhot; 177890f2b693Smrg } 177990f2b693Smrg 1780d6c0b56eSmrg if (use_set_cursor2) { 1781d6c0b56eSmrg int ret; 1782d6c0b56eSmrg 178390f2b693Smrg arg.hot_x = xhot; 178490f2b693Smrg arg.hot_y = yhot; 1785504d986fSmrg 178690f2b693Smrg ret = drmIoctl(pAMDGPUEnt->fd, DRM_IOCTL_MODE_CURSOR2, &arg); 1787d6c0b56eSmrg if (ret == -EINVAL) 1788d6c0b56eSmrg use_set_cursor2 = FALSE; 1789d6c0b56eSmrg else 1790d6c0b56eSmrg return; 1791d6c0b56eSmrg } 1792d6c0b56eSmrg 179390f2b693Smrg drmIoctl(pAMDGPUEnt->fd, DRM_IOCTL_MODE_CURSOR, &arg); 1794d6c0b56eSmrg} 1795d6c0b56eSmrg 179611bf0794Smrg/* Xorg expects a non-NULL return value from drmmode_crtc_shadow_allocate, and 179711bf0794Smrg * passes that back to drmmode_crtc_scanout_create; it doesn't use it for 179811bf0794Smrg * anything else. 179911bf0794Smrg */ 180011bf0794Smrgstatic void * 180111bf0794Smrgdrmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) 1802d6c0b56eSmrg{ 1803d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1804d6c0b56eSmrg 180511bf0794Smrg if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width, 180611bf0794Smrg height)) 180711bf0794Smrg return NULL; 180811bf0794Smrg 180911bf0794Smrg return (void*)~0UL; 1810d6c0b56eSmrg} 1811d6c0b56eSmrg 1812d6c0b56eSmrgstatic PixmapPtr 1813d6c0b56eSmrgdrmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) 1814d6c0b56eSmrg{ 1815d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1816d6c0b56eSmrg 181711bf0794Smrg if (!data) { 181811bf0794Smrg drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width, 181911bf0794Smrg height); 182011bf0794Smrg } 182111bf0794Smrg 182211bf0794Smrg return drmmode_crtc->rotate.pixmap; 1823d6c0b56eSmrg} 1824d6c0b56eSmrg 1825d6c0b56eSmrgstatic void 1826d6c0b56eSmrgdrmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, 1827d6c0b56eSmrg void *data) 1828d6c0b56eSmrg{ 1829d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1830d6c0b56eSmrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 1831d6c0b56eSmrg 1832d6c0b56eSmrg drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->rotate); 1833d6c0b56eSmrg} 1834d6c0b56eSmrg 1835d6c0b56eSmrgstatic void 1836d6c0b56eSmrgdrmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t * red, uint16_t * green, 1837d6c0b56eSmrg uint16_t * blue, int size) 1838d6c0b56eSmrg{ 183924b90cf4Smrg ScrnInfoPtr scrn = crtc->scrn; 184024b90cf4Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 184124b90cf4Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 184224b90cf4Smrg int i; 1843d6c0b56eSmrg 184424b90cf4Smrg drmmode_crtc_gamma_do_set(crtc, red, green, blue, size); 184524b90cf4Smrg 184624b90cf4Smrg /* Compute index of this CRTC into xf86_config->crtc */ 184724b90cf4Smrg for (i = 0; xf86_config->crtc[i] != crtc; i++) {} 184824b90cf4Smrg 184924b90cf4Smrg if (info->hwcursor_disabled & (1 << i)) 185024b90cf4Smrg return; 185124b90cf4Smrg 185224b90cf4Smrg#ifdef HAVE_XF86_CURSOR_RESET_CURSOR 185324b90cf4Smrg xf86CursorResetCursor(scrn->pScreen); 185424b90cf4Smrg#else 185524b90cf4Smrg xf86_reload_cursors(scrn->pScreen); 185624b90cf4Smrg#endif 1857d6c0b56eSmrg} 1858d6c0b56eSmrg 1859d6c0b56eSmrgstatic Bool drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) 1860d6c0b56eSmrg{ 1861d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 186211bf0794Smrg unsigned scanout_id = drmmode_crtc->scanout_id; 1863504d986fSmrg ScreenPtr screen = crtc->scrn->pScreen; 1864504d986fSmrg PixmapDirtyUpdatePtr dirty; 1865d6c0b56eSmrg 1866504d986fSmrg xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { 186724b90cf4Smrg if (amdgpu_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) { 186824b90cf4Smrg PixmapStopDirtyTracking(dirty->src, dirty->slave_dst); 186924b90cf4Smrg break; 187024b90cf4Smrg } 1871d6c0b56eSmrg } 1872d6c0b56eSmrg 187390f2b693Smrg drmmode_crtc_scanout_free(crtc); 187424b90cf4Smrg drmmode_crtc->prime_scanout_pixmap = NULL; 187524b90cf4Smrg 1876504d986fSmrg if (!ppix) 1877504d986fSmrg return TRUE; 1878504d986fSmrg 1879504d986fSmrg if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[0], 1880504d986fSmrg ppix->drawable.width, 1881504d986fSmrg ppix->drawable.height)) 1882504d986fSmrg return FALSE; 1883d6c0b56eSmrg 188411bf0794Smrg if (drmmode_crtc->tear_free && 1885504d986fSmrg !drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], 1886504d986fSmrg ppix->drawable.width, 1887504d986fSmrg ppix->drawable.height)) { 188890f2b693Smrg drmmode_crtc_scanout_free(crtc); 1889504d986fSmrg return FALSE; 1890d6c0b56eSmrg } 1891504d986fSmrg 189224b90cf4Smrg drmmode_crtc->prime_scanout_pixmap = ppix; 189324b90cf4Smrg 189424b90cf4Smrg#ifdef HAS_DIRTYTRACKING_DRAWABLE_SRC 189524b90cf4Smrg PixmapStartDirtyTracking(&ppix->drawable, 189624b90cf4Smrg drmmode_crtc->scanout[scanout_id].pixmap, 189724b90cf4Smrg 0, 0, 0, 0, RR_Rotate_0); 189824b90cf4Smrg#elif defined(HAS_DIRTYTRACKING_ROTATION) 189911bf0794Smrg PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 1900504d986fSmrg 0, 0, 0, 0, RR_Rotate_0); 1901d6c0b56eSmrg#elif defined(HAS_DIRTYTRACKING2) 190211bf0794Smrg PixmapStartDirtyTracking2(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 1903504d986fSmrg 0, 0, 0, 0); 1904d6c0b56eSmrg#else 190511bf0794Smrg PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 0, 0); 1906d6c0b56eSmrg#endif 1907d6c0b56eSmrg return TRUE; 1908d6c0b56eSmrg} 1909d6c0b56eSmrg 191035d5b7c7Smrgstatic void drmmode_crtc_destroy(xf86CrtcPtr crtc) 191135d5b7c7Smrg{ 191235d5b7c7Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 191335d5b7c7Smrg 191435d5b7c7Smrg drmModeFreeCrtc(drmmode_crtc->mode_crtc); 191535d5b7c7Smrg 191635d5b7c7Smrg /* Free LUTs and CTM */ 191735d5b7c7Smrg free(drmmode_crtc->gamma_lut); 191835d5b7c7Smrg free(drmmode_crtc->degamma_lut); 191935d5b7c7Smrg free(drmmode_crtc->ctm); 192035d5b7c7Smrg 192135d5b7c7Smrg free(drmmode_crtc); 192235d5b7c7Smrg crtc->driver_private = NULL; 192335d5b7c7Smrg} 192435d5b7c7Smrg 192535d5b7c7Smrg 1926d6c0b56eSmrgstatic xf86CrtcFuncsRec drmmode_crtc_funcs = { 1927d6c0b56eSmrg .dpms = drmmode_crtc_dpms, 1928d6c0b56eSmrg .set_mode_major = drmmode_set_mode_major, 1929d6c0b56eSmrg .set_cursor_colors = drmmode_set_cursor_colors, 1930d6c0b56eSmrg .set_cursor_position = drmmode_set_cursor_position, 1931d6c0b56eSmrg .show_cursor = drmmode_show_cursor, 1932d6c0b56eSmrg .hide_cursor = drmmode_hide_cursor, 1933d6c0b56eSmrg .load_cursor_argb = drmmode_load_cursor_argb, 1934d6c0b56eSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 1935d6c0b56eSmrg .load_cursor_argb_check = drmmode_load_cursor_argb_check, 1936d6c0b56eSmrg#endif 1937d6c0b56eSmrg 1938d6c0b56eSmrg .gamma_set = drmmode_crtc_gamma_set, 1939d6c0b56eSmrg .shadow_create = drmmode_crtc_shadow_create, 1940d6c0b56eSmrg .shadow_allocate = drmmode_crtc_shadow_allocate, 1941d6c0b56eSmrg .shadow_destroy = drmmode_crtc_shadow_destroy, 194235d5b7c7Smrg .destroy = drmmode_crtc_destroy, 1943d6c0b56eSmrg .set_scanout_pixmap = drmmode_set_scanout_pixmap, 1944d6c0b56eSmrg}; 1945d6c0b56eSmrg 1946d6c0b56eSmrgint drmmode_get_crtc_id(xf86CrtcPtr crtc) 1947d6c0b56eSmrg{ 1948d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1949d6c0b56eSmrg return drmmode_crtc->hw_id; 1950d6c0b56eSmrg} 1951d6c0b56eSmrg 1952d6c0b56eSmrgvoid drmmode_crtc_hw_id(xf86CrtcPtr crtc) 1953d6c0b56eSmrg{ 1954d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1955d6c0b56eSmrg ScrnInfoPtr pScrn = crtc->scrn; 1956d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1957d6c0b56eSmrg int r; 1958d6c0b56eSmrg 1959d6c0b56eSmrg r = amdgpu_query_crtc_from_id(pAMDGPUEnt->pDev, 1960d6c0b56eSmrg drmmode_crtc->mode_crtc->crtc_id, 1961d6c0b56eSmrg &drmmode_crtc->hw_id); 1962d6c0b56eSmrg if (r) 1963d6c0b56eSmrg drmmode_crtc->hw_id = -1; 1964d6c0b56eSmrg} 1965d6c0b56eSmrg 196635d5b7c7Smrg/** 196735d5b7c7Smrg * Initialize color management properties for the given CRTC by programming 196835d5b7c7Smrg * the default gamma/degamma LUTs and CTM. 196935d5b7c7Smrg * 197035d5b7c7Smrg * If the CRTC does not support color management, or if errors occur during 197135d5b7c7Smrg * initialization, all color properties on the driver-private CRTC will left 197235d5b7c7Smrg * as NULL. 197335d5b7c7Smrg * 197435d5b7c7Smrg * @drm_fd: DRM file descriptor 197535d5b7c7Smrg * @crtc: CRTC to initialize color management on. 197635d5b7c7Smrg */ 197735d5b7c7Smrgstatic void drmmode_crtc_cm_init(int drm_fd, xf86CrtcPtr crtc) 197835d5b7c7Smrg{ 197935d5b7c7Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 198035d5b7c7Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 198135d5b7c7Smrg int i; 198235d5b7c7Smrg 198335d5b7c7Smrg if (!drmmode_cm_enabled(drmmode)) 198435d5b7c7Smrg return; 198535d5b7c7Smrg 198635d5b7c7Smrg /* Init CTM to identity. Values are in S31.32 fixed-point format */ 198735d5b7c7Smrg drmmode_crtc->ctm = calloc(1, sizeof(*drmmode_crtc->ctm)); 198835d5b7c7Smrg if (!drmmode_crtc->ctm) { 198935d5b7c7Smrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 199035d5b7c7Smrg "Memory error initializing CTM for CRTC%d", 199135d5b7c7Smrg drmmode_get_crtc_id(crtc)); 199235d5b7c7Smrg return; 199335d5b7c7Smrg } 199435d5b7c7Smrg 199535d5b7c7Smrg drmmode_crtc->ctm->matrix[0] = drmmode_crtc->ctm->matrix[4] = 199635d5b7c7Smrg drmmode_crtc->ctm->matrix[8] = (uint64_t)1 << 32; 199735d5b7c7Smrg 199835d5b7c7Smrg /* Push properties to reset properties currently in hardware */ 199935d5b7c7Smrg for (i = 0; i < CM_GAMMA_LUT; i++) { 200035d5b7c7Smrg if (drmmode_crtc_push_cm_prop(crtc, i)) 200135d5b7c7Smrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 200235d5b7c7Smrg "Failed to initialize color management " 200335d5b7c7Smrg "property %s on CRTC%d. Property value may " 200435d5b7c7Smrg "not reflect actual hardware state.\n", 200535d5b7c7Smrg cm_prop_names[i], 200635d5b7c7Smrg drmmode_get_crtc_id(crtc)); 200735d5b7c7Smrg } 200835d5b7c7Smrg} 200935d5b7c7Smrg 2010d6c0b56eSmrgstatic unsigned int 2011d6c0b56eSmrgdrmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num) 2012d6c0b56eSmrg{ 2013d6c0b56eSmrg xf86CrtcPtr crtc; 2014d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc; 2015d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 201624b90cf4Smrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 2017d6c0b56eSmrg 201824b90cf4Smrg crtc = xf86CrtcCreate(pScrn, &info->drmmode_crtc_funcs); 201935d5b7c7Smrg if (!crtc) 2020d6c0b56eSmrg return 0; 2021d6c0b56eSmrg 2022d6c0b56eSmrg drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1); 2023d6c0b56eSmrg drmmode_crtc->mode_crtc = 2024d6c0b56eSmrg drmModeGetCrtc(pAMDGPUEnt->fd, mode_res->crtcs[num]); 2025d6c0b56eSmrg drmmode_crtc->drmmode = drmmode; 2026d6c0b56eSmrg drmmode_crtc->dpms_mode = DPMSModeOff; 2027d6c0b56eSmrg crtc->driver_private = drmmode_crtc; 2028d6c0b56eSmrg drmmode_crtc_hw_id(crtc); 2029d6c0b56eSmrg 203035d5b7c7Smrg drmmode_crtc_cm_init(pAMDGPUEnt->fd, crtc); 203190f2b693Smrg drmmode_crtc_vrr_init(pAMDGPUEnt->fd, crtc); 203235d5b7c7Smrg 2033d6c0b56eSmrg /* Mark num'th crtc as in use on this device. */ 2034d6c0b56eSmrg pAMDGPUEnt->assigned_crtcs |= (1 << num); 2035d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 2036d6c0b56eSmrg "Allocated crtc nr. %d to this screen.\n", num); 2037d6c0b56eSmrg 2038d6c0b56eSmrg return 1; 2039d6c0b56eSmrg} 2040d6c0b56eSmrg 204124b90cf4Smrg/* 204224b90cf4Smrg * Update all of the property values for an output 204324b90cf4Smrg */ 204424b90cf4Smrgstatic void 204524b90cf4Smrgdrmmode_output_update_properties(xf86OutputPtr output) 204624b90cf4Smrg{ 204724b90cf4Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 204824b90cf4Smrg int i, j, k; 204924b90cf4Smrg int err; 205024b90cf4Smrg drmModeConnectorPtr koutput; 205124b90cf4Smrg 205224b90cf4Smrg /* Use the most recently fetched values from the kernel */ 205324b90cf4Smrg koutput = drmmode_output->mode_output; 205424b90cf4Smrg 205524b90cf4Smrg if (!koutput) 205624b90cf4Smrg return; 205724b90cf4Smrg 205824b90cf4Smrg for (i = 0; i < drmmode_output->num_props; i++) { 205924b90cf4Smrg drmmode_prop_ptr p = &drmmode_output->props[i]; 206024b90cf4Smrg 206124b90cf4Smrg for (j = 0; j < koutput->count_props; j++) { 206224b90cf4Smrg if (koutput->props[j] != p->mode_prop->prop_id) 206324b90cf4Smrg continue; 206424b90cf4Smrg 206524b90cf4Smrg /* Check to see if the property value has changed */ 206624b90cf4Smrg if (koutput->prop_values[j] == p->value) 206724b90cf4Smrg break; 206824b90cf4Smrg 206924b90cf4Smrg p->value = koutput->prop_values[j]; 207024b90cf4Smrg 207124b90cf4Smrg if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 207224b90cf4Smrg INT32 value = p->value; 207324b90cf4Smrg 207424b90cf4Smrg err = RRChangeOutputProperty(output->randr_output, 207524b90cf4Smrg p->atoms[0], XA_INTEGER, 207624b90cf4Smrg 32, PropModeReplace, 1, 207724b90cf4Smrg &value, FALSE, TRUE); 207824b90cf4Smrg if (err != 0) { 207924b90cf4Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 208024b90cf4Smrg "RRChangeOutputProperty error, %d\n", 208124b90cf4Smrg err); 208224b90cf4Smrg } 208324b90cf4Smrg } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 208424b90cf4Smrg for (k = 0; k < p->mode_prop->count_enums; k++) { 208524b90cf4Smrg if (p->mode_prop->enums[k].value == p->value) 208624b90cf4Smrg break; 208724b90cf4Smrg } 208824b90cf4Smrg if (k < p->mode_prop->count_enums) { 208924b90cf4Smrg err = RRChangeOutputProperty(output->randr_output, 209024b90cf4Smrg p->atoms[0], XA_ATOM, 209124b90cf4Smrg 32, PropModeReplace, 1, 209224b90cf4Smrg &p->atoms[k + 1], FALSE, 209324b90cf4Smrg TRUE); 209424b90cf4Smrg if (err != 0) { 209524b90cf4Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 209624b90cf4Smrg "RRChangeOutputProperty error, %d\n", 209724b90cf4Smrg err); 209824b90cf4Smrg } 209924b90cf4Smrg } 210024b90cf4Smrg } 210124b90cf4Smrg 210224b90cf4Smrg break; 210324b90cf4Smrg } 210424b90cf4Smrg } 210524b90cf4Smrg} 210624b90cf4Smrg 2107d6c0b56eSmrgstatic xf86OutputStatus drmmode_output_detect(xf86OutputPtr output) 2108d6c0b56eSmrg{ 2109d6c0b56eSmrg /* go to the hw and retrieve a new output struct */ 2110d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 2111d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 2112d6c0b56eSmrg xf86OutputStatus status; 2113d6c0b56eSmrg drmModeFreeConnector(drmmode_output->mode_output); 2114d6c0b56eSmrg 2115d6c0b56eSmrg drmmode_output->mode_output = 2116d6c0b56eSmrg drmModeGetConnector(pAMDGPUEnt->fd, drmmode_output->output_id); 211724b90cf4Smrg if (!drmmode_output->mode_output) { 211824b90cf4Smrg drmmode_output->output_id = -1; 2119d6c0b56eSmrg return XF86OutputStatusDisconnected; 212024b90cf4Smrg } 212124b90cf4Smrg 212224b90cf4Smrg drmmode_output_update_properties(output); 2123d6c0b56eSmrg 2124d6c0b56eSmrg switch (drmmode_output->mode_output->connection) { 2125d6c0b56eSmrg case DRM_MODE_CONNECTED: 2126d6c0b56eSmrg status = XF86OutputStatusConnected; 2127d6c0b56eSmrg break; 2128d6c0b56eSmrg case DRM_MODE_DISCONNECTED: 2129d6c0b56eSmrg status = XF86OutputStatusDisconnected; 2130d6c0b56eSmrg break; 2131d6c0b56eSmrg default: 2132d6c0b56eSmrg case DRM_MODE_UNKNOWNCONNECTION: 2133d6c0b56eSmrg status = XF86OutputStatusUnknown; 2134d6c0b56eSmrg break; 2135d6c0b56eSmrg } 2136d6c0b56eSmrg return status; 2137d6c0b56eSmrg} 2138d6c0b56eSmrg 2139d6c0b56eSmrgstatic Bool 2140d6c0b56eSmrgdrmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes) 2141d6c0b56eSmrg{ 2142d6c0b56eSmrg return MODE_OK; 2143d6c0b56eSmrg} 2144d6c0b56eSmrg 214524b90cf4Smrgstatic int 214624b90cf4Smrgkoutput_get_prop_idx(int fd, drmModeConnectorPtr koutput, 214724b90cf4Smrg int type, const char *name) 214824b90cf4Smrg{ 214924b90cf4Smrg int idx = -1; 215024b90cf4Smrg 215124b90cf4Smrg for (int i = 0; i < koutput->count_props; i++) { 215224b90cf4Smrg drmModePropertyPtr prop = drmModeGetProperty(fd, koutput->props[i]); 215324b90cf4Smrg 215424b90cf4Smrg if (!prop) 215524b90cf4Smrg continue; 215624b90cf4Smrg 215724b90cf4Smrg if (drm_property_type_is(prop, type) && !strcmp(prop->name, name)) 215824b90cf4Smrg idx = i; 215924b90cf4Smrg 216024b90cf4Smrg drmModeFreeProperty(prop); 216124b90cf4Smrg 216224b90cf4Smrg if (idx > -1) 216324b90cf4Smrg break; 216424b90cf4Smrg } 216524b90cf4Smrg 216624b90cf4Smrg return idx; 216724b90cf4Smrg} 216824b90cf4Smrg 216924b90cf4Smrgstatic int 217024b90cf4Smrgkoutput_get_prop_id(int fd, drmModeConnectorPtr koutput, 217124b90cf4Smrg int type, const char *name) 217224b90cf4Smrg{ 217324b90cf4Smrg int idx = koutput_get_prop_idx(fd, koutput, type, name); 217424b90cf4Smrg 217524b90cf4Smrg return (idx > -1) ? koutput->props[idx] : -1; 217624b90cf4Smrg} 217724b90cf4Smrg 217824b90cf4Smrgstatic drmModePropertyBlobPtr 217924b90cf4Smrgkoutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name) 218024b90cf4Smrg{ 218124b90cf4Smrg drmModePropertyBlobPtr blob = NULL; 218224b90cf4Smrg int idx = koutput_get_prop_idx(fd, koutput, DRM_MODE_PROP_BLOB, name); 218324b90cf4Smrg 218424b90cf4Smrg if (idx > -1) 218524b90cf4Smrg blob = drmModeGetPropertyBlob(fd, koutput->prop_values[idx]); 218624b90cf4Smrg 218724b90cf4Smrg return blob; 218824b90cf4Smrg} 218924b90cf4Smrg 2190d6c0b56eSmrgstatic DisplayModePtr drmmode_output_get_modes(xf86OutputPtr output) 2191d6c0b56eSmrg{ 2192d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 2193d6c0b56eSmrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 2194d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 2195d6c0b56eSmrg int i; 2196d6c0b56eSmrg DisplayModePtr Modes = NULL, Mode; 2197d6c0b56eSmrg xf86MonPtr mon = NULL; 2198d6c0b56eSmrg 2199d6c0b56eSmrg if (!koutput) 2200d6c0b56eSmrg return NULL; 2201d6c0b56eSmrg 220224b90cf4Smrg drmModeFreePropertyBlob(drmmode_output->edid_blob); 220324b90cf4Smrg 2204d6c0b56eSmrg /* look for an EDID property */ 220524b90cf4Smrg drmmode_output->edid_blob = 220624b90cf4Smrg koutput_get_prop_blob(pAMDGPUEnt->fd, koutput, "EDID"); 2207d6c0b56eSmrg 2208d6c0b56eSmrg if (drmmode_output->edid_blob) { 2209d6c0b56eSmrg mon = xf86InterpretEDID(output->scrn->scrnIndex, 2210d6c0b56eSmrg drmmode_output->edid_blob->data); 2211d6c0b56eSmrg if (mon && drmmode_output->edid_blob->length > 128) 2212d6c0b56eSmrg mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; 2213d6c0b56eSmrg } 2214d6c0b56eSmrg xf86OutputSetEDID(output, mon); 2215d6c0b56eSmrg 2216d6c0b56eSmrg /* modes should already be available */ 2217d6c0b56eSmrg for (i = 0; i < koutput->count_modes; i++) { 2218d6c0b56eSmrg Mode = xnfalloc(sizeof(DisplayModeRec)); 2219d6c0b56eSmrg 2220d6c0b56eSmrg drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], 2221d6c0b56eSmrg Mode); 2222d6c0b56eSmrg Modes = xf86ModesAdd(Modes, Mode); 2223d6c0b56eSmrg 2224d6c0b56eSmrg } 2225d6c0b56eSmrg return Modes; 2226d6c0b56eSmrg} 2227d6c0b56eSmrg 2228d6c0b56eSmrgstatic void drmmode_output_destroy(xf86OutputPtr output) 2229d6c0b56eSmrg{ 2230d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 2231d6c0b56eSmrg int i; 2232d6c0b56eSmrg 2233d6c0b56eSmrg if (drmmode_output->edid_blob) 2234d6c0b56eSmrg drmModeFreePropertyBlob(drmmode_output->edid_blob); 2235d6c0b56eSmrg for (i = 0; i < drmmode_output->num_props; i++) { 2236d6c0b56eSmrg drmModeFreeProperty(drmmode_output->props[i].mode_prop); 2237d6c0b56eSmrg free(drmmode_output->props[i].atoms); 2238d6c0b56eSmrg } 2239d6c0b56eSmrg for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) { 2240d6c0b56eSmrg drmModeFreeEncoder(drmmode_output->mode_encoders[i]); 2241d6c0b56eSmrg } 2242d6c0b56eSmrg free(drmmode_output->mode_encoders); 2243d6c0b56eSmrg free(drmmode_output->props); 2244d6c0b56eSmrg drmModeFreeConnector(drmmode_output->mode_output); 2245d6c0b56eSmrg free(drmmode_output); 2246d6c0b56eSmrg output->driver_private = NULL; 2247d6c0b56eSmrg} 2248d6c0b56eSmrg 2249d6c0b56eSmrgstatic void drmmode_output_dpms(xf86OutputPtr output, int mode) 2250d6c0b56eSmrg{ 2251d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 2252d6c0b56eSmrg xf86CrtcPtr crtc = output->crtc; 2253d6c0b56eSmrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 2254d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 2255d6c0b56eSmrg 2256d6c0b56eSmrg if (!koutput) 2257d6c0b56eSmrg return; 2258d6c0b56eSmrg 225924b90cf4Smrg if (mode != DPMSModeOn && crtc) 2260d6c0b56eSmrg drmmode_do_crtc_dpms(crtc, mode); 2261d6c0b56eSmrg 2262d6c0b56eSmrg drmModeConnectorSetProperty(pAMDGPUEnt->fd, koutput->connector_id, 2263d6c0b56eSmrg drmmode_output->dpms_enum_id, mode); 2264d6c0b56eSmrg 2265d6c0b56eSmrg if (mode == DPMSModeOn && crtc) { 2266d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 2267d6c0b56eSmrg 2268d6c0b56eSmrg if (drmmode_crtc->need_modeset) 2269d6c0b56eSmrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 2270d6c0b56eSmrg crtc->x, crtc->y); 2271d6c0b56eSmrg else 2272d6c0b56eSmrg drmmode_do_crtc_dpms(output->crtc, mode); 2273d6c0b56eSmrg } 2274d6c0b56eSmrg} 2275d6c0b56eSmrg 2276d6c0b56eSmrgstatic Bool drmmode_property_ignore(drmModePropertyPtr prop) 2277d6c0b56eSmrg{ 2278d6c0b56eSmrg if (!prop) 2279d6c0b56eSmrg return TRUE; 2280d6c0b56eSmrg /* ignore blob prop */ 2281d6c0b56eSmrg if (prop->flags & DRM_MODE_PROP_BLOB) 2282d6c0b56eSmrg return TRUE; 2283d6c0b56eSmrg /* ignore standard property */ 2284d6c0b56eSmrg if (!strcmp(prop->name, "EDID") || !strcmp(prop->name, "DPMS")) 2285d6c0b56eSmrg return TRUE; 2286d6c0b56eSmrg 2287d6c0b56eSmrg return FALSE; 2288d6c0b56eSmrg} 2289d6c0b56eSmrg 2290d6c0b56eSmrgstatic void drmmode_output_create_resources(xf86OutputPtr output) 2291d6c0b56eSmrg{ 229211bf0794Smrg AMDGPUInfoPtr info = AMDGPUPTR(output->scrn); 2293d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 229435d5b7c7Smrg drmmode_crtc_private_ptr drmmode_crtc; 2295d6c0b56eSmrg drmModeConnectorPtr mode_output = drmmode_output->mode_output; 2296d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 229711bf0794Smrg drmModePropertyPtr drmmode_prop, tearfree_prop; 2298d6c0b56eSmrg int i, j, err; 229935d5b7c7Smrg Atom name; 230035d5b7c7Smrg 230135d5b7c7Smrg /* Create CONNECTOR_ID property */ 230235d5b7c7Smrg name = MakeAtom("CONNECTOR_ID", 12, TRUE); 230335d5b7c7Smrg if (name != BAD_RESOURCE) { 230435d5b7c7Smrg INT32 value = mode_output->connector_id; 230535d5b7c7Smrg 230635d5b7c7Smrg err = RRConfigureOutputProperty(output->randr_output, name, 230735d5b7c7Smrg FALSE, FALSE, TRUE, 1, &value); 230835d5b7c7Smrg if (err != Success) { 230935d5b7c7Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 231035d5b7c7Smrg "RRConfigureOutputProperty error, %d\n", err); 231135d5b7c7Smrg } 231235d5b7c7Smrg 231335d5b7c7Smrg err = RRChangeOutputProperty(output->randr_output, name, 231435d5b7c7Smrg XA_INTEGER, 32, PropModeReplace, 1, 231535d5b7c7Smrg &value, FALSE, FALSE); 231635d5b7c7Smrg if (err != Success) { 231735d5b7c7Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 231835d5b7c7Smrg "RRChangeOutputProperty error, %d\n", err); 231935d5b7c7Smrg } 232035d5b7c7Smrg } 2321d6c0b56eSmrg 2322d6c0b56eSmrg drmmode_output->props = 232311bf0794Smrg calloc(mode_output->count_props + 1, sizeof(drmmode_prop_rec)); 2324d6c0b56eSmrg if (!drmmode_output->props) 2325d6c0b56eSmrg return; 2326d6c0b56eSmrg 2327d6c0b56eSmrg drmmode_output->num_props = 0; 2328d6c0b56eSmrg for (i = 0, j = 0; i < mode_output->count_props; i++) { 2329d6c0b56eSmrg drmmode_prop = 2330d6c0b56eSmrg drmModeGetProperty(pAMDGPUEnt->fd, mode_output->props[i]); 2331d6c0b56eSmrg if (drmmode_property_ignore(drmmode_prop)) { 2332d6c0b56eSmrg drmModeFreeProperty(drmmode_prop); 2333d6c0b56eSmrg continue; 2334d6c0b56eSmrg } 2335d6c0b56eSmrg drmmode_output->props[j].mode_prop = drmmode_prop; 2336d6c0b56eSmrg drmmode_output->props[j].value = mode_output->prop_values[i]; 2337d6c0b56eSmrg drmmode_output->num_props++; 2338d6c0b56eSmrg j++; 2339d6c0b56eSmrg } 2340d6c0b56eSmrg 234111bf0794Smrg /* Userspace-only property for TearFree */ 234211bf0794Smrg tearfree_prop = calloc(1, sizeof(*tearfree_prop)); 234311bf0794Smrg tearfree_prop->flags = DRM_MODE_PROP_ENUM; 234435d5b7c7Smrg strcpy(tearfree_prop->name, "TearFree"); 234511bf0794Smrg tearfree_prop->count_enums = 3; 234611bf0794Smrg tearfree_prop->enums = calloc(tearfree_prop->count_enums, 234711bf0794Smrg sizeof(*tearfree_prop->enums)); 234835d5b7c7Smrg strcpy(tearfree_prop->enums[0].name, "off"); 234935d5b7c7Smrg strcpy(tearfree_prop->enums[1].name, "on"); 235011bf0794Smrg tearfree_prop->enums[1].value = 1; 235135d5b7c7Smrg strcpy(tearfree_prop->enums[2].name, "auto"); 235211bf0794Smrg tearfree_prop->enums[2].value = 2; 235311bf0794Smrg drmmode_output->props[j].mode_prop = tearfree_prop; 235411bf0794Smrg drmmode_output->props[j].value = info->tear_free; 235511bf0794Smrg drmmode_output->tear_free = info->tear_free; 235611bf0794Smrg drmmode_output->num_props++; 235711bf0794Smrg 2358d6c0b56eSmrg for (i = 0; i < drmmode_output->num_props; i++) { 2359d6c0b56eSmrg drmmode_prop_ptr p = &drmmode_output->props[i]; 2360d6c0b56eSmrg drmmode_prop = p->mode_prop; 2361d6c0b56eSmrg 2362d6c0b56eSmrg if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { 2363d6c0b56eSmrg INT32 range[2]; 2364d6c0b56eSmrg INT32 value = p->value; 2365d6c0b56eSmrg 2366d6c0b56eSmrg p->num_atoms = 1; 2367d6c0b56eSmrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 2368d6c0b56eSmrg if (!p->atoms) 2369d6c0b56eSmrg continue; 2370d6c0b56eSmrg p->atoms[0] = 2371d6c0b56eSmrg MakeAtom(drmmode_prop->name, 2372d6c0b56eSmrg strlen(drmmode_prop->name), TRUE); 2373d6c0b56eSmrg range[0] = drmmode_prop->values[0]; 2374d6c0b56eSmrg range[1] = drmmode_prop->values[1]; 2375d6c0b56eSmrg err = 2376d6c0b56eSmrg RRConfigureOutputProperty(output->randr_output, 2377d6c0b56eSmrg p->atoms[0], FALSE, TRUE, 2378d6c0b56eSmrg drmmode_prop->flags & 2379d6c0b56eSmrg DRM_MODE_PROP_IMMUTABLE ? 2380d6c0b56eSmrg TRUE : FALSE, 2, range); 2381d6c0b56eSmrg if (err != 0) { 2382d6c0b56eSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2383d6c0b56eSmrg "RRConfigureOutputProperty error, %d\n", 2384d6c0b56eSmrg err); 2385d6c0b56eSmrg } 2386d6c0b56eSmrg err = 2387d6c0b56eSmrg RRChangeOutputProperty(output->randr_output, 2388d6c0b56eSmrg p->atoms[0], XA_INTEGER, 32, 2389d6c0b56eSmrg PropModeReplace, 1, &value, 2390d6c0b56eSmrg FALSE, TRUE); 2391d6c0b56eSmrg if (err != 0) { 2392d6c0b56eSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2393d6c0b56eSmrg "RRChangeOutputProperty error, %d\n", 2394d6c0b56eSmrg err); 2395d6c0b56eSmrg } 2396d6c0b56eSmrg } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { 2397d6c0b56eSmrg p->num_atoms = drmmode_prop->count_enums + 1; 2398d6c0b56eSmrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 2399d6c0b56eSmrg if (!p->atoms) 2400d6c0b56eSmrg continue; 2401d6c0b56eSmrg p->atoms[0] = 2402d6c0b56eSmrg MakeAtom(drmmode_prop->name, 2403d6c0b56eSmrg strlen(drmmode_prop->name), TRUE); 2404d6c0b56eSmrg for (j = 1; j <= drmmode_prop->count_enums; j++) { 2405d6c0b56eSmrg struct drm_mode_property_enum *e = 2406d6c0b56eSmrg &drmmode_prop->enums[j - 1]; 2407d6c0b56eSmrg p->atoms[j] = 2408d6c0b56eSmrg MakeAtom(e->name, strlen(e->name), TRUE); 2409d6c0b56eSmrg } 2410d6c0b56eSmrg err = 2411d6c0b56eSmrg RRConfigureOutputProperty(output->randr_output, 2412d6c0b56eSmrg p->atoms[0], FALSE, FALSE, 2413d6c0b56eSmrg drmmode_prop->flags & 2414d6c0b56eSmrg DRM_MODE_PROP_IMMUTABLE ? 2415d6c0b56eSmrg TRUE : FALSE, 2416d6c0b56eSmrg p->num_atoms - 1, 2417d6c0b56eSmrg (INT32 *) & p->atoms[1]); 2418d6c0b56eSmrg if (err != 0) { 2419d6c0b56eSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2420d6c0b56eSmrg "RRConfigureOutputProperty error, %d\n", 2421d6c0b56eSmrg err); 2422d6c0b56eSmrg } 2423d6c0b56eSmrg for (j = 0; j < drmmode_prop->count_enums; j++) 2424d6c0b56eSmrg if (drmmode_prop->enums[j].value == p->value) 2425d6c0b56eSmrg break; 2426d6c0b56eSmrg /* there's always a matching value */ 2427d6c0b56eSmrg err = 2428d6c0b56eSmrg RRChangeOutputProperty(output->randr_output, 2429d6c0b56eSmrg p->atoms[0], XA_ATOM, 32, 2430d6c0b56eSmrg PropModeReplace, 1, 2431d6c0b56eSmrg &p->atoms[j + 1], FALSE, 2432d6c0b56eSmrg TRUE); 2433d6c0b56eSmrg if (err != 0) { 2434d6c0b56eSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2435d6c0b56eSmrg "RRChangeOutputProperty error, %d\n", 2436d6c0b56eSmrg err); 2437d6c0b56eSmrg } 2438d6c0b56eSmrg } 2439d6c0b56eSmrg } 244035d5b7c7Smrg 244135d5b7c7Smrg /* Do not configure cm properties on output if there's no support. */ 244235d5b7c7Smrg if (!drmmode_cm_enabled(drmmode_output->drmmode)) 244335d5b7c7Smrg return; 244435d5b7c7Smrg 244535d5b7c7Smrg drmmode_crtc = output->crtc ? output->crtc->driver_private : NULL; 244635d5b7c7Smrg 244735d5b7c7Smrg for (i = 0; i < CM_NUM_PROPS; i++) 244835d5b7c7Smrg rr_configure_and_change_cm_property(output, drmmode_crtc, i); 244935d5b7c7Smrg} 245035d5b7c7Smrg 245135d5b7c7Smrgstatic void 245235d5b7c7Smrgdrmmode_output_set_tear_free(AMDGPUEntPtr pAMDGPUEnt, 245335d5b7c7Smrg drmmode_output_private_ptr drmmode_output, 245435d5b7c7Smrg xf86CrtcPtr crtc, int tear_free) 245535d5b7c7Smrg{ 245635d5b7c7Smrg if (drmmode_output->tear_free == tear_free) 245735d5b7c7Smrg return; 245835d5b7c7Smrg 245935d5b7c7Smrg drmmode_output->tear_free = tear_free; 246035d5b7c7Smrg 246135d5b7c7Smrg if (crtc) { 246235d5b7c7Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 246335d5b7c7Smrg crtc->x, crtc->y); 246435d5b7c7Smrg } 2465d6c0b56eSmrg} 2466d6c0b56eSmrg 2467d6c0b56eSmrgstatic Bool 2468d6c0b56eSmrgdrmmode_output_set_property(xf86OutputPtr output, Atom property, 2469d6c0b56eSmrg RRPropertyValuePtr value) 2470d6c0b56eSmrg{ 2471d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 2472d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 247335d5b7c7Smrg enum drmmode_cm_prop cm_prop_index; 2474d6c0b56eSmrg int i; 2475d6c0b56eSmrg 247635d5b7c7Smrg cm_prop_index = get_cm_enum_from_str(NameForAtom(property)); 247735d5b7c7Smrg if (cm_prop_index >= 0 && cm_prop_index < CM_DEGAMMA_LUT_SIZE) { 247835d5b7c7Smrg if (!output->crtc) 247935d5b7c7Smrg return FALSE; 248035d5b7c7Smrg if (drmmode_crtc_stage_cm_prop(output->crtc, cm_prop_index, 248135d5b7c7Smrg value)) 248235d5b7c7Smrg return FALSE; 248335d5b7c7Smrg if (drmmode_crtc_push_cm_prop(output->crtc, cm_prop_index)) 248435d5b7c7Smrg return FALSE; 248535d5b7c7Smrg return TRUE; 248635d5b7c7Smrg } 248735d5b7c7Smrg 2488d6c0b56eSmrg for (i = 0; i < drmmode_output->num_props; i++) { 2489d6c0b56eSmrg drmmode_prop_ptr p = &drmmode_output->props[i]; 2490d6c0b56eSmrg 2491d6c0b56eSmrg if (p->atoms[0] != property) 2492d6c0b56eSmrg continue; 2493d6c0b56eSmrg 2494d6c0b56eSmrg if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 2495d6c0b56eSmrg uint32_t val; 2496d6c0b56eSmrg 2497d6c0b56eSmrg if (value->type != XA_INTEGER || value->format != 32 || 2498d6c0b56eSmrg value->size != 1) 2499d6c0b56eSmrg return FALSE; 2500d6c0b56eSmrg val = *(uint32_t *) value->data; 2501d6c0b56eSmrg 2502d6c0b56eSmrg drmModeConnectorSetProperty(pAMDGPUEnt->fd, 2503d6c0b56eSmrg drmmode_output->output_id, 2504d6c0b56eSmrg p->mode_prop->prop_id, 2505d6c0b56eSmrg (uint64_t) val); 2506d6c0b56eSmrg return TRUE; 2507d6c0b56eSmrg } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 2508d6c0b56eSmrg Atom atom; 2509d6c0b56eSmrg const char *name; 2510d6c0b56eSmrg int j; 2511d6c0b56eSmrg 2512d6c0b56eSmrg if (value->type != XA_ATOM || value->format != 32 2513d6c0b56eSmrg || value->size != 1) 2514d6c0b56eSmrg return FALSE; 2515d6c0b56eSmrg memcpy(&atom, value->data, 4); 251624b90cf4Smrg if (!(name = NameForAtom(atom))) 251724b90cf4Smrg return FALSE; 2518d6c0b56eSmrg 2519d6c0b56eSmrg /* search for matching name string, then set its value down */ 2520d6c0b56eSmrg for (j = 0; j < p->mode_prop->count_enums; j++) { 2521d6c0b56eSmrg if (!strcmp(p->mode_prop->enums[j].name, name)) { 252211bf0794Smrg if (i == (drmmode_output->num_props - 1)) { 252335d5b7c7Smrg drmmode_output_set_tear_free(pAMDGPUEnt, 252435d5b7c7Smrg drmmode_output, 252535d5b7c7Smrg output->crtc, j); 252611bf0794Smrg } else { 252711bf0794Smrg drmModeConnectorSetProperty(pAMDGPUEnt->fd, 252811bf0794Smrg drmmode_output->output_id, 252911bf0794Smrg p->mode_prop->prop_id, 253011bf0794Smrg p->mode_prop->enums[j].value); 253111bf0794Smrg } 253211bf0794Smrg 2533d6c0b56eSmrg return TRUE; 2534d6c0b56eSmrg } 2535d6c0b56eSmrg } 2536d6c0b56eSmrg } 2537d6c0b56eSmrg } 2538d6c0b56eSmrg 2539d6c0b56eSmrg return TRUE; 2540d6c0b56eSmrg} 2541d6c0b56eSmrg 2542d6c0b56eSmrgstatic Bool drmmode_output_get_property(xf86OutputPtr output, Atom property) 2543d6c0b56eSmrg{ 254435d5b7c7Smrg drmmode_crtc_private_ptr drmmode_crtc; 254535d5b7c7Smrg enum drmmode_cm_prop cm_prop_id; 254635d5b7c7Smrg int ret; 254735d5b7c7Smrg 254835d5b7c7Smrg /* First, see if it's a cm property */ 254935d5b7c7Smrg cm_prop_id = get_cm_enum_from_str(NameForAtom(property)); 255035d5b7c7Smrg if (output->crtc && cm_prop_id != CM_INVALID_PROP) { 255135d5b7c7Smrg drmmode_crtc = output->crtc->driver_private; 255235d5b7c7Smrg 255335d5b7c7Smrg ret = rr_configure_and_change_cm_property(output, drmmode_crtc, 255435d5b7c7Smrg cm_prop_id); 255535d5b7c7Smrg if (ret) { 255635d5b7c7Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 255735d5b7c7Smrg "Error getting color property: %d\n", 255835d5b7c7Smrg ret); 255935d5b7c7Smrg return FALSE; 256035d5b7c7Smrg } 256135d5b7c7Smrg return TRUE; 256235d5b7c7Smrg } 256335d5b7c7Smrg 256435d5b7c7Smrg /* Otherwise, must be an output property. */ 2565d6c0b56eSmrg return TRUE; 2566d6c0b56eSmrg} 2567d6c0b56eSmrg 2568d6c0b56eSmrgstatic const xf86OutputFuncsRec drmmode_output_funcs = { 2569d6c0b56eSmrg .dpms = drmmode_output_dpms, 2570d6c0b56eSmrg .create_resources = drmmode_output_create_resources, 2571d6c0b56eSmrg .set_property = drmmode_output_set_property, 2572d6c0b56eSmrg .get_property = drmmode_output_get_property, 2573d6c0b56eSmrg .detect = drmmode_output_detect, 2574d6c0b56eSmrg .mode_valid = drmmode_output_mode_valid, 2575d6c0b56eSmrg 2576d6c0b56eSmrg .get_modes = drmmode_output_get_modes, 2577d6c0b56eSmrg .destroy = drmmode_output_destroy 2578d6c0b56eSmrg}; 2579d6c0b56eSmrg 2580d6c0b56eSmrgstatic int subpixel_conv_table[7] = { 0, SubPixelUnknown, 2581d6c0b56eSmrg SubPixelHorizontalRGB, 2582d6c0b56eSmrg SubPixelHorizontalBGR, 2583d6c0b56eSmrg SubPixelVerticalRGB, 2584d6c0b56eSmrg SubPixelVerticalBGR, 2585d6c0b56eSmrg SubPixelNone 2586d6c0b56eSmrg}; 2587d6c0b56eSmrg 2588d6c0b56eSmrgconst char *output_names[] = { "None", 2589d6c0b56eSmrg "VGA", 2590d6c0b56eSmrg "DVI-I", 2591d6c0b56eSmrg "DVI-D", 2592d6c0b56eSmrg "DVI-A", 2593d6c0b56eSmrg "Composite", 2594d6c0b56eSmrg "S-video", 2595d6c0b56eSmrg "LVDS", 2596d6c0b56eSmrg "CTV", 2597d6c0b56eSmrg "DIN", 2598d6c0b56eSmrg "DisplayPort", 2599d6c0b56eSmrg "HDMI-A", 2600d6c0b56eSmrg "HDMI-B", 2601d6c0b56eSmrg "TV", 2602d6c0b56eSmrg "eDP", 2603d6c0b56eSmrg "Virtual", 2604d6c0b56eSmrg "DSI", 2605d6c0b56eSmrg}; 2606d6c0b56eSmrg 2607d6c0b56eSmrg#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0])) 2608d6c0b56eSmrg 2609d6c0b56eSmrgstatic xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id) 2610d6c0b56eSmrg{ 2611d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 2612d6c0b56eSmrg int i; 2613d6c0b56eSmrg for (i = 0; i < xf86_config->num_output; i++) { 2614d6c0b56eSmrg xf86OutputPtr output = xf86_config->output[i]; 2615d6c0b56eSmrg drmmode_output_private_ptr drmmode_output; 2616d6c0b56eSmrg drmmode_output = output->driver_private; 2617d6c0b56eSmrg if (drmmode_output->output_id == id) 2618d6c0b56eSmrg return output; 2619d6c0b56eSmrg } 2620d6c0b56eSmrg return NULL; 2621d6c0b56eSmrg} 2622d6c0b56eSmrg 2623d6c0b56eSmrgstatic int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path) 2624d6c0b56eSmrg{ 2625d6c0b56eSmrg char *conn; 2626d6c0b56eSmrg char conn_id[5]; 2627d6c0b56eSmrg int id, len; 2628d6c0b56eSmrg char *blob_data; 2629d6c0b56eSmrg 2630d6c0b56eSmrg if (!path_blob) 2631d6c0b56eSmrg return -1; 2632d6c0b56eSmrg 2633d6c0b56eSmrg blob_data = path_blob->data; 2634d6c0b56eSmrg /* we only handle MST paths for now */ 2635d6c0b56eSmrg if (strncmp(blob_data, "mst:", 4)) 2636d6c0b56eSmrg return -1; 2637d6c0b56eSmrg 2638d6c0b56eSmrg conn = strchr(blob_data + 4, '-'); 2639d6c0b56eSmrg if (!conn) 2640d6c0b56eSmrg return -1; 2641d6c0b56eSmrg len = conn - (blob_data + 4); 2642d6c0b56eSmrg if (len + 1 > 5) 2643d6c0b56eSmrg return -1; 2644d6c0b56eSmrg memcpy(conn_id, blob_data + 4, len); 2645d6c0b56eSmrg conn_id[len] = '\0'; 2646d6c0b56eSmrg id = strtoul(conn_id, NULL, 10); 2647d6c0b56eSmrg 2648d6c0b56eSmrg *conn_base_id = id; 2649d6c0b56eSmrg 2650d6c0b56eSmrg *path = conn + 1; 2651d6c0b56eSmrg return 0; 2652d6c0b56eSmrg} 2653d6c0b56eSmrg 2654d6c0b56eSmrgstatic void 2655d6c0b56eSmrgdrmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name, 2656d6c0b56eSmrg drmModePropertyBlobPtr path_blob, int *num_dvi, int *num_hdmi) 2657d6c0b56eSmrg{ 2658d6c0b56eSmrg xf86OutputPtr output; 2659d6c0b56eSmrg int conn_id; 2660d6c0b56eSmrg char *extra_path; 2661d6c0b56eSmrg 2662d6c0b56eSmrg output = NULL; 2663d6c0b56eSmrg if (parse_path_blob(path_blob, &conn_id, &extra_path) == 0) 2664d6c0b56eSmrg output = find_output(pScrn, conn_id); 2665d6c0b56eSmrg if (output) { 2666d6c0b56eSmrg snprintf(name, 32, "%s-%s", output->name, extra_path); 2667d6c0b56eSmrg } else { 266824b90cf4Smrg if (koutput->connector_type >= NUM_OUTPUT_NAMES) { 2669d6c0b56eSmrg snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, koutput->connector_type_id - 1); 267024b90cf4Smrg } else if (pScrn->is_gpu) { 2671d6c0b56eSmrg snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type], 2672d6c0b56eSmrg pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id - 1); 267324b90cf4Smrg } else { 2674d6c0b56eSmrg /* need to do smart conversion here for compat with non-kms ATI driver */ 2675d6c0b56eSmrg if (koutput->connector_type_id == 1) { 2676d6c0b56eSmrg switch(koutput->connector_type) { 2677d6c0b56eSmrg case DRM_MODE_CONNECTOR_DVII: 2678d6c0b56eSmrg case DRM_MODE_CONNECTOR_DVID: 2679d6c0b56eSmrg case DRM_MODE_CONNECTOR_DVIA: 2680d6c0b56eSmrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi); 2681d6c0b56eSmrg (*num_dvi)++; 2682d6c0b56eSmrg break; 2683d6c0b56eSmrg case DRM_MODE_CONNECTOR_HDMIA: 2684d6c0b56eSmrg case DRM_MODE_CONNECTOR_HDMIB: 2685d6c0b56eSmrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi); 2686d6c0b56eSmrg (*num_hdmi)++; 2687d6c0b56eSmrg break; 2688d6c0b56eSmrg case DRM_MODE_CONNECTOR_VGA: 2689d6c0b56eSmrg case DRM_MODE_CONNECTOR_DisplayPort: 2690d6c0b56eSmrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); 2691d6c0b56eSmrg break; 2692d6c0b56eSmrg default: 2693d6c0b56eSmrg snprintf(name, 32, "%s", output_names[koutput->connector_type]); 2694d6c0b56eSmrg break; 2695d6c0b56eSmrg } 2696d6c0b56eSmrg } else { 2697d6c0b56eSmrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); 2698d6c0b56eSmrg } 2699d6c0b56eSmrg } 2700d6c0b56eSmrg } 2701d6c0b56eSmrg} 2702d6c0b56eSmrg 2703d6c0b56eSmrg 2704d6c0b56eSmrgstatic unsigned int 2705d6c0b56eSmrgdrmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int *num_dvi, int *num_hdmi, int dynamic) 2706d6c0b56eSmrg{ 2707d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 2708d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 2709d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 2710d6c0b56eSmrg xf86OutputPtr output; 2711d6c0b56eSmrg drmModeConnectorPtr koutput; 2712d6c0b56eSmrg drmModeEncoderPtr *kencoders = NULL; 2713d6c0b56eSmrg drmmode_output_private_ptr drmmode_output; 2714d6c0b56eSmrg drmModePropertyBlobPtr path_blob = NULL; 271535d5b7c7Smrg#if XF86_CRTC_VERSION >= 8 271635d5b7c7Smrg Bool nonDesktop = FALSE; 271735d5b7c7Smrg#endif 2718d6c0b56eSmrg char name[32]; 2719d6c0b56eSmrg int i; 2720d6c0b56eSmrg const char *s; 2721d6c0b56eSmrg 2722d6c0b56eSmrg koutput = 2723d6c0b56eSmrg drmModeGetConnector(pAMDGPUEnt->fd, 2724d6c0b56eSmrg mode_res->connectors[num]); 2725d6c0b56eSmrg if (!koutput) 2726d6c0b56eSmrg return 0; 2727d6c0b56eSmrg 272824b90cf4Smrg path_blob = koutput_get_prop_blob(pAMDGPUEnt->fd, koutput, "PATH"); 2729d6c0b56eSmrg 273035d5b7c7Smrg#if XF86_CRTC_VERSION >= 8 273135d5b7c7Smrg i = koutput_get_prop_idx(pAMDGPUEnt->fd, koutput, DRM_MODE_PROP_RANGE, 273235d5b7c7Smrg "non-desktop"); 273335d5b7c7Smrg if (i >= 0) 273435d5b7c7Smrg nonDesktop = koutput->prop_values[i] != 0; 273535d5b7c7Smrg#endif 273635d5b7c7Smrg 2737d6c0b56eSmrg kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders); 2738d6c0b56eSmrg if (!kencoders) { 2739d6c0b56eSmrg goto out_free_encoders; 2740d6c0b56eSmrg } 2741d6c0b56eSmrg 2742d6c0b56eSmrg for (i = 0; i < koutput->count_encoders; i++) { 2743d6c0b56eSmrg kencoders[i] = 2744d6c0b56eSmrg drmModeGetEncoder(pAMDGPUEnt->fd, koutput->encoders[i]); 2745d6c0b56eSmrg if (!kencoders[i]) { 2746d6c0b56eSmrg goto out_free_encoders; 2747d6c0b56eSmrg } 2748d6c0b56eSmrg } 2749d6c0b56eSmrg 2750d6c0b56eSmrg drmmode_create_name(pScrn, koutput, name, path_blob, num_dvi, num_hdmi); 2751d6c0b56eSmrg if (path_blob) { 2752d6c0b56eSmrg drmModeFreePropertyBlob(path_blob); 2753d6c0b56eSmrg } 2754d6c0b56eSmrg 2755d6c0b56eSmrg if (path_blob && dynamic) { 2756d6c0b56eSmrg /* See if we have an output with this name already 2757d6c0b56eSmrg * and hook stuff up. 2758d6c0b56eSmrg */ 2759d6c0b56eSmrg for (i = 0; i < xf86_config->num_output; i++) { 2760d6c0b56eSmrg output = xf86_config->output[i]; 2761d6c0b56eSmrg 2762d6c0b56eSmrg if (strncmp(output->name, name, 32)) 2763d6c0b56eSmrg continue; 2764d6c0b56eSmrg 2765d6c0b56eSmrg drmmode_output = output->driver_private; 2766d6c0b56eSmrg drmmode_output->output_id = mode_res->connectors[num]; 2767d6c0b56eSmrg drmmode_output->mode_output = koutput; 276835d5b7c7Smrg#if XF86_CRTC_VERSION >= 8 276935d5b7c7Smrg output->non_desktop = nonDesktop; 277035d5b7c7Smrg#endif 2771d6c0b56eSmrg for (i = 0; i < koutput->count_encoders; i++) { 2772d6c0b56eSmrg drmModeFreeEncoder(kencoders[i]); 2773d6c0b56eSmrg } 2774d6c0b56eSmrg free(kencoders); 2775d6c0b56eSmrg return 1; 2776d6c0b56eSmrg } 2777d6c0b56eSmrg } 2778d6c0b56eSmrg 2779d6c0b56eSmrg if (xf86IsEntityShared(pScrn->entityList[0])) { 2780d6c0b56eSmrg if ((s = 2781d6c0b56eSmrg xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) { 2782d6c0b56eSmrg if (!AMDGPUZaphodStringMatches(pScrn, s, name)) 2783d6c0b56eSmrg goto out_free_encoders; 2784d6c0b56eSmrg } else { 278590f2b693Smrg if (info->instance_id != num) 2786d6c0b56eSmrg goto out_free_encoders; 2787d6c0b56eSmrg } 2788d6c0b56eSmrg } 2789d6c0b56eSmrg 2790d6c0b56eSmrg output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name); 2791d6c0b56eSmrg if (!output) { 2792d6c0b56eSmrg goto out_free_encoders; 2793d6c0b56eSmrg } 2794d6c0b56eSmrg 2795d6c0b56eSmrg drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1); 2796d6c0b56eSmrg if (!drmmode_output) { 2797d6c0b56eSmrg xf86OutputDestroy(output); 2798d6c0b56eSmrg goto out_free_encoders; 2799d6c0b56eSmrg } 2800d6c0b56eSmrg 2801d6c0b56eSmrg drmmode_output->output_id = mode_res->connectors[num]; 2802d6c0b56eSmrg drmmode_output->mode_output = koutput; 2803d6c0b56eSmrg drmmode_output->mode_encoders = kencoders; 2804d6c0b56eSmrg drmmode_output->drmmode = drmmode; 2805d6c0b56eSmrg output->mm_width = koutput->mmWidth; 2806d6c0b56eSmrg output->mm_height = koutput->mmHeight; 2807d6c0b56eSmrg 2808d6c0b56eSmrg output->subpixel_order = subpixel_conv_table[koutput->subpixel]; 2809d6c0b56eSmrg output->interlaceAllowed = TRUE; 2810d6c0b56eSmrg output->doubleScanAllowed = TRUE; 2811d6c0b56eSmrg output->driver_private = drmmode_output; 281235d5b7c7Smrg#if XF86_CRTC_VERSION >= 8 281335d5b7c7Smrg output->non_desktop = nonDesktop; 281435d5b7c7Smrg#endif 2815d6c0b56eSmrg 2816d6c0b56eSmrg output->possible_crtcs = 0xffffffff; 2817d6c0b56eSmrg for (i = 0; i < koutput->count_encoders; i++) { 2818d6c0b56eSmrg output->possible_crtcs &= kencoders[i]->possible_crtcs; 2819d6c0b56eSmrg } 2820d6c0b56eSmrg /* work out the possible clones later */ 2821d6c0b56eSmrg output->possible_clones = 0; 2822d6c0b56eSmrg 282324b90cf4Smrg drmmode_output->dpms_enum_id = 282424b90cf4Smrg koutput_get_prop_id(pAMDGPUEnt->fd, koutput, DRM_MODE_PROP_ENUM, 282524b90cf4Smrg "DPMS"); 2826d6c0b56eSmrg 2827d6c0b56eSmrg if (dynamic) { 2828d6c0b56eSmrg output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output); 2829d6c0b56eSmrg drmmode_output_create_resources(output); 2830d6c0b56eSmrg } 2831d6c0b56eSmrg 2832d6c0b56eSmrg return 1; 2833d6c0b56eSmrgout_free_encoders: 2834d6c0b56eSmrg if (kencoders) { 2835d6c0b56eSmrg for (i = 0; i < koutput->count_encoders; i++) 2836d6c0b56eSmrg drmModeFreeEncoder(kencoders[i]); 2837d6c0b56eSmrg free(kencoders); 2838d6c0b56eSmrg } 2839d6c0b56eSmrg drmModeFreeConnector(koutput); 2840d6c0b56eSmrg return 0; 2841d6c0b56eSmrg} 2842d6c0b56eSmrg 2843d6c0b56eSmrguint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output) 2844d6c0b56eSmrg{ 2845d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = 2846d6c0b56eSmrg output->driver_private, clone_drmout; 2847d6c0b56eSmrg int i; 2848d6c0b56eSmrg xf86OutputPtr clone_output; 2849d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2850d6c0b56eSmrg int index_mask = 0; 2851d6c0b56eSmrg 2852d6c0b56eSmrg if (drmmode_output->enc_clone_mask == 0) 2853d6c0b56eSmrg return index_mask; 2854d6c0b56eSmrg 2855d6c0b56eSmrg for (i = 0; i < xf86_config->num_output; i++) { 2856d6c0b56eSmrg clone_output = xf86_config->output[i]; 2857d6c0b56eSmrg clone_drmout = clone_output->driver_private; 2858d6c0b56eSmrg if (output == clone_output) 2859d6c0b56eSmrg continue; 2860d6c0b56eSmrg 2861d6c0b56eSmrg if (clone_drmout->enc_mask == 0) 2862d6c0b56eSmrg continue; 2863d6c0b56eSmrg if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask) 2864d6c0b56eSmrg index_mask |= (1 << i); 2865d6c0b56eSmrg } 2866d6c0b56eSmrg return index_mask; 2867d6c0b56eSmrg} 2868d6c0b56eSmrg 2869d6c0b56eSmrgstatic void drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res) 2870d6c0b56eSmrg{ 2871d6c0b56eSmrg int i, j; 2872d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2873d6c0b56eSmrg 2874d6c0b56eSmrg for (i = 0; i < xf86_config->num_output; i++) { 2875d6c0b56eSmrg xf86OutputPtr output = xf86_config->output[i]; 2876d6c0b56eSmrg drmmode_output_private_ptr drmmode_output; 2877d6c0b56eSmrg 2878d6c0b56eSmrg drmmode_output = output->driver_private; 2879d6c0b56eSmrg drmmode_output->enc_clone_mask = 0xff; 2880d6c0b56eSmrg /* and all the possible encoder clones for this output together */ 2881d6c0b56eSmrg for (j = 0; j < drmmode_output->mode_output->count_encoders; 2882d6c0b56eSmrg j++) { 2883d6c0b56eSmrg int k; 2884d6c0b56eSmrg for (k = 0; k < mode_res->count_encoders; k++) { 2885d6c0b56eSmrg if (mode_res->encoders[k] == 2886d6c0b56eSmrg drmmode_output-> 2887d6c0b56eSmrg mode_encoders[j]->encoder_id) 2888d6c0b56eSmrg drmmode_output->enc_mask |= (1 << k); 2889d6c0b56eSmrg } 2890d6c0b56eSmrg 2891d6c0b56eSmrg drmmode_output->enc_clone_mask &= 2892d6c0b56eSmrg drmmode_output->mode_encoders[j]->possible_clones; 2893d6c0b56eSmrg } 2894d6c0b56eSmrg } 2895d6c0b56eSmrg 2896d6c0b56eSmrg for (i = 0; i < xf86_config->num_output; i++) { 2897d6c0b56eSmrg xf86OutputPtr output = xf86_config->output[i]; 2898d6c0b56eSmrg output->possible_clones = find_clones(scrn, output); 2899d6c0b56eSmrg } 2900d6c0b56eSmrg} 2901d6c0b56eSmrg 2902d6c0b56eSmrg/* returns pitch alignment in pixels */ 2903d6c0b56eSmrgint drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe) 2904d6c0b56eSmrg{ 2905d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 2906d6c0b56eSmrg 2907d6c0b56eSmrg if (info->have_tiling_info) 2908d6c0b56eSmrg /* linear aligned requirements */ 2909d6c0b56eSmrg return MAX(64, info->group_bytes / bpe); 2910d6c0b56eSmrg else 2911d6c0b56eSmrg /* default to 512 elements if we don't know the real 2912d6c0b56eSmrg * group size otherwise the kernel may reject the CS 2913d6c0b56eSmrg * if the group sizes don't match as the pitch won't 2914d6c0b56eSmrg * be aligned properly. 2915d6c0b56eSmrg */ 2916d6c0b56eSmrg return 512; 2917d6c0b56eSmrg} 2918d6c0b56eSmrg 2919d6c0b56eSmrgstatic Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height) 2920d6c0b56eSmrg{ 2921d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2922d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 2923d6c0b56eSmrg struct amdgpu_buffer *old_front = NULL; 2924d6c0b56eSmrg ScreenPtr screen = xf86ScrnToScreen(scrn); 2925d6c0b56eSmrg int i, pitch, old_width, old_height, old_pitch; 2926d6c0b56eSmrg int cpp = info->pixel_bytes; 2927d6c0b56eSmrg PixmapPtr ppix = screen->GetScreenPixmap(screen); 2928d6c0b56eSmrg void *fb_shadow; 2929d6c0b56eSmrg int hint = 0; 2930d6c0b56eSmrg 2931d6c0b56eSmrg if (scrn->virtualX == width && scrn->virtualY == height) 2932d6c0b56eSmrg return TRUE; 2933d6c0b56eSmrg 293435d5b7c7Smrg if (width > xf86_config->maxWidth || height > xf86_config->maxHeight) { 293535d5b7c7Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 293635d5b7c7Smrg "Xorg tried resizing screen to %dx%d, but maximum " 293735d5b7c7Smrg "supported is %dx%d\n", width, height, 293835d5b7c7Smrg xf86_config->maxWidth, xf86_config->maxHeight); 293935d5b7c7Smrg return FALSE; 294035d5b7c7Smrg } 294135d5b7c7Smrg 2942d6c0b56eSmrg if (info->shadow_primary) 2943d6c0b56eSmrg hint = AMDGPU_CREATE_PIXMAP_LINEAR | AMDGPU_CREATE_PIXMAP_GTT; 2944d6c0b56eSmrg else if (!info->use_glamor) 2945d6c0b56eSmrg hint = AMDGPU_CREATE_PIXMAP_LINEAR; 2946d6c0b56eSmrg 2947d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_INFO, 2948d6c0b56eSmrg "Allocate new frame buffer %dx%d\n", width, height); 2949d6c0b56eSmrg 2950d6c0b56eSmrg old_width = scrn->virtualX; 2951d6c0b56eSmrg old_height = scrn->virtualY; 2952d6c0b56eSmrg old_pitch = scrn->displayWidth; 2953d6c0b56eSmrg old_front = info->front_buffer; 2954d6c0b56eSmrg 2955d6c0b56eSmrg scrn->virtualX = width; 2956d6c0b56eSmrg scrn->virtualY = height; 2957d6c0b56eSmrg 2958d6c0b56eSmrg info->front_buffer = 2959d6c0b56eSmrg amdgpu_alloc_pixmap_bo(scrn, scrn->virtualX, scrn->virtualY, 2960d6c0b56eSmrg scrn->depth, hint, scrn->bitsPerPixel, 2961d6c0b56eSmrg &pitch); 2962d6c0b56eSmrg if (!info->front_buffer) { 2963d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 2964d6c0b56eSmrg "Failed to allocate front buffer memory\n"); 2965d6c0b56eSmrg goto fail; 2966d6c0b56eSmrg } 2967d6c0b56eSmrg 2968d6c0b56eSmrg if (!info->use_glamor && amdgpu_bo_map(scrn, info->front_buffer) != 0) { 2969d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 2970d6c0b56eSmrg "Failed to map front buffer memory\n"); 2971d6c0b56eSmrg goto fail; 2972d6c0b56eSmrg } 2973d6c0b56eSmrg 2974d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_INFO, " => pitch %d bytes\n", pitch); 2975d6c0b56eSmrg scrn->displayWidth = pitch / cpp; 2976d6c0b56eSmrg 2977d6c0b56eSmrg if (info->use_glamor || 2978d6c0b56eSmrg (info->front_buffer->flags & AMDGPU_BO_FLAGS_GBM)) { 2979d6c0b56eSmrg screen->ModifyPixmapHeader(ppix, 2980d6c0b56eSmrg width, height, -1, -1, pitch, info->front_buffer->cpu_ptr); 2981d6c0b56eSmrg } else { 2982d6c0b56eSmrg fb_shadow = calloc(1, pitch * scrn->virtualY); 298335d5b7c7Smrg if (!fb_shadow) 2984d6c0b56eSmrg goto fail; 2985d6c0b56eSmrg free(info->fb_shadow); 2986d6c0b56eSmrg info->fb_shadow = fb_shadow; 2987d6c0b56eSmrg screen->ModifyPixmapHeader(ppix, 2988d6c0b56eSmrg width, height, -1, -1, pitch, 2989d6c0b56eSmrg info->fb_shadow); 2990d6c0b56eSmrg } 2991d6c0b56eSmrg 2992504d986fSmrg if (!amdgpu_glamor_create_screen_resources(scrn->pScreen)) 2993504d986fSmrg goto fail; 2994504d986fSmrg 299590f2b693Smrg if (info->use_glamor || info->dri2.enabled) { 2996504d986fSmrg if (!amdgpu_set_pixmap_bo(ppix, info->front_buffer)) 2997504d986fSmrg goto fail; 2998504d986fSmrg } 2999d6c0b56eSmrg 300024b90cf4Smrg amdgpu_pixmap_clear(ppix); 3001d6c0b56eSmrg amdgpu_glamor_finish(scrn); 3002d6c0b56eSmrg 3003d6c0b56eSmrg for (i = 0; i < xf86_config->num_crtc; i++) { 3004d6c0b56eSmrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 3005d6c0b56eSmrg 3006d6c0b56eSmrg if (!crtc->enabled) 3007d6c0b56eSmrg continue; 3008d6c0b56eSmrg 3009d6c0b56eSmrg drmmode_set_mode_major(crtc, &crtc->mode, 3010d6c0b56eSmrg crtc->rotation, crtc->x, crtc->y); 3011d6c0b56eSmrg } 3012d6c0b56eSmrg 3013d6c0b56eSmrg if (old_front) { 3014d6c0b56eSmrg amdgpu_bo_unref(&old_front); 3015d6c0b56eSmrg } 3016d6c0b56eSmrg 3017d6c0b56eSmrg return TRUE; 3018d6c0b56eSmrg 3019d6c0b56eSmrgfail: 3020d6c0b56eSmrg if (info->front_buffer) { 3021d6c0b56eSmrg amdgpu_bo_unref(&info->front_buffer); 3022d6c0b56eSmrg } 3023d6c0b56eSmrg info->front_buffer = old_front; 3024d6c0b56eSmrg scrn->virtualX = old_width; 3025d6c0b56eSmrg scrn->virtualY = old_height; 3026d6c0b56eSmrg scrn->displayWidth = old_pitch; 3027d6c0b56eSmrg 3028d6c0b56eSmrg return FALSE; 3029d6c0b56eSmrg} 3030d6c0b56eSmrg 303135d5b7c7Smrgstatic void 303235d5b7c7Smrgdrmmode_validate_leases(ScrnInfoPtr scrn) 303335d5b7c7Smrg{ 303435d5b7c7Smrg#ifdef XF86_LEASE_VERSION 303535d5b7c7Smrg ScreenPtr screen = scrn->pScreen; 303635d5b7c7Smrg rrScrPrivPtr scr_priv = rrGetScrPriv(screen); 303735d5b7c7Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 303835d5b7c7Smrg drmModeLesseeListPtr lessees; 303935d5b7c7Smrg RRLeasePtr lease, next; 304035d5b7c7Smrg int l; 304135d5b7c7Smrg 304235d5b7c7Smrg /* We can't talk to the kernel about leases when VT switched */ 304335d5b7c7Smrg if (!scrn->vtSema) 304435d5b7c7Smrg return; 304535d5b7c7Smrg 304635d5b7c7Smrg lessees = drmModeListLessees(pAMDGPUEnt->fd); 304735d5b7c7Smrg if (!lessees) 304835d5b7c7Smrg return; 304935d5b7c7Smrg 305035d5b7c7Smrg xorg_list_for_each_entry_safe(lease, next, &scr_priv->leases, list) { 305135d5b7c7Smrg drmmode_lease_private_ptr lease_private = lease->devPrivate; 305235d5b7c7Smrg 305335d5b7c7Smrg for (l = 0; l < lessees->count; l++) { 305435d5b7c7Smrg if (lessees->lessees[l] == lease_private->lessee_id) 305535d5b7c7Smrg break; 305635d5b7c7Smrg } 305735d5b7c7Smrg 305835d5b7c7Smrg /* check to see if the lease has gone away */ 305935d5b7c7Smrg if (l == lessees->count) { 306035d5b7c7Smrg free(lease_private); 306135d5b7c7Smrg lease->devPrivate = NULL; 306235d5b7c7Smrg xf86CrtcLeaseTerminated(lease); 306335d5b7c7Smrg } 306435d5b7c7Smrg } 306535d5b7c7Smrg 306635d5b7c7Smrg free(lessees); 306735d5b7c7Smrg#endif 306835d5b7c7Smrg} 306935d5b7c7Smrg 307035d5b7c7Smrg#ifdef XF86_LEASE_VERSION 307135d5b7c7Smrg 307235d5b7c7Smrgstatic int 307335d5b7c7Smrgdrmmode_create_lease(RRLeasePtr lease, int *fd) 307435d5b7c7Smrg{ 307535d5b7c7Smrg ScreenPtr screen = lease->screen; 307635d5b7c7Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 307735d5b7c7Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 307835d5b7c7Smrg drmmode_lease_private_ptr lease_private; 307935d5b7c7Smrg int noutput = lease->numOutputs; 308035d5b7c7Smrg int ncrtc = lease->numCrtcs; 308135d5b7c7Smrg uint32_t *objects; 308235d5b7c7Smrg size_t nobjects; 308335d5b7c7Smrg int lease_fd; 308435d5b7c7Smrg int c, o; 308535d5b7c7Smrg int i; 308635d5b7c7Smrg 308735d5b7c7Smrg nobjects = ncrtc + noutput; 308835d5b7c7Smrg if (nobjects == 0 || nobjects > (SIZE_MAX / 4) || 308935d5b7c7Smrg ncrtc > (SIZE_MAX - noutput)) 309035d5b7c7Smrg return BadValue; 309135d5b7c7Smrg 309235d5b7c7Smrg lease_private = calloc(1, sizeof (drmmode_lease_private_rec)); 309335d5b7c7Smrg if (!lease_private) 309435d5b7c7Smrg return BadAlloc; 309535d5b7c7Smrg 309635d5b7c7Smrg objects = malloc(nobjects * 4); 309735d5b7c7Smrg if (!objects) { 309835d5b7c7Smrg free(lease_private); 309935d5b7c7Smrg return BadAlloc; 310035d5b7c7Smrg } 310135d5b7c7Smrg 310235d5b7c7Smrg i = 0; 310335d5b7c7Smrg 310435d5b7c7Smrg /* Add CRTC ids */ 310535d5b7c7Smrg for (c = 0; c < ncrtc; c++) { 310635d5b7c7Smrg xf86CrtcPtr crtc = lease->crtcs[c]->devPrivate; 310735d5b7c7Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 310835d5b7c7Smrg 310935d5b7c7Smrg objects[i++] = drmmode_crtc->mode_crtc->crtc_id; 311035d5b7c7Smrg } 311135d5b7c7Smrg 311235d5b7c7Smrg /* Add connector ids */ 311335d5b7c7Smrg for (o = 0; o < noutput; o++) { 311435d5b7c7Smrg xf86OutputPtr output = lease->outputs[o]->devPrivate; 311535d5b7c7Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 311635d5b7c7Smrg 311735d5b7c7Smrg objects[i++] = drmmode_output->mode_output->connector_id; 311835d5b7c7Smrg } 311935d5b7c7Smrg 312035d5b7c7Smrg /* call kernel to create lease */ 312135d5b7c7Smrg assert (i == nobjects); 312235d5b7c7Smrg 312335d5b7c7Smrg lease_fd = drmModeCreateLease(pAMDGPUEnt->fd, objects, nobjects, 0, 312435d5b7c7Smrg &lease_private->lessee_id); 312535d5b7c7Smrg 312635d5b7c7Smrg free(objects); 312735d5b7c7Smrg 312835d5b7c7Smrg if (lease_fd < 0) { 312935d5b7c7Smrg free(lease_private); 313035d5b7c7Smrg return BadMatch; 313135d5b7c7Smrg } 313235d5b7c7Smrg 313335d5b7c7Smrg lease->devPrivate = lease_private; 313435d5b7c7Smrg 313535d5b7c7Smrg xf86CrtcLeaseStarted(lease); 313635d5b7c7Smrg 313735d5b7c7Smrg *fd = lease_fd; 313835d5b7c7Smrg return Success; 313935d5b7c7Smrg} 314035d5b7c7Smrg 314135d5b7c7Smrgstatic void 314235d5b7c7Smrgdrmmode_terminate_lease(RRLeasePtr lease) 314335d5b7c7Smrg{ 314435d5b7c7Smrg drmmode_lease_private_ptr lease_private = lease->devPrivate; 314535d5b7c7Smrg ScreenPtr screen = lease->screen; 314635d5b7c7Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 314735d5b7c7Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 314835d5b7c7Smrg 314935d5b7c7Smrg if (drmModeRevokeLease(pAMDGPUEnt->fd, lease_private->lessee_id) == 0) { 315035d5b7c7Smrg free(lease_private); 315135d5b7c7Smrg lease->devPrivate = NULL; 315235d5b7c7Smrg xf86CrtcLeaseTerminated(lease); 315335d5b7c7Smrg } 315435d5b7c7Smrg} 315535d5b7c7Smrg 315635d5b7c7Smrg#endif // XF86_LEASE_VERSION 315735d5b7c7Smrg 3158d6c0b56eSmrgstatic const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { 315935d5b7c7Smrg .resize = drmmode_xf86crtc_resize, 316035d5b7c7Smrg#ifdef XF86_LEASE_VERSION 316135d5b7c7Smrg .create_lease = drmmode_create_lease, 316235d5b7c7Smrg .terminate_lease = drmmode_terminate_lease 316335d5b7c7Smrg#endif 3164d6c0b56eSmrg}; 3165d6c0b56eSmrg 3166d6c0b56eSmrgstatic void 3167d6c0b56eSmrgdrmmode_flip_abort(xf86CrtcPtr crtc, void *event_data) 3168d6c0b56eSmrg{ 316924b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 317024b90cf4Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 3171d6c0b56eSmrg drmmode_flipdata_ptr flipdata = event_data; 317235d5b7c7Smrg int crtc_id = drmmode_get_crtc_id(crtc); 317335d5b7c7Smrg struct drmmode_fb **fb = &flipdata->fb[crtc_id]; 317435d5b7c7Smrg 317535d5b7c7Smrg if (drmmode_crtc->flip_pending == *fb) { 317635d5b7c7Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending, 317735d5b7c7Smrg NULL); 317835d5b7c7Smrg } 317935d5b7c7Smrg drmmode_fb_reference(pAMDGPUEnt->fd, fb, NULL); 3180d6c0b56eSmrg 3181d6c0b56eSmrg if (--flipdata->flip_count == 0) { 3182504d986fSmrg if (!flipdata->fe_crtc) 3183504d986fSmrg flipdata->fe_crtc = crtc; 3184504d986fSmrg flipdata->abort(flipdata->fe_crtc, flipdata->event_data); 3185d6c0b56eSmrg free(flipdata); 3186d6c0b56eSmrg } 3187d6c0b56eSmrg} 3188d6c0b56eSmrg 3189d6c0b56eSmrgstatic void 3190d6c0b56eSmrgdrmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *event_data) 3191d6c0b56eSmrg{ 3192d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 319324b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 3194d6c0b56eSmrg drmmode_flipdata_ptr flipdata = event_data; 319535d5b7c7Smrg int crtc_id = drmmode_get_crtc_id(crtc); 319635d5b7c7Smrg struct drmmode_fb **fb = &flipdata->fb[crtc_id]; 3197d6c0b56eSmrg 3198d6c0b56eSmrg /* Is this the event whose info shall be delivered to higher level? */ 3199d6c0b56eSmrg if (crtc == flipdata->fe_crtc) { 3200d6c0b56eSmrg /* Yes: Cache msc, ust for later delivery. */ 3201d6c0b56eSmrg flipdata->fe_frame = frame; 3202d6c0b56eSmrg flipdata->fe_usec = usec; 3203d6c0b56eSmrg } 3204d6c0b56eSmrg 320590f2b693Smrg if (*fb) { 320690f2b693Smrg if (drmmode_crtc->flip_pending == *fb) { 320790f2b693Smrg drmmode_fb_reference(pAMDGPUEnt->fd, 320890f2b693Smrg &drmmode_crtc->flip_pending, NULL); 320990f2b693Smrg } 321090f2b693Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, *fb); 321190f2b693Smrg drmmode_fb_reference(pAMDGPUEnt->fd, fb, NULL); 321224b90cf4Smrg } 321324b90cf4Smrg 3214d6c0b56eSmrg if (--flipdata->flip_count == 0) { 3215504d986fSmrg /* Deliver MSC & UST from reference/current CRTC to flip event 3216504d986fSmrg * handler 3217504d986fSmrg */ 3218d6c0b56eSmrg if (flipdata->fe_crtc) 3219504d986fSmrg flipdata->handler(flipdata->fe_crtc, flipdata->fe_frame, 3220504d986fSmrg flipdata->fe_usec, flipdata->event_data); 3221504d986fSmrg else 3222504d986fSmrg flipdata->handler(crtc, frame, usec, flipdata->event_data); 3223d6c0b56eSmrg 3224d6c0b56eSmrg free(flipdata); 3225d6c0b56eSmrg } 3226d6c0b56eSmrg} 3227d6c0b56eSmrg 3228504d986fSmrg#if HAVE_NOTIFY_FD 3229504d986fSmrgstatic void drmmode_notify_fd(int fd, int notify, void *data) 3230504d986fSmrg{ 3231504d986fSmrg drmmode_ptr drmmode = data; 323235d5b7c7Smrg amdgpu_drm_handle_event(fd, &drmmode->event_context); 3233504d986fSmrg} 3234504d986fSmrg#else 3235d6c0b56eSmrgstatic void drm_wakeup_handler(pointer data, int err, pointer p) 3236d6c0b56eSmrg{ 3237d6c0b56eSmrg drmmode_ptr drmmode = data; 3238d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(drmmode->scrn); 3239d6c0b56eSmrg fd_set *read_mask = p; 3240d6c0b56eSmrg 3241d6c0b56eSmrg if (err >= 0 && FD_ISSET(pAMDGPUEnt->fd, read_mask)) { 324235d5b7c7Smrg amdgpu_drm_handle_event(pAMDGPUEnt->fd, &drmmode->event_context); 3243d6c0b56eSmrg } 3244d6c0b56eSmrg} 3245504d986fSmrg#endif 3246d6c0b56eSmrg 324711bf0794Smrgstatic Bool drmmode_probe_page_flip_target(AMDGPUEntPtr pAMDGPUEnt) 324811bf0794Smrg{ 324911bf0794Smrg uint64_t cap_value; 325011bf0794Smrg 325111bf0794Smrg return drmGetCap(pAMDGPUEnt->fd, DRM_CAP_PAGE_FLIP_TARGET, 325211bf0794Smrg &cap_value) == 0 && cap_value != 0; 325311bf0794Smrg} 325411bf0794Smrg 325511bf0794Smrgstatic int 325611bf0794Smrgdrmmode_page_flip(AMDGPUEntPtr pAMDGPUEnt, drmmode_crtc_private_ptr drmmode_crtc, 325711bf0794Smrg int fb_id, uint32_t flags, uintptr_t drm_queue_seq) 325811bf0794Smrg{ 325911bf0794Smrg flags |= DRM_MODE_PAGE_FLIP_EVENT; 326011bf0794Smrg return drmModePageFlip(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 326111bf0794Smrg fb_id, flags, (void*)drm_queue_seq); 326211bf0794Smrg} 326311bf0794Smrg 326411bf0794Smrgint 326511bf0794Smrgdrmmode_page_flip_target_absolute(AMDGPUEntPtr pAMDGPUEnt, 326611bf0794Smrg drmmode_crtc_private_ptr drmmode_crtc, 326711bf0794Smrg int fb_id, uint32_t flags, 326811bf0794Smrg uintptr_t drm_queue_seq, uint32_t target_msc) 326911bf0794Smrg{ 327011bf0794Smrg if (pAMDGPUEnt->has_page_flip_target) { 327111bf0794Smrg flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE; 327211bf0794Smrg return drmModePageFlipTarget(pAMDGPUEnt->fd, 327311bf0794Smrg drmmode_crtc->mode_crtc->crtc_id, 327411bf0794Smrg fb_id, flags, (void*)drm_queue_seq, 327511bf0794Smrg target_msc); 327611bf0794Smrg } 327711bf0794Smrg 327811bf0794Smrg return drmmode_page_flip(pAMDGPUEnt, drmmode_crtc, fb_id, flags, 327911bf0794Smrg drm_queue_seq); 328011bf0794Smrg} 328111bf0794Smrg 328211bf0794Smrgint 328311bf0794Smrgdrmmode_page_flip_target_relative(AMDGPUEntPtr pAMDGPUEnt, 328411bf0794Smrg drmmode_crtc_private_ptr drmmode_crtc, 328511bf0794Smrg int fb_id, uint32_t flags, 328611bf0794Smrg uintptr_t drm_queue_seq, uint32_t target_msc) 328711bf0794Smrg{ 328811bf0794Smrg if (pAMDGPUEnt->has_page_flip_target) { 328911bf0794Smrg flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_RELATIVE; 329011bf0794Smrg return drmModePageFlipTarget(pAMDGPUEnt->fd, 329111bf0794Smrg drmmode_crtc->mode_crtc->crtc_id, 329211bf0794Smrg fb_id, flags, (void*)drm_queue_seq, 329311bf0794Smrg target_msc); 329411bf0794Smrg } 329511bf0794Smrg 329611bf0794Smrg return drmmode_page_flip(pAMDGPUEnt, drmmode_crtc, fb_id, flags, 329711bf0794Smrg drm_queue_seq); 329811bf0794Smrg} 329911bf0794Smrg 330035d5b7c7Smrg/** 330135d5b7c7Smrg * Initialize DDX color management support. It does two things: 330235d5b7c7Smrg * 330335d5b7c7Smrg * 1. Cache DRM color management property type IDs, as they do not change. They 330435d5b7c7Smrg * will be used later to modify color management via DRM, or to determine if 330535d5b7c7Smrg * there's kernel support for color management. 330635d5b7c7Smrg * 330735d5b7c7Smrg * 2. Cache degamma/gamma LUT sizes, since all CRTCs have the same LUT sizes on 330835d5b7c7Smrg * AMD hardware. 330935d5b7c7Smrg * 331035d5b7c7Smrg * If the cached ID's are all 0 after calling this function, then color 331135d5b7c7Smrg * management is not supported. For short, checking if the gamma LUT size 331235d5b7c7Smrg * property ID == 0 is sufficient. 331335d5b7c7Smrg * 331435d5b7c7Smrg * This should be called before CRTCs are initialized within pre_init, as the 331535d5b7c7Smrg * cached values will be used there. 331635d5b7c7Smrg * 331735d5b7c7Smrg * @drm_fd: DRM file descriptor 331835d5b7c7Smrg * @drmmode: drmmode object, where the cached IDs are stored 331935d5b7c7Smrg * @mode_res: The DRM mode resource containing the CRTC ids 332035d5b7c7Smrg */ 332135d5b7c7Smrgstatic void drmmode_cm_init(int drm_fd, drmmode_ptr drmmode, 332235d5b7c7Smrg drmModeResPtr mode_res) 332335d5b7c7Smrg{ 332435d5b7c7Smrg drmModeObjectPropertiesPtr drm_props; 332535d5b7c7Smrg drmModePropertyPtr drm_prop; 332635d5b7c7Smrg enum drmmode_cm_prop cm_prop; 332735d5b7c7Smrg uint32_t cm_enabled = 0; 332835d5b7c7Smrg uint32_t cm_all_enabled = (1 << CM_NUM_PROPS) - 1; 332935d5b7c7Smrg int i; 333035d5b7c7Smrg 333135d5b7c7Smrg memset(drmmode->cm_prop_ids, 0, sizeof(drmmode->cm_prop_ids)); 333235d5b7c7Smrg drmmode->gamma_lut_size = drmmode->degamma_lut_size = 0; 333335d5b7c7Smrg 333435d5b7c7Smrg if (!mode_res->crtcs) 333535d5b7c7Smrg return; 333635d5b7c7Smrg 333735d5b7c7Smrg /* AMD hardware has color management support on all pipes. It is 333835d5b7c7Smrg * therefore sufficient to only check the first CRTC. 333935d5b7c7Smrg */ 334035d5b7c7Smrg drm_props = drmModeObjectGetProperties(drm_fd, 334135d5b7c7Smrg mode_res->crtcs[0], 334235d5b7c7Smrg DRM_MODE_OBJECT_CRTC); 334335d5b7c7Smrg if (!drm_props) 334435d5b7c7Smrg return; 334535d5b7c7Smrg 334635d5b7c7Smrg for (i = 0; i < drm_props->count_props; i++) { 334735d5b7c7Smrg drm_prop = drmModeGetProperty(drm_fd, 334835d5b7c7Smrg drm_props->props[i]); 334935d5b7c7Smrg if (!drm_prop) 335035d5b7c7Smrg continue; 335135d5b7c7Smrg 335235d5b7c7Smrg cm_prop = get_cm_enum_from_str(drm_prop->name); 335335d5b7c7Smrg if (cm_prop == CM_INVALID_PROP) 335435d5b7c7Smrg continue; 335535d5b7c7Smrg 335635d5b7c7Smrg if (cm_prop == CM_DEGAMMA_LUT_SIZE) 335735d5b7c7Smrg drmmode->degamma_lut_size = drm_props->prop_values[i]; 335835d5b7c7Smrg else if (cm_prop == CM_GAMMA_LUT_SIZE) 335935d5b7c7Smrg drmmode->gamma_lut_size = drm_props->prop_values[i]; 336035d5b7c7Smrg 336135d5b7c7Smrg drmmode->cm_prop_ids[cm_prop] = drm_props->props[i]; 336235d5b7c7Smrg cm_enabled |= 1 << cm_prop; 336335d5b7c7Smrg 336435d5b7c7Smrg drmModeFreeProperty(drm_prop); 336535d5b7c7Smrg } 336635d5b7c7Smrg drmModeFreeObjectProperties(drm_props); 336735d5b7c7Smrg 336835d5b7c7Smrg /* cm is enabled only if all prop ids are found */ 336935d5b7c7Smrg if (cm_enabled == cm_all_enabled) 337035d5b7c7Smrg return; 337135d5b7c7Smrg 337235d5b7c7Smrg /* Otherwise, disable DDX cm support */ 337335d5b7c7Smrg memset(drmmode->cm_prop_ids, 0, sizeof(drmmode->cm_prop_ids)); 337435d5b7c7Smrg drmmode->gamma_lut_size = drmmode->degamma_lut_size = 0; 337535d5b7c7Smrg} 337635d5b7c7Smrg 3377d6c0b56eSmrgBool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp) 3378d6c0b56eSmrg{ 3379d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 3380d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 3381d6c0b56eSmrg int i, num_dvi = 0, num_hdmi = 0; 3382d6c0b56eSmrg unsigned int crtcs_needed = 0; 338390f2b693Smrg unsigned int crtcs_got = 0; 3384d6c0b56eSmrg drmModeResPtr mode_res; 3385d6c0b56eSmrg char *bus_id_string, *provider_name; 3386d6c0b56eSmrg 3387d6c0b56eSmrg xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs); 3388d6c0b56eSmrg 3389d6c0b56eSmrg drmmode->scrn = pScrn; 3390d6c0b56eSmrg mode_res = drmModeGetResources(pAMDGPUEnt->fd); 3391d6c0b56eSmrg if (!mode_res) 3392d6c0b56eSmrg return FALSE; 3393d6c0b56eSmrg 3394d6c0b56eSmrg drmmode->count_crtcs = mode_res->count_crtcs; 3395d6c0b56eSmrg xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width, 3396d6c0b56eSmrg mode_res->max_height); 3397d6c0b56eSmrg 3398d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 3399d6c0b56eSmrg "Initializing outputs ...\n"); 3400d6c0b56eSmrg for (i = 0; i < mode_res->count_connectors; i++) 3401d6c0b56eSmrg crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, i, &num_dvi, &num_hdmi, 0); 3402d6c0b56eSmrg 3403d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 3404d6c0b56eSmrg "%d crtcs needed for screen.\n", crtcs_needed); 3405d6c0b56eSmrg 340624b90cf4Smrg /* Need per-screen drmmode_crtc_funcs, based on our global template, 340724b90cf4Smrg * so we can disable some functions, depending on screen settings. 340824b90cf4Smrg */ 340924b90cf4Smrg info->drmmode_crtc_funcs = drmmode_crtc_funcs; 341024b90cf4Smrg 3411d6c0b56eSmrg if (!info->use_glamor) { 3412d6c0b56eSmrg /* Rotation requires hardware acceleration */ 341324b90cf4Smrg info->drmmode_crtc_funcs.shadow_allocate = NULL; 341424b90cf4Smrg info->drmmode_crtc_funcs.shadow_create = NULL; 341524b90cf4Smrg info->drmmode_crtc_funcs.shadow_destroy = NULL; 3416d6c0b56eSmrg } 3417d6c0b56eSmrg 341835d5b7c7Smrg drmmode_cm_init(pAMDGPUEnt->fd, drmmode, mode_res); 341935d5b7c7Smrg 342035d5b7c7Smrg /* Spare the server the effort to compute and update unused CLUTs. */ 342135d5b7c7Smrg if (pScrn->depth == 30 && !drmmode_cm_enabled(drmmode)) 342224b90cf4Smrg info->drmmode_crtc_funcs.gamma_set = NULL; 342324b90cf4Smrg 342490f2b693Smrg for (i = 0; i < mode_res->count_crtcs; i++) { 3425d6c0b56eSmrg if (!xf86IsEntityShared(pScrn->entityList[0]) || 342690f2b693Smrg (crtcs_got < crtcs_needed && 342790f2b693Smrg !(pAMDGPUEnt->assigned_crtcs & (1 << i)))) 342890f2b693Smrg crtcs_got += drmmode_crtc_init(pScrn, drmmode, mode_res, i); 342990f2b693Smrg } 3430d6c0b56eSmrg 3431d6c0b56eSmrg /* All ZaphodHeads outputs provided with matching crtcs? */ 343290f2b693Smrg if (crtcs_got < crtcs_needed) { 343390f2b693Smrg if (crtcs_got == 0) { 343490f2b693Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 343590f2b693Smrg "No ZaphodHeads CRTC available, needed %u\n", 343690f2b693Smrg crtcs_needed); 343790f2b693Smrg return FALSE; 343890f2b693Smrg } 343990f2b693Smrg 3440d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 3441d6c0b56eSmrg "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n", 3442d6c0b56eSmrg crtcs_needed); 344390f2b693Smrg } 3444d6c0b56eSmrg 3445d6c0b56eSmrg /* workout clones */ 3446d6c0b56eSmrg drmmode_clones_init(pScrn, drmmode, mode_res); 3447d6c0b56eSmrg 3448d6c0b56eSmrg bus_id_string = DRICreatePCIBusID(info->PciInfo); 3449d6c0b56eSmrg XNFasprintf(&provider_name, "%s @ %s", pScrn->chipset, bus_id_string); 3450d6c0b56eSmrg free(bus_id_string); 3451d6c0b56eSmrg xf86ProviderSetup(pScrn, NULL, provider_name); 3452d6c0b56eSmrg free(provider_name); 3453d6c0b56eSmrg 3454d6c0b56eSmrg xf86InitialConfiguration(pScrn, TRUE); 3455d6c0b56eSmrg 345611bf0794Smrg pAMDGPUEnt->has_page_flip_target = drmmode_probe_page_flip_target(pAMDGPUEnt); 345711bf0794Smrg 3458d6c0b56eSmrg drmModeFreeResources(mode_res); 3459d6c0b56eSmrg return TRUE; 3460d6c0b56eSmrg} 3461d6c0b56eSmrg 3462d6c0b56eSmrgvoid drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 3463d6c0b56eSmrg{ 3464d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 3465d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 3466d6c0b56eSmrg 3467d6c0b56eSmrg info->drmmode_inited = TRUE; 3468d6c0b56eSmrg if (pAMDGPUEnt->fd_wakeup_registered != serverGeneration) { 3469504d986fSmrg#if HAVE_NOTIFY_FD 3470504d986fSmrg SetNotifyFd(pAMDGPUEnt->fd, drmmode_notify_fd, X_NOTIFY_READ, drmmode); 3471504d986fSmrg#else 3472d6c0b56eSmrg AddGeneralSocket(pAMDGPUEnt->fd); 3473d6c0b56eSmrg RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr) NoopDDA, 3474d6c0b56eSmrg drm_wakeup_handler, drmmode); 3475504d986fSmrg#endif 3476d6c0b56eSmrg pAMDGPUEnt->fd_wakeup_registered = serverGeneration; 3477d6c0b56eSmrg pAMDGPUEnt->fd_wakeup_ref = 1; 3478d6c0b56eSmrg } else 3479d6c0b56eSmrg pAMDGPUEnt->fd_wakeup_ref++; 3480d6c0b56eSmrg} 3481d6c0b56eSmrg 3482d6c0b56eSmrgvoid drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 3483d6c0b56eSmrg{ 3484504d986fSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 3485d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 3486d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 3487504d986fSmrg int c; 3488d6c0b56eSmrg 3489d6c0b56eSmrg if (!info->drmmode_inited) 3490d6c0b56eSmrg return; 3491d6c0b56eSmrg 349290f2b693Smrg for (c = 0; c < config->num_crtc; c++) 349390f2b693Smrg drmmode_crtc_scanout_free(config->crtc[c]); 349490f2b693Smrg 3495d6c0b56eSmrg if (pAMDGPUEnt->fd_wakeup_registered == serverGeneration && 3496d6c0b56eSmrg !--pAMDGPUEnt->fd_wakeup_ref) { 3497504d986fSmrg#if HAVE_NOTIFY_FD 3498504d986fSmrg RemoveNotifyFd(pAMDGPUEnt->fd); 3499504d986fSmrg#else 3500d6c0b56eSmrg RemoveGeneralSocket(pAMDGPUEnt->fd); 3501d6c0b56eSmrg RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr) NoopDDA, 3502d6c0b56eSmrg drm_wakeup_handler, drmmode); 3503504d986fSmrg#endif 3504504d986fSmrg } 3505d6c0b56eSmrg} 3506d6c0b56eSmrg 350724b90cf4Smrgstatic void drmmode_sprite_do_set_cursor(struct amdgpu_device_priv *device_priv, 350824b90cf4Smrg ScrnInfoPtr scrn, int x, int y) 350924b90cf4Smrg{ 351024b90cf4Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 351124b90cf4Smrg CursorPtr cursor = device_priv->cursor; 351224b90cf4Smrg Bool sprite_visible = device_priv->sprite_visible; 351324b90cf4Smrg 351424b90cf4Smrg if (cursor) { 351524b90cf4Smrg x -= cursor->bits->xhot; 351624b90cf4Smrg y -= cursor->bits->yhot; 351724b90cf4Smrg 351824b90cf4Smrg device_priv->sprite_visible = 351924b90cf4Smrg x < scrn->virtualX && y < scrn->virtualY && 352024b90cf4Smrg (x + cursor->bits->width > 0) && 352124b90cf4Smrg (y + cursor->bits->height > 0); 352224b90cf4Smrg } else { 352324b90cf4Smrg device_priv->sprite_visible = FALSE; 352424b90cf4Smrg } 352524b90cf4Smrg 352624b90cf4Smrg info->sprites_visible += device_priv->sprite_visible - sprite_visible; 352724b90cf4Smrg} 352824b90cf4Smrg 352935d5b7c7Smrgstatic void drmmode_sprite_set_cursor(DeviceIntPtr pDev, ScreenPtr pScreen, 353035d5b7c7Smrg CursorPtr pCursor, int x, int y) 353124b90cf4Smrg{ 353224b90cf4Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 353324b90cf4Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 353424b90cf4Smrg struct amdgpu_device_priv *device_priv = 353524b90cf4Smrg dixLookupScreenPrivate(&pDev->devPrivates, 353624b90cf4Smrg &amdgpu_device_private_key, pScreen); 353724b90cf4Smrg 353824b90cf4Smrg device_priv->cursor = pCursor; 353924b90cf4Smrg drmmode_sprite_do_set_cursor(device_priv, scrn, x, y); 354024b90cf4Smrg 354135d5b7c7Smrg info->SpriteFuncs->SetCursor(pDev, pScreen, pCursor, x, y); 354224b90cf4Smrg} 354324b90cf4Smrg 354435d5b7c7Smrgstatic void drmmode_sprite_move_cursor(DeviceIntPtr pDev, ScreenPtr pScreen, 354535d5b7c7Smrg int x, int y) 354624b90cf4Smrg{ 354724b90cf4Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 354824b90cf4Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 354924b90cf4Smrg struct amdgpu_device_priv *device_priv = 355024b90cf4Smrg dixLookupScreenPrivate(&pDev->devPrivates, 355124b90cf4Smrg &amdgpu_device_private_key, pScreen); 355224b90cf4Smrg 355324b90cf4Smrg drmmode_sprite_do_set_cursor(device_priv, scrn, x, y); 355424b90cf4Smrg 355535d5b7c7Smrg info->SpriteFuncs->MoveCursor(pDev, pScreen, x, y); 355624b90cf4Smrg} 355724b90cf4Smrg 355835d5b7c7Smrgstatic Bool drmmode_sprite_realize_realize_cursor(DeviceIntPtr pDev, 355935d5b7c7Smrg ScreenPtr pScreen, 356035d5b7c7Smrg CursorPtr pCursor) 356135d5b7c7Smrg{ 356235d5b7c7Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 356335d5b7c7Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 356435d5b7c7Smrg 356535d5b7c7Smrg return info->SpriteFuncs->RealizeCursor(pDev, pScreen, pCursor); 356635d5b7c7Smrg} 356735d5b7c7Smrg 356835d5b7c7Smrgstatic Bool drmmode_sprite_realize_unrealize_cursor(DeviceIntPtr pDev, 356935d5b7c7Smrg ScreenPtr pScreen, 357035d5b7c7Smrg CursorPtr pCursor) 357135d5b7c7Smrg{ 357235d5b7c7Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 357335d5b7c7Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 357435d5b7c7Smrg 357535d5b7c7Smrg return info->SpriteFuncs->UnrealizeCursor(pDev, pScreen, pCursor); 357635d5b7c7Smrg} 357735d5b7c7Smrg 357835d5b7c7Smrgstatic Bool drmmode_sprite_device_cursor_initialize(DeviceIntPtr pDev, 357935d5b7c7Smrg ScreenPtr pScreen) 358035d5b7c7Smrg{ 358135d5b7c7Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 358235d5b7c7Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 358335d5b7c7Smrg 358435d5b7c7Smrg return info->SpriteFuncs->DeviceCursorInitialize(pDev, pScreen); 358535d5b7c7Smrg} 358635d5b7c7Smrg 358735d5b7c7Smrgstatic void drmmode_sprite_device_cursor_cleanup(DeviceIntPtr pDev, 358835d5b7c7Smrg ScreenPtr pScreen) 358935d5b7c7Smrg{ 359035d5b7c7Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 359135d5b7c7Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 359235d5b7c7Smrg 359335d5b7c7Smrg info->SpriteFuncs->DeviceCursorCleanup(pDev, pScreen); 359435d5b7c7Smrg} 359535d5b7c7Smrg 359635d5b7c7SmrgmiPointerSpriteFuncRec drmmode_sprite_funcs = { 359735d5b7c7Smrg .RealizeCursor = drmmode_sprite_realize_realize_cursor, 359835d5b7c7Smrg .UnrealizeCursor = drmmode_sprite_realize_unrealize_cursor, 359935d5b7c7Smrg .SetCursor = drmmode_sprite_set_cursor, 360035d5b7c7Smrg .MoveCursor = drmmode_sprite_move_cursor, 360135d5b7c7Smrg .DeviceCursorInitialize = drmmode_sprite_device_cursor_initialize, 360235d5b7c7Smrg .DeviceCursorCleanup = drmmode_sprite_device_cursor_cleanup, 360335d5b7c7Smrg}; 360435d5b7c7Smrg 360535d5b7c7Smrg 3606d6c0b56eSmrgvoid drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y) 3607d6c0b56eSmrg{ 3608d6c0b56eSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 3609d6c0b56eSmrg xf86OutputPtr output = config->output[config->compat_output]; 3610d6c0b56eSmrg xf86CrtcPtr crtc = output->crtc; 3611d6c0b56eSmrg 3612d6c0b56eSmrg if (crtc && crtc->enabled) { 3613d6c0b56eSmrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y); 3614d6c0b56eSmrg } 3615d6c0b56eSmrg} 3616d6c0b56eSmrg 3617d6c0b56eSmrgBool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, 3618d6c0b56eSmrg Bool set_hw) 3619d6c0b56eSmrg{ 3620d6c0b56eSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 362124b90cf4Smrg unsigned num_desired = 0, num_on = 0; 3622d6c0b56eSmrg int c; 3623d6c0b56eSmrg 362424b90cf4Smrg /* First, disable all unused CRTCs */ 362524b90cf4Smrg if (set_hw) { 362624b90cf4Smrg for (c = 0; c < config->num_crtc; c++) { 362724b90cf4Smrg xf86CrtcPtr crtc = config->crtc[c]; 362824b90cf4Smrg 362924b90cf4Smrg /* Skip disabled CRTCs */ 363024b90cf4Smrg if (crtc->enabled) 363124b90cf4Smrg continue; 363224b90cf4Smrg 363335d5b7c7Smrg drmmode_crtc_dpms(crtc, DPMSModeOff); 363424b90cf4Smrg } 363524b90cf4Smrg } 363624b90cf4Smrg 363724b90cf4Smrg /* Then, try setting the chosen mode on each CRTC */ 3638d6c0b56eSmrg for (c = 0; c < config->num_crtc; c++) { 3639d6c0b56eSmrg xf86CrtcPtr crtc = config->crtc[c]; 3640d6c0b56eSmrg xf86OutputPtr output = NULL; 3641d6c0b56eSmrg int o; 3642d6c0b56eSmrg 364324b90cf4Smrg if (!crtc->enabled) 3644d6c0b56eSmrg continue; 3645d6c0b56eSmrg 3646d6c0b56eSmrg if (config->output[config->compat_output]->crtc == crtc) 3647d6c0b56eSmrg output = config->output[config->compat_output]; 3648d6c0b56eSmrg else { 3649d6c0b56eSmrg for (o = 0; o < config->num_output; o++) 3650d6c0b56eSmrg if (config->output[o]->crtc == crtc) { 3651d6c0b56eSmrg output = config->output[o]; 3652d6c0b56eSmrg break; 3653d6c0b56eSmrg } 3654d6c0b56eSmrg } 3655d6c0b56eSmrg /* paranoia */ 3656d6c0b56eSmrg if (!output) 3657d6c0b56eSmrg continue; 3658d6c0b56eSmrg 365924b90cf4Smrg num_desired++; 366024b90cf4Smrg 3661d6c0b56eSmrg /* Mark that we'll need to re-set the mode for sure */ 3662d6c0b56eSmrg memset(&crtc->mode, 0, sizeof(crtc->mode)); 3663d6c0b56eSmrg if (!crtc->desiredMode.CrtcHDisplay) { 3664d6c0b56eSmrg DisplayModePtr mode = xf86OutputFindClosestMode(output, 3665d6c0b56eSmrg pScrn-> 3666d6c0b56eSmrg currentMode); 3667d6c0b56eSmrg 366824b90cf4Smrg if (!mode) { 366924b90cf4Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 367024b90cf4Smrg "Failed to find mode for CRTC %d\n", c); 367124b90cf4Smrg continue; 367224b90cf4Smrg } 3673d6c0b56eSmrg crtc->desiredMode = *mode; 3674d6c0b56eSmrg crtc->desiredRotation = RR_Rotate_0; 3675d6c0b56eSmrg crtc->desiredX = 0; 3676d6c0b56eSmrg crtc->desiredY = 0; 3677d6c0b56eSmrg } 3678d6c0b56eSmrg 3679d6c0b56eSmrg if (set_hw) { 368024b90cf4Smrg if (crtc->funcs->set_mode_major(crtc, &crtc->desiredMode, 368124b90cf4Smrg crtc->desiredRotation, 368224b90cf4Smrg crtc->desiredX, 368324b90cf4Smrg crtc->desiredY)) { 368424b90cf4Smrg num_on++; 368524b90cf4Smrg } else { 368624b90cf4Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 368724b90cf4Smrg "Failed to set mode on CRTC %d\n", c); 368835d5b7c7Smrg RRCrtcSet(crtc->randr_crtc, NULL, crtc->x, crtc->y, 368935d5b7c7Smrg crtc->rotation, 0, NULL); 369024b90cf4Smrg } 3691d6c0b56eSmrg } else { 3692d6c0b56eSmrg crtc->mode = crtc->desiredMode; 3693d6c0b56eSmrg crtc->rotation = crtc->desiredRotation; 3694d6c0b56eSmrg crtc->x = crtc->desiredX; 3695d6c0b56eSmrg crtc->y = crtc->desiredY; 369624b90cf4Smrg if (drmmode_handle_transform(crtc)) 369724b90cf4Smrg num_on++; 3698d6c0b56eSmrg } 3699d6c0b56eSmrg } 370024b90cf4Smrg 370124b90cf4Smrg if (num_on == 0 && num_desired > 0) { 370224b90cf4Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to enable any CRTC\n"); 370324b90cf4Smrg return FALSE; 370424b90cf4Smrg } 370524b90cf4Smrg 370635d5b7c7Smrg /* Validate leases on VT re-entry */ 370790f2b693Smrg if (dixPrivateKeyRegistered(rrPrivKey)) 370890f2b693Smrg drmmode_validate_leases(pScrn); 370935d5b7c7Smrg 3710d6c0b56eSmrg return TRUE; 3711d6c0b56eSmrg} 3712d6c0b56eSmrg 3713d6c0b56eSmrgBool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn) 3714d6c0b56eSmrg{ 3715d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 371635d5b7c7Smrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 371735d5b7c7Smrg int i; 3718d6c0b56eSmrg 3719d6c0b56eSmrg if (xf86_config->num_crtc) { 3720d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 3721d6c0b56eSmrg "Initializing kms color map\n"); 3722d6c0b56eSmrg if (!miCreateDefColormap(pScreen)) 3723d6c0b56eSmrg return FALSE; 372435d5b7c7Smrg 372535d5b7c7Smrg if (pScrn->depth == 30) { 372635d5b7c7Smrg if (!drmmode_cm_enabled(&info->drmmode)) 372735d5b7c7Smrg return TRUE; 372835d5b7c7Smrg 372935d5b7c7Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 373035d5b7c7Smrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 373135d5b7c7Smrg void *gamma; 373235d5b7c7Smrg 373335d5b7c7Smrg if (crtc->gamma_size == 1024) 373435d5b7c7Smrg continue; 373535d5b7c7Smrg 373635d5b7c7Smrg gamma = malloc(1024 * 3 * sizeof(CARD16)); 373735d5b7c7Smrg if (!gamma) { 373835d5b7c7Smrg ErrorF("Failed to allocate gamma LUT memory\n"); 373935d5b7c7Smrg return FALSE; 374035d5b7c7Smrg } 374135d5b7c7Smrg 374235d5b7c7Smrg free(crtc->gamma_red); 374335d5b7c7Smrg crtc->gamma_size = 1024; 374435d5b7c7Smrg crtc->gamma_red = gamma; 374535d5b7c7Smrg crtc->gamma_green = crtc->gamma_red + crtc->gamma_size; 374635d5b7c7Smrg crtc->gamma_blue = crtc->gamma_green + crtc->gamma_size; 374735d5b7c7Smrg } 374835d5b7c7Smrg } 374935d5b7c7Smrg 375035d5b7c7Smrg /* All Radeons support 10 bit CLUTs. */ 375135d5b7c7Smrg if (!xf86HandleColormaps(pScreen, 1 << pScrn->rgbBits, 10, 375235d5b7c7Smrg NULL, NULL, CMAP_PALETTED_TRUECOLOR 3753d6c0b56eSmrg | CMAP_RELOAD_ON_MODE_SWITCH)) 3754d6c0b56eSmrg return FALSE; 375535d5b7c7Smrg 375635d5b7c7Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 375735d5b7c7Smrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 375835d5b7c7Smrg 375935d5b7c7Smrg drmmode_crtc_gamma_do_set(crtc, crtc->gamma_red, 376035d5b7c7Smrg crtc->gamma_green, 376135d5b7c7Smrg crtc->gamma_blue, 376235d5b7c7Smrg crtc->gamma_size); 376335d5b7c7Smrg } 3764d6c0b56eSmrg } 376535d5b7c7Smrg 3766d6c0b56eSmrg return TRUE; 3767d6c0b56eSmrg} 3768d6c0b56eSmrg 3769504d986fSmrgstatic Bool 3770504d986fSmrgdrmmode_find_output(ScrnInfoPtr scrn, int output_id, int *num_dvi, 3771504d986fSmrg int *num_hdmi) 3772504d986fSmrg{ 3773504d986fSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3774504d986fSmrg int i; 3775504d986fSmrg 3776504d986fSmrg for (i = 0; i < config->num_output; i++) { 3777504d986fSmrg xf86OutputPtr output = config->output[i]; 3778504d986fSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 3779504d986fSmrg 3780504d986fSmrg if (drmmode_output->output_id == output_id) { 3781504d986fSmrg switch(drmmode_output->mode_output->connector_type) { 3782504d986fSmrg case DRM_MODE_CONNECTOR_DVII: 3783504d986fSmrg case DRM_MODE_CONNECTOR_DVID: 3784504d986fSmrg case DRM_MODE_CONNECTOR_DVIA: 3785504d986fSmrg (*num_dvi)++; 3786504d986fSmrg break; 3787504d986fSmrg case DRM_MODE_CONNECTOR_HDMIA: 3788504d986fSmrg case DRM_MODE_CONNECTOR_HDMIB: 3789504d986fSmrg (*num_hdmi)++; 3790504d986fSmrg break; 3791504d986fSmrg } 3792504d986fSmrg 3793504d986fSmrg return TRUE; 3794504d986fSmrg } 3795504d986fSmrg } 3796504d986fSmrg 3797504d986fSmrg return FALSE; 3798504d986fSmrg} 3799d6c0b56eSmrg 3800d6c0b56eSmrgvoid 3801d6c0b56eSmrgamdgpu_mode_hotplug(ScrnInfoPtr scrn, drmmode_ptr drmmode) 3802d6c0b56eSmrg{ 3803d6c0b56eSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3804d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 3805d6c0b56eSmrg drmModeResPtr mode_res; 3806d6c0b56eSmrg int i, j; 3807d6c0b56eSmrg Bool found; 3808d6c0b56eSmrg Bool changed = FALSE; 3809504d986fSmrg int num_dvi = 0, num_hdmi = 0; 3810d6c0b56eSmrg 381124b90cf4Smrg /* Try to re-set the mode on all the connectors with a BAD link-state: 381224b90cf4Smrg * This may happen if a link degrades and a new modeset is necessary, using 381324b90cf4Smrg * different link-training parameters. If the kernel found that the current 381424b90cf4Smrg * mode is not achievable anymore, it should have pruned the mode before 381524b90cf4Smrg * sending the hotplug event. Try to re-set the currently-set mode to keep 381624b90cf4Smrg * the display alive, this will fail if the mode has been pruned. 381724b90cf4Smrg * In any case, we will send randr events for the Desktop Environment to 381824b90cf4Smrg * deal with it, if it wants to. 381924b90cf4Smrg */ 382024b90cf4Smrg for (i = 0; i < config->num_output; i++) { 382124b90cf4Smrg xf86OutputPtr output = config->output[i]; 382224b90cf4Smrg xf86CrtcPtr crtc = output->crtc; 382324b90cf4Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 382424b90cf4Smrg 382524b90cf4Smrg drmmode_output_detect(output); 382624b90cf4Smrg 382724b90cf4Smrg if (!crtc || !drmmode_output->mode_output) 382824b90cf4Smrg continue; 382924b90cf4Smrg 383024b90cf4Smrg /* Get an updated view of the properties for the current connector and 383124b90cf4Smrg * look for the link-status property 383224b90cf4Smrg */ 383324b90cf4Smrg for (j = 0; j < drmmode_output->num_props; j++) { 383424b90cf4Smrg drmmode_prop_ptr p = &drmmode_output->props[j]; 383524b90cf4Smrg 383624b90cf4Smrg if (!strcmp(p->mode_prop->name, "link-status")) { 383724b90cf4Smrg if (p->value != DRM_MODE_LINK_STATUS_BAD) 383824b90cf4Smrg break; 383924b90cf4Smrg 384024b90cf4Smrg /* the connector got a link failure, re-set the current mode */ 384124b90cf4Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 384224b90cf4Smrg crtc->x, crtc->y); 384324b90cf4Smrg 384424b90cf4Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 384524b90cf4Smrg "hotplug event: connector %u's link-state is BAD, " 384624b90cf4Smrg "tried resetting the current mode. You may be left" 384724b90cf4Smrg "with a black screen if this fails...\n", 384824b90cf4Smrg drmmode_output->mode_output->connector_id); 384924b90cf4Smrg 385024b90cf4Smrg break; 385124b90cf4Smrg } 385224b90cf4Smrg } 385324b90cf4Smrg } 385424b90cf4Smrg 3855d6c0b56eSmrg mode_res = drmModeGetResources(pAMDGPUEnt->fd); 3856d6c0b56eSmrg if (!mode_res) 3857d6c0b56eSmrg goto out; 3858d6c0b56eSmrg 3859d6c0b56eSmrgrestart_destroy: 3860d6c0b56eSmrg for (i = 0; i < config->num_output; i++) { 3861d6c0b56eSmrg xf86OutputPtr output = config->output[i]; 3862d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 3863d6c0b56eSmrg found = FALSE; 3864d6c0b56eSmrg for (j = 0; j < mode_res->count_connectors; j++) { 3865d6c0b56eSmrg if (mode_res->connectors[j] == drmmode_output->output_id) { 3866d6c0b56eSmrg found = TRUE; 3867d6c0b56eSmrg break; 3868d6c0b56eSmrg } 3869d6c0b56eSmrg } 3870d6c0b56eSmrg if (found) 3871d6c0b56eSmrg continue; 3872d6c0b56eSmrg 3873d6c0b56eSmrg drmModeFreeConnector(drmmode_output->mode_output); 3874d6c0b56eSmrg drmmode_output->mode_output = NULL; 3875d6c0b56eSmrg drmmode_output->output_id = -1; 3876d6c0b56eSmrg 3877d6c0b56eSmrg changed = TRUE; 3878d6c0b56eSmrg if (drmmode->delete_dp_12_displays) { 3879d6c0b56eSmrg RROutputDestroy(output->randr_output); 3880d6c0b56eSmrg xf86OutputDestroy(output); 3881d6c0b56eSmrg goto restart_destroy; 3882d6c0b56eSmrg } 3883d6c0b56eSmrg } 3884d6c0b56eSmrg 3885d6c0b56eSmrg /* find new output ids we don't have outputs for */ 3886d6c0b56eSmrg for (i = 0; i < mode_res->count_connectors; i++) { 388790f2b693Smrg for (j = 0; j < pAMDGPUEnt->num_scrns; j++) { 388890f2b693Smrg if (drmmode_find_output(pAMDGPUEnt->scrn[j], 388990f2b693Smrg mode_res->connectors[i], 389090f2b693Smrg &num_dvi, &num_hdmi)) 389190f2b693Smrg break; 389290f2b693Smrg } 389390f2b693Smrg 389490f2b693Smrg if (j < pAMDGPUEnt->num_scrns) 3895d6c0b56eSmrg continue; 3896d6c0b56eSmrg 3897504d986fSmrg if (drmmode_output_init(scrn, drmmode, mode_res, i, &num_dvi, 3898504d986fSmrg &num_hdmi, 1) != 0) 3899504d986fSmrg changed = TRUE; 3900d6c0b56eSmrg } 3901d6c0b56eSmrg 390235d5b7c7Smrg /* Check to see if a lessee has disappeared */ 390335d5b7c7Smrg drmmode_validate_leases(scrn); 390435d5b7c7Smrg 390590f2b693Smrg if (changed) { 3906d6c0b56eSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,2,0) 3907d6c0b56eSmrg RRSetChanged(xf86ScrnToScreen(scrn)); 3908d6c0b56eSmrg#else 3909d6c0b56eSmrg rrScrPrivPtr rrScrPriv = rrGetScrPriv(scrn->pScreen); 3910d6c0b56eSmrg rrScrPriv->changed = TRUE; 3911d6c0b56eSmrg#endif 3912d6c0b56eSmrg RRTellChanged(xf86ScrnToScreen(scrn)); 3913d6c0b56eSmrg } 3914d6c0b56eSmrg 3915d6c0b56eSmrg drmModeFreeResources(mode_res); 3916d6c0b56eSmrgout: 3917d6c0b56eSmrg RRGetInfo(xf86ScrnToScreen(scrn), TRUE); 3918d6c0b56eSmrg} 3919d6c0b56eSmrg 3920d6c0b56eSmrg#ifdef HAVE_LIBUDEV 3921d6c0b56eSmrgstatic void drmmode_handle_uevents(int fd, void *closure) 3922d6c0b56eSmrg{ 3923d6c0b56eSmrg drmmode_ptr drmmode = closure; 3924d6c0b56eSmrg ScrnInfoPtr scrn = drmmode->scrn; 3925d6c0b56eSmrg struct udev_device *dev; 3926504d986fSmrg Bool received = FALSE; 392711bf0794Smrg struct timeval tv = { 0, 0 }; 392811bf0794Smrg fd_set readfd; 392911bf0794Smrg 393011bf0794Smrg FD_ZERO(&readfd); 393111bf0794Smrg FD_SET(fd, &readfd); 393211bf0794Smrg 393311bf0794Smrg while (select(fd + 1, &readfd, NULL, NULL, &tv) > 0 && 393411bf0794Smrg FD_ISSET(fd, &readfd)) { 393511bf0794Smrg /* select() ensured that this will not block */ 393611bf0794Smrg dev = udev_monitor_receive_device(drmmode->uevent_monitor); 393711bf0794Smrg if (dev) { 393811bf0794Smrg udev_device_unref(dev); 393911bf0794Smrg received = TRUE; 394011bf0794Smrg } 3941504d986fSmrg } 3942504d986fSmrg 3943504d986fSmrg if (received) 3944504d986fSmrg amdgpu_mode_hotplug(scrn, drmmode); 3945d6c0b56eSmrg} 3946d6c0b56eSmrg#endif 3947d6c0b56eSmrg 3948d6c0b56eSmrgvoid drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode) 3949d6c0b56eSmrg{ 3950d6c0b56eSmrg#ifdef HAVE_LIBUDEV 3951d6c0b56eSmrg struct udev *u; 3952d6c0b56eSmrg struct udev_monitor *mon; 3953d6c0b56eSmrg 3954d6c0b56eSmrg u = udev_new(); 3955d6c0b56eSmrg if (!u) 3956d6c0b56eSmrg return; 3957d6c0b56eSmrg mon = udev_monitor_new_from_netlink(u, "udev"); 3958d6c0b56eSmrg if (!mon) { 3959d6c0b56eSmrg udev_unref(u); 3960d6c0b56eSmrg return; 3961d6c0b56eSmrg } 3962d6c0b56eSmrg 3963d6c0b56eSmrg if (udev_monitor_filter_add_match_subsystem_devtype(mon, 3964d6c0b56eSmrg "drm", 3965d6c0b56eSmrg "drm_minor") < 0 || 3966d6c0b56eSmrg udev_monitor_enable_receiving(mon) < 0) { 3967d6c0b56eSmrg udev_monitor_unref(mon); 3968d6c0b56eSmrg udev_unref(u); 3969d6c0b56eSmrg return; 3970d6c0b56eSmrg } 3971d6c0b56eSmrg 3972d6c0b56eSmrg drmmode->uevent_handler = 3973d6c0b56eSmrg xf86AddGeneralHandler(udev_monitor_get_fd(mon), 3974d6c0b56eSmrg drmmode_handle_uevents, drmmode); 3975d6c0b56eSmrg 3976d6c0b56eSmrg drmmode->uevent_monitor = mon; 3977d6c0b56eSmrg#endif 3978d6c0b56eSmrg} 3979d6c0b56eSmrg 3980d6c0b56eSmrgvoid drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode) 3981d6c0b56eSmrg{ 3982d6c0b56eSmrg#ifdef HAVE_LIBUDEV 3983d6c0b56eSmrg if (drmmode->uevent_handler) { 3984d6c0b56eSmrg struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor); 3985d6c0b56eSmrg xf86RemoveGeneralHandler(drmmode->uevent_handler); 3986d6c0b56eSmrg 3987d6c0b56eSmrg udev_monitor_unref(drmmode->uevent_monitor); 3988d6c0b56eSmrg udev_unref(u); 3989d6c0b56eSmrg } 3990d6c0b56eSmrg#endif 3991d6c0b56eSmrg} 3992d6c0b56eSmrg 3993d6c0b56eSmrgBool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, 3994d6c0b56eSmrg PixmapPtr new_front, uint64_t id, void *data, 399524b90cf4Smrg xf86CrtcPtr ref_crtc, amdgpu_drm_handler_proc handler, 3996504d986fSmrg amdgpu_drm_abort_proc abort, 399711bf0794Smrg enum drmmode_flip_sync flip_sync, 399811bf0794Smrg uint32_t target_msc) 3999d6c0b56eSmrg{ 4000d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 4001d6c0b56eSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 4002d6c0b56eSmrg xf86CrtcPtr crtc = NULL; 4003d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private; 400490f2b693Smrg int crtc_id; 400511bf0794Smrg uint32_t flip_flags = flip_sync == FLIP_ASYNC ? DRM_MODE_PAGE_FLIP_ASYNC : 0; 4006d6c0b56eSmrg drmmode_flipdata_ptr flipdata; 400735d5b7c7Smrg Bool handle_deferred = FALSE; 4008d6c0b56eSmrg uintptr_t drm_queue_seq = 0; 400935d5b7c7Smrg struct drmmode_fb *fb; 401035d5b7c7Smrg int i = 0; 4011d6c0b56eSmrg 401290f2b693Smrg flipdata = calloc(1, sizeof(*flipdata) + drmmode_crtc->drmmode->count_crtcs * 401335d5b7c7Smrg sizeof(flipdata->fb[0])); 4014d6c0b56eSmrg if (!flipdata) { 4015d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 4016d6c0b56eSmrg "flip queue: data alloc failed.\n"); 4017d6c0b56eSmrg goto error; 4018d6c0b56eSmrg } 4019d6c0b56eSmrg 402035d5b7c7Smrg fb = amdgpu_pixmap_get_fb(new_front); 402135d5b7c7Smrg if (!fb) { 402224b90cf4Smrg ErrorF("Failed to get FB for flip\n"); 4023d6c0b56eSmrg goto error; 402424b90cf4Smrg } 4025d6c0b56eSmrg 4026d6c0b56eSmrg /* 4027d6c0b56eSmrg * Queue flips on all enabled CRTCs 4028d6c0b56eSmrg * Note that if/when we get per-CRTC buffers, we'll have to update this. 4029d6c0b56eSmrg * Right now it assumes a single shared fb across all CRTCs, with the 4030d6c0b56eSmrg * kernel fixing up the offset of each CRTC as necessary. 4031d6c0b56eSmrg * 4032d6c0b56eSmrg * Also, flips queued on disabled or incorrectly configured displays 4033d6c0b56eSmrg * may never complete; this is a configuration error. 4034d6c0b56eSmrg */ 4035d6c0b56eSmrg 4036d6c0b56eSmrg flipdata->event_data = data; 4037d6c0b56eSmrg flipdata->handler = handler; 4038d6c0b56eSmrg flipdata->abort = abort; 403924b90cf4Smrg flipdata->fe_crtc = ref_crtc; 4040d6c0b56eSmrg 4041d6c0b56eSmrg for (i = 0; i < config->num_crtc; i++) { 4042d6c0b56eSmrg crtc = config->crtc[i]; 404324b90cf4Smrg drmmode_crtc = crtc->driver_private; 404490f2b693Smrg crtc_id = drmmode_get_crtc_id(crtc); 4045d6c0b56eSmrg 404624b90cf4Smrg if (!drmmode_crtc_can_flip(crtc) || 404724b90cf4Smrg (drmmode_crtc->tear_free && crtc != ref_crtc)) 4048d6c0b56eSmrg continue; 4049d6c0b56eSmrg 4050d6c0b56eSmrg flipdata->flip_count++; 4051d6c0b56eSmrg 4052d6c0b56eSmrg drm_queue_seq = amdgpu_drm_queue_alloc(crtc, client, id, 4053d6c0b56eSmrg flipdata, 4054d6c0b56eSmrg drmmode_flip_handler, 405590f2b693Smrg drmmode_flip_abort, 405690f2b693Smrg TRUE); 4057504d986fSmrg if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) { 4058d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 4059d6c0b56eSmrg "Allocating DRM queue event entry failed.\n"); 4060d6c0b56eSmrg goto error; 4061d6c0b56eSmrg } 4062d6c0b56eSmrg 406324b90cf4Smrg if (drmmode_crtc->tear_free) { 406424b90cf4Smrg BoxRec extents = { .x1 = 0, .y1 = 0, 406524b90cf4Smrg .x2 = new_front->drawable.width, 406624b90cf4Smrg .y2 = new_front->drawable.height }; 406724b90cf4Smrg int scanout_id = drmmode_crtc->scanout_id ^ 1; 406824b90cf4Smrg 406924b90cf4Smrg if (flip_sync == FLIP_ASYNC) { 407024b90cf4Smrg if (!drmmode_wait_vblank(crtc, 407124b90cf4Smrg DRM_VBLANK_RELATIVE | 407224b90cf4Smrg DRM_VBLANK_EVENT, 407324b90cf4Smrg 0, drm_queue_seq, 407424b90cf4Smrg NULL, NULL)) 407524b90cf4Smrg goto flip_error; 407624b90cf4Smrg goto next; 407724b90cf4Smrg } 407824b90cf4Smrg 407990f2b693Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &flipdata->fb[crtc_id], 408035d5b7c7Smrg amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap)); 408190f2b693Smrg if (!flipdata->fb[crtc_id]) { 408224b90cf4Smrg ErrorF("Failed to get FB for TearFree flip\n"); 408324b90cf4Smrg goto error; 408424b90cf4Smrg } 408524b90cf4Smrg 408624b90cf4Smrg amdgpu_scanout_do_update(crtc, scanout_id, new_front, 408735d5b7c7Smrg extents); 408835d5b7c7Smrg amdgpu_glamor_flush(crtc->scrn); 408935d5b7c7Smrg 409035d5b7c7Smrg if (drmmode_crtc->scanout_update_pending) { 409135d5b7c7Smrg amdgpu_drm_wait_pending_flip(crtc); 409235d5b7c7Smrg handle_deferred = TRUE; 409335d5b7c7Smrg amdgpu_drm_abort_entry(drmmode_crtc->scanout_update_pending); 409435d5b7c7Smrg drmmode_crtc->scanout_update_pending = 0; 409535d5b7c7Smrg } 409635d5b7c7Smrg } else { 409790f2b693Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &flipdata->fb[crtc_id], fb); 409824b90cf4Smrg } 409924b90cf4Smrg 410024b90cf4Smrg if (crtc == ref_crtc) { 410111bf0794Smrg if (drmmode_page_flip_target_absolute(pAMDGPUEnt, 410211bf0794Smrg drmmode_crtc, 410390f2b693Smrg flipdata->fb[crtc_id]->handle, 410411bf0794Smrg flip_flags, 410511bf0794Smrg drm_queue_seq, 410611bf0794Smrg target_msc) != 0) 410711bf0794Smrg goto flip_error; 410811bf0794Smrg } else { 410911bf0794Smrg if (drmmode_page_flip_target_relative(pAMDGPUEnt, 411011bf0794Smrg drmmode_crtc, 411190f2b693Smrg flipdata->fb[crtc_id]->handle, 411211bf0794Smrg flip_flags, 411311bf0794Smrg drm_queue_seq, 0) != 0) 411411bf0794Smrg goto flip_error; 4115d6c0b56eSmrg } 411611bf0794Smrg 411724b90cf4Smrg if (drmmode_crtc->tear_free) { 411824b90cf4Smrg drmmode_crtc->scanout_id ^= 1; 411924b90cf4Smrg drmmode_crtc->ignore_damage = TRUE; 412024b90cf4Smrg } 412124b90cf4Smrg 412235d5b7c7Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending, 412390f2b693Smrg flipdata->fb[crtc_id]); 412490f2b693Smrg 412590f2b693Smrg next: 4126d6c0b56eSmrg drm_queue_seq = 0; 4127d6c0b56eSmrg } 4128d6c0b56eSmrg 412935d5b7c7Smrg if (handle_deferred) 413035d5b7c7Smrg amdgpu_drm_queue_handle_deferred(ref_crtc); 4131d6c0b56eSmrg if (flipdata->flip_count > 0) 4132d6c0b56eSmrg return TRUE; 4133d6c0b56eSmrg 413411bf0794Smrgflip_error: 413511bf0794Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed: %s\n", 413611bf0794Smrg strerror(errno)); 413711bf0794Smrg 4138d6c0b56eSmrgerror: 4139d6c0b56eSmrg if (drm_queue_seq) 4140d6c0b56eSmrg amdgpu_drm_abort_entry(drm_queue_seq); 4141d6c0b56eSmrg else if (crtc) 4142d6c0b56eSmrg drmmode_flip_abort(crtc, flipdata); 414311bf0794Smrg else { 414411bf0794Smrg abort(NULL, data); 4145d6c0b56eSmrg free(flipdata); 414611bf0794Smrg } 4147d6c0b56eSmrg 4148d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n", 4149d6c0b56eSmrg strerror(errno)); 415035d5b7c7Smrg if (handle_deferred) 415135d5b7c7Smrg amdgpu_drm_queue_handle_deferred(ref_crtc); 4152d6c0b56eSmrg return FALSE; 4153d6c0b56eSmrg} 4154