drmmode_display.c revision 39413783
1de2362d3Smrg/* 2de2362d3Smrg * Copyright © 2007 Red Hat, Inc. 3de2362d3Smrg * 4de2362d3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5de2362d3Smrg * copy of this software and associated documentation files (the "Software"), 6de2362d3Smrg * to deal in the Software without restriction, including without limitation 7de2362d3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8de2362d3Smrg * and/or sell copies of the Software, and to permit persons to whom the 9de2362d3Smrg * Software is furnished to do so, subject to the following conditions: 10de2362d3Smrg * 11de2362d3Smrg * The above copyright notice and this permission notice (including the next 12de2362d3Smrg * paragraph) shall be included in all copies or substantial portions of the 13de2362d3Smrg * Software. 14de2362d3Smrg * 15de2362d3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16de2362d3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17de2362d3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18de2362d3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19de2362d3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20de2362d3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21de2362d3Smrg * SOFTWARE. 22de2362d3Smrg * 23de2362d3Smrg * Authors: 24de2362d3Smrg * Dave Airlie <airlied@redhat.com> 25de2362d3Smrg * 26de2362d3Smrg */ 27de2362d3Smrg 28de2362d3Smrg#ifdef HAVE_CONFIG_H 29de2362d3Smrg#include "config.h" 30de2362d3Smrg#endif 31de2362d3Smrg 32de2362d3Smrg#include <errno.h> 33de2362d3Smrg#include <sys/ioctl.h> 3418781e08Smrg#include <time.h> 3518781e08Smrg#include "cursorstr.h" 3618781e08Smrg#include "damagestr.h" 378bf5c682Smrg#include "inputstr.h" 388bf5c682Smrg#include "list.h" 39de2362d3Smrg#include "micmap.h" 4039413783Smrg#include "mipointrst.h" 41de2362d3Smrg#include "xf86cmap.h" 4218781e08Smrg#include "xf86Priv.h" 43de2362d3Smrg#include "radeon.h" 4418781e08Smrg#include "radeon_bo_helper.h" 4518781e08Smrg#include "radeon_glamor.h" 46de2362d3Smrg#include "radeon_reg.h" 4718781e08Smrg 4818781e08Smrg#include <dri.h> 49de2362d3Smrg 50de2362d3Smrg#include "drmmode_display.h" 51de2362d3Smrg 52de2362d3Smrg/* DPMS */ 53de2362d3Smrg#ifdef HAVE_XEXTPROTO_71 54de2362d3Smrg#include <X11/extensions/dpmsconst.h> 55de2362d3Smrg#else 56de2362d3Smrg#define DPMS_SERVER 57de2362d3Smrg#include <X11/extensions/dpms.h> 58de2362d3Smrg#endif 59de2362d3Smrg 6018781e08Smrg#define DEFAULT_NOMINAL_FRAME_RATE 60 6118781e08Smrg 6218781e08Smrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 22 6318781e08Smrg#define HAVE_NOTIFY_FD 1 6418781e08Smrg#endif 6518781e08Smrg 6618781e08Smrgstatic Bool 6718781e08Smrgdrmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height); 6818781e08Smrg 6918781e08Smrgstatic Bool 7018781e08SmrgRADEONZaphodStringMatches(ScrnInfoPtr pScrn, const char *s, char *output_name) 7118781e08Smrg{ 7218781e08Smrg int i = 0; 7318781e08Smrg char s1[20]; 7418781e08Smrg 7518781e08Smrg do { 7618781e08Smrg switch(*s) { 7718781e08Smrg case ',': 7818781e08Smrg s1[i] = '\0'; 7918781e08Smrg i = 0; 8018781e08Smrg if (strcmp(s1, output_name) == 0) 8118781e08Smrg return TRUE; 8218781e08Smrg break; 8318781e08Smrg case ' ': 8418781e08Smrg case '\t': 8518781e08Smrg case '\n': 8618781e08Smrg case '\r': 8718781e08Smrg break; 8818781e08Smrg default: 8918781e08Smrg s1[i] = *s; 9018781e08Smrg i++; 9118781e08Smrg break; 9218781e08Smrg } 9318781e08Smrg } while(*s++); 9418781e08Smrg 9518781e08Smrg s1[i] = '\0'; 9618781e08Smrg if (strcmp(s1, output_name) == 0) 9718781e08Smrg return TRUE; 9818781e08Smrg 9918781e08Smrg return FALSE; 10018781e08Smrg} 10118781e08Smrg 1028bf5c682Smrg 103de2362d3Smrgstatic PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn, 104de2362d3Smrg int width, int height, 105de2362d3Smrg int depth, int bpp, 10618781e08Smrg int pitch, 10739413783Smrg struct radeon_buffer *bo) 108de2362d3Smrg{ 109de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 110de2362d3Smrg ScreenPtr pScreen = pScrn->pScreen; 111de2362d3Smrg PixmapPtr pixmap; 112de2362d3Smrg 11318781e08Smrg pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 11418781e08Smrg RADEON_CREATE_PIXMAP_SCANOUT); 115de2362d3Smrg if (!pixmap) 116de2362d3Smrg return NULL; 117de2362d3Smrg 1187314432eSmrg if (!(*pScreen->ModifyPixmapHeader)(pixmap, width, height, 1197314432eSmrg depth, bpp, pitch, NULL)) { 12018781e08Smrg goto fail; 1217314432eSmrg } 1227314432eSmrg 12318781e08Smrg if (!info->use_glamor) 12418781e08Smrg exaMoveInPixmap(pixmap); 12518781e08Smrg 12618781e08Smrg if (!radeon_set_pixmap_bo(pixmap, bo)) 12718781e08Smrg goto fail; 12818781e08Smrg 12939413783Smrg if (info->surf_man && !info->use_glamor) { 13039413783Smrg struct radeon_surface *surface = radeon_get_pixmap_surface(pixmap); 13139413783Smrg 13239413783Smrg if (!radeon_surface_initialize(info, surface, width, height, bpp / 8, 13339413783Smrg radeon_get_pixmap_tiling_flags(pixmap), 0)) 13439413783Smrg goto fail; 135de2362d3Smrg } 136de2362d3Smrg 13718781e08Smrg if (!info->use_glamor || 13839413783Smrg radeon_glamor_create_textured_pixmap(pixmap, bo)) 13918781e08Smrg return pixmap; 14018781e08Smrg 14118781e08Smrgfail: 14218781e08Smrg pScreen->DestroyPixmap(pixmap); 14318781e08Smrg return NULL; 144de2362d3Smrg} 145de2362d3Smrg 146de2362d3Smrgstatic void drmmode_destroy_bo_pixmap(PixmapPtr pixmap) 147de2362d3Smrg{ 148de2362d3Smrg ScreenPtr pScreen = pixmap->drawable.pScreen; 149de2362d3Smrg 150de2362d3Smrg (*pScreen->DestroyPixmap)(pixmap); 151de2362d3Smrg} 152de2362d3Smrg 153de2362d3Smrgstatic void 154de2362d3Smrgdrmmode_ConvertFromKMode(ScrnInfoPtr scrn, 155de2362d3Smrg drmModeModeInfo *kmode, 156de2362d3Smrg DisplayModePtr mode) 157de2362d3Smrg{ 158de2362d3Smrg memset(mode, 0, sizeof(DisplayModeRec)); 159de2362d3Smrg mode->status = MODE_OK; 160de2362d3Smrg 161de2362d3Smrg mode->Clock = kmode->clock; 162de2362d3Smrg 163de2362d3Smrg mode->HDisplay = kmode->hdisplay; 164de2362d3Smrg mode->HSyncStart = kmode->hsync_start; 165de2362d3Smrg mode->HSyncEnd = kmode->hsync_end; 166de2362d3Smrg mode->HTotal = kmode->htotal; 167de2362d3Smrg mode->HSkew = kmode->hskew; 168de2362d3Smrg 169de2362d3Smrg mode->VDisplay = kmode->vdisplay; 170de2362d3Smrg mode->VSyncStart = kmode->vsync_start; 171de2362d3Smrg mode->VSyncEnd = kmode->vsync_end; 172de2362d3Smrg mode->VTotal = kmode->vtotal; 173de2362d3Smrg mode->VScan = kmode->vscan; 174de2362d3Smrg 175de2362d3Smrg mode->Flags = kmode->flags; //& FLAG_BITS; 176de2362d3Smrg mode->name = strdup(kmode->name); 177de2362d3Smrg 178de2362d3Smrg if (kmode->type & DRM_MODE_TYPE_DRIVER) 179de2362d3Smrg mode->type = M_T_DRIVER; 180de2362d3Smrg if (kmode->type & DRM_MODE_TYPE_PREFERRED) 181de2362d3Smrg mode->type |= M_T_PREFERRED; 182de2362d3Smrg xf86SetModeCrtc (mode, scrn->adjustFlags); 183de2362d3Smrg} 184de2362d3Smrg 185de2362d3Smrgstatic void 186de2362d3Smrgdrmmode_ConvertToKMode(ScrnInfoPtr scrn, 187de2362d3Smrg drmModeModeInfo *kmode, 188de2362d3Smrg DisplayModePtr mode) 189de2362d3Smrg{ 190de2362d3Smrg memset(kmode, 0, sizeof(*kmode)); 191de2362d3Smrg 192de2362d3Smrg kmode->clock = mode->Clock; 193de2362d3Smrg kmode->hdisplay = mode->HDisplay; 194de2362d3Smrg kmode->hsync_start = mode->HSyncStart; 195de2362d3Smrg kmode->hsync_end = mode->HSyncEnd; 196de2362d3Smrg kmode->htotal = mode->HTotal; 197de2362d3Smrg kmode->hskew = mode->HSkew; 198de2362d3Smrg 199de2362d3Smrg kmode->vdisplay = mode->VDisplay; 200de2362d3Smrg kmode->vsync_start = mode->VSyncStart; 201de2362d3Smrg kmode->vsync_end = mode->VSyncEnd; 202de2362d3Smrg kmode->vtotal = mode->VTotal; 203de2362d3Smrg kmode->vscan = mode->VScan; 204de2362d3Smrg 205de2362d3Smrg kmode->flags = mode->Flags; //& FLAG_BITS; 206de2362d3Smrg if (mode->name) 207de2362d3Smrg strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN); 208de2362d3Smrg kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0; 209de2362d3Smrg 210de2362d3Smrg} 211de2362d3Smrg 2128bf5c682Smrg/* 2138bf5c682Smrg * Utility helper for drmWaitVBlank 2148bf5c682Smrg */ 2158bf5c682SmrgBool 2168bf5c682Smrgdrmmode_wait_vblank(xf86CrtcPtr crtc, drmVBlankSeqType type, 2178bf5c682Smrg uint32_t target_seq, unsigned long signal, uint64_t *ust, 2188bf5c682Smrg uint32_t *result_seq) 2198bf5c682Smrg{ 2208bf5c682Smrg int crtc_id = drmmode_get_crtc_id(crtc); 2218bf5c682Smrg ScrnInfoPtr scrn = crtc->scrn; 2228bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 2238bf5c682Smrg drmVBlank vbl; 2248bf5c682Smrg 2258bf5c682Smrg if (crtc_id == 1) 2268bf5c682Smrg type |= DRM_VBLANK_SECONDARY; 2278bf5c682Smrg else if (crtc_id > 1) 2288bf5c682Smrg type |= (crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT) & 2298bf5c682Smrg DRM_VBLANK_HIGH_CRTC_MASK; 2308bf5c682Smrg 2318bf5c682Smrg vbl.request.type = type; 2328bf5c682Smrg vbl.request.sequence = target_seq; 2338bf5c682Smrg vbl.request.signal = signal; 2348bf5c682Smrg 2358bf5c682Smrg if (drmWaitVBlank(pRADEONEnt->fd, &vbl) != 0) 2368bf5c682Smrg return FALSE; 2378bf5c682Smrg 2388bf5c682Smrg if (ust) 2398bf5c682Smrg *ust = (uint64_t)vbl.reply.tval_sec * 1000000 + 2408bf5c682Smrg vbl.reply.tval_usec; 2418bf5c682Smrg if (result_seq) 2428bf5c682Smrg *result_seq = vbl.reply.sequence; 2438bf5c682Smrg 2448bf5c682Smrg return TRUE; 2458bf5c682Smrg} 2468bf5c682Smrg 24718781e08Smrg/* 24818781e08Smrg * Retrieves present time in microseconds that is compatible 24918781e08Smrg * with units used by vblank timestamps. Depending on the kernel 25018781e08Smrg * version and DRM kernel module configuration, the vblank 25118781e08Smrg * timestamp can either be in real time or monotonic time 25218781e08Smrg */ 25318781e08Smrgint drmmode_get_current_ust(int drm_fd, CARD64 *ust) 25418781e08Smrg{ 25518781e08Smrg uint64_t cap_value; 25618781e08Smrg int ret; 25718781e08Smrg struct timespec now; 25818781e08Smrg 25918781e08Smrg ret = drmGetCap(drm_fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap_value); 26018781e08Smrg if (ret || !cap_value) 26118781e08Smrg /* old kernel or drm_timestamp_monotonic turned off */ 26218781e08Smrg ret = clock_gettime(CLOCK_REALTIME, &now); 26318781e08Smrg else 26418781e08Smrg ret = clock_gettime(CLOCK_MONOTONIC, &now); 26518781e08Smrg if (ret) 26618781e08Smrg return ret; 26718781e08Smrg *ust = ((CARD64)now.tv_sec * 1000000) + ((CARD64)now.tv_nsec / 1000); 26818781e08Smrg return 0; 26918781e08Smrg} 27018781e08Smrg 27118781e08Smrg/* 27218781e08Smrg * Get current frame count and frame count timestamp of the crtc. 27318781e08Smrg */ 27418781e08Smrgint drmmode_crtc_get_ust_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc) 27518781e08Smrg{ 27618781e08Smrg ScrnInfoPtr scrn = crtc->scrn; 2778bf5c682Smrg uint32_t seq; 27818781e08Smrg 2798bf5c682Smrg if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, ust, &seq)) { 28018781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 28118781e08Smrg "get vblank counter failed: %s\n", strerror(errno)); 2828bf5c682Smrg return -1; 28318781e08Smrg } 28418781e08Smrg 2858bf5c682Smrg *msc = seq; 28618781e08Smrg 28718781e08Smrg return Success; 28818781e08Smrg} 28918781e08Smrg 290de2362d3Smrgstatic void 29118781e08Smrgdrmmode_do_crtc_dpms(xf86CrtcPtr crtc, int mode) 292de2362d3Smrg{ 293de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 29418781e08Smrg ScrnInfoPtr scrn = crtc->scrn; 2958bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 29618781e08Smrg CARD64 ust; 29718781e08Smrg int ret; 2987314432eSmrg 29918781e08Smrg if (drmmode_crtc->dpms_mode == DPMSModeOn && mode != DPMSModeOn) { 3008bf5c682Smrg uint32_t seq; 30118781e08Smrg 30239413783Smrg radeon_drm_wait_pending_flip(crtc); 30318781e08Smrg 30418781e08Smrg /* 30518781e08Smrg * On->Off transition: record the last vblank time, 30618781e08Smrg * sequence number and frame period. 30718781e08Smrg */ 3088bf5c682Smrg if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, &ust, 3098bf5c682Smrg &seq)) 31018781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 31118781e08Smrg "%s cannot get last vblank counter\n", 31218781e08Smrg __func__); 31318781e08Smrg else { 31418781e08Smrg CARD64 nominal_frame_rate, pix_in_frame; 31518781e08Smrg 31618781e08Smrg drmmode_crtc->dpms_last_ust = ust; 31718781e08Smrg drmmode_crtc->dpms_last_seq = seq; 31818781e08Smrg nominal_frame_rate = crtc->mode.Clock; 31918781e08Smrg nominal_frame_rate *= 1000; 32018781e08Smrg pix_in_frame = crtc->mode.HTotal * crtc->mode.VTotal; 32118781e08Smrg if (nominal_frame_rate == 0 || pix_in_frame == 0) 32218781e08Smrg nominal_frame_rate = DEFAULT_NOMINAL_FRAME_RATE; 32318781e08Smrg else 32418781e08Smrg nominal_frame_rate /= pix_in_frame; 32518781e08Smrg drmmode_crtc->dpms_last_fps = nominal_frame_rate; 32618781e08Smrg } 32739413783Smrg 32839413783Smrg drmmode_crtc->dpms_mode = mode; 32939413783Smrg radeon_drm_queue_handle_deferred(crtc); 33018781e08Smrg } else if (drmmode_crtc->dpms_mode != DPMSModeOn && mode == DPMSModeOn) { 33118781e08Smrg /* 33218781e08Smrg * Off->On transition: calculate and accumulate the 33318781e08Smrg * number of interpolated vblanks while we were in Off state 33418781e08Smrg */ 3358bf5c682Smrg ret = drmmode_get_current_ust(pRADEONEnt->fd, &ust); 33618781e08Smrg if (ret) 33718781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 33818781e08Smrg "%s cannot get current time\n", __func__); 33918781e08Smrg else if (drmmode_crtc->dpms_last_ust) { 34018781e08Smrg CARD64 time_elapsed, delta_seq; 34118781e08Smrg time_elapsed = ust - drmmode_crtc->dpms_last_ust; 34218781e08Smrg delta_seq = time_elapsed * drmmode_crtc->dpms_last_fps; 34318781e08Smrg delta_seq /= 1000000; 34418781e08Smrg drmmode_crtc->interpolated_vblanks += delta_seq; 34518781e08Smrg 34618781e08Smrg } 34739413783Smrg 34839413783Smrg drmmode_crtc->dpms_mode = DPMSModeOn; 3497821949aSmrg } 35018781e08Smrg} 35118781e08Smrg 35218781e08Smrgstatic void 35318781e08Smrgdrmmode_crtc_dpms(xf86CrtcPtr crtc, int mode) 35418781e08Smrg{ 35518781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 3568bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn); 35718781e08Smrg 35818781e08Smrg /* Disable unused CRTCs */ 35918781e08Smrg if (!crtc->enabled || mode != DPMSModeOn) { 36039413783Smrg drmmode_do_crtc_dpms(crtc, DPMSModeOff); 3618bf5c682Smrg drmModeSetCrtc(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 36218781e08Smrg 0, 0, 0, NULL, 0, NULL); 3638bf5c682Smrg drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, NULL); 36418781e08Smrg } else if (drmmode_crtc->dpms_mode != DPMSModeOn) 36518781e08Smrg crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation, 36618781e08Smrg crtc->x, crtc->y); 367de2362d3Smrg} 368de2362d3Smrg 369de2362d3Smrgstatic PixmapPtr 370de2362d3Smrgcreate_pixmap_for_fbcon(drmmode_ptr drmmode, 371de2362d3Smrg ScrnInfoPtr pScrn, int fbcon_id) 372de2362d3Smrg{ 3738bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 37418781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 37518781e08Smrg PixmapPtr pixmap = info->fbcon_pixmap; 37639413783Smrg struct radeon_buffer *bo; 377de2362d3Smrg drmModeFBPtr fbcon; 378de2362d3Smrg struct drm_gem_flink flink; 379de2362d3Smrg 38018781e08Smrg if (pixmap) 38118781e08Smrg return pixmap; 38218781e08Smrg 3838bf5c682Smrg fbcon = drmModeGetFB(pRADEONEnt->fd, fbcon_id); 38439413783Smrg if (!fbcon) 385de2362d3Smrg return NULL; 386de2362d3Smrg 387de2362d3Smrg if (fbcon->depth != pScrn->depth || 388de2362d3Smrg fbcon->width != pScrn->virtualX || 389de2362d3Smrg fbcon->height != pScrn->virtualY) 390de2362d3Smrg goto out_free_fb; 391de2362d3Smrg 392de2362d3Smrg flink.handle = fbcon->handle; 3938bf5c682Smrg if (ioctl(pRADEONEnt->fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) { 394de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 395de2362d3Smrg "Couldn't flink fbcon handle\n"); 396de2362d3Smrg goto out_free_fb; 397de2362d3Smrg } 398de2362d3Smrg 39939413783Smrg bo = calloc(1, sizeof(struct radeon_buffer)); 40039413783Smrg if (!bo) { 401de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 40239413783Smrg "Couldn't allocate BO for fbcon handle\n"); 40339413783Smrg goto out_free_fb; 40439413783Smrg } 40539413783Smrg bo->ref_count = 1; 40639413783Smrg 40739413783Smrg bo->bo.radeon = radeon_bo_open(drmmode->bufmgr, flink.name, 0, 0, 0, 0); 40839413783Smrg if (!bo) { 40939413783Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 41039413783Smrg "Couldn't open BO for fbcon handle\n"); 411de2362d3Smrg goto out_free_fb; 412de2362d3Smrg } 413de2362d3Smrg 414de2362d3Smrg pixmap = drmmode_create_bo_pixmap(pScrn, fbcon->width, fbcon->height, 41518781e08Smrg fbcon->depth, fbcon->bpp, fbcon->pitch, 41639413783Smrg bo); 41718781e08Smrg info->fbcon_pixmap = pixmap; 41839413783Smrg radeon_buffer_unref(&bo); 419de2362d3Smrgout_free_fb: 420de2362d3Smrg drmModeFreeFB(fbcon); 421de2362d3Smrg return pixmap; 422de2362d3Smrg} 423de2362d3Smrg 42418781e08Smrgstatic void 42518781e08Smrgdestroy_pixmap_for_fbcon(ScrnInfoPtr pScrn) 42618781e08Smrg{ 42718781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 42818781e08Smrg 42918781e08Smrg /* XXX: The current GPUVM support in the kernel doesn't allow removing 43018781e08Smrg * the virtual address range for this BO, so we need to keep around 43118781e08Smrg * the pixmap to avoid breaking glamor with GPUVM 43239413783Smrg * 43339413783Smrg * Similarly, need to keep around the pixmap with current glamor, to 43439413783Smrg * avoid issues due to a GEM handle lifetime conflict between us and 43539413783Smrg * Mesa 43618781e08Smrg */ 43739413783Smrg if (info->use_glamor && 43839413783Smrg (info->ChipFamily >= CHIP_FAMILY_CAYMAN || 43939413783Smrg xorgGetVersion() >= XORG_VERSION_NUMERIC(1,19,99,1,0))) 44018781e08Smrg return; 44118781e08Smrg 44218781e08Smrg if (info->fbcon_pixmap) 44318781e08Smrg pScrn->pScreen->DestroyPixmap(info->fbcon_pixmap); 44418781e08Smrg info->fbcon_pixmap = NULL; 44518781e08Smrg} 44618781e08Smrg 447de2362d3Smrgvoid drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 448de2362d3Smrg{ 449de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 450de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 451de2362d3Smrg ScreenPtr pScreen = pScrn->pScreen; 4528bf5c682Smrg PixmapPtr src, dst = pScreen->GetScreenPixmap(pScreen); 4538bf5c682Smrg struct drmmode_fb *fb = radeon_pixmap_get_fb(dst); 454de2362d3Smrg int fbcon_id = 0; 45518781e08Smrg Bool force; 45618781e08Smrg GCPtr gc; 457de2362d3Smrg int i; 458de2362d3Smrg 459de2362d3Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 460de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[i]->driver_private; 461de2362d3Smrg 462de2362d3Smrg if (drmmode_crtc->mode_crtc->buffer_id) 463de2362d3Smrg fbcon_id = drmmode_crtc->mode_crtc->buffer_id; 464de2362d3Smrg } 465de2362d3Smrg 466de2362d3Smrg if (!fbcon_id) 46718781e08Smrg return; 46818781e08Smrg 4698bf5c682Smrg if (fbcon_id == fb->handle) { 47018781e08Smrg /* in some rare case there might be no fbcon and we might already 47118781e08Smrg * be the one with the current fb to avoid a false deadlck in 47218781e08Smrg * kernel ttm code just do nothing as anyway there is nothing 47318781e08Smrg * to do 47418781e08Smrg */ 47518781e08Smrg return; 47618781e08Smrg } 477de2362d3Smrg 478de2362d3Smrg src = create_pixmap_for_fbcon(drmmode, pScrn, fbcon_id); 479de2362d3Smrg if (!src) 48018781e08Smrg return; 4810d16fef4Smrg 48218781e08Smrg gc = GetScratchGC(pScrn->depth, pScreen); 48318781e08Smrg ValidateGC(&dst->drawable, gc); 48418781e08Smrg 48518781e08Smrg force = info->accel_state->force; 48618781e08Smrg info->accel_state->force = TRUE; 48718781e08Smrg (*gc->ops->CopyArea)(&src->drawable, &dst->drawable, gc, 0, 0, 48818781e08Smrg pScrn->virtualX, pScrn->virtualY, 0, 0); 48918781e08Smrg info->accel_state->force = force; 49018781e08Smrg 49118781e08Smrg FreeScratchGC(gc); 492de2362d3Smrg 493de2362d3Smrg pScreen->canDoBGNoneRoot = TRUE; 49418781e08Smrg destroy_pixmap_for_fbcon(pScrn); 4957821949aSmrg return; 49618781e08Smrg} 4970d16fef4Smrg 4988bf5c682Smrgvoid 49918781e08Smrgdrmmode_crtc_scanout_destroy(drmmode_ptr drmmode, 50018781e08Smrg struct drmmode_scanout *scanout) 50118781e08Smrg{ 50218781e08Smrg if (scanout->pixmap) { 50318781e08Smrg drmmode_destroy_bo_pixmap(scanout->pixmap); 50418781e08Smrg scanout->pixmap = NULL; 50518781e08Smrg } 50618781e08Smrg 50739413783Smrg radeon_buffer_unref(&scanout->bo); 50818781e08Smrg} 50918781e08Smrg 5108bf5c682Smrgvoid 51118781e08Smrgdrmmode_crtc_scanout_free(drmmode_crtc_private_ptr drmmode_crtc) 51218781e08Smrg{ 5138bf5c682Smrg drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, 5148bf5c682Smrg &drmmode_crtc->scanout[0]); 5158bf5c682Smrg drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, 5168bf5c682Smrg &drmmode_crtc->scanout[1]); 51718781e08Smrg 5188bf5c682Smrg if (drmmode_crtc->scanout_damage) 51918781e08Smrg DamageDestroy(drmmode_crtc->scanout_damage); 52018781e08Smrg} 52118781e08Smrg 5228bf5c682SmrgPixmapPtr 5233ed65abbSmrgdrmmode_crtc_scanout_create(xf86CrtcPtr crtc, struct drmmode_scanout *scanout, 5243ed65abbSmrg int width, int height) 52518781e08Smrg{ 52618781e08Smrg ScrnInfoPtr pScrn = crtc->scrn; 52718781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 52818781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 52918781e08Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 53018781e08Smrg struct radeon_surface surface; 53118781e08Smrg uint32_t tiling = RADEON_CREATE_PIXMAP_TILING_MACRO; 53218781e08Smrg int pitch; 53318781e08Smrg 5343ed65abbSmrg if (scanout->pixmap) { 53518781e08Smrg if (scanout->width == width && scanout->height == height) 5363ed65abbSmrg return scanout->pixmap; 53718781e08Smrg 53818781e08Smrg drmmode_crtc_scanout_destroy(drmmode, scanout); 53918781e08Smrg } 54018781e08Smrg 54118781e08Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) 54218781e08Smrg tiling |= RADEON_CREATE_PIXMAP_TILING_MICRO; 54318781e08Smrg scanout->bo = radeon_alloc_pixmap_bo(pScrn, width, height, pScrn->depth, 54418781e08Smrg tiling, pScrn->bitsPerPixel, 54518781e08Smrg &pitch, &surface, &tiling); 5468bf5c682Smrg if (!scanout->bo) { 5478bf5c682Smrg ErrorF("failed to create CRTC scanout BO\n"); 5488bf5c682Smrg return NULL; 54918781e08Smrg } 55018781e08Smrg 55118781e08Smrg scanout->pixmap = drmmode_create_bo_pixmap(pScrn, 55218781e08Smrg width, height, 55318781e08Smrg pScrn->depth, 55418781e08Smrg pScrn->bitsPerPixel, 55539413783Smrg pitch, scanout->bo); 5568bf5c682Smrg if (!scanout->pixmap) { 5578bf5c682Smrg ErrorF("failed to create CRTC scanout pixmap\n"); 5588bf5c682Smrg goto error; 5598bf5c682Smrg } 5608bf5c682Smrg 5618bf5c682Smrg if (radeon_pixmap_get_fb(scanout->pixmap)) { 5623ed65abbSmrg scanout->width = width; 5633ed65abbSmrg scanout->height = height; 5643ed65abbSmrg } else { 5658bf5c682Smrg ErrorF("failed to create CRTC scanout FB\n"); 5668bf5c682Smrgerror: 5673ed65abbSmrg drmmode_crtc_scanout_destroy(drmmode, scanout); 5683ed65abbSmrg } 56918781e08Smrg 57018781e08Smrg return scanout->pixmap; 57118781e08Smrg} 57218781e08Smrg 57318781e08Smrgstatic void 57418781e08Smrgradeon_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure) 57518781e08Smrg{ 5768bf5c682Smrg drmmode_crtc_private_ptr drmmode_crtc = closure; 5778bf5c682Smrg 5788bf5c682Smrg if (drmmode_crtc->ignore_damage) { 5798bf5c682Smrg RegionEmpty(&damage->damage); 5808bf5c682Smrg drmmode_crtc->ignore_damage = FALSE; 5818bf5c682Smrg return; 5828bf5c682Smrg } 5838bf5c682Smrg 58418781e08Smrg /* Only keep track of the extents */ 58518781e08Smrg RegionUninit(&damage->damage); 58618781e08Smrg damage->damage.data = NULL; 58718781e08Smrg} 58818781e08Smrg 5898bf5c682Smrgstatic void 5908bf5c682Smrgdrmmode_screen_damage_destroy(DamagePtr damage, void *closure) 5918bf5c682Smrg{ 5928bf5c682Smrg drmmode_crtc_private_ptr drmmode_crtc = closure; 5938bf5c682Smrg 5948bf5c682Smrg drmmode_crtc->scanout_damage = NULL; 5958bf5c682Smrg RegionUninit(&drmmode_crtc->scanout_last_region); 5968bf5c682Smrg} 5978bf5c682Smrg 59818781e08Smrgstatic Bool 59918781e08Smrgdrmmode_can_use_hw_cursor(xf86CrtcPtr crtc) 60018781e08Smrg{ 60118781e08Smrg RADEONInfoPtr info = RADEONPTR(crtc->scrn); 60218781e08Smrg 60318781e08Smrg /* Check for Option "SWcursor" */ 60418781e08Smrg if (xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) 60518781e08Smrg return FALSE; 60618781e08Smrg 60718781e08Smrg /* Fall back to SW cursor if the CRTC is transformed */ 60818781e08Smrg if (crtc->transformPresent) 60918781e08Smrg return FALSE; 6100d16fef4Smrg 6118bf5c682Smrg#if XF86_CRTC_VERSION < 7 61218781e08Smrg /* Xorg doesn't correctly handle cursor position transform in the 61318781e08Smrg * rotation case 61418781e08Smrg */ 61518781e08Smrg if (crtc->driverIsPerformingTransform && 61618781e08Smrg (crtc->rotation & 0xf) != RR_Rotate_0) 61718781e08Smrg return FALSE; 61818781e08Smrg#endif 61918781e08Smrg 62018781e08Smrg /* HW cursor not supported with RandR 1.4 multihead up to 1.18.99.901 */ 62118781e08Smrg if (xorgGetVersion() <= XORG_VERSION_NUMERIC(1,18,99,901,0) && 62218781e08Smrg !xorg_list_is_empty(&crtc->scrn->pScreen->pixmap_dirty_list)) 62318781e08Smrg return FALSE; 62418781e08Smrg 62518781e08Smrg return TRUE; 62618781e08Smrg} 62718781e08Smrg 6283ed65abbSmrgstatic void 6293ed65abbSmrgdrmmode_crtc_update_tear_free(xf86CrtcPtr crtc) 6303ed65abbSmrg{ 6313ed65abbSmrg RADEONInfoPtr info = RADEONPTR(crtc->scrn); 6323ed65abbSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 6333ed65abbSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 6343ed65abbSmrg int i; 6353ed65abbSmrg 6363ed65abbSmrg drmmode_crtc->tear_free = FALSE; 6373ed65abbSmrg 6383ed65abbSmrg for (i = 0; i < xf86_config->num_output; i++) { 6393ed65abbSmrg xf86OutputPtr output = xf86_config->output[i]; 6403ed65abbSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 6413ed65abbSmrg 6423ed65abbSmrg if (output->crtc != crtc) 6433ed65abbSmrg continue; 6443ed65abbSmrg 6453ed65abbSmrg if (drmmode_output->tear_free == 1 || 6463ed65abbSmrg (drmmode_output->tear_free == 2 && 6478bf5c682Smrg (crtc->scrn->pScreen->isGPU || 6483ed65abbSmrg info->shadow_primary || 6493ed65abbSmrg crtc->transformPresent || crtc->rotation != RR_Rotate_0))) { 6503ed65abbSmrg drmmode_crtc->tear_free = TRUE; 6513ed65abbSmrg return; 6523ed65abbSmrg } 6533ed65abbSmrg } 6543ed65abbSmrg} 6553ed65abbSmrg 6563ed65abbSmrg#if XF86_CRTC_VERSION < 7 6573ed65abbSmrg#define XF86DriverTransformOutput TRUE 6583ed65abbSmrg#define XF86DriverTransformNone FALSE 6593ed65abbSmrg#endif 6603ed65abbSmrg 66118781e08Smrgstatic Bool 66218781e08Smrgdrmmode_handle_transform(xf86CrtcPtr crtc) 66318781e08Smrg{ 66418781e08Smrg Bool ret; 66518781e08Smrg 6668bf5c682Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 66739413783Smrg crtc->driverIsPerformingTransform = XF86DriverTransformOutput; 6688bf5c682Smrg#else 6698bf5c682Smrg crtc->driverIsPerformingTransform = !crtc->transformPresent && 6708bf5c682Smrg (crtc->rotation & 0xf) == RR_Rotate_0; 6718bf5c682Smrg#endif 67218781e08Smrg 67318781e08Smrg ret = xf86CrtcRotate(crtc); 67418781e08Smrg 67518781e08Smrg crtc->driverIsPerformingTransform &= ret && crtc->transform_in_use; 67618781e08Smrg 67718781e08Smrg return ret; 6780d16fef4Smrg} 6790d16fef4Smrg 6803ed65abbSmrg 6813ed65abbSmrgstatic void 6823ed65abbSmrgdrmmode_crtc_prime_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode, 6838bf5c682Smrg unsigned scanout_id, struct drmmode_fb **fb, 6848bf5c682Smrg int *x, int *y) 6853ed65abbSmrg{ 6863ed65abbSmrg ScrnInfoPtr scrn = crtc->scrn; 6873ed65abbSmrg ScreenPtr screen = scrn->pScreen; 6883ed65abbSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 6893ed65abbSmrg 6903ed65abbSmrg if (drmmode_crtc->tear_free && 6913ed65abbSmrg !drmmode_crtc->scanout[1].pixmap) { 6923ed65abbSmrg RegionPtr region; 6933ed65abbSmrg BoxPtr box; 6943ed65abbSmrg 6953ed65abbSmrg drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], 6963ed65abbSmrg mode->HDisplay, 6973ed65abbSmrg mode->VDisplay); 6983ed65abbSmrg region = &drmmode_crtc->scanout_last_region; 6993ed65abbSmrg RegionUninit(region); 7003ed65abbSmrg region->data = NULL; 7013ed65abbSmrg box = RegionExtents(region); 7023ed65abbSmrg box->x1 = crtc->x; 7033ed65abbSmrg box->y1 = crtc->y; 7043ed65abbSmrg box->x2 = crtc->x + mode->HDisplay; 7053ed65abbSmrg box->y2 = crtc->y + mode->VDisplay; 7063ed65abbSmrg } 7073ed65abbSmrg 7083ed65abbSmrg if (scanout_id != drmmode_crtc->scanout_id) { 7093ed65abbSmrg PixmapDirtyUpdatePtr dirty = NULL; 7103ed65abbSmrg 7113ed65abbSmrg xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, 7123ed65abbSmrg ent) { 7138bf5c682Smrg if (radeon_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) { 7143ed65abbSmrg dirty->slave_dst = 7153ed65abbSmrg drmmode_crtc->scanout[scanout_id].pixmap; 7163ed65abbSmrg break; 7173ed65abbSmrg } 7183ed65abbSmrg } 7193ed65abbSmrg 7203ed65abbSmrg if (!drmmode_crtc->tear_free) { 7213ed65abbSmrg GCPtr gc = GetScratchGC(scrn->depth, screen); 7223ed65abbSmrg 7233ed65abbSmrg ValidateGC(&drmmode_crtc->scanout[0].pixmap->drawable, gc); 7243ed65abbSmrg gc->ops->CopyArea(&drmmode_crtc->scanout[1].pixmap->drawable, 7253ed65abbSmrg &drmmode_crtc->scanout[0].pixmap->drawable, 7263ed65abbSmrg gc, 0, 0, mode->HDisplay, mode->VDisplay, 7273ed65abbSmrg 0, 0); 7283ed65abbSmrg FreeScratchGC(gc); 72939413783Smrg radeon_finish(scrn, drmmode_crtc->scanout[0].bo); 7303ed65abbSmrg } 7313ed65abbSmrg } 7323ed65abbSmrg 7338bf5c682Smrg *fb = radeon_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap); 7343ed65abbSmrg *x = *y = 0; 7353ed65abbSmrg drmmode_crtc->scanout_id = scanout_id; 7363ed65abbSmrg} 7373ed65abbSmrg 7383ed65abbSmrg 7393ed65abbSmrgstatic void 7403ed65abbSmrgdrmmode_crtc_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode, 7418bf5c682Smrg unsigned scanout_id, struct drmmode_fb **fb, int *x, 7428bf5c682Smrg int *y) 7433ed65abbSmrg{ 7443ed65abbSmrg ScrnInfoPtr scrn = crtc->scrn; 7453ed65abbSmrg ScreenPtr screen = scrn->pScreen; 7463ed65abbSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 7473ed65abbSmrg 7488bf5c682Smrg drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[scanout_id], 7493ed65abbSmrg mode->HDisplay, mode->VDisplay); 7503ed65abbSmrg if (drmmode_crtc->tear_free) { 7518bf5c682Smrg drmmode_crtc_scanout_create(crtc, 7528bf5c682Smrg &drmmode_crtc->scanout[scanout_id ^ 1], 7533ed65abbSmrg mode->HDisplay, mode->VDisplay); 7543ed65abbSmrg } 7553ed65abbSmrg 7568bf5c682Smrg if (drmmode_crtc->scanout[scanout_id].pixmap && 7578bf5c682Smrg (!drmmode_crtc->tear_free || 7588bf5c682Smrg drmmode_crtc->scanout[scanout_id ^ 1].pixmap)) { 75939413783Smrg BoxRec extents = { .x1 = 0, .y1 = 0, 76039413783Smrg .x2 = scrn->virtualX, .y2 = scrn->virtualY }; 7613ed65abbSmrg 7623ed65abbSmrg if (!drmmode_crtc->scanout_damage) { 7633ed65abbSmrg drmmode_crtc->scanout_damage = 7643ed65abbSmrg DamageCreate(radeon_screen_damage_report, 7658bf5c682Smrg drmmode_screen_damage_destroy, 7668bf5c682Smrg DamageReportRawRegion, 7678bf5c682Smrg TRUE, screen, drmmode_crtc); 7688bf5c682Smrg DamageRegister(&screen->root->drawable, 7693ed65abbSmrg drmmode_crtc->scanout_damage); 7703ed65abbSmrg } 7713ed65abbSmrg 7728bf5c682Smrg *fb = radeon_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap); 7733ed65abbSmrg *x = *y = 0; 7743ed65abbSmrg 7758bf5c682Smrg radeon_scanout_do_update(crtc, scanout_id, 7768bf5c682Smrg screen->GetWindowPixmap(screen->root), 77739413783Smrg extents); 77839413783Smrg RegionEmpty(DamageRegion(drmmode_crtc->scanout_damage)); 77939413783Smrg radeon_finish(scrn, drmmode_crtc->scanout[scanout_id].bo); 7803ed65abbSmrg } 7813ed65abbSmrg} 7823ed65abbSmrg 7838bf5c682Smrgstatic void 7848bf5c682Smrgdrmmode_crtc_gamma_do_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, 7858bf5c682Smrg uint16_t *blue, int size) 7868bf5c682Smrg{ 7878bf5c682Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 7888bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn); 7898bf5c682Smrg 7908bf5c682Smrg drmModeCrtcSetGamma(pRADEONEnt->fd, 7918bf5c682Smrg drmmode_crtc->mode_crtc->crtc_id, size, red, green, 7928bf5c682Smrg blue); 7938bf5c682Smrg} 7948bf5c682Smrg 7958bf5c682SmrgBool 7968bf5c682Smrgdrmmode_set_mode(xf86CrtcPtr crtc, struct drmmode_fb *fb, DisplayModePtr mode, 7978bf5c682Smrg int x, int y) 7988bf5c682Smrg{ 7998bf5c682Smrg ScrnInfoPtr scrn = crtc->scrn; 8008bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 8018bf5c682Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 8028bf5c682Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 8038bf5c682Smrg uint32_t *output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); 8048bf5c682Smrg int output_count = 0; 8058bf5c682Smrg drmModeModeInfo kmode; 8068bf5c682Smrg Bool ret; 8078bf5c682Smrg int i; 8088bf5c682Smrg 8098bf5c682Smrg if (!output_ids) 8108bf5c682Smrg return FALSE; 8118bf5c682Smrg 8128bf5c682Smrg for (i = 0; i < xf86_config->num_output; i++) { 8138bf5c682Smrg xf86OutputPtr output = xf86_config->output[i]; 8148bf5c682Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 8158bf5c682Smrg 8168bf5c682Smrg if (output->crtc != crtc) 8178bf5c682Smrg continue; 8188bf5c682Smrg 8198bf5c682Smrg output_ids[output_count] = drmmode_output->mode_output->connector_id; 8208bf5c682Smrg output_count++; 8218bf5c682Smrg } 8228bf5c682Smrg 8238bf5c682Smrg drmmode_ConvertToKMode(scrn, &kmode, mode); 8248bf5c682Smrg 8258bf5c682Smrg ret = drmModeSetCrtc(pRADEONEnt->fd, 8268bf5c682Smrg drmmode_crtc->mode_crtc->crtc_id, 8278bf5c682Smrg fb->handle, x, y, output_ids, 8288bf5c682Smrg output_count, &kmode) == 0; 8298bf5c682Smrg 8308bf5c682Smrg if (ret) { 8318bf5c682Smrg drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, fb); 8328bf5c682Smrg } else { 8338bf5c682Smrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 8348bf5c682Smrg "failed to set mode: %s\n", strerror(errno)); 8358bf5c682Smrg } 8368bf5c682Smrg 8378bf5c682Smrg free(output_ids); 8388bf5c682Smrg return ret; 8398bf5c682Smrg} 8408bf5c682Smrg 841de2362d3Smrgstatic Bool 842de2362d3Smrgdrmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, 843de2362d3Smrg Rotation rotation, int x, int y) 844de2362d3Smrg{ 845de2362d3Smrg ScrnInfoPtr pScrn = crtc->scrn; 84618781e08Smrg ScreenPtr pScreen = pScrn->pScreen; 847de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 8488bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 849de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 850de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 8513ed65abbSmrg unsigned scanout_id = 0; 852de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 853de2362d3Smrg int saved_x, saved_y; 854de2362d3Smrg Rotation saved_rotation; 855de2362d3Smrg DisplayModeRec saved_mode; 85618781e08Smrg Bool ret = FALSE; 857de2362d3Smrg int i; 8588bf5c682Smrg struct drmmode_fb *fb = NULL; 8598bf5c682Smrg 8608bf5c682Smrg /* The root window contents may be undefined before the WindowExposures 8618bf5c682Smrg * hook is called for it, so bail if we get here before that 8628bf5c682Smrg */ 8638bf5c682Smrg if (pScreen->WindowExposures == RADEONWindowExposures_oneshot) 8648bf5c682Smrg return FALSE; 865de2362d3Smrg 866de2362d3Smrg saved_mode = crtc->mode; 867de2362d3Smrg saved_x = crtc->x; 868de2362d3Smrg saved_y = crtc->y; 869de2362d3Smrg saved_rotation = crtc->rotation; 870de2362d3Smrg 871de2362d3Smrg if (mode) { 872de2362d3Smrg crtc->mode = *mode; 873de2362d3Smrg crtc->x = x; 874de2362d3Smrg crtc->y = y; 875de2362d3Smrg crtc->rotation = rotation; 876de2362d3Smrg 87718781e08Smrg if (!drmmode_handle_transform(crtc)) 878de2362d3Smrg goto done; 87918781e08Smrg 8803ed65abbSmrg drmmode_crtc_update_tear_free(crtc); 8813ed65abbSmrg if (drmmode_crtc->tear_free) 8823ed65abbSmrg scanout_id = drmmode_crtc->scanout_id; 88339413783Smrg else 88439413783Smrg drmmode_crtc->scanout_id = 0; 885de2362d3Smrg 8868bf5c682Smrg if (drmmode_crtc->prime_scanout_pixmap) { 8873ed65abbSmrg drmmode_crtc_prime_scanout_update(crtc, mode, scanout_id, 8888bf5c682Smrg &fb, &x, &y); 8898bf5c682Smrg } else if (drmmode_crtc->rotate.pixmap) { 8908bf5c682Smrg fb = radeon_pixmap_get_fb(drmmode_crtc->rotate.pixmap); 89118781e08Smrg x = y = 0; 89218781e08Smrg 8938bf5c682Smrg } else if (!pScreen->isGPU && 8943ed65abbSmrg (drmmode_crtc->tear_free || 89518781e08Smrg crtc->driverIsPerformingTransform || 89618781e08Smrg info->shadow_primary)) { 8973ed65abbSmrg drmmode_crtc_scanout_update(crtc, mode, scanout_id, 8988bf5c682Smrg &fb, &x, &y); 899de2362d3Smrg } 90018781e08Smrg 9018bf5c682Smrg if (!fb) 9028bf5c682Smrg fb = radeon_pixmap_get_fb(pScreen->GetWindowPixmap(pScreen->root)); 9038bf5c682Smrg if (!fb) { 9048bf5c682Smrg fb = radeon_fb_create(pScrn, pRADEONEnt->fd, 9058bf5c682Smrg pScrn->virtualX, pScrn->virtualY, 9068bf5c682Smrg pScrn->displayWidth * info->pixel_bytes, 90739413783Smrg info->front_buffer->bo.radeon->handle); 9088bf5c682Smrg /* Prevent refcnt of ad-hoc FBs from reaching 2 */ 9098bf5c682Smrg drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, NULL); 9108bf5c682Smrg drmmode_crtc->fb = fb; 9118bf5c682Smrg } 9128bf5c682Smrg if (!fb) { 9138bf5c682Smrg ErrorF("failed to add FB for modeset\n"); 9148bf5c682Smrg goto done; 91518781e08Smrg } 91618781e08Smrg 91739413783Smrg radeon_drm_wait_pending_flip(crtc); 9188bf5c682Smrg 9198bf5c682Smrg if (!drmmode_set_mode(crtc, fb, mode, x, y)) 92018781e08Smrg goto done; 9218bf5c682Smrg 9228bf5c682Smrg ret = TRUE; 923de2362d3Smrg 92418781e08Smrg if (pScreen) 92518781e08Smrg xf86CrtcSetScreenSubpixelOrder(pScreen); 92618781e08Smrg 92718781e08Smrg drmmode_crtc->need_modeset = FALSE; 92818781e08Smrg 929de2362d3Smrg /* go through all the outputs and force DPMS them back on? */ 930de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 931de2362d3Smrg xf86OutputPtr output = xf86_config->output[i]; 932de2362d3Smrg 933de2362d3Smrg if (output->crtc != crtc) 934de2362d3Smrg continue; 935de2362d3Smrg 936de2362d3Smrg output->funcs->dpms(output, DPMSModeOn); 937de2362d3Smrg } 938de2362d3Smrg } 939de2362d3Smrg 94018781e08Smrg /* Compute index of this CRTC into xf86_config->crtc */ 94118781e08Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 94218781e08Smrg if (xf86_config->crtc[i] != crtc) 94318781e08Smrg continue; 94418781e08Smrg 94518781e08Smrg if (!crtc->enabled || drmmode_can_use_hw_cursor(crtc)) 94618781e08Smrg info->hwcursor_disabled &= ~(1 << i); 94718781e08Smrg else 94818781e08Smrg info->hwcursor_disabled |= 1 << i; 94918781e08Smrg 95018781e08Smrg break; 95118781e08Smrg } 95218781e08Smrg 95318781e08Smrg#ifndef HAVE_XF86_CURSOR_RESET_CURSOR 95418781e08Smrg if (!info->hwcursor_disabled) 95518781e08Smrg xf86_reload_cursors(pScreen); 95618781e08Smrg#endif 957de2362d3Smrg 958de2362d3Smrgdone: 959de2362d3Smrg if (!ret) { 960de2362d3Smrg crtc->x = saved_x; 961de2362d3Smrg crtc->y = saved_y; 962de2362d3Smrg crtc->rotation = saved_rotation; 963de2362d3Smrg crtc->mode = saved_mode; 96418781e08Smrg } else { 9657821949aSmrg crtc->active = TRUE; 96618781e08Smrg 9678bf5c682Smrg if (drmmode_crtc->scanout[scanout_id].pixmap && 9688bf5c682Smrg fb != radeon_pixmap_get_fb(drmmode_crtc-> 96939413783Smrg scanout[scanout_id].pixmap)) { 97039413783Smrg radeon_drm_abort_entry(drmmode_crtc->scanout_update_pending); 97139413783Smrg drmmode_crtc->scanout_update_pending = 0; 97218781e08Smrg drmmode_crtc_scanout_free(drmmode_crtc); 97339413783Smrg } else if (!drmmode_crtc->tear_free) { 9743ed65abbSmrg drmmode_crtc_scanout_destroy(drmmode, 9753ed65abbSmrg &drmmode_crtc->scanout[1]); 9763ed65abbSmrg } 97718781e08Smrg } 97818781e08Smrg 97939413783Smrg radeon_drm_queue_handle_deferred(crtc); 980de2362d3Smrg return ret; 981de2362d3Smrg} 982de2362d3Smrg 983de2362d3Smrgstatic void 984de2362d3Smrgdrmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg) 985de2362d3Smrg{ 986de2362d3Smrg 987de2362d3Smrg} 988de2362d3Smrg 989de2362d3Smrgstatic void 990de2362d3Smrgdrmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y) 991de2362d3Smrg{ 992de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 9938bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn); 994de2362d3Smrg 9958bf5c682Smrg#if XF86_CRTC_VERSION < 7 99618781e08Smrg if (crtc->driverIsPerformingTransform) { 99718781e08Smrg x += crtc->x; 99818781e08Smrg y += crtc->y; 99918781e08Smrg xf86CrtcTransformCursorPos(crtc, &x, &y); 100018781e08Smrg } 100118781e08Smrg#endif 100218781e08Smrg 10038bf5c682Smrg drmModeMoveCursor(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id, x, y); 1004de2362d3Smrg} 1005de2362d3Smrg 10068bf5c682Smrg#if XF86_CRTC_VERSION < 7 100718781e08Smrg 100818781e08Smrgstatic int 100918781e08Smrgdrmmode_cursor_src_offset(Rotation rotation, int width, int height, 101018781e08Smrg int x_dst, int y_dst) 101118781e08Smrg{ 101218781e08Smrg int t; 101318781e08Smrg 101418781e08Smrg switch (rotation & 0xf) { 101518781e08Smrg case RR_Rotate_90: 101618781e08Smrg t = x_dst; 101718781e08Smrg x_dst = height - y_dst - 1; 101818781e08Smrg y_dst = t; 101918781e08Smrg break; 102018781e08Smrg case RR_Rotate_180: 102118781e08Smrg x_dst = width - x_dst - 1; 102218781e08Smrg y_dst = height - y_dst - 1; 102318781e08Smrg break; 102418781e08Smrg case RR_Rotate_270: 102518781e08Smrg t = x_dst; 102618781e08Smrg x_dst = y_dst; 102718781e08Smrg y_dst = width - t - 1; 102818781e08Smrg break; 102918781e08Smrg } 103018781e08Smrg 103118781e08Smrg if (rotation & RR_Reflect_X) 103218781e08Smrg x_dst = width - x_dst - 1; 103318781e08Smrg if (rotation & RR_Reflect_Y) 103418781e08Smrg y_dst = height - y_dst - 1; 103518781e08Smrg 103618781e08Smrg return y_dst * height + x_dst; 103718781e08Smrg} 103818781e08Smrg 103918781e08Smrg#endif 104018781e08Smrg 10418bf5c682Smrgstatic uint32_t 10428bf5c682Smrgdrmmode_cursor_gamma(xf86CrtcPtr crtc, uint32_t argb) 10438bf5c682Smrg{ 10448bf5c682Smrg uint32_t alpha = argb >> 24; 10458bf5c682Smrg uint32_t rgb[3]; 10468bf5c682Smrg int i; 10478bf5c682Smrg 10488bf5c682Smrg if (!alpha) 10498bf5c682Smrg return 0; 10508bf5c682Smrg 10518bf5c682Smrg if (crtc->scrn->depth != 24 && crtc->scrn->depth != 32) 10528bf5c682Smrg return argb; 10538bf5c682Smrg 10548bf5c682Smrg /* Un-premultiply alpha */ 10558bf5c682Smrg for (i = 0; i < 3; i++) 10568bf5c682Smrg rgb[i] = ((argb >> (i * 8)) & 0xff) * 0xff / alpha; 10578bf5c682Smrg 10588bf5c682Smrg /* Apply gamma correction and pre-multiply alpha */ 10598bf5c682Smrg rgb[0] = (crtc->gamma_blue[rgb[0]] >> 8) * alpha / 0xff; 10608bf5c682Smrg rgb[1] = (crtc->gamma_green[rgb[1]] >> 8) * alpha / 0xff; 10618bf5c682Smrg rgb[2] = (crtc->gamma_red[rgb[2]] >> 8) * alpha / 0xff; 10628bf5c682Smrg 10638bf5c682Smrg return alpha << 24 | rgb[2] << 16 | rgb[1] << 8 | rgb[0]; 10648bf5c682Smrg} 10658bf5c682Smrg 1066de2362d3Smrgstatic void 1067de2362d3Smrgdrmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image) 1068de2362d3Smrg{ 106918781e08Smrg ScrnInfoPtr pScrn = crtc->scrn; 107018781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1071de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1072de2362d3Smrg uint32_t *ptr; 1073de2362d3Smrg 1074de2362d3Smrg /* cursor should be mapped already */ 1075de2362d3Smrg ptr = (uint32_t *)(drmmode_crtc->cursor_bo->ptr); 1076de2362d3Smrg 10778bf5c682Smrg#if XF86_CRTC_VERSION < 7 107818781e08Smrg if (crtc->driverIsPerformingTransform) { 107918781e08Smrg uint32_t cursor_w = info->cursor_w, cursor_h = info->cursor_h; 108018781e08Smrg int dstx, dsty; 108118781e08Smrg int srcoffset; 108218781e08Smrg 108318781e08Smrg for (dsty = 0; dsty < cursor_h; dsty++) { 108418781e08Smrg for (dstx = 0; dstx < cursor_w; dstx++) { 108518781e08Smrg srcoffset = drmmode_cursor_src_offset(crtc->rotation, 108618781e08Smrg cursor_w, 108718781e08Smrg cursor_h, 108818781e08Smrg dstx, dsty); 108918781e08Smrg 109018781e08Smrg ptr[dsty * info->cursor_w + dstx] = 10918bf5c682Smrg cpu_to_le32(drmmode_cursor_gamma(crtc, 10928bf5c682Smrg image[srcoffset])); 109318781e08Smrg } 109418781e08Smrg } 109518781e08Smrg } else 109618781e08Smrg#endif 109718781e08Smrg { 109818781e08Smrg uint32_t cursor_size = info->cursor_w * info->cursor_h; 109918781e08Smrg int i; 110018781e08Smrg 110118781e08Smrg for (i = 0; i < cursor_size; i++) 11028bf5c682Smrg ptr[i] = cpu_to_le32(drmmode_cursor_gamma(crtc, image[i])); 110318781e08Smrg } 1104de2362d3Smrg} 1105de2362d3Smrg 110618781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 110718781e08Smrg 110818781e08Smrgstatic Bool drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 * image) 110918781e08Smrg{ 111018781e08Smrg if (!drmmode_can_use_hw_cursor(crtc)) 111118781e08Smrg return FALSE; 111218781e08Smrg 111318781e08Smrg drmmode_load_cursor_argb(crtc, image); 111418781e08Smrg return TRUE; 111518781e08Smrg} 111618781e08Smrg 111718781e08Smrg#endif 1118de2362d3Smrg 1119de2362d3Smrgstatic void 1120de2362d3Smrgdrmmode_hide_cursor (xf86CrtcPtr crtc) 1121de2362d3Smrg{ 112218781e08Smrg ScrnInfoPtr pScrn = crtc->scrn; 112318781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1124de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 11258bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 1126de2362d3Smrg 11278bf5c682Smrg drmModeSetCursor(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 112818781e08Smrg info->cursor_w, info->cursor_h); 1129de2362d3Smrg 1130de2362d3Smrg} 1131de2362d3Smrg 1132de2362d3Smrgstatic void 1133de2362d3Smrgdrmmode_show_cursor (xf86CrtcPtr crtc) 1134de2362d3Smrg{ 113518781e08Smrg ScrnInfoPtr pScrn = crtc->scrn; 113618781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1137de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 11388bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 1139de2362d3Smrg uint32_t handle = drmmode_crtc->cursor_bo->handle; 114018781e08Smrg static Bool use_set_cursor2 = TRUE; 114118781e08Smrg 114218781e08Smrg if (use_set_cursor2) { 114318781e08Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 114418781e08Smrg CursorPtr cursor = xf86_config->cursor; 114518781e08Smrg int xhot = cursor->bits->xhot; 114618781e08Smrg int yhot = cursor->bits->yhot; 114718781e08Smrg int ret; 114818781e08Smrg 114918781e08Smrg if (crtc->rotation != RR_Rotate_0 && 115018781e08Smrg crtc->rotation != (RR_Rotate_180 | RR_Reflect_X | 115118781e08Smrg RR_Reflect_Y)) { 115218781e08Smrg int t; 115318781e08Smrg 115418781e08Smrg /* Reflect & rotate hotspot position */ 115518781e08Smrg if (crtc->rotation & RR_Reflect_X) 115618781e08Smrg xhot = info->cursor_w - xhot - 1; 115718781e08Smrg if (crtc->rotation & RR_Reflect_Y) 115818781e08Smrg yhot = info->cursor_h - yhot - 1; 115918781e08Smrg 116018781e08Smrg switch (crtc->rotation & 0xf) { 116118781e08Smrg case RR_Rotate_90: 116218781e08Smrg t = xhot; 116318781e08Smrg xhot = yhot; 116418781e08Smrg yhot = info->cursor_w - t - 1; 116518781e08Smrg break; 116618781e08Smrg case RR_Rotate_180: 116718781e08Smrg xhot = info->cursor_w - xhot - 1; 116818781e08Smrg yhot = info->cursor_h - yhot - 1; 116918781e08Smrg break; 117018781e08Smrg case RR_Rotate_270: 117118781e08Smrg t = xhot; 117218781e08Smrg xhot = info->cursor_h - yhot - 1; 117318781e08Smrg yhot = t; 117418781e08Smrg } 117518781e08Smrg } 11767314432eSmrg 117718781e08Smrg ret = 11788bf5c682Smrg drmModeSetCursor2(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 117918781e08Smrg handle, info->cursor_w, info->cursor_h, 118018781e08Smrg xhot, yhot); 118118781e08Smrg if (ret == -EINVAL) 118218781e08Smrg use_set_cursor2 = FALSE; 118318781e08Smrg else 118418781e08Smrg return; 118518781e08Smrg } 118618781e08Smrg 11878bf5c682Smrg drmModeSetCursor(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id, handle, 118818781e08Smrg info->cursor_w, info->cursor_h); 1189de2362d3Smrg} 1190de2362d3Smrg 11913ed65abbSmrg/* Xorg expects a non-NULL return value from drmmode_crtc_shadow_allocate, and 11923ed65abbSmrg * passes that back to drmmode_crtc_scanout_create; it doesn't use it for 11933ed65abbSmrg * anything else. 11943ed65abbSmrg */ 1195de2362d3Smrgstatic void * 1196de2362d3Smrgdrmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) 1197de2362d3Smrg{ 1198de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 11997821949aSmrg 12003ed65abbSmrg if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width, 12013ed65abbSmrg height)) 12023ed65abbSmrg return NULL; 12033ed65abbSmrg 12043ed65abbSmrg return (void*)~0UL; 1205de2362d3Smrg} 1206de2362d3Smrg 1207de2362d3Smrgstatic PixmapPtr 1208de2362d3Smrgdrmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) 1209de2362d3Smrg{ 1210de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1211de2362d3Smrg 12123ed65abbSmrg if (!data) { 12133ed65abbSmrg drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width, 12143ed65abbSmrg height); 12153ed65abbSmrg } 12163ed65abbSmrg 12173ed65abbSmrg return drmmode_crtc->rotate.pixmap; 1218de2362d3Smrg} 1219de2362d3Smrg 1220de2362d3Smrgstatic void 12217821949aSmrgdrmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) 1222de2362d3Smrg{ 1223de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1224de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 1225de2362d3Smrg 122618781e08Smrg drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->rotate); 12277821949aSmrg} 1228de2362d3Smrg 12297821949aSmrgstatic void 12307821949aSmrgdrmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, 12317821949aSmrg uint16_t *blue, int size) 12327821949aSmrg{ 12338bf5c682Smrg ScrnInfoPtr scrn = crtc->scrn; 12348bf5c682Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 12358bf5c682Smrg RADEONInfoPtr info = RADEONPTR(scrn); 12368bf5c682Smrg int i; 12378bf5c682Smrg 12388bf5c682Smrg drmmode_crtc_gamma_do_set(crtc, red, green, blue, size); 12398bf5c682Smrg 12408bf5c682Smrg /* Compute index of this CRTC into xf86_config->crtc */ 12418bf5c682Smrg for (i = 0; xf86_config->crtc[i] != crtc; i++) {} 12428bf5c682Smrg 12438bf5c682Smrg if (info->hwcursor_disabled & (1 << i)) 12448bf5c682Smrg return; 12457314432eSmrg 12468bf5c682Smrg#ifdef HAVE_XF86_CURSOR_RESET_CURSOR 12478bf5c682Smrg xf86CursorResetCursor(scrn->pScreen); 12488bf5c682Smrg#else 12498bf5c682Smrg xf86_reload_cursors(scrn->pScreen); 12508bf5c682Smrg#endif 125118781e08Smrg} 125218781e08Smrg 125318781e08Smrgstatic Bool 125418781e08Smrgdrmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) 125518781e08Smrg{ 125618781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 12573ed65abbSmrg unsigned scanout_id = drmmode_crtc->scanout_id; 125818781e08Smrg ScreenPtr screen = crtc->scrn->pScreen; 125918781e08Smrg PixmapDirtyUpdatePtr dirty; 126018781e08Smrg 126118781e08Smrg xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { 12628bf5c682Smrg if (radeon_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) { 12638bf5c682Smrg PixmapStopDirtyTracking(dirty->src, dirty->slave_dst); 12648bf5c682Smrg break; 12658bf5c682Smrg } 126618781e08Smrg } 126718781e08Smrg 12688bf5c682Smrg drmmode_crtc_scanout_free(drmmode_crtc); 12698bf5c682Smrg drmmode_crtc->prime_scanout_pixmap = NULL; 12708bf5c682Smrg 127118781e08Smrg if (!ppix) 127218781e08Smrg return TRUE; 127318781e08Smrg 127418781e08Smrg if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[0], 127518781e08Smrg ppix->drawable.width, 127618781e08Smrg ppix->drawable.height)) 127718781e08Smrg return FALSE; 127818781e08Smrg 12793ed65abbSmrg if (drmmode_crtc->tear_free && 128018781e08Smrg !drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], 128118781e08Smrg ppix->drawable.width, 128218781e08Smrg ppix->drawable.height)) { 128318781e08Smrg drmmode_crtc_scanout_free(drmmode_crtc); 128418781e08Smrg return FALSE; 128518781e08Smrg } 128618781e08Smrg 12878bf5c682Smrg drmmode_crtc->prime_scanout_pixmap = ppix; 12888bf5c682Smrg 12898bf5c682Smrg#ifdef HAS_DIRTYTRACKING_DRAWABLE_SRC 12908bf5c682Smrg PixmapStartDirtyTracking(&ppix->drawable, 12918bf5c682Smrg drmmode_crtc->scanout[scanout_id].pixmap, 12928bf5c682Smrg 0, 0, 0, 0, RR_Rotate_0); 12938bf5c682Smrg#elif defined(HAS_DIRTYTRACKING_ROTATION) 12943ed65abbSmrg PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 129518781e08Smrg 0, 0, 0, 0, RR_Rotate_0); 129618781e08Smrg#elif defined(HAS_DIRTYTRACKING2) 12973ed65abbSmrg PixmapStartDirtyTracking2(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 129818781e08Smrg 0, 0, 0, 0); 129918781e08Smrg#else 13003ed65abbSmrg PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 0, 0); 130118781e08Smrg#endif 130218781e08Smrg return TRUE; 1303de2362d3Smrg} 1304de2362d3Smrg 130518781e08Smrgstatic xf86CrtcFuncsRec drmmode_crtc_funcs = { 1306de2362d3Smrg .dpms = drmmode_crtc_dpms, 1307de2362d3Smrg .set_mode_major = drmmode_set_mode_major, 1308de2362d3Smrg .set_cursor_colors = drmmode_set_cursor_colors, 1309de2362d3Smrg .set_cursor_position = drmmode_set_cursor_position, 1310de2362d3Smrg .show_cursor = drmmode_show_cursor, 1311de2362d3Smrg .hide_cursor = drmmode_hide_cursor, 1312de2362d3Smrg .load_cursor_argb = drmmode_load_cursor_argb, 131318781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 131418781e08Smrg .load_cursor_argb_check = drmmode_load_cursor_argb_check, 131518781e08Smrg#endif 1316de2362d3Smrg 1317de2362d3Smrg .gamma_set = drmmode_crtc_gamma_set, 1318de2362d3Smrg .shadow_create = drmmode_crtc_shadow_create, 1319de2362d3Smrg .shadow_allocate = drmmode_crtc_shadow_allocate, 1320de2362d3Smrg .shadow_destroy = drmmode_crtc_shadow_destroy, 1321de2362d3Smrg .destroy = NULL, /* XXX */ 132218781e08Smrg .set_scanout_pixmap = drmmode_set_scanout_pixmap, 1323de2362d3Smrg}; 1324de2362d3Smrg 1325de2362d3Smrgint drmmode_get_crtc_id(xf86CrtcPtr crtc) 1326de2362d3Smrg{ 1327de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1328de2362d3Smrg return drmmode_crtc->hw_id; 1329de2362d3Smrg} 1330de2362d3Smrg 1331de2362d3Smrgvoid drmmode_crtc_hw_id(xf86CrtcPtr crtc) 1332de2362d3Smrg{ 1333de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 13348bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn); 1335de2362d3Smrg struct drm_radeon_info ginfo; 1336de2362d3Smrg int r; 1337de2362d3Smrg uint32_t tmp; 1338de2362d3Smrg 1339de2362d3Smrg memset(&ginfo, 0, sizeof(ginfo)); 1340de2362d3Smrg ginfo.request = 0x4; 1341de2362d3Smrg tmp = drmmode_crtc->mode_crtc->crtc_id; 1342de2362d3Smrg ginfo.value = (uintptr_t)&tmp; 13438bf5c682Smrg r = drmCommandWriteRead(pRADEONEnt->fd, DRM_RADEON_INFO, &ginfo, sizeof(ginfo)); 1344de2362d3Smrg if (r) { 1345de2362d3Smrg drmmode_crtc->hw_id = -1; 1346de2362d3Smrg return; 1347de2362d3Smrg } 1348de2362d3Smrg drmmode_crtc->hw_id = tmp; 1349de2362d3Smrg} 1350de2362d3Smrg 135118781e08Smrgstatic unsigned int 135218781e08Smrgdrmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num) 1353de2362d3Smrg{ 1354de2362d3Smrg xf86CrtcPtr crtc; 1355de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc; 135618781e08Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 13578bf5c682Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1358de2362d3Smrg 13598bf5c682Smrg crtc = xf86CrtcCreate(pScrn, &info->drmmode_crtc_funcs); 136039413783Smrg if (!crtc) 136118781e08Smrg return 0; 1362de2362d3Smrg 1363de2362d3Smrg drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1); 13648bf5c682Smrg drmmode_crtc->mode_crtc = drmModeGetCrtc(pRADEONEnt->fd, mode_res->crtcs[num]); 1365de2362d3Smrg drmmode_crtc->drmmode = drmmode; 136618781e08Smrg drmmode_crtc->dpms_mode = DPMSModeOff; 1367de2362d3Smrg crtc->driver_private = drmmode_crtc; 1368de2362d3Smrg drmmode_crtc_hw_id(crtc); 1369de2362d3Smrg 137018781e08Smrg /* Mark num'th crtc as in use on this device. */ 137118781e08Smrg pRADEONEnt->assigned_crtcs |= (1 << num); 137218781e08Smrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 137318781e08Smrg "Allocated crtc nr. %d to this screen.\n", num); 137418781e08Smrg 137518781e08Smrg return 1; 1376de2362d3Smrg} 1377de2362d3Smrg 13788bf5c682Smrg/* 13798bf5c682Smrg * Update all of the property values for an output 13808bf5c682Smrg */ 13818bf5c682Smrgstatic void 13828bf5c682Smrgdrmmode_output_update_properties(xf86OutputPtr output) 13838bf5c682Smrg{ 13848bf5c682Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 13858bf5c682Smrg int i, j, k; 13868bf5c682Smrg int err; 13878bf5c682Smrg drmModeConnectorPtr koutput; 13888bf5c682Smrg 13898bf5c682Smrg /* Use the most recently fetched values from the kernel */ 13908bf5c682Smrg koutput = drmmode_output->mode_output; 13918bf5c682Smrg 13928bf5c682Smrg if (!koutput) 13938bf5c682Smrg return; 13948bf5c682Smrg 13958bf5c682Smrg for (i = 0; i < drmmode_output->num_props; i++) { 13968bf5c682Smrg drmmode_prop_ptr p = &drmmode_output->props[i]; 13978bf5c682Smrg 13988bf5c682Smrg for (j = 0; j < koutput->count_props; j++) { 13998bf5c682Smrg if (koutput->props[j] != p->mode_prop->prop_id) 14008bf5c682Smrg continue; 14018bf5c682Smrg 14028bf5c682Smrg /* Check to see if the property value has changed */ 14038bf5c682Smrg if (koutput->prop_values[j] == p->value) 14048bf5c682Smrg break; 14058bf5c682Smrg 14068bf5c682Smrg p->value = koutput->prop_values[j]; 14078bf5c682Smrg 14088bf5c682Smrg if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 14098bf5c682Smrg INT32 value = p->value; 14108bf5c682Smrg 14118bf5c682Smrg err = RRChangeOutputProperty(output->randr_output, 14128bf5c682Smrg p->atoms[0], XA_INTEGER, 14138bf5c682Smrg 32, PropModeReplace, 1, 14148bf5c682Smrg &value, FALSE, TRUE); 14158bf5c682Smrg if (err != 0) { 14168bf5c682Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 14178bf5c682Smrg "RRChangeOutputProperty error, %d\n", 14188bf5c682Smrg err); 14198bf5c682Smrg } 14208bf5c682Smrg } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 14218bf5c682Smrg for (k = 0; k < p->mode_prop->count_enums; k++) { 14228bf5c682Smrg if (p->mode_prop->enums[k].value == p->value) 14238bf5c682Smrg break; 14248bf5c682Smrg } 14258bf5c682Smrg if (k < p->mode_prop->count_enums) { 14268bf5c682Smrg err = RRChangeOutputProperty(output->randr_output, 14278bf5c682Smrg p->atoms[0], XA_ATOM, 14288bf5c682Smrg 32, PropModeReplace, 1, 14298bf5c682Smrg &p->atoms[k + 1], FALSE, 14308bf5c682Smrg TRUE); 14318bf5c682Smrg if (err != 0) { 14328bf5c682Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 14338bf5c682Smrg "RRChangeOutputProperty error, %d\n", 14348bf5c682Smrg err); 14358bf5c682Smrg } 14368bf5c682Smrg } 14378bf5c682Smrg } 14388bf5c682Smrg 14398bf5c682Smrg break; 14408bf5c682Smrg } 14418bf5c682Smrg } 14428bf5c682Smrg} 14438bf5c682Smrg 1444de2362d3Smrgstatic xf86OutputStatus 1445de2362d3Smrgdrmmode_output_detect(xf86OutputPtr output) 1446de2362d3Smrg{ 1447de2362d3Smrg /* go to the hw and retrieve a new output struct */ 1448de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 14498bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn); 1450de2362d3Smrg xf86OutputStatus status; 1451de2362d3Smrg drmModeFreeConnector(drmmode_output->mode_output); 1452de2362d3Smrg 14538bf5c682Smrg drmmode_output->mode_output = 14548bf5c682Smrg drmModeGetConnector(pRADEONEnt->fd, drmmode_output->output_id); 14558bf5c682Smrg if (!drmmode_output->mode_output) { 14568bf5c682Smrg drmmode_output->output_id = -1; 145718781e08Smrg return XF86OutputStatusDisconnected; 14588bf5c682Smrg } 14598bf5c682Smrg 14608bf5c682Smrg drmmode_output_update_properties(output); 1461de2362d3Smrg 1462de2362d3Smrg switch (drmmode_output->mode_output->connection) { 1463de2362d3Smrg case DRM_MODE_CONNECTED: 1464de2362d3Smrg status = XF86OutputStatusConnected; 1465de2362d3Smrg break; 1466de2362d3Smrg case DRM_MODE_DISCONNECTED: 1467de2362d3Smrg status = XF86OutputStatusDisconnected; 1468de2362d3Smrg break; 1469de2362d3Smrg default: 1470de2362d3Smrg case DRM_MODE_UNKNOWNCONNECTION: 1471de2362d3Smrg status = XF86OutputStatusUnknown; 1472de2362d3Smrg break; 1473de2362d3Smrg } 1474de2362d3Smrg return status; 1475de2362d3Smrg} 1476de2362d3Smrg 1477de2362d3Smrgstatic Bool 1478de2362d3Smrgdrmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes) 1479de2362d3Smrg{ 1480de2362d3Smrg return MODE_OK; 1481de2362d3Smrg} 1482de2362d3Smrg 14838bf5c682Smrgstatic int 14848bf5c682Smrgkoutput_get_prop_idx(int fd, drmModeConnectorPtr koutput, 14858bf5c682Smrg int type, const char *name) 14868bf5c682Smrg{ 14878bf5c682Smrg int idx = -1; 14888bf5c682Smrg 14898bf5c682Smrg for (int i = 0; i < koutput->count_props; i++) { 14908bf5c682Smrg drmModePropertyPtr prop = drmModeGetProperty(fd, koutput->props[i]); 14918bf5c682Smrg 14928bf5c682Smrg if (!prop) 14938bf5c682Smrg continue; 14948bf5c682Smrg 14958bf5c682Smrg if (drm_property_type_is(prop, type) && !strcmp(prop->name, name)) 14968bf5c682Smrg idx = i; 14978bf5c682Smrg 14988bf5c682Smrg drmModeFreeProperty(prop); 14998bf5c682Smrg 15008bf5c682Smrg if (idx > -1) 15018bf5c682Smrg break; 15028bf5c682Smrg } 15038bf5c682Smrg 15048bf5c682Smrg return idx; 15058bf5c682Smrg} 15068bf5c682Smrg 15078bf5c682Smrgstatic int 15088bf5c682Smrgkoutput_get_prop_id(int fd, drmModeConnectorPtr koutput, 15098bf5c682Smrg int type, const char *name) 15108bf5c682Smrg{ 15118bf5c682Smrg int idx = koutput_get_prop_idx(fd, koutput, type, name); 15128bf5c682Smrg 15138bf5c682Smrg return (idx > -1) ? koutput->props[idx] : -1; 15148bf5c682Smrg} 15158bf5c682Smrg 15168bf5c682Smrgstatic drmModePropertyBlobPtr 15178bf5c682Smrgkoutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name) 15188bf5c682Smrg{ 15198bf5c682Smrg drmModePropertyBlobPtr blob = NULL; 15208bf5c682Smrg int idx = koutput_get_prop_idx(fd, koutput, DRM_MODE_PROP_BLOB, name); 15218bf5c682Smrg 15228bf5c682Smrg if (idx > -1) 15238bf5c682Smrg blob = drmModeGetPropertyBlob(fd, koutput->prop_values[idx]); 15248bf5c682Smrg 15258bf5c682Smrg return blob; 15268bf5c682Smrg} 15278bf5c682Smrg 1528de2362d3Smrgstatic DisplayModePtr 1529de2362d3Smrgdrmmode_output_get_modes(xf86OutputPtr output) 1530de2362d3Smrg{ 1531de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1532de2362d3Smrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 15338bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn); 1534de2362d3Smrg int i; 1535de2362d3Smrg DisplayModePtr Modes = NULL, Mode; 1536de2362d3Smrg xf86MonPtr mon = NULL; 1537de2362d3Smrg 153818781e08Smrg if (!koutput) 153918781e08Smrg return NULL; 154018781e08Smrg 15418bf5c682Smrg drmModeFreePropertyBlob(drmmode_output->edid_blob); 15428bf5c682Smrg 1543de2362d3Smrg /* look for an EDID property */ 15448bf5c682Smrg drmmode_output->edid_blob = 15458bf5c682Smrg koutput_get_prop_blob(pRADEONEnt->fd, koutput, "EDID"); 1546de2362d3Smrg 1547de2362d3Smrg if (drmmode_output->edid_blob) { 1548de2362d3Smrg mon = xf86InterpretEDID(output->scrn->scrnIndex, 1549de2362d3Smrg drmmode_output->edid_blob->data); 1550de2362d3Smrg if (mon && drmmode_output->edid_blob->length > 128) 1551de2362d3Smrg mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; 1552de2362d3Smrg } 1553de2362d3Smrg xf86OutputSetEDID(output, mon); 1554de2362d3Smrg 1555de2362d3Smrg /* modes should already be available */ 1556de2362d3Smrg for (i = 0; i < koutput->count_modes; i++) { 1557de2362d3Smrg Mode = xnfalloc(sizeof(DisplayModeRec)); 1558de2362d3Smrg 1559de2362d3Smrg drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode); 1560de2362d3Smrg Modes = xf86ModesAdd(Modes, Mode); 1561de2362d3Smrg 1562de2362d3Smrg } 1563de2362d3Smrg return Modes; 1564de2362d3Smrg} 1565de2362d3Smrg 1566de2362d3Smrgstatic void 1567de2362d3Smrgdrmmode_output_destroy(xf86OutputPtr output) 1568de2362d3Smrg{ 1569de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1570de2362d3Smrg int i; 1571de2362d3Smrg 1572de2362d3Smrg if (drmmode_output->edid_blob) 1573de2362d3Smrg drmModeFreePropertyBlob(drmmode_output->edid_blob); 1574de2362d3Smrg for (i = 0; i < drmmode_output->num_props; i++) { 1575de2362d3Smrg drmModeFreeProperty(drmmode_output->props[i].mode_prop); 1576de2362d3Smrg free(drmmode_output->props[i].atoms); 1577de2362d3Smrg } 1578de2362d3Smrg for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) { 1579de2362d3Smrg drmModeFreeEncoder(drmmode_output->mode_encoders[i]); 1580de2362d3Smrg } 158118781e08Smrg free(drmmode_output->mode_encoders); 1582de2362d3Smrg free(drmmode_output->props); 1583de2362d3Smrg drmModeFreeConnector(drmmode_output->mode_output); 1584de2362d3Smrg free(drmmode_output); 1585de2362d3Smrg output->driver_private = NULL; 1586de2362d3Smrg} 1587de2362d3Smrg 1588de2362d3Smrgstatic void 1589de2362d3Smrgdrmmode_output_dpms(xf86OutputPtr output, int mode) 1590de2362d3Smrg{ 1591de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 159218781e08Smrg xf86CrtcPtr crtc = output->crtc; 1593de2362d3Smrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 15948bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn); 1595de2362d3Smrg 159618781e08Smrg if (!koutput) 159718781e08Smrg return; 159818781e08Smrg 15998bf5c682Smrg if (mode != DPMSModeOn && crtc) 160018781e08Smrg drmmode_do_crtc_dpms(crtc, mode); 160118781e08Smrg 16028bf5c682Smrg drmModeConnectorSetProperty(pRADEONEnt->fd, koutput->connector_id, 1603de2362d3Smrg drmmode_output->dpms_enum_id, mode); 160418781e08Smrg 160518781e08Smrg if (mode == DPMSModeOn && crtc) { 160618781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 160718781e08Smrg 160818781e08Smrg if (drmmode_crtc->need_modeset) 160918781e08Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, crtc->x, 161018781e08Smrg crtc->y); 161118781e08Smrg else 161218781e08Smrg drmmode_do_crtc_dpms(crtc, mode); 161318781e08Smrg } 1614de2362d3Smrg} 1615de2362d3Smrg 1616de2362d3Smrg 1617de2362d3Smrgstatic Bool 1618de2362d3Smrgdrmmode_property_ignore(drmModePropertyPtr prop) 1619de2362d3Smrg{ 1620de2362d3Smrg if (!prop) 1621de2362d3Smrg return TRUE; 1622de2362d3Smrg /* ignore blob prop */ 1623de2362d3Smrg if (prop->flags & DRM_MODE_PROP_BLOB) 1624de2362d3Smrg return TRUE; 1625de2362d3Smrg /* ignore standard property */ 1626de2362d3Smrg if (!strcmp(prop->name, "EDID") || 1627de2362d3Smrg !strcmp(prop->name, "DPMS")) 1628de2362d3Smrg return TRUE; 1629de2362d3Smrg 1630de2362d3Smrg return FALSE; 1631de2362d3Smrg} 1632de2362d3Smrg 1633de2362d3Smrgstatic void 1634de2362d3Smrgdrmmode_output_create_resources(xf86OutputPtr output) 1635de2362d3Smrg{ 16363ed65abbSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 1637de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1638de2362d3Smrg drmModeConnectorPtr mode_output = drmmode_output->mode_output; 16398bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn); 16403ed65abbSmrg drmModePropertyPtr drmmode_prop, tearfree_prop; 1641de2362d3Smrg int i, j, err; 164239413783Smrg Atom name; 164339413783Smrg 164439413783Smrg /* Create CONNECTOR_ID property */ 164539413783Smrg name = MakeAtom("CONNECTOR_ID", 12, TRUE); 164639413783Smrg if (name != BAD_RESOURCE) { 164739413783Smrg INT32 value = mode_output->connector_id; 164839413783Smrg 164939413783Smrg err = RRConfigureOutputProperty(output->randr_output, name, 165039413783Smrg FALSE, FALSE, TRUE, 1, &value); 165139413783Smrg if (err != Success) { 165239413783Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 165339413783Smrg "RRConfigureOutputProperty error, %d\n", err); 165439413783Smrg } 165539413783Smrg 165639413783Smrg err = RRChangeOutputProperty(output->randr_output, name, 165739413783Smrg XA_INTEGER, 32, PropModeReplace, 1, 165839413783Smrg &value, FALSE, FALSE); 165939413783Smrg if (err != Success) { 166039413783Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 166139413783Smrg "RRChangeOutputProperty error, %d\n", err); 166239413783Smrg } 166339413783Smrg } 1664de2362d3Smrg 16653ed65abbSmrg drmmode_output->props = calloc(mode_output->count_props + 1, sizeof(drmmode_prop_rec)); 1666de2362d3Smrg if (!drmmode_output->props) 1667de2362d3Smrg return; 1668de2362d3Smrg 1669de2362d3Smrg drmmode_output->num_props = 0; 1670de2362d3Smrg for (i = 0, j = 0; i < mode_output->count_props; i++) { 16718bf5c682Smrg drmmode_prop = drmModeGetProperty(pRADEONEnt->fd, mode_output->props[i]); 1672de2362d3Smrg if (drmmode_property_ignore(drmmode_prop)) { 1673de2362d3Smrg drmModeFreeProperty(drmmode_prop); 1674de2362d3Smrg continue; 1675de2362d3Smrg } 1676de2362d3Smrg drmmode_output->props[j].mode_prop = drmmode_prop; 1677de2362d3Smrg drmmode_output->props[j].value = mode_output->prop_values[i]; 1678de2362d3Smrg drmmode_output->num_props++; 1679de2362d3Smrg j++; 1680de2362d3Smrg } 1681de2362d3Smrg 16823ed65abbSmrg /* Userspace-only property for TearFree */ 16833ed65abbSmrg tearfree_prop = calloc(1, sizeof(*tearfree_prop)); 16843ed65abbSmrg tearfree_prop->flags = DRM_MODE_PROP_ENUM; 168539413783Smrg strcpy(tearfree_prop->name, "TearFree"); 16863ed65abbSmrg tearfree_prop->count_enums = 3; 16873ed65abbSmrg tearfree_prop->enums = calloc(tearfree_prop->count_enums, 16883ed65abbSmrg sizeof(*tearfree_prop->enums)); 168939413783Smrg strcpy(tearfree_prop->enums[0].name, "off"); 169039413783Smrg strcpy(tearfree_prop->enums[1].name, "on"); 16913ed65abbSmrg tearfree_prop->enums[1].value = 1; 169239413783Smrg strcpy(tearfree_prop->enums[2].name, "auto"); 16933ed65abbSmrg tearfree_prop->enums[2].value = 2; 16943ed65abbSmrg drmmode_output->props[j].mode_prop = tearfree_prop; 16953ed65abbSmrg drmmode_output->props[j].value = info->tear_free; 16963ed65abbSmrg drmmode_output->tear_free = info->tear_free; 16973ed65abbSmrg drmmode_output->num_props++; 16983ed65abbSmrg 1699de2362d3Smrg for (i = 0; i < drmmode_output->num_props; i++) { 1700de2362d3Smrg drmmode_prop_ptr p = &drmmode_output->props[i]; 1701de2362d3Smrg drmmode_prop = p->mode_prop; 1702de2362d3Smrg 1703de2362d3Smrg if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { 1704de2362d3Smrg INT32 range[2]; 1705de2362d3Smrg INT32 value = p->value; 1706de2362d3Smrg 1707de2362d3Smrg p->num_atoms = 1; 1708de2362d3Smrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 1709de2362d3Smrg if (!p->atoms) 1710de2362d3Smrg continue; 1711de2362d3Smrg p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 1712de2362d3Smrg range[0] = drmmode_prop->values[0]; 1713de2362d3Smrg range[1] = drmmode_prop->values[1]; 1714de2362d3Smrg err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 1715de2362d3Smrg FALSE, TRUE, 1716de2362d3Smrg drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 1717de2362d3Smrg 2, range); 1718de2362d3Smrg if (err != 0) { 1719de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1720de2362d3Smrg "RRConfigureOutputProperty error, %d\n", err); 1721de2362d3Smrg } 1722de2362d3Smrg err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 1723de2362d3Smrg XA_INTEGER, 32, PropModeReplace, 1, &value, FALSE, TRUE); 1724de2362d3Smrg if (err != 0) { 1725de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1726de2362d3Smrg "RRChangeOutputProperty error, %d\n", err); 1727de2362d3Smrg } 1728de2362d3Smrg } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { 1729de2362d3Smrg p->num_atoms = drmmode_prop->count_enums + 1; 1730de2362d3Smrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 1731de2362d3Smrg if (!p->atoms) 1732de2362d3Smrg continue; 1733de2362d3Smrg p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 1734de2362d3Smrg for (j = 1; j <= drmmode_prop->count_enums; j++) { 1735de2362d3Smrg struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1]; 1736de2362d3Smrg p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE); 1737de2362d3Smrg } 1738de2362d3Smrg err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 1739de2362d3Smrg FALSE, FALSE, 1740de2362d3Smrg drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 1741de2362d3Smrg p->num_atoms - 1, (INT32 *)&p->atoms[1]); 1742de2362d3Smrg if (err != 0) { 1743de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1744de2362d3Smrg "RRConfigureOutputProperty error, %d\n", err); 1745de2362d3Smrg } 1746de2362d3Smrg for (j = 0; j < drmmode_prop->count_enums; j++) 1747de2362d3Smrg if (drmmode_prop->enums[j].value == p->value) 1748de2362d3Smrg break; 1749de2362d3Smrg /* there's always a matching value */ 1750de2362d3Smrg err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 1751de2362d3Smrg XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, TRUE); 1752de2362d3Smrg if (err != 0) { 1753de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1754de2362d3Smrg "RRChangeOutputProperty error, %d\n", err); 1755de2362d3Smrg } 1756de2362d3Smrg } 1757de2362d3Smrg } 1758de2362d3Smrg} 1759de2362d3Smrg 176039413783Smrgstatic void 176139413783Smrgdrmmode_output_set_tear_free(RADEONEntPtr pRADEONEnt, 176239413783Smrg drmmode_output_private_ptr drmmode_output, 176339413783Smrg xf86CrtcPtr crtc, int tear_free) 176439413783Smrg{ 176539413783Smrg if (drmmode_output->tear_free == tear_free) 176639413783Smrg return; 176739413783Smrg 176839413783Smrg drmmode_output->tear_free = tear_free; 176939413783Smrg 177039413783Smrg if (crtc) { 177139413783Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 177239413783Smrg crtc->x, crtc->y); 177339413783Smrg } 177439413783Smrg} 177539413783Smrg 1776de2362d3Smrgstatic Bool 1777de2362d3Smrgdrmmode_output_set_property(xf86OutputPtr output, Atom property, 1778de2362d3Smrg RRPropertyValuePtr value) 1779de2362d3Smrg{ 1780de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 17818bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn); 1782de2362d3Smrg int i; 1783de2362d3Smrg 1784de2362d3Smrg for (i = 0; i < drmmode_output->num_props; i++) { 1785de2362d3Smrg drmmode_prop_ptr p = &drmmode_output->props[i]; 1786de2362d3Smrg 1787de2362d3Smrg if (p->atoms[0] != property) 1788de2362d3Smrg continue; 1789de2362d3Smrg 1790de2362d3Smrg if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 1791de2362d3Smrg uint32_t val; 1792de2362d3Smrg 1793de2362d3Smrg if (value->type != XA_INTEGER || value->format != 32 || 1794de2362d3Smrg value->size != 1) 1795de2362d3Smrg return FALSE; 1796de2362d3Smrg val = *(uint32_t *)value->data; 1797de2362d3Smrg 17988bf5c682Smrg drmModeConnectorSetProperty(pRADEONEnt->fd, drmmode_output->output_id, 1799de2362d3Smrg p->mode_prop->prop_id, (uint64_t)val); 1800de2362d3Smrg return TRUE; 1801de2362d3Smrg } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 1802de2362d3Smrg Atom atom; 1803de2362d3Smrg const char *name; 1804de2362d3Smrg int j; 1805de2362d3Smrg 1806de2362d3Smrg if (value->type != XA_ATOM || value->format != 32 || value->size != 1) 1807de2362d3Smrg return FALSE; 1808de2362d3Smrg memcpy(&atom, value->data, 4); 18098bf5c682Smrg if (!(name = NameForAtom(atom))) 18108bf5c682Smrg return FALSE; 1811de2362d3Smrg 1812de2362d3Smrg /* search for matching name string, then set its value down */ 1813de2362d3Smrg for (j = 0; j < p->mode_prop->count_enums; j++) { 1814de2362d3Smrg if (!strcmp(p->mode_prop->enums[j].name, name)) { 18153ed65abbSmrg if (i == (drmmode_output->num_props - 1)) { 181639413783Smrg drmmode_output_set_tear_free(pRADEONEnt, drmmode_output, 181739413783Smrg output->crtc, j); 18183ed65abbSmrg } else { 18198bf5c682Smrg drmModeConnectorSetProperty(pRADEONEnt->fd, 18203ed65abbSmrg drmmode_output->output_id, 18213ed65abbSmrg p->mode_prop->prop_id, 18223ed65abbSmrg p->mode_prop->enums[j].value); 18233ed65abbSmrg } 18243ed65abbSmrg 1825de2362d3Smrg return TRUE; 1826de2362d3Smrg } 1827de2362d3Smrg } 1828de2362d3Smrg } 1829de2362d3Smrg } 1830de2362d3Smrg 1831de2362d3Smrg return TRUE; 1832de2362d3Smrg} 1833de2362d3Smrg 1834de2362d3Smrgstatic Bool 1835de2362d3Smrgdrmmode_output_get_property(xf86OutputPtr output, Atom property) 1836de2362d3Smrg{ 1837de2362d3Smrg return TRUE; 1838de2362d3Smrg} 1839de2362d3Smrg 1840de2362d3Smrgstatic const xf86OutputFuncsRec drmmode_output_funcs = { 1841de2362d3Smrg .dpms = drmmode_output_dpms, 1842de2362d3Smrg .create_resources = drmmode_output_create_resources, 1843de2362d3Smrg .set_property = drmmode_output_set_property, 1844de2362d3Smrg .get_property = drmmode_output_get_property, 1845de2362d3Smrg .detect = drmmode_output_detect, 1846de2362d3Smrg .mode_valid = drmmode_output_mode_valid, 1847de2362d3Smrg 1848de2362d3Smrg .get_modes = drmmode_output_get_modes, 1849de2362d3Smrg .destroy = drmmode_output_destroy 1850de2362d3Smrg}; 1851de2362d3Smrg 1852de2362d3Smrgstatic int subpixel_conv_table[7] = { 0, SubPixelUnknown, 1853de2362d3Smrg SubPixelHorizontalRGB, 1854de2362d3Smrg SubPixelHorizontalBGR, 1855de2362d3Smrg SubPixelVerticalRGB, 1856de2362d3Smrg SubPixelVerticalBGR, 1857de2362d3Smrg SubPixelNone }; 1858de2362d3Smrg 1859de2362d3Smrgconst char *output_names[] = { "None", 1860de2362d3Smrg "VGA", 1861de2362d3Smrg "DVI", 1862de2362d3Smrg "DVI", 1863de2362d3Smrg "DVI", 1864de2362d3Smrg "Composite", 1865de2362d3Smrg "S-video", 1866de2362d3Smrg "LVDS", 1867de2362d3Smrg "CTV", 1868de2362d3Smrg "DIN", 1869de2362d3Smrg "DisplayPort", 1870de2362d3Smrg "HDMI", 1871de2362d3Smrg "HDMI", 1872de2362d3Smrg "TV", 1873de2362d3Smrg "eDP" 1874de2362d3Smrg}; 1875de2362d3Smrg 187618781e08Smrg#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0])) 187718781e08Smrg 187818781e08Smrgstatic xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id) 187918781e08Smrg{ 188018781e08Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 188118781e08Smrg int i; 188218781e08Smrg for (i = 0; i < xf86_config->num_output; i++) { 188318781e08Smrg xf86OutputPtr output = xf86_config->output[i]; 188418781e08Smrg drmmode_output_private_ptr drmmode_output; 188518781e08Smrg 188618781e08Smrg drmmode_output = output->driver_private; 188718781e08Smrg if (drmmode_output->output_id == id) 188818781e08Smrg return output; 188918781e08Smrg } 189018781e08Smrg return NULL; 189118781e08Smrg} 189218781e08Smrg 189318781e08Smrgstatic int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path) 189418781e08Smrg{ 189518781e08Smrg char *conn; 189618781e08Smrg char conn_id[5]; 189718781e08Smrg int id, len; 189818781e08Smrg char *blob_data; 189918781e08Smrg 190018781e08Smrg if (!path_blob) 190118781e08Smrg return -1; 190218781e08Smrg 190318781e08Smrg blob_data = path_blob->data; 190418781e08Smrg /* we only handle MST paths for now */ 190518781e08Smrg if (strncmp(blob_data, "mst:", 4)) 190618781e08Smrg return -1; 190718781e08Smrg 190818781e08Smrg conn = strchr(blob_data + 4, '-'); 190918781e08Smrg if (!conn) 191018781e08Smrg return -1; 191118781e08Smrg len = conn - (blob_data + 4); 191218781e08Smrg if (len + 1 > 5) 191318781e08Smrg return -1; 191418781e08Smrg memcpy(conn_id, blob_data + 4, len); 191518781e08Smrg conn_id[len] = '\0'; 191618781e08Smrg id = strtoul(conn_id, NULL, 10); 191718781e08Smrg 191818781e08Smrg *conn_base_id = id; 191918781e08Smrg 192018781e08Smrg *path = conn + 1; 192118781e08Smrg return 0; 192218781e08Smrg} 192318781e08Smrg 1924de2362d3Smrgstatic void 192518781e08Smrgdrmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name, 192618781e08Smrg drmModePropertyBlobPtr path_blob, int *num_dvi, int *num_hdmi) 192718781e08Smrg{ 192818781e08Smrg xf86OutputPtr output; 192918781e08Smrg int conn_id; 193018781e08Smrg char *extra_path; 193118781e08Smrg 193218781e08Smrg output = NULL; 193318781e08Smrg if (parse_path_blob(path_blob, &conn_id, &extra_path) == 0) 193418781e08Smrg output = find_output(pScrn, conn_id); 193518781e08Smrg if (output) { 193618781e08Smrg snprintf(name, 32, "%s-%s", output->name, extra_path); 193718781e08Smrg } else { 19388bf5c682Smrg if (koutput->connector_type >= NUM_OUTPUT_NAMES) { 193918781e08Smrg snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, 194018781e08Smrg koutput->connector_type_id - 1); 19418bf5c682Smrg } else if (pScrn->is_gpu) { 194218781e08Smrg snprintf(name, 32, "%s-%d-%d", 194318781e08Smrg output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, 194418781e08Smrg koutput->connector_type_id - 1); 19458bf5c682Smrg } else { 194618781e08Smrg /* need to do smart conversion here for compat with non-kms ATI driver */ 194718781e08Smrg if (koutput->connector_type_id == 1) { 194818781e08Smrg switch(koutput->connector_type) { 194918781e08Smrg case DRM_MODE_CONNECTOR_DVII: 195018781e08Smrg case DRM_MODE_CONNECTOR_DVID: 195118781e08Smrg case DRM_MODE_CONNECTOR_DVIA: 195218781e08Smrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi); 195318781e08Smrg (*num_dvi)++; 195418781e08Smrg break; 195518781e08Smrg case DRM_MODE_CONNECTOR_HDMIA: 195618781e08Smrg case DRM_MODE_CONNECTOR_HDMIB: 195718781e08Smrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi); 195818781e08Smrg (*num_hdmi)++; 195918781e08Smrg break; 196018781e08Smrg case DRM_MODE_CONNECTOR_VGA: 196118781e08Smrg case DRM_MODE_CONNECTOR_DisplayPort: 196218781e08Smrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], 196318781e08Smrg koutput->connector_type_id - 1); 196418781e08Smrg break; 196518781e08Smrg default: 196618781e08Smrg snprintf(name, 32, "%s", output_names[koutput->connector_type]); 196718781e08Smrg break; 196818781e08Smrg } 196918781e08Smrg } else { 197018781e08Smrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], 197118781e08Smrg koutput->connector_type_id - 1); 197218781e08Smrg } 197318781e08Smrg } 197418781e08Smrg } 197518781e08Smrg} 197618781e08Smrg 197718781e08Smrgstatic unsigned int 197818781e08Smrgdrmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int *num_dvi, int *num_hdmi, int dynamic) 19790d16fef4Smrg{ 198018781e08Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 19818bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 1982de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1983de2362d3Smrg xf86OutputPtr output; 1984de2362d3Smrg drmModeConnectorPtr koutput; 1985de2362d3Smrg drmModeEncoderPtr *kencoders = NULL; 1986de2362d3Smrg drmmode_output_private_ptr drmmode_output; 198718781e08Smrg drmModePropertyBlobPtr path_blob = NULL; 198839413783Smrg#if XF86_CRTC_VERSION >= 8 198939413783Smrg Bool nonDesktop = FALSE; 199039413783Smrg#endif 1991de2362d3Smrg char name[32]; 1992de2362d3Smrg int i; 1993de2362d3Smrg const char *s; 1994de2362d3Smrg 19958bf5c682Smrg koutput = drmModeGetConnector(pRADEONEnt->fd, mode_res->connectors[num]); 1996de2362d3Smrg if (!koutput) 199718781e08Smrg return 0; 199818781e08Smrg 19998bf5c682Smrg path_blob = koutput_get_prop_blob(pRADEONEnt->fd, koutput, "PATH"); 2000de2362d3Smrg 200139413783Smrg#if XF86_CRTC_VERSION >= 8 200239413783Smrg i = koutput_get_prop_idx(pRADEONEnt->fd, koutput, DRM_MODE_PROP_RANGE, 200339413783Smrg "non-desktop"); 200439413783Smrg if (i >= 0) 200539413783Smrg nonDesktop = koutput->prop_values[i] != 0; 200639413783Smrg#endif 200739413783Smrg 2008de2362d3Smrg kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders); 2009de2362d3Smrg if (!kencoders) { 2010de2362d3Smrg goto out_free_encoders; 2011de2362d3Smrg } 2012de2362d3Smrg 2013de2362d3Smrg for (i = 0; i < koutput->count_encoders; i++) { 20148bf5c682Smrg kencoders[i] = drmModeGetEncoder(pRADEONEnt->fd, koutput->encoders[i]); 2015de2362d3Smrg if (!kencoders[i]) { 2016de2362d3Smrg goto out_free_encoders; 2017de2362d3Smrg } 2018de2362d3Smrg } 2019de2362d3Smrg 202018781e08Smrg drmmode_create_name(pScrn, koutput, name, path_blob, num_dvi, num_hdmi); 202118781e08Smrg if (path_blob) 202218781e08Smrg drmModeFreePropertyBlob(path_blob); 202318781e08Smrg 202418781e08Smrg if (path_blob && dynamic) { 202518781e08Smrg /* See if we have an output with this name already 202618781e08Smrg * and hook stuff up. 202718781e08Smrg */ 202818781e08Smrg for (i = 0; i < xf86_config->num_output; i++) { 202918781e08Smrg output = xf86_config->output[i]; 203018781e08Smrg 203118781e08Smrg if (strncmp(output->name, name, 32)) 203218781e08Smrg continue; 203318781e08Smrg 203418781e08Smrg drmmode_output = output->driver_private; 203518781e08Smrg drmmode_output->output_id = mode_res->connectors[num]; 203618781e08Smrg drmmode_output->mode_output = koutput; 203739413783Smrg#if XF86_CRTC_VERSION >= 8 203839413783Smrg output->non_desktop = nonDesktop; 203939413783Smrg#endif 204018781e08Smrg for (i = 0; i < koutput->count_encoders; i++) 204118781e08Smrg drmModeFreeEncoder(kencoders[i]); 204218781e08Smrg free(kencoders); 204318781e08Smrg return 0; 204418781e08Smrg } 2045de2362d3Smrg } 2046de2362d3Smrg 2047de2362d3Smrg if (xf86IsEntityShared(pScrn->entityList[0])) { 2048de2362d3Smrg if ((s = xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) { 2049de2362d3Smrg if (!RADEONZaphodStringMatches(pScrn, s, name)) 2050de2362d3Smrg goto out_free_encoders; 2051de2362d3Smrg } else { 205218781e08Smrg if (!info->IsSecondary && (num != 0)) 2053de2362d3Smrg goto out_free_encoders; 2054de2362d3Smrg else if (info->IsSecondary && (num != 1)) 2055de2362d3Smrg goto out_free_encoders; 2056de2362d3Smrg } 2057de2362d3Smrg } 2058de2362d3Smrg 2059de2362d3Smrg output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name); 2060de2362d3Smrg if (!output) { 2061de2362d3Smrg goto out_free_encoders; 2062de2362d3Smrg } 2063de2362d3Smrg 2064de2362d3Smrg drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1); 2065de2362d3Smrg if (!drmmode_output) { 2066de2362d3Smrg xf86OutputDestroy(output); 2067de2362d3Smrg goto out_free_encoders; 2068de2362d3Smrg } 2069de2362d3Smrg 207018781e08Smrg drmmode_output->output_id = mode_res->connectors[num]; 2071de2362d3Smrg drmmode_output->mode_output = koutput; 2072de2362d3Smrg drmmode_output->mode_encoders = kencoders; 2073de2362d3Smrg drmmode_output->drmmode = drmmode; 2074de2362d3Smrg output->mm_width = koutput->mmWidth; 2075de2362d3Smrg output->mm_height = koutput->mmHeight; 2076de2362d3Smrg 2077de2362d3Smrg output->subpixel_order = subpixel_conv_table[koutput->subpixel]; 2078de2362d3Smrg output->interlaceAllowed = TRUE; 2079de2362d3Smrg output->doubleScanAllowed = TRUE; 2080de2362d3Smrg output->driver_private = drmmode_output; 208139413783Smrg#if XF86_CRTC_VERSION >= 8 208239413783Smrg output->non_desktop = nonDesktop; 208339413783Smrg#endif 2084de2362d3Smrg 2085de2362d3Smrg output->possible_crtcs = 0xffffffff; 2086de2362d3Smrg for (i = 0; i < koutput->count_encoders; i++) { 2087de2362d3Smrg output->possible_crtcs &= kencoders[i]->possible_crtcs; 2088de2362d3Smrg } 2089de2362d3Smrg /* work out the possible clones later */ 2090de2362d3Smrg output->possible_clones = 0; 2091de2362d3Smrg 20928bf5c682Smrg drmmode_output->dpms_enum_id = 20938bf5c682Smrg koutput_get_prop_id(pRADEONEnt->fd, koutput, DRM_MODE_PROP_ENUM, 20948bf5c682Smrg "DPMS"); 2095de2362d3Smrg 209618781e08Smrg if (dynamic) { 209718781e08Smrg output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output); 209818781e08Smrg drmmode_output_create_resources(output); 209918781e08Smrg } 210018781e08Smrg 210118781e08Smrg return 1; 2102de2362d3Smrgout_free_encoders: 2103de2362d3Smrg if (kencoders){ 2104de2362d3Smrg for (i = 0; i < koutput->count_encoders; i++) 2105de2362d3Smrg drmModeFreeEncoder(kencoders[i]); 2106de2362d3Smrg free(kencoders); 2107de2362d3Smrg } 2108de2362d3Smrg drmModeFreeConnector(koutput); 210918781e08Smrg return 0; 2110de2362d3Smrg} 2111de2362d3Smrg 2112de2362d3Smrguint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output) 2113de2362d3Smrg{ 2114de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private, clone_drmout; 2115de2362d3Smrg int i; 2116de2362d3Smrg xf86OutputPtr clone_output; 2117de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2118de2362d3Smrg int index_mask = 0; 2119de2362d3Smrg 2120de2362d3Smrg if (drmmode_output->enc_clone_mask == 0) 2121de2362d3Smrg return index_mask; 2122de2362d3Smrg 2123de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 2124de2362d3Smrg clone_output = xf86_config->output[i]; 2125de2362d3Smrg clone_drmout = clone_output->driver_private; 2126de2362d3Smrg if (output == clone_output) 2127de2362d3Smrg continue; 2128de2362d3Smrg 2129de2362d3Smrg if (clone_drmout->enc_mask == 0) 2130de2362d3Smrg continue; 2131de2362d3Smrg if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask) 2132de2362d3Smrg index_mask |= (1 << i); 2133de2362d3Smrg } 2134de2362d3Smrg return index_mask; 2135de2362d3Smrg} 2136de2362d3Smrg 2137de2362d3Smrg 2138de2362d3Smrgstatic void 213918781e08Smrgdrmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res) 2140de2362d3Smrg{ 2141de2362d3Smrg int i, j; 2142de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2143de2362d3Smrg 2144de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 2145de2362d3Smrg xf86OutputPtr output = xf86_config->output[i]; 2146de2362d3Smrg drmmode_output_private_ptr drmmode_output; 2147de2362d3Smrg 2148de2362d3Smrg drmmode_output = output->driver_private; 2149de2362d3Smrg drmmode_output->enc_clone_mask = 0xff; 2150de2362d3Smrg /* and all the possible encoder clones for this output together */ 2151de2362d3Smrg for (j = 0; j < drmmode_output->mode_output->count_encoders; j++) 2152de2362d3Smrg { 2153de2362d3Smrg int k; 215418781e08Smrg for (k = 0; k < mode_res->count_encoders; k++) { 215518781e08Smrg if (mode_res->encoders[k] == drmmode_output->mode_encoders[j]->encoder_id) 2156de2362d3Smrg drmmode_output->enc_mask |= (1 << k); 2157de2362d3Smrg } 2158de2362d3Smrg 2159de2362d3Smrg drmmode_output->enc_clone_mask &= drmmode_output->mode_encoders[j]->possible_clones; 2160de2362d3Smrg } 2161de2362d3Smrg } 2162de2362d3Smrg 2163de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 2164de2362d3Smrg xf86OutputPtr output = xf86_config->output[i]; 2165de2362d3Smrg output->possible_clones = find_clones(scrn, output); 2166de2362d3Smrg } 2167de2362d3Smrg} 2168de2362d3Smrg 2169de2362d3Smrg/* returns height alignment in pixels */ 2170de2362d3Smrgint drmmode_get_height_align(ScrnInfoPtr scrn, uint32_t tiling) 2171de2362d3Smrg{ 2172de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 2173de2362d3Smrg int height_align = 1; 2174de2362d3Smrg 2175de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 2176de2362d3Smrg if (tiling & RADEON_TILING_MACRO) 2177de2362d3Smrg height_align = info->num_channels * 8; 2178de2362d3Smrg else if (tiling & RADEON_TILING_MICRO) 2179de2362d3Smrg height_align = 8; 2180de2362d3Smrg else 2181de2362d3Smrg height_align = 8; 2182de2362d3Smrg } else { 218318781e08Smrg if (tiling & RADEON_TILING_MICRO_SQUARE) 218418781e08Smrg height_align = 32; 218518781e08Smrg else if (tiling) 2186de2362d3Smrg height_align = 16; 2187de2362d3Smrg else 2188de2362d3Smrg height_align = 1; 2189de2362d3Smrg } 2190de2362d3Smrg return height_align; 2191de2362d3Smrg} 2192de2362d3Smrg 2193de2362d3Smrg/* returns pitch alignment in pixels */ 2194de2362d3Smrgint drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling) 2195de2362d3Smrg{ 2196de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 2197de2362d3Smrg int pitch_align = 1; 2198de2362d3Smrg 2199de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 2200de2362d3Smrg if (tiling & RADEON_TILING_MACRO) { 2201de2362d3Smrg /* general surface requirements */ 2202de2362d3Smrg pitch_align = MAX(info->num_banks, 2203de2362d3Smrg (((info->group_bytes / 8) / bpe) * info->num_banks)) * 8; 2204de2362d3Smrg /* further restrictions for scanout */ 2205de2362d3Smrg pitch_align = MAX(info->num_banks * 8, pitch_align); 2206de2362d3Smrg } else if (tiling & RADEON_TILING_MICRO) { 2207de2362d3Smrg /* general surface requirements */ 2208de2362d3Smrg pitch_align = MAX(8, (info->group_bytes / (8 * bpe))); 2209de2362d3Smrg /* further restrictions for scanout */ 2210de2362d3Smrg pitch_align = MAX(info->group_bytes / bpe, pitch_align); 2211de2362d3Smrg } else { 2212de2362d3Smrg if (info->have_tiling_info) 2213de2362d3Smrg /* linear aligned requirements */ 2214de2362d3Smrg pitch_align = MAX(64, info->group_bytes / bpe); 2215de2362d3Smrg else 2216de2362d3Smrg /* default to 512 elements if we don't know the real 2217de2362d3Smrg * group size otherwise the kernel may reject the CS 2218de2362d3Smrg * if the group sizes don't match as the pitch won't 2219de2362d3Smrg * be aligned properly. 2220de2362d3Smrg */ 2221de2362d3Smrg pitch_align = 512; 2222de2362d3Smrg } 2223de2362d3Smrg } else { 2224de2362d3Smrg /* general surface requirements */ 2225de2362d3Smrg if (tiling) 2226de2362d3Smrg pitch_align = 256 / bpe; 2227de2362d3Smrg else 2228de2362d3Smrg pitch_align = 64; 2229de2362d3Smrg } 2230de2362d3Smrg return pitch_align; 2231de2362d3Smrg} 2232de2362d3Smrg 2233de2362d3Smrg/* returns base alignment in bytes */ 2234de2362d3Smrgint drmmode_get_base_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling) 2235de2362d3Smrg{ 2236de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 2237de2362d3Smrg int pixel_align = drmmode_get_pitch_align(scrn, bpe, tiling); 2238de2362d3Smrg int height_align = drmmode_get_height_align(scrn, tiling); 2239de2362d3Smrg int base_align = RADEON_GPU_PAGE_SIZE; 2240de2362d3Smrg 2241de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 2242de2362d3Smrg if (tiling & RADEON_TILING_MACRO) 2243de2362d3Smrg base_align = MAX(info->num_banks * info->num_channels * 8 * 8 * bpe, 2244de2362d3Smrg pixel_align * bpe * height_align); 2245de2362d3Smrg else { 2246de2362d3Smrg if (info->have_tiling_info) 2247de2362d3Smrg base_align = info->group_bytes; 2248de2362d3Smrg else 2249de2362d3Smrg /* default to 512 if we don't know the real 2250de2362d3Smrg * group size otherwise the kernel may reject the CS 2251de2362d3Smrg * if the group sizes don't match as the base won't 2252de2362d3Smrg * be aligned properly. 2253de2362d3Smrg */ 2254de2362d3Smrg base_align = 512; 2255de2362d3Smrg } 2256de2362d3Smrg } 2257de2362d3Smrg return base_align; 2258de2362d3Smrg} 2259de2362d3Smrg 2260de2362d3Smrgstatic Bool 2261de2362d3Smrgdrmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height) 2262de2362d3Smrg{ 2263de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2264de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 226539413783Smrg struct radeon_buffer *old_front = NULL; 2266de2362d3Smrg ScreenPtr screen = xf86ScrnToScreen(scrn); 2267de2362d3Smrg int i, pitch, old_width, old_height, old_pitch; 226839413783Smrg int usage = CREATE_PIXMAP_USAGE_BACKING_PIXMAP; 226918781e08Smrg int cpp = info->pixel_bytes; 227039413783Smrg uint32_t tiling_flags; 2271de2362d3Smrg PixmapPtr ppix = screen->GetScreenPixmap(screen); 2272de2362d3Smrg void *fb_shadow; 2273de2362d3Smrg 2274de2362d3Smrg if (scrn->virtualX == width && scrn->virtualY == height) 2275de2362d3Smrg return TRUE; 2276de2362d3Smrg 227739413783Smrg if (width > xf86_config->maxWidth || height > xf86_config->maxHeight) { 227839413783Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 227939413783Smrg "Xorg tried resizing screen to %dx%d, but maximum " 228039413783Smrg "supported is %dx%d\n", width, height, 228139413783Smrg xf86_config->maxWidth, xf86_config->maxHeight); 228239413783Smrg return FALSE; 2283de2362d3Smrg } 2284de2362d3Smrg 228539413783Smrg if (info->allowColorTiling && !info->shadow_primary) { 228639413783Smrg if (info->ChipFamily < CHIP_FAMILY_R600 || info->allowColorTiling2D) 228739413783Smrg usage |= RADEON_CREATE_PIXMAP_TILING_MACRO; 228839413783Smrg else 228939413783Smrg usage |= RADEON_CREATE_PIXMAP_TILING_MICRO; 2290de2362d3Smrg } 2291de2362d3Smrg 229239413783Smrg xf86DrvMsg(scrn->scrnIndex, X_INFO, "Allocate new frame buffer %dx%d\n", 229339413783Smrg width, height); 2294de2362d3Smrg 2295de2362d3Smrg old_width = scrn->virtualX; 2296de2362d3Smrg old_height = scrn->virtualY; 2297de2362d3Smrg old_pitch = scrn->displayWidth; 229839413783Smrg old_front = info->front_buffer; 2299de2362d3Smrg 2300de2362d3Smrg scrn->virtualX = width; 2301de2362d3Smrg scrn->virtualY = height; 2302de2362d3Smrg 230339413783Smrg info->front_buffer = radeon_alloc_pixmap_bo(scrn, scrn->virtualX, 230439413783Smrg scrn->virtualY, scrn->depth, 230539413783Smrg usage, scrn->bitsPerPixel, 230639413783Smrg &pitch, 230739413783Smrg &info->front_surface, 230839413783Smrg &tiling_flags); 230939413783Smrg if (!info->front_buffer) 2310de2362d3Smrg goto fail; 2311de2362d3Smrg 231239413783Smrg scrn->displayWidth = pitch / cpp; 231339413783Smrg 231439413783Smrg if (!info->use_glamor) { 2315de2362d3Smrg#if X_BYTE_ORDER == X_BIG_ENDIAN 231639413783Smrg switch (cpp) { 231739413783Smrg case 4: 231839413783Smrg tiling_flags |= RADEON_TILING_SWAP_32BIT; 231939413783Smrg break; 232039413783Smrg case 2: 232139413783Smrg tiling_flags |= RADEON_TILING_SWAP_16BIT; 232239413783Smrg break; 232339413783Smrg } 232439413783Smrg if (info->ChipFamily < CHIP_FAMILY_R600 && 232539413783Smrg info->r600_shadow_fb && tiling_flags) 232639413783Smrg tiling_flags |= RADEON_TILING_SURFACE; 2327de2362d3Smrg#endif 232839413783Smrg if (tiling_flags) 232939413783Smrg radeon_bo_set_tiling(info->front_buffer->bo.radeon, tiling_flags, pitch); 233039413783Smrg } 2331de2362d3Smrg 2332de2362d3Smrg if (!info->r600_shadow_fb) { 233339413783Smrg if (info->surf_man && !info->use_glamor) 233439413783Smrg *radeon_get_pixmap_surface(ppix) = info->front_surface; 2335de2362d3Smrg screen->ModifyPixmapHeader(ppix, 2336de2362d3Smrg width, height, -1, -1, pitch, NULL); 2337de2362d3Smrg } else { 233839413783Smrg if (radeon_bo_map(info->front_buffer->bo.radeon, 1)) 2339de2362d3Smrg goto fail; 234039413783Smrg fb_shadow = calloc(1, pitch * scrn->virtualY); 234139413783Smrg if (!fb_shadow) 2342de2362d3Smrg goto fail; 2343de2362d3Smrg free(info->fb_shadow); 2344de2362d3Smrg info->fb_shadow = fb_shadow; 2345de2362d3Smrg screen->ModifyPixmapHeader(ppix, 2346de2362d3Smrg width, height, -1, -1, pitch, 2347de2362d3Smrg info->fb_shadow); 2348de2362d3Smrg } 234918781e08Smrg 235018781e08Smrg if (info->use_glamor) 235118781e08Smrg radeon_glamor_create_screen_resources(scrn->pScreen); 235218781e08Smrg 235318781e08Smrg if (!info->r600_shadow_fb) { 235439413783Smrg if (!radeon_set_pixmap_bo(ppix, info->front_buffer)) 235518781e08Smrg goto fail; 235618781e08Smrg } 235718781e08Smrg 23588bf5c682Smrg radeon_pixmap_clear(ppix); 235939413783Smrg radeon_finish(scrn, info->front_buffer); 23600d16fef4Smrg 2361de2362d3Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 2362de2362d3Smrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 2363de2362d3Smrg 2364de2362d3Smrg if (!crtc->enabled) 2365de2362d3Smrg continue; 2366de2362d3Smrg 2367de2362d3Smrg drmmode_set_mode_major(crtc, &crtc->mode, 2368de2362d3Smrg crtc->rotation, crtc->x, crtc->y); 2369de2362d3Smrg } 2370de2362d3Smrg 237139413783Smrg radeon_buffer_unref(&old_front); 2372de2362d3Smrg 237339413783Smrg radeon_kms_update_vram_limit(scrn, pitch * scrn->virtualY); 2374de2362d3Smrg return TRUE; 2375de2362d3Smrg 2376de2362d3Smrg fail: 237739413783Smrg radeon_buffer_unref(&info->front_buffer); 237839413783Smrg info->front_buffer = old_front; 2379de2362d3Smrg scrn->virtualX = old_width; 2380de2362d3Smrg scrn->virtualY = old_height; 2381de2362d3Smrg scrn->displayWidth = old_pitch; 2382de2362d3Smrg 2383de2362d3Smrg return FALSE; 2384de2362d3Smrg} 2385de2362d3Smrg 238639413783Smrgstatic void 238739413783Smrgdrmmode_validate_leases(ScrnInfoPtr scrn) 238839413783Smrg{ 238939413783Smrg#ifdef XF86_LEASE_VERSION 239039413783Smrg ScreenPtr screen = scrn->pScreen; 239139413783Smrg rrScrPrivPtr scr_priv = rrGetScrPriv(screen); 239239413783Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 239339413783Smrg drmModeLesseeListPtr lessees; 239439413783Smrg RRLeasePtr lease, next; 239539413783Smrg int l; 239639413783Smrg 239739413783Smrg /* We can't talk to the kernel about leases when VT switched */ 239839413783Smrg if (!scrn->vtSema) 239939413783Smrg return; 240039413783Smrg 240139413783Smrg lessees = drmModeListLessees(pRADEONEnt->fd); 240239413783Smrg if (!lessees) 240339413783Smrg return; 240439413783Smrg 240539413783Smrg xorg_list_for_each_entry_safe(lease, next, &scr_priv->leases, list) { 240639413783Smrg drmmode_lease_private_ptr lease_private = lease->devPrivate; 240739413783Smrg 240839413783Smrg for (l = 0; l < lessees->count; l++) { 240939413783Smrg if (lessees->lessees[l] == lease_private->lessee_id) 241039413783Smrg break; 241139413783Smrg } 241239413783Smrg 241339413783Smrg /* check to see if the lease has gone away */ 241439413783Smrg if (l == lessees->count) { 241539413783Smrg free(lease_private); 241639413783Smrg lease->devPrivate = NULL; 241739413783Smrg xf86CrtcLeaseTerminated(lease); 241839413783Smrg } 241939413783Smrg } 242039413783Smrg 242139413783Smrg free(lessees); 242239413783Smrg#endif 242339413783Smrg} 242439413783Smrg 242539413783Smrg#ifdef XF86_LEASE_VERSION 242639413783Smrg 242739413783Smrgstatic int 242839413783Smrgdrmmode_create_lease(RRLeasePtr lease, int *fd) 242939413783Smrg{ 243039413783Smrg ScreenPtr screen = lease->screen; 243139413783Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 243239413783Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 243339413783Smrg drmmode_lease_private_ptr lease_private; 243439413783Smrg int noutput = lease->numOutputs; 243539413783Smrg int ncrtc = lease->numCrtcs; 243639413783Smrg uint32_t *objects; 243739413783Smrg size_t nobjects; 243839413783Smrg int lease_fd; 243939413783Smrg int c, o; 244039413783Smrg int i; 244139413783Smrg 244239413783Smrg nobjects = ncrtc + noutput; 244339413783Smrg if (nobjects == 0 || nobjects > (SIZE_MAX / 4) || 244439413783Smrg ncrtc > (SIZE_MAX - noutput)) 244539413783Smrg return BadValue; 244639413783Smrg 244739413783Smrg lease_private = calloc(1, sizeof (drmmode_lease_private_rec)); 244839413783Smrg if (!lease_private) 244939413783Smrg return BadAlloc; 245039413783Smrg 245139413783Smrg objects = malloc(nobjects * 4); 245239413783Smrg if (!objects) { 245339413783Smrg free(lease_private); 245439413783Smrg return BadAlloc; 245539413783Smrg } 245639413783Smrg 245739413783Smrg i = 0; 245839413783Smrg 245939413783Smrg /* Add CRTC ids */ 246039413783Smrg for (c = 0; c < ncrtc; c++) { 246139413783Smrg xf86CrtcPtr crtc = lease->crtcs[c]->devPrivate; 246239413783Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 246339413783Smrg 246439413783Smrg objects[i++] = drmmode_crtc->mode_crtc->crtc_id; 246539413783Smrg } 246639413783Smrg 246739413783Smrg /* Add connector ids */ 246839413783Smrg for (o = 0; o < noutput; o++) { 246939413783Smrg xf86OutputPtr output = lease->outputs[o]->devPrivate; 247039413783Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 247139413783Smrg 247239413783Smrg objects[i++] = drmmode_output->mode_output->connector_id; 247339413783Smrg } 247439413783Smrg 247539413783Smrg /* call kernel to create lease */ 247639413783Smrg assert (i == nobjects); 247739413783Smrg 247839413783Smrg lease_fd = drmModeCreateLease(pRADEONEnt->fd, objects, nobjects, 0, 247939413783Smrg &lease_private->lessee_id); 248039413783Smrg 248139413783Smrg free(objects); 248239413783Smrg 248339413783Smrg if (lease_fd < 0) { 248439413783Smrg free(lease_private); 248539413783Smrg return BadMatch; 248639413783Smrg } 248739413783Smrg 248839413783Smrg lease->devPrivate = lease_private; 248939413783Smrg 249039413783Smrg xf86CrtcLeaseStarted(lease); 249139413783Smrg 249239413783Smrg *fd = lease_fd; 249339413783Smrg return Success; 249439413783Smrg} 249539413783Smrg 249639413783Smrgstatic void 249739413783Smrgdrmmode_terminate_lease(RRLeasePtr lease) 249839413783Smrg{ 249939413783Smrg drmmode_lease_private_ptr lease_private = lease->devPrivate; 250039413783Smrg ScreenPtr screen = lease->screen; 250139413783Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 250239413783Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 250339413783Smrg 250439413783Smrg if (drmModeRevokeLease(pRADEONEnt->fd, lease_private->lessee_id) == 0) { 250539413783Smrg free(lease_private); 250639413783Smrg lease->devPrivate = NULL; 250739413783Smrg xf86CrtcLeaseTerminated(lease); 250839413783Smrg } 250939413783Smrg} 251039413783Smrg 251139413783Smrg#endif // XF86_LEASE_VERSION 251239413783Smrg 2513de2362d3Smrgstatic const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { 251439413783Smrg .resize = drmmode_xf86crtc_resize, 251539413783Smrg#ifdef XF86_LEASE_VERSION 251639413783Smrg .create_lease = drmmode_create_lease, 251739413783Smrg .terminate_lease = drmmode_terminate_lease 251839413783Smrg#endif 2519de2362d3Smrg}; 2520de2362d3Smrg 2521de2362d3Smrgstatic void 252218781e08Smrgdrmmode_flip_abort(xf86CrtcPtr crtc, void *event_data) 2523de2362d3Smrg{ 25248bf5c682Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 25258bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn); 252618781e08Smrg drmmode_flipdata_ptr flipdata = event_data; 252739413783Smrg int crtc_id = drmmode_get_crtc_id(crtc); 252839413783Smrg struct drmmode_fb **fb = &flipdata->fb[crtc_id]; 252939413783Smrg 253039413783Smrg if (drmmode_crtc->flip_pending == *fb) { 253139413783Smrg drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->flip_pending, 253239413783Smrg NULL); 253339413783Smrg } 253439413783Smrg drmmode_fb_reference(pRADEONEnt->fd, fb, NULL); 253518781e08Smrg 253618781e08Smrg if (--flipdata->flip_count == 0) { 253718781e08Smrg if (!flipdata->fe_crtc) 253818781e08Smrg flipdata->fe_crtc = crtc; 253918781e08Smrg flipdata->abort(flipdata->fe_crtc, flipdata->event_data); 254018781e08Smrg free(flipdata); 254118781e08Smrg } 2542de2362d3Smrg} 2543de2362d3Smrg 2544de2362d3Smrgstatic void 254518781e08Smrgdrmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *event_data) 2546de2362d3Smrg{ 25478bf5c682Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 25488bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn); 254918781e08Smrg drmmode_flipdata_ptr flipdata = event_data; 255039413783Smrg int crtc_id = drmmode_get_crtc_id(crtc); 255139413783Smrg struct drmmode_fb **fb = &flipdata->fb[crtc_id]; 2552de2362d3Smrg 2553de2362d3Smrg /* Is this the event whose info shall be delivered to higher level? */ 255418781e08Smrg if (crtc == flipdata->fe_crtc) { 2555de2362d3Smrg /* Yes: Cache msc, ust for later delivery. */ 2556de2362d3Smrg flipdata->fe_frame = frame; 255718781e08Smrg flipdata->fe_usec = usec; 2558de2362d3Smrg } 2559de2362d3Smrg 256039413783Smrg if (drmmode_crtc->flip_pending == *fb) { 25618bf5c682Smrg drmmode_fb_reference(pRADEONEnt->fd, 25628bf5c682Smrg &drmmode_crtc->flip_pending, NULL); 25638bf5c682Smrg } 256439413783Smrg drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, *fb); 256539413783Smrg drmmode_fb_reference(pRADEONEnt->fd, fb, NULL); 25668bf5c682Smrg 256718781e08Smrg if (--flipdata->flip_count == 0) { 256818781e08Smrg /* Deliver MSC & UST from reference/current CRTC to flip event 256918781e08Smrg * handler 257018781e08Smrg */ 257118781e08Smrg if (flipdata->fe_crtc) 257218781e08Smrg flipdata->handler(flipdata->fe_crtc, flipdata->fe_frame, 257318781e08Smrg flipdata->fe_usec, flipdata->event_data); 257418781e08Smrg else 257518781e08Smrg flipdata->handler(crtc, frame, usec, flipdata->event_data); 2576de2362d3Smrg 257718781e08Smrg free(flipdata); 257818781e08Smrg } 2579de2362d3Smrg} 2580de2362d3Smrg 2581de2362d3Smrg 258218781e08Smrg#if HAVE_NOTIFY_FD 258318781e08Smrgstatic void 258418781e08Smrgdrm_notify_fd(int fd, int ready, void *data) 258518781e08Smrg#else 2586de2362d3Smrgstatic void 2587de2362d3Smrgdrm_wakeup_handler(pointer data, int err, pointer p) 258818781e08Smrg#endif 2589de2362d3Smrg{ 259039413783Smrg drmmode_ptr drmmode = data; 259139413783Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(drmmode->scrn); 25928bf5c682Smrg 259318781e08Smrg#if !HAVE_NOTIFY_FD 2594de2362d3Smrg fd_set *read_mask = p; 2595de2362d3Smrg 25968bf5c682Smrg if (err >= 0 && FD_ISSET(pRADEONEnt->fd, read_mask)) 259718781e08Smrg#endif 259818781e08Smrg { 259939413783Smrg radeon_drm_handle_event(pRADEONEnt->fd, &drmmode->event_context); 2600de2362d3Smrg } 2601de2362d3Smrg} 2602de2362d3Smrg 26038bf5c682Smrgstatic Bool drmmode_probe_page_flip_target(RADEONEntPtr pRADEONEnt) 26043ed65abbSmrg{ 26053ed65abbSmrg#ifdef DRM_CAP_PAGE_FLIP_TARGET 26063ed65abbSmrg uint64_t cap_value; 26073ed65abbSmrg 26088bf5c682Smrg return drmGetCap(pRADEONEnt->fd, DRM_CAP_PAGE_FLIP_TARGET, 26093ed65abbSmrg &cap_value) == 0 && cap_value != 0; 26103ed65abbSmrg#else 26113ed65abbSmrg return FALSE; 26123ed65abbSmrg#endif 26133ed65abbSmrg} 26143ed65abbSmrg 26153ed65abbSmrgstatic int 26168bf5c682Smrgdrmmode_page_flip(RADEONEntPtr pRADEONEnt, 26178bf5c682Smrg drmmode_crtc_private_ptr drmmode_crtc, int fb_id, 26183ed65abbSmrg uint32_t flags, uintptr_t drm_queue_seq) 26193ed65abbSmrg{ 26203ed65abbSmrg flags |= DRM_MODE_PAGE_FLIP_EVENT; 26218bf5c682Smrg return drmModePageFlip(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 26223ed65abbSmrg fb_id, flags, (void*)drm_queue_seq); 26233ed65abbSmrg} 26243ed65abbSmrg 26253ed65abbSmrgint 26263ed65abbSmrgdrmmode_page_flip_target_absolute(RADEONEntPtr pRADEONEnt, 26273ed65abbSmrg drmmode_crtc_private_ptr drmmode_crtc, 26283ed65abbSmrg int fb_id, uint32_t flags, 26293ed65abbSmrg uintptr_t drm_queue_seq, uint32_t target_msc) 26303ed65abbSmrg{ 26313ed65abbSmrg#ifdef DRM_MODE_PAGE_FLIP_TARGET 26323ed65abbSmrg if (pRADEONEnt->has_page_flip_target) { 26333ed65abbSmrg flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE; 26348bf5c682Smrg return drmModePageFlipTarget(pRADEONEnt->fd, 26353ed65abbSmrg drmmode_crtc->mode_crtc->crtc_id, 26363ed65abbSmrg fb_id, flags, (void*)drm_queue_seq, 26373ed65abbSmrg target_msc); 26383ed65abbSmrg } 26393ed65abbSmrg#endif 26403ed65abbSmrg 26418bf5c682Smrg return drmmode_page_flip(pRADEONEnt, drmmode_crtc, fb_id, flags, 26428bf5c682Smrg drm_queue_seq); 26433ed65abbSmrg} 26443ed65abbSmrg 26453ed65abbSmrgint 26463ed65abbSmrgdrmmode_page_flip_target_relative(RADEONEntPtr pRADEONEnt, 26473ed65abbSmrg drmmode_crtc_private_ptr drmmode_crtc, 26483ed65abbSmrg int fb_id, uint32_t flags, 26493ed65abbSmrg uintptr_t drm_queue_seq, uint32_t target_msc) 26503ed65abbSmrg{ 26513ed65abbSmrg#ifdef DRM_MODE_PAGE_FLIP_TARGET 26523ed65abbSmrg if (pRADEONEnt->has_page_flip_target) { 26533ed65abbSmrg flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_RELATIVE; 26548bf5c682Smrg return drmModePageFlipTarget(pRADEONEnt->fd, 26553ed65abbSmrg drmmode_crtc->mode_crtc->crtc_id, 26563ed65abbSmrg fb_id, flags, (void*)drm_queue_seq, 26573ed65abbSmrg target_msc); 26583ed65abbSmrg } 26593ed65abbSmrg#endif 26603ed65abbSmrg 26618bf5c682Smrg return drmmode_page_flip(pRADEONEnt, drmmode_crtc, fb_id, flags, 26628bf5c682Smrg drm_queue_seq); 26633ed65abbSmrg} 26643ed65abbSmrg 2665de2362d3SmrgBool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp) 2666de2362d3Smrg{ 266718781e08Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 266818781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 2669de2362d3Smrg int i, num_dvi = 0, num_hdmi = 0; 267018781e08Smrg drmModeResPtr mode_res; 267118781e08Smrg unsigned int crtcs_needed = 0; 267218781e08Smrg char *bus_id_string, *provider_name; 2673de2362d3Smrg 2674de2362d3Smrg xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs); 2675de2362d3Smrg 2676de2362d3Smrg drmmode->scrn = pScrn; 26778bf5c682Smrg mode_res = drmModeGetResources(pRADEONEnt->fd); 267818781e08Smrg if (!mode_res) 2679de2362d3Smrg return FALSE; 2680de2362d3Smrg 268118781e08Smrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 268218781e08Smrg "Initializing outputs ...\n"); 268318781e08Smrg for (i = 0; i < mode_res->count_connectors; i++) 268418781e08Smrg crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, 268518781e08Smrg i, &num_dvi, &num_hdmi, 0); 268618781e08Smrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 268718781e08Smrg "%d crtcs needed for screen.\n", crtcs_needed); 268818781e08Smrg 26898bf5c682Smrg /* Need per-screen drmmode_crtc_funcs, based on our global template, 26908bf5c682Smrg * so we can disable some functions, depending on screen settings. 26918bf5c682Smrg */ 26928bf5c682Smrg info->drmmode_crtc_funcs = drmmode_crtc_funcs; 26938bf5c682Smrg 269418781e08Smrg if (info->r600_shadow_fb) { 269518781e08Smrg /* Rotation requires hardware acceleration */ 26968bf5c682Smrg info->drmmode_crtc_funcs.shadow_allocate = NULL; 26978bf5c682Smrg info->drmmode_crtc_funcs.shadow_create = NULL; 26988bf5c682Smrg info->drmmode_crtc_funcs.shadow_destroy = NULL; 269918781e08Smrg } 270018781e08Smrg 27018bf5c682Smrg /* Hw gamma lut's are currently bypassed by the hw at color depth 30, 27028bf5c682Smrg * so spare the server the effort to compute and update the cluts. 27038bf5c682Smrg */ 27048bf5c682Smrg if (pScrn->depth == 30) 27058bf5c682Smrg info->drmmode_crtc_funcs.gamma_set = NULL; 27068bf5c682Smrg 270718781e08Smrg drmmode->count_crtcs = mode_res->count_crtcs; 270818781e08Smrg xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width, mode_res->max_height); 270918781e08Smrg 271018781e08Smrg for (i = 0; i < mode_res->count_crtcs; i++) 271118781e08Smrg if (!xf86IsEntityShared(pScrn->entityList[0]) || 271218781e08Smrg (crtcs_needed && !(pRADEONEnt->assigned_crtcs & (1 << i)))) 271318781e08Smrg crtcs_needed -= drmmode_crtc_init(pScrn, drmmode, mode_res, i); 2714de2362d3Smrg 271518781e08Smrg /* All ZaphodHeads outputs provided with matching crtcs? */ 271618781e08Smrg if (xf86IsEntityShared(pScrn->entityList[0]) && (crtcs_needed > 0)) 271718781e08Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 271818781e08Smrg "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n", 271918781e08Smrg crtcs_needed); 2720de2362d3Smrg 2721de2362d3Smrg /* workout clones */ 272218781e08Smrg drmmode_clones_init(pScrn, drmmode, mode_res); 272318781e08Smrg 272418781e08Smrg bus_id_string = DRICreatePCIBusID(info->PciInfo); 272518781e08Smrg XNFasprintf(&provider_name, "%s @ %s", pScrn->chipset, bus_id_string); 272618781e08Smrg free(bus_id_string); 272718781e08Smrg xf86ProviderSetup(pScrn, NULL, provider_name); 272818781e08Smrg free(provider_name); 2729de2362d3Smrg 2730de2362d3Smrg xf86InitialConfiguration(pScrn, TRUE); 2731de2362d3Smrg 27328bf5c682Smrg pRADEONEnt->has_page_flip_target = drmmode_probe_page_flip_target(pRADEONEnt); 27333ed65abbSmrg 273418781e08Smrg drmModeFreeResources(mode_res); 2735de2362d3Smrg return TRUE; 2736de2362d3Smrg} 2737de2362d3Smrg 2738de2362d3Smrgvoid drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 2739de2362d3Smrg{ 2740de2362d3Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 2741de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 2742de2362d3Smrg 274318781e08Smrg if (info->dri2.pKernelDRMVersion->version_minor < 4) 274418781e08Smrg return; 274518781e08Smrg 274618781e08Smrg info->drmmode_inited = TRUE; 274718781e08Smrg if (pRADEONEnt->fd_wakeup_registered != serverGeneration) { 274818781e08Smrg#if HAVE_NOTIFY_FD 274939413783Smrg SetNotifyFd(pRADEONEnt->fd, drm_notify_fd, X_NOTIFY_READ, 275039413783Smrg &info->drmmode); 275118781e08Smrg#else 27528bf5c682Smrg AddGeneralSocket(pRADEONEnt->fd); 2753de2362d3Smrg RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, 275439413783Smrg drm_wakeup_handler, 275539413783Smrg &info->drmmode); 275618781e08Smrg#endif 2757de2362d3Smrg pRADEONEnt->fd_wakeup_registered = serverGeneration; 275818781e08Smrg pRADEONEnt->fd_wakeup_ref = 1; 275918781e08Smrg } else 276018781e08Smrg pRADEONEnt->fd_wakeup_ref++; 276118781e08Smrg} 276218781e08Smrg 276318781e08Smrgvoid drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 276418781e08Smrg{ 276518781e08Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 276618781e08Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 276718781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 276818781e08Smrg int c; 276918781e08Smrg 277018781e08Smrg if (info->dri2.pKernelDRMVersion->version_minor < 4 || !info->drmmode_inited) 277118781e08Smrg return; 277218781e08Smrg 277318781e08Smrg if (pRADEONEnt->fd_wakeup_registered == serverGeneration && 277418781e08Smrg !--pRADEONEnt->fd_wakeup_ref) { 277518781e08Smrg#if HAVE_NOTIFY_FD 27768bf5c682Smrg RemoveNotifyFd(pRADEONEnt->fd); 277718781e08Smrg#else 27788bf5c682Smrg RemoveGeneralSocket(pRADEONEnt->fd); 277918781e08Smrg RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, 27808bf5c682Smrg drm_wakeup_handler, pScrn); 278118781e08Smrg#endif 278218781e08Smrg } 278318781e08Smrg 27843ed65abbSmrg for (c = 0; c < config->num_crtc; c++) 27853ed65abbSmrg drmmode_crtc_scanout_free(config->crtc[c]->driver_private); 2786de2362d3Smrg} 2787de2362d3Smrg 278818781e08Smrg 2789de2362d3SmrgBool drmmode_set_bufmgr(ScrnInfoPtr pScrn, drmmode_ptr drmmode, struct radeon_bo_manager *bufmgr) 2790de2362d3Smrg{ 2791de2362d3Smrg drmmode->bufmgr = bufmgr; 2792de2362d3Smrg return TRUE; 2793de2362d3Smrg} 2794de2362d3Smrg 2795de2362d3Smrg 27968bf5c682Smrgstatic void drmmode_sprite_do_set_cursor(struct radeon_device_priv *device_priv, 27978bf5c682Smrg ScrnInfoPtr scrn, int x, int y) 27988bf5c682Smrg{ 27998bf5c682Smrg RADEONInfoPtr info = RADEONPTR(scrn); 28008bf5c682Smrg CursorPtr cursor = device_priv->cursor; 28018bf5c682Smrg Bool sprite_visible = device_priv->sprite_visible; 28028bf5c682Smrg 28038bf5c682Smrg if (cursor) { 28048bf5c682Smrg x -= cursor->bits->xhot; 28058bf5c682Smrg y -= cursor->bits->yhot; 28068bf5c682Smrg 28078bf5c682Smrg device_priv->sprite_visible = 28088bf5c682Smrg x < scrn->virtualX && y < scrn->virtualY && 28098bf5c682Smrg (x + cursor->bits->width > 0) && 28108bf5c682Smrg (y + cursor->bits->height > 0); 28118bf5c682Smrg } else { 28128bf5c682Smrg device_priv->sprite_visible = FALSE; 28138bf5c682Smrg } 28148bf5c682Smrg 28158bf5c682Smrg info->sprites_visible += device_priv->sprite_visible - sprite_visible; 28168bf5c682Smrg} 28178bf5c682Smrg 281839413783Smrgstatic void drmmode_sprite_set_cursor(DeviceIntPtr pDev, ScreenPtr pScreen, 281939413783Smrg CursorPtr pCursor, int x, int y) 28208bf5c682Smrg{ 28218bf5c682Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 28228bf5c682Smrg RADEONInfoPtr info = RADEONPTR(scrn); 28238bf5c682Smrg struct radeon_device_priv *device_priv = 28248bf5c682Smrg dixLookupScreenPrivate(&pDev->devPrivates, 28258bf5c682Smrg &radeon_device_private_key, pScreen); 28268bf5c682Smrg 28278bf5c682Smrg device_priv->cursor = pCursor; 28288bf5c682Smrg drmmode_sprite_do_set_cursor(device_priv, scrn, x, y); 28298bf5c682Smrg 283039413783Smrg info->SpriteFuncs->SetCursor(pDev, pScreen, pCursor, x, y); 28318bf5c682Smrg} 28328bf5c682Smrg 283339413783Smrgstatic void drmmode_sprite_move_cursor(DeviceIntPtr pDev, ScreenPtr pScreen, 283439413783Smrg int x, int y) 28358bf5c682Smrg{ 28368bf5c682Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 28378bf5c682Smrg RADEONInfoPtr info = RADEONPTR(scrn); 28388bf5c682Smrg struct radeon_device_priv *device_priv = 28398bf5c682Smrg dixLookupScreenPrivate(&pDev->devPrivates, 28408bf5c682Smrg &radeon_device_private_key, pScreen); 28418bf5c682Smrg 28428bf5c682Smrg drmmode_sprite_do_set_cursor(device_priv, scrn, x, y); 28438bf5c682Smrg 284439413783Smrg info->SpriteFuncs->MoveCursor(pDev, pScreen, x, y); 284539413783Smrg} 284639413783Smrg 284739413783Smrgstatic Bool drmmode_sprite_realize_realize_cursor(DeviceIntPtr pDev, 284839413783Smrg ScreenPtr pScreen, 284939413783Smrg CursorPtr pCursor) 285039413783Smrg{ 285139413783Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 285239413783Smrg RADEONInfoPtr info = RADEONPTR(scrn); 285339413783Smrg 285439413783Smrg return info->SpriteFuncs->RealizeCursor(pDev, pScreen, pCursor); 285539413783Smrg} 285639413783Smrg 285739413783Smrgstatic Bool drmmode_sprite_realize_unrealize_cursor(DeviceIntPtr pDev, 285839413783Smrg ScreenPtr pScreen, 285939413783Smrg CursorPtr pCursor) 286039413783Smrg{ 286139413783Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 286239413783Smrg RADEONInfoPtr info = RADEONPTR(scrn); 286339413783Smrg 286439413783Smrg return info->SpriteFuncs->UnrealizeCursor(pDev, pScreen, pCursor); 286539413783Smrg} 286639413783Smrg 286739413783Smrgstatic Bool drmmode_sprite_device_cursor_initialize(DeviceIntPtr pDev, 286839413783Smrg ScreenPtr pScreen) 286939413783Smrg{ 287039413783Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 287139413783Smrg RADEONInfoPtr info = RADEONPTR(scrn); 287239413783Smrg 287339413783Smrg return info->SpriteFuncs->DeviceCursorInitialize(pDev, pScreen); 28748bf5c682Smrg} 2875de2362d3Smrg 287639413783Smrgstatic void drmmode_sprite_device_cursor_cleanup(DeviceIntPtr pDev, 287739413783Smrg ScreenPtr pScreen) 287839413783Smrg{ 287939413783Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 288039413783Smrg RADEONInfoPtr info = RADEONPTR(scrn); 288139413783Smrg 288239413783Smrg info->SpriteFuncs->DeviceCursorCleanup(pDev, pScreen); 288339413783Smrg} 288439413783Smrg 288539413783SmrgmiPointerSpriteFuncRec drmmode_sprite_funcs = { 288639413783Smrg .RealizeCursor = drmmode_sprite_realize_realize_cursor, 288739413783Smrg .UnrealizeCursor = drmmode_sprite_realize_unrealize_cursor, 288839413783Smrg .SetCursor = drmmode_sprite_set_cursor, 288939413783Smrg .MoveCursor = drmmode_sprite_move_cursor, 289039413783Smrg .DeviceCursorInitialize = drmmode_sprite_device_cursor_initialize, 289139413783Smrg .DeviceCursorCleanup = drmmode_sprite_device_cursor_cleanup, 289239413783Smrg}; 289339413783Smrg 289439413783Smrg 2895de2362d3Smrgvoid drmmode_set_cursor(ScrnInfoPtr scrn, drmmode_ptr drmmode, int id, struct radeon_bo *bo) 2896de2362d3Smrg{ 2897de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2898de2362d3Smrg xf86CrtcPtr crtc = xf86_config->crtc[id]; 2899de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 2900de2362d3Smrg 2901de2362d3Smrg drmmode_crtc->cursor_bo = bo; 2902de2362d3Smrg} 2903de2362d3Smrg 2904de2362d3Smrgvoid drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y) 2905de2362d3Smrg{ 2906de2362d3Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 2907de2362d3Smrg xf86OutputPtr output = config->output[config->compat_output]; 2908de2362d3Smrg xf86CrtcPtr crtc = output->crtc; 2909de2362d3Smrg 2910de2362d3Smrg if (crtc && crtc->enabled) { 2911de2362d3Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 2912de2362d3Smrg x, y); 2913de2362d3Smrg } 2914de2362d3Smrg} 2915de2362d3Smrg 291618781e08SmrgBool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, 291718781e08Smrg Bool set_hw) 2918de2362d3Smrg{ 2919de2362d3Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 29208bf5c682Smrg unsigned num_desired = 0, num_on = 0; 2921de2362d3Smrg int c; 2922de2362d3Smrg 29238bf5c682Smrg /* First, disable all unused CRTCs */ 29248bf5c682Smrg if (set_hw) { 29258bf5c682Smrg for (c = 0; c < config->num_crtc; c++) { 29268bf5c682Smrg xf86CrtcPtr crtc = config->crtc[c]; 29278bf5c682Smrg 29288bf5c682Smrg /* Skip disabled CRTCs */ 29298bf5c682Smrg if (crtc->enabled) 29308bf5c682Smrg continue; 29318bf5c682Smrg 293239413783Smrg drmmode_crtc_dpms(crtc, DPMSModeOff); 29338bf5c682Smrg } 29348bf5c682Smrg } 29358bf5c682Smrg 29368bf5c682Smrg /* Then, try setting the chosen mode on each CRTC */ 2937de2362d3Smrg for (c = 0; c < config->num_crtc; c++) { 2938de2362d3Smrg xf86CrtcPtr crtc = config->crtc[c]; 2939de2362d3Smrg xf86OutputPtr output = NULL; 2940de2362d3Smrg int o; 2941de2362d3Smrg 29428bf5c682Smrg if (!crtc->enabled) 2943de2362d3Smrg continue; 2944de2362d3Smrg 2945de2362d3Smrg if (config->output[config->compat_output]->crtc == crtc) 2946de2362d3Smrg output = config->output[config->compat_output]; 2947de2362d3Smrg else 2948de2362d3Smrg { 2949de2362d3Smrg for (o = 0; o < config->num_output; o++) 2950de2362d3Smrg if (config->output[o]->crtc == crtc) 2951de2362d3Smrg { 2952de2362d3Smrg output = config->output[o]; 2953de2362d3Smrg break; 2954de2362d3Smrg } 2955de2362d3Smrg } 2956de2362d3Smrg /* paranoia */ 2957de2362d3Smrg if (!output) 2958de2362d3Smrg continue; 2959de2362d3Smrg 29608bf5c682Smrg num_desired++; 29618bf5c682Smrg 2962de2362d3Smrg /* Mark that we'll need to re-set the mode for sure */ 2963de2362d3Smrg memset(&crtc->mode, 0, sizeof(crtc->mode)); 2964de2362d3Smrg if (!crtc->desiredMode.CrtcHDisplay) 2965de2362d3Smrg { 2966de2362d3Smrg DisplayModePtr mode = xf86OutputFindClosestMode (output, pScrn->currentMode); 2967de2362d3Smrg 29688bf5c682Smrg if (!mode) { 29698bf5c682Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 29708bf5c682Smrg "Failed to find mode for CRTC %d\n", c); 29718bf5c682Smrg continue; 29728bf5c682Smrg } 2973de2362d3Smrg crtc->desiredMode = *mode; 2974de2362d3Smrg crtc->desiredRotation = RR_Rotate_0; 2975de2362d3Smrg crtc->desiredX = 0; 2976de2362d3Smrg crtc->desiredY = 0; 2977de2362d3Smrg } 2978de2362d3Smrg 297918781e08Smrg if (set_hw) { 29808bf5c682Smrg if (crtc->funcs->set_mode_major(crtc, &crtc->desiredMode, 29818bf5c682Smrg crtc->desiredRotation, 29828bf5c682Smrg crtc->desiredX, 29838bf5c682Smrg crtc->desiredY)) { 29848bf5c682Smrg num_on++; 29858bf5c682Smrg } else { 29868bf5c682Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 29878bf5c682Smrg "Failed to set mode on CRTC %d\n", c); 298839413783Smrg RRCrtcSet(crtc->randr_crtc, NULL, crtc->x, crtc->y, 298939413783Smrg crtc->rotation, 0, NULL); 29908bf5c682Smrg } 299118781e08Smrg } else { 299218781e08Smrg crtc->mode = crtc->desiredMode; 299318781e08Smrg crtc->rotation = crtc->desiredRotation; 299418781e08Smrg crtc->x = crtc->desiredX; 299518781e08Smrg crtc->y = crtc->desiredY; 29968bf5c682Smrg if (drmmode_handle_transform(crtc)) 29978bf5c682Smrg num_on++; 299818781e08Smrg } 2999de2362d3Smrg } 30008bf5c682Smrg 30018bf5c682Smrg if (num_on == 0 && num_desired > 0) { 30028bf5c682Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to enable any CRTC\n"); 30038bf5c682Smrg return FALSE; 30048bf5c682Smrg } 30058bf5c682Smrg 300639413783Smrg /* Validate leases on VT re-entry */ 300739413783Smrg drmmode_validate_leases(pScrn); 300839413783Smrg 3009de2362d3Smrg return TRUE; 3010de2362d3Smrg} 3011de2362d3Smrg 301218781e08SmrgBool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn) 3013de2362d3Smrg{ 3014de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 301539413783Smrg int i; 3016de2362d3Smrg 301718781e08Smrg if (xf86_config->num_crtc) { 301818781e08Smrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 301918781e08Smrg "Initializing kms color map\n"); 302018781e08Smrg if (!miCreateDefColormap(pScreen)) 302118781e08Smrg return FALSE; 30228bf5c682Smrg 30238bf5c682Smrg /* All radeons support 10 bit CLUTs. They get bypassed at depth 30. */ 302439413783Smrg if (pScrn->depth != 30) { 302539413783Smrg if (!xf86HandleColormaps(pScreen, 256, 10, NULL, NULL, 302639413783Smrg CMAP_PALETTED_TRUECOLOR 302739413783Smrg | CMAP_RELOAD_ON_MODE_SWITCH)) 302839413783Smrg return FALSE; 302939413783Smrg 303039413783Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 303139413783Smrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 303239413783Smrg 303339413783Smrg drmmode_crtc_gamma_do_set(crtc, crtc->gamma_red, 303439413783Smrg crtc->gamma_green, 303539413783Smrg crtc->gamma_blue, 303639413783Smrg crtc->gamma_size); 303739413783Smrg } 303839413783Smrg } 303918781e08Smrg } 304039413783Smrg 304118781e08Smrg return TRUE; 304218781e08Smrg} 30437314432eSmrg 304418781e08Smrgstatic Bool 304518781e08Smrgdrmmode_find_output(ScrnInfoPtr scrn, int output_id, int *num_dvi, 304618781e08Smrg int *num_hdmi) 304718781e08Smrg{ 304818781e08Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 304918781e08Smrg int i; 30507314432eSmrg 305118781e08Smrg for (i = 0; i < config->num_output; i++) { 305218781e08Smrg xf86OutputPtr output = config->output[i]; 305318781e08Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 305418781e08Smrg 305518781e08Smrg if (drmmode_output->output_id == output_id) { 305618781e08Smrg switch(drmmode_output->mode_output->connector_type) { 305718781e08Smrg case DRM_MODE_CONNECTOR_DVII: 305818781e08Smrg case DRM_MODE_CONNECTOR_DVID: 305918781e08Smrg case DRM_MODE_CONNECTOR_DVIA: 306018781e08Smrg (*num_dvi)++; 306118781e08Smrg break; 306218781e08Smrg case DRM_MODE_CONNECTOR_HDMIA: 306318781e08Smrg case DRM_MODE_CONNECTOR_HDMIB: 306418781e08Smrg (*num_hdmi)++; 306518781e08Smrg break; 306618781e08Smrg } 306718781e08Smrg 306818781e08Smrg return TRUE; 306918781e08Smrg } 307018781e08Smrg } 307118781e08Smrg 307218781e08Smrg return FALSE; 30737314432eSmrg} 30747314432eSmrg 307518781e08Smrgvoid 307618781e08Smrgradeon_mode_hotplug(ScrnInfoPtr scrn, drmmode_ptr drmmode) 30770d16fef4Smrg{ 307818781e08Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 307918781e08Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 308018781e08Smrg drmModeResPtr mode_res; 308118781e08Smrg int i, j; 308218781e08Smrg Bool found; 308318781e08Smrg Bool changed = FALSE; 308418781e08Smrg int num_dvi = 0, num_hdmi = 0; 308518781e08Smrg 30868bf5c682Smrg /* Try to re-set the mode on all the connectors with a BAD link-state: 30878bf5c682Smrg * This may happen if a link degrades and a new modeset is necessary, using 30888bf5c682Smrg * different link-training parameters. If the kernel found that the current 30898bf5c682Smrg * mode is not achievable anymore, it should have pruned the mode before 30908bf5c682Smrg * sending the hotplug event. Try to re-set the currently-set mode to keep 30918bf5c682Smrg * the display alive, this will fail if the mode has been pruned. 30928bf5c682Smrg * In any case, we will send randr events for the Desktop Environment to 30938bf5c682Smrg * deal with it, if it wants to. 30948bf5c682Smrg */ 30958bf5c682Smrg for (i = 0; i < config->num_output; i++) { 30968bf5c682Smrg xf86OutputPtr output = config->output[i]; 30978bf5c682Smrg xf86CrtcPtr crtc = output->crtc; 30988bf5c682Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 30998bf5c682Smrg 31008bf5c682Smrg drmmode_output_detect(output); 31018bf5c682Smrg 31028bf5c682Smrg if (!crtc || !drmmode_output->mode_output) 31038bf5c682Smrg continue; 31048bf5c682Smrg 31058bf5c682Smrg /* Get an updated view of the properties for the current connector and 31068bf5c682Smrg * look for the link-status property 31078bf5c682Smrg */ 31088bf5c682Smrg for (j = 0; j < drmmode_output->num_props; j++) { 31098bf5c682Smrg drmmode_prop_ptr p = &drmmode_output->props[j]; 31108bf5c682Smrg 31118bf5c682Smrg if (!strcmp(p->mode_prop->name, "link-status")) { 31128bf5c682Smrg if (p->value != DRM_MODE_LINK_STATUS_BAD) 31138bf5c682Smrg break; 31148bf5c682Smrg 31158bf5c682Smrg /* the connector got a link failure, re-set the current mode */ 31168bf5c682Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 31178bf5c682Smrg crtc->x, crtc->y); 31188bf5c682Smrg 31198bf5c682Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 31208bf5c682Smrg "hotplug event: connector %u's link-state is BAD, " 31218bf5c682Smrg "tried resetting the current mode. You may be left" 31228bf5c682Smrg "with a black screen if this fails...\n", 31238bf5c682Smrg drmmode_output->mode_output->connector_id); 31248bf5c682Smrg 31258bf5c682Smrg break; 31268bf5c682Smrg } 31278bf5c682Smrg } 31288bf5c682Smrg } 31298bf5c682Smrg 31308bf5c682Smrg mode_res = drmModeGetResources(pRADEONEnt->fd); 313118781e08Smrg if (!mode_res) 313218781e08Smrg goto out; 313318781e08Smrg 313418781e08Smrgrestart_destroy: 313518781e08Smrg for (i = 0; i < config->num_output; i++) { 313618781e08Smrg xf86OutputPtr output = config->output[i]; 313718781e08Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 313818781e08Smrg found = FALSE; 313918781e08Smrg for (j = 0; j < mode_res->count_connectors; j++) { 314018781e08Smrg if (mode_res->connectors[j] == drmmode_output->output_id) { 314118781e08Smrg found = TRUE; 314218781e08Smrg break; 314318781e08Smrg } 314418781e08Smrg } 314518781e08Smrg if (found) 314618781e08Smrg continue; 314718781e08Smrg 314818781e08Smrg drmModeFreeConnector(drmmode_output->mode_output); 314918781e08Smrg drmmode_output->mode_output = NULL; 315018781e08Smrg drmmode_output->output_id = -1; 315118781e08Smrg 315218781e08Smrg changed = TRUE; 315318781e08Smrg if (drmmode->delete_dp_12_displays) { 315418781e08Smrg RROutputDestroy(output->randr_output); 315518781e08Smrg xf86OutputDestroy(output); 315618781e08Smrg goto restart_destroy; 315718781e08Smrg } 315818781e08Smrg } 315918781e08Smrg 316018781e08Smrg /* find new output ids we don't have outputs for */ 316118781e08Smrg for (i = 0; i < mode_res->count_connectors; i++) { 316218781e08Smrg if (drmmode_find_output(pRADEONEnt->primary_scrn, 316318781e08Smrg mode_res->connectors[i], 316418781e08Smrg &num_dvi, &num_hdmi) || 316518781e08Smrg (pRADEONEnt->secondary_scrn && 316618781e08Smrg drmmode_find_output(pRADEONEnt->secondary_scrn, 316718781e08Smrg mode_res->connectors[i], 316818781e08Smrg &num_dvi, &num_hdmi))) 316918781e08Smrg continue; 317018781e08Smrg 317118781e08Smrg if (drmmode_output_init(scrn, drmmode, mode_res, i, &num_dvi, 317218781e08Smrg &num_hdmi, 1) != 0) 317318781e08Smrg changed = TRUE; 317418781e08Smrg } 317518781e08Smrg 317639413783Smrg /* Check to see if a lessee has disappeared */ 317739413783Smrg drmmode_validate_leases(scrn); 317839413783Smrg 317918781e08Smrg if (changed && dixPrivateKeyRegistered(rrPrivKey)) { 318018781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,2,0) 318118781e08Smrg RRSetChanged(xf86ScrnToScreen(scrn)); 318218781e08Smrg#else 318318781e08Smrg rrScrPrivPtr rrScrPriv = rrGetScrPriv(scrn->pScreen); 318418781e08Smrg rrScrPriv->changed = TRUE; 31850d16fef4Smrg#endif 318618781e08Smrg RRTellChanged(xf86ScrnToScreen(scrn)); 318718781e08Smrg } 31887821949aSmrg 318918781e08Smrg drmModeFreeResources(mode_res); 319018781e08Smrgout: 319118781e08Smrg RRGetInfo(xf86ScrnToScreen(scrn), TRUE); 319218781e08Smrg} 3193de2362d3Smrg#ifdef HAVE_LIBUDEV 3194de2362d3Smrgstatic void 3195de2362d3Smrgdrmmode_handle_uevents(int fd, void *closure) 3196de2362d3Smrg{ 3197de2362d3Smrg drmmode_ptr drmmode = closure; 3198de2362d3Smrg ScrnInfoPtr scrn = drmmode->scrn; 3199de2362d3Smrg struct udev_device *dev; 320018781e08Smrg Bool received = FALSE; 32013ed65abbSmrg struct timeval tv = { 0, 0 }; 32023ed65abbSmrg fd_set readfd; 32033ed65abbSmrg 32043ed65abbSmrg FD_ZERO(&readfd); 32053ed65abbSmrg FD_SET(fd, &readfd); 32063ed65abbSmrg 32073ed65abbSmrg while (select(fd + 1, &readfd, NULL, NULL, &tv) > 0 && 32083ed65abbSmrg FD_ISSET(fd, &readfd)) { 32093ed65abbSmrg /* select() ensured that this will not block */ 32103ed65abbSmrg dev = udev_monitor_receive_device(drmmode->uevent_monitor); 32113ed65abbSmrg if (dev) { 32123ed65abbSmrg udev_device_unref(dev); 32133ed65abbSmrg received = TRUE; 32143ed65abbSmrg } 321518781e08Smrg } 321618781e08Smrg 321718781e08Smrg if (received) 321818781e08Smrg radeon_mode_hotplug(scrn, drmmode); 3219de2362d3Smrg} 3220de2362d3Smrg#endif 3221de2362d3Smrg 3222de2362d3Smrgvoid drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode) 3223de2362d3Smrg{ 3224de2362d3Smrg#ifdef HAVE_LIBUDEV 3225de2362d3Smrg struct udev *u; 3226de2362d3Smrg struct udev_monitor *mon; 3227de2362d3Smrg 3228de2362d3Smrg u = udev_new(); 3229de2362d3Smrg if (!u) 3230de2362d3Smrg return; 3231de2362d3Smrg mon = udev_monitor_new_from_netlink(u, "udev"); 3232de2362d3Smrg if (!mon) { 3233de2362d3Smrg udev_unref(u); 3234de2362d3Smrg return; 3235de2362d3Smrg } 3236de2362d3Smrg 3237de2362d3Smrg if (udev_monitor_filter_add_match_subsystem_devtype(mon, 3238de2362d3Smrg "drm", 3239de2362d3Smrg "drm_minor") < 0 || 3240de2362d3Smrg udev_monitor_enable_receiving(mon) < 0) { 3241de2362d3Smrg udev_monitor_unref(mon); 3242de2362d3Smrg udev_unref(u); 3243de2362d3Smrg return; 3244de2362d3Smrg } 3245de2362d3Smrg 3246de2362d3Smrg drmmode->uevent_handler = 3247de2362d3Smrg xf86AddGeneralHandler(udev_monitor_get_fd(mon), 3248de2362d3Smrg drmmode_handle_uevents, 3249de2362d3Smrg drmmode); 3250de2362d3Smrg 3251de2362d3Smrg drmmode->uevent_monitor = mon; 3252de2362d3Smrg#endif 3253de2362d3Smrg} 3254de2362d3Smrg 3255de2362d3Smrgvoid drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode) 3256de2362d3Smrg{ 3257de2362d3Smrg#ifdef HAVE_LIBUDEV 3258de2362d3Smrg if (drmmode->uevent_handler) { 3259de2362d3Smrg struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor); 3260de2362d3Smrg xf86RemoveGeneralHandler(drmmode->uevent_handler); 3261de2362d3Smrg 3262de2362d3Smrg udev_monitor_unref(drmmode->uevent_monitor); 3263de2362d3Smrg udev_unref(u); 3264de2362d3Smrg } 3265de2362d3Smrg#endif 3266de2362d3Smrg} 3267de2362d3Smrg 326818781e08SmrgBool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, 32698bf5c682Smrg PixmapPtr new_front, uint64_t id, void *data, 32708bf5c682Smrg xf86CrtcPtr ref_crtc, radeon_drm_handler_proc handler, 327118781e08Smrg radeon_drm_abort_proc abort, 32723ed65abbSmrg enum drmmode_flip_sync flip_sync, 32733ed65abbSmrg uint32_t target_msc) 3274de2362d3Smrg{ 32753ed65abbSmrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 3276de2362d3Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 327718781e08Smrg xf86CrtcPtr crtc = NULL; 3278de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private; 32793ed65abbSmrg uint32_t flip_flags = flip_sync == FLIP_ASYNC ? DRM_MODE_PAGE_FLIP_ASYNC : 0; 3280de2362d3Smrg drmmode_flipdata_ptr flipdata; 328139413783Smrg Bool handle_deferred = FALSE; 328218781e08Smrg uintptr_t drm_queue_seq = 0; 328339413783Smrg struct drmmode_fb *fb; 328439413783Smrg int i = 0; 3285de2362d3Smrg 328639413783Smrg flipdata = calloc(1, sizeof(*flipdata) + config->num_crtc * 328739413783Smrg sizeof(flipdata->fb[0])); 32887821949aSmrg if (!flipdata) { 32897821949aSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 32907821949aSmrg "flip queue: data alloc failed.\n"); 329118781e08Smrg goto error; 32927821949aSmrg } 329318781e08Smrg 329439413783Smrg fb = radeon_pixmap_get_fb(new_front); 329539413783Smrg if (!fb) { 32968bf5c682Smrg ErrorF("Failed to get FB for flip\n"); 329718781e08Smrg goto error; 32988bf5c682Smrg } 329918781e08Smrg 3300de2362d3Smrg /* 3301de2362d3Smrg * Queue flips on all enabled CRTCs 3302de2362d3Smrg * Note that if/when we get per-CRTC buffers, we'll have to update this. 3303de2362d3Smrg * Right now it assumes a single shared fb across all CRTCs, with the 3304de2362d3Smrg * kernel fixing up the offset of each CRTC as necessary. 3305de2362d3Smrg * 3306de2362d3Smrg * Also, flips queued on disabled or incorrectly configured displays 3307de2362d3Smrg * may never complete; this is a configuration error. 3308de2362d3Smrg */ 3309de2362d3Smrg 3310de2362d3Smrg flipdata->event_data = data; 331118781e08Smrg flipdata->handler = handler; 331218781e08Smrg flipdata->abort = abort; 33138bf5c682Smrg flipdata->fe_crtc = ref_crtc; 331418781e08Smrg 3315de2362d3Smrg for (i = 0; i < config->num_crtc; i++) { 331618781e08Smrg crtc = config->crtc[i]; 33178bf5c682Smrg drmmode_crtc = crtc->driver_private; 331818781e08Smrg 33198bf5c682Smrg if (!drmmode_crtc_can_flip(crtc) || 33208bf5c682Smrg (drmmode_crtc->tear_free && crtc != ref_crtc)) 3321de2362d3Smrg continue; 3322de2362d3Smrg 3323de2362d3Smrg flipdata->flip_count++; 332418781e08Smrg 332518781e08Smrg drm_queue_seq = radeon_drm_queue_alloc(crtc, client, id, 332618781e08Smrg flipdata, 332718781e08Smrg drmmode_flip_handler, 332818781e08Smrg drmmode_flip_abort); 332918781e08Smrg if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) { 333018781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 333118781e08Smrg "Allocating DRM queue event entry failed.\n"); 333218781e08Smrg goto error; 333318781e08Smrg } 3334de2362d3Smrg 33358bf5c682Smrg if (drmmode_crtc->tear_free) { 33368bf5c682Smrg BoxRec extents = { .x1 = 0, .y1 = 0, 33378bf5c682Smrg .x2 = new_front->drawable.width, 33388bf5c682Smrg .y2 = new_front->drawable.height }; 33398bf5c682Smrg int scanout_id = drmmode_crtc->scanout_id ^ 1; 33408bf5c682Smrg 33418bf5c682Smrg if (flip_sync == FLIP_ASYNC) { 33428bf5c682Smrg if (!drmmode_wait_vblank(crtc, 33438bf5c682Smrg DRM_VBLANK_RELATIVE | 33448bf5c682Smrg DRM_VBLANK_EVENT, 33458bf5c682Smrg 0, drm_queue_seq, 33468bf5c682Smrg NULL, NULL)) 33478bf5c682Smrg goto flip_error; 33488bf5c682Smrg goto next; 33498bf5c682Smrg } 33508bf5c682Smrg 335139413783Smrg drmmode_fb_reference(pRADEONEnt->fd, &flipdata->fb[i], 335239413783Smrg radeon_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap)); 335339413783Smrg if (!flipdata->fb[i]) { 33548bf5c682Smrg ErrorF("Failed to get FB for TearFree flip\n"); 33558bf5c682Smrg goto error; 33568bf5c682Smrg } 33578bf5c682Smrg 33588bf5c682Smrg radeon_scanout_do_update(crtc, scanout_id, new_front, 335939413783Smrg extents); 336039413783Smrg radeon_cs_flush_indirect(crtc->scrn); 336139413783Smrg 336239413783Smrg if (drmmode_crtc->scanout_update_pending) { 336339413783Smrg radeon_drm_wait_pending_flip(crtc); 336439413783Smrg handle_deferred = TRUE; 336539413783Smrg radeon_drm_abort_entry(drmmode_crtc->scanout_update_pending); 336639413783Smrg drmmode_crtc->scanout_update_pending = 0; 336739413783Smrg } 336839413783Smrg } else { 336939413783Smrg drmmode_fb_reference(pRADEONEnt->fd, &flipdata->fb[i], fb); 33708bf5c682Smrg } 33718bf5c682Smrg 33728bf5c682Smrg if (crtc == ref_crtc) { 33733ed65abbSmrg if (drmmode_page_flip_target_absolute(pRADEONEnt, 33743ed65abbSmrg drmmode_crtc, 337539413783Smrg flipdata->fb[i]->handle, 33763ed65abbSmrg flip_flags, 33773ed65abbSmrg drm_queue_seq, 33783ed65abbSmrg target_msc) != 0) 33793ed65abbSmrg goto flip_error; 33803ed65abbSmrg } else { 33813ed65abbSmrg if (drmmode_page_flip_target_relative(pRADEONEnt, 33823ed65abbSmrg drmmode_crtc, 338339413783Smrg flipdata->fb[i]->handle, 33843ed65abbSmrg flip_flags, 33853ed65abbSmrg drm_queue_seq, 0) != 0) 33863ed65abbSmrg goto flip_error; 3387de2362d3Smrg } 33883ed65abbSmrg 33898bf5c682Smrg if (drmmode_crtc->tear_free) { 33908bf5c682Smrg drmmode_crtc->scanout_id ^= 1; 33918bf5c682Smrg drmmode_crtc->ignore_damage = TRUE; 33928bf5c682Smrg } 33938bf5c682Smrg 33948bf5c682Smrg next: 339539413783Smrg drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->flip_pending, 339639413783Smrg flipdata->fb[i]); 339718781e08Smrg drm_queue_seq = 0; 3398de2362d3Smrg } 3399de2362d3Smrg 340039413783Smrg if (handle_deferred) 340139413783Smrg radeon_drm_queue_handle_deferred(ref_crtc); 340218781e08Smrg if (flipdata->flip_count > 0) 340318781e08Smrg return TRUE; 34040d16fef4Smrg 34053ed65abbSmrgflip_error: 34063ed65abbSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed: %s\n", 34073ed65abbSmrg strerror(errno)); 34083ed65abbSmrg 340918781e08Smrgerror: 341018781e08Smrg if (drm_queue_seq) 341118781e08Smrg radeon_drm_abort_entry(drm_queue_seq); 341218781e08Smrg else if (crtc) 341318781e08Smrg drmmode_flip_abort(crtc, flipdata); 34143ed65abbSmrg else { 34153ed65abbSmrg abort(NULL, data); 341618781e08Smrg free(flipdata); 34173ed65abbSmrg } 3418de2362d3Smrg 3419de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n", 3420de2362d3Smrg strerror(errno)); 342139413783Smrg if (handle_deferred) 342239413783Smrg radeon_drm_queue_handle_deferred(ref_crtc); 3423de2362d3Smrg return FALSE; 3424de2362d3Smrg} 3425