drmmode_display.c revision 24b90cf4
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" 40d6c0b56eSmrg#include "xf86cmap.h" 41504d986fSmrg#include "xf86Priv.h" 42d6c0b56eSmrg#include "sarea.h" 43d6c0b56eSmrg 44d6c0b56eSmrg#include "drmmode_display.h" 45d6c0b56eSmrg#include "amdgpu_bo_helper.h" 46d6c0b56eSmrg#include "amdgpu_glamor.h" 47d6c0b56eSmrg#include "amdgpu_pixmap.h" 48d6c0b56eSmrg 49d6c0b56eSmrg#include <dri.h> 50d6c0b56eSmrg 51d6c0b56eSmrg/* DPMS */ 52d6c0b56eSmrg#ifdef HAVE_XEXTPROTO_71 53d6c0b56eSmrg#include <X11/extensions/dpmsconst.h> 54d6c0b56eSmrg#else 55d6c0b56eSmrg#define DPMS_SERVER 56d6c0b56eSmrg#include <X11/extensions/dpms.h> 57d6c0b56eSmrg#endif 58d6c0b56eSmrg 59d6c0b56eSmrg#include <gbm.h> 60d6c0b56eSmrg 61d6c0b56eSmrg#define DEFAULT_NOMINAL_FRAME_RATE 60 62d6c0b56eSmrg 63d6c0b56eSmrgstatic Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height); 64d6c0b56eSmrg 65d6c0b56eSmrgstatic Bool 66d6c0b56eSmrgAMDGPUZaphodStringMatches(ScrnInfoPtr pScrn, const char *s, char *output_name) 67d6c0b56eSmrg{ 68d6c0b56eSmrg int i = 0; 69d6c0b56eSmrg char s1[20]; 70d6c0b56eSmrg 71d6c0b56eSmrg do { 72d6c0b56eSmrg switch (*s) { 73d6c0b56eSmrg case ',': 74d6c0b56eSmrg s1[i] = '\0'; 75d6c0b56eSmrg i = 0; 76d6c0b56eSmrg if (strcmp(s1, output_name) == 0) 77d6c0b56eSmrg return TRUE; 78d6c0b56eSmrg break; 79d6c0b56eSmrg case ' ': 80d6c0b56eSmrg case '\t': 81d6c0b56eSmrg case '\n': 82d6c0b56eSmrg case '\r': 83d6c0b56eSmrg break; 84d6c0b56eSmrg default: 85d6c0b56eSmrg s1[i] = *s; 86d6c0b56eSmrg i++; 87d6c0b56eSmrg break; 88d6c0b56eSmrg } 89d6c0b56eSmrg } while (*s++); 90d6c0b56eSmrg 91d6c0b56eSmrg s1[i] = '\0'; 92d6c0b56eSmrg if (strcmp(s1, output_name) == 0) 93d6c0b56eSmrg return TRUE; 94d6c0b56eSmrg 95d6c0b56eSmrg return FALSE; 96d6c0b56eSmrg} 97d6c0b56eSmrg 9824b90cf4Smrg 9924b90cf4Smrg/* Wait for the boolean condition to be FALSE */ 10024b90cf4Smrg#define drmmode_crtc_wait_pending_event(drmmode_crtc, fd, condition) \ 10124b90cf4Smrg do {} while ((condition) && \ 10224b90cf4Smrg drmHandleEvent(fd, &drmmode_crtc->drmmode->event_context) \ 10324b90cf4Smrg > 0); 10424b90cf4Smrg 10524b90cf4Smrg 106d6c0b56eSmrgstatic PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn, 107d6c0b56eSmrg int width, int height, 108d6c0b56eSmrg int depth, int bpp, 109d6c0b56eSmrg int pitch, 110d6c0b56eSmrg struct amdgpu_buffer *bo) 111d6c0b56eSmrg{ 112d6c0b56eSmrg ScreenPtr pScreen = pScrn->pScreen; 113d6c0b56eSmrg PixmapPtr pixmap; 114d6c0b56eSmrg 115d6c0b56eSmrg pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 116d6c0b56eSmrg AMDGPU_CREATE_PIXMAP_SCANOUT); 117d6c0b56eSmrg if (!pixmap) 118d6c0b56eSmrg return NULL; 119d6c0b56eSmrg 120d6c0b56eSmrg if (!(*pScreen->ModifyPixmapHeader) (pixmap, width, height, 121504d986fSmrg depth, bpp, pitch, NULL)) 122504d986fSmrg goto fail; 123d6c0b56eSmrg 124504d986fSmrg if (!amdgpu_glamor_create_textured_pixmap(pixmap, bo)) 125504d986fSmrg goto fail; 126d6c0b56eSmrg 127504d986fSmrg if (amdgpu_set_pixmap_bo(pixmap, bo)) 128504d986fSmrg return pixmap; 129d6c0b56eSmrg 130504d986fSmrgfail: 131504d986fSmrg pScreen->DestroyPixmap(pixmap); 132504d986fSmrg return NULL; 133d6c0b56eSmrg} 134d6c0b56eSmrg 135d6c0b56eSmrgstatic void drmmode_destroy_bo_pixmap(PixmapPtr pixmap) 136d6c0b56eSmrg{ 137d6c0b56eSmrg ScreenPtr pScreen = pixmap->drawable.pScreen; 138d6c0b56eSmrg 139d6c0b56eSmrg (*pScreen->DestroyPixmap) (pixmap); 140d6c0b56eSmrg} 141d6c0b56eSmrg 142d6c0b56eSmrgstatic void 143d6c0b56eSmrgdrmmode_ConvertFromKMode(ScrnInfoPtr scrn, 144d6c0b56eSmrg drmModeModeInfo * kmode, DisplayModePtr mode) 145d6c0b56eSmrg{ 146d6c0b56eSmrg memset(mode, 0, sizeof(DisplayModeRec)); 147d6c0b56eSmrg mode->status = MODE_OK; 148d6c0b56eSmrg 149d6c0b56eSmrg mode->Clock = kmode->clock; 150d6c0b56eSmrg 151d6c0b56eSmrg mode->HDisplay = kmode->hdisplay; 152d6c0b56eSmrg mode->HSyncStart = kmode->hsync_start; 153d6c0b56eSmrg mode->HSyncEnd = kmode->hsync_end; 154d6c0b56eSmrg mode->HTotal = kmode->htotal; 155d6c0b56eSmrg mode->HSkew = kmode->hskew; 156d6c0b56eSmrg 157d6c0b56eSmrg mode->VDisplay = kmode->vdisplay; 158d6c0b56eSmrg mode->VSyncStart = kmode->vsync_start; 159d6c0b56eSmrg mode->VSyncEnd = kmode->vsync_end; 160d6c0b56eSmrg mode->VTotal = kmode->vtotal; 161d6c0b56eSmrg mode->VScan = kmode->vscan; 162d6c0b56eSmrg 163d6c0b56eSmrg mode->Flags = kmode->flags; //& FLAG_BITS; 164d6c0b56eSmrg mode->name = strdup(kmode->name); 165d6c0b56eSmrg 166d6c0b56eSmrg if (kmode->type & DRM_MODE_TYPE_DRIVER) 167d6c0b56eSmrg mode->type = M_T_DRIVER; 168d6c0b56eSmrg if (kmode->type & DRM_MODE_TYPE_PREFERRED) 169d6c0b56eSmrg mode->type |= M_T_PREFERRED; 170d6c0b56eSmrg xf86SetModeCrtc(mode, scrn->adjustFlags); 171d6c0b56eSmrg} 172d6c0b56eSmrg 173d6c0b56eSmrgstatic void 174d6c0b56eSmrgdrmmode_ConvertToKMode(ScrnInfoPtr scrn, 175d6c0b56eSmrg drmModeModeInfo * kmode, DisplayModePtr mode) 176d6c0b56eSmrg{ 177d6c0b56eSmrg memset(kmode, 0, sizeof(*kmode)); 178d6c0b56eSmrg 179d6c0b56eSmrg kmode->clock = mode->Clock; 180d6c0b56eSmrg kmode->hdisplay = mode->HDisplay; 181d6c0b56eSmrg kmode->hsync_start = mode->HSyncStart; 182d6c0b56eSmrg kmode->hsync_end = mode->HSyncEnd; 183d6c0b56eSmrg kmode->htotal = mode->HTotal; 184d6c0b56eSmrg kmode->hskew = mode->HSkew; 185d6c0b56eSmrg 186d6c0b56eSmrg kmode->vdisplay = mode->VDisplay; 187d6c0b56eSmrg kmode->vsync_start = mode->VSyncStart; 188d6c0b56eSmrg kmode->vsync_end = mode->VSyncEnd; 189d6c0b56eSmrg kmode->vtotal = mode->VTotal; 190d6c0b56eSmrg kmode->vscan = mode->VScan; 191d6c0b56eSmrg 192d6c0b56eSmrg kmode->flags = mode->Flags; //& FLAG_BITS; 193d6c0b56eSmrg if (mode->name) 194d6c0b56eSmrg strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN); 195d6c0b56eSmrg kmode->name[DRM_DISPLAY_MODE_LEN - 1] = 0; 196d6c0b56eSmrg 197d6c0b56eSmrg} 198d6c0b56eSmrg 19924b90cf4Smrg/* 20024b90cf4Smrg * Utility helper for drmWaitVBlank 20124b90cf4Smrg */ 20224b90cf4SmrgBool 20324b90cf4Smrgdrmmode_wait_vblank(xf86CrtcPtr crtc, drmVBlankSeqType type, 20424b90cf4Smrg uint32_t target_seq, unsigned long signal, uint64_t *ust, 20524b90cf4Smrg uint32_t *result_seq) 20624b90cf4Smrg{ 20724b90cf4Smrg int crtc_id = drmmode_get_crtc_id(crtc); 20824b90cf4Smrg ScrnInfoPtr scrn = crtc->scrn; 20924b90cf4Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 21024b90cf4Smrg drmVBlank vbl; 21124b90cf4Smrg 21224b90cf4Smrg if (crtc_id == 1) 21324b90cf4Smrg type |= DRM_VBLANK_SECONDARY; 21424b90cf4Smrg else if (crtc_id > 1) 21524b90cf4Smrg type |= (crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT) & 21624b90cf4Smrg DRM_VBLANK_HIGH_CRTC_MASK; 21724b90cf4Smrg 21824b90cf4Smrg vbl.request.type = type; 21924b90cf4Smrg vbl.request.sequence = target_seq; 22024b90cf4Smrg vbl.request.signal = signal; 22124b90cf4Smrg 22224b90cf4Smrg if (drmWaitVBlank(pAMDGPUEnt->fd, &vbl) != 0) 22324b90cf4Smrg return FALSE; 22424b90cf4Smrg 22524b90cf4Smrg if (ust) 22624b90cf4Smrg *ust = (uint64_t)vbl.reply.tval_sec * 1000000 + 22724b90cf4Smrg vbl.reply.tval_usec; 22824b90cf4Smrg if (result_seq) 22924b90cf4Smrg *result_seq = vbl.reply.sequence; 23024b90cf4Smrg 23124b90cf4Smrg return TRUE; 23224b90cf4Smrg} 23324b90cf4Smrg 234d6c0b56eSmrg/* 235d6c0b56eSmrg * Retrieves present time in microseconds that is compatible 236d6c0b56eSmrg * with units used by vblank timestamps. Depending on the kernel 237d6c0b56eSmrg * version and DRM kernel module configuration, the vblank 238d6c0b56eSmrg * timestamp can either be in real time or monotonic time 239d6c0b56eSmrg */ 240d6c0b56eSmrgint drmmode_get_current_ust(int drm_fd, CARD64 * ust) 241d6c0b56eSmrg{ 242d6c0b56eSmrg uint64_t cap_value; 243d6c0b56eSmrg int ret; 244d6c0b56eSmrg struct timespec now; 245d6c0b56eSmrg 246d6c0b56eSmrg ret = drmGetCap(drm_fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap_value); 247d6c0b56eSmrg if (ret || !cap_value) 248d6c0b56eSmrg /* old kernel or drm_timestamp_monotonic turned off */ 249d6c0b56eSmrg ret = clock_gettime(CLOCK_REALTIME, &now); 250d6c0b56eSmrg else 251d6c0b56eSmrg ret = clock_gettime(CLOCK_MONOTONIC, &now); 252d6c0b56eSmrg if (ret) 253d6c0b56eSmrg return ret; 254d6c0b56eSmrg *ust = ((CARD64) now.tv_sec * 1000000) + ((CARD64) now.tv_nsec / 1000); 255d6c0b56eSmrg return 0; 256d6c0b56eSmrg} 257d6c0b56eSmrg 258d6c0b56eSmrg/* 259d6c0b56eSmrg * Get current frame count and frame count timestamp of the crtc. 260d6c0b56eSmrg */ 261d6c0b56eSmrgint drmmode_crtc_get_ust_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc) 262d6c0b56eSmrg{ 263d6c0b56eSmrg ScrnInfoPtr scrn = crtc->scrn; 26424b90cf4Smrg uint32_t seq; 265d6c0b56eSmrg 26624b90cf4Smrg if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, ust, &seq)) { 267d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 268d6c0b56eSmrg "get vblank counter failed: %s\n", strerror(errno)); 26924b90cf4Smrg return -1; 270d6c0b56eSmrg } 271d6c0b56eSmrg 27224b90cf4Smrg *msc = seq; 273d6c0b56eSmrg 274d6c0b56eSmrg return Success; 275d6c0b56eSmrg} 276d6c0b56eSmrg 277d6c0b56eSmrgstatic void 278d6c0b56eSmrgdrmmode_do_crtc_dpms(xf86CrtcPtr crtc, int mode) 279d6c0b56eSmrg{ 280d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 281d6c0b56eSmrg ScrnInfoPtr scrn = crtc->scrn; 282d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 283d6c0b56eSmrg CARD64 ust; 284d6c0b56eSmrg int ret; 285d6c0b56eSmrg 286d6c0b56eSmrg if (drmmode_crtc->dpms_mode == DPMSModeOn && mode != DPMSModeOn) { 28724b90cf4Smrg uint32_t seq; 288d6c0b56eSmrg 28924b90cf4Smrg drmmode_crtc_wait_pending_event(drmmode_crtc, pAMDGPUEnt->fd, 29024b90cf4Smrg drmmode_crtc->flip_pending); 291504d986fSmrg 292d6c0b56eSmrg /* 293d6c0b56eSmrg * On->Off transition: record the last vblank time, 294d6c0b56eSmrg * sequence number and frame period. 295d6c0b56eSmrg */ 29624b90cf4Smrg if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, &ust, 29724b90cf4Smrg &seq)) 298d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 299d6c0b56eSmrg "%s cannot get last vblank counter\n", 300d6c0b56eSmrg __func__); 301d6c0b56eSmrg else { 302d6c0b56eSmrg CARD64 nominal_frame_rate, pix_in_frame; 303d6c0b56eSmrg 304d6c0b56eSmrg drmmode_crtc->dpms_last_ust = ust; 305d6c0b56eSmrg drmmode_crtc->dpms_last_seq = seq; 306d6c0b56eSmrg nominal_frame_rate = crtc->mode.Clock; 307d6c0b56eSmrg nominal_frame_rate *= 1000; 308d6c0b56eSmrg pix_in_frame = crtc->mode.HTotal * crtc->mode.VTotal; 309d6c0b56eSmrg if (nominal_frame_rate == 0 || pix_in_frame == 0) 310d6c0b56eSmrg nominal_frame_rate = DEFAULT_NOMINAL_FRAME_RATE; 311d6c0b56eSmrg else 312d6c0b56eSmrg nominal_frame_rate /= pix_in_frame; 313d6c0b56eSmrg drmmode_crtc->dpms_last_fps = nominal_frame_rate; 314d6c0b56eSmrg } 315d6c0b56eSmrg } else if (drmmode_crtc->dpms_mode != DPMSModeOn && mode == DPMSModeOn) { 316d6c0b56eSmrg /* 317d6c0b56eSmrg * Off->On transition: calculate and accumulate the 318d6c0b56eSmrg * number of interpolated vblanks while we were in Off state 319d6c0b56eSmrg */ 320d6c0b56eSmrg ret = drmmode_get_current_ust(pAMDGPUEnt->fd, &ust); 321d6c0b56eSmrg if (ret) 322d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 323d6c0b56eSmrg "%s cannot get current time\n", __func__); 324d6c0b56eSmrg else if (drmmode_crtc->dpms_last_ust) { 325d6c0b56eSmrg CARD64 time_elapsed, delta_seq; 326d6c0b56eSmrg time_elapsed = ust - drmmode_crtc->dpms_last_ust; 327d6c0b56eSmrg delta_seq = time_elapsed * drmmode_crtc->dpms_last_fps; 328d6c0b56eSmrg delta_seq /= 1000000; 329d6c0b56eSmrg drmmode_crtc->interpolated_vblanks += delta_seq; 330d6c0b56eSmrg 331d6c0b56eSmrg } 332d6c0b56eSmrg } 333d6c0b56eSmrg drmmode_crtc->dpms_mode = mode; 334d6c0b56eSmrg} 335d6c0b56eSmrg 336d6c0b56eSmrgstatic void 337d6c0b56eSmrgdrmmode_crtc_dpms(xf86CrtcPtr crtc, int mode) 338d6c0b56eSmrg{ 339d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 340d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 341d6c0b56eSmrg 342d6c0b56eSmrg /* Disable unused CRTCs and enable/disable active CRTCs */ 343504d986fSmrg if (!crtc->enabled || mode != DPMSModeOn) { 34424b90cf4Smrg drmmode_crtc_wait_pending_event(drmmode_crtc, pAMDGPUEnt->fd, 34524b90cf4Smrg drmmode_crtc->flip_pending); 346d6c0b56eSmrg drmModeSetCrtc(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 347d6c0b56eSmrg 0, 0, 0, NULL, 0, NULL); 34824b90cf4Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, NULL); 349504d986fSmrg } else if (drmmode_crtc->dpms_mode != DPMSModeOn) 350d6c0b56eSmrg crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation, 351d6c0b56eSmrg crtc->x, crtc->y); 352d6c0b56eSmrg} 353d6c0b56eSmrg 354d6c0b56eSmrgstatic PixmapPtr 355d6c0b56eSmrgcreate_pixmap_for_fbcon(drmmode_ptr drmmode, 356d6c0b56eSmrg ScrnInfoPtr pScrn, int fbcon_id) 357d6c0b56eSmrg{ 358d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 359d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 360d6c0b56eSmrg PixmapPtr pixmap = info->fbcon_pixmap; 361d6c0b56eSmrg struct amdgpu_buffer *bo; 362d6c0b56eSmrg drmModeFBPtr fbcon; 363d6c0b56eSmrg struct drm_gem_flink flink; 364d6c0b56eSmrg struct amdgpu_bo_import_result import = {0}; 365d6c0b56eSmrg 366d6c0b56eSmrg if (pixmap) 367d6c0b56eSmrg return pixmap; 368d6c0b56eSmrg 369d6c0b56eSmrg fbcon = drmModeGetFB(pAMDGPUEnt->fd, fbcon_id); 370d6c0b56eSmrg if (fbcon == NULL) 371d6c0b56eSmrg return NULL; 372d6c0b56eSmrg 373d6c0b56eSmrg if (fbcon->depth != pScrn->depth || 374d6c0b56eSmrg fbcon->width != pScrn->virtualX || 375d6c0b56eSmrg fbcon->height != pScrn->virtualY) 376d6c0b56eSmrg goto out_free_fb; 377d6c0b56eSmrg 378d6c0b56eSmrg flink.handle = fbcon->handle; 379d6c0b56eSmrg if (ioctl(pAMDGPUEnt->fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) { 380d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 381d6c0b56eSmrg "Couldn't flink fbcon handle\n"); 382d6c0b56eSmrg goto out_free_fb; 383d6c0b56eSmrg } 384d6c0b56eSmrg 385d6c0b56eSmrg bo = calloc(1, sizeof(struct amdgpu_buffer)); 386d6c0b56eSmrg if (bo == NULL) { 387d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 388d6c0b56eSmrg "Couldn't allocate bo for fbcon handle\n"); 389d6c0b56eSmrg goto out_free_fb; 390d6c0b56eSmrg } 391d6c0b56eSmrg bo->ref_count = 1; 392d6c0b56eSmrg 393d6c0b56eSmrg if (amdgpu_bo_import(pAMDGPUEnt->pDev, 394d6c0b56eSmrg amdgpu_bo_handle_type_gem_flink_name, flink.name, 395d6c0b56eSmrg &import) != 0) { 396d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 397d6c0b56eSmrg "Couldn't import BO for fbcon handle\n"); 398d6c0b56eSmrg goto out_free_bo; 399d6c0b56eSmrg } 400d6c0b56eSmrg bo->bo.amdgpu = import.buf_handle; 401d6c0b56eSmrg 402d6c0b56eSmrg pixmap = drmmode_create_bo_pixmap(pScrn, fbcon->width, fbcon->height, 403d6c0b56eSmrg fbcon->depth, fbcon->bpp, 404d6c0b56eSmrg fbcon->pitch, bo); 405d6c0b56eSmrg info->fbcon_pixmap = pixmap; 406d6c0b56eSmrgout_free_bo: 407d6c0b56eSmrg amdgpu_bo_unref(&bo); 408d6c0b56eSmrgout_free_fb: 409d6c0b56eSmrg drmModeFreeFB(fbcon); 410d6c0b56eSmrg return pixmap; 411d6c0b56eSmrg} 412d6c0b56eSmrg 413d6c0b56eSmrgvoid drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 414d6c0b56eSmrg{ 415d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 416d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 417d6c0b56eSmrg ScreenPtr pScreen = pScrn->pScreen; 41824b90cf4Smrg PixmapPtr src, dst = pScreen->GetScreenPixmap(pScreen); 41924b90cf4Smrg struct drmmode_fb *fb = amdgpu_pixmap_get_fb(dst); 420d6c0b56eSmrg int fbcon_id = 0; 421d6c0b56eSmrg GCPtr gc; 422d6c0b56eSmrg int i; 423d6c0b56eSmrg 424d6c0b56eSmrg for (i = 0; i < xf86_config->num_crtc; i++) { 425d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[i]->driver_private; 426d6c0b56eSmrg 427d6c0b56eSmrg if (drmmode_crtc->mode_crtc->buffer_id) 428d6c0b56eSmrg fbcon_id = drmmode_crtc->mode_crtc->buffer_id; 429d6c0b56eSmrg } 430d6c0b56eSmrg 431d6c0b56eSmrg if (!fbcon_id) 432d6c0b56eSmrg return; 433d6c0b56eSmrg 43424b90cf4Smrg if (fbcon_id == fb->handle) { 435d6c0b56eSmrg /* in some rare case there might be no fbcon and we might already 436d6c0b56eSmrg * be the one with the current fb to avoid a false deadlck in 437d6c0b56eSmrg * kernel ttm code just do nothing as anyway there is nothing 438d6c0b56eSmrg * to do 439d6c0b56eSmrg */ 440d6c0b56eSmrg return; 441d6c0b56eSmrg } 442d6c0b56eSmrg 443d6c0b56eSmrg src = create_pixmap_for_fbcon(drmmode, pScrn, fbcon_id); 444d6c0b56eSmrg if (!src) 445d6c0b56eSmrg return; 446d6c0b56eSmrg 447d6c0b56eSmrg gc = GetScratchGC(pScrn->depth, pScreen); 448d6c0b56eSmrg ValidateGC(&dst->drawable, gc); 449d6c0b56eSmrg 450d6c0b56eSmrg (*gc->ops->CopyArea)(&src->drawable, &dst->drawable, gc, 0, 0, 451d6c0b56eSmrg pScrn->virtualX, pScrn->virtualY, 0, 0); 452d6c0b56eSmrg 453d6c0b56eSmrg FreeScratchGC(gc); 454d6c0b56eSmrg 455d6c0b56eSmrg pScreen->canDoBGNoneRoot = TRUE; 456d6c0b56eSmrg 457d6c0b56eSmrg if (info->fbcon_pixmap) 458d6c0b56eSmrg pScrn->pScreen->DestroyPixmap(info->fbcon_pixmap); 459d6c0b56eSmrg info->fbcon_pixmap = NULL; 460d6c0b56eSmrg 461d6c0b56eSmrg return; 462d6c0b56eSmrg} 463d6c0b56eSmrg 46424b90cf4Smrgvoid 465d6c0b56eSmrgdrmmode_crtc_scanout_destroy(drmmode_ptr drmmode, 466d6c0b56eSmrg struct drmmode_scanout *scanout) 467d6c0b56eSmrg{ 468d6c0b56eSmrg 469d6c0b56eSmrg if (scanout->pixmap) { 470d6c0b56eSmrg drmmode_destroy_bo_pixmap(scanout->pixmap); 471d6c0b56eSmrg scanout->pixmap = NULL; 472d6c0b56eSmrg } 473d6c0b56eSmrg 474d6c0b56eSmrg if (scanout->bo) { 475d6c0b56eSmrg amdgpu_bo_unref(&scanout->bo); 476d6c0b56eSmrg scanout->bo = NULL; 477d6c0b56eSmrg } 478504d986fSmrg} 479504d986fSmrg 48024b90cf4Smrgvoid 481504d986fSmrgdrmmode_crtc_scanout_free(drmmode_crtc_private_ptr drmmode_crtc) 482504d986fSmrg{ 48324b90cf4Smrg drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, 48424b90cf4Smrg &drmmode_crtc->scanout[0]); 48524b90cf4Smrg drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, 48624b90cf4Smrg &drmmode_crtc->scanout[1]); 487d6c0b56eSmrg 48824b90cf4Smrg if (drmmode_crtc->scanout_damage) 489504d986fSmrg DamageDestroy(drmmode_crtc->scanout_damage); 490d6c0b56eSmrg} 491d6c0b56eSmrg 49224b90cf4SmrgPixmapPtr 49311bf0794Smrgdrmmode_crtc_scanout_create(xf86CrtcPtr crtc, struct drmmode_scanout *scanout, 49411bf0794Smrg int width, int height) 495d6c0b56eSmrg{ 496d6c0b56eSmrg ScrnInfoPtr pScrn = crtc->scrn; 497d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 498d6c0b56eSmrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 49911bf0794Smrg int pitch; 500d6c0b56eSmrg 50111bf0794Smrg if (scanout->pixmap) { 502d6c0b56eSmrg if (scanout->width == width && scanout->height == height) 50311bf0794Smrg return scanout->pixmap; 504d6c0b56eSmrg 505d6c0b56eSmrg drmmode_crtc_scanout_destroy(drmmode, scanout); 506d6c0b56eSmrg } 507d6c0b56eSmrg 508d6c0b56eSmrg scanout->bo = amdgpu_alloc_pixmap_bo(pScrn, width, height, 50911bf0794Smrg pScrn->depth, 0, 51011bf0794Smrg pScrn->bitsPerPixel, &pitch); 511d6c0b56eSmrg if (!scanout->bo) { 512d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 51311bf0794Smrg "Failed to allocate scanout buffer memory\n"); 51424b90cf4Smrg return NULL; 515d6c0b56eSmrg } 516d6c0b56eSmrg 517d6c0b56eSmrg scanout->pixmap = drmmode_create_bo_pixmap(pScrn, 518d6c0b56eSmrg width, height, 519d6c0b56eSmrg pScrn->depth, 520d6c0b56eSmrg pScrn->bitsPerPixel, 52111bf0794Smrg pitch, scanout->bo); 52224b90cf4Smrg if (!scanout->pixmap) { 52324b90cf4Smrg ErrorF("failed to create CRTC scanout pixmap\n"); 52424b90cf4Smrg goto error; 52524b90cf4Smrg } 52624b90cf4Smrg 52724b90cf4Smrg if (amdgpu_pixmap_get_fb(scanout->pixmap)) { 52811bf0794Smrg scanout->width = width; 52911bf0794Smrg scanout->height = height; 53011bf0794Smrg } else { 53124b90cf4Smrg ErrorF("failed to create CRTC scanout FB\n"); 53224b90cf4Smrgerror: 53311bf0794Smrg drmmode_crtc_scanout_destroy(drmmode, scanout); 534d6c0b56eSmrg } 535d6c0b56eSmrg 53611bf0794Smrg return scanout->pixmap; 537d6c0b56eSmrg} 538d6c0b56eSmrg 539d6c0b56eSmrgstatic void 540d6c0b56eSmrgamdgpu_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure) 541d6c0b56eSmrg{ 54224b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = closure; 54324b90cf4Smrg 54424b90cf4Smrg if (drmmode_crtc->ignore_damage) { 54524b90cf4Smrg RegionEmpty(&damage->damage); 54624b90cf4Smrg drmmode_crtc->ignore_damage = FALSE; 54724b90cf4Smrg return; 54824b90cf4Smrg } 54924b90cf4Smrg 550d6c0b56eSmrg /* Only keep track of the extents */ 551d6c0b56eSmrg RegionUninit(&damage->damage); 552d6c0b56eSmrg damage->damage.data = NULL; 553d6c0b56eSmrg} 554d6c0b56eSmrg 55524b90cf4Smrgstatic void 55624b90cf4Smrgdrmmode_screen_damage_destroy(DamagePtr damage, void *closure) 55724b90cf4Smrg{ 55824b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = closure; 55924b90cf4Smrg 56024b90cf4Smrg drmmode_crtc->scanout_damage = NULL; 56124b90cf4Smrg RegionUninit(&drmmode_crtc->scanout_last_region); 56224b90cf4Smrg} 56324b90cf4Smrg 564d6c0b56eSmrgstatic Bool 565d6c0b56eSmrgdrmmode_can_use_hw_cursor(xf86CrtcPtr crtc) 566d6c0b56eSmrg{ 567d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn); 568d6c0b56eSmrg 569d6c0b56eSmrg /* Check for Option "SWcursor" */ 570d6c0b56eSmrg if (xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) 571d6c0b56eSmrg return FALSE; 572d6c0b56eSmrg 573d6c0b56eSmrg /* Fall back to SW cursor if the CRTC is transformed */ 574d6c0b56eSmrg if (crtc->transformPresent) 575d6c0b56eSmrg return FALSE; 576d6c0b56eSmrg 57724b90cf4Smrg#if XF86_CRTC_VERSION < 7 578d6c0b56eSmrg /* Xorg doesn't correctly handle cursor position transform in the 579d6c0b56eSmrg * rotation case 580d6c0b56eSmrg */ 581d6c0b56eSmrg if (crtc->driverIsPerformingTransform && 582d6c0b56eSmrg (crtc->rotation & 0xf) != RR_Rotate_0) 583d6c0b56eSmrg return FALSE; 584d6c0b56eSmrg#endif 585d6c0b56eSmrg 586504d986fSmrg /* HW cursor not supported with RandR 1.4 multihead up to 1.18.99.901 */ 587504d986fSmrg if (xorgGetVersion() <= XORG_VERSION_NUMERIC(1,18,99,901,0) && 588504d986fSmrg !xorg_list_is_empty(&crtc->scrn->pScreen->pixmap_dirty_list)) 589d6c0b56eSmrg return FALSE; 590d6c0b56eSmrg 591d6c0b56eSmrg return TRUE; 592d6c0b56eSmrg} 593d6c0b56eSmrg 59411bf0794Smrgstatic void 59511bf0794Smrgdrmmode_crtc_update_tear_free(xf86CrtcPtr crtc) 59611bf0794Smrg{ 59711bf0794Smrg AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn); 59811bf0794Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 59911bf0794Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 60011bf0794Smrg int i; 60111bf0794Smrg 60211bf0794Smrg drmmode_crtc->tear_free = FALSE; 60311bf0794Smrg 60411bf0794Smrg for (i = 0; i < xf86_config->num_output; i++) { 60511bf0794Smrg xf86OutputPtr output = xf86_config->output[i]; 60611bf0794Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 60711bf0794Smrg 60811bf0794Smrg if (output->crtc != crtc) 60911bf0794Smrg continue; 61011bf0794Smrg 61111bf0794Smrg if (drmmode_output->tear_free == 1 || 61211bf0794Smrg (drmmode_output->tear_free == 2 && 61324b90cf4Smrg (crtc->scrn->pScreen->isGPU || 61411bf0794Smrg info->shadow_primary || 61511bf0794Smrg crtc->transformPresent || crtc->rotation != RR_Rotate_0))) { 61611bf0794Smrg drmmode_crtc->tear_free = TRUE; 61711bf0794Smrg return; 61811bf0794Smrg } 61911bf0794Smrg } 62011bf0794Smrg} 62111bf0794Smrg 62211bf0794Smrg#if XF86_CRTC_VERSION < 7 62311bf0794Smrg#define XF86DriverTransformOutput TRUE 62411bf0794Smrg#define XF86DriverTransformNone FALSE 62511bf0794Smrg#endif 62611bf0794Smrg 627d6c0b56eSmrgstatic Bool 628d6c0b56eSmrgdrmmode_handle_transform(xf86CrtcPtr crtc) 629d6c0b56eSmrg{ 630d6c0b56eSmrg Bool ret; 631d6c0b56eSmrg 63224b90cf4Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 633504d986fSmrg if (crtc->transformPresent || crtc->rotation != RR_Rotate_0) 634504d986fSmrg crtc->driverIsPerformingTransform = XF86DriverTransformOutput; 635504d986fSmrg else 636504d986fSmrg crtc->driverIsPerformingTransform = XF86DriverTransformNone; 63724b90cf4Smrg#else 63824b90cf4Smrg crtc->driverIsPerformingTransform = !crtc->transformPresent && 63924b90cf4Smrg crtc->rotation != RR_Rotate_0 && 64024b90cf4Smrg (crtc->rotation & 0xf) == RR_Rotate_0; 64124b90cf4Smrg#endif 642d6c0b56eSmrg 643d6c0b56eSmrg ret = xf86CrtcRotate(crtc); 644d6c0b56eSmrg 645d6c0b56eSmrg crtc->driverIsPerformingTransform &= ret && crtc->transform_in_use; 646d6c0b56eSmrg 647d6c0b56eSmrg return ret; 648d6c0b56eSmrg} 649d6c0b56eSmrg 65011bf0794Smrg 65111bf0794Smrgstatic void 65211bf0794Smrgdrmmode_crtc_prime_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode, 65324b90cf4Smrg unsigned scanout_id, struct drmmode_fb **fb, 65424b90cf4Smrg int *x, int *y) 65511bf0794Smrg{ 65611bf0794Smrg ScrnInfoPtr scrn = crtc->scrn; 65711bf0794Smrg ScreenPtr screen = scrn->pScreen; 65811bf0794Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 65911bf0794Smrg 66011bf0794Smrg if (drmmode_crtc->tear_free && 66111bf0794Smrg !drmmode_crtc->scanout[1].pixmap) { 66211bf0794Smrg RegionPtr region; 66311bf0794Smrg BoxPtr box; 66411bf0794Smrg 66511bf0794Smrg drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], 66611bf0794Smrg mode->HDisplay, 66711bf0794Smrg mode->VDisplay); 66811bf0794Smrg region = &drmmode_crtc->scanout_last_region; 66911bf0794Smrg RegionUninit(region); 67011bf0794Smrg region->data = NULL; 67111bf0794Smrg box = RegionExtents(region); 67211bf0794Smrg box->x1 = crtc->x; 67311bf0794Smrg box->y1 = crtc->y; 67411bf0794Smrg box->x2 = crtc->x + mode->HDisplay; 67511bf0794Smrg box->y2 = crtc->y + mode->VDisplay; 67611bf0794Smrg } 67711bf0794Smrg 67811bf0794Smrg if (scanout_id != drmmode_crtc->scanout_id) { 67911bf0794Smrg PixmapDirtyUpdatePtr dirty = NULL; 68011bf0794Smrg 68111bf0794Smrg xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, 68211bf0794Smrg ent) { 68324b90cf4Smrg if (amdgpu_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) { 68411bf0794Smrg dirty->slave_dst = 68511bf0794Smrg drmmode_crtc->scanout[scanout_id].pixmap; 68611bf0794Smrg break; 68711bf0794Smrg } 68811bf0794Smrg } 68911bf0794Smrg 69011bf0794Smrg if (!drmmode_crtc->tear_free) { 69111bf0794Smrg GCPtr gc = GetScratchGC(scrn->depth, screen); 69211bf0794Smrg 69311bf0794Smrg ValidateGC(&drmmode_crtc->scanout[0].pixmap->drawable, gc); 69411bf0794Smrg gc->ops->CopyArea(&drmmode_crtc->scanout[1].pixmap->drawable, 69511bf0794Smrg &drmmode_crtc->scanout[0].pixmap->drawable, 69611bf0794Smrg gc, 0, 0, mode->HDisplay, mode->VDisplay, 69711bf0794Smrg 0, 0); 69811bf0794Smrg FreeScratchGC(gc); 69911bf0794Smrg amdgpu_glamor_finish(scrn); 70011bf0794Smrg } 70111bf0794Smrg } 70211bf0794Smrg 70324b90cf4Smrg *fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap); 70411bf0794Smrg *x = *y = 0; 70511bf0794Smrg drmmode_crtc->scanout_id = scanout_id; 70611bf0794Smrg} 70711bf0794Smrg 70811bf0794Smrg 70911bf0794Smrgstatic void 71011bf0794Smrgdrmmode_crtc_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode, 71124b90cf4Smrg unsigned scanout_id, struct drmmode_fb **fb, int *x, 71224b90cf4Smrg int *y) 71311bf0794Smrg{ 71411bf0794Smrg ScrnInfoPtr scrn = crtc->scrn; 71511bf0794Smrg ScreenPtr screen = scrn->pScreen; 71611bf0794Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 71711bf0794Smrg 71824b90cf4Smrg drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[scanout_id], 71911bf0794Smrg mode->HDisplay, mode->VDisplay); 72011bf0794Smrg if (drmmode_crtc->tear_free) { 72124b90cf4Smrg drmmode_crtc_scanout_create(crtc, 72224b90cf4Smrg &drmmode_crtc->scanout[scanout_id ^ 1], 72311bf0794Smrg mode->HDisplay, mode->VDisplay); 72411bf0794Smrg } 72511bf0794Smrg 72624b90cf4Smrg if (drmmode_crtc->scanout[scanout_id].pixmap && 72724b90cf4Smrg (!drmmode_crtc->tear_free || 72824b90cf4Smrg drmmode_crtc->scanout[scanout_id ^ 1].pixmap)) { 72911bf0794Smrg RegionPtr region; 73011bf0794Smrg BoxPtr box; 73111bf0794Smrg 73211bf0794Smrg if (!drmmode_crtc->scanout_damage) { 73311bf0794Smrg drmmode_crtc->scanout_damage = 73411bf0794Smrg DamageCreate(amdgpu_screen_damage_report, 73524b90cf4Smrg drmmode_screen_damage_destroy, 73624b90cf4Smrg DamageReportRawRegion, 73724b90cf4Smrg TRUE, screen, drmmode_crtc); 73824b90cf4Smrg DamageRegister(&screen->root->drawable, 73911bf0794Smrg drmmode_crtc->scanout_damage); 74011bf0794Smrg } 74111bf0794Smrg 74211bf0794Smrg region = DamageRegion(drmmode_crtc->scanout_damage); 74311bf0794Smrg RegionUninit(region); 74411bf0794Smrg region->data = NULL; 74511bf0794Smrg box = RegionExtents(region); 74611bf0794Smrg box->x1 = 0; 74711bf0794Smrg box->y1 = 0; 74811bf0794Smrg box->x2 = max(box->x2, scrn->virtualX); 74911bf0794Smrg box->y2 = max(box->y2, scrn->virtualY); 75011bf0794Smrg 75124b90cf4Smrg *fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap); 75211bf0794Smrg *x = *y = 0; 75311bf0794Smrg 75424b90cf4Smrg amdgpu_scanout_do_update(crtc, scanout_id, 75524b90cf4Smrg screen->GetWindowPixmap(screen->root), 75624b90cf4Smrg box); 75711bf0794Smrg amdgpu_glamor_finish(scrn); 75811bf0794Smrg } 75911bf0794Smrg} 76011bf0794Smrg 76124b90cf4Smrgstatic void 76224b90cf4Smrgdrmmode_crtc_gamma_do_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, 76324b90cf4Smrg uint16_t *blue, int size) 76424b90cf4Smrg{ 76524b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 76624b90cf4Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 76724b90cf4Smrg 76824b90cf4Smrg drmModeCrtcSetGamma(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 76924b90cf4Smrg size, red, green, blue); 77024b90cf4Smrg} 77124b90cf4Smrg 77224b90cf4SmrgBool 77324b90cf4Smrgdrmmode_set_mode(xf86CrtcPtr crtc, struct drmmode_fb *fb, DisplayModePtr mode, 77424b90cf4Smrg int x, int y) 77524b90cf4Smrg{ 77624b90cf4Smrg ScrnInfoPtr scrn = crtc->scrn; 77724b90cf4Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 77824b90cf4Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 77924b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 78024b90cf4Smrg uint32_t *output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); 78124b90cf4Smrg int output_count = 0; 78224b90cf4Smrg drmModeModeInfo kmode; 78324b90cf4Smrg Bool ret; 78424b90cf4Smrg int i; 78524b90cf4Smrg 78624b90cf4Smrg if (!output_ids) 78724b90cf4Smrg return FALSE; 78824b90cf4Smrg 78924b90cf4Smrg for (i = 0; i < xf86_config->num_output; i++) { 79024b90cf4Smrg xf86OutputPtr output = xf86_config->output[i]; 79124b90cf4Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 79224b90cf4Smrg 79324b90cf4Smrg if (output->crtc != crtc) 79424b90cf4Smrg continue; 79524b90cf4Smrg 79624b90cf4Smrg output_ids[output_count] = drmmode_output->mode_output->connector_id; 79724b90cf4Smrg output_count++; 79824b90cf4Smrg } 79924b90cf4Smrg 80024b90cf4Smrg drmmode_ConvertToKMode(scrn, &kmode, mode); 80124b90cf4Smrg 80224b90cf4Smrg ret = drmModeSetCrtc(pAMDGPUEnt->fd, 80324b90cf4Smrg drmmode_crtc->mode_crtc->crtc_id, 80424b90cf4Smrg fb->handle, x, y, output_ids, 80524b90cf4Smrg output_count, &kmode) == 0; 80624b90cf4Smrg 80724b90cf4Smrg if (ret) { 80824b90cf4Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, fb); 80924b90cf4Smrg } else { 81024b90cf4Smrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 81124b90cf4Smrg "failed to set mode: %s\n", strerror(errno)); 81224b90cf4Smrg } 81324b90cf4Smrg 81424b90cf4Smrg free(output_ids); 81524b90cf4Smrg return ret; 81624b90cf4Smrg} 81724b90cf4Smrg 818d6c0b56eSmrgstatic Bool 819d6c0b56eSmrgdrmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, 820d6c0b56eSmrg Rotation rotation, int x, int y) 821d6c0b56eSmrg{ 822d6c0b56eSmrg ScrnInfoPtr pScrn = crtc->scrn; 823d6c0b56eSmrg ScreenPtr pScreen = pScrn->pScreen; 824d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 825d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 826d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 827d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 82811bf0794Smrg unsigned scanout_id = 0; 829d6c0b56eSmrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 830d6c0b56eSmrg int saved_x, saved_y; 831d6c0b56eSmrg Rotation saved_rotation; 832d6c0b56eSmrg DisplayModeRec saved_mode; 833504d986fSmrg Bool ret = FALSE; 834d6c0b56eSmrg int i; 83524b90cf4Smrg struct drmmode_fb *fb = NULL; 83624b90cf4Smrg 83724b90cf4Smrg /* The root window contents may be undefined before the WindowExposures 83824b90cf4Smrg * hook is called for it, so bail if we get here before that 83924b90cf4Smrg */ 84024b90cf4Smrg if (pScreen->WindowExposures == AMDGPUWindowExposures_oneshot) 84124b90cf4Smrg return FALSE; 842d6c0b56eSmrg 843d6c0b56eSmrg saved_mode = crtc->mode; 844d6c0b56eSmrg saved_x = crtc->x; 845d6c0b56eSmrg saved_y = crtc->y; 846d6c0b56eSmrg saved_rotation = crtc->rotation; 847d6c0b56eSmrg 848d6c0b56eSmrg if (mode) { 849d6c0b56eSmrg crtc->mode = *mode; 850d6c0b56eSmrg crtc->x = x; 851d6c0b56eSmrg crtc->y = y; 852d6c0b56eSmrg crtc->rotation = rotation; 853d6c0b56eSmrg 854d6c0b56eSmrg if (!drmmode_handle_transform(crtc)) 855d6c0b56eSmrg goto done; 856d6c0b56eSmrg 85711bf0794Smrg drmmode_crtc_update_tear_free(crtc); 85811bf0794Smrg if (drmmode_crtc->tear_free) 85911bf0794Smrg scanout_id = drmmode_crtc->scanout_id; 86011bf0794Smrg 86124b90cf4Smrg /* gamma is disabled in kernel driver for deep color */ 86224b90cf4Smrg if (pScrn->depth != 30) 86324b90cf4Smrg drmmode_crtc_gamma_do_set( 86424b90cf4Smrg crtc, crtc->gamma_red, crtc->gamma_green, 86524b90cf4Smrg crtc->gamma_blue, crtc->gamma_size); 866d6c0b56eSmrg 86724b90cf4Smrg if (drmmode_crtc->prime_scanout_pixmap) { 86811bf0794Smrg drmmode_crtc_prime_scanout_update(crtc, mode, scanout_id, 86924b90cf4Smrg &fb, &x, &y); 87024b90cf4Smrg } else if (drmmode_crtc->rotate.pixmap) { 87124b90cf4Smrg fb = amdgpu_pixmap_get_fb(drmmode_crtc->rotate.pixmap); 872d6c0b56eSmrg x = y = 0; 87311bf0794Smrg 87424b90cf4Smrg } else if (!pScreen->isGPU && 87511bf0794Smrg (drmmode_crtc->tear_free || 876504d986fSmrg crtc->driverIsPerformingTransform || 877504d986fSmrg info->shadow_primary)) { 87811bf0794Smrg drmmode_crtc_scanout_update(crtc, mode, scanout_id, 87924b90cf4Smrg &fb, &x, &y); 880d6c0b56eSmrg } 881d6c0b56eSmrg 88224b90cf4Smrg if (!fb) 88324b90cf4Smrg fb = amdgpu_pixmap_get_fb(pScreen->GetWindowPixmap(pScreen->root)); 88424b90cf4Smrg if (!fb) { 88524b90cf4Smrg union gbm_bo_handle bo_handle; 88624b90cf4Smrg 88724b90cf4Smrg bo_handle = gbm_bo_get_handle(info->front_buffer->bo.gbm); 88824b90cf4Smrg fb = amdgpu_fb_create(pScrn, pAMDGPUEnt->fd, 88924b90cf4Smrg pScrn->virtualX, pScrn->virtualY, 89024b90cf4Smrg pScrn->displayWidth * info->pixel_bytes, 89124b90cf4Smrg bo_handle.u32); 89224b90cf4Smrg /* Prevent refcnt of ad-hoc FBs from reaching 2 */ 89324b90cf4Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, NULL); 89424b90cf4Smrg drmmode_crtc->fb = fb; 89524b90cf4Smrg } 89624b90cf4Smrg if (!fb) { 89724b90cf4Smrg ErrorF("failed to add FB for modeset\n"); 89824b90cf4Smrg goto done; 899504d986fSmrg } 900504d986fSmrg 90124b90cf4Smrg drmmode_crtc_wait_pending_event(drmmode_crtc, pAMDGPUEnt->fd, 90224b90cf4Smrg drmmode_crtc->flip_pending); 90324b90cf4Smrg 90424b90cf4Smrg if (!drmmode_set_mode(crtc, fb, mode, x, y)) 905d6c0b56eSmrg goto done; 90624b90cf4Smrg 90724b90cf4Smrg ret = TRUE; 908d6c0b56eSmrg 909d6c0b56eSmrg if (pScreen) 910d6c0b56eSmrg xf86CrtcSetScreenSubpixelOrder(pScreen); 911d6c0b56eSmrg 912d6c0b56eSmrg drmmode_crtc->need_modeset = FALSE; 913d6c0b56eSmrg 914d6c0b56eSmrg /* go through all the outputs and force DPMS them back on? */ 915d6c0b56eSmrg for (i = 0; i < xf86_config->num_output; i++) { 916d6c0b56eSmrg xf86OutputPtr output = xf86_config->output[i]; 917d6c0b56eSmrg 918d6c0b56eSmrg if (output->crtc != crtc) 919d6c0b56eSmrg continue; 920d6c0b56eSmrg 921d6c0b56eSmrg output->funcs->dpms(output, DPMSModeOn); 922d6c0b56eSmrg } 923d6c0b56eSmrg } 924d6c0b56eSmrg 925d6c0b56eSmrg /* Compute index of this CRTC into xf86_config->crtc */ 926d6c0b56eSmrg for (i = 0; i < xf86_config->num_crtc; i++) { 927d6c0b56eSmrg if (xf86_config->crtc[i] != crtc) 928d6c0b56eSmrg continue; 929d6c0b56eSmrg 930d6c0b56eSmrg if (!crtc->enabled || drmmode_can_use_hw_cursor(crtc)) 931d6c0b56eSmrg info->hwcursor_disabled &= ~(1 << i); 932d6c0b56eSmrg else 933d6c0b56eSmrg info->hwcursor_disabled |= 1 << i; 934d6c0b56eSmrg 935d6c0b56eSmrg break; 936d6c0b56eSmrg } 937d6c0b56eSmrg 938d6c0b56eSmrg#ifndef HAVE_XF86_CURSOR_RESET_CURSOR 939d6c0b56eSmrg if (!info->hwcursor_disabled) 940d6c0b56eSmrg xf86_reload_cursors(pScreen); 941d6c0b56eSmrg#endif 942d6c0b56eSmrg 943d6c0b56eSmrgdone: 944d6c0b56eSmrg if (!ret) { 945d6c0b56eSmrg crtc->x = saved_x; 946d6c0b56eSmrg crtc->y = saved_y; 947d6c0b56eSmrg crtc->rotation = saved_rotation; 948d6c0b56eSmrg crtc->mode = saved_mode; 949504d986fSmrg } else { 950d6c0b56eSmrg crtc->active = TRUE; 951d6c0b56eSmrg 95224b90cf4Smrg if (drmmode_crtc->scanout[scanout_id].pixmap && 95324b90cf4Smrg fb != amdgpu_pixmap_get_fb(drmmode_crtc-> 95424b90cf4Smrg scanout[scanout_id].pixmap)) 955504d986fSmrg drmmode_crtc_scanout_free(drmmode_crtc); 95611bf0794Smrg else if (!drmmode_crtc->tear_free) { 95711bf0794Smrg drmmode_crtc_scanout_destroy(drmmode, 95811bf0794Smrg &drmmode_crtc->scanout[1]); 95911bf0794Smrg } 960504d986fSmrg } 961504d986fSmrg 962d6c0b56eSmrg return ret; 963d6c0b56eSmrg} 964d6c0b56eSmrg 965d6c0b56eSmrgstatic void drmmode_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg) 966d6c0b56eSmrg{ 967d6c0b56eSmrg 968d6c0b56eSmrg} 969d6c0b56eSmrg 970d6c0b56eSmrgstatic void drmmode_set_cursor_position(xf86CrtcPtr crtc, int x, int y) 971d6c0b56eSmrg{ 972d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 973d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 974d6c0b56eSmrg 97524b90cf4Smrg#if XF86_CRTC_VERSION < 7 976d6c0b56eSmrg if (crtc->driverIsPerformingTransform) { 977d6c0b56eSmrg x += crtc->x; 978d6c0b56eSmrg y += crtc->y; 979d6c0b56eSmrg xf86CrtcTransformCursorPos(crtc, &x, &y); 980d6c0b56eSmrg } 981d6c0b56eSmrg#endif 982d6c0b56eSmrg 983d6c0b56eSmrg drmModeMoveCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, x, y); 984d6c0b56eSmrg} 985d6c0b56eSmrg 98624b90cf4Smrg#if XF86_CRTC_VERSION < 7 987d6c0b56eSmrg 988d6c0b56eSmrgstatic int 989d6c0b56eSmrgdrmmode_cursor_src_offset(Rotation rotation, int width, int height, 990d6c0b56eSmrg int x_dst, int y_dst) 991d6c0b56eSmrg{ 992d6c0b56eSmrg int t; 993d6c0b56eSmrg 994d6c0b56eSmrg switch (rotation & 0xf) { 995d6c0b56eSmrg case RR_Rotate_90: 996d6c0b56eSmrg t = x_dst; 997d6c0b56eSmrg x_dst = height - y_dst - 1; 998d6c0b56eSmrg y_dst = t; 999d6c0b56eSmrg break; 1000d6c0b56eSmrg case RR_Rotate_180: 1001d6c0b56eSmrg x_dst = width - x_dst - 1; 1002d6c0b56eSmrg y_dst = height - y_dst - 1; 1003d6c0b56eSmrg break; 1004d6c0b56eSmrg case RR_Rotate_270: 1005d6c0b56eSmrg t = x_dst; 1006d6c0b56eSmrg x_dst = y_dst; 1007d6c0b56eSmrg y_dst = width - t - 1; 1008d6c0b56eSmrg break; 1009d6c0b56eSmrg } 1010d6c0b56eSmrg 1011d6c0b56eSmrg if (rotation & RR_Reflect_X) 1012d6c0b56eSmrg x_dst = width - x_dst - 1; 1013d6c0b56eSmrg if (rotation & RR_Reflect_Y) 1014d6c0b56eSmrg y_dst = height - y_dst - 1; 1015d6c0b56eSmrg 1016d6c0b56eSmrg return y_dst * height + x_dst; 1017d6c0b56eSmrg} 1018d6c0b56eSmrg 1019d6c0b56eSmrg#endif 1020d6c0b56eSmrg 102124b90cf4Smrgstatic uint32_t 102224b90cf4Smrgdrmmode_cursor_gamma(xf86CrtcPtr crtc, uint32_t argb) 102324b90cf4Smrg{ 102424b90cf4Smrg uint32_t alpha = argb >> 24; 102524b90cf4Smrg uint32_t rgb[3]; 102624b90cf4Smrg int i; 102724b90cf4Smrg 102824b90cf4Smrg if (!alpha) 102924b90cf4Smrg return 0; 103024b90cf4Smrg 103124b90cf4Smrg if (crtc->scrn->depth != 24 && crtc->scrn->depth != 32) 103224b90cf4Smrg return argb; 103324b90cf4Smrg 103424b90cf4Smrg /* Un-premultiply alpha */ 103524b90cf4Smrg for (i = 0; i < 3; i++) 103624b90cf4Smrg rgb[i] = ((argb >> (i * 8)) & 0xff) * 0xff / alpha; 103724b90cf4Smrg 103824b90cf4Smrg /* Apply gamma correction and pre-multiply alpha */ 103924b90cf4Smrg rgb[0] = (crtc->gamma_blue[rgb[0]] >> 8) * alpha / 0xff; 104024b90cf4Smrg rgb[1] = (crtc->gamma_green[rgb[1]] >> 8) * alpha / 0xff; 104124b90cf4Smrg rgb[2] = (crtc->gamma_red[rgb[2]] >> 8) * alpha / 0xff; 104224b90cf4Smrg 104324b90cf4Smrg return alpha << 24 | rgb[2] << 16 | rgb[1] << 8 | rgb[0]; 104424b90cf4Smrg} 104524b90cf4Smrg 1046d6c0b56eSmrgstatic void drmmode_do_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image, uint32_t *ptr) 1047d6c0b56eSmrg{ 1048d6c0b56eSmrg ScrnInfoPtr pScrn = crtc->scrn; 1049d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1050d6c0b56eSmrg 105124b90cf4Smrg#if XF86_CRTC_VERSION < 7 1052d6c0b56eSmrg if (crtc->driverIsPerformingTransform) { 1053d6c0b56eSmrg uint32_t cursor_w = info->cursor_w, cursor_h = info->cursor_h; 1054d6c0b56eSmrg int dstx, dsty; 1055d6c0b56eSmrg int srcoffset; 1056d6c0b56eSmrg 1057d6c0b56eSmrg for (dsty = 0; dsty < cursor_h; dsty++) { 1058d6c0b56eSmrg for (dstx = 0; dstx < cursor_w; dstx++) { 1059d6c0b56eSmrg srcoffset = drmmode_cursor_src_offset(crtc->rotation, 1060d6c0b56eSmrg cursor_w, 1061d6c0b56eSmrg cursor_h, 1062d6c0b56eSmrg dstx, dsty); 1063d6c0b56eSmrg 1064d6c0b56eSmrg ptr[dsty * info->cursor_w + dstx] = 106524b90cf4Smrg cpu_to_le32(drmmode_cursor_gamma(crtc, 106624b90cf4Smrg image[srcoffset])); 1067d6c0b56eSmrg } 1068d6c0b56eSmrg } 1069d6c0b56eSmrg } else 1070d6c0b56eSmrg#endif 1071d6c0b56eSmrg { 1072d6c0b56eSmrg uint32_t cursor_size = info->cursor_w * info->cursor_h; 1073d6c0b56eSmrg int i; 1074d6c0b56eSmrg 1075d6c0b56eSmrg for (i = 0; i < cursor_size; i++) 107624b90cf4Smrg ptr[i] = cpu_to_le32(drmmode_cursor_gamma(crtc, image[i])); 1077d6c0b56eSmrg } 1078d6c0b56eSmrg} 1079d6c0b56eSmrg 1080d6c0b56eSmrgstatic void drmmode_load_cursor_argb(xf86CrtcPtr crtc, CARD32 * image) 1081d6c0b56eSmrg{ 1082d6c0b56eSmrg ScrnInfoPtr pScrn = crtc->scrn; 1083d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1084d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1085d6c0b56eSmrg uint32_t cursor_size = info->cursor_w * info->cursor_h; 1086d6c0b56eSmrg 1087d6c0b56eSmrg if (info->gbm) { 1088d6c0b56eSmrg uint32_t ptr[cursor_size]; 1089d6c0b56eSmrg 1090d6c0b56eSmrg drmmode_do_load_cursor_argb(crtc, image, ptr); 1091d6c0b56eSmrg gbm_bo_write(drmmode_crtc->cursor_buffer->bo.gbm, ptr, cursor_size * 4); 1092d6c0b56eSmrg } else { 1093d6c0b56eSmrg /* cursor should be mapped already */ 1094d6c0b56eSmrg uint32_t *ptr = (uint32_t *) (drmmode_crtc->cursor_buffer->cpu_ptr); 1095d6c0b56eSmrg 1096d6c0b56eSmrg drmmode_do_load_cursor_argb(crtc, image, ptr); 1097d6c0b56eSmrg } 1098d6c0b56eSmrg} 1099d6c0b56eSmrg 1100d6c0b56eSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 1101d6c0b56eSmrg 1102d6c0b56eSmrgstatic Bool drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 * image) 1103d6c0b56eSmrg{ 1104d6c0b56eSmrg if (!drmmode_can_use_hw_cursor(crtc)) 1105d6c0b56eSmrg return FALSE; 1106d6c0b56eSmrg 1107d6c0b56eSmrg drmmode_load_cursor_argb(crtc, image); 1108d6c0b56eSmrg return TRUE; 1109d6c0b56eSmrg} 1110d6c0b56eSmrg 1111d6c0b56eSmrg#endif 1112d6c0b56eSmrg 1113d6c0b56eSmrgstatic void drmmode_hide_cursor(xf86CrtcPtr crtc) 1114d6c0b56eSmrg{ 1115d6c0b56eSmrg ScrnInfoPtr pScrn = crtc->scrn; 1116d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1117d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1118d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1119d6c0b56eSmrg 1120d6c0b56eSmrg drmModeSetCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 1121d6c0b56eSmrg info->cursor_w, info->cursor_h); 1122d6c0b56eSmrg 1123d6c0b56eSmrg} 1124d6c0b56eSmrg 1125d6c0b56eSmrgstatic void drmmode_show_cursor(xf86CrtcPtr crtc) 1126d6c0b56eSmrg{ 1127d6c0b56eSmrg ScrnInfoPtr pScrn = crtc->scrn; 1128d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1129d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1130d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1131d6c0b56eSmrg uint32_t bo_handle; 1132d6c0b56eSmrg static Bool use_set_cursor2 = TRUE; 1133d6c0b56eSmrg 1134d6c0b56eSmrg if (!amdgpu_bo_get_handle(drmmode_crtc->cursor_buffer, &bo_handle)) { 1135d6c0b56eSmrg ErrorF("failed to get BO handle for cursor\n"); 1136d6c0b56eSmrg return; 1137d6c0b56eSmrg } 1138d6c0b56eSmrg 1139d6c0b56eSmrg if (use_set_cursor2) { 1140d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 1141d6c0b56eSmrg CursorPtr cursor = xf86_config->cursor; 1142504d986fSmrg int xhot = cursor->bits->xhot; 1143504d986fSmrg int yhot = cursor->bits->yhot; 1144d6c0b56eSmrg int ret; 1145d6c0b56eSmrg 1146504d986fSmrg if (crtc->rotation != RR_Rotate_0 && 1147504d986fSmrg crtc->rotation != (RR_Rotate_180 | RR_Reflect_X | 1148504d986fSmrg RR_Reflect_Y)) { 1149504d986fSmrg int t; 1150504d986fSmrg 1151504d986fSmrg /* Reflect & rotate hotspot position */ 1152504d986fSmrg if (crtc->rotation & RR_Reflect_X) 1153504d986fSmrg xhot = info->cursor_w - xhot - 1; 1154504d986fSmrg if (crtc->rotation & RR_Reflect_Y) 1155504d986fSmrg yhot = info->cursor_h - yhot - 1; 1156504d986fSmrg 1157504d986fSmrg switch (crtc->rotation & 0xf) { 1158504d986fSmrg case RR_Rotate_90: 1159504d986fSmrg t = xhot; 1160504d986fSmrg xhot = yhot; 1161504d986fSmrg yhot = info->cursor_w - t - 1; 1162504d986fSmrg break; 1163504d986fSmrg case RR_Rotate_180: 1164504d986fSmrg xhot = info->cursor_w - xhot - 1; 1165504d986fSmrg yhot = info->cursor_h - yhot - 1; 1166504d986fSmrg break; 1167504d986fSmrg case RR_Rotate_270: 1168504d986fSmrg t = xhot; 1169504d986fSmrg xhot = info->cursor_h - yhot - 1; 1170504d986fSmrg yhot = t; 1171504d986fSmrg } 1172504d986fSmrg } 1173504d986fSmrg 1174d6c0b56eSmrg ret = drmModeSetCursor2(pAMDGPUEnt->fd, 1175d6c0b56eSmrg drmmode_crtc->mode_crtc->crtc_id, 1176d6c0b56eSmrg bo_handle, 1177d6c0b56eSmrg info->cursor_w, info->cursor_h, 1178504d986fSmrg xhot, yhot); 1179d6c0b56eSmrg if (ret == -EINVAL) 1180d6c0b56eSmrg use_set_cursor2 = FALSE; 1181d6c0b56eSmrg else 1182d6c0b56eSmrg return; 1183d6c0b56eSmrg } 1184d6c0b56eSmrg 1185d6c0b56eSmrg drmModeSetCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, bo_handle, 1186d6c0b56eSmrg info->cursor_w, info->cursor_h); 1187d6c0b56eSmrg} 1188d6c0b56eSmrg 118911bf0794Smrg/* Xorg expects a non-NULL return value from drmmode_crtc_shadow_allocate, and 119011bf0794Smrg * passes that back to drmmode_crtc_scanout_create; it doesn't use it for 119111bf0794Smrg * anything else. 119211bf0794Smrg */ 119311bf0794Smrgstatic void * 119411bf0794Smrgdrmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) 1195d6c0b56eSmrg{ 1196d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1197d6c0b56eSmrg 119811bf0794Smrg if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width, 119911bf0794Smrg height)) 120011bf0794Smrg return NULL; 120111bf0794Smrg 120211bf0794Smrg return (void*)~0UL; 1203d6c0b56eSmrg} 1204d6c0b56eSmrg 1205d6c0b56eSmrgstatic PixmapPtr 1206d6c0b56eSmrgdrmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) 1207d6c0b56eSmrg{ 1208d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1209d6c0b56eSmrg 121011bf0794Smrg if (!data) { 121111bf0794Smrg drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width, 121211bf0794Smrg height); 121311bf0794Smrg } 121411bf0794Smrg 121511bf0794Smrg return drmmode_crtc->rotate.pixmap; 1216d6c0b56eSmrg} 1217d6c0b56eSmrg 1218d6c0b56eSmrgstatic void 1219d6c0b56eSmrgdrmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, 1220d6c0b56eSmrg void *data) 1221d6c0b56eSmrg{ 1222d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1223d6c0b56eSmrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 1224d6c0b56eSmrg 1225d6c0b56eSmrg drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->rotate); 1226d6c0b56eSmrg} 1227d6c0b56eSmrg 1228d6c0b56eSmrgstatic void 1229d6c0b56eSmrgdrmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t * red, uint16_t * green, 1230d6c0b56eSmrg uint16_t * blue, int size) 1231d6c0b56eSmrg{ 123224b90cf4Smrg ScrnInfoPtr scrn = crtc->scrn; 123324b90cf4Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 123424b90cf4Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 123524b90cf4Smrg int i; 1236d6c0b56eSmrg 123724b90cf4Smrg drmmode_crtc_gamma_do_set(crtc, red, green, blue, size); 123824b90cf4Smrg 123924b90cf4Smrg /* Compute index of this CRTC into xf86_config->crtc */ 124024b90cf4Smrg for (i = 0; xf86_config->crtc[i] != crtc; i++) {} 124124b90cf4Smrg 124224b90cf4Smrg if (info->hwcursor_disabled & (1 << i)) 124324b90cf4Smrg return; 124424b90cf4Smrg 124524b90cf4Smrg#ifdef HAVE_XF86_CURSOR_RESET_CURSOR 124624b90cf4Smrg xf86CursorResetCursor(scrn->pScreen); 124724b90cf4Smrg#else 124824b90cf4Smrg xf86_reload_cursors(scrn->pScreen); 124924b90cf4Smrg#endif 1250d6c0b56eSmrg} 1251d6c0b56eSmrg 1252d6c0b56eSmrgstatic Bool drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) 1253d6c0b56eSmrg{ 1254d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 125511bf0794Smrg unsigned scanout_id = drmmode_crtc->scanout_id; 1256504d986fSmrg ScreenPtr screen = crtc->scrn->pScreen; 1257504d986fSmrg PixmapDirtyUpdatePtr dirty; 1258d6c0b56eSmrg 1259504d986fSmrg xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { 126024b90cf4Smrg if (amdgpu_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) { 126124b90cf4Smrg PixmapStopDirtyTracking(dirty->src, dirty->slave_dst); 126224b90cf4Smrg break; 126324b90cf4Smrg } 1264d6c0b56eSmrg } 1265d6c0b56eSmrg 126624b90cf4Smrg drmmode_crtc_scanout_free(drmmode_crtc); 126724b90cf4Smrg drmmode_crtc->prime_scanout_pixmap = NULL; 126824b90cf4Smrg 1269504d986fSmrg if (!ppix) 1270504d986fSmrg return TRUE; 1271504d986fSmrg 1272504d986fSmrg if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[0], 1273504d986fSmrg ppix->drawable.width, 1274504d986fSmrg ppix->drawable.height)) 1275504d986fSmrg return FALSE; 1276d6c0b56eSmrg 127711bf0794Smrg if (drmmode_crtc->tear_free && 1278504d986fSmrg !drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], 1279504d986fSmrg ppix->drawable.width, 1280504d986fSmrg ppix->drawable.height)) { 1281504d986fSmrg drmmode_crtc_scanout_free(drmmode_crtc); 1282504d986fSmrg return FALSE; 1283d6c0b56eSmrg } 1284504d986fSmrg 128524b90cf4Smrg drmmode_crtc->prime_scanout_pixmap = ppix; 128624b90cf4Smrg 128724b90cf4Smrg#ifdef HAS_DIRTYTRACKING_DRAWABLE_SRC 128824b90cf4Smrg PixmapStartDirtyTracking(&ppix->drawable, 128924b90cf4Smrg drmmode_crtc->scanout[scanout_id].pixmap, 129024b90cf4Smrg 0, 0, 0, 0, RR_Rotate_0); 129124b90cf4Smrg#elif defined(HAS_DIRTYTRACKING_ROTATION) 129211bf0794Smrg PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 1293504d986fSmrg 0, 0, 0, 0, RR_Rotate_0); 1294d6c0b56eSmrg#elif defined(HAS_DIRTYTRACKING2) 129511bf0794Smrg PixmapStartDirtyTracking2(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 1296504d986fSmrg 0, 0, 0, 0); 1297d6c0b56eSmrg#else 129811bf0794Smrg PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 0, 0); 1299d6c0b56eSmrg#endif 1300d6c0b56eSmrg return TRUE; 1301d6c0b56eSmrg} 1302d6c0b56eSmrg 1303d6c0b56eSmrgstatic xf86CrtcFuncsRec drmmode_crtc_funcs = { 1304d6c0b56eSmrg .dpms = drmmode_crtc_dpms, 1305d6c0b56eSmrg .set_mode_major = drmmode_set_mode_major, 1306d6c0b56eSmrg .set_cursor_colors = drmmode_set_cursor_colors, 1307d6c0b56eSmrg .set_cursor_position = drmmode_set_cursor_position, 1308d6c0b56eSmrg .show_cursor = drmmode_show_cursor, 1309d6c0b56eSmrg .hide_cursor = drmmode_hide_cursor, 1310d6c0b56eSmrg .load_cursor_argb = drmmode_load_cursor_argb, 1311d6c0b56eSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 1312d6c0b56eSmrg .load_cursor_argb_check = drmmode_load_cursor_argb_check, 1313d6c0b56eSmrg#endif 1314d6c0b56eSmrg 1315d6c0b56eSmrg .gamma_set = drmmode_crtc_gamma_set, 1316d6c0b56eSmrg .shadow_create = drmmode_crtc_shadow_create, 1317d6c0b56eSmrg .shadow_allocate = drmmode_crtc_shadow_allocate, 1318d6c0b56eSmrg .shadow_destroy = drmmode_crtc_shadow_destroy, 1319d6c0b56eSmrg .destroy = NULL, /* XXX */ 1320d6c0b56eSmrg .set_scanout_pixmap = drmmode_set_scanout_pixmap, 1321d6c0b56eSmrg}; 1322d6c0b56eSmrg 1323d6c0b56eSmrgint drmmode_get_crtc_id(xf86CrtcPtr crtc) 1324d6c0b56eSmrg{ 1325d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1326d6c0b56eSmrg return drmmode_crtc->hw_id; 1327d6c0b56eSmrg} 1328d6c0b56eSmrg 1329d6c0b56eSmrgvoid drmmode_crtc_hw_id(xf86CrtcPtr crtc) 1330d6c0b56eSmrg{ 1331d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1332d6c0b56eSmrg ScrnInfoPtr pScrn = crtc->scrn; 1333d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1334d6c0b56eSmrg int r; 1335d6c0b56eSmrg 1336d6c0b56eSmrg r = amdgpu_query_crtc_from_id(pAMDGPUEnt->pDev, 1337d6c0b56eSmrg drmmode_crtc->mode_crtc->crtc_id, 1338d6c0b56eSmrg &drmmode_crtc->hw_id); 1339d6c0b56eSmrg if (r) 1340d6c0b56eSmrg drmmode_crtc->hw_id = -1; 1341d6c0b56eSmrg} 1342d6c0b56eSmrg 1343d6c0b56eSmrgstatic unsigned int 1344d6c0b56eSmrgdrmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num) 1345d6c0b56eSmrg{ 1346d6c0b56eSmrg xf86CrtcPtr crtc; 1347d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc; 1348d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 134924b90cf4Smrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1350d6c0b56eSmrg 135124b90cf4Smrg crtc = xf86CrtcCreate(pScrn, &info->drmmode_crtc_funcs); 1352d6c0b56eSmrg if (crtc == NULL) 1353d6c0b56eSmrg return 0; 1354d6c0b56eSmrg 1355d6c0b56eSmrg drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1); 1356d6c0b56eSmrg drmmode_crtc->mode_crtc = 1357d6c0b56eSmrg drmModeGetCrtc(pAMDGPUEnt->fd, mode_res->crtcs[num]); 1358d6c0b56eSmrg drmmode_crtc->drmmode = drmmode; 1359d6c0b56eSmrg drmmode_crtc->dpms_mode = DPMSModeOff; 1360d6c0b56eSmrg crtc->driver_private = drmmode_crtc; 1361d6c0b56eSmrg drmmode_crtc_hw_id(crtc); 1362d6c0b56eSmrg 1363d6c0b56eSmrg /* Mark num'th crtc as in use on this device. */ 1364d6c0b56eSmrg pAMDGPUEnt->assigned_crtcs |= (1 << num); 1365d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 1366d6c0b56eSmrg "Allocated crtc nr. %d to this screen.\n", num); 1367d6c0b56eSmrg 1368d6c0b56eSmrg return 1; 1369d6c0b56eSmrg} 1370d6c0b56eSmrg 137124b90cf4Smrg/* 137224b90cf4Smrg * Update all of the property values for an output 137324b90cf4Smrg */ 137424b90cf4Smrgstatic void 137524b90cf4Smrgdrmmode_output_update_properties(xf86OutputPtr output) 137624b90cf4Smrg{ 137724b90cf4Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 137824b90cf4Smrg int i, j, k; 137924b90cf4Smrg int err; 138024b90cf4Smrg drmModeConnectorPtr koutput; 138124b90cf4Smrg 138224b90cf4Smrg /* Use the most recently fetched values from the kernel */ 138324b90cf4Smrg koutput = drmmode_output->mode_output; 138424b90cf4Smrg 138524b90cf4Smrg if (!koutput) 138624b90cf4Smrg return; 138724b90cf4Smrg 138824b90cf4Smrg for (i = 0; i < drmmode_output->num_props; i++) { 138924b90cf4Smrg drmmode_prop_ptr p = &drmmode_output->props[i]; 139024b90cf4Smrg 139124b90cf4Smrg for (j = 0; j < koutput->count_props; j++) { 139224b90cf4Smrg if (koutput->props[j] != p->mode_prop->prop_id) 139324b90cf4Smrg continue; 139424b90cf4Smrg 139524b90cf4Smrg /* Check to see if the property value has changed */ 139624b90cf4Smrg if (koutput->prop_values[j] == p->value) 139724b90cf4Smrg break; 139824b90cf4Smrg 139924b90cf4Smrg p->value = koutput->prop_values[j]; 140024b90cf4Smrg 140124b90cf4Smrg if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 140224b90cf4Smrg INT32 value = p->value; 140324b90cf4Smrg 140424b90cf4Smrg err = RRChangeOutputProperty(output->randr_output, 140524b90cf4Smrg p->atoms[0], XA_INTEGER, 140624b90cf4Smrg 32, PropModeReplace, 1, 140724b90cf4Smrg &value, FALSE, TRUE); 140824b90cf4Smrg if (err != 0) { 140924b90cf4Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 141024b90cf4Smrg "RRChangeOutputProperty error, %d\n", 141124b90cf4Smrg err); 141224b90cf4Smrg } 141324b90cf4Smrg } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 141424b90cf4Smrg for (k = 0; k < p->mode_prop->count_enums; k++) { 141524b90cf4Smrg if (p->mode_prop->enums[k].value == p->value) 141624b90cf4Smrg break; 141724b90cf4Smrg } 141824b90cf4Smrg if (k < p->mode_prop->count_enums) { 141924b90cf4Smrg err = RRChangeOutputProperty(output->randr_output, 142024b90cf4Smrg p->atoms[0], XA_ATOM, 142124b90cf4Smrg 32, PropModeReplace, 1, 142224b90cf4Smrg &p->atoms[k + 1], FALSE, 142324b90cf4Smrg TRUE); 142424b90cf4Smrg if (err != 0) { 142524b90cf4Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 142624b90cf4Smrg "RRChangeOutputProperty error, %d\n", 142724b90cf4Smrg err); 142824b90cf4Smrg } 142924b90cf4Smrg } 143024b90cf4Smrg } 143124b90cf4Smrg 143224b90cf4Smrg break; 143324b90cf4Smrg } 143424b90cf4Smrg } 143524b90cf4Smrg} 143624b90cf4Smrg 1437d6c0b56eSmrgstatic xf86OutputStatus drmmode_output_detect(xf86OutputPtr output) 1438d6c0b56eSmrg{ 1439d6c0b56eSmrg /* go to the hw and retrieve a new output struct */ 1440d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1441d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 1442d6c0b56eSmrg xf86OutputStatus status; 1443d6c0b56eSmrg drmModeFreeConnector(drmmode_output->mode_output); 1444d6c0b56eSmrg 1445d6c0b56eSmrg drmmode_output->mode_output = 1446d6c0b56eSmrg drmModeGetConnector(pAMDGPUEnt->fd, drmmode_output->output_id); 144724b90cf4Smrg if (!drmmode_output->mode_output) { 144824b90cf4Smrg drmmode_output->output_id = -1; 1449d6c0b56eSmrg return XF86OutputStatusDisconnected; 145024b90cf4Smrg } 145124b90cf4Smrg 145224b90cf4Smrg drmmode_output_update_properties(output); 1453d6c0b56eSmrg 1454d6c0b56eSmrg switch (drmmode_output->mode_output->connection) { 1455d6c0b56eSmrg case DRM_MODE_CONNECTED: 1456d6c0b56eSmrg status = XF86OutputStatusConnected; 1457d6c0b56eSmrg break; 1458d6c0b56eSmrg case DRM_MODE_DISCONNECTED: 1459d6c0b56eSmrg status = XF86OutputStatusDisconnected; 1460d6c0b56eSmrg break; 1461d6c0b56eSmrg default: 1462d6c0b56eSmrg case DRM_MODE_UNKNOWNCONNECTION: 1463d6c0b56eSmrg status = XF86OutputStatusUnknown; 1464d6c0b56eSmrg break; 1465d6c0b56eSmrg } 1466d6c0b56eSmrg return status; 1467d6c0b56eSmrg} 1468d6c0b56eSmrg 1469d6c0b56eSmrgstatic Bool 1470d6c0b56eSmrgdrmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes) 1471d6c0b56eSmrg{ 1472d6c0b56eSmrg return MODE_OK; 1473d6c0b56eSmrg} 1474d6c0b56eSmrg 147524b90cf4Smrgstatic int 147624b90cf4Smrgkoutput_get_prop_idx(int fd, drmModeConnectorPtr koutput, 147724b90cf4Smrg int type, const char *name) 147824b90cf4Smrg{ 147924b90cf4Smrg int idx = -1; 148024b90cf4Smrg 148124b90cf4Smrg for (int i = 0; i < koutput->count_props; i++) { 148224b90cf4Smrg drmModePropertyPtr prop = drmModeGetProperty(fd, koutput->props[i]); 148324b90cf4Smrg 148424b90cf4Smrg if (!prop) 148524b90cf4Smrg continue; 148624b90cf4Smrg 148724b90cf4Smrg if (drm_property_type_is(prop, type) && !strcmp(prop->name, name)) 148824b90cf4Smrg idx = i; 148924b90cf4Smrg 149024b90cf4Smrg drmModeFreeProperty(prop); 149124b90cf4Smrg 149224b90cf4Smrg if (idx > -1) 149324b90cf4Smrg break; 149424b90cf4Smrg } 149524b90cf4Smrg 149624b90cf4Smrg return idx; 149724b90cf4Smrg} 149824b90cf4Smrg 149924b90cf4Smrgstatic int 150024b90cf4Smrgkoutput_get_prop_id(int fd, drmModeConnectorPtr koutput, 150124b90cf4Smrg int type, const char *name) 150224b90cf4Smrg{ 150324b90cf4Smrg int idx = koutput_get_prop_idx(fd, koutput, type, name); 150424b90cf4Smrg 150524b90cf4Smrg return (idx > -1) ? koutput->props[idx] : -1; 150624b90cf4Smrg} 150724b90cf4Smrg 150824b90cf4Smrgstatic drmModePropertyBlobPtr 150924b90cf4Smrgkoutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name) 151024b90cf4Smrg{ 151124b90cf4Smrg drmModePropertyBlobPtr blob = NULL; 151224b90cf4Smrg int idx = koutput_get_prop_idx(fd, koutput, DRM_MODE_PROP_BLOB, name); 151324b90cf4Smrg 151424b90cf4Smrg if (idx > -1) 151524b90cf4Smrg blob = drmModeGetPropertyBlob(fd, koutput->prop_values[idx]); 151624b90cf4Smrg 151724b90cf4Smrg return blob; 151824b90cf4Smrg} 151924b90cf4Smrg 1520d6c0b56eSmrgstatic DisplayModePtr drmmode_output_get_modes(xf86OutputPtr output) 1521d6c0b56eSmrg{ 1522d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1523d6c0b56eSmrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 1524d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 1525d6c0b56eSmrg int i; 1526d6c0b56eSmrg DisplayModePtr Modes = NULL, Mode; 1527d6c0b56eSmrg xf86MonPtr mon = NULL; 1528d6c0b56eSmrg 1529d6c0b56eSmrg if (!koutput) 1530d6c0b56eSmrg return NULL; 1531d6c0b56eSmrg 153224b90cf4Smrg drmModeFreePropertyBlob(drmmode_output->edid_blob); 153324b90cf4Smrg 1534d6c0b56eSmrg /* look for an EDID property */ 153524b90cf4Smrg drmmode_output->edid_blob = 153624b90cf4Smrg koutput_get_prop_blob(pAMDGPUEnt->fd, koutput, "EDID"); 1537d6c0b56eSmrg 1538d6c0b56eSmrg if (drmmode_output->edid_blob) { 1539d6c0b56eSmrg mon = xf86InterpretEDID(output->scrn->scrnIndex, 1540d6c0b56eSmrg drmmode_output->edid_blob->data); 1541d6c0b56eSmrg if (mon && drmmode_output->edid_blob->length > 128) 1542d6c0b56eSmrg mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; 1543d6c0b56eSmrg } 1544d6c0b56eSmrg xf86OutputSetEDID(output, mon); 1545d6c0b56eSmrg 1546d6c0b56eSmrg /* modes should already be available */ 1547d6c0b56eSmrg for (i = 0; i < koutput->count_modes; i++) { 1548d6c0b56eSmrg Mode = xnfalloc(sizeof(DisplayModeRec)); 1549d6c0b56eSmrg 1550d6c0b56eSmrg drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], 1551d6c0b56eSmrg Mode); 1552d6c0b56eSmrg Modes = xf86ModesAdd(Modes, Mode); 1553d6c0b56eSmrg 1554d6c0b56eSmrg } 1555d6c0b56eSmrg return Modes; 1556d6c0b56eSmrg} 1557d6c0b56eSmrg 1558d6c0b56eSmrgstatic void drmmode_output_destroy(xf86OutputPtr output) 1559d6c0b56eSmrg{ 1560d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1561d6c0b56eSmrg int i; 1562d6c0b56eSmrg 1563d6c0b56eSmrg if (drmmode_output->edid_blob) 1564d6c0b56eSmrg drmModeFreePropertyBlob(drmmode_output->edid_blob); 1565d6c0b56eSmrg for (i = 0; i < drmmode_output->num_props; i++) { 1566d6c0b56eSmrg drmModeFreeProperty(drmmode_output->props[i].mode_prop); 1567d6c0b56eSmrg free(drmmode_output->props[i].atoms); 1568d6c0b56eSmrg } 1569d6c0b56eSmrg for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) { 1570d6c0b56eSmrg drmModeFreeEncoder(drmmode_output->mode_encoders[i]); 1571d6c0b56eSmrg } 1572d6c0b56eSmrg free(drmmode_output->mode_encoders); 1573d6c0b56eSmrg free(drmmode_output->props); 1574d6c0b56eSmrg drmModeFreeConnector(drmmode_output->mode_output); 1575d6c0b56eSmrg free(drmmode_output); 1576d6c0b56eSmrg output->driver_private = NULL; 1577d6c0b56eSmrg} 1578d6c0b56eSmrg 1579d6c0b56eSmrgstatic void drmmode_output_dpms(xf86OutputPtr output, int mode) 1580d6c0b56eSmrg{ 1581d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1582d6c0b56eSmrg xf86CrtcPtr crtc = output->crtc; 1583d6c0b56eSmrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 1584d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 1585d6c0b56eSmrg 1586d6c0b56eSmrg if (!koutput) 1587d6c0b56eSmrg return; 1588d6c0b56eSmrg 158924b90cf4Smrg if (mode != DPMSModeOn && crtc) 1590d6c0b56eSmrg drmmode_do_crtc_dpms(crtc, mode); 1591d6c0b56eSmrg 1592d6c0b56eSmrg drmModeConnectorSetProperty(pAMDGPUEnt->fd, koutput->connector_id, 1593d6c0b56eSmrg drmmode_output->dpms_enum_id, mode); 1594d6c0b56eSmrg 1595d6c0b56eSmrg if (mode == DPMSModeOn && crtc) { 1596d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1597d6c0b56eSmrg 1598d6c0b56eSmrg if (drmmode_crtc->need_modeset) 1599d6c0b56eSmrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 1600d6c0b56eSmrg crtc->x, crtc->y); 1601d6c0b56eSmrg else 1602d6c0b56eSmrg drmmode_do_crtc_dpms(output->crtc, mode); 1603d6c0b56eSmrg } 1604d6c0b56eSmrg} 1605d6c0b56eSmrg 1606d6c0b56eSmrgstatic Bool drmmode_property_ignore(drmModePropertyPtr prop) 1607d6c0b56eSmrg{ 1608d6c0b56eSmrg if (!prop) 1609d6c0b56eSmrg return TRUE; 1610d6c0b56eSmrg /* ignore blob prop */ 1611d6c0b56eSmrg if (prop->flags & DRM_MODE_PROP_BLOB) 1612d6c0b56eSmrg return TRUE; 1613d6c0b56eSmrg /* ignore standard property */ 1614d6c0b56eSmrg if (!strcmp(prop->name, "EDID") || !strcmp(prop->name, "DPMS")) 1615d6c0b56eSmrg return TRUE; 1616d6c0b56eSmrg 1617d6c0b56eSmrg return FALSE; 1618d6c0b56eSmrg} 1619d6c0b56eSmrg 1620d6c0b56eSmrgstatic void drmmode_output_create_resources(xf86OutputPtr output) 1621d6c0b56eSmrg{ 162211bf0794Smrg AMDGPUInfoPtr info = AMDGPUPTR(output->scrn); 1623d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1624d6c0b56eSmrg drmModeConnectorPtr mode_output = drmmode_output->mode_output; 1625d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 162611bf0794Smrg drmModePropertyPtr drmmode_prop, tearfree_prop; 1627d6c0b56eSmrg int i, j, err; 1628d6c0b56eSmrg 1629d6c0b56eSmrg drmmode_output->props = 163011bf0794Smrg calloc(mode_output->count_props + 1, sizeof(drmmode_prop_rec)); 1631d6c0b56eSmrg if (!drmmode_output->props) 1632d6c0b56eSmrg return; 1633d6c0b56eSmrg 1634d6c0b56eSmrg drmmode_output->num_props = 0; 1635d6c0b56eSmrg for (i = 0, j = 0; i < mode_output->count_props; i++) { 1636d6c0b56eSmrg drmmode_prop = 1637d6c0b56eSmrg drmModeGetProperty(pAMDGPUEnt->fd, mode_output->props[i]); 1638d6c0b56eSmrg if (drmmode_property_ignore(drmmode_prop)) { 1639d6c0b56eSmrg drmModeFreeProperty(drmmode_prop); 1640d6c0b56eSmrg continue; 1641d6c0b56eSmrg } 1642d6c0b56eSmrg drmmode_output->props[j].mode_prop = drmmode_prop; 1643d6c0b56eSmrg drmmode_output->props[j].value = mode_output->prop_values[i]; 1644d6c0b56eSmrg drmmode_output->num_props++; 1645d6c0b56eSmrg j++; 1646d6c0b56eSmrg } 1647d6c0b56eSmrg 164811bf0794Smrg /* Userspace-only property for TearFree */ 164911bf0794Smrg tearfree_prop = calloc(1, sizeof(*tearfree_prop)); 165011bf0794Smrg tearfree_prop->flags = DRM_MODE_PROP_ENUM; 165111bf0794Smrg strncpy(tearfree_prop->name, "TearFree", 8); 165211bf0794Smrg tearfree_prop->count_enums = 3; 165311bf0794Smrg tearfree_prop->enums = calloc(tearfree_prop->count_enums, 165411bf0794Smrg sizeof(*tearfree_prop->enums)); 165511bf0794Smrg strncpy(tearfree_prop->enums[0].name, "off", 3); 165611bf0794Smrg strncpy(tearfree_prop->enums[1].name, "on", 2); 165711bf0794Smrg tearfree_prop->enums[1].value = 1; 165811bf0794Smrg strncpy(tearfree_prop->enums[2].name, "auto", 4); 165911bf0794Smrg tearfree_prop->enums[2].value = 2; 166011bf0794Smrg drmmode_output->props[j].mode_prop = tearfree_prop; 166111bf0794Smrg drmmode_output->props[j].value = info->tear_free; 166211bf0794Smrg drmmode_output->tear_free = info->tear_free; 166311bf0794Smrg drmmode_output->num_props++; 166411bf0794Smrg 1665d6c0b56eSmrg for (i = 0; i < drmmode_output->num_props; i++) { 1666d6c0b56eSmrg drmmode_prop_ptr p = &drmmode_output->props[i]; 1667d6c0b56eSmrg drmmode_prop = p->mode_prop; 1668d6c0b56eSmrg 1669d6c0b56eSmrg if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { 1670d6c0b56eSmrg INT32 range[2]; 1671d6c0b56eSmrg INT32 value = p->value; 1672d6c0b56eSmrg 1673d6c0b56eSmrg p->num_atoms = 1; 1674d6c0b56eSmrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 1675d6c0b56eSmrg if (!p->atoms) 1676d6c0b56eSmrg continue; 1677d6c0b56eSmrg p->atoms[0] = 1678d6c0b56eSmrg MakeAtom(drmmode_prop->name, 1679d6c0b56eSmrg strlen(drmmode_prop->name), TRUE); 1680d6c0b56eSmrg range[0] = drmmode_prop->values[0]; 1681d6c0b56eSmrg range[1] = drmmode_prop->values[1]; 1682d6c0b56eSmrg err = 1683d6c0b56eSmrg RRConfigureOutputProperty(output->randr_output, 1684d6c0b56eSmrg p->atoms[0], FALSE, TRUE, 1685d6c0b56eSmrg drmmode_prop->flags & 1686d6c0b56eSmrg DRM_MODE_PROP_IMMUTABLE ? 1687d6c0b56eSmrg TRUE : FALSE, 2, range); 1688d6c0b56eSmrg if (err != 0) { 1689d6c0b56eSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1690d6c0b56eSmrg "RRConfigureOutputProperty error, %d\n", 1691d6c0b56eSmrg err); 1692d6c0b56eSmrg } 1693d6c0b56eSmrg err = 1694d6c0b56eSmrg RRChangeOutputProperty(output->randr_output, 1695d6c0b56eSmrg p->atoms[0], XA_INTEGER, 32, 1696d6c0b56eSmrg PropModeReplace, 1, &value, 1697d6c0b56eSmrg FALSE, TRUE); 1698d6c0b56eSmrg if (err != 0) { 1699d6c0b56eSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1700d6c0b56eSmrg "RRChangeOutputProperty error, %d\n", 1701d6c0b56eSmrg err); 1702d6c0b56eSmrg } 1703d6c0b56eSmrg } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { 1704d6c0b56eSmrg p->num_atoms = drmmode_prop->count_enums + 1; 1705d6c0b56eSmrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 1706d6c0b56eSmrg if (!p->atoms) 1707d6c0b56eSmrg continue; 1708d6c0b56eSmrg p->atoms[0] = 1709d6c0b56eSmrg MakeAtom(drmmode_prop->name, 1710d6c0b56eSmrg strlen(drmmode_prop->name), TRUE); 1711d6c0b56eSmrg for (j = 1; j <= drmmode_prop->count_enums; j++) { 1712d6c0b56eSmrg struct drm_mode_property_enum *e = 1713d6c0b56eSmrg &drmmode_prop->enums[j - 1]; 1714d6c0b56eSmrg p->atoms[j] = 1715d6c0b56eSmrg MakeAtom(e->name, strlen(e->name), TRUE); 1716d6c0b56eSmrg } 1717d6c0b56eSmrg err = 1718d6c0b56eSmrg RRConfigureOutputProperty(output->randr_output, 1719d6c0b56eSmrg p->atoms[0], FALSE, FALSE, 1720d6c0b56eSmrg drmmode_prop->flags & 1721d6c0b56eSmrg DRM_MODE_PROP_IMMUTABLE ? 1722d6c0b56eSmrg TRUE : FALSE, 1723d6c0b56eSmrg p->num_atoms - 1, 1724d6c0b56eSmrg (INT32 *) & p->atoms[1]); 1725d6c0b56eSmrg if (err != 0) { 1726d6c0b56eSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1727d6c0b56eSmrg "RRConfigureOutputProperty error, %d\n", 1728d6c0b56eSmrg err); 1729d6c0b56eSmrg } 1730d6c0b56eSmrg for (j = 0; j < drmmode_prop->count_enums; j++) 1731d6c0b56eSmrg if (drmmode_prop->enums[j].value == p->value) 1732d6c0b56eSmrg break; 1733d6c0b56eSmrg /* there's always a matching value */ 1734d6c0b56eSmrg err = 1735d6c0b56eSmrg RRChangeOutputProperty(output->randr_output, 1736d6c0b56eSmrg p->atoms[0], XA_ATOM, 32, 1737d6c0b56eSmrg PropModeReplace, 1, 1738d6c0b56eSmrg &p->atoms[j + 1], FALSE, 1739d6c0b56eSmrg TRUE); 1740d6c0b56eSmrg if (err != 0) { 1741d6c0b56eSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1742d6c0b56eSmrg "RRChangeOutputProperty error, %d\n", 1743d6c0b56eSmrg err); 1744d6c0b56eSmrg } 1745d6c0b56eSmrg } 1746d6c0b56eSmrg } 1747d6c0b56eSmrg} 1748d6c0b56eSmrg 1749d6c0b56eSmrgstatic Bool 1750d6c0b56eSmrgdrmmode_output_set_property(xf86OutputPtr output, Atom property, 1751d6c0b56eSmrg RRPropertyValuePtr value) 1752d6c0b56eSmrg{ 1753d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1754d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 1755d6c0b56eSmrg int i; 1756d6c0b56eSmrg 1757d6c0b56eSmrg for (i = 0; i < drmmode_output->num_props; i++) { 1758d6c0b56eSmrg drmmode_prop_ptr p = &drmmode_output->props[i]; 1759d6c0b56eSmrg 1760d6c0b56eSmrg if (p->atoms[0] != property) 1761d6c0b56eSmrg continue; 1762d6c0b56eSmrg 1763d6c0b56eSmrg if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 1764d6c0b56eSmrg uint32_t val; 1765d6c0b56eSmrg 1766d6c0b56eSmrg if (value->type != XA_INTEGER || value->format != 32 || 1767d6c0b56eSmrg value->size != 1) 1768d6c0b56eSmrg return FALSE; 1769d6c0b56eSmrg val = *(uint32_t *) value->data; 1770d6c0b56eSmrg 1771d6c0b56eSmrg drmModeConnectorSetProperty(pAMDGPUEnt->fd, 1772d6c0b56eSmrg drmmode_output->output_id, 1773d6c0b56eSmrg p->mode_prop->prop_id, 1774d6c0b56eSmrg (uint64_t) val); 1775d6c0b56eSmrg return TRUE; 1776d6c0b56eSmrg } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 1777d6c0b56eSmrg Atom atom; 1778d6c0b56eSmrg const char *name; 1779d6c0b56eSmrg int j; 1780d6c0b56eSmrg 1781d6c0b56eSmrg if (value->type != XA_ATOM || value->format != 32 1782d6c0b56eSmrg || value->size != 1) 1783d6c0b56eSmrg return FALSE; 1784d6c0b56eSmrg memcpy(&atom, value->data, 4); 178524b90cf4Smrg if (!(name = NameForAtom(atom))) 178624b90cf4Smrg return FALSE; 1787d6c0b56eSmrg 1788d6c0b56eSmrg /* search for matching name string, then set its value down */ 1789d6c0b56eSmrg for (j = 0; j < p->mode_prop->count_enums; j++) { 1790d6c0b56eSmrg if (!strcmp(p->mode_prop->enums[j].name, name)) { 179111bf0794Smrg if (i == (drmmode_output->num_props - 1)) { 179211bf0794Smrg if (drmmode_output->tear_free != j) { 179311bf0794Smrg xf86CrtcPtr crtc = output->crtc; 179411bf0794Smrg 179511bf0794Smrg drmmode_output->tear_free = j; 179611bf0794Smrg if (crtc) { 179711bf0794Smrg drmmode_set_mode_major(crtc, 179811bf0794Smrg &crtc->mode, 179911bf0794Smrg crtc->rotation, 180011bf0794Smrg crtc->x, 180111bf0794Smrg crtc->y); 180211bf0794Smrg } 180311bf0794Smrg } 180411bf0794Smrg } else { 180511bf0794Smrg drmModeConnectorSetProperty(pAMDGPUEnt->fd, 180611bf0794Smrg drmmode_output->output_id, 180711bf0794Smrg p->mode_prop->prop_id, 180811bf0794Smrg p->mode_prop->enums[j].value); 180911bf0794Smrg } 181011bf0794Smrg 1811d6c0b56eSmrg return TRUE; 1812d6c0b56eSmrg } 1813d6c0b56eSmrg } 1814d6c0b56eSmrg } 1815d6c0b56eSmrg } 1816d6c0b56eSmrg 1817d6c0b56eSmrg return TRUE; 1818d6c0b56eSmrg} 1819d6c0b56eSmrg 1820d6c0b56eSmrgstatic Bool drmmode_output_get_property(xf86OutputPtr output, Atom property) 1821d6c0b56eSmrg{ 1822d6c0b56eSmrg return TRUE; 1823d6c0b56eSmrg} 1824d6c0b56eSmrg 1825d6c0b56eSmrgstatic const xf86OutputFuncsRec drmmode_output_funcs = { 1826d6c0b56eSmrg .dpms = drmmode_output_dpms, 1827d6c0b56eSmrg .create_resources = drmmode_output_create_resources, 1828d6c0b56eSmrg .set_property = drmmode_output_set_property, 1829d6c0b56eSmrg .get_property = drmmode_output_get_property, 1830d6c0b56eSmrg#if 0 1831d6c0b56eSmrg 1832d6c0b56eSmrg .save = drmmode_crt_save, 1833d6c0b56eSmrg .restore = drmmode_crt_restore, 1834d6c0b56eSmrg .mode_fixup = drmmode_crt_mode_fixup, 1835d6c0b56eSmrg .prepare = drmmode_output_prepare, 1836d6c0b56eSmrg .mode_set = drmmode_crt_mode_set, 1837d6c0b56eSmrg .commit = drmmode_output_commit, 1838d6c0b56eSmrg#endif 1839d6c0b56eSmrg .detect = drmmode_output_detect, 1840d6c0b56eSmrg .mode_valid = drmmode_output_mode_valid, 1841d6c0b56eSmrg 1842d6c0b56eSmrg .get_modes = drmmode_output_get_modes, 1843d6c0b56eSmrg .destroy = drmmode_output_destroy 1844d6c0b56eSmrg}; 1845d6c0b56eSmrg 1846d6c0b56eSmrgstatic int subpixel_conv_table[7] = { 0, SubPixelUnknown, 1847d6c0b56eSmrg SubPixelHorizontalRGB, 1848d6c0b56eSmrg SubPixelHorizontalBGR, 1849d6c0b56eSmrg SubPixelVerticalRGB, 1850d6c0b56eSmrg SubPixelVerticalBGR, 1851d6c0b56eSmrg SubPixelNone 1852d6c0b56eSmrg}; 1853d6c0b56eSmrg 1854d6c0b56eSmrgconst char *output_names[] = { "None", 1855d6c0b56eSmrg "VGA", 1856d6c0b56eSmrg "DVI-I", 1857d6c0b56eSmrg "DVI-D", 1858d6c0b56eSmrg "DVI-A", 1859d6c0b56eSmrg "Composite", 1860d6c0b56eSmrg "S-video", 1861d6c0b56eSmrg "LVDS", 1862d6c0b56eSmrg "CTV", 1863d6c0b56eSmrg "DIN", 1864d6c0b56eSmrg "DisplayPort", 1865d6c0b56eSmrg "HDMI-A", 1866d6c0b56eSmrg "HDMI-B", 1867d6c0b56eSmrg "TV", 1868d6c0b56eSmrg "eDP", 1869d6c0b56eSmrg "Virtual", 1870d6c0b56eSmrg "DSI", 1871d6c0b56eSmrg}; 1872d6c0b56eSmrg 1873d6c0b56eSmrg#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0])) 1874d6c0b56eSmrg 1875d6c0b56eSmrgstatic xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id) 1876d6c0b56eSmrg{ 1877d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1878d6c0b56eSmrg int i; 1879d6c0b56eSmrg for (i = 0; i < xf86_config->num_output; i++) { 1880d6c0b56eSmrg xf86OutputPtr output = xf86_config->output[i]; 1881d6c0b56eSmrg drmmode_output_private_ptr drmmode_output; 1882d6c0b56eSmrg drmmode_output = output->driver_private; 1883d6c0b56eSmrg if (drmmode_output->output_id == id) 1884d6c0b56eSmrg return output; 1885d6c0b56eSmrg } 1886d6c0b56eSmrg return NULL; 1887d6c0b56eSmrg} 1888d6c0b56eSmrg 1889d6c0b56eSmrgstatic int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path) 1890d6c0b56eSmrg{ 1891d6c0b56eSmrg char *conn; 1892d6c0b56eSmrg char conn_id[5]; 1893d6c0b56eSmrg int id, len; 1894d6c0b56eSmrg char *blob_data; 1895d6c0b56eSmrg 1896d6c0b56eSmrg if (!path_blob) 1897d6c0b56eSmrg return -1; 1898d6c0b56eSmrg 1899d6c0b56eSmrg blob_data = path_blob->data; 1900d6c0b56eSmrg /* we only handle MST paths for now */ 1901d6c0b56eSmrg if (strncmp(blob_data, "mst:", 4)) 1902d6c0b56eSmrg return -1; 1903d6c0b56eSmrg 1904d6c0b56eSmrg conn = strchr(blob_data + 4, '-'); 1905d6c0b56eSmrg if (!conn) 1906d6c0b56eSmrg return -1; 1907d6c0b56eSmrg len = conn - (blob_data + 4); 1908d6c0b56eSmrg if (len + 1 > 5) 1909d6c0b56eSmrg return -1; 1910d6c0b56eSmrg memcpy(conn_id, blob_data + 4, len); 1911d6c0b56eSmrg conn_id[len] = '\0'; 1912d6c0b56eSmrg id = strtoul(conn_id, NULL, 10); 1913d6c0b56eSmrg 1914d6c0b56eSmrg *conn_base_id = id; 1915d6c0b56eSmrg 1916d6c0b56eSmrg *path = conn + 1; 1917d6c0b56eSmrg return 0; 1918d6c0b56eSmrg} 1919d6c0b56eSmrg 1920d6c0b56eSmrgstatic void 1921d6c0b56eSmrgdrmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name, 1922d6c0b56eSmrg drmModePropertyBlobPtr path_blob, int *num_dvi, int *num_hdmi) 1923d6c0b56eSmrg{ 1924d6c0b56eSmrg xf86OutputPtr output; 1925d6c0b56eSmrg int conn_id; 1926d6c0b56eSmrg char *extra_path; 1927d6c0b56eSmrg 1928d6c0b56eSmrg output = NULL; 1929d6c0b56eSmrg if (parse_path_blob(path_blob, &conn_id, &extra_path) == 0) 1930d6c0b56eSmrg output = find_output(pScrn, conn_id); 1931d6c0b56eSmrg if (output) { 1932d6c0b56eSmrg snprintf(name, 32, "%s-%s", output->name, extra_path); 1933d6c0b56eSmrg } else { 193424b90cf4Smrg if (koutput->connector_type >= NUM_OUTPUT_NAMES) { 1935d6c0b56eSmrg snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, koutput->connector_type_id - 1); 193624b90cf4Smrg } else if (pScrn->is_gpu) { 1937d6c0b56eSmrg snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type], 1938d6c0b56eSmrg pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id - 1); 193924b90cf4Smrg } else { 1940d6c0b56eSmrg /* need to do smart conversion here for compat with non-kms ATI driver */ 1941d6c0b56eSmrg if (koutput->connector_type_id == 1) { 1942d6c0b56eSmrg switch(koutput->connector_type) { 1943d6c0b56eSmrg case DRM_MODE_CONNECTOR_DVII: 1944d6c0b56eSmrg case DRM_MODE_CONNECTOR_DVID: 1945d6c0b56eSmrg case DRM_MODE_CONNECTOR_DVIA: 1946d6c0b56eSmrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi); 1947d6c0b56eSmrg (*num_dvi)++; 1948d6c0b56eSmrg break; 1949d6c0b56eSmrg case DRM_MODE_CONNECTOR_HDMIA: 1950d6c0b56eSmrg case DRM_MODE_CONNECTOR_HDMIB: 1951d6c0b56eSmrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi); 1952d6c0b56eSmrg (*num_hdmi)++; 1953d6c0b56eSmrg break; 1954d6c0b56eSmrg case DRM_MODE_CONNECTOR_VGA: 1955d6c0b56eSmrg case DRM_MODE_CONNECTOR_DisplayPort: 1956d6c0b56eSmrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); 1957d6c0b56eSmrg break; 1958d6c0b56eSmrg default: 1959d6c0b56eSmrg snprintf(name, 32, "%s", output_names[koutput->connector_type]); 1960d6c0b56eSmrg break; 1961d6c0b56eSmrg } 1962d6c0b56eSmrg } else { 1963d6c0b56eSmrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); 1964d6c0b56eSmrg } 1965d6c0b56eSmrg } 1966d6c0b56eSmrg } 1967d6c0b56eSmrg} 1968d6c0b56eSmrg 1969d6c0b56eSmrg 1970d6c0b56eSmrgstatic unsigned int 1971d6c0b56eSmrgdrmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int *num_dvi, int *num_hdmi, int dynamic) 1972d6c0b56eSmrg{ 1973d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1974d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1975d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1976d6c0b56eSmrg xf86OutputPtr output; 1977d6c0b56eSmrg drmModeConnectorPtr koutput; 1978d6c0b56eSmrg drmModeEncoderPtr *kencoders = NULL; 1979d6c0b56eSmrg drmmode_output_private_ptr drmmode_output; 1980d6c0b56eSmrg drmModePropertyBlobPtr path_blob = NULL; 1981d6c0b56eSmrg char name[32]; 1982d6c0b56eSmrg int i; 1983d6c0b56eSmrg const char *s; 1984d6c0b56eSmrg 1985d6c0b56eSmrg koutput = 1986d6c0b56eSmrg drmModeGetConnector(pAMDGPUEnt->fd, 1987d6c0b56eSmrg mode_res->connectors[num]); 1988d6c0b56eSmrg if (!koutput) 1989d6c0b56eSmrg return 0; 1990d6c0b56eSmrg 199124b90cf4Smrg path_blob = koutput_get_prop_blob(pAMDGPUEnt->fd, koutput, "PATH"); 1992d6c0b56eSmrg 1993d6c0b56eSmrg kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders); 1994d6c0b56eSmrg if (!kencoders) { 1995d6c0b56eSmrg goto out_free_encoders; 1996d6c0b56eSmrg } 1997d6c0b56eSmrg 1998d6c0b56eSmrg for (i = 0; i < koutput->count_encoders; i++) { 1999d6c0b56eSmrg kencoders[i] = 2000d6c0b56eSmrg drmModeGetEncoder(pAMDGPUEnt->fd, koutput->encoders[i]); 2001d6c0b56eSmrg if (!kencoders[i]) { 2002d6c0b56eSmrg goto out_free_encoders; 2003d6c0b56eSmrg } 2004d6c0b56eSmrg } 2005d6c0b56eSmrg 2006d6c0b56eSmrg drmmode_create_name(pScrn, koutput, name, path_blob, num_dvi, num_hdmi); 2007d6c0b56eSmrg if (path_blob) { 2008d6c0b56eSmrg drmModeFreePropertyBlob(path_blob); 2009d6c0b56eSmrg } 2010d6c0b56eSmrg 2011d6c0b56eSmrg if (path_blob && dynamic) { 2012d6c0b56eSmrg /* See if we have an output with this name already 2013d6c0b56eSmrg * and hook stuff up. 2014d6c0b56eSmrg */ 2015d6c0b56eSmrg for (i = 0; i < xf86_config->num_output; i++) { 2016d6c0b56eSmrg output = xf86_config->output[i]; 2017d6c0b56eSmrg 2018d6c0b56eSmrg if (strncmp(output->name, name, 32)) 2019d6c0b56eSmrg continue; 2020d6c0b56eSmrg 2021d6c0b56eSmrg drmmode_output = output->driver_private; 2022d6c0b56eSmrg drmmode_output->output_id = mode_res->connectors[num]; 2023d6c0b56eSmrg drmmode_output->mode_output = koutput; 2024d6c0b56eSmrg for (i = 0; i < koutput->count_encoders; i++) { 2025d6c0b56eSmrg drmModeFreeEncoder(kencoders[i]); 2026d6c0b56eSmrg } 2027d6c0b56eSmrg free(kencoders); 2028d6c0b56eSmrg return 1; 2029d6c0b56eSmrg } 2030d6c0b56eSmrg } 2031d6c0b56eSmrg 2032d6c0b56eSmrg if (xf86IsEntityShared(pScrn->entityList[0])) { 2033d6c0b56eSmrg if ((s = 2034d6c0b56eSmrg xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) { 2035d6c0b56eSmrg if (!AMDGPUZaphodStringMatches(pScrn, s, name)) 2036d6c0b56eSmrg goto out_free_encoders; 2037d6c0b56eSmrg } else { 2038d6c0b56eSmrg if (!info->IsSecondary && (num != 0)) 2039d6c0b56eSmrg goto out_free_encoders; 2040d6c0b56eSmrg else if (info->IsSecondary && (num != 1)) 2041d6c0b56eSmrg goto out_free_encoders; 2042d6c0b56eSmrg } 2043d6c0b56eSmrg } 2044d6c0b56eSmrg 2045d6c0b56eSmrg output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name); 2046d6c0b56eSmrg if (!output) { 2047d6c0b56eSmrg goto out_free_encoders; 2048d6c0b56eSmrg } 2049d6c0b56eSmrg 2050d6c0b56eSmrg drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1); 2051d6c0b56eSmrg if (!drmmode_output) { 2052d6c0b56eSmrg xf86OutputDestroy(output); 2053d6c0b56eSmrg goto out_free_encoders; 2054d6c0b56eSmrg } 2055d6c0b56eSmrg 2056d6c0b56eSmrg drmmode_output->output_id = mode_res->connectors[num]; 2057d6c0b56eSmrg drmmode_output->mode_output = koutput; 2058d6c0b56eSmrg drmmode_output->mode_encoders = kencoders; 2059d6c0b56eSmrg drmmode_output->drmmode = drmmode; 2060d6c0b56eSmrg output->mm_width = koutput->mmWidth; 2061d6c0b56eSmrg output->mm_height = koutput->mmHeight; 2062d6c0b56eSmrg 2063d6c0b56eSmrg output->subpixel_order = subpixel_conv_table[koutput->subpixel]; 2064d6c0b56eSmrg output->interlaceAllowed = TRUE; 2065d6c0b56eSmrg output->doubleScanAllowed = TRUE; 2066d6c0b56eSmrg output->driver_private = drmmode_output; 2067d6c0b56eSmrg 2068d6c0b56eSmrg output->possible_crtcs = 0xffffffff; 2069d6c0b56eSmrg for (i = 0; i < koutput->count_encoders; i++) { 2070d6c0b56eSmrg output->possible_crtcs &= kencoders[i]->possible_crtcs; 2071d6c0b56eSmrg } 2072d6c0b56eSmrg /* work out the possible clones later */ 2073d6c0b56eSmrg output->possible_clones = 0; 2074d6c0b56eSmrg 207524b90cf4Smrg drmmode_output->dpms_enum_id = 207624b90cf4Smrg koutput_get_prop_id(pAMDGPUEnt->fd, koutput, DRM_MODE_PROP_ENUM, 207724b90cf4Smrg "DPMS"); 2078d6c0b56eSmrg 2079d6c0b56eSmrg if (dynamic) { 2080d6c0b56eSmrg output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output); 2081d6c0b56eSmrg drmmode_output_create_resources(output); 2082d6c0b56eSmrg } 2083d6c0b56eSmrg 2084d6c0b56eSmrg return 1; 2085d6c0b56eSmrgout_free_encoders: 2086d6c0b56eSmrg if (kencoders) { 2087d6c0b56eSmrg for (i = 0; i < koutput->count_encoders; i++) 2088d6c0b56eSmrg drmModeFreeEncoder(kencoders[i]); 2089d6c0b56eSmrg free(kencoders); 2090d6c0b56eSmrg } 2091d6c0b56eSmrg drmModeFreeConnector(koutput); 2092d6c0b56eSmrg return 0; 2093d6c0b56eSmrg} 2094d6c0b56eSmrg 2095d6c0b56eSmrguint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output) 2096d6c0b56eSmrg{ 2097d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = 2098d6c0b56eSmrg output->driver_private, clone_drmout; 2099d6c0b56eSmrg int i; 2100d6c0b56eSmrg xf86OutputPtr clone_output; 2101d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2102d6c0b56eSmrg int index_mask = 0; 2103d6c0b56eSmrg 2104d6c0b56eSmrg if (drmmode_output->enc_clone_mask == 0) 2105d6c0b56eSmrg return index_mask; 2106d6c0b56eSmrg 2107d6c0b56eSmrg for (i = 0; i < xf86_config->num_output; i++) { 2108d6c0b56eSmrg clone_output = xf86_config->output[i]; 2109d6c0b56eSmrg clone_drmout = clone_output->driver_private; 2110d6c0b56eSmrg if (output == clone_output) 2111d6c0b56eSmrg continue; 2112d6c0b56eSmrg 2113d6c0b56eSmrg if (clone_drmout->enc_mask == 0) 2114d6c0b56eSmrg continue; 2115d6c0b56eSmrg if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask) 2116d6c0b56eSmrg index_mask |= (1 << i); 2117d6c0b56eSmrg } 2118d6c0b56eSmrg return index_mask; 2119d6c0b56eSmrg} 2120d6c0b56eSmrg 2121d6c0b56eSmrgstatic void drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res) 2122d6c0b56eSmrg{ 2123d6c0b56eSmrg int i, j; 2124d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2125d6c0b56eSmrg 2126d6c0b56eSmrg for (i = 0; i < xf86_config->num_output; i++) { 2127d6c0b56eSmrg xf86OutputPtr output = xf86_config->output[i]; 2128d6c0b56eSmrg drmmode_output_private_ptr drmmode_output; 2129d6c0b56eSmrg 2130d6c0b56eSmrg drmmode_output = output->driver_private; 2131d6c0b56eSmrg drmmode_output->enc_clone_mask = 0xff; 2132d6c0b56eSmrg /* and all the possible encoder clones for this output together */ 2133d6c0b56eSmrg for (j = 0; j < drmmode_output->mode_output->count_encoders; 2134d6c0b56eSmrg j++) { 2135d6c0b56eSmrg int k; 2136d6c0b56eSmrg for (k = 0; k < mode_res->count_encoders; k++) { 2137d6c0b56eSmrg if (mode_res->encoders[k] == 2138d6c0b56eSmrg drmmode_output-> 2139d6c0b56eSmrg mode_encoders[j]->encoder_id) 2140d6c0b56eSmrg drmmode_output->enc_mask |= (1 << k); 2141d6c0b56eSmrg } 2142d6c0b56eSmrg 2143d6c0b56eSmrg drmmode_output->enc_clone_mask &= 2144d6c0b56eSmrg drmmode_output->mode_encoders[j]->possible_clones; 2145d6c0b56eSmrg } 2146d6c0b56eSmrg } 2147d6c0b56eSmrg 2148d6c0b56eSmrg for (i = 0; i < xf86_config->num_output; i++) { 2149d6c0b56eSmrg xf86OutputPtr output = xf86_config->output[i]; 2150d6c0b56eSmrg output->possible_clones = find_clones(scrn, output); 2151d6c0b56eSmrg } 2152d6c0b56eSmrg} 2153d6c0b56eSmrg 2154d6c0b56eSmrg/* returns pitch alignment in pixels */ 2155d6c0b56eSmrgint drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe) 2156d6c0b56eSmrg{ 2157d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 2158d6c0b56eSmrg 2159d6c0b56eSmrg if (info->have_tiling_info) 2160d6c0b56eSmrg /* linear aligned requirements */ 2161d6c0b56eSmrg return MAX(64, info->group_bytes / bpe); 2162d6c0b56eSmrg else 2163d6c0b56eSmrg /* default to 512 elements if we don't know the real 2164d6c0b56eSmrg * group size otherwise the kernel may reject the CS 2165d6c0b56eSmrg * if the group sizes don't match as the pitch won't 2166d6c0b56eSmrg * be aligned properly. 2167d6c0b56eSmrg */ 2168d6c0b56eSmrg return 512; 2169d6c0b56eSmrg} 2170d6c0b56eSmrg 2171d6c0b56eSmrgstatic Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height) 2172d6c0b56eSmrg{ 2173d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2174d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 2175d6c0b56eSmrg struct amdgpu_buffer *old_front = NULL; 2176d6c0b56eSmrg ScreenPtr screen = xf86ScrnToScreen(scrn); 2177d6c0b56eSmrg int i, pitch, old_width, old_height, old_pitch; 2178d6c0b56eSmrg int cpp = info->pixel_bytes; 2179d6c0b56eSmrg PixmapPtr ppix = screen->GetScreenPixmap(screen); 2180d6c0b56eSmrg void *fb_shadow; 2181d6c0b56eSmrg int hint = 0; 2182d6c0b56eSmrg 2183d6c0b56eSmrg if (scrn->virtualX == width && scrn->virtualY == height) 2184d6c0b56eSmrg return TRUE; 2185d6c0b56eSmrg 2186d6c0b56eSmrg if (info->shadow_primary) 2187d6c0b56eSmrg hint = AMDGPU_CREATE_PIXMAP_LINEAR | AMDGPU_CREATE_PIXMAP_GTT; 2188d6c0b56eSmrg else if (!info->use_glamor) 2189d6c0b56eSmrg hint = AMDGPU_CREATE_PIXMAP_LINEAR; 2190d6c0b56eSmrg 2191d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_INFO, 2192d6c0b56eSmrg "Allocate new frame buffer %dx%d\n", width, height); 2193d6c0b56eSmrg 2194d6c0b56eSmrg old_width = scrn->virtualX; 2195d6c0b56eSmrg old_height = scrn->virtualY; 2196d6c0b56eSmrg old_pitch = scrn->displayWidth; 2197d6c0b56eSmrg old_front = info->front_buffer; 2198d6c0b56eSmrg 2199d6c0b56eSmrg scrn->virtualX = width; 2200d6c0b56eSmrg scrn->virtualY = height; 2201d6c0b56eSmrg 2202d6c0b56eSmrg info->front_buffer = 2203d6c0b56eSmrg amdgpu_alloc_pixmap_bo(scrn, scrn->virtualX, scrn->virtualY, 2204d6c0b56eSmrg scrn->depth, hint, scrn->bitsPerPixel, 2205d6c0b56eSmrg &pitch); 2206d6c0b56eSmrg if (!info->front_buffer) { 2207d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 2208d6c0b56eSmrg "Failed to allocate front buffer memory\n"); 2209d6c0b56eSmrg goto fail; 2210d6c0b56eSmrg } 2211d6c0b56eSmrg 2212d6c0b56eSmrg if (!info->use_glamor && amdgpu_bo_map(scrn, info->front_buffer) != 0) { 2213d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 2214d6c0b56eSmrg "Failed to map front buffer memory\n"); 2215d6c0b56eSmrg goto fail; 2216d6c0b56eSmrg } 2217d6c0b56eSmrg 2218d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_INFO, " => pitch %d bytes\n", pitch); 2219d6c0b56eSmrg scrn->displayWidth = pitch / cpp; 2220d6c0b56eSmrg 2221d6c0b56eSmrg if (info->use_glamor || 2222d6c0b56eSmrg (info->front_buffer->flags & AMDGPU_BO_FLAGS_GBM)) { 2223d6c0b56eSmrg screen->ModifyPixmapHeader(ppix, 2224d6c0b56eSmrg width, height, -1, -1, pitch, info->front_buffer->cpu_ptr); 2225d6c0b56eSmrg } else { 2226d6c0b56eSmrg fb_shadow = calloc(1, pitch * scrn->virtualY); 2227d6c0b56eSmrg if (fb_shadow == NULL) 2228d6c0b56eSmrg goto fail; 2229d6c0b56eSmrg free(info->fb_shadow); 2230d6c0b56eSmrg info->fb_shadow = fb_shadow; 2231d6c0b56eSmrg screen->ModifyPixmapHeader(ppix, 2232d6c0b56eSmrg width, height, -1, -1, pitch, 2233d6c0b56eSmrg info->fb_shadow); 2234d6c0b56eSmrg } 2235d6c0b56eSmrg 2236504d986fSmrg if (!amdgpu_glamor_create_screen_resources(scrn->pScreen)) 2237504d986fSmrg goto fail; 2238504d986fSmrg 2239504d986fSmrg if (info->use_glamor || 2240504d986fSmrg (info->front_buffer->flags & AMDGPU_BO_FLAGS_GBM)) { 2241504d986fSmrg if (!amdgpu_set_pixmap_bo(ppix, info->front_buffer)) 2242504d986fSmrg goto fail; 2243504d986fSmrg } 2244d6c0b56eSmrg 224524b90cf4Smrg amdgpu_pixmap_clear(ppix); 2246d6c0b56eSmrg amdgpu_glamor_finish(scrn); 2247d6c0b56eSmrg 2248d6c0b56eSmrg for (i = 0; i < xf86_config->num_crtc; i++) { 2249d6c0b56eSmrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 2250d6c0b56eSmrg 2251d6c0b56eSmrg if (!crtc->enabled) 2252d6c0b56eSmrg continue; 2253d6c0b56eSmrg 2254d6c0b56eSmrg drmmode_set_mode_major(crtc, &crtc->mode, 2255d6c0b56eSmrg crtc->rotation, crtc->x, crtc->y); 2256d6c0b56eSmrg } 2257d6c0b56eSmrg 2258d6c0b56eSmrg if (old_front) { 2259d6c0b56eSmrg amdgpu_bo_unref(&old_front); 2260d6c0b56eSmrg } 2261d6c0b56eSmrg 2262d6c0b56eSmrg return TRUE; 2263d6c0b56eSmrg 2264d6c0b56eSmrgfail: 2265d6c0b56eSmrg if (info->front_buffer) { 2266d6c0b56eSmrg amdgpu_bo_unref(&info->front_buffer); 2267d6c0b56eSmrg } 2268d6c0b56eSmrg info->front_buffer = old_front; 2269d6c0b56eSmrg scrn->virtualX = old_width; 2270d6c0b56eSmrg scrn->virtualY = old_height; 2271d6c0b56eSmrg scrn->displayWidth = old_pitch; 2272d6c0b56eSmrg 2273d6c0b56eSmrg return FALSE; 2274d6c0b56eSmrg} 2275d6c0b56eSmrg 2276d6c0b56eSmrgstatic const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { 2277d6c0b56eSmrg drmmode_xf86crtc_resize 2278d6c0b56eSmrg}; 2279d6c0b56eSmrg 2280d6c0b56eSmrgstatic void 2281d6c0b56eSmrgdrmmode_flip_abort(xf86CrtcPtr crtc, void *event_data) 2282d6c0b56eSmrg{ 228324b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 228424b90cf4Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 2285d6c0b56eSmrg drmmode_flipdata_ptr flipdata = event_data; 2286d6c0b56eSmrg 2287d6c0b56eSmrg if (--flipdata->flip_count == 0) { 2288504d986fSmrg if (!flipdata->fe_crtc) 2289504d986fSmrg flipdata->fe_crtc = crtc; 2290504d986fSmrg flipdata->abort(flipdata->fe_crtc, flipdata->event_data); 229124b90cf4Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &flipdata->fb, NULL); 2292d6c0b56eSmrg free(flipdata); 2293d6c0b56eSmrg } 2294d6c0b56eSmrg 229524b90cf4Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending, 229624b90cf4Smrg NULL); 2297d6c0b56eSmrg} 2298d6c0b56eSmrg 2299d6c0b56eSmrgstatic void 2300d6c0b56eSmrgdrmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *event_data) 2301d6c0b56eSmrg{ 2302d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 230324b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 2304d6c0b56eSmrg drmmode_flipdata_ptr flipdata = event_data; 2305d6c0b56eSmrg 2306d6c0b56eSmrg /* Is this the event whose info shall be delivered to higher level? */ 2307d6c0b56eSmrg if (crtc == flipdata->fe_crtc) { 2308d6c0b56eSmrg /* Yes: Cache msc, ust for later delivery. */ 2309d6c0b56eSmrg flipdata->fe_frame = frame; 2310d6c0b56eSmrg flipdata->fe_usec = usec; 2311d6c0b56eSmrg } 2312d6c0b56eSmrg 231324b90cf4Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, 231424b90cf4Smrg flipdata->fb); 231524b90cf4Smrg if (drmmode_crtc->tear_free || 231624b90cf4Smrg drmmode_crtc->flip_pending == flipdata->fb) { 231724b90cf4Smrg drmmode_fb_reference(pAMDGPUEnt->fd, 231824b90cf4Smrg &drmmode_crtc->flip_pending, NULL); 231924b90cf4Smrg } 232024b90cf4Smrg 2321d6c0b56eSmrg if (--flipdata->flip_count == 0) { 2322504d986fSmrg /* Deliver MSC & UST from reference/current CRTC to flip event 2323504d986fSmrg * handler 2324504d986fSmrg */ 2325d6c0b56eSmrg if (flipdata->fe_crtc) 2326504d986fSmrg flipdata->handler(flipdata->fe_crtc, flipdata->fe_frame, 2327504d986fSmrg flipdata->fe_usec, flipdata->event_data); 2328504d986fSmrg else 2329504d986fSmrg flipdata->handler(crtc, frame, usec, flipdata->event_data); 2330d6c0b56eSmrg 233124b90cf4Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &flipdata->fb, NULL); 2332d6c0b56eSmrg free(flipdata); 2333d6c0b56eSmrg } 2334d6c0b56eSmrg} 2335d6c0b56eSmrg 2336504d986fSmrg#if HAVE_NOTIFY_FD 2337504d986fSmrgstatic void drmmode_notify_fd(int fd, int notify, void *data) 2338504d986fSmrg{ 2339504d986fSmrg drmmode_ptr drmmode = data; 2340504d986fSmrg drmHandleEvent(fd, &drmmode->event_context); 2341504d986fSmrg} 2342504d986fSmrg#else 2343d6c0b56eSmrgstatic void drm_wakeup_handler(pointer data, int err, pointer p) 2344d6c0b56eSmrg{ 2345d6c0b56eSmrg drmmode_ptr drmmode = data; 2346d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(drmmode->scrn); 2347d6c0b56eSmrg fd_set *read_mask = p; 2348d6c0b56eSmrg 2349d6c0b56eSmrg if (err >= 0 && FD_ISSET(pAMDGPUEnt->fd, read_mask)) { 2350d6c0b56eSmrg drmHandleEvent(pAMDGPUEnt->fd, &drmmode->event_context); 2351d6c0b56eSmrg } 2352d6c0b56eSmrg} 2353504d986fSmrg#endif 2354d6c0b56eSmrg 235511bf0794Smrgstatic Bool drmmode_probe_page_flip_target(AMDGPUEntPtr pAMDGPUEnt) 235611bf0794Smrg{ 235711bf0794Smrg uint64_t cap_value; 235811bf0794Smrg 235911bf0794Smrg return drmGetCap(pAMDGPUEnt->fd, DRM_CAP_PAGE_FLIP_TARGET, 236011bf0794Smrg &cap_value) == 0 && cap_value != 0; 236111bf0794Smrg} 236211bf0794Smrg 236311bf0794Smrgstatic int 236411bf0794Smrgdrmmode_page_flip(AMDGPUEntPtr pAMDGPUEnt, drmmode_crtc_private_ptr drmmode_crtc, 236511bf0794Smrg int fb_id, uint32_t flags, uintptr_t drm_queue_seq) 236611bf0794Smrg{ 236711bf0794Smrg flags |= DRM_MODE_PAGE_FLIP_EVENT; 236811bf0794Smrg return drmModePageFlip(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 236911bf0794Smrg fb_id, flags, (void*)drm_queue_seq); 237011bf0794Smrg} 237111bf0794Smrg 237211bf0794Smrgint 237311bf0794Smrgdrmmode_page_flip_target_absolute(AMDGPUEntPtr pAMDGPUEnt, 237411bf0794Smrg drmmode_crtc_private_ptr drmmode_crtc, 237511bf0794Smrg int fb_id, uint32_t flags, 237611bf0794Smrg uintptr_t drm_queue_seq, uint32_t target_msc) 237711bf0794Smrg{ 237811bf0794Smrg if (pAMDGPUEnt->has_page_flip_target) { 237911bf0794Smrg flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE; 238011bf0794Smrg return drmModePageFlipTarget(pAMDGPUEnt->fd, 238111bf0794Smrg drmmode_crtc->mode_crtc->crtc_id, 238211bf0794Smrg fb_id, flags, (void*)drm_queue_seq, 238311bf0794Smrg target_msc); 238411bf0794Smrg } 238511bf0794Smrg 238611bf0794Smrg return drmmode_page_flip(pAMDGPUEnt, drmmode_crtc, fb_id, flags, 238711bf0794Smrg drm_queue_seq); 238811bf0794Smrg} 238911bf0794Smrg 239011bf0794Smrgint 239111bf0794Smrgdrmmode_page_flip_target_relative(AMDGPUEntPtr pAMDGPUEnt, 239211bf0794Smrg drmmode_crtc_private_ptr drmmode_crtc, 239311bf0794Smrg int fb_id, uint32_t flags, 239411bf0794Smrg uintptr_t drm_queue_seq, uint32_t target_msc) 239511bf0794Smrg{ 239611bf0794Smrg if (pAMDGPUEnt->has_page_flip_target) { 239711bf0794Smrg flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_RELATIVE; 239811bf0794Smrg return drmModePageFlipTarget(pAMDGPUEnt->fd, 239911bf0794Smrg drmmode_crtc->mode_crtc->crtc_id, 240011bf0794Smrg fb_id, flags, (void*)drm_queue_seq, 240111bf0794Smrg target_msc); 240211bf0794Smrg } 240311bf0794Smrg 240411bf0794Smrg return drmmode_page_flip(pAMDGPUEnt, drmmode_crtc, fb_id, flags, 240511bf0794Smrg drm_queue_seq); 240611bf0794Smrg} 240711bf0794Smrg 2408d6c0b56eSmrgBool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp) 2409d6c0b56eSmrg{ 2410d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 2411d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 2412d6c0b56eSmrg int i, num_dvi = 0, num_hdmi = 0; 2413d6c0b56eSmrg unsigned int crtcs_needed = 0; 2414d6c0b56eSmrg drmModeResPtr mode_res; 2415d6c0b56eSmrg char *bus_id_string, *provider_name; 2416d6c0b56eSmrg 2417d6c0b56eSmrg xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs); 2418d6c0b56eSmrg 2419d6c0b56eSmrg drmmode->scrn = pScrn; 2420d6c0b56eSmrg mode_res = drmModeGetResources(pAMDGPUEnt->fd); 2421d6c0b56eSmrg if (!mode_res) 2422d6c0b56eSmrg return FALSE; 2423d6c0b56eSmrg 2424d6c0b56eSmrg drmmode->count_crtcs = mode_res->count_crtcs; 2425d6c0b56eSmrg xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width, 2426d6c0b56eSmrg mode_res->max_height); 2427d6c0b56eSmrg 2428d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 2429d6c0b56eSmrg "Initializing outputs ...\n"); 2430d6c0b56eSmrg for (i = 0; i < mode_res->count_connectors; i++) 2431d6c0b56eSmrg crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, i, &num_dvi, &num_hdmi, 0); 2432d6c0b56eSmrg 2433d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 2434d6c0b56eSmrg "%d crtcs needed for screen.\n", crtcs_needed); 2435d6c0b56eSmrg 243624b90cf4Smrg /* Need per-screen drmmode_crtc_funcs, based on our global template, 243724b90cf4Smrg * so we can disable some functions, depending on screen settings. 243824b90cf4Smrg */ 243924b90cf4Smrg info->drmmode_crtc_funcs = drmmode_crtc_funcs; 244024b90cf4Smrg 2441d6c0b56eSmrg if (!info->use_glamor) { 2442d6c0b56eSmrg /* Rotation requires hardware acceleration */ 244324b90cf4Smrg info->drmmode_crtc_funcs.shadow_allocate = NULL; 244424b90cf4Smrg info->drmmode_crtc_funcs.shadow_create = NULL; 244524b90cf4Smrg info->drmmode_crtc_funcs.shadow_destroy = NULL; 2446d6c0b56eSmrg } 2447d6c0b56eSmrg 244824b90cf4Smrg /* Hw gamma lut's are currently bypassed by the hw at color depth 30, 244924b90cf4Smrg * so spare the server the effort to compute and update the cluts. 245024b90cf4Smrg */ 245124b90cf4Smrg if (pScrn->depth == 30) 245224b90cf4Smrg info->drmmode_crtc_funcs.gamma_set = NULL; 245324b90cf4Smrg 2454d6c0b56eSmrg for (i = 0; i < mode_res->count_crtcs; i++) 2455d6c0b56eSmrg if (!xf86IsEntityShared(pScrn->entityList[0]) || 2456d6c0b56eSmrg (crtcs_needed && !(pAMDGPUEnt->assigned_crtcs & (1 << i)))) 2457d6c0b56eSmrg crtcs_needed -= drmmode_crtc_init(pScrn, drmmode, mode_res, i); 2458d6c0b56eSmrg 2459d6c0b56eSmrg /* All ZaphodHeads outputs provided with matching crtcs? */ 2460d6c0b56eSmrg if (xf86IsEntityShared(pScrn->entityList[0]) && (crtcs_needed > 0)) 2461d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 2462d6c0b56eSmrg "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n", 2463d6c0b56eSmrg crtcs_needed); 2464d6c0b56eSmrg 2465d6c0b56eSmrg /* workout clones */ 2466d6c0b56eSmrg drmmode_clones_init(pScrn, drmmode, mode_res); 2467d6c0b56eSmrg 2468d6c0b56eSmrg bus_id_string = DRICreatePCIBusID(info->PciInfo); 2469d6c0b56eSmrg XNFasprintf(&provider_name, "%s @ %s", pScrn->chipset, bus_id_string); 2470d6c0b56eSmrg free(bus_id_string); 2471d6c0b56eSmrg xf86ProviderSetup(pScrn, NULL, provider_name); 2472d6c0b56eSmrg free(provider_name); 2473d6c0b56eSmrg 2474d6c0b56eSmrg xf86InitialConfiguration(pScrn, TRUE); 2475d6c0b56eSmrg 247624b90cf4Smrg drmmode->event_context.version = 2; 2477d6c0b56eSmrg drmmode->event_context.vblank_handler = amdgpu_drm_queue_handler; 2478d6c0b56eSmrg drmmode->event_context.page_flip_handler = amdgpu_drm_queue_handler; 2479d6c0b56eSmrg 248011bf0794Smrg pAMDGPUEnt->has_page_flip_target = drmmode_probe_page_flip_target(pAMDGPUEnt); 248111bf0794Smrg 2482d6c0b56eSmrg drmModeFreeResources(mode_res); 2483d6c0b56eSmrg return TRUE; 2484d6c0b56eSmrg} 2485d6c0b56eSmrg 2486d6c0b56eSmrgvoid drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 2487d6c0b56eSmrg{ 2488d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 2489d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 2490d6c0b56eSmrg 2491d6c0b56eSmrg info->drmmode_inited = TRUE; 2492d6c0b56eSmrg if (pAMDGPUEnt->fd_wakeup_registered != serverGeneration) { 2493504d986fSmrg#if HAVE_NOTIFY_FD 2494504d986fSmrg SetNotifyFd(pAMDGPUEnt->fd, drmmode_notify_fd, X_NOTIFY_READ, drmmode); 2495504d986fSmrg#else 2496d6c0b56eSmrg AddGeneralSocket(pAMDGPUEnt->fd); 2497d6c0b56eSmrg RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr) NoopDDA, 2498d6c0b56eSmrg drm_wakeup_handler, drmmode); 2499504d986fSmrg#endif 2500d6c0b56eSmrg pAMDGPUEnt->fd_wakeup_registered = serverGeneration; 2501d6c0b56eSmrg pAMDGPUEnt->fd_wakeup_ref = 1; 2502d6c0b56eSmrg } else 2503d6c0b56eSmrg pAMDGPUEnt->fd_wakeup_ref++; 2504d6c0b56eSmrg} 2505d6c0b56eSmrg 2506d6c0b56eSmrgvoid drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 2507d6c0b56eSmrg{ 2508504d986fSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 2509d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 2510d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 2511504d986fSmrg int c; 2512d6c0b56eSmrg 2513d6c0b56eSmrg if (!info->drmmode_inited) 2514d6c0b56eSmrg return; 2515d6c0b56eSmrg 2516d6c0b56eSmrg if (pAMDGPUEnt->fd_wakeup_registered == serverGeneration && 2517d6c0b56eSmrg !--pAMDGPUEnt->fd_wakeup_ref) { 2518504d986fSmrg#if HAVE_NOTIFY_FD 2519504d986fSmrg RemoveNotifyFd(pAMDGPUEnt->fd); 2520504d986fSmrg#else 2521d6c0b56eSmrg RemoveGeneralSocket(pAMDGPUEnt->fd); 2522d6c0b56eSmrg RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr) NoopDDA, 2523d6c0b56eSmrg drm_wakeup_handler, drmmode); 2524504d986fSmrg#endif 2525504d986fSmrg } 2526504d986fSmrg 252711bf0794Smrg for (c = 0; c < config->num_crtc; c++) 252811bf0794Smrg drmmode_crtc_scanout_free(config->crtc[c]->driver_private); 2529d6c0b56eSmrg} 2530d6c0b56eSmrg 253124b90cf4Smrgstatic void drmmode_sprite_do_set_cursor(struct amdgpu_device_priv *device_priv, 253224b90cf4Smrg ScrnInfoPtr scrn, int x, int y) 253324b90cf4Smrg{ 253424b90cf4Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 253524b90cf4Smrg CursorPtr cursor = device_priv->cursor; 253624b90cf4Smrg Bool sprite_visible = device_priv->sprite_visible; 253724b90cf4Smrg 253824b90cf4Smrg if (cursor) { 253924b90cf4Smrg x -= cursor->bits->xhot; 254024b90cf4Smrg y -= cursor->bits->yhot; 254124b90cf4Smrg 254224b90cf4Smrg device_priv->sprite_visible = 254324b90cf4Smrg x < scrn->virtualX && y < scrn->virtualY && 254424b90cf4Smrg (x + cursor->bits->width > 0) && 254524b90cf4Smrg (y + cursor->bits->height > 0); 254624b90cf4Smrg } else { 254724b90cf4Smrg device_priv->sprite_visible = FALSE; 254824b90cf4Smrg } 254924b90cf4Smrg 255024b90cf4Smrg info->sprites_visible += device_priv->sprite_visible - sprite_visible; 255124b90cf4Smrg} 255224b90cf4Smrg 255324b90cf4Smrgvoid drmmode_sprite_set_cursor(DeviceIntPtr pDev, ScreenPtr pScreen, 255424b90cf4Smrg CursorPtr pCursor, int x, int y) 255524b90cf4Smrg{ 255624b90cf4Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 255724b90cf4Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 255824b90cf4Smrg struct amdgpu_device_priv *device_priv = 255924b90cf4Smrg dixLookupScreenPrivate(&pDev->devPrivates, 256024b90cf4Smrg &amdgpu_device_private_key, pScreen); 256124b90cf4Smrg 256224b90cf4Smrg device_priv->cursor = pCursor; 256324b90cf4Smrg drmmode_sprite_do_set_cursor(device_priv, scrn, x, y); 256424b90cf4Smrg 256524b90cf4Smrg info->SetCursor(pDev, pScreen, pCursor, x, y); 256624b90cf4Smrg} 256724b90cf4Smrg 256824b90cf4Smrgvoid drmmode_sprite_move_cursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, 256924b90cf4Smrg int y) 257024b90cf4Smrg{ 257124b90cf4Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 257224b90cf4Smrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 257324b90cf4Smrg struct amdgpu_device_priv *device_priv = 257424b90cf4Smrg dixLookupScreenPrivate(&pDev->devPrivates, 257524b90cf4Smrg &amdgpu_device_private_key, pScreen); 257624b90cf4Smrg 257724b90cf4Smrg drmmode_sprite_do_set_cursor(device_priv, scrn, x, y); 257824b90cf4Smrg 257924b90cf4Smrg info->MoveCursor(pDev, pScreen, x, y); 258024b90cf4Smrg} 258124b90cf4Smrg 2582d6c0b56eSmrgvoid drmmode_set_cursor(ScrnInfoPtr scrn, drmmode_ptr drmmode, int id, 2583d6c0b56eSmrg struct amdgpu_buffer *bo) 2584d6c0b56eSmrg{ 2585d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2586d6c0b56eSmrg xf86CrtcPtr crtc = xf86_config->crtc[id]; 2587d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 2588d6c0b56eSmrg 2589d6c0b56eSmrg drmmode_crtc->cursor_buffer = bo; 2590d6c0b56eSmrg} 2591d6c0b56eSmrg 2592d6c0b56eSmrgvoid drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y) 2593d6c0b56eSmrg{ 2594d6c0b56eSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 2595d6c0b56eSmrg xf86OutputPtr output = config->output[config->compat_output]; 2596d6c0b56eSmrg xf86CrtcPtr crtc = output->crtc; 2597d6c0b56eSmrg 2598d6c0b56eSmrg if (crtc && crtc->enabled) { 2599d6c0b56eSmrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y); 2600d6c0b56eSmrg } 2601d6c0b56eSmrg} 2602d6c0b56eSmrg 2603d6c0b56eSmrgBool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, 2604d6c0b56eSmrg Bool set_hw) 2605d6c0b56eSmrg{ 2606d6c0b56eSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 2607d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 260824b90cf4Smrg unsigned num_desired = 0, num_on = 0; 2609d6c0b56eSmrg int c; 2610d6c0b56eSmrg 261124b90cf4Smrg /* First, disable all unused CRTCs */ 261224b90cf4Smrg if (set_hw) { 261324b90cf4Smrg for (c = 0; c < config->num_crtc; c++) { 261424b90cf4Smrg xf86CrtcPtr crtc = config->crtc[c]; 261524b90cf4Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 261624b90cf4Smrg 261724b90cf4Smrg /* Skip disabled CRTCs */ 261824b90cf4Smrg if (crtc->enabled) 261924b90cf4Smrg continue; 262024b90cf4Smrg 262124b90cf4Smrg drmmode_do_crtc_dpms(crtc, DPMSModeOff); 262224b90cf4Smrg drmModeSetCrtc(pAMDGPUEnt->fd, 262324b90cf4Smrg drmmode_crtc->mode_crtc->crtc_id, 262424b90cf4Smrg 0, 0, 0, NULL, 0, NULL); 262524b90cf4Smrg drmmode_fb_reference(pAMDGPUEnt->fd, 262624b90cf4Smrg &drmmode_crtc->fb, NULL); 262724b90cf4Smrg } 262824b90cf4Smrg } 262924b90cf4Smrg 263024b90cf4Smrg /* Then, try setting the chosen mode on each CRTC */ 2631d6c0b56eSmrg for (c = 0; c < config->num_crtc; c++) { 2632d6c0b56eSmrg xf86CrtcPtr crtc = config->crtc[c]; 2633d6c0b56eSmrg xf86OutputPtr output = NULL; 2634d6c0b56eSmrg int o; 2635d6c0b56eSmrg 263624b90cf4Smrg if (!crtc->enabled) 2637d6c0b56eSmrg continue; 2638d6c0b56eSmrg 2639d6c0b56eSmrg if (config->output[config->compat_output]->crtc == crtc) 2640d6c0b56eSmrg output = config->output[config->compat_output]; 2641d6c0b56eSmrg else { 2642d6c0b56eSmrg for (o = 0; o < config->num_output; o++) 2643d6c0b56eSmrg if (config->output[o]->crtc == crtc) { 2644d6c0b56eSmrg output = config->output[o]; 2645d6c0b56eSmrg break; 2646d6c0b56eSmrg } 2647d6c0b56eSmrg } 2648d6c0b56eSmrg /* paranoia */ 2649d6c0b56eSmrg if (!output) 2650d6c0b56eSmrg continue; 2651d6c0b56eSmrg 265224b90cf4Smrg num_desired++; 265324b90cf4Smrg 2654d6c0b56eSmrg /* Mark that we'll need to re-set the mode for sure */ 2655d6c0b56eSmrg memset(&crtc->mode, 0, sizeof(crtc->mode)); 2656d6c0b56eSmrg if (!crtc->desiredMode.CrtcHDisplay) { 2657d6c0b56eSmrg DisplayModePtr mode = xf86OutputFindClosestMode(output, 2658d6c0b56eSmrg pScrn-> 2659d6c0b56eSmrg currentMode); 2660d6c0b56eSmrg 266124b90cf4Smrg if (!mode) { 266224b90cf4Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 266324b90cf4Smrg "Failed to find mode for CRTC %d\n", c); 266424b90cf4Smrg continue; 266524b90cf4Smrg } 2666d6c0b56eSmrg crtc->desiredMode = *mode; 2667d6c0b56eSmrg crtc->desiredRotation = RR_Rotate_0; 2668d6c0b56eSmrg crtc->desiredX = 0; 2669d6c0b56eSmrg crtc->desiredY = 0; 2670d6c0b56eSmrg } 2671d6c0b56eSmrg 2672d6c0b56eSmrg if (set_hw) { 267324b90cf4Smrg if (crtc->funcs->set_mode_major(crtc, &crtc->desiredMode, 267424b90cf4Smrg crtc->desiredRotation, 267524b90cf4Smrg crtc->desiredX, 267624b90cf4Smrg crtc->desiredY)) { 267724b90cf4Smrg num_on++; 267824b90cf4Smrg } else { 267924b90cf4Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 268024b90cf4Smrg "Failed to set mode on CRTC %d\n", c); 268124b90cf4Smrg } 2682d6c0b56eSmrg } else { 2683d6c0b56eSmrg crtc->mode = crtc->desiredMode; 2684d6c0b56eSmrg crtc->rotation = crtc->desiredRotation; 2685d6c0b56eSmrg crtc->x = crtc->desiredX; 2686d6c0b56eSmrg crtc->y = crtc->desiredY; 268724b90cf4Smrg if (drmmode_handle_transform(crtc)) 268824b90cf4Smrg num_on++; 2689d6c0b56eSmrg } 2690d6c0b56eSmrg } 269124b90cf4Smrg 269224b90cf4Smrg if (num_on == 0 && num_desired > 0) { 269324b90cf4Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to enable any CRTC\n"); 269424b90cf4Smrg return FALSE; 269524b90cf4Smrg } 269624b90cf4Smrg 2697d6c0b56eSmrg return TRUE; 2698d6c0b56eSmrg} 2699d6c0b56eSmrg 2700d6c0b56eSmrgBool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn) 2701d6c0b56eSmrg{ 2702d6c0b56eSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 2703d6c0b56eSmrg 2704d6c0b56eSmrg if (xf86_config->num_crtc) { 2705d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 2706d6c0b56eSmrg "Initializing kms color map\n"); 2707d6c0b56eSmrg if (!miCreateDefColormap(pScreen)) 2708d6c0b56eSmrg return FALSE; 270924b90cf4Smrg /* All radeons support 10 bit CLUTs. They get bypassed at depth 30. */ 271024b90cf4Smrg if (pScrn->depth != 30 && 271124b90cf4Smrg !xf86HandleColormaps(pScreen, 256, 10, 2712504d986fSmrg NULL, NULL, 2713d6c0b56eSmrg CMAP_PALETTED_TRUECOLOR 2714d6c0b56eSmrg#if 0 /* This option messes up text mode! (eich@suse.de) */ 2715d6c0b56eSmrg | CMAP_LOAD_EVEN_IF_OFFSCREEN 2716d6c0b56eSmrg#endif 2717d6c0b56eSmrg | CMAP_RELOAD_ON_MODE_SWITCH)) 2718d6c0b56eSmrg return FALSE; 2719d6c0b56eSmrg } 2720d6c0b56eSmrg return TRUE; 2721d6c0b56eSmrg} 2722d6c0b56eSmrg 2723504d986fSmrgstatic Bool 2724504d986fSmrgdrmmode_find_output(ScrnInfoPtr scrn, int output_id, int *num_dvi, 2725504d986fSmrg int *num_hdmi) 2726504d986fSmrg{ 2727504d986fSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2728504d986fSmrg int i; 2729504d986fSmrg 2730504d986fSmrg for (i = 0; i < config->num_output; i++) { 2731504d986fSmrg xf86OutputPtr output = config->output[i]; 2732504d986fSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 2733504d986fSmrg 2734504d986fSmrg if (drmmode_output->output_id == output_id) { 2735504d986fSmrg switch(drmmode_output->mode_output->connector_type) { 2736504d986fSmrg case DRM_MODE_CONNECTOR_DVII: 2737504d986fSmrg case DRM_MODE_CONNECTOR_DVID: 2738504d986fSmrg case DRM_MODE_CONNECTOR_DVIA: 2739504d986fSmrg (*num_dvi)++; 2740504d986fSmrg break; 2741504d986fSmrg case DRM_MODE_CONNECTOR_HDMIA: 2742504d986fSmrg case DRM_MODE_CONNECTOR_HDMIB: 2743504d986fSmrg (*num_hdmi)++; 2744504d986fSmrg break; 2745504d986fSmrg } 2746504d986fSmrg 2747504d986fSmrg return TRUE; 2748504d986fSmrg } 2749504d986fSmrg } 2750504d986fSmrg 2751504d986fSmrg return FALSE; 2752504d986fSmrg} 2753d6c0b56eSmrg 2754d6c0b56eSmrgvoid 2755d6c0b56eSmrgamdgpu_mode_hotplug(ScrnInfoPtr scrn, drmmode_ptr drmmode) 2756d6c0b56eSmrg{ 2757d6c0b56eSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2758d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 2759d6c0b56eSmrg drmModeResPtr mode_res; 2760d6c0b56eSmrg int i, j; 2761d6c0b56eSmrg Bool found; 2762d6c0b56eSmrg Bool changed = FALSE; 2763504d986fSmrg int num_dvi = 0, num_hdmi = 0; 2764d6c0b56eSmrg 276524b90cf4Smrg /* Try to re-set the mode on all the connectors with a BAD link-state: 276624b90cf4Smrg * This may happen if a link degrades and a new modeset is necessary, using 276724b90cf4Smrg * different link-training parameters. If the kernel found that the current 276824b90cf4Smrg * mode is not achievable anymore, it should have pruned the mode before 276924b90cf4Smrg * sending the hotplug event. Try to re-set the currently-set mode to keep 277024b90cf4Smrg * the display alive, this will fail if the mode has been pruned. 277124b90cf4Smrg * In any case, we will send randr events for the Desktop Environment to 277224b90cf4Smrg * deal with it, if it wants to. 277324b90cf4Smrg */ 277424b90cf4Smrg for (i = 0; i < config->num_output; i++) { 277524b90cf4Smrg xf86OutputPtr output = config->output[i]; 277624b90cf4Smrg xf86CrtcPtr crtc = output->crtc; 277724b90cf4Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 277824b90cf4Smrg 277924b90cf4Smrg drmmode_output_detect(output); 278024b90cf4Smrg 278124b90cf4Smrg if (!crtc || !drmmode_output->mode_output) 278224b90cf4Smrg continue; 278324b90cf4Smrg 278424b90cf4Smrg /* Get an updated view of the properties for the current connector and 278524b90cf4Smrg * look for the link-status property 278624b90cf4Smrg */ 278724b90cf4Smrg for (j = 0; j < drmmode_output->num_props; j++) { 278824b90cf4Smrg drmmode_prop_ptr p = &drmmode_output->props[j]; 278924b90cf4Smrg 279024b90cf4Smrg if (!strcmp(p->mode_prop->name, "link-status")) { 279124b90cf4Smrg if (p->value != DRM_MODE_LINK_STATUS_BAD) 279224b90cf4Smrg break; 279324b90cf4Smrg 279424b90cf4Smrg /* the connector got a link failure, re-set the current mode */ 279524b90cf4Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 279624b90cf4Smrg crtc->x, crtc->y); 279724b90cf4Smrg 279824b90cf4Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 279924b90cf4Smrg "hotplug event: connector %u's link-state is BAD, " 280024b90cf4Smrg "tried resetting the current mode. You may be left" 280124b90cf4Smrg "with a black screen if this fails...\n", 280224b90cf4Smrg drmmode_output->mode_output->connector_id); 280324b90cf4Smrg 280424b90cf4Smrg break; 280524b90cf4Smrg } 280624b90cf4Smrg } 280724b90cf4Smrg } 280824b90cf4Smrg 2809d6c0b56eSmrg mode_res = drmModeGetResources(pAMDGPUEnt->fd); 2810d6c0b56eSmrg if (!mode_res) 2811d6c0b56eSmrg goto out; 2812d6c0b56eSmrg 2813d6c0b56eSmrgrestart_destroy: 2814d6c0b56eSmrg for (i = 0; i < config->num_output; i++) { 2815d6c0b56eSmrg xf86OutputPtr output = config->output[i]; 2816d6c0b56eSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 2817d6c0b56eSmrg found = FALSE; 2818d6c0b56eSmrg for (j = 0; j < mode_res->count_connectors; j++) { 2819d6c0b56eSmrg if (mode_res->connectors[j] == drmmode_output->output_id) { 2820d6c0b56eSmrg found = TRUE; 2821d6c0b56eSmrg break; 2822d6c0b56eSmrg } 2823d6c0b56eSmrg } 2824d6c0b56eSmrg if (found) 2825d6c0b56eSmrg continue; 2826d6c0b56eSmrg 2827d6c0b56eSmrg drmModeFreeConnector(drmmode_output->mode_output); 2828d6c0b56eSmrg drmmode_output->mode_output = NULL; 2829d6c0b56eSmrg drmmode_output->output_id = -1; 2830d6c0b56eSmrg 2831d6c0b56eSmrg changed = TRUE; 2832d6c0b56eSmrg if (drmmode->delete_dp_12_displays) { 2833d6c0b56eSmrg RROutputDestroy(output->randr_output); 2834d6c0b56eSmrg xf86OutputDestroy(output); 2835d6c0b56eSmrg goto restart_destroy; 2836d6c0b56eSmrg } 2837d6c0b56eSmrg } 2838d6c0b56eSmrg 2839d6c0b56eSmrg /* find new output ids we don't have outputs for */ 2840d6c0b56eSmrg for (i = 0; i < mode_res->count_connectors; i++) { 2841504d986fSmrg if (drmmode_find_output(pAMDGPUEnt->primary_scrn, 2842504d986fSmrg mode_res->connectors[i], 2843504d986fSmrg &num_dvi, &num_hdmi) || 2844504d986fSmrg (pAMDGPUEnt->secondary_scrn && 2845504d986fSmrg drmmode_find_output(pAMDGPUEnt->secondary_scrn, 2846504d986fSmrg mode_res->connectors[i], 2847504d986fSmrg &num_dvi, &num_hdmi))) 2848d6c0b56eSmrg continue; 2849d6c0b56eSmrg 2850504d986fSmrg if (drmmode_output_init(scrn, drmmode, mode_res, i, &num_dvi, 2851504d986fSmrg &num_hdmi, 1) != 0) 2852504d986fSmrg changed = TRUE; 2853d6c0b56eSmrg } 2854d6c0b56eSmrg 2855504d986fSmrg if (changed && dixPrivateKeyRegistered(rrPrivKey)) { 2856d6c0b56eSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,2,0) 2857d6c0b56eSmrg RRSetChanged(xf86ScrnToScreen(scrn)); 2858d6c0b56eSmrg#else 2859d6c0b56eSmrg rrScrPrivPtr rrScrPriv = rrGetScrPriv(scrn->pScreen); 2860d6c0b56eSmrg rrScrPriv->changed = TRUE; 2861d6c0b56eSmrg#endif 2862d6c0b56eSmrg RRTellChanged(xf86ScrnToScreen(scrn)); 2863d6c0b56eSmrg } 2864d6c0b56eSmrg 2865d6c0b56eSmrg drmModeFreeResources(mode_res); 2866d6c0b56eSmrgout: 2867d6c0b56eSmrg RRGetInfo(xf86ScrnToScreen(scrn), TRUE); 2868d6c0b56eSmrg} 2869d6c0b56eSmrg 2870d6c0b56eSmrg#ifdef HAVE_LIBUDEV 2871d6c0b56eSmrgstatic void drmmode_handle_uevents(int fd, void *closure) 2872d6c0b56eSmrg{ 2873d6c0b56eSmrg drmmode_ptr drmmode = closure; 2874d6c0b56eSmrg ScrnInfoPtr scrn = drmmode->scrn; 2875d6c0b56eSmrg struct udev_device *dev; 2876504d986fSmrg Bool received = FALSE; 287711bf0794Smrg struct timeval tv = { 0, 0 }; 287811bf0794Smrg fd_set readfd; 287911bf0794Smrg 288011bf0794Smrg FD_ZERO(&readfd); 288111bf0794Smrg FD_SET(fd, &readfd); 288211bf0794Smrg 288311bf0794Smrg while (select(fd + 1, &readfd, NULL, NULL, &tv) > 0 && 288411bf0794Smrg FD_ISSET(fd, &readfd)) { 288511bf0794Smrg /* select() ensured that this will not block */ 288611bf0794Smrg dev = udev_monitor_receive_device(drmmode->uevent_monitor); 288711bf0794Smrg if (dev) { 288811bf0794Smrg udev_device_unref(dev); 288911bf0794Smrg received = TRUE; 289011bf0794Smrg } 2891504d986fSmrg } 2892504d986fSmrg 2893504d986fSmrg if (received) 2894504d986fSmrg amdgpu_mode_hotplug(scrn, drmmode); 2895d6c0b56eSmrg} 2896d6c0b56eSmrg#endif 2897d6c0b56eSmrg 2898d6c0b56eSmrgvoid drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode) 2899d6c0b56eSmrg{ 2900d6c0b56eSmrg#ifdef HAVE_LIBUDEV 2901d6c0b56eSmrg struct udev *u; 2902d6c0b56eSmrg struct udev_monitor *mon; 2903d6c0b56eSmrg 2904d6c0b56eSmrg u = udev_new(); 2905d6c0b56eSmrg if (!u) 2906d6c0b56eSmrg return; 2907d6c0b56eSmrg mon = udev_monitor_new_from_netlink(u, "udev"); 2908d6c0b56eSmrg if (!mon) { 2909d6c0b56eSmrg udev_unref(u); 2910d6c0b56eSmrg return; 2911d6c0b56eSmrg } 2912d6c0b56eSmrg 2913d6c0b56eSmrg if (udev_monitor_filter_add_match_subsystem_devtype(mon, 2914d6c0b56eSmrg "drm", 2915d6c0b56eSmrg "drm_minor") < 0 || 2916d6c0b56eSmrg udev_monitor_enable_receiving(mon) < 0) { 2917d6c0b56eSmrg udev_monitor_unref(mon); 2918d6c0b56eSmrg udev_unref(u); 2919d6c0b56eSmrg return; 2920d6c0b56eSmrg } 2921d6c0b56eSmrg 2922d6c0b56eSmrg drmmode->uevent_handler = 2923d6c0b56eSmrg xf86AddGeneralHandler(udev_monitor_get_fd(mon), 2924d6c0b56eSmrg drmmode_handle_uevents, drmmode); 2925d6c0b56eSmrg 2926d6c0b56eSmrg drmmode->uevent_monitor = mon; 2927d6c0b56eSmrg#endif 2928d6c0b56eSmrg} 2929d6c0b56eSmrg 2930d6c0b56eSmrgvoid drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode) 2931d6c0b56eSmrg{ 2932d6c0b56eSmrg#ifdef HAVE_LIBUDEV 2933d6c0b56eSmrg if (drmmode->uevent_handler) { 2934d6c0b56eSmrg struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor); 2935d6c0b56eSmrg xf86RemoveGeneralHandler(drmmode->uevent_handler); 2936d6c0b56eSmrg 2937d6c0b56eSmrg udev_monitor_unref(drmmode->uevent_monitor); 2938d6c0b56eSmrg udev_unref(u); 2939d6c0b56eSmrg } 2940d6c0b56eSmrg#endif 2941d6c0b56eSmrg} 2942d6c0b56eSmrg 2943d6c0b56eSmrgBool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, 2944d6c0b56eSmrg PixmapPtr new_front, uint64_t id, void *data, 294524b90cf4Smrg xf86CrtcPtr ref_crtc, amdgpu_drm_handler_proc handler, 2946504d986fSmrg amdgpu_drm_abort_proc abort, 294711bf0794Smrg enum drmmode_flip_sync flip_sync, 294811bf0794Smrg uint32_t target_msc) 2949d6c0b56eSmrg{ 2950d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 2951d6c0b56eSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2952d6c0b56eSmrg xf86CrtcPtr crtc = NULL; 2953d6c0b56eSmrg drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private; 2954d6c0b56eSmrg int i; 295511bf0794Smrg uint32_t flip_flags = flip_sync == FLIP_ASYNC ? DRM_MODE_PAGE_FLIP_ASYNC : 0; 2956d6c0b56eSmrg drmmode_flipdata_ptr flipdata; 2957d6c0b56eSmrg uintptr_t drm_queue_seq = 0; 2958d6c0b56eSmrg 2959d6c0b56eSmrg flipdata = calloc(1, sizeof(drmmode_flipdata_rec)); 2960d6c0b56eSmrg if (!flipdata) { 2961d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 2962d6c0b56eSmrg "flip queue: data alloc failed.\n"); 2963d6c0b56eSmrg goto error; 2964d6c0b56eSmrg } 2965d6c0b56eSmrg 296624b90cf4Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &flipdata->fb, 296724b90cf4Smrg amdgpu_pixmap_get_fb(new_front)); 296824b90cf4Smrg if (!flipdata->fb) { 296924b90cf4Smrg ErrorF("Failed to get FB for flip\n"); 2970d6c0b56eSmrg goto error; 297124b90cf4Smrg } 2972d6c0b56eSmrg 2973d6c0b56eSmrg /* 2974d6c0b56eSmrg * Queue flips on all enabled CRTCs 2975d6c0b56eSmrg * Note that if/when we get per-CRTC buffers, we'll have to update this. 2976d6c0b56eSmrg * Right now it assumes a single shared fb across all CRTCs, with the 2977d6c0b56eSmrg * kernel fixing up the offset of each CRTC as necessary. 2978d6c0b56eSmrg * 2979d6c0b56eSmrg * Also, flips queued on disabled or incorrectly configured displays 2980d6c0b56eSmrg * may never complete; this is a configuration error. 2981d6c0b56eSmrg */ 2982d6c0b56eSmrg 2983d6c0b56eSmrg flipdata->event_data = data; 2984d6c0b56eSmrg flipdata->handler = handler; 2985d6c0b56eSmrg flipdata->abort = abort; 298624b90cf4Smrg flipdata->fe_crtc = ref_crtc; 2987d6c0b56eSmrg 2988d6c0b56eSmrg for (i = 0; i < config->num_crtc; i++) { 298924b90cf4Smrg struct drmmode_fb *fb = flipdata->fb; 299024b90cf4Smrg 2991d6c0b56eSmrg crtc = config->crtc[i]; 299224b90cf4Smrg drmmode_crtc = crtc->driver_private; 2993d6c0b56eSmrg 299424b90cf4Smrg if (!drmmode_crtc_can_flip(crtc) || 299524b90cf4Smrg (drmmode_crtc->tear_free && crtc != ref_crtc)) 2996d6c0b56eSmrg continue; 2997d6c0b56eSmrg 2998d6c0b56eSmrg flipdata->flip_count++; 2999d6c0b56eSmrg 3000d6c0b56eSmrg drm_queue_seq = amdgpu_drm_queue_alloc(crtc, client, id, 3001d6c0b56eSmrg flipdata, 3002d6c0b56eSmrg drmmode_flip_handler, 3003d6c0b56eSmrg drmmode_flip_abort); 3004504d986fSmrg if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) { 3005d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 3006d6c0b56eSmrg "Allocating DRM queue event entry failed.\n"); 3007d6c0b56eSmrg goto error; 3008d6c0b56eSmrg } 3009d6c0b56eSmrg 301024b90cf4Smrg if (drmmode_crtc->tear_free) { 301124b90cf4Smrg BoxRec extents = { .x1 = 0, .y1 = 0, 301224b90cf4Smrg .x2 = new_front->drawable.width, 301324b90cf4Smrg .y2 = new_front->drawable.height }; 301424b90cf4Smrg int scanout_id = drmmode_crtc->scanout_id ^ 1; 301524b90cf4Smrg 301624b90cf4Smrg if (flip_sync == FLIP_ASYNC) { 301724b90cf4Smrg if (!drmmode_wait_vblank(crtc, 301824b90cf4Smrg DRM_VBLANK_RELATIVE | 301924b90cf4Smrg DRM_VBLANK_EVENT, 302024b90cf4Smrg 0, drm_queue_seq, 302124b90cf4Smrg NULL, NULL)) 302224b90cf4Smrg goto flip_error; 302324b90cf4Smrg goto next; 302424b90cf4Smrg } 302524b90cf4Smrg 302624b90cf4Smrg fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap); 302724b90cf4Smrg if (!fb) { 302824b90cf4Smrg ErrorF("Failed to get FB for TearFree flip\n"); 302924b90cf4Smrg goto error; 303024b90cf4Smrg } 303124b90cf4Smrg 303224b90cf4Smrg amdgpu_scanout_do_update(crtc, scanout_id, new_front, 303324b90cf4Smrg &extents); 303424b90cf4Smrg 303524b90cf4Smrg drmmode_crtc_wait_pending_event(drmmode_crtc, pAMDGPUEnt->fd, 303624b90cf4Smrg drmmode_crtc->scanout_update_pending); 303724b90cf4Smrg } 303824b90cf4Smrg 303924b90cf4Smrg if (crtc == ref_crtc) { 304011bf0794Smrg if (drmmode_page_flip_target_absolute(pAMDGPUEnt, 304111bf0794Smrg drmmode_crtc, 304224b90cf4Smrg fb->handle, 304311bf0794Smrg flip_flags, 304411bf0794Smrg drm_queue_seq, 304511bf0794Smrg target_msc) != 0) 304611bf0794Smrg goto flip_error; 304711bf0794Smrg } else { 304811bf0794Smrg if (drmmode_page_flip_target_relative(pAMDGPUEnt, 304911bf0794Smrg drmmode_crtc, 305024b90cf4Smrg fb->handle, 305111bf0794Smrg flip_flags, 305211bf0794Smrg drm_queue_seq, 0) != 0) 305311bf0794Smrg goto flip_error; 3054d6c0b56eSmrg } 305511bf0794Smrg 305624b90cf4Smrg if (drmmode_crtc->tear_free) { 305724b90cf4Smrg drmmode_crtc->scanout_id ^= 1; 305824b90cf4Smrg drmmode_crtc->ignore_damage = TRUE; 305924b90cf4Smrg } 306024b90cf4Smrg 306124b90cf4Smrg next: 306224b90cf4Smrg drmmode_fb_reference(pAMDGPUEnt->fd, 306324b90cf4Smrg &drmmode_crtc->flip_pending, fb); 3064d6c0b56eSmrg drm_queue_seq = 0; 3065d6c0b56eSmrg } 3066d6c0b56eSmrg 3067d6c0b56eSmrg if (flipdata->flip_count > 0) 3068d6c0b56eSmrg return TRUE; 3069d6c0b56eSmrg 307011bf0794Smrgflip_error: 307111bf0794Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed: %s\n", 307211bf0794Smrg strerror(errno)); 307311bf0794Smrg 3074d6c0b56eSmrgerror: 3075d6c0b56eSmrg if (drm_queue_seq) 3076d6c0b56eSmrg amdgpu_drm_abort_entry(drm_queue_seq); 3077d6c0b56eSmrg else if (crtc) 3078d6c0b56eSmrg drmmode_flip_abort(crtc, flipdata); 307911bf0794Smrg else { 308011bf0794Smrg abort(NULL, data); 308124b90cf4Smrg drmmode_fb_reference(pAMDGPUEnt->fd, &flipdata->fb, NULL); 3082d6c0b56eSmrg free(flipdata); 308311bf0794Smrg } 3084d6c0b56eSmrg 3085d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n", 3086d6c0b56eSmrg strerror(errno)); 3087d6c0b56eSmrg return FALSE; 3088d6c0b56eSmrg} 3089